src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 09 Aug 2018 16:03:50 -0700
changeset 12090 c3209fca27b2
parent 11811 5d94cb6b24d3
child 12105 997ec56425a8
permissions -rw-r--r--
Worked around bug with Sony PS Now PS3 controller where DirectInput polling will continue to return success after the controller is unplugged.
The code is now reliant on SDL_PrivateJoystickAdded() and SDL_PrivateJoystickRemoved() being called correctly when devices are added or removed on Windows
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 
    84 struct report
    85 {
    86 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
    87     void *buf; /* Buffer */
    88 #elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
    89     struct usb_gen_descriptor *buf; /* Buffer */
    90 #else
    91     struct usb_ctl_report *buf; /* Buffer */
    92 #endif
    93     size_t size;                /* Buffer size */
    94     int rid;                    /* Report ID */
    95     enum
    96     {
    97         SREPORT_UNINIT,
    98         SREPORT_CLEAN,
    99         SREPORT_DIRTY
   100     } status;
   101 };
   102 
   103 static struct
   104 {
   105     int uhid_report;
   106     hid_kind_t kind;
   107     const char *name;
   108 } const repinfo[] = {
   109     {UHID_INPUT_REPORT, hid_input, "input"},
   110     {UHID_OUTPUT_REPORT, hid_output, "output"},
   111     {UHID_FEATURE_REPORT, hid_feature, "feature"}
   112 };
   113 
   114 enum
   115 {
   116     REPORT_INPUT = 0,
   117     REPORT_OUTPUT = 1,
   118     REPORT_FEATURE = 2
   119 };
   120 
   121 enum
   122 {
   123     JOYAXE_X,
   124     JOYAXE_Y,
   125     JOYAXE_Z,
   126     JOYAXE_SLIDER,
   127     JOYAXE_WHEEL,
   128     JOYAXE_RX,
   129     JOYAXE_RY,
   130     JOYAXE_RZ,
   131     JOYAXE_count
   132 };
   133 
   134 struct joystick_hwdata
   135 {
   136     int fd;
   137     char *path;
   138     enum
   139     {
   140         BSDJOY_UHID,            /* uhid(4) */
   141         BSDJOY_JOY              /* joy(4) */
   142     } type;
   143     struct report_desc *repdesc;
   144     struct report inreport;
   145     int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
   146 };
   147 
   148 static char *joynames[MAX_JOYS];
   149 static char *joydevnames[MAX_JOYS];
   150 
   151 static int report_alloc(struct report *, struct report_desc *, int);
   152 static void report_free(struct report *);
   153 
   154 #if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
   155 #define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
   156 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
   157 #define REP_BUF_DATA(rep) ((rep)->buf)
   158 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
   159 #define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
   160 #else
   161 #define REP_BUF_DATA(rep) ((rep)->buf->data)
   162 #endif
   163 
   164 static int SDL_SYS_numjoysticks = 0;
   165 
   166 int
   167 SDL_SYS_JoystickInit(void)
   168 {
   169     char s[16];
   170     int i, fd;
   171 
   172     SDL_SYS_numjoysticks = 0;
   173 
   174     SDL_memset(joynames, 0, sizeof(joynames));
   175     SDL_memset(joydevnames, 0, sizeof(joydevnames));
   176 
   177     for (i = 0; i < MAX_UHID_JOYS; i++) {
   178         SDL_Joystick nj;
   179 
   180         SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
   181 
   182         joynames[SDL_SYS_numjoysticks] = SDL_strdup(s);
   183 
   184         if (SDL_SYS_JoystickOpen(&nj, SDL_SYS_numjoysticks) == 0) {
   185             SDL_SYS_JoystickClose(&nj);
   186             SDL_SYS_numjoysticks++;
   187         } else {
   188             SDL_free(joynames[SDL_SYS_numjoysticks]);
   189             joynames[SDL_SYS_numjoysticks] = NULL;
   190         }
   191     }
   192     for (i = 0; i < MAX_JOY_JOYS; i++) {
   193         SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
   194         fd = open(s, O_RDONLY);
   195         if (fd != -1) {
   196             joynames[SDL_SYS_numjoysticks++] = SDL_strdup(s);
   197             close(fd);
   198         }
   199     }
   200 
   201     /* Read the default USB HID usage table. */
   202     hid_init(NULL);
   203 
   204     return (SDL_SYS_numjoysticks);
   205 }
   206 
   207 int
   208 SDL_SYS_NumJoysticks(void)
   209 {
   210     return SDL_SYS_numjoysticks;
   211 }
   212 
   213 void
   214 SDL_SYS_JoystickDetect(void)
   215 {
   216 }
   217 
   218 const char *
   219 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   220 {
   221     if (joydevnames[device_index] != NULL) {
   222         return (joydevnames[device_index]);
   223     }
   224     return (joynames[device_index]);
   225 }
   226 
   227 /* Function to perform the mapping from device index to the instance id for this index */
   228 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   229 {
   230     return device_index;
   231 }
   232 
   233 static int
   234 usage_to_joyaxe(unsigned usage)
   235 {
   236     int joyaxe;
   237     switch (usage) {
   238     case HUG_X:
   239         joyaxe = JOYAXE_X;
   240         break;
   241     case HUG_Y:
   242         joyaxe = JOYAXE_Y;
   243         break;
   244     case HUG_Z:
   245         joyaxe = JOYAXE_Z;
   246         break;
   247     case HUG_SLIDER:
   248         joyaxe = JOYAXE_SLIDER;
   249         break;
   250     case HUG_WHEEL:
   251         joyaxe = JOYAXE_WHEEL;
   252         break;
   253     case HUG_RX:
   254         joyaxe = JOYAXE_RX;
   255         break;
   256     case HUG_RY:
   257         joyaxe = JOYAXE_RY;
   258         break;
   259     case HUG_RZ:
   260         joyaxe = JOYAXE_RZ;
   261         break;
   262     default:
   263         joyaxe = -1;
   264     }
   265     return joyaxe;
   266 }
   267 
   268 static unsigned
   269 hatval_to_sdl(Sint32 hatval)
   270 {
   271     static const unsigned hat_dir_map[8] = {
   272         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
   273         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
   274     };
   275     unsigned result;
   276     if ((hatval & 7) == hatval)
   277         result = hat_dir_map[hatval];
   278     else
   279         result = SDL_HAT_CENTERED;
   280     return result;
   281 }
   282 
   283 
   284 int
   285 SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
   286 {
   287     char *path = joynames[device_index];
   288     struct joystick_hwdata *hw;
   289     struct hid_item hitem;
   290     struct hid_data *hdata;
   291     struct report *rep = NULL;
   292     int fd;
   293     int i;
   294 
   295     fd = open(path, O_RDONLY);
   296     if (fd == -1) {
   297         return SDL_SetError("%s: %s", path, strerror(errno));
   298     }
   299 
   300     joy->instance_id = device_index;
   301     hw = (struct joystick_hwdata *)
   302         SDL_malloc(sizeof(struct joystick_hwdata));
   303     if (hw == NULL) {
   304         close(fd);
   305         return SDL_OutOfMemory();
   306     }
   307     joy->hwdata = hw;
   308     hw->fd = fd;
   309     hw->path = SDL_strdup(path);
   310     if (!SDL_strncmp(path, "/dev/joy", 8)) {
   311         hw->type = BSDJOY_JOY;
   312         joy->naxes = 2;
   313         joy->nbuttons = 2;
   314         joy->nhats = 0;
   315         joy->nballs = 0;
   316         joydevnames[device_index] = SDL_strdup("Gameport joystick");
   317         goto usbend;
   318     } else {
   319         hw->type = BSDJOY_UHID;
   320     }
   321 
   322     {
   323         int ax;
   324         for (ax = 0; ax < JOYAXE_count; ax++)
   325             hw->axis_map[ax] = -1;
   326     }
   327     hw->repdesc = hid_get_report_desc(fd);
   328     if (hw->repdesc == NULL) {
   329         SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   330                      strerror(errno));
   331         goto usberr;
   332     }
   333     rep = &hw->inreport;
   334 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
   335     rep->rid = hid_get_report_id(fd);
   336     if (rep->rid < 0) {
   337 #else
   338     if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
   339 #endif
   340         rep->rid = -1;          /* XXX */
   341     }
   342 #if defined(__NetBSD__)
   343     usb_device_descriptor_t udd;
   344     struct usb_string_desc usd;
   345     if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
   346         goto desc_failed;
   347 
   348     /* Get default language */
   349     usd.usd_string_index = USB_LANGUAGE_TABLE;
   350     usd.usd_language_id = 0;
   351     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
   352         usd.usd_language_id = 0;
   353     } else {
   354         usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
   355     }
   356 
   357     usd.usd_string_index = udd.iProduct;
   358     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
   359         char str[128];
   360         char *new_name = NULL;
   361         int i;
   362         for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
   363             str[i] = UGETW(usd.usd_desc.bString[i]);
   364         }
   365         str[i] = '\0';
   366         asprintf(&new_name, "%s @ %s", str, path);
   367         if (new_name != NULL) {
   368             SDL_free(joydevnames[SDL_SYS_numjoysticks]);
   369             joydevnames[SDL_SYS_numjoysticks] = new_name;
   370         }
   371     }
   372 desc_failed:
   373 #endif
   374     if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   375         goto usberr;
   376     }
   377     if (rep->size <= 0) {
   378         SDL_SetError("%s: Input report descriptor has invalid length",
   379                      hw->path);
   380         goto usberr;
   381     }
   382 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   383     hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
   384 #else
   385     hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   386 #endif
   387     if (hdata == NULL) {
   388         SDL_SetError("%s: Cannot start HID parser", hw->path);
   389         goto usberr;
   390     }
   391     joy->naxes = 0;
   392     joy->nbuttons = 0;
   393     joy->nhats = 0;
   394     joy->nballs = 0;
   395     for (i = 0; i < JOYAXE_count; i++)
   396         hw->axis_map[i] = -1;
   397 
   398     while (hid_get_item(hdata, &hitem) > 0) {
   399         char *sp;
   400         const char *s;
   401 
   402         switch (hitem.kind) {
   403         case hid_collection:
   404             switch (HID_PAGE(hitem.usage)) {
   405             case HUP_GENERIC_DESKTOP:
   406                 switch (HID_USAGE(hitem.usage)) {
   407                 case HUG_JOYSTICK:
   408                 case HUG_GAME_PAD:
   409                     s = hid_usage_in_page(hitem.usage);
   410                     sp = SDL_malloc(SDL_strlen(s) + 5);
   411                     SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
   412                                  s, device_index);
   413                     joydevnames[device_index] = sp;
   414                 }
   415             }
   416             break;
   417         case hid_input:
   418             switch (HID_PAGE(hitem.usage)) {
   419             case HUP_GENERIC_DESKTOP:
   420                 {
   421                     unsigned usage = HID_USAGE(hitem.usage);
   422                     int joyaxe = usage_to_joyaxe(usage);
   423                     if (joyaxe >= 0) {
   424                         hw->axis_map[joyaxe] = 1;
   425                     } else if (usage == HUG_HAT_SWITCH) {
   426                         joy->nhats++;
   427                     }
   428                     break;
   429                 }
   430             case HUP_BUTTON:
   431                 joy->nbuttons++;
   432                 break;
   433             default:
   434                 break;
   435             }
   436             break;
   437         default:
   438             break;
   439         }
   440     }
   441     hid_end_parse(hdata);
   442     for (i = 0; i < JOYAXE_count; i++)
   443         if (hw->axis_map[i] > 0)
   444             hw->axis_map[i] = joy->naxes++;
   445 
   446     if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
   447         SDL_SetError("%s: Not a joystick, ignoring", hw->path);
   448         goto usberr;
   449     }
   450 
   451   usbend:
   452     /* The poll blocks the event thread. */
   453     fcntl(fd, F_SETFL, O_NONBLOCK);
   454 #ifdef __NetBSD__
   455     /* Flush pending events */
   456     if (rep) {
   457         while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
   458             ;
   459     }
   460 #endif
   461 
   462     return (0);
   463   usberr:
   464     close(hw->fd);
   465     SDL_free(hw->path);
   466     SDL_free(hw);
   467     return (-1);
   468 }
   469 
   470 void
   471 SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
   472 {
   473     struct hid_item hitem;
   474     struct hid_data *hdata;
   475     struct report *rep;
   476     int nbutton, naxe = -1;
   477     Sint32 v;
   478 
   479 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   480     struct joystick gameport;
   481     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   482 
   483     if (joy->hwdata->type == BSDJOY_JOY) {
   484         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   485             if (abs(x - gameport.x) > 8) {
   486                 x = gameport.x;
   487                 if (x < xmin) {
   488                     xmin = x;
   489                 }
   490                 if (x > xmax) {
   491                     xmax = x;
   492                 }
   493                 if (xmin == xmax) {
   494                     xmin--;
   495                     xmax++;
   496                 }
   497                 v = (Sint32) x;
   498                 v -= (xmax + xmin + 1) / 2;
   499                 v *= 32768 / ((xmax - xmin + 1) / 2);
   500                 SDL_PrivateJoystickAxis(joy, 0, v);
   501             }
   502             if (abs(y - gameport.y) > 8) {
   503                 y = gameport.y;
   504                 if (y < ymin) {
   505                     ymin = y;
   506                 }
   507                 if (y > ymax) {
   508                     ymax = y;
   509                 }
   510                 if (ymin == ymax) {
   511                     ymin--;
   512                     ymax++;
   513                 }
   514                 v = (Sint32) y;
   515                 v -= (ymax + ymin + 1) / 2;
   516                 v *= 32768 / ((ymax - ymin + 1) / 2);
   517                 SDL_PrivateJoystickAxis(joy, 1, v);
   518             }
   519             SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   520             SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   521         }
   522         return;
   523     }
   524 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
   525 
   526     rep = &joy->hwdata->inreport;
   527 
   528     while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
   529 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   530         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
   531 #else
   532         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   533 #endif
   534         if (hdata == NULL) {
   535             /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
   536             continue;
   537         }
   538 
   539         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
   540             switch (hitem.kind) {
   541             case hid_input:
   542                 switch (HID_PAGE(hitem.usage)) {
   543                 case HUP_GENERIC_DESKTOP:
   544                     {
   545                         unsigned usage = HID_USAGE(hitem.usage);
   546                         int joyaxe = usage_to_joyaxe(usage);
   547                         if (joyaxe >= 0) {
   548                             naxe = joy->hwdata->axis_map[joyaxe];
   549                             /* scaleaxe */
   550                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   551                             v -= (hitem.logical_maximum +
   552                                   hitem.logical_minimum + 1) / 2;
   553                             v *= 32768 /
   554                                 ((hitem.logical_maximum -
   555                                   hitem.logical_minimum + 1) / 2);
   556                             SDL_PrivateJoystickAxis(joy, naxe, v);
   557                         } else if (usage == HUG_HAT_SWITCH) {
   558                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   559                             SDL_PrivateJoystickHat(joy, 0,
   560                                                    hatval_to_sdl(v) -
   561                                                    hitem.logical_minimum);
   562                         }
   563                         break;
   564                     }
   565                 case HUP_BUTTON:
   566                     v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   567                     SDL_PrivateJoystickButton(joy, nbutton, v);
   568                     nbutton++;
   569                     break;
   570                 default:
   571                     continue;
   572                 }
   573                 break;
   574             default:
   575                 break;
   576             }
   577         }
   578         hid_end_parse(hdata);
   579     }
   580 }
   581 
   582 /* Function to close a joystick after use */
   583 void
   584 SDL_SYS_JoystickClose(SDL_Joystick * joy)
   585 {
   586     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   587         report_free(&joy->hwdata->inreport);
   588         hid_dispose_report_desc(joy->hwdata->repdesc);
   589     }
   590     close(joy->hwdata->fd);
   591     SDL_free(joy->hwdata->path);
   592     SDL_free(joy->hwdata);
   593 }
   594 
   595 void
   596 SDL_SYS_JoystickQuit(void)
   597 {
   598     int i;
   599 
   600     for (i = 0; i < MAX_JOYS; i++) {
   601         SDL_free(joynames[i]);
   602         SDL_free(joydevnames[i]);
   603     }
   604 
   605     return;
   606 }
   607 
   608 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   609 {
   610     SDL_JoystickGUID guid;
   611     /* the GUID is just the first 16 chars of the name for now */
   612     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   613     SDL_zero( guid );
   614     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   615     return guid;
   616 }
   617 
   618 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   619 {
   620     SDL_JoystickGUID guid;
   621     /* the GUID is just the first 16 chars of the name for now */
   622     const char *name = joystick->name;
   623     SDL_zero( guid );
   624     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   625     return guid;
   626 }
   627 
   628 static int
   629 report_alloc(struct report *r, struct report_desc *rd, int repind)
   630 {
   631     int len;
   632 
   633 #ifdef __DragonFly__
   634     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   635 #elif __FREEBSD__
   636 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   637 #  if (__FreeBSD_kernel_version <= 500111)
   638     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   639 #  else
   640     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   641 #  endif
   642 # else
   643     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   644 # endif
   645 #else
   646 # ifdef USBHID_NEW
   647     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   648 # else
   649     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   650 # endif
   651 #endif
   652 
   653     if (len < 0) {
   654         return SDL_SetError("Negative HID report size");
   655     }
   656     r->size = len;
   657 
   658     if (r->size > 0) {
   659 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   660         r->buf = SDL_malloc(r->size);
   661 #else
   662         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   663                             r->size);
   664 #endif
   665         if (r->buf == NULL) {
   666             return SDL_OutOfMemory();
   667         }
   668     } else {
   669         r->buf = NULL;
   670     }
   671 
   672     r->status = SREPORT_CLEAN;
   673     return 0;
   674 }
   675 
   676 static void
   677 report_free(struct report *r)
   678 {
   679     SDL_free(r->buf);
   680     r->status = SREPORT_UNINIT;
   681 }
   682 
   683 #endif /* SDL_JOYSTICK_USBHID */
   684 
   685 /* vi: set ts=4 sw=4 expandtab: */