SDL_syshaptic.c (31948B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 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_HAPTIC_LINUX 24 25 #include "SDL_haptic.h" 26 #include "../SDL_syshaptic.h" 27 #include "SDL_joystick.h" 28 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ 29 #include "../../joystick/linux/SDL_sysjoystick_c.h" /* For joystick hwdata */ 30 #include "../../core/linux/SDL_evdev_capabilities.h" 31 #include "../../core/linux/SDL_udev.h" 32 33 #include <unistd.h> /* close */ 34 #include <linux/input.h> /* Force feedback linux stuff. */ 35 #include <fcntl.h> /* O_RDWR */ 36 #include <limits.h> /* INT_MAX */ 37 #include <errno.h> /* errno, strerror */ 38 #include <math.h> /* atan2 */ 39 #include <sys/stat.h> /* stat */ 40 41 /* Just in case. */ 42 #ifndef M_PI 43 # define M_PI 3.14159265358979323846 44 #endif 45 46 47 #define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */ 48 49 static int MaybeAddDevice(const char *path); 50 #if SDL_USE_LIBUDEV 51 static int MaybeRemoveDevice(const char *path); 52 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); 53 #endif /* SDL_USE_LIBUDEV */ 54 55 /* 56 * List of available haptic devices. 57 */ 58 typedef struct SDL_hapticlist_item 59 { 60 char *fname; /* Dev path name (like /dev/input/event1) */ 61 SDL_Haptic *haptic; /* Associated haptic. */ 62 dev_t dev_num; 63 struct SDL_hapticlist_item *next; 64 } SDL_hapticlist_item; 65 66 67 /* 68 * Haptic system hardware data. 69 */ 70 struct haptic_hwdata 71 { 72 int fd; /* File descriptor of the device. */ 73 char *fname; /* Points to the name in SDL_hapticlist. */ 74 }; 75 76 77 /* 78 * Haptic system effect data. 79 */ 80 struct haptic_hweffect 81 { 82 struct ff_effect effect; /* The linux kernel effect structure. */ 83 }; 84 85 static SDL_hapticlist_item *SDL_hapticlist = NULL; 86 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL; 87 static int numhaptics = 0; 88 89 #define EV_TEST(ev,f) \ 90 if (test_bit((ev), features)) ret |= (f); 91 /* 92 * Test whether a device has haptic properties. 93 * Returns available properties or 0 if there are none. 94 */ 95 static int 96 EV_IsHaptic(int fd) 97 { 98 unsigned int ret; 99 unsigned long features[1 + FF_MAX / sizeof(unsigned long)]; 100 101 /* Ask device for what it has. */ 102 ret = 0; 103 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) { 104 return SDL_SetError("Haptic: Unable to get device's features: %s", 105 strerror(errno)); 106 } 107 108 /* Convert supported features to SDL_HAPTIC platform-neutral features. */ 109 EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT); 110 EV_TEST(FF_SINE, SDL_HAPTIC_SINE); 111 /* !!! FIXME: put this back when we have more bits in 2.1 */ 112 /* EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); */ 113 EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE); 114 EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP); 115 EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN); 116 EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP); 117 EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING); 118 EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION); 119 EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER); 120 EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA); 121 EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM); 122 EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN); 123 EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER); 124 EV_TEST(FF_RUMBLE, SDL_HAPTIC_LEFTRIGHT); 125 126 /* Return what it supports. */ 127 return ret; 128 } 129 130 131 /* 132 * Tests whether a device is a mouse or not. 133 */ 134 static int 135 EV_IsMouse(int fd) 136 { 137 unsigned long argp[40]; 138 139 /* Ask for supported features. */ 140 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) { 141 return -1; 142 } 143 144 /* Currently we only test for BTN_MOUSE which can give fake positives. */ 145 if (test_bit(BTN_MOUSE, argp) != 0) { 146 return 1; 147 } 148 149 return 0; 150 } 151 152 /* 153 * Initializes the haptic subsystem by finding available devices. 154 */ 155 int 156 SDL_SYS_HapticInit(void) 157 { 158 const char joydev_pattern[] = "/dev/input/event%d"; 159 char path[PATH_MAX]; 160 int i, j; 161 162 /* 163 * Limit amount of checks to MAX_HAPTICS since we may or may not have 164 * permission to some or all devices. 165 */ 166 i = 0; 167 for (j = 0; j < MAX_HAPTICS; ++j) { 168 169 snprintf(path, PATH_MAX, joydev_pattern, i++); 170 MaybeAddDevice(path); 171 } 172 173 #if SDL_USE_LIBUDEV 174 if (SDL_UDEV_Init() < 0) { 175 return SDL_SetError("Could not initialize UDEV"); 176 } 177 178 if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) { 179 SDL_UDEV_Quit(); 180 return SDL_SetError("Could not setup haptic <-> udev callback"); 181 } 182 183 /* Force a scan to build the initial device list */ 184 SDL_UDEV_Scan(); 185 #endif /* SDL_USE_LIBUDEV */ 186 187 return numhaptics; 188 } 189 190 int 191 SDL_SYS_NumHaptics(void) 192 { 193 return numhaptics; 194 } 195 196 static SDL_hapticlist_item * 197 HapticByDevIndex(int device_index) 198 { 199 SDL_hapticlist_item *item = SDL_hapticlist; 200 201 if ((device_index < 0) || (device_index >= numhaptics)) { 202 return NULL; 203 } 204 205 while (device_index > 0) { 206 SDL_assert(item != NULL); 207 --device_index; 208 item = item->next; 209 } 210 211 return item; 212 } 213 214 #if SDL_USE_LIBUDEV 215 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath) 216 { 217 if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) { 218 return; 219 } 220 221 switch( udev_type ) 222 { 223 case SDL_UDEV_DEVICEADDED: 224 MaybeAddDevice(devpath); 225 break; 226 227 case SDL_UDEV_DEVICEREMOVED: 228 MaybeRemoveDevice(devpath); 229 break; 230 231 default: 232 break; 233 } 234 235 } 236 #endif /* SDL_USE_LIBUDEV */ 237 238 static int 239 MaybeAddDevice(const char *path) 240 { 241 struct stat sb; 242 int fd; 243 int success; 244 SDL_hapticlist_item *item; 245 246 if (path == NULL) { 247 return -1; 248 } 249 250 /* check to see if file exists */ 251 if (stat(path, &sb) != 0) { 252 return -1; 253 } 254 255 /* check for duplicates */ 256 for (item = SDL_hapticlist; item != NULL; item = item->next) { 257 if (item->dev_num == sb.st_rdev) { 258 return -1; /* duplicate. */ 259 } 260 } 261 262 /* try to open */ 263 fd = open(path, O_RDWR, 0); 264 if (fd < 0) { 265 return -1; 266 } 267 268 #ifdef DEBUG_INPUT_EVENTS 269 printf("Checking %s\n", path); 270 #endif 271 272 /* see if it works */ 273 success = EV_IsHaptic(fd); 274 close(fd); 275 if (success <= 0) { 276 return -1; 277 } 278 279 item = (SDL_hapticlist_item *) SDL_calloc(1, sizeof (SDL_hapticlist_item)); 280 if (item == NULL) { 281 return -1; 282 } 283 284 item->fname = SDL_strdup(path); 285 if (item->fname == NULL) { 286 SDL_free(item); 287 return -1; 288 } 289 290 item->dev_num = sb.st_rdev; 291 292 /* TODO: should we add instance IDs? */ 293 if (SDL_hapticlist_tail == NULL) { 294 SDL_hapticlist = SDL_hapticlist_tail = item; 295 } else { 296 SDL_hapticlist_tail->next = item; 297 SDL_hapticlist_tail = item; 298 } 299 300 ++numhaptics; 301 302 /* !!! TODO: Send a haptic add event? */ 303 304 return numhaptics; 305 } 306 307 #if SDL_USE_LIBUDEV 308 static int 309 MaybeRemoveDevice(const char* path) 310 { 311 SDL_hapticlist_item *item; 312 SDL_hapticlist_item *prev = NULL; 313 314 if (path == NULL) { 315 return -1; 316 } 317 318 for (item = SDL_hapticlist; item != NULL; item = item->next) { 319 /* found it, remove it. */ 320 if (SDL_strcmp(path, item->fname) == 0) { 321 const int retval = item->haptic ? item->haptic->index : -1; 322 323 if (prev != NULL) { 324 prev->next = item->next; 325 } else { 326 SDL_assert(SDL_hapticlist == item); 327 SDL_hapticlist = item->next; 328 } 329 if (item == SDL_hapticlist_tail) { 330 SDL_hapticlist_tail = prev; 331 } 332 333 /* Need to decrement the haptic count */ 334 --numhaptics; 335 /* !!! TODO: Send a haptic remove event? */ 336 337 SDL_free(item->fname); 338 SDL_free(item); 339 return retval; 340 } 341 prev = item; 342 } 343 344 return -1; 345 } 346 #endif /* SDL_USE_LIBUDEV */ 347 348 /* 349 * Gets the name from a file descriptor. 350 */ 351 static const char * 352 SDL_SYS_HapticNameFromFD(int fd) 353 { 354 static char namebuf[128]; 355 356 /* We use the evdev name ioctl. */ 357 if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) { 358 return NULL; 359 } 360 361 return namebuf; 362 } 363 364 365 /* 366 * Return the name of a haptic device, does not need to be opened. 367 */ 368 const char * 369 SDL_SYS_HapticName(int index) 370 { 371 SDL_hapticlist_item *item; 372 int fd; 373 const char *name; 374 375 item = HapticByDevIndex(index); 376 /* Open the haptic device. */ 377 name = NULL; 378 fd = open(item->fname, O_RDONLY, 0); 379 380 if (fd >= 0) { 381 382 name = SDL_SYS_HapticNameFromFD(fd); 383 if (name == NULL) { 384 /* No name found, return device character device */ 385 name = item->fname; 386 } 387 close(fd); 388 } 389 390 return name; 391 } 392 393 394 /* 395 * Opens the haptic device from the file descriptor. 396 */ 397 static int 398 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd) 399 { 400 /* Allocate the hwdata */ 401 haptic->hwdata = (struct haptic_hwdata *) 402 SDL_malloc(sizeof(*haptic->hwdata)); 403 if (haptic->hwdata == NULL) { 404 SDL_OutOfMemory(); 405 goto open_err; 406 } 407 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); 408 409 /* Set the data. */ 410 haptic->hwdata->fd = fd; 411 haptic->supported = EV_IsHaptic(fd); 412 haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */ 413 414 /* Set the effects */ 415 if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) { 416 SDL_SetError("Haptic: Unable to query device memory: %s", 417 strerror(errno)); 418 goto open_err; 419 } 420 haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */ 421 haptic->effects = (struct haptic_effect *) 422 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); 423 if (haptic->effects == NULL) { 424 SDL_OutOfMemory(); 425 goto open_err; 426 } 427 /* Clear the memory */ 428 SDL_memset(haptic->effects, 0, 429 sizeof(struct haptic_effect) * haptic->neffects); 430 431 return 0; 432 433 /* Error handling */ 434 open_err: 435 close(fd); 436 if (haptic->hwdata != NULL) { 437 SDL_free(haptic->hwdata); 438 haptic->hwdata = NULL; 439 } 440 return -1; 441 } 442 443 444 /* 445 * Opens a haptic device for usage. 446 */ 447 int 448 SDL_SYS_HapticOpen(SDL_Haptic * haptic) 449 { 450 int fd; 451 int ret; 452 SDL_hapticlist_item *item; 453 454 item = HapticByDevIndex(haptic->index); 455 /* Open the character device */ 456 fd = open(item->fname, O_RDWR, 0); 457 if (fd < 0) { 458 return SDL_SetError("Haptic: Unable to open %s: %s", 459 item->fname, strerror(errno)); 460 } 461 462 /* Try to create the haptic. */ 463 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */ 464 if (ret < 0) { 465 return -1; 466 } 467 468 /* Set the fname. */ 469 haptic->hwdata->fname = SDL_strdup( item->fname ); 470 return 0; 471 } 472 473 474 /* 475 * Opens a haptic device from first mouse it finds for usage. 476 */ 477 int 478 SDL_SYS_HapticMouse(void) 479 { 480 int fd; 481 int device_index = 0; 482 SDL_hapticlist_item *item; 483 484 for (item = SDL_hapticlist; item; item = item->next) { 485 /* Open the device. */ 486 fd = open(item->fname, O_RDWR, 0); 487 if (fd < 0) { 488 return SDL_SetError("Haptic: Unable to open %s: %s", 489 item->fname, strerror(errno)); 490 } 491 492 /* Is it a mouse? */ 493 if (EV_IsMouse(fd)) { 494 close(fd); 495 return device_index; 496 } 497 498 close(fd); 499 500 ++device_index; 501 } 502 503 return -1; 504 } 505 506 507 /* 508 * Checks to see if a joystick has haptic features. 509 */ 510 int 511 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) 512 { 513 #ifdef SDL_JOYSTICK_LINUX 514 if (joystick->driver != &SDL_LINUX_JoystickDriver) { 515 return SDL_FALSE; 516 } 517 if (EV_IsHaptic(joystick->hwdata->fd)) { 518 return SDL_TRUE; 519 } 520 #endif 521 return SDL_FALSE; 522 } 523 524 525 /* 526 * Checks to see if the haptic device and joystick are in reality the same. 527 */ 528 int 529 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) 530 { 531 #ifdef SDL_JOYSTICK_LINUX 532 if (joystick->driver != &SDL_LINUX_JoystickDriver) { 533 return 0; 534 } 535 /* We are assuming Linux is using evdev which should trump the old 536 * joystick methods. */ 537 if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) { 538 return 1; 539 } 540 #endif 541 return 0; 542 } 543 544 545 /* 546 * Opens a SDL_Haptic from a SDL_Joystick. 547 */ 548 int 549 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) 550 { 551 #ifdef SDL_JOYSTICK_LINUX 552 int device_index = 0; 553 int fd; 554 int ret; 555 SDL_hapticlist_item *item; 556 557 if (joystick->driver != &SDL_LINUX_JoystickDriver) { 558 return -1; 559 } 560 /* Find the joystick in the haptic list. */ 561 for (item = SDL_hapticlist; item; item = item->next) { 562 if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) { 563 break; 564 } 565 ++device_index; 566 } 567 haptic->index = device_index; 568 569 if (device_index >= MAX_HAPTICS) { 570 return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities"); 571 } 572 573 fd = open(joystick->hwdata->fname, O_RDWR, 0); 574 if (fd < 0) { 575 return SDL_SetError("Haptic: Unable to open %s: %s", 576 joystick->hwdata->fname, strerror(errno)); 577 } 578 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */ 579 if (ret < 0) { 580 return -1; 581 } 582 583 haptic->hwdata->fname = SDL_strdup( joystick->hwdata->fname ); 584 585 return 0; 586 #else 587 return -1; 588 #endif 589 } 590 591 592 /* 593 * Closes the haptic device. 594 */ 595 void 596 SDL_SYS_HapticClose(SDL_Haptic * haptic) 597 { 598 if (haptic->hwdata) { 599 600 /* Free effects. */ 601 SDL_free(haptic->effects); 602 haptic->effects = NULL; 603 haptic->neffects = 0; 604 605 /* Clean up */ 606 close(haptic->hwdata->fd); 607 608 /* Free */ 609 SDL_free(haptic->hwdata->fname); 610 SDL_free(haptic->hwdata); 611 haptic->hwdata = NULL; 612 } 613 614 /* Clear the rest. */ 615 SDL_memset(haptic, 0, sizeof(SDL_Haptic)); 616 } 617 618 619 /* 620 * Clean up after system specific haptic stuff 621 */ 622 void 623 SDL_SYS_HapticQuit(void) 624 { 625 SDL_hapticlist_item *item = NULL; 626 SDL_hapticlist_item *next = NULL; 627 628 for (item = SDL_hapticlist; item; item = next) { 629 next = item->next; 630 /* Opened and not closed haptics are leaked, this is on purpose. 631 * Close your haptic devices after usage. */ 632 SDL_free(item->fname); 633 SDL_free(item); 634 } 635 636 #if SDL_USE_LIBUDEV 637 SDL_UDEV_DelCallback(haptic_udev_callback); 638 SDL_UDEV_Quit(); 639 #endif /* SDL_USE_LIBUDEV */ 640 641 numhaptics = 0; 642 SDL_hapticlist = NULL; 643 SDL_hapticlist_tail = NULL; 644 } 645 646 647 /* 648 * Converts an SDL button to a ff_trigger button. 649 */ 650 static Uint16 651 SDL_SYS_ToButton(Uint16 button) 652 { 653 Uint16 ff_button; 654 655 ff_button = 0; 656 657 /* 658 * Not sure what the proper syntax is because this actually isn't implemented 659 * in the current kernel from what I've seen (2.6.26). 660 */ 661 if (button != 0) { 662 ff_button = BTN_GAMEPAD + button - 1; 663 } 664 665 return ff_button; 666 } 667 668 669 /* 670 * Initializes the ff_effect usable direction from a SDL_HapticDirection. 671 */ 672 static int 673 SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src) 674 { 675 Uint32 tmp; 676 677 switch (src->type) { 678 case SDL_HAPTIC_POLAR: 679 /* Linux directions start from south. 680 (and range from 0 to 0xFFFF) 681 Quoting include/linux/input.h, line 926: 682 Direction of the effect is encoded as follows: 683 0 deg -> 0x0000 (down) 684 90 deg -> 0x4000 (left) 685 180 deg -> 0x8000 (up) 686 270 deg -> 0xC000 (right) 687 The force pulls into the direction specified by Linux directions, 688 i.e. the opposite convention of SDL directions. 689 */ 690 tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */ 691 *dest = (Uint16) tmp; 692 break; 693 694 case SDL_HAPTIC_SPHERICAL: 695 /* 696 We convert to polar, because that's the only supported direction on Linux. 697 The first value of a spherical direction is practically the same as a 698 Polar direction, except that we have to add 90 degrees. It is the angle 699 from EAST {1,0} towards SOUTH {0,1}. 700 --> add 9000 701 --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. 702 */ 703 tmp = ((src->dir[0]) + 9000) % 36000; /* Convert to polars */ 704 tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */ 705 *dest = (Uint16) tmp; 706 break; 707 708 case SDL_HAPTIC_CARTESIAN: 709 if (!src->dir[1]) 710 *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000); 711 else if (!src->dir[0]) 712 *dest = (src->dir[1] >= 0 ? 0x8000 : 0); 713 else { 714 float f = SDL_atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */ 715 /* 716 atan2 takes the parameters: Y-axis-value and X-axis-value (in that order) 717 - Y-axis-value is the second coordinate (from center to SOUTH) 718 - X-axis-value is the first coordinate (from center to EAST) 719 We add 36000, because atan2 also returns negative values. Then we practically 720 have the first spherical value. Therefore we proceed as in case 721 SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value. 722 --> add 45000 in total 723 --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR. 724 */ 725 tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000; 726 tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */ 727 *dest = (Uint16) tmp; 728 } 729 break; 730 case SDL_HAPTIC_STEERING_AXIS: 731 *dest = 0x4000; 732 break; 733 default: 734 return SDL_SetError("Haptic: Unsupported direction type."); 735 } 736 737 return 0; 738 } 739 740 741 #define CLAMP(x) (((x) > 32767) ? 32767 : x) 742 /* 743 * Initializes the Linux effect struct from a haptic_effect. 744 * Values above 32767 (for unsigned) are unspecified so we must clamp. 745 */ 746 static int 747 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src) 748 { 749 SDL_HapticConstant *constant; 750 SDL_HapticPeriodic *periodic; 751 SDL_HapticCondition *condition; 752 SDL_HapticRamp *ramp; 753 SDL_HapticLeftRight *leftright; 754 755 /* Clear up */ 756 SDL_memset(dest, 0, sizeof(struct ff_effect)); 757 758 switch (src->type) { 759 case SDL_HAPTIC_CONSTANT: 760 constant = &src->constant; 761 762 /* Header */ 763 dest->type = FF_CONSTANT; 764 if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1) 765 return -1; 766 767 /* Replay */ 768 dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ? 769 0 : CLAMP(constant->length); 770 dest->replay.delay = CLAMP(constant->delay); 771 772 /* Trigger */ 773 dest->trigger.button = SDL_SYS_ToButton(constant->button); 774 dest->trigger.interval = CLAMP(constant->interval); 775 776 /* Constant */ 777 dest->u.constant.level = constant->level; 778 779 /* Envelope */ 780 dest->u.constant.envelope.attack_length = 781 CLAMP(constant->attack_length); 782 dest->u.constant.envelope.attack_level = 783 CLAMP(constant->attack_level); 784 dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length); 785 dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level); 786 787 break; 788 789 case SDL_HAPTIC_SINE: 790 /* !!! FIXME: put this back when we have more bits in 2.1 */ 791 /* case SDL_HAPTIC_SQUARE: */ 792 case SDL_HAPTIC_TRIANGLE: 793 case SDL_HAPTIC_SAWTOOTHUP: 794 case SDL_HAPTIC_SAWTOOTHDOWN: 795 periodic = &src->periodic; 796 797 /* Header */ 798 dest->type = FF_PERIODIC; 799 if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1) 800 return -1; 801 802 /* Replay */ 803 dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ? 804 0 : CLAMP(periodic->length); 805 dest->replay.delay = CLAMP(periodic->delay); 806 807 /* Trigger */ 808 dest->trigger.button = SDL_SYS_ToButton(periodic->button); 809 dest->trigger.interval = CLAMP(periodic->interval); 810 811 /* Periodic */ 812 if (periodic->type == SDL_HAPTIC_SINE) 813 dest->u.periodic.waveform = FF_SINE; 814 /* !!! FIXME: put this back when we have more bits in 2.1 */ 815 /* else if (periodic->type == SDL_HAPTIC_SQUARE) 816 dest->u.periodic.waveform = FF_SQUARE; */ 817 else if (periodic->type == SDL_HAPTIC_TRIANGLE) 818 dest->u.periodic.waveform = FF_TRIANGLE; 819 else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP) 820 dest->u.periodic.waveform = FF_SAW_UP; 821 else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN) 822 dest->u.periodic.waveform = FF_SAW_DOWN; 823 dest->u.periodic.period = CLAMP(periodic->period); 824 dest->u.periodic.magnitude = periodic->magnitude; 825 dest->u.periodic.offset = periodic->offset; 826 /* Linux phase is defined in interval "[0x0000, 0x10000[", corresponds with "[0deg, 360deg[" phase shift. */ 827 dest->u.periodic.phase = ((Uint32)periodic->phase * 0x10000U) / 36000; 828 829 /* Envelope */ 830 dest->u.periodic.envelope.attack_length = 831 CLAMP(periodic->attack_length); 832 dest->u.periodic.envelope.attack_level = 833 CLAMP(periodic->attack_level); 834 dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length); 835 dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level); 836 837 break; 838 839 case SDL_HAPTIC_SPRING: 840 case SDL_HAPTIC_DAMPER: 841 case SDL_HAPTIC_INERTIA: 842 case SDL_HAPTIC_FRICTION: 843 condition = &src->condition; 844 845 /* Header */ 846 if (condition->type == SDL_HAPTIC_SPRING) 847 dest->type = FF_SPRING; 848 else if (condition->type == SDL_HAPTIC_DAMPER) 849 dest->type = FF_DAMPER; 850 else if (condition->type == SDL_HAPTIC_INERTIA) 851 dest->type = FF_INERTIA; 852 else if (condition->type == SDL_HAPTIC_FRICTION) 853 dest->type = FF_FRICTION; 854 dest->direction = 0; /* Handled by the condition-specifics. */ 855 856 /* Replay */ 857 dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ? 858 0 : CLAMP(condition->length); 859 dest->replay.delay = CLAMP(condition->delay); 860 861 /* Trigger */ 862 dest->trigger.button = SDL_SYS_ToButton(condition->button); 863 dest->trigger.interval = CLAMP(condition->interval); 864 865 /* Condition */ 866 /* X axis */ 867 dest->u.condition[0].right_saturation = condition->right_sat[0]; 868 dest->u.condition[0].left_saturation = condition->left_sat[0]; 869 dest->u.condition[0].right_coeff = condition->right_coeff[0]; 870 dest->u.condition[0].left_coeff = condition->left_coeff[0]; 871 dest->u.condition[0].deadband = condition->deadband[0]; 872 dest->u.condition[0].center = condition->center[0]; 873 /* Y axis */ 874 dest->u.condition[1].right_saturation = condition->right_sat[1]; 875 dest->u.condition[1].left_saturation = condition->left_sat[1]; 876 dest->u.condition[1].right_coeff = condition->right_coeff[1]; 877 dest->u.condition[1].left_coeff = condition->left_coeff[1]; 878 dest->u.condition[1].deadband = condition->deadband[1]; 879 dest->u.condition[1].center = condition->center[1]; 880 881 /* 882 * There is no envelope in the linux force feedback api for conditions. 883 */ 884 885 break; 886 887 case SDL_HAPTIC_RAMP: 888 ramp = &src->ramp; 889 890 /* Header */ 891 dest->type = FF_RAMP; 892 if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1) 893 return -1; 894 895 /* Replay */ 896 dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ? 897 0 : CLAMP(ramp->length); 898 dest->replay.delay = CLAMP(ramp->delay); 899 900 /* Trigger */ 901 dest->trigger.button = SDL_SYS_ToButton(ramp->button); 902 dest->trigger.interval = CLAMP(ramp->interval); 903 904 /* Ramp */ 905 dest->u.ramp.start_level = ramp->start; 906 dest->u.ramp.end_level = ramp->end; 907 908 /* Envelope */ 909 dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length); 910 dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level); 911 dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length); 912 dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level); 913 914 break; 915 916 case SDL_HAPTIC_LEFTRIGHT: 917 leftright = &src->leftright; 918 919 /* Header */ 920 dest->type = FF_RUMBLE; 921 dest->direction = 0; 922 923 /* Replay */ 924 dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ? 925 0 : CLAMP(leftright->length); 926 927 /* Trigger */ 928 dest->trigger.button = 0; 929 dest->trigger.interval = 0; 930 931 /* Rumble (Linux expects 0-65535, so multiply by 2) */ 932 dest->u.rumble.strong_magnitude = CLAMP(leftright->large_magnitude) * 2; 933 dest->u.rumble.weak_magnitude = CLAMP(leftright->small_magnitude) * 2; 934 935 break; 936 937 938 default: 939 return SDL_SetError("Haptic: Unknown effect type."); 940 } 941 942 return 0; 943 } 944 945 946 /* 947 * Creates a new haptic effect. 948 */ 949 int 950 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, 951 SDL_HapticEffect * base) 952 { 953 struct ff_effect *linux_effect; 954 955 /* Allocate the hardware effect */ 956 effect->hweffect = (struct haptic_hweffect *) 957 SDL_malloc(sizeof(struct haptic_hweffect)); 958 if (effect->hweffect == NULL) { 959 return SDL_OutOfMemory(); 960 } 961 962 /* Prepare the ff_effect */ 963 linux_effect = &effect->hweffect->effect; 964 if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) { 965 goto new_effect_err; 966 } 967 linux_effect->id = -1; /* Have the kernel give it an id */ 968 969 /* Upload the effect */ 970 if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) { 971 SDL_SetError("Haptic: Error uploading effect to the device: %s", 972 strerror(errno)); 973 goto new_effect_err; 974 } 975 976 return 0; 977 978 new_effect_err: 979 SDL_free(effect->hweffect); 980 effect->hweffect = NULL; 981 return -1; 982 } 983 984 985 /* 986 * Updates an effect. 987 * 988 * Note: Dynamically updating the direction can in some cases force 989 * the effect to restart and run once. 990 */ 991 int 992 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, 993 struct haptic_effect *effect, 994 SDL_HapticEffect * data) 995 { 996 struct ff_effect linux_effect; 997 998 /* Create the new effect */ 999 if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) { 1000 return -1; 1001 } 1002 linux_effect.id = effect->hweffect->effect.id; 1003 1004 /* See if it can be uploaded. */ 1005 if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) { 1006 return SDL_SetError("Haptic: Error updating the effect: %s", 1007 strerror(errno)); 1008 } 1009 1010 /* Copy the new effect into memory. */ 1011 SDL_memcpy(&effect->hweffect->effect, &linux_effect, 1012 sizeof(struct ff_effect)); 1013 1014 return effect->hweffect->effect.id; 1015 } 1016 1017 1018 /* 1019 * Runs an effect. 1020 */ 1021 int 1022 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, 1023 Uint32 iterations) 1024 { 1025 struct input_event run; 1026 1027 /* Prepare to run the effect */ 1028 run.type = EV_FF; 1029 run.code = effect->hweffect->effect.id; 1030 /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */ 1031 run.value = (iterations > INT_MAX) ? INT_MAX : iterations; 1032 1033 if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) { 1034 return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno)); 1035 } 1036 1037 return 0; 1038 } 1039 1040 1041 /* 1042 * Stops an effect. 1043 */ 1044 int 1045 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) 1046 { 1047 struct input_event stop; 1048 1049 stop.type = EV_FF; 1050 stop.code = effect->hweffect->effect.id; 1051 stop.value = 0; 1052 1053 if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) { 1054 return SDL_SetError("Haptic: Unable to stop the effect: %s", 1055 strerror(errno)); 1056 } 1057 1058 return 0; 1059 } 1060 1061 1062 /* 1063 * Frees the effect. 1064 */ 1065 void 1066 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) 1067 { 1068 if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) { 1069 SDL_SetError("Haptic: Error removing the effect from the device: %s", 1070 strerror(errno)); 1071 } 1072 SDL_free(effect->hweffect); 1073 effect->hweffect = NULL; 1074 } 1075 1076 1077 /* 1078 * Gets the status of a haptic effect. 1079 */ 1080 int 1081 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, 1082 struct haptic_effect *effect) 1083 { 1084 #if 0 /* Not supported atm. */ 1085 struct input_event ie; 1086 1087 ie.type = EV_FF; 1088 ie.type = EV_FF_STATUS; 1089 ie.code = effect->hweffect->effect.id; 1090 1091 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { 1092 return SDL_SetError("Haptic: Error getting device status."); 1093 } 1094 1095 return 0; 1096 #endif 1097 1098 return -1; 1099 } 1100 1101 1102 /* 1103 * Sets the gain. 1104 */ 1105 int 1106 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) 1107 { 1108 struct input_event ie; 1109 1110 ie.type = EV_FF; 1111 ie.code = FF_GAIN; 1112 ie.value = (0xFFFFUL * gain) / 100; 1113 1114 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { 1115 return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno)); 1116 } 1117 1118 return 0; 1119 } 1120 1121 1122 /* 1123 * Sets the autocentering. 1124 */ 1125 int 1126 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) 1127 { 1128 struct input_event ie; 1129 1130 ie.type = EV_FF; 1131 ie.code = FF_AUTOCENTER; 1132 ie.value = (0xFFFFUL * autocenter) / 100; 1133 1134 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) { 1135 return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno)); 1136 } 1137 1138 return 0; 1139 } 1140 1141 1142 /* 1143 * Pausing is not supported atm by linux. 1144 */ 1145 int 1146 SDL_SYS_HapticPause(SDL_Haptic * haptic) 1147 { 1148 return -1; 1149 } 1150 1151 1152 /* 1153 * Unpausing is not supported atm by linux. 1154 */ 1155 int 1156 SDL_SYS_HapticUnpause(SDL_Haptic * haptic) 1157 { 1158 return -1; 1159 } 1160 1161 1162 /* 1163 * Stops all the currently playing effects. 1164 */ 1165 int 1166 SDL_SYS_HapticStopAll(SDL_Haptic * haptic) 1167 { 1168 int i, ret; 1169 1170 /* Linux does not support this natively so we have to loop. */ 1171 for (i = 0; i < haptic->neffects; i++) { 1172 if (haptic->effects[i].hweffect != NULL) { 1173 ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]); 1174 if (ret < 0) { 1175 return SDL_SetError 1176 ("Haptic: Error while trying to stop all playing effects."); 1177 } 1178 } 1179 } 1180 return 0; 1181 } 1182 1183 #endif /* SDL_HAPTIC_LINUX */ 1184 1185 /* vi: set ts=4 sw=4 expandtab: */