1 /** \file   joy-unix.c
2  * \brief   Linux/BSD joystick support
3  *
4  * \author  Bernhard Kuhn <kuhn@eikon.e-technik.tu-muenchen.de>
5  * \author  Ulmer Lionel <ulmer@poly.polytechnique.fr>
6  * \author  Marco van den Heuvel <blackystardust68@yahoo.com>
7  * \author  Daniel Sladic <sladic@eecg.toronto.edu>
8  * \author  Krister Walfridsson <cato@df.lth.se>
9  * \author  Luca Montecchiani  <m.luca@usa.net> (http://i.am/m.luca)
10  */
11 
12 /*
13  * This file is part of VICE, the Versatile Commodore Emulator.
14  * See README for copyright notice.
15  *
16  *  This program is free software; you can redistribute it and/or modify
17  *  it under the terms of the GNU General Public License as published by
18  *  the Free Software Foundation; either version 2 of the License, or
19  *  (at your option) any later version.
20  *
21  *  This program is distributed in the hope that it will be useful,
22  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *  GNU General Public License for more details.
25  *
26  *  You should have received a copy of the GNU General Public License
27  *  along with this program; if not, write to the Free Software
28  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29  *  02111-1307  USA.
30  *
31  */
32 
33 #include "vice.h"
34 
35 #if defined(UNIX_COMPILE) && !defined(MACOSX_SUPPORT)
36 
37 #include <fcntl.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 
43 #include "cmdline.h"
44 #include "joy.h"
45 #include "joyport.h"
46 #include "joystick.h"
47 #include "keyboard.h"
48 #include "log.h"
49 #include "resources.h"
50 #include "types.h"
51 
joy_arch_set_device(int port,int new_dev)52 int joy_arch_set_device(int port, int new_dev)
53 {
54     if (new_dev < 0 || new_dev > JOYDEV_MAX) {
55         return -1;
56     }
57 
58     return 0;
59 }
60 
61 /* Resources.  */
62 
joy_arch_resources_init(void)63 int joy_arch_resources_init(void)
64 {
65     return 0;
66 }
67 
68 /* Command-line options.  */
69 
70 static const cmdline_option_t joydev1cmdline_options[] =
71 {
72     { "-joydev1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
73       NULL, NULL, "JoyDevice1", NULL,
74 #ifdef HAS_JOYSTICK
75 #  ifdef HAS_USB_JOYSTICK
76       "<0-13>", "Set device for joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1, 12: USB joystick 0, 13: USB joystick 1)" },
77 #  else
78 #    ifdef HAS_DIGITAL_JOYSTICK
79       "<0-11>", "Set device for joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1)" },
80 #    else
81       "<0-9>", "Set device for joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5)" },
82 #    endif
83 #  endif
84 #else
85       "<0-3>", "Set device for joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2)" },
86 #endif
87     CMDLINE_LIST_END
88 };
89 
90 static const cmdline_option_t joydev2cmdline_options[] =
91 {
92     { "-joydev2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
93       NULL, NULL, "JoyDevice2", NULL,
94 #ifdef HAS_JOYSTICK
95 #  ifdef HAS_USB_JOYSTICK
96       "<0-13>", "Set device for joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1, 12: USB joystick 0, 13: USB joystick 1)" },
97 #  else
98 #    ifdef HAS_DIGITAL_JOYSTICK
99       "<0-11>", "Set device for joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1)" },
100 #    else
101       "<0-9>", "Set device for joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5)" },
102 #    endif
103 #  endif
104 #else
105       "<0-3>", "Set device for joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2)" },
106 #endif
107     CMDLINE_LIST_END
108 };
109 
110 static const cmdline_option_t joydev3cmdline_options[] =
111 {
112     { "-extrajoydev1", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
113       NULL, NULL, "JoyDevice3", NULL,
114 #ifdef HAS_JOYSTICK
115 #  ifdef HAS_USB_JOYSTICK
116       "<0-13>", "Set device for extra joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1, 12: USB joystick 0, 13: USB joystick 1)" },
117 #  else
118 #    ifdef HAS_DIGITAL_JOYSTICK
119       "<0-11>", "Set device for extra joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1)" },
120 #    else
121       "<0-9>", "Set device for extra joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5)" },
122 #    endif
123 #  endif
124 #else
125       "<0-3>", "Set device for extra joystick port 1 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2)" },
126 #endif
127     CMDLINE_LIST_END
128 };
129 
130 static const cmdline_option_t joydev4cmdline_options[] =
131 {
132     { "-extrajoydev2", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
133       NULL, NULL, "JoyDevice4", NULL,
134 #ifdef HAS_JOYSTICK
135 #  ifdef HAS_USB_JOYSTICK
136       "<0-13>", "Set device for extra joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1, 12: USB joystick 0, 13: USB joystick 1)" },
137 #  else
138 #    ifdef HAS_DIGITAL_JOYSTICK
139       "<0-11>", "Set device for extra joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1)" },
140 #    else
141       "<0-9>", "Set device for extra joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5)" },
142 #    endif
143 #  endif
144 #else
145       "<0-3>", "Set device for extra joystick port 2 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2)" },
146 #endif
147     CMDLINE_LIST_END
148 };
149 
150 static const cmdline_option_t joydev5cmdline_options[] =
151 {
152     { "-extrajoydev3", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
153       NULL, NULL, "JoyDevice5", NULL,
154 #ifdef HAS_JOYSTICK
155 #  ifdef HAS_USB_JOYSTICK
156       "<0-13>", "Set device for extra joystick port 3 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1, 12: USB joystick 0, 13: USB joystick 1)" },
157 #  else
158 #    ifdef HAS_DIGITAL_JOYSTICK
159       "<0-11>", "Set device for extra joystick port 3 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5, 10: Digital joystick 0, 11: Digital joystick 1)" },
160 #    else
161       "<0-9>", "Set device for extra joystick port 3 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2, 4: Analog joystick 0, 5: Analog joystick 1, 6: Analog joystick 2, 7: Analog joystick 3, 8: Analog joystick 4, 9: Analog joystick 5)" },
162 #    endif
163 #  endif
164 #else
165       "<0-3>", "Set device for extra joystick port 3 (0: None, 1: Numpad, 2: Keyset 1, 3: Keyset 2)" },
166 #endif
167     CMDLINE_LIST_END
168 };
169 
joy_arch_cmdline_options_init(void)170 int joy_arch_cmdline_options_init(void)
171 {
172     if (joyport_get_port_name(JOYPORT_1)) {
173         if (cmdline_register_options(joydev1cmdline_options) < 0) {
174             return -1;
175         }
176     }
177     if (joyport_get_port_name(JOYPORT_2)) {
178         if (cmdline_register_options(joydev2cmdline_options) < 0) {
179             return -1;
180         }
181     }
182     if (joyport_get_port_name(JOYPORT_3)) {
183         if (cmdline_register_options(joydev3cmdline_options) < 0) {
184             return -1;
185         }
186     }
187     if (joyport_get_port_name(JOYPORT_4)) {
188         if (cmdline_register_options(joydev4cmdline_options) < 0) {
189             return -1;
190         }
191     }
192     if (joyport_get_port_name(JOYPORT_5)) {
193         if (cmdline_register_options(joydev5cmdline_options) < 0) {
194             return -1;
195         }
196     }
197 
198     return 0;
199 }
200 
201 /* ------------------------------------------------------------------------- */
202 
203 #  ifdef HAS_JOYSTICK
204 #    ifdef LINUX_JOYSTICK
205 #      include <linux/joystick.h>
206 
207 /* Compile time New 1.1.xx API presence check */
208 #      ifdef JS_VERSION
209 #        include <sys/ioctl.h>
210 #        include <errno.h>
211 #        define NEW_JOYSTICK 1
212 #        undef HAS_DIGITAL_JOYSTICK
213 static int use_old_api=0;
214 #      else
215 static int use_old_api=1;
216 #      endif
217 
218 #    elif defined(BSD_JOYSTICK)
219 #      ifdef HAVE_MACHINE_JOYSTICK_H
220 #        include <machine/joystick.h>
221 #      endif
222 #      ifdef HAVE_SYS_JOYSTICK_H
223 #        include <sys/joystick.h>
224 #      endif
225 #      define JS_DATA_TYPE joystick
226 #      define JS_RETURN sizeof(struct joystick)
227 int use_old_api=1;
228 #    else
229 #      error Unknown Joystick
230 #    endif
231 
232 #    define ANALOG_JOY_NUM (JOYDEV_ANALOG_5-JOYDEV_ANALOG_0+1)
233 
234 /* file handles for the joystick device files */
235 
236 static int ajoyfd[ANALOG_JOY_NUM] = { -1, -1, -1, -1, -1, -1 };
237 static int djoyfd[2] = { -1, -1 };
238 
239 #    define JOYCALLOOPS 100
240 #    define JOYSENSITIVITY 5
241 static int joyxcal[2];
242 static int joyycal[2];
243 static int joyxmin[2];
244 static int joyxmax[2];
245 static int joyymin[2];
246 static int joyymax[2];
247 
248 log_t joystick_log = LOG_ERR;
249 
250 /* ------------------------------------------------------------------------- */
251 
252 /**********************************************************
253  * Generic high level joy routine                         *
254  **********************************************************/
joy_arch_init(void)255 int joy_arch_init(void)
256 {
257     if (use_old_api) {
258         old_joystick_init();
259     } else {
260         new_joystick_init();
261     }
262 #    ifdef HAS_USB_JOYSTICK
263     usb_joystick_init();
264 #    endif
265     return 0;
266 }
267 
joystick_close(void)268 void joystick_close(void)
269 {
270     if (use_old_api) {
271         old_joystick_close();
272     } else {
273         new_joystick_close();
274     }
275 #    ifdef HAS_USB_JOYSTICK
276     usb_joystick_close();
277 #    endif
278 }
279 
joystick(void)280 void joystick(void)
281 {
282     if (use_old_api) {
283         old_joystick();
284     } else {
285         new_joystick();
286     }
287 #    ifdef HAS_USB_JOYSTICK
288     usb_joystick();
289 #    endif
290 }
291 
292 /** \brief  Struct containing device name and id
293  */
294 typedef struct device_info_s {
295     const char *name;   /**< device name */
296     int         id;     /**< device ID (\see joy.h) */
297 } device_info_t;
298 
299 static device_info_t predefined_device_list[] = {
300 #ifdef HAS_JOYSTICK
301     { "Analog joystick 0",  JOYDEV_ANALOG_0 },
302     { "Analog joystick 1",  JOYDEV_ANALOG_1 },
303     { "Analog joystick 2",  JOYDEV_ANALOG_2 },
304     { "Analog joystick 3",  JOYDEV_ANALOG_3 },
305     { "Analog joystick 4",  JOYDEV_ANALOG_4 },
306     { "Analog joystick 5",  JOYDEV_ANALOG_5 },
307 #endif
308 #ifdef HAS_DIGITAL_JOYSTICK
309     { "Digital joystick 0", JOYDEV_DIGITAL_0 },
310     { "Digital joystick 1", JOYDEV_DIGITAL_1 },
311 #endif
312 #ifdef HAS_USB_JOYSTICK
313     { "USB joystick 0",     JOYDEV_USB_0 },
314     { "USB joystick 1",     JOYDEV_USB_1 },
315 #endif
316     { NULL, -1 }
317 };
318 
319 static int joystickdeviceidx = 0;
320 
joystick_ui_reset_device_list(void)321 void joystick_ui_reset_device_list(void)
322 {
323     joystickdeviceidx = 0;
324 }
325 
326 /* FIXME: proper device names will be returned only when using the "new" API
327           and only for "analog" joysticks. */
joystick_ui_get_next_device_name(int * id)328 const char *joystick_ui_get_next_device_name(int *id)
329 {
330     const char *name;
331     static char jname[0x80];
332     int idx;
333 
334     /* printf("joystick_ui_get_next_device_name  id: %d\n", joystickdeviceidx); */
335 
336     if ((name = predefined_device_list[joystickdeviceidx].name)) {
337         *id = predefined_device_list[joystickdeviceidx].id;
338         joystickdeviceidx++;
339 
340         if (!use_old_api) {
341 #ifdef HAS_JOYSTICK
342 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined (__DragonflyBSD__)
343             if ((*id >= JOYDEV_ANALOG_0) && (*id <= JOYDEV_ANALOG_5)) {
344                 idx = *id - JOYDEV_ANALOG_0;
345                 if (ajoyfd[idx] >= 0) {
346                     sprintf(jname, "%u: ", idx);
347                     ioctl(ajoyfd[idx], JSIOCGNAME (sizeof (jname) - 4), &jname[3]);
348                     *id = idx + JOYDEV_ANALOG_0;
349                     /* printf("joystick_ui_get_next_device_name  got name: %d: %s: %s\n", *id, name, jname); */
350                     return jname;
351                 } else {
352                     /* no joystick at this port */
353                     return NULL;
354                 }
355             }
356 #endif /* BSD */
357 #endif
358         }
359         /* return name from the predefined list instead */
360         return name;
361     }
362     return NULL;
363 }
364 
365 /**********************************************************
366  * Older Joystick routine 0.8x Linux/BSD driver           *
367  **********************************************************/
old_joystick_init(void)368 void old_joystick_init(void)
369 {
370     int i;
371 
372     joystick_log = log_open("Joystick");
373 
374     /* close all device files */
375     for (i = 0; i < 2; i++) {
376         if (ajoyfd[i] != -1) {
377             close(ajoyfd[i]);
378         }
379         if (djoyfd[i] != -1) {
380             close(djoyfd[i]);
381         }
382     }
383 
384     /* open analog device files */
385     for (i = 0; i < 2; i++) {
386 
387         const char *dev;
388 #    ifdef LINUX_JOYSTICK
389         dev = (i == 0) ? "/dev/js0" : "/dev/js1";
390 #    elif defined(BSD_JOYSTICK)
391         dev = (i == 0) ? "/dev/joy0" : "/dev/joy1";
392 #    endif
393 
394         ajoyfd[i] = open(dev, O_RDONLY);
395         if (ajoyfd[i] < 0) {
396             log_warning(joystick_log, "Cannot open joystick device `%s'.", dev);
397         } else {
398             int j;
399 
400             /* calibration loop */
401             for (j = 0; j < JOYCALLOOPS; j++) {
402                 struct JS_DATA_TYPE js;
403                 int status = read(ajoyfd[i], &js, JS_RETURN);
404 
405                 if (status != JS_RETURN) {
406                     log_warning(joystick_log, "Error reading joystick device `%s'.", dev);
407                 } else {
408                     /* determine average */
409                     joyxcal[i] += js.x;
410                     joyycal[i] += js.y;
411                 }
412             }
413 
414             /* correct average */
415             joyxcal[i] /= JOYCALLOOPS;
416             joyycal[i] /= JOYCALLOOPS;
417 
418             /* determine treshoulds */
419             joyxmin[i] = joyxcal[i] - joyxcal[i] / JOYSENSITIVITY;
420             joyxmax[i] = joyxcal[i] + joyxcal[i] / JOYSENSITIVITY;
421             joyymin[i] = joyycal[i] - joyycal[i] / JOYSENSITIVITY;
422             joyymax[i] = joyycal[i] + joyycal[i] / JOYSENSITIVITY;
423 
424             log_message(joystick_log, "Hardware joystick calibration for device `%s':", dev);
425             log_message(joystick_log, "  X: min: %i , mid: %i , max: %i.", joyxmin[i], joyxcal[i], joyxmax[i]);
426             log_message(joystick_log, "  Y: min: %i , mid: %i , max: %i.", joyymin[i], joyycal[i], joyymax[i]);
427         }
428     }
429 
430 #    ifdef HAS_DIGITAL_JOYSTICK
431     /* open device files for digital joystick */
432     for (i = 0; i < 2; i++) {
433         const char *dev;
434         dev = (i == 0) ? "/dev/djs0" : "/dev/djs1";
435 
436         djoyfd[i] = open(dev, O_RDONLY);
437         if (djoyfd[i] < 0) {
438             log_message(joystick_log, "Cannot open joystick device `%s'.", dev);
439         }
440     }
441 #    endif
442 }
443 
old_joystick_close(void)444 void old_joystick_close(void)
445 {
446     if (ajoyfd[0] > 0) {
447         close(ajoyfd[0]);
448     }
449     if (ajoyfd[1] > 0) {
450         close(ajoyfd[1]);
451     }
452     if (djoyfd[0] > 0) {
453         close(djoyfd[0]);
454     }
455     if (djoyfd[1] > 0) {
456         close(djoyfd[1]);
457     }
458 }
459 
old_joystick(void)460 void old_joystick(void)
461 {
462     int i;
463 
464     for (i = 1; i <= 5; i++) {
465         int joyport = joystick_port_map[i - 1];
466 
467 #    ifdef HAS_DIGITAL_JOYSTICK
468         if (joyport == JOYDEV_DIGITAL_0 || joyport == JOYDEV_DIGITAL_1) {
469             int status;
470             struct DJS_DATA_TYPE djs;
471             int djoyport = joyport - JOYDEV_DIGITAL_0;
472 
473             if (djoyfd[djoyport] > 0) {
474                 status = read(djoyfd[djoyport], &djs, DJS_RETURN);
475                 if (status != DJS_RETURN) {
476                     log_error(joystick_log, "Error reading digital joystick device.");
477                 } else {
478                     BYTE newval;
479 
480                     newval = ((joystick_get_value_absolute & 0xe0) | ((~(djs.switches >> 3)) & 0x1f));
481                     joystick_set_value_absolute(i, newval);
482                 }
483             }
484         } else
485 #    endif
486         if (joyport == JOYDEV_ANALOG_0 || joyport == JOYDEV_ANALOG_1) {
487             int status;
488             struct JS_DATA_TYPE js;
489             int ajoyport = joyport - JOYDEV_ANALOG_0;
490 
491             if (ajoyfd[ajoyport] > 0) {
492                 status = read(ajoyfd[ajoyport], &js, JS_RETURN);
493                 if (status != JS_RETURN) {
494                     log_error(joystick_log, "Error reading joystick device.");
495                 } else {
496                     joystick_set_value_absolute(i, 0);
497 
498                     if (js.y < joyymin[ajoyport]) {
499                         joystick_set_value_or(i, 1);
500                     }
501                     if (js.y > joyymax[ajoyport]) {
502                         joystick_set_value_or(i, 2);
503                     }
504                     if (js.x < joyxmin[ajoyport]) {
505                         joystick_set_value_or(i, 4);
506                     }
507                     if (js.x > joyxmax[ajoyport]) {
508                         joystick_set_value_or(i, 8);
509                     }
510 #    ifdef LINUX_JOYSTICK
511                     if (js.buttons) {
512                         joystick_set_value_or(i, 16);
513                     }
514 #    elif defined(BSD_JOYSTICK)
515                     if (js.b1 || js.b2) {
516                         joystick_set_value_or(i, 16);
517                     }
518 #    endif
519                 }
520             }
521         }
522     }
523 }
524 
525 #    ifndef NEW_JOYSTICK
new_joystick_init(void)526 void new_joystick_init(void)
527 {
528 }
529 
new_joystick_close(void)530 void new_joystick_close(void)
531 {
532 }
533 
new_joystick(void)534 void new_joystick(void)
535 {
536 }
537 #    else /* NEW_JOYSTICK */
new_joystick_init(void)538 void new_joystick_init(void)
539 {
540     int i;
541     int ver = 0;
542     int axes, buttons;
543     char name[60];
544     struct JS_DATA_TYPE js;
545 
546     const char *joydevs[ANALOG_JOY_NUM][2] = {
547         { "/dev/js0", "/dev/input/js0" },
548         { "/dev/js1", "/dev/input/js1" },
549         { "/dev/js2", "/dev/input/js2" },
550         { "/dev/js3", "/dev/input/js3" },
551         { "/dev/js4", "/dev/input/js4" },
552         { "/dev/js5", "/dev/input/js5" }
553     };
554 
555     if (joystick_log == LOG_ERR) {
556         joystick_log = log_open("Joystick");
557     }
558 
559     log_message(joystick_log, "Linux joystick interface initialization...");
560     /* close all device files */
561     for (i = 0; i < ANALOG_JOY_NUM; i++) {
562         if (ajoyfd[i] != -1) {
563             close (ajoyfd[i]);
564         }
565     }
566 
567     /* open analog device files */
568 
569     for (i = 0; i < ANALOG_JOY_NUM; i++) {
570         const char *dev;
571         int j;
572         for (j = 0; j < 2; j++) {
573             dev = joydevs[i][j];
574             ajoyfd[i] = open(dev, O_RDONLY);
575             if (ajoyfd[i] >= 0) {
576                 break;
577             }
578         }
579 
580         if (ajoyfd[i] >= 0) {
581             if (read (ajoyfd[i], &js, sizeof(struct JS_DATA_TYPE)) < 0) {
582                 close (ajoyfd[i]);
583                 ajoyfd[i] = -1;
584                 continue;
585             }
586             if (ioctl(ajoyfd[i], JSIOCGVERSION, &ver)) {
587                 log_message(joystick_log, "%s unknown type", dev);
588                 log_message(joystick_log, "Built in driver version: %d.%d.%d", JS_VERSION >> 16, (JS_VERSION >> 8) & 0xff, JS_VERSION & 0xff);
589                 log_message(joystick_log, "Kernel driver version  : 0.8 ??");
590                 log_message(joystick_log, "Please update your Joystick driver!");
591                 log_message(joystick_log, "Fall back to old api routine");
592                 use_old_api = 1;
593                 old_joystick_init();
594                 return;
595             }
596             ioctl(ajoyfd[i], JSIOCGVERSION, &ver);
597             ioctl(ajoyfd[i], JSIOCGAXES, &axes);
598             ioctl(ajoyfd[i], JSIOCGBUTTONS, &buttons);
599             ioctl(ajoyfd[i], JSIOCGNAME (sizeof (name)), name);
600             log_message(joystick_log, "%s is %s", dev, name);
601             log_message(joystick_log, "Built in driver version: %d.%d.%d", JS_VERSION >> 16, (JS_VERSION >> 8) & 0xff, JS_VERSION & 0xff);
602             log_message(joystick_log, "Kernel driver version  : %d.%d.%d", ver >> 16, (ver >> 8) & 0xff, ver & 0xff);
603             fcntl(ajoyfd[i], F_SETFL, O_NONBLOCK);
604         } else {
605             log_warning(joystick_log, "Cannot open joystick device `%s'.", dev);
606         }
607     }
608 }
609 
new_joystick_close(void)610 void new_joystick_close(void)
611 {
612     int i;
613 
614     for (i=0; i<ANALOG_JOY_NUM; ++i) {
615         if (ajoyfd[i] > 0) {
616             close (ajoyfd[i]);
617         }
618     }
619 }
620 
new_joystick(void)621 void new_joystick(void)
622 {
623     int i;
624     struct js_event e;
625     int ajoyport;
626 
627     for (i = 1; i <= 5; i++) {
628         int joyport = joystick_port_map[i - 1];
629 
630         if ((joyport < JOYDEV_ANALOG_0) || (joyport > JOYDEV_ANALOG_5)) {
631             continue;
632         }
633 
634         ajoyport = joyport - JOYDEV_ANALOG_0;
635 
636         if (ajoyfd[ajoyport] < 0) {
637             continue;
638         }
639 
640         /* Read all queued events. */
641         while (read(ajoyfd[ajoyport], &e, sizeof(struct js_event)) == sizeof(struct js_event)) {
642             switch (e.type & ~JS_EVENT_INIT) {
643             case JS_EVENT_BUTTON:
644                 /* Generally, only the first few buttons are "fire" on a modern
645                    joystick, the others being reserved for more esoteric things
646                    like "SELECT", "START", "PAUSE", and directional movement.
647                    The following treats only the first four buttons on a joystick
648                    as fire buttons and ignores the rest.
649                 */
650                 if (! (e.number & ~3)) { /* only first four buttons are fire */
651                     joystick_set_value_and(i, ~16); /* reset fire bit */
652                     if (e.value) {
653                         joystick_set_value_or(i, 16);
654                     }
655                 }
656                 break;
657             case JS_EVENT_AXIS:
658                 if (e.number == 0) {
659                     joystick_set_value_and(i, 19); /* reset 2 bit */
660                     if (e.value > 16384) {
661                         joystick_set_value_or(i, 8);
662                     } else if (e.value < -16384) {
663                         joystick_set_value_or(i, 4);
664                     }
665                 }
666                 if (e.number == 1) {
667                     joystick_set_value_and(i, 28); /* reset 2 bit */
668                     if (e.value > 16384) {
669                         joystick_set_value_or(i, 2);
670                     } else if (e.value < -16384) {
671                         joystick_set_value_or(i, 1);
672                     }
673                 }
674                 break;
675             }
676         }
677     }
678 }
679 #    endif  /* NEW_JOYSTICK */
680 #  else /* HAS_JOYSTICK */
joy_arch_init(void)681 int joy_arch_init(void)
682 {
683     return 0;
684 }
685 
joystick_close(void)686 void joystick_close(void)
687 {
688     /* NOP */
689 }
690 
691 #  endif /* HAS_JOYSTICK */
692 
693 #endif
694