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
102c6118e43040034d80894daeba41960bf0035b31Hendrik Iben *  Copyright (c) 2010 Hendrik Iben
115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * This program is free software; you can redistribute it and/or modify it
155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * under the terms of the GNU General Public License as published by the Free
165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Software Foundation; either version 2 of the License, or (at your option)
175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * any later version.
185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/device.h>
215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/hid.h>
225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include <linux/module.h>
2332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/random.h>
2432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/sched.h>
2532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/wait.h>
265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include "hid-ids.h"
28606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#include "hid-lg.h"
295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_RDESC		0x001
315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_BAD_RELATIVE_KEYS	0x002
325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_DUPLICATE_USAGES	0x004
335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_EXPANDED_KEYMAP	0x010
345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_IGNORE_DOUBLED_WHEEL	0x020
355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_WIRELESS		0x040
365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_INVERT_HWHEEL	0x080
375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_NOGET		0x100
38606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF			0x200
39606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF2			0x400
4024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina#define LG_RDESC_REL_ABS	0x800
4174f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein#define LG_FF3			0x1000
4232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#define LG_FF4			0x2000
435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
44dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer/* Size of the original descriptor of the Driving Force Pro wheel */
45dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer#define DFP_RDESC_ORIG_SIZE	97
46dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
47dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer/* Fixed report descriptor for Logitech Driving Force Pro wheel controller
48dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer *
49dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * The original descriptor hides the separate throttle and brake axes in
50dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * a custom vendor usage page, providing only a combined value as
51dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * GenericDesktop.Y.
52dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * This descriptor removes the combined Y axis and instead reports
53dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * separate throttle (Y) and brake (RZ).
54dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer */
55dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauerstatic __u8 dfp_rdesc_fixed[] = {
56dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01,         /*  Usage Page (Desktop),                   */
57dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x04,         /*  Usage (Joystik),                        */
58dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x01,         /*  Collection (Application),               */
59dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02,         /*      Collection (Logical),               */
60dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01,         /*          Report Count (1),               */
61dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x0E,         /*          Report Size (14),               */
62dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x14,               /*          Logical Minimum (0),            */
63dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
64dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x34,               /*          Physical Minimum (0),           */
65dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
66dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x30,         /*          Usage (X),                      */
67dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
68dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x0E,         /*          Report Count (14),              */
69dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x01,         /*          Report Size (1),                */
70dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x01,         /*          Logical Maximum (1),            */
71dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x45, 0x01,         /*          Physical Maximum (1),           */
72dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x09,         /*          Usage Page (Button),            */
73dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x19, 0x01,         /*          Usage Minimum (01h),            */
74dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
75dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
76dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01,         /*          Usage Page (Desktop),           */
77dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01,         /*          Report Count (1),               */
78dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x04,         /*          Report Size (4),                */
79dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x07,         /*          Logical Maximum (7),            */
80dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
81dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x14,         /*          Unit (Degrees),                 */
82dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x39,         /*          Usage (Hat Switch),             */
83dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x42,         /*          Input (Variable, Nullstate),    */
84dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x00,         /*          Unit,                           */
85dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
86dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
87dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x08,         /*          Report Size (8),                */
88dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01,         /*          Input (Constant),               */
89dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x31,         /*          Usage (Y),                      */
90dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
91dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x35,         /*          Usage (Rz),                     */
92dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
93dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01,         /*          Input (Constant),               */
94dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0,               /*      End Collection,                     */
95dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02,         /*      Collection (Logical),               */
96dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x02,         /*          Usage (02h),                    */
97dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x07,         /*          Report Count (7),               */
98dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x91, 0x02,         /*          Output (Variable),              */
99dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0,               /*      End Collection,                     */
100dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0                /*  End Collection                          */
101dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer};
102dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
103dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
1045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
1055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Certain Logitech keyboards send in report #3 keys which are far
1065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * above the logical maximum described in descriptor. This extends
1075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * the original value of 0x28c of logical maximum to 0x104d
1085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
10973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
11073e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov		unsigned int *rsize)
1115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
1125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
1135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
11473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
1155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
1164291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_info(hdev,
1174291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 "fixing up Logitech keyboard report descriptor\n");
1185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[84] = rdesc[89] = 0x4d;
1195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[85] = rdesc[90] = 0x10;
1205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
12173e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
12224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
12324985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
1244291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_info(hdev,
1254291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 "fixing up rel/abs in Logitech report descriptor\n");
12624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		rdesc[33] = rdesc[50] = 0x02;
12724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	}
128d8692ac012104ebffb343c0bcb4a2b8642c821a6Jiri Kosina	if ((quirks & LG_FF4) && *rsize >= 101 &&
12932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
13032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			rdesc[47] == 0x05 && rdesc[48] == 0x09) {
1314291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
13232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		rdesc[41] = 0x05;
13332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		rdesc[42] = 0x09;
13432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		rdesc[47] = 0x95;
13532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		rdesc[48] = 0x0B;
13632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	}
137dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
138dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	switch (hdev->product) {
139dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
140dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		if (*rsize == DFP_RDESC_ORIG_SIZE) {
141dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			hid_info(hdev,
142dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer				"fixing up Logitech Driving Force Pro report descriptor\n");
143dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			rdesc = dfp_rdesc_fixed;
144dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			*rsize = sizeof(dfp_rdesc_fixed);
145dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		}
146dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		break;
147dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	}
148dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
14973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	return rdesc;
1505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
1515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
1535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		EV_KEY, (c))
1545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_ultrax_remote_mapping(struct hid_input *hi,
1565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, unsigned long **bit, int *max)
1575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
1585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
1595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
1605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	set_bit(EV_REP, hi->input->evbit);
1625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
1635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Reported on Logitech Ultra X Media Remote */
1645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
1655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
1665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
1675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x025: lg_map_key_clear(KEY_TV);		break;
1685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x026: lg_map_key_clear(KEY_MENU);		break;
1695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
1705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
1715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x033: lg_map_key_clear(KEY_LAST);		break;
1725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x047: lg_map_key_clear(KEY_MP3);		break;
1735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x048: lg_map_key_clear(KEY_DVD);		break;
1745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
1755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
1765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
1775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
1785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
1795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x051: lg_map_key_clear(KEY_RED);		break;
1805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
1815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
1825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
1835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
1845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
1855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
1865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
1875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
18866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosinastatic int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
18966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		unsigned long **bit, int *max)
19066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina{
19166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
19266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
19366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
19466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	switch (usage->hid & HID_USAGE) {
19566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
19666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
19766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	default:
19866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
19966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
20066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	}
20166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	return 1;
20266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina}
20366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
2045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
2055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
2065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
2085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
2095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
2115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
2125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
2135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
2145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
2155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
21618392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two entries are Playlist 1 and 2 on the MX3200 */
21718392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
21818392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
2195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
2205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
2215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
2225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
2235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
2245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
2255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
2265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
2275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
2285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
2295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
23018392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
2315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
2325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
2335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
2345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
2355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
2365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* this one is marked as 'Rotate' */
2375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
2385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
2395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
2405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
24118392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
24218392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two are 'Start/answer call' and 'End/reject call'
24318392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	   on the MX3200 */
24418392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1031: lg_map_key_clear(KEY_OK);			break;
24518392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
2465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
2475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
2485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
2495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
2505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
2515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
2525f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
2535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
2545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
2555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
2565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
2575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
2585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
2605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
2615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
2635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
2645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
2665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
2675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
2685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* extended mapping for certain Logitech hardware (Logitech cordless
2705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	   desktop LX500) */
2715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	static const u8 e_keymap[] = {
2725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,216,  0,213,175,156,  0,  0,  0,  0,
2735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
2745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		174,167,152,161,112,  0,  0,  0,154,  0,
2755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
2765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
2775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
2785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,183,184,185,186,187,
2795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		188,189,190,191,192,193,194,  0,  0,  0
2805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	};
2815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
2825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned int hid = usage->hid;
2835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
2855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			lg_ultrax_remote_mapping(hi, usage, bit, max))
2865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
2875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
28866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
28966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina			lg_dinovo_mapping(hi, usage, bit, max))
29066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 1;
29166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
2925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
2935f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
2945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
2965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
2975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid &= HID_USAGE;
2995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Special handling for Logitech Cordless Desktop */
3015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (field->application == HID_GD_MOUSE) {
3025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				(hid == 7 || hid == 8))
3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return -1;
3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	} else {
3065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		if ((quirks & LG_EXPANDED_KEYMAP) &&
3075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				hid < ARRAY_SIZE(e_keymap) &&
3085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				e_keymap[hid] != 0) {
3095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			hid_map_usage(hi, usage, bit, max, EV_KEY,
3105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby					e_keymap[hid]);
3115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return 1;
3125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		}
3135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
3145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
3165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
3195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
3205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
3215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
3255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			(field->flags & HID_MAIN_ITEM_RELATIVE))
3265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
3275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
3295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			 usage->type == EV_REL || usage->type == EV_ABS))
3305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		clear_bit(usage->code, *bit);
3315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
3335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_event(struct hid_device *hdev, struct hid_field *field,
3365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, __s32 value)
3375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
3395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
3415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		input_event(field->hidinput->input, usage->type, usage->code,
3425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				-value);
3435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
3445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
3455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
3475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
3505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned long quirks = id->driver_data;
352606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	unsigned int connect_mask = HID_CONNECT_DEFAULT;
3535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	int ret;
3545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid_set_drvdata(hdev, (void *)quirks);
3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (quirks & LG_NOGET)
3585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		hdev->quirks |= HID_QUIRK_NOGET;
3595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	ret = hid_parse(hdev);
3615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
3624291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "parse failed\n");
3635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
3645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
3655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3667362cd2286d2364cca6738b583668f64254fe04bMichal Malý	if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
367606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		connect_mask &= ~HID_CONNECT_FF;
368606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
369606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	ret = hid_hw_start(hdev, connect_mask);
3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
3714291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "hw start failed\n");
3725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
3735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3757362cd2286d2364cca6738b583668f64254fe04bMichal Malý	/* Setup wireless link with Logitech Wii wheel */
3767362cd2286d2364cca6738b583668f64254fe04bMichal Malý	if(hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
37732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
37832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
37932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
38032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
38132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		if (ret >= 0) {
38232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			/* insert a little delay of 10 jiffies ~ 40ms */
38332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			wait_queue_head_t wait;
38432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			init_waitqueue_head (&wait);
38532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			wait_event_interruptible_timeout(wait, 0, 10);
38632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
38732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			/* Select random Address */
38832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			buf[1] = 0xB2;
38932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			get_random_bytes(&buf[2], 2);
39032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
39132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
39232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		}
39332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	}
39432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
395606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	if (quirks & LG_FF)
396606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lgff_init(hdev);
397606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	if (quirks & LG_FF2)
398606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lg2ff_init(hdev);
39974f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	if (quirks & LG_FF3)
40074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		lg3ff_init(hdev);
40132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	if (quirks & LG_FF4)
40232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		lg4ff_init(hdev);
403606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
4045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
4055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free:
4065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return ret;
4075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
4085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
40930bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malýstatic void lg_remove(struct hid_device *hdev)
41030bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý{
41130bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
41230bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	if(quirks & LG_FF4)
41330bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý		lg4ff_deinit(hdev);
41430bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý
41530bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	hid_hw_stop(hdev);
41630bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý}
41730bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý
4185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = {
4195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
4205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
4215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
4225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
4235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
4245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
4255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
4275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_BAD_RELATIVE_KEYS },
4285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
4305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
4315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
4325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
4335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
4345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
4355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
4375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
4385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
4395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
4405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
4425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_NOGET },
4435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
4447362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_NOGET | LG_FF4 },
445606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
4462c6118e43040034d80894daeba41960bf0035b31Hendrik Iben	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
4472c6118e43040034d80894daeba41960bf0035b31Hendrik Iben		.driver_data = LG_FF2 },
448606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
449606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
450606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
451606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
452606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
453606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
454606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
455606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
456606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
4577362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
458606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
4597362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
460243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
4617362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
4627362cd2286d2364cca6738b583668f64254fe04bMichal Malý	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
4637362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
464fdc6807fcd09416c5537f479e1dcd624118e234cPeter Gundermann	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
4657362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
4665623a24a80814fe471e777f12b9dbbb0f77e002eJiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
4677362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_NOGET | LG_FF4 },
46832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
46932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		.driver_data = LG_FF4 },
470fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
471fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina		.driver_data = LG_FF },
472606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
473606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF2 },
47474f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
47574f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		.driver_data = LG_FF3 },
47624985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
47724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
47824985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
47924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
4805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ }
4815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
48224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina
4835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices);
4845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = {
4865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.name = "logitech",
4875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.id_table = lg_devices,
4885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.report_fixup = lg_report_fixup,
4895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapping = lg_input_mapping,
4905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapped = lg_input_mapped,
4915f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.event = lg_event,
4925f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.probe = lg_probe,
49330bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	.remove = lg_remove,
4945f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
4955f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
496a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic int __init lg_init(void)
4975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
4985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return hid_register_driver(&lg_driver);
4995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
5005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
501a24f423bdf253ccee369adc6c5451b40a0716fbbPeter Huewestatic void __exit lg_exit(void)
5025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
5035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid_unregister_driver(&lg_driver);
5045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
5055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_init(lg_init);
5075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabymodule_exit(lg_exit);
5085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL");
509