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