hid-lg.c revision 73e4008ddddc84d5f2499c17012b340a0dae153e
15f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
25f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  HID driver for some logitech "special" devices
35f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *
45f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 1999 Andreas Gal
55f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
65f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
75f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 2006-2007 Jiri Kosina
85f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 2007 Paul Walmsley
95f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby *  Copyright (c) 2008 Jiri Slaby
105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * This program is free software; you can redistribute it and/or modify it
145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * under the terms of the GNU General Public License as published by the Free
155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Software Foundation; either version 2 of the License, or (at your option)
165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * any later version.
175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/device.h>
205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/hid.h>
215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/module.h>
225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include "hid-ids.h"
24606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#include "hid-lg.h"
255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_RDESC		0x001
275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_BAD_RELATIVE_KEYS	0x002
285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_DUPLICATE_USAGES	0x004
295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_EXPANDED_KEYMAP	0x010
305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_IGNORE_DOUBLED_WHEEL	0x020
315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_WIRELESS		0x040
325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_INVERT_HWHEEL	0x080
335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_NOGET		0x100
34606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF			0x200
35606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF2			0x400
3624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina#define LG_RDESC_REL_ABS	0x800
3774f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein#define LG_FF3			0x1000
385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Certain Logitech keyboards send in report #3 keys which are far
415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * above the logical maximum described in descriptor. This extends
425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * the original value of 0x28c of logical maximum to 0x104d
435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
4473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
4573e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov		unsigned int *rsize)
465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		dev_info(&hdev->dev, "fixing up Logitech keyboard report "
525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				"descriptor\n");
535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[84] = rdesc[89] = 0x4d;
545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[85] = rdesc[90] = 0x10;
555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
5673e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
5724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
5824985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
5924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
6024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina				"report descriptor\n");
6124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		rdesc[33] = rdesc[50] = 0x02;
6224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	}
6373e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	return rdesc;
645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		EV_KEY, (c))
685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_ultrax_remote_mapping(struct hid_input *hi,
705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, unsigned long **bit, int *max)
715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	set_bit(EV_REP, hi->input->evbit);
765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Reported on Logitech Ultra X Media Remote */
785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x025: lg_map_key_clear(KEY_TV);		break;
825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x026: lg_map_key_clear(KEY_MENU);		break;
835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x033: lg_map_key_clear(KEY_LAST);		break;
865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x047: lg_map_key_clear(KEY_MP3);		break;
875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x048: lg_map_key_clear(KEY_DVD);		break;
885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x051: lg_map_key_clear(KEY_RED);		break;
945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
1005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
1015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
10266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosinastatic int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
10366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		unsigned long **bit, int *max)
10466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina{
10566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
10666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
10766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
10866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	switch (usage->hid & HID_USAGE) {
10966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
11066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
11166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	default:
11266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
11366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
11466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	}
11566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	return 1;
11666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina}
11766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
1185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
1195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
1205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
1215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
1225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
1235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
1255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
1265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
1275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
1285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
1295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
13018392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two entries are Playlist 1 and 2 on the MX3200 */
13118392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
13218392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
1335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
1345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
1355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
1365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
1375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
1385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
1395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
1405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
1415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
1425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
1435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
14418392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
1455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
1465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
1475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
1485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
1495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
1505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* this one is marked as 'Rotate' */
1515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
1525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
1535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
1545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
15518392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
15618392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two are 'Start/answer call' and 'End/reject call'
15718392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	   on the MX3200 */
15818392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1031: lg_map_key_clear(KEY_OK);			break;
15918392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
1605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
1615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
1625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
1635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
1645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
1655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
1665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
1675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
1685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
1695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
1705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
1715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
1725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
1745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
1755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
1765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
1775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
1785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
1805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
1815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
1825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
1835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* extended mapping for certain Logitech hardware (Logitech cordless
1845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	   desktop LX500) */
1855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	static const u8 e_keymap[] = {
1865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,216,  0,213,175,156,  0,  0,  0,  0,
1875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
1885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		174,167,152,161,112,  0,  0,  0,154,  0,
1895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
1905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
1915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
1925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,183,184,185,186,187,
1935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		188,189,190,191,192,193,194,  0,  0,  0
1945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	};
1955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
1965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned int hid = usage->hid;
1975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
1995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			lg_ultrax_remote_mapping(hi, usage, bit, max))
2005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
2015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
20266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
20366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina			lg_dinovo_mapping(hi, usage, bit, max))
20466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 1;
20566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
2065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
2075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
2085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
2105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
2115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid &= HID_USAGE;
2135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Special handling for Logitech Cordless Desktop */
2155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (field->application == HID_GD_MOUSE) {
2165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
2175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				(hid == 7 || hid == 8))
2185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return -1;
2195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	} else {
2205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		if ((quirks & LG_EXPANDED_KEYMAP) &&
2215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				hid < ARRAY_SIZE(e_keymap) &&
2225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				e_keymap[hid] != 0) {
2235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			hid_map_usage(hi, usage, bit, max, EV_KEY,
2245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby					e_keymap[hid]);
2255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return 1;
2265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		}
2275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
2305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
2315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
2335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
2345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
2355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
2375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
2395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			(field->flags & HID_MAIN_ITEM_RELATIVE))
2405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
2415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
2435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			 usage->type == EV_REL || usage->type == EV_ABS))
2445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		clear_bit(usage->code, *bit);
2455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
2475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
2485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_event(struct hid_device *hdev, struct hid_field *field,
2505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, __s32 value)
2515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
2535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
2555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		input_event(field->hidinput->input, usage->type, usage->code,
2565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				-value);
2575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
2585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
2615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
2625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
2645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = id->driver_data;
266606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	unsigned int connect_mask = HID_CONNECT_DEFAULT;
2675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	int ret;
2685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid_set_drvdata(hdev, (void *)quirks);
2705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (quirks & LG_NOGET)
2725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		hdev->quirks |= HID_QUIRK_NOGET;
2735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	ret = hid_parse(hdev);
2755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
2765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		dev_err(&hdev->dev, "parse failed\n");
2775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
2785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
28074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	if (quirks & (LG_FF | LG_FF2 | LG_FF3))
281606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		connect_mask &= ~HID_CONNECT_FF;
282606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
283606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	ret = hid_hw_start(hdev, connect_mask);
2845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
2855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		dev_err(&hdev->dev, "hw start failed\n");
2865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
2875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
289606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	if (quirks & LG_FF)
290606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lgff_init(hdev);
291606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	if (quirks & LG_FF2)
292606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lg2ff_init(hdev);
29374f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	if (quirks & LG_FF3)
29474f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		lg3ff_init(hdev);
295606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
2965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
2975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free:
2985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return ret;
2995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = {
3025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
3065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
3075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
3085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
3105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_BAD_RELATIVE_KEYS },
3115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
3135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
3145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
3155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
3165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
3175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
3185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
3205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
3215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
3225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
3255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_NOGET },
3265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
327606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_NOGET | LG_FF },
328606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
329606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
330606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
331606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
332606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
333606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
334606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
335606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
336606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
337606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
338606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
339606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
340606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
341243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
342243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant		.driver_data = LG_FF },
343fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
344fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina		.driver_data = LG_FF },
345606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
346606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF2 },
34774f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
34874f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		.driver_data = LG_FF3 },
34924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
35024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
35124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
35224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
3535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ }
3545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
35524985cf68612a5617d396b0b188cec807641cde1Jiri Kosina
3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices);
3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = {
3595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.name = "logitech",
3605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.id_table = lg_devices,
3615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.report_fixup = lg_report_fixup,
3625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapping = lg_input_mapping,
3635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapped = lg_input_mapped,
3645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.event = lg_event,
3655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.probe = lg_probe,
3665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
3675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
368a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init lg_init(void)
3695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return hid_register_driver(&lg_driver);
3715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
373a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit lg_exit(void)
3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid_unregister_driver(&lg_driver);
3765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_init(lg_init);
3795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_exit(lg_exit);
3805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL");
381