joystick_linuxinput.c 47.7 KB
Newer Older
1 2 3 4
/*		DirectInput Joystick device
 *
 * Copyright 1998,2000 Marcus Meissner
 * Copyright 1998,1999 Lionel Ulmer
5
 * Copyright 2000-2001 TransGaming Technologies Inc.
6
 * Copyright 2005 Daniel Remenak
7
 *
8 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 29 30
#include <stdio.h>
#include <string.h>
#include <time.h>
31 32 33 34 35 36
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
37
#include <fcntl.h>
38 39 40
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
41 42 43 44 45 46
#include <errno.h>
#ifdef HAVE_SYS_ERRNO_H
# include <sys/errno.h>
#endif
#ifdef HAVE_LINUX_INPUT_H
# include <linux/input.h>
47
# undef SW_MAX
48 49 50
# if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
#  define HAVE_CORRECT_LINUXINPUT_H
# endif
51
#endif
52 53 54
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#endif
55

56
#include "wine/debug.h"
57
#include "wine/unicode.h"
58
#include "wine/list.h"
59
#include "windef.h"
60 61
#include "winbase.h"
#include "winerror.h"
62
#include "winreg.h"
63 64 65 66
#include "dinput.h"

#include "dinput_private.h"
#include "device_private.h"
67
#include "joystick_private.h"
68

69
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
70

71 72 73 74
#ifdef HAVE_CORRECT_LINUXINPUT_H

#define EVDEVPREFIX	"/dev/input/event"

75
/* Wine joystick driver object instances */
76 77 78
#define WINE_JOYSTICK_MAX_AXES    8
#define WINE_JOYSTICK_MAX_POVS    4
#define WINE_JOYSTICK_MAX_BUTTONS 128
79

80 81 82 83 84 85 86 87
struct wine_input_absinfo {
    LONG value;
    LONG minimum;
    LONG maximum;
    LONG fuzz;
    LONG flat;
};

88
/* implemented in effect_linuxinput.c */
89
HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff);
90 91 92
HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);

93
typedef struct JoystickImpl JoystickImpl;
94 95
static const IDirectInputDevice8AVtbl JoystickAvt;
static const IDirectInputDevice8WVtbl JoystickWvt;
96 97 98 99 100 101 102 103 104 105 106 107 108 109

struct JoyDev {
	char *device;
	char *name;
	GUID guid;

	int has_ff;
        int num_effects;

	/* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
	BYTE				evbits[(EV_MAX+7)/8];
	BYTE				absbits[(ABS_MAX+7)/8];
	BYTE				keybits[(KEY_MAX+7)/8];
	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 123 124

	/* joystick private */
	int				joyfd;

125
	int                             dev_axes_to_di[ABS_MAX];
126
        POINTL                          povs[4];
127

128 129 130
	/* LUT for KEY_ to offset in rgbButtons */
	BYTE				buttons[KEY_MAX];

131
	/* Force feedback variables */
132
        struct list                     ff_effects;
133
	int				ff_state;
134
	int				ff_autocenter;
135
	int				ff_gain;
136 137
};

138 139
static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
{
140 141
    return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
           JoystickGenericImpl, base), JoystickImpl, generic);
142 143 144
}
static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
{
145 146
    return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
           JoystickGenericImpl, base), JoystickImpl, generic);
147
}
148 149
static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(JoystickImpl *This)
{
150
    return &This->generic.base.IDirectInputDevice8A_iface;
151 152 153
}
static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
{
154
    return &This->generic.base.IDirectInputDevice8W_iface;
155
}
156

157 158
static void fake_current_js_state(JoystickImpl *ji);
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 164 165 166 167 168
  0x9e573eda,
  0x7734,
  0x11d2,
  {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};

169
#define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
170

171 172 173 174 175 176
#define MAX_JOYDEV 64

static int have_joydevs = -1;
static struct JoyDev *joydevs = NULL;

static void find_joydevs(void)
177
{
178
    int i;
179

180 181 182
    if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1)
        /* Someone beat us to it */
        return;
183

184 185 186 187 188 189 190
    for (i = 0; i < MAX_JOYDEV; i++)
    {
        char buf[MAX_PATH];
        struct JoyDev joydev = {0};
        int fd;
        int no_ff_check = 0;
        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 197 198 199 200
        if ((fd = open(buf, O_RDWR)) == -1)
        {
            fd = open(buf, O_RDONLY);
            no_ff_check = 1;
        }
201

202 203 204 205 206
        if (fd == -1)
        {
            WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno));
            continue;
        }
