src/haptic/linux/SDL_syshaptic.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 29 Nov 2014 11:51:13 -0800
changeset 9251 198989b162d3
parent 9249 35a4fab04296
child 9266 f6355bfca853
permissions -rw-r--r--
Fixed bug 2766 - Haptic coding bugs and fixes for Linux FF: periodic.phase handled as time instead of angle; + direction clarification

Elias Vanderstuyft

Remove the dependency of the calculation of Linux "phase" on "period",
currently the "phase" parameter is interpreted as a time shift, instead of a phase shift.
The Linux input documentation is not clear about the exact units of the "phase" parameter (see http://lxr.free-electrons.com/source/include/uapi/linux/input.h?v=3.17#L1075 ),
but we're about to standardize the 'phase shift' interpretation into the Linux input documentation,
since this will ease the job of a driver to recalculate the effect's state when the user dynamically updates the "period" parameter.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 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_internal.h"
    22 
    23 #ifdef SDL_HAPTIC_LINUX
    24 
    25 #include "SDL_assert.h"
    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 #include "../../core/linux/SDL_udev.h"
    32 
    33 #include <unistd.h>             /* close */
    34 #include <linux/input.h>        /* Force feedback linux stuff. */
    35 #include <fcntl.h>              /* O_RDWR */
    36 #include <limits.h>             /* INT_MAX */
    37 #include <errno.h>              /* errno, strerror */
    38 #include <math.h>               /* atan2 */
    39 #include <sys/stat.h>           /* stat */
    40 
    41 /* Just in case. */
    42 #ifndef M_PI
    43 #  define M_PI     3.14159265358979323846
    44 #endif
    45 
    46 
    47 #define MAX_HAPTICS  32         /* It's doubtful someone has more then 32 evdev */
    48 
    49 static int MaybeAddDevice(const char *path);
    50 #if SDL_USE_LIBUDEV
    51 static int MaybeRemoveDevice(const char *path);
    52 void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
    53 #endif /* SDL_USE_LIBUDEV */
    54 
    55 /*
    56  * List of available haptic devices.
    57  */
    58 typedef struct SDL_hapticlist_item
    59 {
    60     char *fname;                /* Dev path name (like /dev/input/event1) */
    61     SDL_Haptic *haptic;         /* Associated haptic. */
    62     struct SDL_hapticlist_item *next;
    63 } SDL_hapticlist_item;
    64 
    65 
    66 /*
    67  * Haptic system hardware data.
    68  */
    69 struct haptic_hwdata
    70 {
    71     int fd;                     /* File descriptor of the device. */
    72     char *fname;                /* Points to the name in SDL_hapticlist. */
    73 };
    74 
    75 
    76 /*
    77  * Haptic system effect data.
    78  */
    79 struct haptic_hweffect
    80 {
    81     struct ff_effect effect;    /* The linux kernel effect structure. */
    82 };
    83 
    84 static SDL_hapticlist_item *SDL_hapticlist = NULL;
    85 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
    86 static int numhaptics = 0;
    87 
    88 #define test_bit(nr, addr) \
    89    (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
    90 #define EV_TEST(ev,f) \
    91    if (test_bit((ev), features)) ret |= (f);
    92 /*
    93  * Test whether a device has haptic properties.
    94  * Returns available properties or 0 if there are none.
    95  */
    96 static int
    97 EV_IsHaptic(int fd)
    98 {
    99     unsigned int ret;
   100     unsigned long features[1 + FF_MAX / sizeof(unsigned long)];
   101 
   102     /* Ask device for what it has. */
   103     ret = 0;
   104     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(features)), features) < 0) {
   105         return SDL_SetError("Haptic: Unable to get device's features: %s",
   106                             strerror(errno));
   107     }
   108 
   109     /* Convert supported features to SDL_HAPTIC platform-neutral features. */
   110     EV_TEST(FF_CONSTANT, SDL_HAPTIC_CONSTANT);
   111     EV_TEST(FF_SINE, SDL_HAPTIC_SINE);
   112     /* !!! FIXME: put this back when we have more bits in 2.1 */
   113     /* EV_TEST(FF_SQUARE, SDL_HAPTIC_SQUARE); */
   114     EV_TEST(FF_TRIANGLE, SDL_HAPTIC_TRIANGLE);
   115     EV_TEST(FF_SAW_UP, SDL_HAPTIC_SAWTOOTHUP);
   116     EV_TEST(FF_SAW_DOWN, SDL_HAPTIC_SAWTOOTHDOWN);
   117     EV_TEST(FF_RAMP, SDL_HAPTIC_RAMP);
   118     EV_TEST(FF_SPRING, SDL_HAPTIC_SPRING);
   119     EV_TEST(FF_FRICTION, SDL_HAPTIC_FRICTION);
   120     EV_TEST(FF_DAMPER, SDL_HAPTIC_DAMPER);
   121     EV_TEST(FF_INERTIA, SDL_HAPTIC_INERTIA);
   122     EV_TEST(FF_CUSTOM, SDL_HAPTIC_CUSTOM);
   123     EV_TEST(FF_GAIN, SDL_HAPTIC_GAIN);
   124     EV_TEST(FF_AUTOCENTER, SDL_HAPTIC_AUTOCENTER);
   125     EV_TEST(FF_RUMBLE, SDL_HAPTIC_LEFTRIGHT);
   126 
   127     /* Return what it supports. */
   128     return ret;
   129 }
   130 
   131 
   132 /*
   133  * Tests whether a device is a mouse or not.
   134  */
   135 static int
   136 EV_IsMouse(int fd)
   137 {
   138     unsigned long argp[40];
   139 
   140     /* Ask for supported features. */
   141     if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(argp)), argp) < 0) {
   142         return -1;
   143     }
   144 
   145     /* Currently we only test for BTN_MOUSE which can give fake positives. */
   146     if (test_bit(BTN_MOUSE, argp) != 0) {
   147         return 1;
   148     }
   149 
   150     return 0;
   151 }
   152 
   153 /*
   154  * Initializes the haptic subsystem by finding available devices.
   155  */
   156 int
   157 SDL_SYS_HapticInit(void)
   158 {
   159     const char joydev_pattern[] = "/dev/input/event%d";
   160     char path[PATH_MAX];
   161     int i, j;
   162 
   163     /*
   164      * Limit amount of checks to MAX_HAPTICS since we may or may not have
   165      * permission to some or all devices.
   166      */
   167     i = 0;
   168     for (j = 0; j < MAX_HAPTICS; ++j) {
   169 
   170         snprintf(path, PATH_MAX, joydev_pattern, i++);
   171         MaybeAddDevice(path);
   172     }
   173 
   174 #if SDL_USE_LIBUDEV
   175     if (SDL_UDEV_Init() < 0) {
   176         return SDL_SetError("Could not initialize UDEV");
   177     }
   178 
   179     if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) {
   180         SDL_UDEV_Quit();
   181         return SDL_SetError("Could not setup haptic <-> udev callback");
   182     }
   183 #endif /* SDL_USE_LIBUDEV */
   184 
   185     return numhaptics;
   186 }
   187 
   188 int
   189 SDL_SYS_NumHaptics()
   190 {
   191     return numhaptics;
   192 }
   193 
   194 static SDL_hapticlist_item *
   195 HapticByDevIndex(int device_index)
   196 {
   197     SDL_hapticlist_item *item = SDL_hapticlist;
   198 
   199     if ((device_index < 0) || (device_index >= numhaptics)) {
   200         return NULL;
   201     }
   202 
   203     while (device_index > 0) {
   204         SDL_assert(item != NULL);
   205         --device_index;
   206         item = item->next;
   207     }
   208 
   209     return item;
   210 }
   211 
   212 #if SDL_USE_LIBUDEV
   213 void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
   214 {
   215     if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
   216         return;
   217     }
   218 
   219     switch( udev_type )
   220     {
   221         case SDL_UDEV_DEVICEADDED:
   222             MaybeAddDevice(devpath);
   223             break;
   224 
   225         case SDL_UDEV_DEVICEREMOVED:
   226             MaybeRemoveDevice(devpath);
   227             break;
   228 
   229         default:
   230             break;
   231     }
   232 
   233 }
   234 #endif /* SDL_USE_LIBUDEV */
   235 
   236 static int
   237 MaybeAddDevice(const char *path)
   238 {
   239     dev_t dev_nums[MAX_HAPTICS];
   240     struct stat sb;
   241     int fd;
   242     int k;
   243     int duplicate;
   244     int success;
   245     SDL_hapticlist_item *item;
   246 
   247 
   248     if (path == NULL) {
   249         return -1;
   250     }
   251 
   252     /* check to see if file exists */
   253     if (stat(path, &sb) != 0) {
   254         return -1;
   255     }
   256 
   257     /* check for duplicates */
   258     duplicate = 0;
   259     for (k = 0; (k < numhaptics) && !duplicate; ++k) {
   260         if (sb.st_rdev == dev_nums[k]) {
   261             duplicate = 1;
   262         }
   263     }
   264     if (duplicate) {
   265         return -1;
   266     }
   267 
   268     /* try to open */
   269     fd = open(path, O_RDWR, 0);
   270     if (fd < 0) {
   271         return -1;
   272     }
   273 
   274 #ifdef DEBUG_INPUT_EVENTS
   275     printf("Checking %s\n", path);
   276 #endif
   277 
   278     /* see if it works */
   279     success = EV_IsHaptic(fd);
   280     close(fd);
   281     if (success <= 0) {
   282         return -1;
   283     }
   284 
   285     item = (SDL_hapticlist_item *) SDL_calloc(1, sizeof (SDL_hapticlist_item));
   286     if (item == NULL) {
   287         return -1;
   288     }
   289 
   290     item->fname = SDL_strdup(path);
   291     if ( (item->fname == NULL) ) {
   292         SDL_free(item->fname);
   293         SDL_free(item);
   294         return -1;
   295     }
   296 
   297     /* TODO: should we add instance IDs? */
   298     if (SDL_hapticlist_tail == NULL) {
   299         SDL_hapticlist = SDL_hapticlist_tail = item;
   300     } else {
   301         SDL_hapticlist_tail->next = item;
   302         SDL_hapticlist_tail = item;
   303     }
   304 
   305     dev_nums[numhaptics] = sb.st_rdev;
   306 
   307     ++numhaptics;
   308 
   309     /* !!! TODO: Send a haptic add event? */
   310 
   311     return numhaptics;
   312 }
   313 
   314 #if SDL_USE_LIBUDEV
   315 static int
   316 MaybeRemoveDevice(const char* path)
   317 {
   318     SDL_hapticlist_item *item;
   319     SDL_hapticlist_item *prev = NULL;
   320 
   321     if (path == NULL) {
   322         return -1;
   323     }
   324 
   325     for (item = SDL_hapticlist; item != NULL; item = item->next) {
   326         /* found it, remove it. */
   327         if (SDL_strcmp(path, item->fname) == 0) {
   328             const int retval = item->haptic ? item->haptic->index : -1;
   329 
   330             if (prev != NULL) {
   331                 prev->next = item->next;
   332             } else {
   333                 SDL_assert(SDL_hapticlist == item);
   334                 SDL_hapticlist = item->next;
   335             }
   336             if (item == SDL_hapticlist_tail) {
   337                 SDL_hapticlist_tail = prev;
   338             }
   339 
   340             /* Need to decrement the haptic count */
   341             --numhaptics;
   342             /* !!! TODO: Send a haptic remove event? */
   343 
   344             SDL_free(item->fname);
   345             SDL_free(item);
   346             return retval;
   347         }
   348         prev = item;
   349     }
   350 
   351     return -1;
   352 }
   353 #endif /* SDL_USE_LIBUDEV */
   354 
   355 /*
   356  * Gets the name from a file descriptor.
   357  */
   358 static const char *
   359 SDL_SYS_HapticNameFromFD(int fd)
   360 {
   361     static char namebuf[128];
   362 
   363     /* We use the evdev name ioctl. */
   364     if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) {
   365         return NULL;
   366     }
   367 
   368     return namebuf;
   369 }
   370 
   371 
   372 /*
   373  * Return the name of a haptic device, does not need to be opened.
   374  */
   375 const char *
   376 SDL_SYS_HapticName(int index)
   377 {
   378     SDL_hapticlist_item *item;
   379     int fd;
   380     const char *name;
   381 
   382     item = HapticByDevIndex(index);
   383     /* Open the haptic device. */
   384     name = NULL;
   385     fd = open(item->fname, O_RDONLY, 0);
   386 
   387     if (fd >= 0) {
   388 
   389         name = SDL_SYS_HapticNameFromFD(fd);
   390         if (name == NULL) {
   391             /* No name found, return device character device */
   392             name = item->fname;
   393         }
   394     }
   395     close(fd);
   396 
   397     return name;
   398 }
   399 
   400 
   401 /*
   402  * Opens the haptic device from the file descriptor.
   403  */
   404 static int
   405 SDL_SYS_HapticOpenFromFD(SDL_Haptic * haptic, int fd)
   406 {
   407     /* Allocate the hwdata */
   408     haptic->hwdata = (struct haptic_hwdata *)
   409         SDL_malloc(sizeof(*haptic->hwdata));
   410     if (haptic->hwdata == NULL) {
   411         SDL_OutOfMemory();
   412         goto open_err;
   413     }
   414     SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   415 
   416     /* Set the data. */
   417     haptic->hwdata->fd = fd;
   418     haptic->supported = EV_IsHaptic(fd);
   419     haptic->naxes = 2;          /* Hardcoded for now, not sure if it's possible to find out. */
   420 
   421     /* Set the effects */
   422     if (ioctl(fd, EVIOCGEFFECTS, &haptic->neffects) < 0) {
   423         SDL_SetError("Haptic: Unable to query device memory: %s",
   424                      strerror(errno));
   425         goto open_err;
   426     }
   427     haptic->nplaying = haptic->neffects;        /* Linux makes no distinction. */
   428     haptic->effects = (struct haptic_effect *)
   429         SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   430     if (haptic->effects == NULL) {
   431         SDL_OutOfMemory();
   432         goto open_err;
   433     }
   434     /* Clear the memory */
   435     SDL_memset(haptic->effects, 0,
   436                sizeof(struct haptic_effect) * haptic->neffects);
   437 
   438     return 0;
   439 
   440     /* Error handling */
   441   open_err:
   442     close(fd);
   443     if (haptic->hwdata != NULL) {
   444         free(haptic->hwdata);
   445         haptic->hwdata = NULL;
   446     }
   447     return -1;
   448 }
   449 
   450 
   451 /*
   452  * Opens a haptic device for usage.
   453  */
   454 int
   455 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   456 {
   457     int fd;
   458     int ret;
   459     SDL_hapticlist_item *item;
   460 
   461     item = HapticByDevIndex(haptic->index);
   462     /* Open the character device */
   463     fd = open(item->fname, O_RDWR, 0);
   464     if (fd < 0) {
   465         return SDL_SetError("Haptic: Unable to open %s: %s",
   466                             item->fname, strerror(errno));
   467     }
   468 
   469     /* Try to create the haptic. */
   470     ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
   471     if (ret < 0) {
   472         return -1;
   473     }
   474 
   475     /* Set the fname. */
   476     haptic->hwdata->fname = item->fname;
   477     return 0;
   478 }
   479 
   480 
   481 /*
   482  * Opens a haptic device from first mouse it finds for usage.
   483  */
   484 int
   485 SDL_SYS_HapticMouse(void)
   486 {
   487     int fd;
   488     int device_index = 0;
   489     SDL_hapticlist_item *item;
   490 
   491     for (item = SDL_hapticlist; item; item = item->next) {
   492         /* Open the device. */
   493         fd = open(item->fname, O_RDWR, 0);
   494         if (fd < 0) {
   495             return SDL_SetError("Haptic: Unable to open %s: %s",
   496                                 item->fname, strerror(errno));
   497         }
   498 
   499         /* Is it a mouse? */
   500         if (EV_IsMouse(fd)) {
   501             close(fd);
   502             return device_index;
   503         }
   504 
   505         close(fd);
   506 
   507         ++device_index;
   508     }
   509 
   510     return -1;
   511 }
   512 
   513 
   514 /*
   515  * Checks to see if a joystick has haptic features.
   516  */
   517 int
   518 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   519 {
   520     return EV_IsHaptic(joystick->hwdata->fd);
   521 }
   522 
   523 
   524 /*
   525  * Checks to see if the haptic device and joystick are in reality the same.
   526  */
   527 int
   528 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   529 {
   530     /* We are assuming Linux is using evdev which should trump the old
   531      * joystick methods. */
   532     if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
   533         return 1;
   534     }
   535     return 0;
   536 }
   537 
   538 
   539 /*
   540  * Opens a SDL_Haptic from a SDL_Joystick.
   541  */
   542 int
   543 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   544 {
   545     int device_index = 0;
   546     int fd;
   547     int ret;
   548     SDL_hapticlist_item *item;
   549 
   550 
   551     /* Find the joystick in the haptic list. */
   552     for (item = SDL_hapticlist; item; item = item->next) {
   553         if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
   554             haptic->index = device_index;
   555             break;
   556         }
   557         ++device_index;
   558     }
   559     if (device_index >= MAX_HAPTICS) {
   560         return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
   561     }
   562 
   563     fd = open(joystick->hwdata->fname, O_RDWR, 0);
   564     if (fd < 0) {
   565         return SDL_SetError("Haptic: Unable to open %s: %s",
   566                             joystick->hwdata->fname, strerror(errno));
   567     }
   568     ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
   569     if (ret < 0) {
   570         return -1;
   571     }
   572 
   573     haptic->hwdata->fname = item->fname;
   574     return 0;
   575 }
   576 
   577 
   578 /*
   579  * Closes the haptic device.
   580  */
   581 void
   582 SDL_SYS_HapticClose(SDL_Haptic * haptic)
   583 {
   584     if (haptic->hwdata) {
   585 
   586         /* Free effects. */
   587         SDL_free(haptic->effects);
   588         haptic->effects = NULL;
   589         haptic->neffects = 0;
   590 
   591         /* Clean up */
   592         close(haptic->hwdata->fd);
   593 
   594         /* Free */
   595         SDL_free(haptic->hwdata);
   596         haptic->hwdata = NULL;
   597     }
   598 
   599     /* Clear the rest. */
   600     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   601 }
   602 
   603 
   604 /*
   605  * Clean up after system specific haptic stuff
   606  */
   607 void
   608 SDL_SYS_HapticQuit(void)
   609 {
   610     SDL_hapticlist_item *item = NULL;
   611     SDL_hapticlist_item *next = NULL;
   612 
   613     for (item = SDL_hapticlist; item; item = next) {
   614         next = item->next;
   615         /* Opened and not closed haptics are leaked, this is on purpose.
   616          * Close your haptic devices after usage. */
   617         SDL_free(item->fname);
   618         item->fname = NULL;
   619     }
   620 
   621 #if SDL_USE_LIBUDEV
   622     SDL_UDEV_DelCallback(haptic_udev_callback);
   623     SDL_UDEV_Quit();
   624 #endif /* SDL_USE_LIBUDEV */
   625 
   626     numhaptics = 0;
   627     SDL_hapticlist = NULL;
   628     SDL_hapticlist_tail = NULL;
   629 }
   630 
   631 
   632 /*
   633  * Converts an SDL button to a ff_trigger button.
   634  */
   635 static Uint16
   636 SDL_SYS_ToButton(Uint16 button)
   637 {
   638     Uint16 ff_button;
   639 
   640     ff_button = 0;
   641 
   642     /*
   643      * Not sure what the proper syntax is because this actually isn't implemented
   644      * in the current kernel from what I've seen (2.6.26).
   645      */
   646     if (button != 0) {
   647         ff_button = BTN_GAMEPAD + button - 1;
   648     }
   649 
   650     return ff_button;
   651 }
   652 
   653 
   654 /*
   655  * Initializes the ff_effect usable direction from a SDL_HapticDirection.
   656  */
   657 static int
   658 SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
   659 {
   660     Uint32 tmp;
   661 
   662     switch (src->type) {
   663     case SDL_HAPTIC_POLAR:
   664         /* Linux directions start from south.
   665                 (and range from 0 to 0xFFFF)
   666                    Quoting include/linux/input.h, line 926:
   667                    Direction of the effect is encoded as follows:
   668                         0 deg -> 0x0000 (down)
   669                         90 deg -> 0x4000 (left)
   670                         180 deg -> 0x8000 (up)
   671                         270 deg -> 0xC000 (right)
   672                    The force pulls into the direction specified by Linux directions,
   673                    i.e. the opposite convention of SDL directions.
   674                     */
   675         tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   676         *dest = (Uint16) tmp;
   677         break;
   678 
   679     case SDL_HAPTIC_SPHERICAL:
   680             /*
   681                 We convert to polar, because that's the only supported direction on Linux.
   682                 The first value of a spherical direction is practically the same as a
   683                 Polar direction, except that we have to add 90 degrees. It is the angle
   684                 from EAST {1,0} towards SOUTH {0,1}.
   685                 --> add 9000
   686                 --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   687             */
   688             tmp = ((src->dir[0]) + 9000) % 36000;    /* Convert to polars */
   689         tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   690         *dest = (Uint16) tmp;
   691         break;
   692 
   693     case SDL_HAPTIC_CARTESIAN:
   694         if (!src->dir[1])
   695             *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000);
   696         else if (!src->dir[0])
   697             *dest = (src->dir[1] >= 0 ? 0x8000 : 0);
   698         else {
   699             float f = atan2(src->dir[1], src->dir[0]);    /* Ideally we'd use fixed point math instead of floats... */
   700                     /*
   701                       atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
   702                        - Y-axis-value is the second coordinate (from center to SOUTH)
   703                        - X-axis-value is the first coordinate (from center to EAST)
   704                         We add 36000, because atan2 also returns negative values. Then we practically
   705                         have the first spherical value. Therefore we proceed as in case
   706                         SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
   707                       --> add 45000 in total
   708                       --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   709                     */
   710                 tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
   711             tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   712             *dest = (Uint16) tmp;
   713         }
   714         break;
   715 
   716     default:
   717         return SDL_SetError("Haptic: Unsupported direction type.");
   718     }
   719 
   720     return 0;
   721 }
   722 
   723 
   724 #define  CLAMP(x)    (((x) > 32767) ? 32767 : x)
   725 /*
   726  * Initializes the Linux effect struct from a haptic_effect.
   727  * Values above 32767 (for unsigned) are unspecified so we must clamp.
   728  */
   729 static int
   730 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
   731 {
   732     SDL_HapticConstant *constant;
   733     SDL_HapticPeriodic *periodic;
   734     SDL_HapticCondition *condition;
   735     SDL_HapticRamp *ramp;
   736     SDL_HapticLeftRight *leftright;
   737 
   738     /* Clear up */
   739     SDL_memset(dest, 0, sizeof(struct ff_effect));
   740 
   741     switch (src->type) {
   742     case SDL_HAPTIC_CONSTANT:
   743         constant = &src->constant;
   744 
   745         /* Header */
   746         dest->type = FF_CONSTANT;
   747         if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1)
   748             return -1;
   749 
   750         /* Replay */
   751         dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
   752             0 : CLAMP(constant->length);
   753         dest->replay.delay = CLAMP(constant->delay);
   754 
   755         /* Trigger */
   756         dest->trigger.button = SDL_SYS_ToButton(constant->button);
   757         dest->trigger.interval = CLAMP(constant->interval);
   758 
   759         /* Constant */
   760         dest->u.constant.level = constant->level;
   761 
   762         /* Envelope */
   763         dest->u.constant.envelope.attack_length =
   764             CLAMP(constant->attack_length);
   765         dest->u.constant.envelope.attack_level =
   766             CLAMP(constant->attack_level);
   767         dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
   768         dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
   769 
   770         break;
   771 
   772     case SDL_HAPTIC_SINE:
   773     /* !!! FIXME: put this back when we have more bits in 2.1 */
   774     /* case SDL_HAPTIC_SQUARE: */
   775     case SDL_HAPTIC_TRIANGLE:
   776     case SDL_HAPTIC_SAWTOOTHUP:
   777     case SDL_HAPTIC_SAWTOOTHDOWN:
   778         periodic = &src->periodic;
   779 
   780         /* Header */
   781         dest->type = FF_PERIODIC;
   782         if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1)
   783             return -1;
   784 
   785         /* Replay */
   786         dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
   787             0 : CLAMP(periodic->length);
   788         dest->replay.delay = CLAMP(periodic->delay);
   789 
   790         /* Trigger */
   791         dest->trigger.button = SDL_SYS_ToButton(periodic->button);
   792         dest->trigger.interval = CLAMP(periodic->interval);
   793 
   794         /* Periodic */
   795         if (periodic->type == SDL_HAPTIC_SINE)
   796             dest->u.periodic.waveform = FF_SINE;
   797         /* !!! FIXME: put this back when we have more bits in 2.1 */
   798         /* else if (periodic->type == SDL_HAPTIC_SQUARE)
   799             dest->u.periodic.waveform = FF_SQUARE; */
   800         else if (periodic->type == SDL_HAPTIC_TRIANGLE)
   801             dest->u.periodic.waveform = FF_TRIANGLE;
   802         else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
   803             dest->u.periodic.waveform = FF_SAW_UP;
   804         else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
   805             dest->u.periodic.waveform = FF_SAW_DOWN;
   806         dest->u.periodic.period = CLAMP(periodic->period);
   807         dest->u.periodic.magnitude = periodic->magnitude;
   808         dest->u.periodic.offset = periodic->offset;
   809         /* Linux phase is defined in interval "[0x0000, 0x10000[", corresponds with "[0deg, 360deg[" phase shift. */
   810         dest->u.periodic.phase = ((Uint32)periodic->phase * 0x10000U) / 36000;
   811 
   812         /* Envelope */
   813         dest->u.periodic.envelope.attack_length =
   814             CLAMP(periodic->attack_length);
   815         dest->u.periodic.envelope.attack_level =
   816             CLAMP(periodic->attack_level);
   817         dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
   818         dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
   819 
   820         break;
   821 
   822     case SDL_HAPTIC_SPRING:
   823     case SDL_HAPTIC_DAMPER:
   824     case SDL_HAPTIC_INERTIA:
   825     case SDL_HAPTIC_FRICTION:
   826         condition = &src->condition;
   827 
   828         /* Header */
   829         if (condition->type == SDL_HAPTIC_SPRING)
   830             dest->type = FF_SPRING;
   831         else if (condition->type == SDL_HAPTIC_DAMPER)
   832             dest->type = FF_DAMPER;
   833         else if (condition->type == SDL_HAPTIC_INERTIA)
   834             dest->type = FF_INERTIA;
   835         else if (condition->type == SDL_HAPTIC_FRICTION)
   836             dest->type = FF_FRICTION;
   837         dest->direction = 0;    /* Handled by the condition-specifics. */
   838 
   839         /* Replay */
   840         dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
   841             0 : CLAMP(condition->length);
   842         dest->replay.delay = CLAMP(condition->delay);
   843 
   844         /* Trigger */
   845         dest->trigger.button = SDL_SYS_ToButton(condition->button);
   846         dest->trigger.interval = CLAMP(condition->interval);
   847 
   848         /* Condition */
   849         /* X axis */
   850         dest->u.condition[0].right_saturation = condition->right_sat[0];
   851         dest->u.condition[0].left_saturation = condition->left_sat[0];
   852         dest->u.condition[0].right_coeff = condition->right_coeff[0];
   853         dest->u.condition[0].left_coeff = condition->left_coeff[0];
   854         dest->u.condition[0].deadband = condition->deadband[0];
   855         dest->u.condition[0].center = condition->center[0];
   856         /* Y axis */
   857         dest->u.condition[1].right_saturation = condition->right_sat[1];
   858         dest->u.condition[1].left_saturation = condition->left_sat[1];
   859         dest->u.condition[1].right_coeff = condition->right_coeff[1];
   860         dest->u.condition[1].left_coeff = condition->left_coeff[1];
   861         dest->u.condition[1].deadband = condition->deadband[1];
   862         dest->u.condition[1].center = condition->center[1];
   863 
   864         /*
   865          * There is no envelope in the linux force feedback api for conditions.
   866          */
   867 
   868         break;
   869 
   870     case SDL_HAPTIC_RAMP:
   871         ramp = &src->ramp;
   872 
   873         /* Header */
   874         dest->type = FF_RAMP;
   875         if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1)
   876             return -1;
   877 
   878         /* Replay */
   879         dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
   880             0 : CLAMP(ramp->length);
   881         dest->replay.delay = CLAMP(ramp->delay);
   882 
   883         /* Trigger */
   884         dest->trigger.button = SDL_SYS_ToButton(ramp->button);
   885         dest->trigger.interval = CLAMP(ramp->interval);
   886 
   887         /* Ramp */
   888         dest->u.ramp.start_level = ramp->start;
   889         dest->u.ramp.end_level = ramp->end;
   890 
   891         /* Envelope */
   892         dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
   893         dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
   894         dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
   895         dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
   896 
   897         break;
   898 
   899     case SDL_HAPTIC_LEFTRIGHT:
   900         leftright = &src->leftright;
   901 
   902         /* Header */
   903         dest->type = FF_RUMBLE;
   904         dest->direction = 0;
   905 
   906         /* Replay */
   907         dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
   908             0 : CLAMP(leftright->length);
   909 
   910         /* Trigger */
   911         dest->trigger.button = 0;
   912         dest->trigger.interval = 0;
   913 
   914         /* Rumble */
   915         dest->u.rumble.strong_magnitude = leftright->large_magnitude;
   916         dest->u.rumble.weak_magnitude = leftright->small_magnitude;
   917 
   918         break;
   919 
   920 
   921     default:
   922         return SDL_SetError("Haptic: Unknown effect type.");
   923     }
   924 
   925     return 0;
   926 }
   927 
   928 
   929 /*
   930  * Creates a new haptic effect.
   931  */
   932 int
   933 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   934                         SDL_HapticEffect * base)
   935 {
   936     struct ff_effect *linux_effect;
   937 
   938     /* Allocate the hardware effect */
   939     effect->hweffect = (struct haptic_hweffect *)
   940         SDL_malloc(sizeof(struct haptic_hweffect));
   941     if (effect->hweffect == NULL) {
   942         return SDL_OutOfMemory();
   943     }
   944 
   945     /* Prepare the ff_effect */
   946     linux_effect = &effect->hweffect->effect;
   947     if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
   948         goto new_effect_err;
   949     }
   950     linux_effect->id = -1;      /* Have the kernel give it an id */
   951 
   952     /* Upload the effect */
   953     if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
   954         SDL_SetError("Haptic: Error uploading effect to the device: %s",
   955                      strerror(errno));
   956         goto new_effect_err;
   957     }
   958 
   959     return 0;
   960 
   961   new_effect_err:
   962     free(effect->hweffect);
   963     effect->hweffect = NULL;
   964     return -1;
   965 }
   966 
   967 
   968 /*
   969  * Updates an effect.
   970  *
   971  * Note: Dynamically updating the direction can in some cases force
   972  * the effect to restart and run once.
   973  */
   974 int
   975 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   976                            struct haptic_effect *effect,
   977                            SDL_HapticEffect * data)
   978 {
   979     struct ff_effect linux_effect;
   980 
   981     /* Create the new effect */
   982     if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
   983         return -1;
   984     }
   985     linux_effect.id = effect->hweffect->effect.id;
   986 
   987     /* See if it can be uploaded. */
   988     if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
   989         return SDL_SetError("Haptic: Error updating the effect: %s",
   990                             strerror(errno));
   991     }
   992 
   993     /* Copy the new effect into memory. */
   994     SDL_memcpy(&effect->hweffect->effect, &linux_effect,
   995                sizeof(struct ff_effect));
   996 
   997     return effect->hweffect->effect.id;
   998 }
   999 
  1000 
  1001 /*
  1002  * Runs an effect.
  1003  */
  1004 int
  1005 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
  1006                         Uint32 iterations)
  1007 {
  1008     struct input_event run;
  1009 
  1010     /* Prepare to run the effect */
  1011     run.type = EV_FF;
  1012     run.code = effect->hweffect->effect.id;
  1013     /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
  1014     run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
  1015 
  1016     if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
  1017         return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
  1018     }
  1019 
  1020     return 0;
  1021 }
  1022 
  1023 
  1024 /*
  1025  * Stops an effect.
  1026  */
  1027 int
  1028 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1029 {
  1030     struct input_event stop;
  1031 
  1032     stop.type = EV_FF;
  1033     stop.code = effect->hweffect->effect.id;
  1034     stop.value = 0;
  1035 
  1036     if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
  1037         return SDL_SetError("Haptic: Unable to stop the effect: %s",
  1038                             strerror(errno));
  1039     }
  1040 
  1041     return 0;
  1042 }
  1043 
  1044 
  1045 /*
  1046  * Frees the effect.
  1047  */
  1048 void
  1049 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1050 {
  1051     if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
  1052         SDL_SetError("Haptic: Error removing the effect from the device: %s",
  1053                      strerror(errno));
  1054     }
  1055     SDL_free(effect->hweffect);
  1056     effect->hweffect = NULL;
  1057 }
  1058 
  1059 
  1060 /*
  1061  * Gets the status of a haptic effect.
  1062  */
  1063 int
  1064 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
  1065                               struct haptic_effect *effect)
  1066 {
  1067 #if 0                           /* Not supported atm. */
  1068     struct input_event ie;
  1069 
  1070     ie.type = EV_FF;
  1071     ie.type = EV_FF_STATUS;
  1072     ie.code = effect->hweffect->effect.id;
  1073 
  1074     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1075         return SDL_SetError("Haptic: Error getting device status.");
  1076     }
  1077 
  1078     return 0;
  1079 #endif
  1080 
  1081     return -1;
  1082 }
  1083 
  1084 
  1085 /*
  1086  * Sets the gain.
  1087  */
  1088 int
  1089 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
  1090 {
  1091     struct input_event ie;
  1092 
  1093     ie.type = EV_FF;
  1094     ie.code = FF_GAIN;
  1095     ie.value = (0xFFFFUL * gain) / 100;
  1096 
  1097     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1098         return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
  1099     }
  1100 
  1101     return 0;
  1102 }
  1103 
  1104 
  1105 /*
  1106  * Sets the autocentering.
  1107  */
  1108 int
  1109 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1110 {
  1111     struct input_event ie;
  1112 
  1113     ie.type = EV_FF;
  1114     ie.code = FF_AUTOCENTER;
  1115     ie.value = (0xFFFFUL * autocenter) / 100;
  1116 
  1117     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1118         return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
  1119     }
  1120 
  1121     return 0;
  1122 }
  1123 
  1124 
  1125 /*
  1126  * Pausing is not supported atm by linux.
  1127  */
  1128 int
  1129 SDL_SYS_HapticPause(SDL_Haptic * haptic)
  1130 {
  1131     return -1;
  1132 }
  1133 
  1134 
  1135 /*
  1136  * Unpausing is not supported atm by linux.
  1137  */
  1138 int
  1139 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
  1140 {
  1141     return -1;
  1142 }
  1143 
  1144 
  1145 /*
  1146  * Stops all the currently playing effects.
  1147  */
  1148 int
  1149 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
  1150 {
  1151     int i, ret;
  1152 
  1153     /* Linux does not support this natively so we have to loop. */
  1154     for (i = 0; i < haptic->neffects; i++) {
  1155         if (haptic->effects[i].hweffect != NULL) {
  1156             ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
  1157             if (ret < 0) {
  1158                 return SDL_SetError
  1159                     ("Haptic: Error while trying to stop all playing effects.");
  1160             }
  1161         }
  1162     }
  1163     return 0;
  1164 }
  1165 
  1166 
  1167 #endif /* SDL_HAPTIC_LINUX */