summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c')
-rw-r--r--apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c608
1 files changed, 0 insertions, 608 deletions
diff --git a/apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c b/apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c
deleted file mode 100644
index 500fc62951..0000000000
--- a/apps/plugins/sdl/src/joystick/bsd/SDL_sysjoystick.c
+++ /dev/null
@@ -1,608 +0,0 @@
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
84struct 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
99static 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
109enum {
110 REPORT_INPUT = 0,
111 REPORT_OUTPUT = 1,
112 REPORT_FEATURE = 2
113};
114
115enum {
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
127struct 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
145static char *joynames[MAX_JOYS];
146static char *joydevnames[MAX_JOYS];
147
148static int report_alloc(struct report *, struct report_desc *, int);
149static 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
159int
160SDL_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
201const char *
202SDL_SYS_JoystickName(int index)
203{
204 if (joydevnames[index] != NULL) {
205 return (joydevnames[index]);
206 }
207 return (joynames[index]);
208}
209
210static int
211usage_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
237static unsigned
238hatval_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
253int
254SDL_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
389usbend:
390 /* The poll blocks the event thread. */
391 fcntl(fd, F_SETFL, O_NONBLOCK);
392
393 return (0);
394usberr:
395 close(hw->fd);
396 SDL_free(hw->path);
397 SDL_free(hw);
398 return (-1);
399}
400
401void
402SDL_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 */
524void
525SDL_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
538void
539SDL_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
553static int
554report_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
599static void
600report_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 */