207

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
        if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1)
        {
            WARN("ioct(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno));
            close(fd);
            continue;
        }
        if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1)
        {
            WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
            close(fd);
            continue;
        }
        if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1)
        {
            WARN("ioct(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno));
            close(fd);
            continue;
        }

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
        /* A true joystick has at least axis X and Y, and at least 1
         * button. copied from linux/drivers/input/joydev.c */
        if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) ||
            !(test_bit(joydev.keybits, BTN_TRIGGER) ||
              test_bit(joydev.keybits, BTN_A) ||
              test_bit(joydev.keybits, BTN_1)))
        {
            close(fd);
            continue;
        }

        if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
        {
            close(fd);
            continue;
242 243
        }
        strcpy(joydev.device, buf);
244

245 246 247
        buf[MAX_PATH - 1] = 0;
        if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 &&
            (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
248
            strcpy(joydev.name, buf);
249
        else
250
            joydev.name = joydev.device;
251 252 253 254 255 256 257 258 259 260

	joydev.guid = DInput_Wine_Joystick_Base_GUID;
	joydev.guid.Data3 += have_joydevs;

        TRACE("Found a joystick on %s: %s (%s)\n", 
            joydev.device, joydev.name, 
            debugstr_guid(&joydev.guid)
            );

#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
261 262 263 264 265 266
        if (!no_ff_check &&
            test_bit(joydev.evbits, EV_FF) &&
            ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 &&
            ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 &&
            joydev.num_effects > 0)
        {
267 268 269 270 271
	    TRACE(" ... with force feedback\n");
	    joydev.has_ff = 1;
        }
#endif

272 273 274 275 276
        for (j = 0; j < ABS_MAX;j ++)
        {
            if (!test_bit(joydev.absbits, j)) continue;
            if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1)
            {
277
	      TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
278
		  j,
279 280 281 282 283
		  joydev.axes[j].value,
		  joydev.axes[j].minimum,
		  joydev.axes[j].maximum,
		  joydev.axes[j].fuzz,
		  joydev.axes[j].flat
284 285 286 287
		  );
	    }
	}

288 289 290 291 292 293 294 295
        if (ioctl(fd, EVIOCGID, &device_id) == -1)
            WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
        else
        {
            joydev.vendor_id = device_id.vendor;
            joydev.product_id = device_id.product;
        }

296 297 298 299 300 301 302 303 304 305 306 307
        if (!have_joydevs)
            new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
        else
            new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev));

        if (!new_joydevs)
        {
            close(fd);
            continue;
        }
        joydevs = new_joydevs;
        memcpy(joydevs + have_joydevs, &joydev, sizeof(joydev));
308 309
        have_joydevs++;

310
        close(fd);
311
    }
312 313
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{
    DWORD dwSize = lpddi->dwSize;

    TRACE("%d %p\n", dwSize, lpddi);
    memset(lpddi, 0, dwSize);

    lpddi->dwSize       = dwSize;
    lpddi->guidInstance = joydevs[id].guid;
    lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
    lpddi->guidFFDriver = GUID_NULL;

    if (version >= 0x0800)
        lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
    else
        lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);

    strcpy(lpddi->tszInstanceName, joydevs[id].name);
332
    strcpy(lpddi->tszProductName, joydevs[id].name);
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
}

static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
{
    DWORD dwSize = lpddi->dwSize;

    TRACE("%d %p\n", dwSize, lpddi);
    memset(lpddi, 0, dwSize);

    lpddi->dwSize       = dwSize;
    lpddi->guidInstance = joydevs[id].guid;
    lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
    lpddi->guidFFDriver = GUID_NULL;

    if (version >= 0x0800)
        lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
    else
        lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);

    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 361 362
  if (id >= have_joydevs) {
    return FALSE;
  }
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 371
  if (dwFlags & DIEDFL_FORCEFEEDBACK)
    return FALSE;
372
#endif
373

374
  if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
375
    fill_joystick_dideviceinstanceA(lpddi, version, id);
376 377 378
    return TRUE;
  }
  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 396
  if (dwFlags & DIEDFL_FORCEFEEDBACK)
    return FALSE;
397
#endif
398

399
  if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
400
    fill_joystick_dideviceinstanceW(lpddi, version, id);
401 402 403
    return TRUE;
  }
  return FALSE;
404 405
}

406
static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsigned short index)
407
{
408 409 410
    JoystickImpl* newDevice;
    LPDIDATAFORMAT df = NULL;
    int i, idx = 0;
411
    int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2];
412

413 414
    newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
    if (!newDevice) return NULL;
415

416 417
    newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
    newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
418 419 420 421
    newDevice->generic.base.ref    = 1;
    newDevice->generic.base.guid   = *rguid;
    newDevice->generic.base.dinput = dinput;
    newDevice->generic.joy_polldev = joy_polldev;
422 423
    newDevice->joyfd       = -1;
    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 432
       enabled. */
    newDevice->ff_autocenter = 1;
433
    newDevice->ff_gain = 0xFFFF;
