Correct crypt context init in CryptProtectData/CryptUnprotectData.
[wine] / dlls / dinput / joystick_linux.c
1 /*              DirectInput Joystick device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 /*
23  * To Do:
24  *      dead zone
25  *      force feedback
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <time.h>
35 #include <errno.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 #include <sys/fcntl.h>
43 #ifdef HAVE_SYS_IOCTL_H
44 # include <sys/ioctl.h>
45 #endif
46 #include <errno.h>
47 #ifdef HAVE_SYS_ERRNO_H
48 # include <sys/errno.h>
49 #endif
50 #ifdef HAVE_LINUX_IOCTL_H
51 # include <linux/ioctl.h>
52 #endif
53 #ifdef HAVE_LINUX_JOYSTICK_H
54 # include <linux/joystick.h>
55 #endif
56
57 #include "wine/debug.h"
58 #include "wine/unicode.h"
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winerror.h"
62 #include "winreg.h"
63 #include "dinput.h"
64
65 #include "dinput_private.h"
66 #include "device_private.h"
67
68 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
69
70 #ifdef HAVE_LINUX_22_JOYSTICK_API
71
72 #define JOYDEV "/dev/js"
73
74 typedef struct {
75     LONG lMin;
76     LONG lMax;
77     LONG lDeadZone;
78     LONG lSaturation;
79 } ObjProps;
80
81 typedef struct {
82     LONG lX;
83     LONG lY;
84 } POV;
85
86 typedef struct JoystickImpl JoystickImpl;
87 static IDirectInputDevice8AVtbl JoystickAvt;
88 static IDirectInputDevice8WVtbl JoystickWvt;
89 struct JoystickImpl
90 {
91         LPVOID                          lpVtbl;
92         DWORD                           ref;
93         GUID                            guid;
94         char                            dev[32];
95
96         /* The 'parent' DInput */
97         IDirectInputImpl               *dinput;
98
99         /* joystick private */
100         int                             joyfd;
101         DIJOYSTATE2                     js;             /* wine data */
102         LPDIDATAFORMAT                  user_df;        /* user defined format */
103         DataFormat                      *transform;     /* wine to user format converter */
104         int                             *offsets;       /* object offsets */
105         ObjProps                        *props;
106         HANDLE                          hEvent;
107         LPDIDEVICEOBJECTDATA            data_queue;
108         int                             queue_head, queue_tail, queue_len;
109         BOOL                            acquired;
110         char                            *name;
111         DIDEVCAPS                       devcaps;
112         LONG                            deadzone;
113         int                             *axis_map;
114         int                             axes;
115         int                             buttons;
116         POV                             povs[4];
117         CRITICAL_SECTION                crit;
118         BOOL                            overflow;
119 };
120
121 static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
122   0x9e573ed9,
123   0x7734,
124   0x11d2,
125   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
126 };
127
128 static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps)
129 {
130     TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize);
131     TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags);
132     TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType,
133           lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
134           lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" :
135           lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" :
136           lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" :
137           lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" :
138           lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN");
139     TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes);
140     TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons);
141     TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs);
142     if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) {
143         TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod);
144         TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution);
145         TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision);
146         TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision);
147         TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion);
148     }
149 }
150
151 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
152 {
153     int fd = -1;
154     char dev[32];
155
156     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
157         WARN("force feedback not supported\n");
158         return FALSE;
159     }
160
161     if ((dwDevType == 0) ||
162         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
163         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
164         /* check whether we have a joystick */
165         sprintf(dev, "%s%d", JOYDEV, id);
166         if ((fd = open(dev,O_RDONLY)) < 0) {
167             WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
168             return FALSE;
169         }
170
171         /* Return joystick */
172         lpddi->guidInstance = DInput_Wine_Joystick_GUID;
173         lpddi->guidInstance.Data3 = id;
174         lpddi->guidProduct = DInput_Wine_Joystick_GUID;
175         /* we only support traditional joysticks for now */
176         if (version >= 0x0800)
177             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
178         else
179             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
180         sprintf(lpddi->tszInstanceName, "Joystick %d", id);
181 #if defined(JSIOCGNAME)
182         if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) {
183             WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
184             strcpy(lpddi->tszProductName, "Wine Joystick");
185         }
186 #else
187         strcpy(lpddi->tszProductName, "Wine Joystick");
188 #endif
189
190         lpddi->guidFFDriver = GUID_NULL;
191         close(fd);
192         TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName);
193         return TRUE;
194     }
195
196     return FALSE;
197 }
198
199 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
200 {
201     int fd = -1;
202     char name[MAX_PATH];
203     char dev[32];
204     char friendly[32];
205
206     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
207         WARN("force feedback not supported\n");
208         return FALSE;
209     }
210
211     if ((dwDevType == 0) ||
212         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
213         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
214         /* check whether we have a joystick */
215         sprintf(dev, "%s%d", JOYDEV, id);
216         if ((fd = open(dev,O_RDONLY)) < 0) {
217             WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno));
218             return FALSE;
219         }
220
221         /* Return joystick */
222         lpddi->guidInstance = DInput_Wine_Joystick_GUID;
223         lpddi->guidInstance.Data3 = id;
224         lpddi->guidProduct = DInput_Wine_Joystick_GUID;
225         /* we only support traditional joysticks for now */
226         if (version >= 0x0800)
227             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
228         else
229             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
230         sprintf(friendly, "Joystick %d", id);
231         MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
232 #if defined(JSIOCGNAME)
233         if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) {
234             WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno));
235             strcpy(name, "Wine Joystick");
236         }
237 #else
238         strcpy(name, "Wine Joystick");
239 #endif
240         MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
241         lpddi->guidFFDriver = GUID_NULL;
242         close(fd);
243         TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name);
244         return TRUE;
245     }
246
247     return FALSE;
248 }
249
250 /*
251  * Get a config key from either the app-specific or the default config
252  */
253
254 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
255                                     char *buffer, DWORD size )
256 {
257     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size ))
258         return 0;
259
260     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, buffer, &size ))
261         return 0;
262
263     return ERROR_FILE_NOT_FOUND;
264 }
265
266 /*
267  * Setup the dinput options.
268  */
269
270 static HRESULT setup_dinput_options(JoystickImpl * device)
271 {
272     char buffer[MAX_PATH+1];
273     HKEY hkey, appkey = 0;
274     DWORD len;
275
276     buffer[MAX_PATH]='\0';
277
278     if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\dinput", &hkey)) hkey = 0;
279
280     len = GetModuleFileNameA( 0, buffer, MAX_PATH );
281     if (len && len < MAX_PATH) {
282         HKEY tmpkey;
283
284         if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\AppDefaults", &tmpkey )) {
285            char appname[MAX_PATH+16];
286            char *p = strrchr( buffer, '\\' );
287            if (p!=NULL) {
288                    strcpy(appname,p+1);
289                    strcat(appname,"\\dinput");
290                    TRACE("appname = [%s] \n",appname);
291                    if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
292            }
293            RegCloseKey( tmpkey );
294         }
295     }
296
297     /* get options */
298
299     if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) {
300         device->deadzone = atoi(buffer);
301         TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone);
302     }
303
304     if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) {
305         int tokens = 0;
306         int axis = 0;
307         int pov = 0;
308         const char *delim = ",";
309         char * ptr;
310         TRACE("\"%s\" = \"%s\"\n", device->name, buffer);
311
312         device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int));
313         if (device->axis_map == 0)
314             return DIERR_OUTOFMEMORY;
315
316         if ((ptr = strtok(buffer, delim)) != NULL) {
317             do {
318                 if (strcmp(ptr, "X") == 0) {
319                     device->axis_map[tokens] = 0;
320                     axis++;
321                 } else if (strcmp(ptr, "Y") == 0) {
322                     device->axis_map[tokens] = 1;
323                     axis++;
324                 } else if (strcmp(ptr, "Z") == 0) {
325                     device->axis_map[tokens] = 2;
326                     axis++;
327                 } else if (strcmp(ptr, "Rx") == 0) {
328                     device->axis_map[tokens] = 3;
329                     axis++;
330                 } else if (strcmp(ptr, "Ry") == 0) {
331                     device->axis_map[tokens] = 4;
332                     axis++;
333                 } else if (strcmp(ptr, "Rz") == 0) {
334                     device->axis_map[tokens] = 5;
335                     axis++;
336                 } else if (strcmp(ptr, "Slider1") == 0) {
337                     device->axis_map[tokens] = 6;
338                     axis++;
339                 } else if (strcmp(ptr, "Slider2") == 0) {
340                     device->axis_map[tokens] = 7;
341                     axis++;
342                 } else if (strcmp(ptr, "POV1") == 0) {
343                     device->axis_map[tokens++] = 8;
344                     device->axis_map[tokens] = 8;
345                     pov++;
346                 } else if (strcmp(ptr, "POV2") == 0) {
347                     device->axis_map[tokens++] = 9;
348                     device->axis_map[tokens] = 9;
349                     pov++;
350                 } else if (strcmp(ptr, "POV3") == 0) {
351                     device->axis_map[tokens++] = 10;
352                     device->axis_map[tokens] = 10;
353                     pov++;
354                 } else if (strcmp(ptr, "POV4") == 0) {
355                     device->axis_map[tokens++] = 11;
356                     device->axis_map[tokens] = 11;
357                     pov++;
358                 } else {
359                     ERR("invalid joystick axis type: %s\n", ptr);
360                     device->axis_map[tokens] = tokens;
361                     axis++;
362                 }
363
364                 tokens++;
365             } while ((ptr = strtok(NULL, delim)) != NULL);
366
367             if (tokens != device->devcaps.dwAxes) {
368                 ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens);
369                 while (tokens < device->axes) {
370                     device->axis_map[tokens] = tokens;
371                     tokens++;
372                 }
373             }
374         }
375
376         device->devcaps.dwAxes = axis;
377         device->devcaps.dwPOVs = pov;
378     }
379
380     if (appkey)
381         RegCloseKey( appkey );
382
383     if (hkey)
384         RegCloseKey( hkey );
385
386     return DI_OK;
387 }
388
389 void calculate_ids(JoystickImpl* device)
390 {
391     int i;
392     int axis = 0;
393     int button = 0;
394     int pov = 0;
395     int axis_base;
396     int pov_base;
397     int button_base;
398
399     /* Make two passes over the format. The first counts the number
400      * for each type and the second sets the id */
401     for (i = 0; i < device->user_df->dwNumObjs; i++) {
402         if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS)
403             axis++;
404         else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV)
405             pov++;
406         else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON)
407             button++;
408     }
409
410     axis_base = 0;
411     pov_base = axis;
412     button_base = axis + pov;
413
414     axis = 0;
415     button = 0;
416     pov = 0;
417
418     for (i = 0; i < device->user_df->dwNumObjs; i++) {
419         DWORD type = 0;
420         if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) {
421             axis++;
422             type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
423                 DIDFT_MAKEINSTANCE(axis + axis_base);
424             TRACE("axis type = 0x%08lx\n", type);
425         } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) {
426             pov++;
427             type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
428                 DIDFT_MAKEINSTANCE(pov + pov_base);
429             TRACE("POV type = 0x%08lx\n", type);
430         } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) {
431             button++;
432             type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) |
433                 DIDFT_MAKEINSTANCE(button + button_base);
434             TRACE("button type = 0x%08lx\n", type);
435         }
436         device->user_df->rgodf[i].dwType = type;
437     }
438 }
439
440 static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev)
441 {
442     DWORD i;
443     JoystickImpl* newDevice;
444     char name[MAX_PATH];
445     HRESULT hr;
446
447     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
448     if (newDevice == 0) {
449         WARN("out of memory\n");
450         *pdev = 0;
451         return DIERR_OUTOFMEMORY;
452     }
453
454     sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3);
455
456     if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) {
457         WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno));
458         HeapFree(GetProcessHeap(), 0, newDevice);
459         return DIERR_DEVICENOTREG;
460     }
461
462     /* get the device name */
463 #if defined(JSIOCGNAME)
464     if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) {
465         WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno));
466         strcpy(name, "Wine Joystick");
467     }
468 #else
469     strcpy(name, "Wine Joystick");
470 #endif
471
472     /* copy the device name */
473     newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
474     strcpy(newDevice->name, name);
475
476 #ifdef JSIOCGAXES
477     if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) {
478         WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
479         newDevice->axes = 2;
480     }
481 #endif
482 #ifdef JSIOCGBUTTONS
483     if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) {
484         WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno));
485         newDevice->buttons = 2;
486     }
487 #endif
488
489     newDevice->lpVtbl = jvt;
490     newDevice->ref = 1;
491     newDevice->dinput = dinput;
492     newDevice->acquired = FALSE;
493     newDevice->overflow = FALSE;
494     CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid));
495
496     /* setup_dinput_options may change these */
497     newDevice->deadzone = 5000;
498     newDevice->devcaps.dwButtons = newDevice->buttons;
499     newDevice->devcaps.dwAxes = newDevice->axes;
500     newDevice->devcaps.dwPOVs = 0;
501
502     /* do any user specified configuration */
503     hr = setup_dinput_options(newDevice);
504     if (hr != DI_OK)
505         goto FAILED1;
506
507     if (newDevice->axis_map == 0) {
508         newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int));
509         if (newDevice->axis_map == 0)
510             goto FAILED;
511
512         for (i = 0; i < newDevice->axes; i++)
513             newDevice->axis_map[i] = i;
514     }
515
516     /* wine uses DIJOYSTATE2 as it's internal format so copy
517      * the already defined format c_dfDIJoystick2 */
518     newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize);
519     if (newDevice->user_df == 0)
520         goto FAILED;
521
522     CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
523
524     /* copy default objects */
525     newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
526     if (newDevice->user_df->rgodf == 0)
527         goto FAILED;
528
529     CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize);
530
531     /* create default properties */
532     newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
533     if (newDevice->props == 0)
534         goto FAILED;
535
536     /* initialize default properties */
537     for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
538         newDevice->props[i].lMin = 0;
539         newDevice->props[i].lMax = 0xffff;
540         newDevice->props[i].lDeadZone = newDevice->deadzone;    /* % * 1000 */
541         newDevice->props[i].lSaturation = 0;
542     }
543
544     /* create an offsets array */
545     newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int));
546     if (newDevice->offsets == 0)
547         goto FAILED;
548
549     /* create the default transform filter */
550     newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets);
551
552     calculate_ids(newDevice);
553
554     IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
555     InitializeCriticalSection(&(newDevice->crit));
556     newDevice->crit.DebugInfo->Spare[1] = (DWORD)"DINPUT_Mouse";
557
558     newDevice->devcaps.dwSize = sizeof(newDevice->devcaps);
559     newDevice->devcaps.dwFlags = DIDC_ATTACHED;
560     if (newDevice->dinput->dwVersion >= 0x0800)
561         newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
562     else
563         newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
564     newDevice->devcaps.dwFFSamplePeriod = 0;
565     newDevice->devcaps.dwFFMinTimeResolution = 0;
566     newDevice->devcaps.dwFirmwareRevision = 0;
567     newDevice->devcaps.dwHardwareRevision = 0;
568     newDevice->devcaps.dwFFDriverVersion = 0;
569
570     if (TRACE_ON(dinput)) {
571         _dump_DIDATAFORMAT(newDevice->user_df);
572        for (i = 0; i < (newDevice->axes); i++)
573            TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]);
574         _dump_DIDEVCAPS(&newDevice->devcaps);
575     }
576
577     *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
578
579     return DI_OK;
580
581 FAILED:
582     hr = DIERR_OUTOFMEMORY;
583 FAILED1:
584     HeapFree(GetProcessHeap(),0,newDevice->axis_map);
585     HeapFree(GetProcessHeap(),0,newDevice->name);
586     HeapFree(GetProcessHeap(),0,newDevice->props);
587     HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf);
588     HeapFree(GetProcessHeap(),0,newDevice->user_df);
589     HeapFree(GetProcessHeap(),0,newDevice);
590     *pdev = 0;
591
592     return hr;
593 }
594
595 static BOOL IsJoystickGUID(REFGUID guid)
596 {
597     GUID wine_joystick = DInput_Wine_Joystick_GUID;
598     GUID dev_guid = *guid;
599
600     wine_joystick.Data3 = 0;
601     dev_guid.Data3 = 0;
602
603     return IsEqualGUID(&wine_joystick, &dev_guid);
604 }
605
606 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
607 {
608   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
609       (IsJoystickGUID(rguid))) {
610     if ((riid == NULL) ||
611         IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
612         IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
613         IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
614         IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
615       return alloc_device(rguid, &JoystickAvt, dinput, pdev);
616     } else {
617       WARN("no interface\n");
618       *pdev = 0;
619       return DIERR_NOINTERFACE;
620     }
621   }
622
623   WARN("invalid device GUID\n");
624   *pdev = 0;
625   return DIERR_DEVICENOTREG;
626 }
627
628 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
629 {
630   if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
631       (IsJoystickGUID(rguid))) {
632     if ((riid == NULL) ||
633         IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
634         IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
635         IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
636         IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
637       return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev);
638     } else {
639       WARN("no interface\n");
640       *pdev = 0;
641       return DIERR_NOINTERFACE;
642     }
643   }
644
645   WARN("invalid device GUID\n");
646   *pdev = 0;
647   return DIERR_DEVICENOTREG;
648 }
649
650 const struct dinput_device joystick_linux_device = {
651   "Wine Linux joystick driver",
652   joydev_enum_deviceA,
653   joydev_enum_deviceW,
654   joydev_create_deviceA,
655   joydev_create_deviceW
656 };
657
658 /******************************************************************************
659  *      Joystick
660  */
661 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
662 {
663     JoystickImpl *This = (JoystickImpl *)iface;
664     ULONG ref;
665
666     ref = InterlockedDecrement((&This->ref));
667     if (ref)
668         return ref;
669
670     /* Free the device name */
671     HeapFree(GetProcessHeap(),0,This->name);
672
673     /* Free the axis map */
674     HeapFree(GetProcessHeap(),0,This->axis_map);
675
676     /* Free the data queue */
677     HeapFree(GetProcessHeap(),0,This->data_queue);
678
679     /* Free the DataFormat */
680     HeapFree(GetProcessHeap(), 0, This->user_df->rgodf);
681     HeapFree(GetProcessHeap(), 0, This->user_df);
682
683     /* Free the properties */
684     HeapFree(GetProcessHeap(), 0, This->props);
685
686     /* Free the offsets array */
687     HeapFree(GetProcessHeap(),0,This->offsets);
688
689     /* release the data transform filter */
690     release_DataFormat(This->transform);
691
692     This->crit.DebugInfo->Spare[1] = 0;
693     DeleteCriticalSection(&(This->crit));
694     IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
695
696     HeapFree(GetProcessHeap(),0,This);
697     return 0;
698 }
699
700 /******************************************************************************
701   *   SetDataFormat : the application can choose the format of the data
702   *   the device driver sends back with GetDeviceState.
703   */
704 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
705     LPDIRECTINPUTDEVICE8A iface,
706     LPCDIDATAFORMAT df)
707 {
708     JoystickImpl *This = (JoystickImpl *)iface;
709     unsigned int i;
710     LPDIDATAFORMAT new_df = 0;
711     LPDIOBJECTDATAFORMAT new_rgodf = 0;
712     ObjProps * new_props = 0;
713
714     TRACE("(%p,%p)\n",This,df);
715
716     if (df == NULL) {
717         WARN("invalid pointer\n");
718         return E_POINTER;
719     }
720
721     if (df->dwSize != sizeof(*df)) {
722         WARN("invalid argument\n");
723         return DIERR_INVALIDPARAM;
724     }
725
726     if (This->acquired) {
727         WARN("acquired\n");
728         return DIERR_ACQUIRED;
729     }
730
731     if (TRACE_ON(dinput))
732         _dump_DIDATAFORMAT(df);
733
734     /* Store the new data format */
735     new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
736     if (new_df == 0)
737         goto FAILED;
738
739     new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
740     if (new_rgodf == 0)
741         goto FAILED;
742
743     new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps));
744     if (new_props == 0)
745         goto FAILED;
746
747     HeapFree(GetProcessHeap(),0,This->user_df);
748     HeapFree(GetProcessHeap(),0,This->user_df->rgodf);
749     HeapFree(GetProcessHeap(),0,This->props);
750     release_DataFormat(This->transform);
751
752     This->user_df = new_df;
753     CopyMemory(This->user_df, df, df->dwSize);
754     This->user_df->rgodf = new_rgodf;
755     CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
756     This->props = new_props;
757     for (i = 0; i < df->dwNumObjs; i++) {
758         This->props[i].lMin = 0;
759         This->props[i].lMax = 0xffff;
760         This->props[i].lDeadZone = 1000;
761         This->props[i].lSaturation = 0;
762     }
763     This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets);
764
765     calculate_ids(This);
766
767     return DI_OK;
768
769 FAILED:
770     WARN("out of memory\n");
771     HeapFree(GetProcessHeap(),0,new_props);
772     HeapFree(GetProcessHeap(),0,new_rgodf);
773     HeapFree(GetProcessHeap(),0,new_df);
774     return DIERR_OUTOFMEMORY;
775 }
776
777 /******************************************************************************
778   *     Acquire : gets exclusive control of the joystick
779   */
780 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
781 {
782     JoystickImpl *This = (JoystickImpl *)iface;
783
784     TRACE("(%p)\n",This);
785
786     if (This->acquired) {
787         WARN("already acquired\n");
788         return S_FALSE;
789     }
790
791     /* open the joystick device */
792     if (This->joyfd==-1) {
793         TRACE("opening joystick device %s\n", This->dev);
794
795         This->joyfd=open(This->dev,O_RDONLY);
796         if (This->joyfd==-1) {
797             ERR("open(%s) failed: %s\n", This->dev, strerror(errno));
798             return DIERR_NOTFOUND;
799         }
800     }
801
802     This->acquired = TRUE;
803
804     return DI_OK;
805 }
806
807 /******************************************************************************
808   *     Unacquire : frees the joystick
809   */
810 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
811 {
812     JoystickImpl *This = (JoystickImpl *)iface;
813
814     TRACE("(%p)\n",This);
815
816     if (!This->acquired) {
817         WARN("not acquired\n");
818         return DIERR_NOTACQUIRED;
819     }
820
821     if (This->joyfd!=-1) {
822         TRACE("closing joystick device\n");
823         close(This->joyfd);
824         This->joyfd = -1;
825         This->acquired = FALSE;
826         return DI_OK;
827     }
828
829     This->acquired = FALSE;
830
831     return DI_NOEFFECT;
832 }
833
834 LONG map_axis(JoystickImpl * This, short val, short index)
835 {
836     double    fval = val;
837     double    fmin = This->props[index].lMin;
838     double    fmax = This->props[index].lMax;
839     double    fret;
840
841     fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin;
842
843     if (fret >= 0.0)
844         fret += 0.5;
845     else
846         fret -= 0.5;
847
848     return fret;
849 }
850
851 /* convert wine format offset to user format object index */
852 int offset_to_object(JoystickImpl *This, int offset)
853 {
854     int i;
855
856     for (i = 0; i < This->user_df->dwNumObjs; i++) {
857         if (This->user_df->rgodf[i].dwOfs == offset)
858             return i;
859     }
860
861     return -1;
862 }
863
864 static LONG calculate_pov(JoystickImpl *This, int index)
865 {
866     if (This->povs[index].lX < 16384) {
867         if (This->povs[index].lY < 16384)
868             This->js.rgdwPOV[index] = 31500;
869         else if (This->povs[index].lY > 49150)
870             This->js.rgdwPOV[index] = 22500;
871         else
872             This->js.rgdwPOV[index] = 27000;
873     } else if (This->povs[index].lX > 49150) {
874         if (This->povs[index].lY < 16384)
875             This->js.rgdwPOV[index] = 4500;
876         else if (This->povs[index].lY > 49150)
877             This->js.rgdwPOV[index] = 13500;
878         else
879             This->js.rgdwPOV[index] = 9000;
880     } else {
881         if (This->povs[index].lY < 16384)
882             This->js.rgdwPOV[index] = 0;
883         else if (This->povs[index].lY > 49150)
884             This->js.rgdwPOV[index] = 18000;
885         else
886             This->js.rgdwPOV[index] = -1;
887     }
888
889     return This->js.rgdwPOV[index];
890 }
891
892 static void joy_polldev(JoystickImpl *This) {
893     struct timeval tv;
894     fd_set      readfds;
895     struct      js_event jse;
896     TRACE("(%p)\n", This);
897
898     if (This->joyfd==-1) {
899         WARN("no device\n");
900         return;
901     }
902     while (1) {
903         memset(&tv,0,sizeof(tv));
904         FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds);
905         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
906             return;
907         /* we have one event, so we can read */
908         if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
909             return;
910         }
911         TRACE("js_event: type 0x%x, number %d, value %d\n",
912               jse.type,jse.number,jse.value);
913         if (jse.type & JS_EVENT_BUTTON) {
914             int offset = This->offsets[jse.number + 12];
915             int value = jse.value?0x80:0x00;
916
917             This->js.rgbButtons[jse.number] = value;
918             GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++);
919         } else if (jse.type & JS_EVENT_AXIS) {
920             int number = This->axis_map[jse.number];    /* wine format object index */
921             if (number < 12) {
922                 int offset = This->offsets[number];
923                 int index = offset_to_object(This, offset);
924                 LONG value = map_axis(This, jse.value, index);
925
926                 /* FIXME do deadzone and saturation here */
927
928                 TRACE("changing axis %d => %d\n", jse.number, number);
929                 switch (number) {
930                 case 0:
931                     This->js.lX = value;
932                     break;
933                 case 1:
934                     This->js.lY = value;
935                     break;
936                 case 2:
937                     This->js.lZ = value;
938                     break;
939                 case 3:
940                     This->js.lRx = value;
941                     break;
942                 case 4:
943                     This->js.lRy = value;
944                     break;
945                 case 5:
946                     This->js.lRz = value;
947                     break;
948                 case 6:
949                     This->js.rglSlider[0] = value;
950                     break;
951                 case 7:
952                     This->js.rglSlider[1] = value;
953                     break;
954                 case 8:
955                     /* FIXME don't go off array */
956                     if (This->axis_map[jse.number + 1] == number)
957                         This->povs[0].lX = value;
958                     else if (This->axis_map[jse.number - 1] == number)
959                         This->povs[0].lY = value;
960                     value = calculate_pov(This, 0);
961                     break;
962                 case 9:
963                     if (This->axis_map[jse.number + 1] == number)
964                         This->povs[1].lX = value;
965                     else if (This->axis_map[jse.number - 1] == number)
966                         This->povs[1].lY = value;
967                     value = calculate_pov(This, 1);
968                     break;
969                 case 10:
970                     if (This->axis_map[jse.number + 1] == number)
971                         This->povs[2].lX = value;
972                     else if (This->axis_map[jse.number - 1] == number)
973                         This->povs[2].lY = value;
974                     value = calculate_pov(This, 2);
975                     break;
976                 case 11:
977                     if (This->axis_map[jse.number + 1] == number)
978                         This->povs[3].lX = value;
979                     else if (This->axis_map[jse.number - 1] == number)
980                         This->povs[3].lY = value;
981                     value = calculate_pov(This, 3);
982                     break;
983                 }
984
985                 GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++);
986             } else
987                 WARN("axis %d not supported\n", number);
988         }
989     }
990 }
991
992 /******************************************************************************
993   *     GetDeviceState : returns the "state" of the joystick.
994   *
995   */
996 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
997     LPDIRECTINPUTDEVICE8A iface,
998     DWORD len,
999     LPVOID ptr)
1000 {
1001     JoystickImpl *This = (JoystickImpl *)iface;
1002
1003     TRACE("(%p,0x%08lx,%p)\n",This,len,ptr);
1004
1005     if (!This->acquired) {
1006         WARN("not acquired\n");
1007         return DIERR_NOTACQUIRED;
1008     }
1009
1010     /* update joystick state */
1011     joy_polldev(This);
1012
1013     /* convert and copy data to user supplied buffer */
1014     fill_DataFormat(ptr, &This->js, This->transform);
1015
1016     return DI_OK;
1017 }
1018
1019 /******************************************************************************
1020   *     GetDeviceData : gets buffered input data.
1021   */
1022 static HRESULT WINAPI JoystickAImpl_GetDeviceData(
1023     LPDIRECTINPUTDEVICE8A iface,
1024     DWORD dodsize,
1025     LPDIDEVICEOBJECTDATA dod,
1026     LPDWORD entries,
1027     DWORD flags)
1028 {
1029     JoystickImpl *This = (JoystickImpl *)iface;
1030     DWORD len;
1031     int nqtail;
1032     HRESULT hr = DI_OK;
1033
1034     TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
1035
1036     if (!This->acquired) {
1037         WARN("not acquired\n");
1038         return DIERR_NOTACQUIRED;
1039     }
1040
1041     EnterCriticalSection(&(This->crit));
1042
1043     joy_polldev(This);
1044
1045     len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
1046         + (This->queue_head - This->queue_tail);
1047     if (len > *entries)
1048         len = *entries;
1049
1050     if (dod == NULL) {
1051         if (len)
1052             TRACE("Application discarding %ld event(s).\n", len);
1053
1054         *entries = len;
1055         nqtail = This->queue_tail + len;
1056         while (nqtail >= This->queue_len)
1057             nqtail -= This->queue_len;
1058     } else {
1059         if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) {
1060             ERR("Wrong structure size !\n");
1061             LeaveCriticalSection(&(This->crit));
1062             return DIERR_INVALIDPARAM;
1063         }
1064
1065         if (len)
1066             TRACE("Application retrieving %ld event(s).\n", len);
1067
1068         *entries = 0;
1069         nqtail = This->queue_tail;
1070         while (len) {
1071             /* Copy the buffered data into the application queue */
1072             memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize);
1073             /* Advance position */
1074             nqtail++;
1075             if (nqtail >= This->queue_len)
1076                 nqtail -= This->queue_len;
1077             (*entries)++;
1078             len--;
1079         }
1080     }
1081
1082     if (This->overflow) {
1083         hr = DI_BUFFEROVERFLOW;
1084         if (!(flags & DIGDD_PEEK)) {
1085             This->overflow = FALSE;
1086         }
1087     }
1088
1089     if (!(flags & DIGDD_PEEK))
1090         This->queue_tail = nqtail;
1091
1092     LeaveCriticalSection(&(This->crit));
1093
1094     return hr;
1095 }
1096
1097 int find_property(JoystickImpl * This, LPCDIPROPHEADER ph)
1098 {
1099     int i;
1100     if (ph->dwHow == DIPH_BYOFFSET) {
1101         return offset_to_object(This, ph->dwObj);
1102     } else if (ph->dwHow == DIPH_BYID) {
1103         for (i = 0; i < This->user_df->dwNumObjs; i++) {
1104             if ((This->user_df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) {
1105                 return i;
1106             }
1107         }
1108     }
1109
1110     return -1;
1111 }
1112
1113 /******************************************************************************
1114   *     SetProperty : change input device properties
1115   */
1116 static HRESULT WINAPI JoystickAImpl_SetProperty(
1117     LPDIRECTINPUTDEVICE8A iface,
1118     REFGUID rguid,
1119     LPCDIPROPHEADER ph)
1120 {
1121     JoystickImpl *This = (JoystickImpl *)iface;
1122     int i;
1123
1124     TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
1125
1126     if (ph == NULL) {
1127         WARN("invalid parameter: ph == NULL\n");
1128         return DIERR_INVALIDPARAM;
1129     }
1130
1131     if (TRACE_ON(dinput))
1132         _dump_DIPROPHEADER(ph);
1133
1134     if (!HIWORD(rguid)) {
1135         switch ((DWORD)rguid) {
1136         case (DWORD) DIPROP_BUFFERSIZE: {
1137             LPCDIPROPDWORD      pd = (LPCDIPROPDWORD)ph;
1138             TRACE("buffersize = %ld\n",pd->dwData);
1139             if (This->data_queue)
1140                 This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1141             else
1142                 This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1143             This->queue_head = 0;
1144             This->queue_tail = 0;
1145             This->queue_len  = pd->dwData;
1146             break;
1147         }
1148         case (DWORD)DIPROP_RANGE: {
1149             LPCDIPROPRANGE      pr = (LPCDIPROPRANGE)ph;
1150             if (ph->dwHow == DIPH_DEVICE) {
1151                 TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax);
1152                 for (i = 0; i < This->user_df->dwNumObjs; i++) {
1153                     This->props[i].lMin = pr->lMin;
1154                     This->props[i].lMax = pr->lMax;
1155                 }
1156             } else {
1157                 int obj = find_property(This, ph);
1158                 TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj);
1159                 if (obj >= 0) {
1160                     This->props[obj].lMin = pr->lMin;
1161                     This->props[obj].lMax = pr->lMax;
1162                     return DI_OK;
1163                 }
1164             }
1165             break;
1166         }
1167         case (DWORD)DIPROP_DEADZONE: {
1168             LPCDIPROPDWORD      pd = (LPCDIPROPDWORD)ph;
1169             if (ph->dwHow == DIPH_DEVICE) {
1170                 TRACE("deadzone(%ld) all\n",pd->dwData);
1171                 for (i = 0; i < This->user_df->dwNumObjs; i++)
1172                     This->props[i].lDeadZone  = pd->dwData;
1173             } else {
1174                 int obj = find_property(This, ph);
1175                 TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj);
1176                 if (obj >= 0) {
1177                     This->props[obj].lDeadZone  = pd->dwData;
1178                     return DI_OK;
1179                 }
1180             }
1181             break;
1182         }
1183         case (DWORD)DIPROP_SATURATION: {
1184             LPCDIPROPDWORD      pd = (LPCDIPROPDWORD)ph;
1185             if (ph->dwHow == DIPH_DEVICE) {
1186                 TRACE("saturation(%ld) all\n",pd->dwData);
1187                 for (i = 0; i < This->user_df->dwNumObjs; i++)
1188                     This->props[i].lSaturation = pd->dwData;
1189             } else {
1190                 int obj = find_property(This, ph);
1191                 TRACE("saturation(%ld) obj=%d\n",pd->dwData,obj);
1192                 if (obj >= 0) {
1193                     This->props[obj].lSaturation = pd->dwData;
1194                     return DI_OK;
1195                 }
1196             }
1197             break;
1198         }
1199         default:
1200             FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1201             break;
1202         }
1203     }
1204
1205     return DI_OK;
1206 }
1207
1208 /******************************************************************************
1209   *     SetEventNotification : specifies event to be sent on state change
1210   */
1211 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
1212         LPDIRECTINPUTDEVICE8A iface, HANDLE hnd
1213 ) {
1214     JoystickImpl *This = (JoystickImpl *)iface;
1215
1216     TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1217     This->hEvent = hnd;
1218     return DI_OK;
1219 }
1220
1221 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
1222         LPDIRECTINPUTDEVICE8A iface,
1223         LPDIDEVCAPS lpDIDevCaps)
1224 {
1225     JoystickImpl *This = (JoystickImpl *)iface;
1226     int size;
1227
1228     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
1229
1230     if (lpDIDevCaps == NULL) {
1231         WARN("invalid pointer\n");
1232         return E_POINTER;
1233     }
1234
1235     size = lpDIDevCaps->dwSize;
1236
1237     if (!(size == sizeof(DIDEVCAPS) || size == sizeof(DIDEVCAPS_DX3))) {
1238         WARN("invalid parameter\n");
1239         return DIERR_INVALIDPARAM;
1240     }
1241
1242     CopyMemory(lpDIDevCaps, &This->devcaps, size);
1243     lpDIDevCaps->dwSize = size;
1244
1245     if (TRACE_ON(dinput))
1246         _dump_DIDEVCAPS(lpDIDevCaps);
1247
1248     return DI_OK;
1249 }
1250
1251 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
1252 {
1253     JoystickImpl *This = (JoystickImpl *)iface;
1254
1255     TRACE("(%p)\n",This);
1256
1257     if (!This->acquired) {
1258         WARN("not acquired\n");
1259         return DIERR_NOTACQUIRED;
1260     }
1261
1262     joy_polldev(This);
1263     return DI_OK;
1264 }
1265
1266 /******************************************************************************
1267   *     EnumObjects : enumerate the different buttons and axis...
1268   */
1269 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1270         LPDIRECTINPUTDEVICE8A iface,
1271         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1272         LPVOID lpvRef,
1273         DWORD dwFlags)
1274 {
1275   JoystickImpl *This = (JoystickImpl *)iface;
1276   DIDEVICEOBJECTINSTANCEA ddoi;
1277   BYTE i;
1278   int user_offset;
1279   int user_object;
1280
1281   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1282   if (TRACE_ON(dinput)) {
1283     TRACE("  - flags = ");
1284     _dump_EnumObjects_flags(dwFlags);
1285     TRACE("\n");
1286   }
1287
1288   /* Only the fields till dwFFMaxForce are relevant */
1289   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1290
1291   /* For the joystick, do as is done in the GetCapabilities function */
1292   if ((dwFlags == DIDFT_ALL) ||
1293       (dwFlags & DIDFT_AXIS) ||
1294       (dwFlags & DIDFT_POV)) {
1295     int pov[4] = { 0, 0, 0, 0 };
1296     int axes = 0;
1297     int povs = 0;
1298
1299     for (i = 0; i < This->axes; i++) {
1300       int wine_obj = This->axis_map[i];
1301       BOOL skip = FALSE;
1302
1303       switch (wine_obj) {
1304       case 0:
1305         ddoi.guidType = GUID_XAxis;
1306         break;
1307       case 1:
1308         ddoi.guidType = GUID_YAxis;
1309         break;
1310       case 2:
1311         ddoi.guidType = GUID_ZAxis;
1312         break;
1313       case 3:
1314         ddoi.guidType = GUID_RxAxis;
1315         break;
1316       case 4:
1317         ddoi.guidType = GUID_RyAxis;
1318         break;
1319       case 5:
1320         ddoi.guidType = GUID_RzAxis;
1321         break;
1322       case 6:
1323         ddoi.guidType = GUID_Slider;
1324         break;
1325       case 7:
1326         ddoi.guidType = GUID_Slider;
1327         break;
1328       case 8:
1329         pov[0]++;
1330         ddoi.guidType = GUID_POV;
1331         break;
1332       case 9:
1333         pov[1]++;
1334         ddoi.guidType = GUID_POV;
1335         break;
1336       case 10:
1337         pov[2]++;
1338         ddoi.guidType = GUID_POV;
1339         break;
1340       case 11:
1341         pov[3]++;
1342         ddoi.guidType = GUID_POV;
1343         break;
1344       default:
1345         ddoi.guidType = GUID_Unknown;
1346       }
1347       if (wine_obj < 8) {
1348           user_offset = This->offsets[wine_obj];        /* get user offset from wine index */
1349           user_object = offset_to_object(This, user_offset);
1350
1351           ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff;
1352           ddoi.dwOfs =  This->user_df->rgodf[user_object].dwOfs;
1353           sprintf(ddoi.tszName, "Axis %d", axes);
1354           axes++;
1355       } else {
1356           if (pov[wine_obj - 8] < 2) {
1357               user_offset = This->offsets[wine_obj];    /* get user offset from wine index */
1358               user_object = offset_to_object(This, user_offset);
1359
1360               ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff;
1361               ddoi.dwOfs =  This->user_df->rgodf[user_object].dwOfs;
1362               sprintf(ddoi.tszName, "POV %d", povs);
1363               povs++;
1364           } else
1365               skip = TRUE;
1366       }
1367       if (!skip) {
1368           _dump_OBJECTINSTANCEA(&ddoi);
1369           if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE)
1370               return DI_OK;
1371       }
1372     }
1373   }
1374
1375   if ((dwFlags == DIDFT_ALL) ||
1376       (dwFlags & DIDFT_BUTTON)) {
1377
1378     /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */
1379     ddoi.guidType = GUID_Button;
1380
1381     for (i = 0; i < This->buttons; i++) {
1382       user_offset = This->offsets[i + 12];      /* get user offset from wine index */
1383       user_object = offset_to_object(This, user_offset);
1384       ddoi.guidType = GUID_Button;
1385       ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff;
1386       ddoi.dwOfs =  This->user_df->rgodf[user_object].dwOfs;
1387       sprintf(ddoi.tszName, "Button %d", i);
1388       _dump_OBJECTINSTANCEA(&ddoi);
1389       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1390     }
1391   }
1392
1393   return DI_OK;
1394 }
1395
1396 /******************************************************************************
1397   *     EnumObjects : enumerate the different buttons and axis...
1398   */
1399 static HRESULT WINAPI JoystickWImpl_EnumObjects(
1400         LPDIRECTINPUTDEVICE8W iface,
1401         LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
1402         LPVOID lpvRef,
1403         DWORD dwFlags)
1404 {
1405   JoystickImpl *This = (JoystickImpl *)iface;
1406
1407   device_enumobjects_AtoWcb_data data;
1408
1409   data.lpCallBack = lpCallback;
1410   data.lpvRef = lpvRef;
1411
1412   return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1413 }
1414
1415 /******************************************************************************
1416   *     GetProperty : get input device properties
1417   */
1418 static HRESULT WINAPI JoystickAImpl_GetProperty(
1419     LPDIRECTINPUTDEVICE8A iface,
1420     REFGUID rguid,
1421     LPDIPROPHEADER pdiph)
1422 {
1423     JoystickImpl *This = (JoystickImpl *)iface;
1424
1425     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
1426
1427     if (TRACE_ON(dinput))
1428         _dump_DIPROPHEADER(pdiph);
1429
1430     if (!HIWORD(rguid)) {
1431         switch ((DWORD)rguid) {
1432         case (DWORD) DIPROP_BUFFERSIZE: {
1433             LPDIPROPDWORD       pd = (LPDIPROPDWORD)pdiph;
1434             TRACE(" return buffersize = %d\n",This->queue_len);
1435             pd->dwData = This->queue_len;
1436             break;
1437         }
1438         case (DWORD) DIPROP_RANGE: {
1439             LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
1440             int obj = find_property(This, pdiph);
1441             /* The app is querying the current range of the axis
1442              * return the lMin and lMax values */
1443             if (obj >= 0) {
1444                 pr->lMin = This->props[obj].lMin;
1445                 pr->lMax = This->props[obj].lMax;
1446                 TRACE("range(%ld, %ld) obj=%d\n", pr->lMin, pr->lMax, obj);
1447                 return DI_OK;
1448             }
1449             break;
1450         }
1451         case (DWORD) DIPROP_DEADZONE: {
1452             LPDIPROPDWORD       pd = (LPDIPROPDWORD)pdiph;
1453             int obj = find_property(This, pdiph);
1454             if (obj >= 0) {
1455                 pd->dwData = This->props[obj].lDeadZone;
1456                 TRACE("deadzone(%ld) obj=%d\n", pd->dwData, obj);
1457                 return DI_OK;
1458             }
1459             break;
1460         }
1461         case (DWORD) DIPROP_SATURATION: {
1462             LPDIPROPDWORD       pd = (LPDIPROPDWORD)pdiph;
1463             int obj = find_property(This, pdiph);
1464             if (obj >= 0) {
1465                 pd->dwData = This->props[obj].lSaturation;
1466                 TRACE("saturation(%ld) obj=%d\n", pd->dwData, obj);
1467                 return DI_OK;
1468             }
1469             break;
1470         }
1471         default:
1472             FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1473             break;
1474         }
1475     }
1476
1477     return DI_OK;
1478 }
1479
1480 /******************************************************************************
1481   *     GetObjectInfo : get object info
1482   */
1483 HRESULT WINAPI JoystickAImpl_GetObjectInfo(
1484         LPDIRECTINPUTDEVICE8A iface,
1485         LPDIDEVICEOBJECTINSTANCEA pdidoi,
1486         DWORD dwObj,
1487         DWORD dwHow)
1488 {
1489     JoystickImpl *This = (JoystickImpl *)iface;
1490     DIDEVICEOBJECTINSTANCEA didoiA;
1491     unsigned int i;
1492
1493     TRACE("(%p,%p,%ld,0x%08lx(%s))\n",
1494           iface, pdidoi, dwObj, dwHow,
1495           dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" :
1496           dwHow == DIPH_BYID ? "DIPH_BYID" :
1497           dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" :
1498           "UNKNOWN");
1499
1500     if (pdidoi == NULL) {
1501         WARN("invalid parameter: pdidoi = NULL\n");
1502         return DIERR_INVALIDPARAM;
1503     }
1504
1505     if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) &&
1506         (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) {
1507         WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n",
1508              pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA),
1509              sizeof(DIDEVICEOBJECTINSTANCE_DX3A));
1510         return DIERR_INVALIDPARAM;
1511     }
1512
1513     ZeroMemory(&didoiA, sizeof(didoiA));
1514     didoiA.dwSize = pdidoi->dwSize;
1515
1516     switch (dwHow) {
1517     case DIPH_BYOFFSET: {
1518         int axis = 0;
1519         int pov = 0;
1520         int button = 0;
1521         for (i = 0; i < This->user_df->dwNumObjs; i++) {
1522             if (This->user_df->rgodf[i].dwOfs == dwObj) {
1523                 if (This->user_df->rgodf[i].pguid)
1524                     didoiA.guidType = *This->user_df->rgodf[i].pguid;
1525                 else
1526                     didoiA.guidType = GUID_NULL;
1527
1528                 didoiA.dwOfs = dwObj;
1529                 didoiA.dwType = This->user_df->rgodf[i].dwType;
1530                 didoiA.dwFlags = This->user_df->rgodf[i].dwFlags;
1531
1532                 if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS)
1533                     sprintf(didoiA.tszName, "Axis %d", axis);
1534                 else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV)
1535                     sprintf(didoiA.tszName, "POV %d", pov);
1536                 else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON)
1537                     sprintf(didoiA.tszName, "Button %d", button);
1538
1539                 CopyMemory(pdidoi, &didoiA, pdidoi->dwSize);
1540                 return DI_OK;
1541             }
1542
1543             if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS)
1544                 axis++;
1545             else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV)
1546                 pov++;
1547             else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON)
1548                 button++;
1549         }
1550         break;
1551     }
1552     case DIPH_BYID:
1553         FIXME("dwHow = DIPH_BYID not implemented\n");
1554         break;
1555     case DIPH_BYUSAGE:
1556         FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1557         break;
1558     default:
1559         WARN("invalid parameter: dwHow = %08lx\n", dwHow);
1560         return DIERR_INVALIDPARAM;
1561     }
1562
1563     CopyMemory(pdidoi, &didoiA, pdidoi->dwSize);
1564
1565     return DI_OK;
1566 }
1567
1568 /******************************************************************************
1569   *     GetDeviceInfo : get information about a device's identity
1570   */
1571 HRESULT WINAPI JoystickAImpl_GetDeviceInfo(
1572     LPDIRECTINPUTDEVICE8A iface,
1573     LPDIDEVICEINSTANCEA pdidi)
1574 {
1575     JoystickImpl *This = (JoystickImpl *)iface;
1576
1577     TRACE("(%p,%p)\n", iface, pdidi);
1578
1579     if (pdidi == NULL) {
1580         WARN("invalid pointer\n");
1581         return E_POINTER;
1582     }
1583
1584     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
1585         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) {
1586         WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n",
1587              pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A),
1588              sizeof(DIDEVICEINSTANCEA));
1589         return DIERR_INVALIDPARAM;
1590     }
1591
1592     /* Return joystick */
1593     pdidi->guidInstance = GUID_Joystick;
1594     pdidi->guidProduct = DInput_Wine_Joystick_GUID;
1595     /* we only support traditional joysticks for now */
1596     pdidi->dwDevType = This->devcaps.dwDevType;
1597     strcpy(pdidi->tszInstanceName, "Joystick");
1598     strcpy(pdidi->tszProductName, This->name);
1599     if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) {
1600         pdidi->guidFFDriver = GUID_NULL;
1601         pdidi->wUsagePage = 0;
1602         pdidi->wUsage = 0;
1603     }
1604
1605     return DI_OK;
1606 }
1607
1608 /******************************************************************************
1609   *     GetDeviceInfo : get information about a device's identity
1610   */
1611 HRESULT WINAPI JoystickWImpl_GetDeviceInfo(
1612     LPDIRECTINPUTDEVICE8W iface,
1613     LPDIDEVICEINSTANCEW pdidi)
1614 {
1615     JoystickImpl *This = (JoystickImpl *)iface;
1616
1617     TRACE("(%p,%p)\n", iface, pdidi);
1618
1619     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
1620         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) {
1621         WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n",
1622              pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W),
1623              sizeof(DIDEVICEINSTANCEW));
1624         return DIERR_INVALIDPARAM;
1625     }
1626
1627     /* Return joystick */
1628     pdidi->guidInstance = GUID_Joystick;
1629     pdidi->guidProduct = DInput_Wine_Joystick_GUID;
1630     /* we only support traditional joysticks for now */
1631     pdidi->dwDevType = This->devcaps.dwDevType;
1632     MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, pdidi->tszInstanceName, MAX_PATH);
1633     MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH);
1634     if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) {
1635         pdidi->guidFFDriver = GUID_NULL;
1636         pdidi->wUsagePage = 0;
1637         pdidi->wUsage = 0;
1638     }
1639
1640     return DI_OK;
1641 }
1642
1643 static IDirectInputDevice8AVtbl JoystickAvt =
1644 {
1645         IDirectInputDevice2AImpl_QueryInterface,
1646         IDirectInputDevice2AImpl_AddRef,
1647         JoystickAImpl_Release,
1648         JoystickAImpl_GetCapabilities,
1649         JoystickAImpl_EnumObjects,
1650         JoystickAImpl_GetProperty,
1651         JoystickAImpl_SetProperty,
1652         JoystickAImpl_Acquire,
1653         JoystickAImpl_Unacquire,
1654         JoystickAImpl_GetDeviceState,
1655         JoystickAImpl_GetDeviceData,
1656         JoystickAImpl_SetDataFormat,
1657         JoystickAImpl_SetEventNotification,
1658         IDirectInputDevice2AImpl_SetCooperativeLevel,
1659         JoystickAImpl_GetObjectInfo,
1660         JoystickAImpl_GetDeviceInfo,
1661         IDirectInputDevice2AImpl_RunControlPanel,
1662         IDirectInputDevice2AImpl_Initialize,
1663         IDirectInputDevice2AImpl_CreateEffect,
1664         IDirectInputDevice2AImpl_EnumEffects,
1665         IDirectInputDevice2AImpl_GetEffectInfo,
1666         IDirectInputDevice2AImpl_GetForceFeedbackState,
1667         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1668         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1669         IDirectInputDevice2AImpl_Escape,
1670         JoystickAImpl_Poll,
1671         IDirectInputDevice2AImpl_SendDeviceData,
1672         IDirectInputDevice7AImpl_EnumEffectsInFile,
1673         IDirectInputDevice7AImpl_WriteEffectToFile,
1674         IDirectInputDevice8AImpl_BuildActionMap,
1675         IDirectInputDevice8AImpl_SetActionMap,
1676         IDirectInputDevice8AImpl_GetImageInfo
1677 };
1678
1679 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1680 # define XCAST(fun)     (typeof(SysJoystickWvt.fun))
1681 #else
1682 # define XCAST(fun)     (void*)
1683 #endif
1684
1685 static IDirectInputDevice8WVtbl SysJoystickWvt =
1686 {
1687         IDirectInputDevice2WImpl_QueryInterface,
1688         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1689         XCAST(Release)JoystickAImpl_Release,
1690         XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
1691         JoystickWImpl_EnumObjects,
1692         XCAST(GetProperty)JoystickAImpl_GetProperty,
1693         XCAST(SetProperty)JoystickAImpl_SetProperty,
1694         XCAST(Acquire)JoystickAImpl_Acquire,
1695         XCAST(Unacquire)JoystickAImpl_Unacquire,
1696         XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
1697         XCAST(GetDeviceData)JoystickAImpl_GetDeviceData,
1698         XCAST(SetDataFormat)JoystickAImpl_SetDataFormat,
1699         XCAST(SetEventNotification)JoystickAImpl_SetEventNotification,
1700         XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
1701         IDirectInputDevice2WImpl_GetObjectInfo,
1702         JoystickWImpl_GetDeviceInfo,
1703         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1704         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1705         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
1706         IDirectInputDevice2WImpl_EnumEffects,
1707         IDirectInputDevice2WImpl_GetEffectInfo,
1708         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
1709         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1710         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1711         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1712         XCAST(Poll)JoystickAImpl_Poll,
1713         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1714         IDirectInputDevice7WImpl_EnumEffectsInFile,
1715         IDirectInputDevice7WImpl_WriteEffectToFile,
1716         IDirectInputDevice8WImpl_BuildActionMap,
1717         IDirectInputDevice8WImpl_SetActionMap,
1718         IDirectInputDevice8WImpl_GetImageInfo
1719 };
1720 #undef XCAST
1721
1722 #else  /* HAVE_LINUX_22_JOYSTICK_API */
1723
1724 const struct dinput_device joystick_linux_device = {
1725   "Wine Linux joystick driver",
1726   NULL,
1727   NULL,
1728   NULL,
1729   NULL
1730 };
1731
1732 #endif  /* HAVE_LINUX_22_JOYSTICK_API */