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 #include <sys/ioctl.h>
48 #ifdef HAVE_LINUX_JOYSTICK_H
49 #include <linux/joystick.h>
50 #define JOYDEV "/dev/js%d"
52 #ifdef HAVE_SYS_ERRNO_H
53 #include <sys/errno.h>
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(joystick);
65 #ifdef HAVE_LINUX_JOYSTICK_H
67 #define MAXJOYSTICK (JOYSTICKID2 + 1)
69 typedef struct tagWINE_JSTCK {
74 static WINE_JSTCK JSTCK_Data[MAXJOYSTICK];
76 /**************************************************************************
77 * JSTCK_drvGet [internal]
79 static WINE_JSTCK* JSTCK_drvGet(DWORD dwDevID)
83 if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
85 p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
86 if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
89 return (WINE_JSTCK*)dwDevID;
92 /**************************************************************************
93 * JSTCK_drvOpen [internal]
95 static DWORD JSTCK_drvOpen(LPSTR str, DWORD dwIntf)
97 if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use)
100 JSTCK_Data[dwIntf].joyIntf = dwIntf;
101 JSTCK_Data[dwIntf].in_use = 1;
102 return (DWORD)&JSTCK_Data[dwIntf];
105 /**************************************************************************
106 * JSTCK_drvClose [internal]
108 static DWORD JSTCK_drvClose(DWORD dwDevID)
110 WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID);
125 /**************************************************************************
126 * JSTCK_OpenDevice [internal]
128 static int JSTCK_OpenDevice(WINE_JSTCK* jstick)
133 sprintf(buf, JOYDEV, jstick->joyIntf);
134 #ifdef HAVE_LINUX_22_JOYSTICK_API
135 flags = O_RDONLY | O_NONBLOCK;
139 return open(buf, flags);
142 /**************************************************************************
143 * JoyGetDevCaps [MMSYSTEM.102]
145 static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
148 #ifdef HAVE_LINUX_22_JOYSTICK_API
152 char identString[MAXPNAMELEN];
156 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
157 return MMSYSERR_NODRIVER;
159 #ifdef HAVE_LINUX_22_JOYSTICK_API
161 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
162 ioctl(dev, JSIOCGAXES, &nrOfAxes);
163 ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
164 ioctl(dev, JSIOCGVERSION, &driverVersion);
165 ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
166 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
167 driverVersion, identString, nrOfAxes, nrOfButtons);
168 lpCaps->wMid = MM_MICROSOFT;
169 lpCaps->wPid = MM_PC_JOYSTICK;
170 strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
171 lpCaps->szPname[MAXPNAMELEN-1] = '\0';
173 lpCaps->wXmax = 0xFFFF;
175 lpCaps->wYmax = 0xFFFF;
177 lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
178 lpCaps->wNumButtons = nrOfButtons;
179 if (dwSize == sizeof(JOYCAPSA)) {
180 /* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
181 if (nrOfAxes > 6) nrOfAxes = 6;
182 /* complete 95 structure */
184 lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
186 lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
188 lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
189 lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
190 lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
191 lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
192 strcpy(lpCaps->szRegKey, "");
193 strcpy(lpCaps->szOEMVxD, "");
196 case 6: lpCaps->wCaps |= JOYCAPS_HASV;
197 case 5: lpCaps->wCaps |= JOYCAPS_HASU;
198 case 4: lpCaps->wCaps |= JOYCAPS_HASR;
199 case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
200 /* FIXME: don't know how to detect for
201 JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
207 lpCaps->wMid = MM_MICROSOFT;
208 lpCaps->wPid = MM_PC_JOYSTICK;
209 strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
211 lpCaps->wXmax = 0xFFFF;
213 lpCaps->wYmax = 0xFFFF;
216 lpCaps->wNumButtons = 2;
217 if (dwSize == sizeof(JOYCAPSA)) {
218 /* complete 95 structure */
226 lpCaps->wMaxAxes = 2;
227 lpCaps->wNumAxes = 2;
228 lpCaps->wMaxButtons = 4;
229 strcpy(lpCaps->szRegKey,"");
230 strcpy(lpCaps->szOEMVxD,"");
234 return JOYERR_NOERROR;
237 /**************************************************************************
238 * JSTCK_GetPos [internal]
240 static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
244 #ifdef HAVE_LINUX_22_JOYSTICK_API
251 if ((jstck = JSTCK_drvGet(dwDevID)) == NULL)
252 return MMSYSERR_NODRIVER;
254 if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
256 #ifdef HAVE_LINUX_22_JOYSTICK_API
257 /* After opening the device, its state can be
258 read with JS_EVENT_INIT flag */
259 while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
260 if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
263 if (lpInfo->dwFlags & JOY_RETURNX)
264 lpInfo->dwXpos = ev.value + 32767;
267 if (lpInfo->dwFlags & JOY_RETURNY)
268 lpInfo->dwYpos = ev.value + 32767;
271 if (lpInfo->dwFlags & JOY_RETURNZ)
272 lpInfo->dwZpos = ev.value + 32767;
275 if (lpInfo->dwFlags & JOY_RETURNR)
276 lpInfo->dwRpos = ev.value + 32767;
278 if (lpInfo->dwFlags & JOY_RETURNU)
279 lpInfo->dwUpos = ev.value + 32767;
281 if (lpInfo->dwFlags & JOY_RETURNV)
282 lpInfo->dwVpos = ev.value + 32767;
285 FIXME("Unknown joystick event '%d'\n", ev.number);
287 } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
288 if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
290 lpInfo->dwButtons |= (1 << ev.number);
291 /* FIXME: what to do for this field when
292 * multiple buttons are depressed ?
294 lpInfo->dwButtonNumber = ev.number + 1;
299 /* EAGAIN is returned when the queue is empty */
300 if (errno != EAGAIN) {
301 /* FIXME: error should not be ignored */
302 ERR("Error while reading joystick state (%s)\n", strerror(errno));
305 dev_stat = read(dev, &js, sizeof(js));
306 if (dev_stat != sizeof(js)) {
308 return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
312 if (lpInfo->dwFlags & JOY_RETURNX)
313 lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */
314 if (lpInfo->dwFlags & JOY_RETURNY)
315 lpInfo->dwYpos = js.y;
316 if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
317 lpInfo->dwButtons = js.buttons;
322 TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n",
323 lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
324 lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
325 (unsigned int)lpInfo->dwButtons,
326 (unsigned int)lpInfo->dwFlags);
328 return JOYERR_NOERROR;
331 /**************************************************************************
332 * JSTCK_GetPos [internal]
334 static LONG JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
339 memset(&ji, 0, sizeof(ji));
341 ji.dwSize = sizeof(ji);
342 ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
343 ret = JSTCK_GetPosEx(dwDevID, &ji);
344 if (ret == JOYERR_NOERROR) {
345 lpInfo->wXpos = ji.dwXpos;
346 lpInfo->wYpos = ji.dwYpos;
347 lpInfo->wZpos = ji.dwZpos;
348 lpInfo->wButtons = ji.dwButtons;
354 /**************************************************************************
355 * DriverProc (JOYSTICK.@)
357 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
358 DWORD dwParam1, DWORD dwParam2)
360 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
361 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
364 case DRV_LOAD: return 1;
365 case DRV_FREE: return 1;
366 case DRV_OPEN: return JSTCK_drvOpen((LPSTR)dwParam1, dwParam2);
367 case DRV_CLOSE: return JSTCK_drvClose(dwDevID);
368 case DRV_ENABLE: return 1;
369 case DRV_DISABLE: return 1;
370 case DRV_QUERYCONFIGURE: return 1;
371 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
372 case DRV_INSTALL: return DRVCNF_RESTART;
373 case DRV_REMOVE: return DRVCNF_RESTART;
375 case JDD_GETNUMDEVS: return 1;
376 case JDD_GETDEVCAPS: return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
377 case JDD_GETPOS: return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
378 case JDD_SETCALIBRATION:
379 case JDD_CONFIGCHANGED: return JOYERR_NOCANDO;
380 case JDD_GETPOSEX: return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
382 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
388 /**************************************************************************
389 * DriverProc (JOYSTICK.@)
391 LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
392 DWORD dwParam1, DWORD dwParam2)
394 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
395 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
404 case DRV_QUERYCONFIGURE: return 0;
405 case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
406 case DRV_INSTALL: return DRVCNF_RESTART;
407 case DRV_REMOVE: return DRVCNF_RESTART;
409 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);