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>
44 #include "debugtools.h"
46 DEFAULT_DEBUG_CHANNEL(joystick
);
48 #ifdef HAVE_LINUX_JOYSTICK_H
50 #define MAXJOYSTICK (JOYSTICKID2 + 1)
52 typedef struct tagWINE_JSTCK
{
57 static WINE_JSTCK JSTCK_Data
[MAXJOYSTICK
];
59 /**************************************************************************
60 * JSTCK_drvGet [internal]
62 static WINE_JSTCK
* JSTCK_drvGet(DWORD dwDevID
)
66 if ((dwDevID
- (DWORD
)JSTCK_Data
) % sizeof(JSTCK_Data
[0]) != 0)
68 p
= (dwDevID
- (DWORD
)JSTCK_Data
) / sizeof(JSTCK_Data
[0]);
69 if (p
< 0 || p
>= MAXJOYSTICK
|| !((WINE_JSTCK
*)dwDevID
)->in_use
)
72 return (WINE_JSTCK
*)dwDevID
;
75 /**************************************************************************
76 * JSTCK_drvOpen [internal]
78 static DWORD
JSTCK_drvOpen(LPSTR str
, DWORD dwIntf
)
80 if (dwIntf
>= MAXJOYSTICK
|| JSTCK_Data
[dwIntf
].in_use
)
83 JSTCK_Data
[dwIntf
].joyIntf
= dwIntf
;
84 JSTCK_Data
[dwIntf
].in_use
= 1;
85 return (DWORD
)&JSTCK_Data
[dwIntf
];
88 /**************************************************************************
89 * JSTCK_drvClose [internal]
91 static DWORD
JSTCK_drvClose(DWORD dwDevID
)
93 WINE_JSTCK
* jstck
= JSTCK_drvGet(dwDevID
);
108 /**************************************************************************
109 * JSTCK_OpenDevice [internal]
111 static int JSTCK_OpenDevice(WINE_JSTCK
* jstick
)
116 sprintf(buf
, JOYDEV
, jstick
->joyIntf
);
117 #ifdef HAVE_LINUX_22_JOYSTICK_API
118 flags
= O_RDONLY
| O_NONBLOCK
;
122 return open(buf
, flags
);
125 /**************************************************************************
126 * JoyGetDevCaps [MMSYSTEM.102]
128 static LONG
JSTCK_GetDevCaps(DWORD dwDevID
, LPJOYCAPSA lpCaps
, DWORD dwSize
)
131 #ifdef HAVE_LINUX_22_JOYSTICK_API
135 char identString
[MAXPNAMELEN
];
139 if ((jstck
= JSTCK_drvGet(dwDevID
)) == NULL
)
140 return MMSYSERR_NODRIVER
;
142 #ifdef HAVE_LINUX_22_JOYSTICK_API
144 if ((dev
= JSTCK_OpenDevice(jstck
)) < 0) return JOYERR_PARMS
;
145 ioctl(dev
, JSIOCGAXES
, &nrOfAxes
);
146 ioctl(dev
, JSIOCGBUTTONS
, &nrOfButtons
);
147 ioctl(dev
, JSIOCGVERSION
, &driverVersion
);
148 ioctl(dev
, JSIOCGNAME(sizeof(identString
)), &identString
);
149 TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
150 driverVersion
, identString
, nrOfAxes
, nrOfButtons
);
151 lpCaps
->wMid
= MM_MICROSOFT
;
152 lpCaps
->wPid
= MM_PC_JOYSTICK
;
153 strncpy(lpCaps
->szPname
, identString
, MAXPNAMELEN
);
154 lpCaps
->szPname
[MAXPNAMELEN
-1] = '\0';
156 lpCaps
->wXmax
= 0xFFFF;
158 lpCaps
->wYmax
= 0xFFFF;
160 lpCaps
->wZmax
= (nrOfAxes
>= 3) ? 0xFFFF : 0;
161 lpCaps
->wNumButtons
= nrOfButtons
;
162 if (dwSize
== sizeof(JOYCAPSA
)) {
163 /* since we supose ntOfAxes <= 6 in the following code, do it explicitely */
164 if (nrOfAxes
> 6) nrOfAxes
= 6;
165 /* complete 95 structure */
167 lpCaps
->wRmax
= nrOfAxes
>= 4 ? 0xFFFF : 0;
169 lpCaps
->wUmax
= nrOfAxes
>= 5 ? 0xFFFF : 0;
171 lpCaps
->wVmax
= nrOfAxes
>= 6 ? 0xFFFF : 0;
172 lpCaps
->wMaxAxes
= 6; /* same as MS Joystick Driver */
173 lpCaps
->wNumAxes
= nrOfAxes
; /* nr of axes in use */
174 lpCaps
->wMaxButtons
= 32; /* same as MS Joystick Driver */
175 strcpy(lpCaps
->szRegKey
, "");
176 strcpy(lpCaps
->szOEMVxD
, "");
179 case 6: lpCaps
->wCaps
|= JOYCAPS_HASV
;
180 case 5: lpCaps
->wCaps
|= JOYCAPS_HASU
;
181 case 4: lpCaps
->wCaps
|= JOYCAPS_HASR
;
182 case 3: lpCaps
->wCaps
|= JOYCAPS_HASZ
;
183 /* FIXME: don't know how to detect for
184 JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
190 lpCaps
->wMid
= MM_MICROSOFT
;
191 lpCaps
->wPid
= MM_PC_JOYSTICK
;
192 strcpy(lpCaps
->szPname
, "WineJoy"); /* joystick product name */
194 lpCaps
->wXmax
= 0xFFFF;
196 lpCaps
->wYmax
= 0xFFFF;
199 lpCaps
->wNumButtons
= 2;
200 if (dwSize
== sizeof(JOYCAPSA
)) {
201 /* complete 95 structure */
209 lpCaps
->wMaxAxes
= 2;
210 lpCaps
->wNumAxes
= 2;
211 lpCaps
->wMaxButtons
= 4;
212 strcpy(lpCaps
->szRegKey
,"");
213 strcpy(lpCaps
->szOEMVxD
,"");
217 return JOYERR_NOERROR
;
220 /**************************************************************************
221 * JSTCK_GetPos [internal]
223 static LONG
JSTCK_GetPosEx(DWORD dwDevID
, LPJOYINFOEX lpInfo
)
227 #ifdef HAVE_LINUX_22_JOYSTICK_API
234 if ((jstck
= JSTCK_drvGet(dwDevID
)) == NULL
)
235 return MMSYSERR_NODRIVER
;
237 if ((dev
= JSTCK_OpenDevice(jstck
)) < 0) return JOYERR_PARMS
;
239 #ifdef HAVE_LINUX_22_JOYSTICK_API
240 /* After opening the device it's state can be
241 read with JS_EVENT_INIT flag */
242 while ((read(dev
, &ev
, sizeof(struct js_event
))) > 0) {
243 if (ev
.type
== (JS_EVENT_AXIS
| JS_EVENT_INIT
)) {
246 if (lpInfo
->dwFlags
& JOY_RETURNX
)
247 lpInfo
->dwXpos
= ev
.value
+ 32767;
250 if (lpInfo
->dwFlags
& JOY_RETURNY
)
251 lpInfo
->dwYpos
= ev
.value
+ 32767;
254 if (lpInfo
->dwFlags
& JOY_RETURNZ
)
255 lpInfo
->dwZpos
= ev
.value
+ 32767;
258 if (lpInfo
->dwFlags
& JOY_RETURNR
)
259 lpInfo
->dwRpos
= ev
.value
+ 32767;
261 if (lpInfo
->dwFlags
& JOY_RETURNU
)
262 lpInfo
->dwUpos
= ev
.value
+ 32767;
264 if (lpInfo
->dwFlags
& JOY_RETURNV
)
265 lpInfo
->dwVpos
= ev
.value
+ 32767;
268 FIXME("Unknown joystick event '%d'\n", ev
.number
);
270 } else if (ev
.type
== (JS_EVENT_BUTTON
| JS_EVENT_INIT
)) {
271 if (lpInfo
->dwFlags
& JOY_RETURNBUTTONS
) {
273 lpInfo
->dwButtons
|= (1 << ev
.number
);
274 /* FIXME: what to do for this field when
275 * multiple buttons are depressed ?
277 lpInfo
->dwButtonNumber
= ev
.number
+ 1;
282 /* EAGAIN is returned when the queue is empty */
283 if (errno
!= EAGAIN
) {
284 /* FIXME: error should not be ignored */
285 ERR("Error while reading joystick state (%d)\n", errno
);
288 dev_stat
= read(dev
, &js
, sizeof(js
));
289 if (dev_stat
!= sizeof(js
)) {
291 return JOYERR_UNPLUGGED
; /* FIXME: perhaps wrong, but what should I return else ? */
295 if (lpInfo
->dwFlags
& JOY_RETURNX
)
296 lpInfo
->dwXpos
= js
.x
; /* FIXME: perhaps multiply it somehow ? */
297 if (lpInfo
->dwFlags
& JOY_RETURNY
)
298 lpInfo
->dwYpos
= js
.y
;
299 if (lpInfo
->dwFlags
& JOY_RETURNBUTTONS
)
300 lpInfo
->dwButtons
= js
.buttons
;
305 TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n",
306 lpInfo
->dwXpos
, lpInfo
->dwYpos
, lpInfo
->dwZpos
,
307 lpInfo
->dwRpos
, lpInfo
->dwUpos
, lpInfo
->dwVpos
,
308 (unsigned int)lpInfo
->dwButtons
,
309 (unsigned int)lpInfo
->dwFlags
);
311 return JOYERR_NOERROR
;
314 /**************************************************************************
315 * JSTCK_GetPos [internal]
317 static LONG
JSTCK_GetPos(DWORD dwDevID
, LPJOYINFO lpInfo
)
322 memset(&ji
, 0, sizeof(ji
));
324 ji
.dwSize
= sizeof(ji
);
325 ji
.dwFlags
= JOY_RETURNX
| JOY_RETURNY
| JOY_RETURNZ
| JOY_RETURNBUTTONS
;
326 ret
= JSTCK_GetPosEx(dwDevID
, &ji
);
327 if (ret
== JOYERR_NOERROR
) {
328 lpInfo
->wXpos
= ji
.dwXpos
;
329 lpInfo
->wYpos
= ji
.dwYpos
;
330 lpInfo
->wZpos
= ji
.dwZpos
;
331 lpInfo
->wButtons
= ji
.dwButtons
;
337 /**************************************************************************
338 * JSTCK_DriverProc [internal]
340 LONG CALLBACK
JSTCK_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
341 DWORD dwParam1
, DWORD dwParam2
)
343 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
344 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
347 case DRV_LOAD
: return 1;
348 case DRV_FREE
: return 1;
349 case DRV_OPEN
: return JSTCK_drvOpen((LPSTR
)dwParam1
, dwParam2
);
350 case DRV_CLOSE
: return JSTCK_drvClose(dwDevID
);
351 case DRV_ENABLE
: return 1;
352 case DRV_DISABLE
: return 1;
353 case DRV_QUERYCONFIGURE
: return 1;
354 case DRV_CONFIGURE
: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK
); return 1;
355 case DRV_INSTALL
: return DRVCNF_RESTART
;
356 case DRV_REMOVE
: return DRVCNF_RESTART
;
358 case JDD_GETNUMDEVS
: return 1;
359 case JDD_GETDEVCAPS
: return JSTCK_GetDevCaps(dwDevID
, (LPJOYCAPSA
)dwParam1
, dwParam2
);
360 case JDD_GETPOS
: return JSTCK_GetPos(dwDevID
, (LPJOYINFO
)dwParam1
);
361 case JDD_SETCALIBRATION
:
362 case JDD_CONFIGCHANGED
: return JOYERR_NOCANDO
;
363 case JDD_GETPOSEX
: return JSTCK_GetPosEx(dwDevID
, (LPJOYINFOEX
)dwParam1
);
365 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
371 /**************************************************************************
372 * JSTCK_DriverProc [internal]
374 LONG CALLBACK
JSTCK_DriverProc(DWORD dwDevID
, HDRVR hDriv
, DWORD wMsg
,
375 DWORD dwParam1
, DWORD dwParam2
)
377 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
378 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
387 case DRV_QUERYCONFIGURE
: return 0;
388 case DRV_CONFIGURE
: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK
); return 1;
389 case DRV_INSTALL
: return DRVCNF_RESTART
;
390 case DRV_REMOVE
: return DRVCNF_RESTART
;
392 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);