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