Version:  2.0.40 2.2.26 2.4.37 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9

Linux/drivers/hid/hid-lg.c

  1 /*
  2  *  HID driver for some logitech "special" devices
  3  *
  4  *  Copyright (c) 1999 Andreas Gal
  5  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  6  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  7  *  Copyright (c) 2006-2007 Jiri Kosina
  8  *  Copyright (c) 2008 Jiri Slaby
  9  *  Copyright (c) 2010 Hendrik Iben
 10  */
 11 
 12 /*
 13  * This program is free software; you can redistribute it and/or modify it
 14  * under the terms of the GNU General Public License as published by the Free
 15  * Software Foundation; either version 2 of the License, or (at your option)
 16  * any later version.
 17  */
 18 
 19 #include <linux/device.h>
 20 #include <linux/hid.h>
 21 #include <linux/module.h>
 22 #include <linux/random.h>
 23 #include <linux/sched.h>
 24 #include <linux/usb.h>
 25 #include <linux/wait.h>
 26 
 27 #include "usbhid/usbhid.h"
 28 #include "hid-ids.h"
 29 #include "hid-lg.h"
 30 #include "hid-lg4ff.h"
 31 
 32 #define LG_RDESC                0x001
 33 #define LG_BAD_RELATIVE_KEYS    0x002
 34 #define LG_DUPLICATE_USAGES     0x004
 35 #define LG_EXPANDED_KEYMAP      0x010
 36 #define LG_IGNORE_DOUBLED_WHEEL 0x020
 37 #define LG_WIRELESS             0x040
 38 #define LG_INVERT_HWHEEL        0x080
 39 #define LG_NOGET                0x100
 40 #define LG_FF                   0x200
 41 #define LG_FF2                  0x400
 42 #define LG_RDESC_REL_ABS        0x800
 43 #define LG_FF3                  0x1000
 44 #define LG_FF4                  0x2000
 45 
 46 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
 47 #define DF_RDESC_ORIG_SIZE      130
 48 #define DFP_RDESC_ORIG_SIZE     97
 49 #define FV_RDESC_ORIG_SIZE      130
 50 #define MOMO_RDESC_ORIG_SIZE    87
 51 #define MOMO2_RDESC_ORIG_SIZE   87
 52 #define FFG_RDESC_ORIG_SIZE     85
 53 
 54 /* Fixed report descriptors for Logitech Driving Force (and Pro)
 55  * wheel controllers
 56  *
 57  * The original descriptors hide the separate throttle and brake axes in
 58  * a custom vendor usage page, providing only a combined value as
 59  * GenericDesktop.Y.
 60  * These descriptors remove the combined Y axis and instead report
 61  * separate throttle (Y) and brake (RZ).
 62  */
 63 static __u8 df_rdesc_fixed[] = {
 64 0x05, 0x01,         /*  Usage Page (Desktop),                   */
 65 0x09, 0x04,         /*  Usage (Joystick),                       */
 66 0xA1, 0x01,         /*  Collection (Application),               */
 67 0xA1, 0x02,         /*      Collection (Logical),               */
 68 0x95, 0x01,         /*          Report Count (1),               */
 69 0x75, 0x0A,         /*          Report Size (10),               */
 70 0x14,               /*          Logical Minimum (0),            */
 71 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
 72 0x34,               /*          Physical Minimum (0),           */
 73 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
 74 0x09, 0x30,         /*          Usage (X),                      */
 75 0x81, 0x02,         /*          Input (Variable),               */
 76 0x95, 0x0C,         /*          Report Count (12),              */
 77 0x75, 0x01,         /*          Report Size (1),                */
 78 0x25, 0x01,         /*          Logical Maximum (1),            */
 79 0x45, 0x01,         /*          Physical Maximum (1),           */
 80 0x05, 0x09,         /*          Usage (Buttons),                */
 81 0x19, 0x01,         /*          Usage Minimum (1),              */
 82 0x29, 0x0c,         /*          Usage Maximum (12),             */
 83 0x81, 0x02,         /*          Input (Variable),               */
 84 0x95, 0x02,         /*          Report Count (2),               */
 85 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
 86 0x09, 0x01,         /*          Usage (?: 1),                   */
 87 0x81, 0x02,         /*          Input (Variable),               */
 88 0x05, 0x01,         /*          Usage Page (Desktop),           */
 89 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 90 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 91 0x95, 0x01,         /*          Report Count (1),               */
 92 0x75, 0x08,         /*          Report Size (8),                */
 93 0x81, 0x02,         /*          Input (Variable),               */
 94 0x25, 0x07,         /*          Logical Maximum (7),            */
 95 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 96 0x75, 0x04,         /*          Report Size (4),                */
 97 0x65, 0x14,         /*          Unit (Degrees),                 */
 98 0x09, 0x39,         /*          Usage (Hat Switch),             */
 99 0x81, 0x42,         /*          Input (Variable, Null State),   */
100 0x75, 0x01,         /*          Report Size (1),                */
101 0x95, 0x04,         /*          Report Count (4),               */
102 0x65, 0x00,         /*          Unit (none),                    */
103 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
104 0x09, 0x01,         /*          Usage (?: 1),                   */
105 0x25, 0x01,         /*          Logical Maximum (1),            */
106 0x45, 0x01,         /*          Physical Maximum (1),           */
107 0x81, 0x02,         /*          Input (Variable),               */
108 0x05, 0x01,         /*          Usage Page (Desktop),           */
109 0x95, 0x01,         /*          Report Count (1),               */
110 0x75, 0x08,         /*          Report Size (8),                */
111 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
112 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
113 0x09, 0x31,         /*          Usage (Y),                      */
114 0x81, 0x02,         /*          Input (Variable),               */
115 0x09, 0x35,         /*          Usage (Rz),                     */
116 0x81, 0x02,         /*          Input (Variable),               */
117 0xC0,               /*      End Collection,                     */
118 0xA1, 0x02,         /*      Collection (Logical),               */
119 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
120 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
121 0x95, 0x07,         /*          Report Count (7),               */
122 0x75, 0x08,         /*          Report Size (8),                */
123 0x09, 0x03,         /*          Usage (?: 3),                   */
124 0x91, 0x02,         /*          Output (Variable),              */
125 0xC0,               /*      End Collection,                     */
126 0xC0                /*  End Collection                          */
127 };
128 
129 static __u8 dfp_rdesc_fixed[] = {
130 0x05, 0x01,         /*  Usage Page (Desktop),                   */
131 0x09, 0x04,         /*  Usage (Joystick),                       */
132 0xA1, 0x01,         /*  Collection (Application),               */
133 0xA1, 0x02,         /*      Collection (Logical),               */
134 0x95, 0x01,         /*          Report Count (1),               */
135 0x75, 0x0E,         /*          Report Size (14),               */
136 0x14,               /*          Logical Minimum (0),            */
137 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
138 0x34,               /*          Physical Minimum (0),           */
139 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
140 0x09, 0x30,         /*          Usage (X),                      */
141 0x81, 0x02,         /*          Input (Variable),               */
142 0x95, 0x0E,         /*          Report Count (14),              */
143 0x75, 0x01,         /*          Report Size (1),                */
144 0x25, 0x01,         /*          Logical Maximum (1),            */
145 0x45, 0x01,         /*          Physical Maximum (1),           */
146 0x05, 0x09,         /*          Usage Page (Button),            */
147 0x19, 0x01,         /*          Usage Minimum (01h),            */
148 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
149 0x81, 0x02,         /*          Input (Variable),               */
150 0x05, 0x01,         /*          Usage Page (Desktop),           */
151 0x95, 0x01,         /*          Report Count (1),               */
152 0x75, 0x04,         /*          Report Size (4),                */
153 0x25, 0x07,         /*          Logical Maximum (7),            */
154 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
155 0x65, 0x14,         /*          Unit (Degrees),                 */
156 0x09, 0x39,         /*          Usage (Hat Switch),             */
157 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
158 0x65, 0x00,         /*          Unit,                           */
159 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
160 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
161 0x75, 0x08,         /*          Report Size (8),                */
162 0x81, 0x01,         /*          Input (Constant),               */
163 0x09, 0x31,         /*          Usage (Y),                      */
164 0x81, 0x02,         /*          Input (Variable),               */
165 0x09, 0x35,         /*          Usage (Rz),                     */
166 0x81, 0x02,         /*          Input (Variable),               */
167 0x81, 0x01,         /*          Input (Constant),               */
168 0xC0,               /*      End Collection,                     */
169 0xA1, 0x02,         /*      Collection (Logical),               */
170 0x09, 0x02,         /*          Usage (02h),                    */
171 0x95, 0x07,         /*          Report Count (7),               */
172 0x91, 0x02,         /*          Output (Variable),              */
173 0xC0,               /*      End Collection,                     */
174 0xC0                /*  End Collection                          */
175 };
176 
177 static __u8 fv_rdesc_fixed[] = {
178 0x05, 0x01,         /*  Usage Page (Desktop),                   */
179 0x09, 0x04,         /*  Usage (Joystick),                       */
180 0xA1, 0x01,         /*  Collection (Application),               */
181 0xA1, 0x02,         /*      Collection (Logical),               */
182 0x95, 0x01,         /*          Report Count (1),               */
183 0x75, 0x0A,         /*          Report Size (10),               */
184 0x15, 0x00,         /*          Logical Minimum (0),            */
185 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
186 0x35, 0x00,         /*          Physical Minimum (0),           */
187 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
188 0x09, 0x30,         /*          Usage (X),                      */
189 0x81, 0x02,         /*          Input (Variable),               */
190 0x95, 0x0C,         /*          Report Count (12),              */
191 0x75, 0x01,         /*          Report Size (1),                */
192 0x25, 0x01,         /*          Logical Maximum (1),            */
193 0x45, 0x01,         /*          Physical Maximum (1),           */
194 0x05, 0x09,         /*          Usage Page (Button),            */
195 0x19, 0x01,         /*          Usage Minimum (01h),            */
196 0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
197 0x81, 0x02,         /*          Input (Variable),               */
198 0x95, 0x02,         /*          Report Count (2),               */
199 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
200 0x09, 0x01,         /*          Usage (01h),                    */
201 0x81, 0x02,         /*          Input (Variable),               */
202 0x09, 0x02,         /*          Usage (02h),                    */
203 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
204 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
205 0x95, 0x01,         /*          Report Count (1),               */
206 0x75, 0x08,         /*          Report Size (8),                */
207 0x81, 0x02,         /*          Input (Variable),               */
208 0x05, 0x01,         /*          Usage Page (Desktop),           */
209 0x25, 0x07,         /*          Logical Maximum (7),            */
210 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
211 0x75, 0x04,         /*          Report Size (4),                */
212 0x65, 0x14,         /*          Unit (Degrees),                 */
213 0x09, 0x39,         /*          Usage (Hat Switch),             */
214 0x81, 0x42,         /*          Input (Variable, Null State),   */
215 0x75, 0x01,         /*          Report Size (1),                */
216 0x95, 0x04,         /*          Report Count (4),               */
217 0x65, 0x00,         /*          Unit,                           */
218 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
219 0x09, 0x01,         /*          Usage (01h),                    */
220 0x25, 0x01,         /*          Logical Maximum (1),            */
221 0x45, 0x01,         /*          Physical Maximum (1),           */
222 0x81, 0x02,         /*          Input (Variable),               */
223 0x05, 0x01,         /*          Usage Page (Desktop),           */
224 0x95, 0x01,         /*          Report Count (1),               */
225 0x75, 0x08,         /*          Report Size (8),                */
226 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
227 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
228 0x09, 0x31,         /*          Usage (Y),                      */
229 0x81, 0x02,         /*          Input (Variable),               */
230 0x09, 0x32,         /*          Usage (Z),                      */
231 0x81, 0x02,         /*          Input (Variable),               */
232 0xC0,               /*      End Collection,                     */
233 0xA1, 0x02,         /*      Collection (Logical),               */
234 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
235 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
236 0x95, 0x07,         /*          Report Count (7),               */
237 0x75, 0x08,         /*          Report Size (8),                */
238 0x09, 0x03,         /*          Usage (03h),                    */
239 0x91, 0x02,         /*          Output (Variable),              */
240 0xC0,               /*      End Collection,                     */
241 0xC0                /*  End Collection                          */
242 };
243 
244 static __u8 momo_rdesc_fixed[] = {
245 0x05, 0x01,         /*  Usage Page (Desktop),               */
246 0x09, 0x04,         /*  Usage (Joystick),                   */
247 0xA1, 0x01,         /*  Collection (Application),           */
248 0xA1, 0x02,         /*      Collection (Logical),           */
249 0x95, 0x01,         /*          Report Count (1),           */
250 0x75, 0x0A,         /*          Report Size (10),           */
251 0x15, 0x00,         /*          Logical Minimum (0),        */
252 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
253 0x35, 0x00,         /*          Physical Minimum (0),       */
254 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
255 0x09, 0x30,         /*          Usage (X),                  */
256 0x81, 0x02,         /*          Input (Variable),           */
257 0x95, 0x08,         /*          Report Count (8),           */
258 0x75, 0x01,         /*          Report Size (1),            */
259 0x25, 0x01,         /*          Logical Maximum (1),        */
260 0x45, 0x01,         /*          Physical Maximum (1),       */
261 0x05, 0x09,         /*          Usage Page (Button),        */
262 0x19, 0x01,         /*          Usage Minimum (01h),        */
263 0x29, 0x08,         /*          Usage Maximum (08h),        */
264 0x81, 0x02,         /*          Input (Variable),           */
265 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
266 0x75, 0x0E,         /*          Report Size (14),           */
267 0x95, 0x01,         /*          Report Count (1),           */
268 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
269 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
270 0x09, 0x00,         /*          Usage (00h),                */
271 0x81, 0x02,         /*          Input (Variable),           */
272 0x05, 0x01,         /*          Usage Page (Desktop),       */
273 0x75, 0x08,         /*          Report Size (8),            */
274 0x09, 0x31,         /*          Usage (Y),                  */
275 0x81, 0x02,         /*          Input (Variable),           */
276 0x09, 0x32,         /*          Usage (Z),                  */
277 0x81, 0x02,         /*          Input (Variable),           */
278 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
279 0x09, 0x01,         /*          Usage (01h),                */
280 0x81, 0x02,         /*          Input (Variable),           */
281 0xC0,               /*      End Collection,                 */
282 0xA1, 0x02,         /*      Collection (Logical),           */
283 0x09, 0x02,         /*          Usage (02h),                */
284 0x95, 0x07,         /*          Report Count (7),           */
285 0x91, 0x02,         /*          Output (Variable),          */
286 0xC0,               /*      End Collection,                 */
287 0xC0                /*  End Collection                      */
288 };
289 
290 static __u8 momo2_rdesc_fixed[] = {
291 0x05, 0x01,         /*  Usage Page (Desktop),               */
292 0x09, 0x04,         /*  Usage (Joystick),                   */
293 0xA1, 0x01,         /*  Collection (Application),           */
294 0xA1, 0x02,         /*      Collection (Logical),           */
295 0x95, 0x01,         /*          Report Count (1),           */
296 0x75, 0x0A,         /*          Report Size (10),           */
297 0x15, 0x00,         /*          Logical Minimum (0),        */
298 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
299 0x35, 0x00,         /*          Physical Minimum (0),       */
300 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
301 0x09, 0x30,         /*          Usage (X),                  */
302 0x81, 0x02,         /*          Input (Variable),           */
303 0x95, 0x0A,         /*          Report Count (10),          */
304 0x75, 0x01,         /*          Report Size (1),            */
305 0x25, 0x01,         /*          Logical Maximum (1),        */
306 0x45, 0x01,         /*          Physical Maximum (1),       */
307 0x05, 0x09,         /*          Usage Page (Button),        */
308 0x19, 0x01,         /*          Usage Minimum (01h),        */
309 0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
310 0x81, 0x02,         /*          Input (Variable),           */
311 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
312 0x09, 0x00,         /*          Usage (00h),                */
313 0x95, 0x04,         /*          Report Count (4),           */
314 0x81, 0x02,         /*          Input (Variable),           */
315 0x95, 0x01,         /*          Report Count (1),           */
316 0x75, 0x08,         /*          Report Size (8),            */
317 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
318 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
319 0x09, 0x01,         /*          Usage (01h),                */
320 0x81, 0x02,         /*          Input (Variable),           */
321 0x05, 0x01,         /*          Usage Page (Desktop),       */
322 0x09, 0x31,         /*          Usage (Y),                  */
323 0x81, 0x02,         /*          Input (Variable),           */
324 0x09, 0x32,         /*          Usage (Z),                  */
325 0x81, 0x02,         /*          Input (Variable),           */
326 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
327 0x09, 0x00,         /*          Usage (00h),                */
328 0x81, 0x02,         /*          Input (Variable),           */
329 0xC0,               /*      End Collection,                 */
330 0xA1, 0x02,         /*      Collection (Logical),           */
331 0x09, 0x02,         /*          Usage (02h),                */
332 0x95, 0x07,         /*          Report Count (7),           */
333 0x91, 0x02,         /*          Output (Variable),          */
334 0xC0,               /*      End Collection,                 */
335 0xC0                /*  End Collection                      */
336 };
337 
338 static __u8 ffg_rdesc_fixed[] = {
339 0x05, 0x01,         /*  Usage Page (Desktop),               */
340 0x09, 0x04,         /*  Usage (Joystik),                    */
341 0xA1, 0x01,         /*  Collection (Application),           */
342 0xA1, 0x02,         /*      Collection (Logical),           */
343 0x95, 0x01,         /*          Report Count (1),           */
344 0x75, 0x0A,         /*          Report Size (10),           */
345 0x15, 0x00,         /*          Logical Minimum (0),        */
346 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
347 0x35, 0x00,         /*          Physical Minimum (0),       */
348 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
349 0x09, 0x30,         /*          Usage (X),                  */
350 0x81, 0x02,         /*          Input (Variable),           */
351 0x95, 0x06,         /*          Report Count (6),           */
352 0x75, 0x01,         /*          Report Size (1),            */
353 0x25, 0x01,         /*          Logical Maximum (1),        */
354 0x45, 0x01,         /*          Physical Maximum (1),       */
355 0x05, 0x09,         /*          Usage Page (Button),        */
356 0x19, 0x01,         /*          Usage Minimum (01h),        */
357 0x29, 0x06,         /*          Usage Maximum (06h),        */
358 0x81, 0x02,         /*          Input (Variable),           */
359 0x95, 0x01,         /*          Report Count (1),           */
360 0x75, 0x08,         /*          Report Size (8),            */
361 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
362 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
363 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
364 0x09, 0x01,         /*          Usage (01h),                */
365 0x81, 0x02,         /*          Input (Variable),           */
366 0x05, 0x01,         /*          Usage Page (Desktop),       */
367 0x81, 0x01,         /*          Input (Constant),           */
368 0x09, 0x31,         /*          Usage (Y),                  */
369 0x81, 0x02,         /*          Input (Variable),           */
370 0x09, 0x32,         /*          Usage (Z),                  */
371 0x81, 0x02,         /*          Input (Variable),           */
372 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
373 0x09, 0x01,         /*          Usage (01h),                */
374 0x81, 0x02,         /*          Input (Variable),           */
375 0xC0,               /*      End Collection,                 */
376 0xA1, 0x02,         /*      Collection (Logical),           */
377 0x09, 0x02,         /*          Usage (02h),                */
378 0x95, 0x07,         /*          Report Count (7),           */
379 0x91, 0x02,         /*          Output (Variable),          */
380 0xC0,               /*      End Collection,                 */
381 0xC0                /*  End Collection                      */
382 };
383 
384 /*
385  * Certain Logitech keyboards send in report #3 keys which are far
386  * above the logical maximum described in descriptor. This extends
387  * the original value of 0x28c of logical maximum to 0x104d
388  */
389 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
390                 unsigned int *rsize)
391 {
392         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
393 
394         if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
395                         rdesc[84] == 0x8c && rdesc[85] == 0x02) {
396                 hid_info(hdev,
397                          "fixing up Logitech keyboard report descriptor\n");
398                 rdesc[84] = rdesc[89] = 0x4d;
399                 rdesc[85] = rdesc[90] = 0x10;
400         }
401         if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
402                         rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
403                         rdesc[49] == 0x81 && rdesc[50] == 0x06) {
404                 hid_info(hdev,
405                          "fixing up rel/abs in Logitech report descriptor\n");
406                 rdesc[33] = rdesc[50] = 0x02;
407         }
408 
409         switch (hdev->product) {
410 
411         case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
412                 if (*rsize == FFG_RDESC_ORIG_SIZE) {
413                         hid_info(hdev,
414                                 "fixing up Logitech Wingman Formula Force GP report descriptor\n");
415                         rdesc = ffg_rdesc_fixed;
416                         *rsize = sizeof(ffg_rdesc_fixed);
417                 }
418                 break;
419 
420         /* Several wheels report as this id when operating in emulation mode. */
421         case USB_DEVICE_ID_LOGITECH_WHEEL:
422                 if (*rsize == DF_RDESC_ORIG_SIZE) {
423                         hid_info(hdev,
424                                 "fixing up Logitech Driving Force report descriptor\n");
425                         rdesc = df_rdesc_fixed;
426                         *rsize = sizeof(df_rdesc_fixed);
427                 }
428                 break;
429 
430         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
431                 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
432                         hid_info(hdev,
433                                 "fixing up Logitech Momo Force (Red) report descriptor\n");
434                         rdesc = momo_rdesc_fixed;
435                         *rsize = sizeof(momo_rdesc_fixed);
436                 }
437                 break;
438 
439         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
440                 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
441                         hid_info(hdev,
442                                 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
443                         rdesc = momo2_rdesc_fixed;
444                         *rsize = sizeof(momo2_rdesc_fixed);
445                 }
446                 break;
447 
448         case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
449                 if (*rsize == FV_RDESC_ORIG_SIZE) {
450                         hid_info(hdev,
451                                 "fixing up Logitech Formula Vibration report descriptor\n");
452                         rdesc = fv_rdesc_fixed;
453                         *rsize = sizeof(fv_rdesc_fixed);
454                 }
455                 break;
456 
457         case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
458                 if (*rsize == DFP_RDESC_ORIG_SIZE) {
459                         hid_info(hdev,
460                                 "fixing up Logitech Driving Force Pro report descriptor\n");
461                         rdesc = dfp_rdesc_fixed;
462                         *rsize = sizeof(dfp_rdesc_fixed);
463                 }
464                 break;
465 
466         case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
467                 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
468                                 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
469                         hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
470                         rdesc[41] = 0x05;
471                         rdesc[42] = 0x09;
472                         rdesc[47] = 0x95;
473                         rdesc[48] = 0x0B;
474                 }
475                 break;
476         }
477 
478         return rdesc;
479 }
480 
481 #define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
482                 EV_KEY, (c))
483 
484 static int lg_ultrax_remote_mapping(struct hid_input *hi,
485                 struct hid_usage *usage, unsigned long **bit, int *max)
486 {
487         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
488                 return 0;
489 
490         set_bit(EV_REP, hi->input->evbit);
491         switch (usage->hid & HID_USAGE) {
492         /* Reported on Logitech Ultra X Media Remote */
493         case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
494         case 0x00d: lg_map_key_clear(KEY_HOME);         break;
495         case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
496         case 0x025: lg_map_key_clear(KEY_TV);           break;
497         case 0x026: lg_map_key_clear(KEY_MENU);         break;
498         case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
499         case 0x032: lg_map_key_clear(KEY_TEXT);         break;
500         case 0x033: lg_map_key_clear(KEY_LAST);         break;
501         case 0x047: lg_map_key_clear(KEY_MP3);          break;
502         case 0x048: lg_map_key_clear(KEY_DVD);          break;
503         case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
504         case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
505         case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
506         case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
507         case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
508         case 0x051: lg_map_key_clear(KEY_RED);          break;
509         case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
510 
511         default:
512                 return 0;
513         }
514         return 1;
515 }
516 
517 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
518                 unsigned long **bit, int *max)
519 {
520         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
521                 return 0;
522 
523         switch (usage->hid & HID_USAGE) {
524 
525         case 0x00d: lg_map_key_clear(KEY_MEDIA);        break;
526         default:
527                 return 0;
528 
529         }
530         return 1;
531 }
532 
533 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
534                 unsigned long **bit, int *max)
535 {
536         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
537                 return 0;
538 
539         switch (usage->hid & HID_USAGE) {
540         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
541         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
542         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
543         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
544         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
545         /* The following two entries are Playlist 1 and 2 on the MX3200 */
546         case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
547         case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
548         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
549         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
550         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
551         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
552         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
553         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
554         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
555         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
556         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
557         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
558         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
559         case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
560         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
561         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
562         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
563         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
564         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
565         /* this one is marked as 'Rotate' */
566         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
567         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
568         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
569         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
570         case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
571         /* The following two are 'Start/answer call' and 'End/reject call'
572            on the MX3200 */
573         case 0x1031: lg_map_key_clear(KEY_OK);                  break;
574         case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
575         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
576         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
577         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
578         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
579         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
580         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
581         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
582         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
583         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
584         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
585         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
586         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
587 
588         default:
589                 return 0;
590         }
591         return 1;
592 }
593 
594 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
595                 struct hid_field *field, struct hid_usage *usage,
596                 unsigned long **bit, int *max)
597 {
598         /* extended mapping for certain Logitech hardware (Logitech cordless
599            desktop LX500) */
600         static const u8 e_keymap[] = {
601                   0,216,  0,213,175,156,  0,  0,  0,  0,
602                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
603                 174,167,152,161,112,  0,  0,  0,154,  0,
604                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
605                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
606                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
607                   0,  0,  0,  0,  0,183,184,185,186,187,
608                 188,189,190,191,192,193,194,  0,  0,  0
609         };
610         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
611         unsigned int hid = usage->hid;
612 
613         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
614                         lg_ultrax_remote_mapping(hi, usage, bit, max))
615                 return 1;
616 
617         if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
618                         lg_dinovo_mapping(hi, usage, bit, max))
619                 return 1;
620 
621         if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
622                 return 1;
623 
624         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
625                 return 0;
626 
627         hid &= HID_USAGE;
628 
629         /* Special handling for Logitech Cordless Desktop */
630         if (field->application == HID_GD_MOUSE) {
631                 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
632                                 (hid == 7 || hid == 8))
633                         return -1;
634         } else {
635                 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
636                                 hid < ARRAY_SIZE(e_keymap) &&
637                                 e_keymap[hid] != 0) {
638                         hid_map_usage(hi, usage, bit, max, EV_KEY,
639                                         e_keymap[hid]);
640                         return 1;
641                 }
642         }
643 
644         return 0;
645 }
646 
647 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
648                 struct hid_field *field, struct hid_usage *usage,
649                 unsigned long **bit, int *max)
650 {
651         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
652 
653         if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
654                         (field->flags & HID_MAIN_ITEM_RELATIVE))
655                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
656 
657         if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
658                          usage->type == EV_REL || usage->type == EV_ABS))
659                 clear_bit(usage->code, *bit);
660 
661         /* Ensure that Logitech wheels are not given a default fuzz/flat value */
662         if (usage->type == EV_ABS && (usage->code == ABS_X ||
663                         usage->code == ABS_Y || usage->code == ABS_Z ||
664                         usage->code == ABS_RZ)) {
665                 switch (hdev->product) {
666                 case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
667                 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
668                 case USB_DEVICE_ID_LOGITECH_WHEEL:
669                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
670                 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
671                 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
672                 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
673                 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
674                 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
675                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
676                 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
677                         field->application = HID_GD_MULTIAXIS;
678                         break;
679                 default:
680                         break;
681                 }
682         }
683 
684         return 0;
685 }
686 
687 static int lg_event(struct hid_device *hdev, struct hid_field *field,
688                 struct hid_usage *usage, __s32 value)
689 {
690         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
691 
692         if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
693                 input_event(field->hidinput->input, usage->type, usage->code,
694                                 -value);
695                 return 1;
696         }
697         if (drv_data->quirks & LG_FF4) {
698                 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
699         }
700 
701         return 0;
702 }
703 
704 static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
705                 u8 *rd, int size)
706 {
707         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
708 
709         if (drv_data->quirks & LG_FF4)
710                 return lg4ff_raw_event(hdev, report, rd, size, drv_data);
711 
712         return 0;
713 }
714 
715 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
716 {
717         struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
718         __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
719         unsigned int connect_mask = HID_CONNECT_DEFAULT;
720         struct lg_drv_data *drv_data;
721         int ret;
722 
723         /* G29 only work with the 1st interface */
724         if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
725             (iface_num != 0)) {
726                 dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
727                 return -ENODEV;
728         }
729 
730         drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
731         if (!drv_data) {
732                 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
733                 return -ENOMEM;
734         }
735         drv_data->quirks = id->driver_data;
736 
737         hid_set_drvdata(hdev, (void *)drv_data);
738 
739         if (drv_data->quirks & LG_NOGET)
740                 hdev->quirks |= HID_QUIRK_NOGET;
741 
742         ret = hid_parse(hdev);
743         if (ret) {
744                 hid_err(hdev, "parse failed\n");
745                 goto err_free;
746         }
747 
748         if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
749                 connect_mask &= ~HID_CONNECT_FF;
750 
751         ret = hid_hw_start(hdev, connect_mask);
752         if (ret) {
753                 hid_err(hdev, "hw start failed\n");
754                 goto err_free;
755         }
756 
757         /* Setup wireless link with Logitech Wii wheel */
758         if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
759                 const unsigned char cbuf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
760                 u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
761 
762                 if (!buf) {
763                         ret = -ENOMEM;
764                         goto err_free;
765                 }
766 
767                 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
768                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
769                 if (ret >= 0) {
770                         /* insert a little delay of 10 jiffies ~ 40ms */
771                         wait_queue_head_t wait;
772                         init_waitqueue_head (&wait);
773                         wait_event_interruptible_timeout(wait, 0,
774                                                          msecs_to_jiffies(40));
775 
776                         /* Select random Address */
777                         buf[1] = 0xB2;
778                         get_random_bytes(&buf[2], 2);
779 
780                         ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
781                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
782                 }
783                 kfree(buf);
784         }
785 
786         if (drv_data->quirks & LG_FF)
787                 ret = lgff_init(hdev);
788         else if (drv_data->quirks & LG_FF2)
789                 ret = lg2ff_init(hdev);
790         else if (drv_data->quirks & LG_FF3)
791                 ret = lg3ff_init(hdev);
792         else if (drv_data->quirks & LG_FF4)
793                 ret = lg4ff_init(hdev);
794 
795         if (ret)
796                 goto err_free;
797 
798         return 0;
799 err_free:
800         kfree(drv_data);
801         return ret;
802 }
803 
804 static void lg_remove(struct hid_device *hdev)
805 {
806         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
807         if (drv_data->quirks & LG_FF4)
808                 lg4ff_deinit(hdev);
809         else
810                 hid_hw_stop(hdev);
811         kfree(drv_data);
812 }
813 
814 static const struct hid_device_id lg_devices[] = {
815         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
816                 .driver_data = LG_RDESC | LG_WIRELESS },
817         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
818                 .driver_data = LG_RDESC | LG_WIRELESS },
819         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
820                 .driver_data = LG_RDESC | LG_WIRELESS },
821 
822         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
823                 .driver_data = LG_BAD_RELATIVE_KEYS },
824 
825         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
826                 .driver_data = LG_DUPLICATE_USAGES },
827         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
828                 .driver_data = LG_DUPLICATE_USAGES },
829         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
830                 .driver_data = LG_DUPLICATE_USAGES },
831 
832         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
833                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
834         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
835                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
836 
837         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
838                 .driver_data = LG_NOGET },
839         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
840                 .driver_data = LG_NOGET },
841         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
842                 .driver_data = LG_NOGET | LG_FF4 },
843 
844         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
845                 .driver_data = LG_FF2 },
846         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
847                 .driver_data = LG_FF },
848         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
849                 .driver_data = LG_FF },
850         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
851                 .driver_data = LG_FF4 },
852         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
853                 .driver_data = LG_FF },
854         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
855                 .driver_data = LG_FF },
856         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
857                 .driver_data = LG_NOGET | LG_FF4 },
858         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
859                 .driver_data = LG_FF4 },
860         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
861                 .driver_data = LG_FF2 },
862         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
863                 .driver_data = LG_FF4 },
864         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
865                 .driver_data = LG_FF4 },
866         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
867                 .driver_data = LG_FF4 },
868         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
869                 .driver_data = LG_NOGET | LG_FF4 },
870         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
871                 .driver_data = LG_FF4 },
872         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
873                 .driver_data = LG_NOGET | LG_FF4 },
874         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
875                 .driver_data = LG_FF2 },
876         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
877                 .driver_data = LG_FF3 },
878         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
879                 .driver_data = LG_RDESC_REL_ABS },
880         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
881                 .driver_data = LG_RDESC_REL_ABS },
882         { }
883 };
884 
885 MODULE_DEVICE_TABLE(hid, lg_devices);
886 
887 static struct hid_driver lg_driver = {
888         .name = "logitech",
889         .id_table = lg_devices,
890         .report_fixup = lg_report_fixup,
891         .input_mapping = lg_input_mapping,
892         .input_mapped = lg_input_mapped,
893         .event = lg_event,
894         .raw_event = lg_raw_event,
895         .probe = lg_probe,
896         .remove = lg_remove,
897 };
898 module_hid_driver(lg_driver);
899 
900 #ifdef CONFIG_LOGIWHEELS_FF
901 int lg4ff_no_autoswitch = 0;
902 module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
903 MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
904 #endif
905 
906 MODULE_LICENSE("GPL");
907 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us