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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #ifdef HAVE_SYS_TIME_H
39 # include <sys/time.h>
40 #endif
41 #include <fcntl.h>
42 #ifdef HAVE_SYS_IOCTL_H
43 # include <sys/ioctl.h>
44 #endif
45 #include <errno.h>
46 #ifdef HAVE_LINUX_IOCTL_H
47 # include <linux/ioctl.h>
48 #endif
49 #ifdef HAVE_LINUX_JOYSTICK_H
50 # include <linux/joystick.h>
51 # undef SW_MAX
52 #endif
53 #ifdef HAVE_SYS_POLL_H
54 # include <sys/poll.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 "dinput.h"
63 
64 #include "dinput_private.h"
65 #include "device_private.h"
66 #include "joystick_private.h"
67 
68 #ifdef HAVE_LINUX_22_JOYSTICK_API
69 
70 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
71 
72 #define JOYDEV_NEW "/dev/input/js"
73 #define JOYDEV_OLD "/dev/js"
74 #define JOYDEVDRIVER " (js)"
75 
76 struct JoyDev
77 {
78     char device[MAX_PATH];
79     char name[MAX_PATH];
80     GUID guid_product;
81 
82     BYTE axis_count;
83     BYTE button_count;
84     int  *dev_axes_map;
85 
86     WORD vendor_id, product_id, bus_type;
87 };
88 
89 typedef struct JoystickImpl JoystickImpl;
90 static const IDirectInputDevice8AVtbl JoystickAvt;
91 static const IDirectInputDevice8WVtbl JoystickWvt;
92 struct JoystickImpl
93 {
94         struct JoystickGenericImpl generic;
95 
96         struct JoyDev                  *joydev;
97 
98 	/* joystick private */
99 	int				joyfd;
100         POINTL                          povs[4];
101 };
102 
103 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
104 {
105     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
106            JoystickGenericImpl, base), JoystickImpl, generic);
107 }
108 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
109 {
110     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
111            JoystickGenericImpl, base), JoystickImpl, generic);
112 }
113 
114 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
115 {
116     return &This->generic.base.IDirectInputDevice8W_iface;
117 }
118 
119 static const GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
120   0x9e573ed9,
121   0x7734,
122   0x11d2,
123   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
124 };
125 
126 /*
127  * Construct the GUID in the same way of Windows doing this.
128  * Data1 is concatenation of productid and vendorid.
129  * Data2 and Data3 are NULL.
130  * Data4 seems to be a constant.
131  */
132 static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
133   0x000000000,
134   0x0000,
135   0x0000,
136   {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
137 };
138 
139 #define MAX_JOYSTICKS 64
140 static INT joystick_devices_count = -1;
141 static struct JoyDev *joystick_devices;
142 
143 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface);
144 
145 #define SYS_PATH_FORMAT "/sys/class/input/js%d/device/id/%s"
146 static BOOL read_sys_id_variable(int index, const char *property, WORD *value)
147 {
148     char sys_path[sizeof(SYS_PATH_FORMAT) + 16], id_str[5];
149     int sys_fd;
150     BOOL ret = FALSE;
151 
152     sprintf(sys_path, SYS_PATH_FORMAT, index, property);
153     if ((sys_fd = open(sys_path, O_RDONLY)) != -1)
154     {
155         if (read(sys_fd, id_str, 4) == 4)
156         {
157             id_str[4] = '\0';
158             *value = strtol(id_str, NULL, 16);
159             ret = TRUE;
160         }
161 
162         close(sys_fd);
163     }
164     return ret;
165 }
166 #undef SYS_PATH_FORMAT
167 
168 static INT find_joystick_devices(void)
169 {
170     INT i;
171 
172     if (joystick_devices_count != -1) return joystick_devices_count;
173 
174     joystick_devices_count = 0;
175     for (i = 0; i < MAX_JOYSTICKS; i++)
176     {
177         int fd;
178         struct JoyDev joydev, *new_joydevs;
179         BYTE axes_map[ABS_MAX + 1];
180 
181         snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
182         if ((fd = open(joydev.device, O_RDONLY)) == -1)
183         {
184             snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_OLD, i);
185             if ((fd = open(joydev.device, O_RDONLY)) == -1) continue;
186         }
187 
188         strcpy(joydev.name, "Wine Joystick");
189 #if defined(JSIOCGNAME)
190         if (ioctl(fd, JSIOCGNAME(sizeof(joydev.name) - sizeof(JOYDEVDRIVER)), joydev.name) < 0)
191             WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", joydev.device, strerror(errno));
192 #endif
193 
194         /* Append driver name */
195         strcat(joydev.name, JOYDEVDRIVER);
196 
197         if (device_disabled_registry(joydev.name)) {
198             close(fd);
199             continue;
200         }
201 
202 #ifdef JSIOCGAXES
203         if (ioctl(fd, JSIOCGAXES, &joydev.axis_count) < 0)
204         {
205             WARN("ioctl(%s,JSIOCGAXES) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
206             joydev.axis_count = 2;
207         }
208 #else
209         WARN("reading number of joystick axes unsupported in this platform, defaulting to 2\n");
210         joydev.axis_count = 2;
211 #endif
212 #ifdef JSIOCGBUTTONS
213         if (ioctl(fd, JSIOCGBUTTONS, &joydev.button_count) < 0)
214         {
215             WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defaulting to 2\n", joydev.device, strerror(errno));
216             joydev.button_count = 2;
217         }
218 #else
219         WARN("reading number of joystick buttons unsupported in this platform, defaulting to 2\n");
220         joydev.button_count = 2;
221 #endif
222 
223         if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
224         {
225             WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno));
226             joydev.dev_axes_map = NULL;
227         }
228         else
229             if ((joydev.dev_axes_map = HeapAlloc(GetProcessHeap(), 0, joydev.axis_count * sizeof(int))))
230             {
231                 INT j, found_axes = 0;
232 
233                 /* Remap to DI numbers */
234                 for (j = 0; j < joydev.axis_count; j++)
235                 {
236                     if (axes_map[j] < 8)
237                     {
238                         /* Axis match 1-to-1 */
239                         joydev.dev_axes_map[j] = j;
240                         found_axes++;
241                     }
242                     else if (axes_map[j] == 16 ||
243                              axes_map[j] == 17)
244                     {
245                         /* POV axis */
246                         joydev.dev_axes_map[j] = 8;
247                         found_axes++;
248                     }
249                     else
250                         joydev.dev_axes_map[j] = -1;
251                 }
252 
253                 /* If no axes were configured but there are axes assume a 1-to-1 (wii controller) */
254                 if (joydev.axis_count && !found_axes)
255                 {
256                     int axes_limit = min(joydev.axis_count, 8); /* generic driver limit */
257 
258                     ERR("Incoherent joystick data, advertised %d axes, detected 0. Assuming 1-to-1.\n",
259                         joydev.axis_count);
260                     for (j = 0; j < axes_limit; j++)
261                         joydev.dev_axes_map[j] = j;
262 
263                     joydev.axis_count = axes_limit;
264                 }
265             }
266 
267         /* Find vendor_id and product_id in sysfs */
268         joydev.vendor_id  = 0;
269         joydev.product_id = 0;
270 
271         read_sys_id_variable(i, "vendor", &joydev.vendor_id);
272         read_sys_id_variable(i, "product", &joydev.product_id);
273         read_sys_id_variable(i, "bustype", &joydev.bus_type);
274 
275         if (joydev.vendor_id == 0 || joydev.product_id == 0)
276         {
277             joydev.guid_product = DInput_Wine_Joystick_GUID;
278         }
279         else
280         {
281             /* Concatenate product_id with vendor_id to mimic Windows behaviour */
282             joydev.guid_product       = DInput_Wine_Joystick_Constant_Part_GUID;
283             joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
284         }
285 
286         close(fd);
287 
288         if (!joystick_devices_count)
289             new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
290         else
291             new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joystick_devices,
292                                       (joystick_devices_count + 1) * sizeof(struct JoyDev));
293         if (!new_joydevs) continue;
294 
295         TRACE("Found a joystick on %s: %s\n  with %d axes and %d buttons\n", joydev.device,
296               joydev.name, joydev.axis_count, joydev.button_count);
297 
298         joystick_devices = new_joydevs;
299         joystick_devices[joystick_devices_count++] = joydev;
300     }
301 
302     return joystick_devices_count;
303 }
304 
305 static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
306 {
307     DWORD dwSize = lpddi->dwSize;
308 
309     TRACE("%d %p\n", dwSize, lpddi);
310     memset(lpddi, 0, dwSize);
311 
312     /* Return joystick */
313     lpddi->dwSize = dwSize;
314     lpddi->guidInstance = DInput_Wine_Joystick_GUID;
315     lpddi->guidInstance.Data3 = id;
316     lpddi->guidProduct = joystick_devices[id].guid_product;
317     /* we only support traditional joysticks for now */
318     if (version >= 0x0800)
319         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
320     else
321         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
322 
323     /* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */
324     if (joystick_devices[id].bus_type == BUS_USB &&
325         joystick_devices[id].vendor_id && joystick_devices[id].product_id)
326     {
327         lpddi->dwDevType |= DIDEVTYPE_HID;
328         lpddi->wUsagePage = 0x01; /* Desktop */
329         if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
330             lpddi->wUsage = 0x04; /* Joystick */
331         else
332             lpddi->wUsage = 0x05; /* Game Pad */
333     }
334 
335     MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
336     MultiByteToWideChar(CP_ACP, 0, joystick_devices[id].name, -1, lpddi->tszProductName, MAX_PATH);
337     lpddi->guidFFDriver = GUID_NULL;
338 }
339 
340 static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
341 {
342     DIDEVICEINSTANCEW lpddiW;
343     DWORD dwSize = lpddi->dwSize;
344 
345     lpddiW.dwSize = sizeof(lpddiW);
346     fill_joystick_dideviceinstanceW(&lpddiW, version, id);
347 
348     TRACE("%d %p\n", dwSize, lpddi);
349     memset(lpddi, 0, dwSize);
350 
351     /* Convert W->A */
352     lpddi->dwSize = dwSize;
353     lpddi->guidInstance = lpddiW.guidInstance;
354     lpddi->guidProduct = lpddiW.guidProduct;
355     lpddi->dwDevType = lpddiW.dwDevType;
356     strcpy(lpddi->tszInstanceName, joystick_devices[id].name);
357     strcpy(lpddi->tszProductName,  joystick_devices[id].name);
358     lpddi->guidFFDriver = lpddiW.guidFFDriver;
359     lpddi->wUsagePage = lpddiW.wUsagePage;
360     lpddi->wUsage = lpddiW.wUsage;
361 }
362 
363 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
364 {
365     int fd = -1;
366 
367     if (id >= find_joystick_devices()) return E_FAIL;
368 
369     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
370         WARN("force feedback not supported\n");
371         return S_FALSE;
372     }
373 
374     if ((dwDevType == 0) ||
375 	((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
376 	(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
377         /* check whether we have a joystick */
378         if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
379         {
380             WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
381             return S_FALSE;
382         }
383         fill_joystick_dideviceinstanceA( lpddi, version, id );
384         close(fd);
385         TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
386         return S_OK;
387     }
388 
389     return S_FALSE;
390 }
391 
392 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
393 {
394     int fd = -1;
395 
396     if (id >= find_joystick_devices()) return E_FAIL;
397 
398     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
399         WARN("force feedback not supported\n");
400         return S_FALSE;
401     }
402 
403     if ((dwDevType == 0) ||
404 	((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
405 	(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
406         /* check whether we have a joystick */
407         if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
408         {
409             WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id].device, strerror(errno));
410             return S_FALSE;
411         }
412         fill_joystick_dideviceinstanceW( lpddi, version, id );
413         close(fd);
414         TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id].device, joystick_devices[id].name);
415         return S_OK;
416     }
417 
418     return S_FALSE;
419 }
420 
421 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
422                             JoystickImpl **pdev, unsigned short index)
423 {
424     DWORD i;
425     JoystickImpl* newDevice;
426     HRESULT hr;
427     LPDIDATAFORMAT df = NULL;
428     int idx = 0;
429     DIDEVICEINSTANCEW ddi;
430 
431     TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
432 
433     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
434     if (newDevice == 0) {
435         WARN("out of memory\n");
436         *pdev = 0;
437         return DIERR_OUTOFMEMORY;
438     }
439 
440     newDevice->joydev = &joystick_devices[index];
441     newDevice->joyfd = -1;
442     newDevice->generic.guidInstance = DInput_Wine_Joystick_GUID;
443     newDevice->generic.guidInstance.Data3 = index;
444     newDevice->generic.guidProduct = DInput_Wine_Joystick_GUID;
445     newDevice->generic.joy_polldev = joy_polldev;
446     newDevice->generic.name        = newDevice->joydev->name;
447     newDevice->generic.device_axis_count = newDevice->joydev->axis_count;
448     newDevice->generic.devcaps.dwButtons = newDevice->joydev->button_count;
449 
450     if (newDevice->generic.devcaps.dwButtons > 128)
451     {
452         WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
453         newDevice->generic.devcaps.dwButtons = 128;
454     }
455 
456     newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
457     newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
458     newDevice->generic.base.ref = 1;
459     newDevice->generic.base.dinput = dinput;
460     newDevice->generic.base.guid = *rguid;
461     InitializeCriticalSection(&newDevice->generic.base.crit);
462     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
463 
464     /* setup_dinput_options may change these */
465     newDevice->generic.deadzone = 0;
466 
467     /* do any user specified configuration */
468     hr = setup_dinput_options(&newDevice->generic, newDevice->joydev->dev_axes_map);
469     if (hr != DI_OK)
470         goto FAILED1;
471 
472     /* Create copy of default data format */
473     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
474     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
475 
476     df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
477     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
478 
479     for (i = 0; i < newDevice->generic.device_axis_count; i++)
480     {
481         int wine_obj = newDevice->generic.axis_map[i];
482 
483         if (wine_obj < 0) continue;
484 
485         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
486         if (wine_obj < 8)
487             df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
488         else
489         {
490             df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
491             i++; /* POV takes 2 axes */
492         }
493     }
494     for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
495     {
496         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
497         df->rgodf[idx  ].pguid = &GUID_Button;
498         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
499     }
500     newDevice->generic.base.data_format.wine_df = df;
501 
502     /* initialize default properties */
503     for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) {
504         newDevice->generic.props[i].lDevMin = -32767;
505         newDevice->generic.props[i].lDevMax = +32767;
506         newDevice->generic.props[i].lMin = 0;
507         newDevice->generic.props[i].lMax = 0xffff;
508         newDevice->generic.props[i].lDeadZone = newDevice->generic.deadzone; /* % * 1000 */
509         newDevice->generic.props[i].lSaturation = 0;
510     }
511 
512     IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
513 
514     EnterCriticalSection(&dinput->crit);
515     list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
516     LeaveCriticalSection(&dinput->crit);
517 
518     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
519     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
520 
521     ddi.dwSize = sizeof(ddi);
522     fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
523     newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
524 
525     newDevice->generic.devcaps.dwFFSamplePeriod = 0;
526     newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
527     newDevice->generic.devcaps.dwFirmwareRevision = 0;
528     newDevice->generic.devcaps.dwHardwareRevision = 0;
529     newDevice->generic.devcaps.dwFFDriverVersion = 0;
530 
531     if (TRACE_ON(dinput)) {
532         _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
533        for (i = 0; i < (newDevice->generic.device_axis_count); i++)
534            TRACE("axis_map[%d] = %d\n", i, newDevice->generic.axis_map[i]);
535         _dump_DIDEVCAPS(&newDevice->generic.devcaps);
536     }
537 
538     *pdev = newDevice;
539 
540     return DI_OK;
541 
542 FAILED:
543     hr = DIERR_OUTOFMEMORY;
544 FAILED1:
545     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
546     HeapFree(GetProcessHeap(), 0, df);
547     release_DataFormat(&newDevice->generic.base.data_format);
548     HeapFree(GetProcessHeap(),0,newDevice->generic.axis_map);
549     HeapFree(GetProcessHeap(),0,newDevice);
550     *pdev = 0;
551 
552     return hr;
553 }
554 
555 /******************************************************************************
556   *     get_joystick_index : Get the joystick index from a given GUID
557   */
558 static unsigned short get_joystick_index(REFGUID guid)
559 {
560     GUID wine_joystick = DInput_Wine_Joystick_GUID;
561     GUID dev_guid = *guid;
562 
563     wine_joystick.Data3 = 0;
564     dev_guid.Data3 = 0;
565 
566     /* for the standard joystick GUID use index 0 */
567     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
568 
569     /* for the wine joystick GUIDs use the index stored in Data3 */
570     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
571 
572     return MAX_JOYSTICKS;
573 }
574 
575 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
576 {
577     unsigned short index;
578 
579     TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
580     find_joystick_devices();
581     *pdev = NULL;
582 
583     if ((index = get_joystick_index(rguid)) < MAX_JOYSTICKS &&
584         joystick_devices_count && index < joystick_devices_count)
585     {
586         JoystickImpl *This;
587         HRESULT hr;
588 
589         if (riid == NULL)
590             ;/* nothing */
591         else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
592                  IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
593                  IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
594                  IsEqualGUID(&IID_IDirectInputDevice8A, riid))
595         {
596             unicode = 0;
597         }
598         else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
599                  IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
600                  IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
601                  IsEqualGUID(&IID_IDirectInputDevice8W, riid))
602         {
603             unicode = 1;
604         }
605         else
606         {
607             WARN("no interface\n");
608             return DIERR_NOINTERFACE;
609         }
610 
611         hr = alloc_device(rguid, dinput, &This, index);
612         if (!This) return hr;
613 
614         if (unicode)
615             *pdev = &This->generic.base.IDirectInputDevice8W_iface;
616         else
617             *pdev = &This->generic.base.IDirectInputDevice8A_iface;
618 
619         return hr;
620     }
621 
622     return DIERR_DEVICENOTREG;
623 }
624 
625 #undef MAX_JOYSTICKS
626 
627 const struct dinput_device joystick_linux_device = {
628   "Wine Linux joystick driver",
629   joydev_enum_deviceA,
630   joydev_enum_deviceW,
631   joydev_create_device
632 };
633 
634 /******************************************************************************
635   *     Acquire : gets exclusive control of the joystick
636   */
637 static HRESULT WINAPI JoystickLinuxWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
638 {
639     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
640     HRESULT res;
641 
642     TRACE("(%p)\n",This);
643 
644     res = IDirectInputDevice2WImpl_Acquire(iface);
645     if (res != DI_OK)
646         return res;
647 
648     /* open the joystick device */
649     if (This->joyfd==-1) {
650         TRACE("opening joystick device %s\n", This->joydev->device);
651 
652         This->joyfd = open(This->joydev->device, O_RDONLY);
653         if (This->joyfd==-1) {
654             ERR("open(%s) failed: %s\n", This->joydev->device, strerror(errno));
655             IDirectInputDevice2WImpl_Unacquire(iface);
656             return DIERR_NOTFOUND;
657         }
658     }
659 
660     return DI_OK;
661 }
662 
663 static HRESULT WINAPI JoystickLinuxAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
664 {
665     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
666     return JoystickLinuxWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
667 }
668 
669 /******************************************************************************
670   *     GetProperty : get input device properties
671   */
672 static HRESULT WINAPI JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
673 {
674     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
675 
676     TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
677     _dump_DIPROPHEADER(pdiph);
678 
679     if (!IS_DIPROP(rguid)) return DI_OK;
680 
681     switch (LOWORD(rguid)) {
682 
683         case (DWORD_PTR) DIPROP_VIDPID:
684         {
685             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
686 
687             if (!This->joydev->product_id || !This->joydev->vendor_id)
688                 return DIERR_UNSUPPORTED;
689             pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
690             TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
691             break;
692         }
693         case (DWORD_PTR) DIPROP_JOYSTICKID:
694         {
695             LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
696 
697             pd->dwData = get_joystick_index(&This->generic.base.guid);
698             TRACE("DIPROP_JOYSTICKID(%d)\n", pd->dwData);
699             break;
700         }
701 
702     default:
703         return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
704     }
705 
706     return DI_OK;
707 }
708 
709 static HRESULT WINAPI JoystickLinuxAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
710 {
711     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
712     return JoystickLinuxWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
713 }
714 
715 /******************************************************************************
716   *     GetDeviceInfo : get information about a device's identity
717   */
718 static HRESULT WINAPI JoystickLinuxAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, LPDIDEVICEINSTANCEA ddi)
719 {
720     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
721 
722     TRACE("(%p) %p\n", This, ddi);
723 
724     if (ddi == NULL) return E_POINTER;
725     if ((ddi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
726         (ddi->dwSize != sizeof(DIDEVICEINSTANCEA)))
727         return DIERR_INVALIDPARAM;
728 
729     fill_joystick_dideviceinstanceA( ddi, This->generic.base.dinput->dwVersion,
730                                      get_joystick_index(&This->generic.base.guid) );
731     return DI_OK;
732 }
733 
734 static HRESULT WINAPI JoystickLinuxWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW ddi)
735 {
736     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
737 
738     TRACE("(%p) %p\n", This, ddi);
739 
740     if (ddi == NULL) return E_POINTER;
741     if ((ddi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
742         (ddi->dwSize != sizeof(DIDEVICEINSTANCEW)))
743         return DIERR_INVALIDPARAM;
744 
745     fill_joystick_dideviceinstanceW( ddi, This->generic.base.dinput->dwVersion,
746                                      get_joystick_index(&This->generic.base.guid) );
747     return DI_OK;
748 }
749 
750 /******************************************************************************
751   *     Unacquire : frees the joystick
752   */
753 static HRESULT WINAPI JoystickLinuxWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
754 {
755     JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
756     HRESULT res;
757 
758     TRACE("(%p)\n",This);
759 
760     res = IDirectInputDevice2WImpl_Unacquire(iface);
761 
762     if (res != DI_OK)
763         return res;
764 
765     if (This->joyfd!=-1) {
766         TRACE("closing joystick device\n");
767         close(This->joyfd);
768         This->joyfd = -1;
769         return DI_OK;
770     }
771 
772     return DI_NOEFFECT;
773 }
774 
775 static HRESULT WINAPI JoystickLinuxAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
776 {
777     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
778     return JoystickLinuxWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
779 }
780 
781 static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
782 {
783     struct pollfd plfd;
784     struct js_event jse;
785     JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
786 
787     TRACE("(%p)\n", This);
788 
789     if (This->joyfd==-1) {
790         WARN("no device\n");
791         return;
792     }
793     while (1)
794     {
795         LONG value;
796         int inst_id = -1;
797 
798 	plfd.fd = This->joyfd;
799 	plfd.events = POLLIN;
800 	if (poll(&plfd,1,0) != 1)
801 	    return;
802 	/* we have one event, so we can read */
803 	if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
804 	    return;
805 	}
806         TRACE("js_event: type 0x%x, number %d, value %d\n",
807               jse.type,jse.number,jse.value);
808         if (jse.type & JS_EVENT_BUTTON)
809         {
810             if (jse.number >= This->generic.devcaps.dwButtons) return;
811 
812             inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON;
813             This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00;
814         }
815         else if (jse.type & JS_EVENT_AXIS)
816         {
817             int number = This->generic.axis_map[jse.number];	/* wine format object index */
818 
819             if (number < 0) return;
820             inst_id = number < 8 ?  DIDFT_MAKEINSTANCE(number) | DIDFT_ABSAXIS :
821                                     DIDFT_MAKEINSTANCE(number - 8) | DIDFT_POV;
822             value = joystick_map_axis(&This->generic.props[id_to_object(This->generic.base.data_format.wine_df, inst_id)], jse.value);
823 
824             TRACE("changing axis %d => %d\n", jse.number, number);
825             switch (number)
826             {
827                 case 0: This->generic.js.lX  = value; break;
828                 case 1: This->generic.js.lY  = value; break;
829                 case 2: This->generic.js.lZ  = value; break;
830                 case 3: This->generic.js.lRx = value; break;
831                 case 4: This->generic.js.lRy = value; break;
832                 case 5: This->generic.js.lRz = value; break;
833                 case 6: This->generic.js.rglSlider[0] = value; break;
834                 case 7: This->generic.js.rglSlider[1] = value; break;
835                 case 8: case 9: case 10: case 11:
836                 {
837                     int idx = number - 8;
838 
839                     if (jse.number % 2)
840                         This->povs[idx].y = jse.value;
841                     else
842                         This->povs[idx].x = jse.value;
843 
844                     This->generic.js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
845                     break;
846                 }
847                 default:
848                     WARN("axis %d not supported\n", number);
849             }
850         }
851         if (inst_id >= 0)
852             queue_event(iface, inst_id, value, GetCurrentTime(), This->generic.base.dinput->evsequence++);
853     }
854 }
855 
856 static const IDirectInputDevice8AVtbl JoystickAvt =
857 {
858 	IDirectInputDevice2AImpl_QueryInterface,
859 	IDirectInputDevice2AImpl_AddRef,
860         IDirectInputDevice2AImpl_Release,
861 	JoystickAGenericImpl_GetCapabilities,
862         IDirectInputDevice2AImpl_EnumObjects,
863 	JoystickLinuxAImpl_GetProperty,
864 	JoystickAGenericImpl_SetProperty,
865 	JoystickLinuxAImpl_Acquire,
866 	JoystickLinuxAImpl_Unacquire,
867 	JoystickAGenericImpl_GetDeviceState,
868 	IDirectInputDevice2AImpl_GetDeviceData,
869 	IDirectInputDevice2AImpl_SetDataFormat,
870 	IDirectInputDevice2AImpl_SetEventNotification,
871 	IDirectInputDevice2AImpl_SetCooperativeLevel,
872 	JoystickAGenericImpl_GetObjectInfo,
873 	JoystickLinuxAImpl_GetDeviceInfo,
874 	IDirectInputDevice2AImpl_RunControlPanel,
875 	IDirectInputDevice2AImpl_Initialize,
876 	IDirectInputDevice2AImpl_CreateEffect,
877 	IDirectInputDevice2AImpl_EnumEffects,
878 	IDirectInputDevice2AImpl_GetEffectInfo,
879 	IDirectInputDevice2AImpl_GetForceFeedbackState,
880 	IDirectInputDevice2AImpl_SendForceFeedbackCommand,
881 	IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
882 	IDirectInputDevice2AImpl_Escape,
883 	JoystickAGenericImpl_Poll,
884 	IDirectInputDevice2AImpl_SendDeviceData,
885 	IDirectInputDevice7AImpl_EnumEffectsInFile,
886 	IDirectInputDevice7AImpl_WriteEffectToFile,
887 	JoystickAGenericImpl_BuildActionMap,
888 	JoystickAGenericImpl_SetActionMap,
889 	IDirectInputDevice8AImpl_GetImageInfo
890 };
891 
892 static const IDirectInputDevice8WVtbl JoystickWvt =
893 {
894     IDirectInputDevice2WImpl_QueryInterface,
895     IDirectInputDevice2WImpl_AddRef,
896     IDirectInputDevice2WImpl_Release,
897     JoystickWGenericImpl_GetCapabilities,
898     IDirectInputDevice2WImpl_EnumObjects,
899     JoystickLinuxWImpl_GetProperty,
900     JoystickWGenericImpl_SetProperty,
901     JoystickLinuxWImpl_Acquire,
902     JoystickLinuxWImpl_Unacquire,
903     JoystickWGenericImpl_GetDeviceState,
904     IDirectInputDevice2WImpl_GetDeviceData,
905     IDirectInputDevice2WImpl_SetDataFormat,
906     IDirectInputDevice2WImpl_SetEventNotification,
907     IDirectInputDevice2WImpl_SetCooperativeLevel,
908     JoystickWGenericImpl_GetObjectInfo,
909     JoystickLinuxWImpl_GetDeviceInfo,
910     IDirectInputDevice2WImpl_RunControlPanel,
911     IDirectInputDevice2WImpl_Initialize,
912     IDirectInputDevice2WImpl_CreateEffect,
913     IDirectInputDevice2WImpl_EnumEffects,
914     IDirectInputDevice2WImpl_GetEffectInfo,
915     IDirectInputDevice2WImpl_GetForceFeedbackState,
916     IDirectInputDevice2WImpl_SendForceFeedbackCommand,
917     IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
918     IDirectInputDevice2WImpl_Escape,
919     JoystickWGenericImpl_Poll,
920     IDirectInputDevice2WImpl_SendDeviceData,
921     IDirectInputDevice7WImpl_EnumEffectsInFile,
922     IDirectInputDevice7WImpl_WriteEffectToFile,
923     JoystickWGenericImpl_BuildActionMap,
924     JoystickWGenericImpl_SetActionMap,
925     IDirectInputDevice8WImpl_GetImageInfo
926 };
927 
928 #else  /* HAVE_LINUX_22_JOYSTICK_API */
929 
930 const struct dinput_device joystick_linux_device = {
931   "Wine Linux joystick driver",
932   NULL,
933   NULL,
934   NULL
935 };
936 
937 #endif  /* HAVE_LINUX_22_JOYSTICK_API */
938