1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
5 * Copyright 1997 Andreas Mohr
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * nearly all joystick functions can be regarded as obsolete,
24 * as Linux (2.1.x) now supports extended joysticks
25 * with a completely new joystick driver interface
26 * new driver's docu says:
27 * "For backward compatibility the old interface is still included,
28 * but will be dropped in the future."
29 * Thus we should implement the new interface and at most keep the old
30 * routines for backward compatibility.
36 * 01/2000 added support for new joystick driver
47 #ifdef HAVE_SYS_IOCTL_H
48 #include <sys/ioctl.h>
50 #ifdef HAVE_LINUX_JOYSTICK_H
51 #include <linux/joystick.h>
52 #define JOYDEV "/dev/js%d"
54 #ifdef HAVE_SYS_ERRNO_H
55 #include <sys/errno.h>
63 #include "wine/debug.h"
65 WINE_DEFAULT_DEBUG_CHANNEL(joystick);
67 #ifdef HAVE_LINUX_JOYSTICK_H
69 #define MAXJOYSTICK (JOYSTICKID2 + 1)
71 typedef struct tagWINE_JSTCK {
76 static WINE_JSTCK JSTCK_Data[MAXJOYSTICK];
78 /**************************************************************************
79 * JSTCK_drvGet [internal]
81 static WINE_JSTCK* JSTCK_drvGet(DWORD dwDevID)
85 if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
87 p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
88 if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
91 return (WINE_JSTCK*)dwDevID;
94 /**************************************************************************
95 * JSTCK_drvOpen [internal]
97 static DWORD JSTCK_drvOpen(LPSTR str, DWORD dwIntf)
99 if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
102 JSTCK_Data[dwIntf].joyIntf = dwIntf;
103 JSTCK_Data[dwIntf].in_use = 1;
104 return (DWORD)&JSTCK_Data[dwIntf];
107 /**************************************************************************
108 * JSTCK_drvClose [internal]
110 static DWORD JSTCK_drvClose(DWORD dwDevID)
112 WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
127 /**************************************************************************
128 * JSTCK_OpenDevice [internal]
130 static int JSTCK_OpenDevice(WINE_JSTCK* jstick)
135 sprintf(buf, JOYDEV, jstick->joyIntf);
136 #ifdef HAVE_LINUX_22_JOYSTICK_API
137 flags = O_RDONLY | O_NONBLOCK;
141 return open(buf, flags);
144 /**************************************************************************
145 * JoyGetDevCaps [MMSYSTEM.102]
147 static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
150 #ifdef HAVE_LINUX_22_JOYSTICK_API
154 char identString[MAXPNAMELEN];
158 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
159 return MMSYSERR_NODRIVER;
161 #ifdef HAVE_LINUX_22_JOYSTICK_API
163 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
164 ioctl(dev, JSIOCGAXES, &nrOfAxes);
165 ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
166 ioctl(dev, JSIOCGVERSION, &driverVersion);
167 ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
168 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
169 driverVersion, identString, nrOfAxes, nrOfButtons);
170 lpCaps->wMid = MM_MICROSOFT;
171 lpCaps->wPid = MM_PC_JOYSTICK;
172 strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
173 lpCaps->szPname[MAXPNAMELEN-1] = '\0';
175 lpCaps->wXmax = 0xFFFF;
177 lpCaps->wYmax = 0xFFFF;
179 lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
180 lpCaps->wNumButtons = nrOfButtons;
181 if (dwSize == sizeof(JOYCAPSA)) {
182 /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
183 if (nrOfAxes > 6) nrOfAxes = 6;
184 /* complete 95 structure */
186 lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
188 lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
190 lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
191 lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
192 lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
193 lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
194 strcpy(lpCaps->szRegKey, "");
195 strcpy(lpCaps->szOEMVxD, "");
198 case 6: lpCaps->wCaps |= JOYCAPS_HASV;
199 case 5: lpCaps->wCaps |= JOYCAPS_HASU;
200 case 4: lpCaps->wCaps |= JOYCAPS_HASR;
201 case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
202 /* FIXME: don't know how to detect for
203 JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
209 lpCaps->wMid = MM_MICROSOFT;
210 lpCaps->wPid = MM_PC_JOYSTICK;
211 strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
213 lpCaps->wXmax = 0xFFFF;
215 lpCaps->wYmax = 0xFFFF;
218 lpCaps->wNumButtons = 2;
219 if (dwSize == sizeof(JOYCAPSA)) {
220 /* complete 95 structure */
228 lpCaps->wMaxAxes = 2;
229 lpCaps->wNumAxes = 2;
230 lpCaps->wMaxButtons = 4;
231 strcpy(lpCaps->szRegKey,"");
232 strcpy(lpCaps->szOEMVxD,"");
236 return JOYERR_NOERROR;
239 /**************************************************************************
240 * JSTCK_GetPos [internal]
242 static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
246 #ifdef HAVE_LINUX_22_JOYSTICK_API
253 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
254 return MMSYSERR_NODRIVER;
256 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
258 #ifdef HAVE_LINUX_22_JOYSTICK_API
259 /* After opening the device, its state can be
260 read with JS_EVENT_INIT flag */
261 while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
262 if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
265 if (lpInfo->dwFlags & JOY_RETURNX)
266 lpInfo->dwXpos = ev.value + 32767;
269 if (lpInfo->dwFlags & JOY_RETURNY)
270 lpInfo->dwYpos = ev.value + 32767;
273 if (lpInfo->dwFlags & JOY_RETURNZ)
274 lpInfo->dwZpos = ev.value + 32767;
277 if (lpInfo->dwFlags & JOY_RETURNR)
278 lpInfo->dwRpos = ev.value + 32767;
280 if (lpInfo->dwFlags & JOY_RETURNU)
281 lpInfo->dwUpos = ev.value + 32767;
283 if (lpInfo->dwFlags & JOY_RETURNV)
284 lpInfo->dwVpos = ev.value + 32767;
287 FIXME("Unknown joystick event '%d'\n", ev.number);
289 } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
290 if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
292 lpInfo->dwButtons |= (1 << ev.number);
293 /* FIXME: what to do for this field when
294 * multiple buttons are depressed ?
296 lpInfo->dwButtonNumber = ev.number + 1;
301 /* EAGAIN is returned when the queue is empty */
302 if (errno != EAGAIN) {
303 /* FIXME: error should not be ignored */
304 ERR("Error while reading joystick state (%s)\n", strerror(errno));
307 dev_stat = read(dev, &js, sizeof(js));
308 if (dev_stat != sizeof(js)) {
310 return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
314 if (lpInfo->dwFlags & JOY_RETURNX)
315 lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */
316 if (lpInfo->dwFlags & JOY_RETURNY)
317 lpInfo->dwYpos = js.y;
318 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
319 lpInfo->dwButtons = js.buttons;
324 TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n",
325 lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
326 lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
327 (unsigned int)lpInfo->dwButtons,
328 (unsigned int)lpInfo->dwFlags);
330 return JOYERR_NOERROR;
333 /**************************************************************************
334 * JSTCK_GetPos [internal]
336 static LONG JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
341 memset(&ji, 0, sizeof(ji));
343 ji.dwSize = sizeof(ji);
344 ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
345 ret = JSTCK_GetPosEx(dwDevID, &ji);
346 if (ret == JOYERR_NOERROR) {
347 lpInfo->wXpos = ji.dwXpos;
348 lpInfo->wYpos = ji.dwYpos;
349 lpInfo->wZpos = ji.dwZpos;
350 lpInfo->wButtons = ji.dwButtons;
356 /**************************************************************************
357 * DriverProc (JOYSTICK.@)
359 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
360 DWORD dwParam1, DWORD dwParam2)
362 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
363 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
366 case DRV_LOAD: return 1;
367 case DRV_FREE: return 1;
368 case DRV_OPEN: return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2);
369 case DRV_CLOSE: return JSTCK_drvClose(dwDevID);
370 case DRV_ENABLE: return 1;
371 case DRV_DISABLE: return 1;
372 case DRV_QUERYCONFIGURE: return 1;
373 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
374 case DRV_INSTALL: return DRVCNF_RESTART;
375 case DRV_REMOVE: return DRVCNF_RESTART;
377 case JDD_GETNUMDEVS: return 1;
378 case JDD_GETDEVCAPS: return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
379 case JDD_GETPOS: return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
380 case JDD_SETCALIBRATION:
381 case JDD_CONFIGCHANGED: return JOYERR_NOCANDO;
382 case JDD_GETPOSEX: return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
384 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
390 /**************************************************************************
391 * DriverProc (JOYSTICK.@)
393 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
394 DWORD dwParam1, DWORD dwParam2)
396 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
397 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
406 case DRV_QUERYCONFIGURE: return 0;
407 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
408 case DRV_INSTALL: return DRVCNF_RESTART;
409 case DRV_REMOVE: return DRVCNF_RESTART;
411 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);