src/haptic/linux/SDL_syshaptic.c
author Sam Lantinga
Mon, 18 Jan 2010 14:57:41 +0000
changeset 3680 7c18b38f0f9a
parent 3218 81773a1eac83
child 4514 0c71708adbcb
permissions -rw-r--r--
Fixed bug #920

From Martin:

Alright... I corrected SDL_SYS_ToDirection in SDL_syshaptic.c in the linux
directory of haptic. Now in all 3 cases the same value is returned, at least.
Therefore now it should behave the same way as on Windows.

I added some comments and corrected the cases SDL_HAPTIC_CARTESIAN and
SDL_HAPTIC_SPHERICAL.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 2008 Edgar Simo
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #ifdef SDL_HAPTIC_LINUX
    25 
    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 
    32 #include <unistd.h>             /* close */
    33 #include <linux/input.h>        /* Force feedback linux stuff. */
    34 #include <fcntl.h>              /* O_RDWR */
    35 #include <limits.h>             /* INT_MAX */
    36 #include <errno.h>              /* errno, strerror */
    37 #include <math.h>               /* atan2 */
    38 #include <sys/stat.h>           /* stat */
    39 
    40 /* Just in case. */
    41 #ifndef M_PI
    42 #  define M_PI     3.14159265358979323846
    43 #endif
    44 
    45 
    46 #define MAX_HAPTICS  32         /* It's doubtful someone has more then 32 evdev */
    47 
    48 
    49 /*
    50  * List of available haptic devices.
    51  */
    52 static struct
    53 {
    54     char *fname;                /* Dev path name (like /dev/input/event1) */
    55     SDL_Haptic *haptic;         /* Assosciated haptic. */
    56 } SDL_hapticlist[MAX_HAPTICS];
    57 
    58 
    59 /*
    60  * Haptic system hardware data.
    61  */
    62 struct haptic_hwdata
    63 {
    64     int fd;                     /* File descriptor of the device. */
    65     char *fname;                /* Points to the name in SDL_hapticlist. */
    66 };
    67 
    68 
    69 /*
    70  * Haptic system effect data.
    71  */
    72 struct haptic_hweffect
    73 {
    74     struct ff_effect effect;    /* The linux kernel effect structure. */
    75 };
    76 
    77 
    78 
    79 #define test_bit(nr, addr) \
    80    (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
    81 #define EV_TEST(ev,f) \
    82    if (test_bit((ev), features)) ret |= (f);
    83 /*
    84  * Test whether a device has haptic properties.
    85  * Returns available properties or 0 if there are none.
    86  */
    87 static int
    88 EV_IsHaptic(int fd)
    89 {
    90     unsigned int ret;
    91     unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
    92 
    93     /* Ask device for what it has. */
    94     ret = 0;
    95     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
    96         SDL_SetError("Haptic: Unable to get device's features: %s",
    97                      strerror(errno));
    98         return -1;
    99     }
   100 
   101     /* Convert supported features to SDL_HAPTIC platform-neutral features. */
   102     EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
   103     EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
   104     EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE);
   105     EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
   106     EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
   107     EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
   108     EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
   109     EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
   110     EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
   111     EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
   112     EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
   113     EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
   114     EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
   115     EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
   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 *
   228 SDL_SYS_HapticName(int index)
   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     const char *name;
   258 
   259     /* Allocate the hwdata */
   260     haptic->hwdata = (struct haptic_hwdata *)
   261         SDL_malloc(sizeof(*haptic->hwdata));
   262     if (haptic->hwdata == NULL) {
   263         SDL_OutOfMemory();
   264         goto open_err;
   265     }
   266     SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   267 
   268     /* Set the data. */
   269     haptic->hwdata->fd = fd;
   270     haptic->supported = EV_IsHaptic(fd);
   271     haptic->naxes = 2;          /* Hardcoded for now, not sure if it's possible to find out. */
   272 
   273     /* Set the effects */
   274     if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
   275         SDL_SetError("Haptic: Unable to query device memory: %s",
   276                      strerror(errno));
   277         goto open_err;
   278     }
   279     haptic->nplaying = haptic->neffects;        /* Linux makes no distinction. */
   280     haptic->effects = (struct haptic_effect *)
   281         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   282     if (haptic->effects == NULL) {
   283         SDL_OutOfMemory();
   284         goto open_err;
   285     }
   286     /* Clear the memory */
   287     SDL_memset(haptic->effects, 0,
   288                sizeof(struct haptic_effect) * haptic->neffects);
   289 
   290     return 0;
   291 
   292     /* Error handling */
   293   open_err:
   294     close(fd);
   295     if (haptic->hwdata != NULL) {
   296         free(haptic->hwdata);
   297         haptic->hwdata = NULL;
   298     }
   299     return -1;
   300 }
   301 
   302 
   303 /*
   304  * Opens a haptic device for usage.
   305  */
   306 int
   307 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   308 {
   309     int fd;
   310     int ret;
   311 
   312     /* Open the character device */
   313     fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
   314     if (fd < 0) {
   315         SDL_SetError("Haptic: Unable to open %s: %s",
   316                      SDL_hapticlist[haptic->index], strerror(errno));
   317         return -1;
   318     }
   319 
   320     /* Try to create the haptic. */
   321     ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
   322     if (ret < 0) {
   323         return -1;
   324     }
   325 
   326     /* Set the fname. */
   327     haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
   328     return 0;
   329 }
   330 
   331 
   332 /*
   333  * Opens a haptic device from first mouse it finds for usage.
   334  */
   335 int
   336 SDL_SYS_HapticMouse(void)
   337 {
   338     int fd;
   339     int i;
   340 
   341     for (i = 0; i < SDL_numhaptics; i++) {
   342 
   343         /* Open the device. */
   344         fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
   345         if (fd < 0) {
   346             SDL_SetError("Haptic: Unable to open %s: %s",
   347                          SDL_hapticlist[i], strerror(errno));
   348             return -1;
   349         }
   350 
   351         /* Is it a mouse? */
   352         if (EV_IsMouse(fd)) {
   353             close(fd);
   354             return i;
   355         }
   356 
   357         close(fd);
   358     }
   359 
   360     return -1;
   361 }
   362 
   363 
   364 /*
   365  * Checks to see if a joystick has haptic features.
   366  */
   367 int
   368 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   369 {
   370     return EV_IsHaptic(joystick->hwdata->fd);
   371 }
   372 
   373 
   374 /*
   375  * Checks to see if the haptic device and joystick and in reality the same.
   376  */
   377 int
   378 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   379 {
   380     /* We are assuming linux is using evdev which should trump the old
   381      * joystick methods. */
   382     if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
   383         return 1;
   384     }
   385     return 0;
   386 }
   387 
   388 
   389 /*
   390  * Opens a SDL_Haptic from a SDL_Joystick.
   391  */
   392 int
   393 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   394 {
   395     int i;
   396     int fd;
   397     int ret;
   398 
   399 
   400     /* Find the joystick in the haptic list. */
   401     for (i = 0; i < MAX_HAPTICS; i++) {
   402         if (SDL_hapticlist[i].fname != NULL) {
   403             if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
   404                 == 0) {
   405                 haptic->index = i;
   406                 break;
   407             }
   408         }
   409     }
   410     if (i >= MAX_HAPTICS) {
   411         SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
   412         return -1;
   413     }
   414 
   415     fd = open(joystick->hwdata->fname, O_RDWR, 0);
   416     if (fd < 0) {
   417         SDL_SetError("Haptic: Unable to open %s: %s",
   418                      joystick->hwdata->fname, strerror(errno));
   419         return -1;
   420     }
   421     ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
   422     if (ret < 0) {
   423         return -1;
   424     }
   425 
   426     haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
   427     return 0;
   428 }
   429 
   430 
   431 /*
   432  * Closes the haptic device.
   433  */
   434 void
   435 SDL_SYS_HapticClose(SDL_Haptic * haptic)
   436 {
   437     if (haptic->hwdata) {
   438 
   439         /* Free effects. */
   440         SDL_free(haptic->effects);
   441         haptic->effects = NULL;
   442         haptic->neffects = 0;
   443 
   444         /* Clean up */
   445         close(haptic->hwdata->fd);
   446 
   447         /* Free */
   448         SDL_free(haptic->hwdata);
   449         haptic->hwdata = NULL;
   450     }
   451 
   452     /* Clear the rest. */
   453     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   454 }
   455 
   456 
   457 /* 
   458  * Clean up after system specific haptic stuff
   459  */
   460 void
   461 SDL_SYS_HapticQuit(void)
   462 {
   463     int i;
   464 
   465     for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
   466         /* Opened and not closed haptics are leaked, this is on purpose.
   467          * Close your haptic devices after usage. */
   468 
   469         SDL_free(SDL_hapticlist[i].fname);
   470     }
   471     SDL_hapticlist[0].fname = NULL;
   472 }
   473 
   474 
   475 /*
   476  * Converts an SDL button to a ff_trigger button.
   477  */
   478 static Uint16
   479 SDL_SYS_ToButton(Uint16 button)
   480 {
   481     Uint16 ff_button;
   482 
   483     ff_button = 0;
   484 
   485     /*
   486      * Not sure what the proper syntax is because this actually isn't implemented
   487      * in the current kernel from what I've seen (2.6.26).
   488      */
   489     if (button != 0) {
   490         ff_button = BTN_GAMEPAD + button - 1;
   491     }
   492 
   493     return ff_button;
   494 }
   495 
   496 
   497 /*
   498  * Returns the ff_effect usable direction from a SDL_HapticDirection.
   499  */
   500 static Uint16
   501 SDL_SYS_ToDirection(SDL_HapticDirection * dir)
   502 {
   503     Uint32 tmp;
   504     float f;                    /* Ideally we'd use fixed point math instead of floats... */
   505 
   506     switch (dir->type) {
   507     case SDL_HAPTIC_POLAR:
   508         /* Linux directions start from south.
   509         		(and range from 0 to 0xFFFF)
   510 				   Quoting include/linux/input.h, line 926:
   511 				   Direction of the effect is encoded as follows:
   512 						0 deg -> 0x0000 (down)
   513 						90 deg -> 0x4000 (left)
   514 						180 deg -> 0x8000 (up)
   515 						270 deg -> 0xC000 (right)
   516 					*/
   517         tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF]
   518         return (Uint16) tmp;
   519 
   520 	   case SDL_HAPTIC_SPHERICAL:
   521    			/*
   522    				We convert to polar, because that's the only supported direction on Linux.
   523    				The first value of a spherical direction is practically the same as a
   524    				Polar direction, except that we have to add 90 degrees. It is the angle
   525    				from EAST {1,0} towards SOUTH {0,1}.
   526    				--> add 9000
   527    				--> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   528    			*/
   529 		   	tmp = ((dir->dir[0]) + 9000) % 36000;    /* Convert to polars */
   530         tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF]
   531         return (Uint16) tmp;
   532 
   533     case SDL_HAPTIC_CARTESIAN:
   534         f = atan2(dir->dir[1], dir->dir[0]);
   535 					/* 
   536 					  atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
   537 					   - Y-axis-value is the second coordinate (from center to SOUTH)
   538 					   - X-axis-value is the first coordinate (from center to EAST)
   539 						We add 36000, because atan2 also returns negative values. Then we practically
   540 						have the first spherical value. Therefore we proceed as in case
   541 						SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
   542 					  --> add 45000 in total
   543 					  --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   544 					*/
   545 				tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
   546         tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; // convert to range [0,0xFFFF]
   547         return (Uint16) tmp;
   548 
   549     default:
   550         SDL_SetError("Haptic: Unsupported direction type.");
   551         return (Uint16) - 1;
   552     }
   553 
   554     return 0;
   555 }
   556 
   557 
   558 #define  CLAMP(x)    (((x) > 32767) ? 32767 : x)
   559 /*
   560  * Initializes the linux effect struct from a haptic_effect.
   561  * Values above 32767 (for unsigned) are unspecified so we must clamp.
   562  */
   563 static int
   564 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
   565 {
   566     Uint32 tmp;
   567     SDL_HapticConstant *constant;
   568     SDL_HapticPeriodic *periodic;
   569     SDL_HapticCondition *condition;
   570     SDL_HapticRamp *ramp;
   571 
   572     /* Clear up */
   573     SDL_memset(dest, 0, sizeof(struct ff_effect));
   574 
   575     switch (src->type) {
   576     case SDL_HAPTIC_CONSTANT:
   577         constant = &src->constant;
   578 
   579         /* Header */
   580         dest->type = FF_CONSTANT;
   581         dest->direction = SDL_SYS_ToDirection(&constant->direction);
   582         if (dest->direction == (Uint16) - 1)
   583             return -1;
   584 
   585         /* Replay */
   586         dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
   587             0 : CLAMP(constant->length);
   588         dest->replay.delay = CLAMP(constant->delay);
   589 
   590         /* Trigger */
   591         dest->trigger.button = SDL_SYS_ToButton(constant->button);
   592         dest->trigger.interval = CLAMP(constant->interval);
   593 
   594         /* Constant */
   595         dest->u.constant.level = constant->level;
   596 
   597         /* Envelope */
   598         dest->u.constant.envelope.attack_length =
   599             CLAMP(constant->attack_length);
   600         dest->u.constant.envelope.attack_level =
   601             CLAMP(constant->attack_level);
   602         dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
   603         dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
   604 
   605         break;
   606 
   607     case SDL_HAPTIC_SINE:
   608     case SDL_HAPTIC_SQUARE:
   609     case SDL_HAPTIC_TRIANGLE:
   610     case SDL_HAPTIC_SAWTOOTHUP:
   611     case SDL_HAPTIC_SAWTOOTHDOWN:
   612         periodic = &src->periodic;
   613 
   614         /* Header */
   615         dest->type = FF_PERIODIC;
   616         dest->direction = SDL_SYS_ToDirection(&periodic->direction);
   617         if (dest->direction == (Uint16) - 1)
   618             return -1;
   619 
   620         /* Replay */
   621         dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
   622             0 : CLAMP(periodic->length);
   623         dest->replay.delay = CLAMP(periodic->delay);
   624 
   625         /* Trigger */
   626         dest->trigger.button = SDL_SYS_ToButton(periodic->button);
   627         dest->trigger.interval = CLAMP(periodic->interval);
   628 
   629         /* Periodic */
   630         if (periodic->type == SDL_HAPTIC_SINE)
   631             dest->u.periodic.waveform = FF_SINE;
   632         else if (periodic->type == SDL_HAPTIC_SQUARE)
   633             dest->u.periodic.waveform = FF_SQUARE;
   634         else if (periodic->type == SDL_HAPTIC_TRIANGLE)
   635             dest->u.periodic.waveform = FF_TRIANGLE;
   636         else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
   637             dest->u.periodic.waveform = FF_SAW_UP;
   638         else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
   639             dest->u.periodic.waveform = FF_SAW_DOWN;
   640         dest->u.periodic.period = CLAMP(periodic->period);
   641         dest->u.periodic.magnitude = periodic->magnitude;
   642         dest->u.periodic.offset = periodic->offset;
   643         /* Phase is calculated based of offset from period and then clamped. */
   644         tmp = ((periodic->phase % 36000) * dest->u.periodic.period) / 36000;
   645         dest->u.periodic.phase = CLAMP(tmp);
   646 
   647         /* Envelope */
   648         dest->u.periodic.envelope.attack_length =
   649             CLAMP(periodic->attack_length);
   650         dest->u.periodic.envelope.attack_level =
   651             CLAMP(periodic->attack_level);
   652         dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
   653         dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
   654 
   655         break;
   656 
   657     case SDL_HAPTIC_SPRING:
   658     case SDL_HAPTIC_DAMPER:
   659     case SDL_HAPTIC_INERTIA:
   660     case SDL_HAPTIC_FRICTION:
   661         condition = &src->condition;
   662 
   663         /* Header */
   664         if (condition->type == SDL_HAPTIC_SPRING)
   665             dest->type = FF_SPRING;
   666         else if (condition->type == SDL_HAPTIC_DAMPER)
   667             dest->type = FF_DAMPER;
   668         else if (condition->type == SDL_HAPTIC_INERTIA)
   669             dest->type = FF_INERTIA;
   670         else if (condition->type == SDL_HAPTIC_FRICTION)
   671             dest->type = FF_FRICTION;
   672         dest->direction = 0;    /* Handled by the condition-specifics. */
   673 
   674         /* Replay */
   675         dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
   676             0 : CLAMP(condition->length);
   677         dest->replay.delay = CLAMP(condition->delay);
   678 
   679         /* Trigger */
   680         dest->trigger.button = SDL_SYS_ToButton(condition->button);
   681         dest->trigger.interval = CLAMP(condition->interval);
   682 
   683         /* Condition */
   684         /* X axis */
   685         dest->u.condition[0].right_saturation =
   686             CLAMP(condition->right_sat[0]);
   687         dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
   688         dest->u.condition[0].right_coeff = condition->right_coeff[0];
   689         dest->u.condition[0].left_coeff = condition->left_coeff[0];
   690         dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
   691         dest->u.condition[0].center = condition->center[0];
   692         /* Y axis */
   693         dest->u.condition[1].right_saturation =
   694             CLAMP(condition->right_sat[1]);
   695         dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
   696         dest->u.condition[1].right_coeff = condition->right_coeff[1];
   697         dest->u.condition[1].left_coeff = condition->left_coeff[1];
   698         dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
   699         dest->u.condition[1].center = condition->center[1];
   700 
   701         /*
   702          * There is no envelope in the linux force feedback api for conditions.
   703          */
   704 
   705         break;
   706 
   707     case SDL_HAPTIC_RAMP:
   708         ramp = &src->ramp;
   709 
   710         /* Header */
   711         dest->type = FF_RAMP;
   712         dest->direction = SDL_SYS_ToDirection(&ramp->direction);
   713         if (dest->direction == (Uint16) - 1)
   714             return -1;
   715 
   716         /* Replay */
   717         dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
   718             0 : CLAMP(ramp->length);
   719         dest->replay.delay = CLAMP(ramp->delay);
   720 
   721         /* Trigger */
   722         dest->trigger.button = SDL_SYS_ToButton(ramp->button);
   723         dest->trigger.interval = CLAMP(ramp->interval);
   724 
   725         /* Ramp */
   726         dest->u.ramp.start_level = ramp->start;
   727         dest->u.ramp.end_level = ramp->end;
   728 
   729         /* Envelope */
   730         dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
   731         dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
   732         dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
   733         dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
   734 
   735         break;
   736 
   737 
   738     default:
   739         SDL_SetError("Haptic: Unknown effect type.");
   740         return -1;
   741     }
   742 
   743     return 0;
   744 }
   745 
   746 
   747 /*
   748  * Creates a new haptic effect.
   749  */
   750 int
   751 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   752                         SDL_HapticEffect * base)
   753 {
   754     struct ff_effect *linux_effect;
   755 
   756     /* Allocate the hardware effect */
   757     effect->hweffect = (struct haptic_hweffect *)
   758         SDL_malloc(sizeof(struct haptic_hweffect));
   759     if (effect->hweffect == NULL) {
   760         SDL_OutOfMemory();
   761         return -1;
   762     }
   763 
   764     /* Prepare the ff_effect */
   765     linux_effect = &effect->hweffect->effect;
   766     if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
   767         goto new_effect_err;
   768     }
   769     linux_effect->id = -1;      /* Have the kernel give it an id */
   770 
   771     /* Upload the effect */
   772     if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
   773         SDL_SetError("Haptic: Error uploading effect to the device: %s",
   774                      strerror(errno));
   775         goto new_effect_err;
   776     }
   777 
   778     return 0;
   779 
   780   new_effect_err:
   781     free(effect->hweffect);
   782     effect->hweffect = NULL;
   783     return -1;
   784 }
   785 
   786 
   787 /*
   788  * Updates an effect.
   789  *
   790  * Note: Dynamically updating the direction can in some cases force
   791  * the effect to restart and run once.
   792  */
   793 int
   794 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   795                            struct haptic_effect *effect,
   796                            SDL_HapticEffect * data)
   797 {
   798     struct ff_effect linux_effect;
   799 
   800     /* Create the new effect */
   801     if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
   802         return -1;
   803     }
   804     linux_effect.id = effect->hweffect->effect.id;
   805 
   806     /* See if it can be uploaded. */
   807     if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
   808         SDL_SetError("Haptic: Error updating the effect: %s",
   809                      strerror(errno));
   810         return -1;
   811     }
   812 
   813     /* Copy the new effect into memory. */
   814     SDL_memcpy(&effect->hweffect->effect, &linux_effect,
   815                sizeof(struct ff_effect));
   816 
   817     return effect->hweffect->effect.id;
   818 }
   819 
   820 
   821 /*
   822  * Runs an effect.
   823  */
   824 int
   825 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   826                         Uint32 iterations)
   827 {
   828     struct input_event run;
   829 
   830     /* Prepare to run the effect */
   831     run.type = EV_FF;
   832     run.code = effect->hweffect->effect.id;
   833     /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
   834     run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
   835 
   836     if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
   837         SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
   838         return -1;
   839     }
   840 
   841     return 0;
   842 }
   843 
   844 
   845 /*
   846  * Stops an effect.
   847  */
   848 int
   849 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
   850 {
   851     struct input_event stop;
   852 
   853     stop.type = EV_FF;
   854     stop.code = effect->hweffect->effect.id;
   855     stop.value = 0;
   856 
   857     if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
   858         SDL_SetError("Haptic: Unable to stop the effect: %s",
   859                      strerror(errno));
   860         return -1;
   861     }
   862 
   863     return 0;
   864 }
   865 
   866 
   867 /*
   868  * Frees the effect.
   869  */
   870 void
   871 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
   872 {
   873     if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
   874         SDL_SetError("Haptic: Error removing the effect from the device: %s",
   875                      strerror(errno));
   876     }
   877     SDL_free(effect->hweffect);
   878     effect->hweffect = NULL;
   879 }
   880 
   881 
   882 /*
   883  * Gets the status of a haptic effect.
   884  */
   885 int
   886 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
   887                               struct haptic_effect *effect)
   888 {
   889 #if 0                           /* Not supported atm. */
   890     struct input_event ie;
   891 
   892     ie.type = EV_FF;
   893     ie.type = EV_FF_STATUS;
   894     ie.code = effect->hweffect->effect.id;
   895 
   896     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
   897         SDL_SetError("Haptic: Error getting device status.");
   898         return -1;
   899     }
   900 
   901     return 0;
   902 #endif
   903 
   904     return -1;
   905 }
   906 
   907 
   908 /*
   909  * Sets the gain.
   910  */
   911 int
   912 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
   913 {
   914     struct input_event ie;
   915 
   916     ie.type = EV_FF;
   917     ie.code = FF_GAIN;
   918     ie.value = (0xFFFFUL * gain) / 100;
   919 
   920     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
   921         SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
   922         return -1;
   923     }
   924 
   925     return 0;
   926 }
   927 
   928 
   929 /*
   930  * Sets the autocentering.
   931  */
   932 int
   933 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   934 {
   935     struct input_event ie;
   936 
   937     ie.type = EV_FF;
   938     ie.code = FF_AUTOCENTER;
   939     ie.value = (0xFFFFUL * autocenter) / 100;
   940 
   941     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
   942         SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
   943         return -1;
   944     }
   945 
   946     return 0;
   947 }
   948 
   949 
   950 /*
   951  * Pausing is not supported atm by linux.
   952  */
   953 int
   954 SDL_SYS_HapticPause(SDL_Haptic * haptic)
   955 {
   956     return -1;
   957 }
   958 
   959 
   960 /*
   961  * Unpausing is not supported atm by linux.
   962  */
   963 int
   964 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
   965 {
   966     return -1;
   967 }
   968 
   969 
   970 /*
   971  * Stops all the currently playing effects.
   972  */
   973 int
   974 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
   975 {
   976     int i, ret;
   977 
   978     /* Linux does not support this natively so we have to loop. */
   979     for (i = 0; i < haptic->neffects; i++) {
   980         if (haptic->effects[i].hweffect != NULL) {
   981             ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
   982             if (ret < 0) {
   983                 SDL_SetError
   984                     ("Haptic: Error while trying to stop all playing effects.");
   985                 return -1;
   986             }
   987         }
   988     }
   989     return 0;
   990 }
   991 
   992 
   993 #endif /* SDL_HAPTIC_LINUX */