dinput: Common implementation of BuildActionMap for keyboard and mouse.
[wine] / dlls / dinput / joystick_linuxinput.c
1 /*              DirectInput Joystick device
2  *
3  * Copyright 1998,2000 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2005 Daniel Remenak
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <time.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 #endif
37 #include <fcntl.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 # include <sys/ioctl.h>
40 #endif
41 #include <errno.h>
42 #ifdef HAVE_SYS_ERRNO_H
43 # include <sys/errno.h>
44 #endif
45 #ifdef HAVE_LINUX_INPUT_H
46 # include <linux/input.h>
47 # undef SW_MAX
48 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
49 #  define HAVE_CORRECT_LINUXINPUT_H
50 # endif
51 #endif
52 #ifdef HAVE_SYS_POLL_H
53 # include <sys/poll.h>
54 #endif
55
56 #include "wine/debug.h"
57 #include "wine/unicode.h"
58 #include "wine/list.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 #include "joystick_private.h"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
70
71 #ifdef HAVE_CORRECT_LINUXINPUT_H
72
73 #define EVDEVPREFIX     "/dev/input/event"
74
75 /* Wine joystick driver object instances */
76 #define WINE_JOYSTICK_MAX_AXES    8
77 #define WINE_JOYSTICK_MAX_POVS    4
78 #define WINE_JOYSTICK_MAX_BUTTONS 128
79
80 struct wine_input_absinfo {
81     LONG value;
82     LONG minimum;
83     LONG maximum;
84     LONG fuzz;
85     LONG flat;
86 };
87
88 /* implemented in effect_linuxinput.c */
89 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff);
90 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
91 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
92
93 typedef struct JoystickImpl JoystickImpl;
94 static const IDirectInputDevice8AVtbl JoystickAvt;
95 static const IDirectInputDevice8WVtbl JoystickWvt;
96
97 struct JoyDev {
98         char *device;
99         char *name;
100         GUID guid;
101
102         int has_ff;
103         int num_effects;
104
105         /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
106         BYTE                            evbits[(EV_MAX+7)/8];
107         BYTE                            absbits[(ABS_MAX+7)/8];
108         BYTE                            keybits[(KEY_MAX+7)/8];
109         BYTE                            ffbits[(FF_MAX+7)/8];   
110
111         /* data returned by the EVIOCGABS() ioctl */
112         struct wine_input_absinfo       axes[ABS_MAX];
113
114         WORD vendor_id, product_id;
115 };
116
117 struct JoystickImpl
118 {
119         struct JoystickGenericImpl      generic;
120         struct JoyDev                  *joydev;
121
122         /* joystick private */
123         int                             joyfd;
124
125         int                             dev_axes_to_di[ABS_MAX];
126         POINTL                          povs[4];
127
128         /* LUT for KEY_ to offset in rgbButtons */
129         BYTE                            buttons[KEY_MAX];
130
131         /* Force feedback variables */
132         struct list                     ff_effects;
133         int                             ff_state;
134         int                             ff_autocenter;
135         int                             ff_gain;
136 };
137
138 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
139 {
140     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
141            JoystickGenericImpl, base), JoystickImpl, generic);
142 }
143 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
144 {
145     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
146            JoystickGenericImpl, base), JoystickImpl, generic);
147 }
148 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(JoystickImpl *This)
149 {
150     return &This->generic.base.IDirectInputDevice8A_iface;
151 }
152 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
153 {
154     return &This->generic.base.IDirectInputDevice8W_iface;
155 }
156
157 static void fake_current_js_state(JoystickImpl *ji);
158 static void find_joydevs(void);
159 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
160
161 /* This GUID is slightly different from the linux joystick one. Take note. */
162 static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
163   0x9e573eda,
164   0x7734,
165   0x11d2,
166   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
167 };
168
169 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
170
171 #define MAX_JOYDEV 64
172
173 static int have_joydevs = -1;
174 static struct JoyDev *joydevs = NULL;
175
176 static void find_joydevs(void)
177 {
178     int i;
179
180     if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1)
181         /* Someone beat us to it */
182         return;
183
184     for (i = 0; i < MAX_JOYDEV; i++)
185     {
186         char buf[MAX_PATH];
187         struct JoyDev joydev = {0};
188         int fd;
189         int no_ff_check = 0;
190         int j;
191         struct JoyDev *new_joydevs;
192         struct input_id device_id = {0};
193
194         snprintf(buf, sizeof(buf), EVDEVPREFIX"%d", i);
195
196         if ((fd = open(buf, O_RDWR)) == -1)
197         {
198             fd = open(buf, O_RDONLY);
199             no_ff_check = 1;
200         }
201
202         if (fd == -1)
203         {
204             WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno));
205             continue;
206         }
207
208         if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1)
209         {
210             WARN("ioct(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno));
211             close(fd);
212             continue;
213         }
214         if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1)
215         {
216             WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
217             close(fd);
218             continue;
219         }
220         if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1)
221         {
222             WARN("ioct(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno));
223             close(fd);
224             continue;
225         }
226
227         /* A true joystick has at least axis X and Y, and at least 1
228          * button. copied from linux/drivers/input/joydev.c */
229         if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) ||
230             !(test_bit(joydev.keybits, BTN_TRIGGER) ||
231               test_bit(joydev.keybits, BTN_A) ||
232               test_bit(joydev.keybits, BTN_1)))
233         {
234             close(fd);
235             continue;
236         }
237
238         if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
239         {
240             close(fd);
241             continue;
242         }
243         strcpy(joydev.device, buf);
244
245         buf[MAX_PATH - 1] = 0;
246         if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 &&
247             (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
248             strcpy(joydev.name, buf);
249         else
250             joydev.name = joydev.device;
251
252         joydev.guid = DInput_Wine_Joystick_Base_GUID;
253         joydev.guid.Data3 += have_joydevs;
254
255         TRACE("Found a joystick on %s: %s (%s)\n", 
256             joydev.device, joydev.name, 
257             debugstr_guid(&joydev.guid)
258             );
259
260 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
261         if (!no_ff_check &&
262             test_bit(joydev.evbits, EV_FF) &&
263             ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 &&
264             ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 &&
265             joydev.num_effects > 0)
266         {
267             TRACE(" ... with force feedback\n");
268             joydev.has_ff = 1;
269         }
270 #endif
271
272         for (j = 0; j < ABS_MAX;j ++)
273         {
274             if (!test_bit(joydev.absbits, j)) continue;
275             if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1)
276             {
277               TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
278                   j,
279                   joydev.axes[j].value,
280                   joydev.axes[j].minimum,
281                   joydev.axes[j].maximum,
282                   joydev.axes[j].fuzz,
283                   joydev.axes[j].flat
284                   );
285             }
286         }
287
288         if (ioctl(fd, EVIOCGID, &device_id) == -1)
289             WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
290         else
291         {
292             joydev.vendor_id = device_id.vendor;
293             joydev.product_id = device_id.product;
294         }
295
296         if (!have_joydevs)
297             new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
298         else
299             new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev));
300
301         if (!new_joydevs)
302         {
303             close(fd);
304             continue;
305         }
306         joydevs = new_joydevs;
307         memcpy(joydevs + have_joydevs, &joydev, sizeof(joydev));
308         have_joydevs++;
309
310         close(fd);
311     }
312 }
313
314 static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
315 {
316     DWORD dwSize = lpddi->dwSize;
317
318     TRACE("%d %p\n", dwSize, lpddi);
319     memset(lpddi, 0, dwSize);
320
321     lpddi->dwSize       = dwSize;
322     lpddi->guidInstance = joydevs[id].guid;
323     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
324     lpddi->guidFFDriver = GUID_NULL;
325
326     if (version >= 0x0800)
327         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
328     else
329         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
330
331     strcpy(lpddi->tszInstanceName, joydevs[id].name);
332     strcpy(lpddi->tszProductName, joydevs[id].name);
333 }
334
335 static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
336 {
337     DWORD dwSize = lpddi->dwSize;
338
339     TRACE("%d %p\n", dwSize, lpddi);
340     memset(lpddi, 0, dwSize);
341
342     lpddi->dwSize       = dwSize;
343     lpddi->guidInstance = joydevs[id].guid;
344     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
345     lpddi->guidFFDriver = GUID_NULL;
346
347     if (version >= 0x0800)
348         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
349     else
350         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
351
352     MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
353     MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
354 }
355
356 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
357 {
358   find_joydevs();
359
360   if (id >= have_joydevs) {
361     return FALSE;
362   }
363
364   if (!((dwDevType == 0) ||
365         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
366         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
367     return FALSE;
368
369 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
370   if (dwFlags & DIEDFL_FORCEFEEDBACK)
371     return FALSE;
372 #endif
373
374   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
375     fill_joystick_dideviceinstanceA(lpddi, version, id);
376     return TRUE;
377   }
378   return FALSE;
379 }
380
381 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
382 {
383   find_joydevs();
384
385   if (id >= have_joydevs) {
386     return FALSE;
387   }
388
389   if (!((dwDevType == 0) ||
390         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
391         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
392     return FALSE;
393
394 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
395   if (dwFlags & DIEDFL_FORCEFEEDBACK)
396     return FALSE;
397 #endif
398
399   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
400     fill_joystick_dideviceinstanceW(lpddi, version, id);
401     return TRUE;
402   }
403   return FALSE;
404 }
405
406 static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index)
407 {
408     JoystickImpl* newDevice;
409     LPDIDATAFORMAT df = NULL;
410     int i, idx = 0;
411     int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2];
412
413     newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
414     if (!newDevice) return NULL;
415
416     newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
417     newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
418     newDevice->generic.base.ref    = 1;
419     newDevice->generic.base.guid   = *rguid;
420     newDevice->generic.base.dinput = dinput;
421     newDevice->generic.joy_polldev = joy_polldev;
422     newDevice->joyfd       = -1;
423     newDevice->joydev      = &joydevs[index];
424     newDevice->generic.name        = newDevice->joydev->name;
425     list_init(&newDevice->ff_effects);
426 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
427     newDevice->ff_state    = FF_STATUS_STOPPED;
428 #endif
429     /* There is no way in linux to query force feedback autocenter status.
430        Instead, track it with ff_autocenter, and assume it's initially
431        enabled. */
432     newDevice->ff_autocenter = 1;
433     newDevice->ff_gain = 0xFFFF;
434     InitializeCriticalSection(&newDevice->generic.base.crit);
435     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
436
437     /* Count number of available axes - supported Axis & POVs */
438     for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++)
439     {
440         if (test_bit(newDevice->joydev->absbits, i))
441         {
442             newDevice->generic.device_axis_count++;
443             newDevice->dev_axes_to_di[i] = idx;
444             newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum;
445             newDevice->generic.props[idx].lDevMax = newDevice->joydev->axes[i].maximum;
446             default_axis_map[idx] = i;
447             idx++;
448         }
449         else
450             newDevice->dev_axes_to_di[i] = -1;
451     }
452
453     for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++)
454     {
455         if (test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) &&
456             test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2))
457         {
458             newDevice->generic.device_axis_count += 2;
459             newDevice->generic.props[idx  ].lDevMin = newDevice->joydev->axes[ABS_HAT0X + i * 2].minimum;
460             newDevice->generic.props[idx  ].lDevMax = newDevice->joydev->axes[ABS_HAT0X + i * 2].maximum;
461             newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = idx;
462             newDevice->generic.props[idx+1].lDevMin = newDevice->joydev->axes[ABS_HAT0Y + i * 2].minimum;
463             newDevice->generic.props[idx+1].lDevMax = newDevice->joydev->axes[ABS_HAT0Y + i * 2].maximum;
464             newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = idx + 1;
465
466             default_axis_map[idx] = default_axis_map[idx + 1] = WINE_JOYSTICK_MAX_AXES + i;
467             idx += 2;
468         }
469         else
470             newDevice->dev_axes_to_di[ABS_HAT0X + i * 2] = newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = -1;
471     }
472
473     /* do any user specified configuration */
474     if (setup_dinput_options(&newDevice->generic, default_axis_map) != DI_OK) goto failed;
475
476     /* Create copy of default data format */
477     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
478     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
479     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
480
481
482     /* Construct internal data format */
483
484     /* Supported Axis & POVs */
485     for (i = 0, idx = 0; i < newDevice->generic.device_axis_count; i++)
486     {
487         int wine_obj = newDevice->generic.axis_map[i];
488
489         if (wine_obj < 0) continue;
490
491         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
492         if (wine_obj < 8)
493             df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
494         else
495         {
496             df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
497             i++; /* POV takes 2 axes */
498         }
499
500         newDevice->generic.props[idx].lMin        = 0;
501         newDevice->generic.props[idx].lMax        = 0xffff;
502         newDevice->generic.props[idx].lSaturation = 0;
503         newDevice->generic.props[idx].lDeadZone   = newDevice->generic.deadzone;
504
505         /* Linux supports force-feedback on X & Y axes only */
506         if (newDevice->joydev->has_ff && (i == 0 || i == 1))
507             df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
508
509         idx++;
510     }
511
512     /* Buttons can be anywhere, so check all */
513     for (i = 0; i < KEY_MAX && newDevice->generic.devcaps.dwButtons < WINE_JOYSTICK_MAX_BUTTONS; i++)
514     {
515         if (!test_bit(newDevice->joydev->keybits, i)) continue;
516
517         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->generic.devcaps.dwButtons + 12], df->dwObjSize);
518         newDevice->buttons[i] = 0x80 | newDevice->generic.devcaps.dwButtons;
519         df->rgodf[idx  ].pguid = &GUID_Button;
520         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->generic.devcaps.dwButtons++) | DIDFT_PSHBUTTON;
521     }
522     df->dwNumObjs = idx;
523     newDevice->generic.base.data_format.wine_df = df;
524
525     fake_current_js_state(newDevice);
526
527     /* Fill the caps */
528     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
529     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
530     if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
531         newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
532     else
533         newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
534
535     if (newDevice->joydev->has_ff)
536         newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
537
538     IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
539
540     EnterCriticalSection(&dinput->crit);
541     list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
542     LeaveCriticalSection(&dinput->crit);
543
544     return newDevice;
545
546 failed:
547     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
548     HeapFree(GetProcessHeap(), 0, df);
549     HeapFree(GetProcessHeap(), 0, newDevice->generic.axis_map);
550     HeapFree(GetProcessHeap(), 0, newDevice);
551     return NULL;
552 }
553
554 /******************************************************************************
555   *     get_joystick_index : Get the joystick index from a given GUID
556   */
557 static unsigned short get_joystick_index(REFGUID guid)
558 {
559     GUID wine_joystick = DInput_Wine_Joystick_Base_GUID;
560     GUID dev_guid = *guid;
561
562     wine_joystick.Data3 = 0;
563     dev_guid.Data3 = 0;
564
565     /* for the standard joystick GUID use index 0 */
566     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
567
568     /* for the wine joystick GUIDs use the index stored in Data3 */
569     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3;
570
571     return MAX_JOYDEV;
572 }
573
574 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
575 {
576     unsigned short index;
577
578     TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
579     find_joydevs();
580     *pdev = NULL;
581
582     if ((index = get_joystick_index(rguid)) < MAX_JOYDEV &&
583         have_joydevs && index < have_joydevs)
584     {
585         JoystickImpl *This;
586
587         if (riid == NULL)
588             ;/* nothing */
589         else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
590                  IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
591                  IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
592                  IsEqualGUID(&IID_IDirectInputDevice8A, riid))
593         {
594             unicode = 0;
595         }
596         else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
597                  IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
598                  IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
599                  IsEqualGUID(&IID_IDirectInputDevice8W, riid))
600         {
601             unicode = 1;
602         }
603         else
604         {
605             WARN("no interface\n");
606             return DIERR_NOINTERFACE;
607         }
608
609         This = alloc_device(rguid, dinput, index);
610         TRACE("Created a Joystick device (%p)\n", This);
611
612         if (!This) return DIERR_OUTOFMEMORY;
613
614         if (unicode)
615             *pdev = &This->generic.base.IDirectInputDevice8W_iface;
616         else
617             *pdev = &This->generic.base.IDirectInputDevice8A_iface;
618
619         return DI_OK;
620     }
621
622     return DIERR_DEVICENOTREG;
623 }
624
625
626 const struct dinput_device joystick_linuxinput_device = {
627   "Wine Linux-input joystick driver",
628   joydev_enum_deviceA,
629   joydev_enum_deviceW,
630   joydev_create_device
631 };
632
633 /******************************************************************************
634   *     Acquire : gets exclusive control of the joystick
635   */
636 static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
637 {
638     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
639     HRESULT res;
640
641     TRACE("(this=%p)\n",This);
642
643     if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK)
644     {
645         WARN("Failed to acquire: %x\n", res);
646         return res;
647     }
648
649     if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1)
650     {
651         if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1)
652         {
653             /* Couldn't open the device at all */
654             ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno));
655             IDirectInputDevice2WImpl_Unacquire(iface);
656             return DIERR_NOTFOUND;
657         }
658         else
659         {
660             /* Couldn't open in r/w but opened in read-only. */
661             WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n", This->joydev->device);
662         }
663     }
664     else
665     {
666         struct input_event event;
667
668         event.type = EV_FF;
669         event.code = FF_GAIN;
670         event.value = This->ff_gain;
671         if (write(This->joyfd, &event, sizeof(event)) == -1)
672             ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
673         if (!This->ff_autocenter)
674         {
675             /* Disable autocenter. */
676             event.code = FF_AUTOCENTER;
677             event.value = 0;
678             if (write(This->joyfd, &event, sizeof(event)) == -1)
679                 ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
680         }
681     }
682
683     return DI_OK;
684 }
685
686 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
687 {
688     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
689     return JoystickWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
690 }
691
692 /******************************************************************************
693   *     Unacquire : frees the joystick
694   */
695 static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
696 {
697     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
698     HRESULT res;
699
700     TRACE("(this=%p)\n",This);
701     res = IDirectInputDevice2WImpl_Unacquire(iface);
702     if (res==DI_OK && This->joyfd!=-1) {
703       effect_list_item *itr;
704       struct input_event event;
705
706       /* For each known effect:
707        * - stop it
708        * - unload it
709        * But, unlike DISFFC_RESET, do not release the effect.
710        */
711       LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) {
712           IDirectInputEffect_Stop(itr->ref);
713           IDirectInputEffect_Unload(itr->ref);
714       }
715
716       /* Enable autocenter. */
717       event.type = EV_FF;
718       event.code = FF_AUTOCENTER;
719       /* TODO: Read autocenter strength before disabling it, and use it here
720        * instead of 0xFFFF (maximum strength).
721        */
722       event.value = 0xFFFF;
723       if (write(This->joyfd, &event, sizeof(event)) == -1)
724         ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno));
725
726       close(This->joyfd);
727       This->joyfd = -1;
728     }
729     return res;
730 }
731
732 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
733 {
734     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
735     return JoystickWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
736 }
737
738 /* 
739  * set the current state of the js device as it would be with the middle
740  * values on the axes
741  */
742 #define CENTER_AXIS(a) \
743     (ji->dev_axes_to_di[a] == -1 ? 0 : joystick_map_axis( &ji->generic.props[ji->dev_axes_to_di[a]], \
744                                                           ji->joydev->axes[a].value ))
745 static void fake_current_js_state(JoystickImpl *ji)
746 {
747     int i;
748
749     /* center the axes */
750     ji->generic.js.lX           = CENTER_AXIS(ABS_X);
751     ji->generic.js.lY           = CENTER_AXIS(ABS_Y);
752     ji->generic.js.lZ           = CENTER_AXIS(ABS_Z);
753     ji->generic.js.lRx          = CENTER_AXIS(ABS_RX);
754     ji->generic.js.lRy          = CENTER_AXIS(ABS_RY);
755     ji->generic.js.lRz          = CENTER_AXIS(ABS_RZ);
756     ji->generic.js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE);
757     ji->generic.js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER);
758
759     /* POV center is -1 */
760     for (i = 0; i < 4; i++)
761         ji->generic.js.rgdwPOV[i] = -1;
762 }
763 #undef CENTER_AXIS
764
765 /* convert wine format offset to user format object index */
766 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
767 {
768     struct pollfd plfd;
769     struct input_event ie;
770     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
771
772     if (This->joyfd==-1)
773         return;
774
775     while (1)
776     {
777         LONG value = 0;
778         int inst_id = -1;
779
780         plfd.fd = This->joyfd;
781         plfd.events = POLLIN;
782
783         if (poll(&plfd,1,0) != 1)
784             return;
785
786         /* we have one event, so we can read */
787         if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
788             return;
789
790         TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
791         switch (ie.type) {
792         case EV_KEY:    /* button */
793         {
794             int btn = This->buttons[ie.code];
795
796             TRACE("(%p) %d -> %d\n", This, ie.code, btn);
797             if (btn & 0x80)
798             {
799                 btn &= 0x7F;
800                 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
801                 This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
802             }
803             break;
804         }
805         case EV_ABS:
806         {
807             int axis = This->dev_axes_to_di[ie.code];
808
809             /* User axis remapping */
810             if (axis < 0) break;
811             axis = This->generic.axis_map[axis];
812             if (axis < 0) break;
813
814             inst_id = axis < 8 ?  DIDFT_MAKEINSTANCE(axis) | DIDFT_ABSAXIS :
815                                   DIDFT_MAKEINSTANCE(axis - 8) | DIDFT_POV;
816             value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], ie.value);
817
818             switch (axis) {
819             case 0: This->generic.js.lX  = value; break;
820             case 1: This->generic.js.lY  = value; break;
821             case 2: This->generic.js.lZ  = value; break;
822             case 3: This->generic.js.lRx = value; break;
823             case 4: This->generic.js.lRy = value; break;
824             case 5: This->generic.js.lRz = value; break;
825             case 6: This->generic.js.rglSlider[0] = value; break;
826             case 7: This->generic.js.rglSlider[1] = value; break;
827             case 8: case 9: case 10: case 11:
828             {
829                 int idx = axis - 8;
830
831                 if (ie.code % 2)
832                     This->povs[idx].y = ie.value;
833                 else
834                     This->povs[idx].x = ie.value;
835
836                 This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
837                 break;
838             }
839             default:
840                 FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value);
841             }
842             break;
843         }
844 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
845         case EV_FF_STATUS:
846             This->ff_state = ie.value;
847             break;
848 #endif
849 #ifdef EV_SYN
850         case EV_SYN:
851             /* there is nothing to do */
852             break;
853 #endif
854 #ifdef EV_MSC
855         case EV_MSC:
856             /* Ignore */
857             break;
858 #endif
859         default:
860             FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
861             break;
862         }
863         if (inst_id >= 0)
864             queue_event(iface, inst_id,
865                         value, ie.time.tv_usec, This->generic.base.dinput->evsequence++);
866     }
867 }
868
869 /******************************************************************************
870   *     SetProperty : change input device properties
871   */
872 static HRESULT WINAPI JoystickWImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph)
873 {
874   JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
875
876   if (!ph) {
877     WARN("invalid argument\n");
878     return DIERR_INVALIDPARAM;
879   }
880
881   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
882   TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n",
883         ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow);
884
885   if (IS_DIPROP(rguid)) {
886     switch (LOWORD(rguid)) {
887     case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
888       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
889       FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
890       break;
891     }
892     case (DWORD_PTR)DIPROP_AUTOCENTER: {
893       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
894
895       TRACE("autocenter(%d)\n", pd->dwData);
896       This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON;
897
898       break;
899     }
900     case (DWORD_PTR)DIPROP_FFGAIN: {
901       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
902
903       TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
904       This->ff_gain = MulDiv(pd->dwData, 0xFFFF, 10000);
905       if (This->generic.base.acquired) {
906         /* Update immediately. */
907         struct input_event event;
908
909         event.type = EV_FF;
910         event.code = FF_GAIN;
911         event.value = This->ff_gain;
912         if (write(This->joyfd, &event, sizeof(event)) == -1)
913           ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
914       }
915       break;
916     }
917     default:
918       return JoystickWGenericImpl_SetProperty(iface, rguid, ph);
919     }
920   }
921   return DI_OK;
922 }
923
924 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER ph)
925 {
926     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
927     return JoystickWImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, ph);
928 }
929
930 /******************************************************************************
931   *     GetProperty : get input device properties
932   */
933 static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
934 {
935     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
936
937     TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
938     _dump_DIPROPHEADER(pdiph);
939
940     if (!IS_DIPROP(rguid)) return DI_OK;
941
942     switch (LOWORD(rguid)) {
943     case (DWORD_PTR) DIPROP_AUTOCENTER:
944     {
945         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
946
947         pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF;
948         TRACE("autocenter(%d)\n", pd->dwData);
949         break;
950     }
951     case (DWORD_PTR) DIPROP_FFGAIN:
952     {
953         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
954
955         pd->dwData = MulDiv(This->ff_gain, 10000, 0xFFFF);
956         TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
957         break;
958     }
959
960     case (DWORD_PTR) DIPROP_VIDPID:
961     {
962         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
963
964         if (!This->joydev->product_id || !This->joydev->vendor_id)
965             return DIERR_UNSUPPORTED;
966         pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
967         TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
968         break;
969     }
970
971     default:
972         return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
973     }
974
975     return DI_OK;
976 }
977
978 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
979 {
980     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
981     return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
982 }
983
984 /****************************************************************************** 
985   *     CreateEffect - Create a new FF effect with the specified params
986   */
987 static HRESULT WINAPI JoystickWImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid,
988                                                  LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
989                                                  LPUNKNOWN pUnkOuter)
990 {
991 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
992     effect_list_item* new_effect = NULL;
993     HRESULT retval = DI_OK;
994 #endif
995
996     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
997     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
998
999 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
1000     TRACE("not available (compiled w/o ff support)\n");
1001     *ppdef = NULL;
1002     return DI_OK;
1003 #else
1004
1005     if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
1006         return DIERR_OUTOFMEMORY;
1007
1008     retval = linuxinput_create_effect(&This->joyfd, rguid, &new_effect->entry, &new_effect->ref);
1009     if (retval != DI_OK)
1010     {
1011         HeapFree(GetProcessHeap(), 0, new_effect);
1012         return retval;
1013     }
1014
1015     if (lpeff != NULL)
1016     {
1017         retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0);
1018
1019         if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
1020         {
1021             HeapFree(GetProcessHeap(), 0, new_effect);
1022             return retval;
1023         }
1024     }
1025
1026     list_add_tail(&This->ff_effects, &new_effect->entry);
1027     *ppdef = new_effect->ref;
1028
1029     if (pUnkOuter != NULL)
1030         FIXME("Interface aggregation not implemented.\n");
1031
1032     return DI_OK;
1033
1034 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1035 }
1036
1037 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid,
1038                                                  LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
1039                                                  LPUNKNOWN pUnkOuter)
1040 {
1041     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1042     return JoystickWImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter);
1043 }
1044
1045 /*******************************************************************************
1046  *      EnumEffects - Enumerate available FF effects
1047  */
1048 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
1049                                                 LPDIENUMEFFECTSCALLBACKA lpCallback,
1050                                                 LPVOID pvRef,
1051                                                 DWORD dwEffType)
1052 {
1053 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1054     DIEFFECTINFOA dei; /* feif */
1055     DWORD type = DIEFT_GETTYPE(dwEffType);
1056     JoystickImpl* This = impl_from_IDirectInputDevice8A(iface);
1057
1058     TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type);
1059
1060     dei.dwSize = sizeof(DIEFFECTINFOA);          
1061
1062     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1063         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1064         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1065         (*lpCallback)(&dei, pvRef);
1066     }
1067
1068     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1069         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1070         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1071             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1072             (*lpCallback)(&dei, pvRef);
1073         }
1074         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1075             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1076             (*lpCallback)(&dei, pvRef);
1077         }
1078         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1079             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1080             (*lpCallback)(&dei, pvRef);
1081         }
1082         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1083             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1084             (*lpCallback)(&dei, pvRef);
1085         }
1086         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1087             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1088             (*lpCallback)(&dei, pvRef);
1089         }
1090     } 
1091
1092     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1093         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1094         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1095         (*lpCallback)(&dei, pvRef);
1096     }
1097
1098     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1099         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1100             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1101             (*lpCallback)(&dei, pvRef);
1102         }
1103         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1104             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1105             (*lpCallback)(&dei, pvRef);
1106         }
1107         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1108             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1109             (*lpCallback)(&dei, pvRef);
1110         }
1111         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1112             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1113             (*lpCallback)(&dei, pvRef);
1114         }
1115     }
1116
1117 #endif
1118
1119     return DI_OK;
1120 }
1121
1122 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
1123                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
1124                                                 LPVOID pvRef,
1125                                                 DWORD dwEffType)
1126 {
1127 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1128     /* seems silly to duplicate all this code but all the structures and functions
1129      * are actually different (A/W) */
1130     DIEFFECTINFOW dei; /* feif */
1131     DWORD type = DIEFT_GETTYPE(dwEffType);
1132     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1133     int xfd = This->joyfd;
1134
1135     TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
1136
1137     dei.dwSize = sizeof(DIEFFECTINFOW);          
1138
1139     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1140         && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1141         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1142         (*lpCallback)(&dei, pvRef);
1143     }
1144
1145     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1146         && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
1147         if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1148             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1149             (*lpCallback)(&dei, pvRef);
1150         }
1151         if (test_bit(This->joydev->ffbits, FF_SINE)) {
1152             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1153             (*lpCallback)(&dei, pvRef);
1154         }
1155         if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1156             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1157             (*lpCallback)(&dei, pvRef);
1158         }
1159         if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1160             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1161             (*lpCallback)(&dei, pvRef);
1162         }
1163         if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1164             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1165             (*lpCallback)(&dei, pvRef);
1166         }
1167     } 
1168
1169     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1170         && test_bit(This->joydev->ffbits, FF_RAMP)) {
1171         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1172         (*lpCallback)(&dei, pvRef);
1173     }
1174
1175     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1176         if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1177             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1178             (*lpCallback)(&dei, pvRef);
1179         }
1180         if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1181             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1182             (*lpCallback)(&dei, pvRef);
1183         }
1184         if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1185             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1186             (*lpCallback)(&dei, pvRef);
1187         }
1188         if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1189             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1190             (*lpCallback)(&dei, pvRef);
1191         }
1192     }
1193
1194     /* return to unacquired state if that's where it was */
1195     if (xfd == -1)
1196         IDirectInputDevice8_Unacquire(iface);
1197 #endif
1198
1199     return DI_OK;
1200 }
1201
1202 /*******************************************************************************
1203  *      GetEffectInfo - Get information about a particular effect 
1204  */
1205 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
1206                                                   LPDIEFFECTINFOA pdei,
1207                                                   REFGUID guid)
1208 {
1209     JoystickImpl* This = impl_from_IDirectInputDevice8A(iface);
1210
1211     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1212
1213 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1214     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
1215 #else
1216     return DI_OK;
1217 #endif
1218 }
1219
1220 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
1221                                                   LPDIEFFECTINFOW pdei,
1222                                                   REFGUID guid)
1223 {
1224     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1225
1226     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1227
1228 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1229     return linuxinput_get_info_W(This->joyfd, guid, pdei);
1230 #else
1231     return DI_OK;
1232 #endif
1233 }
1234
1235 /*******************************************************************************
1236  *      GetForceFeedbackState - Get information about the device's FF state 
1237  */
1238 static HRESULT WINAPI JoystickWImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut)
1239 {
1240     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1241
1242     TRACE("(this=%p,%p)\n", This, pdwOut);
1243
1244     (*pdwOut) = 0;
1245
1246 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1247     /* DIGFFS_STOPPED is the only mandatory flag to report */
1248     if (This->ff_state == FF_STATUS_STOPPED)
1249         (*pdwOut) |= DIGFFS_STOPPED;
1250 #endif
1251
1252     return DI_OK;
1253 }
1254
1255 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut)
1256 {
1257     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1258     return JoystickWImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut);
1259 }
1260
1261 /*******************************************************************************
1262  *      SendForceFeedbackCommand - Send a command to the device's FF system
1263  */
1264 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags)
1265 {
1266     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1267     TRACE("(this=%p,%d)\n", This, dwFlags);
1268
1269 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1270     switch (dwFlags)
1271     {
1272     case DISFFC_STOPALL:
1273     {
1274         /* Stop all effects */
1275         effect_list_item *itr;
1276
1277         LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
1278             IDirectInputEffect_Stop(itr->ref);
1279         break;
1280     }
1281
1282     case DISFFC_RESET:
1283     {
1284         effect_list_item *itr, *ptr;
1285
1286         /* Stop, unload, release and free all effects */
1287         /* This returns the device to its "bare" state */
1288         LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
1289             IDirectInputEffect_Release(itr->ref);
1290         break;
1291     }
1292     case DISFFC_PAUSE:
1293     case DISFFC_CONTINUE:
1294         FIXME("No support for Pause or Continue in linux\n");
1295         break;
1296
1297     case DISFFC_SETACTUATORSOFF:
1298     case DISFFC_SETACTUATORSON:
1299         FIXME("No direct actuator control in linux\n");
1300         break;
1301
1302     default:
1303         FIXME("Unknown Force Feedback Command!\n");
1304         return DIERR_INVALIDPARAM;
1305     }
1306     return DI_OK;
1307 #else
1308     return DIERR_UNSUPPORTED;
1309 #endif
1310 }
1311
1312 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags)
1313 {
1314     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1315     return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags);
1316 }
1317
1318 /*******************************************************************************
1319  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
1320  *              created for this device.
1321  */
1322 static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
1323                                                              LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1324                                                              LPVOID pvRef, DWORD dwFlags)
1325 {
1326     /* this function is safe to call on non-ff-enabled builds */
1327     JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1328     effect_list_item *itr, *ptr;
1329
1330     TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
1331
1332     if (!lpCallback)
1333         return DIERR_INVALIDPARAM;
1334
1335     if (dwFlags != 0)
1336         FIXME("Flags specified, but no flags exist yet (DX9)!\n");
1337
1338     LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
1339         (*lpCallback)(itr->ref, pvRef);
1340
1341     return DI_OK;
1342 }
1343
1344 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface,
1345                                                              LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1346                                                              LPVOID pvRef, DWORD dwFlags)
1347 {
1348     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1349     return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags);
1350 }
1351
1352 /******************************************************************************
1353   *     GetDeviceInfo : get information about a device's identity
1354   */
1355 static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface,
1356                                                   LPDIDEVICEINSTANCEA pdidi)
1357 {
1358     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1359
1360     TRACE("(%p) %p\n", This, pdidi);
1361
1362     if (pdidi == NULL) return E_POINTER;
1363     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
1364         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)))
1365         return DIERR_INVALIDPARAM;
1366
1367     fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion,
1368                                     get_joystick_index(&This->generic.base.guid));
1369     return DI_OK;
1370 }
1371
1372 static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface,
1373                                                   LPDIDEVICEINSTANCEW pdidi)
1374 {
1375     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1376
1377     TRACE("(%p) %p\n", This, pdidi);
1378
1379     if (pdidi == NULL) return E_POINTER;
1380     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
1381         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)))
1382         return DIERR_INVALIDPARAM;
1383
1384     fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion,
1385                                     get_joystick_index(&This->generic.base.guid));
1386     return DI_OK;
1387 }
1388
1389 static const IDirectInputDevice8AVtbl JoystickAvt =
1390 {
1391         IDirectInputDevice2AImpl_QueryInterface,
1392         IDirectInputDevice2AImpl_AddRef,
1393         IDirectInputDevice2AImpl_Release,
1394         JoystickAGenericImpl_GetCapabilities,
1395         IDirectInputDevice2AImpl_EnumObjects,
1396         JoystickAImpl_GetProperty,
1397         JoystickAImpl_SetProperty,
1398         JoystickAImpl_Acquire,
1399         JoystickAImpl_Unacquire,
1400         JoystickAGenericImpl_GetDeviceState,
1401         IDirectInputDevice2AImpl_GetDeviceData,
1402         IDirectInputDevice2AImpl_SetDataFormat,
1403         IDirectInputDevice2AImpl_SetEventNotification,
1404         IDirectInputDevice2AImpl_SetCooperativeLevel,
1405         JoystickAGenericImpl_GetObjectInfo,
1406         JoystickAImpl_GetDeviceInfo,
1407         IDirectInputDevice2AImpl_RunControlPanel,
1408         IDirectInputDevice2AImpl_Initialize,
1409         JoystickAImpl_CreateEffect,
1410         JoystickAImpl_EnumEffects,
1411         JoystickAImpl_GetEffectInfo,
1412         JoystickAImpl_GetForceFeedbackState,
1413         JoystickAImpl_SendForceFeedbackCommand,
1414         JoystickAImpl_EnumCreatedEffectObjects,
1415         IDirectInputDevice2AImpl_Escape,
1416         JoystickAGenericImpl_Poll,
1417         IDirectInputDevice2AImpl_SendDeviceData,
1418         IDirectInputDevice7AImpl_EnumEffectsInFile,
1419         IDirectInputDevice7AImpl_WriteEffectToFile,
1420         JoystickAGenericImpl_BuildActionMap,
1421         JoystickAGenericImpl_SetActionMap,
1422         IDirectInputDevice8AImpl_GetImageInfo
1423 };
1424
1425 static const IDirectInputDevice8WVtbl JoystickWvt =
1426 {
1427     IDirectInputDevice2WImpl_QueryInterface,
1428     IDirectInputDevice2WImpl_AddRef,
1429     IDirectInputDevice2WImpl_Release,
1430     JoystickWGenericImpl_GetCapabilities,
1431     IDirectInputDevice2WImpl_EnumObjects,
1432     JoystickWImpl_GetProperty,
1433     JoystickWImpl_SetProperty,
1434     JoystickWImpl_Acquire,
1435     JoystickWImpl_Unacquire,
1436     JoystickWGenericImpl_GetDeviceState,
1437     IDirectInputDevice2WImpl_GetDeviceData,
1438     IDirectInputDevice2WImpl_SetDataFormat,
1439     IDirectInputDevice2WImpl_SetEventNotification,
1440     IDirectInputDevice2WImpl_SetCooperativeLevel,
1441     JoystickWGenericImpl_GetObjectInfo,
1442     JoystickWImpl_GetDeviceInfo,
1443     IDirectInputDevice2WImpl_RunControlPanel,
1444     IDirectInputDevice2WImpl_Initialize,
1445     JoystickWImpl_CreateEffect,
1446     JoystickWImpl_EnumEffects,
1447     JoystickWImpl_GetEffectInfo,
1448     JoystickWImpl_GetForceFeedbackState,
1449     JoystickWImpl_SendForceFeedbackCommand,
1450     JoystickWImpl_EnumCreatedEffectObjects,
1451     IDirectInputDevice2WImpl_Escape,
1452     JoystickWGenericImpl_Poll,
1453     IDirectInputDevice2WImpl_SendDeviceData,
1454     IDirectInputDevice7WImpl_EnumEffectsInFile,
1455     IDirectInputDevice7WImpl_WriteEffectToFile,
1456     JoystickWGenericImpl_BuildActionMap,
1457     JoystickWGenericImpl_SetActionMap,
1458     IDirectInputDevice8WImpl_GetImageInfo
1459 };
1460
1461 #else  /* HAVE_CORRECT_LINUXINPUT_H */
1462
1463 const struct dinput_device joystick_linuxinput_device = {
1464   "Wine Linux-input joystick driver",
1465   NULL,
1466   NULL,
1467   NULL
1468 };
1469
1470 #endif  /* HAVE_CORRECT_LINUXINPUT_H */