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

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