434 435
    InitializeCriticalSection(&newDevice->generic.base.crit);
    newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
436

437 438 439 440 441 442 443 444 445
    /* Count number of available axes - supported Axis & POVs */
    for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++)
    {
        if (test_bit(newDevice->joydev->absbits, i))
        {
            newDevice->generic.device_axis_count++;
            newDevice->dev_axes_to_di[i] = idx;
            newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum;
            newDevice->generic.props[idx].lDevMax = newDevice->joydev->axes[i].maximum;
446
            default_axis_map[idx] = i;
447 448 449 450 451
            idx++;
        }
        else
            newDevice->dev_axes_to_di[i] = -1;
    }
452

453
    for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++)
454
    {
455 456 457 458
        if (test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) &&
            test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2))
        {
            newDevice->generic.device_axis_count += 2;
459 460
            newDevice->generic.props[idx  ].lDevMin = newDevice->joydev->axes[ABS_HAT0X + i * 2].minimum;
            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 463
            newDevice->generic.props[idx+1].lDevMin = newDevice->joydev->axes[ABS_HAT0Y + i * 2].minimum;
            newDevice->generic.props[idx+1].lDevMax = newDevice->joydev->axes[ABS_HAT0Y + i * 2].maximum;
464 465 466 467
            newDevice->dev_axes_to_di[ABS_HAT0Y + i * 2] = idx + 1;

            default_axis_map[idx] = default_axis_map[idx + 1] = WINE_JOYSTICK_MAX_AXES + i;
            idx += 2;
468 469 470
        }
        else
            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 477 478 479 480
    /* Create copy of default data format */
    if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
    memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
    if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;

481 482 483 484 485

    /* Construct internal data format */

    /* Supported Axis & POVs */
    for (i = 0, idx = 0; i < newDevice->generic.device_axis_count; i++)
486
    {
487 488 489 490 491 492 493 494 495 496 497
        int wine_obj = newDevice->generic.axis_map[i];

        if (wine_obj < 0) continue;

        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
        if (wine_obj < 8)
            df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
        else
        {
            df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV;
            i++; /* POV takes 2 axes */
498
        }
499

500 501
        newDevice->generic.props[idx].lMin        = 0;
        newDevice->generic.props[idx].lMax        = 0xffff;
502
        newDevice->generic.props[idx].lSaturation = 0;
503
        newDevice->generic.props[idx].lDeadZone   = newDevice->generic.deadzone;
504

505 506 507 508
        /* Linux supports force-feedback on X & Y axes only */
        if (newDevice->joydev->has_ff && (i == 0 || i == 1))
            df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;

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 516
    {
        if (!test_bit(newDevice->joydev->keybits, i)) continue;

517 518
        memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->generic.devcaps.dwButtons + 12], df->dwObjSize);
        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 526
    fake_current_js_state(newDevice);

527 528 529 530 531 532 533 534 535 536 537
    /* Fill the caps */
    newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
    newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
    if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
        newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
    else
        newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);

    if (newDevice->joydev->has_ff)
        newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;

538
    IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
539 540 541 542 543

    EnterCriticalSection(&dinput->crit);
    list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
    LeaveCriticalSection(&dinput->crit);

544
    return newDevice;
545

546 547 548
failed:
    if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
    HeapFree(GetProcessHeap(), 0, df);
549
    HeapFree(GetProcessHeap(), 0, newDevice->generic.axis_map);
550 551
    HeapFree(GetProcessHeap(), 0, newDevice);
    return NULL;
552 553
}

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
/******************************************************************************
  *     get_joystick_index : Get the joystick index from a given GUID
  */
