Imported Upstream version 1.2.15
[platform/upstream/SDL.git] / src / joystick / bsd / SDL_sysjoystick.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #ifdef SDL_JOYSTICK_USBHID
25
26 /*
27  * Joystick driver for the uhid(4) interface found in OpenBSD,
28  * NetBSD and FreeBSD.
29  *
30  * Maintainer: <vedge at csoft.org>
31  */
32
33 #include <sys/param.h>
34
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38
39 #ifndef __FreeBSD_kernel_version
40 #define __FreeBSD_kernel_version __FreeBSD_version
41 #endif
42
43 #if defined(HAVE_USB_H)
44 #include <usb.h>
45 #endif
46 #ifdef __DragonFly__
47 #include <bus/usb/usb.h>
48 #include <bus/usb/usbhid.h>
49 #else
50 #include <dev/usb/usb.h>
51 #include <dev/usb/usbhid.h>
52 #endif
53
54 #if defined(HAVE_USBHID_H)
55 #include <usbhid.h>
56 #elif defined(HAVE_LIBUSB_H)
57 #include <libusb.h>
58 #elif defined(HAVE_LIBUSBHID_H)
59 #include <libusbhid.h>
60 #endif
61
62 #if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
63 #ifndef __DragonFly__
64 #include <osreldate.h>
65 #endif
66 #if __FreeBSD_kernel_version > 800063
67 #include <dev/usb/usb_ioctl.h>
68 #endif
69 #include <sys/joystick.h>
70 #endif
71
72 #if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
73 #include <machine/joystick.h>
74 #endif
75
76 #include "SDL_joystick.h"
77 #include "../SDL_sysjoystick.h"
78 #include "../SDL_joystick_c.h"
79
80 #define MAX_UHID_JOYS   4
81 #define MAX_JOY_JOYS    2
82 #define MAX_JOYS        (MAX_UHID_JOYS + MAX_JOY_JOYS)
83
84 struct report {
85 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
86         struct  usb_gen_descriptor *buf;        /* Buffer */
87 #else
88         struct  usb_ctl_report *buf;    /* Buffer */
89 #endif
90         size_t  size;                   /* Buffer size */
91         int     rid;                    /* Report ID */
92         enum {
93                 SREPORT_UNINIT,
94                 SREPORT_CLEAN,
95                 SREPORT_DIRTY
96         } status;
97 };
98
99 static struct {
100         int     uhid_report;
101         hid_kind_t kind;
102         const   char *name;
103 } const repinfo[] = {
104         { UHID_INPUT_REPORT,    hid_input,      "input" },
105         { UHID_OUTPUT_REPORT,   hid_output,     "output" },
106         { UHID_FEATURE_REPORT,  hid_feature,    "feature" }
107 };
108
109 enum {
110         REPORT_INPUT = 0,
111         REPORT_OUTPUT = 1,
112         REPORT_FEATURE = 2
113 };
114
115 enum {
116         JOYAXE_X,
117         JOYAXE_Y,
118         JOYAXE_Z,
119         JOYAXE_SLIDER,
120         JOYAXE_WHEEL,
121         JOYAXE_RX,
122         JOYAXE_RY,
123         JOYAXE_RZ,
124         JOYAXE_count
125 };
126
127 struct joystick_hwdata {
128         int     fd;
129         char    *path;
130         enum {
131                 BSDJOY_UHID,    /* uhid(4) */
132                 BSDJOY_JOY      /* joy(4) */
133         } type;
134         struct  report_desc *repdesc;
135         struct  report inreport;
136         int     axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,..*/
137         int     x;
138         int     y;
139         int     xmin;
140         int     ymin;
141         int     xmax;
142         int     ymax;
143 };
144
145 static char *joynames[MAX_JOYS];
146 static char *joydevnames[MAX_JOYS];
147
148 static int      report_alloc(struct report *, struct report_desc *, int);
149 static void     report_free(struct report *);
150
151 #if defined(USBHID_UCR_DATA) || defined(__FreeBSD_kernel__)
152 #define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
153 #elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
154 #define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
155 #else
156 #define REP_BUF_DATA(rep) ((rep)->buf->data)
157 #endif
158
159 int
160 SDL_SYS_JoystickInit(void)
161 {
162         char s[16];
163         int i, fd;
164
165         SDL_numjoysticks = 0;
166
167         SDL_memset(joynames, 0, sizeof(joynames));
168         SDL_memset(joydevnames, 0, sizeof(joydevnames));
169
170         for (i = 0; i < MAX_UHID_JOYS; i++) {
171                 SDL_Joystick nj;
172
173                 SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
174
175                 nj.index = SDL_numjoysticks;
176                 joynames[nj.index] = strdup(s);
177
178                 if (SDL_SYS_JoystickOpen(&nj) == 0) {
179                         SDL_SYS_JoystickClose(&nj);
180                         SDL_numjoysticks++;
181                 } else {
182                         SDL_free(joynames[nj.index]);
183                         joynames[nj.index] = NULL;
184                 }
185         }
186         for (i = 0; i < MAX_JOY_JOYS; i++) {
187                 SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
188                 fd = open(s, O_RDONLY);
189                 if (fd != -1) {
190                         joynames[SDL_numjoysticks++] = strdup(s);
191                         close(fd);
192                 }
193         }
194
195         /* Read the default USB HID usage table. */
196         hid_init(NULL);
197
198         return (SDL_numjoysticks);
199 }
200
201 const char *
202 SDL_SYS_JoystickName(int index)
203 {
204         if (joydevnames[index] != NULL) {
205                 return (joydevnames[index]);
206         }
207         return (joynames[index]);
208 }
209
210 static int
211 usage_to_joyaxe(unsigned usage)
212 {
213     int joyaxe;
214     switch (usage) {
215     case HUG_X:
216         joyaxe = JOYAXE_X; break;
217     case HUG_Y:
218         joyaxe = JOYAXE_Y; break;
219     case HUG_Z:
220         joyaxe = JOYAXE_Z; break;
221     case HUG_SLIDER:
222         joyaxe = JOYAXE_SLIDER; break;
223     case HUG_WHEEL:
224         joyaxe = JOYAXE_WHEEL; break;
225     case HUG_RX:
226         joyaxe = JOYAXE_RX; break;
227     case HUG_RY:
228         joyaxe = JOYAXE_RY; break;
229     case HUG_RZ:
230         joyaxe = JOYAXE_RZ; break;
231     default:
232         joyaxe = -1;
233     }
234     return joyaxe;    
235 }
236
237 static unsigned
238 hatval_to_sdl(Sint32 hatval)
239 {
240     static const unsigned hat_dir_map[8] = {
241         SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, 
242         SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
243     };
244     unsigned result;
245     if ((hatval & 7) == hatval) 
246         result = hat_dir_map[hatval];
247     else 
248         result = SDL_HAT_CENTERED;
249     return result;
250 }
251
252
253 int
254 SDL_SYS_JoystickOpen(SDL_Joystick *joy)
255 {
256         char *path = joynames[joy->index];
257         struct joystick_hwdata *hw;
258         struct hid_item hitem;
259         struct hid_data *hdata;
260         struct report *rep;
261         int fd;
262         int i;
263
264         fd = open(path, O_RDONLY);
265         if (fd == -1) {
266                 SDL_SetError("%s: %s", path, strerror(errno));
267                 return (-1);
268         }
269
270         hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata));
271         if (hw == NULL) {
272                 SDL_OutOfMemory();
273                 close(fd);
274                 return (-1);
275         }
276         joy->hwdata = hw;
277         hw->fd = fd;
278         hw->path = strdup(path);
279         hw->x = 0;
280         hw->y = 0;
281         hw->xmin = 0xffff;
282         hw->ymin = 0xffff;
283         hw->xmax = 0;
284         hw->ymax = 0;
285         if (! SDL_strncmp(path, "/dev/joy", 8)) {
286                 hw->type = BSDJOY_JOY;
287                 joy->naxes = 2;
288                 joy->nbuttons = 2;
289                 joy->nhats = 0;
290                 joy->nballs = 0;
291                 joydevnames[joy->index] = strdup("Gameport joystick");
292                 goto usbend;
293         } else {
294                 hw->type = BSDJOY_UHID;
295         }
296
297         {
298             int ax;
299             for (ax = 0; ax < JOYAXE_count; ax++)
300                 hw->axis_map[ax] = -1;
301         }
302         hw->repdesc = hid_get_report_desc(fd);
303         if (hw->repdesc == NULL) {
304                 SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
305                     strerror(errno));
306                 goto usberr;
307         }
308         rep = &hw->inreport;
309 #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
310        rep->rid = hid_get_report_id(fd);
311        if (rep->rid < 0) {
312 #else
313         if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
314 #endif
315                 rep->rid = -1; /* XXX */
316         }
317         if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
318                 goto usberr;
319         }
320         if (rep->size <= 0) {
321                 SDL_SetError("%s: Input report descriptor has invalid length",
322                     hw->path);
323                 goto usberr;
324         }
325
326 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
327         hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
328 #else
329         hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
330 #endif
331         if (hdata == NULL) {
332                 SDL_SetError("%s: Cannot start HID parser", hw->path);
333                 goto usberr;
334         }
335         joy->naxes = 0;
336         joy->nbuttons = 0;
337         joy->nhats = 0;
338         joy->nballs = 0;
339         for (i=0; i<JOYAXE_count; i++)
340                 hw->axis_map[i] = -1;
341
342         while (hid_get_item(hdata, &hitem) > 0) {
343                 char *sp;
344                 const char *s;
345
346                 switch (hitem.kind) {
347                 case hid_collection:
348                         switch (HID_PAGE(hitem.usage)) {
349                         case HUP_GENERIC_DESKTOP:
350                                 switch (HID_USAGE(hitem.usage)) {
351                                 case HUG_JOYSTICK:
352                                 case HUG_GAME_PAD:
353                                         s = hid_usage_in_page(hitem.usage);
354                                         sp = SDL_malloc(SDL_strlen(s) + 5);
355                                         SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s,
356                                             joy->index);
357                                         joydevnames[joy->index] = sp;
358                                 }
359                         }
360                         break;
361                 case hid_input:
362                         switch (HID_PAGE(hitem.usage)) {
363                         case HUP_GENERIC_DESKTOP: {
364                             unsigned usage = HID_USAGE(hitem.usage);
365                             int joyaxe = usage_to_joyaxe(usage);
366                             if (joyaxe >= 0) {
367                                 hw->axis_map[joyaxe] = 1;
368                             } else if (usage == HUG_HAT_SWITCH) {
369                                 joy->nhats++;
370                             }
371                             break;
372                         }
373                         case HUP_BUTTON:
374                                 joy->nbuttons++;
375                                 break;
376                         default:
377                                 break;
378                         }
379                         break;
380                 default:
381                         break;
382                 }
383         }
384         hid_end_parse(hdata);
385         for (i=0; i<JOYAXE_count; i++)
386                 if (hw->axis_map[i] > 0)
387                         hw->axis_map[i] = joy->naxes++;
388
389 usbend:
390         /* The poll blocks the event thread. */
391         fcntl(fd, F_SETFL, O_NONBLOCK);
392
393         return (0);
394 usberr:
395         close(hw->fd);
396         SDL_free(hw->path);
397         SDL_free(hw);
398         return (-1);
399 }
400
401 void
402 SDL_SYS_JoystickUpdate(SDL_Joystick *joy)
403 {
404         struct hid_item hitem;
405         struct hid_data *hdata;
406         struct report *rep;
407         int nbutton, naxe = -1;
408         Sint32 v;
409
410 #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
411         struct joystick gameport;
412  
413         if (joy->hwdata->type == BSDJOY_JOY) {
414                 if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport)
415                         return;
416                 if (abs(joy->hwdata->x - gameport.x) > 8) {
417                         joy->hwdata->x = gameport.x;
418                         if (joy->hwdata->x < joy->hwdata->xmin) {
419                                 joy->hwdata->xmin = joy->hwdata->x;
420                         }
421                         if (joy->hwdata->x > joy->hwdata->xmax) {
422                                 joy->hwdata->xmax = joy->hwdata->x;
423                         }
424                         if (joy->hwdata->xmin == joy->hwdata->xmax) {
425                                 joy->hwdata->xmin--;
426                                 joy->hwdata->xmax++;
427                         }
428                         v = (Sint32)joy->hwdata->x;
429                         v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2;
430                         v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2);
431                         SDL_PrivateJoystickAxis(joy, 0, v);
432                 }
433                 if (abs(joy->hwdata->y - gameport.y) > 8) {
434                         joy->hwdata->y = gameport.y;
435                         if (joy->hwdata->y < joy->hwdata->ymin) {
436                                 joy->hwdata->ymin = joy->hwdata->y;
437                         }
438                         if (joy->hwdata->y > joy->hwdata->ymax) {
439                                 joy->hwdata->ymax = joy->hwdata->y;
440                         }
441                         if (joy->hwdata->ymin == joy->hwdata->ymax) {
442                                 joy->hwdata->ymin--;
443                                 joy->hwdata->ymax++;
444                         }
445                         v = (Sint32)joy->hwdata->y;
446                         v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2;
447                         v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2);
448                         SDL_PrivateJoystickAxis(joy, 1, v);
449                 }
450                 if (gameport.b1 != joy->buttons[0]) {
451                         SDL_PrivateJoystickButton(joy, 0, gameport.b1);
452                 }
453                 if (gameport.b2 != joy->buttons[1]) {
454                         SDL_PrivateJoystickButton(joy, 1, gameport.b2);
455                 }
456                 return;
457         }
458 #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
459         
460         rep = &joy->hwdata->inreport;
461
462         if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) {
463                 return;
464         }
465 #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
466         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
467 #else
468         hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
469 #endif
470         if (hdata == NULL) {
471                 fprintf(stderr, "%s: Cannot start HID parser\n",
472                     joy->hwdata->path);
473                 return;
474         }
475
476         for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
477                 switch (hitem.kind) {
478                 case hid_input:
479                         switch (HID_PAGE(hitem.usage)) {
480                         case HUP_GENERIC_DESKTOP: {
481                             unsigned usage = HID_USAGE(hitem.usage);
482                             int joyaxe = usage_to_joyaxe(usage);
483                             if (joyaxe >= 0) {
484                                 naxe = joy->hwdata->axis_map[joyaxe];
485                                 /* scaleaxe */
486                                 v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
487                                                          &hitem);
488                                 v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2;
489                                 v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2);
490                                 if (v != joy->axes[naxe]) {
491                                     SDL_PrivateJoystickAxis(joy, naxe, v);
492                                 }
493                             } else if (usage == HUG_HAT_SWITCH) {
494                                 v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
495                                                          &hitem);
496                                 SDL_PrivateJoystickHat(joy, 0,
497                                         hatval_to_sdl(v)-hitem.logical_minimum);
498                             }
499                             break;
500                         }
501                         case HUP_BUTTON:
502                                 v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
503                                     &hitem);
504                                 if (joy->buttons[nbutton] != v) {
505                                         SDL_PrivateJoystickButton(joy,
506                                             nbutton, v);
507                                 }
508                                 nbutton++;
509                                 break;
510                         default:
511                                 continue;
512                         }
513                         break;
514                 default:
515                         break;
516                 }
517         }
518         hid_end_parse(hdata);
519
520         return;
521 }
522
523 /* Function to close a joystick after use */
524 void
525 SDL_SYS_JoystickClose(SDL_Joystick *joy)
526 {
527         if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8))      {
528                 report_free(&joy->hwdata->inreport);
529                 hid_dispose_report_desc(joy->hwdata->repdesc);
530         }
531         close(joy->hwdata->fd);
532         SDL_free(joy->hwdata->path);
533         SDL_free(joy->hwdata);
534
535         return;
536 }
537
538 void
539 SDL_SYS_JoystickQuit(void)
540 {
541         int i;
542
543         for (i = 0; i < MAX_JOYS; i++) {
544                 if (joynames[i] != NULL)
545                         SDL_free(joynames[i]);
546                 if (joydevnames[i] != NULL)
547                         SDL_free(joydevnames[i]);
548         }
549
550         return;
551 }
552
553 static int
554 report_alloc(struct report *r, struct report_desc *rd, int repind)
555 {
556         int len;
557
558 #ifdef __DragonFly__
559         len = hid_report_size(rd, r->rid, repinfo[repind].kind);
560 #elif __FREEBSD__
561 # if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
562 #  if (__FreeBSD_kernel_version <= 500111)
563         len = hid_report_size(rd, r->rid, repinfo[repind].kind);
564 #  else
565         len = hid_report_size(rd, repinfo[repind].kind, r->rid);
566 #  endif
567 # else
568         len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
569 # endif
570 #else
571 # ifdef USBHID_NEW
572         len = hid_report_size(rd, repinfo[repind].kind, r->rid);
573 # else
574         len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
575 # endif
576 #endif
577
578         if (len < 0) {
579                 SDL_SetError("Negative HID report size");
580                 return (-1);
581         }
582         r->size = len;
583
584         if (r->size > 0) {
585                 r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
586                     r->size);
587                 if (r->buf == NULL) {
588                         SDL_OutOfMemory();
589                         return (-1);
590                 }
591         } else {
592                 r->buf = NULL;
593         }
594
595         r->status = SREPORT_CLEAN;
596         return (0);
597 }
598
599 static void
600 report_free(struct report *r)
601 {
602         if (r->buf != NULL) {
603                 SDL_free(r->buf);
604         }
605         r->status = SREPORT_UNINIT;
606 }
607
608 #endif /* SDL_JOYSTICK_USBHID */