xref: /linux/drivers/hid/hid-lg.c (revision 2a2c74b2efcb1a0ca3fdcb5fbb96ad8de6a29177)
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 
31 #define LG_RDESC		0x001
32 #define LG_BAD_RELATIVE_KEYS	0x002
33 #define LG_DUPLICATE_USAGES	0x004
34 #define LG_EXPANDED_KEYMAP	0x010
35 #define LG_IGNORE_DOUBLED_WHEEL	0x020
36 #define LG_WIRELESS		0x040
37 #define LG_INVERT_HWHEEL	0x080
38 #define LG_NOGET		0x100
39 #define LG_FF			0x200
40 #define LG_FF2			0x400
41 #define LG_RDESC_REL_ABS	0x800
42 #define LG_FF3			0x1000
43 #define LG_FF4			0x2000
44 
45 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
46 #define DF_RDESC_ORIG_SIZE	130
47 #define DFP_RDESC_ORIG_SIZE	97
48 #define FV_RDESC_ORIG_SIZE	130
49 #define MOMO_RDESC_ORIG_SIZE	87
50 #define MOMO2_RDESC_ORIG_SIZE	87
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 (Joystik),                        */
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 (Joystik),                        */
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 (Joystik),                        */
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 (Joystik),                    */
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 (Joystik),                    */
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 /*
337  * Certain Logitech keyboards send in report #3 keys which are far
338  * above the logical maximum described in descriptor. This extends
339  * the original value of 0x28c of logical maximum to 0x104d
340  */
341 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
342 		unsigned int *rsize)
343 {
344 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
345 	struct usb_device_descriptor *udesc;
346 	__u16 bcdDevice, rev_maj, rev_min;
347 
348 	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
349 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
350 		hid_info(hdev,
351 			 "fixing up Logitech keyboard report descriptor\n");
352 		rdesc[84] = rdesc[89] = 0x4d;
353 		rdesc[85] = rdesc[90] = 0x10;
354 	}
355 	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
356 			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
357 			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
358 		hid_info(hdev,
359 			 "fixing up rel/abs in Logitech report descriptor\n");
360 		rdesc[33] = rdesc[50] = 0x02;
361 	}
362 
363 	switch (hdev->product) {
364 
365 	/* Several wheels report as this id when operating in emulation mode. */
366 	case USB_DEVICE_ID_LOGITECH_WHEEL:
367 		udesc = &(hid_to_usb_dev(hdev)->descriptor);
368 		if (!udesc) {
369 			hid_err(hdev, "NULL USB device descriptor\n");
370 			break;
371 		}
372 		bcdDevice = le16_to_cpu(udesc->bcdDevice);
373 		rev_maj = bcdDevice >> 8;
374 		rev_min = bcdDevice & 0xff;
375 
376 		/* Update the report descriptor for only the Driving Force wheel */
377 		if (rev_maj == 1 && rev_min == 2 &&
378 				*rsize == DF_RDESC_ORIG_SIZE) {
379 			hid_info(hdev,
380 				"fixing up Logitech Driving Force report descriptor\n");
381 			rdesc = df_rdesc_fixed;
382 			*rsize = sizeof(df_rdesc_fixed);
383 		}
384 		break;
385 
386 	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
387 		if (*rsize == MOMO_RDESC_ORIG_SIZE) {
388 			hid_info(hdev,
389 				"fixing up Logitech Momo Force (Red) report descriptor\n");
390 			rdesc = momo_rdesc_fixed;
391 			*rsize = sizeof(momo_rdesc_fixed);
392 		}
393 		break;
394 
395 	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
396 		if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
397 			hid_info(hdev,
398 				"fixing up Logitech Momo Racing Force (Black) report descriptor\n");
399 			rdesc = momo2_rdesc_fixed;
400 			*rsize = sizeof(momo2_rdesc_fixed);
401 		}
402 		break;
403 
404 	case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
405 		if (*rsize == FV_RDESC_ORIG_SIZE) {
406 			hid_info(hdev,
407 				"fixing up Logitech Formula Vibration report descriptor\n");
408 			rdesc = fv_rdesc_fixed;
409 			*rsize = sizeof(fv_rdesc_fixed);
410 		}
411 		break;
412 
413 	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
414 		if (*rsize == DFP_RDESC_ORIG_SIZE) {
415 			hid_info(hdev,
416 				"fixing up Logitech Driving Force Pro report descriptor\n");
417 			rdesc = dfp_rdesc_fixed;
418 			*rsize = sizeof(dfp_rdesc_fixed);
419 		}
420 		break;
421 
422 	case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
423 		if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
424 				rdesc[47] == 0x05 && rdesc[48] == 0x09) {
425 			hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
426 			rdesc[41] = 0x05;
427 			rdesc[42] = 0x09;
428 			rdesc[47] = 0x95;
429 			rdesc[48] = 0x0B;
430 		}
431 		break;
432 	}
433 
434 	return rdesc;
435 }
436 
437 #define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
438 		EV_KEY, (c))
439 
440 static int lg_ultrax_remote_mapping(struct hid_input *hi,
441 		struct hid_usage *usage, unsigned long **bit, int *max)
442 {
443 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
444 		return 0;
445 
446 	set_bit(EV_REP, hi->input->evbit);
447 	switch (usage->hid & HID_USAGE) {
448 	/* Reported on Logitech Ultra X Media Remote */
449 	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
450 	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
451 	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
452 	case 0x025: lg_map_key_clear(KEY_TV);		break;
453 	case 0x026: lg_map_key_clear(KEY_MENU);		break;
454 	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
455 	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
456 	case 0x033: lg_map_key_clear(KEY_LAST);		break;
457 	case 0x047: lg_map_key_clear(KEY_MP3);		break;
458 	case 0x048: lg_map_key_clear(KEY_DVD);		break;
459 	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
460 	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
461 	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
462 	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
463 	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
464 	case 0x051: lg_map_key_clear(KEY_RED);		break;
465 	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
466 
467 	default:
468 		return 0;
469 	}
470 	return 1;
471 }
472 
473 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
474 		unsigned long **bit, int *max)
475 {
476 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
477 		return 0;
478 
479 	switch (usage->hid & HID_USAGE) {
480 
481 	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
482 	default:
483 		return 0;
484 
485 	}
486 	return 1;
487 }
488 
489 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
490 		unsigned long **bit, int *max)
491 {
492 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
493 		return 0;
494 
495 	switch (usage->hid & HID_USAGE) {
496 	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
497 	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
498 	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
499 	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
500 	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
501 	/* The following two entries are Playlist 1 and 2 on the MX3200 */
502 	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
503 	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
504 	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
505 	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
506 	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
507 	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
508 	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
509 	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
510 	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
511 	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
512 	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
513 	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
514 	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
515 	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
516 	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
517 	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
518 	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
519 	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
520 	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
521 	/* this one is marked as 'Rotate' */
522 	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
523 	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
524 	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
525 	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
526 	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
527 	/* The following two are 'Start/answer call' and 'End/reject call'
528 	   on the MX3200 */
529 	case 0x1031: lg_map_key_clear(KEY_OK);			break;
530 	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
531 	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
532 	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
533 	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
534 	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
535 	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
536 	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
537 	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
538 	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
539 	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
540 	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
541 	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
542 	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
543 
544 	default:
545 		return 0;
546 	}
547 	return 1;
548 }
549 
550 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
551 		struct hid_field *field, struct hid_usage *usage,
552 		unsigned long **bit, int *max)
553 {
554 	/* extended mapping for certain Logitech hardware (Logitech cordless
555 	   desktop LX500) */
556 	static const u8 e_keymap[] = {
557 		  0,216,  0,213,175,156,  0,  0,  0,  0,
558 		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
559 		174,167,152,161,112,  0,  0,  0,154,  0,
560 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
561 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
562 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
563 		  0,  0,  0,  0,  0,183,184,185,186,187,
564 		188,189,190,191,192,193,194,  0,  0,  0
565 	};
566 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
567 	unsigned int hid = usage->hid;
568 
569 	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
570 			lg_ultrax_remote_mapping(hi, usage, bit, max))
571 		return 1;
572 
573 	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
574 			lg_dinovo_mapping(hi, usage, bit, max))
575 		return 1;
576 
577 	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
578 		return 1;
579 
580 	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
581 		return 0;
582 
583 	hid &= HID_USAGE;
584 
585 	/* Special handling for Logitech Cordless Desktop */
586 	if (field->application == HID_GD_MOUSE) {
587 		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
588 				(hid == 7 || hid == 8))
589 			return -1;
590 	} else {
591 		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
592 				hid < ARRAY_SIZE(e_keymap) &&
593 				e_keymap[hid] != 0) {
594 			hid_map_usage(hi, usage, bit, max, EV_KEY,
595 					e_keymap[hid]);
596 			return 1;
597 		}
598 	}
599 
600 	return 0;
601 }
602 
603 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
604 		struct hid_field *field, struct hid_usage *usage,
605 		unsigned long **bit, int *max)
606 {
607 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
608 
609 	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
610 			(field->flags & HID_MAIN_ITEM_RELATIVE))
611 		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
612 
613 	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
614 			 usage->type == EV_REL || usage->type == EV_ABS))
615 		clear_bit(usage->code, *bit);
616 
617 	/* Ensure that Logitech wheels are not given a default fuzz/flat value */
618 	if (usage->type == EV_ABS && (usage->code == ABS_X ||
619 			usage->code == ABS_Y || usage->code == ABS_Z ||
620 			usage->code == ABS_RZ)) {
621 		switch (hdev->product) {
622 		case USB_DEVICE_ID_LOGITECH_WHEEL:
623 		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
624 		case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
625 		case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
626 		case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
627 		case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
628 		case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
629 		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
630 		case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
631 			field->application = HID_GD_MULTIAXIS;
632 			break;
633 		default:
634 			break;
635 		}
636 	}
637 
638 	return 0;
639 }
640 
641 static int lg_event(struct hid_device *hdev, struct hid_field *field,
642 		struct hid_usage *usage, __s32 value)
643 {
644 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
645 
646 	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
647 		input_event(field->hidinput->input, usage->type, usage->code,
648 				-value);
649 		return 1;
650 	}
651 	if (drv_data->quirks & LG_FF4) {
652 		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
653 	}
654 
655 	return 0;
656 }
657 
658 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
659 {
660 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
661 	struct lg_drv_data *drv_data;
662 	int ret;
663 
664 	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
665 	if (!drv_data) {
666 		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
667 		return -ENOMEM;
668 	}
669 	drv_data->quirks = id->driver_data;
670 
671 	hid_set_drvdata(hdev, (void *)drv_data);
672 
673 	if (drv_data->quirks & LG_NOGET)
674 		hdev->quirks |= HID_QUIRK_NOGET;
675 
676 	ret = hid_parse(hdev);
677 	if (ret) {
678 		hid_err(hdev, "parse failed\n");
679 		goto err_free;
680 	}
681 
682 	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
683 		connect_mask &= ~HID_CONNECT_FF;
684 
685 	ret = hid_hw_start(hdev, connect_mask);
686 	if (ret) {
687 		hid_err(hdev, "hw start failed\n");
688 		goto err_free;
689 	}
690 
691 	/* Setup wireless link with Logitech Wii wheel */
692 	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
693 		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
694 
695 		ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
696 					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
697 
698 		if (ret >= 0) {
699 			/* insert a little delay of 10 jiffies ~ 40ms */
700 			wait_queue_head_t wait;
701 			init_waitqueue_head (&wait);
702 			wait_event_interruptible_timeout(wait, 0, 10);
703 
704 			/* Select random Address */
705 			buf[1] = 0xB2;
706 			get_random_bytes(&buf[2], 2);
707 
708 			ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
709 					HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
710 		}
711 	}
712 
713 	if (drv_data->quirks & LG_FF)
714 		lgff_init(hdev);
715 	if (drv_data->quirks & LG_FF2)
716 		lg2ff_init(hdev);
717 	if (drv_data->quirks & LG_FF3)
718 		lg3ff_init(hdev);
719 	if (drv_data->quirks & LG_FF4)
720 		lg4ff_init(hdev);
721 
722 	return 0;
723 err_free:
724 	kfree(drv_data);
725 	return ret;
726 }
727 
728 static void lg_remove(struct hid_device *hdev)
729 {
730 	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
731 	if (drv_data->quirks & LG_FF4)
732 		lg4ff_deinit(hdev);
733 
734 	hid_hw_stop(hdev);
735 	kfree(drv_data);
736 }
737 
738 static const struct hid_device_id lg_devices[] = {
739 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
740 		.driver_data = LG_RDESC | LG_WIRELESS },
741 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
742 		.driver_data = LG_RDESC | LG_WIRELESS },
743 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
744 		.driver_data = LG_RDESC | LG_WIRELESS },
745 
746 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
747 		.driver_data = LG_BAD_RELATIVE_KEYS },
748 
749 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
750 		.driver_data = LG_DUPLICATE_USAGES },
751 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
752 		.driver_data = LG_DUPLICATE_USAGES },
753 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
754 		.driver_data = LG_DUPLICATE_USAGES },
755 
756 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
757 		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
758 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
759 		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
760 
761 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
762 		.driver_data = LG_NOGET },
763 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
764 		.driver_data = LG_NOGET },
765 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
766 		.driver_data = LG_NOGET | LG_FF4 },
767 
768 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
769 		.driver_data = LG_FF2 },
770 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
771 		.driver_data = LG_FF },
772 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
773 		.driver_data = LG_FF },
774 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
775 		.driver_data = LG_FF },
776 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
777 		.driver_data = LG_FF },
778 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
779 		.driver_data = LG_NOGET | LG_FF4 },
780 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
781 		.driver_data = LG_FF4 },
782 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
783 		.driver_data = LG_FF2 },
784 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
785 		.driver_data = LG_FF4 },
786 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
787 		.driver_data = LG_FF4 },
788 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
789 		.driver_data = LG_FF4 },
790 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
791 		.driver_data = LG_NOGET | LG_FF4 },
792 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
793 		.driver_data = LG_FF4 },
794 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
795 		.driver_data = LG_FF },
796 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
797 		.driver_data = LG_FF2 },
798 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
799 		.driver_data = LG_FF3 },
800 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
801 		.driver_data = LG_RDESC_REL_ABS },
802 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
803 		.driver_data = LG_RDESC_REL_ABS },
804 	{ }
805 };
806 
807 MODULE_DEVICE_TABLE(hid, lg_devices);
808 
809 static struct hid_driver lg_driver = {
810 	.name = "logitech",
811 	.id_table = lg_devices,
812 	.report_fixup = lg_report_fixup,
813 	.input_mapping = lg_input_mapping,
814 	.input_mapped = lg_input_mapped,
815 	.event = lg_event,
816 	.probe = lg_probe,
817 	.remove = lg_remove,
818 };
819 module_hid_driver(lg_driver);
820 
821 MODULE_LICENSE("GPL");
822