src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 19 Jun 2019 17:11:20 -0700
changeset 12897 25998acc4810
parent 12738 64dabb27041d
permissions -rw-r--r--
Fixed bug 4672 - Warnings in SDL_LogEvent()
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 #ifdef __OpenBSD__
    84 
    85 #define HUG_DPAD_UP         0x90
    86 #define HUG_DPAD_DOWN       0x91
    87 #define HUG_DPAD_RIGHT      0x92
    88 #define HUG_DPAD_LEFT       0x93
    89 
    90 #define HAT_CENTERED        0x00
    91 #define HAT_UP              0x01
    92 #define HAT_RIGHT           0x02
    93 #define HAT_DOWN            0x04
    94 #define HAT_LEFT            0x08
    95 #define HAT_RIGHTUP         (HAT_RIGHT|HAT_UP)
    96 #define HAT_RIGHTDOWN       (HAT_RIGHT|HAT_DOWN)
    97 #define HAT_LEFTUP          (HAT_LEFT|HAT_UP)
    98 #define HAT_LEFTDOWN        (HAT_LEFT|HAT_DOWN)
    99 
   100 /* calculate the value from the state of the dpad */
   101 int
   102 dpad_to_sdl(Sint32 *dpad)
   103 {
   104     if (dpad[2]) {
   105         if (dpad[0])
   106             return HAT_RIGHTUP;
   107         else if (dpad[1])
   108             return HAT_RIGHTDOWN;
   109         else
   110             return HAT_RIGHT;
   111     } else if (dpad[3]) {
   112         if (dpad[0])
   113             return HAT_LEFTUP;
   114         else if (dpad[1])
   115             return HAT_LEFTDOWN;
   116         else
   117             return HAT_LEFT;
   118     } else if (dpad[0]) {
   119         return HAT_UP;
   120     } else if (dpad[1]) {
   121         return HAT_DOWN;
   122     }
   123     return HAT_CENTERED;
   124 }
   125 #endif
   126 
   127 struct report
   128 {
   129 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   130     void *buf; /* Buffer */
   131 #elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
   132     struct usb_gen_descriptor *buf; /* Buffer */
   133 #else
   134     struct usb_ctl_report *buf; /* Buffer */
   135 #endif
   136     size_t size;                /* Buffer size */
   137     int rid;                    /* Report ID */
   138     enum
   139     {
   140         SREPORT_UNINIT,
   141         SREPORT_CLEAN,
   142         SREPORT_DIRTY
   143     } status;
   144 };
   145 
   146 static struct
   147 {
   148     int uhid_report;
   149     hid_kind_t kind;
   150     const char *name;
   151 } const repinfo[] = {
   152     {UHID_INPUT_REPORT, hid_input, "input"},
   153     {UHID_OUTPUT_REPORT, hid_output, "output"},
   154     {UHID_FEATURE_REPORT, hid_feature, "feature"}
   155 };
   156 
   157 enum
   158 {
   159     REPORT_INPUT = 0,
   160     REPORT_OUTPUT = 1,
   161     REPORT_FEATURE = 2
   162 };
   163 
   164 enum
   165 {
   166     JOYAXE_X,
   167     JOYAXE_Y,
   168     JOYAXE_Z,
   169     JOYAXE_SLIDER,
   170     JOYAXE_WHEEL,
   171     JOYAXE_RX,
   172     JOYAXE_RY,
   173     JOYAXE_RZ,
   174     JOYAXE_count
   175 };
   176 
   177 struct joystick_hwdata
   178 {
   179     int fd;
   180     char *path;
   181     enum
   182     {
   183         BSDJOY_UHID,            /* uhid(4) */
   184         BSDJOY_JOY              /* joy(4) */
   185     } type;
   186     struct report_desc *repdesc;
   187     struct report inreport;
   188     int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
   189 };
   190 
   191 static char *joynames[MAX_JOYS];
   192 static char *joydevnames[MAX_JOYS];
   193 
   194 static int report_alloc(struct report *, struct report_desc *, int);
   195 static void report_free(struct report *);
   196 
   197 #if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
   198 #define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
   199 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
   200 #define REP_BUF_DATA(rep) ((rep)->buf)
   201 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
   202 #define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
   203 #else
   204 #define REP_BUF_DATA(rep) ((rep)->buf->data)
   205 #endif
   206 
   207 static int numjoysticks = 0;
   208 
   209 static int BSD_JoystickOpen(SDL_Joystick * joy, int device_index);
   210 static void BSD_JoystickClose(SDL_Joystick * joy);
   211 
   212 static int
   213 BSD_JoystickInit(void)
   214 {
   215     char s[16];
   216     int i, fd;
   217 
   218     numjoysticks = 0;
   219 
   220     SDL_memset(joynames, 0, sizeof(joynames));
   221     SDL_memset(joydevnames, 0, sizeof(joydevnames));
   222 
   223     for (i = 0; i < MAX_UHID_JOYS; i++) {
   224         SDL_Joystick nj;
   225 
   226         SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
   227 
   228         joynames[numjoysticks] = SDL_strdup(s);
   229 
   230         if (BSD_JoystickOpen(&nj, numjoysticks) == 0) {
   231             BSD_JoystickClose(&nj);
   232             numjoysticks++;
   233         } else {
   234             SDL_free(joynames[numjoysticks]);
   235             joynames[numjoysticks] = NULL;
   236         }
   237     }
   238     for (i = 0; i < MAX_JOY_JOYS; i++) {
   239         SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
   240         fd = open(s, O_RDONLY);
   241         if (fd != -1) {
   242             joynames[numjoysticks++] = SDL_strdup(s);
   243             close(fd);
   244         }
   245     }
   246 
   247     /* Read the default USB HID usage table. */
   248     hid_init(NULL);
   249 
   250     return (numjoysticks);
   251 }
   252 
   253 static int
   254 BSD_JoystickGetCount(void)
   255 {
   256     return numjoysticks;
   257 }
   258 
   259 static void
   260 BSD_JoystickDetect(void)
   261 {
   262 }
   263 
   264 static const char *
   265 BSD_JoystickGetDeviceName(int device_index)
   266 {
   267     if (joydevnames[device_index] != NULL) {
   268         return (joydevnames[device_index]);
   269     }
   270     return (joynames[device_index]);
   271 }
   272 
   273 static int
   274 BSD_JoystickGetDevicePlayerIndex(int device_index)
   275 {
   276     return -1;
   277 }
   278 
   279 /* Function to perform the mapping from device index to the instance id for this index */
   280 static SDL_JoystickID
   281 BSD_JoystickGetDeviceInstanceID(int device_index)
   282 {
   283     return device_index;
   284 }
   285 
   286 static int
   287 usage_to_joyaxe(unsigned usage)
   288 {
   289     int joyaxe;
   290     switch (usage) {
   291     case HUG_X:
   292         joyaxe = JOYAXE_X;
   293         break;
   294     case HUG_Y:
   295         joyaxe = JOYAXE_Y;
   296         break;
   297     case HUG_Z:
   298         joyaxe = JOYAXE_Z;
   299         break;
   300     case HUG_SLIDER:
   301         joyaxe = JOYAXE_SLIDER;
   302         break;
   303     case HUG_WHEEL:
   304         joyaxe = JOYAXE_WHEEL;
   305         break;
   306     case HUG_RX:
   307         joyaxe = JOYAXE_RX;
   308         break;
   309     case HUG_RY:
   310         joyaxe = JOYAXE_RY;
   311         break;
   312     case HUG_RZ:
   313         joyaxe = JOYAXE_RZ;
   314         break;
   315     default:
   316         joyaxe = -1;
   317     }
   318     return joyaxe;
   319 }
   320 
   321 static unsigned
   322 hatval_to_sdl(Sint32 hatval)
   323 {
   324     static const unsigned hat_dir_map[8] = {
   325         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
   326         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
   327     };
   328     unsigned result;
   329     if ((hatval & 7) == hatval)
   330         result = hat_dir_map[hatval];
   331     else
   332         result = SDL_HAT_CENTERED;
   333     return result;
   334 }
   335 
   336 
   337 static int
   338 BSD_JoystickOpen(SDL_Joystick * joy, int device_index)
   339 {
   340     char *path = joynames[device_index];
   341     struct joystick_hwdata *hw;
   342     struct hid_item hitem;
   343     struct hid_data *hdata;
   344     struct report *rep = NULL;
   345 #if defined(__NetBSD__)
   346     usb_device_descriptor_t udd;
   347     struct usb_string_desc usd;
   348 #endif
   349     int fd;
   350     int i;
   351 
   352     fd = open(path, O_RDONLY);
   353     if (fd == -1) {
   354         return SDL_SetError("%s: %s", path, strerror(errno));
   355     }
   356 
   357     joy->instance_id = device_index;
   358     hw = (struct joystick_hwdata *)
   359         SDL_malloc(sizeof(struct joystick_hwdata));
   360     if (hw == NULL) {
   361         close(fd);
   362         return SDL_OutOfMemory();
   363     }
   364     joy->hwdata = hw;
   365     hw->fd = fd;
   366     hw->path = SDL_strdup(path);
   367     if (!SDL_strncmp(path, "/dev/joy", 8)) {
   368         hw->type = BSDJOY_JOY;
   369         joy->naxes = 2;
   370         joy->nbuttons = 2;
   371         joy->nhats = 0;
   372         joy->nballs = 0;
   373         joydevnames[device_index] = SDL_strdup("Gameport joystick");
   374         goto usbend;
   375     } else {
   376         hw->type = BSDJOY_UHID;
   377     }
   378 
   379     {
   380         int ax;
   381         for (ax = 0; ax < JOYAXE_count; ax++)
   382             hw->axis_map[ax] = -1;
   383     }
   384     hw->repdesc = hid_get_report_desc(fd);
   385     if (hw->repdesc == NULL) {
   386         SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   387                      strerror(errno));
   388         goto usberr;
   389     }
   390     rep = &hw->inreport;
   391 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
   392     rep->rid = hid_get_report_id(fd);
   393     if (rep->rid < 0) {
   394 #else
   395     if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
   396 #endif
   397         rep->rid = -1;          /* XXX */
   398     }
   399 #if defined(__NetBSD__)
   400     if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
   401         goto desc_failed;
   402 
   403     /* Get default language */
   404     usd.usd_string_index = USB_LANGUAGE_TABLE;
   405     usd.usd_language_id = 0;
   406     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
   407         usd.usd_language_id = 0;
   408     } else {
   409         usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
   410     }
   411 
   412     usd.usd_string_index = udd.iProduct;
   413     if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
   414         char str[128];
   415         char *new_name = NULL;
   416         int i;
   417         for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
   418             str[i] = UGETW(usd.usd_desc.bString[i]);
   419         }
   420         str[i] = '\0';
   421         asprintf(&new_name, "%s @ %s", str, path);
   422         if (new_name != NULL) {
   423             SDL_free(joydevnames[numjoysticks]);
   424             joydevnames[numjoysticks] = new_name;
   425         }
   426     }
   427 desc_failed:
   428 #endif
   429     if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   430         goto usberr;
   431     }
   432     if (rep->size <= 0) {
   433         SDL_SetError("%s: Input report descriptor has invalid length",
   434                      hw->path);
   435         goto usberr;
   436     }
   437 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   438     hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
   439 #else
   440     hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   441 #endif
   442     if (hdata == NULL) {
   443         SDL_SetError("%s: Cannot start HID parser", hw->path);
   444         goto usberr;
   445     }
   446     joy->naxes = 0;
   447     joy->nbuttons = 0;
   448     joy->nhats = 0;
   449     joy->nballs = 0;
   450     for (i = 0; i < JOYAXE_count; i++)
   451         hw->axis_map[i] = -1;
   452 
   453     while (hid_get_item(hdata, &hitem) > 0) {
   454         char *sp;
   455         const char *s;
   456 
   457         switch (hitem.kind) {
   458         case hid_collection:
   459             switch (HID_PAGE(hitem.usage)) {
   460             case HUP_GENERIC_DESKTOP:
   461                 switch (HID_USAGE(hitem.usage)) {
   462                 case HUG_JOYSTICK:
   463                 case HUG_GAME_PAD:
   464                     s = hid_usage_in_page(hitem.usage);
   465                     sp = SDL_malloc(SDL_strlen(s) + 5);
   466                     SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
   467                                  s, device_index);
   468                     joydevnames[device_index] = sp;
   469                 }
   470             }
   471             break;
   472         case hid_input:
   473             switch (HID_PAGE(hitem.usage)) {
   474             case HUP_GENERIC_DESKTOP:
   475                 {
   476                     unsigned usage = HID_USAGE(hitem.usage);
   477                     int joyaxe = usage_to_joyaxe(usage);
   478                     if (joyaxe >= 0) {
   479                         hw->axis_map[joyaxe] = 1;
   480                     } else if (usage == HUG_HAT_SWITCH
   481 #ifdef __OpenBSD__
   482                                || usage == HUG_DPAD_UP
   483 #endif
   484                                ) {
   485                         joy->nhats++;
   486                     }
   487                     break;
   488                 }
   489             case HUP_BUTTON:
   490                 joy->nbuttons++;
   491                 break;
   492             default:
   493                 break;
   494             }
   495             break;
   496         default:
   497             break;
   498         }
   499     }
   500     hid_end_parse(hdata);
   501     for (i = 0; i < JOYAXE_count; i++)
   502         if (hw->axis_map[i] > 0)
   503             hw->axis_map[i] = joy->naxes++;
   504 
   505     if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
   506         SDL_SetError("%s: Not a joystick, ignoring", hw->path);
   507         goto usberr;
   508     }
   509 
   510   usbend:
   511     /* The poll blocks the event thread. */
   512     fcntl(fd, F_SETFL, O_NONBLOCK);
   513 #ifdef __NetBSD__
   514     /* Flush pending events */
   515     if (rep) {
   516         while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
   517             ;
   518     }
   519 #endif
   520 
   521     return (0);
   522   usberr:
   523     close(hw->fd);
   524     SDL_free(hw->path);
   525     SDL_free(hw);
   526     return (-1);
   527 }
   528 
   529 static void
   530 BSD_JoystickUpdate(SDL_Joystick * joy)
   531 {
   532     struct hid_item hitem;
   533     struct hid_data *hdata;
   534     struct report *rep;
   535     int nbutton, naxe = -1;
   536     Sint32 v;
   537 #ifdef __OpenBSD__
   538     Sint32 dpad[4] = {0, 0, 0, 0};
   539 #endif
   540 
   541 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
   542     struct joystick gameport;
   543     static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
   544 
   545     if (joy->hwdata->type == BSDJOY_JOY) {
   546         while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
   547             if (abs(x - gameport.x) > 8) {
   548                 x = gameport.x;
   549                 if (x < xmin) {
   550                     xmin = x;
   551                 }
   552                 if (x > xmax) {
   553                     xmax = x;
   554                 }
   555                 if (xmin == xmax) {
   556                     xmin--;
   557                     xmax++;
   558                 }
   559                 v = (Sint32) x;
   560                 v -= (xmax + xmin + 1) / 2;
   561                 v *= 32768 / ((xmax - xmin + 1) / 2);
   562                 SDL_PrivateJoystickAxis(joy, 0, v);
   563             }
   564             if (abs(y - gameport.y) > 8) {
   565                 y = gameport.y;
   566                 if (y < ymin) {
   567                     ymin = y;
   568                 }
   569                 if (y > ymax) {
   570                     ymax = y;
   571                 }
   572                 if (ymin == ymax) {
   573                     ymin--;
   574                     ymax++;
   575                 }
   576                 v = (Sint32) y;
   577                 v -= (ymax + ymin + 1) / 2;
   578                 v *= 32768 / ((ymax - ymin + 1) / 2);
   579                 SDL_PrivateJoystickAxis(joy, 1, v);
   580             }
   581             SDL_PrivateJoystickButton(joy, 0, gameport.b1);
   582             SDL_PrivateJoystickButton(joy, 1, gameport.b2);
   583         }
   584         return;
   585     }
   586 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
   587 
   588     rep = &joy->hwdata->inreport;
   589 
   590     while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
   591 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
   592         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
   593 #else
   594         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   595 #endif
   596         if (hdata == NULL) {
   597             /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
   598             continue;
   599         }
   600 
   601         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
   602             switch (hitem.kind) {
   603             case hid_input:
   604                 switch (HID_PAGE(hitem.usage)) {
   605                 case HUP_GENERIC_DESKTOP:
   606                     {
   607                         unsigned usage = HID_USAGE(hitem.usage);
   608                         int joyaxe = usage_to_joyaxe(usage);
   609                         if (joyaxe >= 0) {
   610                             naxe = joy->hwdata->axis_map[joyaxe];
   611                             /* scaleaxe */
   612                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   613                             v -= (hitem.logical_maximum +
   614                                   hitem.logical_minimum + 1) / 2;
   615                             v *= 32768 /
   616                                 ((hitem.logical_maximum -
   617                                   hitem.logical_minimum + 1) / 2);
   618                             SDL_PrivateJoystickAxis(joy, naxe, v);
   619                         } else if (usage == HUG_HAT_SWITCH) {
   620                             v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   621                             SDL_PrivateJoystickHat(joy, 0,
   622                                                    hatval_to_sdl(v) -
   623                                                    hitem.logical_minimum);
   624                         }
   625 #ifdef __OpenBSD__
   626                         else if (usage == HUG_DPAD_UP)
   627                             dpad[0] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   628                         else if (usage == HUG_DPAD_DOWN)
   629                             dpad[1] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   630                         else if (usage == HUG_DPAD_RIGHT)
   631                             dpad[2] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   632                         else if (usage == HUG_DPAD_LEFT)
   633                             dpad[3] = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   634 #endif
   635                         break;
   636                     }
   637                 case HUP_BUTTON:
   638                     v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
   639                     SDL_PrivateJoystickButton(joy, nbutton, v);
   640                     nbutton++;
   641                     break;
   642                 default:
   643                     continue;
   644                 }
   645                 break;
   646             default:
   647                 break;
   648             }
   649         }
   650 #ifdef __OpenBSD__
   651         SDL_PrivateJoystickHat(joy, 0, dpad_to_sdl(dpad));
   652 #endif
   653         hid_end_parse(hdata);
   654     }
   655 }
   656 
   657 /* Function to close a joystick after use */
   658 static void
   659 BSD_JoystickClose(SDL_Joystick * joy)
   660 {
   661     if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
   662         report_free(&joy->hwdata->inreport);
   663         hid_dispose_report_desc(joy->hwdata->repdesc);
   664     }
   665     close(joy->hwdata->fd);
   666     SDL_free(joy->hwdata->path);
   667     SDL_free(joy->hwdata);
   668 }
   669 
   670 static void
   671 BSD_JoystickQuit(void)
   672 {
   673     int i;
   674 
   675     for (i = 0; i < MAX_JOYS; i++) {
   676         SDL_free(joynames[i]);
   677         SDL_free(joydevnames[i]);
   678     }
   679 
   680     return;
   681 }
   682 
   683 static SDL_JoystickGUID
   684 BSD_JoystickGetDeviceGUID( int device_index )
   685 {
   686     SDL_JoystickGUID guid;
   687     /* the GUID is just the first 16 chars of the name for now */
   688     const char *name = BSD_JoystickGetDeviceName( device_index );
   689     SDL_zero( guid );
   690     SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
   691     return guid;
   692 }
   693 
   694 static int
   695 report_alloc(struct report *r, struct report_desc *rd, int repind)
   696 {
   697     int len;
   698 
   699 #ifdef __DragonFly__
   700     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   701 #elif __FREEBSD__
   702 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
   703 #  if (__FreeBSD_kernel_version <= 500111)
   704     len = hid_report_size(rd, r->rid, repinfo[repind].kind);
   705 #  else
   706     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   707 #  endif
   708 # else
   709     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   710 # endif
   711 #else
   712 # ifdef USBHID_NEW
   713     len = hid_report_size(rd, repinfo[repind].kind, r->rid);
   714 # else
   715     len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   716 # endif
   717 #endif
   718 
   719     if (len < 0) {
   720         return SDL_SetError("Negative HID report size");
   721     }
   722     r->size = len;
   723 
   724     if (r->size > 0) {
   725 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
   726         r->buf = SDL_malloc(r->size);
   727 #else
   728         r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
   729                             r->size);
   730 #endif
   731         if (r->buf == NULL) {
   732             return SDL_OutOfMemory();
   733         }
   734     } else {
   735         r->buf = NULL;
   736     }
   737 
   738     r->status = SREPORT_CLEAN;
   739     return 0;
   740 }
   741 
   742 static void
   743 report_free(struct report *r)
   744 {
   745     SDL_free(r->buf);
   746     r->status = SREPORT_UNINIT;
   747 }
   748 
   749 static int
   750 BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   751 {
   752     return SDL_Unsupported();
   753 }
   754 
   755 SDL_JoystickDriver SDL_BSD_JoystickDriver =
   756 {
   757     BSD_JoystickInit,
   758     BSD_JoystickGetCount,
   759     BSD_JoystickDetect,
   760     BSD_JoystickGetDeviceName,
   761     BSD_JoystickGetDevicePlayerIndex,
   762     BSD_JoystickGetDeviceGUID,
   763     BSD_JoystickGetDeviceInstanceID,
   764     BSD_JoystickOpen,
   765     BSD_JoystickRumble,
   766     BSD_JoystickUpdate,
   767     BSD_JoystickClose,
   768     BSD_JoystickQuit,
   769 };
   770 
   771 #endif /* SDL_JOYSTICK_USBHID */
   772 
   773 /* vi: set ts=4 sw=4 expandtab: */