src/joystick/bsd/SDL_sysjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 10 Aug 2018 14:42:40 -0400
changeset 12105 997ec56425a8
parent 12090 c3209fca27b2
child 12106 94f9bf5b9c36
permissions -rw-r--r--
bsd: Update joystick code for new interfaces.

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