src/joystick/bsd/SDL_sysjoystick.c
author Ryan C. Gordon
Sat, 19 Sep 2020 14:01:57 -0400
changeset 14040 fe260271ec7a
parent 13872 75c33f89d791
permissions -rw-r--r--
jack: Fixed memory leak on device close.
     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
   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
   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
   254 BSD_JoystickGetCount(void)
   255 {
   256     return numjoysticks;
   257 }
   258 
   259 static void
   260 BSD_JoystickDetect(void)
   261 {
   262 }
   263 
   264 static const char *
   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
   274 BSD_JoystickGetDevicePlayerIndex(int device_index)
   275 {
   276     return -1;
   277 }
   278 
   279 static void
   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
   286 BSD_JoystickGetDeviceInstanceID(int device_index)
   287 {
   288     return device_index;
   289 }
   290 
   291 static int
   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
   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
   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: */