src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 03 Jan 2017 23:39:28 -0800
changeset 10745 7461fcef6ae2
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Fixed binding the D-pad on some Super NES style controllers
Fixed a case where partial trigger pull could be bound to another button

There is a fundamental problem not resolved by this commit:

Some controllers have axes (triggers, pedals, etc.) that don't start at zero, but we're guaranteed that if we get a value that it's correct. For these controllers, the current code works, where we take the first value we get and use that as the zero point and generate axis motion starting from that point on.

Other controllers have digital axes (D-pad) that assume a zero starting point, and the first value we get is the min or max axis value when the D-pad is moved. For these controllers, the current code thinks that the zero point is the axis value after the D-pad motion and this doesn't work.

My hypothesis is that the first class of devices is more common and that we should solve for that, and add an exception to SDL_JoystickAxesCenteredAtZero() as needed for the second class of devices.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #ifdef SDL_JOYSTICK_USBHID
    24 
    25 /*
    26  * Joystick driver for the uhid(4) interface found in OpenBSD,
    27  * NetBSD and FreeBSD.
    28  *
    29  * Maintainer: <vedge at csoft.org>
    30  */
    31 
    32 #include <sys/param.h>
    33 
    34 #include <unistd.h>
    35 #include <fcntl.h>
    36 #include <errno.h>
    37 
    38 #ifndef __FreeBSD_kernel_version
    39 #define __FreeBSD_kernel_version __FreeBSD_version
    40 #endif
    41 
    42 #if defined(HAVE_USB_H)
    43 #include <usb.h>
    44 #endif
    45 #ifdef __DragonFly__
    46 #include <bus/usb/usb.h>
    47 #include <bus/usb/usbhid.h>
    48 #else
    49 #include <dev/usb/usb.h>
    50 #include <dev/usb/usbhid.h>
    51 #endif
    52 
    53 #if defined(HAVE_USBHID_H)
    54 #include <usbhid.h>
    55 #elif defined(HAVE_LIBUSB_H)
    56 #include <libusb.h>
    57 #elif defined(HAVE_LIBUSBHID_H)
    58 #include <libusbhid.h>
    59 #endif
    60 
    61 #if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
    62 #ifndef __DragonFly__
    63 #include <osreldate.h>
    64 #endif
    65 #if __FreeBSD_kernel_version > 800063
    66 #include <dev/usb/usb_ioctl.h>
    67 #endif
    68 #include <sys/joystick.h>
    69 #endif
    70 
    71 #if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
    72 #include <machine/joystick.h>
    73 #endif
    74 
    75 #include "SDL_joystick.h"
    76 #include "../SDL_sysjoystick.h"
    77 #include "../SDL_joystick_c.h"
    78 
    79 #define MAX_UHID_JOYS   64
    80 #define MAX_JOY_JOYS    2
    81 #define MAX_JOYS    (MAX_UHID_JOYS + MAX_JOY_JOYS)
    82 
    83 
    84 struct report
    85 {
    86 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
    87     void *buf; /* Buffer */
    88 #elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
    89     struct usb_gen_descriptor *buf; /* Buffer */
    90 #else
    91     struct usb_ctl_report *buf; /* Buffer */
    92 #endif
    93     size_t size;                /* Buffer size */
    94     int rid;                    /* Report ID */
    95     enum
    96     {
    97         SREPORT_UNINIT,
    98         SREPORT_CLEAN,
    99         SREPORT_DIRTY
   100     } status;
   101 };
   102 
   103 static struct
   104 {
   105     int uhid_report;
   106     hid_kind_t kind;
   107     const char *name;
   108 } const repinfo[] = {
   109     {UHID_INPUT_REPORT, hid_input, "input"},
   110     {UHID_OUTPUT_REPORT, hid_output, "output"},
   111     {UHID_FEATURE_REPORT, hid_feature, "feature"}
   112 };
   113 
   114 enum
   115 {
   116     REPORT_INPUT = 0,
   117     REPORT_OUTPUT = 1,
   118     REPORT_FEATURE = 2
   119 };
   120 
   121 enum
   122 {
   123     JOYAXE_X,
   124     JOYAXE_Y,
   125     JOYAXE_Z,
   126     JOYAXE_SLIDER,
   127     JOYAXE_WHEEL,
   128     JOYAXE_RX,
   129     JOYAXE_RY,
   130     JOYAXE_RZ,
   131     JOYAXE_count
   132 };
   133 
   134 struct joystick_hwdata
   135 {
   136     int fd;
   137     char *path;
   138     enum
   139     {
   140         BSDJOY_UHID,            /* uhid(4) */
   141         BSDJOY_JOY              /* joy(4) */
   142     } type;
   143     struct report_desc *repdesc;
   144     struct report inreport;
   145     int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
   146 };
   147 
   148 static char *joynames[MAX_JOYS];
   149 static char *joydevnames[MAX_JOYS];
   150 
   151 static int report_alloc(struct report *, struct report_desc *, int);
   152 static void report_free(struct report *);
   153 
   154 #if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
   155 #define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
   156 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
   157 #define REP_BUF_DATA(rep) ((rep)->buf)
   158 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
   159 #define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
   160 #else
   161 #define REP_BUF_DATA(rep) ((rep)->buf->data)
   162 #endif
   163 
   164 static int SDL_SYS_numjoysticks = 0;
   165 
   166 int
   167 SDL_SYS_JoystickInit(void)
   168 {
   169     char s[16];
   170     int i, fd;
   171 
   172     SDL_SYS_numjoysticks = 0;
   173 
   174     SDL_memset(joynames, 0, sizeof(joynames));
   175     SDL_memset(joydevnames, 0, sizeof(joydevnames));
   176 
   177     for (i = 0; i < MAX_UHID_JOYS; i++) {
   178         SDL_Joystick nj;
   179 
   180         SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
   181 
   182         joynames[SDL_SYS_numjoysticks] = SDL_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++] = SDL_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
   208 SDL_SYS_NumJoysticks(void)
   209 {
   210     return SDL_SYS_numjoysticks;
   211 }
   212 
   213 void
   214 SDL_SYS_JoystickDetect(void)
   215 {
   216 }
   217 
   218 const char *
   219 SDL_SYS_JoystickNameForDeviceIndex(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 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   229 {
   230     return device_index;
   231 }
   232 
   233 static int
   234 usage_to_joyaxe(unsigned usage)
   235 {
   236     int joyaxe;
   237     switch (usage) {
   238     case HUG_X:
   239         joyaxe = JOYAXE_X;
   240         break;
   241     case HUG_Y:
   242         joyaxe = JOYAXE_Y;
   243         break;
   244     case HUG_Z:
   245         joyaxe = JOYAXE_Z;
   246         break;
   247     case HUG_SLIDER:
   248         joyaxe = JOYAXE_SLIDER;
   249         break;
   250     case HUG_WHEEL:
   251         joyaxe = JOYAXE_WHEEL;
   252         break;
   253     case HUG_RX:
   254         joyaxe = JOYAXE_RX;
   255         break;
   256     case HUG_RY:
   257         joyaxe = JOYAXE_RY;
   258         break;
   259     case HUG_RZ:
   260         joyaxe = JOYAXE_RZ;
   261         break;
   262     default:
   263         joyaxe = -1;
   264     }
   265     return joyaxe;
   266 }
   267 
   268 static unsigned
   269 hatval_to_sdl(Sint32 hatval)
   270 {
   271     static const unsigned hat_dir_map[8] = {
   272         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
   273         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
   274     };
   275     unsigned result;
   276     if ((hatval & 7) == hatval)
   277         result = hat_dir_map[hatval];
   278     else
   279         result = SDL_HAT_CENTERED;
   280     return result;
   281 }
   282 
   283 
   284 int
   285 SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
   286 {
   287     char *path = joynames[device_index];
   288     struct joystick_hwdata *hw;
   289     struct hid_item hitem;
   290     struct hid_data *hdata;
   291     struct report *rep = NULL;
   292     int fd;
   293     int i;
   294 
   295     fd = open(path, O_RDONLY);
   296     if (fd == -1) {
   297         return SDL_SetError("%s: %s", path, strerror(errno));
   298     }
   299 
   300     joy->instance_id = device_index;
   301     hw = (struct joystick_hwdata *)
   302         SDL_malloc(sizeof(struct joystick_hwdata));
   303     if (hw == NULL) {
   304         close(fd);
   305         return SDL_OutOfMemory();
   306     }
   307     joy->hwdata = hw;
   308     hw->fd = fd;
   309     hw->path = SDL_strdup(path);
   310     if (!SDL_strncmp(path, "/dev/joy", 8)) {
   311         hw->type = BSDJOY_JOY;
   312         joy->naxes = 2;
   313         joy->nbuttons = 2;
   314         joy->nhats = 0;
   315         joy->nballs = 0;
   316         joydevnames[device_index] = SDL_strdup("Gameport joystick");
   317         goto usbend;
   318     } else {
   319         hw->type = BSDJOY_UHID;
   320     }
   321 
   322     {
   323         int ax;
   324         for (ax = 0; ax < JOYAXE_count; ax++)
   325             hw->axis_map[ax] = -1;
   326     }
   327     hw->repdesc = hid_get_report_desc(fd);
   328     if (hw->repdesc == NULL) {
   329         SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   330                      strerror(errno));
   331         goto usberr;
   332     }
   333     rep = &hw->inreport;
   334 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
   335     rep->rid = hid_get_report_id(fd);
   336     if (rep->rid < 0) {
   337 #else
   338     if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
   339 #endif
   340         rep->rid = -1;          /* XXX */
   341     }
   342 #if defined(__NetBSD__)
   343     usb_device_descriptor_t udd;
   344     struct usb_string_desc usd;
   345     if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
   346         goto desc_failed;
   347 
   348     /* Get default language */
   349     usd.usd_string_index = USB_LANGUAGE_TABLE;
   350     usd.usd_language_id = 0;
   351     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
   352         usd.usd_language_id = 0;
   353     } else {
   354         usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
   355     }
   356 
   357     usd.usd_string_index = udd.iProduct;
   358     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
   359         char str[128];
   360         char *new_name = NULL;
   361         int i;
   362         for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
   363             str[i] = UGETW(usd.usd_desc.bString[i]);
   364         }
   365         str[i] = '\0';
   366         asprintf(&new_name, "%s @ %s", str, path);
   367         if (new_name != NULL) {
   368             SDL_free(joydevnames[SDL_SYS_numjoysticks]);
   369             joydevnames[SDL_SYS_numjoysticks] = new_name;
   370         }
   371     }
   372 desc_failed:
   373 #endif
   374     if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   375         goto usberr;
   376     }
   377     if (rep->size <= 0) {
   378         SDL_SetError("%s: Input report descriptor has invalid length",
   379                      hw->path);
   380         goto usberr;
   381     }
   382 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   383     hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
   384 #else
   385     hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   386 #endif
   387     if (hdata == NULL) {
   388         SDL_SetError("%s: Cannot start HID parser", hw->path);
   389         goto usberr;
   390     }
   391     joy->naxes = 0;
   392     joy->nbuttons = 0;
   393     joy->nhats = 0;
   394     joy->nballs = 0;
   395     for (i = 0; i < JOYAXE_count; i++)
   396         hw->axis_map[i] = -1;
   397 
   398     while (hid_get_item(hdata, &hitem) > 0) {
   399         char *sp;
   400         const char *s;
   401 
   402         switch (hitem.kind) {
   403         case hid_collection:
   404             switch (HID_PAGE(hitem.usage)) {
   405             case HUP_GENERIC_DESKTOP:
   406                 switch (HID_USAGE(hitem.usage)) {
   407                 case HUG_JOYSTICK:
   408                 case HUG_GAME_PAD:
   409                     s = hid_usage_in_page(hitem.usage);
   410                     sp = SDL_malloc(SDL_strlen(s) + 5);
   411                     SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
   412                                  s, device_index);
   413                     joydevnames[device_index] = sp;
   414                 }
   415             }
   416             break;
   417         case hid_input:
   418             switch (HID_PAGE(hitem.usage)) {
   419             case HUP_GENERIC_DESKTOP:
   420                 {
   421                     unsigned usage = HID_USAGE(hitem.usage);
   422                     int joyaxe = usage_to_joyaxe(usage);
   423                     if (joyaxe >= 0) {
   424                         hw->axis_map[joyaxe] = 1;
   425                     } else if (usage == HUG_HAT_SWITCH) {
   426                         joy->nhats++;
   427                     }
   428                     break;
   429                 }
   430             case HUP_BUTTON:
   431                 joy->nbuttons++;
   432                 break;
   433             default:
   434                 break;
   435             }
   436             break;
   437         default:
   438             break;
   439         }
   440     }
   441     hid_end_parse(hdata);
   442     for (i = 0; i < JOYAXE_count; i++)
   443         if (hw->axis_map[i] > 0)
   444             hw->axis_map[i] = joy->naxes++;
   445 
   446     if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
   447         SDL_SetError("%s: Not a joystick, ignoring", hw->path);
   448         goto usberr;
   449     }
   450 
   451   usbend:
   452     /* The poll blocks the event thread. */
   453     fcntl(fd, F_SETFL, O_NONBLOCK);
   454 #ifdef __NetBSD__
   455     /* Flush pending events */
   456     if (rep) {
   457         while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
   458             ;
   459     }
   460 #endif
   461 
   462     return (0);
   463   usberr:
   464     close(hw->fd);
   465     SDL_free(hw->path);
   466     SDL_free(hw);
   467     return (-1);
   468 }
   469 
   470 /* Function to determine if this joystick is attached to the system right now */
   471 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   472 {
   473     return SDL_TRUE;
   474 }
   475 
   476 void
   477 SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
   478 {
   479     struct hid_item hitem;
   480     struct hid_data *hdata;
   481     struct report *rep;
   482     int nbutton, naxe = -1;
   483     Sint32 v;
   484 
   485 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   486     struct joystick gameport;
   487     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   488 
   489     if (joy->hwdata->type == BSDJOY_JOY) {
   490         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   491             if (abs(x - gameport.x) > 8) {
   492                 x = gameport.x;
   493                 if (x < xmin) {
   494                     xmin = x;
   495                 }
   496                 if (x > xmax) {
   497                     xmax = x;
   498                 }
   499                 if (xmin == xmax) {
   500                     xmin--;
   501                     xmax++;
   502                 }
   503                 v = (Sint32) x;
   504                 v -= (xmax + xmin + 1) / 2;
   505                 v *= 32768 / ((xmax - xmin + 1) / 2);
   506                 SDL_PrivateJoystickAxis(joy, 0, v);
   507             }
   508             if (abs(y - gameport.y) > 8) {
   509                 y = gameport.y;
   510                 if (y < ymin) {
   511                     ymin = y;
   512                 }
   513                 if (y > ymax) {
   514                     ymax = y;
   515                 }
   516                 if (ymin == ymax) {
   517                     ymin--;
   518                     ymax++;
   519                 }
   520                 v = (Sint32) y;
   521                 v -= (ymax + ymin + 1) / 2;
   522                 v *= 32768 / ((ymax - ymin + 1) / 2);
   523                 SDL_PrivateJoystickAxis(joy, 1, v);
   524             }
   525             SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   526             SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   527         }
   528         return;
   529     }
   530 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
   531 
   532     rep = &joy->hwdata->inreport;
   533 
   534     while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
   535 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   536         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
   537 #else
   538         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   539 #endif
   540         if (hdata == NULL) {
   541             /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
   542             continue;
   543         }
   544 
   545         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
   546             switch (hitem.kind) {
   547             case hid_input:
   548                 switch (HID_PAGE(hitem.usage)) {
   549                 case HUP_GENERIC_DESKTOP:
   550                     {
   551                         unsigned usage = HID_USAGE(hitem.usage);
   552                         int joyaxe = usage_to_joyaxe(usage);
   553                         if (joyaxe >= 0) {
   554                             naxe = joy->hwdata->axis_map[joyaxe];
   555                             /* scaleaxe */
   556                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   557                             v -= (hitem.logical_maximum +
   558                                   hitem.logical_minimum + 1) / 2;
   559                             v *= 32768 /
   560                                 ((hitem.logical_maximum -
   561                                   hitem.logical_minimum + 1) / 2);
   562                             SDL_PrivateJoystickAxis(joy, naxe, v);
   563                         } else if (usage == HUG_HAT_SWITCH) {
   564                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   565                             SDL_PrivateJoystickHat(joy, 0,
   566                                                    hatval_to_sdl(v) -
   567                                                    hitem.logical_minimum);
   568                         }
   569                         break;
   570                     }
   571                 case HUP_BUTTON:
   572                     v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   573                     SDL_PrivateJoystickButton(joy, nbutton, v);
   574                     nbutton++;
   575                     break;
   576                 default:
   577                     continue;
   578                 }
   579                 break;
   580             default:
   581                 break;
   582             }
   583         }
   584         hid_end_parse(hdata);
   585     }
   586 }
   587 
   588 /* Function to close a joystick after use */
   589 void
   590 SDL_SYS_JoystickClose(SDL_Joystick * joy)
   591 {
   592     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   593         report_free(&joy->hwdata->inreport);
   594         hid_dispose_report_desc(joy->hwdata->repdesc);
   595     }
   596     close(joy->hwdata->fd);
   597     SDL_free(joy->hwdata->path);
   598     SDL_free(joy->hwdata);
   599 }
   600 
   601 void
   602 SDL_SYS_JoystickQuit(void)
   603 {
   604     int i;
   605 
   606     for (i = 0; i < MAX_JOYS; i++) {
   607         SDL_free(joynames[i]);
   608         SDL_free(joydevnames[i]);
   609     }
   610 
   611     return;
   612 }
   613 
   614 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   615 {
   616     SDL_JoystickGUID guid;
   617     /* the GUID is just the first 16 chars of the name for now */
   618     const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   619     SDL_zero( guid );
   620     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   621     return guid;
   622 }
   623 
   624 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   625 {
   626     SDL_JoystickGUID guid;
   627     /* the GUID is just the first 16 chars of the name for now */
   628     const char *name = joystick->name;
   629     SDL_zero( guid );
   630     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   631     return guid;
   632 }
   633 
   634 static int
   635 report_alloc(struct report *r, struct report_desc *rd, int repind)
   636 {
   637     int len;
   638 
   639 #ifdef __DragonFly__
   640     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   641 #elif __FREEBSD__
   642 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   643 #  if (__FreeBSD_kernel_version <= 500111)
   644     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   645 #  else
   646     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   647 #  endif
   648 # else
   649     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   650 # endif
   651 #else
   652 # ifdef USBHID_NEW
   653     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   654 # else
   655     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   656 # endif
   657 #endif
   658 
   659     if (len < 0) {
   660         return SDL_SetError("Negative HID report size");
   661     }
   662     r->size = len;
   663 
   664     if (r->size > 0) {
   665 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   666         r->buf = SDL_malloc(r->size);
   667 #else
   668         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   669                             r->size);
   670 #endif
   671         if (r->buf == NULL) {
   672             return SDL_OutOfMemory();
   673         }
   674     } else {
   675         r->buf = NULL;
   676     }
   677 
   678     r->status = SREPORT_CLEAN;
   679     return 0;
   680 }
   681 
   682 static void
   683 report_free(struct report *r)
   684 {
   685     SDL_free(r->buf);
   686     r->status = SREPORT_UNINIT;
   687 }
   688 
   689 #endif /* SDL_JOYSTICK_USBHID */
   690 
   691 /* vi: set ts=4 sw=4 expandtab: */