static unsigned short get_joystick_index(REFGUID guid)
{
    GUID wine_joystick = DInput_Wine_Joystick_Base_GUID;
    GUID dev_guid = *guid;

    wine_joystick.Data3 = 0;
    dev_guid.Data3 = 0;

    /* for the standard joystick GUID use index 0 */
    if(IsEqualGUID(&GUID_Joystick,guid)) return 0;

    /* for the wine joystick GUIDs use the index stored in Data3 */
    if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3;

    return MAX_JOYDEV;
}

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 583 584
    if ((index = get_joystick_index(rguid)) < MAX_JOYDEV &&
        have_joydevs && index < have_joydevs)
    {
585 586 587 588 589 590 591 592
        JoystickImpl *This;

        if (riid == NULL)
            ;/* nothing */
        else if (IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
593
        {
594 595 596 597 598 599 600 601 602 603 604 605 606
            unicode = 0;
        }
        else if (IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
                 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
        {
            unicode = 1;
        }
        else
        {
            WARN("no interface\n");
            return DIERR_NOINTERFACE;
607
        }
608

609 610
        This = alloc_device(rguid, dinput, index);
        TRACE("Created a Joystick device (%p)\n", This);
611

612
        if (!This) return DIERR_OUTOFMEMORY;
613

614 615 616 617
        if (unicode)
            *pdev = &This->generic.base.IDirectInputDevice8W_iface;
        else
            *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 629
  joydev_enum_deviceA,
  joydev_enum_deviceW,
630
  joydev_create_device
631 632 633 634 635
};

/******************************************************************************
  *     Acquire : gets exclusive control of the joystick
  */
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 646 647 648 649 650 651 652 653 654
    {
        WARN("Failed to acquire: %x\n", res);
        return res;
    }

    if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1)
    {
        if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1)
        {
            /* Couldn't open the device at all */
            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 659 660 661 662
        else
        {
            /* Couldn't open in r/w but opened in read-only. */
            WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n", This->joydev->device);
        }
663
    }
664 665
    else
    {
666 667 668 669 670 671 672
        struct input_event event;

        event.type = EV_FF;
        event.code = FF_GAIN;
        event.value = This->ff_gain;
        if (write(This->joyfd, &event, sizeof(event)) == -1)
            ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
673 674 675 676 677 678 679 680 681
        if (!This->ff_autocenter)
        {
            /* Disable autocenter. */
            event.code = FF_AUTOCENTER;
            event.value = 0;
            if (write(This->joyfd, &event, sizeof(event)) == -1)
                ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
        }
    }
682

683
    return DI_OK;
684 685
}

686 687 688 689 690 691
static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
}

692 693 694
/******************************************************************************
  *     Unacquire : frees the joystick
  */
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 707 708 709 710 711 712 713 714 715

      /* For each known effect:
       * - stop it
       * - unload it
       * But, unlike DISFFC_RESET, do not release the effect.
       */
      LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) {
          IDirectInputEffect_Stop(itr->ref);
          IDirectInputEffect_Unload(itr->ref);
      }

716 717 718
      /* Enable autocenter. */
      event.type = EV_FF;
      event.code = FF_AUTOCENTER;
719 720
      /* TODO: Read autocenter strength before disabling it, and use it here
       * instead of 0xFFFF (maximum strength).
721 722 723 724 725
       */
      event.value = 0xFFFF;
      if (write(This->joyfd, &event, sizeof(event)) == -1)
        ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno));

726 727
      close(This->joyfd);
      This->joyfd = -1;
728
    }
729
    return res;
730 731
}

732 733 734 735 736 737
static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
}

738 739 740 741
/* 
 * set the current state of the js device as it would be with the middle
 * values on the axes
 */
742
#define CENTER_AXIS(a) \
743 744
    (ji->dev_axes_to_di[a] == -1 ? 0 : joystick_map_axis( &ji->generic.props[ji->dev_axes_to_di[a]], \
                                                          ji->joydev->axes[a].value ))
745 746
static void fake_current_js_state(JoystickImpl *ji)
{
747 748 749
    int i;

    /* center the axes */
750 751 752 753 754 755 756 757
    ji->generic.js.lX           = CENTER_AXIS(ABS_X);
    ji->generic.js.lY           = CENTER_AXIS(ABS_Y);
    ji->generic.js.lZ           = CENTER_AXIS(ABS_Z);
    ji->generic.js.lRx          = CENTER_AXIS(ABS_RX);
    ji->generic.js.lRy          = CENTER_AXIS(ABS_RY);
    ji->generic.js.lRz          = CENTER_AXIS(ABS_RZ);
    ji->generic.js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE);
    ji->generic.js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER);
758 759 760

    /* POV center is -1 */
    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 773 774

    if (This->joyfd==-1)
	return;

