src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 04 Mar 2013 20:27:51 -0800
changeset 6963 4658b1101200
parent 6885 700f1b25f77f
child 7037 3fedf1f25b94
permissions -rw-r--r--
Fixed bug 1553 - Fix USB joystick input for FreeBSD 9.0+

Marcus von Appen

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