src/haptic/linux/SDL_syshaptic.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 16 Feb 2020 00:08:36 -0800
changeset 13532 fab2cd7dee5b
parent 13422 fd6a12de91c7
permissions -rw-r--r--
Further improvements for bug 4128 - CMAKE: Generated target import file contains incorrect include path

Mohamed

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