xref: /linux/drivers/hid/hid-lg.c (revision da733563be5a9da26fe81d9f007262d00b846e22)
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) 2007 Paul Walmsley
9  *  Copyright (c) 2008 Jiri Slaby
10  *  Copyright (c) 2010 Hendrik Iben
11  */
12 
13 /*
14  * This program is free software; you can redistribute it and/or modify it
15  * under the terms of the GNU General Public License as published by the Free
16  * Software Foundation; either version 2 of the License, or (at your option)
17  * any later version.
18  */
19 
20 #include <linux/device.h>
21 #include <linux/hid.h>
22 #include <linux/module.h>
23 #include <linux/random.h>
24 #include <linux/sched.h>
25 #include <linux/wait.h>
26 
27 #include "hid-ids.h"
28 #include "hid-lg.h"
29 
30 #define LG_RDESC		0x001
31 #define LG_BAD_RELATIVE_KEYS	0x002
32 #define LG_DUPLICATE_USAGES	0x004
33 #define LG_EXPANDED_KEYMAP	0x010
34 #define LG_IGNORE_DOUBLED_WHEEL	0x020
35 #define LG_WIRELESS		0x040
36 #define LG_INVERT_HWHEEL	0x080
37 #define LG_NOGET		0x100
38 #define LG_FF			0x200
39 #define LG_FF2			0x400
40 #define LG_RDESC_REL_ABS	0x800
41 #define LG_FF3			0x1000
42 #define LG_FF4			0x2000
43 
44 /* Size of the original descriptor of the Driving Force Pro wheel */
45 #define DFP_RDESC_ORIG_SIZE	97
46 
47 /* Fixed report descriptor for Logitech Driving Force Pro wheel controller
48  *
49  * The original descriptor hides the separate throttle and brake axes in
50  * a custom vendor usage page, providing only a combined value as
51  * GenericDesktop.Y.
52  * This descriptor removes the combined Y axis and instead reports
53  * separate throttle (Y) and brake (RZ).
54  */
55 static __u8 dfp_rdesc_fixed[] = {
56 0x05, 0x01,         /*  Usage Page (Desktop),                   */
57 0x09, 0x04,         /*  Usage (Joystik),                        */
58 0xA1, 0x01,         /*  Collection (Application),               */
59 0xA1, 0x02,         /*      Collection (Logical),               */
60 0x95, 0x01,         /*          Report Count (1),               */
61 0x75, 0x0E,         /*          Report Size (14),               */
62 0x14,               /*          Logical Minimum (0),            */
63 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
64 0x34,               /*          Physical Minimum (0),           */
65 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
66 0x09, 0x30,         /*          Usage (X),                      */
67 0x81, 0x02,         /*          Input (Variable),               */
68 0x95, 0x0E,         /*          Report Count (14),              */
69 0x75, 0x01,         /*          Report Size (1),                */
70 0x25, 0x01,         /*          Logical Maximum (1),            */
71 0x45, 0x01,         /*          Physical Maximum (1),           */
72 0x05, 0x09,         /*          Usage Page (Button),            */
73 0x19, 0x01,         /*          Usage Minimum (01h),            */
74 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
75 0x81, 0x02,         /*          Input (Variable),               */
76 0x05, 0x01,         /*          Usage Page (Desktop),           */
77 0x95, 0x01,         /*          Report Count (1),               */
78 0x75, 0x04,         /*          Report Size (4),                */
79 0x25, 0x07,         /*          Logical Maximum (7),            */
80 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
81 0x65, 0x14,         /*          Unit (Degrees),                 */
82 0x09, 0x39,         /*          Usage (Hat Switch),             */
83 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
84 0x65, 0x00,         /*          Unit,                           */
85 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
86 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
87 0x75, 0x08,         /*          Report Size (8),                */
88 0x81, 0x01,         /*          Input (Constant),               */
89 0x09, 0x31,         /*          Usage (Y),                      */
90 0x81, 0x02,         /*          Input (Variable),               */
91 0x09, 0x35,         /*          Usage (Rz),                     */
92 0x81, 0x02,         /*          Input (Variable),               */
93 0x81, 0x01,         /*          Input (Constant),               */
94 0xC0,               /*      End Collection,                     */
95 0xA1, 0x02,         /*      Collection (Logical),               */
96 0x09, 0x02,         /*          Usage (02h),                    */
97 0x95, 0x07,         /*          Report Count (7),               */
98 0x91, 0x02,         /*          Output (Variable),              */
99 0xC0,               /*      End Collection,                     */
100 0xC0                /*  End Collection                          */
101 };
102 
103 
104 /*
105  * Certain Logitech keyboards send in report #3 keys which are far
106  * above the logical maximum described in descriptor. This extends
107  * the original value of 0x28c of logical maximum to 0x104d
108  */
109 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
110 		unsigned int *rsize)
111 {
112 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
113 
114 	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
115 			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
116 		hid_info(hdev,
117 			 "fixing up Logitech keyboard report descriptor\n");
118 		rdesc[84] = rdesc[89] = 0x4d;
119 		rdesc[85] = rdesc[90] = 0x10;
120 	}
121 	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
122 			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
123 			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
124 		hid_info(hdev,
125 			 "fixing up rel/abs in Logitech report descriptor\n");
126 		rdesc[33] = rdesc[50] = 0x02;
127 	}
128 	if ((quirks & LG_FF4) && *rsize >= 101 &&
129 			rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
130 			rdesc[47] == 0x05 && rdesc[48] == 0x09) {
131 		hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
132 		rdesc[41] = 0x05;
133 		rdesc[42] = 0x09;
134 		rdesc[47] = 0x95;
135 		rdesc[48] = 0x0B;
136 	}
137 
138 	switch (hdev->product) {
139 	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
140 		if (*rsize == DFP_RDESC_ORIG_SIZE) {
141 			hid_info(hdev,
142 				"fixing up Logitech Driving Force Pro report descriptor\n");
143 			rdesc = dfp_rdesc_fixed;
144 			*rsize = sizeof(dfp_rdesc_fixed);
145 		}
146 		break;
147 	}
148 
149 	return rdesc;
150 }
151 
152 #define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
153 		EV_KEY, (c))
154 
155 static int lg_ultrax_remote_mapping(struct hid_input *hi,
156 		struct hid_usage *usage, unsigned long **bit, int *max)
157 {
158 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
159 		return 0;
160 
161 	set_bit(EV_REP, hi->input->evbit);
162 	switch (usage->hid & HID_USAGE) {
163 	/* Reported on Logitech Ultra X Media Remote */
164 	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
165 	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
166 	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
167 	case 0x025: lg_map_key_clear(KEY_TV);		break;
168 	case 0x026: lg_map_key_clear(KEY_MENU);		break;
169 	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
170 	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
171 	case 0x033: lg_map_key_clear(KEY_LAST);		break;
172 	case 0x047: lg_map_key_clear(KEY_MP3);		break;
173 	case 0x048: lg_map_key_clear(KEY_DVD);		break;
174 	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
175 	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
176 	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
177 	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
178 	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
179 	case 0x051: lg_map_key_clear(KEY_RED);		break;
180 	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
181 
182 	default:
183 		return 0;
184 	}
185 	return 1;
186 }
187 
188 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
189 		unsigned long **bit, int *max)
190 {
191 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
192 		return 0;
193 
194 	switch (usage->hid & HID_USAGE) {
195 
196 	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
197 	default:
198 		return 0;
199 
200 	}
201 	return 1;
202 }
203 
204 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
205 		unsigned long **bit, int *max)
206 {
207 	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
208 		return 0;
209 
210 	switch (usage->hid & HID_USAGE) {
211 	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
212 	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
213 	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
214 	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
215 	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
216 	/* The following two entries are Playlist 1 and 2 on the MX3200 */
217 	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
218 	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
219 	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
220 	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
221 	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
222 	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
223 	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
224 	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
225 	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
226 	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
227 	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
228 	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
229 	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
230 	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
231 	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
232 	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
233 	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
234 	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
235 	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
236 	/* this one is marked as 'Rotate' */
237 	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
238 	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
239 	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
240 	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
241 	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
242 	/* The following two are 'Start/answer call' and 'End/reject call'
243 	   on the MX3200 */
244 	case 0x1031: lg_map_key_clear(KEY_OK);			break;
245 	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
246 	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
247 	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
248 	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
249 	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
250 	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
251 	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
252 	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
253 	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
254 	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
255 	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
256 	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
257 	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
258 
259 	default:
260 		return 0;
261 	}
262 	return 1;
263 }
264 
265 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
266 		struct hid_field *field, struct hid_usage *usage,
267 		unsigned long **bit, int *max)
268 {
269 	/* extended mapping for certain Logitech hardware (Logitech cordless
270 	   desktop LX500) */
271 	static const u8 e_keymap[] = {
272 		  0,216,  0,213,175,156,  0,  0,  0,  0,
273 		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
274 		174,167,152,161,112,  0,  0,  0,154,  0,
275 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
276 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
277 		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
278 		  0,  0,  0,  0,  0,183,184,185,186,187,
279 		188,189,190,191,192,193,194,  0,  0,  0
280 	};
281 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
282 	unsigned int hid = usage->hid;
283 
284 	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
285 			lg_ultrax_remote_mapping(hi, usage, bit, max))
286 		return 1;
287 
288 	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
289 			lg_dinovo_mapping(hi, usage, bit, max))
290 		return 1;
291 
292 	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
293 		return 1;
294 
295 	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
296 		return 0;
297 
298 	hid &= HID_USAGE;
299 
300 	/* Special handling for Logitech Cordless Desktop */
301 	if (field->application == HID_GD_MOUSE) {
302 		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
303 				(hid == 7 || hid == 8))
304 			return -1;
305 	} else {
306 		if ((quirks & LG_EXPANDED_KEYMAP) &&
307 				hid < ARRAY_SIZE(e_keymap) &&
308 				e_keymap[hid] != 0) {
309 			hid_map_usage(hi, usage, bit, max, EV_KEY,
310 					e_keymap[hid]);
311 			return 1;
312 		}
313 	}
314 
315 	return 0;
316 }
317 
318 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
319 		struct hid_field *field, struct hid_usage *usage,
320 		unsigned long **bit, int *max)
321 {
322 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
323 
324 	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
325 			(field->flags & HID_MAIN_ITEM_RELATIVE))
326 		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
327 
328 	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
329 			 usage->type == EV_REL || usage->type == EV_ABS))
330 		clear_bit(usage->code, *bit);
331 
332 	return 0;
333 }
334 
335 static int lg_event(struct hid_device *hdev, struct hid_field *field,
336 		struct hid_usage *usage, __s32 value)
337 {
338 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
339 
340 	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
341 		input_event(field->hidinput->input, usage->type, usage->code,
342 				-value);
343 		return 1;
344 	}
345 
346 	return 0;
347 }
348 
349 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
350 {
351 	unsigned long quirks = id->driver_data;
352 	unsigned int connect_mask = HID_CONNECT_DEFAULT;
353 	int ret;
354 
355 	hid_set_drvdata(hdev, (void *)quirks);
356 
357 	if (quirks & LG_NOGET)
358 		hdev->quirks |= HID_QUIRK_NOGET;
359 
360 	ret = hid_parse(hdev);
361 	if (ret) {
362 		hid_err(hdev, "parse failed\n");
363 		goto err_free;
364 	}
365 
366 	if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
367 		connect_mask &= ~HID_CONNECT_FF;
368 
369 	ret = hid_hw_start(hdev, connect_mask);
370 	if (ret) {
371 		hid_err(hdev, "hw start failed\n");
372 		goto err_free;
373 	}
374 
375 	/* Setup wireless link with Logitech Wii wheel */
376 	if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
377 		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
378 
379 		ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
380 
381 		if (ret >= 0) {
382 			/* insert a little delay of 10 jiffies ~ 40ms */
383 			wait_queue_head_t wait;
384 			init_waitqueue_head (&wait);
385 			wait_event_interruptible_timeout(wait, 0, 10);
386 
387 			/* Select random Address */
388 			buf[1] = 0xB2;
389 			get_random_bytes(&buf[2], 2);
390 
391 			ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
392 		}
393 	}
394 
395 	if (quirks & LG_FF)
396 		lgff_init(hdev);
397 	if (quirks & LG_FF2)
398 		lg2ff_init(hdev);
399 	if (quirks & LG_FF3)
400 		lg3ff_init(hdev);
401 	if (quirks & LG_FF4)
402 		lg4ff_init(hdev);
403 
404 	return 0;
405 err_free:
406 	return ret;
407 }
408 
409 static void lg_remove(struct hid_device *hdev)
410 {
411 	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
412 	if(quirks & LG_FF4)
413 		lg4ff_deinit(hdev);
414 
415 	hid_hw_stop(hdev);
416 }
417 
418 static const struct hid_device_id lg_devices[] = {
419 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
420 		.driver_data = LG_RDESC | LG_WIRELESS },
421 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
422 		.driver_data = LG_RDESC | LG_WIRELESS },
423 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
424 		.driver_data = LG_RDESC | LG_WIRELESS },
425 
426 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
427 		.driver_data = LG_BAD_RELATIVE_KEYS },
428 
429 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
430 		.driver_data = LG_DUPLICATE_USAGES },
431 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
432 		.driver_data = LG_DUPLICATE_USAGES },
433 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
434 		.driver_data = LG_DUPLICATE_USAGES },
435 
436 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
437 		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
438 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
439 		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
440 
441 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
442 		.driver_data = LG_NOGET },
443 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
444 		.driver_data = LG_NOGET | LG_FF4 },
445 
446 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
447 		.driver_data = LG_FF2 },
448 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
449 		.driver_data = LG_FF },
450 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
451 		.driver_data = LG_FF },
452 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
453 		.driver_data = LG_FF },
454 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
455 		.driver_data = LG_FF },
456 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
457 		.driver_data = LG_FF4 },
458 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
459 		.driver_data = LG_FF4 },
460 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
461 		.driver_data = LG_FF4 },
462 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
463 		.driver_data = LG_FF4 },
464 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
465 		.driver_data = LG_FF4 },
466 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
467 		.driver_data = LG_NOGET | LG_FF4 },
468 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
469 		.driver_data = LG_FF4 },
470 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
471 		.driver_data = LG_FF },
472 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
473 		.driver_data = LG_FF2 },
474 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
475 		.driver_data = LG_FF3 },
476 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
477 		.driver_data = LG_RDESC_REL_ABS },
478 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
479 		.driver_data = LG_RDESC_REL_ABS },
480 	{ }
481 };
482 
483 MODULE_DEVICE_TABLE(hid, lg_devices);
484 
485 static struct hid_driver lg_driver = {
486 	.name = "logitech",
487 	.id_table = lg_devices,
488 	.report_fixup = lg_report_fixup,
489 	.input_mapping = lg_input_mapping,
490 	.input_mapped = lg_input_mapped,
491 	.event = lg_event,
492 	.probe = lg_probe,
493 	.remove = lg_remove,
494 };
495 
496 static int __init lg_init(void)
497 {
498 	return hid_register_driver(&lg_driver);
499 }
500 
501 static void __exit lg_exit(void)
502 {
503 	hid_unregister_driver(&lg_driver);
504 }
505 
506 module_init(lg_init);
507 module_exit(lg_exit);
508 MODULE_LICENSE("GPL");
509