No longer directly accessing debuggee memory.
[wine] / dlls / winmm / joystick / joystick.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * joystick functions
4  *
5  * Copyright 1997 Andreas Mohr
6  *
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.
15  */
16
17 /*
18  * Wolfgang Schwotzer
19  *
20  *    01/2000    added support for new joystick driver
21  *
22  */
23
24 #include "config.h"
25
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"
45
46 DEFAULT_DEBUG_CHANNEL(joystick);
47
48 #ifdef HAVE_LINUX_JOYSTICK_H
49
50 #define MAXJOYSTICK     (JOYSTICKID2 + 1)
51
52 static  struct dummy_struct* JSTCK_Dummy = NULL;
53
54 /**************************************************************************
55  *                              JSTCK_drvOpen                   [internal]      
56  */
57 static  DWORD   JSTCK_drvOpen(LPSTR str)
58 {
59     if (JSTCK_Dummy)
60         return 0;
61     
62     /* I know, this is ugly, but who cares... */
63     JSTCK_Dummy = (struct dummy_struct*)1;
64     return 1;
65 }
66
67 /**************************************************************************
68  *                              JSTCK_drvClose                  [internal]      
69  */
70 static  DWORD   JSTCK_drvClose(DWORD dwDevID)
71 {
72     if (JSTCK_Dummy) {
73         JSTCK_Dummy = NULL;
74         return 1;
75     }
76     return 0;
77 }
78
79 struct js_status
80 {
81     int buttons;
82     int x;
83     int y;
84 };
85
86 /**************************************************************************
87  *                              JSTCK_OpenDevice           [internal]
88  */
89 static  int     JSTCK_OpenDevice(WORD wID)
90 {
91     char        buf[20];
92     int         flags;
93     
94     if (wID >= MAXJOYSTICK) return -1;
95
96     sprintf(buf, JOYDEV, wID);
97 #ifdef HAVE_LINUX_22_JOYSTICK_API
98     flags = O_RDONLY | O_NONBLOCK;
99 #else
100     flags = O_RDONLY;
101 #endif
102     return open(buf, flags);
103 }
104
105 /**************************************************************************
106  *                              JoyGetDevCaps           [MMSYSTEM.102]
107  */
108 static  LONG    JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
109 {
110 #ifdef HAVE_LINUX_22_JOYSTICK_API
111     int         dev;
112     char        nrOfAxes;
113     char        nrOfButtons;
114     char        identString[MAXPNAMELEN];
115     int         driverVersion;
116 #endif
117
118     if (dwDevID >= MAXJOYSTICK) return MMSYSERR_NODRIVER;
119
120 #ifdef HAVE_LINUX_22_JOYSTICK_API
121     
122     if ((dev = JSTCK_OpenDevice(dwDevID)) < 0) return JOYERR_PARMS;
123     ioctl(dev, JSIOCGAXES, &nrOfAxes);
124     ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
125     ioctl(dev, JSIOCGVERSION, &driverVersion);
126     ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
127     TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
128           driverVersion, identString, nrOfAxes, nrOfButtons);
129     lpCaps->wMid = MM_MICROSOFT;
130     lpCaps->wPid = MM_PC_JOYSTICK;
131     strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
132     lpCaps->szPname[MAXPNAMELEN-1] = '\0';
133     lpCaps->wXmin = 0;
134     lpCaps->wXmax = 0xFFFF;
135     lpCaps->wYmin = 0;
136     lpCaps->wYmax = 0xFFFF;
137     lpCaps->wZmin = 0;
138     lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
139     lpCaps->wNumButtons = nrOfButtons;
140     if (dwSize == sizeof(JOYCAPSA)) {
141         /* since we supose ntOfAxes <= 6 in the following code, do it explicitely */
142         if (nrOfAxes > 6) nrOfAxes = 6;
143         /* complete 95 structure */
144         lpCaps->wRmin = 0;
145         lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
146         lpCaps->wUmin = 0;
147         lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
148         lpCaps->wVmin = 0;
149         lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
150         lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
151         lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
152         lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
153         strcpy(lpCaps->szRegKey, "");
154         strcpy(lpCaps->szOEMVxD, "");
155         lpCaps->wCaps = 0;
156         switch(nrOfAxes) {
157         case 6: lpCaps->wCaps |= JOYCAPS_HASV;
158         case 5: lpCaps->wCaps |= JOYCAPS_HASU;
159         case 4: lpCaps->wCaps |= JOYCAPS_HASR;
160         case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
161             /* FIXME: don't know how to detect for
162                JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
163         }
164     }
165     close(dev);
166
167 #else
168     lpCaps->wMid = MM_MICROSOFT;
169     lpCaps->wPid = MM_PC_JOYSTICK;
170     strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
171     lpCaps->wXmin = 0;
172     lpCaps->wXmax = 0xFFFF;
173     lpCaps->wYmin = 0;
174     lpCaps->wYmax = 0xFFFF;
175     lpCaps->wZmin = 0;
176     lpCaps->wZmax = 0;
177     lpCaps->wNumButtons = 2;
178     if (dwSize == sizeof(JOYCAPSA)) {
179         /* complete 95 structure */
180         lpCaps->wRmin = 0;
181         lpCaps->wRmax = 0;
182         lpCaps->wUmin = 0;
183         lpCaps->wUmax = 0;
184         lpCaps->wVmin = 0;
185         lpCaps->wVmax = 0;
186         lpCaps->wCaps = 0;
187         lpCaps->wMaxAxes = 2;
188         lpCaps->wNumAxes = 2;
189         lpCaps->wMaxButtons = 4;
190         strcpy(lpCaps->szRegKey,"");
191         strcpy(lpCaps->szOEMVxD,"");
192     }
193 #endif
194
195     return JOYERR_NOERROR;
196 }
197
198 /**************************************************************************
199  *                              JSTCK_GetPos                    [internal]
200  */
201 static LONG     JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
202 {
203     int                 dev;
204 #ifdef HAVE_LINUX_22_JOYSTICK_API
205     struct js_event     ev;
206 #else
207     struct js_status    js;
208     int                 dev_stat;
209 #endif
210     
211     if ((dev = JSTCK_OpenDevice(dwDevID)) < 0) return JOYERR_PARMS;
212
213 #ifdef HAVE_LINUX_22_JOYSTICK_API
214     /* After opening the device it's state can be
215        read with JS_EVENT_INIT flag */
216     while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
217         if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
218             switch (ev.number) {
219             case 0:
220                 if (lpInfo->dwFlags & JOY_RETURNX)
221                     lpInfo->dwXpos   = ev.value + 32767;
222                 break;
223             case 1: 
224                 if (lpInfo->dwFlags & JOY_RETURNY)
225                     lpInfo->dwYpos   = ev.value + 32767;
226                 break;
227             case 2:
228                 if (lpInfo->dwFlags & JOY_RETURNZ)
229                     lpInfo->dwZpos   = ev.value + 32767;
230                 break;
231             case 3: 
232                 if (lpInfo->dwFlags & JOY_RETURNR)
233                     lpInfo->dwRpos   = ev.value + 32767;
234             case 4: 
235                 if (lpInfo->dwFlags & JOY_RETURNU)
236                     lpInfo->dwUpos   = ev.value + 32767;
237             case 5: 
238                 if (lpInfo->dwFlags & JOY_RETURNV)
239                     lpInfo->dwVpos   = ev.value + 32767;
240                 break;
241             default: 
242                 FIXME("Unknown joystick event '%d'\n", ev.number);
243             }
244         } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
245             if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
246                 if (ev.value) {
247                     lpInfo->dwButtons |= (1 << ev.number);
248                     /* FIXME: what to do for this field when 
249                      * multiple buttons are depressed ?
250                      */
251                     lpInfo->dwButtonNumber = ev.number + 1;
252                 }
253             }
254         }
255     }
256     /* EAGAIN is returned when the queue is empty */
257     if (errno != EAGAIN) {
258         /* FIXME: error should not be ignored */
259         ERR("Error while reading joystick state (%d)\n", errno);
260     }
261 #else
262     dev_stat = read(dev, &js, sizeof(js));
263     if (dev_stat != sizeof(js)) {
264         close(dev);
265         return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
266     }
267     js.x = js.x<<8;
268     js.y = js.y<<8;
269     if (lpInfo->dwFlags & JOY_RETURNX)
270         lpInfo->dwXpos = js.x;   /* FIXME: perhaps multiply it somehow ? */
271     if (lpInfo->dwFlags & JOY_RETURNY)
272         lpInfo->dwYpos = js.y;
273     if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
274         lpInfo->dwButtons = js.buttons;
275 #endif
276
277     close(dev);
278
279     TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n", 
280           lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
281           lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
282           (unsigned int)lpInfo->dwButtons,
283           (unsigned int)lpInfo->dwFlags);
284
285     return JOYERR_NOERROR;
286 }
287
288 /**************************************************************************
289  *                              JSTCK_GetPos                    [internal]
290  */
291 static LONG     JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
292 {
293     JOYINFOEX   ji;
294     LONG        ret;
295
296     memset(&ji, 0, sizeof(ji));
297
298     ji.dwSize = sizeof(ji);
299     ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
300     ret = JSTCK_GetPosEx(dwDevID, &ji);
301     if (ret == JOYERR_NOERROR)  {
302         lpInfo->wXpos    = ji.dwXpos;
303         lpInfo->wYpos    = ji.dwYpos;
304         lpInfo->wZpos    = ji.dwZpos;
305         lpInfo->wButtons = ji.dwButtons;
306     }
307
308     return ret;
309 }
310
311 /**************************************************************************
312  *                              JSTCK_DriverProc                [internal]
313  */
314 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
315                                   DWORD dwParam1, DWORD dwParam2)
316 {
317     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
318     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
319     
320     switch(wMsg) {
321     case DRV_LOAD:              return 1;
322     case DRV_FREE:              return 1;
323     case DRV_OPEN:              return JSTCK_drvOpen((LPSTR)dwParam1);
324     case DRV_CLOSE:             return JSTCK_drvClose(dwDevID);
325     case DRV_ENABLE:            return 1;
326     case DRV_DISABLE:           return 1;
327     case DRV_QUERYCONFIGURE:    return 1;
328     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
329     case DRV_INSTALL:           return DRVCNF_RESTART;
330     case DRV_REMOVE:            return DRVCNF_RESTART;
331
332     case JDD_GETNUMDEVS:        return MAXJOYSTICK;
333     case JDD_GETDEVCAPS:        return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
334     case JDD_GETPOS:            return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
335     case JDD_SETCALIBRATION:    
336     case JDD_CONFIGCHANGED:     return JOYERR_NOCANDO;
337     case JDD_GETPOSEX:          return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
338     default:
339         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
340     }
341 }
342
343 #else
344
345 /**************************************************************************
346  *                              JSTCK_DriverProc                [internal]
347  */
348 LONG CALLBACK   JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
349                                   DWORD dwParam1, DWORD dwParam2)
350 {
351     /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
352     /* EPP        dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
353     
354     switch(wMsg) {
355     case DRV_LOAD:              
356     case DRV_FREE:              
357     case DRV_OPEN:              
358     case DRV_CLOSE:             
359     case DRV_ENABLE:            
360     case DRV_DISABLE:           
361     case DRV_QUERYCONFIGURE:    return 0;
362     case DRV_CONFIGURE:         MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK);       return 1;
363     case DRV_INSTALL:           return DRVCNF_RESTART;
364     case DRV_REMOVE:            return DRVCNF_RESTART;
365     default:
366         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
367     }
368 }
369
370 #endif