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
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d ®2 endm macro vzip8 reg2 vzip d d ®2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld [DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld fname[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp local skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head if pixblock_size cache_preload_simple endif process_pixblock_tail pixinterleave dst_w_basereg irp if pixblock_size chunk_size tst beq if DST_W else pixst DST_W else mov ORIG_W endif add lsl if lsl endif if lsl endif lsl endif lsl endif lsl endif subs mov DST_W if regs_shortage str endif bge start_of_loop_label endm macro generate_composite_function
GLboolean GLboolean GLboolean b
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)