775 776 777 778 779
    while (1)
    {
        LONG value = 0;
        int inst_id = -1;

780 781
	plfd.fd = This->joyfd;
	plfd.events = POLLIN;
782

783
	if (poll(&plfd,1,0) != 1)
784 785 786 787 788 789 790 791 792
	    return;

	/* we have one event, so we can read */
	if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
	    return;

	TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
	switch (ie.type) {
	case EV_KEY:	/* button */
793
        {
794
            int btn = This->buttons[ie.code];
795

796
            TRACE("(%p) %d -> %d\n", This, ie.code, btn);
797 798 799 800
            if (btn & 0x80)
            {
                btn &= 0x7F;
                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 810 811 812 813

            /* User axis remapping */
            if (axis < 0) break;
            axis = This->generic.axis_map[axis];
            if (axis < 0) break;

814 815
            inst_id = axis < 8 ?  DIDFT_MAKEINSTANCE(axis) | DIDFT_ABSAXIS :
                                  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 819 820 821 822 823 824 825 826 827
	    switch (axis) {
            case 0: This->generic.js.lX  = value; break;
            case 1: This->generic.js.lY  = value; break;
            case 2: This->generic.js.lZ  = value; break;
            case 3: This->generic.js.lRx = value; break;
            case 4: This->generic.js.lRy = value; break;
            case 5: This->generic.js.lRz = value; break;
            case 6: This->generic.js.rglSlider[0] = value; break;
            case 7: This->generic.js.rglSlider[1] = value; break;
            case 8: case 9: case 10: case 11:
828
            {
829
                int idx = axis - 8;
830 831 832 833 834 835

                if (ie.code % 2)
                    This->povs[idx].y = ie.value;
                else
                    This->povs[idx].x = ie.value;

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 846 847
	case EV_FF_STATUS:
	    This->ff_state = ie.value;
	    break;
848
#endif
849
#ifdef EV_SYN
850 851 852
	case EV_SYN:
	    /* there is nothing to do */
	    break;
853 854 855 856 857
#endif
#ifdef EV_MSC
        case EV_MSC:
            /* Ignore */
            break;
858
#endif
859 860 861 862
	default:
	    FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
	    break;
	}
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 871
    }
}

/******************************************************************************
  *     SetProperty : change input device properties
  */
872
static HRESULT WINAPI JoystickWImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER ph)
873
{
874
  JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
875

876 877 878 879 880 881
  if (!ph) {
    WARN("invalid argument\n");
    return DIERR_INVALIDPARAM;
  }

  TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
882 883
  TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n",
        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 889 890 891
      LPCDIPROPDWORD	pd = (LPCDIPROPDWORD)ph;
      FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
      break;
    }
892
    case (DWORD_PTR)DIPROP_AUTOCENTER: {
893 894
      LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;

895 896 897
      TRACE("autocenter(%d)\n", pd->dwData);
      This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON;

898 899
      break;
    }
900 901 902 903 904
    case (DWORD_PTR)DIPROP_FFGAIN: {
      LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;

      TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
      This->ff_gain = MulDiv(pd->dwData, 0xFFFF, 10000);
905
      if (This->generic.base.acquired) {
906 907 908 909 910 911 912 913 914 915 916
        /* Update immediately. */
        struct input_event event;

        event.type = EV_FF;
        event.code = FF_GAIN;
        event.value = This->ff_gain;
        if (write(This->joyfd, &event, sizeof(event)) == -1)
          ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
      }
      break;
    }
917
    default:
918
      return JoystickWGenericImpl_SetProperty(iface, rguid, ph);
919 920
    }
  }
921
  return DI_OK;
922 923
}

924 925 926 927 928 929
static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER ph)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, ph);
}

930 931 932
/******************************************************************************
  *     GetProperty : get input device properties
  */
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 944 945 946 947 948 949 950
    case (DWORD_PTR) DIPROP_AUTOCENTER:
    {
        LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;

        pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF;
        TRACE("autocenter(%d)\n", pd->dwData);
        break;
    }
951 952 953 954 955 956 957 958
    case (DWORD_PTR) DIPROP_FFGAIN:
    {
        LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;

        pd->dwData = MulDiv(This->ff_gain, 10000, 0xFFFF);
        TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
        break;
    }
959

960 961 962 963 964 965 966 967 968 969 970
    case (DWORD_PTR) DIPROP_VIDPID:
    {
        LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;

        if (!This->joydev->product_id || !This->joydev->vendor_id)
            return DIERR_UNSUPPORTED;
        pd->dwData = MAKELONG(This->joydev->vendor_id, This->joydev->product_id);
        TRACE("DIPROP_VIDPID(%08x)\n", pd->dwData);
        break;
    }

971
    default:
972
        return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
973
    }
974

975
    return DI_OK;
976 977
}

978 979 980 981 982 983
static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
}

984 985 986
/****************************************************************************** 
  *	CreateEffect - Create a new FF effect with the specified params
  */
987 988 989
static HRESULT WINAPI JoystickWImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid,
                                                 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
                                                 LPUNKNOWN pUnkOuter)
990 991
{
#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
992
    effect_list_item* new_effect = NULL;
993 994 995
    HRESULT retval = DI_OK;
#endif

996
    JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
997 998 999 1000 1001
    TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);

#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
    TRACE("not available (compiled w/o ff support)\n");
    *ppdef = NULL;
1002
    return DI_OK;
1003 1004
#else

1005 1006
    if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
        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 1012 1013
    {
        HeapFree(GetProcessHeap(), 0, new_effect);
        return retval;
    }
1014

1015
    if (lpeff != NULL)
1016 1017
    {
        retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0);
1018

1019 1020 1021 1022 1023 1024 1025 1026 1027
        if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
        {
            HeapFree(GetProcessHeap(), 0, new_effect);
            return retval;
        }
    }

    list_add_tail(&This->ff_effects, &new_effect->entry);
    *ppdef = new_effect->ref;
