xref: /linux/drivers/hid/hid-lg.c (revision 56fb34d86e875dbb0d3e6a81c5d3d035db373031)
1 // SPDX-License-Identifier: GPL-2.0-or-later
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
9  *  Copyright (c) 2008 Jiri Slaby
10  *  Copyright (c) 2010 Hendrik Iben
11  */
12 
13 /*
14  */
15 
16 #include <linux/device.h>
17 #include <linux/hid.h>
18 #include <linux/module.h>
19 #include <linux/random.h>
20 #include <linux/sched.h>
21 #include <linux/usb.h>
22 #include <linux/wait.h>
23 
24 #include "usbhid/usbhid.h"
25 #include "hid-ids.h"
26 #include "hid-lg.h"
27 #include "hid-lg4ff.h"
28 
29 #define LG_RDESC		0x001
30 #define LG_BAD_RELATIVE_KEYS	0x002
31 #define LG_DUPLICATE_USAGES	0x004
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
37 #define LG_FF			0x200
38 #define LG_FF2			0x400
39 #define LG_RDESC_REL_ABS	0x800
40 #define LG_FF3			0x1000
41 #define LG_FF4			0x2000
42 
43 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
44 #define DF_RDESC_ORIG_SIZE	130
45 #define DFP_RDESC_ORIG_SIZE	97
46 #define FV_RDESC_ORIG_SIZE	130
47 #define MOMO_RDESC_ORIG_SIZE	87
48 #define MOMO2_RDESC_ORIG_SIZE	87
49 #define FFG_RDESC_ORIG_SIZE	85
50 #define FG_RDESC_ORIG_SIZE	82
51 
52 /* Fixed report descriptors for Logitech Driving Force (and Pro)
53  * wheel controllers
54  *
55  * The original descriptors hide the separate throttle and brake axes in
56  * a custom vendor usage page, providing only a combined value as
57  * GenericDesktop.Y.
58  * These descriptors remove the combined Y axis and instead report
59  * separate throttle (Y) and brake (RZ).
60  */
61 static __u8 df_rdesc_fixed[] = {
62 0x05, 0x01,         /*  Usage Page (Desktop),                   */
63 0x09, 0x04,         /*  Usage (Joystick),                       */
64 0xA1, 0x01,         /*  Collection (Application),               */
65 0xA1, 0x02,         /*      Collection (Logical),               */
66 0x95, 0x01,         /*          Report Count (1),               */
67 0x75, 0x0A,         /*          Report Size (10),               */
68 0x14,               /*          Logical Minimum (0),            */
69 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
70 0x34,               /*          Physical Minimum (0),           */
71 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
72 0x09, 0x30,         /*          Usage (X),                      */
73 0x81, 0x02,         /*          Input (Variable),               */
74 0x95, 0x0C,         /*          Report Count (12),              */
75 0x75, 0x01,         /*          Report Size (1),                */
76 0x25, 0x01,         /*          Logical Maximum (1),            */
77 0x45, 0x01,         /*          Physical Maximum (1),           */
78 0x05, 0x09,         /*          Usage (Buttons),                */
79 0x19, 0x01,         /*          Usage Minimum (1),              */
80 0x29, 0x0c,         /*          Usage Maximum (12),             */
81 0x81, 0x02,         /*          Input (Variable),               */
82 0x95, 0x02,         /*          Report Count (2),               */
83 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
84 0x09, 0x01,         /*          Usage (?: 1),                   */
85 0x81, 0x02,         /*          Input (Variable),               */
86 0x05, 0x01,         /*          Usage Page (Desktop),           */
87 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
88 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
89 0x95, 0x01,         /*          Report Count (1),               */
90 0x75, 0x08,         /*          Report Size (8),                */
91 0x81, 0x02,         /*          Input (Variable),               */
92 0x25, 0x07,         /*          Logical Maximum (7),            */
93 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
94 0x75, 0x04,         /*          Report Size (4),                */
95 0x65, 0x14,         /*          Unit (Degrees),                 */
96 0x09, 0x39,         /*          Usage (Hat Switch),             */
97 0x81, 0x42,         /*          Input (Variable, Null State),   */
98 0x75, 0x01,         /*          Report Size (1),                */
99 0x95, 0x04,         /*          Report Count (4),               */
100 0x65, 0x00,         /*          Unit (none),                    */
101 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
102 0x09, 0x01,         /*          Usage (?: 1),                   */
103 0x25, 0x01,         /*          Logical Maximum (1),            */
104 0x45, 0x01,         /*          Physical Maximum (1),           */
105 0x81, 0x02,         /*          Input (Variable),               */
106 0x05, 0x01,         /*          Usage Page (Desktop),           */
107 0x95, 0x01,         /*          Report Count (1),               */
108 0x75, 0x08,         /*          Report Size (8),                */
109 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
110 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
111 0x09, 0x31,         /*          Usage (Y),                      */
112 0x81, 0x02,         /*          Input (Variable),               */
113 0x09, 0x35,         /*          Usage (Rz),                     */
114 0x81, 0x02,         /*          Input (Variable),               */
115 0xC0,               /*      End Collection,                     */
116 0xA1, 0x02,         /*      Collection (Logical),               */
117 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
118 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
119 0x95, 0x07,         /*          Report Count (7),               */
120 0x75, 0x08,         /*          Report Size (8),                */
121 0x09, 0x03,         /*          Usage (?: 3),                   */
122 0x91, 0x02,         /*          Output (Variable),              */
123 0xC0,               /*      End Collection,                     */
124 0xC0                /*  End Collection                          */
125 };
126 
127 static __u8 dfp_rdesc_fixed[] = {
128 0x05, 0x01,         /*  Usage Page (Desktop),                   */
129 0x09, 0x04,         /*  Usage (Joystick),                       */
130 0xA1, 0x01,         /*  Collection (Application),               */
131 0xA1, 0x02,         /*      Collection (Logical),               */
132 0x95, 0x01,         /*          Report Count (1),               */
133 0x75, 0x0E,         /*          Report Size (14),               */
134 0x14,               /*          Logical Minimum (0),            */
135 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
136 0x34,               /*          Physical Minimum (0),           */
137 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
138 0x09, 0x30,         /*          Usage (X),                      */
139 0x81, 0x02,         /*          Input (Variable),               */
140 0x95, 0x0E,         /*          Report Count (14),              */
141 0x75, 0x01,         /*          Report Size (1),                */
142 0x25, 0x01,         /*          Logical Maximum (1),            */
143 0x45, 0x01,         /*          Physical Maximum (1),           */
144 0x05, 0x09,         /*          Usage Page (Button),            */
145 0x19, 0x01,         /*          Usage Minimum (01h),            */
146 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
147 0x81, 0x02,         /*          Input (Variable),               */
148 0x05, 0x01,         /*          Usage Page (Desktop),           */
149 0x95, 0x01,         /*          Report Count (1),               */
150 0x75, 0x04,         /*          Report Size (4),                */
151 0x25, 0x07,         /*          Logical Maximum (7),            */
152 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
153 0x65, 0x14,         /*          Unit (Degrees),                 */
154 0x09, 0x39,         /*          Usage (Hat Switch),             */
155 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
156 0x65, 0x00,         /*          Unit,                           */
157 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
158 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
159 0x75, 0x08,         /*          Report Size (8),                */
160 0x81, 0x01,         /*          Input (Constant),               */
161 0x09, 0x31,         /*          Usage (Y),                      */
162 0x81, 0x02,         /*          Input (Variable),               */
163 0x09, 0x35,         /*          Usage (Rz),                     */
164 0x81, 0x02,         /*          Input (Variable),               */
165 0x81, 0x01,         /*          Input (Constant),               */
166 0xC0,               /*      End Collection,                     */
167 0xA1, 0x02,         /*      Collection (Logical),               */
168 0x09, 0x02,         /*          Usage (02h),                    */
169 0x95, 0x07,         /*          Report Count (7),               */
170 0x91, 0x02,         /*          Output (Variable),              */
171 0xC0,               /*      End Collection,                     */
172 0xC0                /*  End Collection                          */
173 };
174 
175 static __u8 fv_rdesc_fixed[] = {
176 0x05, 0x01,         /*  Usage Page (Desktop),                   */
177 0x09, 0x04,         /*  Usage (Joystick),                       */
178 0xA1, 0x01,         /*  Collection (Application),               */
179 0xA1, 0x02,         /*      Collection (Logical),               */
180 0x95, 0x01,         /*          Report Count (1),               */
181 0x75, 0x0A,         /*          Report Size (10),               */
182 0x15, 0x00,         /*          Logical Minimum (0),            */
183 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
184 0x35, 0x00,         /*          Physical Minimum (0),           */
185 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
186 0x09, 0x30,         /*          Usage (X),                      */
187 0x81, 0x02,         /*          Input (Variable),               */
188 0x95, 0x0C,         /*          Report Count (12),              */
189 0x75, 0x01,         /*          Report Size (1),                */
190 0x25, 0x01,         /*          Logical Maximum (1),            */
191 0x45, 0x01,         /*          Physical Maximum (1),           */
192 0x05, 0x09,         /*          Usage Page (Button),            */
193 0x19, 0x01,         /*          Usage Minimum (01h),            */
194 0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
195 0x81, 0x02,         /*          Input (Variable),               */
196 0x95, 0x02,         /*          Report Count (2),               */
197 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
198 0x09, 0x01,         /*          Usage (01h),                    */
199 0x81, 0x02,         /*          Input (Variable),               */
200 0x09, 0x02,         /*          Usage (02h),                    */
201 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
202 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
203 0x95, 0x01,         /*          Report Count (1),               */
204 0x75, 0x08,         /*          Report Size (8),                */
205 0x81, 0x02,         /*          Input (Variable),               */
206 0x05, 0x01,         /*          Usage Page (Desktop),           */
207 0x25, 0x07,         /*          Logical Maximum (7),            */
208 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
209 0x75, 0x04,         /*          Report Size (4),                */
210 0x65, 0x14,         /*          Unit (Degrees),                 */
211 0x09, 0x39,         /*          Usage (Hat Switch),             */
212 0x81, 0x42,         /*          Input (Variable, Null State),   */
213 0x75, 0x01,         /*          Report Size (1),                */
214 0x95, 0x04,         /*          Report Count (4),               */
215 0x65, 0x00,         /*          Unit,                           */
216 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
217 0x09, 0x01,         /*          Usage (01h),                    */
218 0x25, 0x01,         /*          Logical Maximum (1),            */
219 0x45, 0x01,         /*          Physical Maximum (1),           */
220 0x81, 0x02,         /*          Input (Variable),               */
221 0x05, 0x01,         /*          Usage Page (Desktop),           */
222 0x95, 0x01,         /*          Report Count (1),               */
223 0x75, 0x08,         /*          Report Size (8),                */
224 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
225 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
226 0x09, 0x31,         /*          Usage (Y),                      */
227 0x81, 0x02,         /*          Input (Variable),               */
228 0x09, 0x32,         /*          Usage (Z),                      */
229 0x81, 0x02,         /*          Input (Variable),               */
230 0xC0,               /*      End Collection,                     */
231 0xA1, 0x02,         /*      Collection (Logical),               */
232 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
233 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
234 0x95, 0x07,         /*          Report Count (7),               */
235 0x75, 0x08,         /*          Report Size (8),                */
236 0x09, 0x03,         /*          Usage (03h),                    */
237 0x91, 0x02,         /*          Output (Variable),              */
238 0xC0,               /*      End Collection,                     */
239 0xC0                /*  End Collection                          */
240 };
241 
242 static __u8 momo_rdesc_fixed[] = {
243 0x05, 0x01,         /*  Usage Page (Desktop),               */
244 0x09, 0x04,         /*  Usage (Joystick),                   */
245 0xA1, 0x01,         /*  Collection (Application),           */
246 0xA1, 0x02,         /*      Collection (Logical),           */
247 0x95, 0x01,         /*          Report Count (1),           */
248 0x75, 0x0A,         /*          Report Size (10),           */
249 0x15, 0x00,         /*          Logical Minimum (0),        */
250 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
251 0x35, 0x00,         /*          Physical Minimum (0),       */
252 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
253 0x09, 0x30,         /*          Usage (X),                  */
254 0x81, 0x02,         /*          Input (Variable),           */
255 0x95, 0x08,         /*          Report Count (8),           */
256 0x75, 0x01,         /*          Report Size (1),            */
257 0x25, 0x01,         /*          Logical Maximum (1),        */
258 0x45, 0x01,         /*          Physical Maximum (1),       */
259 0x05, 0x09,         /*          Usage Page (Button),        */
260 0x19, 0x01,         /*          Usage Minimum (01h),        */
261 0x29, 0x08,         /*          Usage Maximum (08h),        */
262 0x81, 0x02,         /*          Input (Variable),           */
263 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
264 0x75, 0x0E,         /*          Report Size (14),           */
265 0x95, 0x01,         /*          Report Count (1),           */
266 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
267 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
268 0x09, 0x00,         /*          Usage (00h),                */
269 0x81, 0x02,         /*          Input (Variable),           */
270 0x05, 0x01,         /*          Usage Page (Desktop),       */
271 0x75, 0x08,         /*          Report Size (8),            */
272 0x09, 0x31,         /*          Usage (Y),                  */
273 0x81, 0x02,         /*          Input (Variable),           */
274 0x09, 0x32,         /*          Usage (Z),                  */
275 0x81, 0x02,         /*          Input (Variable),           */
276 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
277 0x09, 0x01,         /*          Usage (01h),                */
278 0x81, 0x02,         /*          Input (Variable),           */
279 0xC0,               /*      End Collection,                 */
280 0xA1, 0x02,         /*      Collection (Logical),           */
281 0x09, 0x02,         /*          Usage (02h),                */
282 0x95, 0x07,         /*          Report Count (7),           */
283 0x91, 0x02,         /*          Output (Variable),          */
284 0xC0,               /*      End Collection,                 */
285 0xC0                /*  End Collection                      */
286 };
287 
288 static __u8 momo2_rdesc_fixed[] = {
289 0x05, 0x01,         /*  Usage Page (Desktop),               */
290 0x09, 0x04,         /*  Usage (Joystick),                   */
291 0xA1, 0x01,         /*  Collection (Application),           */
292 0xA1, 0x02,         /*      Collection (Logical),           */
293 0x95, 0x01,         /*          Report Count (1),           */
294 0x75, 0x0A,         /*          Report Size (10),           */
295 0x15, 0x00,         /*          Logical Minimum (0),        */
296 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
297 0x35, 0x00,         /*          Physical Minimum (0),       */
298 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
299 0x09, 0x30,         /*          Usage (X),                  */
300 0x81, 0x02,         /*          Input (Variable),           */
301 0x95, 0x0A,         /*          Report Count (10),          */
302 0x75, 0x01,         /*          Report Size (1),            */
303 0x25, 0x01,         /*          Logical Maximum (1),        */
304 0x45, 0x01,         /*          Physical Maximum (1),       */
305 0x05, 0x09,         /*          Usage Page (Button),        */
306 0x19, 0x01,         /*          Usage Minimum (01h),        */
307 0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
308 0x81, 0x02,         /*          Input (Variable),           */
309 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
310 0x09, 0x00,         /*          Usage (00h),                */
311 0x95, 0x04,         /*          Report Count (4),           */
312 0x81, 0x02,         /*          Input (Variable),           */
313 0x95, 0x01,         /*          Report Count (1),           */
314 0x75, 0x08,         /*          Report Size (8),            */
315 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
316 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
317 0x09, 0x01,         /*          Usage (01h),                */
318 0x81, 0x02,         /*          Input (Variable),           */
319 0x05, 0x01,         /*          Usage Page (Desktop),       */
320 0x09, 0x31,         /*          Usage (Y),                  */
321 0x81, 0x02,         /*          Input (Variable),           */
322 0x09, 0x32,         /*          Usage (Z),                  */
323 0x81, 0x02,         /*          Input (Variable),           */
324 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
325 0x09, 0x00,         /*          Usage (00h),                */
326 0x81, 0x02,         /*          Input (Variable),           */
327 0xC0,               /*      End Collection,                 */
328 0xA1, 0x02,         /*      Collection (Logical),           */
329 0x09, 0x02,         /*          Usage (02h),                */
330 0x95, 0x07,         /*          Report Count (7),           */
331 0x91, 0x02,         /*          Output (Variable),          */
332 0xC0,               /*      End Collection,                 */
333 0xC0                /*  End Collection                      */
334 };
335 
336 static __u8 ffg_rdesc_fixed[] = {
337 0x05, 0x01,         /*  Usage Page (Desktop),               */
338 0x09, 0x04,         /*  Usage (Joystik),                    */
339 0xA1, 0x01,         /*  Collection (Application),           */
340 0xA1, 0x02,         /*      Collection (Logical),           */
341 0x95, 0x01,         /*          Report Count (1),           */
342 0x75, 0x0A,         /*          Report Size (10),           */
343 0x15, 0x00,         /*          Logical Minimum (0),        */
344 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
345 0x35, 0x00,         /*          Physical Minimum (0),       */
346 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
347 0x09, 0x30,         /*          Usage (X),                  */
348 0x81, 0x02,         /*          Input (Variable),           */
349 0x95, 0x06,         /*          Report Count (6),           */
350 0x75, 0x01,         /*          Report Size (1),            */
351 0x25, 0x01,         /*          Logical Maximum (1),        */
352 0x45, 0x01,         /*          Physical Maximum (1),       */
353 0x05, 0x09,         /*          Usage Page (Button),        */
354 0x19, 0x01,         /*          Usage Minimum (01h),        */
355 0x29, 0x06,         /*          Usage Maximum (06h),        */
356 0x81, 0x02,         /*          Input (Variable),           */
357 0x95, 0x01,         /*          Report Count (1),           */
358 0x75, 0x08,         /*          Report Size (8),            */
359 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
360 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
361 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
362 0x09, 0x01,         /*          Usage (01h),                */
363 0x81, 0x02,         /*          Input (Variable),           */
364 0x05, 0x01,         /*          Usage Page (Desktop),       */
365 0x81, 0x01,         /*          Input (Constant),           */
366 0x09, 0x31,         /*          Usage (Y),                  */
367 0x81, 0x02,         /*          Input (Variable),           */
368 0x09, 0x32,         /*          Usage (Z),                  */
369 0x81, 0x02,         /*          Input (Variable),           */
370 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
371 0x09, 0x01,         /*          Usage (01h),                */
372 0x81, 0x02,         /*          Input (Variable),           */
373 0xC0,               /*      End Collection,                 */
374 0xA1, 0x02,         /*      Collection (Logical),           */
375 0x09, 0x02,         /*          Usage (02h),                */
376 0x95, 0x07,         /*          Report Count (7),           */
377 0x91, 0x02,         /*          Output (Variable),          */
378 0xC0,               /*      End Collection,                 */
379 0xC0                /*  End Collection                      */
380 };
381 
382 static __u8 fg_rdesc_fixed[] = {
383 0x05, 0x01,         /*  Usage Page (Desktop),               */
384 0x09, 0x04,         /*  Usage (Joystik),                    */
385 0xA1, 0x01,         /*  Collection (Application),           */
386 0xA1, 0x02,         /*      Collection (Logical),           */
387 0x15, 0x00,         /*          Logical Minimum (0),        */
388 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
389 0x35, 0x00,         /*          Physical Minimum (0),       */
390 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
391 0x75, 0x08,         /*          Report Size (8),            */
392 0x95, 0x01,         /*          Report Count (1),           */
393 0x09, 0x30,         /*          Usage (X),                  */
394 0x81, 0x02,         /*          Input (Variable),           */
395 0xA4,               /*  Push,                               */
396 0x25, 0x01,         /*          Logical Maximum (1),        */
397 0x45, 0x01,         /*          Physical Maximum (1),       */
398 0x75, 0x01,         /*          Report Size (1),            */
399 0x95, 0x02,         /*          Report Count (2),           */
400 0x81, 0x01,         /*          Input (Constant),           */
401 0x95, 0x06,         /*          Report Count (6),           */
402 0x05, 0x09,         /*          Usage Page (Button),        */
403 0x19, 0x01,         /*          Usage Minimum (01h),        */
404 0x29, 0x06,         /*          Usage Maximum (06h),        */
405 0x81, 0x02,         /*          Input (Variable),           */
406 0x05, 0x01,         /*          Usage Page (Desktop),       */
407 0xB4,               /*  Pop,                                */
408 0x81, 0x02,         /*          Input (Constant),           */
409 0x09, 0x31,         /*          Usage (Y),                  */
410 0x81, 0x02,         /*          Input (Variable),           */
411 0x09, 0x32,         /*          Usage (Z),                  */
412 0x81, 0x02,         /*          Input (Variable),           */
413 0xC0,               /*      End Collection,                 */
414 0xA1, 0x02,         /*      Collection (Logical),           */
415 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
416 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
417 0x75, 0x08,         /*          Report Size (8),            */
418 0x95, 0x04,         /*          Report Count (4),           */
419 0x09, 0x02,         /*          Usage (02h),                */
420 0xB1, 0x02,         /*          Feature (Variable),         */
421 0xC0,               /*      End Collection,                 */
422 0xC0                /*  End Collection,                     */
423 };
424 
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  */
430 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
431 		unsigned int *rsize)
432 {
433 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
434 
435 	if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
436 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
437 		hid_info(hdev,
438 			 "fixing up Logitech keyboard report descriptor\n");
439 		rdesc[84] = rdesc[89] = 0x4d;
440 		rdesc[85] = rdesc[90] = 0x10;
441 	}
442 	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
443 			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
444 			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
445 		hid_info(hdev,
446 			 "fixing up rel/abs in Logitech report descriptor\n");
447 		rdesc[33] = rdesc[50] = 0x02;
448 	}
449 
450 	switch (hdev->product) {
451 
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 
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 
474 	/* Several wheels report as this id when operating in emulation mode. */
475 	case USB_DEVICE_ID_LOGITECH_WHEEL:
476 		if (*rsize == DF_RDESC_ORIG_SIZE) {
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 
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 
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 
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 
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;
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;
530 	}
531 
532 	return rdesc;
533 }
534 
535 #define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
536 		EV_KEY, (c))
537 
538 static 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 
571 static 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 
587 static 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;
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;
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;
613 	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
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;
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;
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 
648 static 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 	};
664 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
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 
671 	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
672 			lg_dinovo_mapping(hi, usage, bit, max))
673 		return 1;
674 
675 	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
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) {
685 		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
686 				(hid == 7 || hid == 8))
687 			return -1;
688 	} else {
689 		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
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 
701 static 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 {
705 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
706 
707 	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
708 			(field->flags & HID_MAIN_ITEM_RELATIVE))
709 		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
710 
711 	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
712 			 usage->type == EV_REL || usage->type == EV_ABS))
713 		clear_bit(usage->code, *bit);
714 
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) {
720 		case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
721 		case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
722 		case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
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:
731 		case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
732 			field->application = HID_GD_MULTIAXIS;
733 			break;
734 		default:
735 			break;
736 		}
737 	}
738 
739 	return 0;
740 }
741 
742 static int lg_event(struct hid_device *hdev, struct hid_field *field,
743 		struct hid_usage *usage, __s32 value)
744 {
745 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
746 
747 	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
748 		input_event(field->hidinput->input, usage->type, usage->code,
749 				-value);
750 		return 1;
751 	}
752 	if (drv_data->quirks & LG_FF4) {
753 		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
754 	}
755 
756 	return 0;
757 }
758 
759 static 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 
770 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
771 {
772 	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
773 	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
774 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
775 	struct lg_drv_data *drv_data;
776 	int ret;
777 
778 	/* G29 only work with the 1st interface */
779 	if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
780 	    (iface_num != 0)) {
781 		dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
782 		return -ENODEV;
783 	}
784 
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;
791 
792 	hid_set_drvdata(hdev, (void *)drv_data);
793 
794 	if (drv_data->quirks & LG_NOGET)
795 		hdev->quirks |= HID_QUIRK_NOGET;
796 
797 	ret = hid_parse(hdev);
798 	if (ret) {
799 		hid_err(hdev, "parse failed\n");
800 		goto err_free;
801 	}
802 
803 	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
804 		connect_mask &= ~HID_CONNECT_FF;
805 
806 	ret = hid_hw_start(hdev, connect_mask);
807 	if (ret) {
808 		hid_err(hdev, "hw start failed\n");
809 		goto err_free;
810 	}
811 
812 	/* Setup wireless link with Logitech Wii wheel */
813 	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
814 		static const unsigned char cbuf[] = {
815 			0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
816 		};
817 		u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
818 
819 		if (!buf) {
820 			ret = -ENOMEM;
821 			goto err_stop;
822 		}
823 
824 		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
825 					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
826 		if (ret >= 0) {
827 			/* insert a little delay of 10 jiffies ~ 40ms */
828 			wait_queue_head_t wait;
829 			init_waitqueue_head (&wait);
830 			wait_event_interruptible_timeout(wait, 0,
831 							 msecs_to_jiffies(40));
832 
833 			/* Select random Address */
834 			buf[1] = 0xB2;
835 			get_random_bytes(&buf[2], 2);
836 
837 			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
838 					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
839 		}
840 		kfree(buf);
841 	}
842 
843 	if (drv_data->quirks & LG_FF)
844 		ret = lgff_init(hdev);
845 	else if (drv_data->quirks & LG_FF2)
846 		ret = lg2ff_init(hdev);
847 	else if (drv_data->quirks & LG_FF3)
848 		ret = lg3ff_init(hdev);
849 	else if (drv_data->quirks & LG_FF4)
850 		ret = lg4ff_init(hdev);
851 
852 	if (ret)
853 		goto err_stop;
854 
855 	return 0;
856 
857 err_stop:
858 	hid_hw_stop(hdev);
859 err_free:
860 	kfree(drv_data);
861 	return ret;
862 }
863 
864 static void lg_remove(struct hid_device *hdev)
865 {
866 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
867 	if (drv_data->quirks & LG_FF4)
868 		lg4ff_deinit(hdev);
869 	hid_hw_stop(hdev);
870 	kfree(drv_data);
871 }
872 
873 static const struct hid_device_id lg_devices[] = {
874 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
875 		.driver_data = LG_RDESC | LG_WIRELESS },
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 
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 
892 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
893 		.driver_data = LG_NOGET },
894 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
895 		.driver_data = LG_NOGET },
896 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
897 		.driver_data = LG_NOGET | LG_FF4 },
898 
899 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
900 		.driver_data = LG_FF2 },
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 },
905 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
906 		.driver_data = LG_FF4 },
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),
912 		.driver_data = LG_NOGET | LG_FF4 },
913 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
914 		.driver_data = LG_FF4 },
915 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
916 		.driver_data = LG_FF2 },
917 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
918 		.driver_data = LG_FF4 },
919 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
920 		.driver_data = LG_FF4 },
921 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
922 		.driver_data = LG_FF4 },
923 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
924 		.driver_data = LG_NOGET | LG_FF4 },
925 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
926 		.driver_data = LG_FF4 },
927 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
928 		.driver_data = LG_NOGET },
929 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
930 		.driver_data = LG_NOGET | LG_FF4 },
931 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
932 		.driver_data = LG_NOGET | LG_FF2 },
933 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
934 		.driver_data = LG_FF3 },
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 },
939 	{ }
940 };
941 
942 MODULE_DEVICE_TABLE(hid, lg_devices);
943 
944 static 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,
951 	.raw_event = lg_raw_event,
952 	.probe = lg_probe,
953 	.remove = lg_remove,
954 };
955 module_hid_driver(lg_driver);
956 
957 #ifdef CONFIG_LOGIWHEELS_FF
958 int lg4ff_no_autoswitch = 0;
959 module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
960 MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
961 #endif
962 
963 MODULE_LICENSE("GPL");
964