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