summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c')
-rw-r--r--contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c868
1 files changed, 868 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c b/contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c
new file mode 100644
index 0000000..b3fd3e9
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/joystick/bsd/SDL_bsdjoystick.c
@@ -0,0 +1,868 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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_PrivateJoystickHat(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