Implemented the DirectSound HAL in winmm's wineoss (Open Sound System)
[wine/gsoc_dplay.git] / dlls / winmm / joystick / joystick.c
blob256fdc7240eac0e983624ec4796da5f8234c988a
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * joystick functions
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.
18 * Wolfgang Schwotzer
20 * 01/2000 added support for new joystick driver
24 #include "config.h"
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <sys/ioctl.h>
32 #ifdef HAVE_LINUX_JOYSTICK_H
33 #include <linux/joystick.h>
34 #define JOYDEV "/dev/js%d"
35 #endif
36 #ifdef HAVE_SYS_ERRNO_H
37 #include <sys/errno.h>
38 #endif
39 #include "windef.h"
40 #include "wingdi.h"
41 #include "winuser.h"
42 #include "mmddk.h"
43 #include "driver.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 {
53 int joyIntf;
54 int in_use;
55 } WINE_JSTCK;
57 static WINE_JSTCK JSTCK_Data[MAXJOYSTICK];
59 /**************************************************************************
60 * JSTCK_drvGet [internal]
62 static WINE_JSTCK* JSTCK_drvGet(DWORD dwDevID)
64 int p;
66 if ((dwDevID - (DWORD)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0)
67 return NULL;
68 p = (dwDevID - (DWORD)JSTCK_Data) / sizeof(JSTCK_Data[0]);
69 if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use)
70 return NULL;
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)
81 return 0;
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);
95 if (jstck == NULL)
96 return 0;
97 jstck->in_use = 0;
98 return 1;
101 struct js_status
103 int buttons;
104 int x;
105 int y;
108 /**************************************************************************
109 * JSTCK_OpenDevice [internal]
111 static int JSTCK_OpenDevice(WINE_JSTCK* jstick)
113 char buf[20];
114 int flags;
116 sprintf(buf, JOYDEV, jstick->joyIntf);
117 #ifdef HAVE_LINUX_22_JOYSTICK_API
118 flags = O_RDONLY | O_NONBLOCK;
119 #else
120 flags = O_RDONLY;
121 #endif
122 return open(buf, flags);
125 /**************************************************************************
126 * JoyGetDevCaps [MMSYSTEM.102]
128 static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
130 WINE_JSTCK* jstck;
131 #ifdef HAVE_LINUX_22_JOYSTICK_API
132 int dev;
133 char nrOfAxes;
134 char nrOfButtons;
135 char identString[MAXPNAMELEN];
136 int driverVersion;
137 #endif
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';
155 lpCaps->wXmin = 0;
156 lpCaps->wXmax = 0xFFFF;
157 lpCaps->wYmin = 0;
158 lpCaps->wYmax = 0xFFFF;
159 lpCaps->wZmin = 0;
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 */
166 lpCaps->wRmin = 0;
167 lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
168 lpCaps->wUmin = 0;
169 lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
170 lpCaps->wVmin = 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, "");
177 lpCaps->wCaps = 0;
178 switch(nrOfAxes) {
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 */
187 close(dev);
189 #else
190 lpCaps->wMid = MM_MICROSOFT;
191 lpCaps->wPid = MM_PC_JOYSTICK;
192 strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
193 lpCaps->wXmin = 0;
194 lpCaps->wXmax = 0xFFFF;
195 lpCaps->wYmin = 0;
196 lpCaps->wYmax = 0xFFFF;
197 lpCaps->wZmin = 0;
198 lpCaps->wZmax = 0;
199 lpCaps->wNumButtons = 2;
200 if (dwSize == sizeof(JOYCAPSA)) {
201 /* complete 95 structure */
202 lpCaps->wRmin = 0;
203 lpCaps->wRmax = 0;
204 lpCaps->wUmin = 0;
205 lpCaps->wUmax = 0;
206 lpCaps->wVmin = 0;
207 lpCaps->wVmax = 0;
208 lpCaps->wCaps = 0;
209 lpCaps->wMaxAxes = 2;
210 lpCaps->wNumAxes = 2;
211 lpCaps->wMaxButtons = 4;
212 strcpy(lpCaps->szRegKey,"");
213 strcpy(lpCaps->szOEMVxD,"");
215 #endif
217 return JOYERR_NOERROR;
220 /**************************************************************************
221 * JSTCK_GetPos [internal]
223 static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
225 WINE_JSTCK* jstck;
226 int dev;
227 #ifdef HAVE_LINUX_22_JOYSTICK_API
228 struct js_event ev;
229 #else
230 struct js_status js;
231 int dev_stat;
232 #endif
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)) {
244 switch (ev.number) {
245 case 0:
246 if (lpInfo->dwFlags & JOY_RETURNX)
247 lpInfo->dwXpos = ev.value + 32767;
248 break;
249 case 1:
250 if (lpInfo->dwFlags & JOY_RETURNY)
251 lpInfo->dwYpos = ev.value + 32767;
252 break;
253 case 2:
254 if (lpInfo->dwFlags & JOY_RETURNZ)
255 lpInfo->dwZpos = ev.value + 32767;
256 break;
257 case 3:
258 if (lpInfo->dwFlags & JOY_RETURNR)
259 lpInfo->dwRpos = ev.value + 32767;
260 case 4:
261 if (lpInfo->dwFlags & JOY_RETURNU)
262 lpInfo->dwUpos = ev.value + 32767;
263 case 5:
264 if (lpInfo->dwFlags & JOY_RETURNV)
265 lpInfo->dwVpos = ev.value + 32767;
266 break;
267 default:
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) {
272 if (ev.value) {
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);
287 #else
288 dev_stat = read(dev, &js, sizeof(js));
289 if (dev_stat != sizeof(js)) {
290 close(dev);
291 return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
293 js.x = js.x<<8;
294 js.y = js.y<<8;
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;
301 #endif
303 close(dev);
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)
319 JOYINFOEX ji;
320 LONG ret;
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;
334 return ret;
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); */
346 switch(wMsg) {
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);
364 default:
365 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
369 #else
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); */
380 switch(wMsg) {
381 case DRV_LOAD:
382 case DRV_FREE:
383 case DRV_OPEN:
384 case DRV_CLOSE:
385 case DRV_ENABLE:
386 case DRV_DISABLE:
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;
391 default:
392 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
396 #endif