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 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) 81 IsJoystick(
int fd,
char *namebuf,
const size_t namebuflen,
SDL_JoystickGUID *guid)
83 struct input_id inpid;
88 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
89 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
90 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
92 if ((ioctl(fd, EVIOCGBIT(0,
sizeof(evbit)), evbit) < 0) ||
93 (ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) < 0) ||
94 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) < 0)) {
98 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
99 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
104 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
108 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
112 #ifdef DEBUG_JOYSTICK 113 printf(
"Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
123 if (inpid.vendor && inpid.product && inpid.version) {
138 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
140 if (devpath ==
NULL) {
145 case SDL_UDEV_DEVICEADDED:
146 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
149 MaybeAddDevice(devpath);
152 case SDL_UDEV_DEVICEREMOVED:
153 MaybeRemoveDevice(devpath);
166 MaybeAddDevice(
const char *
path)
173 SDL_joylist_item *item;
179 if (stat(path, &sb) == -1) {
184 for (item = SDL_joylist; item !=
NULL; item = item->next) {
185 if (sb.st_rdev == item->devnum) {
190 fd = open(path, O_RDONLY, 0);
195 #ifdef DEBUG_INPUT_EVENTS 196 printf(
"Checking %s\n", path);
199 isstick = IsJoystick(fd, namebuf,
sizeof (namebuf), &guid);
205 item = (SDL_joylist_item *)
SDL_malloc(
sizeof (SDL_joylist_item));
211 item->devnum = sb.st_rdev;
216 if ( (item->path ==
NULL) || (item->name ==
NULL) ) {
223 item->device_instance = instance_counter++;
224 if (SDL_joylist_tail ==
NULL) {
225 SDL_joylist = SDL_joylist_tail = item;
227 SDL_joylist_tail->next = item;
228 SDL_joylist_tail = item;
242 MaybeRemoveDevice(
const char *path)
244 SDL_joylist_item *item;
245 SDL_joylist_item *prev =
NULL;
251 for (item = SDL_joylist; item !=
NULL; item = item->next) {
254 const int retval = item->device_instance;
256 item->hwdata->item =
NULL;
259 prev->next = item->next;
262 SDL_joylist = item->next;
264 if (item == SDL_joylist_tail) {
265 SDL_joylist_tail = prev;
286 JoystickInitWithoutUdev(
void)
294 for (i = 0; i < 32; i++) {
296 MaybeAddDevice(path);
305 JoystickInitWithUdev(
void)
307 if (SDL_UDEV_Init() < 0) {
312 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
314 return SDL_SetError(
"Could not set up joystick <-> udev callback");
329 char *envcopy, *envpath, *delim;
332 while (envpath !=
NULL) {
337 MaybeAddDevice(envpath);
344 return JoystickInitWithUdev();
347 return JoystickInitWithoutUdev();
363 static SDL_joylist_item *
364 JoystickByDevIndex(
int device_index)
366 SDL_joylist_item *item = SDL_joylist;
368 if ((device_index < 0) || (device_index >=
numjoysticks)) {
372 while (device_index > 0) {
385 return JoystickByDevIndex(device_index)->name;
391 return JoystickByDevIndex(device_index)->device_instance;
395 allocate_hatdata(SDL_Joystick * joystick)
399 joystick->hwdata->hats =
400 (
struct hwdata_hat *)
SDL_malloc(joystick->nhats *
401 sizeof(
struct hwdata_hat));
402 if (joystick->hwdata->hats ==
NULL) {
405 for (i = 0; i < joystick->nhats; ++
i) {
406 joystick->hwdata->hats[
i].axis[0] = 1;
407 joystick->hwdata->hats[
i].axis[1] = 1;
413 allocate_balldata(SDL_Joystick * joystick)
417 joystick->hwdata->balls =
418 (
struct hwdata_ball *)
SDL_malloc(joystick->nballs *
419 sizeof(
struct hwdata_ball));
420 if (joystick->hwdata->balls ==
NULL) {
423 for (i = 0; i < joystick->nballs; ++
i) {
424 joystick->hwdata->balls[
i].axis[0] = 0;
425 joystick->hwdata->balls[
i].axis[1] = 0;
431 ConfigJoystick(SDL_Joystick * joystick,
int fd)
434 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
435 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
436 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
439 if ((ioctl(fd, EVIOCGBIT(EV_KEY,
sizeof(keybit)), keybit) >= 0) &&
440 (ioctl(fd, EVIOCGBIT(EV_ABS,
sizeof(absbit)), absbit) >= 0) &&
441 (ioctl(fd, EVIOCGBIT(EV_REL,
sizeof(relbit)), relbit) >= 0)) {
444 for (i = BTN_JOYSTICK; i < KEY_MAX; ++
i) {
445 if (test_bit(i, keybit)) {
446 #ifdef DEBUG_INPUT_EVENTS 447 printf(
"Joystick has button: 0x%x\n", i);
449 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
450 ++joystick->nbuttons;
453 for (i = BTN_MISC; i < BTN_JOYSTICK; ++
i) {
454 if (test_bit(i, keybit)) {
455 #ifdef DEBUG_INPUT_EVENTS 456 printf(
"Joystick has button: 0x%x\n", i);
458 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
459 ++joystick->nbuttons;
462 for (i = 0; i < ABS_MAX; ++
i) {
464 if (i == ABS_HAT0X) {
468 if (test_bit(i, absbit)) {
469 struct input_absinfo absinfo;
471 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
474 #ifdef DEBUG_INPUT_EVENTS 475 printf(
"Joystick has absolute axis: 0x%.2x\n", i);
476 printf(
"Values = { %d, %d, %d, %d, %d }\n",
477 absinfo.value, absinfo.minimum, absinfo.maximum,
478 absinfo.fuzz, absinfo.flat);
480 joystick->hwdata->abs_map[
i] = joystick->naxes;
481 if (absinfo.minimum == absinfo.maximum) {
482 joystick->hwdata->abs_correct[
i].used = 0;
484 joystick->hwdata->abs_correct[
i].used = 1;
485 joystick->hwdata->abs_correct[
i].coef[0] =
486 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
487 joystick->hwdata->abs_correct[i].coef[1] =
488 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
489 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
491 joystick->hwdata->abs_correct[
i].coef[2] =
494 joystick->hwdata->abs_correct[
i].coef[2] = 0;
500 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
501 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
502 struct input_absinfo absinfo;
504 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
507 #ifdef DEBUG_INPUT_EVENTS 508 printf(
"Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
509 printf(
"Values = { %d, %d, %d, %d, %d }\n",
510 absinfo.value, absinfo.minimum, absinfo.maximum,
511 absinfo.fuzz, absinfo.flat);
516 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
521 if (joystick->nhats > 0) {
522 if (allocate_hatdata(joystick) < 0) {
526 if (joystick->nballs > 0) {
527 if (allocate_balldata(joystick) < 0) {
528 joystick->nballs = 0;
543 SDL_joylist_item *item = JoystickByDevIndex(device_index);
552 fd = open(fname, O_RDONLY, 0);
557 joystick->instance_id = item->device_instance;
560 if (joystick->hwdata ==
NULL) {
564 SDL_memset(joystick->hwdata, 0,
sizeof(*joystick->hwdata));
565 joystick->hwdata->item =
item;
566 joystick->hwdata->guid = item->guid;
567 joystick->hwdata->fd =
fd;
568 joystick->hwdata->fname =
SDL_strdup(item->path);
569 if (joystick->hwdata->fname ==
NULL) {
571 joystick->hwdata =
NULL;
577 item->hwdata = joystick->hwdata;
580 fcntl(fd, F_SETFL, O_NONBLOCK);
583 ConfigJoystick(joystick, fd);
586 joystick->hwdata->fresh = 1;
594 return joystick->hwdata->item !=
NULL;
600 struct hwdata_hat *the_hat;
601 const Uint8 position_map[3][3] = {
607 the_hat = &stick->hwdata->hats[hat];
610 }
else if (value == 0) {
612 }
else if (value > 0) {
615 if (value != the_hat->axis[axis]) {
618 position_map[the_hat->
619 axis[1]][the_hat->axis[0]]);
624 HandleBall(SDL_Joystick * stick,
Uint8 ball,
int axis,
int value)
626 stick->hwdata->balls[ball].axis[
axis] +=
value;
631 AxisCorrect(SDL_Joystick * joystick,
int which,
int value)
633 struct axis_correct *correct;
635 correct = &joystick->hwdata->abs_correct[which];
638 if (value > correct->coef[0]) {
642 value -= correct->coef[1];
644 value -= correct->coef[0];
646 value *= correct->coef[2];
660 PollAllValues(SDL_Joystick * joystick)
662 struct input_absinfo absinfo;
666 for (a = ABS_X; b < ABS_MAX; a++) {
679 if (joystick->hwdata->abs_correct[b].used) {
680 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
681 absinfo.value = AxisCorrect(joystick, b, absinfo.value);
683 #ifdef DEBUG_INPUT_EVENTS 684 printf(
"Joystick : Re-read Axis %d (%d) val= %d\n",
685 joystick->hwdata->abs_map[b], a, absinfo.value);
688 joystick->hwdata->abs_map[b],
698 HandleInputEvents(SDL_Joystick * joystick)
700 struct input_event
events[32];
704 if (joystick->hwdata->fresh) {
705 PollAllValues(joystick);
706 joystick->hwdata->fresh = 0;
709 while ((len = read(joystick->hwdata->fd,
events, (
sizeof events))) > 0) {
711 for (i = 0; i <
len; ++
i) {
715 if (code >= BTN_MISC) {
718 joystick->hwdata->key_map[code],
733 HandleHat(joystick, code / 2, code % 2,
events[i].value);
737 AxisCorrect(joystick, code,
events[i].value);
739 joystick->hwdata->abs_map[code],
749 HandleBall(joystick, code / 2, code % 2,
events[i].value);
758 #ifdef DEBUG_INPUT_EVENTS 759 printf(
"Event SYN_DROPPED detected\n");
761 PollAllValues(joystick);
778 HandleInputEvents(joystick);
781 for (i = 0; i < joystick->nballs; ++
i) {
784 xrel = joystick->hwdata->balls[
i].axis[0];
785 yrel = joystick->hwdata->balls[
i].axis[1];
787 joystick->hwdata->balls[
i].axis[0] = 0;
788 joystick->hwdata->balls[
i].axis[1] = 0;
798 if (joystick->hwdata) {
799 close(joystick->hwdata->fd);
800 if (joystick->hwdata->item) {
801 joystick->hwdata->item->hwdata =
NULL;
814 SDL_joylist_item *item =
NULL;
815 SDL_joylist_item *next =
NULL;
817 for (item = SDL_joylist; item; item = next) {
824 SDL_joylist = SDL_joylist_tail =
NULL;
827 instance_counter = 0;
830 SDL_UDEV_DelCallback(joystick_udev_callback);
837 return JoystickByDevIndex(device_index)->guid;
842 return joystick->hwdata->guid;
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
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)
GLuint GLuint GLsizei GLenum type
int SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball, Sint16 xrel, Sint16 yrel)
#define SDL_HAT_RIGHTDOWN
GLsizei const GLfloat * value
uint8_t Uint8
An unsigned 8-bit integer type.
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
void SDL_SYS_JoystickDetect()
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)
#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
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
GLboolean GLboolean GLboolean GLboolean a
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)