src/joystick/linux/SDL_sysjoystick.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. mystrdup
  2. test_bit
  3. EV_IsJoystick
  4. SDL_SYS_JoystickInit
  5. SDL_SYS_JoystickName
  6. allocate_hatdata
  7. allocate_balldata
  8. ConfigJoystick
  9. EV_ConfigJoystick
  10. SDL_SYS_JoystickOpen
  11. HandleHat
  12. HandleAnalogHat
  13. HandleBall
  14. JS_HandleEvents
  15. EV_AxisCorrect
  16. EV_HandleEvents
  17. SDL_SYS_JoystickUpdate
  18. SDL_SYS_JoystickClose
  19. SDL_SYS_JoystickQuit

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 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     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_sysjoystick.c,v 1.1.2.26 2001/03/05 17:09:25 hercules Exp $";
  26 #endif
  27 
  28 /* This is the system specific header for the SDL joystick API */
  29 
  30 #include <stdio.h>              /* For the definition of NULL */
  31 #include <stdlib.h>             /* For getenv() prototype */
  32 #include <string.h>
  33 #include <sys/stat.h>
  34 #include <unistd.h>
  35 #include <fcntl.h>
  36 #include <sys/ioctl.h>
  37 #include <limits.h>             /* For the definition of PATH_MAX */
  38 
  39 #include <linux/joystick.h>
  40 #ifdef USE_INPUT_EVENTS
  41 #include <linux/input.h>
  42 #endif
  43 
  44 #include "SDL_error.h"
  45 #include "SDL_joystick.h"
  46 #include "SDL_sysjoystick.h"
  47 #include "SDL_joystick_c.h"
  48 
  49 /* Define this if you want to map axes to hats and trackballs */
  50 #define FANCY_HATS_AND_BALLS
  51 
  52 #ifdef FANCY_HATS_AND_BALLS
  53 /* Special joystick configurations:
  54         'JoystickName' Naxes Nhats Nballs
  55  */
  56 static const char *special_joysticks[] = {
  57         "'MadCatz Panther XL' 3 2 1", /* We don't handle a rudder (axis 8) */
  58         "'SideWinder Precision Pro' 4 1 0",
  59         "'SideWinder 3D Pro' 4 1 0",
  60         "'Microsoft SideWinder 3D Pro' 4 1 0",
  61         "'Microsoft SideWinder Dual Strike USB version 1.0' 2 1 0",
  62         "'WingMan Interceptor' 3 3 0",
  63         /* WingMan Extreme Analog - not recognized by default
  64         "'Analog 3-axis 4-button joystick' 2 1",
  65         */
  66         "'WingMan Extreme Digital 3D' 4 1 0",
  67         NULL
  68 };
  69 #else
  70 #undef USE_INPUT_EVENTS
  71 #endif
  72 
  73 /* The maximum number of joysticks we'll detect */
  74 #define MAX_JOYSTICKS   32
  75 
  76 /* A list of available joysticks */
  77 static char *SDL_joylist[MAX_JOYSTICKS];
  78 
  79 /* The private structure used to keep track of a joystick */
  80 struct joystick_hwdata {
  81         int fd;
  82         /* The current linux joystick driver maps hats to two axes */
  83         int analog_hat;         /* Well, except for analog hats */
  84         struct hwdata_hat {
  85                 int axis[2];
  86         } *hats;
  87         /* The current linux joystick driver maps balls to two axes */
  88         struct hwdata_ball {
  89                 int axis[2];
  90         } *balls;
  91 
  92         /* Support for the Linux 2.4 unified input interface */
  93         SDL_bool is_hid;
  94 #ifdef USE_INPUT_EVENTS
  95         Uint8 key_map[KEY_MAX-BTN_MISC];
  96         Uint8 abs_map[ABS_MAX];
  97         struct axis_correct {
  98                 int used;
  99                 int coef[3];
 100         } abs_correct[ABS_MAX];
 101 #endif
 102 };
 103 
 104 static char *mystrdup(const char *string)
     /* [<][>][^][v][top][bottom][index][help] */
 105 {
 106         char *newstring;
 107 
 108         newstring = (char *)malloc(strlen(string)+1);
 109         if ( newstring ) {
 110                 strcpy(newstring, string);
 111         }
 112         return(newstring);
 113 }
 114 
 115 #ifdef USE_INPUT_EVENTS
 116 #define test_bit(nr, addr) \
     /* [<][>][^][v][top][bottom][index][help] */
 117         (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
 118 
 119 static int EV_IsJoystick(int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 120 {
 121         unsigned long evbit[40];
 122         unsigned long keybit[40];
 123         unsigned long absbit[40];
 124 
 125         if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
 126              (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
 127              (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) {
 128                 return(0);
 129         }
 130         if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
 131               test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
 132              (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0;
 133         return(1);
 134 }
 135 
 136 #endif /* USE_INPUT_EVENTS */
 137 
 138 /* Function to scan the system for joysticks */
 139 int SDL_SYS_JoystickInit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 140 {
 141         /* The base path of the joystick devices */
 142         const char *joydev_pattern[2] = {
 143                 "/dev/js%d",
 144 #ifdef USE_INPUT_EVENTS
 145                 "/dev/input/event%d"
 146 #else
 147                 "/dev/input/js%d"
 148 #endif
 149         };
 150         int numjoysticks;
 151         int i, j, done;
 152         int fd;
 153         char path[PATH_MAX];
 154         dev_t dev_nums[MAX_JOYSTICKS];  /* major/minor device numbers */
 155         struct stat sb;
 156         int n, duplicate;
 157 
 158         numjoysticks = 0;
 159 
 160         /* First see if the user specified a joystick to use */
 161         if ( getenv("SDL_JOYSTICK_DEVICE") != NULL ) {
 162                 strncpy(path, getenv("SDL_JOYSTICK_DEVICE"), sizeof(path));
 163                 path[sizeof(path)-1] = '\0';
 164                 if ( stat(path, &sb) == 0 ) {
 165                         fd = open(path, O_RDONLY, 0);
 166                         if ( fd >= 0 ) {
 167                                 /* Assume the user knows what they're doing. */
 168                                 SDL_joylist[numjoysticks] = mystrdup(path);
 169                                 if ( SDL_joylist[numjoysticks] ) {
 170                                         dev_nums[numjoysticks] = sb.st_rdev;
 171                                         ++numjoysticks;
 172                                 }
 173                                 close(fd);
 174                         }
 175                 }
 176         }
 177         for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) {
 178                 done = 0;
 179                 for ( j=0; (j < MAX_JOYSTICKS) && !done; ++j ) {
 180                         sprintf(path, joydev_pattern[i], j);
 181 
 182                         /* rcg06302000 replaced access(F_OK) call with stat().
 183                          * stat() will fail if the file doesn't exist, so it's
 184                          * equivalent behaviour.
 185                          */
 186                         if ( stat(path, &sb) == 0 ) {
 187                                 /* Check to make sure it's not already in list.
 188                                  * This happens when we see a stick via symlink.
 189                                  */
 190                                 duplicate = 0;
 191                                 for (n=0; (n<numjoysticks) && !duplicate; ++n) {
 192                                         if ( sb.st_rdev == dev_nums[n] ) {
 193                                                 duplicate = 1;
 194                                         }
 195                                 }
 196                                 if (duplicate) {
 197                                         continue;
 198                                 }
 199 
 200                                 fd = open(path, O_RDONLY, 0);
 201                                 if ( fd < 0 ) {
 202                                         continue;
 203                                 }
 204 #ifdef USE_INPUT_EVENTS
 205 #ifdef DEBUG_INPUT_EVENTS
 206                                 printf("Checking %s\n", path);
 207 #endif
 208                                 if ( (i > 0) && ! EV_IsJoystick(fd) ) {
 209                                         close(fd);
 210                                         continue;
 211                                 }
 212 #endif
 213                                 close(fd);
 214 
 215                                 /* We're fine, add this joystick */
 216                                 SDL_joylist[numjoysticks] = mystrdup(path);
 217                                 if ( SDL_joylist[numjoysticks] ) {
 218                                         dev_nums[numjoysticks] = sb.st_rdev;
 219                                         ++numjoysticks;
 220                                 }
 221                         } else {
 222                                 done = 1;
 223                         }
 224                 }
 225         }
 226         return(numjoysticks);
 227 }
 228 
 229 /* Function to get the device-dependent name of a joystick */
 230 const char *SDL_SYS_JoystickName(int index)
     /* [<][>][^][v][top][bottom][index][help] */
 231 {
 232         int fd;
 233         static char namebuf[128];
 234         char *name;
 235 
 236         name = NULL;
 237         fd = open(SDL_joylist[index], O_RDONLY, 0);
 238         if ( fd >= 0 ) {
 239                 if ( 
 240 #ifdef USE_INPUT_EVENTS
 241                      (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) &&
 242 #endif
 243                      (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) {
 244                         name = SDL_joylist[index];
 245                 } else {
 246                         name = namebuf;
 247                 }
 248                 close(fd);
 249         }
 250         return name;
 251 }
 252 
 253 #ifdef FANCY_HATS_AND_BALLS
 254 
 255 static int allocate_hatdata(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257         int i;
 258 
 259         joystick->hwdata->hats = (struct hwdata_hat *)malloc(
 260                 joystick->nhats * sizeof(struct hwdata_hat));
 261         if ( joystick->hwdata->hats == NULL ) {
 262                 return(-1);
 263         }
 264         for ( i=0; i<joystick->nhats; ++i ) {
 265                 joystick->hwdata->hats[i].axis[0] = 1;
 266                 joystick->hwdata->hats[i].axis[1] = 1;
 267         }
 268         return(0);
 269 }
 270 
 271 static int allocate_balldata(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 272 {
 273         int i;
 274 
 275         joystick->hwdata->balls = (struct hwdata_ball *)malloc(
 276                 joystick->nballs * sizeof(struct hwdata_ball));
 277         if ( joystick->hwdata->balls == NULL ) {
 278                 return(-1);
 279         }
 280         for ( i=0; i<joystick->nballs; ++i ) {
 281                 joystick->hwdata->balls[i].axis[0] = 0;
 282                 joystick->hwdata->balls[i].axis[1] = 0;
 283         }
 284         return(0);
 285 }
 286 
 287 static SDL_bool ConfigJoystick(SDL_Joystick *joystick,
     /* [<][>][^][v][top][bottom][index][help] */
 288                         const char *name, const char *config)
 289 {
 290         char cfg_name[128];
 291         SDL_bool handled;
 292 
 293         if ( config == NULL ) {
 294                 return(SDL_FALSE);
 295         }
 296         strcpy(cfg_name, "");
 297         if ( *config == '\'' ) {
 298                 sscanf(config, "'%[^']s'", cfg_name);
 299                 config += strlen(cfg_name)+2;
 300         } else {
 301                 sscanf(config, "%s", cfg_name);
 302                 config += strlen(cfg_name);
 303         }
 304         handled = SDL_FALSE;
 305         if ( strcmp(cfg_name, name) == 0 ) {
 306                 /* Get the number of axes, hats and balls for this joystick */
 307                 int joystick_axes = joystick->naxes;
 308                 sscanf(config, "%d %d %d", 
 309                         &joystick->naxes, &joystick->nhats, &joystick->nballs);
 310 
 311                 /* Allocate the extra data for mapping them */
 312                 if ( joystick->nhats > 0 ) {
 313                         /* HACK: Analog hats map to only one axis */
 314                         if (joystick_axes == (joystick->naxes+joystick->nhats)){
 315                                 joystick->hwdata->analog_hat = 1;
 316                         } else {
 317                                 if ( allocate_hatdata(joystick) < 0 ) {
 318                                         joystick->nhats = 0;
 319                                 }
 320                                 joystick->hwdata->analog_hat = 0;
 321                         }
 322                 }
 323                 if ( joystick->nballs > 0 ) {
 324                         if ( allocate_balldata(joystick) < 0 ) {
 325                                 joystick->nballs = 0;
 326                         }
 327                 }
 328                 handled = SDL_TRUE;
 329         }
 330         return(handled);
 331 }
 332 
 333 #ifdef USE_INPUT_EVENTS
 334 
 335 static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 336 {
 337         int i;
 338         unsigned long keybit[40];
 339         unsigned long absbit[40];
 340         unsigned long relbit[40];
 341 
 342         /* See if this device uses the new unified event API */
 343         if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
 344              (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
 345              (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) {
 346                 joystick->hwdata->is_hid = SDL_TRUE;
 347 
 348                 /* Get the number of buttons, axes, and other thingamajigs */
 349                 for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) {
 350                         if ( test_bit(i, keybit) ) {
 351 #ifdef DEBUG_INPUT_EVENTS
 352                                 printf("Joystick has button: 0x%x\n", i);
 353 #endif
 354                                 joystick->hwdata->key_map[i-BTN_MISC] =
 355                                                 joystick->nbuttons;
 356                                 ++joystick->nbuttons;
 357                         }
 358                 }
 359                 for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) {
 360                         if ( test_bit(i, keybit) ) {
 361 #ifdef DEBUG_INPUT_EVENTS
 362                                 printf("Joystick has button: 0x%x\n", i);
 363 #endif
 364                                 joystick->hwdata->key_map[i-BTN_MISC] =
 365                                                 joystick->nbuttons;
 366                                 ++joystick->nbuttons;
 367                         }
 368                 }
 369                 for ( i=0; i<ABS_MAX; ++i ) {
 370                         /* Skip hats */
 371                         if ( i == ABS_HAT0X ) {
 372                                 i = ABS_HAT3Y;
 373                                 continue;
 374                         }
 375                         if ( test_bit(i, absbit) ) {
 376                                 int values[5];
 377 
 378                                 ioctl(fd, EVIOCGABS(i), values);
 379 #ifdef DEBUG_INPUT_EVENTS
 380                                 printf("Joystick has absolute axis: %x\n", i);
 381                                 printf("Values = { %d, %d, %d, %d, %d }\n",
 382                                         values[0], values[1],
 383                                         values[2], values[3], values[4]);
 384 #endif /* DEBUG_INPUT_EVENTS */
 385                                 joystick->hwdata->abs_map[i] = joystick->naxes;
 386                                 if ( values[1] == values[2] ) {
 387                                     joystick->hwdata->abs_correct[i].used = 0;
 388                                 } else {
 389                                     joystick->hwdata->abs_correct[i].used = 1;
 390                                     joystick->hwdata->abs_correct[i].coef[0] =
 391                                         (values[2] + values[1]) / 2 - values[4];
 392                                     joystick->hwdata->abs_correct[i].coef[1] =
 393                                         (values[2] + values[1]) / 2 + values[4];
 394                                     joystick->hwdata->abs_correct[i].coef[2] =
 395                                         (1 << 29) / ((values[2] - values[1]) / 2 - 2 * values[4]);
 396                                 }
 397                                 ++joystick->naxes;
 398                         }
 399                 }
 400                 for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) {
 401                         if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) {
 402 #ifdef DEBUG_INPUT_EVENTS
 403                                 printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2);
 404 #endif
 405                                 ++joystick->nhats;
 406                         }
 407                 }
 408                 if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) {
 409                         ++joystick->nballs;
 410                 }
 411 
 412                 /* Allocate data to keep track of these thingamajigs */
 413                 if ( joystick->nhats > 0 ) {
 414                         if ( allocate_hatdata(joystick) < 0 ) {
 415                                 joystick->nhats = 0;
 416                         }
 417                 }
 418                 if ( joystick->nballs > 0 ) {
 419                         if ( allocate_balldata(joystick) < 0 ) {
 420                                 joystick->nballs = 0;
 421                         }
 422                 }
 423         }
 424         return(joystick->hwdata->is_hid);
 425 }
 426 
 427 #endif /* USE_INPUT_EVENTS */
 428 
 429 #endif /* FANCY_HATS_AND_BALLS */
 430 
 431 /* Function to open a joystick for use.
 432    The joystick to open is specified by the index field of the joystick.
 433    This should fill the nbuttons and naxes fields of the joystick structure.
 434    It returns 0, or -1 if there is an error.
 435  */
 436 int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 437 {
 438 #ifdef FANCY_HATS_AND_BALLS
 439         const char *name;
 440         int i;
 441 #endif
 442         int fd;
 443         unsigned char n;
 444 
 445         /* Open the joystick and set the joystick file descriptor */
 446         fd = open(SDL_joylist[joystick->index], O_RDONLY, 0);
 447         if ( fd < 0 ) {
 448                 SDL_SetError("Unable to open %s\n",
 449                              SDL_joylist[joystick->index]);
 450                 return(-1);
 451         }
 452         joystick->hwdata = (struct joystick_hwdata *)
 453                            malloc(sizeof(*joystick->hwdata));
 454         if ( joystick->hwdata == NULL ) {
 455                 SDL_OutOfMemory();
 456                 close(fd);
 457                 return(-1);
 458         }
 459         memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
 460         joystick->hwdata->fd = fd;
 461 
 462         /* Set the joystick to non-blocking read mode */
 463         fcntl(fd, F_SETFL, O_NONBLOCK);
 464 
 465         /* Get the number of buttons and axes on the joystick */
 466 #ifdef USE_INPUT_EVENTS
 467         if ( ! EV_ConfigJoystick(joystick, fd) )
 468 #endif
 469         {
 470                 if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
 471                         joystick->naxes = 2;
 472                 } else {
 473                         joystick->naxes = n;
 474                 }
 475                 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
 476                         joystick->nbuttons = 2;
 477                 } else {
 478                         joystick->nbuttons = n;
 479                 }
 480 #ifdef FANCY_HATS_AND_BALLS
 481                 /* Check for special joystick support */
 482                 name = SDL_SYS_JoystickName(joystick->index);
 483                 for ( i=0; special_joysticks[i]; ++i ) {
 484                         if (ConfigJoystick(joystick,name,special_joysticks[i])){
 485                                 break;
 486                         }
 487                 }
 488                 if ( special_joysticks[i] == NULL ) {
 489                         ConfigJoystick(joystick, name,
 490                                         getenv("SDL_LINUX_JOYSTICK"));
 491                 }
 492 #endif /* FANCY_HATS_AND_BALLS */
 493         }
 494         return(0);
 495 }
 496 
 497 static __inline__
 498 void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
     /* [<][>][^][v][top][bottom][index][help] */
 499 {
 500         struct hwdata_hat *the_hat;
 501         const Uint8 position_map[3][3] = {
 502                 { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
 503                 { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
 504                 { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
 505         };
 506 
 507         the_hat = &stick->hwdata->hats[hat];
 508         if ( value < 0 ) {
 509                 value = 0;
 510         } else
 511         if ( value == 0 ) {
 512                 value = 1;
 513         } else
 514         if ( value > 0 ) {
 515                 value = 2;
 516         }
 517         if ( value != the_hat->axis[axis] ) {
 518                 the_hat->axis[axis] = value;
 519                 SDL_PrivateJoystickHat(stick, hat,
 520                         position_map[the_hat->axis[1]][the_hat->axis[0]]);
 521         }
 522 }
 523 
 524 /* This was necessary for the Wingman Extreme Analog joystick */
 525 static __inline__
 526 void HandleAnalogHat(SDL_Joystick *stick, Uint8 hat, int value)
     /* [<][>][^][v][top][bottom][index][help] */
 527 {
 528         const Uint8 position_map[] = {
 529                 SDL_HAT_UP,
 530                 SDL_HAT_RIGHT,
 531                 SDL_HAT_DOWN,
 532                 SDL_HAT_LEFT,
 533                 SDL_HAT_CENTERED
 534         };
 535         SDL_PrivateJoystickHat(stick, hat, position_map[(value/16000)+2]);
 536 }
 537 
 538 static __inline__
 539 void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
     /* [<][>][^][v][top][bottom][index][help] */
 540 {
 541         stick->hwdata->balls[ball].axis[axis] += value;
 542 }
 543 
 544 /* Function to update the state of a joystick - called as a device poll.
 545  * This function shouldn't update the joystick structure directly,
 546  * but instead should call SDL_PrivateJoystick*() to deliver events
 547  * and update joystick device state.
 548  */
 549 static __inline__ void JS_HandleEvents(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 550 {
 551         struct js_event events[32];
 552         int i, len;
 553         Uint8 other_axis;
 554 
 555         while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
 556                 len /= sizeof(events[0]);
 557                 for ( i=0; i<len; ++i ) {
 558                         switch (events[i].type & ~JS_EVENT_INIT) {
 559                             case JS_EVENT_AXIS:
 560                                 if ( events[i].number < joystick->naxes ) {
 561                                         SDL_PrivateJoystickAxis(joystick,
 562                                            events[i].number, events[i].value);
 563                                         break;
 564                                 }
 565                                 events[i].number -= joystick->naxes;
 566                                 if ( joystick->hwdata->analog_hat ) {
 567                                         other_axis = events[i].number;
 568                                         if ( other_axis < joystick->nhats ) {
 569                                                 HandleAnalogHat(joystick, other_axis,
 570                                                         events[i].value);
 571                                                 break;
 572                                         }
 573                                 } else {
 574                                         other_axis = (events[i].number / 2);
 575                                         if ( other_axis < joystick->nhats ) {
 576                                                 HandleHat(joystick, other_axis,
 577                                                         events[i].number%2,
 578                                                         events[i].value);
 579                                                 break;
 580                                         }
 581                                 }
 582                                 events[i].number -= joystick->nhats*2;
 583                                 other_axis = (events[i].number / 2);
 584                                 if ( other_axis < joystick->nballs ) {
 585                                         HandleBall(joystick, other_axis,
 586                                                 events[i].number%2,
 587                                                 events[i].value);
 588                                         break;
 589                                 }
 590                                 break;
 591                             case JS_EVENT_BUTTON:
 592                                 SDL_PrivateJoystickButton(joystick,
 593                                            events[i].number, events[i].value);
 594                                 break;
 595                             default:
 596                                 /* ?? */
 597                                 break;
 598                         }
 599                 }
 600         }
 601 }
 602 #ifdef USE_INPUT_EVENTS
 603 static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value)
     /* [<][>][^][v][top][bottom][index][help] */
 604 {
 605         struct axis_correct *correct;
 606 
 607         correct = &joystick->hwdata->abs_correct[which];
 608         if ( correct->used ) {
 609                 if ( value > correct->coef[0] ) {
 610                         if ( value < correct->coef[1] ) {
 611                                 return 0;
 612                         }
 613                         value -= correct->coef[1];
 614                 } else {
 615                         value -= correct->coef[0];
 616                 }
 617                 value *= correct->coef[2];
 618                 value >>= 14;
 619         }
 620         /* Clamp and return */
 621         if ( value < -32767 ) {
 622                 value = -32767;
 623         } else
 624         if ( value > 32767 ) {
 625                 value = 32767;
 626         }
 627         return value;
 628 }
 629 
 630 static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 631 {
 632         struct input_event events[32];
 633         int i, len;
 634         int code;
 635 
 636         while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
 637                 len /= sizeof(events[0]);
 638                 for ( i=0; i<len; ++i ) {
 639                         code = events[i].code;
 640                         switch (events[i].type) {
 641                             case EV_KEY:
 642                                 if ( code >= BTN_MISC ) {
 643                                         code -= BTN_MISC;
 644                                         SDL_PrivateJoystickButton(joystick,
 645                                            joystick->hwdata->key_map[code],
 646                                            events[i].value);
 647                                 }
 648                                 break;
 649                             case EV_ABS:
 650                                 switch (code) {
 651                                     case ABS_HAT0X:
 652                                     case ABS_HAT0Y:
 653                                     case ABS_HAT1X:
 654                                     case ABS_HAT1Y:
 655                                     case ABS_HAT2X:
 656                                     case ABS_HAT2Y:
 657                                     case ABS_HAT3X:
 658                                     case ABS_HAT3Y:
 659                                         code -= ABS_HAT0X;
 660                                         HandleHat(joystick, code/2, code%2,
 661                                                         events[i].value);
 662                                         break;
 663                                     default:
 664                                         events[i].value = EV_AxisCorrect(joystick, code, events[i].value);
 665                                         SDL_PrivateJoystickAxis(joystick,
 666                                            joystick->hwdata->abs_map[code],
 667                                            events[i].value);
 668                                         break;
 669                                 }
 670                                 break;
 671                             case EV_REL:
 672                                 switch (code) {
 673                                     case REL_X:
 674                                     case REL_Y:
 675                                         code -= REL_X;
 676                                         HandleBall(joystick, code/2, code%2,
 677                                                         events[i].value);
 678                                         break;
 679                                     default:
 680                                         break;
 681                                 }
 682                                 break;
 683                             default:
 684                                 break;
 685                         }
 686                 }
 687         }
 688 }
 689 #endif /* USE_INPUT_EVENTS */
 690 
 691 void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 692 {
 693         int i;
 694         
 695 #ifdef USE_INPUT_EVENTS
 696         if ( joystick->hwdata->is_hid )
 697                 EV_HandleEvents(joystick);
 698         else
 699 #endif
 700                 JS_HandleEvents(joystick);
 701 
 702         /* Deliver ball motion updates */
 703         for ( i=0; i<joystick->nballs; ++i ) {
 704                 int xrel, yrel;
 705 
 706                 xrel = joystick->hwdata->balls[i].axis[0];
 707                 yrel = joystick->hwdata->balls[i].axis[1];
 708                 if ( xrel || yrel ) {
 709                         joystick->hwdata->balls[i].axis[0] = 0;
 710                         joystick->hwdata->balls[i].axis[1] = 0;
 711                         SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel);
 712                 }
 713         }
 714 }
 715 
 716 /* Function to close a joystick after use */
 717 void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
     /* [<][>][^][v][top][bottom][index][help] */
 718 {
 719         if ( joystick->hwdata ) {
 720                 close(joystick->hwdata->fd);
 721                 if ( joystick->hwdata->hats ) {
 722                         free(joystick->hwdata->hats);
 723                 }
 724                 if ( joystick->hwdata->balls ) {
 725                         free(joystick->hwdata->balls);
 726                 }
 727                 free(joystick->hwdata);
 728                 joystick->hwdata = NULL;
 729         }
 730 }
 731 
 732 /* Function to perform any system-specific joystick related cleanup */
 733 void SDL_SYS_JoystickQuit(void)
     /* [<][>][^][v][top][bottom][index][help] */
 734 {
 735         int i;
 736 
 737         for ( i=0; SDL_joylist[i]; ++i ) {
 738                 free(SDL_joylist[i]);
 739         }
 740         SDL_joylist[0] = NULL;
 741 }
 742 

/* [<][>][^][v][top][bottom][index][help] */