1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 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) interface found in OpenBSD,
27 * NetBSD and FreeBSD.
28 *
29 * Maintainer: <vedge at csoft.org>
30 */
31
32 #include <sys/param.h>
33
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <errno.h>
37
38 #ifndef __FreeBSD_kernel_version
39 #define __FreeBSD_kernel_version __FreeBSD_version
40 #endif
41
42 #if defined(HAVE_USB_H)
43 #include <usb.h>
44 #endif
45 #ifdef __DragonFly__
46 #include <bus/usb/usb.h>
47 #include <bus/usb/usbhid.h>
48 #else
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbhid.h>
51 #endif
52
53 #if defined(HAVE_USBHID_H)
54 #include <usbhid.h>
55 #elif defined(HAVE_LIBUSB_H)
56 #include <libusb.h>
57 #elif defined(HAVE_LIBUSBHID_H)
58 #include <libusbhid.h>
59 #endif
60
61 #if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
62 #ifndef __DragonFly__
63 #include <osreldate.h>
64 #endif
65 #if __FreeBSD_kernel_version > 800063
66 #include <dev/usb/usb_ioctl.h>
67 #endif
68 #include <sys/joystick.h>
69 #endif
70
71 #if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
72 #include <machine/joystick.h>
73 #endif
74
75 #include "SDL_joystick.h"
76 #include "../SDL_sysjoystick.h"
77 #include "../SDL_joystick_c.h"
78
79 #define MAX_UHID_JOYS 64
80 #define MAX_JOY_JOYS 2
81 #define MAX_JOYS (MAX_UHID_JOYS + MAX_JOY_JOYS)
82
83 #ifdef __OpenBSD__
84
85 #define HUG_DPAD_UP 0x90
86 #define HUG_DPAD_DOWN 0x91
87 #define HUG_DPAD_RIGHT 0x92
88 #define HUG_DPAD_LEFT 0x93
89
90 #define HAT_CENTERED 0x00
91 #define HAT_UP 0x01
92 #define HAT_RIGHT 0x02
93 #define HAT_DOWN 0x04
94 #define HAT_LEFT 0x08
95 #define HAT_RIGHTUP (HAT_RIGHT|HAT_UP)
96 #define HAT_RIGHTDOWN (HAT_RIGHT|HAT_DOWN)
97 #define HAT_LEFTUP (HAT_LEFT|HAT_UP)
98 #define HAT_LEFTDOWN (HAT_LEFT|HAT_DOWN)
99
100 /* calculate the value from the state of the dpad */
101 int
dpad_to_sdl(Sint32 * dpad)102 dpad_to_sdl(Sint32 *dpad)
103 {
104 if (dpad[2]) {
105 if (dpad[0])
106 return HAT_RIGHTUP;
107 else if (dpad[1])
108 return HAT_RIGHTDOWN;
109 else
110 return HAT_RIGHT;
111 } else if (dpad[3]) {
112 if (dpad[0])
113 return HAT_LEFTUP;
114 else if (dpad[1])
115 return HAT_LEFTDOWN;
116 else
117 return HAT_LEFT;
118 } else if (dpad[0]) {
119 return HAT_UP;
120 } else if (dpad[1]) {
121 return HAT_DOWN;
122 }
123 return HAT_CENTERED;
124 }
125 #endif
126
127 struct report
128 {
129 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
130 void *buf; /* Buffer */
131 #elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
132 struct usb_gen_descriptor *buf; /* Buffer */
133 #else
134 struct usb_ctl_report *buf; /* Buffer */
135 #endif
136 size_t size; /* Buffer size */
137 int rid; /* Report ID */
138 enum
139 {
140 SREPORT_UNINIT,
141 SREPORT_CLEAN,
142 SREPORT_DIRTY
143 } status;
144 };
145
146 static struct
147 {
148 int uhid_report;
149 hid_kind_t kind;
150 const char *name;
151 } const repinfo[] = {
152 {UHID_INPUT_REPORT, hid_input, "input"},
153 {UHID_OUTPUT_REPORT, hid_output, "output"},
154 {UHID_FEATURE_REPORT, hid_feature, "feature"}
155 };
156
157 enum
158 {
159 REPORT_INPUT = 0,
160 REPORT_OUTPUT = 1,
161 REPORT_FEATURE = 2
162 };
163
164 enum
165 {
166 JOYAXE_X,
167 JOYAXE_Y,
168 JOYAXE_Z,
169 JOYAXE_SLIDER,
170 JOYAXE_WHEEL,
171 JOYAXE_RX,
172 JOYAXE_RY,
173 JOYAXE_RZ,
174 JOYAXE_count
175 };
176
177 struct joystick_hwdata
178 {
179 int fd;
180 char *path;
181 enum
182 {
183 BSDJOY_UHID, /* uhid(4) */
184 BSDJOY_JOY /* joy(4) */
185 } type;
186 struct report_desc *repdesc;
187 struct report inreport;
188 int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
189 };
190
191 static char *joynames[MAX_JOYS];
192 static char *joydevnames[MAX_JOYS];
193
194 static int report_alloc(struct report *, struct report_desc *, int);
195 static void report_free(struct report *);
196
197 #if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
198 #define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
199 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
200 #define REP_BUF_DATA(rep) ((rep)->buf)
201 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
202 #define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
203 #else
204 #define REP_BUF_DATA(rep) ((rep)->buf->data)
205 #endif
206
207 static int numjoysticks = 0;
208
209 static int BSD_JoystickOpen(SDL_Joystick * joy, int device_index);
210 static void BSD_JoystickClose(SDL_Joystick * joy);
211
212 static int
BSD_JoystickInit(void)213 BSD_JoystickInit(void)
214 {
215 char s[16];
216 int i, fd;
217
218 numjoysticks = 0;
219
220 SDL_memset(joynames, 0, sizeof(joynames));
221 SDL_memset(joydevnames, 0, sizeof(joydevnames));
222
223 for (i = 0; i < MAX_UHID_JOYS; i++) {
224 SDL_Joystick nj;
225
226 SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
227
228 joynames[numjoysticks] = SDL_strdup(s);
229
230 if (BSD_JoystickOpen(&nj, numjoysticks) == 0) {
231 BSD_JoystickClose(&nj);
232 numjoysticks++;
233 } else {
234 SDL_free(joynames[numjoysticks]);
235 joynames[numjoysticks] = NULL;
236 }
237 }
238 for (i = 0; i < MAX_JOY_JOYS; i++) {
239 SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
240 fd = open(s, O_RDONLY);
241 if (fd != -1) {
242 joynames[numjoysticks++] = SDL_strdup(s);
243 close(fd);
244 }
245 }
246
247 /* Read the default USB HID usage table. */
248 hid_init(NULL);
249
250 return (numjoysticks);
251 }
252
253 static int
BSD_JoystickGetCount(void)254 BSD_JoystickGetCount(void)
255 {
256 return numjoysticks;
257 }
258
259 static void
BSD_JoystickDetect(void)260 BSD_JoystickDetect(void)
261 {
262 }
263
264 static const char *
BSD_JoystickGetDeviceName(int device_index)265 BSD_JoystickGetDeviceName(int device_index)
266 {
267 if (joydevnames[device_index] != NULL) {
268 return (joydevnames[device_index]);
269 }
270 return (joynames[device_index]);
271 }
272
273 static int
BSD_JoystickGetDevicePlayerIndex(int device_index)274 BSD_JoystickGetDevicePlayerIndex(int device_index)
275 {
276 return -1;
277 }
278
279 static void
BSD_JoystickSetDevicePlayerIndex(int device_index,int player_index)280 BSD_JoystickSetDevicePlayerIndex(int device_index, int player_index)
281 {
282 }
283
284 /* Function to perform the mapping from device index to the instance id for this index */
285 static SDL_JoystickID
BSD_JoystickGetDeviceInstanceID(int device_index)286 BSD_JoystickGetDeviceInstanceID(int device_index)
287 {
288 return device_index;
289 }
290
291 static int
usage_to_joyaxe(unsigned usage)292 usage_to_joyaxe(unsigned usage)
293 {
294 int joyaxe;
295 switch (usage) {
296 case HUG_X:
297 joyaxe = JOYAXE_X;
298 break;
299 case HUG_Y:
300 joyaxe = JOYAXE_Y;
301 break;
302 case HUG_Z:
303 joyaxe = JOYAXE_Z;
304 break;
305 case HUG_SLIDER:
306 joyaxe = JOYAXE_SLIDER;
307 break;
308 case HUG_WHEEL:
309 joyaxe = JOYAXE_WHEEL;
310 break;
311 case HUG_RX:
312 joyaxe = JOYAXE_RX;
313 break;
314 case HUG_RY:
315 joyaxe = JOYAXE_RY;
316 break;
317 case HUG_RZ:
318 joyaxe = JOYAXE_RZ;
319 break;
320 default:
321 joyaxe = -1;
322 }
323 return joyaxe;
324 }
325
326 static unsigned
hatval_to_sdl(Sint32 hatval)327 hatval_to_sdl(Sint32 hatval)
328 {
329 static const unsigned hat_dir_map[8] = {
330 SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
331 SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
332 };
333 unsigned result;
334 if ((hatval & 7) == hatval)
335 result = hat_dir_map[hatval];
336 else
337 result = SDL_HAT_CENTERED;
338 return result;
339 }
340
341
342 static int
BSD_JoystickOpen(SDL_Joystick * joy,int device_index)343 BSD_JoystickOpen(SDL_Joystick * joy, int device_index)
344 {
345 char *path = joynames[device_index];
346 struct joystick_hwdata *hw;
347 struct hid_item hitem;
348 struct hid_data *hdata;
349 struct report *rep = NULL;
350 #if defined(__NetBSD__)
351 usb_device_descriptor_t udd;
352 struct usb_string_desc usd;
353 #endif
354 int fd;
355 int i;
356
357 fd = open(path, O_RDONLY);
358 if (fd == -1) {
359 return SDL_SetError("%s: %s", path, strerror(errno));
360 }
361
362 joy->instance_id = device_index;
363 hw = (struct joystick_hwdata *)
364 SDL_malloc(sizeof(struct joystick_hwdata));
365 if (hw == NULL) {
366 close(fd);
367 return SDL_OutOfMemory();
368 }
369 joy->hwdata = hw;
370 hw->fd = fd;
371 hw->path = SDL_strdup(path);
372 if (!SDL_strncmp(path, "/dev/joy", 8)) {
373 hw->type = BSDJOY_JOY;
374 joy->naxes = 2;
375 joy->nbuttons = 2;
376 joy->nhats = 0;
377 joy->nballs = 0;
378 joydevnames[device_index] = SDL_strdup("Gameport joystick");
379 goto usbend;
380 } else {
381 hw->type = BSDJOY_UHID;
382 }
383
384 {
385 int ax;
386 for (ax = 0; ax < JOYAXE_count; ax++)
387 hw->axis_map[ax] = -1;
388 }
389 hw->repdesc = hid_get_report_desc(fd);
390 if (hw->repdesc == NULL) {
391 SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
392 strerror(errno));
393 goto usberr;
394 }
395 rep = &hw->inreport;
396 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
397 rep->rid = hid_get_report_id(fd);
398 if (rep->rid < 0) {
399 #else
400 if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
401 #endif
402 rep->rid = -1; /* XXX */
403 }
404 #if defined(__NetBSD__)
405 if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
406 goto desc_failed;
407
408 /* Get default language */
409 usd.usd_string_index = USB_LANGUAGE_TABLE;
410 usd.usd_language_id = 0;
411 if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
412 usd.usd_language_id = 0;
413 } else {
414 usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
415 }
416
417 usd.usd_string_index = udd.iProduct;
418 if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
419 char str[128];
420 char *new_name = NULL;
421 int i;
422 for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
423 str[i] = UGETW(usd.usd_desc.bString[i]);
424 }
425 str[i] = '\0';
426 asprintf(&new_name, "%s @ %s", str, path);
427 if (new_name != NULL) {
428 SDL_free(joydevnames[numjoysticks]);
429 joydevnames[numjoysticks] = new_name;
430 }
431 }
432 desc_failed:
433 #endif
434 if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
435 goto usberr;
436 }
437 if (rep->size <= 0) {
438 SDL_SetError("%s: Input report descriptor has invalid length",
439 hw->path);
440 goto usberr;
441 }
442 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
443 hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
444 #else
445 hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
446 #endif
447 if (hdata == NULL) {
448 SDL_SetError("%s: Cannot start HID parser", hw->path);
449 goto usberr;
450 }
451 joy->naxes = 0;
452 joy->nbuttons = 0;
453 joy->nhats = 0;
454 joy->nballs = 0;
455 for (i = 0; i < JOYAXE_count; i++)
456 hw->axis_map[i] = -1;
457
458 while (hid_get_item(hdata, &hitem) > 0) {
459 char *sp;
460 const char *s;
461
462 switch (hitem.kind) {
463 case hid_collection:
464 switch (HID_PAGE(hitem.usage)) {
465 case HUP_GENERIC_DESKTOP:
466 switch (HID_USAGE(hitem.usage)) {
467 case HUG_JOYSTICK:
468 case HUG_GAME_PAD:
469 s = hid_usage_in_page(hitem.usage);
470 sp = SDL_malloc(SDL_strlen(s) + 5);
471 SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
472 s, device_index);
473 joydevnames[device_index] = sp;
474 }
475 }
476 break;
477 case hid_input:
478 switch (HID_PAGE(hitem.usage)) {
479 case HUP_GENERIC_DESKTOP:
480 {
481 unsigned usage = HID_USAGE(hitem.usage);
482 int joyaxe = usage_to_joyaxe(usage);
483 if (joyaxe >= 0) {
484 hw->axis_map[joyaxe] = 1;
485 } else if (usage == HUG_HAT_SWITCH
486 #ifdef __OpenBSD__
487 || usage == HUG_DPAD_UP
488 #endif
489 ) {
490 joy->nhats++;
491 }
492 break;
493 }
494 case HUP_BUTTON:
495 joy->nbuttons++;
496 break;
497 default:
498 break;
499 }
500 break;
501 default:
502 break;
503 }
504 }
505 hid_end_parse(hdata);
506 for (i = 0; i < JOYAXE_count; i++)
507 if (hw->axis_map[i] > 0)
508 hw->axis_map[i] = joy->naxes++;
509
510 if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
511 SDL_SetError("%s: Not a joystick, ignoring", hw->path);
512 goto usberr;
513 }
514
515 usbend:
516 /* The poll blocks the event thread. */
517 fcntl(fd, F_SETFL, O_NONBLOCK);
518 #ifdef __NetBSD__
519 /* Flush pending events */
520 if (rep) {
521 while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
522 ;
523 }
524 #endif
525
526 return (0);
527 usberr:
528 close(hw->fd);
529 SDL_free(hw->path);
530 SDL_free(hw);
531 return (-1);
532 }
533
534 static void
535 BSD_JoystickUpdate(SDL_Joystick * joy)
536 {
537 struct hid_item hitem;
538 struct hid_data *hdata;
539 struct report *rep;
540 int nbutton, naxe = -1;
541 Sint32 v;
542 #ifdef __OpenBSD__
543 Sint32 dpad[4] = {0, 0, 0, 0};
544 #endif
545
546 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
547 struct joystick gameport;
548 static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
549
550 if (joy->hwdata->type == BSDJOY_JOY) {
551 while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
552 if (abs(x - gameport.x) > 8) {
553 x = gameport.x;
554 if (x < xmin) {
555 xmin = x;
556 }
557 if (x > xmax) {
558 xmax = x;
559 }
560 if (xmin == xmax) {
561 xmin--;
562 xmax++;
563 }
564 v = (Sint32) x;
565 v -= (xmax + xmin + 1) / 2;
566 v *= 32768 / ((xmax - xmin + 1) / 2);
567 SDL_PrivateJoystickAxis(joy, 0, v);
568 }
569 if (abs(y - gameport.y) > 8) {
570 y = gameport.y;
571 if (y < ymin) {
572 ymin = y;
573 }
574 if (y > ymax) {
575 ymax = y;
576 }
577 if (ymin == ymax) {
578 ymin--;
579 ymax++;
580 }
581 v = (Sint32) y;
582 v -= (ymax + ymin + 1) / 2;
583 v *= 32768 / ((ymax - ymin + 1) / 2);
584 SDL_PrivateJoystickAxis(joy, 1, v);
585 }
586 SDL_PrivateJoystickButton(joy, 0, gameport.b1);
587 SDL_PrivateJoystickButton(joy, 1, gameport.b2);
588 }
589 return;
590 }
591 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
592
593 rep = &joy->hwdata->inreport;
594
595 while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
596 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
597 hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
598 #else
599 hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
600 #endif
601 if (hdata == NULL) {
602 /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
603 continue;
604 }
605
606 for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
607 switch (hitem.kind) {
608 case hid_input:
609 switch (HID_PAGE(hitem.usage)) {
610 case HUP_GENERIC_DESKTOP:
611 {
612 unsigned usage = HID_USAGE(hitem.usage);
613 int joyaxe = usage_to_joyaxe(usage);
614 if (joyaxe >= 0) {
615 naxe = joy->hwdata->axis_map[joyaxe];
616 /* scaleaxe */
617 v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
618 v -= (hitem.logical_maximum +
619 hitem.logical_minimum + 1) / 2;
620 v *= 32768 /
621 ((hitem.logical_maximum -
622 hitem.logical_minimum + 1) / 2);
623 SDL_PrivateJoystickAxis(joy, naxe, v);
624 } else if (usage == HUG_HAT_SWITCH) {
625 v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
626 SDL_PrivateJoystickHat(joy, 0,
627 hatval_to_sdl(v) -
628 hitem.logical_minimum);
629 }
630 #ifdef __OpenBSD__
631 else if (usage == HUG_DPAD_UP) {
632 dpad[0] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
633 SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
634 }
635 else if (usage == HUG_DPAD_DOWN) {
636 dpad[1] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
637 SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
638 }
639 else if (usage == HUG_DPAD_RIGHT) {
640 dpad[2] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
641 SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
642 }
643 else if (usage == HUG_DPAD_LEFT) {
644 dpad[3] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
645 SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
646 }
647 #endif
648 break;
649 }
650 case HUP_BUTTON:
651 v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
652 SDL_PrivateJoystickButton(joy, nbutton, v);
653 nbutton++;
654 break;
655 default:
656 continue;
657 }
658 break;
659 default:
660 break;
661 }
662 }
663 hid_end_parse(hdata);
664 }
665 }
666
667 /* Function to close a joystick after use */
668 static void
669 BSD_JoystickClose(SDL_Joystick * joy)
670 {
671 if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
672 report_free(&joy->hwdata->inreport);
673 hid_dispose_report_desc(joy->hwdata->repdesc);
674 }
675 close(joy->hwdata->fd);
676 SDL_free(joy->hwdata->path);
677 SDL_free(joy->hwdata);
678 }
679
680 static void
681 BSD_JoystickQuit(void)
682 {
683 int i;
684
685 for (i = 0; i < MAX_JOYS; i++) {
686 SDL_free(joynames[i]);
687 SDL_free(joydevnames[i]);
688 }
689
690 return;
691 }
692
693 static SDL_JoystickGUID
694 BSD_JoystickGetDeviceGUID( int device_index )
695 {
696 SDL_JoystickGUID guid;
697 /* the GUID is just the first 16 chars of the name for now */
698 const char *name = BSD_JoystickGetDeviceName( device_index );
699 SDL_zero( guid );
700 SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
701 return guid;
702 }
703
704 static int
705 report_alloc(struct report *r, struct report_desc *rd, int repind)
706 {
707 int len;
708
709 #ifdef __DragonFly__
710 len = hid_report_size(rd, r->rid, repinfo[repind].kind);
711 #elif __FREEBSD__
712 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
713 # if (__FreeBSD_kernel_version <= 500111)
714 len = hid_report_size(rd, r->rid, repinfo[repind].kind);
715 # else
716 len = hid_report_size(rd, repinfo[repind].kind, r->rid);
717 # endif
718 # else
719 len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
720 # endif
721 #else
722 # ifdef USBHID_NEW
723 len = hid_report_size(rd, repinfo[repind].kind, r->rid);
724 # else
725 len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
726 # endif
727 #endif
728
729 if (len < 0) {
730 return SDL_SetError("Negative HID report size");
731 }
732 r->size = len;
733
734 if (r->size > 0) {
735 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
736 r->buf = SDL_malloc(r->size);
737 #else
738 r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
739 r->size);
740 #endif
741 if (r->buf == NULL) {
742 return SDL_OutOfMemory();
743 }
744 } else {
745 r->buf = NULL;
746 }
747
748 r->status = SREPORT_CLEAN;
749 return 0;
750 }
751
752 static void
753 report_free(struct report *r)
754 {
755 SDL_free(r->buf);
756 r->status = SREPORT_UNINIT;
757 }
758
759 static int
760 BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
761 {
762 return SDL_Unsupported();
763 }
764
765 static SDL_bool
766 BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
767 {
768 return SDL_FALSE;
769 }
770
771 SDL_JoystickDriver SDL_BSD_JoystickDriver =
772 {
773 BSD_JoystickInit,
774 BSD_JoystickGetCount,
775 BSD_JoystickDetect,
776 BSD_JoystickGetDeviceName,
777 BSD_JoystickGetDevicePlayerIndex,
778 BSD_JoystickSetDevicePlayerIndex,
779 BSD_JoystickGetDeviceGUID,
780 BSD_JoystickGetDeviceInstanceID,
781 BSD_JoystickOpen,
782 BSD_JoystickRumble,
783 BSD_JoystickUpdate,
784 BSD_JoystickClose,
785 BSD_JoystickQuit,
786 BSD_JoystickGetGamepadMapping
787 };
788
789 #endif /* SDL_JOYSTICK_USBHID */
790
791 /* vi: set ts=4 sw=4 expandtab: */
792