1 /*
2 * E-UAE - The portable Amiga Emulator
3 *
4 * AmigaInput joystick driver
5 *
6 * Copyright 2005 Richard Drummond
7 */
8
9 #include "sysconfig.h"
10 #include "sysdeps.h"
11
12 #include "options.h"
13 #include "inputdevice.h"
14
15 #include <amigainput/amigainput.h>
16 #include <proto/exec.h>
17 #include <proto/amigainput.h>
18
19 #define MAX_JOYSTICKS MAX_INPUT_DEVICES
20 #define MAX_AXES 2
21 #define MAX_BUTTONS 12
22
23 struct Library *AIN_Base;
24 struct AIN_IFace *IAIN;
25
26 /*
27 * Per-joystick data private to driver
28 */
29 struct joystick
30 {
31 AIN_DeviceID id;
32 const char *name;
33
34 AIN_DeviceHandle *handle;
35 APTR context;
36
37 uint32 axisCount;
38 uint32 buttonCount;
39
40 uint32 axisBufferOffset[MAX_AXES];
41 int32 axisData[MAX_AXES];
42
43 uint32 buttonBufferOffset[MAX_BUTTONS];
44 int32 buttonData[MAX_BUTTONS];
45 };
46
47
48 static APTR joystickContext;
49 static uint32 joystickCount;
50 static struct joystick joystickList [MAX_JOYSTICKS];
51
52
openAmigaInput(void)53 static BOOL openAmigaInput (void)
54 {
55 AIN_Base = OpenLibrary ("AmigaInput.library", 51);
56
57 if (AIN_Base) {
58 IAIN = (struct AIN_IFace *) GetInterface (AIN_Base, "main", 1, NULL);
59
60 if (!IAIN) {
61 CloseLibrary (AIN_Base);
62 AIN_Base = NULL;
63 }
64 } else
65 write_log ("Failed to open AmigaInput.library\n");
66
67 return AIN_Base != NULL;
68 }
69
closeAmigaInput(void)70 static void closeAmigaInput (void)
71 {
72 if (IAIN) {
73 DropInterface ((struct Interface *)IAIN);
74 IAIN = NULL;
75 }
76
77 if (AIN_Base) {
78 CloseLibrary (AIN_Base);
79 AIN_Base = NULL;
80 }
81 }
82
83
84 /* A handy container to encapsulate the information we
85 * need when enumerating joysticks on the system.
86 */
87 struct enumPacket
88 {
89 APTR context;
90 uint32 *count;
91 struct joystick *joyList;
92 };
93
94 /*
95 * Callback to enumerate joysticks
96 */
enumerateJoysticks(AIN_Device * device,void * UserData)97 static BOOL enumerateJoysticks (AIN_Device *device, void *UserData)
98 {
99 APTR context = ((struct enumPacket *)UserData)->context;
100 uint32 *count = ((struct enumPacket *)UserData)->count;
101 struct joystick *joy = &((struct enumPacket *)UserData)->joyList[*count];
102
103 BOOL result = FALSE;
104
105 if (*count < MAX_JOYSTICKS) {
106 if (device->Type == AINDT_JOYSTICK) {
107
108 unsigned int i;
109
110 joy->context = context;
111 joy->id = device->DeviceID;
112 joy->name = my_strdup (device->DeviceName);
113 joy->axisCount = device->NumAxes;
114 joy->buttonCount = device->NumButtons;
115
116 if (joy->axisCount > MAX_AXES) joy->axisCount = MAX_AXES;
117 if (joy->buttonCount > MAX_BUTTONS) joy->buttonCount = MAX_BUTTONS;
118
119 /* Query offsets in ReadDevice buffer for axes' data */
120 for (i = 0; i < joy->axisCount; i++)
121 result = AIN_Query (joy->context, joy->id, AINQ_AXIS_OFFSET, i,
122 &(joy->axisBufferOffset[i]), 4);
123
124 /* Query offsets in ReadDevice buffer for buttons' data */
125 for (i = 0; i < joy->buttonCount; i++)
126 result = result && AIN_Query (joy->context, joy->id, AINQ_BUTTON_OFFSET, i,
127 &(joy->buttonBufferOffset[i]), 4);
128
129 if (result) {
130 write_log ("Found joystick #%d (AI ID=%d) '%s' with %d axes, %d buttons\n",
131 *count, joy->id, joy->name, joy->axisCount, joy->buttonCount);
132
133 (*count)++;
134 }
135 }
136 }
137
138 return result;
139 }
140
141
init_joysticks(void)142 static int init_joysticks (void)
143 {
144 int i;
145 int success = 0;
146
147 if (!joystickContext) {
148
149 if (openAmigaInput ()) {
150
151 joystickContext = AIN_CreateContext (1, NULL);
152 if (joystickContext) {
153
154 struct enumPacket packet = {
155 joystickContext, &joystickCount, &joystickList[0]
156 };
157
158 AIN_EnumDevices (joystickContext, enumerateJoysticks, &packet);
159
160 write_log ("Found %d joysticks\n", joystickCount);
161
162 success = 1;
163 }
164 }
165 }
166
167 return success;
168 }
169
close_joysticks(void)170 static void close_joysticks (void)
171 {
172 unsigned int i = joystickCount;
173
174 while (i-- > 0) {
175 struct joystick *joy = &joystickList[i];
176
177 if (joy->handle) {
178 AIN_ReleaseDevice (joy->context, joy->handle);
179 joy->handle = 0;
180 }
181 }
182 joystickCount = 0;
183
184 if (joystickContext)
185 AIN_DeleteContext (joystickContext);
186 joystickContext = 0;
187 }
188
189 #define BUFFER_OFFSET(buffer, offset) (((int32 *)buffer)[offset])
190
read_joy(unsigned int num)191 static void read_joy (unsigned int num)
192 {
193 struct joystick *joy = &joystickList[num];
194
195 if (joy->handle) {
196 void *buffer;
197
198 /*
199 * Poll device for data
200 */
201 if (AIN_ReadDevice (joy->context, joy->handle, &buffer)) {
202 unsigned int i;
203
204 /* Extract axis data from buffer and notify UAE of any changes
205 * in axis state
206 */
207 for (i = 0; i < joy->axisCount; i++) {
208 int axisdata = BUFFER_OFFSET (buffer, joy->axisBufferOffset[i]);
209
210 if (axisdata != joy->axisData[i]) {
211 setjoystickstate (num, i, axisdata, 32767);
212 joy->axisData[i] = axisdata;
213 }
214 }
215
216 /* Extract button data from buffer and notify SDL of any changes
217 * in button state
218 *
219 * Note: We don't support analog buttons.
220 */
221 for (i = 0; i < joy->buttonCount; i++) {
222 int buttondata = BUFFER_OFFSET (buffer, joy->buttonBufferOffset[i]);
223
224 if (buttondata != joy->buttonData[i]) {
225 setjoybuttonstate (num, i, buttondata ? 1 : 0);
226 joy->buttonData[i] = buttondata;
227 }
228 }
229
230 }
231 }
232 }
233
234 /*
235 * Query number of joysticks attached to system
236 */
get_joystick_num(void)237 static unsigned int get_joystick_num (void)
238 {
239 return joystickCount;
240 }
241
242 /*
243 * Query number of 'widgets' supported by joystick #joynum
244 */
get_joystick_widget_num(unsigned int joynum)245 static unsigned int get_joystick_widget_num (unsigned int joynum)
246 {
247 return joystickList[joynum].axisCount + joystickList[joynum].buttonCount;
248 }
249
250 /*
251 * Query type of widget #widgetnum on joystick #joynum
252 */
get_joystick_widget_type(unsigned int joynum,unsigned int widgetnum,char * name,uae_u32 * code)253 static int get_joystick_widget_type (unsigned int joynum, unsigned int widgetnum, char *name, uae_u32 *code)
254 {
255 struct joystick *joy = &joystickList[joynum];
256
257 if (widgetnum >= joy->axisCount && widgetnum < joy->axisCount + joy->buttonCount) {
258 if (name)
259 sprintf (name, "Button %d", widgetnum + 1 - joy->axisCount);
260 return IDEV_WIDGET_BUTTON;
261 } else if (widgetnum < joy->axisCount) {
262 if (name)
263 sprintf (name, "Axis %d", widgetnum + 1);
264 return IDEV_WIDGET_AXIS;
265 }
266 return IDEV_WIDGET_NONE;
267 }
268
get_joystick_widget_first(unsigned int joynum,int type)269 static int get_joystick_widget_first (unsigned int joynum, int type)
270 {
271 switch (type) {
272 case IDEV_WIDGET_BUTTON:
273 return joystickList[joynum].axisCount;
274 case IDEV_WIDGET_AXIS:
275 return 0;
276 }
277 return -1;
278 }
279
get_joystick_friendlyname(unsigned int joynum)280 static const char *get_joystick_friendlyname (unsigned int joynum)
281 {
282 return (char *)joystickList[joynum].name;
283 }
284
get_joystick_uniquename(unsigned int joynum)285 static const char *get_joystick_uniquename (unsigned int joynum)
286 {
287 return (char *)joystickList[joynum].name;
288 }
289
read_joysticks(void)290 static void read_joysticks (void)
291 {
292 unsigned int i = joystickCount;
293
294 while (i > 0)
295 read_joy (--i);
296 }
297
acquire_joy(unsigned int joynum,int flags)298 static int acquire_joy (unsigned int joynum, int flags)
299 {
300 struct joystick *joy = &joystickList[joynum];
301 int result = 0;
302
303 joy->handle = AIN_ObtainDevice (joy->context, joy->id);
304
305 if (joy->handle)
306 result = 1;
307 else
308 write_log ("Failed to acquire joy\n");
309 return result;
310 }
311
unacquire_joy(unsigned int joynum)312 static void unacquire_joy (unsigned int joynum)
313 {
314 struct joystick *joy = &joystickList[joynum];
315
316 if (joy->handle) {
317 AIN_ReleaseDevice (joy->context, joy->handle);
318 joy->handle = 0;
319 }
320 }
321
get_joystick_flags(int num)322 static int get_joystick_flags (int num)
323 {
324 return 0;
325 }
326
327 struct inputdevice_functions inputdevicefunc_joystick = {
328 init_joysticks,
329 close_joysticks,
330 acquire_joy,
331 unacquire_joy,
332 read_joysticks,
333 get_joystick_num,
334 get_joystick_friendlyname,
335 get_joystick_uniquename,
336 get_joystick_widget_num,
337 get_joystick_widget_type,
338 get_joystick_widget_first,
339 get_joystick_flags
340 };
341
342 /*
343 * Set default inputdevice config
344 */
input_get_default_joystick(struct uae_input_device * uid,int num,int port,int cd32)345 int input_get_default_joystick (struct uae_input_device *uid, int num, int port, int cd32)
346 {
347 unsigned int i, port;
348
349 for (i = 0; i < joystickCount; i++) {
350 port = i & 1;
351 uid[i].eventid[ID_AXIS_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_HORIZ : INPUTEVENT_JOY1_HORIZ;
352 uid[i].eventid[ID_AXIS_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_VERT : INPUTEVENT_JOY1_VERT;
353 uid[i].eventid[ID_BUTTON_OFFSET + 0][0] = port ? INPUTEVENT_JOY2_FIRE_BUTTON : INPUTEVENT_JOY1_FIRE_BUTTON;
354 uid[i].eventid[ID_BUTTON_OFFSET + 1][0] = port ? INPUTEVENT_JOY2_2ND_BUTTON : INPUTEVENT_JOY1_2ND_BUTTON;
355 uid[i].eventid[ID_BUTTON_OFFSET + 2][0] = port ? INPUTEVENT_JOY2_3RD_BUTTON : INPUTEVENT_JOY1_3RD_BUTTON;
356 }
357 uid[0].enabled = 1;
358 if (i == 0)
359 return 1;
360 return 0;
361 }
362