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>
37 #include <linux/joystick.h>
42 #include "../../events/SDL_events_c.h"
43 #include "../SDL_sysjoystick.h"
44 #include "../SDL_joystick_c.h"
45 #include "../steam/SDL_steamcontroller.h"
46 #include "SDL_sysjoystick_c.h"
47 #include "../hidapi/SDL_hidapijoystick_c.h"
54 #include "../../core/linux/SDL_udev.h"
56 static int MaybeAddDevice(
const char *
path);
58 static int MaybeRemoveDevice(
const char *
path);
59 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath);
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 #define test_bit(nr, addr) \
84 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
85 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
93 static Uint32 joystick_blacklist[] = {
182 struct input_id inpid;
189 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
190 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
191 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
193 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
194 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
195 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
199 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
200 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
205 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
209 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
213 #ifdef SDL_JOYSTICK_HIDAPI
223 if (
id == joystick_blacklist[i]) {
228 #ifdef DEBUG_JOYSTICK
229 printf(
"Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
239 if (inpid.vendor && inpid.product) {
257 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
259 if (devpath ==
NULL) {
264 case SDL_UDEV_DEVICEADDED:
265 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
268 MaybeAddDevice(devpath);
271 case SDL_UDEV_DEVICEREMOVED:
272 MaybeRemoveDevice(devpath);
285 MaybeAddDevice(
const char *
path)
292 SDL_joylist_item *item;
298 if (stat(path, &sb) == -1) {
303 for (item = SDL_joylist; item !=
NULL; item = item->next) {
304 if (sb.st_rdev == item->devnum) {
309 fd = open(path, O_RDONLY, 0);
314 #ifdef DEBUG_INPUT_EVENTS
315 printf(
"Checking %s\n", path);
318 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
324 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
330 item->devnum = sb.st_rdev;
335 if ((item->path ==
NULL) || (item->name ==
NULL)) {
343 if (SDL_joylist_tail ==
NULL) {
344 SDL_joylist = SDL_joylist_tail = item;
346 SDL_joylist_tail->next = item;
347 SDL_joylist_tail = item;
361 MaybeRemoveDevice(
const char *path)
363 SDL_joylist_item *item;
364 SDL_joylist_item *prev =
NULL;
370 for (item = SDL_joylist; item !=
NULL; item = item->next) {
373 const int retval = item->device_instance;
375 item->hwdata->item =
NULL;
378 prev->next = item->next;
381 SDL_joylist = item->next;
383 if (item == SDL_joylist_tail) {
384 SDL_joylist_tail = prev;
404 #if ! SDL_USE_LIBUDEV
406 JoystickInitWithoutUdev(
void)
414 for (i = 0; i < 32; i++) {
416 MaybeAddDevice(path);
425 JoystickInitWithUdev(
void)
427 if (SDL_UDEV_Init() < 0) {
432 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
434 return SDL_SetError(
"Could not set up joystick <-> udev callback");
446 SDL_joylist_item *item;
448 item = (SDL_joylist_item *)
SDL_calloc(1,
sizeof (SDL_joylist_item));
456 item->m_bSteamController =
SDL_TRUE;
458 if ((item->path ==
NULL) || (item->name ==
NULL)) {
466 if (SDL_joylist_tail ==
NULL) {
467 SDL_joylist = SDL_joylist_tail = item;
469 SDL_joylist_tail->next = item;
470 SDL_joylist_tail = item;
481 static void SteamControllerDisconnectedCallback(
int device_instance)
483 SDL_joylist_item *item;
484 SDL_joylist_item *prev =
NULL;
486 for (item = SDL_joylist; item !=
NULL; item = item->next) {
488 if (item->device_instance == device_instance) {
490 item->hwdata->item =
NULL;
493 prev->next = item->next;
496 SDL_joylist = item->next;
498 if (item == SDL_joylist_tail) {
499 SDL_joylist_tail = prev;
516 LINUX_JoystickInit(
void)
520 char *envcopy, *envpath, *delim;
523 while (envpath !=
NULL) {
528 MaybeAddDevice(envpath);
535 SteamControllerDisconnectedCallback);
538 return JoystickInitWithUdev();
540 return JoystickInitWithoutUdev();
545 LINUX_JoystickGetCount(
void)
551 LINUX_JoystickDetect(
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_JoystickGetDeviceGUID(
int device_index )
594 return JoystickByDevIndex(device_index)->guid;
599 LINUX_JoystickGetDeviceInstanceID(
int device_index)
601 return JoystickByDevIndex(device_index)->device_instance;
605 allocate_hatdata(SDL_Joystick * joystick)
609 joystick->hwdata->hats =
610 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
611 sizeof(
struct hwdata_hat));
612 if (joystick->hwdata->hats ==
NULL) {
615 for (i = 0; i < joystick->nhats; ++
i) {
616 joystick->hwdata->hats[
i].axis[0] = 1;
617 joystick->hwdata->hats[
i].axis[1] = 1;
623 allocate_balldata(SDL_Joystick * joystick)
627 joystick->hwdata->balls =
628 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
629 sizeof(
struct hwdata_ball));
630 if (joystick->hwdata->balls ==
NULL) {
633 for (i = 0; i < joystick->nballs; ++
i) {
634 joystick->hwdata->balls[
i].axis[0] = 0;
635 joystick->hwdata->balls[
i].axis[1] = 0;
641 ConfigJoystick(SDL_Joystick * joystick,
int fd)
644 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
645 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
646 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
647 unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
650 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
651 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
652 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
655 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
656 if (test_bit(i, keybit)) {
657 #ifdef DEBUG_INPUT_EVENTS
658 printf(
"Joystick has button: 0x%x\n", i);
660 joystick->hwdata->key_map[
i] = joystick->nbuttons;
661 ++joystick->nbuttons;
664 for (i = 0; i < BTN_JOYSTICK; ++
i) {
665 if (test_bit(i, keybit)) {
666 #ifdef DEBUG_INPUT_EVENTS
667 printf(
"Joystick has button: 0x%x\n", i);
669 joystick->hwdata->key_map[
i] = joystick->nbuttons;
670 ++joystick->nbuttons;
673 for (i = 0; i < ABS_MAX; ++
i) {
675 if (i == ABS_HAT0X) {
679 if (test_bit(i, absbit)) {
680 struct input_absinfo absinfo;
682 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
685 #ifdef DEBUG_INPUT_EVENTS
686 printf(
"Joystick has absolute axis: 0x%.2x\n", i);
687 printf(
"Values = { %d, %d, %d, %d, %d }\n",
688 absinfo.value, absinfo.minimum, absinfo.maximum,
689 absinfo.fuzz, absinfo.flat);
691 joystick->hwdata->abs_map[
i] = joystick->naxes;
692 if (absinfo.minimum == absinfo.maximum) {
693 joystick->hwdata->abs_correct[
i].used = 0;
695 joystick->hwdata->abs_correct[
i].used = 1;
696 joystick->hwdata->abs_correct[
i].coef[0] =
697 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
698 joystick->hwdata->abs_correct[i].coef[1] =
699 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
700 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
702 joystick->hwdata->abs_correct[
i].coef[2] =
705 joystick->hwdata->abs_correct[
i].coef[2] = 0;
711 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
712 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
713 struct input_absinfo absinfo;
715 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
718 #ifdef DEBUG_INPUT_EVENTS
719 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
720 printf(
"Values = { %d, %d, %d, %d, %d }\n",
721 absinfo.value, absinfo.minimum, absinfo.maximum,
722 absinfo.fuzz, absinfo.flat);
727 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
732 if (joystick->nhats > 0) {
733 if (allocate_hatdata(joystick) < 0) {
737 if (joystick->nballs > 0) {
738 if (allocate_balldata(joystick) < 0) {
739 joystick->nballs = 0;
744 if (ioctl(fd, EVIOCGBIT(EV_FF,
sizeof(ffbit)), ffbit) >= 0) {
745 if (test_bit(FF_RUMBLE, ffbit)) {
746 joystick->hwdata->ff_rumble =
SDL_TRUE;
748 if (test_bit(FF_SINE, ffbit)) {
749 joystick->hwdata->ff_sine =
SDL_TRUE;
761 LINUX_JoystickOpen(SDL_Joystick * joystick,
int device_index)
763 SDL_joylist_item *item = JoystickByDevIndex(device_index);
769 joystick->instance_id = item->device_instance;
772 if (joystick->hwdata ==
NULL) {
775 joystick->hwdata->item =
item;
776 joystick->hwdata->guid = item->guid;
777 joystick->hwdata->effect.id = -1;
778 joystick->hwdata->m_bSteamController = item->m_bSteamController;
780 if (item->m_bSteamController) {
781 joystick->hwdata->fd = -1;
786 int fd = open(item->path, O_RDWR, 0);
789 joystick->hwdata =
NULL;
793 joystick->hwdata->fd =
fd;
794 joystick->hwdata->fname =
SDL_strdup(item->path);
795 if (joystick->hwdata->fname ==
NULL) {
797 joystick->hwdata =
NULL;
803 fcntl(fd, F_SETFL, O_NONBLOCK);
806 ConfigJoystick(joystick, fd);
810 item->hwdata = joystick->hwdata;
813 joystick->hwdata->fresh = 1;
819 LINUX_JoystickRumble(SDL_Joystick * joystick,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble,
Uint32 duration_ms)
821 struct input_event
event;
823 if (joystick->hwdata->ff_rumble) {
824 struct ff_effect *effect = &joystick->hwdata->effect;
826 effect->type = FF_RUMBLE;
827 effect->replay.length =
SDL_min(duration_ms, 32767);
828 effect->u.rumble.strong_magnitude = low_frequency_rumble;
829 effect->u.rumble.weak_magnitude = high_frequency_rumble;
830 }
else if (joystick->hwdata->ff_sine) {
832 Sint16 magnitude = (
Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
833 struct ff_effect *effect = &joystick->hwdata->effect;
835 effect->type = FF_PERIODIC;
836 effect->replay.length =
SDL_min(duration_ms, 32767);
837 effect->u.periodic.waveform = FF_SINE;
838 effect->u.periodic.magnitude = magnitude;
843 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
844 return SDL_SetError(
"Couldn't update rumble effect: %s", strerror(errno));
848 event.code = joystick->hwdata->effect.id;
850 if (write(joystick->hwdata->fd, &
event,
sizeof(
event)) < 0) {
851 return SDL_SetError(
"Couldn't start rumble effect: %s", strerror(errno));
859 struct hwdata_hat *the_hat;
860 const Uint8 position_map[3][3] = {
866 the_hat = &stick->hwdata->hats[hat];
869 }
else if (value == 0) {
871 }
else if (value > 0) {
874 if (value != the_hat->axis[axis]) {
877 position_map[the_hat->
878 axis[1]][the_hat->axis[0]]);
883 HandleBall(SDL_Joystick * stick,
Uint8 ball,
int axis,
int value)
885 stick->hwdata->balls[ball].axis[
axis] +=
value;
890 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
892 struct axis_correct *correct;
894 correct = &joystick->hwdata->abs_correct[which];
897 if (value > correct->coef[0]) {
901 value -= correct->coef[1];
903 value -= correct->coef[0];
905 value *= correct->coef[2];
919 PollAllValues(SDL_Joystick * joystick)
921 struct input_absinfo absinfo;
925 for (a = ABS_X; b < ABS_MAX; a++) {
938 if (joystick->hwdata->abs_correct[b].used) {
939 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
940 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
942 #ifdef DEBUG_INPUT_EVENTS
943 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
944 joystick->hwdata->abs_map[b], a, absinfo.value);
947 joystick->hwdata->abs_map[b],
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, code / 2, code % 2,
events[i].value);
993 AxisCorrect(joystick, code,
events[i].value);
995 joystick->hwdata->abs_map[code],
1005 HandleBall(joystick, code / 2, code % 2,
events[i].value);
1014 #ifdef DEBUG_INPUT_EVENTS
1015 printf(
"Event SYN_DROPPED detected\n");
1017 PollAllValues(joystick);
1030 LINUX_JoystickUpdate(SDL_Joystick * joystick)
1034 if (joystick->hwdata->m_bSteamController) {
1039 HandleInputEvents(joystick);
1042 for (i = 0; i < joystick->nballs; ++
i) {
1045 xrel = joystick->hwdata->balls[
i].axis[0];
1046 yrel = joystick->hwdata->balls[
i].axis[1];
1048 joystick->hwdata->balls[
i].axis[0] = 0;
1049 joystick->hwdata->balls[
i].axis[1] = 0;
1057 LINUX_JoystickClose(SDL_Joystick * joystick)
1059 if (joystick->hwdata) {
1060 if (joystick->hwdata->effect.id >= 0) {
1061 ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1062 joystick->hwdata->effect.id = -1;
1064 if (joystick->hwdata->fd >= 0) {
1065 close(joystick->hwdata->fd);
1067 if (joystick->hwdata->item) {
1068 joystick->hwdata->item->hwdata =
NULL;
1079 LINUX_JoystickQuit(
void)
1081 SDL_joylist_item *item =
NULL;
1082 SDL_joylist_item *next =
NULL;
1084 for (item = SDL_joylist; item; item = next) {
1091 SDL_joylist = SDL_joylist_tail =
NULL;
1096 SDL_UDEV_DelCallback(joystick_udev_callback);
1106 LINUX_JoystickGetCount,
1107 LINUX_JoystickDetect,
1108 LINUX_JoystickGetDeviceName,
1109 LINUX_JoystickGetDevicePlayerIndex,
1110 LINUX_JoystickGetDeviceGUID,
1111 LINUX_JoystickGetDeviceInstanceID,
1113 LINUX_JoystickRumble,
1114 LINUX_JoystickUpdate,
1115 LINUX_JoystickClose,
void SDL_UpdateSteamControllers(void)
#define MAKE_VIDPID(VID, PID)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback, SteamControllerDisconnectedCallback_t disconnectedCallback)
void SDL_QuitSteamControllers(void)
static SDL_Event events[EVENT_BUF_SIZE]
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
GLuint const GLchar * name
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)
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
GLsizei const GLfloat * value
SDL_JoystickDriver SDL_LINUX_JoystickDriver
#define SDL_assert(condition)
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
void SDL_UpdateSteamController(SDL_Joystick *joystick)
#define SDL_OutOfMemory()
SDL_JoystickID SDL_GetNextJoystickInstanceID()
struct SDL_joylist_item * item
GLuint GLuint GLsizei GLenum type
void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
#define SDL_arraysize(array)
GLsizei const GLchar *const * path
GLboolean GLboolean GLboolean GLboolean a
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version)
GLboolean GLboolean GLboolean b
#define SDL_Unsupported()