summaryrefslogtreecommitdiff
path: root/apps/plugins/sdl/src/joystick/linux
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/src/joystick/linux')
-rw-r--r--apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c1218
1 files changed, 0 insertions, 1218 deletions
diff --git a/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c b/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c
deleted file mode 100644
index ee43974789..0000000000
--- a/apps/plugins/sdl/src/joystick/linux/SDL_sysjoystick.c
+++ /dev/null
@@ -1,1218 +0,0 @@
1/*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24#ifdef SDL_JOYSTICK_LINUX
25
26/* This is the system specific header for the SDL joystick API */
27
28#include <sys/stat.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <sys/ioctl.h>
32#include <limits.h> /* For the definition of PATH_MAX */
33#include <linux/joystick.h>
34#if SDL_INPUT_LINUXEV
35#include <linux/input.h>
36#endif
37
38#include "SDL_joystick.h"
39#include "../SDL_sysjoystick.h"
40#include "../SDL_joystick_c.h"
41
42/* Special joystick configurations */
43static struct {
44 const char *name;
45 int naxes;
46 int nhats;
47 int nballs;
48} special_joysticks[] = {
49 { "MadCatz Panther XL", 3, 2, 1 }, /* We don't handle rudder (axis 8) */
50 { "SideWinder Precision Pro", 4, 1, 0 },
51 { "SideWinder 3D Pro", 4, 1, 0 },
52 { "Microsoft SideWinder 3D Pro", 4, 1, 0 },
53 { "Microsoft SideWinder Precision Pro", 4, 1, 0 },
54 { "Microsoft SideWinder Dual Strike USB version 1.0", 2, 1, 0 },
55 { "WingMan Interceptor", 3, 3, 0 },
56 { "WingMan Extreme Digital 3D", 4, 1, 0 },
57 { "Microsoft SideWinder Precision 2 Joystick", 4, 1, 0 },
58 { "Logitech Inc. WingMan Extreme Digital 3D", 4, 1, 0 },
59 { "Saitek Saitek X45", 6, 1, 0 }
60};
61
62/* It looks like newer kernels have the logical mapping at the driver level */
63#define NO_LOGICAL_JOYSTICKS
64
65#ifndef NO_LOGICAL_JOYSTICKS
66
67/*
68 Some USB HIDs show up as a single joystick even though they actually
69 control 2 or more joysticks.
70*/
71/*
72 This code handles the MP-8800 (Quad) and MP-8866 (Dual), which can
73 be identified by their transparent blue design. It's quite trivial
74 to add other joysticks with similar quirky behavior.
75 -id
76*/
77
78struct joystick_logical_mapping {
79 int njoy;
80 int nthing;
81};
82
83/*
84 {logical joy, logical axis},
85 {logical joy, logical hat},
86 {logical joy, logical ball},
87 {logical joy, logical button}
88*/
89
90static struct joystick_logical_mapping mp88xx_1_logical_axismap[] = {
91 {0,0},{0,1},{0,2},{0,3},{0,4},{0,5}
92};
93static struct joystick_logical_mapping mp88xx_1_logical_buttonmap[] = {
94 {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11}
95};
96
97static struct joystick_logical_mapping mp88xx_2_logical_axismap[] = {
98 {0,0},{0,1},{0,2},{1,0},{1,1},{0,3},
99 {1,2},{1,3},{0,4},{0,5},{1,4},{1,5}
100};
101static struct joystick_logical_mapping mp88xx_2_logical_buttonmap[] = {
102 {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11},
103 {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11}
104};
105
106static struct joystick_logical_mapping mp88xx_3_logical_axismap[] = {
107 {0,0},{0,1},{0,2},{1,0},{1,1},{0,3},
108 {1,2},{1,3},{2,0},{2,1},{2,2},{2,3},
109 {0,4},{0,5},{1,4},{1,5},{2,4},{2,5}
110};
111static struct joystick_logical_mapping mp88xx_3_logical_buttonmap[] = {
112 {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11},
113 {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11},
114 {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11}
115};
116
117static struct joystick_logical_mapping mp88xx_4_logical_axismap[] = {
118 {0,0},{0,1},{0,2},{1,0},{1,1},{0,3},
119 {1,2},{1,3},{2,0},{2,1},{2,2},{2,3},
120 {3,0},{3,1},{3,2},{3,3},{0,4},{0,5},
121 {1,4},{1,5},{2,4},{2,5},{3,4},{3,5}
122};
123static struct joystick_logical_mapping mp88xx_4_logical_buttonmap[] = {
124 {0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9},{0,10},{0,11},
125 {1,0},{1,1},{1,2},{1,3},{1,4},{1,5},{1,6},{1,7},{1,8},{1,9},{1,10},{1,11},
126 {2,0},{2,1},{2,2},{2,3},{2,4},{2,5},{2,6},{2,7},{2,8},{2,9},{2,10},{2,11},
127 {3,0},{3,1},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{3,8},{3,9},{3,10},{3,11}
128};
129
130struct joystick_logical_layout {
131 int naxes;
132 int nhats;
133 int nballs;
134 int nbuttons;
135};
136
137static struct joystick_logical_layout mp88xx_1_logical_layout[] = {
138 {6, 0, 0, 12}
139};
140static struct joystick_logical_layout mp88xx_2_logical_layout[] = {
141 {6, 0, 0, 12},
142 {6, 0, 0, 12}
143};
144static struct joystick_logical_layout mp88xx_3_logical_layout[] = {
145 {6, 0, 0, 12},
146 {6, 0, 0, 12},
147 {6, 0, 0, 12}
148};
149static struct joystick_logical_layout mp88xx_4_logical_layout[] = {
150 {6, 0, 0, 12},
151 {6, 0, 0, 12},
152 {6, 0, 0, 12},
153 {6, 0, 0, 12}
154};
155
156/*
157 This array sets up a means of mapping a single physical joystick to
158 multiple logical joysticks. (djm)
159
160 njoys
161 the number of logical joysticks
162
163 layouts
164 an array of layout structures, one to describe each logical joystick
165
166 axes, hats, balls, buttons
167 arrays that map a physical thingy to a logical thingy
168 */
169struct joystick_logicalmap {
170 const char *name;
171 int nbuttons;
172 int njoys;
173 struct joystick_logical_layout *layout;
174 struct joystick_logical_mapping *axismap;
175 struct joystick_logical_mapping *hatmap;
176 struct joystick_logical_mapping *ballmap;
177 struct joystick_logical_mapping *buttonmap;
178};
179
180static struct joystick_logicalmap joystick_logicalmap[] = {
181 {
182 "WiseGroup.,Ltd MP-8866 Dual USB Joypad",
183 12,
184 1,
185 mp88xx_1_logical_layout,
186 mp88xx_1_logical_axismap,
187 NULL,
188 NULL,
189 mp88xx_1_logical_buttonmap
190 },
191 {
192 "WiseGroup.,Ltd MP-8866 Dual USB Joypad",
193 24,
194 2,
195 mp88xx_2_logical_layout,
196 mp88xx_2_logical_axismap,
197 NULL,
198 NULL,
199 mp88xx_2_logical_buttonmap
200 },
201 {
202 "WiseGroup.,Ltd MP-8800 Quad USB Joypad",
203 12,
204 1,
205 mp88xx_1_logical_layout,
206 mp88xx_1_logical_axismap,
207 NULL,
208 NULL,
209 mp88xx_1_logical_buttonmap
210 },
211 {
212 "WiseGroup.,Ltd MP-8800 Quad USB Joypad",
213 24,
214 2,
215 mp88xx_2_logical_layout,
216 mp88xx_2_logical_axismap,
217 NULL,
218 NULL,
219 mp88xx_2_logical_buttonmap
220 },
221 {
222 "WiseGroup.,Ltd MP-8800 Quad USB Joypad",
223 36,
224 3,
225 mp88xx_3_logical_layout,
226 mp88xx_3_logical_axismap,
227 NULL,
228 NULL,
229 mp88xx_3_logical_buttonmap
230 },
231 {
232 "WiseGroup.,Ltd MP-8800 Quad USB Joypad",
233 48,
234 4,
235 mp88xx_4_logical_layout,
236 mp88xx_4_logical_axismap,
237 NULL,
238 NULL,
239 mp88xx_4_logical_buttonmap
240 }
241};
242
243/* find the head of a linked list, given a point in it
244 */
245#define SDL_joylist_head(i, start)\
246 for(i = start; SDL_joylist[i].fname == NULL;) i = SDL_joylist[i].prev;
247
248#define SDL_logical_joydecl(d) d
249
250
251#else
252
253#define SDL_logical_joydecl(d)
254
255#endif /* USE_LOGICAL_JOYSTICKS */
256
257/* The maximum number of joysticks we'll detect */
258#define MAX_JOYSTICKS 32
259
260/* A list of available joysticks */
261static struct
262{
263 char* fname;
264#ifndef NO_LOGICAL_JOYSTICKS
265 SDL_Joystick* joy;
266 struct joystick_logicalmap* map;
267 int prev;
268 int next;
269 int logicalno;
270#endif /* USE_LOGICAL_JOYSTICKS */
271} SDL_joylist[MAX_JOYSTICKS];
272
273
274/* The private structure used to keep track of a joystick */
275struct joystick_hwdata {
276 int fd;
277 /* The current linux joystick driver maps hats to two axes */
278 struct hwdata_hat {
279 int axis[2];
280 } *hats;
281 /* The current linux joystick driver maps balls to two axes */
282 struct hwdata_ball {
283 int axis[2];
284 } *balls;
285
286 /* Support for the Linux 2.4 unified input interface */
287#if SDL_INPUT_LINUXEV
288 SDL_bool is_hid;
289 Uint8 key_map[KEY_MAX-BTN_MISC];
290 Uint8 abs_map[ABS_MAX];
291 struct axis_correct {
292 int used;
293 int coef[3];
294 } abs_correct[ABS_MAX];
295#endif
296};
297
298
299#ifndef NO_LOGICAL_JOYSTICKS
300
301static int CountLogicalJoysticks(int max)
302{
303 register int i, j, k, ret, prev;
304 const char* name;
305 int nbuttons, fd;
306 unsigned char n;
307
308 ret = 0;
309
310 for(i = 0; i < max; i++) {
311 name = SDL_SYS_JoystickName(i);
312
313 fd = open(SDL_joylist[i].fname, O_RDONLY, 0);
314 if ( fd >= 0 ) {
315 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
316 nbuttons = -1;
317 } else {
318 nbuttons = n;
319 }
320 close(fd);
321 }
322 else {
323 nbuttons=-1;
324 }
325
326 if (name) {
327 for(j = 0; j < SDL_arraysize(joystick_logicalmap); j++) {
328 if (!SDL_strcmp(name, joystick_logicalmap[j].name) && (nbuttons==-1 || nbuttons==joystick_logicalmap[j].nbuttons)) {
329 prev = i;
330 SDL_joylist[prev].map = &(joystick_logicalmap[j]);
331
332 for(k = 1; k < joystick_logicalmap[j].njoys; k++) {
333 SDL_joylist[prev].next = max + ret;
334 SDL_joylist[max+ret].prev = prev;
335
336 prev = max + ret;
337 SDL_joylist[prev].logicalno = k;
338 SDL_joylist[prev].map = &(joystick_logicalmap[j]);
339 ret++;
340 }
341
342 break;
343 }
344 }
345 }
346 }
347
348 return ret;
349}
350
351static void LogicalSuffix(int logicalno, char* namebuf, int len)
352{
353 register int slen;
354 const static char suffixs[] =
355 "01020304050607080910111213141516171819"
356 "20212223242526272829303132";
357 const char* suffix;
358 slen = SDL_strlen(namebuf);
359 suffix = NULL;
360
361 if (logicalno*2<sizeof(suffixs))
362 suffix = suffixs + (logicalno*2);
363
364 if (slen + 4 < len && suffix) {
365 namebuf[slen++] = ' ';
366 namebuf[slen++] = '#';
367 namebuf[slen++] = suffix[0];
368 namebuf[slen++] = suffix[1];
369 namebuf[slen++] = 0;
370 }
371}
372
373#endif /* USE_LOGICAL_JOYSTICKS */
374
375#if SDL_INPUT_LINUXEV
376#define test_bit(nr, addr) \
377 (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
378#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
379
380static int EV_IsJoystick(int fd)
381{
382 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
383 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
384 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
385
386 if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
387 (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
388 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) {
389 return(0);
390 }
391 if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
392 test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
393 (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0;
394 return(1);
395}
396
397#endif /* SDL_INPUT_LINUXEV */
398
399/* Function to scan the system for joysticks */
400int SDL_SYS_JoystickInit(void)
401{
402 /* The base path of the joystick devices */
403 const char *joydev_pattern[] = {
404#if SDL_INPUT_LINUXEV
405 "/dev/input/event%d",
406#endif
407 "/dev/input/js%d",
408 "/dev/js%d"
409 };
410 int numjoysticks;
411 int i, j;
412 int fd;
413 char path[PATH_MAX];
414 dev_t dev_nums[MAX_JOYSTICKS]; /* major/minor device numbers */
415 struct stat sb;
416 int n, duplicate;
417
418 numjoysticks = 0;
419
420 /* First see if the user specified one or more joysticks to use */
421 if ( SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL ) {
422 char *envcopy, *envpath, *delim;
423 envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
424 envpath = envcopy;
425 while ( envpath != NULL ) {
426 delim = SDL_strchr(envpath, ':');
427 if ( delim != NULL ) {
428 *delim++ = '\0';
429 }
430 if ( stat(envpath, &sb) == 0 ) {
431 fd = open(envpath, O_RDONLY, 0);
432 if ( fd >= 0 ) {
433 /* Assume the user knows what they're doing. */
434 SDL_joylist[numjoysticks].fname = SDL_strdup(envpath);
435 if ( SDL_joylist[numjoysticks].fname ) {
436 dev_nums[numjoysticks] = sb.st_rdev;
437 ++numjoysticks;
438 }
439 close(fd);
440 }
441 }
442 envpath = delim;
443 }
444 SDL_free(envcopy);
445 }
446
447 for ( i=0; i<SDL_arraysize(joydev_pattern); ++i ) {
448 for ( j=0; j < MAX_JOYSTICKS; ++j ) {
449 SDL_snprintf(path, SDL_arraysize(path), joydev_pattern[i], j);
450
451 /* rcg06302000 replaced access(F_OK) call with stat().
452 * stat() will fail if the file doesn't exist, so it's
453 * equivalent behaviour.
454 */
455 if ( stat(path, &sb) == 0 ) {
456 /* Check to make sure it's not already in list.
457 * This happens when we see a stick via symlink.
458 */
459 duplicate = 0;
460 for (n=0; (n<numjoysticks) && !duplicate; ++n) {
461 if ( sb.st_rdev == dev_nums[n] ) {
462 duplicate = 1;
463 }
464 }
465 if (duplicate) {
466 continue;
467 }
468
469 fd = open(path, O_RDONLY, 0);
470 if ( fd < 0 ) {
471 continue;
472 }
473#if SDL_INPUT_LINUXEV
474#ifdef DEBUG_INPUT_EVENTS
475 printf("Checking %s\n", path);
476#endif
477 if ( (i == 0) && ! EV_IsJoystick(fd) ) {
478 close(fd);
479 continue;
480 }
481#endif
482 close(fd);
483
484 /* We're fine, add this joystick */
485 SDL_joylist[numjoysticks].fname = SDL_strdup(path);
486 if ( SDL_joylist[numjoysticks].fname ) {
487 dev_nums[numjoysticks] = sb.st_rdev;
488 ++numjoysticks;
489 }
490 }
491 }
492
493#if SDL_INPUT_LINUXEV
494 /* This is a special case...
495 If the event devices are valid then the joystick devices
496 will be duplicates but without extra information about their
497 hats or balls. Unfortunately, the event devices can't
498 currently be calibrated, so it's a win-lose situation.
499 So : /dev/input/eventX = /dev/input/jsY = /dev/jsY
500 */
501 if ( (i == 0) && (numjoysticks > 0) )
502 break;
503#endif
504 }
505#ifndef NO_LOGICAL_JOYSTICKS
506 numjoysticks += CountLogicalJoysticks(numjoysticks);
507#endif
508
509 return(numjoysticks);
510}
511
512/* Function to get the device-dependent name of a joystick */
513const char *SDL_SYS_JoystickName(int index)
514{
515 int fd;
516 static char namebuf[128];
517 char *name;
518 SDL_logical_joydecl(int oindex = index);
519
520#ifndef NO_LOGICAL_JOYSTICKS
521 SDL_joylist_head(index, index);
522#endif
523 name = NULL;
524 fd = open(SDL_joylist[index].fname, O_RDONLY, 0);
525 if ( fd >= 0 ) {
526 if (
527#if SDL_INPUT_LINUXEV
528 (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) &&
529#endif
530 (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) {
531 name = SDL_joylist[index].fname;
532 } else {
533 name = namebuf;
534 }
535 close(fd);
536
537
538#ifndef NO_LOGICAL_JOYSTICKS
539 if (SDL_joylist[oindex].prev || SDL_joylist[oindex].next || index!=oindex)
540 {
541 LogicalSuffix(SDL_joylist[oindex].logicalno, namebuf, 128);
542 }
543#endif
544 }
545 return name;
546}
547
548static int allocate_hatdata(SDL_Joystick *joystick)
549{
550 int i;
551
552 joystick->hwdata->hats = (struct hwdata_hat *)SDL_malloc(
553 joystick->nhats * sizeof(struct hwdata_hat));
554 if ( joystick->hwdata->hats == NULL ) {
555 return(-1);
556 }
557 for ( i=0; i<joystick->nhats; ++i ) {
558 joystick->hwdata->hats[i].axis[0] = 1;
559 joystick->hwdata->hats[i].axis[1] = 1;
560 }
561 return(0);
562}
563
564static int allocate_balldata(SDL_Joystick *joystick)
565{
566 int i;
567
568 joystick->hwdata->balls = (struct hwdata_ball *)SDL_malloc(
569 joystick->nballs * sizeof(struct hwdata_ball));
570 if ( joystick->hwdata->balls == NULL ) {
571 return(-1);
572 }
573 for ( i=0; i<joystick->nballs; ++i ) {
574 joystick->hwdata->balls[i].axis[0] = 0;
575 joystick->hwdata->balls[i].axis[1] = 0;
576 }
577 return(0);
578}
579
580static SDL_bool JS_ConfigJoystick(SDL_Joystick *joystick, int fd)
581{
582 SDL_bool handled;
583 unsigned char n;
584 int tmp_naxes, tmp_nhats, tmp_nballs;
585 const char *name;
586 char *env, env_name[128];
587 int i;
588
589 handled = SDL_FALSE;
590
591 /* Default joystick device settings */
592 if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
593 joystick->naxes = 2;
594 } else {
595 joystick->naxes = n;
596 }
597 if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
598 joystick->nbuttons = 2;
599 } else {
600 joystick->nbuttons = n;
601 }
602
603 name = SDL_SYS_JoystickName(joystick->index);
604
605 /* Generic analog joystick support */
606 if ( SDL_strstr(name, "Analog") == name && SDL_strstr(name, "-hat") ) {
607 if ( SDL_sscanf(name,"Analog %d-axis %*d-button %d-hat",
608 &tmp_naxes, &tmp_nhats) == 2 ) {
609
610 joystick->naxes = tmp_naxes;
611 joystick->nhats = tmp_nhats;
612
613 handled = SDL_TRUE;
614 }
615 }
616
617 /* Special joystick support */
618 for ( i=0; i < SDL_arraysize(special_joysticks); ++i ) {
619 if ( SDL_strcmp(name, special_joysticks[i].name) == 0 ) {
620
621 joystick->naxes = special_joysticks[i].naxes;
622 joystick->nhats = special_joysticks[i].nhats;
623 joystick->nballs = special_joysticks[i].nballs;
624
625 handled = SDL_TRUE;
626 break;
627 }
628 }
629
630 /* User environment joystick support */
631 if ( (env = SDL_getenv("SDL_LINUX_JOYSTICK")) ) {
632 *env_name = '\0';
633 if ( *env == '\'' && SDL_sscanf(env, "'%[^']s'", env_name) == 1 )
634 env += SDL_strlen(env_name)+2;
635 else if ( SDL_sscanf(env, "%s", env_name) == 1 )
636 env += SDL_strlen(env_name);
637
638 if ( SDL_strcmp(name, env_name) == 0 ) {
639
640 if ( SDL_sscanf(env, "%d %d %d", &tmp_naxes, &tmp_nhats,
641 &tmp_nballs) == 3 ) {
642
643 joystick->naxes = tmp_naxes;
644 joystick->nhats = tmp_nhats;
645 joystick->nballs = tmp_nballs;
646
647 handled = SDL_TRUE;
648 }
649 }
650 }
651
652 /* Remap hats and balls */
653 if (handled) {
654 if ( joystick->nhats > 0 ) {
655 if ( allocate_hatdata(joystick) < 0 ) {
656 joystick->nhats = 0;
657 }
658 }
659 if ( joystick->nballs > 0 ) {
660 if ( allocate_balldata(joystick) < 0 ) {
661 joystick->nballs = 0;
662 }
663 }
664 }
665
666 return(handled);
667}
668
669#if SDL_INPUT_LINUXEV
670
671static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd)
672{
673 int i, t;
674 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
675 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
676 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
677
678 /* See if this device uses the new unified event API */
679 if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
680 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
681 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) {
682 joystick->hwdata->is_hid = SDL_TRUE;
683
684 /* Get the number of buttons, axes, and other thingamajigs */
685 for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) {
686 if ( test_bit(i, keybit) ) {
687#ifdef DEBUG_INPUT_EVENTS
688 printf("Joystick has button: 0x%x\n", i);
689#endif
690 joystick->hwdata->key_map[i-BTN_MISC] =
691 joystick->nbuttons;
692 ++joystick->nbuttons;
693 }
694 }
695 for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) {
696 if ( test_bit(i, keybit) ) {
697#ifdef DEBUG_INPUT_EVENTS
698 printf("Joystick has button: 0x%x\n", i);
699#endif
700 joystick->hwdata->key_map[i-BTN_MISC] =
701 joystick->nbuttons;
702 ++joystick->nbuttons;
703 }
704 }
705 for ( i=0; i<ABS_MISC; ++i ) {
706 /* Skip hats */
707 if ( i == ABS_HAT0X ) {
708 i = ABS_HAT3Y;
709 continue;
710 }
711 if ( test_bit(i, absbit) ) {
712 struct input_absinfo absinfo;
713
714 if ( ioctl(fd, EVIOCGABS(i), &absinfo) < 0 )
715 continue;
716#ifdef DEBUG_INPUT_EVENTS
717 printf("Joystick has absolute axis: %x\n", i);
718 printf("Values = { %d, %d, %d, %d, %d }\n",
719 absinfo.value, absinfo.minimum,
720 absinfo.maximum, absinfo.fuzz, absinfo.flat);
721#endif /* DEBUG_INPUT_EVENTS */
722 joystick->hwdata->abs_map[i] = joystick->naxes;
723 if ( absinfo.minimum == absinfo.maximum ) {
724 joystick->hwdata->abs_correct[i].used = 0;
725 } else {
726 joystick->hwdata->abs_correct[i].used = 1;
727 joystick->hwdata->abs_correct[i].coef[0] =
728 (absinfo.maximum + absinfo.minimum) / 2 - absinfo.flat;
729 joystick->hwdata->abs_correct[i].coef[1] =
730 (absinfo.maximum + absinfo.minimum) / 2 + absinfo.flat;
731 t = ((absinfo.maximum - absinfo.minimum) / 2 - 2 * absinfo.flat);
732 if ( t != 0 ) {
733 joystick->hwdata->abs_correct[i].coef[2] = (1 << 29) / t;
734 } else {
735 joystick->hwdata->abs_correct[i].coef[2] = 0;
736 }
737 }
738 ++joystick->naxes;
739 }
740 }
741 for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) {
742 if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) {
743#ifdef DEBUG_INPUT_EVENTS
744 printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2);
745#endif
746 ++joystick->nhats;
747 }
748 }
749 if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) {
750 ++joystick->nballs;
751 }
752
753 /* Allocate data to keep track of these thingamajigs */
754 if ( joystick->nhats > 0 ) {
755 if ( allocate_hatdata(joystick) < 0 ) {
756 joystick->nhats = 0;
757 }
758 }
759 if ( joystick->nballs > 0 ) {
760 if ( allocate_balldata(joystick) < 0 ) {
761 joystick->nballs = 0;
762 }
763 }
764 }
765 return(joystick->hwdata->is_hid);
766}
767
768#endif /* SDL_INPUT_LINUXEV */
769
770#ifndef NO_LOGICAL_JOYSTICKS
771static void ConfigLogicalJoystick(SDL_Joystick *joystick)
772{
773 struct joystick_logical_layout* layout;
774
775 layout = SDL_joylist[joystick->index].map->layout +
776 SDL_joylist[joystick->index].logicalno;
777
778 joystick->nbuttons = layout->nbuttons;
779 joystick->nhats = layout->nhats;
780 joystick->naxes = layout->naxes;
781 joystick->nballs = layout->nballs;
782}
783#endif
784
785
786/* Function to open a joystick for use.
787 The joystick to open is specified by the index field of the joystick.
788 This should fill the nbuttons and naxes fields of the joystick structure.
789 It returns 0, or -1 if there is an error.
790 */
791int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
792{
793 int fd;
794 SDL_logical_joydecl(int realindex);
795 SDL_logical_joydecl(SDL_Joystick *realjoy = NULL);
796
797 /* Open the joystick and set the joystick file descriptor */
798#ifndef NO_LOGICAL_JOYSTICKS
799 if (SDL_joylist[joystick->index].fname == NULL) {
800 SDL_joylist_head(realindex, joystick->index);
801 realjoy = SDL_JoystickOpen(realindex);
802
803 if (realjoy == NULL)
804 return(-1);
805
806 fd = realjoy->hwdata->fd;
807
808 } else {
809 fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0);
810 }
811 SDL_joylist[joystick->index].joy = joystick;
812#else
813 fd = open(SDL_joylist[joystick->index].fname, O_RDONLY, 0);
814#endif
815
816 if ( fd < 0 ) {
817 SDL_SetError("Unable to open %s\n",
818 SDL_joylist[joystick->index]);
819 return(-1);
820 }
821 joystick->hwdata = (struct joystick_hwdata *)
822 SDL_malloc(sizeof(*joystick->hwdata));
823 if ( joystick->hwdata == NULL ) {
824 SDL_OutOfMemory();
825 close(fd);
826 return(-1);
827 }
828 SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
829 joystick->hwdata->fd = fd;
830
831 /* Set the joystick to non-blocking read mode */
832 fcntl(fd, F_SETFL, O_NONBLOCK);
833
834 /* Get the number of buttons and axes on the joystick */
835#ifndef NO_LOGICAL_JOYSTICKS
836 if (realjoy)
837 ConfigLogicalJoystick(joystick);
838 else
839#endif
840#if SDL_INPUT_LINUXEV
841 if ( ! EV_ConfigJoystick(joystick, fd) )
842#endif
843 JS_ConfigJoystick(joystick, fd);
844
845 return(0);
846}
847
848#ifndef NO_LOGICAL_JOYSTICKS
849
850static SDL_Joystick* FindLogicalJoystick(
851 SDL_Joystick *joystick, struct joystick_logical_mapping* v)
852{
853 SDL_Joystick *logicaljoy;
854 register int i;
855
856 i = joystick->index;
857 logicaljoy = NULL;
858
859 /* get the fake joystick that will receive the event
860 */
861 for(;;) {
862
863 if (SDL_joylist[i].logicalno == v->njoy) {
864 logicaljoy = SDL_joylist[i].joy;
865 break;
866 }
867
868 if (SDL_joylist[i].next == 0)
869 break;
870
871 i = SDL_joylist[i].next;
872
873 }
874
875 return logicaljoy;
876}
877
878static int LogicalJoystickButton(
879 SDL_Joystick *joystick, Uint8 button, Uint8 state){
880 struct joystick_logical_mapping* buttons;
881 SDL_Joystick *logicaljoy = NULL;
882
883 /* if there's no map then this is just a regular joystick
884 */
885 if (SDL_joylist[joystick->index].map == NULL)
886 return 0;
887
888 /* get the logical joystick that will receive the event
889 */
890 buttons = SDL_joylist[joystick->index].map->buttonmap+button;
891 logicaljoy = FindLogicalJoystick(joystick, buttons);
892
893 if (logicaljoy == NULL)
894 return 1;
895
896 SDL_PrivateJoystickButton(logicaljoy, buttons->nthing, state);
897
898 return 1;
899}
900
901static int LogicalJoystickAxis(
902 SDL_Joystick *joystick, Uint8 axis, Sint16 value)
903{
904 struct joystick_logical_mapping* axes;
905 SDL_Joystick *logicaljoy = NULL;
906
907 /* if there's no map then this is just a regular joystick
908 */
909 if (SDL_joylist[joystick->index].map == NULL)
910 return 0;
911
912 /* get the logical joystick that will receive the event
913 */
914 axes = SDL_joylist[joystick->index].map->axismap+axis;
915 logicaljoy = FindLogicalJoystick(joystick, axes);
916
917 if (logicaljoy == NULL)
918 return 1;
919
920 SDL_PrivateJoystickAxis(logicaljoy, axes->nthing, value);
921
922 return 1;
923}
924#endif /* USE_LOGICAL_JOYSTICKS */
925
926static __inline__
927void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
928{
929 struct hwdata_hat *the_hat;
930 const Uint8 position_map[3][3] = {
931 { SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
932 { SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
933 { SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
934 };
935 SDL_logical_joydecl(SDL_Joystick *logicaljoy = NULL);
936 SDL_logical_joydecl(struct joystick_logical_mapping* hats = NULL);
937
938 if (stick->nhats <= hat) {
939 return; /* whoops, that shouldn't happen! */
940 }
941
942 the_hat = &stick->hwdata->hats[hat];
943 if ( value < 0 ) {
944 value = 0;
945 } else
946 if ( value == 0 ) {
947 value = 1;
948 } else
949 if ( value > 0 ) {
950 value = 2;
951 }
952 if ( value != the_hat->axis[axis] ) {
953 the_hat->axis[axis] = value;
954
955#ifndef NO_LOGICAL_JOYSTICKS
956 /* if there's no map then this is just a regular joystick
957 */
958 if (SDL_joylist[stick->index].map != NULL) {
959
960 /* get the fake joystick that will receive the event
961 */
962 hats = SDL_joylist[stick->index].map->hatmap+hat;
963 logicaljoy = FindLogicalJoystick(stick, hats);
964 }
965
966 if (logicaljoy) {
967 stick = logicaljoy;
968 hat = hats->nthing;
969 }
970#endif /* USE_LOGICAL_JOYSTICKS */
971
972 SDL_PrivateJoystickHat(stick, hat,
973 position_map[the_hat->axis[1]][the_hat->axis[0]]);
974 }
975}
976
977static __inline__
978void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
979{
980 if ((stick->nballs <= ball) || (axis >= 2)) {
981 return; /* whoops, that shouldn't happen! */
982 }
983 stick->hwdata->balls[ball].axis[axis] += value;
984}
985
986/* Function to update the state of a joystick - called as a device poll.
987 * This function shouldn't update the joystick structure directly,
988 * but instead should call SDL_PrivateJoystick*() to deliver events
989 * and update joystick device state.
990 */
991static __inline__ void JS_HandleEvents(SDL_Joystick *joystick)
992{
993 struct js_event events[32];
994 int i, len;
995 Uint8 other_axis;
996
997#ifndef NO_LOGICAL_JOYSTICKS
998 if (SDL_joylist[joystick->index].fname == NULL) {
999 SDL_joylist_head(i, joystick->index);
1000 JS_HandleEvents(SDL_joylist[i].joy);
1001 return;
1002 }
1003#endif
1004
1005 while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1006 len /= sizeof(events[0]);
1007 for ( i=0; i<len; ++i ) {
1008 switch (events[i].type & ~JS_EVENT_INIT) {
1009 case JS_EVENT_AXIS:
1010 if ( events[i].number < joystick->naxes ) {
1011#ifndef NO_LOGICAL_JOYSTICKS
1012 if (!LogicalJoystickAxis(joystick,
1013 events[i].number, events[i].value))
1014#endif
1015 SDL_PrivateJoystickAxis(joystick,
1016 events[i].number, events[i].value);
1017 break;
1018 }
1019 events[i].number -= joystick->naxes;
1020 other_axis = (events[i].number / 2);
1021 if ( other_axis < joystick->nhats ) {
1022 HandleHat(joystick, other_axis,
1023 events[i].number%2,
1024 events[i].value);
1025 break;
1026 }
1027 events[i].number -= joystick->nhats*2;
1028 other_axis = (events[i].number / 2);
1029 if ( other_axis < joystick->nballs ) {
1030 HandleBall(joystick, other_axis,
1031 events[i].number%2,
1032 events[i].value);
1033 break;
1034 }
1035 break;
1036 case JS_EVENT_BUTTON:
1037#ifndef NO_LOGICAL_JOYSTICKS
1038 if (!LogicalJoystickButton(joystick,
1039 events[i].number, events[i].value))
1040#endif
1041 SDL_PrivateJoystickButton(joystick,
1042 events[i].number, events[i].value);
1043 break;
1044 default:
1045 /* ?? */
1046 break;
1047 }
1048 }
1049 }
1050}
1051#if SDL_INPUT_LINUXEV
1052static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value)
1053{
1054 struct axis_correct *correct;
1055
1056 correct = &joystick->hwdata->abs_correct[which];
1057 if ( correct->used ) {
1058 if ( value > correct->coef[0] ) {
1059 if ( value < correct->coef[1] ) {
1060 return 0;
1061 }
1062 value -= correct->coef[1];
1063 } else {
1064 value -= correct->coef[0];
1065 }
1066 value *= correct->coef[2];
1067 value >>= 14;
1068 }
1069
1070 /* Clamp and return */
1071 if ( value < -32768 ) return -32768;
1072 if ( value > 32767 ) return 32767;
1073
1074 return value;
1075}
1076
1077static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
1078{
1079 struct input_event events[32];
1080 int i, len;
1081 int code;
1082
1083#ifndef NO_LOGICAL_JOYSTICKS
1084 if (SDL_joylist[joystick->index].fname == NULL) {
1085 SDL_joylist_head(i, joystick->index);
1086 return EV_HandleEvents(SDL_joylist[i].joy);
1087 }
1088#endif
1089
1090 while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1091 len /= sizeof(events[0]);
1092 for ( i=0; i<len; ++i ) {
1093 code = events[i].code;
1094 switch (events[i].type) {
1095 case EV_KEY:
1096 if ( code >= BTN_MISC ) {
1097 code -= BTN_MISC;
1098#ifndef NO_LOGICAL_JOYSTICKS
1099 if (!LogicalJoystickButton(joystick,
1100 joystick->hwdata->key_map[code],
1101 events[i].value))
1102#endif
1103 SDL_PrivateJoystickButton(joystick,
1104 joystick->hwdata->key_map[code],
1105 events[i].value);
1106 }
1107 break;
1108 case EV_ABS:
1109 switch (code) {
1110 case ABS_HAT0X:
1111 case ABS_HAT0Y:
1112 case ABS_HAT1X:
1113 case ABS_HAT1Y:
1114 case ABS_HAT2X:
1115 case ABS_HAT2Y:
1116 case ABS_HAT3X:
1117 case ABS_HAT3Y:
1118 code -= ABS_HAT0X;
1119 HandleHat(joystick, code/2, code%2,
1120 events[i].value);
1121 break;
1122 default:
1123 events[i].value = EV_AxisCorrect(joystick, code, events[i].value);
1124#ifndef NO_LOGICAL_JOYSTICKS
1125 if (!LogicalJoystickAxis(joystick,
1126 joystick->hwdata->abs_map[code],
1127 events[i].value))
1128#endif
1129 SDL_PrivateJoystickAxis(joystick,
1130 joystick->hwdata->abs_map[code],
1131 events[i].value);
1132 break;
1133 }
1134 break;
1135 case EV_REL:
1136 switch (code) {
1137 case REL_X:
1138 case REL_Y:
1139 code -= REL_X;
1140 HandleBall(joystick, code/2, code%2,
1141 events[i].value);
1142 break;
1143 default:
1144 break;
1145 }
1146 break;
1147 default:
1148 break;
1149 }
1150 }
1151 }
1152}
1153#endif /* SDL_INPUT_LINUXEV */
1154
1155void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
1156{
1157 int i;
1158
1159#if SDL_INPUT_LINUXEV
1160 if ( joystick->hwdata->is_hid )
1161 EV_HandleEvents(joystick);
1162 else
1163#endif
1164 JS_HandleEvents(joystick);
1165
1166 /* Deliver ball motion updates */
1167 for ( i=0; i<joystick->nballs; ++i ) {
1168 int xrel, yrel;
1169
1170 xrel = joystick->hwdata->balls[i].axis[0];
1171 yrel = joystick->hwdata->balls[i].axis[1];
1172 if ( xrel || yrel ) {
1173 joystick->hwdata->balls[i].axis[0] = 0;
1174 joystick->hwdata->balls[i].axis[1] = 0;
1175 SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel);
1176 }
1177 }
1178}
1179
1180/* Function to close a joystick after use */
1181void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
1182{
1183#ifndef NO_LOGICAL_JOYSTICKS
1184 register int i;
1185 if (SDL_joylist[joystick->index].fname == NULL) {
1186 SDL_joylist_head(i, joystick->index);
1187 SDL_JoystickClose(SDL_joylist[i].joy);
1188 }
1189#endif
1190
1191 if ( joystick->hwdata ) {
1192#ifndef NO_LOGICAL_JOYSTICKS
1193 if (SDL_joylist[joystick->index].fname != NULL)
1194#endif
1195 close(joystick->hwdata->fd);
1196 if ( joystick->hwdata->hats ) {
1197 SDL_free(joystick->hwdata->hats);
1198 }
1199 if ( joystick->hwdata->balls ) {
1200 SDL_free(joystick->hwdata->balls);
1201 }
1202 SDL_free(joystick->hwdata);
1203 joystick->hwdata = NULL;
1204 }
1205}
1206
1207/* Function to perform any system-specific joystick related cleanup */
1208void SDL_SYS_JoystickQuit(void)
1209{
1210 int i;
1211
1212 for ( i=0; SDL_joylist[i].fname; ++i ) {
1213 SDL_free(SDL_joylist[i].fname);
1214 SDL_joylist[i].fname = NULL;
1215 }
1216}
1217
1218#endif /* SDL_JOYSTICK_LINUX */