comparison src/joystick/linux/SDL_sysjoystick.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children 0cc95f442f3a
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
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$";
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)
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) \
117 (((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
118
119 static int EV_IsJoystick(int fd)
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)
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)
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)
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)
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,
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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