zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_syshaptic.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 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_config.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 
31 #include <unistd.h> /* close */
32 #include <linux/input.h> /* Force feedback linux stuff. */
33 #include <fcntl.h> /* O_RDWR */
34 #include <limits.h> /* INT_MAX */
35 #include <errno.h> /* errno, strerror */
36 #include <math.h> /* atan2 */
37 #include <sys/stat.h> /* stat */
38 
39 /* Just in case. */
40 #ifndef M_PI
41 # define M_PI 3.14159265358979323846
42 #endif
43 
44 
45 #define MAX_HAPTICS 32 /* It's doubtful someone has more then 32 evdev */
46 
47 
48 /*
49  * List of available haptic devices.
50  */
51 static struct
52 {
53  char *fname; /* Dev path name (like /dev/input/event1) */
54  SDL_Haptic *haptic; /* Assosciated haptic. */
55 } SDL_hapticlist[MAX_HAPTICS];
56 
57 
58 /*
59  * Haptic system hardware data.
60  */
61 struct haptic_hwdata
62 {
63  int fd; /* File descriptor of the device. */
64  char *fname; /* Points to the name in SDL_hapticlist. */
65 };
66 
67 
68 /*
69  * Haptic system effect data.
70  */
71 struct haptic_hweffect
72 {
73  struct ff_effect effect; /* The linux kernel effect structure. */
74 };
75 
76 
77 
78 #define test_bit(nr, addr) \
79  (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
80 #define EV_TEST(ev,f) \
81  if (test_bit((ev), features)) ret |= (f);
82 /*
83  * Test whether a device has haptic properties.
84  * Returns available properties or 0 if there are none.
85  */
86 static int
87 EV_IsHaptic(int fd)
88 {
89  unsigned int ret;
90  unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
91 
92  /* Ask device for what it has. */
93  ret = 0;
94  if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
95  return SDL_SetError("Haptic: Unable to get device's features: %s",
96  strerror(errno));
97  }
98 
99  /* Convert supported features to SDL_HAPTIC platform-neutral features. */
100  EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
101  EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
102  /* !!! FIXME: put this back when we have more bits in 2.1 */
103  /* EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); */
104  EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
105  EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
106  EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
107  EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
108  EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
109  EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
110  EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
111  EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
112  EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
113  EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
114  EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
115  EV_TEST(FF_RUMBLE, SDL_HAPTIC_LEFTRIGHT);
116 
117  /* Return what it supports. */
118  return ret;
119 }
120 
121 
122 /*
123  * Tests whether a device is a mouse or not.
124  */
125 static int
126 EV_IsMouse(int fd)
127 {
128  unsigned long argp[40];
129 
130  /* Ask for supported features. */
131  if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
132  return -1;
133  }
134 
135  /* Currently we only test for BTN_MOUSE which can give fake positives. */
136  if (test_bit(BTN_MOUSE, argp) != 0) {
137  return 1;
138  }
139 
140  return 0;
141 }
142 
143 /*
144  * Initializes the haptic subsystem by finding available devices.
145  */
146 int
147 SDL_SYS_HapticInit(void)
148 {
149  const char joydev_pattern[] = "/dev/input/event%d";
150  dev_t dev_nums[MAX_HAPTICS];
151  char path[PATH_MAX];
152  struct stat sb;
153  int fd;
154  int i, j, k;
155  int duplicate;
156  int numhaptics;
157 
158  numhaptics = 0;
159 
160  /*
161  * Limit amount of checks to MAX_HAPTICS since we may or may not have
162  * permission to some or all devices.
163  */
164  i = 0;
165  for (j = 0; j < MAX_HAPTICS; ++j) {
166 
167  snprintf(path, PATH_MAX, joydev_pattern, i++);
168 
169  /* check to see if file exists */
170  if (stat(path, &sb) != 0)
171  break;
172 
173  /* check for duplicates */
174  duplicate = 0;
175  for (k = 0; (k < numhaptics) && !duplicate; ++k) {
176  if (sb.st_rdev == dev_nums[k]) {
177  duplicate = 1;
178  }
179  }
180  if (duplicate) {
181  continue;
182  }
183 
184  /* try to open */
185  fd = open(path, O_RDWR, 0);
186  if (fd < 0)
187  continue;
188 
189 #ifdef DEBUG_INPUT_EVENTS
190  printf("Checking %s\n", path);
191 #endif
192 
193  /* see if it works */
194  if (EV_IsHaptic(fd) > 0) {
195  SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
196  SDL_hapticlist[numhaptics].haptic = NULL;
197  dev_nums[numhaptics] = sb.st_rdev;
198  ++numhaptics;
199  }
200  close(fd);
201  }
202 
203  return numhaptics;
204 }
205 
206 
207 /*
208  * Gets the name from a file descriptor.
209  */
210 static const char *
211 SDL_SYS_HapticNameFromFD(int fd)
212 {
213  static char namebuf[128];
214 
215  /* We use the evdev name ioctl. */
216  if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
217  return NULL;
218  }
219 
220  return namebuf;
221 }
222 
223 
224 /*
225  * Return the name of a haptic device, does not need to be opened.
226  */
227 const char *
229 {
230  int fd;
231  const char *name;
232 
233  /* Open the haptic device. */
234  name = NULL;
235  fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
236 
237  if (fd >= 0) {
238 
239  name = SDL_SYS_HapticNameFromFD(fd);
240  if (name == NULL) {
241  /* No name found, return device character device */
242  name = SDL_hapticlist[index].fname;
243  }
244  }
245  close(fd);
246 
247  return name;
248 }
249 
250 
251 /*
252  * Opens the haptic device from the file descriptor.
253  */
254 static int
255 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
256 {
257  /* Allocate the hwdata */
258  haptic->hwdata = (struct haptic_hwdata *)
259  SDL_malloc(sizeof(*haptic->hwdata));
260  if (haptic->hwdata == NULL) {
261  SDL_OutOfMemory();
262  goto open_err;
263  }
264  SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
265 
266  /* Set the data. */
267  haptic->hwdata->fd = fd;
268  haptic->supported = EV_IsHaptic(fd);
269  haptic->naxes = 2; /* Hardcoded for now, not sure if it's possible to find out. */
270 
271  /* Set the effects */
272  if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
273  SDL_SetError("Haptic: Unable to query device memory: %s",
274  strerror(errno));
275  goto open_err;
276  }
277  haptic->nplaying = haptic->neffects; /* Linux makes no distinction. */
278  haptic->effects = (struct haptic_effect *)
279  SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
280  if (haptic->effects == NULL) {
281  SDL_OutOfMemory();
282  goto open_err;
283  }
284  /* Clear the memory */
285  SDL_memset(haptic->effects, 0,
286  sizeof(struct haptic_effect) * haptic->neffects);
287 
288  return 0;
289 
290  /* Error handling */
291  open_err:
292  close(fd);
293  if (haptic->hwdata != NULL) {
294  free(haptic->hwdata);
295  haptic->hwdata = NULL;
296  }
297  return -1;
298 }
299 
300 
301 /*
302  * Opens a haptic device for usage.
303  */
304 int
306 {
307  int fd;
308  int ret;
309 
310  /* Open the character device */
311  fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
312  if (fd < 0) {
313  return SDL_SetError("Haptic: Unable to open %s: %s",
314  SDL_hapticlist[haptic->index], strerror(errno));
315  }
316 
317  /* Try to create the haptic. */
318  ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
319  if (ret < 0) {
320  return -1;
321  }
322 
323  /* Set the fname. */
324  haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
325  return 0;
326 }
327 
328 
329 /*
330  * Opens a haptic device from first mouse it finds for usage.
331  */
332 int
334 {
335  int fd;
336  int i;
337 
338  for (i = 0; i < SDL_numhaptics; i++) {
339 
340  /* Open the device. */
341  fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
342  if (fd < 0) {
343  return SDL_SetError("Haptic: Unable to open %s: %s",
344  SDL_hapticlist[i], strerror(errno));
345  }
346 
347  /* Is it a mouse? */
348  if (EV_IsMouse(fd)) {
349  close(fd);
350  return i;
351  }
352 
353  close(fd);
354  }
355 
356  return -1;
357 }
358 
359 
360 /*
361  * Checks to see if a joystick has haptic features.
362  */
363 int
365 {
366  return EV_IsHaptic(joystick->hwdata->fd);
367 }
368 
369 
370 /*
371  * Checks to see if the haptic device and joystick are in reality the same.
372  */
373 int
375 {
376  /* We are assuming Linux is using evdev which should trump the old
377  * joystick methods. */
378  if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
379  return 1;
380  }
381  return 0;
382 }
383 
384 
385 /*
386  * Opens a SDL_Haptic from a SDL_Joystick.
387  */
388 int
390 {
391  int i;
392  int fd;
393  int ret;
394 
395 
396  /* Find the joystick in the haptic list. */
397  for (i = 0; i < MAX_HAPTICS; i++) {
398  if (SDL_hapticlist[i].fname != NULL) {
399  if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
400  == 0) {
401  haptic->index = i;
402  break;
403  }
404  }
405  }
406  if (i >= MAX_HAPTICS) {
407  return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
408  }
409 
410  fd = open(joystick->hwdata->fname, O_RDWR, 0);
411  if (fd < 0) {
412  return SDL_SetError("Haptic: Unable to open %s: %s",
413  joystick->hwdata->fname, strerror(errno));
414  }
415  ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
416  if (ret < 0) {
417  return -1;
418  }
419 
420  haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
421  return 0;
422 }
423 
424 
425 /*
426  * Closes the haptic device.
427  */
428 void
430 {
431  if (haptic->hwdata) {
432 
433  /* Free effects. */
434  SDL_free(haptic->effects);
435  haptic->effects = NULL;
436  haptic->neffects = 0;
437 
438  /* Clean up */
439  close(haptic->hwdata->fd);
440 
441  /* Free */
442  SDL_free(haptic->hwdata);
443  haptic->hwdata = NULL;
444  }
445 
446  /* Clear the rest. */
447  SDL_memset(haptic, 0, sizeof(SDL_Haptic));
448 }
449 
450 
451 /*
452  * Clean up after system specific haptic stuff
453  */
454 void
455 SDL_SYS_HapticQuit(void)
456 {
457  int i;
458 
459  for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
460  /* Opened and not closed haptics are leaked, this is on purpose.
461  * Close your haptic devices after usage. */
462 
463  SDL_free(SDL_hapticlist[i].fname);
464  }
465  SDL_hapticlist[0].fname = NULL;
466 }
467 
468 
469 /*
470  * Converts an SDL button to a ff_trigger button.
471  */
472 static Uint16
473 SDL_SYS_ToButton(Uint16 button)
474 {
475  Uint16 ff_button;
476 
477  ff_button = 0;
478 
479  /*
480  * Not sure what the proper syntax is because this actually isn't implemented
481  * in the current kernel from what I've seen (2.6.26).
482  */
483  if (button != 0) {
484  ff_button = BTN_GAMEPAD + button - 1;
485  }
486 
487  return ff_button;
488 }
489 
490 
491 /*
492  * Returns the ff_effect usable direction from a SDL_HapticDirection.
493  */
494 static Uint16
495 SDL_SYS_ToDirection(SDL_HapticDirection * dir)
496 {
497  Uint32 tmp;
498  float f; /* Ideally we'd use fixed point math instead of floats... */
499 
500  switch (dir->type) {
501  case SDL_HAPTIC_POLAR:
502  /* Linux directions start from south.
503  (and range from 0 to 0xFFFF)
504  Quoting include/linux/input.h, line 926:
505  Direction of the effect is encoded as follows:
506  0 deg -> 0x0000 (down)
507  90 deg -> 0x4000 (left)
508  180 deg -> 0x8000 (up)
509  270 deg -> 0xC000 (right)
510  */
511  tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
512  return (Uint16) tmp;
513 
515  /*
516  We convert to polar, because that's the only supported direction on Linux.
517  The first value of a spherical direction is practically the same as a
518  Polar direction, except that we have to add 90 degrees. It is the angle
519  from EAST {1,0} towards SOUTH {0,1}.
520  --> add 9000
521  --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
522  */
523  tmp = ((dir->dir[0]) + 9000) % 36000; /* Convert to polars */
524  tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
525  return (Uint16) tmp;
526 
528  f = atan2(dir->dir[1], dir->dir[0]);
529  /*
530  atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
531  - Y-axis-value is the second coordinate (from center to SOUTH)
532  - X-axis-value is the first coordinate (from center to EAST)
533  We add 36000, because atan2 also returns negative values. Then we practically
534  have the first spherical value. Therefore we proceed as in case
535  SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
536  --> add 45000 in total
537  --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
538  */
539  tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
540  tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
541  return (Uint16) tmp;
542 
543  default:
544  return (Uint16) SDL_SetError("Haptic: Unsupported direction type.");
545  }
546 
547  return 0;
548 }
549 
550 
551 #define CLAMP(x) (((x) > 32767) ? 32767 : x)
552 /*
553  * Initializes the Linux effect struct from a haptic_effect.
554  * Values above 32767 (for unsigned) are unspecified so we must clamp.
555  */
556 static int
557 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
558 {
559  Uint32 tmp;
560  SDL_HapticConstant *constant;
561  SDL_HapticPeriodic *periodic;
563  SDL_HapticRamp *ramp;
564  SDL_HapticLeftRight *leftright;
565 
566  /* Clear up */
567  SDL_memset(dest, 0, sizeof(struct ff_effect));
568 
569  switch (src->type) {
570  case SDL_HAPTIC_CONSTANT:
571  constant = &src->constant;
572 
573  /* Header */
574  dest->type = FF_CONSTANT;
575  dest->direction = SDL_SYS_ToDirection(&constant->direction);
576  if (dest->direction == (Uint16) - 1)
577  return -1;
578 
579  /* Replay */
580  dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
581  0 : CLAMP(constant->length);
582  dest->replay.delay = CLAMP(constant->delay);
583 
584  /* Trigger */
585  dest->trigger.button = SDL_SYS_ToButton(constant->button);
586  dest->trigger.interval = CLAMP(constant->interval);
587 
588  /* Constant */
589  dest->u.constant.level = constant->level;
590 
591  /* Envelope */
592  dest->u.constant.envelope.attack_length =
593  CLAMP(constant->attack_length);
594  dest->u.constant.envelope.attack_level =
595  CLAMP(constant->attack_level);
596  dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
597  dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
598 
599  break;
600 
601  case SDL_HAPTIC_SINE:
602  /* !!! FIXME: put this back when we have more bits in 2.1 */
603  /* case SDL_HAPTIC_SQUARE: */
604  case SDL_HAPTIC_TRIANGLE:
607  periodic = &src->periodic;
608 
609  /* Header */
610  dest->type = FF_PERIODIC;
611  dest->direction = SDL_SYS_ToDirection(&periodic->direction);
612  if (dest->direction == (Uint16) - 1)
613  return -1;
614 
615  /* Replay */
616  dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
617  0 : CLAMP(periodic->length);
618  dest->replay.delay = CLAMP(periodic->delay);
619 
620  /* Trigger */
621  dest->trigger.button = SDL_SYS_ToButton(periodic->button);
622  dest->trigger.interval = CLAMP(periodic->interval);
623 
624  /* Periodic */
625  if (periodic->type == SDL_HAPTIC_SINE)
626  dest->u.periodic.waveform = FF_SINE;
627  /* !!! FIXME: put this back when we have more bits in 2.1 */
628  /* else if (periodic->type == SDL_HAPTIC_SQUARE)
629  dest->u.periodic.waveform = FF_SQUARE; */
630  else if (periodic->type == SDL_HAPTIC_TRIANGLE)
631  dest->u.periodic.waveform = FF_TRIANGLE;
632  else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
633  dest->u.periodic.waveform = FF_SAW_UP;
634  else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
635  dest->u.periodic.waveform = FF_SAW_DOWN;
636  dest->u.periodic.period = CLAMP(periodic->period);
637  dest->u.periodic.magnitude = periodic->magnitude;
638  dest->u.periodic.offset = periodic->offset;
639  /* Phase is calculated based of offset from period and then clamped. */
640  tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000;
641  dest->u.periodic.phase = CLAMP(tmp);
642 
643  /* Envelope */
644  dest->u.periodic.envelope.attack_length =
645  CLAMP(periodic->attack_length);
646  dest->u.periodic.envelope.attack_level =
647  CLAMP(periodic->attack_level);
648  dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
649  dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
650 
651  break;
652 
653  case SDL_HAPTIC_SPRING:
654  case SDL_HAPTIC_DAMPER:
655  case SDL_HAPTIC_INERTIA:
656  case SDL_HAPTIC_FRICTION:
657  condition = &src->condition;
658 
659  /* Header */
660  if (condition->type == SDL_HAPTIC_SPRING)
661  dest->type = FF_SPRING;
662  else if (condition->type == SDL_HAPTIC_DAMPER)
663  dest->type = FF_DAMPER;
664  else if (condition->type == SDL_HAPTIC_INERTIA)
665  dest->type = FF_INERTIA;
666  else if (condition->type == SDL_HAPTIC_FRICTION)
667  dest->type = FF_FRICTION;
668  dest->direction = 0; /* Handled by the condition-specifics. */
669 
670  /* Replay */
671  dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
672  0 : CLAMP(condition->length);
673  dest->replay.delay = CLAMP(condition->delay);
674 
675  /* Trigger */
676  dest->trigger.button = SDL_SYS_ToButton(condition->button);
677  dest->trigger.interval = CLAMP(condition->interval);
678 
679  /* Condition */
680  /* X axis */
681  dest->u.condition[0].right_saturation =
682  CLAMP(condition->right_sat[0]);
683  dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
684  dest->u.condition[0].right_coeff = condition->right_coeff[0];
685  dest->u.condition[0].left_coeff = condition->left_coeff[0];
686  dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
687  dest->u.condition[0].center = condition->center[0];
688  /* Y axis */
689  dest->u.condition[1].right_saturation =
690  CLAMP(condition->right_sat[1]);
691  dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
692  dest->u.condition[1].right_coeff = condition->right_coeff[1];
693  dest->u.condition[1].left_coeff = condition->left_coeff[1];
694  dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
695  dest->u.condition[1].center = condition->center[1];
696 
697  /*
698  * There is no envelope in the linux force feedback api for conditions.
699  */
700 
701  break;
702 
703  case SDL_HAPTIC_RAMP:
704  ramp = &src->ramp;
705 
706  /* Header */
707  dest->type = FF_RAMP;
708  dest->direction = SDL_SYS_ToDirection(&ramp->direction);
709  if (dest->direction == (Uint16) - 1)
710  return -1;
711 
712  /* Replay */
713  dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
714  0 : CLAMP(ramp->length);
715  dest->replay.delay = CLAMP(ramp->delay);
716 
717  /* Trigger */
718  dest->trigger.button = SDL_SYS_ToButton(ramp->button);
719  dest->trigger.interval = CLAMP(ramp->interval);
720 
721  /* Ramp */
722  dest->u.ramp.start_level = ramp->start;
723  dest->u.ramp.end_level = ramp->end;
724 
725  /* Envelope */
726  dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
727  dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
728  dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
729  dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
730 
731  break;
732 
734  leftright = &src->leftright;
735 
736  /* Header */
737  dest->type = FF_RUMBLE;
738  dest->direction = 0;
739 
740  /* Replay */
741  dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
742  0 : CLAMP(leftright->length);
743 
744  /* Trigger */
745  dest->trigger.button = 0;
746  dest->trigger.interval = 0;
747 
748  /* Rumble */
749  dest->u.rumble.strong_magnitude = leftright->large_magnitude;
750  dest->u.rumble.weak_magnitude = leftright->small_magnitude;
751 
752  break;
753 
754 
755  default:
756  return SDL_SetError("Haptic: Unknown effect type.");
757  }
758 
759  return 0;
760 }
761 
762 
763 /*
764  * Creates a new haptic effect.
765  */
766 int
768  SDL_HapticEffect * base)
769 {
770  struct ff_effect *linux_effect;
771 
772  /* Allocate the hardware effect */
773  effect->hweffect = (struct haptic_hweffect *)
774  SDL_malloc(sizeof(struct haptic_hweffect));
775  if (effect->hweffect == NULL) {
776  return SDL_OutOfMemory();
777  }
778 
779  /* Prepare the ff_effect */
780  linux_effect = &effect->hweffect->effect;
781  if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
782  goto new_effect_err;
783  }
784  linux_effect->id = -1; /* Have the kernel give it an id */
785 
786  /* Upload the effect */
787  if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
788  SDL_SetError("Haptic: Error uploading effect to the device: %s",
789  strerror(errno));
790  goto new_effect_err;
791  }
792 
793  return 0;
794 
795  new_effect_err:
796  free(effect->hweffect);
797  effect->hweffect = NULL;
798  return -1;
799 }
800 
801 
802 /*
803  * Updates an effect.
804  *
805  * Note: Dynamically updating the direction can in some cases force
806  * the effect to restart and run once.
807  */
808 int
810  struct haptic_effect *effect,
812 {
813  struct ff_effect linux_effect;
814 
815  /* Create the new effect */
816  if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
817  return -1;
818  }
819  linux_effect.id = effect->hweffect->effect.id;
820 
821  /* See if it can be uploaded. */
822  if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
823  return SDL_SetError("Haptic: Error updating the effect: %s",
824  strerror(errno));
825  }
826 
827  /* Copy the new effect into memory. */
828  SDL_memcpy(&effect->hweffect->effect, &linux_effect,
829  sizeof(struct ff_effect));
830 
831  return effect->hweffect->effect.id;
832 }
833 
834 
835 /*
836  * Runs an effect.
837  */
838 int
839 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
840  Uint32 iterations)
841 {
842  struct input_event run;
843 
844  /* Prepare to run the effect */
845  run.type = EV_FF;
846  run.code = effect->hweffect->effect.id;
847  /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
848  run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
849 
850  if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
851  return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
852  }
853 
854  return 0;
855 }
856 
857 
858 /*
859  * Stops an effect.
860  */
861 int
862 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
863 {
864  struct input_event stop;
865 
866  stop.type = EV_FF;
867  stop.code = effect->hweffect->effect.id;
868  stop.value = 0;
869 
870  if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
871  return SDL_SetError("Haptic: Unable to stop the effect: %s",
872  strerror(errno));
873  }
874 
875  return 0;
876 }
877 
878 
879 /*
880  * Frees the effect.
881  */
882 void
883 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
884 {
885  if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
886  SDL_SetError("Haptic: Error removing the effect from the device: %s",
887  strerror(errno));
888  }
889  SDL_free(effect->hweffect);
890  effect->hweffect = NULL;
891 }
892 
893 
894 /*
895  * Gets the status of a haptic effect.
896  */
897 int
899  struct haptic_effect *effect)
900 {
901 #if 0 /* Not supported atm. */
902  struct input_event ie;
903 
904  ie.type = EV_FF;
905  ie.type = EV_FF_STATUS;
906  ie.code = effect->hweffect->effect.id;
907 
908  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
909  return SDL_SetError("Haptic: Error getting device status.");
910  }
911 
912  return 0;
913 #endif
914 
915  return -1;
916 }
917 
918 
919 /*
920  * Sets the gain.
921  */
922 int
923 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
924 {
925  struct input_event ie;
926 
927  ie.type = EV_FF;
928  ie.code = FF_GAIN;
929  ie.value = (0xFFFFUL * gain) / 100;
930 
931  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
932  return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
933  }
934 
935  return 0;
936 }
937 
938 
939 /*
940  * Sets the autocentering.
941  */
942 int
943 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
944 {
945  struct input_event ie;
946 
947  ie.type = EV_FF;
948  ie.code = FF_AUTOCENTER;
949  ie.value = (0xFFFFUL * autocenter) / 100;
950 
951  if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
952  return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
953  }
954 
955  return 0;
956 }
957 
958 
959 /*
960  * Pausing is not supported atm by linux.
961  */
962 int
964 {
965  return -1;
966 }
967 
968 
969 /*
970  * Unpausing is not supported atm by linux.
971  */
972 int
974 {
975  return -1;
976 }
977 
978 
979 /*
980  * Stops all the currently playing effects.
981  */
982 int
984 {
985  int i, ret;
986 
987  /* Linux does not support this natively so we have to loop. */
988  for (i = 0; i < haptic->neffects; i++) {
989  if (haptic->effects[i].hweffect != NULL) {
990  ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
991  if (ret < 0) {
992  return SDL_SetError
993  ("Haptic: Error while trying to stop all playing effects.");
994  }
995  }
996  }
997  return 0;
998 }
999 
1000 
1001 #endif /* SDL_HAPTIC_LINUX */
int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
struct haptic_hwdata * hwdata
Definition: SDL_syshaptic.h:52
Uint16 deadband[3]
Definition: SDL_haptic.h:611
Structure that represents a haptic direction.
Definition: SDL_haptic.h:439
GLenum condition
Definition: gl2ext.h:1403
struct haptic_effect * effects
Definition: SDL_syshaptic.h:46
#define SDL_HAPTIC_SPHERICAL
Uses spherical coordinates for the direction.
Definition: SDL_haptic.h:329
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:285
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:538
#define NULL
Definition: ftobjs.h:61
GLclampf f
Definition: glew.h:3390
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:276
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:263
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:189
int32_t k
Definition: e_log.c:102
int SDL_SYS_HapticOpen(SDL_Haptic *haptic)
int SDL_SYS_HapticMouse(void)
int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:246
SDL_EventEntry * free
Definition: SDL_events.c:80
DECLSPEC void SDLCALL SDL_free(void *mem)
Uint16 fade_level
Definition: SDL_haptic.h:650
int32_t j
Definition: e_log.c:102
SDL_HapticRamp ramp
Definition: SDL_haptic.h:794
int SDL_SYS_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
const char * SDL_SYS_HapticName(int index)
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:591
EGLImageKHR EGLint * name
Definition: eglext.h:284
The SDL Haptic subsystem allows you to control haptic (force feedback) devices.
int SDL_SYS_HapticUnpause(SDL_Haptic *haptic)
Sint16 left_coeff[3]
Definition: SDL_haptic.h:610
Uint16 right_sat[3]
Definition: SDL_haptic.h:607
Sint16 right_coeff[3]
Definition: SDL_haptic.h:609
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:166
GLsizei const GLchar *const * path
Definition: glew.h:5828
int SDL_SYS_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
struct joystick_hwdata * hwdata
ret
Definition: glew_str_glx.c:2
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:457
Uint8 SDL_numhaptics
Definition: SDL_haptic.c:28
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:344
Uint16 interval
Definition: SDL_haptic.h:640
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:322
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
unsigned int supported
Definition: SDL_syshaptic.h:49
SDL_HapticCondition condition
Definition: SDL_haptic.h:793
A structure containing a template for a Left/Right effect.
Definition: SDL_haptic.h:665
The generic template for any haptic effect.
Definition: SDL_haptic.h:787
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:157
int SDL_SYS_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
int
Definition: SDL_systhread.c:37
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
DECLSPEC char *SDLCALL SDL_strdup(const char *str)
Definition: SDL_string.c:511
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:315
DECLSPEC void *SDLCALL SDL_memset(void *dst, int c, size_t len)
Definition: SDL_string.c:261
SDL_HapticConstant constant
Definition: SDL_haptic.h:791
DECLSPEC int SDLCALL SDL_SetError(const char *fmt,...)
Definition: SDL_error.c:53
DECLSPEC void *SDLCALL SDL_malloc(size_t size)
GLuint index
Definition: glew.h:1800
int SDL_SYS_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
DECLSPEC int SDLCALL SDL_strcmp(const char *str1, const char *str2)
Definition: SDL_string.c:910
int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
SDL_HapticDirection direction
Definition: SDL_haptic.h:632
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:628
#define M_PI
Definition: os.h:45
void SDL_SYS_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
Uint16 attack_length
Definition: SDL_haptic.h:647
#define EVIOCRMFF
#define PATH_MAX
Definition: hrtf.c:34
Uint16 fade_length
Definition: SDL_haptic.h:649
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_HapticEffect effect
Definition: SDL_syshaptic.h:35
int SDL_SYS_HapticInit(void)
void SDL_SYS_HapticQuit(void)
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:36
void SDL_SYS_HapticClose(SDL_Haptic *haptic)
int SDL_SYS_HapticPause(SDL_Haptic *haptic)
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
Definition: SDL_string.c:293
SDL_HapticDirection direction
Definition: SDL_haptic.h:544
SDL_HapticLeftRight leftright
Definition: SDL_haptic.h:795
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:216
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:226
int SDL_SYS_HapticStopAll(SDL_Haptic *haptic)
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:198
int SDL_SYS_HapticSetGain(SDL_Haptic *haptic, int gain)
GLenum src
Definition: glew.h:2396
int i
Definition: pngrutil.c:1377
#define SDL_HAPTIC_LEFTRIGHT
Left/Right effect supported.
Definition: SDL_haptic.h:177
int SDL_SYS_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
SDL_HapticPeriodic periodic
Definition: SDL_haptic.h:792
Uint16 attack_level
Definition: SDL_haptic.h:648
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:256
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:207
SDL_HapticDirection direction
Definition: SDL_haptic.h:461
int SDL_SYS_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:236
Uint16 left_sat[3]
Definition: SDL_haptic.h:608