pinctrl: ocelot: fix pinmuxing for pins after 31
[linux-2.6-block.git] / drivers / hid / hid-lg.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
5f22a799
JS
2/*
3 * HID driver for some logitech "special" devices
4 *
5 * Copyright (c) 1999 Andreas Gal
6 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
7 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
8 * Copyright (c) 2006-2007 Jiri Kosina
5f22a799 9 * Copyright (c) 2008 Jiri Slaby
2c6118e4 10 * Copyright (c) 2010 Hendrik Iben
5f22a799
JS
11 */
12
13/*
5f22a799
JS
14 */
15
16#include <linux/device.h>
17#include <linux/hid.h>
18#include <linux/module.h>
32c88cbc
SW
19#include <linux/random.h>
20#include <linux/sched.h>
54bfe3f0 21#include <linux/usb.h>
32c88cbc 22#include <linux/wait.h>
5f22a799 23
54bfe3f0 24#include "usbhid/usbhid.h"
5f22a799 25#include "hid-ids.h"
606bd0a8 26#include "hid-lg.h"
a54dc779 27#include "hid-lg4ff.h"
5f22a799
JS
28
29#define LG_RDESC 0x001
30#define LG_BAD_RELATIVE_KEYS 0x002
31#define LG_DUPLICATE_USAGES 0x004
5f22a799
JS
32#define LG_EXPANDED_KEYMAP 0x010
33#define LG_IGNORE_DOUBLED_WHEEL 0x020
34#define LG_WIRELESS 0x040
35#define LG_INVERT_HWHEEL 0x080
36#define LG_NOGET 0x100
606bd0a8
JS
37#define LG_FF 0x200
38#define LG_FF2 0x400
24985cf6 39#define LG_RDESC_REL_ABS 0x800
74f292ca 40#define LG_FF3 0x1000
32c88cbc 41#define LG_FF4 0x2000
5f22a799 42
54bfe3f0
PS
43/* Size of the original descriptors of the Driving Force (and Pro) wheels */
44#define DF_RDESC_ORIG_SIZE 130
dc0a4f0c 45#define DFP_RDESC_ORIG_SIZE 97
7f505470 46#define FV_RDESC_ORIG_SIZE 130
270baef1 47#define MOMO_RDESC_ORIG_SIZE 87
348cbaa8 48#define MOMO2_RDESC_ORIG_SIZE 87
560bea30 49#define FFG_RDESC_ORIG_SIZE 85
e41b3cda 50#define FG_RDESC_ORIG_SIZE 82
dc0a4f0c 51
54bfe3f0
PS
52/* Fixed report descriptors for Logitech Driving Force (and Pro)
53 * wheel controllers
dc0a4f0c 54 *
54bfe3f0 55 * The original descriptors hide the separate throttle and brake axes in
dc0a4f0c
MB
56 * a custom vendor usage page, providing only a combined value as
57 * GenericDesktop.Y.
54bfe3f0 58 * These descriptors remove the combined Y axis and instead report
dc0a4f0c
MB
59 * separate throttle (Y) and brake (RZ).
60 */
54bfe3f0
PS
61static __u8 df_rdesc_fixed[] = {
620x05, 0x01, /* Usage Page (Desktop), */
bfb61abf 630x09, 0x04, /* Usage (Joystick), */
54bfe3f0
PS
640xA1, 0x01, /* Collection (Application), */
650xA1, 0x02, /* Collection (Logical), */
660x95, 0x01, /* Report Count (1), */
670x75, 0x0A, /* Report Size (10), */
680x14, /* Logical Minimum (0), */
690x26, 0xFF, 0x03, /* Logical Maximum (1023), */
700x34, /* Physical Minimum (0), */
710x46, 0xFF, 0x03, /* Physical Maximum (1023), */
720x09, 0x30, /* Usage (X), */
730x81, 0x02, /* Input (Variable), */
740x95, 0x0C, /* Report Count (12), */
750x75, 0x01, /* Report Size (1), */
760x25, 0x01, /* Logical Maximum (1), */
770x45, 0x01, /* Physical Maximum (1), */
780x05, 0x09, /* Usage (Buttons), */
790x19, 0x01, /* Usage Minimum (1), */
800x29, 0x0c, /* Usage Maximum (12), */
810x81, 0x02, /* Input (Variable), */
820x95, 0x02, /* Report Count (2), */
830x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
840x09, 0x01, /* Usage (?: 1), */
850x81, 0x02, /* Input (Variable), */
860x05, 0x01, /* Usage Page (Desktop), */
54bfe3f0
PS
870x26, 0xFF, 0x00, /* Logical Maximum (255), */
880x46, 0xFF, 0x00, /* Physical Maximum (255), */
890x95, 0x01, /* Report Count (1), */
900x75, 0x08, /* Report Size (8), */
910x81, 0x02, /* Input (Variable), */
920x25, 0x07, /* Logical Maximum (7), */
930x46, 0x3B, 0x01, /* Physical Maximum (315), */
940x75, 0x04, /* Report Size (4), */
950x65, 0x14, /* Unit (Degrees), */
960x09, 0x39, /* Usage (Hat Switch), */
970x81, 0x42, /* Input (Variable, Null State), */
980x75, 0x01, /* Report Size (1), */
990x95, 0x04, /* Report Count (4), */
1000x65, 0x00, /* Unit (none), */
1010x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
1020x09, 0x01, /* Usage (?: 1), */
1030x25, 0x01, /* Logical Maximum (1), */
1040x45, 0x01, /* Physical Maximum (1), */
1050x81, 0x02, /* Input (Variable), */
5a9b571b
PS
1060x05, 0x01, /* Usage Page (Desktop), */
1070x95, 0x01, /* Report Count (1), */
54bfe3f0
PS
1080x75, 0x08, /* Report Size (8), */
1090x26, 0xFF, 0x00, /* Logical Maximum (255), */
1100x46, 0xFF, 0x00, /* Physical Maximum (255), */
5a9b571b
PS
1110x09, 0x31, /* Usage (Y), */
1120x81, 0x02, /* Input (Variable), */
1130x09, 0x35, /* Usage (Rz), */
54bfe3f0
PS
1140x81, 0x02, /* Input (Variable), */
1150xC0, /* End Collection, */
1160xA1, 0x02, /* Collection (Logical), */
1170x26, 0xFF, 0x00, /* Logical Maximum (255), */
1180x46, 0xFF, 0x00, /* Physical Maximum (255), */
1190x95, 0x07, /* Report Count (7), */
1200x75, 0x08, /* Report Size (8), */
1210x09, 0x03, /* Usage (?: 3), */
1220x91, 0x02, /* Output (Variable), */
1230xC0, /* End Collection, */
1240xC0 /* End Collection */
125};
126
dc0a4f0c
MB
127static __u8 dfp_rdesc_fixed[] = {
1280x05, 0x01, /* Usage Page (Desktop), */
bfb61abf 1290x09, 0x04, /* Usage (Joystick), */
dc0a4f0c
MB
1300xA1, 0x01, /* Collection (Application), */
1310xA1, 0x02, /* Collection (Logical), */
1320x95, 0x01, /* Report Count (1), */
1330x75, 0x0E, /* Report Size (14), */
1340x14, /* Logical Minimum (0), */
1350x26, 0xFF, 0x3F, /* Logical Maximum (16383), */
1360x34, /* Physical Minimum (0), */
1370x46, 0xFF, 0x3F, /* Physical Maximum (16383), */
1380x09, 0x30, /* Usage (X), */
1390x81, 0x02, /* Input (Variable), */
1400x95, 0x0E, /* Report Count (14), */
1410x75, 0x01, /* Report Size (1), */
1420x25, 0x01, /* Logical Maximum (1), */
1430x45, 0x01, /* Physical Maximum (1), */
1440x05, 0x09, /* Usage Page (Button), */
1450x19, 0x01, /* Usage Minimum (01h), */
1460x29, 0x0E, /* Usage Maximum (0Eh), */
1470x81, 0x02, /* Input (Variable), */
1480x05, 0x01, /* Usage Page (Desktop), */
1490x95, 0x01, /* Report Count (1), */
1500x75, 0x04, /* Report Size (4), */
1510x25, 0x07, /* Logical Maximum (7), */
1520x46, 0x3B, 0x01, /* Physical Maximum (315), */
1530x65, 0x14, /* Unit (Degrees), */
1540x09, 0x39, /* Usage (Hat Switch), */
1550x81, 0x42, /* Input (Variable, Nullstate), */
1560x65, 0x00, /* Unit, */
1570x26, 0xFF, 0x00, /* Logical Maximum (255), */
1580x46, 0xFF, 0x00, /* Physical Maximum (255), */
1590x75, 0x08, /* Report Size (8), */
1600x81, 0x01, /* Input (Constant), */
1610x09, 0x31, /* Usage (Y), */
1620x81, 0x02, /* Input (Variable), */
1630x09, 0x35, /* Usage (Rz), */
1640x81, 0x02, /* Input (Variable), */
1650x81, 0x01, /* Input (Constant), */
1660xC0, /* End Collection, */
1670xA1, 0x02, /* Collection (Logical), */
1680x09, 0x02, /* Usage (02h), */
1690x95, 0x07, /* Report Count (7), */
1700x91, 0x02, /* Output (Variable), */
1710xC0, /* End Collection, */
1720xC0 /* End Collection */
173};
174
7f505470
SW
175static __u8 fv_rdesc_fixed[] = {
1760x05, 0x01, /* Usage Page (Desktop), */
bfb61abf 1770x09, 0x04, /* Usage (Joystick), */
7f505470
SW
1780xA1, 0x01, /* Collection (Application), */
1790xA1, 0x02, /* Collection (Logical), */
1800x95, 0x01, /* Report Count (1), */
1810x75, 0x0A, /* Report Size (10), */
1820x15, 0x00, /* Logical Minimum (0), */
1830x26, 0xFF, 0x03, /* Logical Maximum (1023), */
1840x35, 0x00, /* Physical Minimum (0), */
1850x46, 0xFF, 0x03, /* Physical Maximum (1023), */
1860x09, 0x30, /* Usage (X), */
1870x81, 0x02, /* Input (Variable), */
1880x95, 0x0C, /* Report Count (12), */
1890x75, 0x01, /* Report Size (1), */
1900x25, 0x01, /* Logical Maximum (1), */
1910x45, 0x01, /* Physical Maximum (1), */
1920x05, 0x09, /* Usage Page (Button), */
1930x19, 0x01, /* Usage Minimum (01h), */
1940x29, 0x0C, /* Usage Maximum (0Ch), */
1950x81, 0x02, /* Input (Variable), */
1960x95, 0x02, /* Report Count (2), */
1970x06, 0x00, 0xFF, /* Usage Page (FF00h), */
1980x09, 0x01, /* Usage (01h), */
1990x81, 0x02, /* Input (Variable), */
2000x09, 0x02, /* Usage (02h), */
2010x26, 0xFF, 0x00, /* Logical Maximum (255), */
2020x46, 0xFF, 0x00, /* Physical Maximum (255), */
2030x95, 0x01, /* Report Count (1), */
2040x75, 0x08, /* Report Size (8), */
2050x81, 0x02, /* Input (Variable), */
2060x05, 0x01, /* Usage Page (Desktop), */
2070x25, 0x07, /* Logical Maximum (7), */
2080x46, 0x3B, 0x01, /* Physical Maximum (315), */
2090x75, 0x04, /* Report Size (4), */
2100x65, 0x14, /* Unit (Degrees), */
2110x09, 0x39, /* Usage (Hat Switch), */
2120x81, 0x42, /* Input (Variable, Null State), */
2130x75, 0x01, /* Report Size (1), */
2140x95, 0x04, /* Report Count (4), */
2150x65, 0x00, /* Unit, */
2160x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2170x09, 0x01, /* Usage (01h), */
2180x25, 0x01, /* Logical Maximum (1), */
2190x45, 0x01, /* Physical Maximum (1), */
2200x81, 0x02, /* Input (Variable), */
2210x05, 0x01, /* Usage Page (Desktop), */
2220x95, 0x01, /* Report Count (1), */
2230x75, 0x08, /* Report Size (8), */
2240x26, 0xFF, 0x00, /* Logical Maximum (255), */
2250x46, 0xFF, 0x00, /* Physical Maximum (255), */
2260x09, 0x31, /* Usage (Y), */
2270x81, 0x02, /* Input (Variable), */
2280x09, 0x32, /* Usage (Z), */
2290x81, 0x02, /* Input (Variable), */
2300xC0, /* End Collection, */
2310xA1, 0x02, /* Collection (Logical), */
2320x26, 0xFF, 0x00, /* Logical Maximum (255), */
2330x46, 0xFF, 0x00, /* Physical Maximum (255), */
2340x95, 0x07, /* Report Count (7), */
2350x75, 0x08, /* Report Size (8), */
2360x09, 0x03, /* Usage (03h), */
2370x91, 0x02, /* Output (Variable), */
2380xC0, /* End Collection, */
2390xC0 /* End Collection */
240};
241
270baef1
SW
242static __u8 momo_rdesc_fixed[] = {
2430x05, 0x01, /* Usage Page (Desktop), */
bfb61abf 2440x09, 0x04, /* Usage (Joystick), */
270baef1
SW
2450xA1, 0x01, /* Collection (Application), */
2460xA1, 0x02, /* Collection (Logical), */
2470x95, 0x01, /* Report Count (1), */
2480x75, 0x0A, /* Report Size (10), */
2490x15, 0x00, /* Logical Minimum (0), */
2500x26, 0xFF, 0x03, /* Logical Maximum (1023), */
2510x35, 0x00, /* Physical Minimum (0), */
2520x46, 0xFF, 0x03, /* Physical Maximum (1023), */
2530x09, 0x30, /* Usage (X), */
2540x81, 0x02, /* Input (Variable), */
2550x95, 0x08, /* Report Count (8), */
2560x75, 0x01, /* Report Size (1), */
2570x25, 0x01, /* Logical Maximum (1), */
2580x45, 0x01, /* Physical Maximum (1), */
2590x05, 0x09, /* Usage Page (Button), */
2600x19, 0x01, /* Usage Minimum (01h), */
2610x29, 0x08, /* Usage Maximum (08h), */
2620x81, 0x02, /* Input (Variable), */
2630x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2640x75, 0x0E, /* Report Size (14), */
2650x95, 0x01, /* Report Count (1), */
2660x26, 0xFF, 0x00, /* Logical Maximum (255), */
2670x46, 0xFF, 0x00, /* Physical Maximum (255), */
2680x09, 0x00, /* Usage (00h), */
2690x81, 0x02, /* Input (Variable), */
2700x05, 0x01, /* Usage Page (Desktop), */
2710x75, 0x08, /* Report Size (8), */
2720x09, 0x31, /* Usage (Y), */
2730x81, 0x02, /* Input (Variable), */
2740x09, 0x32, /* Usage (Z), */
2750x81, 0x02, /* Input (Variable), */
2760x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2770x09, 0x01, /* Usage (01h), */
2780x81, 0x02, /* Input (Variable), */
2790xC0, /* End Collection, */
2800xA1, 0x02, /* Collection (Logical), */
2810x09, 0x02, /* Usage (02h), */
2820x95, 0x07, /* Report Count (7), */
2830x91, 0x02, /* Output (Variable), */
2840xC0, /* End Collection, */
2850xC0 /* End Collection */
286};
dc0a4f0c 287
348cbaa8
SW
288static __u8 momo2_rdesc_fixed[] = {
2890x05, 0x01, /* Usage Page (Desktop), */
bfb61abf 2900x09, 0x04, /* Usage (Joystick), */
348cbaa8
SW
2910xA1, 0x01, /* Collection (Application), */
2920xA1, 0x02, /* Collection (Logical), */
2930x95, 0x01, /* Report Count (1), */
2940x75, 0x0A, /* Report Size (10), */
2950x15, 0x00, /* Logical Minimum (0), */
2960x26, 0xFF, 0x03, /* Logical Maximum (1023), */
2970x35, 0x00, /* Physical Minimum (0), */
2980x46, 0xFF, 0x03, /* Physical Maximum (1023), */
2990x09, 0x30, /* Usage (X), */
3000x81, 0x02, /* Input (Variable), */
3010x95, 0x0A, /* Report Count (10), */
3020x75, 0x01, /* Report Size (1), */
3030x25, 0x01, /* Logical Maximum (1), */
3040x45, 0x01, /* Physical Maximum (1), */
3050x05, 0x09, /* Usage Page (Button), */
3060x19, 0x01, /* Usage Minimum (01h), */
3070x29, 0x0A, /* Usage Maximum (0Ah), */
3080x81, 0x02, /* Input (Variable), */
3090x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3100x09, 0x00, /* Usage (00h), */
3110x95, 0x04, /* Report Count (4), */
3120x81, 0x02, /* Input (Variable), */
3130x95, 0x01, /* Report Count (1), */
3140x75, 0x08, /* Report Size (8), */
3150x26, 0xFF, 0x00, /* Logical Maximum (255), */
3160x46, 0xFF, 0x00, /* Physical Maximum (255), */
3170x09, 0x01, /* Usage (01h), */
3180x81, 0x02, /* Input (Variable), */
3190x05, 0x01, /* Usage Page (Desktop), */
3200x09, 0x31, /* Usage (Y), */
3210x81, 0x02, /* Input (Variable), */
3220x09, 0x32, /* Usage (Z), */
3230x81, 0x02, /* Input (Variable), */
3240x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3250x09, 0x00, /* Usage (00h), */
3260x81, 0x02, /* Input (Variable), */
3270xC0, /* End Collection, */
3280xA1, 0x02, /* Collection (Logical), */
3290x09, 0x02, /* Usage (02h), */
3300x95, 0x07, /* Report Count (7), */
3310x91, 0x02, /* Output (Variable), */
3320xC0, /* End Collection, */
3330xC0 /* End Collection */
334};
335
560bea30
SW
336static __u8 ffg_rdesc_fixed[] = {
3370x05, 0x01, /* Usage Page (Desktop), */
3380x09, 0x04, /* Usage (Joystik), */
3390xA1, 0x01, /* Collection (Application), */
3400xA1, 0x02, /* Collection (Logical), */
3410x95, 0x01, /* Report Count (1), */
3420x75, 0x0A, /* Report Size (10), */
3430x15, 0x00, /* Logical Minimum (0), */
3440x26, 0xFF, 0x03, /* Logical Maximum (1023), */
3450x35, 0x00, /* Physical Minimum (0), */
3460x46, 0xFF, 0x03, /* Physical Maximum (1023), */
3470x09, 0x30, /* Usage (X), */
3480x81, 0x02, /* Input (Variable), */
3490x95, 0x06, /* Report Count (6), */
3500x75, 0x01, /* Report Size (1), */
3510x25, 0x01, /* Logical Maximum (1), */
3520x45, 0x01, /* Physical Maximum (1), */
3530x05, 0x09, /* Usage Page (Button), */
3540x19, 0x01, /* Usage Minimum (01h), */
3550x29, 0x06, /* Usage Maximum (06h), */
3560x81, 0x02, /* Input (Variable), */
3570x95, 0x01, /* Report Count (1), */
3580x75, 0x08, /* Report Size (8), */
3590x26, 0xFF, 0x00, /* Logical Maximum (255), */
3600x46, 0xFF, 0x00, /* Physical Maximum (255), */
3610x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3620x09, 0x01, /* Usage (01h), */
3630x81, 0x02, /* Input (Variable), */
3640x05, 0x01, /* Usage Page (Desktop), */
3650x81, 0x01, /* Input (Constant), */
3660x09, 0x31, /* Usage (Y), */
3670x81, 0x02, /* Input (Variable), */
3680x09, 0x32, /* Usage (Z), */
3690x81, 0x02, /* Input (Variable), */
3700x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3710x09, 0x01, /* Usage (01h), */
3720x81, 0x02, /* Input (Variable), */
3730xC0, /* End Collection, */
3740xA1, 0x02, /* Collection (Logical), */
3750x09, 0x02, /* Usage (02h), */
3760x95, 0x07, /* Report Count (7), */
3770x91, 0x02, /* Output (Variable), */
3780xC0, /* End Collection, */
3790xC0 /* End Collection */
380};
381
e41b3cda
JW
382static __u8 fg_rdesc_fixed[] = {
3830x05, 0x01, /* Usage Page (Desktop), */
3840x09, 0x04, /* Usage (Joystik), */
3850xA1, 0x01, /* Collection (Application), */
3860xA1, 0x02, /* Collection (Logical), */
3870x15, 0x00, /* Logical Minimum (0), */
3880x26, 0xFF, 0x00, /* Logical Maximum (255), */
3890x35, 0x00, /* Physical Minimum (0), */
3900x46, 0xFF, 0x00, /* Physical Maximum (255), */
3910x75, 0x08, /* Report Size (8), */
3920x95, 0x01, /* Report Count (1), */
3930x09, 0x30, /* Usage (X), */
3940x81, 0x02, /* Input (Variable), */
3950xA4, /* Push, */
3960x25, 0x01, /* Logical Maximum (1), */
3970x45, 0x01, /* Physical Maximum (1), */
3980x75, 0x01, /* Report Size (1), */
3990x95, 0x02, /* Report Count (2), */
4000x81, 0x01, /* Input (Constant), */
4010x95, 0x06, /* Report Count (6), */
4020x05, 0x09, /* Usage Page (Button), */
4030x19, 0x01, /* Usage Minimum (01h), */
4040x29, 0x06, /* Usage Maximum (06h), */
4050x81, 0x02, /* Input (Variable), */
4060x05, 0x01, /* Usage Page (Desktop), */
4070xB4, /* Pop, */
4080x81, 0x02, /* Input (Constant), */
4090x09, 0x31, /* Usage (Y), */
4100x81, 0x02, /* Input (Variable), */
4110x09, 0x32, /* Usage (Z), */
4120x81, 0x02, /* Input (Variable), */
4130xC0, /* End Collection, */
4140xA1, 0x02, /* Collection (Logical), */
4150x26, 0xFF, 0x00, /* Logical Maximum (255), */
4160x46, 0xFF, 0x00, /* Physical Maximum (255), */
4170x75, 0x08, /* Report Size (8), */
4180x95, 0x04, /* Report Count (4), */
4190x09, 0x02, /* Usage (02h), */
4200xB1, 0x02, /* Feature (Variable), */
4210xC0, /* End Collection, */
4220xC0 /* End Collection, */
423};
424
5f22a799
JS
425/*
426 * Certain Logitech keyboards send in report #3 keys which are far
427 * above the logical maximum described in descriptor. This extends
428 * the original value of 0x28c of logical maximum to 0x104d
429 */
73e4008d
NK
430static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
431 unsigned int *rsize)
5f22a799 432{
25751553 433 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5f22a799 434
4ab25786 435 if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
5f22a799 436 rdesc[84] == 0x8c && rdesc[85] == 0x02) {
4291ee30
JP
437 hid_info(hdev,
438 "fixing up Logitech keyboard report descriptor\n");
5f22a799
JS
439 rdesc[84] = rdesc[89] = 0x4d;
440 rdesc[85] = rdesc[90] = 0x10;
441 }
4ab25786 442 if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
24985cf6
JK
443 rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
444 rdesc[49] == 0x81 && rdesc[50] == 0x06) {
4291ee30
JP
445 hid_info(hdev,
446 "fixing up rel/abs in Logitech report descriptor\n");
24985cf6
JK
447 rdesc[33] = rdesc[50] = 0x02;
448 }
dc0a4f0c
MB
449
450 switch (hdev->product) {
54bfe3f0 451
e41b3cda
JW
452 case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
453 if (*rsize == FG_RDESC_ORIG_SIZE) {
454 hid_info(hdev,
455 "fixing up Logitech Wingman Formula GP report descriptor\n");
456 rdesc = fg_rdesc_fixed;
457 *rsize = sizeof(fg_rdesc_fixed);
458 } else {
459 hid_info(hdev,
460 "rdesc size test failed for formula gp\n");
461 }
462 break;
463
464
560bea30
SW
465 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
466 if (*rsize == FFG_RDESC_ORIG_SIZE) {
467 hid_info(hdev,
468 "fixing up Logitech Wingman Formula Force GP report descriptor\n");
469 rdesc = ffg_rdesc_fixed;
470 *rsize = sizeof(ffg_rdesc_fixed);
471 }
472 break;
473
54bfe3f0
PS
474 /* Several wheels report as this id when operating in emulation mode. */
475 case USB_DEVICE_ID_LOGITECH_WHEEL:
7363b25a 476 if (*rsize == DF_RDESC_ORIG_SIZE) {
54bfe3f0
PS
477 hid_info(hdev,
478 "fixing up Logitech Driving Force report descriptor\n");
479 rdesc = df_rdesc_fixed;
480 *rsize = sizeof(df_rdesc_fixed);
481 }
482 break;
483
270baef1
SW
484 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
485 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
486 hid_info(hdev,
487 "fixing up Logitech Momo Force (Red) report descriptor\n");
488 rdesc = momo_rdesc_fixed;
489 *rsize = sizeof(momo_rdesc_fixed);
490 }
491 break;
492
348cbaa8
SW
493 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
494 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
495 hid_info(hdev,
496 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
497 rdesc = momo2_rdesc_fixed;
498 *rsize = sizeof(momo2_rdesc_fixed);
499 }
500 break;
501
7f505470
SW
502 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
503 if (*rsize == FV_RDESC_ORIG_SIZE) {
504 hid_info(hdev,
505 "fixing up Logitech Formula Vibration report descriptor\n");
506 rdesc = fv_rdesc_fixed;
507 *rsize = sizeof(fv_rdesc_fixed);
508 }
509 break;
510
dc0a4f0c
MB
511 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
512 if (*rsize == DFP_RDESC_ORIG_SIZE) {
513 hid_info(hdev,
514 "fixing up Logitech Driving Force Pro report descriptor\n");
515 rdesc = dfp_rdesc_fixed;
516 *rsize = sizeof(dfp_rdesc_fixed);
517 }
518 break;
b5836246
SW
519
520 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
521 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
522 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
523 hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
524 rdesc[41] = 0x05;
525 rdesc[42] = 0x09;
526 rdesc[47] = 0x95;
527 rdesc[48] = 0x0B;
528 }
529 break;
dc0a4f0c
MB
530 }
531
73e4008d 532 return rdesc;
5f22a799
JS
533}
534
535#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
536 EV_KEY, (c))
537
538static int lg_ultrax_remote_mapping(struct hid_input *hi,
539 struct hid_usage *usage, unsigned long **bit, int *max)
540{
541 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
542 return 0;
543
544 set_bit(EV_REP, hi->input->evbit);
545 switch (usage->hid & HID_USAGE) {
546 /* Reported on Logitech Ultra X Media Remote */
547 case 0x004: lg_map_key_clear(KEY_AGAIN); break;
548 case 0x00d: lg_map_key_clear(KEY_HOME); break;
549 case 0x024: lg_map_key_clear(KEY_SHUFFLE); break;
550 case 0x025: lg_map_key_clear(KEY_TV); break;
551 case 0x026: lg_map_key_clear(KEY_MENU); break;
552 case 0x031: lg_map_key_clear(KEY_AUDIO); break;
553 case 0x032: lg_map_key_clear(KEY_TEXT); break;
554 case 0x033: lg_map_key_clear(KEY_LAST); break;
555 case 0x047: lg_map_key_clear(KEY_MP3); break;
556 case 0x048: lg_map_key_clear(KEY_DVD); break;
557 case 0x049: lg_map_key_clear(KEY_MEDIA); break;
558 case 0x04a: lg_map_key_clear(KEY_VIDEO); break;
559 case 0x04b: lg_map_key_clear(KEY_ANGLE); break;
560 case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
561 case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
562 case 0x051: lg_map_key_clear(KEY_RED); break;
563 case 0x052: lg_map_key_clear(KEY_CLOSE); break;
564
565 default:
566 return 0;
567 }
568 return 1;
569}
570
66d61bec
JK
571static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
572 unsigned long **bit, int *max)
573{
574 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
575 return 0;
576
577 switch (usage->hid & HID_USAGE) {
578
579 case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
580 default:
581 return 0;
582
583 }
584 return 1;
585}
586
5f22a799
JS
587static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
588 unsigned long **bit, int *max)
589{
590 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
591 return 0;
592
593 switch (usage->hid & HID_USAGE) {
594 case 0x1001: lg_map_key_clear(KEY_MESSENGER); break;
595 case 0x1003: lg_map_key_clear(KEY_SOUND); break;
596 case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
597 case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
598 case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
18392212
LC
599 /* The following two entries are Playlist 1 and 2 on the MX3200 */
600 case 0x100f: lg_map_key_clear(KEY_FN_1); break;
601 case 0x1010: lg_map_key_clear(KEY_FN_2); break;
5f22a799
JS
602 case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
603 case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
604 case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
605 case 0x1014: lg_map_key_clear(KEY_MESSENGER); break;
606 case 0x1015: lg_map_key_clear(KEY_RECORD); break;
607 case 0x1016: lg_map_key_clear(KEY_PLAYER); break;
608 case 0x1017: lg_map_key_clear(KEY_EJECTCD); break;
609 case 0x1018: lg_map_key_clear(KEY_MEDIA); break;
610 case 0x1019: lg_map_key_clear(KEY_PROG1); break;
611 case 0x101a: lg_map_key_clear(KEY_PROG2); break;
612 case 0x101b: lg_map_key_clear(KEY_PROG3); break;
18392212 613 case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
5f22a799
JS
614 case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
615 case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
616 case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
617 case 0x1023: lg_map_key_clear(KEY_CLOSE); break;
618 case 0x1027: lg_map_key_clear(KEY_MENU); break;
619 /* this one is marked as 'Rotate' */
620 case 0x1028: lg_map_key_clear(KEY_ANGLE); break;
621 case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
622 case 0x102a: lg_map_key_clear(KEY_BACK); break;
623 case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
18392212
LC
624 case 0x102d: lg_map_key_clear(KEY_WWW); break;
625 /* The following two are 'Start/answer call' and 'End/reject call'
626 on the MX3200 */
627 case 0x1031: lg_map_key_clear(KEY_OK); break;
628 case 0x1032: lg_map_key_clear(KEY_CANCEL); break;
5f22a799
JS
629 case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
630 case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
631 case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
632 case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break;
633 case 0x1045: lg_map_key_clear(KEY_UNDO); break;
634 case 0x1046: lg_map_key_clear(KEY_REDO); break;
635 case 0x1047: lg_map_key_clear(KEY_PRINT); break;
636 case 0x1048: lg_map_key_clear(KEY_SAVE); break;
637 case 0x1049: lg_map_key_clear(KEY_PROG1); break;
638 case 0x104a: lg_map_key_clear(KEY_PROG2); break;
639 case 0x104b: lg_map_key_clear(KEY_PROG3); break;
640 case 0x104c: lg_map_key_clear(KEY_PROG4); break;
641
642 default:
643 return 0;
644 }
645 return 1;
646}
647
648static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
649 struct hid_field *field, struct hid_usage *usage,
650 unsigned long **bit, int *max)
651{
652 /* extended mapping for certain Logitech hardware (Logitech cordless
653 desktop LX500) */
654 static const u8 e_keymap[] = {
655 0,216, 0,213,175,156, 0, 0, 0, 0,
656 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
657 174,167,152,161,112, 0, 0, 0,154, 0,
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
660 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
661 0, 0, 0, 0, 0,183,184,185,186,187,
662 188,189,190,191,192,193,194, 0, 0, 0
663 };
25751553 664 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5f22a799
JS
665 unsigned int hid = usage->hid;
666
667 if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
668 lg_ultrax_remote_mapping(hi, usage, bit, max))
669 return 1;
670
66d61bec
JK
671 if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
672 lg_dinovo_mapping(hi, usage, bit, max))
673 return 1;
674
8577dbf9 675 if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
5f22a799
JS
676 return 1;
677
678 if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
679 return 0;
680
681 hid &= HID_USAGE;
682
683 /* Special handling for Logitech Cordless Desktop */
684 if (field->application == HID_GD_MOUSE) {
8577dbf9 685 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
5f22a799
JS
686 (hid == 7 || hid == 8))
687 return -1;
688 } else {
8577dbf9 689 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
5f22a799
JS
690 hid < ARRAY_SIZE(e_keymap) &&
691 e_keymap[hid] != 0) {
692 hid_map_usage(hi, usage, bit, max, EV_KEY,
693 e_keymap[hid]);
694 return 1;
695 }
696 }
697
698 return 0;
699}
700
701static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
702 struct hid_field *field, struct hid_usage *usage,
703 unsigned long **bit, int *max)
704{
25751553 705 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5f22a799 706
8577dbf9 707 if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
5f22a799
JS
708 (field->flags & HID_MAIN_ITEM_RELATIVE))
709 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
710
8577dbf9 711 if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
5f22a799
JS
712 usage->type == EV_REL || usage->type == EV_ABS))
713 clear_bit(usage->code, *bit);
714
94b3f712
SW
715 /* Ensure that Logitech wheels are not given a default fuzz/flat value */
716 if (usage->type == EV_ABS && (usage->code == ABS_X ||
717 usage->code == ABS_Y || usage->code == ABS_Z ||
718 usage->code == ABS_RZ)) {
719 switch (hdev->product) {
29fae1c8 720 case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
e41b3cda 721 case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
560bea30 722 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
94b3f712
SW
723 case USB_DEVICE_ID_LOGITECH_WHEEL:
724 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
725 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
726 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
727 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
728 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
729 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
730 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
bd04363d 731 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
94b3f712
SW
732 field->application = HID_GD_MULTIAXIS;
733 break;
734 default:
735 break;
736 }
737 }
738
5f22a799
JS
739 return 0;
740}
741
742static int lg_event(struct hid_device *hdev, struct hid_field *field,
743 struct hid_usage *usage, __s32 value)
744{
25751553 745 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5f22a799 746
8577dbf9 747 if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
5f22a799
JS
748 input_event(field->hidinput->input, usage->type, usage->code,
749 -value);
750 return 1;
751 }
2b24a960
MM
752 if (drv_data->quirks & LG_FF4) {
753 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
754 }
5f22a799
JS
755
756 return 0;
757}
758
c832f86e
SW
759static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
760 u8 *rd, int size)
761{
762 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
763
764 if (drv_data->quirks & LG_FF4)
765 return lg4ff_raw_event(hdev, report, rd, size, drv_data);
766
767 return 0;
768}
769
5f22a799
JS
770static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
771{
29fae1c8
SW
772 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
773 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
606bd0a8 774 unsigned int connect_mask = HID_CONNECT_DEFAULT;
8577dbf9 775 struct lg_drv_data *drv_data;
5f22a799
JS
776 int ret;
777
2078665a
BT
778 /* G29 only work with the 1st interface */
779 if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
780 (iface_num != 0)) {
29fae1c8
SW
781 dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
782 return -ENODEV;
783 }
784
8577dbf9
MM
785 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
786 if (!drv_data) {
787 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
788 return -ENOMEM;
789 }
790 drv_data->quirks = id->driver_data;
a80fe5d6 791
8577dbf9 792 hid_set_drvdata(hdev, (void *)drv_data);
5f22a799 793
8577dbf9 794 if (drv_data->quirks & LG_NOGET)
5f22a799
JS
795 hdev->quirks |= HID_QUIRK_NOGET;
796
797 ret = hid_parse(hdev);
798 if (ret) {
4291ee30 799 hid_err(hdev, "parse failed\n");
5f22a799
JS
800 goto err_free;
801 }
802
8577dbf9 803 if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
606bd0a8
JS
804 connect_mask &= ~HID_CONNECT_FF;
805
806 ret = hid_hw_start(hdev, connect_mask);
5f22a799 807 if (ret) {
4291ee30 808 hid_err(hdev, "hw start failed\n");
5f22a799
JS
809 goto err_free;
810 }
811
7362cd22 812 /* Setup wireless link with Logitech Wii wheel */
a80fe5d6 813 if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
47af1cdb
CIK
814 static const unsigned char cbuf[] = {
815 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
816 };
061232f0 817 u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
32c88cbc 818
061232f0
BT
819 if (!buf) {
820 ret = -ENOMEM;
821 goto err_free;
822 }
32c88cbc 823
061232f0
BT
824 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
825 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
32c88cbc
SW
826 if (ret >= 0) {
827 /* insert a little delay of 10 jiffies ~ 40ms */
828 wait_queue_head_t wait;
829 init_waitqueue_head (&wait);
e0393062
NMG
830 wait_event_interruptible_timeout(wait, 0,
831 msecs_to_jiffies(40));
32c88cbc
SW
832
833 /* Select random Address */
834 buf[1] = 0xB2;
835 get_random_bytes(&buf[2], 2);
836
061232f0 837 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
b0dd72aa 838 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
32c88cbc 839 }
061232f0 840 kfree(buf);
32c88cbc
SW
841 }
842
8577dbf9 843 if (drv_data->quirks & LG_FF)
2dbf635e 844 ret = lgff_init(hdev);
f4e1eb96 845 else if (drv_data->quirks & LG_FF2)
2dbf635e 846 ret = lg2ff_init(hdev);
f4e1eb96 847 else if (drv_data->quirks & LG_FF3)
2dbf635e 848 ret = lg3ff_init(hdev);
f4e1eb96 849 else if (drv_data->quirks & LG_FF4)
2dbf635e
MM
850 ret = lg4ff_init(hdev);
851
852 if (ret)
853 goto err_free;
606bd0a8 854
5f22a799
JS
855 return 0;
856err_free:
8577dbf9 857 kfree(drv_data);
5f22a799
JS
858 return ret;
859}
860
30bb75d7
MM
861static void lg_remove(struct hid_device *hdev)
862{
25751553 863 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
8577dbf9 864 if (drv_data->quirks & LG_FF4)
30bb75d7 865 lg4ff_deinit(hdev);
b211a638
MM
866 else
867 hid_hw_stop(hdev);
8577dbf9 868 kfree(drv_data);
30bb75d7
MM
869}
870
5f22a799
JS
871static const struct hid_device_id lg_devices[] = {
872 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
873 .driver_data = LG_RDESC | LG_WIRELESS },
874 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
875 .driver_data = LG_RDESC | LG_WIRELESS },
5f22a799
JS
876
877 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
878 .driver_data = LG_BAD_RELATIVE_KEYS },
879
880 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
881 .driver_data = LG_DUPLICATE_USAGES },
882 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
883 .driver_data = LG_DUPLICATE_USAGES },
884 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
885 .driver_data = LG_DUPLICATE_USAGES },
886
5f22a799
JS
887 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
888 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
889 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
890 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
891
5f22a799
JS
892 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
893 .driver_data = LG_NOGET },
56d0c8b7
VK
894 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
895 .driver_data = LG_NOGET },
5f22a799 896 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
7362cd22 897 .driver_data = LG_NOGET | LG_FF4 },
606bd0a8 898
2c6118e4
HI
899 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
900 .driver_data = LG_FF2 },
606bd0a8
JS
901 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
902 .driver_data = LG_FF },
903 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
904 .driver_data = LG_FF },
c873d9ab
SW
905 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
906 .driver_data = LG_FF4 },
606bd0a8
JS
907 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
908 .driver_data = LG_FF },
909 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
910 .driver_data = LG_FF },
911 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
270baef1 912 .driver_data = LG_NOGET | LG_FF4 },
606bd0a8 913 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
7362cd22 914 .driver_data = LG_FF4 },
bd04363d
EV
915 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
916 .driver_data = LG_FF2 },
243b706d 917 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
7362cd22
MM
918 .driver_data = LG_FF4 },
919 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
920 .driver_data = LG_FF4 },
fdc6807f 921 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
7362cd22 922 .driver_data = LG_FF4 },
5623a24a 923 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
7362cd22 924 .driver_data = LG_NOGET | LG_FF4 },
32c88cbc
SW
925 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
926 .driver_data = LG_FF4 },
e41b3cda
JW
927 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
928 .driver_data = LG_NOGET },
a80fe5d6 929 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
560bea30 930 .driver_data = LG_NOGET | LG_FF4 },
606bd0a8 931 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
877a021e 932 .driver_data = LG_NOGET | LG_FF2 },
74f292ca
GS
933 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
934 .driver_data = LG_FF3 },
24985cf6
JK
935 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
936 .driver_data = LG_RDESC_REL_ABS },
937 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
938 .driver_data = LG_RDESC_REL_ABS },
5f22a799
JS
939 { }
940};
24985cf6 941
5f22a799
JS
942MODULE_DEVICE_TABLE(hid, lg_devices);
943
944static struct hid_driver lg_driver = {
945 .name = "logitech",
946 .id_table = lg_devices,
947 .report_fixup = lg_report_fixup,
948 .input_mapping = lg_input_mapping,
949 .input_mapped = lg_input_mapped,
950 .event = lg_event,
c832f86e 951 .raw_event = lg_raw_event,
5f22a799 952 .probe = lg_probe,
30bb75d7 953 .remove = lg_remove,
5f22a799 954};
f425458e 955module_hid_driver(lg_driver);
5f22a799 956
a54dc779
MM
957#ifdef CONFIG_LOGIWHEELS_FF
958int lg4ff_no_autoswitch = 0;
959module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
960MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
961#endif
962
5f22a799 963MODULE_LICENSE("GPL");