1028 1029 1030 1031 1032 1033 1034

    if (pUnkOuter != NULL)
	FIXME("Interface aggregation not implemented.\n");

    return DI_OK;

#endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
1035 1036 1037 1038 1039 1040 1041 1042 1043
}

static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid,
                                                 LPCDIEFFECT lpeff, LPDIRECTINPUTEFFECT *ppdef,
                                                 LPUNKNOWN pUnkOuter)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter);
}
1044 1045 1046 1047 1048 1049 1050 1051 1052

/*******************************************************************************
 *	EnumEffects - Enumerate available FF effects
 */
static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
						LPDIENUMEFFECTSCALLBACKA lpCallback,
						LPVOID pvRef,
						DWORD dwEffType)
{
1053
#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1054 1055
    DIEFFECTINFOA dei; /* feif */
    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 1061 1062

    dei.dwSize = sizeof(DIEFFECTINFOA);          

    if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1063
	&& test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1064
	IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1065 1066 1067 1068
	(*lpCallback)(&dei, pvRef);
    }

    if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1069 1070
	&& test_bit(This->joydev->ffbits, FF_PERIODIC)) {
	if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1071
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1072 1073
	    (*lpCallback)(&dei, pvRef);
	}
1074
	if (test_bit(This->joydev->ffbits, FF_SINE)) {
1075
            IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1076 1077
	    (*lpCallback)(&dei, pvRef);
	}
1078
	if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1079
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1080 1081
	    (*lpCallback)(&dei, pvRef);
	}
1082
	if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1083
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1084 1085
	    (*lpCallback)(&dei, pvRef);
	}
1086
	if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1087
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1088 1089 1090 1091 1092
	    (*lpCallback)(&dei, pvRef);
	}
    } 

    if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1093
	&& test_bit(This->joydev->ffbits, FF_RAMP)) {
1094
        IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1095 1096 1097 1098
        (*lpCallback)(&dei, pvRef);
    }

    if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1099
	if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1100
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1101 1102
	    (*lpCallback)(&dei, pvRef);
	}
1103
	if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1104
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1105 1106
	    (*lpCallback)(&dei, pvRef);
	}
1107
	if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1108
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1109 1110
	    (*lpCallback)(&dei, pvRef);
	}
1111
	if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1112
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
	    (*lpCallback)(&dei, pvRef);
	}
    }

#endif

    return DI_OK;
}

static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
                                                LPDIENUMEFFECTSCALLBACKW lpCallback,
                                                LPVOID pvRef,
                                                DWORD dwEffType)
{
1127
#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
1128 1129 1130 1131
    /* seems silly to duplicate all this code but all the structures and functions
     * are actually different (A/W) */
    DIEFFECTINFOW dei; /* feif */
    DWORD type = DIEFT_GETTYPE(dwEffType);
1132
    JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1133 1134
    int xfd = This->joyfd;

1135
    TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
1136 1137 1138 1139

    dei.dwSize = sizeof(DIEFFECTINFOW);          

    if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
1140
	&& test_bit(This->joydev->ffbits, FF_CONSTANT)) {
1141
	IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
1142 1143 1144 1145
	(*lpCallback)(&dei, pvRef);
    }

    if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
1146 1147
	&& test_bit(This->joydev->ffbits, FF_PERIODIC)) {
	if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
1148
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
1149 1150
	    (*lpCallback)(&dei, pvRef);
	}
1151
	if (test_bit(This->joydev->ffbits, FF_SINE)) {
1152
            IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
1153 1154
	    (*lpCallback)(&dei, pvRef);
	}
1155
	if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
1156
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
1157 1158
	    (*lpCallback)(&dei, pvRef);
	}
1159
	if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
1160
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
1161 1162
	    (*lpCallback)(&dei, pvRef);
	}
1163
	if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
1164
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
1165 1166 1167 1168 1169
	    (*lpCallback)(&dei, pvRef);
	}
    } 

    if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
1170
	&& test_bit(This->joydev->ffbits, FF_RAMP)) {
1171
        IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
1172 1173 1174 1175
        (*lpCallback)(&dei, pvRef);
    }

    if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
1176
	if (test_bit(This->joydev->ffbits, FF_SPRING)) {
1177
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
1178 1179
	    (*lpCallback)(&dei, pvRef);
	}
1180
	if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
1181
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
1182 1183
	    (*lpCallback)(&dei, pvRef);
	}
1184
	if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
1185
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
1186 1187
	    (*lpCallback)(&dei, pvRef);
	}
1188
	if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
1189
	    IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
1190 1191 1192 1193
	    (*lpCallback)(&dei, pvRef);
	}
    }

1194
    /* return to unacquired state if that's where it was */
1195
    if (xfd == -1)
1196
	IDirectInputDevice8_Unacquire(iface);
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
#endif

    return DI_OK;
}

