src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 22 Dec 2016 18:43:00 -0700
changeset 10714 a9c15922ad7b
parent 10617 346c02ff71b6
child 10737 3406a0f8b041
permissions -rw-r--r--
Fixed compile errors on various platforms
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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 /* Function to determine if this joystick is attached to the system right now */
   471 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   472 {
   473     return SDL_TRUE;
   474 }
   475 
   476 void
   477 SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
   478 {
   479     struct hid_item hitem;
   480     struct hid_data *hdata;
   481     struct report *rep;
   482     int nbutton, naxe = -1;
   483     Sint32 v;
   484 
   485 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   486     struct joystick gameport;
   487     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   488 
   489     if (joy->hwdata->type == BSDJOY_JOY) {
   490         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   491             if (abs(x - gameport.x) > 8) {
   492                 x = gameport.x;
   493                 if (x < xmin) {
   494                     xmin = x;
   495                 }
   496                 if (x > xmax) {
   497                     xmax = x;
   498                 }
   499                 if (xmin == xmax) {
   500                     xmin--;
   501                     xmax++;
   502                 }
   503                 v = (Sint32) x;
   504                 v -= (xmax + xmin + 1) / 2;
   505                 v *= 32768 / ((xmax - xmin + 1) / 2);
   506                 SDL_PrivateJoystickAxis(joy, 0, v);
   507             }
   508             if (abs(y - gameport.y) > 8) {
   509                 y = gameport.y;
   510                 if (y < ymin) {
   511                     ymin = y;
   512                 }
   513                 if (y > ymax) {
   514                     ymax = y;
   515                 }
   516                 if (ymin == ymax) {
   517                     ymin--;
   518                     ymax++;
   519                 }
   520                 v = (Sint32) y;
   521                 v -= (ymax + ymin + 1) / 2;
   522                 v *= 32768 / ((ymax - ymin + 1) / 2);
   523                 SDL_PrivateJoystickAxis(joy, 1, v);
   524             }
   525             if (gameport.b1 != joy->buttons[0]) {
   526                 SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   527             }
   528             if (gameport.b2 != joy->buttons[1]) {
   529                 SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   530             }
   531         }
   532         return;
   533     }
   534 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
   535 
   536     rep = &joy->hwdata->inreport;
   537 
   538     while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
   539 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   540         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
   541 #else
   542         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   543 #endif
   544         if (hdata == NULL) {
   545             /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
   546             continue;
   547         }
   548 
   549         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
   550             switch (hitem.kind) {
   551             case hid_input:
   552                 switch (HID_PAGE(hitem.usage)) {
   553                 case HUP_GENERIC_DESKTOP:
   554                     {
   555                         unsigned usage = HID_USAGE(hitem.usage);
   556                         int joyaxe = usage_to_joyaxe(usage);
   557                         if (joyaxe >= 0) {
   558                             naxe = joy->hwdata->axis_map[joyaxe];
   559                             /* scaleaxe */
   560                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   561                             v -= (hitem.logical_maximum +
   562                                   hitem.logical_minimum + 1) / 2;
   563                             v *= 32768 /
   564                                 ((hitem.logical_maximum -
   565                                   hitem.logical_minimum + 1) / 2);
   566                             if (v != joy->axes[naxe].value) {
   567                                 SDL_PrivateJoystickAxis(joy, naxe, v);
   568                             }
   569                         } else if (usage == HUG_HAT_SWITCH) {
   570                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   571                             SDL_PrivateJoystickHat(joy, 0,
   572                                                    hatval_to_sdl(v) -
   573                                                    hitem.logical_minimum);
   574                         }
   575                         break;
   576                     }
   577                 case HUP_BUTTON:
   578                     v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   579                     if (joy->buttons[nbutton] != v) {
   580                         SDL_PrivateJoystickButton(joy, nbutton, v);
   581                     }
   582                     nbutton++;
   583                     break;
   584                 default:
   585                     continue;
   586                 }
   587                 break;
   588             default:
   589                 break;
   590             }
   591         }
   592         hid_end_parse(hdata);
   593     }
   594 }
   595 
   596 /* Function to close a joystick after use */
   597 void
   598 SDL_SYS_JoystickClose(SDL_Joystick * joy)
   599 {
   600     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   601         report_free(&joy->hwdata->inreport);
   602         hid_dispose_report_desc(joy->hwdata->repdesc);
   603     }
   604     close(joy->hwdata->fd);
   605     SDL_free(joy->hwdata->path);
   606     SDL_free(joy->hwdata);
   607 }
   608 
   609 void
   610 SDL_SYS_JoystickQuit(void)
   611 {
   612     int i;
   613 
   614     for (i = 0; i < MAX_JOYS; i++) {
   615         SDL_free(joynames[i]);
   616         SDL_free(joydevnames[i]);
   617     }
   618 
   619     return;
   620 }
   621 
   622 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   623 {
   624     SDL_JoystickGUID guid;
   625     /* the GUID is just the first 16 chars of the name for now */
   626     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   627     SDL_zero( guid );
   628     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   629     return guid;
   630 }
   631 
   632 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   633 {
   634     SDL_JoystickGUID guid;
   635     /* the GUID is just the first 16 chars of the name for now */
   636     const char *name = joystick->name;
   637     SDL_zero( guid );
   638     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   639     return guid;
   640 }
   641 
   642 static int
   643 report_alloc(struct report *r, struct report_desc *rd, int repind)
   644 {
   645     int len;
   646 
   647 #ifdef __DragonFly__
   648     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   649 #elif __FREEBSD__
   650 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   651 #  if (__FreeBSD_kernel_version <= 500111)
   652     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   653 #  else
   654     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   655 #  endif
   656 # else
   657     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   658 # endif
   659 #else
   660 # ifdef USBHID_NEW
   661     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   662 # else
   663     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   664 # endif
   665 #endif
   666 
   667     if (len < 0) {
   668         return SDL_SetError("Negative HID report size");
   669     }
   670     r->size = len;
   671 
   672     if (r->size > 0) {
   673 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   674         r->buf = SDL_malloc(r->size);
   675 #else
   676         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   677                             r->size);
   678 #endif
   679         if (r->buf == NULL) {
   680             return SDL_OutOfMemory();
   681         }
   682     } else {
   683         r->buf = NULL;
   684     }
   685 
   686     r->status = SREPORT_CLEAN;
   687     return 0;
   688 }
   689 
   690 static void
   691 report_free(struct report *r)
   692 {
   693     SDL_free(r->buf);
   694     r->status = SREPORT_UNINIT;
   695 }
   696 
   697 #endif /* SDL_JOYSTICK_USBHID */
   698 
   699 /* vi: set ts=4 sw=4 expandtab: */