2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #ifdef SDL_HAPTIC_LINUX
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"
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 */
43 # define M_PI 3.14159265358979323846
47 #define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */
49 static int MaybeAddDevice(const char *path);
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 */
56 * List of available haptic devices.
58 typedef struct SDL_hapticlist_item
60 char *fname; /* Dev path name (like /dev/input/event1) */
61 SDL_Haptic *haptic; /* Associated haptic. */
63 struct SDL_hapticlist_item *next;
64 } SDL_hapticlist_item;
68 * Haptic system hardware data.
72 int fd; /* File descriptor of the device. */
73 char *fname; /* Points to the name in SDL_hapticlist. */
78 * Haptic system effect data.
80 struct haptic_hweffect
82 struct ff_effect effect; /* The linux kernel effect structure. */
85 static SDL_hapticlist_item *SDL_hapticlist = NULL;
86 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
87 static int numhaptics = 0;
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);
94 * Test whether a device has haptic properties.
95 * Returns available properties or 0 if there are none.
101 unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
103 /* Ask device for what it has. */
105 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
106 return SDL_SetError("Haptic: Unable to get device's features: %s",
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);
128 /* Return what it supports. */
134 * Tests whether a device is a mouse or not.
139 unsigned long argp[40];
141 /* Ask for supported features. */
142 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
146 /* Currently we only test for BTN_MOUSE which can give fake positives. */
147 if (test_bit(BTN_MOUSE, argp) != 0) {
155 * Initializes the haptic subsystem by finding available devices.
158 SDL_SYS_HapticInit(void)
160 const char joydev_pattern[] = "/dev/input/event%d";
165 * Limit amount of checks to MAX_HAPTICS since we may or may not have
166 * permission to some or all devices.
169 for (j = 0; j < MAX_HAPTICS; ++j) {
171 snprintf(path, PATH_MAX, joydev_pattern, i++);
172 MaybeAddDevice(path);
176 if (SDL_UDEV_Init() < 0) {
177 return SDL_SetError("Could not initialize UDEV");
180 if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) {
182 return SDL_SetError("Could not setup haptic <-> udev callback");
184 #endif /* SDL_USE_LIBUDEV */
195 static SDL_hapticlist_item *
196 HapticByDevIndex(int device_index)
198 SDL_hapticlist_item *item = SDL_hapticlist;
200 if ((device_index < 0) || (device_index >= numhaptics)) {
204 while (device_index > 0) {
205 SDL_assert(item != NULL);
214 void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
216 if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
222 case SDL_UDEV_DEVICEADDED:
223 MaybeAddDevice(devpath);
226 case SDL_UDEV_DEVICEREMOVED:
227 MaybeRemoveDevice(devpath);
235 #endif /* SDL_USE_LIBUDEV */
238 MaybeAddDevice(const char *path)
243 SDL_hapticlist_item *item;
249 /* check to see if file exists */
250 if (stat(path, &sb) != 0) {
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. */
262 fd = open(path, O_RDWR, 0);
267 #ifdef DEBUG_INPUT_EVENTS
268 printf("Checking %s\n", path);
271 /* see if it works */
272 success = EV_IsHaptic(fd);
278 item = (SDL_hapticlist_item *) SDL_calloc(1, sizeof (SDL_hapticlist_item));
283 item->fname = SDL_strdup(path);
284 if (item->fname == NULL) {
289 item->dev_num = sb.st_rdev;
291 /* TODO: should we add instance IDs? */
292 if (SDL_hapticlist_tail == NULL) {
293 SDL_hapticlist = SDL_hapticlist_tail = item;
295 SDL_hapticlist_tail->next = item;
296 SDL_hapticlist_tail = item;
301 /* !!! TODO: Send a haptic add event? */
308 MaybeRemoveDevice(const char* path)
310 SDL_hapticlist_item *item;
311 SDL_hapticlist_item *prev = NULL;
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;
323 prev->next = item->next;
325 SDL_assert(SDL_hapticlist == item);
326 SDL_hapticlist = item->next;
328 if (item == SDL_hapticlist_tail) {
329 SDL_hapticlist_tail = prev;
332 /* Need to decrement the haptic count */
334 /* !!! TODO: Send a haptic remove event? */
336 SDL_free(item->fname);
345 #endif /* SDL_USE_LIBUDEV */
348 * Gets the name from a file descriptor.
351 SDL_SYS_HapticNameFromFD(int fd)
353 static char namebuf[128];
355 /* We use the evdev name ioctl. */
356 if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
365 * Return the name of a haptic device, does not need to be opened.
368 SDL_SYS_HapticName(int index)
370 SDL_hapticlist_item *item;
374 item = HapticByDevIndex(index);
375 /* Open the haptic device. */
377 fd = open(item->fname, O_RDONLY, 0);
381 name = SDL_SYS_HapticNameFromFD(fd);
383 /* No name found, return device character device */
394 * Opens the haptic device from the file descriptor.
397 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
399 /* Allocate the hwdata */
400 haptic->hwdata = (struct haptic_hwdata *)
401 SDL_malloc(sizeof(*haptic->hwdata));
402 if (haptic->hwdata == NULL) {
406 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
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. */
413 /* Set the effects */
414 if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
415 SDL_SetError("Haptic: Unable to query device memory: %s",
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) {
426 /* Clear the memory */
427 SDL_memset(haptic->effects, 0,
428 sizeof(struct haptic_effect) * haptic->neffects);
435 if (haptic->hwdata != NULL) {
436 SDL_free(haptic->hwdata);
437 haptic->hwdata = NULL;
444 * Opens a haptic device for usage.
447 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
451 SDL_hapticlist_item *item;
453 item = HapticByDevIndex(haptic->index);
454 /* Open the character device */
455 fd = open(item->fname, O_RDWR, 0);
457 return SDL_SetError("Haptic: Unable to open %s: %s",
458 item->fname, strerror(errno));
461 /* Try to create the haptic. */
462 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
468 haptic->hwdata->fname = SDL_strdup( item->fname );
474 * Opens a haptic device from first mouse it finds for usage.
477 SDL_SYS_HapticMouse(void)
480 int device_index = 0;
481 SDL_hapticlist_item *item;
483 for (item = SDL_hapticlist; item; item = item->next) {
484 /* Open the device. */
485 fd = open(item->fname, O_RDWR, 0);
487 return SDL_SetError("Haptic: Unable to open %s: %s",
488 item->fname, strerror(errno));
492 if (EV_IsMouse(fd)) {
507 * Checks to see if a joystick has haptic features.
510 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
512 return EV_IsHaptic(joystick->hwdata->fd);
517 * Checks to see if the haptic device and joystick are in reality the same.
520 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
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) {
532 * Opens a SDL_Haptic from a SDL_Joystick.
535 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
537 int device_index = 0;
540 SDL_hapticlist_item *item;
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) {
549 haptic->index = device_index;
551 if (device_index >= MAX_HAPTICS) {
552 return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
555 fd = open(joystick->hwdata->fname, O_RDWR, 0);
557 return SDL_SetError("Haptic: Unable to open %s: %s",
558 joystick->hwdata->fname, strerror(errno));
560 ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
565 haptic->hwdata->fname = SDL_strdup( joystick->hwdata->fname );
572 * Closes the haptic device.
575 SDL_SYS_HapticClose(SDL_Haptic * haptic)
577 if (haptic->hwdata) {
580 SDL_free(haptic->effects);
581 haptic->effects = NULL;
582 haptic->neffects = 0;
585 close(haptic->hwdata->fd);
588 SDL_free(haptic->hwdata->fname);
589 SDL_free(haptic->hwdata);
590 haptic->hwdata = NULL;
593 /* Clear the rest. */
594 SDL_memset(haptic, 0, sizeof(SDL_Haptic));
599 * Clean up after system specific haptic stuff
602 SDL_SYS_HapticQuit(void)
604 SDL_hapticlist_item *item = NULL;
605 SDL_hapticlist_item *next = NULL;
607 for (item = SDL_hapticlist; item; 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);
616 SDL_UDEV_DelCallback(haptic_udev_callback);
618 #endif /* SDL_USE_LIBUDEV */
621 SDL_hapticlist = NULL;
622 SDL_hapticlist_tail = NULL;
627 * Converts an SDL button to a ff_trigger button.
630 SDL_SYS_ToButton(Uint16 button)
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).
641 ff_button = BTN_GAMEPAD + button - 1;
649 * Initializes the ff_effect usable direction from a SDL_HapticDirection.
652 SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
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.
669 tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
670 *dest = (Uint16) tmp;
673 case SDL_HAPTIC_SPHERICAL:
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}.
680 --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
682 tmp = ((src->dir[0]) + 9000) % 36000; /* Convert to polars */
683 tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
684 *dest = (Uint16) tmp;
687 case SDL_HAPTIC_CARTESIAN:
689 *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000);
690 else if (!src->dir[0])
691 *dest = (src->dir[1] >= 0 ? 0x8000 : 0);
693 float f = atan2(src->dir[1], src->dir[0]); /* Ideally we'd use fixed point math instead of floats... */
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.
704 tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
705 tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
706 *dest = (Uint16) tmp;
711 return SDL_SetError("Haptic: Unsupported direction type.");
718 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
720 * Initializes the Linux effect struct from a haptic_effect.
721 * Values above 32767 (for unsigned) are unspecified so we must clamp.
724 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
726 SDL_HapticConstant *constant;
727 SDL_HapticPeriodic *periodic;
728 SDL_HapticCondition *condition;
729 SDL_HapticRamp *ramp;
730 SDL_HapticLeftRight *leftright;
733 SDL_memset(dest, 0, sizeof(struct ff_effect));
736 case SDL_HAPTIC_CONSTANT:
737 constant = &src->constant;
740 dest->type = FF_CONSTANT;
741 if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1)
745 dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
746 0 : CLAMP(constant->length);
747 dest->replay.delay = CLAMP(constant->delay);
750 dest->trigger.button = SDL_SYS_ToButton(constant->button);
751 dest->trigger.interval = CLAMP(constant->interval);
754 dest->u.constant.level = constant->level;
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);
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;
775 dest->type = FF_PERIODIC;
776 if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1)
780 dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
781 0 : CLAMP(periodic->length);
782 dest->replay.delay = CLAMP(periodic->delay);
785 dest->trigger.button = SDL_SYS_ToButton(periodic->button);
786 dest->trigger.interval = CLAMP(periodic->interval);
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;
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);
816 case SDL_HAPTIC_SPRING:
817 case SDL_HAPTIC_DAMPER:
818 case SDL_HAPTIC_INERTIA:
819 case SDL_HAPTIC_FRICTION:
820 condition = &src->condition;
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. */
834 dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
835 0 : CLAMP(condition->length);
836 dest->replay.delay = CLAMP(condition->delay);
839 dest->trigger.button = SDL_SYS_ToButton(condition->button);
840 dest->trigger.interval = CLAMP(condition->interval);
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];
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];
859 * There is no envelope in the linux force feedback api for conditions.
864 case SDL_HAPTIC_RAMP:
868 dest->type = FF_RAMP;
869 if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1)
873 dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
874 0 : CLAMP(ramp->length);
875 dest->replay.delay = CLAMP(ramp->delay);
878 dest->trigger.button = SDL_SYS_ToButton(ramp->button);
879 dest->trigger.interval = CLAMP(ramp->interval);
882 dest->u.ramp.start_level = ramp->start;
883 dest->u.ramp.end_level = ramp->end;
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);
893 case SDL_HAPTIC_LEFTRIGHT:
894 leftright = &src->leftright;
897 dest->type = FF_RUMBLE;
901 dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
902 0 : CLAMP(leftright->length);
905 dest->trigger.button = 0;
906 dest->trigger.interval = 0;
909 dest->u.rumble.strong_magnitude = leftright->large_magnitude;
910 dest->u.rumble.weak_magnitude = leftright->small_magnitude;
916 return SDL_SetError("Haptic: Unknown effect type.");
924 * Creates a new haptic effect.
927 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
928 SDL_HapticEffect * base)
930 struct ff_effect *linux_effect;
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();
939 /* Prepare the ff_effect */
940 linux_effect = &effect->hweffect->effect;
941 if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
944 linux_effect->id = -1; /* Have the kernel give it an id */
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",
956 SDL_free(effect->hweffect);
957 effect->hweffect = NULL;
965 * Note: Dynamically updating the direction can in some cases force
966 * the effect to restart and run once.
969 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
970 struct haptic_effect *effect,
971 SDL_HapticEffect * data)
973 struct ff_effect linux_effect;
975 /* Create the new effect */
976 if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
979 linux_effect.id = effect->hweffect->effect.id;
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",
987 /* Copy the new effect into memory. */
988 SDL_memcpy(&effect->hweffect->effect, &linux_effect,
989 sizeof(struct ff_effect));
991 return effect->hweffect->effect.id;
999 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1002 struct input_event run;
1004 /* Prepare to run the effect */
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;
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));
1022 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1024 struct input_event stop;
1027 stop.code = effect->hweffect->effect.id;
1030 if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
1031 return SDL_SetError("Haptic: Unable to stop the effect: %s",
1043 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1045 if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
1046 SDL_SetError("Haptic: Error removing the effect from the device: %s",
1049 SDL_free(effect->hweffect);
1050 effect->hweffect = NULL;
1055 * Gets the status of a haptic effect.
1058 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
1059 struct haptic_effect *effect)
1061 #if 0 /* Not supported atm. */
1062 struct input_event ie;
1065 ie.type = EV_FF_STATUS;
1066 ie.code = effect->hweffect->effect.id;
1068 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1069 return SDL_SetError("Haptic: Error getting device status.");
1083 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
1085 struct input_event ie;
1089 ie.value = (0xFFFFUL * gain) / 100;
1091 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1092 return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
1100 * Sets the autocentering.
1103 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1105 struct input_event ie;
1108 ie.code = FF_AUTOCENTER;
1109 ie.value = (0xFFFFUL * autocenter) / 100;
1111 if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
1112 return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
1120 * Pausing is not supported atm by linux.
1123 SDL_SYS_HapticPause(SDL_Haptic * haptic)
1130 * Unpausing is not supported atm by linux.
1133 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
1140 * Stops all the currently playing effects.
1143 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
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]);
1153 ("Haptic: Error while trying to stop all playing effects.");
1160 #endif /* SDL_HAPTIC_LINUX */
1162 /* vi: set ts=4 sw=4 expandtab: */