SDL_sysjoystick.c (25195B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#ifdef SDL_JOYSTICK_LINUX 24 25#ifndef SDL_INPUT_LINUXEV 26#error SDL now requires a Linux 2.4+ kernel with /dev/input/event support. 27#endif 28 29/* This is the Linux implementation of the SDL joystick API */ 30 31#include <sys/stat.h> 32#include <unistd.h> 33#include <fcntl.h> 34#include <sys/ioctl.h> 35#include <limits.h> /* For the definition of PATH_MAX */ 36#include <linux/joystick.h> 37 38#include "SDL_assert.h" 39#include "SDL_joystick.h" 40#include "SDL_endian.h" 41#include "../SDL_sysjoystick.h" 42#include "../SDL_joystick_c.h" 43#include "SDL_sysjoystick_c.h" 44 45/* !!! FIXME: move this somewhere else. */ 46#if !SDL_EVENTS_DISABLED 47#include "../../events/SDL_events_c.h" 48#endif 49 50/* This isn't defined in older Linux kernel headers */ 51#ifndef SYN_DROPPED 52#define SYN_DROPPED 3 53#endif 54 55#include "../../core/linux/SDL_udev.h" 56 57static int MaybeAddDevice(const char *path); 58#if SDL_USE_LIBUDEV 59static int MaybeRemoveDevice(const char *path); 60void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); 61#endif /* SDL_USE_LIBUDEV */ 62 63 64/* A linked list of available joysticks */ 65typedef struct SDL_joylist_item 66{ 67 int device_instance; 68 char *path; /* "/dev/input/event2" or whatever */ 69 char *name; /* "SideWinder 3D Pro" or whatever */ 70 SDL_JoystickGUID guid; 71 dev_t devnum; 72 struct joystick_hwdata *hwdata; 73 struct SDL_joylist_item *next; 74} SDL_joylist_item; 75 76static SDL_joylist_item *SDL_joylist = NULL; 77static SDL_joylist_item *SDL_joylist_tail = NULL; 78static int numjoysticks = 0; 79static int instance_counter = 0; 80 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) 84 85static int 86IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid) 87{ 88 struct input_id inpid; 89 Uint16 *guid16 = (Uint16 *) ((char *) &guid->data); 90 91#if !SDL_USE_LIBUDEV 92 /* When udev is enabled we only get joystick devices here, so there's no need to test them */ 93 unsigned long evbit[NBITS(EV_MAX)] = { 0 }; 94 unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; 95 unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; 96 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)) { 100 return (0); 101 } 102 103 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && 104 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) { 105 return 0; 106 } 107#endif 108 109 if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) { 110 return 0; 111 } 112 113 if (ioctl(fd, EVIOCGID, &inpid) < 0) { 114 return 0; 115 } 116 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); 119#endif 120 121 SDL_memset(guid->data, 0, sizeof(guid->data)); 122 123 /* We only need 16 bits for each of these; space them out to fill 128. */ 124 /* Byteswap so devices get same GUID on little/big endian platforms. */ 125 *(guid16++) = SDL_SwapLE16(inpid.bustype); 126 *(guid16++) = 0; 127 128 if (inpid.vendor && inpid.product && inpid.version) { 129 *(guid16++) = SDL_SwapLE16(inpid.vendor); 130 *(guid16++) = 0; 131 *(guid16++) = SDL_SwapLE16(inpid.product); 132 *(guid16++) = 0; 133 *(guid16++) = SDL_SwapLE16(inpid.version); 134 *(guid16++) = 0; 135 } else { 136 SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4); 137 } 138 139 return 1; 140} 141 142#if SDL_USE_LIBUDEV 143void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) 144{ 145 if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { 146 return; 147 } 148 149 switch( udev_type ) 150 { 151 case SDL_UDEV_DEVICEADDED: 152 MaybeAddDevice(devpath); 153 break; 154 155 case SDL_UDEV_DEVICEREMOVED: 156 MaybeRemoveDevice(devpath); 157 break; 158 159 default: 160 break; 161 } 162 163} 164#endif /* SDL_USE_LIBUDEV */ 165 166 167/* !!! FIXME: I would love to dump this code and use libudev instead. */ 168static int 169MaybeAddDevice(const char *path) 170{ 171 struct stat sb; 172 int fd = -1; 173 int isstick = 0; 174 char namebuf[128]; 175 SDL_JoystickGUID guid; 176 SDL_joylist_item *item; 177#if !SDL_EVENTS_DISABLED 178 SDL_Event event; 179#endif 180 181 if (path == NULL) { 182 return -1; 183 } 184 185 if (stat(path, &sb) == -1) { 186 return -1; 187 } 188 189 /* Check to make sure it's not already in list. */ 190 for (item = SDL_joylist; item != NULL; item = item->next) { 191 if (sb.st_rdev == item->devnum) { 192 return -1; /* already have this one */ 193 } 194 } 195 196 fd = open(path, O_RDONLY, 0); 197 if (fd < 0) { 198 return -1; 199 } 200 201#ifdef DEBUG_INPUT_EVENTS 202 printf("Checking %s\n", path); 203#endif 204 205 isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid); 206 close(fd); 207 if (!isstick) { 208 return -1; 209 } 210 211 item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item)); 212 if (item == NULL) { 213 return -1; 214 } 215 216 SDL_zerop(item); 217 item->devnum = sb.st_rdev; 218 item->path = SDL_strdup(path); 219 item->name = SDL_strdup(namebuf); 220 item->guid = guid; 221 222 if ( (item->path == NULL) || (item->name == NULL) ) { 223 SDL_free(item->path); 224 SDL_free(item->name); 225 SDL_free(item); 226 return -1; 227 } 228 229 item->device_instance = instance_counter++; 230 if (SDL_joylist_tail == NULL) { 231 SDL_joylist = SDL_joylist_tail = item; 232 } else { 233 SDL_joylist_tail->next = item; 234 SDL_joylist_tail = item; 235 } 236 237 /* Need to increment the joystick count before we post the event */ 238 ++numjoysticks; 239 240 /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */ 241#if !SDL_EVENTS_DISABLED 242 event.type = SDL_JOYDEVICEADDED; 243 244 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 245 event.jdevice.which = (numjoysticks - 1); 246 if ( (SDL_EventOK == NULL) || 247 (*SDL_EventOK) (SDL_EventOKParam, &event) ) { 248 SDL_PushEvent(&event); 249 } 250 } 251#endif /* !SDL_EVENTS_DISABLED */ 252 253 return numjoysticks; 254} 255 256#if SDL_USE_LIBUDEV 257/* !!! FIXME: I would love to dump this code and use libudev instead. */ 258static int 259MaybeRemoveDevice(const char *path) 260{ 261 SDL_joylist_item *item; 262 SDL_joylist_item *prev = NULL; 263#if !SDL_EVENTS_DISABLED 264 SDL_Event event; 265#endif 266 267 if (path == NULL) { 268 return -1; 269 } 270 271 for (item = SDL_joylist; item != NULL; item = item->next) { 272 /* found it, remove it. */ 273 if (SDL_strcmp(path, item->path) == 0) { 274 const int retval = item->device_instance; 275 if (item->hwdata) { 276 item->hwdata->item = NULL; 277 } 278 if (prev != NULL) { 279 prev->next = item->next; 280 } else { 281 SDL_assert(SDL_joylist == item); 282 SDL_joylist = item->next; 283 } 284 if (item == SDL_joylist_tail) { 285 SDL_joylist_tail = prev; 286 } 287 288 /* Need to decrement the joystick count before we post the event */ 289 --numjoysticks; 290 291 /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */ 292#if !SDL_EVENTS_DISABLED 293 event.type = SDL_JOYDEVICEREMOVED; 294 295 if (SDL_GetEventState(event.type) == SDL_ENABLE) { 296 event.jdevice.which = item->device_instance; 297 if ( (SDL_EventOK == NULL) || 298 (*SDL_EventOK) (SDL_EventOKParam, &event) ) { 299 SDL_PushEvent(&event); 300 } 301 } 302#endif /* !SDL_EVENTS_DISABLED */ 303 304 SDL_free(item->path); 305 SDL_free(item->name); 306 SDL_free(item); 307 return retval; 308 } 309 prev = item; 310 } 311 312 return -1; 313} 314#endif 315 316static int 317JoystickInitWithoutUdev(void) 318{ 319 int i; 320 char path[PATH_MAX]; 321 322 /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */ 323 /* !!! FIXME: we could at least readdir() through /dev/input...? */ 324 /* !!! FIXME: (or delete this and rely on libudev?) */ 325 for (i = 0; i < 32; i++) { 326 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i); 327 MaybeAddDevice(path); 328 } 329 330 return numjoysticks; 331} 332 333 334#if SDL_USE_LIBUDEV 335static int 336JoystickInitWithUdev(void) 337{ 338 339 if (SDL_UDEV_Init() < 0) { 340 return SDL_SetError("Could not initialize UDEV"); 341 } 342 343 /* Set up the udev callback */ 344 if ( SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { 345 SDL_UDEV_Quit(); 346 return SDL_SetError("Could not set up joystick <-> udev callback"); 347 } 348 349 /* Force a scan to build the initial device list */ 350 SDL_UDEV_Scan(); 351 352 return numjoysticks; 353} 354#endif 355 356int 357SDL_SYS_JoystickInit(void) 358{ 359 /* First see if the user specified one or more joysticks to use */ 360 if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) { 361 char *envcopy, *envpath, *delim; 362 envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE")); 363 envpath = envcopy; 364 while (envpath != NULL) { 365 delim = SDL_strchr(envpath, ':'); 366 if (delim != NULL) { 367 *delim++ = '\0'; 368 } 369 MaybeAddDevice(envpath); 370 envpath = delim; 371 } 372 SDL_free(envcopy); 373 } 374 375#if SDL_USE_LIBUDEV 376 return JoystickInitWithUdev(); 377#endif 378 379 return JoystickInitWithoutUdev(); 380} 381 382int SDL_SYS_NumJoysticks() 383{ 384 return numjoysticks; 385} 386 387void SDL_SYS_JoystickDetect() 388{ 389#if SDL_USE_LIBUDEV 390 SDL_UDEV_Poll(); 391#endif 392 393} 394 395static SDL_joylist_item * 396JoystickByDevIndex(int device_index) 397{ 398 SDL_joylist_item *item = SDL_joylist; 399 400 if ((device_index < 0) || (device_index >= numjoysticks)) { 401 return NULL; 402 } 403 404 while (device_index > 0) { 405 SDL_assert(item != NULL); 406 device_index--; 407 item = item->next; 408 } 409 410 return item; 411} 412 413/* Function to get the device-dependent name of a joystick */ 414const char * 415SDL_SYS_JoystickNameForDeviceIndex(int device_index) 416{ 417 return JoystickByDevIndex(device_index)->name; 418} 419 420/* Function to perform the mapping from device index to the instance id for this index */ 421SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) 422{ 423 return JoystickByDevIndex(device_index)->device_instance; 424} 425 426static int 427allocate_hatdata(SDL_Joystick * joystick) 428{ 429 int i; 430 431 joystick->hwdata->hats = 432 (struct hwdata_hat *) SDL_malloc(joystick->nhats * 433 sizeof(struct hwdata_hat)); 434 if (joystick->hwdata->hats == NULL) { 435 return (-1); 436 } 437 for (i = 0; i < joystick->nhats; ++i) { 438 joystick->hwdata->hats[i].axis[0] = 1; 439 joystick->hwdata->hats[i].axis[1] = 1; 440 } 441 return (0); 442} 443 444static int 445allocate_balldata(SDL_Joystick * joystick) 446{ 447 int i; 448 449 joystick->hwdata->balls = 450 (struct hwdata_ball *) SDL_malloc(joystick->nballs * 451 sizeof(struct hwdata_ball)); 452 if (joystick->hwdata->balls == NULL) { 453 return (-1); 454 } 455 for (i = 0; i < joystick->nballs; ++i) { 456 joystick->hwdata->balls[i].axis[0] = 0; 457 joystick->hwdata->balls[i].axis[1] = 0; 458 } 459 return (0); 460} 461 462static void 463ConfigJoystick(SDL_Joystick * joystick, int fd) 464{ 465 int i, t; 466 unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; 467 unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; 468 unsigned long relbit[NBITS(REL_MAX)] = { 0 }; 469 470 /* See if this device uses the new unified event API */ 471 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && 472 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) && 473 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) { 474 475 /* Get the number of buttons, axes, and other thingamajigs */ 476 for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) { 477 if (test_bit(i, keybit)) { 478#ifdef DEBUG_INPUT_EVENTS 479 printf("Joystick has button: 0x%x\n", i); 480#endif 481 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons; 482 ++joystick->nbuttons; 483 } 484 } 485 for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) { 486 if (test_bit(i, keybit)) { 487#ifdef DEBUG_INPUT_EVENTS 488 printf("Joystick has button: 0x%x\n", i); 489#endif 490 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons; 491 ++joystick->nbuttons; 492 } 493 } 494 for (i = 0; i < ABS_MISC; ++i) { 495 /* Skip hats */ 496 if (i == ABS_HAT0X) { 497 i = ABS_HAT3Y; 498 continue; 499 } 500 if (test_bit(i, absbit)) { 501 struct input_absinfo absinfo; 502 503 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { 504 continue; 505 } 506#ifdef DEBUG_INPUT_EVENTS 507 printf("Joystick has absolute axis: 0x%.2x\n", i); 508 printf("Values = { %d, %d, %d, %d, %d }\n", 509 absinfo.value, absinfo.minimum, absinfo.maximum, 510 absinfo.fuzz, absinfo.flat); 511#endif /* DEBUG_INPUT_EVENTS */ 512 joystick->hwdata->abs_map[i] = joystick->naxes; 513 if (absinfo.minimum == absinfo.maximum) { 514 joystick->hwdata->abs_correct[i].used = 0; 515 } else { 516 joystick->hwdata->abs_correct[i].used = 1; 517 joystick->hwdata->abs_correct[i].coef[0] = 518 (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat; 519 joystick->hwdata->abs_correct[i].coef[1] = 520 (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat; 521 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat); 522 if (t != 0) { 523 joystick->hwdata->abs_correct[i].coef[2] = 524 (1 << 28) / t; 525 } else { 526 joystick->hwdata->abs_correct[i].coef[2] = 0; 527 } 528 } 529 ++joystick->naxes; 530 } 531 } 532 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) { 533 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) { 534 struct input_absinfo absinfo; 535 536 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { 537 continue; 538 } 539#ifdef DEBUG_INPUT_EVENTS 540 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2); 541 printf("Values = { %d, %d, %d, %d, %d }\n", 542 absinfo.value, absinfo.minimum, absinfo.maximum, 543 absinfo.fuzz, absinfo.flat); 544#endif /* DEBUG_INPUT_EVENTS */ 545 ++joystick->nhats; 546 } 547 } 548 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { 549 ++joystick->nballs; 550 } 551 552 /* Allocate data to keep track of these thingamajigs */ 553 if (joystick->nhats > 0) { 554 if (allocate_hatdata(joystick) < 0) { 555 joystick->nhats = 0; 556 } 557 } 558 if (joystick->nballs > 0) { 559 if (allocate_balldata(joystick) < 0) { 560 joystick->nballs = 0; 561 } 562 } 563 } 564} 565 566 567/* Function to open a joystick for use. 568 The joystick to open is specified by the index field of the joystick. 569 This should fill the nbuttons and naxes fields of the joystick structure. 570 It returns 0, or -1 if there is an error. 571 */ 572int 573SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) 574{ 575 SDL_joylist_item *item = JoystickByDevIndex(device_index); 576 char *fname = NULL; 577 int fd = -1; 578 579 if (item == NULL) { 580 return SDL_SetError("No such device"); 581 } 582 583 fname = item->path; 584 fd = open(fname, O_RDONLY, 0); 585 if (fd < 0) { 586 return SDL_SetError("Unable to open %s", fname); 587 } 588 589 joystick->instance_id = item->device_instance; 590 joystick->hwdata = (struct joystick_hwdata *) 591 SDL_malloc(sizeof(*joystick->hwdata)); 592 if (joystick->hwdata == NULL) { 593 close(fd); 594 return SDL_OutOfMemory(); 595 } 596 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata)); 597 joystick->hwdata->item = item; 598 joystick->hwdata->guid = item->guid; 599 joystick->hwdata->fd = fd; 600 joystick->hwdata->fname = SDL_strdup(item->path); 601 if (joystick->hwdata->fname == NULL) { 602 SDL_free(joystick->hwdata); 603 joystick->hwdata = NULL; 604 close(fd); 605 return SDL_OutOfMemory(); 606 } 607 608 SDL_assert(item->hwdata == NULL); 609 item->hwdata = joystick->hwdata; 610 611 /* Set the joystick to non-blocking read mode */ 612 fcntl(fd, F_SETFL, O_NONBLOCK); 613 614 /* Get the number of buttons and axes on the joystick */ 615 ConfigJoystick(joystick, fd); 616 617 /* mark joystick as fresh and ready */ 618 joystick->hwdata->fresh = 1; 619 620 return (0); 621} 622 623/* Function to determine is this joystick is attached to the system right now */ 624SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) 625{ 626 return !joystick->closed && (joystick->hwdata->item != NULL); 627} 628 629static SDL_INLINE void 630HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value) 631{ 632 struct hwdata_hat *the_hat; 633 const Uint8 position_map[3][3] = { 634 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP}, 635 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT}, 636 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN} 637 }; 638 639 the_hat = &stick->hwdata->hats[hat]; 640 if (value < 0) { 641 value = 0; 642 } else if (value == 0) { 643 value = 1; 644 } else if (value > 0) { 645 value = 2; 646 } 647 if (value != the_hat->axis[axis]) { 648 the_hat->axis[axis] = value; 649 SDL_PrivateJoystickHat(stick, hat, 650 position_map[the_hat-> 651 axis[1]][the_hat->axis[0]]); 652 } 653} 654 655static SDL_INLINE void 656HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value) 657{ 658 stick->hwdata->balls[ball].axis[axis] += value; 659} 660 661 662static SDL_INLINE int 663AxisCorrect(SDL_Joystick * joystick, int which, int value) 664{ 665 struct axis_correct *correct; 666 667 correct = &joystick->hwdata->abs_correct[which]; 668 if (correct->used) { 669 value *= 2; 670 if (value > correct->coef[0]) { 671 if (value < correct->coef[1]) { 672 return 0; 673 } 674 value -= correct->coef[1]; 675 } else { 676 value -= correct->coef[0]; 677 } 678 value *= correct->coef[2]; 679 value >>= 13; 680 } 681 682 /* Clamp and return */ 683 if (value < -32768) 684 return -32768; 685 if (value > 32767) 686 return 32767; 687 688 return value; 689} 690 691static SDL_INLINE void 692PollAllValues(SDL_Joystick * joystick) 693{ 694 struct input_absinfo absinfo; 695 int a, b = 0; 696 697 /* Poll all axis */ 698 for (a = ABS_X; b < ABS_MAX; a++) { 699 switch (a) { 700 case ABS_HAT0X: 701 case ABS_HAT0Y: 702 case ABS_HAT1X: 703 case ABS_HAT1Y: 704 case ABS_HAT2X: 705 case ABS_HAT2Y: 706 case ABS_HAT3X: 707 case ABS_HAT3Y: 708 /* ingore hats */ 709 break; 710 default: 711 if (joystick->hwdata->abs_correct[b].used) { 712 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) { 713 absinfo.value = AxisCorrect(joystick, b, absinfo.value); 714 715#ifdef DEBUG_INPUT_EVENTS 716 printf("Joystick : Re-read Axis %d (%d) val= %d\n", 717 joystick->hwdata->abs_map[b], a, absinfo.value); 718#endif 719 SDL_PrivateJoystickAxis(joystick, 720 joystick->hwdata->abs_map[b], 721 absinfo.value); 722 } 723 } 724 b++; 725 } 726 } 727} 728 729static SDL_INLINE void 730HandleInputEvents(SDL_Joystick * joystick) 731{ 732 struct input_event events[32]; 733 int i, len; 734 int code; 735 736 if (joystick->hwdata->fresh) { 737 PollAllValues(joystick); 738 joystick->hwdata->fresh = 0; 739 } 740 741 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) { 742 len /= sizeof(events[0]); 743 for (i = 0; i < len; ++i) { 744 code = events[i].code; 745 switch (events[i].type) { 746 case EV_KEY: 747 if (code >= BTN_MISC) { 748 code -= BTN_MISC; 749 SDL_PrivateJoystickButton(joystick, 750 joystick->hwdata->key_map[code], 751 events[i].value); 752 } 753 break; 754 case EV_ABS: 755 if (code >= ABS_MISC) { 756 break; 757 } 758 759 switch (code) { 760 case ABS_HAT0X: 761 case ABS_HAT0Y: 762 case ABS_HAT1X: 763 case ABS_HAT1Y: 764 case ABS_HAT2X: 765 case ABS_HAT2Y: 766 case ABS_HAT3X: 767 case ABS_HAT3Y: 768 code -= ABS_HAT0X; 769 HandleHat(joystick, code / 2, code % 2, events[i].value); 770 break; 771 default: 772 events[i].value = 773 AxisCorrect(joystick, code, events[i].value); 774 SDL_PrivateJoystickAxis(joystick, 775 joystick->hwdata->abs_map[code], 776 events[i].value); 777 break; 778 } 779 break; 780 case EV_REL: 781 switch (code) { 782 case REL_X: 783 case REL_Y: 784 code -= REL_X; 785 HandleBall(joystick, code / 2, code % 2, events[i].value); 786 break; 787 default: 788 break; 789 } 790 break; 791 case EV_SYN: 792 switch (code) { 793 case SYN_DROPPED : 794#ifdef DEBUG_INPUT_EVENTS 795 printf("Event SYN_DROPPED detected\n"); 796#endif 797 PollAllValues(joystick); 798 break; 799 default: 800 break; 801 } 802 default: 803 break; 804 } 805 } 806 } 807} 808 809void 810SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) 811{ 812 int i; 813 814 HandleInputEvents(joystick); 815 816 /* Deliver ball motion updates */ 817 for (i = 0; i < joystick->nballs; ++i) { 818 int xrel, yrel; 819 820 xrel = joystick->hwdata->balls[i].axis[0]; 821 yrel = joystick->hwdata->balls[i].axis[1]; 822 if (xrel || yrel) { 823 joystick->hwdata->balls[i].axis[0] = 0; 824 joystick->hwdata->balls[i].axis[1] = 0; 825 SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel); 826 } 827 } 828} 829 830/* Function to close a joystick after use */ 831void 832SDL_SYS_JoystickClose(SDL_Joystick * joystick) 833{ 834 if (joystick->hwdata) { 835 close(joystick->hwdata->fd); 836 if (joystick->hwdata->item) { 837 joystick->hwdata->item->hwdata = NULL; 838 } 839 SDL_free(joystick->hwdata->hats); 840 SDL_free(joystick->hwdata->balls); 841 SDL_free(joystick->hwdata->fname); 842 SDL_free(joystick->hwdata); 843 joystick->hwdata = NULL; 844 } 845 joystick->closed = 1; 846} 847 848/* Function to perform any system-specific joystick related cleanup */ 849void 850SDL_SYS_JoystickQuit(void) 851{ 852 SDL_joylist_item *item = NULL; 853 SDL_joylist_item *next = NULL; 854 855 for (item = SDL_joylist; item; item = next) { 856 next = item->next; 857 SDL_free(item->path); 858 SDL_free(item->name); 859 SDL_free(item); 860 } 861 862 SDL_joylist = SDL_joylist_tail = NULL; 863 864 numjoysticks = 0; 865 instance_counter = 0; 866 867#if SDL_USE_LIBUDEV 868 SDL_UDEV_DelCallback(joystick_udev_callback); 869 SDL_UDEV_Quit(); 870#endif 871} 872 873SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) 874{ 875 return JoystickByDevIndex(device_index)->guid; 876} 877 878SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) 879{ 880 return joystick->hwdata->guid; 881} 882 883#endif /* SDL_JOYSTICK_LINUX */ 884 885/* vi: set ts=4 sw=4 expandtab: */