Rework haptic backend to properly support hotplugging of haptic devices.
authorEdward Rudd <urkle@outoforder.cc>
Tue, 04 Feb 2014 15:44:09 -0500
changeset 81703b7bb407fcf7
parent 8169 663ba61243ff
child 8171 e4f51a5bc1ed
Rework haptic backend to properly support hotplugging of haptic devices.

* currently only linux backend updated.
src/haptic/SDL_haptic.c
src/haptic/SDL_syshaptic.h
src/haptic/linux/SDL_syshaptic.c
     1.1 --- a/src/haptic/SDL_haptic.c	Tue Feb 04 15:40:51 2014 -0500
     1.2 +++ b/src/haptic/SDL_haptic.c	Tue Feb 04 15:44:09 2014 -0500
     1.3 @@ -25,8 +25,7 @@
     1.4  #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
     1.5  #include "SDL_assert.h"
     1.6  
     1.7 -Uint8 SDL_numhaptics = 0;
     1.8 -SDL_Haptic **SDL_haptics = NULL;
     1.9 +SDL_Haptic *SDL_haptics = NULL;
    1.10  
    1.11  
    1.12  /*
    1.13 @@ -35,20 +34,10 @@
    1.14  int
    1.15  SDL_HapticInit(void)
    1.16  {
    1.17 -    int arraylen;
    1.18      int status;
    1.19  
    1.20 -    SDL_numhaptics = 0;
    1.21      status = SDL_SYS_HapticInit();
    1.22      if (status >= 0) {
    1.23 -        arraylen = (status + 1) * sizeof(*SDL_haptics);
    1.24 -        SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
    1.25 -        if (SDL_haptics == NULL) {      /* Out of memory. */
    1.26 -            SDL_numhaptics = 0;
    1.27 -        } else {
    1.28 -            SDL_memset(SDL_haptics, 0, arraylen);
    1.29 -            SDL_numhaptics = status;
    1.30 -        }
    1.31          status = 0;
    1.32      }
    1.33  
    1.34 @@ -62,16 +51,19 @@
    1.35  static int
    1.36  ValidHaptic(SDL_Haptic * haptic)
    1.37  {
    1.38 -    int i;
    1.39      int valid;
    1.40 +    SDL_Haptic *hapticlist;
    1.41  
    1.42      valid = 0;
    1.43      if (haptic != NULL) {
    1.44 -        for (i = 0; i < SDL_numhaptics; i++) {
    1.45 -            if (SDL_haptics[i] == haptic) {
    1.46 +        hapticlist = SDL_haptics;
    1.47 +        while ( hapticlist )
    1.48 +        {
    1.49 +            if (hapticlist == haptic) {
    1.50                  valid = 1;
    1.51                  break;
    1.52              }
    1.53 +            hapticlist = hapticlist->next;
    1.54          }
    1.55      }
    1.56  
    1.57 @@ -90,7 +82,7 @@
    1.58  int
    1.59  SDL_NumHaptics(void)
    1.60  {
    1.61 -    return SDL_numhaptics;
    1.62 +    return SDL_SYS_NumHaptics();
    1.63  }
    1.64  
    1.65  
    1.66 @@ -100,9 +92,9 @@
    1.67  const char *
    1.68  SDL_HapticName(int device_index)
    1.69  {
    1.70 -    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
    1.71 +    if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
    1.72          SDL_SetError("Haptic: There are %d haptic devices available",
    1.73 -                     SDL_numhaptics);
    1.74 +                     SDL_NumHaptics());
    1.75          return NULL;
    1.76      }
    1.77      return SDL_SYS_HapticName(device_index);
    1.78 @@ -115,22 +107,27 @@
    1.79  SDL_Haptic *
    1.80  SDL_HapticOpen(int device_index)
    1.81  {
    1.82 -    int i;
    1.83      SDL_Haptic *haptic;
    1.84 +    SDL_Haptic *hapticlist;
    1.85  
    1.86 -    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
    1.87 +    if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
    1.88          SDL_SetError("Haptic: There are %d haptic devices available",
    1.89 -                     SDL_numhaptics);
    1.90 +                     SDL_NumHaptics());
    1.91          return NULL;
    1.92      }
    1.93  
    1.94 -    /* If the haptic is already open, return it */
    1.95 -    for (i = 0; SDL_haptics[i]; i++) {
    1.96 -        if (device_index == SDL_haptics[i]->index) {
    1.97 -            haptic = SDL_haptics[i];
    1.98 +    hapticlist = SDL_haptics;
    1.99 +    /* If the haptic is already open, return it
   1.100 +    * TODO: Should we create haptic instance IDs like the Joystick API?
   1.101 +    */
   1.102 +    while ( hapticlist )
   1.103 +    {
   1.104 +        if (device_index == hapticlist->index) {
   1.105 +            haptic = hapticlist;
   1.106              ++haptic->ref_count;
   1.107              return haptic;
   1.108          }
   1.109 +        hapticlist = hapticlist->next;
   1.110      }
   1.111  
   1.112      /* Create the haptic device */
   1.113 @@ -150,15 +147,10 @@
   1.114      }
   1.115  
   1.116      /* Add haptic to list */
   1.117 -    for (i = 0; SDL_haptics[i]; i++)
   1.118 -        /* Skip to next haptic */ ;
   1.119 -    if (i >= SDL_numhaptics) {
   1.120 -        SDL_free(haptic);
   1.121 -        SDL_SetError("Haptic: Trying to add device past the number originally detected");
   1.122 -        return NULL;
   1.123 -    }
   1.124 -    SDL_haptics[i] = haptic;
   1.125      ++haptic->ref_count;
   1.126 +    /* Link the haptic in the list */
   1.127 +    haptic->next = SDL_haptics;
   1.128 +    SDL_haptics = haptic;
   1.129  
   1.130      /* Disable autocenter and set gain to max. */
   1.131      if (haptic->supported & SDL_HAPTIC_GAIN)
   1.132 @@ -176,21 +168,26 @@
   1.133  int
   1.134  SDL_HapticOpened(int device_index)
   1.135  {
   1.136 -    int i, opened;
   1.137 +    int opened;
   1.138 +    SDL_Haptic *hapticlist;
   1.139  
   1.140      /* Make sure it's valid. */
   1.141 -    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   1.142 +    if ((device_index < 0) || (device_index >= SDL_NumHaptics())) {
   1.143          SDL_SetError("Haptic: There are %d haptic devices available",
   1.144 -                     SDL_numhaptics);
   1.145 +                     SDL_NumHaptics());
   1.146          return 0;
   1.147      }
   1.148  
   1.149      opened = 0;
   1.150 -    for (i = 0; SDL_haptics[i]; i++) {
   1.151 -        if (SDL_haptics[i]->index == (Uint8) device_index) {
   1.152 +    hapticlist = SDL_haptics;
   1.153 +    /* TODO Should this use an instance ID? */
   1.154 +    while ( hapticlist )
   1.155 +    {
   1.156 +        if (hapticlist->index == (Uint8) device_index) {
   1.157              opened = 1;
   1.158              break;
   1.159          }
   1.160 +        hapticlist = hapticlist->next;
   1.161      }
   1.162      return opened;
   1.163  }
   1.164 @@ -271,13 +268,13 @@
   1.165  SDL_Haptic *
   1.166  SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   1.167  {
   1.168 -    int i;
   1.169      SDL_Haptic *haptic;
   1.170 +    SDL_Haptic *hapticlist;
   1.171  
   1.172      /* Make sure there is room. */
   1.173 -    if (SDL_numhaptics <= 0) {
   1.174 +    if (SDL_NumHaptics() <= 0) {
   1.175          SDL_SetError("Haptic: There are %d haptic devices available",
   1.176 -                     SDL_numhaptics);
   1.177 +                     SDL_NumHaptics());
   1.178          return NULL;
   1.179      }
   1.180  
   1.181 @@ -293,13 +290,16 @@
   1.182          return NULL;
   1.183      }
   1.184  
   1.185 +    hapticlist = SDL_haptics;
   1.186      /* Check to see if joystick's haptic is already open */
   1.187 -    for (i = 0; SDL_haptics[i]; i++) {
   1.188 -        if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   1.189 -            haptic = SDL_haptics[i];
   1.190 +    while ( hapticlist )
   1.191 +    {
   1.192 +        if (SDL_SYS_JoystickSameHaptic(hapticlist, joystick)) {
   1.193 +            haptic = hapticlist;
   1.194              ++haptic->ref_count;
   1.195              return haptic;
   1.196          }
   1.197 +        hapticlist = hapticlist->next;
   1.198      }
   1.199  
   1.200      /* Create the haptic device */
   1.201 @@ -318,15 +318,10 @@
   1.202      }
   1.203  
   1.204      /* Add haptic to list */
   1.205 -    for (i = 0; SDL_haptics[i]; i++)
   1.206 -        /* Skip to next haptic */ ;
   1.207 -    if (i >= SDL_numhaptics) {
   1.208 -        SDL_free(haptic);
   1.209 -        SDL_SetError("Haptic: Trying to add device past the number originally detected");
   1.210 -        return NULL;
   1.211 -    }
   1.212 -    SDL_haptics[i] = haptic;
   1.213      ++haptic->ref_count;
   1.214 +    /* Link the haptic in the list */
   1.215 +    haptic->next = SDL_haptics;
   1.216 +    SDL_haptics = haptic;
   1.217  
   1.218      return haptic;
   1.219  }
   1.220 @@ -339,6 +334,8 @@
   1.221  SDL_HapticClose(SDL_Haptic * haptic)
   1.222  {
   1.223      int i;
   1.224 +    SDL_Haptic *hapticlist;
   1.225 +    SDL_Haptic *hapticlistprev;
   1.226  
   1.227      /* Must be valid */
   1.228      if (!ValidHaptic(haptic)) {
   1.229 @@ -359,13 +356,26 @@
   1.230      SDL_SYS_HapticClose(haptic);
   1.231  
   1.232      /* Remove from the list */
   1.233 -    for (i = 0; SDL_haptics[i]; ++i) {
   1.234 -        if (haptic == SDL_haptics[i]) {
   1.235 -            SDL_haptics[i] = NULL;
   1.236 -            SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   1.237 -                       (SDL_numhaptics - i) * sizeof(haptic));
   1.238 +    hapticlist = SDL_haptics;
   1.239 +    hapticlistprev = NULL;
   1.240 +    while ( hapticlist )
   1.241 +    {
   1.242 +        if (haptic == hapticlist)
   1.243 +        {
   1.244 +            if ( hapticlistprev )
   1.245 +            {
   1.246 +                /* unlink this entry */
   1.247 +                hapticlistprev->next = hapticlist->next;
   1.248 +            }
   1.249 +            else
   1.250 +            {
   1.251 +                SDL_haptics = haptic->next;
   1.252 +            }
   1.253 +
   1.254              break;
   1.255          }
   1.256 +        hapticlistprev = hapticlist;
   1.257 +        hapticlist = hapticlist->next;
   1.258      }
   1.259  
   1.260      /* Free */
   1.261 @@ -379,9 +389,8 @@
   1.262  SDL_HapticQuit(void)
   1.263  {
   1.264      SDL_SYS_HapticQuit();
   1.265 -    SDL_free(SDL_haptics);
   1.266 +    SDL_assert(SDL_haptics == NULL);
   1.267      SDL_haptics = NULL;
   1.268 -    SDL_numhaptics = 0;
   1.269  }
   1.270  
   1.271  /*
     2.1 --- a/src/haptic/SDL_syshaptic.h	Tue Feb 04 15:40:51 2014 -0500
     2.2 +++ b/src/haptic/SDL_syshaptic.h	Tue Feb 04 15:44:09 2014 -0500
     2.3 @@ -54,6 +54,7 @@
     2.4  
     2.5      int rumble_id;              /* ID of rumble effect for simple rumble API. */
     2.6      SDL_HapticEffect rumble_effect; /* Rumble effect. */
     2.7 +    struct _SDL_Haptic *next; /* pointer to next haptic we have allocated */
     2.8  };
     2.9  
    2.10  /*
    2.11 @@ -63,6 +64,9 @@
    2.12   */
    2.13  extern int SDL_SYS_HapticInit(void);
    2.14  
    2.15 +/* Function to return the number of haptic devices plugged in right now */
    2.16 +extern int SDL_SYS_NumHaptics();
    2.17 +
    2.18  /*
    2.19   * Gets the device dependent name of the haptic device
    2.20   */
     3.1 --- a/src/haptic/linux/SDL_syshaptic.c	Tue Feb 04 15:40:51 2014 -0500
     3.2 +++ b/src/haptic/linux/SDL_syshaptic.c	Tue Feb 04 15:44:09 2014 -0500
     3.3 @@ -22,11 +22,13 @@
     3.4  
     3.5  #ifdef SDL_HAPTIC_LINUX
     3.6  
     3.7 +#include "SDL_assert.h"
     3.8  #include "SDL_haptic.h"
     3.9  #include "../SDL_syshaptic.h"
    3.10  #include "SDL_joystick.h"
    3.11  #include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
    3.12  #include "../../joystick/linux/SDL_sysjoystick_c.h"     /* For joystick hwdata */
    3.13 +#include "../../core/linux/SDL_udev.h"
    3.14  
    3.15  #include <unistd.h>             /* close */
    3.16  #include <linux/input.h>        /* Force feedback linux stuff. */
    3.17 @@ -44,15 +46,21 @@
    3.18  
    3.19  #define MAX_HAPTICS  32         /* It's doubtful someone has more then 32 evdev */
    3.20  
    3.21 +static int MaybeAddDevice(const char *path);
    3.22 +#if SDL_USE_LIBUDEV
    3.23 +static int MaybeRemoveDevice(const char *path);
    3.24 +void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
    3.25 +#endif /* SDL_USE_LIBUDEV */
    3.26  
    3.27  /*
    3.28   * List of available haptic devices.
    3.29   */
    3.30 -static struct
    3.31 +typedef struct SDL_hapticlist_item
    3.32  {
    3.33      char *fname;                /* Dev path name (like /dev/input/event1) */
    3.34      SDL_Haptic *haptic;         /* Assosciated haptic. */
    3.35 -} SDL_hapticlist[MAX_HAPTICS];
    3.36 +	struct SDL_hapticlist_item *next;
    3.37 +} SDL_hapticlist_item;
    3.38  
    3.39  
    3.40  /*
    3.41 @@ -73,7 +81,9 @@
    3.42      struct ff_effect effect;    /* The linux kernel effect structure. */
    3.43  };
    3.44  
    3.45 -
    3.46 +static SDL_hapticlist_item *SDL_hapticlist = NULL;
    3.47 +static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
    3.48 +static int numhaptics = 0;
    3.49  
    3.50  #define test_bit(nr, addr) \
    3.51     (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
    3.52 @@ -147,15 +157,8 @@
    3.53  SDL_SYS_HapticInit(void)
    3.54  {
    3.55      const char joydev_pattern[] = "/dev/input/event%d";
    3.56 -    dev_t dev_nums[MAX_HAPTICS];
    3.57      char path[PATH_MAX];
    3.58 -    struct stat sb;
    3.59 -    int fd;
    3.60 -    int i, j, k;
    3.61 -    int duplicate;
    3.62 -    int numhaptics;
    3.63 -
    3.64 -    numhaptics = 0;
    3.65 +    int i, j;
    3.66  
    3.67      /*
    3.68       * Limit amount of checks to MAX_HAPTICS since we may or may not have
    3.69 @@ -165,44 +168,189 @@
    3.70      for (j = 0; j < MAX_HAPTICS; ++j) {
    3.71  
    3.72          snprintf(path, PATH_MAX, joydev_pattern, i++);
    3.73 +        MaybeAddDevice(path);
    3.74 +    }
    3.75  
    3.76 -        /* check to see if file exists */
    3.77 -        if (stat(path, &sb) != 0)
    3.78 +#if SDL_USE_LIBUDEV
    3.79 +	if (SDL_UDEV_Init() < 0) {
    3.80 +        return SDL_SetError("Could not initialize UDEV");
    3.81 +    }
    3.82 +
    3.83 +	if ( SDL_UDEV_AddCallback(haptic_udev_callback) < 0) {
    3.84 +		SDL_UDEV_Quit();
    3.85 +		return SDL_SetError("Could not setup haptic <-> udev callback");
    3.86 +	}
    3.87 +#endif /* SDL_USE_LIBUDEV */
    3.88 +	
    3.89 +    return numhaptics;
    3.90 +}
    3.91 +
    3.92 +int
    3.93 +SDL_SYS_NumHaptics()
    3.94 +{
    3.95 +    return numhaptics;
    3.96 +}
    3.97 +
    3.98 +static SDL_hapticlist_item *
    3.99 +HapticByDevIndex(int device_index)
   3.100 +{
   3.101 +    SDL_hapticlist_item *item = SDL_hapticlist;
   3.102 +
   3.103 +    if ((device_index < 0) || (device_index >= numhaptics)) {
   3.104 +        return NULL;
   3.105 +    }
   3.106 +
   3.107 +    while (device_index > 0) {
   3.108 +        SDL_assert(item != NULL);
   3.109 +        device_index--;
   3.110 +        item = item->next;
   3.111 +    }
   3.112 +
   3.113 +    return item;
   3.114 +}
   3.115 +
   3.116 +#if SDL_USE_LIBUDEV
   3.117 +void haptic_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
   3.118 +{
   3.119 +    if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
   3.120 +        return;
   3.121 +    }
   3.122 +    
   3.123 +    switch( udev_type )
   3.124 +    {
   3.125 +        case SDL_UDEV_DEVICEADDED:
   3.126 +            MaybeAddDevice(devpath);
   3.127              break;
   3.128 +            
   3.129 +        case SDL_UDEV_DEVICEREMOVED:
   3.130 +            MaybeRemoveDevice(devpath);
   3.131 +            break;
   3.132 +            
   3.133 +        default:
   3.134 +            break;
   3.135 +    }
   3.136 +    
   3.137 +}
   3.138 +#endif /* SDL_USE_LIBUDEV */
   3.139  
   3.140 -        /* check for duplicates */
   3.141 -        duplicate = 0;
   3.142 -        for (k = 0; (k < numhaptics) && !duplicate; ++k) {
   3.143 -            if (sb.st_rdev == dev_nums[k]) {
   3.144 -                duplicate = 1;
   3.145 -            }
   3.146 +static int
   3.147 +MaybeAddDevice(const char *path)
   3.148 +{
   3.149 +    dev_t dev_nums[MAX_HAPTICS];
   3.150 +    struct stat sb;
   3.151 +    int fd;
   3.152 +    int k;
   3.153 +    int duplicate;
   3.154 +    int success;
   3.155 +    SDL_hapticlist_item *item;
   3.156 +
   3.157 +
   3.158 +    if (path == NULL) {
   3.159 +        return -1;
   3.160 +    }
   3.161 +
   3.162 +    /* check to see if file exists */
   3.163 +    if (stat(path, &sb) != 0) {
   3.164 +        return -1;
   3.165 +	}
   3.166 +
   3.167 +    /* check for duplicates */
   3.168 +    duplicate = 0;
   3.169 +    for (k = 0; (k < numhaptics) && !duplicate; ++k) {
   3.170 +        if (sb.st_rdev == dev_nums[k]) {
   3.171 +            duplicate = 1;
   3.172          }
   3.173 -        if (duplicate) {
   3.174 -            continue;
   3.175 -        }
   3.176 +    }
   3.177 +    if (duplicate) {
   3.178 +        return -1;
   3.179 +    }
   3.180  
   3.181 -        /* try to open */
   3.182 -        fd = open(path, O_RDWR, 0);
   3.183 -        if (fd < 0)
   3.184 -            continue;
   3.185 +    /* try to open */
   3.186 +    fd = open(path, O_RDWR, 0);
   3.187 +    if (fd < 0) {
   3.188 +        return -1;
   3.189 +	}
   3.190  
   3.191  #ifdef DEBUG_INPUT_EVENTS
   3.192 -        printf("Checking %s\n", path);
   3.193 +    printf("Checking %s\n", path);
   3.194  #endif
   3.195  
   3.196 -        /* see if it works */
   3.197 -        if (EV_IsHaptic(fd) > 0) {
   3.198 -            SDL_hapticlist[numhaptics].fname = SDL_strdup(path);
   3.199 -            SDL_hapticlist[numhaptics].haptic = NULL;
   3.200 -            dev_nums[numhaptics] = sb.st_rdev;
   3.201 -            ++numhaptics;
   3.202 -        }
   3.203 -        close(fd);
   3.204 +    /* see if it works */
   3.205 +    success = EV_IsHaptic(fd);
   3.206 +    close(fd);
   3.207 +    if (success <= 0) {
   3.208 +        return -1;
   3.209      }
   3.210  
   3.211 +    item = (SDL_hapticlist_item *) SDL_malloc(sizeof (SDL_hapticlist_item));
   3.212 +    if (item == NULL) {
   3.213 +        return -1;
   3.214 +    }
   3.215 +    SDL_zerop(item);
   3.216 +    item->fname = SDL_strdup(path);
   3.217 +    if ( (item->fname == NULL) ) {
   3.218 +        SDL_free(item->fname);
   3.219 +        SDL_free(item);
   3.220 +        return -1;
   3.221 +    }
   3.222 +
   3.223 +    /* TODO: should we add instance IDs? */
   3.224 +    if (SDL_hapticlist_tail == NULL) {
   3.225 +        SDL_hapticlist = SDL_hapticlist_tail = item;
   3.226 +    } else {
   3.227 +        SDL_hapticlist_tail->next = item;
   3.228 +        SDL_hapticlist_tail = item;
   3.229 +    }
   3.230 +
   3.231 +    dev_nums[numhaptics] = sb.st_rdev;
   3.232 +
   3.233 +    ++numhaptics;
   3.234 +
   3.235 +    /* !!! TODO: Send a haptic add event? */
   3.236 +
   3.237      return numhaptics;
   3.238  }
   3.239  
   3.240 +#if SDL_USE_LIBUDEV
   3.241 +static int
   3.242 +MaybeRemoveDevice(const char* path)
   3.243 +{
   3.244 +    SDL_hapticlist_item *item;
   3.245 +    SDL_hapticlist_item *prev = NULL;
   3.246 +
   3.247 +    if (path == NULL) {
   3.248 +        return -1;
   3.249 +    }
   3.250 +
   3.251 +    for (item = SDL_hapticlist; item != NULL; item = item->next) {
   3.252 +        /* found it, remove it. */
   3.253 +        if (SDL_strcmp(path, item->fname) == 0) {
   3.254 +            const int retval = item->haptic ? item->haptic->index : -1;
   3.255 +
   3.256 +            if (prev != NULL) {
   3.257 +                prev->next = item->next;
   3.258 +            } else {
   3.259 +                SDL_assert(SDL_hapticlist == item);
   3.260 +                SDL_hapticlist = item->next;
   3.261 +            }
   3.262 +            if (item == SDL_hapticlist_tail) {
   3.263 +                SDL_hapticlist_tail = prev;
   3.264 +            }
   3.265 +
   3.266 +            /* Need to decrement the haptic count */
   3.267 +            --numhaptics;
   3.268 +            /* !!! TODO: Send a haptic remove event? */
   3.269 +
   3.270 +            SDL_free(item->fname);
   3.271 +            SDL_free(item);
   3.272 +            return retval;
   3.273 +        }
   3.274 +        prev = item;
   3.275 +    }
   3.276 +
   3.277 +    return -1;
   3.278 +}
   3.279 +#endif /* SDL_USE_LIBUDEV */
   3.280  
   3.281  /*
   3.282   * Gets the name from a file descriptor.
   3.283 @@ -227,19 +375,21 @@
   3.284  const char *
   3.285  SDL_SYS_HapticName(int index)
   3.286  {
   3.287 +	SDL_hapticlist_item *item;
   3.288      int fd;
   3.289      const char *name;
   3.290  
   3.291 +	item = HapticByDevIndex(index);
   3.292      /* Open the haptic device. */
   3.293      name = NULL;
   3.294 -    fd = open(SDL_hapticlist[index].fname, O_RDONLY, 0);
   3.295 +    fd = open(item->fname, O_RDONLY, 0);
   3.296  
   3.297      if (fd >= 0) {
   3.298  
   3.299          name = SDL_SYS_HapticNameFromFD(fd);
   3.300          if (name == NULL) {
   3.301              /* No name found, return device character device */
   3.302 -            name = SDL_hapticlist[index].fname;
   3.303 +            name = item->fname;
   3.304          }
   3.305      }
   3.306      close(fd);
   3.307 @@ -306,12 +456,14 @@
   3.308  {
   3.309      int fd;
   3.310      int ret;
   3.311 +	SDL_hapticlist_item *item;
   3.312  
   3.313 +	item = HapticByDevIndex(haptic->index);
   3.314      /* Open the character device */
   3.315 -    fd = open(SDL_hapticlist[haptic->index].fname, O_RDWR, 0);
   3.316 +    fd = open(item->fname, O_RDWR, 0);
   3.317      if (fd < 0) {
   3.318          return SDL_SetError("Haptic: Unable to open %s: %s",
   3.319 -                            SDL_hapticlist[haptic->index], strerror(errno));
   3.320 +                            item->fname, strerror(errno));
   3.321      }
   3.322  
   3.323      /* Try to create the haptic. */
   3.324 @@ -321,7 +473,7 @@
   3.325      }
   3.326  
   3.327      /* Set the fname. */
   3.328 -    haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
   3.329 +    haptic->hwdata->fname = item->fname;
   3.330      return 0;
   3.331  }
   3.332  
   3.333 @@ -333,24 +485,27 @@
   3.334  SDL_SYS_HapticMouse(void)
   3.335  {
   3.336      int fd;
   3.337 -    int i;
   3.338 +    int device_index = 0;
   3.339 +	SDL_hapticlist_item *item;
   3.340  
   3.341 -    for (i = 0; i < SDL_numhaptics; i++) {
   3.342 -
   3.343 +	
   3.344 +    for (item = SDL_hapticlist; item; item = item->next) {
   3.345          /* Open the device. */
   3.346 -        fd = open(SDL_hapticlist[i].fname, O_RDWR, 0);
   3.347 +        fd = open(item->fname, O_RDWR, 0);
   3.348          if (fd < 0) {
   3.349              return SDL_SetError("Haptic: Unable to open %s: %s",
   3.350 -                                SDL_hapticlist[i], strerror(errno));
   3.351 +                                item->fname, strerror(errno));
   3.352          }
   3.353  
   3.354          /* Is it a mouse? */
   3.355          if (EV_IsMouse(fd)) {
   3.356              close(fd);
   3.357 -            return i;
   3.358 +            return device_index;
   3.359          }
   3.360  
   3.361          close(fd);
   3.362 +
   3.363 +		++device_index;
   3.364      }
   3.365  
   3.366      return -1;
   3.367 @@ -388,22 +543,21 @@
   3.368  int
   3.369  SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
   3.370  {
   3.371 -    int i;
   3.372 +    int device_index = 0;
   3.373      int fd;
   3.374      int ret;
   3.375 +	SDL_hapticlist_item *item;
   3.376  
   3.377  
   3.378      /* Find the joystick in the haptic list. */
   3.379 -    for (i = 0; i < MAX_HAPTICS; i++) {
   3.380 -        if (SDL_hapticlist[i].fname != NULL) {
   3.381 -            if (SDL_strcmp(SDL_hapticlist[i].fname, joystick->hwdata->fname)
   3.382 -                == 0) {
   3.383 -                haptic->index = i;
   3.384 -                break;
   3.385 -            }
   3.386 -        }
   3.387 +    for (item = SDL_hapticlist; item; item = item->next) {
   3.388 +		if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) {
   3.389 +			haptic->index = device_index;
   3.390 +			break;
   3.391 +		}
   3.392 +		++device_index;
   3.393      }
   3.394 -    if (i >= MAX_HAPTICS) {
   3.395 +    if (device_index >= MAX_HAPTICS) {
   3.396          return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities");
   3.397      }
   3.398  
   3.399 @@ -417,7 +571,7 @@
   3.400          return -1;
   3.401      }
   3.402  
   3.403 -    haptic->hwdata->fname = SDL_hapticlist[haptic->index].fname;
   3.404 +    haptic->hwdata->fname = item->fname;
   3.405      return 0;
   3.406  }
   3.407  
   3.408 @@ -454,15 +608,23 @@
   3.409  void
   3.410  SDL_SYS_HapticQuit(void)
   3.411  {
   3.412 -    int i;
   3.413 +    SDL_hapticlist_item *item = NULL;
   3.414 +	SDL_hapticlist_item *next = NULL;
   3.415  
   3.416 -    for (i = 0; SDL_hapticlist[i].fname != NULL; i++) {
   3.417 +    for (item = SDL_hapticlist; item; item = next) {
   3.418 +		next = item->next;
   3.419          /* Opened and not closed haptics are leaked, this is on purpose.
   3.420           * Close your haptic devices after usage. */
   3.421 +		SDL_free(item->fname);
   3.422 +		item->fname = NULL;
   3.423 +    }
   3.424  
   3.425 -        SDL_free(SDL_hapticlist[i].fname);
   3.426 -    }
   3.427 -    SDL_hapticlist[0].fname = NULL;
   3.428 +#if SDL_USE_LIBUDEV
   3.429 +    SDL_UDEV_DelCallback(haptic_udev_callback);
   3.430 +    SDL_UDEV_Quit();
   3.431 +#endif /* SDL_USE_LIBUDEV */
   3.432 +
   3.433 +    numhaptics = 0;
   3.434  }
   3.435  
   3.436