Atlas - SDL_bsdjoystick.c
Home / ext / SDL / src / joystick / bsd Lines: 2 | Size: 23959 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_JOYSTICK_USBHID 24 25/* 26 * Joystick driver for the uhid(4) / ujoy(4) interface found in OpenBSD, 27 * NetBSD and FreeBSD. 28 * 29 * Maintainer: <vedge at csoft.org> 30 */ 31 32#include <sys/param.h> 33#include <sys/stat.h> 34 35#include <unistd.h> 36#include <fcntl.h> 37#include <errno.h> 38 39#ifndef __FreeBSD_kernel_version 40#define __FreeBSD_kernel_version __FreeBSD_version 41#endif 42 43#ifdef HAVE_USB_H 44#include <usb.h> 45#endif 46#ifdef __DragonFly__ 47#include <bus/u4b/usb.h> 48#include <bus/u4b/usbhid.h> 49#else 50#include <dev/usb/usb.h> 51#include <dev/usb/usbhid.h> 52#endif 53 54#ifdef HAVE_USBHID_H 55#include <usbhid.h> 56#elif defined(HAVE_LIBUSB_H) 57#include <libusb.h> 58#elif defined(HAVE_LIBUSBHID_H) 59#include <libusbhid.h> 60#endif 61 62#if defined(SDL_PLATFORM_FREEBSD) 63#include <osreldate.h> 64#if __FreeBSD_kernel_version > 800063 65#include <dev/usb/usb_ioctl.h> 66#elif defined(__DragonFly__) 67#include <bus/u4b/usb_ioctl.h> 68#endif 69#include <sys/joystick.h> 70#endif 71 72#ifdef SDL_HAVE_MACHINE_JOYSTICK_H 73#include <machine/joystick.h> 74#endif 75 76#include "../SDL_sysjoystick.h" 77#include "../SDL_joystick_c.h" 78#include "../hidapi/SDL_hidapijoystick_c.h" 79 80#if defined(SDL_PLATFORM_FREEBSD) || defined(SDL_HAVE_MACHINE_JOYSTICK_H) || defined(__FreeBSD_kernel__) || defined(__DragonFly_) 81#define SUPPORT_JOY_GAMEPORT 82#endif 83 84#define MAX_UHID_JOYS 64 85#define MAX_JOY_JOYS 2 86#define MAX_JOYS (MAX_UHID_JOYS + MAX_JOY_JOYS) 87 88#ifdef SDL_PLATFORM_OPENBSD 89 90#define HUG_DPAD_UP 0x90 91#define HUG_DPAD_DOWN 0x91 92#define HUG_DPAD_RIGHT 0x92 93#define HUG_DPAD_LEFT 0x93 94 95#define HAT_UP 0x01 96#define HAT_RIGHT 0x02 97#define HAT_DOWN 0x04 98#define HAT_LEFT 0x08 99 100#endif 101 102struct report 103{ 104#if defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 900000) || \ 105 defined(__DragonFly__) 106 void *buf; // Buffer 107#elif defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 800063) 108 struct usb_gen_descriptor *buf; // Buffer 109#else 110 struct usb_ctl_report *buf; // Buffer 111#endif 112 size_t size; // Buffer size 113 int rid; // Report ID 114 enum 115 { 116 SREPORT_UNINIT, 117 SREPORT_CLEAN, 118 SREPORT_DIRTY 119 } status; 120}; 121 122static struct 123{ 124 int uhid_report; 125 hid_kind_t kind; 126 const char *name; 127} const repinfo[] = { 128 { UHID_INPUT_REPORT, hid_input, "input" }, 129 { UHID_OUTPUT_REPORT, hid_output, "output" }, 130 { UHID_FEATURE_REPORT, hid_feature, "feature" } 131}; 132 133enum 134{ 135 REPORT_INPUT = 0, 136 REPORT_OUTPUT = 1, 137 REPORT_FEATURE = 2 138}; 139 140enum 141{ 142 JOYAXE_X, 143 JOYAXE_Y, 144 JOYAXE_Z, 145 JOYAXE_SLIDER, 146 JOYAXE_WHEEL, 147 JOYAXE_RX, 148 JOYAXE_RY, 149 JOYAXE_RZ, 150 JOYAXE_count 151}; 152 153struct joystick_hwdata 154{ 155 int fd; 156 enum 157 { 158 BSDJOY_UHID, // uhid(4) 159 BSDJOY_JOY // joy(4) 160 } type; 161 162 int naxes; 163 int nbuttons; 164 int nhats; 165 struct report_desc *repdesc; 166 struct report inreport; 167 int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */ 168}; 169 170// A linked list of available joysticks 171typedef struct SDL_joylist_item 172{ 173 SDL_JoystickID device_instance; 174 char *path; // "/dev/uhid0" or whatever 175 char *name; // "SideWinder 3D Pro" or whatever 176 SDL_GUID guid; 177 dev_t devnum; 178 struct SDL_joylist_item *next; 179} SDL_joylist_item; 180 181static SDL_joylist_item *SDL_joylist = NULL; 182static SDL_joylist_item *SDL_joylist_tail = NULL; 183static int numjoysticks = 0; 184 185static bool report_alloc(struct report *, struct report_desc *, int); 186static void report_free(struct report *); 187 188#if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063) 189#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data) 190#elif (defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 900000)) || \ 191 defined(__DragonFly__) 192#define REP_BUF_DATA(rep) ((rep)->buf) 193#elif (defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 800063)) 194#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data) 195#else 196#define REP_BUF_DATA(rep) ((rep)->buf->data) 197#endif 198 199static int usage_to_joyaxe(int usage) 200{ 201 int joyaxe; 202 switch (usage) { 203 case HUG_X: 204 joyaxe = JOYAXE_X; 205 break; 206 case HUG_Y: 207 joyaxe = JOYAXE_Y; 208 break; 209 case HUG_Z: 210 joyaxe = JOYAXE_Z; 211 break; 212 case HUG_SLIDER: 213 joyaxe = JOYAXE_SLIDER; 214 break; 215 case HUG_WHEEL: 216 joyaxe = JOYAXE_WHEEL; 217 break; 218 case HUG_RX: 219 joyaxe = JOYAXE_RX; 220 break; 221 case HUG_RY: 222 joyaxe = JOYAXE_RY; 223 break; 224 case HUG_RZ: 225 joyaxe = JOYAXE_RZ; 226 break; 227 default: 228 joyaxe = -1; 229 } 230 return joyaxe; 231} 232 233static void FreeJoylistItem(SDL_joylist_item *item) 234{ 235 SDL_free(item->path); 236 SDL_free(item->name); 237 SDL_free(item); 238} 239 240static void FreeHwData(struct joystick_hwdata *hw) 241{ 242 if (hw->type == BSDJOY_UHID) { 243 report_free(&hw->inreport); 244 245 if (hw->repdesc) { 246 hid_dispose_report_desc(hw->repdesc); 247 } 248 } 249 close(hw->fd); 250 SDL_free(hw); 251} 252 253static struct joystick_hwdata *CreateHwData(const char *path) 254{ 255 struct joystick_hwdata *hw; 256 struct hid_item hitem; 257 struct hid_data *hdata; 258 struct report *rep = NULL; 259 int fd; 260 int i; 261 262 fd = open(path, O_RDONLY | O_CLOEXEC); 263 if (fd == -1) { 264 SDL_SetError("%s: %s", path, strerror(errno)); 265 return NULL; 266 } 267 268 hw = (struct joystick_hwdata *) 269 SDL_calloc(1, sizeof(struct joystick_hwdata)); 270 if (!hw) { 271 close(fd); 272 return NULL; 273 } 274 hw->fd = fd; 275 276#ifdef SUPPORT_JOY_GAMEPORT 277 if (SDL_strncmp(path, "/dev/joy", 8) == 0) { 278 hw->type = BSDJOY_JOY; 279 hw->naxes = 2; 280 hw->nbuttons = 2; 281 } else 282#endif 283 { 284 hw->type = BSDJOY_UHID; 285 { 286 int ax; 287 for (ax = 0; ax < JOYAXE_count; ax++) { 288 hw->axis_map[ax] = -1; 289 } 290 } 291 hw->repdesc = hid_get_report_desc(fd); 292 if (!hw->repdesc) { 293 SDL_SetError("%s: USB_GET_REPORT_DESC: %s", path, 294 strerror(errno)); 295 goto usberr; 296 } 297 rep = &hw->inreport; 298#if defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 299 rep->rid = hid_get_report_id(fd); 300 if (rep->rid < 0) { 301#else 302 if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { 303#endif 304 rep->rid = -1; // XXX 305 } 306 if (!report_alloc(rep, hw->repdesc, REPORT_INPUT)) { 307 goto usberr; 308 } 309 if (rep->size <= 0) { 310 SDL_SetError("%s: Input report descriptor has invalid length", 311 path); 312 goto usberr; 313 } 314#if defined(USBHID_NEW) || (defined(SDL_PLATFORM_FREEBSD) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 315 hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); 316#else 317 hdata = hid_start_parse(hw->repdesc, 1 << hid_input); 318#endif 319 if (!hdata) { 320 SDL_SetError("%s: Cannot start HID parser", path); 321 goto usberr; 322 } 323 for (i = 0; i < JOYAXE_count; i++) { 324 hw->axis_map[i] = -1; 325 } 326 327 while (hid_get_item(hdata, &hitem) > 0) { 328 switch (hitem.kind) { 329 case hid_input: 330 switch (HID_PAGE(hitem.usage)) { 331 case HUP_GENERIC_DESKTOP: 332 { 333 int usage = HID_USAGE(hitem.usage); 334 int joyaxe = usage_to_joyaxe(usage); 335 if (joyaxe >= 0) { 336 hw->axis_map[joyaxe] = 1; 337 } else if (usage == HUG_HAT_SWITCH 338#ifdef SDL_PLATFORM_OPENBSD 339 || usage == HUG_DPAD_UP 340#endif 341 ) { 342 hw->nhats++; 343 } 344 break; 345 } 346 case HUP_BUTTON: 347 { 348 int usage = HID_USAGE(hitem.usage); 349 if (usage > hw->nbuttons) { 350 hw->nbuttons = usage; 351 } 352 } break; 353 default: 354 break; 355 } 356 break; 357 default: 358 break; 359 } 360 } 361 hid_end_parse(hdata); 362 for (i = 0; i < JOYAXE_count; i++) { 363 if (hw->axis_map[i] > 0) { 364 hw->axis_map[i] = hw->naxes++; 365 } 366 } 367 368 if (hw->naxes == 0 && hw->nbuttons == 0 && hw->nhats == 0) { 369 SDL_SetError("%s: Not a joystick, ignoring", path); 370 goto usberr; 371 } 372 } 373 374 // The poll blocks the event thread. 375 fcntl(fd, F_SETFL, O_NONBLOCK); 376#ifdef SDL_PLATFORM_NETBSD 377 // Flush pending events 378 if (rep) { 379 while (read(fd, REP_BUF_DATA(rep), rep->size) == rep->size) 380 ; 381 } 382#endif 383 384 return hw; 385 386usberr: 387 FreeHwData(hw); 388 return NULL; 389} 390 391static bool MaybeAddDevice(const char *path) 392{ 393 struct stat sb; 394 char *name = NULL; 395 SDL_GUID guid; 396 SDL_joylist_item *item; 397 struct joystick_hwdata *hw; 398 399 if (!path) { 400 return false; 401 } 402 403 if (stat(path, &sb) == -1) { 404 return false; 405 } 406 407 // Check to make sure it's not already in list. 408 for (item = SDL_joylist; item; item = item->next) { 409 if (sb.st_rdev == item->devnum) { 410 return false; // already have this one 411 } 412 } 413 414 hw = CreateHwData(path); 415 if (!hw) { 416 return false; 417 } 418 419 if (hw->type == BSDJOY_JOY) { 420 name = SDL_strdup("Gameport joystick"); 421 guid = SDL_CreateJoystickGUIDForName(name); 422 } else { 423#ifdef USB_GET_DEVICEINFO 424 struct usb_device_info di; 425 if (ioctl(hw->fd, USB_GET_DEVICEINFO, &di) != -1) { 426 name = SDL_CreateJoystickName(di.udi_vendorNo, di.udi_productNo, di.udi_vendor, di.udi_product); 427 guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, di.udi_vendor, di.udi_product, 0, 0); 428 429 if (SDL_ShouldIgnoreJoystick(di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name) || 430 SDL_JoystickHandledByAnotherDriver(&SDL_BSD_JoystickDriver, di.udi_vendorNo, di.udi_productNo, di.udi_releaseNo, name)) { 431 SDL_free(name); 432 FreeHwData(hw); 433 return false; 434 } 435 } 436#endif // USB_GET_DEVICEINFO 437 } 438 if (!name) { 439 name = SDL_strdup(path); 440 guid = SDL_CreateJoystickGUIDForName(name); 441 } 442 FreeHwData(hw); 443 444 item = (SDL_joylist_item *)SDL_calloc(1, sizeof(SDL_joylist_item)); 445 if (!item) { 446 SDL_free(name); 447 return false; 448 } 449 450 item->devnum = sb.st_rdev; 451 item->path = SDL_strdup(path); 452 item->name = name; 453 item->guid = guid; 454 455 if ((!item->path) || (!item->name)) { 456 FreeJoylistItem(item); 457 return false; 458 } 459 460 item->device_instance = SDL_GetNextObjectID(); 461 if (!SDL_joylist_tail) { 462 SDL_joylist = SDL_joylist_tail = item; 463 } else { 464 SDL_joylist_tail->next = item; 465 SDL_joylist_tail = item; 466 } 467 468 // Need to increment the joystick count before we post the event 469 ++numjoysticks; 470 471 SDL_PrivateJoystickAdded(item->device_instance); 472 473 return true; 474} 475 476static bool BSD_JoystickInit(void) 477{ 478 char s[16]; 479 int i; 480 481 for (i = 0; i < MAX_UHID_JOYS; i++) { 482#if defined(SDL_PLATFORM_OPENBSD) && (OpenBSD >= 202105) 483 SDL_snprintf(s, SDL_arraysize(s), "/dev/ujoy/%d", i); 484#else 485 SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i); 486#endif 487 MaybeAddDevice(s); 488 } 489#ifdef SUPPORT_JOY_GAMEPORT 490 for (i = 0; i < MAX_JOY_JOYS; i++) { 491 SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i); 492 MaybeAddDevice(s); 493 } 494#endif // SUPPORT_JOY_GAMEPORT 495 496 // Read the default USB HID usage table. 497 hid_init(NULL); 498 499 return true; 500} 501 502static int BSD_JoystickGetCount(void) 503{ 504 return numjoysticks; 505} 506 507static void BSD_JoystickDetect(void) 508{ 509} 510 511static bool BSD_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) 512{ 513 // We don't override any other drivers 514 return false; 515} 516 517static SDL_joylist_item *GetJoystickByDevIndex(int device_index) 518{ 519 SDL_joylist_item *item = SDL_joylist; 520 521 if ((device_index < 0) || (device_index >= numjoysticks)) { 522 return NULL; 523 } 524 525 while (device_index > 0) { 526 SDL_assert(item != NULL); 527 device_index--; 528 item = item->next; 529 } 530 531 return item; 532} 533 534static const char *BSD_JoystickGetDeviceName(int device_index) 535{ 536 return GetJoystickByDevIndex(device_index)->name; 537} 538 539static const char *BSD_JoystickGetDevicePath(int device_index) 540{ 541 return GetJoystickByDevIndex(device_index)->path; 542} 543 544static int BSD_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) 545{ 546 return -1; 547} 548 549static int BSD_JoystickGetDevicePlayerIndex(int device_index) 550{ 551 return -1; 552} 553 554static void BSD_JoystickSetDevicePlayerIndex(int device_index, int player_index) 555{ 556} 557 558static SDL_GUID BSD_JoystickGetDeviceGUID(int device_index) 559{ 560 return GetJoystickByDevIndex(device_index)->guid; 561} 562 563// Function to perform the mapping from device index to the instance id for this index 564static SDL_JoystickID BSD_JoystickGetDeviceInstanceID(int device_index) 565{ 566 return GetJoystickByDevIndex(device_index)->device_instance; 567} 568 569static unsigned hatval_to_sdl(Sint32 hatval) 570{ 571 static const unsigned hat_dir_map[8] = { 572 SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, 573 SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP 574 }; 575 unsigned result; 576 if ((hatval & 7) == hatval) 577 result = hat_dir_map[hatval]; 578 else 579 result = SDL_HAT_CENTERED; 580 return result; 581} 582 583static bool BSD_JoystickOpen(SDL_Joystick *joy, int device_index) 584{ 585 SDL_joylist_item *item = GetJoystickByDevIndex(device_index); 586 struct joystick_hwdata *hw; 587 588 if (!item) { 589 return SDL_SetError("No such device"); 590 } 591 592 hw = CreateHwData(item->path); 593 if (!hw) { 594 return false; 595 } 596 597 joy->hwdata = hw; 598 joy->naxes = hw->naxes; 599 joy->nbuttons = hw->nbuttons; 600 joy->nhats = hw->nhats; 601 602 return true; 603} 604 605static void BSD_JoystickUpdate(SDL_Joystick *joy) 606{ 607 struct hid_item hitem; 608 struct hid_data *hdata; 609 struct report *rep; 610 int nbutton, naxe = -1; 611 Sint32 v; 612#ifdef SDL_PLATFORM_OPENBSD 613 Sint32 dpad[4] = { 0, 0, 0, 0 }; 614#endif 615 Uint64 timestamp = SDL_GetTicksNS(); 616 617#ifdef SUPPORT_JOY_GAMEPORT 618 struct joystick gameport; 619 static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0; 620 621 if (joy->hwdata->type == BSDJOY_JOY) { 622 while (read(joy->hwdata->fd, &gameport, sizeof(gameport)) == sizeof(gameport)) { 623 if (SDL_abs(x - gameport.x) > 8) { 624 x = gameport.x; 625 if (x < xmin) { 626 xmin = x; 627 } 628 if (x > xmax) { 629 xmax = x; 630 } 631 if (xmin == xmax) { 632 xmin--; 633 xmax++; 634 } 635 v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * ((Sint32)x - xmin)) / (xmax - xmin)) + SDL_JOYSTICK_AXIS_MIN; 636 SDL_SendJoystickAxis(timestamp, joy, 0, v); 637 } 638 if (SDL_abs(y - gameport.y) > 8) { 639 y = gameport.y; 640 if (y < ymin) { 641 ymin = y; 642 } 643 if (y > ymax) { 644 ymax = y; 645 } 646 if (ymin == ymax) { 647 ymin--; 648 ymax++; 649 } 650 v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * ((Sint32)y - ymin)) / (ymax - ymin)) + SDL_JOYSTICK_AXIS_MIN; 651 SDL_SendJoystickAxis(timestamp, joy, 1, v); 652 } 653 SDL_SendJoystickButton(timestamp, joy, 0, (gameport.b1 != 0)); 654 SDL_SendJoystickButton(timestamp, joy, 1, (gameport.b2 != 0)); 655 } 656 return; 657 } 658#endif // SUPPORT_JOY_GAMEPORT 659 660 rep = &joy->hwdata->inreport; 661 662 while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) { 663#if defined(USBHID_NEW) || (defined(SDL_PLATFORM_FREEBSD) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) 664 hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); 665#else 666 hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); 667#endif 668 if (!hdata) { 669 // fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path); 670 continue; 671 } 672 673 while (hid_get_item(hdata, &hitem) > 0) { 674 switch (hitem.kind) { 675 case hid_input: 676 switch (HID_PAGE(hitem.usage)) { 677 case HUP_GENERIC_DESKTOP: 678 { 679 int usage = HID_USAGE(hitem.usage); 680 int joyaxe = usage_to_joyaxe(usage); 681 if (joyaxe >= 0) { 682 naxe = joy->hwdata->axis_map[joyaxe]; 683 // scaleaxe 684 v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 685 v = (((SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) * (v - hitem.logical_minimum)) / (hitem.logical_maximum - hitem.logical_minimum)) + SDL_JOYSTICK_AXIS_MIN; 686 SDL_SendJoystickAxis(timestamp, joy, naxe, v); 687 } else if (usage == HUG_HAT_SWITCH) { 688 v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 689 SDL_SendJoystickHat(timestamp, joy, 0, 690 hatval_to_sdl(v) - 691 hitem.logical_minimum); 692 } 693#ifdef SDL_PLATFORM_OPENBSD 694 /* here D-pad directions are reported like separate buttons. 695 * calculate the SDL hat value from the 4 separate values. 696 */ 697 switch (usage) { 698 case HUG_DPAD_UP: 699 dpad[0] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 700 break; 701 case HUG_DPAD_DOWN: 702 dpad[1] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 703 break; 704 case HUG_DPAD_RIGHT: 705 dpad[2] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 706 break; 707 case HUG_DPAD_LEFT: 708 dpad[3] = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 709 break; 710 //default: 711 // no-op 712 } 713 SDL_SendJoystickHat(timestamp, joy, 0, (dpad[0] * HAT_UP) | 714 (dpad[1] * HAT_DOWN) | 715 (dpad[2] * HAT_RIGHT) | 716 (dpad[3] * HAT_LEFT) ); 717#endif 718 break; 719 } 720 case HUP_BUTTON: 721 v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); 722 nbutton = HID_USAGE(hitem.usage) - 1; // SDL buttons are zero-based 723 SDL_SendJoystickButton(timestamp, joy, nbutton, (v != 0)); 724 break; 725 default: 726 continue; 727 } 728 break; 729 default: 730 break; 731 } 732 } 733 hid_end_parse(hdata); 734 } 735} 736 737// Function to close a joystick after use 738static void BSD_JoystickClose(SDL_Joystick *joy) 739{ 740 if (joy->hwdata) { 741 FreeHwData(joy->hwdata); 742 joy->hwdata = NULL; 743 } 744} 745 746static void BSD_JoystickQuit(void) 747{ 748 SDL_joylist_item *item = NULL; 749 SDL_joylist_item *next = NULL; 750 751 for (item = SDL_joylist; item; item = next) { 752 next = item->next; 753 FreeJoylistItem(item); 754 } 755 756 SDL_joylist = SDL_joylist_tail = NULL; 757 758 numjoysticks = 0; 759} 760 761static bool report_alloc(struct report *r, struct report_desc *rd, int repind) 762{ 763 int len; 764 765#ifdef __DragonFly__ 766 len = hid_report_size(rd, repinfo[repind].kind, r->rid); 767#elif defined(SDL_PLATFORM_FREEBSD) 768#if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__) 769#if (__FreeBSD_kernel_version <= 500111) 770 len = hid_report_size(rd, r->rid, repinfo[repind].kind); 771#else 772 len = hid_report_size(rd, repinfo[repind].kind, r->rid); 773#endif 774#else 775 len = hid_report_size(rd, repinfo[repind].kind, &r->rid); 776#endif 777#else 778#ifdef USBHID_NEW 779 len = hid_report_size(rd, repinfo[repind].kind, r->rid); 780#else 781 len = hid_report_size(rd, repinfo[repind].kind, &r->rid); 782#endif 783#endif 784 785 if (len < 0) { 786 return SDL_SetError("Negative HID report size"); 787 } 788 r->size = len; 789 790 if (r->size > 0) { 791#if defined(SDL_PLATFORM_FREEBSD) && (__FreeBSD_kernel_version > 900000) || defined(__DragonFly__) 792 r->buf = SDL_malloc(r->size); 793#else 794 r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) + 795 r->size); 796#endif 797 if (!r->buf) { 798 return false; 799 } 800 } else { 801 r->buf = NULL; 802 } 803 804 r->status = SREPORT_CLEAN; 805 return true; 806} 807 808static void report_free(struct report *r) 809{ 810 SDL_free(r->buf); 811 r->status = SREPORT_UNINIT; 812} 813 814static bool BSD_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) 815{ 816 return SDL_Unsupported(); 817} 818 819static bool BSD_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) 820{ 821 return SDL_Unsupported(); 822} 823 824static bool BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 825{ 826 return false; 827} 828 829static bool BSD_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) 830{ 831 return SDL_Unsupported(); 832} 833 834static bool BSD_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) 835{ 836 return SDL_Unsupported(); 837} 838 839static bool BSD_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) 840{ 841 return SDL_Unsupported(); 842} 843 844SDL_JoystickDriver SDL_BSD_JoystickDriver = { 845 BSD_JoystickInit, 846 BSD_JoystickGetCount, 847 BSD_JoystickDetect, 848 BSD_JoystickIsDevicePresent, 849 BSD_JoystickGetDeviceName, 850 BSD_JoystickGetDevicePath, 851 BSD_JoystickGetDeviceSteamVirtualGamepadSlot, 852 BSD_JoystickGetDevicePlayerIndex, 853 BSD_JoystickSetDevicePlayerIndex, 854 BSD_JoystickGetDeviceGUID, 855 BSD_JoystickGetDeviceInstanceID, 856 BSD_JoystickOpen, 857 BSD_JoystickRumble, 858 BSD_JoystickRumbleTriggers, 859 BSD_JoystickSetLED, 860 BSD_JoystickSendEffect, 861 BSD_JoystickSetSensorsEnabled, 862 BSD_JoystickUpdate, 863 BSD_JoystickClose, 864 BSD_JoystickQuit, 865 BSD_JoystickGetGamepadMapping 866}; 867 868#endif // SDL_JOYSTICK_USBHID 869[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.