/*******************************************************************************
 *      GetEffectInfo - Get information about a particular effect 
 */
static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
						  LPDIEFFECTINFOA pdei,
						  REFGUID guid)
{
1209
    JoystickImpl* This = impl_from_IDirectInputDevice8A(iface);
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223

    TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));

#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
    return linuxinput_get_info_A(This->joyfd, guid, pdei); 
#else
    return DI_OK;
#endif
}

static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
                                                  LPDIEFFECTINFOW pdei,
                                                  REFGUID guid)
{
1224 1225
    JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);

1226
    TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
1227

1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
    return linuxinput_get_info_W(This->joyfd, guid, pdei);
#else
    return DI_OK;
#endif
}

/*******************************************************************************
 *      GetForceFeedbackState - Get information about the device's FF state 
 */
1238
static HRESULT WINAPI JoystickWImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut)
1239
{
1240
    JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254

    TRACE("(this=%p,%p)\n", This, pdwOut);

    (*pdwOut) = 0;

#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
    /* DIGFFS_STOPPED is the only mandatory flag to report */
    if (This->ff_state == FF_STATUS_STOPPED)
	(*pdwOut) |= DIGFFS_STOPPED;
#endif

    return DI_OK;
}

1255 1256 1257 1258 1259 1260
static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut);
}

1261 1262 1263
/*******************************************************************************
 *      SendForceFeedbackCommand - Send a command to the device's FF system
 */
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 1271 1272 1273
    switch (dwFlags)
    {
    case DISFFC_STOPALL:
    {
1274
	/* Stop all effects */
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285
        effect_list_item *itr;

        LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
            IDirectInputEffect_Stop(itr->ref);
        break;
    }

    case DISFFC_RESET:
    {
        effect_list_item *itr, *ptr;

1286 1287
	/* Stop, unload, release and free all effects */
	/* This returns the device to its "bare" state */
1288 1289 1290 1291 1292 1293
        LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
            IDirectInputEffect_Release(itr->ref);
        break;
    }
    case DISFFC_PAUSE:
    case DISFFC_CONTINUE:
1294
	FIXME("No support for Pause or Continue in linux\n");
1295 1296 1297 1298 1299 1300 1301 1302
        break;

    case DISFFC_SETACTUATORSOFF:
    case DISFFC_SETACTUATORSON:
        FIXME("No direct actuator control in linux\n");
        break;

    default:
1303 1304 1305 1306 1307 1308 1309 1310 1311
	FIXME("Unknown Force Feedback Command!\n");
	return DIERR_INVALIDPARAM;
    }
    return DI_OK;
#else
    return DIERR_UNSUPPORTED;
#endif
}

1312 1313 1314 1315 1316 1317
static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags);
}

1318 1319 1320 1321
/*******************************************************************************
 *      EnumCreatedEffectObjects - Enumerate all the effects that have been
 *		created for this device.
 */
1322 1323 1324
static HRESULT WINAPI JoystickWImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
                                                             LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
                                                             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 1329
    effect_list_item *itr, *ptr;

1330
    TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
1331 1332 1333 1334 1335

    if (!lpCallback)
	return DIERR_INVALIDPARAM;

    if (dwFlags != 0)
1336
	FIXME("Flags specified, but no flags exist yet (DX9)!\n");
1337

1338 1339
    LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
        (*lpCallback)(itr->ref, pvRef);
1340 1341 1342 1343

    return DI_OK;
}

1344 1345 1346 1347 1348 1349 1350 1351
static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface,
                                                             LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
                                                             LPVOID pvRef, DWORD dwFlags)
{
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
    return JoystickWImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, pvRef, dwFlags);
}

1352 1353 1354 1355 1356 1357
/******************************************************************************
  *     GetDeviceInfo : get information about a device's identity
  */
static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface,
                                                  LPDIDEVICEINSTANCEA pdidi)
{
1358
    JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1359 1360 1361 1362 1363 1364 1365 1366

    TRACE("(%p) %p\n", This, pdidi);

    if (pdidi == NULL) return E_POINTER;
    if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
        (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)))
        return DIERR_INVALIDPARAM;

1367 1368
    fill_joystick_dideviceinstanceA(pdidi, This->generic.base.dinput->dwVersion,
                                    get_joystick_index(&This->generic.base.guid));
1369 1370 1371 1372 1373 1374
    return DI_OK;
}

static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface,
                                                  LPDIDEVICEINSTANCEW pdidi)
{
1375
    JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1376 1377 1378 1379 1380 1381 1382 1383

    TRACE("(%p) %p\n", This, pdidi);

    if (pdidi == NULL) return E_POINTER;
    if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
        (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)))
        return DIERR_INVALIDPARAM;

