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)) {
518 return EV_IsHaptic(joystick->hwdata->fd);
546 int device_index = 0;
556 if (
SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
561 haptic->index = device_index;
563 if (device_index >= MAX_HAPTICS) {
564 return SDL_SetError(
"Haptic: Joystick doesn't have Haptic capabilities");
567 fd = open(joystick->hwdata->fname, O_RDWR, 0);
570 joystick->hwdata->fname, strerror(errno));
572 ret = SDL_SYS_HapticOpenFromFD(
haptic,
fd);
597 close(
haptic->hwdata->fd);
628 SDL_UDEV_DelCallback(haptic_udev_callback);
634 SDL_hapticlist_tail =
NULL;
653 ff_button = BTN_GAMEPAD +
button - 1;
681 tmp = ((
src->dir[0] % 36000) * 0x8000) / 18000;
694 tmp = ((
src->dir[0]) + 9000) % 36000;
695 tmp = (tmp * 0x8000) / 18000;
701 *dest = (
src->dir[0] >= 0 ? 0x4000 : 0xC000);
702 else if (!
src->dir[0])
703 *dest = (
src->dir[1] >= 0 ? 0x8000 : 0);
716 tmp = (((
Sint32) (
f * 18000. / M_PI)) + 45000) % 36000;
717 tmp = (tmp * 0x8000) / 18000;
723 return SDL_SetError(
"Haptic: Unsupported direction type.");
730 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
745 SDL_memset(dest, 0,
sizeof(
struct ff_effect));
749 constant = &
src->constant;
752 dest->
type = FF_CONSTANT;
753 if (SDL_SYS_ToDirection(&dest->direction, &constant->
direction) == -1)
758 0 : CLAMP(constant->
length);
759 dest->replay.delay = CLAMP(constant->
delay);
762 dest->trigger.button = SDL_SYS_ToButton(constant->
button);
763 dest->trigger.interval = CLAMP(constant->
interval);
766 dest->u.constant.level = constant->
level;
769 dest->u.constant.envelope.attack_length =
771 dest->u.constant.envelope.attack_level =
773 dest->u.constant.envelope.fade_length = CLAMP(constant->
fade_length);
774 dest->u.constant.envelope.fade_level = CLAMP(constant->
fade_level);
784 periodic = &
src->periodic;
787 dest->
type = FF_PERIODIC;
788 if (SDL_SYS_ToDirection(&dest->direction, &periodic->
direction) == -1)
793 0 : CLAMP(periodic->
length);
794 dest->replay.delay = CLAMP(periodic->
delay);
797 dest->trigger.button = SDL_SYS_ToButton(periodic->
button);
798 dest->trigger.interval = CLAMP(periodic->
interval);
802 dest->u.periodic.waveform = FF_SINE;
807 dest->u.periodic.waveform = FF_TRIANGLE;
809 dest->u.periodic.waveform = FF_SAW_UP;
811 dest->u.periodic.waveform = FF_SAW_DOWN;
812 dest->u.periodic.period = CLAMP(periodic->
period);
813 dest->u.periodic.magnitude = periodic->
magnitude;
814 dest->u.periodic.offset = periodic->
offset;
816 dest->u.periodic.phase = ((
Uint32)periodic->
phase * 0x10000U) / 36000;
819 dest->u.periodic.envelope.attack_length =
821 dest->u.periodic.envelope.attack_level =
823 dest->u.periodic.envelope.fade_length = CLAMP(periodic->
fade_length);
824 dest->u.periodic.envelope.fade_level = CLAMP(periodic->
fade_level);
836 dest->type = FF_SPRING;
838 dest->type = FF_DAMPER;
840 dest->type = FF_INERTIA;
842 dest->type = FF_FRICTION;
848 dest->replay.delay = CLAMP(
condition->delay);
851 dest->trigger.button = SDL_SYS_ToButton(
condition->button);
852 dest->trigger.interval = CLAMP(
condition->interval);
856 dest->u.condition[0].right_saturation =
condition->right_sat[0];
857 dest->u.condition[0].left_saturation =
condition->left_sat[0];
858 dest->u.condition[0].right_coeff =
condition->right_coeff[0];
859 dest->u.condition[0].left_coeff =
condition->left_coeff[0];
860 dest->u.condition[0].deadband =
condition->deadband[0];
861 dest->u.condition[0].center =
condition->center[0];
863 dest->u.condition[1].right_saturation =
condition->right_sat[1];
864 dest->u.condition[1].left_saturation =
condition->left_sat[1];
865 dest->u.condition[1].right_coeff =
condition->right_coeff[1];
866 dest->u.condition[1].left_coeff =
condition->left_coeff[1];
867 dest->u.condition[1].deadband =
condition->deadband[1];
868 dest->u.condition[1].center =
condition->center[1];
880 dest->
type = FF_RAMP;
881 if (SDL_SYS_ToDirection(&dest->direction, &ramp->
direction) == -1)
887 dest->replay.delay = CLAMP(ramp->
delay);
890 dest->trigger.button = SDL_SYS_ToButton(ramp->
button);
891 dest->trigger.interval = CLAMP(ramp->
interval);
894 dest->u.ramp.start_level = ramp->
start;
895 dest->u.ramp.end_level = ramp->
end;
898 dest->u.ramp.envelope.attack_length = CLAMP(ramp->
attack_length);
899 dest->u.ramp.envelope.attack_level = CLAMP(ramp->
attack_level);
900 dest->u.ramp.envelope.fade_length = CLAMP(ramp->
fade_length);
901 dest->u.ramp.envelope.fade_level = CLAMP(ramp->
fade_level);
906 leftright = &
src->leftright;
909 dest->
type = FF_RUMBLE;
914 0 : CLAMP(leftright->
length);
917 dest->trigger.button = 0;
918 dest->trigger.interval = 0;
921 dest->u.rumble.strong_magnitude = CLAMP(leftright->
large_magnitude) * 2;
942 struct ff_effect *linux_effect;
952 linux_effect = &effect->
hweffect->effect;
953 if (SDL_SYS_ToFFEffect(linux_effect,
base) != 0) {
956 linux_effect->id = -1;
959 if (ioctl(
haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
960 SDL_SetError(
"Haptic: Error uploading effect to the device: %s",
985 struct ff_effect linux_effect;
988 if (SDL_SYS_ToFFEffect(&linux_effect,
data) != 0) {
991 linux_effect.id = effect->
hweffect->effect.id;
994 if (ioctl(
haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
995 return SDL_SetError(
"Haptic: Error updating the effect: %s",
1001 sizeof(
struct ff_effect));
1003 return effect->
hweffect->effect.id;
1014 struct input_event run;
1018 run.code = effect->
hweffect->effect.id;
1022 if (write(
haptic->hwdata->fd, (
const void *) &run,
sizeof(run)) < 0) {
1023 return SDL_SetError(
"Haptic: Unable to run the effect: %s", strerror(errno));
1036 struct input_event stop;
1039 stop.code = effect->
hweffect->effect.id;
1042 if (write(
haptic->hwdata->fd, (
const void *) &stop,
sizeof(stop)) < 0) {
1043 return SDL_SetError(
"Haptic: Unable to stop the effect: %s",
1057 if (ioctl(
haptic->hwdata->fd, EVIOCRMFF, effect->
hweffect->effect.id) < 0) {
1058 SDL_SetError(
"Haptic: Error removing the effect from the device: %s",
1074 struct input_event ie;
1077 ie.type = EV_FF_STATUS;
1078 ie.code = effect->
hweffect->effect.id;
1080 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1081 return SDL_SetError(
"Haptic: Error getting device status.");
1097 struct input_event ie;
1101 ie.value = (0xFFFFUL * gain) / 100;
1103 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1104 return SDL_SetError(
"Haptic: Error setting gain: %s", strerror(errno));
1117 struct input_event ie;
1120 ie.code = FF_AUTOCENTER;
1121 ie.value = (0xFFFFUL * autocenter) / 100;
1123 if (write(
haptic->hwdata->fd, &ie,
sizeof(ie)) < 0) {
1124 return SDL_SetError(
"Haptic: Error setting autocenter: %s", strerror(errno));
1160 for (
i = 0;
i <
haptic->neffects;
i++) {
1165 (
"Haptic: Error while trying to stop all playing effects.");