21 #include "../../SDL_internal.h"
23 #ifdef SDL_JOYSTICK_LINUX
25 #ifndef SDL_INPUT_LINUXEV
26 #error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
35 #include <sys/ioctl.h>
38 #include <linux/joystick.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"
56 #include "../../core/linux/SDL_udev.h"
58 static int MaybeAddDevice(
const char *
path);
60 static int MaybeRemoveDevice(
const char *
path);
64 typedef struct SDL_joylist_item
72 struct SDL_joylist_item *next;
78 static SDL_joylist_item *SDL_joylist =
NULL;
79 static SDL_joylist_item *SDL_joylist_tail =
NULL;
83 static Uint32 last_joy_detect_time;
84 static time_t last_input_dir_mtime;
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)
92 PrefixMatch(
const char *
a,
const char *
b)
106 FixupDeviceInfoForMapping(
int fd,
struct input_id *inpid)
108 if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
110 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
113 if ((ioctl(
fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
114 test_bit(0x2c0, keybit)) {
116 inpid->version = 0x0902;
125 struct input_id inpid;
132 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
133 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
134 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
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)) {
142 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
143 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
148 if (ioctl(
fd, EVIOCGID, &inpid) < 0) {
156 if (ioctl(
fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
161 for (spot = namebuf + 1; *spot; ++spot) {
162 int matchlen = PrefixMatch(namebuf, spot);
163 if (matchlen > 0 && spot[matchlen - 1] ==
' ') {
170 #ifdef SDL_JOYSTICK_HIDAPI
177 FixupDeviceInfoForMapping(
fd, &inpid);
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);
190 if (inpid.vendor && inpid.product) {
208 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
210 if (devpath ==
NULL) {
215 case SDL_UDEV_DEVICEADDED:
216 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
219 MaybeAddDevice(devpath);
222 case SDL_UDEV_DEVICEREMOVED:
223 MaybeRemoveDevice(devpath);
234 MaybeAddDevice(
const char *
path)
241 SDL_joylist_item *item;
247 if (stat(
path, &sb) == -1) {
252 for (item = SDL_joylist; item !=
NULL; item = item->next) {
253 if (sb.st_rdev == item->devnum) {
258 fd = open(
path, O_RDONLY, 0);
263 #ifdef DEBUG_INPUT_EVENTS
264 printf(
"Checking %s\n",
path);
267 isstick = IsJoystick(
fd, namebuf,
sizeof (namebuf), &guid);
273 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
279 item->devnum = sb.st_rdev;
284 if ((item->path ==
NULL) || (item->name ==
NULL)) {
292 if (SDL_joylist_tail ==
NULL) {
293 SDL_joylist = SDL_joylist_tail = item;
295 SDL_joylist_tail->next = item;
296 SDL_joylist_tail = item;
309 MaybeRemoveDevice(
const char *
path)
311 SDL_joylist_item *item;
312 SDL_joylist_item *prev =
NULL;
318 for (item = SDL_joylist; item !=
NULL; item = item->next) {
321 const int retval = item->device_instance;
323 item->hwdata->item =
NULL;
326 prev->next = item->next;
329 SDL_joylist = item->next;
331 if (item == SDL_joylist_tail) {
332 SDL_joylist_tail = prev;
353 HandlePendingRemovals(
void)
355 SDL_joylist_item *prev =
NULL;
356 SDL_joylist_item *item = SDL_joylist;
358 while (item !=
NULL) {
359 if (item->hwdata && item->hwdata->gone) {
360 item->hwdata->item =
NULL;
363 prev->next = item->next;
366 SDL_joylist = item->next;
368 if (item == SDL_joylist_tail) {
369 SDL_joylist_tail = prev;
395 SDL_joylist_item *item;
397 item = (SDL_joylist_item *)
SDL_calloc(1,
sizeof (SDL_joylist_item));
405 item->m_bSteamController =
SDL_TRUE;
407 if ((item->path ==
NULL) || (item->name ==
NULL)) {
415 if (SDL_joylist_tail ==
NULL) {
416 SDL_joylist = SDL_joylist_tail = item;
418 SDL_joylist_tail->next = item;
419 SDL_joylist_tail = item;
430 static void SteamControllerDisconnectedCallback(
int device_instance)
432 SDL_joylist_item *item;
433 SDL_joylist_item *prev =
NULL;
435 for (item = SDL_joylist; item !=
NULL; item = item->next) {
437 if (item->device_instance == device_instance) {
439 item->hwdata->item =
NULL;
442 prev->next = item->next;
445 SDL_joylist = item->next;
447 if (item == SDL_joylist_tail) {
448 SDL_joylist_tail = prev;
465 LINUX_JoystickDetect(
void)
470 const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000;
473 if (!last_joy_detect_time ||
SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
477 if (stat(
"/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
481 folder = opendir(
"/dev/input");
483 while ((dent = readdir(folder))) {
488 MaybeAddDevice(
path);
495 last_input_dir_mtime = sb.st_mtime;
498 last_joy_detect_time = now;
502 HandlePendingRemovals();
508 LINUX_JoystickInit(
void)
512 char *envcopy, *envpath, *delim;
515 while (envpath !=
NULL) {
520 MaybeAddDevice(envpath);
527 SteamControllerDisconnectedCallback);
530 if (SDL_UDEV_Init() < 0) {
535 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
537 return SDL_SetError(
"Could not set up joystick <-> udev callback");
544 last_joy_detect_time = 0;
545 last_input_dir_mtime = 0;
548 LINUX_JoystickDetect();
555 LINUX_JoystickGetCount(
void)
560 static SDL_joylist_item *
561 JoystickByDevIndex(
int device_index)
563 SDL_joylist_item *item = SDL_joylist;
565 if ((device_index < 0) || (device_index >=
numjoysticks)) {
569 while (device_index > 0) {
580 LINUX_JoystickGetDeviceName(
int device_index)
582 return JoystickByDevIndex(device_index)->name;
586 LINUX_JoystickGetDevicePlayerIndex(
int device_index)
592 LINUX_JoystickSetDevicePlayerIndex(
int device_index,
int player_index)
597 LINUX_JoystickGetDeviceGUID(
int device_index )
599 return JoystickByDevIndex(device_index)->guid;
604 LINUX_JoystickGetDeviceInstanceID(
int device_index)
606 return JoystickByDevIndex(device_index)->device_instance;
610 allocate_hatdata(SDL_Joystick * joystick)
614 joystick->hwdata->hats =
615 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
616 sizeof(
struct hwdata_hat));
617 if (joystick->hwdata->hats ==
NULL) {
620 for (
i = 0;
i < joystick->nhats; ++
i) {
621 joystick->hwdata->hats[
i].axis[0] = 1;
622 joystick->hwdata->hats[
i].axis[1] = 1;
628 allocate_balldata(SDL_Joystick * joystick)
632 joystick->hwdata->balls =
633 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
634 sizeof(
struct hwdata_ball));
635 if (joystick->hwdata->balls ==
NULL) {
638 for (
i = 0;
i < joystick->nballs; ++
i) {
639 joystick->hwdata->balls[
i].axis[0] = 0;
640 joystick->hwdata->balls[
i].axis[1] = 0;
646 ConfigJoystick(SDL_Joystick * joystick,
int fd)
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 };
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)) {
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);
665 joystick->hwdata->key_map[
i] = joystick->nbuttons;
666 ++joystick->nbuttons;
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);
674 joystick->hwdata->key_map[
i] = joystick->nbuttons;
675 ++joystick->nbuttons;
678 for (
i = 0;
i < ABS_MAX; ++
i) {
680 if (
i == ABS_HAT0X) {
684 if (test_bit(
i, absbit)) {
685 struct input_absinfo absinfo;
687 if (ioctl(
fd, EVIOCGABS(
i), &absinfo) < 0) {
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);
696 joystick->hwdata->abs_map[
i] = joystick->naxes;
697 if (absinfo.minimum == absinfo.maximum) {
698 joystick->hwdata->abs_correct[
i].used = 0;
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);
707 joystick->hwdata->abs_correct[
i].coef[2] =
710 joystick->hwdata->abs_correct[
i].coef[2] = 0;
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;
721 if (ioctl(
fd, EVIOCGABS(
i), &absinfo) < 0) {
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);
730 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
733 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
738 if (joystick->nhats > 0) {
739 if (allocate_hatdata(joystick) < 0) {
743 if (joystick->nballs > 0) {
744 if (allocate_balldata(joystick) < 0) {
745 joystick->nballs = 0;
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;
754 if (test_bit(FF_SINE, ffbit)) {
755 joystick->hwdata->ff_sine =
SDL_TRUE;
767 LINUX_JoystickOpen(SDL_Joystick * joystick,
int device_index)
769 SDL_joylist_item *item = JoystickByDevIndex(device_index);
775 joystick->instance_id = item->device_instance;
784 joystick->hwdata->m_bSteamController =
item->m_bSteamController;
787 if (
item->m_bSteamController) {
793 int fd = open(
item->path, O_RDWR, 0);
810 fcntl(
fd, F_SETFL, O_NONBLOCK);
826 LINUX_JoystickRumble(SDL_Joystick *
joystick,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble)
828 struct input_event
event;
830 if (joystick->hwdata->ff_rumble) {
831 struct ff_effect *effect = &joystick->hwdata->effect;
833 effect->type = FF_RUMBLE;
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) {
839 Sint16 magnitude = (
Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
840 struct ff_effect *effect = &joystick->hwdata->effect;
842 effect->type = FF_PERIODIC;
844 effect->u.periodic.waveform = FF_SINE;
845 effect->u.periodic.magnitude = magnitude;
850 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
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));
859 event.code = joystick->hwdata->effect.id;
861 if (write(joystick->hwdata->fd, &
event,
sizeof(
event)) < 0) {
862 return SDL_SetError(
"Couldn't start rumble effect: %s", strerror(errno));
870 struct hwdata_hat *the_hat;
871 const Uint8 position_map[3][3] = {
877 the_hat = &stick->hwdata->hats[hat];
880 }
else if (
value == 0) {
882 }
else if (
value > 0) {
888 position_map[the_hat->axis[1]][the_hat->axis[0]]);
895 stick->hwdata->balls[ball].axis[
axis] +=
value;
900 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
902 struct axis_correct *correct;
904 correct = &joystick->hwdata->abs_correct[which];
907 if (
value > correct->coef[0]) {
911 value -= correct->coef[1];
913 value -= correct->coef[0];
915 value *= correct->coef[2];
929 PollAllValues(SDL_Joystick * joystick)
931 struct input_absinfo absinfo;
935 for (
i = ABS_X;
i < ABS_MAX;
i++) {
936 if (
i == ABS_HAT0X) {
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);
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);
949 joystick->hwdata->abs_map[
i],
957 HandleInputEvents(SDL_Joystick * joystick)
959 struct input_event
events[32];
963 if (joystick->hwdata->fresh) {
964 PollAllValues(joystick);
965 joystick->hwdata->fresh = 0;
968 while ((
len = read(joystick->hwdata->fd,
events, (
sizeof events))) > 0) {
970 for (
i = 0;
i <
len; ++
i) {
975 joystick->hwdata->key_map[code],
989 HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2,
events[
i].value);
992 if (joystick->hwdata->abs_map[code] != 0xFF) {
996 joystick->hwdata->abs_map[code],
1007 HandleBall(joystick, code / 2, code % 2,
events[
i].
value);
1016 #ifdef DEBUG_INPUT_EVENTS
1017 printf(
"Event SYN_DROPPED detected\n");
1019 PollAllValues(joystick);
1030 if (errno == ENODEV) {
1037 LINUX_JoystickUpdate(SDL_Joystick * joystick)
1041 if (joystick->hwdata->m_bSteamController) {
1046 HandleInputEvents(joystick);
1049 for (
i = 0;
i < joystick->nballs; ++
i) {
1052 xrel = joystick->hwdata->balls[
i].axis[0];
1053 yrel = joystick->hwdata->balls[
i].axis[1];
1055 joystick->hwdata->balls[
i].axis[0] = 0;
1056 joystick->hwdata->balls[
i].axis[1] = 0;
1064 LINUX_JoystickClose(SDL_Joystick * joystick)
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;
1071 if (joystick->hwdata->fd >= 0) {
1072 close(joystick->hwdata->fd);
1074 if (joystick->hwdata->item) {
1075 joystick->hwdata->item->hwdata =
NULL;
1086 LINUX_JoystickQuit(
void)
1088 SDL_joylist_item *item =
NULL;
1089 SDL_joylist_item *next =
NULL;
1091 for (item = SDL_joylist; item; item = next) {
1098 SDL_joylist = SDL_joylist_tail =
NULL;
1103 SDL_UDEV_DelCallback(joystick_udev_callback);
1113 LINUX_JoystickGetCount,
1114 LINUX_JoystickDetect,
1115 LINUX_JoystickGetDeviceName,
1116 LINUX_JoystickGetDevicePlayerIndex,
1117 LINUX_JoystickSetDevicePlayerIndex,
1118 LINUX_JoystickGetDeviceGUID,
1119 LINUX_JoystickGetDeviceInstanceID,
1121 LINUX_JoystickRumble,
1122 LINUX_JoystickUpdate,
1123 LINUX_JoystickClose,