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