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