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. 34 #include <sys/ioctl.h> 36 #include <linux/joystick.h> 41 #include "../SDL_sysjoystick.h" 42 #include "../SDL_joystick_c.h" 43 #include "SDL_sysjoystick_c.h" 50 #include "../../core/linux/SDL_udev.h" 52 static int MaybeAddDevice(
const char *
path);
54 static int MaybeRemoveDevice(
const char *
path);
55 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath);
60 typedef struct SDL_joylist_item
68 struct SDL_joylist_item *next;
71 static SDL_joylist_item *SDL_joylist =
NULL;
72 static SDL_joylist_item *SDL_joylist_tail =
NULL;
74 static int instance_counter = 0;
76 #define test_bit(nr, addr) \ 77 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) 78 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) 86 static Uint32 joystick_blacklist[] = {
175 struct input_id inpid;
182 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
183 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
184 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
186 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
187 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
188 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
192 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
193 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
198 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
202 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
209 if (
id == joystick_blacklist[i]) {
214 #ifdef DEBUG_JOYSTICK 215 printf(
"Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
225 if (inpid.vendor && inpid.product) {
244 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
246 if (devpath ==
NULL) {
251 case SDL_UDEV_DEVICEADDED:
252 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
255 MaybeAddDevice(devpath);
258 case SDL_UDEV_DEVICEREMOVED:
259 MaybeRemoveDevice(devpath);
272 MaybeAddDevice(
const char *
path)
279 SDL_joylist_item *item;
285 if (stat(path, &sb) == -1) {
290 for (item = SDL_joylist; item !=
NULL; item = item->next) {
291 if (sb.st_rdev == item->devnum) {
296 fd = open(path, O_RDONLY, 0);
301 #ifdef DEBUG_INPUT_EVENTS 302 printf(
"Checking %s\n", path);
305 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
311 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
317 item->devnum = sb.st_rdev;
322 if ( (item->path ==
NULL) || (item->name ==
NULL) ) {
329 item->device_instance = instance_counter++;
330 if (SDL_joylist_tail ==
NULL) {
331 SDL_joylist = SDL_joylist_tail = item;
333 SDL_joylist_tail->next = item;
334 SDL_joylist_tail = item;
348 MaybeRemoveDevice(
const char *path)
350 SDL_joylist_item *item;
351 SDL_joylist_item *prev =
NULL;
357 for (item = SDL_joylist; item !=
NULL; item = item->next) {
360 const int retval = item->device_instance;
362 item->hwdata->item =
NULL;
365 prev->next = item->next;
368 SDL_joylist = item->next;
370 if (item == SDL_joylist_tail) {
371 SDL_joylist_tail = prev;
391 #if ! SDL_USE_LIBUDEV 393 JoystickInitWithoutUdev(
void)
401 for (i = 0; i < 32; i++) {
403 MaybeAddDevice(path);
412 JoystickInitWithUdev(
void)
414 if (SDL_UDEV_Init() < 0) {
419 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
421 return SDL_SetError(
"Could not set up joystick <-> udev callback");
436 char *envcopy, *envpath, *delim;
439 while (envpath !=
NULL) {
444 MaybeAddDevice(envpath);
451 return JoystickInitWithUdev();
453 return JoystickInitWithoutUdev();
472 static SDL_joylist_item *
473 JoystickByDevIndex(
int device_index)
475 SDL_joylist_item *item = SDL_joylist;
477 if ((device_index < 0) || (device_index >=
numjoysticks)) {
481 while (device_index > 0) {
494 return JoystickByDevIndex(device_index)->name;
500 return JoystickByDevIndex(device_index)->device_instance;
504 allocate_hatdata(SDL_Joystick * joystick)
508 joystick->hwdata->hats =
509 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
510 sizeof(
struct hwdata_hat));
511 if (joystick->hwdata->hats ==
NULL) {
514 for (i = 0; i < joystick->nhats; ++
i) {
515 joystick->hwdata->hats[
i].axis[0] = 1;
516 joystick->hwdata->hats[
i].axis[1] = 1;
522 allocate_balldata(SDL_Joystick * joystick)
526 joystick->hwdata->balls =
527 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
528 sizeof(
struct hwdata_ball));
529 if (joystick->hwdata->balls ==
NULL) {
532 for (i = 0; i < joystick->nballs; ++
i) {
533 joystick->hwdata->balls[
i].axis[0] = 0;
534 joystick->hwdata->balls[
i].axis[1] = 0;
540 ConfigJoystick(SDL_Joystick * joystick,
int fd)
543 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
544 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
545 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
548 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
549 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
550 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
553 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
554 if (test_bit(i, keybit)) {
555 #ifdef DEBUG_INPUT_EVENTS 556 printf(
"Joystick has button: 0x%x\n", i);
558 joystick->hwdata->key_map[
i] = joystick->nbuttons;
559 ++joystick->nbuttons;
562 for (i = 0; i < BTN_JOYSTICK; ++
i) {
563 if (test_bit(i, keybit)) {
564 #ifdef DEBUG_INPUT_EVENTS 565 printf(
"Joystick has button: 0x%x\n", i);
567 joystick->hwdata->key_map[
i] = joystick->nbuttons;
568 ++joystick->nbuttons;
571 for (i = 0; i < ABS_MAX; ++
i) {
573 if (i == ABS_HAT0X) {
577 if (test_bit(i, absbit)) {
578 struct input_absinfo absinfo;
580 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
583 #ifdef DEBUG_INPUT_EVENTS 584 printf(
"Joystick has absolute axis: 0x%.2x\n", i);
585 printf(
"Values = { %d, %d, %d, %d, %d }\n",
586 absinfo.value, absinfo.minimum, absinfo.maximum,
587 absinfo.fuzz, absinfo.flat);
589 joystick->hwdata->abs_map[
i] = joystick->naxes;
590 if (absinfo.minimum == absinfo.maximum) {
591 joystick->hwdata->abs_correct[
i].used = 0;
593 joystick->hwdata->abs_correct[
i].used = 1;
594 joystick->hwdata->abs_correct[
i].coef[0] =
595 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
596 joystick->hwdata->abs_correct[i].coef[1] =
597 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
598 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
600 joystick->hwdata->abs_correct[
i].coef[2] =
603 joystick->hwdata->abs_correct[
i].coef[2] = 0;
609 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
610 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
611 struct input_absinfo absinfo;
613 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
616 #ifdef DEBUG_INPUT_EVENTS 617 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
618 printf(
"Values = { %d, %d, %d, %d, %d }\n",
619 absinfo.value, absinfo.minimum, absinfo.maximum,
620 absinfo.fuzz, absinfo.flat);
625 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
630 if (joystick->nhats > 0) {
631 if (allocate_hatdata(joystick) < 0) {
635 if (joystick->nballs > 0) {
636 if (allocate_balldata(joystick) < 0) {
637 joystick->nballs = 0;
652 SDL_joylist_item *item = JoystickByDevIndex(device_index);
661 fd = open(fname, O_RDONLY, 0);
666 joystick->instance_id = item->device_instance;
669 if (joystick->hwdata ==
NULL) {
673 SDL_memset(joystick->hwdata, 0,
sizeof(*joystick->hwdata));
674 joystick->hwdata->item =
item;
675 joystick->hwdata->guid = item->guid;
676 joystick->hwdata->fd =
fd;
677 joystick->hwdata->fname =
SDL_strdup(item->path);
678 if (joystick->hwdata->fname ==
NULL) {
680 joystick->hwdata =
NULL;
686 item->hwdata = joystick->hwdata;
689 fcntl(fd, F_SETFL, O_NONBLOCK);
692 ConfigJoystick(joystick, fd);
695 joystick->hwdata->fresh = 1;
703 return joystick->hwdata->item !=
NULL;
709 struct hwdata_hat *the_hat;
710 const Uint8 position_map[3][3] = {
716 the_hat = &stick->hwdata->hats[hat];
719 }
else if (value == 0) {
721 }
else if (value > 0) {
724 if (value != the_hat->axis[axis]) {
727 position_map[the_hat->
728 axis[1]][the_hat->axis[0]]);
733 HandleBall(SDL_Joystick * stick,
Uint8 ball,
int axis,
int value)
735 stick->hwdata->balls[ball].axis[
axis] +=
value;
740 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
742 struct axis_correct *correct;
744 correct = &joystick->hwdata->abs_correct[which];
747 if (value > correct->coef[0]) {
751 value -= correct->coef[1];
753 value -= correct->coef[0];
755 value *= correct->coef[2];
769 PollAllValues(SDL_Joystick * joystick)
771 struct input_absinfo absinfo;
775 for (a = ABS_X; b < ABS_MAX; a++) {
788 if (joystick->hwdata->abs_correct[b].used) {
789 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
790 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
792 #ifdef DEBUG_INPUT_EVENTS 793 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
794 joystick->hwdata->abs_map[b], a, absinfo.value);
797 joystick->hwdata->abs_map[b],
807 HandleInputEvents(SDL_Joystick * joystick)
809 struct input_event
events[32];
813 if (joystick->hwdata->fresh) {
814 PollAllValues(joystick);
815 joystick->hwdata->fresh = 0;
818 while ((len = read(joystick->hwdata->fd,
events, (
sizeof events))) > 0) {
820 for (i = 0; i <
len; ++
i) {
825 joystick->hwdata->key_map[code],
839 HandleHat(joystick, code / 2, code % 2,
events[i].value);
843 AxisCorrect(joystick, code,
events[i].value);
845 joystick->hwdata->abs_map[code],
855 HandleBall(joystick, code / 2, code % 2,
events[i].value);
864 #ifdef DEBUG_INPUT_EVENTS 865 printf(
"Event SYN_DROPPED detected\n");
867 PollAllValues(joystick);
884 HandleInputEvents(joystick);
887 for (i = 0; i < joystick->nballs; ++
i) {
890 xrel = joystick->hwdata->balls[
i].axis[0];
891 yrel = joystick->hwdata->balls[
i].axis[1];
893 joystick->hwdata->balls[
i].axis[0] = 0;
894 joystick->hwdata->balls[
i].axis[1] = 0;
904 if (joystick->hwdata) {
905 close(joystick->hwdata->fd);
906 if (joystick->hwdata->item) {
907 joystick->hwdata->item->hwdata =
NULL;
920 SDL_joylist_item *item =
NULL;
921 SDL_joylist_item *next =
NULL;
923 for (item = SDL_joylist; item; item = next) {
930 SDL_joylist = SDL_joylist_tail =
NULL;
933 instance_counter = 0;
936 SDL_UDEV_DelCallback(joystick_udev_callback);
943 return JoystickByDevIndex(device_index)->guid;
948 return joystick->hwdata->guid;
#define MAKE_VIDPID(VID, PID)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
static SDL_Event events[EVENT_BUF_SIZE]
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
void SDL_SYS_JoystickQuit(void)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
GLuint const GLchar * name
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
void SDL_PrivateJoystickAdded(int device_index)
const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index)
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
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)
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
#define SDL_assert(condition)
int SDL_SYS_JoystickInit(void)
#define SDL_OutOfMemory()
int SDL_SYS_NumJoysticks(void)
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
GLuint GLuint GLsizei GLenum type
#define SDL_arraysize(array)
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
GLsizei const GLchar *const * path
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
void SDL_SYS_JoystickDetect(void)