zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.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 system specific header for 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 /*
56  * !!! FIXME: move all the udev stuff to src/core/linux, so I can reuse it
57  * !!! FIXME: for audio hardware disconnects.
58  */
59 #ifdef HAVE_LIBUDEV_H
60 #define SDL_USE_LIBUDEV 1
61 #include "SDL_loadso.h"
62 #include <libudev.h>
63 #include <sys/time.h>
64 #include <sys/types.h>
65 
66 /* we never link directly to libudev. */
67 /* !!! FIXME: can we generalize this? ALSA, etc, do the same things. */
68 static const char *udev_library = "libudev.so.0";
69 static void *udev_handle = NULL;
70 
71 /* !!! FIXME: this is kinda ugly. */
72 static SDL_bool
73 load_udev_sym(const char *fn, void **addr)
74 {
75  *addr = SDL_LoadFunction(udev_handle, fn);
76  if (*addr == NULL) {
77  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
78  return SDL_FALSE;
79  }
80 
81  return SDL_TRUE;
82 }
83 
84 /* libudev entry points... */
85 static const char *(*UDEV_udev_device_get_action)(struct udev_device *) = NULL;
86 static const char *(*UDEV_udev_device_get_devnode)(struct udev_device *) = NULL;
87 static const char *(*UDEV_udev_device_get_property_value)(struct udev_device *, const char *) = NULL;
88 static struct udev_device *(*UDEV_udev_device_new_from_syspath)(struct udev *, const char *) = NULL;
89 static void (*UDEV_udev_device_unref)(struct udev_device *) = NULL;
90 static int (*UDEV_udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *) = NULL;
91 static int (*UDEV_udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *) = NULL;
92 static struct udev_list_entry *(*UDEV_udev_enumerate_get_list_entry)(struct udev_enumerate *) = NULL;
93 static struct udev_enumerate *(*UDEV_udev_enumerate_new)(struct udev *) = NULL;
94 static int (*UDEV_udev_enumerate_scan_devices)(struct udev_enumerate *) = NULL;
95 static void (*UDEV_udev_enumerate_unref)(struct udev_enumerate *) = NULL;
96 static const char *(*UDEV_udev_list_entry_get_name)(struct udev_list_entry *) = NULL;
97 static struct udev_list_entry *(*UDEV_udev_list_entry_get_next)(struct udev_list_entry *) = NULL;
98 static int (*UDEV_udev_monitor_enable_receiving)(struct udev_monitor *) = NULL;
99 static int (*UDEV_udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *) = NULL;
100 static int (*UDEV_udev_monitor_get_fd)(struct udev_monitor *) = NULL;
101 static struct udev_monitor *(*UDEV_udev_monitor_new_from_netlink)(struct udev *, const char *) = NULL;
102 static struct udev_device *(*UDEV_udev_monitor_receive_device)(struct udev_monitor *) = NULL;
103 static void (*UDEV_udev_monitor_unref)(struct udev_monitor *) = NULL;
104 static struct udev *(*UDEV_udev_new)(void) = NULL;
105 static void (*UDEV_udev_unref)(struct udev *) = NULL;
106 
107 static int
108 load_udev_syms(void)
109 {
110  /* cast funcs to char* first, to please GCC's strict aliasing rules. */
111  #define SDL_UDEV_SYM(x) \
112  if (!load_udev_sym(#x, (void **) (char *) &UDEV_##x)) return -1
113 
114  SDL_UDEV_SYM(udev_device_get_action);
115  SDL_UDEV_SYM(udev_device_get_devnode);
116  SDL_UDEV_SYM(udev_device_get_property_value);
117  SDL_UDEV_SYM(udev_device_new_from_syspath);
118  SDL_UDEV_SYM(udev_device_unref);
119  SDL_UDEV_SYM(udev_enumerate_add_match_property);
120  SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
121  SDL_UDEV_SYM(udev_enumerate_get_list_entry);
122  SDL_UDEV_SYM(udev_enumerate_new);
123  SDL_UDEV_SYM(udev_enumerate_scan_devices);
124  SDL_UDEV_SYM(udev_enumerate_unref);
125  SDL_UDEV_SYM(udev_list_entry_get_name);
126  SDL_UDEV_SYM(udev_list_entry_get_next);
127  SDL_UDEV_SYM(udev_monitor_enable_receiving);
128  SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
129  SDL_UDEV_SYM(udev_monitor_get_fd);
130  SDL_UDEV_SYM(udev_monitor_new_from_netlink);
131  SDL_UDEV_SYM(udev_monitor_receive_device);
132  SDL_UDEV_SYM(udev_monitor_unref);
133  SDL_UDEV_SYM(udev_new);
134  SDL_UDEV_SYM(udev_unref);
135 
136  #undef SDL_UDEV_SYM
137 
138  return 0;
139 }
140 
141 static void
142 UnloadUDEVLibrary(void)
143 {
144  if (udev_handle != NULL) {
145  SDL_UnloadObject(udev_handle);
146  udev_handle = NULL;
147  }
148 }
149 
150 static int
151 LoadUDEVLibrary(void)
152 {
153  int retval = 0;
154  if (udev_handle == NULL) {
155  udev_handle = SDL_LoadObject(udev_library);
156  if (udev_handle == NULL) {
157  retval = -1;
158  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
159  } else {
160  retval = load_udev_syms();
161  if (retval < 0) {
162  UnloadUDEVLibrary();
163  }
164  }
165  }
166 
167  return retval;
168 }
169 
170 static struct udev *udev = NULL;
171 static struct udev_monitor *udev_mon = NULL;
172 #endif
173 
174 
175 /* A linked list of available joysticks */
176 typedef struct SDL_joylist_item
177 {
178  int device_instance;
179  char *path; /* "/dev/input/event2" or whatever */
180  char *name; /* "SideWinder 3D Pro" or whatever */
181  SDL_JoystickGUID guid;
182  dev_t devnum;
183  struct joystick_hwdata *hwdata;
184  struct SDL_joylist_item *next;
185 } SDL_joylist_item;
186 
187 static SDL_joylist_item *SDL_joylist = NULL;
188 static SDL_joylist_item *SDL_joylist_tail = NULL;
189 static int numjoysticks = 0;
190 static int instance_counter = 0;
191 
192 #define test_bit(nr, addr) \
193  (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
194 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
195 
196 static int
197 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
198 {
199  unsigned long evbit[NBITS(EV_MAX)] = { 0 };
200  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
201  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
202  struct input_id inpid;
203  Uint16 *guid16 = (Uint16 *) ((char *) &guid->data);
204 
205  if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
206  (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
207  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
208  return (0);
209  }
210 
211  if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
212  test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
213  return 0;
214  }
215 
216  if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
217  return 0;
218  }
219 
220  if (ioctl(fd, EVIOCGID, &inpid) < 0) {
221  return 0;
222  }
223 
224 #ifdef DEBUG_JOYSTICK
225  printf("Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
226 #endif
227 
228  SDL_memset(guid->data, 0, sizeof(guid->data));
229 
230  /* We only need 16 bits for each of these; space them out to fill 128. */
231  /* Byteswap so devices get same GUID on little/big endian platforms. */
232  *(guid16++) = SDL_SwapLE16(inpid.bustype);
233  *(guid16++) = 0;
234 
235  if (inpid.vendor && inpid.product && inpid.version) {
236  *(guid16++) = SDL_SwapLE16(inpid.vendor);
237  *(guid16++) = 0;
238  *(guid16++) = SDL_SwapLE16(inpid.product);
239  *(guid16++) = 0;
240  *(guid16++) = SDL_SwapLE16(inpid.version);
241  *(guid16++) = 0;
242  } else {
243  SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
244  }
245 
246  return 1;
247 }
248 
249 
250 /* !!! FIXME: I would love to dump this code and use libudev instead. */
251 static int
252 MaybeAddDevice(const char *path)
253 {
254  struct stat sb;
255  int fd = -1;
256  int isstick = 0;
257  char namebuf[128];
258  SDL_JoystickGUID guid;
259  SDL_joylist_item *item;
260 
261  if (path == NULL) {
262  return -1;
263  }
264 
265  if (stat(path, &sb) == -1) {
266  return -1;
267  }
268 
269  /* Check to make sure it's not already in list. */
270  for (item = SDL_joylist; item != NULL; item = item->next) {
271  if (sb.st_rdev == item->devnum) {
272  return -1; /* already have this one */
273  }
274  }
275 
276  fd = open(path, O_RDONLY, 0);
277  if (fd < 0) {
278  return -1;
279  }
280 
281 #ifdef DEBUG_INPUT_EVENTS
282  printf("Checking %s\n", path);
283 #endif
284 
285  isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
286  close(fd);
287  if (!isstick) {
288  return -1;
289  }
290 
291  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
292  if (item == NULL) {
293  return -1;
294  }
295 
296  SDL_zerop(item);
297  item->devnum = sb.st_rdev;
298  item->path = SDL_strdup(path);
299  item->name = SDL_strdup(namebuf);
300  item->guid = guid;
301 
302  if ( (item->path == NULL) || (item->name == NULL) ) {
303  SDL_free(item->path);
304  SDL_free(item->name);
305  SDL_free(item);
306  return -1;
307  }
308 
309  item->device_instance = instance_counter++;
310  if (SDL_joylist_tail == NULL) {
311  SDL_joylist = SDL_joylist_tail = item;
312  } else {
313  SDL_joylist_tail->next = item;
314  SDL_joylist_tail = item;
315  }
316 
317  return numjoysticks++;
318 }
319 
320 #if SDL_USE_LIBUDEV
321 /* !!! FIXME: I would love to dump this code and use libudev instead. */
322 static int
323 MaybeRemoveDevice(const char *path)
324 {
325  SDL_joylist_item *item;
326  SDL_joylist_item *prev = NULL;
327 
328  if (path == NULL) {
329  return -1;
330  }
331 
332  for (item = SDL_joylist; item != NULL; item = item->next) {
333  /* found it, remove it. */
334  if (SDL_strcmp(path, item->path) == 0) {
335  const int retval = item->device_instance;
336  if (item->hwdata) {
337  item->hwdata->item = NULL;
338  }
339  if (prev != NULL) {
340  prev->next = item->next;
341  } else {
342  SDL_assert(SDL_joylist == item);
343  SDL_joylist = item->next;
344  }
345  if (item == SDL_joylist_tail) {
346  SDL_joylist_tail = prev;
347  }
348  SDL_free(item->path);
349  SDL_free(item->name);
350  SDL_free(item);
351  numjoysticks--;
352  return retval;
353  }
354  prev = item;
355  }
356 
357  return -1;
358 }
359 #endif
360 
361 static int
362 JoystickInitWithoutUdev(void)
363 {
364  int i;
365  char path[PATH_MAX];
366 
367  /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
368  /* !!! FIXME: we could at least readdir() through /dev/input...? */
369  /* !!! FIXME: (or delete this and rely on libudev?) */
370  for (i = 0; i < 32; i++) {
371  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
372  MaybeAddDevice(path);
373  }
374 
375  return numjoysticks;
376 }
377 
378 
379 #if SDL_USE_LIBUDEV
380 static int
381 JoystickInitWithUdev(void)
382 {
383  struct udev_enumerate *enumerate = NULL;
384  struct udev_list_entry *devs = NULL;
385  struct udev_list_entry *item = NULL;
386 
387  SDL_assert(udev == NULL);
388  udev = UDEV_udev_new();
389  if (udev == NULL) {
390  return SDL_SetError("udev_new() failed");
391  }
392 
393  udev_mon = UDEV_udev_monitor_new_from_netlink(udev, "udev");
394  if (udev_mon != NULL) { /* okay if it's NULL, we just lose hotplugging. */
395  UDEV_udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
396  "input", NULL);
397  UDEV_udev_monitor_enable_receiving(udev_mon);
398  }
399 
400  enumerate = UDEV_udev_enumerate_new(udev);
401  if (enumerate == NULL) {
402  return SDL_SetError("udev_enumerate_new() failed");
403  }
404 
405  UDEV_udev_enumerate_add_match_subsystem(enumerate, "input");
406  UDEV_udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");
407  UDEV_udev_enumerate_scan_devices(enumerate);
408  devs = UDEV_udev_enumerate_get_list_entry(enumerate);
409  for (item = devs; item; item = UDEV_udev_list_entry_get_next(item)) {
410  const char *path = UDEV_udev_list_entry_get_name(item);
411  struct udev_device *dev = UDEV_udev_device_new_from_syspath(udev, path);
412  MaybeAddDevice(UDEV_udev_device_get_devnode(dev));
413  UDEV_udev_device_unref(dev);
414  }
415 
416  UDEV_udev_enumerate_unref(enumerate);
417 
418  return numjoysticks;
419 }
420 #endif
421 
422 int
424 {
425  /* First see if the user specified one or more joysticks to use */
426  if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
427  char *envcopy, *envpath, *delim;
428  envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
429  envpath = envcopy;
430  while (envpath != NULL) {
431  delim = SDL_strchr(envpath, ':');
432  if (delim != NULL) {
433  *delim++ = '\0';
434  }
435  MaybeAddDevice(envpath);
436  envpath = delim;
437  }
438  SDL_free(envcopy);
439  }
440 
441 #if SDL_USE_LIBUDEV
442  if (LoadUDEVLibrary() == 0) { /* okay if this fails, FOR NOW. */
443  return JoystickInitWithUdev();
444  }
445 #endif
446 
447  return JoystickInitWithoutUdev();
448 }
449 
451 {
452  return numjoysticks;
453 }
454 
455 static SDL_bool
456 HotplugUpdateAvailable(void)
457 {
458 #if SDL_USE_LIBUDEV
459  if (udev_mon != NULL) {
460  const int fd = UDEV_udev_monitor_get_fd(udev_mon);
461  fd_set fds;
462  struct timeval tv;
463 
464  FD_ZERO(&fds);
465  FD_SET(fd, &fds);
466  tv.tv_sec = 0;
467  tv.tv_usec = 0;
468  if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
469  return SDL_TRUE;
470  }
471  }
472 #endif
473 
474  return SDL_FALSE;
475 }
476 
478 {
479 #if SDL_USE_LIBUDEV
480  struct udev_device *dev = NULL;
481  const char *devnode = NULL;
482  const char *action = NULL;
483  const char *val = NULL;
484 
485  while (HotplugUpdateAvailable()) {
486  dev = UDEV_udev_monitor_receive_device(udev_mon);
487  if (dev == NULL) {
488  break;
489  }
490  val = UDEV_udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
491  if ((!val) || (SDL_strcmp(val, "1") != 0)) {
492  continue;
493  }
494 
495  action = UDEV_udev_device_get_action(dev);
496  devnode = UDEV_udev_device_get_devnode(dev);
497 
498  if (SDL_strcmp(action, "add") == 0) {
499  const int device_index = MaybeAddDevice(devnode);
500  if (device_index != -1) {
501  /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */
502  #if !SDL_EVENTS_DISABLED
504  event.type = SDL_JOYDEVICEADDED;
505 
506  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
507  event.jdevice.which = device_index;
508  if ( (SDL_EventOK == NULL) ||
509  (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
510  SDL_PushEvent(&event);
511  }
512  }
513  #endif /* !SDL_EVENTS_DISABLED */
514  }
515  } else if (SDL_strcmp(action, "remove") == 0) {
516  const int inst = MaybeRemoveDevice(devnode);
517  if (inst != -1) {
518  /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */
519  #if !SDL_EVENTS_DISABLED
521  event.type = SDL_JOYDEVICEREMOVED;
522 
523  if (SDL_GetEventState(event.type) == SDL_ENABLE) {
524  event.jdevice.which = inst;
525  if ( (SDL_EventOK == NULL) ||
526  (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
527  SDL_PushEvent(&event);
528  }
529  }
530  #endif /* !SDL_EVENTS_DISABLED */
531  }
532  }
533  UDEV_udev_device_unref(dev);
534  }
535 #endif
536 }
537 
539 {
540  /*
541  * This results in a select() call, so technically we're polling to
542  * decide if we should poll, but I think this function is here because
543  * Windows has to do an enormous amount of work to detect new sticks,
544  * whereas libudev just needs to see if there's more data available on
545  * a socket...so this should be acceptable, I hope.
546  */
547  return HotplugUpdateAvailable();
548 }
549 
550 static SDL_joylist_item *
551 JoystickByDevIndex(int device_index)
552 {
553  SDL_joylist_item *item = SDL_joylist;
554 
555  if ((device_index < 0) || (device_index >= numjoysticks)) {
556  return NULL;
557  }
558 
559  while (device_index > 0) {
560  SDL_assert(item != NULL);
561  device_index--;
562  item = item->next;
563  }
564 
565  return item;
566 }
567 
568 /* Function to get the device-dependent name of a joystick */
569 const char *
570 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
571 {
572  return JoystickByDevIndex(device_index)->name;
573 }
574 
575 /* Function to perform the mapping from device index to the instance id for this index */
577 {
578  return JoystickByDevIndex(device_index)->device_instance;
579 }
580 
581 static int
582 allocate_hatdata(SDL_Joystick * joystick)
583 {
584  int i;
585 
586  joystick->hwdata->hats =
587  (struct hwdata_hat *) SDL_malloc(joystick->nhats *
588  sizeof(struct hwdata_hat));
589  if (joystick->hwdata->hats == NULL) {
590  return (-1);
591  }
592  for (i = 0; i < joystick->nhats; ++i) {
593  joystick->hwdata->hats[i].axis[0] = 1;
594  joystick->hwdata->hats[i].axis[1] = 1;
595  }
596  return (0);
597 }
598 
599 static int
600 allocate_balldata(SDL_Joystick * joystick)
601 {
602  int i;
603 
604  joystick->hwdata->balls =
605  (struct hwdata_ball *) SDL_malloc(joystick->nballs *
606  sizeof(struct hwdata_ball));
607  if (joystick->hwdata->balls == NULL) {
608  return (-1);
609  }
610  for (i = 0; i < joystick->nballs; ++i) {
611  joystick->hwdata->balls[i].axis[0] = 0;
612  joystick->hwdata->balls[i].axis[1] = 0;
613  }
614  return (0);
615 }
616 
617 static void
618 ConfigJoystick(SDL_Joystick * joystick, int fd)
619 {
620  int i, t;
621  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
622  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
623  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
624 
625  /* See if this device uses the new unified event API */
626  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
627  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
628  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
629 
630  /* Get the number of buttons, axes, and other thingamajigs */
631  for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
632  if (test_bit(i, keybit)) {
633 #ifdef DEBUG_INPUT_EVENTS
634  printf("Joystick has button: 0x%x\n", i);
635 #endif
636  joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
637  ++joystick->nbuttons;
638  }
639  }
640  for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
641  if (test_bit(i, keybit)) {
642 #ifdef DEBUG_INPUT_EVENTS
643  printf("Joystick has button: 0x%x\n", i);
644 #endif
645  joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
646  ++joystick->nbuttons;
647  }
648  }
649  for (i = 0; i < ABS_MISC; ++i) {
650  /* Skip hats */
651  if (i == ABS_HAT0X) {
652  i = ABS_HAT3Y;
653  continue;
654  }
655  if (test_bit(i, absbit)) {
656  struct input_absinfo absinfo;
657 
658  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0)
659  continue;
660 #ifdef DEBUG_INPUT_EVENTS
661  printf("Joystick has absolute axis: %x\n", i);
662  printf("Values = { %d, %d, %d, %d, %d }\n",
663  absinfo.value, absinfo.minimum, absinfo.maximum,
664  absinfo.fuzz, absinfo.flat);
665 #endif /* DEBUG_INPUT_EVENTS */
666  joystick->hwdata->abs_map[i] = joystick->naxes;
667  if (absinfo.minimum == absinfo.maximum) {
668  joystick->hwdata->abs_correct[i].used = 0;
669  } else {
670  joystick->hwdata->abs_correct[i].used = 1;
671  joystick->hwdata->abs_correct[i].coef[0] =
672  (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
673  joystick->hwdata->abs_correct[i].coef[1] =
674  (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
675  t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
676  if (t != 0) {
677  joystick->hwdata->abs_correct[i].coef[2] =
678  (1 << 28) / t;
679  } else {
680  joystick->hwdata->abs_correct[i].coef[2] = 0;
681  }
682  }
683  ++joystick->naxes;
684  }
685  }
686  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
687  if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
688 #ifdef DEBUG_INPUT_EVENTS
689  printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
690 #endif
691  ++joystick->nhats;
692  }
693  }
694  if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
695  ++joystick->nballs;
696  }
697 
698  /* Allocate data to keep track of these thingamajigs */
699  if (joystick->nhats > 0) {
700  if (allocate_hatdata(joystick) < 0) {
701  joystick->nhats = 0;
702  }
703  }
704  if (joystick->nballs > 0) {
705  if (allocate_balldata(joystick) < 0) {
706  joystick->nballs = 0;
707  }
708  }
709  }
710 }
711 
712 
713 /* Function to open a joystick for use.
714  The joystick to open is specified by the index field of the joystick.
715  This should fill the nbuttons and naxes fields of the joystick structure.
716  It returns 0, or -1 if there is an error.
717  */
718 int
719 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
720 {
721  SDL_joylist_item *item = JoystickByDevIndex(device_index);
722  char *fname = NULL;
723  int fd = -1;
724 
725  if (item == NULL) {
726  return SDL_SetError("No such device");
727  }
728 
729  fname = item->path;
730  fd = open(fname, O_RDONLY, 0);
731  if (fd < 0) {
732  return SDL_SetError("Unable to open %s", fname);
733  }
734 
735  joystick->instance_id = item->device_instance;
736  joystick->hwdata = (struct joystick_hwdata *)
737  SDL_malloc(sizeof(*joystick->hwdata));
738  if (joystick->hwdata == NULL) {
739  close(fd);
740  return SDL_OutOfMemory();
741  }
742  SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
743  joystick->hwdata->item = item;
744  joystick->hwdata->guid = item->guid;
745  joystick->hwdata->fd = fd;
746  joystick->hwdata->fname = SDL_strdup(item->path);
747  if (joystick->hwdata->fname == NULL) {
748  SDL_free(joystick->hwdata);
749  joystick->hwdata = NULL;
750  close(fd);
751  return SDL_OutOfMemory();
752  }
753 
754  SDL_assert(item->hwdata == NULL);
755  item->hwdata = joystick->hwdata;
756 
757  /* Set the joystick to non-blocking read mode */
758  fcntl(fd, F_SETFL, O_NONBLOCK);
759 
760  /* Get the number of buttons and axes on the joystick */
761  ConfigJoystick(joystick, fd);
762 
763  /* mark joystick as fresh and ready */
764  joystick->hwdata->fresh = 1;
765 
766  return (0);
767 }
768 
769 /* Function to determine is this joystick is attached to the system right now */
771 {
772  return !joystick->closed && (joystick->hwdata->item != NULL);
773 }
774 
775 static __inline__ void
776 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
777 {
778  struct hwdata_hat *the_hat;
779  const Uint8 position_map[3][3] = {
783  };
784 
785  the_hat = &stick->hwdata->hats[hat];
786  if (value < 0) {
787  value = 0;
788  } else if (value == 0) {
789  value = 1;
790  } else if (value > 0) {
791  value = 2;
792  }
793  if (value != the_hat->axis[axis]) {
794  the_hat->axis[axis] = value;
795  SDL_PrivateJoystickHat(stick, hat,
796  position_map[the_hat->
797  axis[1]][the_hat->axis[0]]);
798  }
799 }
800 
801 static __inline__ void
802 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
803 {
804  stick->hwdata->balls[ball].axis[axis] += value;
805 }
806 
807 
808 static __inline__ int
809 AxisCorrect(SDL_Joystick * joystick, int which, int value)
810 {
811  struct axis_correct *correct;
812 
813  correct = &joystick->hwdata->abs_correct[which];
814  if (correct->used) {
815  value *= 2;
816  if (value > correct->coef[0]) {
817  if (value < correct->coef[1]) {
818  return 0;
819  }
820  value -= correct->coef[1];
821  } else {
822  value -= correct->coef[0];
823  }
824  value *= correct->coef[2];
825  value >>= 13;
826  }
827 
828  /* Clamp and return */
829  if (value < -32768)
830  return -32768;
831  if (value > 32767)
832  return 32767;
833 
834  return value;
835 }
836 
837 static __inline__ void
838 PollAllValues(SDL_Joystick * joystick)
839 {
840  struct input_absinfo absinfo;
841  int a, b = 0;
842 
843  /* Poll all axis */
844  for (a = ABS_X; b < ABS_MAX; a++) {
845  switch (a) {
846  case ABS_HAT0X:
847  case ABS_HAT0Y:
848  case ABS_HAT1X:
849  case ABS_HAT1Y:
850  case ABS_HAT2X:
851  case ABS_HAT2Y:
852  case ABS_HAT3X:
853  case ABS_HAT3Y:
854  /* ingore hats */
855  break;
856  default:
857  if (joystick->hwdata->abs_correct[b].used) {
858  if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
859  absinfo.value = AxisCorrect(joystick, b, absinfo.value);
860 
861 #ifdef DEBUG_INPUT_EVENTS
862  printf("Joystick : Re-read Axis %d (%d) val= %d\n",
863  joystick->hwdata->abs_map[b], a, absinfo.value);
864 #endif
865  SDL_PrivateJoystickAxis(joystick,
866  joystick->hwdata->abs_map[b],
867  absinfo.value);
868  }
869  }
870  b++;
871  }
872  }
873 }
874 
875 static __inline__ void
876 HandleInputEvents(SDL_Joystick * joystick)
877 {
878  struct input_event events[32];
879  int i, len;
880  int code;
881 
882  if (joystick->hwdata->fresh) {
883  PollAllValues(joystick);
884  joystick->hwdata->fresh = 0;
885  }
886 
887  while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
888  len /= sizeof(events[0]);
889  for (i = 0; i < len; ++i) {
890  code = events[i].code;
891  switch (events[i].type) {
892  case EV_KEY:
893  if (code >= BTN_MISC) {
894  code -= BTN_MISC;
895  SDL_PrivateJoystickButton(joystick,
896  joystick->hwdata->key_map[code],
897  events[i].value);
898  }
899  break;
900  case EV_ABS:
901  if (code >= ABS_MISC) {
902  break;
903  }
904 
905  switch (code) {
906  case ABS_HAT0X:
907  case ABS_HAT0Y:
908  case ABS_HAT1X:
909  case ABS_HAT1Y:
910  case ABS_HAT2X:
911  case ABS_HAT2Y:
912  case ABS_HAT3X:
913  case ABS_HAT3Y:
914  code -= ABS_HAT0X;
915  HandleHat(joystick, code / 2, code % 2, events[i].value);
916  break;
917  default:
918  events[i].value =
919  AxisCorrect(joystick, code, events[i].value);
920  SDL_PrivateJoystickAxis(joystick,
921  joystick->hwdata->abs_map[code],
922  events[i].value);
923  break;
924  }
925  break;
926  case EV_REL:
927  switch (code) {
928  case REL_X:
929  case REL_Y:
930  code -= REL_X;
931  HandleBall(joystick, code / 2, code % 2, events[i].value);
932  break;
933  default:
934  break;
935  }
936  break;
937  case EV_SYN:
938  switch (code) {
939  case SYN_DROPPED :
940 #ifdef DEBUG_INPUT_EVENTS
941  printf("Event SYN_DROPPED detected\n");
942 #endif
943  PollAllValues(joystick);
944  break;
945  default:
946  break;
947  }
948  default:
949  break;
950  }
951  }
952  }
953 }
954 
955 void
957 {
958  int i;
959 
960  HandleInputEvents(joystick);
961 
962  /* Deliver ball motion updates */
963  for (i = 0; i < joystick->nballs; ++i) {
964  int xrel, yrel;
965 
966  xrel = joystick->hwdata->balls[i].axis[0];
967  yrel = joystick->hwdata->balls[i].axis[1];
968  if (xrel || yrel) {
969  joystick->hwdata->balls[i].axis[0] = 0;
970  joystick->hwdata->balls[i].axis[1] = 0;
971  SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
972  }
973  }
974 }
975 
976 /* Function to close a joystick after use */
977 void
979 {
980  if (joystick->hwdata) {
981  close(joystick->hwdata->fd);
982  if (joystick->hwdata->item) {
983  joystick->hwdata->item->hwdata = NULL;
984  }
985  SDL_free(joystick->hwdata->hats);
986  SDL_free(joystick->hwdata->balls);
987  SDL_free(joystick->hwdata->fname);
988  SDL_free(joystick->hwdata);
989  joystick->hwdata = NULL;
990  }
991  joystick->closed = 1;
992 }
993 
994 /* Function to perform any system-specific joystick related cleanup */
995 void
997 {
998  SDL_joylist_item *item = NULL;
999  SDL_joylist_item *next = NULL;
1000 
1001  for (item = SDL_joylist; item; item = next) {
1002  next = item->next;
1003  SDL_free(item->path);
1004  SDL_free(item->name);
1005  SDL_free(item);
1006  }
1007 
1008  SDL_joylist = SDL_joylist_tail = NULL;
1009 
1010  numjoysticks = 0;
1011  instance_counter = 0;
1012 
1013 #if SDL_USE_LIBUDEV
1014  if (udev_mon != NULL) {
1015  UDEV_udev_monitor_unref(udev_mon);
1016  udev_mon = NULL;
1017  }
1018  if (udev != NULL) {
1019  UDEV_udev_unref(udev);
1020  udev = NULL;
1021  }
1022  UnloadUDEVLibrary();
1023 #endif
1024 }
1025 
1027 {
1028  return JoystickByDevIndex(device_index)->guid;
1029 }
1030 
1032 {
1033  return joystick->hwdata->guid;
1034 }
1035 
1036 #endif /* SDL_JOYSTICK_LINUX */
1037 
1038 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:199
struct joystick_hwdata::hwdata_ball * balls
#define __inline__
Definition: begin_code.h:119
GLuint const GLfloat * val
Definition: glew.h:2715
DECLSPEC int SDLCALL SDL_PushEvent(SDL_Event *event)
Add an event to the event queue.
Definition: SDL_events.c:457
SDL_JoystickGUID guid
#define EVIOCGID
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:536
int SDL_SYS_NumJoysticks()
#define NULL
Definition: ftobjs.h:61
DECLSPEC int SDLCALL SDL_snprintf(char *text, size_t maxlen, const char *fmt,...)
Definition: SDL_string.c:1277
GLenum GLvoid * addr
Definition: glew.h:10667
SDL_bool
Definition: SDL_stdinc.h:116
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:196
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:72
GLdouble GLdouble t
Definition: glew.h:1384
DECLSPEC void SDLCALL SDL_free(void *mem)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:610
#define SDL_ENABLE
Definition: SDL_events.h:688
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:8736
EGLImageKHR EGLint * name
Definition: eglext.h:284
GLenum GLsizei len
Definition: glew.h:7035
void SDL_SYS_JoystickQuit(void)
Uint8 data[16]
Definition: SDL_joystick.h:69
DECLSPEC char *SDLCALL SDL_strchr(const char *str, int c)
Definition: SDL_string.c:575
GLsizei const GLchar *const * path
Definition: glew.h:5828
struct joystick_hwdata * hwdata
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:496
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:193
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:574
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:197
#define SDL_GetEventState(type)
Definition: SDL_events.h:701
int
Definition: SDL_systhread.c:37
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:195
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_EventFilter SDL_EventOK
Definition: SDL_events.c:40
DECLSPEC void *SDLCALL SDL_LoadObject(const char *sofile)
DECLSPEC size_t SDLCALL SDL_strlcpy(char *dst, const char *src, size_t maxlen)
Definition: SDL_string.c:448
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
void SDL_SYS_JoystickDetect()
DECLSPEC void SDLCALL SDL_UnloadObject(void *handle)
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
struct SDL_joylist_item * item
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
SDL_bool SDL_SYS_JoystickNeedsPolling()
#define SDL_assert(condition)
Definition: SDL_assert.h:159
int SDL_SYS_JoystickInit(void)
void * SDL_EventOKParam
Definition: SDL_events.c:41
Definition: inftrees.h:24
#define PATH_MAX
Definition: hrtf.c:34
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:83
Uint8 key_map[KEY_MAX-BTN_MISC]
EGLSurface EGLint void ** value
Definition: eglext.h:301
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:198
#define SDL_zerop(x)
Definition: SDL_stdinc.h:255
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
GLdouble GLdouble GLdouble b
Definition: glew.h:8383
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
General event structure.
Definition: SDL_events.h:495
struct joystick_hwdata::axis_correct abs_correct[ABS_MAX]
DECLSPEC char *SDLCALL SDL_getenv(const char *name)
Definition: SDL_getenv.c:179
int i
Definition: pngrutil.c:1377
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:191
DECLSPEC void *SDLCALL SDL_LoadFunction(void *handle, const char *name)
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:211
Uint8 abs_map[ABS_MAX]
#define SDL_HAT_UP
Definition: SDL_joystick.h:192
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:194
SDL_JoystickID instance_id
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
Uint32 type
Definition: SDL_events.h:497
cl_event event
Definition: glew.h:3556