21 #include "../../SDL_internal.h"
23 #ifdef SDL_HAPTIC_LINUX
27 #include "../SDL_syshaptic.h"
29 #include "../../joystick/SDL_sysjoystick.h"
30 #include "../../joystick/linux/SDL_sysjoystick_c.h"
31 #include "../../core/linux/SDL_udev.h"
34 #include <linux/input.h>
43 # define M_PI 3.14159265358979323846
47 #define MAX_HAPTICS 32
49 static int MaybeAddDevice(
const char *
path);
51 static int MaybeRemoveDevice(
const char *
path);
52 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath);
82 struct ff_effect effect;
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);
101 unsigned long features[1 + FF_MAX /
sizeof(
unsigned long)];
105 if (ioctl(
fd, EVIOCGBIT(EV_FF,
sizeof(features)), features) < 0) {
106 return SDL_SetError(
"Haptic: Unable to get device's features: %s",
139 unsigned long argp[40];
142 if (ioctl(
fd, EVIOCGBIT(EV_KEY,
sizeof(argp)), argp) < 0) {
147 if (test_bit(BTN_MOUSE, argp) != 0) {
160 const char joydev_pattern[] =
"/dev/input/event%d";
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) {
180 if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) {
182 return SDL_SetError(
"Could not setup haptic <-> udev callback");
199 HapticByDevIndex(
int device_index)
203 if ((device_index < 0) || (device_index >= numhaptics)) {
207 while (device_index > 0) {
217 static void haptic_udev_callback(SDL_UDEV_deviceevent udev_type,
int udev_class,
const char *devpath)
219 if (devpath ==
NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
225 case SDL_UDEV_DEVICEADDED:
226 MaybeAddDevice(devpath);
229 case SDL_UDEV_DEVICEREMOVED:
230 MaybeRemoveDevice(devpath);
241 MaybeAddDevice(
const char *
path)
253 if (stat(
path, &sb) != 0) {
259 if (item->dev_num == sb.st_rdev) {
265 fd = open(
path, O_RDWR, 0);
270 #ifdef DEBUG_INPUT_EVENTS
271 printf(
"Checking %s\n",
path);
275 success = EV_IsHaptic(
fd);
287 if (item->fname ==
NULL) {
292 item->dev_num = sb.st_rdev;
295 if (SDL_hapticlist_tail ==
NULL) {
298 SDL_hapticlist_tail->
next = item;
299 SDL_hapticlist_tail = item;
311 MaybeRemoveDevice(
const char*
path)
331 if (item == SDL_hapticlist_tail) {
332 SDL_hapticlist_tail = prev;
354 SDL_SYS_HapticNameFromFD(
int fd)
356 static char namebuf[128];
359 if (ioctl(
fd, EVIOCGNAME(
sizeof(namebuf)), namebuf) <= 0) {
377 item = HapticByDevIndex(
index);
380 fd = open(item->fname, O_RDONLY, 0);
384 name = SDL_SYS_HapticNameFromFD(
fd);
400 SDL_SYS_HapticOpenFromFD(SDL_Haptic *
haptic,
int fd)
413 haptic->supported = EV_IsHaptic(
fd);
417 if (ioctl(
fd, EVIOCGEFFECTS, &
haptic->neffects) < 0) {
418 SDL_SetError(
"Haptic: Unable to query device memory: %s",
456 item = HapticByDevIndex(
haptic->index);
458 fd = open(item->fname, O_RDWR, 0);
461 item->fname, strerror(errno));
465 ret = SDL_SYS_HapticOpenFromFD(
haptic,
fd);
483 int device_index = 0;
488 fd = open(item->fname, O_RDWR, 0);
491 item->fname, strerror(errno));
495 if (EV_IsMouse(
fd)) {
515 return EV_IsHaptic(joystick->hwdata->fd);
540 int device_index = 0;
547 if (
SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
552 haptic->index = device_index;
554 if (device_index >= MAX_HAPTICS) {
555 return SDL_SetError(
"Haptic: Joystick doesn't have Haptic capabilities");
558 fd = open(joystick->hwdata->fname, O_RDWR, 0);
561 joystick->hwdata->fname, strerror(errno));
563 ret = SDL_SYS_HapticOpenFromFD(
haptic,
fd);
588 close(
haptic->hwdata->fd);
619 SDL_UDEV_DelCallback(haptic_udev_callback);
625 SDL_hapticlist_tail =
NULL;
644 ff_button = BTN_GAMEPAD +
button - 1;
672 tmp = ((
src->dir[0] % 36000) * 0x8000) / 18000;
685 tmp = ((
src->dir[0]) + 9000) % 36000;
686 tmp = (tmp * 0x8000) / 18000;
692 *dest = (
src->dir[0] >= 0 ? 0x4000 : 0xC000);
693 else if (!
src->dir[0])
694 *dest = (
src->dir[1] >= 0 ? 0x8000 : 0);
707 tmp = (((
Sint32) (
f * 18000. / M_PI)) + 45000) % 36000;
708 tmp = (tmp * 0x8000) / 18000;
714 return SDL_SetError(
"Haptic: Unsupported direction type.");
721 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
736 SDL_memset(dest, 0,
sizeof(
struct ff_effect));
740 constant = &
src->constant;
743 dest->
type = FF_CONSTANT;
744 if (SDL_SYS_ToDirection(&dest->direction, &constant->
direction) == -1)
749 0 : CLAMP(constant->
length);
750 dest->replay.delay = CLAMP(constant->
delay);
753 dest->trigger.button = SDL_SYS_ToButton(constant->
button);
754 dest->trigger.interval = CLAMP(constant->
interval);
757 dest->u.constant.level = constant->
level;
760 dest->u.constant.envelope.attack_length =
762 dest->u.constant.envelope.attack_level =
764 dest->u.constant.envelope.fade_length = CLAMP(constant->
fade_length);
765 dest->u.constant.envelope.fade_level = CLAMP(constant->
fade_level);
775 periodic = &
src->periodic;
778 dest->
type = FF_PERIODIC;
779 if (SDL_SYS_ToDirection(&dest->direction, &periodic->
direction) == -1)
784 0 : CLAMP(periodic->
length);
785 dest->replay.delay = CLAMP(periodic->
delay);
788 dest->trigger.button = SDL_SYS_ToButton(periodic->
button);
789 dest->trigger.interval = CLAMP(periodic->
interval);
793 dest->u.periodic.waveform = FF_SINE;
798 dest->u.periodic.waveform = FF_TRIANGLE;
800 dest->u.periodic.waveform = FF_SAW_UP;
802 dest->u.periodic.waveform = FF_SAW_DOWN;
803 dest->u.periodic.period = CLAMP(periodic->
period);
804 dest->u.periodic.magnitude = periodic->
magnitude;
805 dest->u.periodic.offset = periodic->
offset;
807 dest->u.periodic.phase = ((
Uint32)periodic->
phase * 0x10000U) / 36000;
810 dest->u.periodic.envelope.attack_length =
812 dest->u.periodic.envelope.attack_level =
814 dest->u.periodic.envelope.fade_length = CLAMP(periodic->
fade_length);
815 dest->u.periodic.envelope.fade_level = CLAMP(periodic->
fade_level);
827 dest->type = FF_SPRING;
829 dest->type = FF_DAMPER;
831 dest->type = FF_INERTIA;
833 dest->type = FF_FRICTION;
839 dest->replay.delay = CLAMP(
condition->delay);
842 dest->trigger.button = SDL_SYS_ToButton(
condition->button);
843 dest->trigger.interval = CLAMP(
condition->interval);
847 dest->u.condition[0].right_saturation =
condition->right_sat[0];
848 dest->u.condition[0].left_saturation =
condition->left_sat[0];
849 dest->u.condition[0].right_coeff =
condition->right_coeff[0];
850 dest->u.condition[0].left_coeff =
condition->left_coeff[0];
851 dest->u.condition[0].deadband =
condition->deadband[0];
852 dest->u.condition[0].center =
condition->center[0];
854 dest->u.condition[1].right_saturation =
condition->right_sat[1];
855 dest->u.condition[1].left_saturation =
condition->left_sat[1];
856 dest->u.condition[1].right_coeff =
condition->right_coeff[1];
857 dest->u.condition[1].left_coeff =
condition->left_coeff[1];
858 dest->u.condition[1].deadband =
condition->deadband[1];
859 dest->u.condition[1].center =
condition->center[1];
871 dest->
type = FF_RAMP;
872 if (SDL_SYS_ToDirection(&dest->direction, &ramp->
direction) == -1)
878 dest->replay.delay = CLAMP(ramp->
delay);
881 dest->trigger.button = SDL_SYS_ToButton(ramp->
button);
882 dest->trigger.interval = CLAMP(ramp->
interval);
885 dest->u.ramp.start_level = ramp->
start;
886 dest->u.ramp.end_level = ramp->
end;
889 dest->u.ramp.envelope.attack_length = CLAMP(ramp->
attack_length);
890 dest->u.ramp.envelope.attack_level = CLAMP(ramp->
attack_level);
891 dest->u.ramp.envelope.fade_length = CLAMP(ramp->
fade_length);
892 dest->u.ramp.envelope.fade_level = CLAMP(ramp->
fade_level);
897 leftright = &
src->leftright;
900 dest->
type = FF_RUMBLE;
905 0 : CLAMP(leftright->
length);
908 dest->trigger.button = 0;
909 dest->trigger.interval = 0;
912 dest->u.rumble.strong_magnitude = CLAMP(leftright->
large_magnitude) * 2;
933 struct ff_effect *linux_effect;
943 linux_effect = &effect->
hweffect->effect;
944 if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
947 linux_effect->id = -1;
950 if (ioctl(
haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
951 SDL_SetError(
"Haptic: Error uploading effect to the device: %s",
976 struct ff_effect linux_effect;
979 if (SDL_SYS_ToFFEffect(&linux_effect,
data) != 0) {
982 linux_effect.id = effect->
hweffect->effect.id;
985 if (ioctl(
haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
986 return SDL_SetError(
"Haptic: Error updating the effect: %s",
992 sizeof(
struct ff_effect));
1005 struct input_event run;
1009 run.code = effect->
hweffect->effect.id;
1013 if (write(
haptic->hwdata->fd, (
const void *) &run,
sizeof(run)) < 0) {
1014 return SDL_SetError(
"Haptic: Unable to run the effect: %s", strerror(errno));
1027 struct input_event stop;
1030 stop.code = effect->
hweffect->effect.id;
1033 if (write(
haptic->hwdata->fd, (
const void *) &stop,
sizeof(stop)) < 0) {
1034 return SDL_SetError(
"Haptic: Unable to stop the effect: %s",
1048 if (ioctl(
haptic->hwdata->fd, EVIOCRMFF, effect->
hweffect->effect.id) < 0) {
1049 SDL_SetError(
"Haptic: Error removing the effect from the device: %s",
1065 struct input_event ie;
1068 ie.type = EV_FF_STATUS;
1069 ie.code = effect->
hweffect->effect.id;
1071 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1072 return SDL_SetError(
"Haptic: Error getting device status.");
1088 struct input_event ie;
1092 ie.value = (0xFFFFUL * gain) / 100;
1094 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1095 return SDL_SetError(
"Haptic: Error setting gain: %s", strerror(errno));
1108 struct input_event ie;
1111 ie.code = FF_AUTOCENTER;
1112 ie.value = (0xFFFFUL * autocenter) / 100;
1114 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1115 return SDL_SetError(
"Haptic: Error setting autocenter: %s", strerror(errno));
1151 for (
i = 0;
i <
haptic->neffects;
i++) {
1156 (
"Haptic: Error while trying to stop all playing effects.");