hid-lg.c revision bd04363d3990c0727b7512a79a08c68436878bb0
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) 2008 Jiri Slaby
92c6118e43040034d80894daeba41960bf0035b31Hendrik Iben *  Copyright (c) 2010 Hendrik Iben
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>
2232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/random.h>
2332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/sched.h>
2454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra#include <linux/usb.h>
2532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#include <linux/wait.h>
265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra#include "usbhid/usbhid.h"
285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#include "hid-ids.h"
29606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#include "hid-lg.h"
305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_RDESC		0x001
325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_BAD_RELATIVE_KEYS	0x002
335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_DUPLICATE_USAGES	0x004
345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_EXPANDED_KEYMAP	0x010
355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_IGNORE_DOUBLED_WHEEL	0x020
365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_WIRELESS		0x040
375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_INVERT_HWHEEL	0x080
385f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define LG_NOGET		0x100
39606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF			0x200
40606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby#define LG_FF2			0x400
4124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina#define LG_RDESC_REL_ABS	0x800
4274f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein#define LG_FF3			0x1000
4332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood#define LG_FF4			0x2000
445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra/* Size of the original descriptors of the Driving Force (and Pro) wheels */
4654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra#define DF_RDESC_ORIG_SIZE	130
47dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer#define DFP_RDESC_ORIG_SIZE	97
48270baef1fafab50410e0e395ec26834de2dcc390Simon Wood#define MOMO_RDESC_ORIG_SIZE	87
49dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
5054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra/* Fixed report descriptors for Logitech Driving Force (and Pro)
5154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra * wheel controllers
52dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer *
5354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra * The original descriptors hide the separate throttle and brake axes in
54dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * a custom vendor usage page, providing only a combined value as
55dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * GenericDesktop.Y.
5654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra * These descriptors remove the combined Y axis and instead report
57dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer * separate throttle (Y) and brake (RZ).
58dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer */
5954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarrastatic __u8 df_rdesc_fixed[] = {
6054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x05, 0x01,         /*  Usage Page (Desktop),                   */
6154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x04,         /*  Usage (Joystik),                        */
6254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xA1, 0x01,         /*  Collection (Application),               */
6354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xA1, 0x02,         /*      Collection (Logical),               */
6454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x01,         /*          Report Count (1),               */
6554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x0A,         /*          Report Size (10),               */
6654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x14,               /*          Logical Minimum (0),            */
6754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
6854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x34,               /*          Physical Minimum (0),           */
6954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
7054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x30,         /*          Usage (X),                      */
7154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
7254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x0C,         /*          Report Count (12),              */
7354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x01,         /*          Report Size (1),                */
7454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x25, 0x01,         /*          Logical Maximum (1),            */
7554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x45, 0x01,         /*          Physical Maximum (1),           */
7654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x05, 0x09,         /*          Usage (Buttons),                */
7754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x19, 0x01,         /*          Usage Minimum (1),              */
7854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x29, 0x0c,         /*          Usage Maximum (12),             */
7954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
8054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x02,         /*          Report Count (2),               */
8154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
8254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x01,         /*          Usage (?: 1),                   */
8354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
8454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x05, 0x01,         /*          Usage Page (Desktop),           */
8554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
8654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
8754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x01,         /*          Report Count (1),               */
8854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x08,         /*          Report Size (8),                */
8954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
9054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x25, 0x07,         /*          Logical Maximum (7),            */
9154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
9254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x04,         /*          Report Size (4),                */
9354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x65, 0x14,         /*          Unit (Degrees),                 */
9454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x39,         /*          Usage (Hat Switch),             */
9554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x42,         /*          Input (Variable, Null State),   */
9654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x01,         /*          Report Size (1),                */
9754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x04,         /*          Report Count (4),               */
9854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x65, 0x00,         /*          Unit (none),                    */
9954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
10054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x01,         /*          Usage (?: 1),                   */
10154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x25, 0x01,         /*          Logical Maximum (1),            */
10254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x45, 0x01,         /*          Physical Maximum (1),           */
10354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
1045a9b571bacafffaff75f4f523c4479c85e83cb15Paul Sbarra0x05, 0x01,         /*          Usage Page (Desktop),           */
1055a9b571bacafffaff75f4f523c4479c85e83cb15Paul Sbarra0x95, 0x01,         /*          Report Count (1),               */
10654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x08,         /*          Report Size (8),                */
10754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
10854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
1095a9b571bacafffaff75f4f523c4479c85e83cb15Paul Sbarra0x09, 0x31,         /*          Usage (Y),                      */
1105a9b571bacafffaff75f4f523c4479c85e83cb15Paul Sbarra0x81, 0x02,         /*          Input (Variable),               */
1115a9b571bacafffaff75f4f523c4479c85e83cb15Paul Sbarra0x09, 0x35,         /*          Usage (Rz),                     */
11254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x81, 0x02,         /*          Input (Variable),               */
11354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xC0,               /*      End Collection,                     */
11454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xA1, 0x02,         /*      Collection (Logical),               */
11554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
11654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
11754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x95, 0x07,         /*          Report Count (7),               */
11854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x75, 0x08,         /*          Report Size (8),                */
11954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x09, 0x03,         /*          Usage (?: 3),                   */
12054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0x91, 0x02,         /*          Output (Variable),              */
12154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xC0,               /*      End Collection,                     */
12254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra0xC0                /*  End Collection                          */
12354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra};
12454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra
125dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauerstatic __u8 dfp_rdesc_fixed[] = {
126dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01,         /*  Usage Page (Desktop),                   */
127dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x04,         /*  Usage (Joystik),                        */
128dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x01,         /*  Collection (Application),               */
129dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02,         /*      Collection (Logical),               */
130dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01,         /*          Report Count (1),               */
131dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x0E,         /*          Report Size (14),               */
132dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x14,               /*          Logical Minimum (0),            */
133dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
134dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x34,               /*          Physical Minimum (0),           */
135dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
136dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x30,         /*          Usage (X),                      */
137dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
138dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x0E,         /*          Report Count (14),              */
139dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x01,         /*          Report Size (1),                */
140dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x01,         /*          Logical Maximum (1),            */
141dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x45, 0x01,         /*          Physical Maximum (1),           */
142dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x09,         /*          Usage Page (Button),            */
143dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x19, 0x01,         /*          Usage Minimum (01h),            */
144dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
145dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
146dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x05, 0x01,         /*          Usage Page (Desktop),           */
147dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x01,         /*          Report Count (1),               */
148dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x04,         /*          Report Size (4),                */
149dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x25, 0x07,         /*          Logical Maximum (7),            */
150dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
151dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x14,         /*          Unit (Degrees),                 */
152dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x39,         /*          Usage (Hat Switch),             */
153dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x42,         /*          Input (Variable, Nullstate),    */
154dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x65, 0x00,         /*          Unit,                           */
155dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
156dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
157dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x75, 0x08,         /*          Report Size (8),                */
158dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01,         /*          Input (Constant),               */
159dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x31,         /*          Usage (Y),                      */
160dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
161dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x35,         /*          Usage (Rz),                     */
162dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x02,         /*          Input (Variable),               */
163dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x81, 0x01,         /*          Input (Constant),               */
164dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0,               /*      End Collection,                     */
165dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xA1, 0x02,         /*      Collection (Logical),               */
166dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x09, 0x02,         /*          Usage (02h),                    */
167dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x95, 0x07,         /*          Report Count (7),               */
168dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0x91, 0x02,         /*          Output (Variable),              */
169dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0,               /*      End Collection,                     */
170dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer0xC0                /*  End Collection                          */
171dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer};
172dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
173270baef1fafab50410e0e395ec26834de2dcc390Simon Woodstatic __u8 momo_rdesc_fixed[] = {
174270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x05, 0x01,         /*  Usage Page (Desktop),               */
175270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x04,         /*  Usage (Joystik),                    */
176270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xA1, 0x01,         /*  Collection (Application),           */
177270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xA1, 0x02,         /*      Collection (Logical),           */
178270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x95, 0x01,         /*          Report Count (1),           */
179270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x75, 0x0A,         /*          Report Size (10),           */
180270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x15, 0x00,         /*          Logical Minimum (0),        */
181270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
182270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x35, 0x00,         /*          Physical Minimum (0),       */
183270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
184270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x30,         /*          Usage (X),                  */
185270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
186270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x95, 0x08,         /*          Report Count (8),           */
187270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x75, 0x01,         /*          Report Size (1),            */
188270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x25, 0x01,         /*          Logical Maximum (1),        */
189270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x45, 0x01,         /*          Physical Maximum (1),       */
190270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x05, 0x09,         /*          Usage Page (Button),        */
191270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x19, 0x01,         /*          Usage Minimum (01h),        */
192270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x29, 0x08,         /*          Usage Maximum (08h),        */
193270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
194270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
195270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x75, 0x0E,         /*          Report Size (14),           */
196270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x95, 0x01,         /*          Report Count (1),           */
197270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
198270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
199270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x00,         /*          Usage (00h),                */
200270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
201270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x05, 0x01,         /*          Usage Page (Desktop),       */
202270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x75, 0x08,         /*          Report Size (8),            */
203270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x31,         /*          Usage (Y),                  */
204270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
205270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x32,         /*          Usage (Z),                  */
206270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
207270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
208270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x01,         /*          Usage (01h),                */
209270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x81, 0x02,         /*          Input (Variable),           */
210270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xC0,               /*      End Collection,                 */
211270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xA1, 0x02,         /*      Collection (Logical),           */
212270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x09, 0x02,         /*          Usage (02h),                */
213270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x95, 0x07,         /*          Report Count (7),           */
214270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0x91, 0x02,         /*          Output (Variable),          */
215270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xC0,               /*      End Collection,                 */
216270baef1fafab50410e0e395ec26834de2dcc390Simon Wood0xC0                /*  End Collection                      */
217270baef1fafab50410e0e395ec26834de2dcc390Simon Wood};
218dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
2195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby/*
2205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * Certain Logitech keyboards send in report #3 keys which are far
2215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * above the logical maximum described in descriptor. This extends
2225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby * the original value of 0x28c of logical maximum to 0x104d
2235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby */
22473e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashovstatic __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
22573e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov		unsigned int *rsize)
2265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
2272575155309947063927b123c56119f36dfda3b50Axel Lin	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
22854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra	struct usb_device_descriptor *udesc;
22954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra	__u16 bcdDevice, rev_maj, rev_min;
2305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
2318577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
2325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			rdesc[84] == 0x8c && rdesc[85] == 0x02) {
2334291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_info(hdev,
2344291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 "fixing up Logitech keyboard report descriptor\n");
2355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[84] = rdesc[89] = 0x4d;
2365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		rdesc[85] = rdesc[90] = 0x10;
2375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
2388577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
23924985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
24024985cf68612a5617d396b0b188cec807641cde1Jiri Kosina			rdesc[49] == 0x81 && rdesc[50] == 0x06) {
2414291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_info(hdev,
2424291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches			 "fixing up rel/abs in Logitech report descriptor\n");
24324985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		rdesc[33] = rdesc[50] = 0x02;
24424985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	}
245dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
246dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	switch (hdev->product) {
24754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra
24854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra	/* Several wheels report as this id when operating in emulation mode. */
24954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra	case USB_DEVICE_ID_LOGITECH_WHEEL:
25054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		udesc = &(hid_to_usb_dev(hdev)->descriptor);
25154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		if (!udesc) {
25254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra			hid_err(hdev, "NULL USB device descriptor\n");
25354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra			break;
25454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		}
25554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		bcdDevice = le16_to_cpu(udesc->bcdDevice);
25654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		rev_maj = bcdDevice >> 8;
25754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		rev_min = bcdDevice & 0xff;
25854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra
25954bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		/* Update the report descriptor for only the Driving Force wheel */
26054bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		if (rev_maj == 1 && rev_min == 2 &&
26154bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra				*rsize == DF_RDESC_ORIG_SIZE) {
26254bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra			hid_info(hdev,
26354bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra				"fixing up Logitech Driving Force report descriptor\n");
26454bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra			rdesc = df_rdesc_fixed;
26554bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra			*rsize = sizeof(df_rdesc_fixed);
26654bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		}
26754bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra		break;
26854bfe3f0dab2b2f0ac629690f187537d95adeb4fPaul Sbarra
269270baef1fafab50410e0e395ec26834de2dcc390Simon Wood	case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
270270baef1fafab50410e0e395ec26834de2dcc390Simon Wood		if (*rsize == MOMO_RDESC_ORIG_SIZE) {
271270baef1fafab50410e0e395ec26834de2dcc390Simon Wood			hid_info(hdev,
272270baef1fafab50410e0e395ec26834de2dcc390Simon Wood				"fixing up Logitech Momo Force (Red) report descriptor\n");
273270baef1fafab50410e0e395ec26834de2dcc390Simon Wood			rdesc = momo_rdesc_fixed;
274270baef1fafab50410e0e395ec26834de2dcc390Simon Wood			*rsize = sizeof(momo_rdesc_fixed);
275270baef1fafab50410e0e395ec26834de2dcc390Simon Wood		}
276270baef1fafab50410e0e395ec26834de2dcc390Simon Wood		break;
277270baef1fafab50410e0e395ec26834de2dcc390Simon Wood
278dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
279dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		if (*rsize == DFP_RDESC_ORIG_SIZE) {
280dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			hid_info(hdev,
281dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer				"fixing up Logitech Driving Force Pro report descriptor\n");
282dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			rdesc = dfp_rdesc_fixed;
283dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer			*rsize = sizeof(dfp_rdesc_fixed);
284dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		}
285dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer		break;
286b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood
287b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood	case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
288b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood		if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
289b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood				rdesc[47] == 0x05 && rdesc[48] == 0x09) {
290b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood			hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
291b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood			rdesc[41] = 0x05;
292b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood			rdesc[42] = 0x09;
293b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood			rdesc[47] = 0x95;
294b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood			rdesc[48] = 0x0B;
295b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood		}
296b5836246c127ce1f0afe9790537b94c71efd2d2aSimon Wood		break;
297dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer	}
298dc0a4f0ce2b1a9ef5947cdb6d62f60008a7e42bfMichael Bauer
29973e4008ddddc84d5f2499c17012b340a0dae153eNikolai Kondrashov	return rdesc;
3005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby#define lg_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
3035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		EV_KEY, (c))
3045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_ultrax_remote_mapping(struct hid_input *hi,
3065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, unsigned long **bit, int *max)
3075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
3095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
3105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	set_bit(EV_REP, hi->input->evbit);
3125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
3135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Reported on Logitech Ultra X Media Remote */
3145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x004: lg_map_key_clear(KEY_AGAIN);	break;
3155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x00d: lg_map_key_clear(KEY_HOME);		break;
3165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x024: lg_map_key_clear(KEY_SHUFFLE);	break;
3175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x025: lg_map_key_clear(KEY_TV);		break;
3185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x026: lg_map_key_clear(KEY_MENU);		break;
3195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x031: lg_map_key_clear(KEY_AUDIO);	break;
3205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x032: lg_map_key_clear(KEY_TEXT);		break;
3215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x033: lg_map_key_clear(KEY_LAST);		break;
3225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x047: lg_map_key_clear(KEY_MP3);		break;
3235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x048: lg_map_key_clear(KEY_DVD);		break;
3245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x049: lg_map_key_clear(KEY_MEDIA);	break;
3255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04a: lg_map_key_clear(KEY_VIDEO);	break;
3265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04b: lg_map_key_clear(KEY_ANGLE);	break;
3275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04c: lg_map_key_clear(KEY_LANGUAGE);	break;
3285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x04d: lg_map_key_clear(KEY_SUBTITLE);	break;
3295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x051: lg_map_key_clear(KEY_RED);		break;
3305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x052: lg_map_key_clear(KEY_CLOSE);	break;
3315f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
3335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
3345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
3355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
3365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
3375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
33866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosinastatic int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
33966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		unsigned long **bit, int *max)
34066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina{
34166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
34266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
34366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
34466d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	switch (usage->hid & HID_USAGE) {
34566d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
34666d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	case 0x00d: lg_map_key_clear(KEY_MEDIA);	break;
34766d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	default:
34866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 0;
34966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
35066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	}
35166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	return 1;
35266d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina}
35366d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
3545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
3555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
3565f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
3575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
3585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
3595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
3605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	switch (usage->hid & HID_USAGE) {
3615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1001: lg_map_key_clear(KEY_MESSENGER);		break;
3625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1003: lg_map_key_clear(KEY_SOUND);		break;
3635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1004: lg_map_key_clear(KEY_VIDEO);		break;
3645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1005: lg_map_key_clear(KEY_AUDIO);		break;
3655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);		break;
36618392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two entries are Playlist 1 and 2 on the MX3200 */
36718392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x100f: lg_map_key_clear(KEY_FN_1);		break;
36818392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1010: lg_map_key_clear(KEY_FN_2);		break;
3695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);	break;
3705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1012: lg_map_key_clear(KEY_NEXTSONG);		break;
3715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1013: lg_map_key_clear(KEY_CAMERA);		break;
3725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1014: lg_map_key_clear(KEY_MESSENGER);		break;
3735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1015: lg_map_key_clear(KEY_RECORD);		break;
3745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1016: lg_map_key_clear(KEY_PLAYER);		break;
3755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1017: lg_map_key_clear(KEY_EJECTCD);		break;
3765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1018: lg_map_key_clear(KEY_MEDIA);		break;
3775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1019: lg_map_key_clear(KEY_PROG1);		break;
3785f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101a: lg_map_key_clear(KEY_PROG2);		break;
3795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101b: lg_map_key_clear(KEY_PROG3);		break;
38018392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
3815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x101f: lg_map_key_clear(KEY_ZOOMIN);		break;
3825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);		break;
3835f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);		break;
3845f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1023: lg_map_key_clear(KEY_CLOSE);		break;
3855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1027: lg_map_key_clear(KEY_MENU);		break;
3865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* this one is marked as 'Rotate' */
3875f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1028: lg_map_key_clear(KEY_ANGLE);		break;
3885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1029: lg_map_key_clear(KEY_SHUFFLE);		break;
3895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102a: lg_map_key_clear(KEY_BACK);		break;
3905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);	break;
39118392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x102d: lg_map_key_clear(KEY_WWW);			break;
39218392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	/* The following two are 'Start/answer call' and 'End/reject call'
39318392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	   on the MX3200 */
39418392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1031: lg_map_key_clear(KEY_OK);			break;
39518392212932ecbdc71bc6a298ad301328eefb09dLorenzo Castelli	case 0x1032: lg_map_key_clear(KEY_CANCEL);		break;
3965f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1041: lg_map_key_clear(KEY_BATTERY);		break;
3975f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);	break;
3985f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);		break;
3995f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1044: lg_map_key_clear(KEY_PRESENTATION);	break;
4005f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1045: lg_map_key_clear(KEY_UNDO);		break;
4015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1046: lg_map_key_clear(KEY_REDO);		break;
4025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1047: lg_map_key_clear(KEY_PRINT);		break;
4035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1048: lg_map_key_clear(KEY_SAVE);		break;
4045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x1049: lg_map_key_clear(KEY_PROG1);		break;
4055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104a: lg_map_key_clear(KEY_PROG2);		break;
4065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104b: lg_map_key_clear(KEY_PROG3);		break;
4075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	case 0x104c: lg_map_key_clear(KEY_PROG4);		break;
4085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	default:
4105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
4115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
4125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 1;
4135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
4145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
4165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
4175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
4185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
4195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* extended mapping for certain Logitech hardware (Logitech cordless
4205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	   desktop LX500) */
4215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	static const u8 e_keymap[] = {
4225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,216,  0,213,175,156,  0,  0,  0,  0,
4235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		144,  0,  0,  0,  0,  0,  0,  0,  0,212,
4245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		174,167,152,161,112,  0,  0,  0,154,  0,
4255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
4285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		  0,  0,  0,  0,  0,183,184,185,186,187,
4295f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		188,189,190,191,192,193,194,  0,  0,  0
4305f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	};
4312575155309947063927b123c56119f36dfda3b50Axel Lin	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
4325f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	unsigned int hid = usage->hid;
4335f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4345f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
4355f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			lg_ultrax_remote_mapping(hi, usage, bit, max))
4365f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
4375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
43866d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina	if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
43966d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina			lg_dinovo_mapping(hi, usage, bit, max))
44066d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina		return 1;
44166d61bec697e99476c2fb095f9a6ead3be2e1c21Jiri Kosina
4428577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
4435f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
4445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
4465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 0;
4475f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4485f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	hid &= HID_USAGE;
4495f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4505f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	/* Special handling for Logitech Cordless Desktop */
4515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (field->application == HID_GD_MOUSE) {
4528577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý		if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
4535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				(hid == 7 || hid == 8))
4545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return -1;
4555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	} else {
4568577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý		if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
4575f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				hid < ARRAY_SIZE(e_keymap) &&
4585f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				e_keymap[hid] != 0) {
4595f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			hid_map_usage(hi, usage, bit, max, EV_KEY,
4605f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby					e_keymap[hid]);
4615f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			return 1;
4625f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		}
4635f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
4645f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
4665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
4675f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
4695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_field *field, struct hid_usage *usage,
4705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		unsigned long **bit, int *max)
4715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
4722575155309947063927b123c56119f36dfda3b50Axel Lin	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
4735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4748577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
4755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			(field->flags & HID_MAIN_ITEM_RELATIVE))
4765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		field->flags &= ~HID_MAIN_ITEM_RELATIVE;
4775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
4788577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
4795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby			 usage->type == EV_REL || usage->type == EV_ABS))
4805f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		clear_bit(usage->code, *bit);
4815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
48294b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood	/* Ensure that Logitech wheels are not given a default fuzz/flat value */
48394b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood	if (usage->type == EV_ABS && (usage->code == ABS_X ||
48494b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood			usage->code == ABS_Y || usage->code == ABS_Z ||
48594b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood			usage->code == ABS_RZ)) {
48694b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		switch (hdev->product) {
48794b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_WHEEL:
48894b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
48994b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
49094b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
49194b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
49294b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
49394b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
49494b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
495bd04363d3990c0727b7512a79a08c68436878bb0Elias Vanderstuyft		case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
49694b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood			field->application = HID_GD_MULTIAXIS;
49794b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood			break;
49894b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		default:
49994b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood			break;
50094b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood		}
50194b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood	}
50294b3f712fe2cd5c33d57ca0ab9604d2402bc72cdSimon Wood
5035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
5045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
5055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_event(struct hid_device *hdev, struct hid_field *field,
5075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		struct hid_usage *usage, __s32 value)
5085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
5092575155309947063927b123c56119f36dfda3b50Axel Lin	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5118577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
5125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		input_event(field->hidinput->input, usage->type, usage->code,
5135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby				-value);
5145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		return 1;
5155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
5162b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý	if (drv_data->quirks & LG_FF4) {
5172b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý		return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
5182b24a960016b8d3221a6dd2764ab97247c48dd97Michal Malý	}
5195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
5215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
5225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
5245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby{
525606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	unsigned int connect_mask = HID_CONNECT_DEFAULT;
5268577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	struct lg_drv_data *drv_data;
5275f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	int ret;
5285f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5298577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
5308577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (!drv_data) {
5318577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý		hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
5328577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý		return -ENOMEM;
5338577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	}
5348577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	drv_data->quirks = id->driver_data;
535a80fe5d6e3190f65be8cc7efa487f187eb3dbffaMichal Malý
5368577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	hid_set_drvdata(hdev, (void *)drv_data);
5375f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5388577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_NOGET)
5395f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		hdev->quirks |= HID_QUIRK_NOGET;
5405f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5415f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	ret = hid_parse(hdev);
5425f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
5434291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "parse failed\n");
5445f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
5455f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
5465f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5478577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
548606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		connect_mask &= ~HID_CONNECT_FF;
549606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
550606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	ret = hid_hw_start(hdev, connect_mask);
5515f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	if (ret) {
5524291ee305e9bb0699504a66f0e2b7aefcf0512a5Joe Perches		hid_err(hdev, "hw start failed\n");
5535f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		goto err_free;
5545f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	}
5555f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
5567362cd2286d2364cca6738b583668f64254fe04bMichal Malý	/* Setup wireless link with Logitech Wii wheel */
557a80fe5d6e3190f65be8cc7efa487f187eb3dbffaMichal Malý	if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
55832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
55932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
56032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
56132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
56232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		if (ret >= 0) {
56332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			/* insert a little delay of 10 jiffies ~ 40ms */
56432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			wait_queue_head_t wait;
56532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			init_waitqueue_head (&wait);
56632c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			wait_event_interruptible_timeout(wait, 0, 10);
56732c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
56832c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			/* Select random Address */
56932c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			buf[1] = 0xB2;
57032c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			get_random_bytes(&buf[2], 2);
57132c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
57232c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood			ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
57332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		}
57432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	}
57532c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood
5768577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_FF)
577606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lgff_init(hdev);
5788577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_FF2)
579606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		lg2ff_init(hdev);
5808577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_FF3)
58174f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		lg3ff_init(hdev);
5828577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_FF4)
58332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		lg4ff_init(hdev);
584606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
5855f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return 0;
5865f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabyerr_free:
5878577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	kfree(drv_data);
5885f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	return ret;
5895f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby}
5905f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
59130bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malýstatic void lg_remove(struct hid_device *hdev)
59230bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý{
5932575155309947063927b123c56119f36dfda3b50Axel Lin	struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
5948577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	if (drv_data->quirks & LG_FF4)
59530bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý		lg4ff_deinit(hdev);
59630bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý
59730bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	hid_hw_stop(hdev);
5988577dbf9d6eb07213caefb49e2017c177c5f023dMichal Malý	kfree(drv_data);
59930bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý}
60030bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý
6015f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic const struct hid_device_id lg_devices[] = {
6025f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
6035f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
6045f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
6055f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
6065f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
6075f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_RDESC | LG_WIRELESS },
6085f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6095f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
6105f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_BAD_RELATIVE_KEYS },
6115f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6125f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
6135f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
6145f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
6155f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
6165f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
6175f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_DUPLICATE_USAGES },
6185f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6195f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
6205f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
6215f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
6225f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
6235f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6245f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
6255f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby		.driver_data = LG_NOGET },
6265f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
6277362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_NOGET | LG_FF4 },
628606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby
6292c6118e43040034d80894daeba41960bf0035b31Hendrik Iben	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
6302c6118e43040034d80894daeba41960bf0035b31Hendrik Iben		.driver_data = LG_FF2 },
631606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
632606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
633606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
634606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
635606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
636606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
637606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
638606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF },
639606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
640270baef1fafab50410e0e395ec26834de2dcc390Simon Wood		.driver_data = LG_NOGET | LG_FF4 },
641606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
6427362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
643bd04363d3990c0727b7512a79a08c68436878bb0Elias Vanderstuyft	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
644bd04363d3990c0727b7512a79a08c68436878bb0Elias Vanderstuyft		.driver_data = LG_FF2 },
645243b706d8a71364ad6080328d45b73516c8af5f3Christophe Borivant	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
6467362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
6477362cd2286d2364cca6738b583668f64254fe04bMichal Malý	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
6487362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
649fdc6807fcd09416c5537f479e1dcd624118e234cPeter Gundermann	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
6507362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_FF4 },
6515623a24a80814fe471e777f12b9dbbb0f77e002eJiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
6527362cd2286d2364cca6738b583668f64254fe04bMichal Malý		.driver_data = LG_NOGET | LG_FF4 },
65332c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
65432c88cbc3080f43c429f6456aa9cd845e37f3778Simon Wood		.driver_data = LG_FF4 },
655a80fe5d6e3190f65be8cc7efa487f187eb3dbffaMichal Malý	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
656fd30ea8c871552ddd6a5e1c0886de8fef4df53bcJiri Kosina		.driver_data = LG_FF },
657606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
658606bd0a8616a0e59021cb2997e942513f24f641dJiri Slaby		.driver_data = LG_FF2 },
65974f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
66074f292ca8c7a2b9370f80d97a49e48174f4c7635Gary Stein		.driver_data = LG_FF3 },
66124985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
66224985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
66324985cf68612a5617d396b0b188cec807641cde1Jiri Kosina	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
66424985cf68612a5617d396b0b188cec807641cde1Jiri Kosina		.driver_data = LG_RDESC_REL_ABS },
6655f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	{ }
6665f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
66724985cf68612a5617d396b0b188cec807641cde1Jiri Kosina
6685f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_DEVICE_TABLE(hid, lg_devices);
6695f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6705f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slabystatic struct hid_driver lg_driver = {
6715f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.name = "logitech",
6725f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.id_table = lg_devices,
6735f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.report_fixup = lg_report_fixup,
6745f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapping = lg_input_mapping,
6755f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.input_mapped = lg_input_mapped,
6765f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.event = lg_event,
6775f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby	.probe = lg_probe,
67830bb75d71b3732c0adb6297815288ce0fb9cc04cMichal Malý	.remove = lg_remove,
6795f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby};
680f425458eafd51b6b5ab64f407922e1198c567cb2H Hartley Sweetenmodule_hid_driver(lg_driver);
6815f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri Slaby
6825f22a7992349c5ca3842190be52d5e9a1dd7adf4Jiri SlabyMODULE_LICENSE("GPL");
683