1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1997 Andreas Mohr
7 * nearly all joystick functions can be regarded as obsolete,
8 * as Linux (2.1.x) now supports extended joysticks
9 * with a completely new joystick driver interface
10 * new driver's docu says:
11 * "For backward compatibility the old interface is still included,
12 * but will be dropped in the future."
13 * Thus we should implement the new interface and at most keep the old
14 * routines for backward compatibility.
20 * 01/2000 added support for new joystick driver
31 #include <sys/ioctl.h>
32 #ifdef HAVE_LINUX_JOYSTICK_H
33 #include <linux/joystick.h>
34 #define JOYDEV "/dev/js%d"
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
45 #include "debugtools.h"
47 DEFAULT_DEBUG_CHANNEL(joystick);
49 #ifdef HAVE_LINUX_JOYSTICK_H
51 #define MAXJOYSTICK (JOYSTICKID2 + 1)
53 typedef struct tagWINE_JSTCK {
58 static WINE_JSTCK JSTCK_Data[MAXJOYSTICK];
60 /**************************************************************************
61 * JSTCK_drvGet [internal]
63 static WINE_JSTCK* JSTCK_drvGet(DWORD dwDevID)
67 if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
69 p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
70 if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
73 return (WINE_JSTCK*)dwDevID;
76 /**************************************************************************
77 * JSTCK_drvOpen [internal]
79 static DWORD JSTCK_drvOpen(LPSTR str, DWORD dwIntf)
81 if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
84 JSTCK_Data[dwIntf].joyIntf = dwIntf;
85 JSTCK_Data[dwIntf].in_use = 1;
86 return (DWORD)&JSTCK_Data[dwIntf];
89 /**************************************************************************
90 * JSTCK_drvClose [internal]
92 static DWORD JSTCK_drvClose(DWORD dwDevID)
94 WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
109 /**************************************************************************
110 * JSTCK_OpenDevice [internal]
112 static int JSTCK_OpenDevice(WINE_JSTCK* jstick)
117 sprintf(buf, JOYDEV, jstick->joyIntf);
118 #ifdef HAVE_LINUX_22_JOYSTICK_API
119 flags = O_RDONLY | O_NONBLOCK;
123 return open(buf, flags);
126 /**************************************************************************
127 * JoyGetDevCaps [MMSYSTEM.102]
129 static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
132 #ifdef HAVE_LINUX_22_JOYSTICK_API
136 char identString[MAXPNAMELEN];
140 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
141 return MMSYSERR_NODRIVER;
143 #ifdef HAVE_LINUX_22_JOYSTICK_API
145 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
146 ioctl(dev, JSIOCGAXES, &nrOfAxes);
147 ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
148 ioctl(dev, JSIOCGVERSION, &driverVersion);
149 ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
150 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
151 driverVersion, identString, nrOfAxes, nrOfButtons);
152 lpCaps->wMid = MM_MICROSOFT;
153 lpCaps->wPid = MM_PC_JOYSTICK;
154 strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
155 lpCaps->szPname[MAXPNAMELEN-1] = '\0';
157 lpCaps->wXmax = 0xFFFF;
159 lpCaps->wYmax = 0xFFFF;
161 lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
162 lpCaps->wNumButtons = nrOfButtons;
163 if (dwSize == sizeof(JOYCAPSA)) {
164 /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
165 if (nrOfAxes > 6) nrOfAxes = 6;
166 /* complete 95 structure */
168 lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
170 lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
172 lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
173 lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
174 lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
175 lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
176 strcpy(lpCaps->szRegKey, "");
177 strcpy(lpCaps->szOEMVxD, "");
180 case 6: lpCaps->wCaps |= JOYCAPS_HASV;
181 case 5: lpCaps->wCaps |= JOYCAPS_HASU;
182 case 4: lpCaps->wCaps |= JOYCAPS_HASR;
183 case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
184 /* FIXME: don't know how to detect for
185 JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
191 lpCaps->wMid = MM_MICROSOFT;
192 lpCaps->wPid = MM_PC_JOYSTICK;
193 strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
195 lpCaps->wXmax = 0xFFFF;
197 lpCaps->wYmax = 0xFFFF;
200 lpCaps->wNumButtons = 2;
201 if (dwSize == sizeof(JOYCAPSA)) {
202 /* complete 95 structure */
210 lpCaps->wMaxAxes = 2;
211 lpCaps->wNumAxes = 2;
212 lpCaps->wMaxButtons = 4;
213 strcpy(lpCaps->szRegKey,"");
214 strcpy(lpCaps->szOEMVxD,"");
218 return JOYERR_NOERROR;
221 /**************************************************************************
222 * JSTCK_GetPos [internal]
224 static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
228 #ifdef HAVE_LINUX_22_JOYSTICK_API
235 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
236 return MMSYSERR_NODRIVER;
238 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
240 #ifdef HAVE_LINUX_22_JOYSTICK_API
241 /* After opening the device it's state can be
242 read with JS_EVENT_INIT flag */
243 while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
244 if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
247 if (lpInfo->dwFlags & JOY_RETURNX)
248 lpInfo->dwXpos = ev.value + 32767;
251 if (lpInfo->dwFlags & JOY_RETURNY)
252 lpInfo->dwYpos = ev.value + 32767;
255 if (lpInfo->dwFlags & JOY_RETURNZ)
256 lpInfo->dwZpos = ev.value + 32767;
259 if (lpInfo->dwFlags & JOY_RETURNR)
260 lpInfo->dwRpos = ev.value + 32767;
262 if (lpInfo->dwFlags & JOY_RETURNU)
263 lpInfo->dwUpos = ev.value + 32767;
265 if (lpInfo->dwFlags & JOY_RETURNV)
266 lpInfo->dwVpos = ev.value + 32767;
269 FIXME("Unknown joystick event '%d'\n", ev.number);
271 } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
272 if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
274 lpInfo->dwButtons |= (1 << ev.number);
275 /* FIXME: what to do for this field when
276 * multiple buttons are depressed ?
278 lpInfo->dwButtonNumber = ev.number + 1;
283 /* EAGAIN is returned when the queue is empty */
284 if (errno != EAGAIN) {
285 /* FIXME: error should not be ignored */
286 ERR("Error while reading joystick state (%s)\n", strerror(errno));
289 dev_stat = read(dev, &js, sizeof(js));
290 if (dev_stat != sizeof(js)) {
292 return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
296 if (lpInfo->dwFlags & JOY_RETURNX)
297 lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */
298 if (lpInfo->dwFlags & JOY_RETURNY)
299 lpInfo->dwYpos = js.y;
300 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
301 lpInfo->dwButtons = js.buttons;
306 TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n",
307 lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
308 lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
309 (unsigned int)lpInfo->dwButtons,
310 (unsigned int)lpInfo->dwFlags);
312 return JOYERR_NOERROR;
315 /**************************************************************************
316 * JSTCK_GetPos [internal]
318 static LONG JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
323 memset(&ji, 0, sizeof(ji));
325 ji.dwSize = sizeof(ji);
326 ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
327 ret = JSTCK_GetPosEx(dwDevID, &ji);
328 if (ret == JOYERR_NOERROR) {
329 lpInfo->wXpos = ji.dwXpos;
330 lpInfo->wYpos = ji.dwYpos;
331 lpInfo->wZpos = ji.dwZpos;
332 lpInfo->wButtons = ji.dwButtons;
338 /**************************************************************************
339 * JSTCK_DriverProc [internal]
341 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
342 DWORD dwParam1, DWORD dwParam2)
344 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
345 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
348 case DRV_LOAD: return 1;
349 case DRV_FREE: return 1;
350 case DRV_OPEN: return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2);
351 case DRV_CLOSE: return JSTCK_drvClose(dwDevID);
352 case DRV_ENABLE: return 1;
353 case DRV_DISABLE: return 1;
354 case DRV_QUERYCONFIGURE: return 1;
355 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
356 case DRV_INSTALL: return DRVCNF_RESTART;
357 case DRV_REMOVE: return DRVCNF_RESTART;
359 case JDD_GETNUMDEVS: return 1;
360 case JDD_GETDEVCAPS: return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
361 case JDD_GETPOS: return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
362 case JDD_SETCALIBRATION:
363 case JDD_CONFIGCHANGED: return JOYERR_NOCANDO;
364 case JDD_GETPOSEX: return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
366 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
372 /**************************************************************************
373 * JSTCK_DriverProc [internal]
375 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
376 DWORD dwParam1, DWORD dwParam2)
378 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
379 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
388 case DRV_QUERYCONFIGURE: return 0;
389 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
390 case DRV_INSTALL: return DRVCNF_RESTART;
391 case DRV_REMOVE: return DRVCNF_RESTART;
393 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);