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