src/joystick/bsd/SDL_sysjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 29 Dec 2015 02:29:56 -0500
changeset 9986 081fbd89a347
parent 9619 b94b6d0bff0f
child 9998 f67cf37e9cd4
permissions -rw-r--r--
NetBSD: improved joystick support (thanks, Thomas!).

This patch skips non-joystick HID devices and gives joysticks on NetBSD
a human readable name.

Fixes Bugzilla #3178.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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] = 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++] = 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 SDL_SYS_NumJoysticks()
   208 {
   209     return SDL_SYS_numjoysticks;
   210 }
   211 
   212 void SDL_SYS_JoystickDetect()
   213 {
   214 }
   215 
   216 const char *
   217 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   218 {
   219     if (joydevnames[device_index] != NULL) {
   220         return (joydevnames[device_index]);
   221     }
   222     return (joynames[device_index]);
   223 }
   224 
   225 /* Function to perform the mapping from device index to the instance id for this index */
   226 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   227 {
   228     return device_index;
   229 }
   230 
   231 static int
   232 usage_to_joyaxe(unsigned usage)
   233 {
   234     int joyaxe;
   235     switch (usage) {
   236     case HUG_X:
   237         joyaxe = JOYAXE_X;
   238         break;
   239     case HUG_Y:
   240         joyaxe = JOYAXE_Y;
   241         break;
   242     case HUG_Z:
   243         joyaxe = JOYAXE_Z;
   244         break;
   245     case HUG_SLIDER:
   246         joyaxe = JOYAXE_SLIDER;
   247         break;
   248     case HUG_WHEEL:
   249         joyaxe = JOYAXE_WHEEL;
   250         break;
   251     case HUG_RX:
   252         joyaxe = JOYAXE_RX;
   253         break;
   254     case HUG_RY:
   255         joyaxe = JOYAXE_RY;
   256         break;
   257     case HUG_RZ:
   258         joyaxe = JOYAXE_RZ;
   259         break;
   260     default:
   261         joyaxe = -1;
   262     }
   263     return joyaxe;
   264 }
   265 
   266 static unsigned
   267 hatval_to_sdl(Sint32 hatval)
   268 {
   269     static const unsigned hat_dir_map[8] = {
   270         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
   271         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
   272     };
   273     unsigned result;
   274     if ((hatval & 7) == hatval)
   275         result = hat_dir_map[hatval];
   276     else
   277         result = SDL_HAT_CENTERED;
   278     return result;
   279 }
   280 
   281 
   282 int
   283 SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
   284 {
   285     char *path = joynames[device_index];
   286     struct joystick_hwdata *hw;
   287     struct hid_item hitem;
   288     struct hid_data *hdata;
   289     struct report *rep = NULL;
   290     int fd;
   291     int i;
   292 
   293     fd = open(path, O_RDONLY);
   294     if (fd == -1) {
   295         return SDL_SetError("%s: %s", path, strerror(errno));
   296     }
   297 
   298     joy->instance_id = device_index;
   299     hw = (struct joystick_hwdata *)
   300         SDL_malloc(sizeof(struct joystick_hwdata));
   301     if (hw == NULL) {
   302         close(fd);
   303         return SDL_OutOfMemory();
   304     }
   305     joy->hwdata = hw;
   306     hw->fd = fd;
   307     hw->path = strdup(path);
   308     if (!SDL_strncmp(path, "/dev/joy", 8)) {
   309         hw->type = BSDJOY_JOY;
   310         joy->naxes = 2;
   311         joy->nbuttons = 2;
   312         joy->nhats = 0;
   313         joy->nballs = 0;
   314         joydevnames[device_index] = strdup("Gameport joystick");
   315         goto usbend;
   316     } else {
   317         hw->type = BSDJOY_UHID;
   318     }
   319 
   320     {
   321         int ax;
   322         for (ax = 0; ax < JOYAXE_count; ax++)
   323             hw->axis_map[ax] = -1;
   324     }
   325     hw->repdesc = hid_get_report_desc(fd);
   326     if (hw->repdesc == NULL) {
   327         SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   328                      strerror(errno));
   329         goto usberr;
   330     }
   331     rep = &hw->inreport;
   332 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
   333     rep->rid = hid_get_report_id(fd);
   334     if (rep->rid < 0) {
   335 #else
   336     if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
   337 #endif
   338         rep->rid = -1;          /* XXX */
   339     }
   340 #if defined(__NetBSD__)
   341     usb_device_descriptor_t udd;
   342     struct usb_string_desc usd;
   343     if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
   344         goto desc_failed;
   345 
   346     /* Get default language */
   347     usd.usd_string_index = USB_LANGUAGE_TABLE;
   348     usd.usd_language_id = 0;
   349     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
   350         usd.usd_language_id = 0;
   351     } else {
   352         usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
   353     }
   354 
   355     usd.usd_string_index = udd.iProduct;
   356     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
   357         char str[128];
   358         char *new_name = NULL;
   359         int i;
   360         for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
   361             str[i] = UGETW(usd.usd_desc.bString[i]);
   362         }
   363         str[i] = '\0';
   364         asprintf(&new_name, "%s @ %s", str, path);
   365         if (new_name != NULL) {
   366             free(joydevnames[SDL_SYS_numjoysticks]);
   367             joydevnames[SDL_SYS_numjoysticks] = new_name;
   368         }
   369     }
   370 desc_failed:
   371 #endif
   372     if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   373         goto usberr;
   374     }
   375     if (rep->size <= 0) {
   376         SDL_SetError("%s: Input report descriptor has invalid length",
   377                      hw->path);
   378         goto usberr;
   379     }
   380 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   381     hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
   382 #else
   383     hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   384 #endif
   385     if (hdata == NULL) {
   386         SDL_SetError("%s: Cannot start HID parser", hw->path);
   387         goto usberr;
   388     }
   389     joy->naxes = 0;
   390     joy->nbuttons = 0;
   391     joy->nhats = 0;
   392     joy->nballs = 0;
   393     for (i = 0; i < JOYAXE_count; i++)
   394         hw->axis_map[i] = -1;
   395 
   396     while (hid_get_item(hdata, &hitem) > 0) {
   397         char *sp;
   398         const char *s;
   399 
   400         switch (hitem.kind) {
   401         case hid_collection:
   402             switch (HID_PAGE(hitem.usage)) {
   403             case HUP_GENERIC_DESKTOP:
   404                 switch (HID_USAGE(hitem.usage)) {
   405                 case HUG_JOYSTICK:
   406                 case HUG_GAME_PAD:
   407                     s = hid_usage_in_page(hitem.usage);
   408                     sp = SDL_malloc(SDL_strlen(s) + 5);
   409                     SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
   410                                  s, device_index);
   411                     joydevnames[device_index] = sp;
   412                 }
   413             }
   414             break;
   415         case hid_input:
   416             switch (HID_PAGE(hitem.usage)) {
   417             case HUP_GENERIC_DESKTOP:
   418                 {
   419                     unsigned usage = HID_USAGE(hitem.usage);
   420                     int joyaxe = usage_to_joyaxe(usage);
   421                     if (joyaxe >= 0) {
   422                         hw->axis_map[joyaxe] = 1;
   423                     } else if (usage == HUG_HAT_SWITCH) {
   424                         joy->nhats++;
   425                     }
   426                     break;
   427                 }
   428             case HUP_BUTTON:
   429                 joy->nbuttons++;
   430                 break;
   431             default:
   432                 break;
   433             }
   434             break;
   435         default:
   436             break;
   437         }
   438     }
   439     hid_end_parse(hdata);
   440     for (i = 0; i < JOYAXE_count; i++)
   441         if (hw->axis_map[i] > 0)
   442             hw->axis_map[i] = joy->naxes++;
   443 
   444     if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
   445         SDL_SetError("%s: Not a joystick, ignoring", hw->path);
   446         goto usberr;
   447     }
   448 
   449   usbend:
   450     /* The poll blocks the event thread. */
   451     fcntl(fd, F_SETFL, O_NONBLOCK);
   452 #ifdef __NetBSD__
   453     /* Flush pending events */
   454     if (rep) {
   455         while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
   456             ;
   457     }
   458 #endif
   459 
   460     return (0);
   461   usberr:
   462     close(hw->fd);
   463     SDL_free(hw->path);
   464     SDL_free(hw);
   465     return (-1);
   466 }
   467 
   468 /* Function to determine if this joystick is attached to the system right now */
   469 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   470 {
   471     return SDL_TRUE;
   472 }
   473 
   474 void
   475 SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
   476 {
   477     struct hid_item hitem;
   478     struct hid_data *hdata;
   479     struct report *rep;
   480     int nbutton, naxe = -1;
   481     Sint32 v;
   482 
   483 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   484     struct joystick gameport;
   485     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   486 
   487     if (joy->hwdata->type == BSDJOY_JOY) {
   488         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   489             if (abs(x - gameport.x) > 8) {
   490                 x = gameport.x;
   491                 if (x < xmin) {
   492                     xmin = x;
   493                 }
   494                 if (x > xmax) {
   495                     xmax = x;
   496                 }
   497                 if (xmin == xmax) {
   498                     xmin--;
   499                     xmax++;
   500                 }
   501                 v = (Sint32) x;
   502                 v -= (xmax + xmin + 1) / 2;
   503                 v *= 32768 / ((xmax - xmin + 1) / 2);
   504                 SDL_PrivateJoystickAxis(joy, 0, v);
   505             }
   506             if (abs(y - gameport.y) > 8) {
   507                 y = gameport.y;
   508                 if (y < ymin) {
   509                     ymin = y;
   510                 }
   511                 if (y > ymax) {
   512                     ymax = y;
   513                 }
   514                 if (ymin == ymax) {
   515                     ymin--;
   516                     ymax++;
   517                 }
   518                 v = (Sint32) y;
   519                 v -= (ymax + ymin + 1) / 2;
   520                 v *= 32768 / ((ymax - ymin + 1) / 2);
   521                 SDL_PrivateJoystickAxis(joy, 1, v);
   522             }
   523             if (gameport.b1 != joy->buttons[0]) {
   524                 SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   525             }
   526             if (gameport.b2 != joy->buttons[1]) {
   527                 SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   528             }
   529         }
   530         return;
   531     }
   532 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
   533 
   534     rep = &joy->hwdata->inreport;
   535 
   536     while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
   537 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   538         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
   539 #else
   540         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   541 #endif
   542         if (hdata == NULL) {
   543             /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
   544             continue;
   545         }
   546 
   547         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
   548             switch (hitem.kind) {
   549             case hid_input:
   550                 switch (HID_PAGE(hitem.usage)) {
   551                 case HUP_GENERIC_DESKTOP:
   552                     {
   553                         unsigned usage = HID_USAGE(hitem.usage);
   554                         int joyaxe = usage_to_joyaxe(usage);
   555                         if (joyaxe >= 0) {
   556                             naxe = joy->hwdata->axis_map[joyaxe];
   557                             /* scaleaxe */
   558                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   559                             v -= (hitem.logical_maximum +
   560                                   hitem.logical_minimum + 1) / 2;
   561                             v *= 32768 /
   562                                 ((hitem.logical_maximum -
   563                                   hitem.logical_minimum + 1) / 2);
   564                             if (v != joy->axes[naxe]) {
   565                                 SDL_PrivateJoystickAxis(joy, naxe, v);
   566                             }
   567                         } else if (usage == HUG_HAT_SWITCH) {
   568                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   569                             SDL_PrivateJoystickHat(joy, 0,
   570                                                    hatval_to_sdl(v) -
   571                                                    hitem.logical_minimum);
   572                         }
   573                         break;
   574                     }
   575                 case HUP_BUTTON:
   576                     v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   577                     if (joy->buttons[nbutton] != v) {
   578                         SDL_PrivateJoystickButton(joy, nbutton, v);
   579                     }
   580                     nbutton++;
   581                     break;
   582                 default:
   583                     continue;
   584                 }
   585                 break;
   586             default:
   587                 break;
   588             }
   589         }
   590         hid_end_parse(hdata);
   591     }
   592 }
   593 
   594 /* Function to close a joystick after use */
   595 void
   596 SDL_SYS_JoystickClose(SDL_Joystick * joy)
   597 {
   598     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   599         report_free(&joy->hwdata->inreport);
   600         hid_dispose_report_desc(joy->hwdata->repdesc);
   601     }
   602     close(joy->hwdata->fd);
   603     SDL_free(joy->hwdata->path);
   604     SDL_free(joy->hwdata);
   605 }
   606 
   607 void
   608 SDL_SYS_JoystickQuit(void)
   609 {
   610     int i;
   611 
   612     for (i = 0; i < MAX_JOYS; i++) {
   613         SDL_free(joynames[i]);
   614         SDL_free(joydevnames[i]);
   615     }
   616 
   617     return;
   618 }
   619 
   620 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   621 {
   622     SDL_JoystickGUID guid;
   623     /* the GUID is just the first 16 chars of the name for now */
   624     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   625     SDL_zero( guid );
   626     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   627     return guid;
   628 }
   629 
   630 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   631 {
   632     SDL_JoystickGUID guid;
   633     /* the GUID is just the first 16 chars of the name for now */
   634     const char *name = joystick->name;
   635     SDL_zero( guid );
   636     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   637     return guid;
   638 }
   639 
   640 static int
   641 report_alloc(struct report *r, struct report_desc *rd, int repind)
   642 {
   643     int len;
   644 
   645 #ifdef __DragonFly__
   646     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   647 #elif __FREEBSD__
   648 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   649 #  if (__FreeBSD_kernel_version <= 500111)
   650     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   651 #  else
   652     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   653 #  endif
   654 # else
   655     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   656 # endif
   657 #else
   658 # ifdef USBHID_NEW
   659     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   660 # else
   661     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   662 # endif
   663 #endif
   664 
   665     if (len < 0) {
   666         return SDL_SetError("Negative HID report size");
   667     }
   668     r->size = len;
   669 
   670     if (r->size > 0) {
   671 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   672         r->buf = SDL_malloc(r->size);
   673 #else
   674         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   675                             r->size);
   676 #endif
   677         if (r->buf == NULL) {
   678             return SDL_OutOfMemory();
   679         }
   680     } else {
   681         r->buf = NULL;
   682     }
   683 
   684     r->status = SREPORT_CLEAN;
   685     return 0;
   686 }
   687 
   688 static void
   689 report_free(struct report *r)
   690 {
   691     SDL_free(r->buf);
   692     r->status = SREPORT_UNINIT;
   693 }
   694 
   695 #endif /* SDL_JOYSTICK_USBHID */
   696 
   697 /* vi: set ts=4 sw=4 expandtab: */