hid-lg.c revision 7362cd2286d2364cca6738b583668f64254fe04b
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 */
55static __u8 dfp_rdesc_fixed[] = {
560x05, 0x01,         /*  Usage Page (Desktop),                   */
570x09, 0x04,         /*  Usage (Joystik),                        */
580xA1, 0x01,         /*  Collection (Application),               */
590xA1, 0x02,         /*      Collection (Logical),               */
600x95, 0x01,         /*          Report Count (1),               */
610x75, 0x0E,         /*          Report Size (14),               */
620x14,               /*          Logical Minimum (0),            */
630x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
640x34,               /*          Physical Minimum (0),           */
650x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
660x09, 0x30,         /*          Usage (X),                      */
670x81, 0x02,         /*          Input (Variable),               */
680x95, 0x0E,         /*          Report Count (14),              */
690x75, 0x01,         /*          Report Size (1),                */
700x25, 0x01,         /*          Logical Maximum (1),            */
710x45, 0x01,         /*          Physical Maximum (1),           */
720x05, 0x09,         /*          Usage Page (Button),            */
730x19, 0x01,         /*          Usage Minimum (01h),            */
740x29, 0x0E,         /*          Usage Maximum (0Eh),            */
750x81, 0x02,         /*          Input (Variable),               */
760x05, 0x01,         /*          Usage Page (Desktop),           */
770x95, 0x01,         /*          Report Count (1),               */
780x75, 0x04,         /*          Report Size (4),                */
790x25, 0x07,         /*          Logical Maximum (7),            */
800x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
810x65, 0x14,         /*          Unit (Degrees),                 */
820x09, 0x39,         /*          Usage (Hat Switch),             */
830x81, 0x42,         /*          Input (Variable, Nullstate),    */
840x65, 0x00,         /*          Unit,                           */
850x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
860x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
870x75, 0x08,         /*          Report Size (8),                */
880x81, 0x01,         /*          Input (Constant),               */
890x09, 0x31,         /*          Usage (Y),                      */
900x81, 0x02,         /*          Input (Variable),               */
910x09, 0x35,         /*          Usage (Rz),                     */
920x81, 0x02,         /*          Input (Variable),               */
930x81, 0x01,         /*          Input (Constant),               */
940xC0,               /*      End Collection,                     */
950xA1, 0x02,         /*      Collection (Logical),               */
960x09, 0x02,         /*          Usage (02h),                    */
970x95, 0x07,         /*          Report Count (7),               */
980x91, 0x02,         /*          Output (Variable),              */
990xC0,               /*      End Collection,                     */
1000xC0                /*  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 */
109static __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
155static 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
188static 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
204static 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
265static 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
318static 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
335static 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
349static 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;
405err_free:
406	return ret;
407}
408
409static const struct hid_device_id lg_devices[] = {
410	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
411		.driver_data = LG_RDESC | LG_WIRELESS },
412	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
413		.driver_data = LG_RDESC | LG_WIRELESS },
414	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
415		.driver_data = LG_RDESC | LG_WIRELESS },
416
417	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
418		.driver_data = LG_BAD_RELATIVE_KEYS },
419
420	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
421		.driver_data = LG_DUPLICATE_USAGES },
422	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
423		.driver_data = LG_DUPLICATE_USAGES },
424	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
425		.driver_data = LG_DUPLICATE_USAGES },
426
427	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
428		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
429	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
430		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
431
432	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
433		.driver_data = LG_NOGET },
434	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
435		.driver_data = LG_NOGET | LG_FF4 },
436
437	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
438		.driver_data = LG_FF2 },
439	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
440		.driver_data = LG_FF },
441	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
442		.driver_data = LG_FF },
443	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
444		.driver_data = LG_FF },
445	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
446		.driver_data = LG_FF },
447	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
448		.driver_data = LG_FF4 },
449	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
450		.driver_data = LG_FF4 },
451	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
452		.driver_data = LG_FF4 },
453	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
454		.driver_data = LG_FF4 },
455	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
456		.driver_data = LG_FF4 },
457	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
458		.driver_data = LG_NOGET | LG_FF4 },
459	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
460		.driver_data = LG_FF4 },
461	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
462		.driver_data = LG_FF },
463	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
464		.driver_data = LG_FF2 },
465	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
466		.driver_data = LG_FF3 },
467	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
468		.driver_data = LG_RDESC_REL_ABS },
469	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
470		.driver_data = LG_RDESC_REL_ABS },
471	{ }
472};
473
474MODULE_DEVICE_TABLE(hid, lg_devices);
475
476static struct hid_driver lg_driver = {
477	.name = "logitech",
478	.id_table = lg_devices,
479	.report_fixup = lg_report_fixup,
480	.input_mapping = lg_input_mapping,
481	.input_mapped = lg_input_mapped,
482	.event = lg_event,
483	.probe = lg_probe,
484};
485
486static int __init lg_init(void)
487{
488	return hid_register_driver(&lg_driver);
489}
490
491static void __exit lg_exit(void)
492{
493	hid_unregister_driver(&lg_driver);
494}
495
496module_init(lg_init);
497module_exit(lg_exit);
498MODULE_LICENSE("GPL");
499