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_LINUX
24
25 #ifndef SDL_INPUT_LINUXEV
26 #error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
27 #endif
28
29 /* This is the Linux implementation of the SDL joystick API */
30
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 #include <limits.h> /* For the definition of PATH_MAX */
36 #include <linux/joystick.h>
37
38 #include "SDL_assert.h"
39 #include "SDL_joystick.h"
40 #include "SDL_endian.h"
41 #include "../SDL_sysjoystick.h"
42 #include "../SDL_joystick_c.h"
43 #include "SDL_sysjoystick_c.h"
44
45 /* This isn't defined in older Linux kernel headers */
46 #ifndef SYN_DROPPED
47 #define SYN_DROPPED 3
48 #endif
49
50 #include "../../core/linux/SDL_udev.h"
51
52 static int MaybeAddDevice(const char *path);
53 #if SDL_USE_LIBUDEV
54 static int MaybeRemoveDevice(const char *path);
55 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
56 #endif /* SDL_USE_LIBUDEV */
57
58
59 /* A linked list of available joysticks */
60 typedef struct SDL_joylist_item
61 {
62 int device_instance;
63 char *path; /* "/dev/input/event2" or whatever */
64 char *name; /* "SideWinder 3D Pro" or whatever */
65 SDL_JoystickGUID guid;
66 dev_t devnum;
67 struct joystick_hwdata *hwdata;
68 struct SDL_joylist_item *next;
69 } SDL_joylist_item;
70
71 static SDL_joylist_item *SDL_joylist = NULL;
72 static SDL_joylist_item *SDL_joylist_tail = NULL;
73 static int numjoysticks = 0;
74 static int instance_counter = 0;
75
76 #define test_bit(nr, addr) \
77 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
78 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
79
80 static int
IsJoystick(int fd,char * namebuf,const size_t namebuflen,SDL_JoystickGUID * guid)81 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
82 {
83 struct input_id inpid;
84 Uint16 *guid16 = (Uint16 *) ((char *) &guid->data);
85
86 #if !SDL_USE_LIBUDEV
87 /* When udev is enabled we only get joystick devices here, so there's no need to test them */
88 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
89 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
90 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
91
92 if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
93 (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
94 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
95 return (0);
96 }
97
98 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
99 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
100 return 0;
101 }
102 #endif
103
104 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
105 return 0;
106 }
107
108 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
109 return 0;
110 }
111
112 #ifdef DEBUG_JOYSTICK
113 printf("Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
114 #endif
115
116 SDL_memset(guid->data, 0, sizeof(guid->data));
117
118 /* We only need 16 bits for each of these; space them out to fill 128. */
119 /* Byteswap so devices get same GUID on little/big endian platforms. */
120 *(guid16++) = SDL_SwapLE16(inpid.bustype);
121 *(guid16++) = 0;
122
123 if (inpid.vendor && inpid.product && inpid.version) {
124 *(guid16++) = SDL_SwapLE16(inpid.vendor);
125 *(guid16++) = 0;
126 *(guid16++) = SDL_SwapLE16(inpid.product);
127 *(guid16++) = 0;
128 *(guid16++) = SDL_SwapLE16(inpid.version);
129 *(guid16++) = 0;
130 } else {
131 SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
132 }
133
134 return 1;
135 }
136
137 #if SDL_USE_LIBUDEV
joystick_udev_callback(SDL_UDEV_deviceevent udev_type,int udev_class,const char * devpath)138 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
139 {
140 if (devpath == NULL) {
141 return;
142 }
143
144 switch (udev_type) {
145 case SDL_UDEV_DEVICEADDED:
146 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
147 return;
148 }
149 MaybeAddDevice(devpath);
150 break;
151
152 case SDL_UDEV_DEVICEREMOVED:
153 MaybeRemoveDevice(devpath);
154 break;
155
156 default:
157 break;
158 }
159
160 }
161 #endif /* SDL_USE_LIBUDEV */
162
163
164 /* !!! FIXME: I would love to dump this code and use libudev instead. */
165 static int
MaybeAddDevice(const char * path)166 MaybeAddDevice(const char *path)
167 {
168 struct stat sb;
169 int fd = -1;
170 int isstick = 0;
171 char namebuf[128];
172 SDL_JoystickGUID guid;
173 SDL_joylist_item *item;
174
175 if (path == NULL) {
176 return -1;
177 }
178
179 if (stat(path, &sb) == -1) {
180 return -1;
181 }
182
183 /* Check to make sure it's not already in list. */
184 for (item = SDL_joylist; item != NULL; item = item->next) {
185 if (sb.st_rdev == item->devnum) {
186 return -1; /* already have this one */
187 }
188 }
189
190 fd = open(path, O_RDONLY, 0);
191 if (fd < 0) {
192 return -1;
193 }
194
195 #ifdef DEBUG_INPUT_EVENTS
196 printf("Checking %s\n", path);
197 #endif
198
199 isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
200 close(fd);
201 if (!isstick) {
202 return -1;
203 }
204
205 item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
206 if (item == NULL) {
207 return -1;
208 }
209
210 SDL_zerop(item);
211 item->devnum = sb.st_rdev;
212 item->path = SDL_strdup(path);
213 item->name = SDL_strdup(namebuf);
214 item->guid = guid;
215
216 if ( (item->path == NULL) || (item->name == NULL) ) {
217 SDL_free(item->path);
218 SDL_free(item->name);
219 SDL_free(item);
220 return -1;
221 }
222
223 item->device_instance = instance_counter++;
224 if (SDL_joylist_tail == NULL) {
225 SDL_joylist = SDL_joylist_tail = item;
226 } else {
227 SDL_joylist_tail->next = item;
228 SDL_joylist_tail = item;
229 }
230
231 /* Need to increment the joystick count before we post the event */
232 ++numjoysticks;
233
234 SDL_PrivateJoystickAdded(numjoysticks - 1);
235
236 return numjoysticks;
237 }
238
239 #if SDL_USE_LIBUDEV
240 /* !!! FIXME: I would love to dump this code and use libudev instead. */
241 static int
MaybeRemoveDevice(const char * path)242 MaybeRemoveDevice(const char *path)
243 {
244 SDL_joylist_item *item;
245 SDL_joylist_item *prev = NULL;
246
247 if (path == NULL) {
248 return -1;
249 }
250
251 for (item = SDL_joylist; item != NULL; item = item->next) {
252 /* found it, remove it. */
253 if (SDL_strcmp(path, item->path) == 0) {
254 const int retval = item->device_instance;
255 if (item->hwdata) {
256 item->hwdata->item = NULL;
257 }
258 if (prev != NULL) {
259 prev->next = item->next;
260 } else {
261 SDL_assert(SDL_joylist == item);
262 SDL_joylist = item->next;
263 }
264 if (item == SDL_joylist_tail) {
265 SDL_joylist_tail = prev;
266 }
267
268 /* Need to decrement the joystick count before we post the event */
269 --numjoysticks;
270
271 SDL_PrivateJoystickRemoved(item->device_instance);
272
273 SDL_free(item->path);
274 SDL_free(item->name);
275 SDL_free(item);
276 return retval;
277 }
278 prev = item;
279 }
280
281 return -1;
282 }
283 #endif
284
285 static int
JoystickInitWithoutUdev(void)286 JoystickInitWithoutUdev(void)
287 {
288 int i;
289 char path[PATH_MAX];
290
291 /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
292 /* !!! FIXME: we could at least readdir() through /dev/input...? */
293 /* !!! FIXME: (or delete this and rely on libudev?) */
294 for (i = 0; i < 32; i++) {
295 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
296 MaybeAddDevice(path);
297 }
298
299 return numjoysticks;
300 }
301
302
303 #if SDL_USE_LIBUDEV
304 static int
JoystickInitWithUdev(void)305 JoystickInitWithUdev(void)
306 {
307 if (SDL_UDEV_Init() < 0) {
308 return SDL_SetError("Could not initialize UDEV");
309 }
310
311 /* Set up the udev callback */
312 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
313 SDL_UDEV_Quit();
314 return SDL_SetError("Could not set up joystick <-> udev callback");
315 }
316
317 /* Force a scan to build the initial device list */
318 SDL_UDEV_Scan();
319
320 return numjoysticks;
321 }
322 #endif
323
324 int
SDL_SYS_JoystickInit(void)325 SDL_SYS_JoystickInit(void)
326 {
327 /* First see if the user specified one or more joysticks to use */
328 if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
329 char *envcopy, *envpath, *delim;
330 envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
331 envpath = envcopy;
332 while (envpath != NULL) {
333 delim = SDL_strchr(envpath, ':');
334 if (delim != NULL) {
335 *delim++ = '\0';
336 }
337 MaybeAddDevice(envpath);
338 envpath = delim;
339 }
340 SDL_free(envcopy);
341 }
342
343 #if SDL_USE_LIBUDEV
344 return JoystickInitWithUdev();
345 #endif
346
347 return JoystickInitWithoutUdev();
348 }
349
SDL_SYS_NumJoysticks()350 int SDL_SYS_NumJoysticks()
351 {
352 return numjoysticks;
353 }
354
SDL_SYS_JoystickDetect()355 void SDL_SYS_JoystickDetect()
356 {
357 #if SDL_USE_LIBUDEV
358 SDL_UDEV_Poll();
359 #endif
360
361 }
362
363 static SDL_joylist_item *
JoystickByDevIndex(int device_index)364 JoystickByDevIndex(int device_index)
365 {
366 SDL_joylist_item *item = SDL_joylist;
367
368 if ((device_index < 0) || (device_index >= numjoysticks)) {
369 return NULL;
370 }
371
372 while (device_index > 0) {
373 SDL_assert(item != NULL);
374 device_index--;
375 item = item->next;
376 }
377
378 return item;
379 }
380
381 /* Function to get the device-dependent name of a joystick */
382 const char *
SDL_SYS_JoystickNameForDeviceIndex(int device_index)383 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
384 {
385 return JoystickByDevIndex(device_index)->name;
386 }
387
388 /* Function to perform the mapping from device index to the instance id for this index */
SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)389 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
390 {
391 return JoystickByDevIndex(device_index)->device_instance;
392 }
393
394 static int
allocate_hatdata(SDL_Joystick * joystick)395 allocate_hatdata(SDL_Joystick * joystick)
396 {
397 int i;
398
399 joystick->hwdata->hats =
400 (struct hwdata_hat *) SDL_malloc(joystick->nhats *
401 sizeof(struct hwdata_hat));
402 if (joystick->hwdata->hats == NULL) {
403 return (-1);
404 }
405 for (i = 0; i < joystick->nhats; ++i) {
406 joystick->hwdata->hats[i].axis[0] = 1;
407 joystick->hwdata->hats[i].axis[1] = 1;
408 }
409 return (0);
410 }
411
412 static int
allocate_balldata(SDL_Joystick * joystick)413 allocate_balldata(SDL_Joystick * joystick)
414 {
415 int i;
416
417 joystick->hwdata->balls =
418 (struct hwdata_ball *) SDL_malloc(joystick->nballs *
419 sizeof(struct hwdata_ball));
420 if (joystick->hwdata->balls == NULL) {
421 return (-1);
422 }
423 for (i = 0; i < joystick->nballs; ++i) {
424 joystick->hwdata->balls[i].axis[0] = 0;
425 joystick->hwdata->balls[i].axis[1] = 0;
426 }
427 return (0);
428 }
429
430 static void
ConfigJoystick(SDL_Joystick * joystick,int fd)431 ConfigJoystick(SDL_Joystick * joystick, int fd)
432 {
433 int i, t;
434 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
435 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
436 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
437
438 /* See if this device uses the new unified event API */
439 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
440 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
441 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
442
443 /* Get the number of buttons, axes, and other thingamajigs */
444 for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
445 if (test_bit(i, keybit)) {
446 #ifdef DEBUG_INPUT_EVENTS
447 printf("Joystick has button: 0x%x\n", i);
448 #endif
449 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
450 ++joystick->nbuttons;
451 }
452 }
453 for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
454 if (test_bit(i, keybit)) {
455 #ifdef DEBUG_INPUT_EVENTS
456 printf("Joystick has button: 0x%x\n", i);
457 #endif
458 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
459 ++joystick->nbuttons;
460 }
461 }
462 for (i = 0; i < ABS_MAX; ++i) {
463 /* Skip hats */
464 if (i == ABS_HAT0X) {
465 i = ABS_HAT3Y;
466 continue;
467 }
468 if (test_bit(i, absbit)) {
469 struct input_absinfo absinfo;
470
471 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
472 continue;
473 }
474 #ifdef DEBUG_INPUT_EVENTS
475 printf("Joystick has absolute axis: 0x%.2x\n", i);
476 printf("Values = { %d, %d, %d, %d, %d }\n",
477 absinfo.value, absinfo.minimum, absinfo.maximum,
478 absinfo.fuzz, absinfo.flat);
479 #endif /* DEBUG_INPUT_EVENTS */
480 joystick->hwdata->abs_map[i] = joystick->naxes;
481 if (absinfo.minimum == absinfo.maximum) {
482 joystick->hwdata->abs_correct[i].used = 0;
483 } else {
484 joystick->hwdata->abs_correct[i].used = 1;
485 joystick->hwdata->abs_correct[i].coef[0] =
486 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
487 joystick->hwdata->abs_correct[i].coef[1] =
488 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
489 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
490 if (t != 0) {
491 joystick->hwdata->abs_correct[i].coef[2] =
492 (1 << 28) / t;
493 } else {
494 joystick->hwdata->abs_correct[i].coef[2] = 0;
495 }
496 }
497 ++joystick->naxes;
498 }
499 }
500 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
501 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
502 struct input_absinfo absinfo;
503
504 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
505 continue;
506 }
507 #ifdef DEBUG_INPUT_EVENTS
508 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
509 printf("Values = { %d, %d, %d, %d, %d }\n",
510 absinfo.value, absinfo.minimum, absinfo.maximum,
511 absinfo.fuzz, absinfo.flat);
512 #endif /* DEBUG_INPUT_EVENTS */
513 ++joystick->nhats;
514 }
515 }
516 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
517 ++joystick->nballs;
518 }
519
520 /* Allocate data to keep track of these thingamajigs */
521 if (joystick->nhats > 0) {
522 if (allocate_hatdata(joystick) < 0) {
523 joystick->nhats = 0;
524 }
525 }
526 if (joystick->nballs > 0) {
527 if (allocate_balldata(joystick) < 0) {
528 joystick->nballs = 0;
529 }
530 }
531 }
532 }
533
534
535 /* Function to open a joystick for use.
536 The joystick to open is specified by the device index.
537 This should fill the nbuttons and naxes fields of the joystick structure.
538 It returns 0, or -1 if there is an error.
539 */
540 int
SDL_SYS_JoystickOpen(SDL_Joystick * joystick,int device_index)541 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
542 {
543 SDL_joylist_item *item = JoystickByDevIndex(device_index);
544 char *fname = NULL;
545 int fd = -1;
546
547 if (item == NULL) {
548 return SDL_SetError("No such device");
549 }
550
551 fname = item->path;
552 fd = open(fname, O_RDONLY, 0);
553 if (fd < 0) {
554 return SDL_SetError("Unable to open %s", fname);
555 }
556
557 joystick->instance_id = item->device_instance;
558 joystick->hwdata = (struct joystick_hwdata *)
559 SDL_malloc(sizeof(*joystick->hwdata));
560 if (joystick->hwdata == NULL) {
561 close(fd);
562 return SDL_OutOfMemory();
563 }
564 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
565 joystick->hwdata->item = item;
566 joystick->hwdata->guid = item->guid;
567 joystick->hwdata->fd = fd;
568 joystick->hwdata->fname = SDL_strdup(item->path);
569 if (joystick->hwdata->fname == NULL) {
570 SDL_free(joystick->hwdata);
571 joystick->hwdata = NULL;
572 close(fd);
573 return SDL_OutOfMemory();
574 }
575
576 SDL_assert(item->hwdata == NULL);
577 item->hwdata = joystick->hwdata;
578
579 /* Set the joystick to non-blocking read mode */
580 fcntl(fd, F_SETFL, O_NONBLOCK);
581
582 /* Get the number of buttons and axes on the joystick */
583 ConfigJoystick(joystick, fd);
584
585 /* mark joystick as fresh and ready */
586 joystick->hwdata->fresh = 1;
587
588 return (0);
589 }
590
591 /* Function to determine if this joystick is attached to the system right now */
SDL_SYS_JoystickAttached(SDL_Joystick * joystick)592 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
593 {
594 return joystick->hwdata->item != NULL;
595 }
596
597 static SDL_INLINE void
HandleHat(SDL_Joystick * stick,Uint8 hat,int axis,int value)598 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
599 {
600 struct hwdata_hat *the_hat;
601 const Uint8 position_map[3][3] = {
602 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
603 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
604 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
605 };
606
607 the_hat = &stick->hwdata->hats[hat];
608 if (value < 0) {
609 value = 0;
610 } else if (value == 0) {
611 value = 1;
612 } else if (value > 0) {
613 value = 2;
614 }
615 if (value != the_hat->axis[axis]) {
616 the_hat->axis[axis] = value;
617 SDL_PrivateJoystickHat(stick, hat,
618 position_map[the_hat->
619 axis[1]][the_hat->axis[0]]);
620 }
621 }
622
623 static SDL_INLINE void
HandleBall(SDL_Joystick * stick,Uint8 ball,int axis,int value)624 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
625 {
626 stick->hwdata->balls[ball].axis[axis] += value;
627 }
628
629
630 static SDL_INLINE int
AxisCorrect(SDL_Joystick * joystick,int which,int value)631 AxisCorrect(SDL_Joystick * joystick, int which, int value)
632 {
633 struct axis_correct *correct;
634
635 correct = &joystick->hwdata->abs_correct[which];
636 if (correct->used) {
637 value *= 2;
638 if (value > correct->coef[0]) {
639 if (value < correct->coef[1]) {
640 return 0;
641 }
642 value -= correct->coef[1];
643 } else {
644 value -= correct->coef[0];
645 }
646 value *= correct->coef[2];
647 value >>= 13;
648 }
649
650 /* Clamp and return */
651 if (value < -32768)
652 return -32768;
653 if (value > 32767)
654 return 32767;
655
656 return value;
657 }
658
659 static SDL_INLINE void
PollAllValues(SDL_Joystick * joystick)660 PollAllValues(SDL_Joystick * joystick)
661 {
662 struct input_absinfo absinfo;
663 int a, b = 0;
664
665 /* Poll all axis */
666 for (a = ABS_X; b < ABS_MAX; a++) {
667 switch (a) {
668 case ABS_HAT0X:
669 case ABS_HAT0Y:
670 case ABS_HAT1X:
671 case ABS_HAT1Y:
672 case ABS_HAT2X:
673 case ABS_HAT2Y:
674 case ABS_HAT3X:
675 case ABS_HAT3Y:
676 /* ingore hats */
677 break;
678 default:
679 if (joystick->hwdata->abs_correct[b].used) {
680 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
681 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
682
683 #ifdef DEBUG_INPUT_EVENTS
684 printf("Joystick : Re-read Axis %d (%d) val= %d\n",
685 joystick->hwdata->abs_map[b], a, absinfo.value);
686 #endif
687 SDL_PrivateJoystickAxis(joystick,
688 joystick->hwdata->abs_map[b],
689 absinfo.value);
690 }
691 }
692 b++;
693 }
694 }
695 }
696
697 static SDL_INLINE void
HandleInputEvents(SDL_Joystick * joystick)698 HandleInputEvents(SDL_Joystick * joystick)
699 {
700 struct input_event events[32];
701 int i, len;
702 int code;
703
704 if (joystick->hwdata->fresh) {
705 PollAllValues(joystick);
706 joystick->hwdata->fresh = 0;
707 }
708
709 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
710 len /= sizeof(events[0]);
711 for (i = 0; i < len; ++i) {
712 code = events[i].code;
713 switch (events[i].type) {
714 case EV_KEY:
715 if (code >= BTN_MISC) {
716 code -= BTN_MISC;
717 SDL_PrivateJoystickButton(joystick,
718 joystick->hwdata->key_map[code],
719 events[i].value);
720 }
721 break;
722 case EV_ABS:
723 switch (code) {
724 case ABS_HAT0X:
725 case ABS_HAT0Y:
726 case ABS_HAT1X:
727 case ABS_HAT1Y:
728 case ABS_HAT2X:
729 case ABS_HAT2Y:
730 case ABS_HAT3X:
731 case ABS_HAT3Y:
732 code -= ABS_HAT0X;
733 HandleHat(joystick, code / 2, code % 2, events[i].value);
734 break;
735 default:
736 events[i].value =
737 AxisCorrect(joystick, code, events[i].value);
738 SDL_PrivateJoystickAxis(joystick,
739 joystick->hwdata->abs_map[code],
740 events[i].value);
741 break;
742 }
743 break;
744 case EV_REL:
745 switch (code) {
746 case REL_X:
747 case REL_Y:
748 code -= REL_X;
749 HandleBall(joystick, code / 2, code % 2, events[i].value);
750 break;
751 default:
752 break;
753 }
754 break;
755 case EV_SYN:
756 switch (code) {
757 case SYN_DROPPED :
758 #ifdef DEBUG_INPUT_EVENTS
759 printf("Event SYN_DROPPED detected\n");
760 #endif
761 PollAllValues(joystick);
762 break;
763 default:
764 break;
765 }
766 default:
767 break;
768 }
769 }
770 }
771 }
772
773 void
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)774 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
775 {
776 int i;
777
778 HandleInputEvents(joystick);
779
780 /* Deliver ball motion updates */
781 for (i = 0; i < joystick->nballs; ++i) {
782 int xrel, yrel;
783
784 xrel = joystick->hwdata->balls[i].axis[0];
785 yrel = joystick->hwdata->balls[i].axis[1];
786 if (xrel || yrel) {
787 joystick->hwdata->balls[i].axis[0] = 0;
788 joystick->hwdata->balls[i].axis[1] = 0;
789 SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
790 }
791 }
792 }
793
794 /* Function to close a joystick after use */
795 void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)796 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
797 {
798 if (joystick->hwdata) {
799 close(joystick->hwdata->fd);
800 if (joystick->hwdata->item) {
801 joystick->hwdata->item->hwdata = NULL;
802 }
803 SDL_free(joystick->hwdata->hats);
804 SDL_free(joystick->hwdata->balls);
805 SDL_free(joystick->hwdata->fname);
806 SDL_free(joystick->hwdata);
807 }
808 }
809
810 /* Function to perform any system-specific joystick related cleanup */
811 void
SDL_SYS_JoystickQuit(void)812 SDL_SYS_JoystickQuit(void)
813 {
814 SDL_joylist_item *item = NULL;
815 SDL_joylist_item *next = NULL;
816
817 for (item = SDL_joylist; item; item = next) {
818 next = item->next;
819 SDL_free(item->path);
820 SDL_free(item->name);
821 SDL_free(item);
822 }
823
824 SDL_joylist = SDL_joylist_tail = NULL;
825
826 numjoysticks = 0;
827 instance_counter = 0;
828
829 #if SDL_USE_LIBUDEV
830 SDL_UDEV_DelCallback(joystick_udev_callback);
831 SDL_UDEV_Quit();
832 #endif
833 }
834
SDL_SYS_JoystickGetDeviceGUID(int device_index)835 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
836 {
837 return JoystickByDevIndex(device_index)->guid;
838 }
839
SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)840 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
841 {
842 return joystick->hwdata->guid;
843 }
844
845 #endif /* SDL_JOYSTICK_LINUX */
846
847 /* vi: set ts=4 sw=4 expandtab: */
848