1384 1385
    fill_joystick_dideviceinstanceW(pdidi, This->generic.base.dinput->dwVersion,
                                    get_joystick_index(&This->generic.base.guid));
1386 1387 1388
    return DI_OK;
}

1389
static const IDirectInputDevice8AVtbl JoystickAvt =
1390 1391 1392
{
	IDirectInputDevice2AImpl_QueryInterface,
	IDirectInputDevice2AImpl_AddRef,
1393
        IDirectInputDevice2AImpl_Release,
1394
        JoystickAGenericImpl_GetCapabilities,
1395
        IDirectInputDevice2AImpl_EnumObjects,
1396 1397 1398 1399
	JoystickAImpl_GetProperty,
	JoystickAImpl_SetProperty,
	JoystickAImpl_Acquire,
	JoystickAImpl_Unacquire,
1400
        JoystickAGenericImpl_GetDeviceState,
1401
	IDirectInputDevice2AImpl_GetDeviceData,
1402
        IDirectInputDevice2AImpl_SetDataFormat,
1403
	IDirectInputDevice2AImpl_SetEventNotification,
1404
	IDirectInputDevice2AImpl_SetCooperativeLevel,
1405
        JoystickAGenericImpl_GetObjectInfo,
1406
	JoystickAImpl_GetDeviceInfo,
1407 1408
	IDirectInputDevice2AImpl_RunControlPanel,
	IDirectInputDevice2AImpl_Initialize,
1409 1410 1411 1412 1413 1414
	JoystickAImpl_CreateEffect,
	JoystickAImpl_EnumEffects,
	JoystickAImpl_GetEffectInfo,
	JoystickAImpl_GetForceFeedbackState,
	JoystickAImpl_SendForceFeedbackCommand,
	JoystickAImpl_EnumCreatedEffectObjects,
1415
	IDirectInputDevice2AImpl_Escape,
1416
        JoystickAGenericImpl_Poll,
1417 1418
	IDirectInputDevice2AImpl_SendDeviceData,
	IDirectInputDevice7AImpl_EnumEffectsInFile,
1419
        IDirectInputDevice7AImpl_WriteEffectToFile,
1420 1421
        JoystickAGenericImpl_BuildActionMap,
        JoystickAGenericImpl_SetActionMap,
1422
        IDirectInputDevice8AImpl_GetImageInfo
1423 1424
};

1425
static const IDirectInputDevice8WVtbl JoystickWvt =
1426
{
1427 1428 1429
    IDirectInputDevice2WImpl_QueryInterface,
    IDirectInputDevice2WImpl_AddRef,
    IDirectInputDevice2WImpl_Release,
1430
    JoystickWGenericImpl_GetCapabilities,
1431
    IDirectInputDevice2WImpl_EnumObjects,
1432 1433 1434 1435
    JoystickWImpl_GetProperty,
    JoystickWImpl_SetProperty,
    JoystickWImpl_Acquire,
    JoystickWImpl_Unacquire,
1436
    JoystickWGenericImpl_GetDeviceState,
1437 1438 1439 1440 1441 1442 1443 1444
    IDirectInputDevice2WImpl_GetDeviceData,
    IDirectInputDevice2WImpl_SetDataFormat,
    IDirectInputDevice2WImpl_SetEventNotification,
    IDirectInputDevice2WImpl_SetCooperativeLevel,
    JoystickWGenericImpl_GetObjectInfo,
    JoystickWImpl_GetDeviceInfo,
    IDirectInputDevice2WImpl_RunControlPanel,
    IDirectInputDevice2WImpl_Initialize,
1445
    JoystickWImpl_CreateEffect,
1446 1447
    JoystickWImpl_EnumEffects,
    JoystickWImpl_GetEffectInfo,
1448 1449 1450
    JoystickWImpl_GetForceFeedbackState,
    JoystickWImpl_SendForceFeedbackCommand,
    JoystickWImpl_EnumCreatedEffectObjects,
1451
    IDirectInputDevice2WImpl_Escape,
1452
    JoystickWGenericImpl_Poll,
1453 1454 1455
    IDirectInputDevice2WImpl_SendDeviceData,
    IDirectInputDevice7WImpl_EnumEffectsInFile,
    IDirectInputDevice7WImpl_WriteEffectToFile,
1456 1457
    JoystickWGenericImpl_BuildActionMap,
    JoystickWGenericImpl_SetActionMap,
1458
    IDirectInputDevice8WImpl_GetImageInfo
1459 1460
};

1461
#else  /* HAVE_CORRECT_LINUXINPUT_H */
1462

1463
const struct dinput_device joystick_linuxinput_device = {
1464 1465 1466 1467 1468 1469 1470
  "Wine Linux-input joystick driver",
  NULL,
  NULL,
  NULL
};

#endif  /* HAVE_CORRECT_LINUXINPUT_H */