SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 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 static 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
81 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
82 {
83  /* This list is taken from:
84  https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
85  */
86  static Uint32 joystick_blacklist[] = {
87  /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */
88  /* Microsoft Wireless Desktop - Comfort Edition */
89  MAKE_VIDPID(0x045e, 0x009d),
90 
91  /* Microsoft Microsoft® Digital Media Pro Keyboard */
92  /* Microsoft Corp. Digital Media Pro Keyboard */
93  MAKE_VIDPID(0x045e, 0x00b0),
94 
95  /* Microsoft Microsoft® Digital Media Keyboard */
96  /* Microsoft Corp. Digital Media Keyboard 1.0A */
97  MAKE_VIDPID(0x045e, 0x00b4),
98 
99  /* Microsoft Microsoft® Digital Media Keyboard 3000 */
100  MAKE_VIDPID(0x045e, 0x0730),
101 
102  /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */
103  /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */
104  /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */
105  /* Microsoft Wireless Mobile Mouse 1000 */
106  /* Microsoft Wireless Desktop 3000 */
107  MAKE_VIDPID(0x045e, 0x0745),
108 
109  /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */
110  MAKE_VIDPID(0x045e, 0x0748),
111 
112  /* Microsoft Corp. Wired Keyboard 600 */
113  MAKE_VIDPID(0x045e, 0x0750),
114 
115  /* Microsoft Corp. Sidewinder X4 keyboard */
116  MAKE_VIDPID(0x045e, 0x0768),
117 
118  /* Microsoft Corp. Arc Touch Mouse Transceiver */
119  MAKE_VIDPID(0x045e, 0x0773),
120 
121  /* Microsoft® 2.4GHz Transceiver v9.0 */
122  /* Microsoft® Nano Transceiver v2.1 */
123  /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */
124  MAKE_VIDPID(0x045e, 0x07a5),
125 
126  /* Microsoft® Nano Transceiver v1.0 */
127  /* Microsoft Wireless Keyboard 800 */
128  MAKE_VIDPID(0x045e, 0x07b2),
129 
130  /* Microsoft® Nano Transceiver v2.0 */
131  MAKE_VIDPID(0x045e, 0x0800),
132 
133  /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */
134  MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */
135  MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */
136  MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */
137  MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */
138  MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */
139  MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */
140  MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */
141  MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */
142  MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire 4 6x8 */
143  MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun 4x5 */
144  MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */
145  MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */
146  MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */
147 
148  MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */
149  MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */
150  MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */
151  MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */
152  MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */
153  MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */
154  MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */
155  MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */
156  MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */
157  MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */
158  MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */
159  MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */
160  MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */
161  MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */
162  MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */
163  MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */
164  MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */
165 
166  MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */
167 
168  MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */
169 
170  MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */
171 
172  MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */
173  MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */
174  };
175  struct input_id inpid;
176  int i;
177  Uint32 id;
178  Uint16 *guid16 = (Uint16 *)guid->data;
179 
180 #if !SDL_USE_LIBUDEV
181  /* When udev is enabled we only get joystick devices here, so there's no need to test them */
182  unsigned long evbit[NBITS(EV_MAX)] = { 0 };
183  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
184  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
185 
186  if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
187  (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
188  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
189  return (0);
190  }
191 
192  if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
193  test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
194  return 0;
195  }
196 #endif
197 
198  if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
199  return 0;
200  }
201 
202  if (ioctl(fd, EVIOCGID, &inpid) < 0) {
203  return 0;
204  }
205 
206  /* Check the joystick blacklist */
207  id = MAKE_VIDPID(inpid.vendor, inpid.product);
208  for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
209  if (id == joystick_blacklist[i]) {
210  return 0;
211  }
212  }
213 
214 #ifdef DEBUG_JOYSTICK
215  printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
216 #endif
217 
218  SDL_memset(guid->data, 0, sizeof(guid->data));
219 
220  /* We only need 16 bits for each of these; space them out to fill 128. */
221  /* Byteswap so devices get same GUID on little/big endian platforms. */
222  *guid16++ = SDL_SwapLE16(inpid.bustype);
223  *guid16++ = 0;
224 
225  if (inpid.vendor && inpid.product) {
226  *guid16++ = SDL_SwapLE16(inpid.vendor);
227  *guid16++ = 0;
228  *guid16++ = SDL_SwapLE16(inpid.product);
229  *guid16++ = 0;
230  *guid16++ = SDL_SwapLE16(inpid.version);
231  *guid16++ = 0;
232  } else {
233  SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
234  }
235 
236  if (SDL_IsGameControllerNameAndGUID(namebuf, *guid) &&
237  SDL_ShouldIgnoreGameController(namebuf, *guid)) {
238  return 0;
239  }
240  return 1;
241 }
242 
243 #if SDL_USE_LIBUDEV
244 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
245 {
246  if (devpath == NULL) {
247  return;
248  }
249 
250  switch (udev_type) {
251  case SDL_UDEV_DEVICEADDED:
252  if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
253  return;
254  }
255  MaybeAddDevice(devpath);
256  break;
257 
258  case SDL_UDEV_DEVICEREMOVED:
259  MaybeRemoveDevice(devpath);
260  break;
261 
262  default:
263  break;
264  }
265 
266 }
267 #endif /* SDL_USE_LIBUDEV */
268 
269 
270 /* !!! FIXME: I would love to dump this code and use libudev instead. */
271 static int
272 MaybeAddDevice(const char *path)
273 {
274  struct stat sb;
275  int fd = -1;
276  int isstick = 0;
277  char namebuf[128];
278  SDL_JoystickGUID guid;
279  SDL_joylist_item *item;
280 
281  if (path == NULL) {
282  return -1;
283  }
284 
285  if (stat(path, &sb) == -1) {
286  return -1;
287  }
288 
289  /* Check to make sure it's not already in list. */
290  for (item = SDL_joylist; item != NULL; item = item->next) {
291  if (sb.st_rdev == item->devnum) {
292  return -1; /* already have this one */
293  }
294  }
295 
296  fd = open(path, O_RDONLY, 0);
297  if (fd < 0) {
298  return -1;
299  }
300 
301 #ifdef DEBUG_INPUT_EVENTS
302  printf("Checking %s\n", path);
303 #endif
304 
305  isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
306  close(fd);
307  if (!isstick) {
308  return -1;
309  }
310 
311  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
312  if (item == NULL) {
313  return -1;
314  }
315 
316  SDL_zerop(item);
317  item->devnum = sb.st_rdev;
318  item->path = SDL_strdup(path);
319  item->name = SDL_strdup(namebuf);
320  item->guid = guid;
321 
322  if ( (item->path == NULL) || (item->name == NULL) ) {
323  SDL_free(item->path);
324  SDL_free(item->name);
325  SDL_free(item);
326  return -1;
327  }
328 
329  item->device_instance = instance_counter++;
330  if (SDL_joylist_tail == NULL) {
331  SDL_joylist = SDL_joylist_tail = item;
332  } else {
333  SDL_joylist_tail->next = item;
334  SDL_joylist_tail = item;
335  }
336 
337  /* Need to increment the joystick count before we post the event */
338  ++numjoysticks;
339 
341 
342  return numjoysticks;
343 }
344 
345 #if SDL_USE_LIBUDEV
346 /* !!! FIXME: I would love to dump this code and use libudev instead. */
347 static int
348 MaybeRemoveDevice(const char *path)
349 {
350  SDL_joylist_item *item;
351  SDL_joylist_item *prev = NULL;
352 
353  if (path == NULL) {
354  return -1;
355  }
356 
357  for (item = SDL_joylist; item != NULL; item = item->next) {
358  /* found it, remove it. */
359  if (SDL_strcmp(path, item->path) == 0) {
360  const int retval = item->device_instance;
361  if (item->hwdata) {
362  item->hwdata->item = NULL;
363  }
364  if (prev != NULL) {
365  prev->next = item->next;
366  } else {
367  SDL_assert(SDL_joylist == item);
368  SDL_joylist = item->next;
369  }
370  if (item == SDL_joylist_tail) {
371  SDL_joylist_tail = prev;
372  }
373 
374  /* Need to decrement the joystick count before we post the event */
375  --numjoysticks;
376 
377  SDL_PrivateJoystickRemoved(item->device_instance);
378 
379  SDL_free(item->path);
380  SDL_free(item->name);
381  SDL_free(item);
382  return retval;
383  }
384  prev = item;
385  }
386 
387  return -1;
388 }
389 #endif
390 
391 #if ! SDL_USE_LIBUDEV
392 static int
393 JoystickInitWithoutUdev(void)
394 {
395  int i;
396  char path[PATH_MAX];
397 
398  /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
399  /* !!! FIXME: we could at least readdir() through /dev/input...? */
400  /* !!! FIXME: (or delete this and rely on libudev?) */
401  for (i = 0; i < 32; i++) {
402  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
403  MaybeAddDevice(path);
404  }
405 
406  return numjoysticks;
407 }
408 #endif
409 
410 #if SDL_USE_LIBUDEV
411 static int
412 JoystickInitWithUdev(void)
413 {
414  if (SDL_UDEV_Init() < 0) {
415  return SDL_SetError("Could not initialize UDEV");
416  }
417 
418  /* Set up the udev callback */
419  if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
420  SDL_UDEV_Quit();
421  return SDL_SetError("Could not set up joystick <-> udev callback");
422  }
423 
424  /* Force a scan to build the initial device list */
425  SDL_UDEV_Scan();
426 
427  return numjoysticks;
428 }
429 #endif
430 
431 int
433 {
434  /* First see if the user specified one or more joysticks to use */
435  if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
436  char *envcopy, *envpath, *delim;
437  envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
438  envpath = envcopy;
439  while (envpath != NULL) {
440  delim = SDL_strchr(envpath, ':');
441  if (delim != NULL) {
442  *delim++ = '\0';
443  }
444  MaybeAddDevice(envpath);
445  envpath = delim;
446  }
447  SDL_free(envcopy);
448  }
449 
450 #if SDL_USE_LIBUDEV
451  return JoystickInitWithUdev();
452 #else
453  return JoystickInitWithoutUdev();
454 #endif
455 }
456 
457 int
459 {
460  return numjoysticks;
461 }
462 
463 void
465 {
466 #if SDL_USE_LIBUDEV
467  SDL_UDEV_Poll();
468 #endif
469 
470 }
471 
472 static SDL_joylist_item *
473 JoystickByDevIndex(int device_index)
474 {
475  SDL_joylist_item *item = SDL_joylist;
476 
477  if ((device_index < 0) || (device_index >= numjoysticks)) {
478  return NULL;
479  }
480 
481  while (device_index > 0) {
482  SDL_assert(item != NULL);
483  device_index--;
484  item = item->next;
485  }
486 
487  return item;
488 }
489 
490 /* Function to get the device-dependent name of a joystick */
491 const char *
492 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
493 {
494  return JoystickByDevIndex(device_index)->name;
495 }
496 
497 /* Function to perform the mapping from device index to the instance id for this index */
499 {
500  return JoystickByDevIndex(device_index)->device_instance;
501 }
502 
503 static int
504 allocate_hatdata(SDL_Joystick * joystick)
505 {
506  int i;
507 
508  joystick->hwdata->hats =
509  (struct hwdata_hat *) SDL_malloc(joystick->nhats *
510  sizeof(struct hwdata_hat));
511  if (joystick->hwdata->hats == NULL) {
512  return (-1);
513  }
514  for (i = 0; i < joystick->nhats; ++i) {
515  joystick->hwdata->hats[i].axis[0] = 1;
516  joystick->hwdata->hats[i].axis[1] = 1;
517  }
518  return (0);
519 }
520 
521 static int
522 allocate_balldata(SDL_Joystick * joystick)
523 {
524  int i;
525 
526  joystick->hwdata->balls =
527  (struct hwdata_ball *) SDL_malloc(joystick->nballs *
528  sizeof(struct hwdata_ball));
529  if (joystick->hwdata->balls == NULL) {
530  return (-1);
531  }
532  for (i = 0; i < joystick->nballs; ++i) {
533  joystick->hwdata->balls[i].axis[0] = 0;
534  joystick->hwdata->balls[i].axis[1] = 0;
535  }
536  return (0);
537 }
538 
539 static void
540 ConfigJoystick(SDL_Joystick * joystick, int fd)
541 {
542  int i, t;
543  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
544  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
545  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
546 
547  /* See if this device uses the new unified event API */
548  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
549  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
550  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
551 
552  /* Get the number of buttons, axes, and other thingamajigs */
553  for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
554  if (test_bit(i, keybit)) {
555 #ifdef DEBUG_INPUT_EVENTS
556  printf("Joystick has button: 0x%x\n", i);
557 #endif
558  joystick->hwdata->key_map[i] = joystick->nbuttons;
559  ++joystick->nbuttons;
560  }
561  }
562  for (i = 0; i < BTN_JOYSTICK; ++i) {
563  if (test_bit(i, keybit)) {
564 #ifdef DEBUG_INPUT_EVENTS
565  printf("Joystick has button: 0x%x\n", i);
566 #endif
567  joystick->hwdata->key_map[i] = joystick->nbuttons;
568  ++joystick->nbuttons;
569  }
570  }
571  for (i = 0; i < ABS_MAX; ++i) {
572  /* Skip hats */
573  if (i == ABS_HAT0X) {
574  i = ABS_HAT3Y;
575  continue;
576  }
577  if (test_bit(i, absbit)) {
578  struct input_absinfo absinfo;
579 
580  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
581  continue;
582  }
583 #ifdef DEBUG_INPUT_EVENTS
584  printf("Joystick has absolute axis: 0x%.2x\n", i);
585  printf("Values = { %d, %d, %d, %d, %d }\n",
586  absinfo.value, absinfo.minimum, absinfo.maximum,
587  absinfo.fuzz, absinfo.flat);
588 #endif /* DEBUG_INPUT_EVENTS */
589  joystick->hwdata->abs_map[i] = joystick->naxes;
590  if (absinfo.minimum == absinfo.maximum) {
591  joystick->hwdata->abs_correct[i].used = 0;
592  } else {
593  joystick->hwdata->abs_correct[i].used = 1;
594  joystick->hwdata->abs_correct[i].coef[0] =
595  (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
596  joystick->hwdata->abs_correct[i].coef[1] =
597  (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
598  t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
599  if (t != 0) {
600  joystick->hwdata->abs_correct[i].coef[2] =
601  (1 << 28) / t;
602  } else {
603  joystick->hwdata->abs_correct[i].coef[2] = 0;
604  }
605  }
606  ++joystick->naxes;
607  }
608  }
609  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
610  if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
611  struct input_absinfo absinfo;
612 
613  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
614  continue;
615  }
616 #ifdef DEBUG_INPUT_EVENTS
617  printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
618  printf("Values = { %d, %d, %d, %d, %d }\n",
619  absinfo.value, absinfo.minimum, absinfo.maximum,
620  absinfo.fuzz, absinfo.flat);
621 #endif /* DEBUG_INPUT_EVENTS */
622  ++joystick->nhats;
623  }
624  }
625  if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
626  ++joystick->nballs;
627  }
628 
629  /* Allocate data to keep track of these thingamajigs */
630  if (joystick->nhats > 0) {
631  if (allocate_hatdata(joystick) < 0) {
632  joystick->nhats = 0;
633  }
634  }
635  if (joystick->nballs > 0) {
636  if (allocate_balldata(joystick) < 0) {
637  joystick->nballs = 0;
638  }
639  }
640  }
641 }
642 
643 
644 /* Function to open a joystick for use.
645  The joystick to open is specified by the device index.
646  This should fill the nbuttons and naxes fields of the joystick structure.
647  It returns 0, or -1 if there is an error.
648  */
649 int
650 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
651 {
652  SDL_joylist_item *item = JoystickByDevIndex(device_index);
653  char *fname = NULL;
654  int fd = -1;
655 
656  if (item == NULL) {
657  return SDL_SetError("No such device");
658  }
659 
660  fname = item->path;
661  fd = open(fname, O_RDONLY, 0);
662  if (fd < 0) {
663  return SDL_SetError("Unable to open %s", fname);
664  }
665 
666  joystick->instance_id = item->device_instance;
667  joystick->hwdata = (struct joystick_hwdata *)
668  SDL_malloc(sizeof(*joystick->hwdata));
669  if (joystick->hwdata == NULL) {
670  close(fd);
671  return SDL_OutOfMemory();
672  }
673  SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
674  joystick->hwdata->item = item;
675  joystick->hwdata->guid = item->guid;
676  joystick->hwdata->fd = fd;
677  joystick->hwdata->fname = SDL_strdup(item->path);
678  if (joystick->hwdata->fname == NULL) {
679  SDL_free(joystick->hwdata);
680  joystick->hwdata = NULL;
681  close(fd);
682  return SDL_OutOfMemory();
683  }
684 
685  SDL_assert(item->hwdata == NULL);
686  item->hwdata = joystick->hwdata;
687 
688  /* Set the joystick to non-blocking read mode */
689  fcntl(fd, F_SETFL, O_NONBLOCK);
690 
691  /* Get the number of buttons and axes on the joystick */
692  ConfigJoystick(joystick, fd);
693 
694  /* mark joystick as fresh and ready */
695  joystick->hwdata->fresh = 1;
696 
697  return (0);
698 }
699 
700 /* Function to determine if this joystick is attached to the system right now */
701 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
702 {
703  return joystick->hwdata->item != NULL;
704 }
705 
706 static SDL_INLINE void
707 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
708 {
709  struct hwdata_hat *the_hat;
710  const Uint8 position_map[3][3] = {
714  };
715 
716  the_hat = &stick->hwdata->hats[hat];
717  if (value < 0) {
718  value = 0;
719  } else if (value == 0) {
720  value = 1;
721  } else if (value > 0) {
722  value = 2;
723  }
724  if (value != the_hat->axis[axis]) {
725  the_hat->axis[axis] = value;
726  SDL_PrivateJoystickHat(stick, hat,
727  position_map[the_hat->
728  axis[1]][the_hat->axis[0]]);
729  }
730 }
731 
732 static SDL_INLINE void
733 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
734 {
735  stick->hwdata->balls[ball].axis[axis] += value;
736 }
737 
738 
739 static SDL_INLINE int
740 AxisCorrect(SDL_Joystick * joystick, int which, int value)
741 {
742  struct axis_correct *correct;
743 
744  correct = &joystick->hwdata->abs_correct[which];
745  if (correct->used) {
746  value *= 2;
747  if (value > correct->coef[0]) {
748  if (value < correct->coef[1]) {
749  return 0;
750  }
751  value -= correct->coef[1];
752  } else {
753  value -= correct->coef[0];
754  }
755  value *= correct->coef[2];
756  value >>= 13;
757  }
758 
759  /* Clamp and return */
760  if (value < -32768)
761  return -32768;
762  if (value > 32767)
763  return 32767;
764 
765  return value;
766 }
767 
768 static SDL_INLINE void
769 PollAllValues(SDL_Joystick * joystick)
770 {
771  struct input_absinfo absinfo;
772  int a, b = 0;
773 
774  /* Poll all axis */
775  for (a = ABS_X; b < ABS_MAX; a++) {
776  switch (a) {
777  case ABS_HAT0X:
778  case ABS_HAT0Y:
779  case ABS_HAT1X:
780  case ABS_HAT1Y:
781  case ABS_HAT2X:
782  case ABS_HAT2Y:
783  case ABS_HAT3X:
784  case ABS_HAT3Y:
785  /* ingore hats */
786  break;
787  default:
788  if (joystick->hwdata->abs_correct[b].used) {
789  if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
790  absinfo.value = AxisCorrect(joystick, b, absinfo.value);
791 
792 #ifdef DEBUG_INPUT_EVENTS
793  printf("Joystick : Re-read Axis %d (%d) val= %d\n",
794  joystick->hwdata->abs_map[b], a, absinfo.value);
795 #endif
796  SDL_PrivateJoystickAxis(joystick,
797  joystick->hwdata->abs_map[b],
798  absinfo.value);
799  }
800  }
801  b++;
802  }
803  }
804 }
805 
806 static SDL_INLINE void
807 HandleInputEvents(SDL_Joystick * joystick)
808 {
809  struct input_event events[32];
810  int i, len;
811  int code;
812 
813  if (joystick->hwdata->fresh) {
814  PollAllValues(joystick);
815  joystick->hwdata->fresh = 0;
816  }
817 
818  while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
819  len /= sizeof(events[0]);
820  for (i = 0; i < len; ++i) {
821  code = events[i].code;
822  switch (events[i].type) {
823  case EV_KEY:
824  SDL_PrivateJoystickButton(joystick,
825  joystick->hwdata->key_map[code],
826  events[i].value);
827  break;
828  case EV_ABS:
829  switch (code) {
830  case ABS_HAT0X:
831  case ABS_HAT0Y:
832  case ABS_HAT1X:
833  case ABS_HAT1Y:
834  case ABS_HAT2X:
835  case ABS_HAT2Y:
836  case ABS_HAT3X:
837  case ABS_HAT3Y:
838  code -= ABS_HAT0X;
839  HandleHat(joystick, code / 2, code % 2, events[i].value);
840  break;
841  default:
842  events[i].value =
843  AxisCorrect(joystick, code, events[i].value);
844  SDL_PrivateJoystickAxis(joystick,
845  joystick->hwdata->abs_map[code],
846  events[i].value);
847  break;
848  }
849  break;
850  case EV_REL:
851  switch (code) {
852  case REL_X:
853  case REL_Y:
854  code -= REL_X;
855  HandleBall(joystick, code / 2, code % 2, events[i].value);
856  break;
857  default:
858  break;
859  }
860  break;
861  case EV_SYN:
862  switch (code) {
863  case SYN_DROPPED :
864 #ifdef DEBUG_INPUT_EVENTS
865  printf("Event SYN_DROPPED detected\n");
866 #endif
867  PollAllValues(joystick);
868  break;
869  default:
870  break;
871  }
872  default:
873  break;
874  }
875  }
876  }
877 }
878 
879 void
880 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
881 {
882  int i;
883 
884  HandleInputEvents(joystick);
885 
886  /* Deliver ball motion updates */
887  for (i = 0; i < joystick->nballs; ++i) {
888  int xrel, yrel;
889 
890  xrel = joystick->hwdata->balls[i].axis[0];
891  yrel = joystick->hwdata->balls[i].axis[1];
892  if (xrel || yrel) {
893  joystick->hwdata->balls[i].axis[0] = 0;
894  joystick->hwdata->balls[i].axis[1] = 0;
895  SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
896  }
897  }
898 }
899 
900 /* Function to close a joystick after use */
901 void
902 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
903 {
904  if (joystick->hwdata) {
905  close(joystick->hwdata->fd);
906  if (joystick->hwdata->item) {
907  joystick->hwdata->item->hwdata = NULL;
908  }
909  SDL_free(joystick->hwdata->hats);
910  SDL_free(joystick->hwdata->balls);
911  SDL_free(joystick->hwdata->fname);
912  SDL_free(joystick->hwdata);
913  }
914 }
915 
916 /* Function to perform any system-specific joystick related cleanup */
917 void
919 {
920  SDL_joylist_item *item = NULL;
921  SDL_joylist_item *next = NULL;
922 
923  for (item = SDL_joylist; item; item = next) {
924  next = item->next;
925  SDL_free(item->path);
926  SDL_free(item->name);
927  SDL_free(item);
928  }
929 
930  SDL_joylist = SDL_joylist_tail = NULL;
931 
932  numjoysticks = 0;
933  instance_counter = 0;
934 
935 #if SDL_USE_LIBUDEV
936  SDL_UDEV_DelCallback(joystick_udev_callback);
937  SDL_UDEV_Quit();
938 #endif
939 }
940 
942 {
943  return JoystickByDevIndex(device_index)->guid;
944 }
945 
946 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
947 {
948  return joystick->hwdata->guid;
949 }
950 
951 #endif /* SDL_JOYSTICK_LINUX */
952 
953 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:310
#define SDL_strlcpy
GLuint id
#define MAKE_VIDPID(VID, PID)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:641
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:718
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:307
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:35
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:794
SDL_Texture * axis
void SDL_SYS_JoystickQuit(void)
uint32_t Uint32
Definition: SDL_stdinc.h:181
Uint8 data[16]
Definition: SDL_joystick.h:71
#define SDL_zerop(x)
Definition: SDL_stdinc.h:386
GLenum GLsizei len
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:661
GLuint const GLchar * name
#define SDL_strchr
SDL_bool retval
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:304
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:758
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:308
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:306
uint8_t Uint8
Definition: SDL_stdinc.h:157
void SDL_free(void *mem)
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
void SDL_PrivateJoystickAdded(int device_index)
Definition: SDL_joystick.c:595
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:50
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SYS_JoystickInit(void)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
int SDL_SYS_NumJoysticks(void)
#define SDL_SetError
#define SDL_strdup
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:309
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
uint16_t Uint16
Definition: SDL_stdinc.h:169
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
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:131
#define SDL_malloc
GLsizei const GLchar *const * path
#define SDL_strcmp
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:302
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
GLboolean GLboolean GLboolean GLboolean a
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:232
#define SDL_HAT_UP
Definition: SDL_joystick.h:303
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:305
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
#define SDL_memset
void SDL_SYS_JoystickDetect(void)