src/haptic/linux/SDL_syshaptic.c
author David Ludwig <dludwig@pobox.com>
Wed, 25 Dec 2013 21:39:48 -0500
changeset 8563 c0e68f3b6bbb
parent 7708 d5aa9910b1f7
child 8093 b43765095a6f
permissions -rw-r--r--
WinRT: compiled the d3d11 renderer's shaders into SDL itself

Previously, the shaders would get compiled separately, the output of which would need to be packaged into the app. This change should make SDL's dll be the only binary needed to include SDL in a WinRT app.
     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 *
   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     /* 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
   305 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   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
   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             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
   364 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   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
   374 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   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
   389 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   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
   429 SDL_SYS_HapticClose(SDL_Haptic * haptic)
   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 
   514        case SDL_HAPTIC_SPHERICAL:
   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 
   527     case SDL_HAPTIC_CARTESIAN:
   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;
   562     SDL_HapticCondition *condition;
   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:
   605     case SDL_HAPTIC_SAWTOOTHUP:
   606     case SDL_HAPTIC_SAWTOOTHDOWN:
   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 
   733     case SDL_HAPTIC_LEFTRIGHT:
   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
   767 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   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
   809 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   810                            struct haptic_effect *effect,
   811                            SDL_HapticEffect * data)
   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
   898 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
   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
   963 SDL_SYS_HapticPause(SDL_Haptic * haptic)
   964 {
   965     return -1;
   966 }
   967 
   968 
   969 /*
   970  * Unpausing is not supported atm by linux.
   971  */
   972 int
   973 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
   974 {
   975     return -1;
   976 }
   977 
   978 
   979 /*
   980  * Stops all the currently playing effects.
   981  */
   982 int
   983 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
   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 */