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" 46 #if !SDL_EVENTS_DISABLED 47 #include "../../events/SDL_events_c.h" 55 #include "../../core/linux/SDL_udev.h" 57 static int MaybeAddDevice(
const char *
path);
59 static int MaybeRemoveDevice(
const char *
path);
60 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath);
65 typedef struct SDL_joylist_item
73 struct SDL_joylist_item *next;
76 static SDL_joylist_item *SDL_joylist =
NULL;
77 static SDL_joylist_item *SDL_joylist_tail =
NULL;
79 static int instance_counter = 0;
81 #define test_bit(nr, addr) \ 82 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) 83 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) 86 IsJoystick(
int fd,
char *namebuf,
const size_t namebuflen,
SDL_JoystickGUID *guid)
88 struct input_id inpid;
93 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
94 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
95 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
97 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
98 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
99 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
103 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
104 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
109 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
113 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
117 #ifdef DEBUG_JOYSTICK 118 printf(
"Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
128 if (inpid.vendor && inpid.product && inpid.version) {
143 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
145 if (devpath ==
NULL) {
150 case SDL_UDEV_DEVICEADDED:
151 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
154 MaybeAddDevice(devpath);
157 case SDL_UDEV_DEVICEREMOVED:
158 MaybeRemoveDevice(devpath);
171 MaybeAddDevice(
const char *
path)
178 SDL_joylist_item *item;
179 #if !SDL_EVENTS_DISABLED 187 if (stat(path, &sb) == -1) {
192 for (item = SDL_joylist; item !=
NULL; item = item->next) {
193 if (sb.st_rdev == item->devnum) {
198 fd = open(path, O_RDONLY, 0);
203 #ifdef DEBUG_INPUT_EVENTS 204 printf(
"Checking %s\n", path);
207 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
213 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
219 item->devnum = sb.st_rdev;
224 if ( (item->path ==
NULL) || (item->name ==
NULL) ) {
231 item->device_instance = instance_counter++;
232 if (SDL_joylist_tail ==
NULL) {
233 SDL_joylist = SDL_joylist_tail = item;
235 SDL_joylist_tail->next = item;
236 SDL_joylist_tail = item;
243 #if !SDL_EVENTS_DISABLED 261 MaybeRemoveDevice(
const char *path)
263 SDL_joylist_item *item;
264 SDL_joylist_item *prev =
NULL;
265 #if !SDL_EVENTS_DISABLED 273 for (item = SDL_joylist; item !=
NULL; item = item->next) {
276 const int retval = item->device_instance;
278 item->hwdata->item =
NULL;
281 prev->next = item->next;
284 SDL_joylist = item->next;
286 if (item == SDL_joylist_tail) {
287 SDL_joylist_tail = prev;
294 #if !SDL_EVENTS_DISABLED 298 event.jdevice.which = item->device_instance;
319 JoystickInitWithoutUdev(
void)
327 for (i = 0; i < 32; i++) {
329 MaybeAddDevice(path);
338 JoystickInitWithUdev(
void)
340 if (SDL_UDEV_Init() < 0) {
345 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
347 return SDL_SetError(
"Could not set up joystick <-> udev callback");
362 char *envcopy, *envpath, *delim;
365 while (envpath !=
NULL) {
370 MaybeAddDevice(envpath);
377 return JoystickInitWithUdev();
380 return JoystickInitWithoutUdev();
396 static SDL_joylist_item *
397 JoystickByDevIndex(
int device_index)
399 SDL_joylist_item *item = SDL_joylist;
401 if ((device_index < 0) || (device_index >=
numjoysticks)) {
405 while (device_index > 0) {
418 return JoystickByDevIndex(device_index)->name;
424 return JoystickByDevIndex(device_index)->device_instance;
428 allocate_hatdata(SDL_Joystick * joystick)
432 joystick->hwdata->hats =
433 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
434 sizeof(
struct hwdata_hat));
435 if (joystick->hwdata->hats ==
NULL) {
438 for (i = 0; i < joystick->nhats; ++
i) {
439 joystick->hwdata->hats[
i].axis[0] = 1;
440 joystick->hwdata->hats[
i].axis[1] = 1;
446 allocate_balldata(SDL_Joystick * joystick)
450 joystick->hwdata->balls =
451 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
452 sizeof(
struct hwdata_ball));
453 if (joystick->hwdata->balls ==
NULL) {
456 for (i = 0; i < joystick->nballs; ++
i) {
457 joystick->hwdata->balls[
i].axis[0] = 0;
458 joystick->hwdata->balls[
i].axis[1] = 0;
464 ConfigJoystick(SDL_Joystick * joystick,
int fd)
467 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
468 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
469 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
472 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
473 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
474 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
477 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
478 if (test_bit(i, keybit)) {
479 #ifdef DEBUG_INPUT_EVENTS 480 printf(
"Joystick has button: 0x%x\n", i);
482 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
483 ++joystick->nbuttons;
486 for (i = BTN_MISC; i < BTN_JOYSTICK; ++
i) {
487 if (test_bit(i, keybit)) {
488 #ifdef DEBUG_INPUT_EVENTS 489 printf(
"Joystick has button: 0x%x\n", i);
491 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
492 ++joystick->nbuttons;
495 for (i = 0; i < ABS_MAX; ++
i) {
497 if (i == ABS_HAT0X) {
501 if (test_bit(i, absbit)) {
502 struct input_absinfo absinfo;
504 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
507 #ifdef DEBUG_INPUT_EVENTS 508 printf(
"Joystick has absolute axis: 0x%.2x\n", i);
509 printf(
"Values = { %d, %d, %d, %d, %d }\n",
510 absinfo.value, absinfo.minimum, absinfo.maximum,
511 absinfo.fuzz, absinfo.flat);
513 joystick->hwdata->abs_map[
i] = joystick->naxes;
514 if (absinfo.minimum == absinfo.maximum) {
515 joystick->hwdata->abs_correct[
i].used = 0;
517 joystick->hwdata->abs_correct[
i].used = 1;
518 joystick->hwdata->abs_correct[
i].coef[0] =
519 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
520 joystick->hwdata->abs_correct[i].coef[1] =
521 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
522 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
524 joystick->hwdata->abs_correct[
i].coef[2] =
527 joystick->hwdata->abs_correct[
i].coef[2] = 0;
533 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
534 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
535 struct input_absinfo absinfo;
537 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
540 #ifdef DEBUG_INPUT_EVENTS 541 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
542 printf(
"Values = { %d, %d, %d, %d, %d }\n",
543 absinfo.value, absinfo.minimum, absinfo.maximum,
544 absinfo.fuzz, absinfo.flat);
549 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
554 if (joystick->nhats > 0) {
555 if (allocate_hatdata(joystick) < 0) {
559 if (joystick->nballs > 0) {
560 if (allocate_balldata(joystick) < 0) {
561 joystick->nballs = 0;
576 SDL_joylist_item *item = JoystickByDevIndex(device_index);
585 fd = open(fname, O_RDONLY, 0);
590 joystick->instance_id = item->device_instance;
593 if (joystick->hwdata ==
NULL) {
597 SDL_memset(joystick->hwdata, 0,
sizeof(*joystick->hwdata));
598 joystick->hwdata->item =
item;
599 joystick->hwdata->guid = item->guid;
600 joystick->hwdata->fd =
fd;
601 joystick->hwdata->fname =
SDL_strdup(item->path);
602 if (joystick->hwdata->fname ==
NULL) {
604 joystick->hwdata =
NULL;
610 item->hwdata = joystick->hwdata;
613 fcntl(fd, F_SETFL, O_NONBLOCK);
616 ConfigJoystick(joystick, fd);
619 joystick->hwdata->fresh = 1;
627 return joystick->hwdata->item !=
NULL;
633 struct hwdata_hat *the_hat;
634 const Uint8 position_map[3][3] = {
640 the_hat = &stick->hwdata->hats[hat];
643 }
else if (value == 0) {
645 }
else if (value > 0) {
648 if (value != the_hat->axis[axis]) {
651 position_map[the_hat->
652 axis[1]][the_hat->axis[0]]);
657 HandleBall(SDL_Joystick * stick,
Uint8 ball,
int axis,
int value)
659 stick->hwdata->balls[ball].axis[
axis] +=
value;
664 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
666 struct axis_correct *correct;
668 correct = &joystick->hwdata->abs_correct[which];
671 if (value > correct->coef[0]) {
675 value -= correct->coef[1];
677 value -= correct->coef[0];
679 value *= correct->coef[2];
693 PollAllValues(SDL_Joystick * joystick)
695 struct input_absinfo absinfo;
699 for (a = ABS_X; b < ABS_MAX; a++) {
712 if (joystick->hwdata->abs_correct[b].used) {
713 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
714 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
716 #ifdef DEBUG_INPUT_EVENTS 717 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
718 joystick->hwdata->abs_map[b], a, absinfo.value);
721 joystick->hwdata->abs_map[b],
731 HandleInputEvents(SDL_Joystick * joystick)
733 struct input_event
events[32];
737 if (joystick->hwdata->fresh) {
738 PollAllValues(joystick);
739 joystick->hwdata->fresh = 0;
742 while ((len = read(joystick->hwdata->fd,
events, (
sizeof events))) > 0) {
744 for (i = 0; i <
len; ++
i) {
748 if (code >= BTN_MISC) {
751 joystick->hwdata->key_map[code],
766 HandleHat(joystick, code / 2, code % 2,
events[i].value);
770 AxisCorrect(joystick, code,
events[i].value);
772 joystick->hwdata->abs_map[code],
782 HandleBall(joystick, code / 2, code % 2,
events[i].value);
791 #ifdef DEBUG_INPUT_EVENTS 792 printf(
"Event SYN_DROPPED detected\n");
794 PollAllValues(joystick);
811 HandleInputEvents(joystick);
814 for (i = 0; i < joystick->nballs; ++
i) {
817 xrel = joystick->hwdata->balls[
i].axis[0];
818 yrel = joystick->hwdata->balls[
i].axis[1];
820 joystick->hwdata->balls[
i].axis[0] = 0;
821 joystick->hwdata->balls[
i].axis[1] = 0;
831 if (joystick->hwdata) {
832 close(joystick->hwdata->fd);
833 if (joystick->hwdata->item) {
834 joystick->hwdata->item->hwdata =
NULL;
847 SDL_joylist_item *item =
NULL;
848 SDL_joylist_item *next =
NULL;
850 for (item = SDL_joylist; item; item = next) {
857 SDL_joylist = SDL_joylist_tail =
NULL;
860 instance_counter = 0;
863 SDL_UDEV_DelCallback(joystick_udev_callback);
870 return JoystickByDevIndex(device_index)->guid;
875 return joystick->hwdata->guid;
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
int SDL_SYS_NumJoysticks()
static SDL_Event events[EVENT_BUF_SIZE]
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
GLuint const GLchar * name
void SDL_SYS_JoystickQuit(void)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
#define SDL_GetEventState(type)
GLsizei const GLfloat * value
uint8_t Uint8
An unsigned 8-bit integer type.
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
SDL_EventFilter SDL_EventOK
void SDL_SYS_JoystickDetect()
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)
#define SDL_assert(condition)
int SDL_SYS_JoystickInit(void)
#define SDL_OutOfMemory()
struct SDL_joylist_item * item
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
uint16_t Uint16
An unsigned 16-bit integer type.
#define SDL_arraysize(array)
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick, int device_index)
GLsizei const GLchar *const * path
GLuint GLuint GLsizei GLenum type
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)