• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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