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