SDL  2.0
SDL_sysjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 <errno.h> /* errno, strerror */
33 #include <fcntl.h>
34 #include <limits.h> /* For the definition of PATH_MAX */
35 #include <sys/ioctl.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <linux/joystick.h>
39 
40 #include "SDL_assert.h"
41 #include "SDL_joystick.h"
42 #include "SDL_endian.h"
43 #include "SDL_timer.h"
44 #include "../../events/SDL_events_c.h"
45 #include "../SDL_sysjoystick.h"
46 #include "../SDL_joystick_c.h"
47 #include "../steam/SDL_steamcontroller.h"
48 #include "SDL_sysjoystick_c.h"
49 #include "../hidapi/SDL_hidapijoystick_c.h"
50 
51 /* This isn't defined in older Linux kernel headers */
52 #ifndef SYN_DROPPED
53 #define SYN_DROPPED 3
54 #endif
55 
56 #include "../../core/linux/SDL_udev.h"
57 
58 static int MaybeAddDevice(const char *path);
59 #if SDL_USE_LIBUDEV
60 static int MaybeRemoveDevice(const char *path);
61 #endif /* SDL_USE_LIBUDEV */
62 
63 /* A linked list of available joysticks */
64 typedef struct SDL_joylist_item
65 {
66  int device_instance;
67  char *path; /* "/dev/input/event2" or whatever */
68  char *name; /* "SideWinder 3D Pro" or whatever */
69  SDL_JoystickGUID guid;
70  dev_t devnum;
71  struct joystick_hwdata *hwdata;
72  struct SDL_joylist_item *next;
73 
74  /* Steam Controller support */
75  SDL_bool m_bSteamController;
76 } SDL_joylist_item;
77 
78 static SDL_joylist_item *SDL_joylist = NULL;
79 static SDL_joylist_item *SDL_joylist_tail = NULL;
80 static int numjoysticks = 0;
81 
82 #if !SDL_USE_LIBUDEV
83 static Uint32 last_joy_detect_time;
84 static time_t last_input_dir_mtime;
85 #endif
86 
87 #define test_bit(nr, addr) \
88  (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
89 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
90 
91 static int
92 PrefixMatch(const char *a, const char *b)
93 {
94  int matchlen = 0;
95  while (*a && *b) {
96  if (*a++ == *b++) {
97  ++matchlen;
98  } else {
99  break;
100  }
101  }
102  return matchlen;
103 }
104 
105 static void
106 FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
107 {
108  if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
109  /* This is a Microsoft Xbox One Elite Series 2 controller */
110  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
111 
112  /* The first version of the firmware duplicated all the inputs */
113  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
114  test_bit(0x2c0, keybit)) {
115  /* Change the version to 0x0902, so we can map it differently */
116  inpid->version = 0x0902;
117  }
118  }
119 }
120 
121 
122 static int
123 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
124 {
125  struct input_id inpid;
126  Uint16 *guid16 = (Uint16 *)guid->data;
127  const char *name;
128  const char *spot;
129 
130 #if !SDL_USE_LIBUDEV
131  /* When udev is enabled we only get joystick devices here, so there's no need to test them */
132  unsigned long evbit[NBITS(EV_MAX)] = { 0 };
133  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
134  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
135 
136  if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
137  (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
138  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
139  return (0);
140  }
141 
142  if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
143  test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
144  return 0;
145  }
146 #endif
147 
148  if (ioctl(fd, EVIOCGID, &inpid) < 0) {
149  return 0;
150  }
151 
152  name = SDL_GetCustomJoystickName(inpid.vendor, inpid.product);
153  if (name) {
154  SDL_strlcpy(namebuf, name, namebuflen);
155  } else {
156  if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
157  return 0;
158  }
159 
160  /* Remove duplicate manufacturer in the name */
161  for (spot = namebuf + 1; *spot; ++spot) {
162  int matchlen = PrefixMatch(namebuf, spot);
163  if (matchlen > 0 && spot[matchlen - 1] == ' ') {
164  SDL_memmove(namebuf, spot, SDL_strlen(spot)+1);
165  break;
166  }
167  }
168  }
169 
170 #ifdef SDL_JOYSTICK_HIDAPI
171  if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, namebuf)) {
172  /* The HIDAPI driver is taking care of this device */
173  return 0;
174  }
175 #endif
176 
177  FixupDeviceInfoForMapping(fd, &inpid);
178 
179 #ifdef DEBUG_JOYSTICK
180  printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
181 #endif
182 
183  SDL_memset(guid->data, 0, sizeof(guid->data));
184 
185  /* We only need 16 bits for each of these; space them out to fill 128. */
186  /* Byteswap so devices get same GUID on little/big endian platforms. */
187  *guid16++ = SDL_SwapLE16(inpid.bustype);
188  *guid16++ = 0;
189 
190  if (inpid.vendor && inpid.product) {
191  *guid16++ = SDL_SwapLE16(inpid.vendor);
192  *guid16++ = 0;
193  *guid16++ = SDL_SwapLE16(inpid.product);
194  *guid16++ = 0;
195  *guid16++ = SDL_SwapLE16(inpid.version);
196  *guid16++ = 0;
197  } else {
198  SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
199  }
200 
201  if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
202  return 0;
203  }
204  return 1;
205 }
206 
207 #if SDL_USE_LIBUDEV
208 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
209 {
210  if (devpath == NULL) {
211  return;
212  }
213 
214  switch (udev_type) {
215  case SDL_UDEV_DEVICEADDED:
216  if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
217  return;
218  }
219  MaybeAddDevice(devpath);
220  break;
221 
222  case SDL_UDEV_DEVICEREMOVED:
223  MaybeRemoveDevice(devpath);
224  break;
225 
226  default:
227  break;
228  }
229 
230 }
231 #endif /* SDL_USE_LIBUDEV */
232 
233 static int
234 MaybeAddDevice(const char *path)
235 {
236  struct stat sb;
237  int fd = -1;
238  int isstick = 0;
239  char namebuf[128];
240  SDL_JoystickGUID guid;
241  SDL_joylist_item *item;
242 
243  if (path == NULL) {
244  return -1;
245  }
246 
247  if (stat(path, &sb) == -1) {
248  return -1;
249  }
250 
251  /* Check to make sure it's not already in list. */
252  for (item = SDL_joylist; item != NULL; item = item->next) {
253  if (sb.st_rdev == item->devnum) {
254  return -1; /* already have this one */
255  }
256  }
257 
258  fd = open(path, O_RDONLY, 0);
259  if (fd < 0) {
260  return -1;
261  }
262 
263 #ifdef DEBUG_INPUT_EVENTS
264  printf("Checking %s\n", path);
265 #endif
266 
267  isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
268  close(fd);
269  if (!isstick) {
270  return -1;
271  }
272 
273  item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
274  if (item == NULL) {
275  return -1;
276  }
277 
278  SDL_zerop(item);
279  item->devnum = sb.st_rdev;
280  item->path = SDL_strdup(path);
281  item->name = SDL_strdup(namebuf);
282  item->guid = guid;
283 
284  if ((item->path == NULL) || (item->name == NULL)) {
285  SDL_free(item->path);
286  SDL_free(item->name);
287  SDL_free(item);
288  return -1;
289  }
290 
291  item->device_instance = SDL_GetNextJoystickInstanceID();
292  if (SDL_joylist_tail == NULL) {
293  SDL_joylist = SDL_joylist_tail = item;
294  } else {
295  SDL_joylist_tail->next = item;
296  SDL_joylist_tail = item;
297  }
298 
299  /* Need to increment the joystick count before we post the event */
300  ++numjoysticks;
301 
302  SDL_PrivateJoystickAdded(item->device_instance);
303 
304  return numjoysticks;
305 }
306 
307 #if SDL_USE_LIBUDEV
308 static int
309 MaybeRemoveDevice(const char *path)
310 {
311  SDL_joylist_item *item;
312  SDL_joylist_item *prev = NULL;
313 
314  if (path == NULL) {
315  return -1;
316  }
317 
318  for (item = SDL_joylist; item != NULL; item = item->next) {
319  /* found it, remove it. */
320  if (SDL_strcmp(path, item->path) == 0) {
321  const int retval = item->device_instance;
322  if (item->hwdata) {
323  item->hwdata->item = NULL;
324  }
325  if (prev != NULL) {
326  prev->next = item->next;
327  } else {
328  SDL_assert(SDL_joylist == item);
329  SDL_joylist = item->next;
330  }
331  if (item == SDL_joylist_tail) {
332  SDL_joylist_tail = prev;
333  }
334 
335  /* Need to decrement the joystick count before we post the event */
336  --numjoysticks;
337 
338  SDL_PrivateJoystickRemoved(item->device_instance);
339 
340  SDL_free(item->path);
341  SDL_free(item->name);
342  SDL_free(item);
343  return retval;
344  }
345  prev = item;
346  }
347 
348  return -1;
349 }
350 #endif
351 
352 static void
353 HandlePendingRemovals(void)
354 {
355  SDL_joylist_item *prev = NULL;
356  SDL_joylist_item *item = SDL_joylist;
357 
358  while (item != NULL) {
359  if (item->hwdata && item->hwdata->gone) {
360  item->hwdata->item = NULL;
361 
362  if (prev != NULL) {
363  prev->next = item->next;
364  } else {
365  SDL_assert(SDL_joylist == item);
366  SDL_joylist = item->next;
367  }
368  if (item == SDL_joylist_tail) {
369  SDL_joylist_tail = prev;
370  }
371 
372  /* Need to decrement the joystick count before we post the event */
373  --numjoysticks;
374 
375  SDL_PrivateJoystickRemoved(item->device_instance);
376 
377  SDL_free(item->path);
378  SDL_free(item->name);
379  SDL_free(item);
380 
381  if (prev != NULL) {
382  item = prev->next;
383  } else {
384  item = SDL_joylist;
385  }
386  } else {
387  prev = item;
388  item = item->next;
389  }
390  }
391 }
392 
393 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
394 {
395  SDL_joylist_item *item;
396 
397  item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
398  if (item == NULL) {
399  return SDL_FALSE;
400  }
401 
402  item->path = SDL_strdup("");
403  item->name = SDL_strdup(name);
404  item->guid = guid;
405  item->m_bSteamController = SDL_TRUE;
406 
407  if ((item->path == NULL) || (item->name == NULL)) {
408  SDL_free(item->path);
409  SDL_free(item->name);
410  SDL_free(item);
411  return SDL_FALSE;
412  }
413 
414  *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
415  if (SDL_joylist_tail == NULL) {
416  SDL_joylist = SDL_joylist_tail = item;
417  } else {
418  SDL_joylist_tail->next = item;
419  SDL_joylist_tail = item;
420  }
421 
422  /* Need to increment the joystick count before we post the event */
423  ++numjoysticks;
424 
425  SDL_PrivateJoystickAdded(item->device_instance);
426 
427  return SDL_TRUE;
428 }
429 
430 static void SteamControllerDisconnectedCallback(int device_instance)
431 {
432  SDL_joylist_item *item;
433  SDL_joylist_item *prev = NULL;
434 
435  for (item = SDL_joylist; item != NULL; item = item->next) {
436  /* found it, remove it. */
437  if (item->device_instance == device_instance) {
438  if (item->hwdata) {
439  item->hwdata->item = NULL;
440  }
441  if (prev != NULL) {
442  prev->next = item->next;
443  } else {
444  SDL_assert(SDL_joylist == item);
445  SDL_joylist = item->next;
446  }
447  if (item == SDL_joylist_tail) {
448  SDL_joylist_tail = prev;
449  }
450 
451  /* Need to decrement the joystick count before we post the event */
452  --numjoysticks;
453 
454  SDL_PrivateJoystickRemoved(item->device_instance);
455 
456  SDL_free(item->name);
457  SDL_free(item);
458  return;
459  }
460  prev = item;
461  }
462 }
463 
464 static void
465 LINUX_JoystickDetect(void)
466 {
467 #if SDL_USE_LIBUDEV
468  SDL_UDEV_Poll();
469 #else
470  const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
471  Uint32 now = SDL_GetTicks();
472 
473  if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
474  struct stat sb;
475 
476  /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
477  if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
478  DIR *folder;
479  struct dirent *dent;
480 
481  folder = opendir("/dev/input");
482  if (folder) {
483  while ((dent = readdir(folder))) {
484  int len = SDL_strlen(dent->d_name);
485  if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
486  char path[PATH_MAX];
487  SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
488  MaybeAddDevice(path);
489  }
490  }
491 
492  closedir(folder);
493  }
494 
495  last_input_dir_mtime = sb.st_mtime;
496  }
497 
498  last_joy_detect_time = now;
499  }
500 #endif
501 
502  HandlePendingRemovals();
503 
505 }
506 
507 static int
508 LINUX_JoystickInit(void)
509 {
510  /* First see if the user specified one or more joysticks to use */
511  if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
512  char *envcopy, *envpath, *delim;
513  envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
514  envpath = envcopy;
515  while (envpath != NULL) {
516  delim = SDL_strchr(envpath, ':');
517  if (delim != NULL) {
518  *delim++ = '\0';
519  }
520  MaybeAddDevice(envpath);
521  envpath = delim;
522  }
523  SDL_free(envcopy);
524  }
525 
526  SDL_InitSteamControllers(SteamControllerConnectedCallback,
527  SteamControllerDisconnectedCallback);
528 
529 #if SDL_USE_LIBUDEV
530  if (SDL_UDEV_Init() < 0) {
531  return SDL_SetError("Could not initialize UDEV");
532  }
533 
534  /* Set up the udev callback */
535  if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
536  SDL_UDEV_Quit();
537  return SDL_SetError("Could not set up joystick <-> udev callback");
538  }
539 
540  /* Force a scan to build the initial device list */
541  SDL_UDEV_Scan();
542 #else
543  /* Force immediate joystick detection */
544  last_joy_detect_time = 0;
545  last_input_dir_mtime = 0;
546 
547  /* Report all devices currently present */
548  LINUX_JoystickDetect();
549 #endif
550 
551  return 0;
552 }
553 
554 static int
555 LINUX_JoystickGetCount(void)
556 {
557  return numjoysticks;
558 }
559 
560 static SDL_joylist_item *
561 JoystickByDevIndex(int device_index)
562 {
563  SDL_joylist_item *item = SDL_joylist;
564 
565  if ((device_index < 0) || (device_index >= numjoysticks)) {
566  return NULL;
567  }
568 
569  while (device_index > 0) {
570  SDL_assert(item != NULL);
571  device_index--;
572  item = item->next;
573  }
574 
575  return item;
576 }
577 
578 /* Function to get the device-dependent name of a joystick */
579 static const char *
580 LINUX_JoystickGetDeviceName(int device_index)
581 {
582  return JoystickByDevIndex(device_index)->name;
583 }
584 
585 static int
586 LINUX_JoystickGetDevicePlayerIndex(int device_index)
587 {
588  return -1;
589 }
590 
591 static void
592 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
593 {
594 }
595 
596 static SDL_JoystickGUID
597 LINUX_JoystickGetDeviceGUID( int device_index )
598 {
599  return JoystickByDevIndex(device_index)->guid;
600 }
601 
602 /* Function to perform the mapping from device index to the instance id for this index */
603 static SDL_JoystickID
604 LINUX_JoystickGetDeviceInstanceID(int device_index)
605 {
606  return JoystickByDevIndex(device_index)->device_instance;
607 }
608 
609 static int
610 allocate_hatdata(SDL_Joystick * joystick)
611 {
612  int i;
613 
614  joystick->hwdata->hats =
615  (struct hwdata_hat *) SDL_malloc(joystick->nhats *
616  sizeof(struct hwdata_hat));
617  if (joystick->hwdata->hats == NULL) {
618  return (-1);
619  }
620  for (i = 0; i < joystick->nhats; ++i) {
621  joystick->hwdata->hats[i].axis[0] = 1;
622  joystick->hwdata->hats[i].axis[1] = 1;
623  }
624  return (0);
625 }
626 
627 static int
628 allocate_balldata(SDL_Joystick * joystick)
629 {
630  int i;
631 
632  joystick->hwdata->balls =
633  (struct hwdata_ball *) SDL_malloc(joystick->nballs *
634  sizeof(struct hwdata_ball));
635  if (joystick->hwdata->balls == NULL) {
636  return (-1);
637  }
638  for (i = 0; i < joystick->nballs; ++i) {
639  joystick->hwdata->balls[i].axis[0] = 0;
640  joystick->hwdata->balls[i].axis[1] = 0;
641  }
642  return (0);
643 }
644 
645 static void
646 ConfigJoystick(SDL_Joystick * joystick, int fd)
647 {
648  int i, t;
649  unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
650  unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
651  unsigned long relbit[NBITS(REL_MAX)] = { 0 };
652  unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
653 
654  /* See if this device uses the new unified event API */
655  if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
656  (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
657  (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
658 
659  /* Get the number of buttons, axes, and other thingamajigs */
660  for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
661  if (test_bit(i, keybit)) {
662 #ifdef DEBUG_INPUT_EVENTS
663  printf("Joystick has button: 0x%x\n", i);
664 #endif
665  joystick->hwdata->key_map[i] = joystick->nbuttons;
666  ++joystick->nbuttons;
667  }
668  }
669  for (i = 0; i < BTN_JOYSTICK; ++i) {
670  if (test_bit(i, keybit)) {
671 #ifdef DEBUG_INPUT_EVENTS
672  printf("Joystick has button: 0x%x\n", i);
673 #endif
674  joystick->hwdata->key_map[i] = joystick->nbuttons;
675  ++joystick->nbuttons;
676  }
677  }
678  for (i = 0; i < ABS_MAX; ++i) {
679  /* Skip hats */
680  if (i == ABS_HAT0X) {
681  i = ABS_HAT3Y;
682  continue;
683  }
684  if (test_bit(i, absbit)) {
685  struct input_absinfo absinfo;
686 
687  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
688  continue;
689  }
690 #ifdef DEBUG_INPUT_EVENTS
691  printf("Joystick has absolute axis: 0x%.2x\n", i);
692  printf("Values = { %d, %d, %d, %d, %d }\n",
693  absinfo.value, absinfo.minimum, absinfo.maximum,
694  absinfo.fuzz, absinfo.flat);
695 #endif /* DEBUG_INPUT_EVENTS */
696  joystick->hwdata->abs_map[i] = joystick->naxes;
697  if (absinfo.minimum == absinfo.maximum) {
698  joystick->hwdata->abs_correct[i].used = 0;
699  } else {
700  joystick->hwdata->abs_correct[i].used = 1;
701  joystick->hwdata->abs_correct[i].coef[0] =
702  (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
703  joystick->hwdata->abs_correct[i].coef[1] =
704  (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
705  t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
706  if (t != 0) {
707  joystick->hwdata->abs_correct[i].coef[2] =
708  (1 << 28) / t;
709  } else {
710  joystick->hwdata->abs_correct[i].coef[2] = 0;
711  }
712  }
713  ++joystick->naxes;
714  }
715  }
716  for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
717  if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
718  struct input_absinfo absinfo;
719  int hat_index = (i - ABS_HAT0X) / 2;
720 
721  if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
722  continue;
723  }
724 #ifdef DEBUG_INPUT_EVENTS
725  printf("Joystick has hat %d\n", hat_index);
726  printf("Values = { %d, %d, %d, %d, %d }\n",
727  absinfo.value, absinfo.minimum, absinfo.maximum,
728  absinfo.fuzz, absinfo.flat);
729 #endif /* DEBUG_INPUT_EVENTS */
730  joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
731  }
732  }
733  if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
734  ++joystick->nballs;
735  }
736 
737  /* Allocate data to keep track of these thingamajigs */
738  if (joystick->nhats > 0) {
739  if (allocate_hatdata(joystick) < 0) {
740  joystick->nhats = 0;
741  }
742  }
743  if (joystick->nballs > 0) {
744  if (allocate_balldata(joystick) < 0) {
745  joystick->nballs = 0;
746  }
747  }
748  }
749 
750  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
751  if (test_bit(FF_RUMBLE, ffbit)) {
752  joystick->hwdata->ff_rumble = SDL_TRUE;
753  }
754  if (test_bit(FF_SINE, ffbit)) {
755  joystick->hwdata->ff_sine = SDL_TRUE;
756  }
757  }
758 }
759 
760 
761 /* Function to open a joystick for use.
762  The joystick to open is specified by the device index.
763  This should fill the nbuttons and naxes fields of the joystick structure.
764  It returns 0, or -1 if there is an error.
765  */
766 static int
767 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
768 {
769  SDL_joylist_item *item = JoystickByDevIndex(device_index);
770 
771  if (item == NULL) {
772  return SDL_SetError("No such device");
773  }
774 
775  joystick->instance_id = item->device_instance;
776  joystick->hwdata = (struct joystick_hwdata *)
777  SDL_calloc(1, sizeof(*joystick->hwdata));
778  if (joystick->hwdata == NULL) {
779  return SDL_OutOfMemory();
780  }
781  joystick->hwdata->item = item;
782  joystick->hwdata->guid = item->guid;
783  joystick->hwdata->effect.id = -1;
784  joystick->hwdata->m_bSteamController = item->m_bSteamController;
785  SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
786 
787  if (item->m_bSteamController) {
788  joystick->hwdata->fd = -1;
790  &joystick->naxes,
791  &joystick->nhats);
792  } else {
793  int fd = open(item->path, O_RDWR, 0);
794  if (fd < 0) {
795  SDL_free(joystick->hwdata);
796  joystick->hwdata = NULL;
797  return SDL_SetError("Unable to open %s", item->path);
798  }
799 
800  joystick->hwdata->fd = fd;
801  joystick->hwdata->fname = SDL_strdup(item->path);
802  if (joystick->hwdata->fname == NULL) {
803  SDL_free(joystick->hwdata);
804  joystick->hwdata = NULL;
805  close(fd);
806  return SDL_OutOfMemory();
807  }
808 
809  /* Set the joystick to non-blocking read mode */
810  fcntl(fd, F_SETFL, O_NONBLOCK);
811 
812  /* Get the number of buttons and axes on the joystick */
813  ConfigJoystick(joystick, fd);
814  }
815 
816  SDL_assert(item->hwdata == NULL);
817  item->hwdata = joystick->hwdata;
818 
819  /* mark joystick as fresh and ready */
820  joystick->hwdata->fresh = 1;
821 
822  return (0);
823 }
824 
825 static int
826 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
827 {
828  struct input_event event;
829 
830  if (joystick->hwdata->ff_rumble) {
831  struct ff_effect *effect = &joystick->hwdata->effect;
832 
833  effect->type = FF_RUMBLE;
834  effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
835  effect->u.rumble.strong_magnitude = low_frequency_rumble;
836  effect->u.rumble.weak_magnitude = high_frequency_rumble;
837  } else if (joystick->hwdata->ff_sine) {
838  /* Scale and average the two rumble strengths */
839  Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
840  struct ff_effect *effect = &joystick->hwdata->effect;
841 
842  effect->type = FF_PERIODIC;
843  effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
844  effect->u.periodic.waveform = FF_SINE;
845  effect->u.periodic.magnitude = magnitude;
846  } else {
847  return SDL_Unsupported();
848  }
849 
850  if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
851  /* The kernel may have lost this effect, try to allocate a new one */
852  joystick->hwdata->effect.id = -1;
853  if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
854  return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
855  }
856  }
857 
858  event.type = EV_FF;
859  event.code = joystick->hwdata->effect.id;
860  event.value = 1;
861  if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
862  return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
863  }
864  return 0;
865 }
866 
867 static SDL_INLINE void
868 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
869 {
870  struct hwdata_hat *the_hat;
871  const Uint8 position_map[3][3] = {
875  };
876 
877  the_hat = &stick->hwdata->hats[hat];
878  if (value < 0) {
879  value = 0;
880  } else if (value == 0) {
881  value = 1;
882  } else if (value > 0) {
883  value = 2;
884  }
885  if (value != the_hat->axis[axis]) {
886  the_hat->axis[axis] = value;
887  SDL_PrivateJoystickHat(stick, hat,
888  position_map[the_hat->axis[1]][the_hat->axis[0]]);
889  }
890 }
891 
892 static SDL_INLINE void
893 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
894 {
895  stick->hwdata->balls[ball].axis[axis] += value;
896 }
897 
898 
899 static SDL_INLINE int
900 AxisCorrect(SDL_Joystick * joystick, int which, int value)
901 {
902  struct axis_correct *correct;
903 
904  correct = &joystick->hwdata->abs_correct[which];
905  if (correct->used) {
906  value *= 2;
907  if (value > correct->coef[0]) {
908  if (value < correct->coef[1]) {
909  return 0;
910  }
911  value -= correct->coef[1];
912  } else {
913  value -= correct->coef[0];
914  }
915  value *= correct->coef[2];
916  value >>= 13;
917  }
918 
919  /* Clamp and return */
920  if (value < -32768)
921  return -32768;
922  if (value > 32767)
923  return 32767;
924 
925  return value;
926 }
927 
928 static SDL_INLINE void
929 PollAllValues(SDL_Joystick * joystick)
930 {
931  struct input_absinfo absinfo;
932  int i;
933 
934  /* Poll all axis */
935  for (i = ABS_X; i < ABS_MAX; i++) {
936  if (i == ABS_HAT0X) {
937  i = ABS_HAT3Y;
938  continue;
939  }
940  if (joystick->hwdata->abs_correct[i].used) {
941  if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
942  absinfo.value = AxisCorrect(joystick, i, absinfo.value);
943 
944 #ifdef DEBUG_INPUT_EVENTS
945  printf("Joystick : Re-read Axis %d (%d) val= %d\n",
946  joystick->hwdata->abs_map[i], i, absinfo.value);
947 #endif
948  SDL_PrivateJoystickAxis(joystick,
949  joystick->hwdata->abs_map[i],
950  absinfo.value);
951  }
952  }
953  }
954 }
955 
956 static SDL_INLINE void
957 HandleInputEvents(SDL_Joystick * joystick)
958 {
959  struct input_event events[32];
960  int i, len;
961  int code;
962 
963  if (joystick->hwdata->fresh) {
964  PollAllValues(joystick);
965  joystick->hwdata->fresh = 0;
966  }
967 
968  while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
969  len /= sizeof(events[0]);
970  for (i = 0; i < len; ++i) {
971  code = events[i].code;
972  switch (events[i].type) {
973  case EV_KEY:
974  SDL_PrivateJoystickButton(joystick,
975  joystick->hwdata->key_map[code],
976  events[i].value);
977  break;
978  case EV_ABS:
979  switch (code) {
980  case ABS_HAT0X:
981  case ABS_HAT0Y:
982  case ABS_HAT1X:
983  case ABS_HAT1Y:
984  case ABS_HAT2X:
985  case ABS_HAT2Y:
986  case ABS_HAT3X:
987  case ABS_HAT3Y:
988  code -= ABS_HAT0X;
989  HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
990  break;
991  default:
992  if (joystick->hwdata->abs_map[code] != 0xFF) {
993  events[i].value =
994  AxisCorrect(joystick, code, events[i].value);
995  SDL_PrivateJoystickAxis(joystick,
996  joystick->hwdata->abs_map[code],
997  events[i].value);
998  }
999  break;
1000  }
1001  break;
1002  case EV_REL:
1003  switch (code) {
1004  case REL_X:
1005  case REL_Y:
1006  code -= REL_X;
1007  HandleBall(joystick, code / 2, code % 2, events[i].value);
1008  break;
1009  default:
1010  break;
1011  }
1012  break;
1013  case EV_SYN:
1014  switch (code) {
1015  case SYN_DROPPED :
1016 #ifdef DEBUG_INPUT_EVENTS
1017  printf("Event SYN_DROPPED detected\n");
1018 #endif
1019  PollAllValues(joystick);
1020  break;
1021  default:
1022  break;
1023  }
1024  default:
1025  break;
1026  }
1027  }
1028  }
1029 
1030  if (errno == ENODEV) {
1031  /* We have to wait until the JoystickDetect callback to remove this */
1032  joystick->hwdata->gone = SDL_TRUE;
1033  }
1034 }
1035 
1036 static void
1037 LINUX_JoystickUpdate(SDL_Joystick * joystick)
1038 {
1039  int i;
1040 
1041  if (joystick->hwdata->m_bSteamController) {
1042  SDL_UpdateSteamController(joystick);
1043  return;
1044  }
1045 
1046  HandleInputEvents(joystick);
1047 
1048  /* Deliver ball motion updates */
1049  for (i = 0; i < joystick->nballs; ++i) {
1050  int xrel, yrel;
1051 
1052  xrel = joystick->hwdata->balls[i].axis[0];
1053  yrel = joystick->hwdata->balls[i].axis[1];
1054  if (xrel || yrel) {
1055  joystick->hwdata->balls[i].axis[0] = 0;
1056  joystick->hwdata->balls[i].axis[1] = 0;
1057  SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1058  }
1059  }
1060 }
1061 
1062 /* Function to close a joystick after use */
1063 static void
1064 LINUX_JoystickClose(SDL_Joystick * joystick)
1065 {
1066  if (joystick->hwdata) {
1067  if (joystick->hwdata->effect.id >= 0) {
1068  ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1069  joystick->hwdata->effect.id = -1;
1070  }
1071  if (joystick->hwdata->fd >= 0) {
1072  close(joystick->hwdata->fd);
1073  }
1074  if (joystick->hwdata->item) {
1075  joystick->hwdata->item->hwdata = NULL;
1076  }
1077  SDL_free(joystick->hwdata->hats);
1078  SDL_free(joystick->hwdata->balls);
1079  SDL_free(joystick->hwdata->fname);
1080  SDL_free(joystick->hwdata);
1081  }
1082 }
1083 
1084 /* Function to perform any system-specific joystick related cleanup */
1085 static void
1086 LINUX_JoystickQuit(void)
1087 {
1088  SDL_joylist_item *item = NULL;
1089  SDL_joylist_item *next = NULL;
1090 
1091  for (item = SDL_joylist; item; item = next) {
1092  next = item->next;
1093  SDL_free(item->path);
1094  SDL_free(item->name);
1095  SDL_free(item);
1096  }
1097 
1098  SDL_joylist = SDL_joylist_tail = NULL;
1099 
1100  numjoysticks = 0;
1101 
1102 #if SDL_USE_LIBUDEV
1103  SDL_UDEV_DelCallback(joystick_udev_callback);
1104  SDL_UDEV_Quit();
1105 #endif
1106 
1108 }
1109 
1110 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
1111 {
1112  LINUX_JoystickInit,
1113  LINUX_JoystickGetCount,
1114  LINUX_JoystickDetect,
1115  LINUX_JoystickGetDeviceName,
1116  LINUX_JoystickGetDevicePlayerIndex,
1117  LINUX_JoystickSetDevicePlayerIndex,
1118  LINUX_JoystickGetDeviceGUID,
1119  LINUX_JoystickGetDeviceInstanceID,
1120  LINUX_JoystickOpen,
1121  LINUX_JoystickRumble,
1122  LINUX_JoystickUpdate,
1123  LINUX_JoystickClose,
1124  LINUX_JoystickQuit,
1125 };
1126 
1127 #endif /* SDL_JOYSTICK_LINUX */
1128 
1129 /* vi: set ts=4 sw=4 expandtab: */
SDL_ShouldIgnoreJoystick
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
Definition: SDL_joystick.c:1698
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_MAX_RUMBLE_DURATION_MS
#define SDL_MAX_RUMBLE_DURATION_MS
Definition: SDL_sysjoystick.h:143
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
SDL_GetCustomJoystickName
const char * SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product)
Definition: SDL_joystick.c:1386
numjoysticks
static int numjoysticks
Definition: SDL_sysjoystick.m:83
SDL_HAT_CENTERED
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:339
NULL
#define NULL
Definition: begin_code.h:167
SDL_HAT_DOWN
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:342
SDL_timer.h
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1112
SDL_joystick.h
SDL_zerop
#define SDL_zerop(x)
Definition: SDL_stdinc.h:419
SDL_InitSteamControllers
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
Definition: SDL_steamcontroller.c:28
SDL_PrivateJoystickAdded
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:921
HIDAPI_IsDevicePresent
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
joystick_hwdata::joystick
SDL_Joystick * joystick
Definition: SDL_sysjoystick_c.h:42
SDL_GetNextJoystickInstanceID
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:250
SDL_endian.h
SDL_JoystickGUID::data
Uint8 data[16]
Definition: SDL_joystick.h:71
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3733
SDL_strncmp
#define SDL_strncmp
Definition: SDL_dynapi_overrides.h:418
a
GLboolean GLboolean GLboolean GLboolean a
Definition: SDL_opengl_glext.h:1112
SDL_SwapLE16
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:244
SDL_HAT_LEFTDOWN
#define SDL_HAT_LEFTDOWN
Definition: SDL_joystick.h:347
SDL_PrivateJoystickRemoved
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
Definition: SDL_joystick.c:987
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:1023
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
Sint16
int16_t Sint16
Definition: SDL_stdinc.h:185
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2929
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2652
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_strchr
#define SDL_strchr
Definition: SDL_dynapi_overrides.h:401
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_INLINE
#define SDL_INLINE
Definition: begin_code.h:134
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
t
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:1162
SDL_QuitSteamControllers
void SDL_QuitSteamControllers(void)
Definition: SDL_steamcontroller.c:48
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_HAT_LEFT
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:343
SDL_assert.h
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
SDL_memmove
#define SDL_memmove
Definition: SDL_dynapi_overrides.h:388
SDL_PrivateJoystickBall
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
Definition: SDL_joystick.c:1126
SDL_HAT_LEFTUP
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:346
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_PrivateJoystickHat
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:1086
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
events
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:39
SDL_getenv
#define SDL_getenv
Definition: SDL_dynapi_overrides.h:378
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_HAT_RIGHT
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:341
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:701
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_UpdateSteamControllers
void SDL_UpdateSteamControllers(void)
Definition: SDL_steamcontroller.c:40
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:40
joystick_hwdata::item
struct SDL_joylist_item * item
Definition: SDL_sysjoystick_c.h:33
SDL_strdup
#define SDL_strdup
Definition: SDL_dynapi_overrides.h:397
SDL_GetSteamControllerInputs
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
Definition: SDL_steamcontroller.c:33
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
SDL_LINUX_JoystickDriver
SDL_JoystickDriver SDL_LINUX_JoystickDriver
SDL_TICKS_PASSED
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
SDL_HAT_UP
#define SDL_HAT_UP
Definition: SDL_joystick.h:340
SDL_Unsupported
#define SDL_Unsupported()
Definition: SDL_error.h:53
SDL_malloc
#define SDL_malloc
Definition: SDL_dynapi_overrides.h:374
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_JoystickGUID
Definition: SDL_joystick.h:70
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_HAT_RIGHTDOWN
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:345
i
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_HAT_RIGHTUP
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:344
SDL_UpdateSteamController
void SDL_UpdateSteamController(SDL_Joystick *joystick)
Definition: SDL_steamcontroller.c:44
joystick_hwdata
Definition: SDL_sysjoystick_c.h:46
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179