src/joystick/bsd/SDL_sysjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 10 Aug 2018 14:54:26 -0400
changeset 12106 94f9bf5b9c36
parent 12105 997ec56425a8
child 12359 691c32a30fb9
permissions -rw-r--r--
bsd: Patched to compile.

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