src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Oct 2018 16:53:14 -0700
changeset 12359 691c32a30fb9
parent 12106 94f9bf5b9c36
child 12378 61b267339239
permissions -rw-r--r--
Generalized the XInput user index into a player index
     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 numjoysticks = 0;
   165 
   166 static int BSD_JoystickOpen(SDL_Joystick * joy, int device_index);
   167 static void BSD_JoystickClose(SDL_Joystick * joy);
   168 
   169 static int
   170 BSD_JoystickInit(void)
   171 {
   172     char s[16];
   173     int i, fd;
   174 
   175     numjoysticks = 0;
   176 
   177     SDL_memset(joynames, 0, sizeof(joynames));
   178     SDL_memset(joydevnames, 0, sizeof(joydevnames));
   179 
   180     for (i = 0; i < MAX_UHID_JOYS; i++) {
   181         SDL_Joystick nj;
   182 
   183         SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
   184 
   185         joynames[numjoysticks] = SDL_strdup(s);
   186 
   187         if (BSD_JoystickOpen(&nj, numjoysticks) == 0) {
   188             BSD_JoystickClose(&nj);
   189             numjoysticks++;
   190         } else {
   191             SDL_free(joynames[numjoysticks]);
   192             joynames[numjoysticks] = NULL;
   193         }
   194     }
   195     for (i = 0; i < MAX_JOY_JOYS; i++) {
   196         SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
   197         fd = open(s, O_RDONLY);
   198         if (fd != -1) {
   199             joynames[numjoysticks++] = SDL_strdup(s);
   200             close(fd);
   201         }
   202     }
   203 
   204     /* Read the default USB HID usage table. */
   205     hid_init(NULL);
   206 
   207     return (numjoysticks);
   208 }
   209 
   210 static int
   211 BSD_JoystickGetCount(void)
   212 {
   213     return numjoysticks;
   214 }
   215 
   216 static void
   217 BSD_JoystickDetect(void)
   218 {
   219 }
   220 
   221 static const char *
   222 BSD_JoystickGetDeviceName(int device_index)
   223 {
   224     if (joydevnames[device_index] != NULL) {
   225         return (joydevnames[device_index]);
   226     }
   227     return (joynames[device_index]);
   228 }
   229 
   230 static int
   231 BSD_JoystickGetDevicePlayerIndex(int device_index)
   232 {
   233     return -1;
   234 }
   235 
   236 /* Function to perform the mapping from device index to the instance id for this index */
   237 static SDL_JoystickID
   238 BSD_JoystickGetDeviceInstanceID(int device_index)
   239 {
   240     return device_index;
   241 }
   242 
   243 static int
   244 usage_to_joyaxe(unsigned usage)
   245 {
   246     int joyaxe;
   247     switch (usage) {
   248     case HUG_X:
   249         joyaxe = JOYAXE_X;
   250         break;
   251     case HUG_Y:
   252         joyaxe = JOYAXE_Y;
   253         break;
   254     case HUG_Z:
   255         joyaxe = JOYAXE_Z;
   256         break;
   257     case HUG_SLIDER:
   258         joyaxe = JOYAXE_SLIDER;
   259         break;
   260     case HUG_WHEEL:
   261         joyaxe = JOYAXE_WHEEL;
   262         break;
   263     case HUG_RX:
   264         joyaxe = JOYAXE_RX;
   265         break;
   266     case HUG_RY:
   267         joyaxe = JOYAXE_RY;
   268         break;
   269     case HUG_RZ:
   270         joyaxe = JOYAXE_RZ;
   271         break;
   272     default:
   273         joyaxe = -1;
   274     }
   275     return joyaxe;
   276 }
   277 
   278 static unsigned
   279 hatval_to_sdl(Sint32 hatval)
   280 {
   281     static const unsigned hat_dir_map[8] = {
   282         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
   283         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
   284     };
   285     unsigned result;
   286     if ((hatval & 7) == hatval)
   287         result = hat_dir_map[hatval];
   288     else
   289         result = SDL_HAT_CENTERED;
   290     return result;
   291 }
   292 
   293 
   294 static int
   295 BSD_JoystickOpen(SDL_Joystick * joy, int device_index)
   296 {
   297     char *path = joynames[device_index];
   298     struct joystick_hwdata *hw;
   299     struct hid_item hitem;
   300     struct hid_data *hdata;
   301     struct report *rep = NULL;
   302     int fd;
   303     int i;
   304 
   305     fd = open(path, O_RDONLY);
   306     if (fd == -1) {
   307         return SDL_SetError("%s: %s", path, strerror(errno));
   308     }
   309 
   310     joy->instance_id = device_index;
   311     hw = (struct joystick_hwdata *)
   312         SDL_malloc(sizeof(struct joystick_hwdata));
   313     if (hw == NULL) {
   314         close(fd);
   315         return SDL_OutOfMemory();
   316     }
   317     joy->hwdata = hw;
   318     hw->fd = fd;
   319     hw->path = SDL_strdup(path);
   320     if (!SDL_strncmp(path, "/dev/joy", 8)) {
   321         hw->type = BSDJOY_JOY;
   322         joy->naxes = 2;
   323         joy->nbuttons = 2;
   324         joy->nhats = 0;
   325         joy->nballs = 0;
   326         joydevnames[device_index] = SDL_strdup("Gameport joystick");
   327         goto usbend;
   328     } else {
   329         hw->type = BSDJOY_UHID;
   330     }
   331 
   332     {
   333         int ax;
   334         for (ax = 0; ax < JOYAXE_count; ax++)
   335             hw->axis_map[ax] = -1;
   336     }
   337     hw->repdesc = hid_get_report_desc(fd);
   338     if (hw->repdesc == NULL) {
   339         SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   340                      strerror(errno));
   341         goto usberr;
   342     }
   343     rep = &hw->inreport;
   344 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
   345     rep->rid = hid_get_report_id(fd);
   346     if (rep->rid < 0) {
   347 #else
   348     if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
   349 #endif
   350         rep->rid = -1;          /* XXX */
   351     }
   352 #if defined(__NetBSD__)
   353     usb_device_descriptor_t udd;
   354     struct usb_string_desc usd;
   355     if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
   356         goto desc_failed;
   357 
   358     /* Get default language */
   359     usd.usd_string_index = USB_LANGUAGE_TABLE;
   360     usd.usd_language_id = 0;
   361     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
   362         usd.usd_language_id = 0;
   363     } else {
   364         usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
   365     }
   366 
   367     usd.usd_string_index = udd.iProduct;
   368     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
   369         char str[128];
   370         char *new_name = NULL;
   371         int i;
   372         for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
   373             str[i] = UGETW(usd.usd_desc.bString[i]);
   374         }
   375         str[i] = '\0';
   376         asprintf(&new_name, "%s @ %s", str, path);
   377         if (new_name != NULL) {
   378             SDL_free(joydevnames[numjoysticks]);
   379             joydevnames[numjoysticks] = new_name;
   380         }
   381     }
   382 desc_failed:
   383 #endif
   384     if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   385         goto usberr;
   386     }
   387     if (rep->size <= 0) {
   388         SDL_SetError("%s: Input report descriptor has invalid length",
   389                      hw->path);
   390         goto usberr;
   391     }
   392 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   393     hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
   394 #else
   395     hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   396 #endif
   397     if (hdata == NULL) {
   398         SDL_SetError("%s: Cannot start HID parser", hw->path);
   399         goto usberr;
   400     }
   401     joy->naxes = 0;
   402     joy->nbuttons = 0;
   403     joy->nhats = 0;
   404     joy->nballs = 0;
   405     for (i = 0; i < JOYAXE_count; i++)
   406         hw->axis_map[i] = -1;
   407 
   408     while (hid_get_item(hdata, &hitem) > 0) {
   409         char *sp;
   410         const char *s;
   411 
   412         switch (hitem.kind) {
   413         case hid_collection:
   414             switch (HID_PAGE(hitem.usage)) {
   415             case HUP_GENERIC_DESKTOP:
   416                 switch (HID_USAGE(hitem.usage)) {
   417                 case HUG_JOYSTICK:
   418                 case HUG_GAME_PAD:
   419                     s = hid_usage_in_page(hitem.usage);
   420                     sp = SDL_malloc(SDL_strlen(s) + 5);
   421                     SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
   422                                  s, device_index);
   423                     joydevnames[device_index] = sp;
   424                 }
   425             }
   426             break;
   427         case hid_input:
   428             switch (HID_PAGE(hitem.usage)) {
   429             case HUP_GENERIC_DESKTOP:
   430                 {
   431                     unsigned usage = HID_USAGE(hitem.usage);
   432                     int joyaxe = usage_to_joyaxe(usage);
   433                     if (joyaxe >= 0) {
   434                         hw->axis_map[joyaxe] = 1;
   435                     } else if (usage == HUG_HAT_SWITCH) {
   436                         joy->nhats++;
   437                     }
   438                     break;
   439                 }
   440             case HUP_BUTTON:
   441                 joy->nbuttons++;
   442                 break;
   443             default:
   444                 break;
   445             }
   446             break;
   447         default:
   448             break;
   449         }
   450     }
   451     hid_end_parse(hdata);
   452     for (i = 0; i < JOYAXE_count; i++)
   453         if (hw->axis_map[i] > 0)
   454             hw->axis_map[i] = joy->naxes++;
   455 
   456     if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
   457         SDL_SetError("%s: Not a joystick, ignoring", hw->path);
   458         goto usberr;
   459     }
   460 
   461   usbend:
   462     /* The poll blocks the event thread. */
   463     fcntl(fd, F_SETFL, O_NONBLOCK);
   464 #ifdef __NetBSD__
   465     /* Flush pending events */
   466     if (rep) {
   467         while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
   468             ;
   469     }
   470 #endif
   471 
   472     return (0);
   473   usberr:
   474     close(hw->fd);
   475     SDL_free(hw->path);
   476     SDL_free(hw);
   477     return (-1);
   478 }
   479 
   480 static void
   481 BSD_JoystickUpdate(SDL_Joystick * joy)
   482 {
   483     struct hid_item hitem;
   484     struct hid_data *hdata;
   485     struct report *rep;
   486     int nbutton, naxe = -1;
   487     Sint32 v;
   488 
   489 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   490     struct joystick gameport;
   491     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   492 
   493     if (joy->hwdata->type == BSDJOY_JOY) {
   494         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   495             if (abs(x - gameport.x) > 8) {
   496                 x = gameport.x;
   497                 if (x < xmin) {
   498                     xmin = x;
   499                 }
   500                 if (x > xmax) {
   501                     xmax = x;
   502                 }
   503                 if (xmin == xmax) {
   504                     xmin--;
   505                     xmax++;
   506                 }
   507                 v = (Sint32) x;
   508                 v -= (xmax + xmin + 1) / 2;
   509                 v *= 32768 / ((xmax - xmin + 1) / 2);
   510                 SDL_PrivateJoystickAxis(joy, 0, v);
   511             }
   512             if (abs(y - gameport.y) > 8) {
   513                 y = gameport.y;
   514                 if (y < ymin) {
   515                     ymin = y;
   516                 }
   517                 if (y > ymax) {
   518                     ymax = y;
   519                 }
   520                 if (ymin == ymax) {
   521                     ymin--;
   522                     ymax++;
   523                 }
   524                 v = (Sint32) y;
   525                 v -= (ymax + ymin + 1) / 2;
   526                 v *= 32768 / ((ymax - ymin + 1) / 2);
   527                 SDL_PrivateJoystickAxis(joy, 1, v);
   528             }
   529             SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   530             SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   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                             SDL_PrivateJoystickAxis(joy, naxe, v);
   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                     SDL_PrivateJoystickButton(joy, nbutton, v);
   578                     nbutton++;
   579                     break;
   580                 default:
   581                     continue;
   582                 }
   583                 break;
   584             default:
   585                 break;
   586             }
   587         }
   588         hid_end_parse(hdata);
   589     }
   590 }
   591 
   592 /* Function to close a joystick after use */
   593 static void
   594 BSD_JoystickClose(SDL_Joystick * joy)
   595 {
   596     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   597         report_free(&joy->hwdata->inreport);
   598         hid_dispose_report_desc(joy->hwdata->repdesc);
   599     }
   600     close(joy->hwdata->fd);
   601     SDL_free(joy->hwdata->path);
   602     SDL_free(joy->hwdata);
   603 }
   604 
   605 static void
   606 BSD_JoystickQuit(void)
   607 {
   608     int i;
   609 
   610     for (i = 0; i < MAX_JOYS; i++) {
   611         SDL_free(joynames[i]);
   612         SDL_free(joydevnames[i]);
   613     }
   614 
   615     return;
   616 }
   617 
   618 static SDL_JoystickGUID
   619 BSD_JoystickGetDeviceGUID( int device_index )
   620 {
   621     SDL_JoystickGUID guid;
   622     /* the GUID is just the first 16 chars of the name for now */
   623     const char *name = BSD_JoystickGetDeviceName( device_index );
   624     SDL_zero( guid );
   625     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   626     return guid;
   627 }
   628 
   629 static int
   630 report_alloc(struct report *r, struct report_desc *rd, int repind)
   631 {
   632     int len;
   633 
   634 #ifdef __DragonFly__
   635     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   636 #elif __FREEBSD__
   637 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   638 #  if (__FreeBSD_kernel_version <= 500111)
   639     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   640 #  else
   641     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   642 #  endif
   643 # else
   644     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   645 # endif
   646 #else
   647 # ifdef USBHID_NEW
   648     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   649 # else
   650     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   651 # endif
   652 #endif
   653 
   654     if (len < 0) {
   655         return SDL_SetError("Negative HID report size");
   656     }
   657     r->size = len;
   658 
   659     if (r->size > 0) {
   660 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   661         r->buf = SDL_malloc(r->size);
   662 #else
   663         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   664                             r->size);
   665 #endif
   666         if (r->buf == NULL) {
   667             return SDL_OutOfMemory();
   668         }
   669     } else {
   670         r->buf = NULL;
   671     }
   672 
   673     r->status = SREPORT_CLEAN;
   674     return 0;
   675 }
   676 
   677 static void
   678 report_free(struct report *r)
   679 {
   680     SDL_free(r->buf);
   681     r->status = SREPORT_UNINIT;
   682 }
   683 
   684 static int
   685 BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   686 {
   687     return SDL_Unsupported();
   688 }
   689 
   690 SDL_JoystickDriver SDL_BSD_JoystickDriver =
   691 {
   692     BSD_JoystickInit,
   693     BSD_JoystickGetCount,
   694     BSD_JoystickDetect,
   695     BSD_JoystickGetDeviceName,
   696     BSD_JoystickGetDevicePlayerIndex,
   697     BSD_JoystickGetDeviceGUID,
   698     BSD_JoystickGetDeviceInstanceID,
   699     BSD_JoystickOpen,
   700     BSD_JoystickRumble,
   701     BSD_JoystickUpdate,
   702     BSD_JoystickClose,
   703     BSD_JoystickQuit,
   704 };
   705 
   706 #endif /* SDL_JOYSTICK_USBHID */
   707 
   708 /* vi: set ts=4 sw=4 expandtab: */