1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Joystick emulation for Linux and BSD. They share too much code to
5 * split this file.
6 *
7 * This uses the deprecated 0.x Linux joystick API.
8 *
9 * Copyright 1997 Bernd Schmidt
10 * Copyright 1998 Krister Walfridsson
11 * Copyright 2003-2006 Richard Drummond
12 * Copyright 2004 Nick Seow (Alternative Linux joystick device path)
13 */
14
15 #include "sysconfig.h"
16 #include "sysdeps.h"
17
18 #include "options.h"
19 #include "memory_uae.h"
20 #include "custom.h"
21 #include "inputdevice.h"
22
23 #define JS_MAXPATHLEN 20 // Longest device name would be "/dev/input/js"
24 char js_prefix[JS_MAXPATHLEN]; // Joystick device, which varies, except number
25
26 #ifdef HAVE_MACHINE_JOYSTICK_H
27
28 /* The BSD way. */
29
30 # include <machine/joystick.h>
31 typedef struct joystick uae_joystick_t;
32
33 #define JS_DEVNAME_PREFIX "joy"
34
35 #else
36
37 /* The Linux way. */
38
39 /* There are too many different versions of <linux/joystick.h>. Rather
40 * than trying to work correctly with all of them, we duplicate the
41 * necessary definitions here. */
42 typedef struct
43 {
44 int buttons;
45 int x;
46 int y;
47 } uae_joystick_t;
48
49 #define JS_DEVNAME_PREFIX "js" // Try this first
50
51 #endif
52
53 /* Hard code these for the old joystick API */
54 #define MAX_BUTTONS 2
55 #define MAX_AXLES 2
56 #define FIRST_AXLE 0
57 #define FIRST_BUTTON 2
58
59 static unsigned int nr_joysticks;
60
61 static int js0, js1;
62
63 struct joy_range
64 {
65 int minx, maxx, miny, maxy;
66 int centrex, centrey;
67 } range0, range1;
68
69
read_joy(unsigned int nr)70 static void read_joy (unsigned int nr)
71 {
72 uae_joystick_t buffer;
73 int len;
74 int fd = nr == 0 ? js0 : js1;
75 struct joy_range *r = nr == 0 ? &range0 : &range1;
76
77 if (currprefs.input_selected_setting == 0) {
78 if (jsem_isjoy (0, &currprefs) != (int)nr && jsem_isjoy (1, &currprefs) != (int)nr)
79 return;
80 }
81
82 len = read(fd, &buffer, sizeof(buffer));
83 if (len != sizeof(buffer))
84 return;
85
86 /* According to old 0.x JS API, we don't know the range
87 * or the centre for either axis, so we try to work these
88 * out as we go along.
89 *
90 * Must be a better way to do this . . .
91 */
92 if (buffer.x < r->minx) r->minx = buffer.x;
93 if (buffer.y < r->miny) r->miny = buffer.y;
94 if (buffer.x > r->maxx) r->maxx = buffer.x;
95 if (buffer.y > r->maxy) r->maxy = buffer.y;
96
97 r->centrex = (r->maxx-r->minx)/2 + r->minx;
98 r->centrey = (r->maxy-r->miny)/2 + r->miny;
99
100 /* Translate these values to be centred on 0 and
101 * feed 'em to the inputdevice system */
102 setjoystickstate (nr, 0, buffer.x - r->centrex, r->centrex );
103 setjoystickstate (nr, 1, buffer.y - r->centrey, r->centrey );
104
105 #ifdef HAVE_MACHINE_JOYSTICK_H
106 setjoybuttonstate (nr, 0, buffer.b1);
107 setjoybuttonstate (nr, 1, buffer.b2);
108 #else
109 setjoybuttonstate (nr, 0, buffer.buttons & 1);
110 setjoybuttonstate (nr, 1, buffer.buttons & 2);
111 #endif
112 }
113
init_joysticks(void)114 static int init_joysticks(void)
115 {
116 char js_path[JS_MAXPATHLEN]; // temporary buffer for device name
117 nr_joysticks = 0;
118 js0 = -1; js1 = -1;
119
120 snprintf (js_prefix, JS_MAXPATHLEN, "/dev/%s", JS_DEVNAME_PREFIX);
121
122 snprintf (js_path, JS_MAXPATHLEN, "%s0", js_prefix);
123 if ((js0 = open (js_path, O_RDONLY)) >= 0)
124 nr_joysticks++;
125
126 snprintf (js_path, JS_MAXPATHLEN, "%s1", js_prefix);
127 if ((js1 = open (js_path, O_RDONLY)) >= 0)
128 nr_joysticks++;
129
130 #ifdef __linux__
131 if (nr_joysticks == 0) {
132 /*
133 * If we haven't found any joysticks yet,
134 * look for /dev/input/js* nodes
135 */
136 sprintf (js_prefix, "/dev/input/%s", JS_DEVNAME_PREFIX);
137
138 snprintf (js_path, JS_MAXPATHLEN, "%s0", js_prefix);
139 if ((js0 = open (js_path, O_RDONLY)) >= 0)
140 nr_joysticks++;
141
142 snprintf (js_path, JS_MAXPATHLEN, "%s1", js_prefix);
143 if ((js1 = open (js_path, O_RDONLY)) >= 0)
144 nr_joysticks++;
145 }
146 #endif
147
148 write_log ("Found %d joystick(s)\n", nr_joysticks);
149
150 range0.minx = INT_MAX;
151 range0.maxx = INT_MIN;
152 range0.miny = INT_MAX;
153 range0.maxy = INT_MIN;
154 range1.minx = INT_MAX;
155 range1.maxx = INT_MIN;
156 range1.miny = INT_MAX;
157 range1.maxy = INT_MIN;
158 range0.centrex = 0;
159 range1.centrey = 0;
160 return 1;
161 }
162
close_joysticks(void)163 static void close_joysticks(void)
164 {
165 if (js0 >= 0)
166 close (js0);
167 if (js1 >= 0)
168 close (js1);
169 }
170
get_joystick_num(void)171 static int get_joystick_num (void)
172 {
173 return nr_joysticks;
174 }
175
acquire_joy(int num,int flags)176 static int acquire_joy (int num, int flags)
177 {
178 return 1;
179 }
180
unacquire_joy(int num)181 static void unacquire_joy (int num)
182 {
183 }
184
read_joysticks(void)185 static void read_joysticks (void)
186 {
187 int i = 0;
188 for ( ; i < get_joystick_num(); i++)
189 read_joy (i);
190 }
191
get_joystick_friendlyname(int joy)192 static TCHAR *get_joystick_friendlyname (int joy)
193 {
194 static char name[100];
195 sprintf (name, "%d: %s%d", joy + 1, js_prefix, joy);
196 return name;
197 }
198
get_joystick_uniquename(int joy)199 static TCHAR *get_joystick_uniquename (int joy)
200 {
201 static char name[100];
202 sprintf (name, "%d%s%d", joy + 1, js_prefix, joy);
203 return name;
204 }
205
get_joystick_widget_num(int joy)206 static int get_joystick_widget_num (int joy)
207 {
208 return MAX_AXLES + MAX_BUTTONS;
209 }
210
get_joystick_widget_type(int joy,int num,TCHAR * name,uae_u32 * dummy)211 static int get_joystick_widget_type (int joy, int num, TCHAR *name, uae_u32 *dummy)
212 {
213 if (num >= MAX_AXLES && num < MAX_AXLES+MAX_BUTTONS) {
214 if (name)
215 sprintf (name, "Button %d", num + 1 - MAX_AXLES);
216 return IDEV_WIDGET_BUTTON;
217 } else if (num < MAX_AXLES) {
218 if (name)
219 sprintf (name, "Axis %d", num + 1);
220 return IDEV_WIDGET_AXIS;
221 }
222 return IDEV_WIDGET_NONE;
223 }
224
get_joystick_widget_first(int joy,int type)225 static int get_joystick_widget_first (int joy, int type)
226 {
227 switch (type) {
228 case IDEV_WIDGET_BUTTON:
229 return FIRST_BUTTON;
230 case IDEV_WIDGET_AXIS:
231 return FIRST_AXLE;
232 }
233
234 return -1;
235 }
236
get_joystick_flags(int num)237 static int get_joystick_flags (int num)
238 {
239 return 0;
240 }
241
242 struct inputdevice_functions inputdevicefunc_joystick = {
243 init_joysticks,
244 close_joysticks,
245 acquire_joy,
246 unacquire_joy,
247 read_joysticks,
248 get_joystick_num,
249 get_joystick_friendlyname,
250 get_joystick_uniquename,
251 get_joystick_widget_num,
252 get_joystick_widget_type,
253 get_joystick_widget_first,
254 get_joystick_flags
255 };
256
257 /*
258 * Set default inputdevice config for joysticks
259 */
input_get_default_joystick(struct uae_input_device * uid,int num,int port,int af,int mode,bool gp)260 int input_get_default_joystick (struct uae_input_device *uid, int num, int port, int af, int mode, bool gp)
261 {
262 unsigned int i;
263
264 for (i = 0; i < nr_joysticks; i++) {
265 port = i & 1;
266 uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_HORIZ : INPUTEVENT_JOY1_HORIZ;
267 uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_VERT : INPUTEVENT_JOY1_VERT;
268 uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON;
269 uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON;
270 uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON;
271 }
272 uid[0].enabled = 1;
273
274 if (i == 0)
275 return 1;
276 return 0;
277 }
278