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