src/haptic/darwin/SDL_syshaptic.c
author Edgar Simo <bobbens@gmail.com>
Tue, 15 Jul 2008 16:35:14 +0000
branchgsoc2008_force_feedback
changeset 2520 6aee9eb4fc6d
child 2521 7aa91c21ce5f
permissions -rw-r--r--
Adding initial darwin port of haptic subsystem - broken atm.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 2008 Edgar Simo
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #ifdef SDL_HAPTIC_IOKIT
    25 
    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/dawrin/SDL_sysjoystick_c.h"*/ /* For joystick hwdata */ 
    31 
    32 #include <ForceFeedback/ForceFeedback.h>
    33 #include <ForceFeedback/ForceFeedbackConstants.h>
    34 
    35 
    36 #define MAX_HAPTICS  32
    37 
    38 
    39 /*
    40  * List of available haptic devices.
    41  */
    42 static struct
    43 {
    44    io_service_t dev;
    45    SDL_Haptic *haptic;
    46 } SDL_hapticlist[MAX_HAPTICS];
    47 
    48 
    49 /*
    50  * Haptic system hardware data.
    51  */
    52 struct haptic_hwdata
    53 {
    54    FFDeviceObjectReference device; /* Hardware device. */
    55 };
    56 
    57 
    58 /*
    59  * Haptic system effect data.
    60  */
    61 struct haptic_hweffect
    62 {
    63    FFEffectObjectReference ref; /* Reference. */
    64    struct FFEFFECT effect; /* Hardware effect. */
    65 };
    66 
    67 
    68 /*
    69  * Initializes the haptic subsystem.
    70  */
    71 int
    72 SDL_SYS_HapticInit(void)
    73 {
    74    int numhaptics;
    75    IOReturn result;
    76    io_iterator_t iter;
    77    CFDictionaryRef match;
    78    io_sercive_t device;
    79 
    80    /* Get HID devices. */
    81    match = IOServiceMatching(kIOHIDDeviceKey);
    82    if (match == NULL) {
    83       SDL_SetError("Haptic: Failed to get IOServiceMatching.");
    84       return -1;
    85    }
    86 
    87    /* Now search I/O Registry for matching devices. */
    88    result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter);
    89    if (result != kIOReturnSuccess) {
    90       SDL_SetError("Haptic: Couldn't create a HID object iterator.");
    91       return -1;
    92    }
    93    /* IOServiceGetMatchingServices consumes dictionary. */
    94 
    95    numhaptics = 0;
    96    while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
    97 
    98       /* Check for force feedback. */
    99       if (FFIsForceFeedback(device) == FF_OK) {
   100          SDL_hapticlist[numhaptics].dev = device;
   101          SDL_hapticlist[numhaptics].haptic = NULL;
   102          numhaptics++;
   103       }
   104 
   105       /* Reached haptic limit. */
   106       if (numhaptics >= MAX_HAPTICS)
   107          break;
   108    }
   109    IOObjectRelease(iter);
   110 
   111    return numhaptics;
   112 }
   113 
   114 
   115 /*
   116  * Return the name of a haptic device, does not need to be opened.
   117  */
   118 const char *
   119 SDL_SYS_HapticName(int index)
   120 {
   121    return NULL;
   122 }
   123 
   124 
   125 #define FF_TEST(ff, s) \
   126 if (features.supportedEffects & ff) supported |= s
   127 /*
   128  * Gets supported features.
   129  */
   130 static unsigned int
   131 GetSupportedFeatures(FFDeviceObjectReference device,
   132                      int *neffects, int *nplaying)
   133 {
   134    HRESULT ret;
   135    FFCAPABILITIES features;
   136    unsigned int supported;
   137    Uint32 val;
   138 
   139    ret = FFDeviceGetForceFeedbackCapabilities(device, &features);
   140    if (ret != FF_OK) {
   141       SDL_SetError("Haptic: Unable to get device's supported features.");
   142       return 0;
   143    }
   144 
   145    supported = 0;
   146 
   147    /* Get maximum effects. */
   148    *neffects = features.storageCapacity;
   149    *nplaying = features.playbackCapacity;
   150 
   151    /* Test for effects. */
   152    FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT);
   153    FF_TEST(FFCAP_ET_RAMPFORCE,     SDL_HAPTIC_RAMP);
   154    FF_TEST(FFCAP_ET_SQUARE,        SDL_HAPTIC_SQUARE);
   155    FF_TEST(FFCAP_ET_SINE,          SDL_HAPTIC_SINE);
   156    FF_TEST(FFCAP_ET_TRIANGLE,      SDL_HAPTIC_TRIANGLE);
   157    FF_TEST(FFCAP_ET_SAWTOOTHUP,    SDL_HAPTIC_SAWTOOTHUP);
   158    FF_TEST(FFCAP_ET_SAWTOOTHDOWN,  SDL_HAPTIC_SAWTOOTHDOWN);
   159    FF_TEST(FFCAP_ET_SPRING,        SDL_HAPTIC_SPRING);
   160    FF_TEST(FFCAP_ET_DAMPER,        SDL_HAPTIC_DAMPER);
   161    FF_TEST(FFCAP_ET_INERTIA,       SDL_HAPTIC_INERTIA);
   162    FF_TEST(FFCAP_ET_FRICTION,      SDL_HAPTIC_FRICTION);
   163    FF_TEST(FFCAP_ET_CUSTOMFORCE,   SDL_HAPTIC_CUSTOM);
   164 
   165    /* Check if supports gain. */
   166    ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN,
   167                                           val, sizeof(val));
   168    if (ret == FF_OK) supported |= SDL_HAPTIC_GAIN;
   169    else if (ret != FFERR_UNSUPPORTED) {
   170       SDL_SetError("Haptic: Unable to get if device supports gain.");
   171       return 0;
   172    }
   173 
   174    /* Checks if supports autocenter. */
   175    ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFAUTOCENTER,
   176                                           val, sizeof(val));
   177    if (ret == FF_OK) supported |= SDL_HAPTIC_AUTOCENTER;
   178    else if (ret != FFERR_UNSUPPORTED) {
   179       SDL_SetError("Haptic: Unable to get if device supports autocenter.");
   180       return 0;
   181    }
   182 
   183    /* Always supported features. */
   184    supported |= SDL_HAPTIC_STATUS;
   185    return supported;
   186 }
   187 
   188 
   189 /*
   190  * Opens the haptic device from the file descriptor.
   191  */
   192 static int
   193 SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
   194 {
   195    /* Allocate the hwdata */
   196    haptic->hwdata = (struct haptic_hwdata *)
   197          SDL_malloc(sizeof(*haptic->hwdata));
   198    if (haptic->hwdata == NULL) {
   199       SDL_OutOfMemory();
   200       goto creat_err;
   201    }
   202    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
   203   
   204    /* Open the device */
   205    if (FFCreateDevice( &service, &haptic->hwdata->device ) != FF_OK) {
   206       SDL_SetError("Haptic: Unable to create device from service.");
   207       goto creat_err;
   208    }
   209 
   210    /* Get supported features. */
   211    haptic->supported = GetSupportedFeatures(haptic->hwdata->device,
   212                                             &haptic->neffects, &haptic->nplaying);
   213    if (haptic->supported == 0) { /* Error since device supports nothing. */
   214       goto open_err;
   215    }
   216    haptic->effects = (struct haptic_effect *)
   217          SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
   218    if (haptic->effects == NULL) {
   219       SDL_OutOfMemory();
   220       goto open_err;
   221    }
   222    /* Clear the memory */
   223    SDL_memset(haptic->effects, 0,
   224          sizeof(struct haptic_effect) * haptic->neffects);
   225    
   226    return 0;
   227    
   228    /* Error handling */
   229 open_err:
   230    FFReleaseDevice(haptic->hwdata->device);
   231 creat_err:
   232    if (haptic->hwdata != NULL) {
   233       free(haptic->hwdata);
   234       haptic->hwdata = NULL;                                              
   235    }
   236    return -1;
   237 
   238 }
   239 
   240 
   241 /*
   242  * Opens a haptic device for usage.
   243  */
   244 int
   245 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
   246 {
   247    return SDL_SYS_HapticOpenFromService(haptic,
   248                 SDL_hapticlist[haptic->index].device);
   249 }
   250 
   251 
   252 /*
   253  * Opens a haptic device from first mouse it finds for usage.
   254  */
   255 int
   256 SDL_SYS_HapticMouse(void)
   257 {
   258    return -1;
   259 }
   260 
   261 
   262 /*
   263  * Checks to see if a joystick has haptic features.
   264  */
   265 int
   266 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
   267 {
   268    return SDL_FALSE;
   269 }
   270 
   271 
   272 /*
   273  * Checks to see if the haptic device and joystick and in reality the same.
   274  */
   275 int
   276 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
   277 {
   278    if (SDL_strcmp(joystick->name,haptic->name)==0) {
   279       return 1;
   280    }
   281    return 0;
   282 }
   283 
   284 
   285 /*
   286  * Opens a SDL_Haptic from a SDL_Joystick.
   287  */
   288 int
   289 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   290 {
   291    return -1;
   292 }
   293 
   294 
   295 /*
   296  * Closes the haptic device.
   297  */
   298 void
   299 SDL_SYS_HapticClose(SDL_Haptic * haptic)
   300 {
   301    int i;
   302 
   303    if (haptic->hwdata) {
   304 
   305       /* Clean up */
   306       FFReleaseDevice(haptic->hwdata->device);
   307 
   308       /* Free */
   309       SDL_free(haptic->hwdata);
   310       haptic->hwdata = NULL;
   311       for (i=0; i<haptic->neffects; i++) {
   312          if (haptic->effects[i].hweffect != NULL)
   313             SDL_free(haptic->effects[i].hweffect->effect.lpvTypeSpecificParams);
   314       }
   315       SDL_free(haptic->effects);
   316       haptic->neffects = 0;
   317    }
   318 }
   319 
   320 
   321 /* 
   322  * Clean up after system specific haptic stuff
   323  */
   324 void
   325 SDL_SYS_HapticQuit(void)
   326 {
   327    int i;
   328 
   329    for (i=0; i < SDL_numhaptics; i++) {
   330       IOObjectRelease(SDL_hapticlist[i].dev);
   331       /* TODO free effects. */
   332    }
   333 }
   334 
   335 
   336 /*
   337  * Sets the direction.
   338  */
   339 static int
   340 SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int axes )
   341 {
   342    LONG *dir;
   343    dir = SDL_malloc( sizeof(LONG) * axes );
   344    if (dir == NULL) {
   345       SDL_OutOfMemory();
   346       return -1;
   347    }
   348    SDL_memset( dir, 0, sizeof(LONG) * axes );
   349    effect->rglDirection = dir;
   350 
   351    switch (dir->type) {
   352       case SDL_HAPTIC_POLAR:
   353          effect->dwFlags |= FFEFF_POLAR;
   354          dir[0] = dir->dir[0];
   355          return 0;
   356       case SDL_HAPTIC_CARTESIAN:
   357          effects->dwFlags |= FFEFF_CARTESIAN;
   358          dir[0] = dir->dir[0];
   359          dir[1] = dir->dir[1];
   360          dir[2] = dir->dir[2];
   361          return 0;
   362       case SDL_HAPTIC_SHPERICAL:
   363          effects->dwFlags |= FFEFF_SPHERICAL;
   364          dir[0] = dir->dir[0];
   365          dir[1] = dir->dir[1];
   366          dir[2] = dir->dir[2];
   367          return 0;
   368 
   369       default:
   370          SDL_SetError("Haptic: Unknown direction type.");
   371          return -1;
   372    }
   373 }
   374 
   375 #define CONVERT(x)   (((x)*10000) / 0xFFFF )
   376 /*
   377  * Creates the FFStruct
   378  */
   379 static int
   380 SDL_SYS_ToFFEFFECT( FFEFFECT * dest, SDL_HapticEffect * src )
   381 {
   382    FFCONSTANTFORCE *constant;
   383    FFPERIODIC *periodic;
   384    FFCONDITION *condition;
   385    FFRAMPFORCE *ramp;
   386    FFCUSTOMFORCE *custom;
   387    SDL_HapticConstant *hap_constant;
   388    SDL_HapticPeriodic *hap-periodic;
   389    SDL_HapticCondition *hap_condition;
   390    SDL_HapticRamp *hap_ramp;
   391 
   392    /* Set global stuff. */
   393    SDL_memset(dest, 0, sizeof(FFEFFECT));
   394    dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */
   395    dest->dwSamplePeriod = 0; /* Not used by us. */
   396    dest->dwGain = 10000; /* Gain is set globally, not locally. */
   397    dest->lpEnvelope.dwSize = sizeof(FFENVELOPE); /* Always should be this. */
   398 
   399    switch (src->type) {
   400       case SDL_HAPTIC_CONSTANT:
   401          hap_constant = &src->constant;
   402          constant = SDL_malloc( sizeof(FFCONSTANTFORCE) );
   403 
   404          /* Specifics */
   405          constant->lMagnitude = CONVERT(hap_constant->level);
   406          dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); 
   407          dest->lpvTypeSpecificParams = constant;
   408 
   409          /* Generics */
   410          dest->dwDuration = src->length * 1000; /* In microseconds. */
   411          dest->dwTriggerButton = FFJOFS_BUTTON(hap_constant->button);
   412          dest->dwTriggerRepeatInterval = hap_constant->interval;
   413          dest->dwStartDelay = src->delay * 1000; /* In microseconds. */
   414 
   415          /* Axes */
   416          dest->cAxes = 2; /* TODO handle */
   417          dest->rgdwAxes = 0;
   418 
   419          /* Direction. */
   420          if (SDL_SYS_SetDirection(dest, hap_constant->direction, dest->cAxes) < 0) {
   421             return -1;
   422          }
   423          
   424          /* Envelope */
   425          dest->lpEnvelope.dwAttackLevel = CONVERT(hap_constant->attack_level);
   426          dest->lpEnvelope.dwAttackTime = hap_constant->attack_length * 1000;
   427          dest->lpEnvelope.dwFadeLevel = CONVERT(hap_constant->fade_level);
   428          dest->lpEnvelope.dwFadeTime = hap_constant->fade_length * 1000;
   429 
   430          break;
   431 
   432          /* TODO finish */
   433 
   434       case SDL_HAPTIC_SINE:
   435       case SDL_HAPTIC_SQUARE:
   436       case SDL_HAPTIC_TRIANGLE:
   437       case SDL_HAPTIC_SAWTOOTHUP:
   438       case SDL_HAPTIC_SAWTOOTHDOWN:
   439          periodic = &src->periodic;
   440 
   441          break;
   442 
   443       case SDL_HAPTIC_SPRING:
   444       case SDL_HAPTIC_DAMPER:
   445       case SDL_HAPTIC_INERTIA:
   446       case SDL_HAPTIC_FRICTION:
   447          condition = &src->condition;
   448 
   449          break;
   450 
   451       case SDL_HAPTIC_RAMP:
   452          ramp = &src->ramp;
   453 
   454          break;
   455 
   456 
   457       default:
   458          SDL_SetError("Haptic: Unknown effect type.");
   459          return -1;
   460    }
   461 
   462    return 0;
   463 }
   464 
   465 
   466 /*
   467  * Gets the effect type from the generic SDL haptic effect wrapper.
   468  */
   469 CFUUIDRef SDL_SYS_HapticEffectType(struct haptic_effect * effect)
   470 {
   471    switch (effect->effect->type) {
   472       case SDL_HAPTIC_CONSTANT:
   473          return kFFEffectType_ConstantForce_ID;
   474 
   475       case SDL_HAPTIC_RAMP:
   476          return kFFEffectType_RampForce_ID;
   477 
   478       case SDL_HAPTIC_SQUARE:
   479          return kFFEffectType_Square_ID;
   480 
   481       case SDL_HAPTIC_SINE:
   482          return kFFEffectType_Sine_ID;
   483 
   484       case SDL_HAPTIC_TRIANGLE;
   485          return kFFEffectType_Triangle_ID;
   486 
   487       case SDL_HAPTIC_SAWTOOTHUP:
   488          return kFFEffectType_SawtoothUp_ID;
   489 
   490       case SDL_HAPTIC_SAWTOOTHDOWN:
   491          return kFFEffectType_SawtoothDown_ID;
   492 
   493       case SDL_HAPTIC_SPRING:
   494          return kFFEffectType_Spring_ID;
   495 
   496       case SDL_HAPTIC_DAMPER:
   497          return kFFEffectType_Damper_ID;
   498 
   499       case SDL_HAPTIC_INERTIA:
   500          return kFFEffectType_Inertia_ID;
   501 
   502       case SDL_HAPTIC_FRICTION:
   503          return kFFEffectType_Friction_ID;
   504 
   505       case SDL_HAPTIC_CUSTOM:
   506          return kFFEffectType_CustomForce_ID;
   507 
   508       default:
   509          SDL_SetError("Haptic: Unknown effect type.");
   510          return NULL;
   511    }
   512 }
   513 
   514 
   515 /*
   516  * Creates a new haptic effect.
   517  */
   518 int
   519 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   520       SDL_HapticEffect * base)
   521 {
   522    HRESULT ret;
   523    CFUUIDRef type;
   524 
   525    /* Alloc the effect. */
   526    effect->hweffect = (struct haptic_hweffect *)
   527          SDL_malloc(sizeof(struct haptic_hweffect));
   528    if (effect->hweffect == NULL) {
   529       SDL_OutOfMemory();
   530       return -1;
   531    }
   532 
   533    /* Get the type. */
   534    type = SDL_SYS_HapticEffectType(effect);
   535    if (type == NULL) {
   536       SDL_free(effect->hweffect);
   537       effect->hweffect = NULL;
   538       return -1;
   539    }
   540 
   541    /* Get the effect. */
   542    if (SDL_SYS_ToFFEFFECT( &effect->hweffect->effect, &haptic_effect->effect ) < 0) {
   543       /* TODO cleanup alloced stuff. */
   544       return -1;
   545    }
   546 
   547    ret = FFDeviceCreateEffect( haptic->hwdata->device, type,
   548          &effect->hweffect->effect, &effect->hweffect->ref );
   549 }
   550 
   551 
   552 /*
   553  * Updates an effect.
   554  */
   555 int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
   556       struct haptic_effect * effect, SDL_HapticEffect * data)
   557 {
   558    /* TODO */
   559    return -1;
   560 }
   561 
   562 
   563 /*
   564  * Runs an effect.
   565  */
   566 int
   567 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect,
   568                         Uint32 iterations)
   569 {
   570    HRESULT ret;
   571    Uint32 iter;
   572 
   573    /* Check if it's infinite. */
   574    if (iterations == SDL_HAPTIC_INFINITY) {
   575       iter = INFINITE;
   576    }
   577    else
   578       iter = iterations;
   579 
   580    /* Run the effect. */
   581    ret = FFEffectStart(effect->hweffect->ref, iter, 0);
   582    if (ret != FF_OK) {
   583       SDL_SetError("Haptic: Unable to run the effect.");
   584       return -1;
   585    }
   586 
   587    return 0;
   588 }
   589 
   590 
   591 /*
   592  * Stops an effect.
   593  */
   594 int
   595 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
   596 {
   597    HRESULT ret;
   598 
   599    ret = FFEffectStop(effect->hweffect->ref);
   600    if (ret != FF_OK) {
   601       SDL_SetError("Haptic: Unable to stop the effect.");
   602       return -1;
   603    }
   604 
   605    return 0;
   606 }
   607 
   608 
   609 /*
   610  * Frees the effect.
   611  */
   612 void
   613 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect)
   614 {
   615    HRESULT ret;
   616 
   617    ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref);
   618    if (ret != FF_OK) {
   619       SDL_SetError("Haptic: Error removing the effect from the device.");
   620    }
   621    SDL_free(effect->hweffect->effect.lpvTypeSpecificParams);
   622    effect->hweffect->effect.lpvTypeSpecificParams = NULL;
   623    SDL_free(effect->hweffect);
   624    effect->hweffect = NULL;
   625 }
   626 
   627 
   628 /*
   629  * Gets the status of a haptic effect.
   630  */
   631 int
   632 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect)
   633 {
   634    HRESULT ret;
   635    FFEffectStatusFlag status;
   636 
   637    ret = FFEffectGetEffectStatus(effect->hweffect.ref, &status);
   638    if (ret != FF_OK) {
   639       SDL_SetError("Haptic: Unable to get effect status.");
   640       return -1;
   641    }
   642 
   643    if (status == 0) return SDL_FALSE;
   644    return SDL_TRUE; /* Assume it's playing or emulated. */
   645 }
   646 
   647 
   648 /*
   649  * Sets the gain.
   650  */
   651 int
   652 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
   653 {
   654    HRESULT ret;
   655    Uint32 val;
   656 
   657    val = gain * 100; /* Mac OS X uses 0 to 10,000 */
   658    ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val);
   659    if (ret != FF_OK) {
   660       SDL_SetError("Haptic: Error setting gain.");
   661       return -1;
   662    }
   663 
   664    return 0;
   665 }
   666 
   667 
   668 /*
   669  * Sets the autocentering.
   670  */
   671 int
   672 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   673 {
   674    HRESULT ret;
   675    Uint32 val;
   676 
   677    /* Mac OS X only has 0 (off) and 1 (on) */
   678    if (autocenter == 0) val = 0;
   679    else val = 1;
   680 
   681    ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device,
   682                FFPROP_FFAUTOCENTER, &val);
   683    if (ret != FF_OK) {
   684       SDL_SetError("Haptic: Error setting autocenter.");
   685       return -1;
   686    }
   687   
   688    return 0;
   689 
   690 }
   691 
   692 
   693 #endif /* SDL_HAPTIC_LINUX */