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