src/haptic/linux/SDL_syshaptic.c
author Ryan C. Gordon
Sat, 31 Oct 2020 11:32:40 -0400
changeset 14210 2b1cce20e59b
parent 13864 3aa34ecfeb63
permissions -rw-r--r--
coreaudio: Remove unnecessary include of CoreServices.h
     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 #ifdef SDL_JOYSTICK_LINUX
   516     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
   517         return SDL_FALSE;
   518     }
   519     if (EV_IsHaptic(joystick->hwdata->fd)) {
   520         return SDL_TRUE;
   521     }
   522 #endif
   523     return SDL_FALSE;
   524 }
   525 
   526 
   527 /*
   528  * Checks to see if the haptic device and joystick are in reality the same.
   529  */
   530 int
   531 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   532 {
   533 #ifdef SDL_JOYSTICK_LINUX
   534     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
   535         return 0;
   536     }
   537     /* We are assuming Linux is using evdev which should trump the old
   538      * joystick methods. */
   539     if (SDL_strcmp(joystick->hwdata->fname, haptic->hwdata->fname) == 0) {
   540         return 1;
   541     }
   542 #endif
   543     return 0;
   544 }
   545 
   546 
   547 /*
   548  * Opens a SDL_Haptic from a SDL_Joystick.
   549  */
   550 int
   551 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   552 {
   553 #ifdef SDL_JOYSTICK_LINUX
   554     int device_index = 0;
   555     int fd;
   556     int ret;
   557     SDL_hapticlist_item *item;
   558     
   559     if (joystick->driver != &SDL_LINUX_JoystickDriver) {
   560         return -1;
   561     }
   562     /* Find the joystick in the haptic list. */
   563     for (item = SDL_hapticlist; item; item = item->next) {
   564         if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
   565             break;
   566         }
   567         ++device_index;
   568     }
   569     haptic->index = device_index;
   570 
   571     if (device_index >= MAX_HAPTICS) {
   572         return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
   573     }
   574 
   575     fd = open(joystick->hwdata->fname, O_RDWR, 0);
   576     if (fd < 0) {
   577         return SDL_SetError("Haptic: Unable to open %s: %s",
   578                             joystick->hwdata->fname, strerror(errno));
   579     }
   580     ret = SDL_SYS_HapticOpenFromFD(haptic, fd); /* Already closes on error. */
   581     if (ret < 0) {
   582         return -1;
   583     }
   584 
   585     haptic->hwdata->fname = SDL_strdup( joystick->hwdata->fname );
   586 
   587     return 0;
   588 #else
   589     return -1;
   590 #endif
   591 }
   592 
   593 
   594 /*
   595  * Closes the haptic device.
   596  */
   597 void
   598 SDL_SYS_HapticClose(SDL_Haptic * haptic)
   599 {
   600     if (haptic->hwdata) {
   601 
   602         /* Free effects. */
   603         SDL_free(haptic->effects);
   604         haptic->effects = NULL;
   605         haptic->neffects = 0;
   606 
   607         /* Clean up */
   608         close(haptic->hwdata->fd);
   609 
   610         /* Free */
   611         SDL_free(haptic->hwdata->fname);
   612         SDL_free(haptic->hwdata);
   613         haptic->hwdata = NULL;
   614     }
   615 
   616     /* Clear the rest. */
   617     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   618 }
   619 
   620 
   621 /*
   622  * Clean up after system specific haptic stuff
   623  */
   624 void
   625 SDL_SYS_HapticQuit(void)
   626 {
   627     SDL_hapticlist_item *item = NULL;
   628     SDL_hapticlist_item *next = NULL;
   629 
   630     for (item = SDL_hapticlist; item; item = next) {
   631         next = item->next;
   632         /* Opened and not closed haptics are leaked, this is on purpose.
   633          * Close your haptic devices after usage. */
   634         SDL_free(item->fname);
   635         SDL_free(item);
   636     }
   637 
   638 #if SDL_USE_LIBUDEV
   639     SDL_UDEV_DelCallback(haptic_udev_callback);
   640     SDL_UDEV_Quit();
   641 #endif /* SDL_USE_LIBUDEV */
   642 
   643     numhaptics = 0;
   644     SDL_hapticlist = NULL;
   645     SDL_hapticlist_tail = NULL;
   646 }
   647 
   648 
   649 /*
   650  * Converts an SDL button to a ff_trigger button.
   651  */
   652 static Uint16
   653 SDL_SYS_ToButton(Uint16 button)
   654 {
   655     Uint16 ff_button;
   656 
   657     ff_button = 0;
   658 
   659     /*
   660      * Not sure what the proper syntax is because this actually isn't implemented
   661      * in the current kernel from what I've seen (2.6.26).
   662      */
   663     if (button != 0) {
   664         ff_button = BTN_GAMEPAD + button - 1;
   665     }
   666 
   667     return ff_button;
   668 }
   669 
   670 
   671 /*
   672  * Initializes the ff_effect usable direction from a SDL_HapticDirection.
   673  */
   674 static int
   675 SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
   676 {
   677     Uint32 tmp;
   678 
   679     switch (src->type) {
   680     case SDL_HAPTIC_POLAR:
   681         /* Linux directions start from south.
   682                 (and range from 0 to 0xFFFF)
   683                    Quoting include/linux/input.h, line 926:
   684                    Direction of the effect is encoded as follows:
   685                         0 deg -> 0x0000 (down)
   686                         90 deg -> 0x4000 (left)
   687                         180 deg -> 0x8000 (up)
   688                         270 deg -> 0xC000 (right)
   689                    The force pulls into the direction specified by Linux directions,
   690                    i.e. the opposite convention of SDL directions.
   691                     */
   692         tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   693         *dest = (Uint16) tmp;
   694         break;
   695 
   696     case SDL_HAPTIC_SPHERICAL:
   697             /*
   698                 We convert to polar, because that's the only supported direction on Linux.
   699                 The first value of a spherical direction is practically the same as a
   700                 Polar direction, except that we have to add 90 degrees. It is the angle
   701                 from EAST {1,0} towards SOUTH {0,1}.
   702                 --> add 9000
   703                 --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   704             */
   705             tmp = ((src->dir[0]) + 9000) % 36000;    /* Convert to polars */
   706         tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   707         *dest = (Uint16) tmp;
   708         break;
   709 
   710     case SDL_HAPTIC_CARTESIAN:
   711         if (!src->dir[1])
   712             *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000);
   713         else if (!src->dir[0])
   714             *dest = (src->dir[1] >= 0 ? 0x8000 : 0);
   715         else {
   716             float f = SDL_atan2(src->dir[1], src->dir[0]);    /* Ideally we'd use fixed point math instead of floats... */
   717                     /*
   718                       atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
   719                        - Y-axis-value is the second coordinate (from center to SOUTH)
   720                        - X-axis-value is the first coordinate (from center to EAST)
   721                         We add 36000, because atan2 also returns negative values. Then we practically
   722                         have the first spherical value. Therefore we proceed as in case
   723                         SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
   724                       --> add 45000 in total
   725                       --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
   726                     */
   727                 tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
   728             tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
   729             *dest = (Uint16) tmp;
   730         }
   731         break;
   732     case SDL_HAPTIC_STEERING_AXIS:
   733         *dest = 0x4000;
   734         break;
   735     default:
   736         return SDL_SetError("Haptic: Unsupported direction type.");
   737     }
   738 
   739     return 0;
   740 }
   741 
   742 
   743 #define  CLAMP(x)    (((x) > 32767) ? 32767 : x)
   744 /*
   745  * Initializes the Linux effect struct from a haptic_effect.
   746  * Values above 32767 (for unsigned) are unspecified so we must clamp.
   747  */
   748 static int
   749 SDL_SYS_ToFFEffect(struct ff_effect *dest, SDL_HapticEffect * src)
   750 {
   751     SDL_HapticConstant *constant;
   752     SDL_HapticPeriodic *periodic;
   753     SDL_HapticCondition *condition;
   754     SDL_HapticRamp *ramp;
   755     SDL_HapticLeftRight *leftright;
   756 
   757     /* Clear up */
   758     SDL_memset(dest, 0, sizeof(struct ff_effect));
   759 
   760     switch (src->type) {
   761     case SDL_HAPTIC_CONSTANT:
   762         constant = &src->constant;
   763 
   764         /* Header */
   765         dest->type = FF_CONSTANT;
   766         if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1)
   767             return -1;
   768 
   769         /* Replay */
   770         dest->replay.length = (constant->length == SDL_HAPTIC_INFINITY) ?
   771             0 : CLAMP(constant->length);
   772         dest->replay.delay = CLAMP(constant->delay);
   773 
   774         /* Trigger */
   775         dest->trigger.button = SDL_SYS_ToButton(constant->button);
   776         dest->trigger.interval = CLAMP(constant->interval);
   777 
   778         /* Constant */
   779         dest->u.constant.level = constant->level;
   780 
   781         /* Envelope */
   782         dest->u.constant.envelope.attack_length =
   783             CLAMP(constant->attack_length);
   784         dest->u.constant.envelope.attack_level =
   785             CLAMP(constant->attack_level);
   786         dest->u.constant.envelope.fade_length = CLAMP(constant->fade_length);
   787         dest->u.constant.envelope.fade_level = CLAMP(constant->fade_level);
   788 
   789         break;
   790 
   791     case SDL_HAPTIC_SINE:
   792     /* !!! FIXME: put this back when we have more bits in 2.1 */
   793     /* case SDL_HAPTIC_SQUARE: */
   794     case SDL_HAPTIC_TRIANGLE:
   795     case SDL_HAPTIC_SAWTOOTHUP:
   796     case SDL_HAPTIC_SAWTOOTHDOWN:
   797         periodic = &src->periodic;
   798 
   799         /* Header */
   800         dest->type = FF_PERIODIC;
   801         if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1)
   802             return -1;
   803 
   804         /* Replay */
   805         dest->replay.length = (periodic->length == SDL_HAPTIC_INFINITY) ?
   806             0 : CLAMP(periodic->length);
   807         dest->replay.delay = CLAMP(periodic->delay);
   808 
   809         /* Trigger */
   810         dest->trigger.button = SDL_SYS_ToButton(periodic->button);
   811         dest->trigger.interval = CLAMP(periodic->interval);
   812 
   813         /* Periodic */
   814         if (periodic->type == SDL_HAPTIC_SINE)
   815             dest->u.periodic.waveform = FF_SINE;
   816         /* !!! FIXME: put this back when we have more bits in 2.1 */
   817         /* else if (periodic->type == SDL_HAPTIC_SQUARE)
   818             dest->u.periodic.waveform = FF_SQUARE; */
   819         else if (periodic->type == SDL_HAPTIC_TRIANGLE)
   820             dest->u.periodic.waveform = FF_TRIANGLE;
   821         else if (periodic->type == SDL_HAPTIC_SAWTOOTHUP)
   822             dest->u.periodic.waveform = FF_SAW_UP;
   823         else if (periodic->type == SDL_HAPTIC_SAWTOOTHDOWN)
   824             dest->u.periodic.waveform = FF_SAW_DOWN;
   825         dest->u.periodic.period = CLAMP(periodic->period);
   826         dest->u.periodic.magnitude = periodic->magnitude;
   827         dest->u.periodic.offset = periodic->offset;
   828         /* Linux phase is defined in interval "[0x0000, 0x10000[", corresponds with "[0deg, 360deg[" phase shift. */
   829         dest->u.periodic.phase = ((Uint32)periodic->phase * 0x10000U) / 36000;
   830 
   831         /* Envelope */
   832         dest->u.periodic.envelope.attack_length =
   833             CLAMP(periodic->attack_length);
   834         dest->u.periodic.envelope.attack_level =
   835             CLAMP(periodic->attack_level);
   836         dest->u.periodic.envelope.fade_length = CLAMP(periodic->fade_length);
   837         dest->u.periodic.envelope.fade_level = CLAMP(periodic->fade_level);
   838 
   839         break;
   840 
   841     case SDL_HAPTIC_SPRING:
   842     case SDL_HAPTIC_DAMPER:
   843     case SDL_HAPTIC_INERTIA:
   844     case SDL_HAPTIC_FRICTION:
   845         condition = &src->condition;
   846 
   847         /* Header */
   848         if (condition->type == SDL_HAPTIC_SPRING)
   849             dest->type = FF_SPRING;
   850         else if (condition->type == SDL_HAPTIC_DAMPER)
   851             dest->type = FF_DAMPER;
   852         else if (condition->type == SDL_HAPTIC_INERTIA)
   853             dest->type = FF_INERTIA;
   854         else if (condition->type == SDL_HAPTIC_FRICTION)
   855             dest->type = FF_FRICTION;
   856         dest->direction = 0;    /* Handled by the condition-specifics. */
   857 
   858         /* Replay */
   859         dest->replay.length = (condition->length == SDL_HAPTIC_INFINITY) ?
   860             0 : CLAMP(condition->length);
   861         dest->replay.delay = CLAMP(condition->delay);
   862 
   863         /* Trigger */
   864         dest->trigger.button = SDL_SYS_ToButton(condition->button);
   865         dest->trigger.interval = CLAMP(condition->interval);
   866 
   867         /* Condition */
   868         /* X axis */
   869         dest->u.condition[0].right_saturation = condition->right_sat[0];
   870         dest->u.condition[0].left_saturation = condition->left_sat[0];
   871         dest->u.condition[0].right_coeff = condition->right_coeff[0];
   872         dest->u.condition[0].left_coeff = condition->left_coeff[0];
   873         dest->u.condition[0].deadband = condition->deadband[0];
   874         dest->u.condition[0].center = condition->center[0];
   875         /* Y axis */
   876         dest->u.condition[1].right_saturation = condition->right_sat[1];
   877         dest->u.condition[1].left_saturation = condition->left_sat[1];
   878         dest->u.condition[1].right_coeff = condition->right_coeff[1];
   879         dest->u.condition[1].left_coeff = condition->left_coeff[1];
   880         dest->u.condition[1].deadband = condition->deadband[1];
   881         dest->u.condition[1].center = condition->center[1];
   882 
   883         /*
   884          * There is no envelope in the linux force feedback api for conditions.
   885          */
   886 
   887         break;
   888 
   889     case SDL_HAPTIC_RAMP:
   890         ramp = &src->ramp;
   891 
   892         /* Header */
   893         dest->type = FF_RAMP;
   894         if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1)
   895             return -1;
   896 
   897         /* Replay */
   898         dest->replay.length = (ramp->length == SDL_HAPTIC_INFINITY) ?
   899             0 : CLAMP(ramp->length);
   900         dest->replay.delay = CLAMP(ramp->delay);
   901 
   902         /* Trigger */
   903         dest->trigger.button = SDL_SYS_ToButton(ramp->button);
   904         dest->trigger.interval = CLAMP(ramp->interval);
   905 
   906         /* Ramp */
   907         dest->u.ramp.start_level = ramp->start;
   908         dest->u.ramp.end_level = ramp->end;
   909 
   910         /* Envelope */
   911         dest->u.ramp.envelope.attack_length = CLAMP(ramp->attack_length);
   912         dest->u.ramp.envelope.attack_level = CLAMP(ramp->attack_level);
   913         dest->u.ramp.envelope.fade_length = CLAMP(ramp->fade_length);
   914         dest->u.ramp.envelope.fade_level = CLAMP(ramp->fade_level);
   915 
   916         break;
   917 
   918     case SDL_HAPTIC_LEFTRIGHT:
   919         leftright = &src->leftright;
   920 
   921         /* Header */
   922         dest->type = FF_RUMBLE;
   923         dest->direction = 0;
   924 
   925         /* Replay */
   926         dest->replay.length = (leftright->length == SDL_HAPTIC_INFINITY) ?
   927             0 : CLAMP(leftright->length);
   928 
   929         /* Trigger */
   930         dest->trigger.button = 0;
   931         dest->trigger.interval = 0;
   932 
   933         /* Rumble (Linux expects 0-65535, so multiply by 2) */
   934         dest->u.rumble.strong_magnitude = CLAMP(leftright->large_magnitude) * 2;
   935         dest->u.rumble.weak_magnitude = CLAMP(leftright->small_magnitude) * 2;
   936 
   937         break;
   938 
   939 
   940     default:
   941         return SDL_SetError("Haptic: Unknown effect type.");
   942     }
   943 
   944     return 0;
   945 }
   946 
   947 
   948 /*
   949  * Creates a new haptic effect.
   950  */
   951 int
   952 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
   953                         SDL_HapticEffect * base)
   954 {
   955     struct ff_effect *linux_effect;
   956 
   957     /* Allocate the hardware effect */
   958     effect->hweffect = (struct haptic_hweffect *)
   959         SDL_malloc(sizeof(struct haptic_hweffect));
   960     if (effect->hweffect == NULL) {
   961         return SDL_OutOfMemory();
   962     }
   963 
   964     /* Prepare the ff_effect */
   965     linux_effect = &effect->hweffect->effect;
   966     if (SDL_SYS_ToFFEffect(linux_effect, base) != 0) {
   967         goto new_effect_err;
   968     }
   969     linux_effect->id = -1;      /* Have the kernel give it an id */
   970 
   971     /* Upload the effect */
   972     if (ioctl(haptic->hwdata->fd, EVIOCSFF, linux_effect) < 0) {
   973         SDL_SetError("Haptic: Error uploading effect to the device: %s",
   974                      strerror(errno));
   975         goto new_effect_err;
   976     }
   977 
   978     return 0;
   979 
   980   new_effect_err:
   981     SDL_free(effect->hweffect);
   982     effect->hweffect = NULL;
   983     return -1;
   984 }
   985 
   986 
   987 /*
   988  * Updates an effect.
   989  *
   990  * Note: Dynamically updating the direction can in some cases force
   991  * the effect to restart and run once.
   992  */
   993 int
   994 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   995                            struct haptic_effect *effect,
   996                            SDL_HapticEffect * data)
   997 {
   998     struct ff_effect linux_effect;
   999 
  1000     /* Create the new effect */
  1001     if (SDL_SYS_ToFFEffect(&linux_effect, data) != 0) {
  1002         return -1;
  1003     }
  1004     linux_effect.id = effect->hweffect->effect.id;
  1005 
  1006     /* See if it can be uploaded. */
  1007     if (ioctl(haptic->hwdata->fd, EVIOCSFF, &linux_effect) < 0) {
  1008         return SDL_SetError("Haptic: Error updating the effect: %s",
  1009                             strerror(errno));
  1010     }
  1011 
  1012     /* Copy the new effect into memory. */
  1013     SDL_memcpy(&effect->hweffect->effect, &linux_effect,
  1014                sizeof(struct ff_effect));
  1015 
  1016     return effect->hweffect->effect.id;
  1017 }
  1018 
  1019 
  1020 /*
  1021  * Runs an effect.
  1022  */
  1023 int
  1024 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
  1025                         Uint32 iterations)
  1026 {
  1027     struct input_event run;
  1028 
  1029     /* Prepare to run the effect */
  1030     run.type = EV_FF;
  1031     run.code = effect->hweffect->effect.id;
  1032     /* We don't actually have infinity here, so we just do INT_MAX which is pretty damn close. */
  1033     run.value = (iterations > INT_MAX) ? INT_MAX : iterations;
  1034 
  1035     if (write(haptic->hwdata->fd, (const void *) &run, sizeof(run)) < 0) {
  1036         return SDL_SetError("Haptic: Unable to run the effect: %s", strerror(errno));
  1037     }
  1038 
  1039     return 0;
  1040 }
  1041 
  1042 
  1043 /*
  1044  * Stops an effect.
  1045  */
  1046 int
  1047 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1048 {
  1049     struct input_event stop;
  1050 
  1051     stop.type = EV_FF;
  1052     stop.code = effect->hweffect->effect.id;
  1053     stop.value = 0;
  1054 
  1055     if (write(haptic->hwdata->fd, (const void *) &stop, sizeof(stop)) < 0) {
  1056         return SDL_SetError("Haptic: Unable to stop the effect: %s",
  1057                             strerror(errno));
  1058     }
  1059 
  1060     return 0;
  1061 }
  1062 
  1063 
  1064 /*
  1065  * Frees the effect.
  1066  */
  1067 void
  1068 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
  1069 {
  1070     if (ioctl(haptic->hwdata->fd, EVIOCRMFF, effect->hweffect->effect.id) < 0) {
  1071         SDL_SetError("Haptic: Error removing the effect from the device: %s",
  1072                      strerror(errno));
  1073     }
  1074     SDL_free(effect->hweffect);
  1075     effect->hweffect = NULL;
  1076 }
  1077 
  1078 
  1079 /*
  1080  * Gets the status of a haptic effect.
  1081  */
  1082 int
  1083 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
  1084                               struct haptic_effect *effect)
  1085 {
  1086 #if 0                           /* Not supported atm. */
  1087     struct input_event ie;
  1088 
  1089     ie.type = EV_FF;
  1090     ie.type = EV_FF_STATUS;
  1091     ie.code = effect->hweffect->effect.id;
  1092 
  1093     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1094         return SDL_SetError("Haptic: Error getting device status.");
  1095     }
  1096 
  1097     return 0;
  1098 #endif
  1099 
  1100     return -1;
  1101 }
  1102 
  1103 
  1104 /*
  1105  * Sets the gain.
  1106  */
  1107 int
  1108 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
  1109 {
  1110     struct input_event ie;
  1111 
  1112     ie.type = EV_FF;
  1113     ie.code = FF_GAIN;
  1114     ie.value = (0xFFFFUL * gain) / 100;
  1115 
  1116     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1117         return SDL_SetError("Haptic: Error setting gain: %s", strerror(errno));
  1118     }
  1119 
  1120     return 0;
  1121 }
  1122 
  1123 
  1124 /*
  1125  * Sets the autocentering.
  1126  */
  1127 int
  1128 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
  1129 {
  1130     struct input_event ie;
  1131 
  1132     ie.type = EV_FF;
  1133     ie.code = FF_AUTOCENTER;
  1134     ie.value = (0xFFFFUL * autocenter) / 100;
  1135 
  1136     if (write(haptic->hwdata->fd, &ie, sizeof(ie)) < 0) {
  1137         return SDL_SetError("Haptic: Error setting autocenter: %s", strerror(errno));
  1138     }
  1139 
  1140     return 0;
  1141 }
  1142 
  1143 
  1144 /*
  1145  * Pausing is not supported atm by linux.
  1146  */
  1147 int
  1148 SDL_SYS_HapticPause(SDL_Haptic * haptic)
  1149 {
  1150     return -1;
  1151 }
  1152 
  1153 
  1154 /*
  1155  * Unpausing is not supported atm by linux.
  1156  */
  1157 int
  1158 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
  1159 {
  1160     return -1;
  1161 }
  1162 
  1163 
  1164 /*
  1165  * Stops all the currently playing effects.
  1166  */
  1167 int
  1168 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
  1169 {
  1170     int i, ret;
  1171 
  1172     /* Linux does not support this natively so we have to loop. */
  1173     for (i = 0; i < haptic->neffects; i++) {
  1174         if (haptic->effects[i].hweffect != NULL) {
  1175             ret = SDL_SYS_HapticStopEffect(haptic, &haptic->effects[i]);
  1176             if (ret < 0) {
  1177                 return SDL_SetError
  1178                     ("Haptic: Error while trying to stop all playing effects.");
  1179             }
  1180         }
  1181     }
  1182     return 0;
  1183 }
  1184 
  1185 #endif /* SDL_HAPTIC_LINUX */
  1186 
  1187 /* vi: set ts=4 sw=4 expandtab: */