linux/drivers/hid/hid-lg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  HID driver for some logitech "special" devices
   4 *
   5 *  Copyright (c) 1999 Andreas Gal
   6 *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
   7 *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
   8 *  Copyright (c) 2006-2007 Jiri Kosina
   9 *  Copyright (c) 2008 Jiri Slaby
  10 *  Copyright (c) 2010 Hendrik Iben
  11 */
  12
  13/*
  14 */
  15
  16#include <linux/device.h>
  17#include <linux/hid.h>
  18#include <linux/module.h>
  19#include <linux/random.h>
  20#include <linux/sched.h>
  21#include <linux/usb.h>
  22#include <linux/wait.h>
  23
  24#include "usbhid/usbhid.h"
  25#include "hid-ids.h"
  26#include "hid-lg.h"
  27#include "hid-lg4ff.h"
  28
  29#define LG_RDESC                0x001
  30#define LG_BAD_RELATIVE_KEYS    0x002
  31#define LG_DUPLICATE_USAGES     0x004
  32#define LG_EXPANDED_KEYMAP      0x010
  33#define LG_IGNORE_DOUBLED_WHEEL 0x020
  34#define LG_WIRELESS             0x040
  35#define LG_INVERT_HWHEEL        0x080
  36#define LG_NOGET                0x100
  37#define LG_FF                   0x200
  38#define LG_FF2                  0x400
  39#define LG_RDESC_REL_ABS        0x800
  40#define LG_FF3                  0x1000
  41#define LG_FF4                  0x2000
  42
  43/* Size of the original descriptors of the Driving Force (and Pro) wheels */
  44#define DF_RDESC_ORIG_SIZE      130
  45#define DFP_RDESC_ORIG_SIZE     97
  46#define FV_RDESC_ORIG_SIZE      130
  47#define MOMO_RDESC_ORIG_SIZE    87
  48#define MOMO2_RDESC_ORIG_SIZE   87
  49#define FFG_RDESC_ORIG_SIZE     85
  50#define FG_RDESC_ORIG_SIZE      82
  51
  52/* Fixed report descriptors for Logitech Driving Force (and Pro)
  53 * wheel controllers
  54 *
  55 * The original descriptors hide the separate throttle and brake axes in
  56 * a custom vendor usage page, providing only a combined value as
  57 * GenericDesktop.Y.
  58 * These descriptors remove the combined Y axis and instead report
  59 * separate throttle (Y) and brake (RZ).
  60 */
  61static __u8 df_rdesc_fixed[] = {
  620x05, 0x01,         /*  Usage Page (Desktop),                   */
  630x09, 0x04,         /*  Usage (Joystick),                       */
  640xA1, 0x01,         /*  Collection (Application),               */
  650xA1, 0x02,         /*      Collection (Logical),               */
  660x95, 0x01,         /*          Report Count (1),               */
  670x75, 0x0A,         /*          Report Size (10),               */
  680x14,               /*          Logical Minimum (0),            */
  690x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
  700x34,               /*          Physical Minimum (0),           */
  710x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
  720x09, 0x30,         /*          Usage (X),                      */
  730x81, 0x02,         /*          Input (Variable),               */
  740x95, 0x0C,         /*          Report Count (12),              */
  750x75, 0x01,         /*          Report Size (1),                */
  760x25, 0x01,         /*          Logical Maximum (1),            */
  770x45, 0x01,         /*          Physical Maximum (1),           */
  780x05, 0x09,         /*          Usage (Buttons),                */
  790x19, 0x01,         /*          Usage Minimum (1),              */
  800x29, 0x0c,         /*          Usage Maximum (12),             */
  810x81, 0x02,         /*          Input (Variable),               */
  820x95, 0x02,         /*          Report Count (2),               */
  830x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
  840x09, 0x01,         /*          Usage (?: 1),                   */
  850x81, 0x02,         /*          Input (Variable),               */
  860x05, 0x01,         /*          Usage Page (Desktop),           */
  870x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
  880x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
  890x95, 0x01,         /*          Report Count (1),               */
  900x75, 0x08,         /*          Report Size (8),                */
  910x81, 0x02,         /*          Input (Variable),               */
  920x25, 0x07,         /*          Logical Maximum (7),            */
  930x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
  940x75, 0x04,         /*          Report Size (4),                */
  950x65, 0x14,         /*          Unit (Degrees),                 */
  960x09, 0x39,         /*          Usage (Hat Switch),             */
  970x81, 0x42,         /*          Input (Variable, Null State),   */
  980x75, 0x01,         /*          Report Size (1),                */
  990x95, 0x04,         /*          Report Count (4),               */
 1000x65, 0x00,         /*          Unit (none),                    */
 1010x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
 1020x09, 0x01,         /*          Usage (?: 1),                   */
 1030x25, 0x01,         /*          Logical Maximum (1),            */
 1040x45, 0x01,         /*          Physical Maximum (1),           */
 1050x81, 0x02,         /*          Input (Variable),               */
 1060x05, 0x01,         /*          Usage Page (Desktop),           */
 1070x95, 0x01,         /*          Report Count (1),               */
 1080x75, 0x08,         /*          Report Size (8),                */
 1090x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 1100x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 1110x09, 0x31,         /*          Usage (Y),                      */
 1120x81, 0x02,         /*          Input (Variable),               */
 1130x09, 0x35,         /*          Usage (Rz),                     */
 1140x81, 0x02,         /*          Input (Variable),               */
 1150xC0,               /*      End Collection,                     */
 1160xA1, 0x02,         /*      Collection (Logical),               */
 1170x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 1180x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 1190x95, 0x07,         /*          Report Count (7),               */
 1200x75, 0x08,         /*          Report Size (8),                */
 1210x09, 0x03,         /*          Usage (?: 3),                   */
 1220x91, 0x02,         /*          Output (Variable),              */
 1230xC0,               /*      End Collection,                     */
 1240xC0                /*  End Collection                          */
 125};
 126
 127static __u8 dfp_rdesc_fixed[] = {
 1280x05, 0x01,         /*  Usage Page (Desktop),                   */
 1290x09, 0x04,         /*  Usage (Joystick),                       */
 1300xA1, 0x01,         /*  Collection (Application),               */
 1310xA1, 0x02,         /*      Collection (Logical),               */
 1320x95, 0x01,         /*          Report Count (1),               */
 1330x75, 0x0E,         /*          Report Size (14),               */
 1340x14,               /*          Logical Minimum (0),            */
 1350x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
 1360x34,               /*          Physical Minimum (0),           */
 1370x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
 1380x09, 0x30,         /*          Usage (X),                      */
 1390x81, 0x02,         /*          Input (Variable),               */
 1400x95, 0x0E,         /*          Report Count (14),              */
 1410x75, 0x01,         /*          Report Size (1),                */
 1420x25, 0x01,         /*          Logical Maximum (1),            */
 1430x45, 0x01,         /*          Physical Maximum (1),           */
 1440x05, 0x09,         /*          Usage Page (Button),            */
 1450x19, 0x01,         /*          Usage Minimum (01h),            */
 1460x29, 0x0E,         /*          Usage Maximum (0Eh),            */
 1470x81, 0x02,         /*          Input (Variable),               */
 1480x05, 0x01,         /*          Usage Page (Desktop),           */
 1490x95, 0x01,         /*          Report Count (1),               */
 1500x75, 0x04,         /*          Report Size (4),                */
 1510x25, 0x07,         /*          Logical Maximum (7),            */
 1520x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 1530x65, 0x14,         /*          Unit (Degrees),                 */
 1540x09, 0x39,         /*          Usage (Hat Switch),             */
 1550x81, 0x42,         /*          Input (Variable, Nullstate),    */
 1560x65, 0x00,         /*          Unit,                           */
 1570x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 1580x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 1590x75, 0x08,         /*          Report Size (8),                */
 1600x81, 0x01,         /*          Input (Constant),               */
 1610x09, 0x31,         /*          Usage (Y),                      */
 1620x81, 0x02,         /*          Input (Variable),               */
 1630x09, 0x35,         /*          Usage (Rz),                     */
 1640x81, 0x02,         /*          Input (Variable),               */
 1650x81, 0x01,         /*          Input (Constant),               */
 1660xC0,               /*      End Collection,                     */
 1670xA1, 0x02,         /*      Collection (Logical),               */
 1680x09, 0x02,         /*          Usage (02h),                    */
 1690x95, 0x07,         /*          Report Count (7),               */
 1700x91, 0x02,         /*          Output (Variable),              */
 1710xC0,               /*      End Collection,                     */
 1720xC0                /*  End Collection                          */
 173};
 174
 175static __u8 fv_rdesc_fixed[] = {
 1760x05, 0x01,         /*  Usage Page (Desktop),                   */
 1770x09, 0x04,         /*  Usage (Joystick),                       */
 1780xA1, 0x01,         /*  Collection (Application),               */
 1790xA1, 0x02,         /*      Collection (Logical),               */
 1800x95, 0x01,         /*          Report Count (1),               */
 1810x75, 0x0A,         /*          Report Size (10),               */
 1820x15, 0x00,         /*          Logical Minimum (0),            */
 1830x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
 1840x35, 0x00,         /*          Physical Minimum (0),           */
 1850x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
 1860x09, 0x30,         /*          Usage (X),                      */
 1870x81, 0x02,         /*          Input (Variable),               */
 1880x95, 0x0C,         /*          Report Count (12),              */
 1890x75, 0x01,         /*          Report Size (1),                */
 1900x25, 0x01,         /*          Logical Maximum (1),            */
 1910x45, 0x01,         /*          Physical Maximum (1),           */
 1920x05, 0x09,         /*          Usage Page (Button),            */
 1930x19, 0x01,         /*          Usage Minimum (01h),            */
 1940x29, 0x0C,         /*          Usage Maximum (0Ch),            */
 1950x81, 0x02,         /*          Input (Variable),               */
 1960x95, 0x02,         /*          Report Count (2),               */
 1970x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
 1980x09, 0x01,         /*          Usage (01h),                    */
 1990x81, 0x02,         /*          Input (Variable),               */
 2000x09, 0x02,         /*          Usage (02h),                    */
 2010x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 2020x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 2030x95, 0x01,         /*          Report Count (1),               */
 2040x75, 0x08,         /*          Report Size (8),                */
 2050x81, 0x02,         /*          Input (Variable),               */
 2060x05, 0x01,         /*          Usage Page (Desktop),           */
 2070x25, 0x07,         /*          Logical Maximum (7),            */
 2080x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 2090x75, 0x04,         /*          Report Size (4),                */
 2100x65, 0x14,         /*          Unit (Degrees),                 */
 2110x09, 0x39,         /*          Usage (Hat Switch),             */
 2120x81, 0x42,         /*          Input (Variable, Null State),   */
 2130x75, 0x01,         /*          Report Size (1),                */
 2140x95, 0x04,         /*          Report Count (4),               */
 2150x65, 0x00,         /*          Unit,                           */
 2160x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
 2170x09, 0x01,         /*          Usage (01h),                    */
 2180x25, 0x01,         /*          Logical Maximum (1),            */
 2190x45, 0x01,         /*          Physical Maximum (1),           */
 2200x81, 0x02,         /*          Input (Variable),               */
 2210x05, 0x01,         /*          Usage Page (Desktop),           */
 2220x95, 0x01,         /*          Report Count (1),               */
 2230x75, 0x08,         /*          Report Size (8),                */
 2240x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 2250x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 2260x09, 0x31,         /*          Usage (Y),                      */
 2270x81, 0x02,         /*          Input (Variable),               */
 2280x09, 0x32,         /*          Usage (Z),                      */
 2290x81, 0x02,         /*          Input (Variable),               */
 2300xC0,               /*      End Collection,                     */
 2310xA1, 0x02,         /*      Collection (Logical),               */
 2320x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 2330x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 2340x95, 0x07,         /*          Report Count (7),               */
 2350x75, 0x08,         /*          Report Size (8),                */
 2360x09, 0x03,         /*          Usage (03h),                    */
 2370x91, 0x02,         /*          Output (Variable),              */
 2380xC0,               /*      End Collection,                     */
 2390xC0                /*  End Collection                          */
 240};
 241
 242static __u8 momo_rdesc_fixed[] = {
 2430x05, 0x01,         /*  Usage Page (Desktop),               */
 2440x09, 0x04,         /*  Usage (Joystick),                   */
 2450xA1, 0x01,         /*  Collection (Application),           */
 2460xA1, 0x02,         /*      Collection (Logical),           */
 2470x95, 0x01,         /*          Report Count (1),           */
 2480x75, 0x0A,         /*          Report Size (10),           */
 2490x15, 0x00,         /*          Logical Minimum (0),        */
 2500x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 2510x35, 0x00,         /*          Physical Minimum (0),       */
 2520x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 2530x09, 0x30,         /*          Usage (X),                  */
 2540x81, 0x02,         /*          Input (Variable),           */
 2550x95, 0x08,         /*          Report Count (8),           */
 2560x75, 0x01,         /*          Report Size (1),            */
 2570x25, 0x01,         /*          Logical Maximum (1),        */
 2580x45, 0x01,         /*          Physical Maximum (1),       */
 2590x05, 0x09,         /*          Usage Page (Button),        */
 2600x19, 0x01,         /*          Usage Minimum (01h),        */
 2610x29, 0x08,         /*          Usage Maximum (08h),        */
 2620x81, 0x02,         /*          Input (Variable),           */
 2630x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 2640x75, 0x0E,         /*          Report Size (14),           */
 2650x95, 0x01,         /*          Report Count (1),           */
 2660x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 2670x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 2680x09, 0x00,         /*          Usage (00h),                */
 2690x81, 0x02,         /*          Input (Variable),           */
 2700x05, 0x01,         /*          Usage Page (Desktop),       */
 2710x75, 0x08,         /*          Report Size (8),            */
 2720x09, 0x31,         /*          Usage (Y),                  */
 2730x81, 0x02,         /*          Input (Variable),           */
 2740x09, 0x32,         /*          Usage (Z),                  */
 2750x81, 0x02,         /*          Input (Variable),           */
 2760x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 2770x09, 0x01,         /*          Usage (01h),                */
 2780x81, 0x02,         /*          Input (Variable),           */
 2790xC0,               /*      End Collection,                 */
 2800xA1, 0x02,         /*      Collection (Logical),           */
 2810x09, 0x02,         /*          Usage (02h),                */
 2820x95, 0x07,         /*          Report Count (7),           */
 2830x91, 0x02,         /*          Output (Variable),          */
 2840xC0,               /*      End Collection,                 */
 2850xC0                /*  End Collection                      */
 286};
 287
 288static __u8 momo2_rdesc_fixed[] = {
 2890x05, 0x01,         /*  Usage Page (Desktop),               */
 2900x09, 0x04,         /*  Usage (Joystick),                   */
 2910xA1, 0x01,         /*  Collection (Application),           */
 2920xA1, 0x02,         /*      Collection (Logical),           */
 2930x95, 0x01,         /*          Report Count (1),           */
 2940x75, 0x0A,         /*          Report Size (10),           */
 2950x15, 0x00,         /*          Logical Minimum (0),        */
 2960x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 2970x35, 0x00,         /*          Physical Minimum (0),       */
 2980x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 2990x09, 0x30,         /*          Usage (X),                  */
 3000x81, 0x02,         /*          Input (Variable),           */
 3010x95, 0x0A,         /*          Report Count (10),          */
 3020x75, 0x01,         /*          Report Size (1),            */
 3030x25, 0x01,         /*          Logical Maximum (1),        */
 3040x45, 0x01,         /*          Physical Maximum (1),       */
 3050x05, 0x09,         /*          Usage Page (Button),        */
 3060x19, 0x01,         /*          Usage Minimum (01h),        */
 3070x29, 0x0A,         /*          Usage Maximum (0Ah),        */
 3080x81, 0x02,         /*          Input (Variable),           */
 3090x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 3100x09, 0x00,         /*          Usage (00h),                */
 3110x95, 0x04,         /*          Report Count (4),           */
 3120x81, 0x02,         /*          Input (Variable),           */
 3130x95, 0x01,         /*          Report Count (1),           */
 3140x75, 0x08,         /*          Report Size (8),            */
 3150x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 3160x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 3170x09, 0x01,         /*          Usage (01h),                */
 3180x81, 0x02,         /*          Input (Variable),           */
 3190x05, 0x01,         /*          Usage Page (Desktop),       */
 3200x09, 0x31,         /*          Usage (Y),                  */
 3210x81, 0x02,         /*          Input (Variable),           */
 3220x09, 0x32,         /*          Usage (Z),                  */
 3230x81, 0x02,         /*          Input (Variable),           */
 3240x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 3250x09, 0x00,         /*          Usage (00h),                */
 3260x81, 0x02,         /*          Input (Variable),           */
 3270xC0,               /*      End Collection,                 */
 3280xA1, 0x02,         /*      Collection (Logical),           */
 3290x09, 0x02,         /*          Usage (02h),                */
 3300x95, 0x07,         /*          Report Count (7),           */
 3310x91, 0x02,         /*          Output (Variable),          */
 3320xC0,               /*      End Collection,                 */
 3330xC0                /*  End Collection                      */
 334};
 335
 336static __u8 ffg_rdesc_fixed[] = {
 3370x05, 0x01,         /*  Usage Page (Desktop),               */
 3380x09, 0x04,         /*  Usage (Joystik),                    */
 3390xA1, 0x01,         /*  Collection (Application),           */
 3400xA1, 0x02,         /*      Collection (Logical),           */
 3410x95, 0x01,         /*          Report Count (1),           */
 3420x75, 0x0A,         /*          Report Size (10),           */
 3430x15, 0x00,         /*          Logical Minimum (0),        */
 3440x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 3450x35, 0x00,         /*          Physical Minimum (0),       */
 3460x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 3470x09, 0x30,         /*          Usage (X),                  */
 3480x81, 0x02,         /*          Input (Variable),           */
 3490x95, 0x06,         /*          Report Count (6),           */
 3500x75, 0x01,         /*          Report Size (1),            */
 3510x25, 0x01,         /*          Logical Maximum (1),        */
 3520x45, 0x01,         /*          Physical Maximum (1),       */
 3530x05, 0x09,         /*          Usage Page (Button),        */
 3540x19, 0x01,         /*          Usage Minimum (01h),        */
 3550x29, 0x06,         /*          Usage Maximum (06h),        */
 3560x81, 0x02,         /*          Input (Variable),           */
 3570x95, 0x01,         /*          Report Count (1),           */
 3580x75, 0x08,         /*          Report Size (8),            */
 3590x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 3600x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 3610x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 3620x09, 0x01,         /*          Usage (01h),                */
 3630x81, 0x02,         /*          Input (Variable),           */
 3640x05, 0x01,         /*          Usage Page (Desktop),       */
 3650x81, 0x01,         /*          Input (Constant),           */
 3660x09, 0x31,         /*          Usage (Y),                  */
 3670x81, 0x02,         /*          Input (Variable),           */
 3680x09, 0x32,         /*          Usage (Z),                  */
 3690x81, 0x02,         /*          Input (Variable),           */
 3700x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 3710x09, 0x01,         /*          Usage (01h),                */
 3720x81, 0x02,         /*          Input (Variable),           */
 3730xC0,               /*      End Collection,                 */
 3740xA1, 0x02,         /*      Collection (Logical),           */
 3750x09, 0x02,         /*          Usage (02h),                */
 3760x95, 0x07,         /*          Report Count (7),           */
 3770x91, 0x02,         /*          Output (Variable),          */
 3780xC0,               /*      End Collection,                 */
 3790xC0                /*  End Collection                      */
 380};
 381
 382static __u8 fg_rdesc_fixed[] = {
 3830x05, 0x01,         /*  Usage Page (Desktop),               */
 3840x09, 0x04,         /*  Usage (Joystik),                    */
 3850xA1, 0x01,         /*  Collection (Application),           */
 3860xA1, 0x02,         /*      Collection (Logical),           */
 3870x15, 0x00,         /*          Logical Minimum (0),        */
 3880x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 3890x35, 0x00,         /*          Physical Minimum (0),       */
 3900x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 3910x75, 0x08,         /*          Report Size (8),            */
 3920x95, 0x01,         /*          Report Count (1),           */
 3930x09, 0x30,         /*          Usage (X),                  */
 3940x81, 0x02,         /*          Input (Variable),           */
 3950xA4,               /*  Push,                               */
 3960x25, 0x01,         /*          Logical Maximum (1),        */
 3970x45, 0x01,         /*          Physical Maximum (1),       */
 3980x75, 0x01,         /*          Report Size (1),            */
 3990x95, 0x02,         /*          Report Count (2),           */
 4000x81, 0x01,         /*          Input (Constant),           */
 4010x95, 0x06,         /*          Report Count (6),           */
 4020x05, 0x09,         /*          Usage Page (Button),        */
 4030x19, 0x01,         /*          Usage Minimum (01h),        */
 4040x29, 0x06,         /*          Usage Maximum (06h),        */
 4050x81, 0x02,         /*          Input (Variable),           */
 4060x05, 0x01,         /*          Usage Page (Desktop),       */
 4070xB4,               /*  Pop,                                */
 4080x81, 0x02,         /*          Input (Constant),           */
 4090x09, 0x31,         /*          Usage (Y),                  */
 4100x81, 0x02,         /*          Input (Variable),           */
 4110x09, 0x32,         /*          Usage (Z),                  */
 4120x81, 0x02,         /*          Input (Variable),           */
 4130xC0,               /*      End Collection,                 */
 4140xA1, 0x02,         /*      Collection (Logical),           */
 4150x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 4160x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 4170x75, 0x08,         /*          Report Size (8),            */
 4180x95, 0x04,         /*          Report Count (4),           */
 4190x09, 0x02,         /*          Usage (02h),                */
 4200xB1, 0x02,         /*          Feature (Variable),         */
 4210xC0,               /*      End Collection,                 */
 4220xC0                /*  End Collection,                     */
 423};
 424
 425/*
 426 * Certain Logitech keyboards send in report #3 keys which are far
 427 * above the logical maximum described in descriptor. This extends
 428 * the original value of 0x28c of logical maximum to 0x104d
 429 */
 430static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 431                unsigned int *rsize)
 432{
 433        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 434
 435        if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
 436                        rdesc[84] == 0x8c && rdesc[85] == 0x02) {
 437                hid_info(hdev,
 438                         "fixing up Logitech keyboard report descriptor\n");
 439                rdesc[84] = rdesc[89] = 0x4d;
 440                rdesc[85] = rdesc[90] = 0x10;
 441        }
 442        if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
 443                        rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
 444                        rdesc[49] == 0x81 && rdesc[50] == 0x06) {
 445                hid_info(hdev,
 446                         "fixing up rel/abs in Logitech report descriptor\n");
 447                rdesc[33] = rdesc[50] = 0x02;
 448        }
 449
 450        switch (hdev->product) {
 451
 452        case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
 453                if (*rsize == FG_RDESC_ORIG_SIZE) {
 454                        hid_info(hdev,
 455                                "fixing up Logitech Wingman Formula GP report descriptor\n");
 456                        rdesc = fg_rdesc_fixed;
 457                        *rsize = sizeof(fg_rdesc_fixed);
 458                } else {
 459                        hid_info(hdev,
 460                                "rdesc size test failed for formula gp\n");
 461                }
 462                break;
 463
 464
 465        case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
 466                if (*rsize == FFG_RDESC_ORIG_SIZE) {
 467                        hid_info(hdev,
 468                                "fixing up Logitech Wingman Formula Force GP report descriptor\n");
 469                        rdesc = ffg_rdesc_fixed;
 470                        *rsize = sizeof(ffg_rdesc_fixed);
 471                }
 472                break;
 473
 474        /* Several wheels report as this id when operating in emulation mode. */
 475        case USB_DEVICE_ID_LOGITECH_WHEEL:
 476                if (*rsize == DF_RDESC_ORIG_SIZE) {
 477                        hid_info(hdev,
 478                                "fixing up Logitech Driving Force report descriptor\n");
 479                        rdesc = df_rdesc_fixed;
 480                        *rsize = sizeof(df_rdesc_fixed);
 481                }
 482                break;
 483
 484        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 485                if (*rsize == MOMO_RDESC_ORIG_SIZE) {
 486                        hid_info(hdev,
 487                                "fixing up Logitech Momo Force (Red) report descriptor\n");
 488                        rdesc = momo_rdesc_fixed;
 489                        *rsize = sizeof(momo_rdesc_fixed);
 490                }
 491                break;
 492
 493        case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 494                if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
 495                        hid_info(hdev,
 496                                "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
 497                        rdesc = momo2_rdesc_fixed;
 498                        *rsize = sizeof(momo2_rdesc_fixed);
 499                }
 500                break;
 501
 502        case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 503                if (*rsize == FV_RDESC_ORIG_SIZE) {
 504                        hid_info(hdev,
 505                                "fixing up Logitech Formula Vibration report descriptor\n");
 506                        rdesc = fv_rdesc_fixed;
 507                        *rsize = sizeof(fv_rdesc_fixed);
 508                }
 509                break;
 510
 511        case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 512                if (*rsize == DFP_RDESC_ORIG_SIZE) {
 513                        hid_info(hdev,
 514                                "fixing up Logitech Driving Force Pro report descriptor\n");
 515                        rdesc = dfp_rdesc_fixed;
 516                        *rsize = sizeof(dfp_rdesc_fixed);
 517                }
 518                break;
 519
 520        case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
 521                if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
 522                                rdesc[47] == 0x05 && rdesc[48] == 0x09) {
 523                        hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
 524                        rdesc[41] = 0x05;
 525                        rdesc[42] = 0x09;
 526                        rdesc[47] = 0x95;
 527                        rdesc[48] = 0x0B;
 528                }
 529                break;
 530        }
 531
 532        return rdesc;
 533}
 534
 535#define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
 536                EV_KEY, (c))
 537
 538static int lg_ultrax_remote_mapping(struct hid_input *hi,
 539                struct hid_usage *usage, unsigned long **bit, int *max)
 540{
 541        if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 542                return 0;
 543
 544        set_bit(EV_REP, hi->input->evbit);
 545        switch (usage->hid & HID_USAGE) {
 546        /* Reported on Logitech Ultra X Media Remote */
 547        case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
 548        case 0x00d: lg_map_key_clear(KEY_HOME);         break;
 549        case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
 550        case 0x025: lg_map_key_clear(KEY_TV);           break;
 551        case 0x026: lg_map_key_clear(KEY_MENU);         break;
 552        case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
 553        case 0x032: lg_map_key_clear(KEY_TEXT);         break;
 554        case 0x033: lg_map_key_clear(KEY_LAST);         break;
 555        case 0x047: lg_map_key_clear(KEY_MP3);          break;
 556        case 0x048: lg_map_key_clear(KEY_DVD);          break;
 557        case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
 558        case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
 559        case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
 560        case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
 561        case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
 562        case 0x051: lg_map_key_clear(KEY_RED);          break;
 563        case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
 564
 565        default:
 566                return 0;
 567        }
 568        return 1;
 569}
 570
 571static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
 572                unsigned long **bit, int *max)
 573{
 574        if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 575                return 0;
 576
 577        switch (usage->hid & HID_USAGE) {
 578
 579        case 0x00d: lg_map_key_clear(KEY_MEDIA);        break;
 580        default:
 581                return 0;
 582
 583        }
 584        return 1;
 585}
 586
 587static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
 588                unsigned long **bit, int *max)
 589{
 590        if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 591                return 0;
 592
 593        switch (usage->hid & HID_USAGE) {
 594        case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
 595        case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
 596        case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
 597        case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
 598        case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
 599        /* The following two entries are Playlist 1 and 2 on the MX3200 */
 600        case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
 601        case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
 602        case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
 603        case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
 604        case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
 605        case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
 606        case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
 607        case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
 608        case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
 609        case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
 610        case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
 611        case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
 612        case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
 613        case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 614        case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
 615        case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
 616        case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
 617        case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
 618        case 0x1027: lg_map_key_clear(KEY_MENU);                break;
 619        /* this one is marked as 'Rotate' */
 620        case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
 621        case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
 622        case 0x102a: lg_map_key_clear(KEY_BACK);                break;
 623        case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 624        case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
 625        /* The following two are 'Start/answer call' and 'End/reject call'
 626           on the MX3200 */
 627        case 0x1031: lg_map_key_clear(KEY_OK);                  break;
 628        case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
 629        case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
 630        case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
 631        case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
 632        case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
 633        case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
 634        case 0x1046: lg_map_key_clear(KEY_REDO);                break;
 635        case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
 636        case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
 637        case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
 638        case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
 639        case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
 640        case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
 641
 642        default:
 643                return 0;
 644        }
 645        return 1;
 646}
 647
 648static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 649                struct hid_field *field, struct hid_usage *usage,
 650                unsigned long **bit, int *max)
 651{
 652        /* extended mapping for certain Logitech hardware (Logitech cordless
 653           desktop LX500) */
 654        static const u8 e_keymap[] = {
 655                  0,216,  0,213,175,156,  0,  0,  0,  0,
 656                144,  0,  0,  0,  0,  0,  0,  0,  0,212,
 657                174,167,152,161,112,  0,  0,  0,154,  0,
 658                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 659                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 660                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 661                  0,  0,  0,  0,  0,183,184,185,186,187,
 662                188,189,190,191,192,193,194,  0,  0,  0
 663        };
 664        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 665        unsigned int hid = usage->hid;
 666
 667        if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
 668                        lg_ultrax_remote_mapping(hi, usage, bit, max))
 669                return 1;
 670
 671        if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
 672                        lg_dinovo_mapping(hi, usage, bit, max))
 673                return 1;
 674
 675        if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
 676                return 1;
 677
 678        if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
 679                return 0;
 680
 681        hid &= HID_USAGE;
 682
 683        /* Special handling for Logitech Cordless Desktop */
 684        if (field->application == HID_GD_MOUSE) {
 685                if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
 686                                (hid == 7 || hid == 8))
 687                        return -1;
 688        } else {
 689                if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
 690                                hid < ARRAY_SIZE(e_keymap) &&
 691                                e_keymap[hid] != 0) {
 692                        hid_map_usage(hi, usage, bit, max, EV_KEY,
 693                                        e_keymap[hid]);
 694                        return 1;
 695                }
 696        }
 697
 698        return 0;
 699}
 700
 701static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 702                struct hid_field *field, struct hid_usage *usage,
 703                unsigned long **bit, int *max)
 704{
 705        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 706
 707        if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 708                        (field->flags & HID_MAIN_ITEM_RELATIVE))
 709                field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 710
 711        if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
 712                         usage->type == EV_REL || usage->type == EV_ABS))
 713                clear_bit(usage->code, *bit);
 714
 715        /* Ensure that Logitech wheels are not given a default fuzz/flat value */
 716        if (usage->type == EV_ABS && (usage->code == ABS_X ||
 717                        usage->code == ABS_Y || usage->code == ABS_Z ||
 718                        usage->code == ABS_RZ)) {
 719                switch (hdev->product) {
 720                case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 721                case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
 722                case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
 723                case USB_DEVICE_ID_LOGITECH_WHEEL:
 724                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 725                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 726                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 727                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 728                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 729                case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
 730                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 731                case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 732                        field->application = HID_GD_MULTIAXIS;
 733                        break;
 734                default:
 735                        break;
 736                }
 737        }
 738
 739        return 0;
 740}
 741
 742static int lg_event(struct hid_device *hdev, struct hid_field *field,
 743                struct hid_usage *usage, __s32 value)
 744{
 745        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 746
 747        if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 748                input_event(field->hidinput->input, usage->type, usage->code,
 749                                -value);
 750                return 1;
 751        }
 752        if (drv_data->quirks & LG_FF4) {
 753                return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
 754        }
 755
 756        return 0;
 757}
 758
 759static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
 760                u8 *rd, int size)
 761{
 762        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 763
 764        if (drv_data->quirks & LG_FF4)
 765                return lg4ff_raw_event(hdev, report, rd, size, drv_data);
 766
 767        return 0;
 768}
 769
 770static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 771{
 772        struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 773        __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
 774        unsigned int connect_mask = HID_CONNECT_DEFAULT;
 775        struct lg_drv_data *drv_data;
 776        int ret;
 777
 778        /* G29 only work with the 1st interface */
 779        if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
 780            (iface_num != 0)) {
 781                dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
 782                return -ENODEV;
 783        }
 784
 785        drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
 786        if (!drv_data) {
 787                hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
 788                return -ENOMEM;
 789        }
 790        drv_data->quirks = id->driver_data;
 791
 792        hid_set_drvdata(hdev, (void *)drv_data);
 793
 794        if (drv_data->quirks & LG_NOGET)
 795                hdev->quirks |= HID_QUIRK_NOGET;
 796
 797        ret = hid_parse(hdev);
 798        if (ret) {
 799                hid_err(hdev, "parse failed\n");
 800                goto err_free;
 801        }
 802
 803        if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
 804                connect_mask &= ~HID_CONNECT_FF;
 805
 806        ret = hid_hw_start(hdev, connect_mask);
 807        if (ret) {
 808                hid_err(hdev, "hw start failed\n");
 809                goto err_free;
 810        }
 811
 812        /* Setup wireless link with Logitech Wii wheel */
 813        if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
 814                static const unsigned char cbuf[] = {
 815                        0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 816                };
 817                u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
 818
 819                if (!buf) {
 820                        ret = -ENOMEM;
 821                        goto err_stop;
 822                }
 823
 824                ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 825                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 826                if (ret >= 0) {
 827                        /* insert a little delay of 10 jiffies ~ 40ms */
 828                        wait_queue_head_t wait;
 829                        init_waitqueue_head (&wait);
 830                        wait_event_interruptible_timeout(wait, 0,
 831                                                         msecs_to_jiffies(40));
 832
 833                        /* Select random Address */
 834                        buf[1] = 0xB2;
 835                        get_random_bytes(&buf[2], 2);
 836
 837                        ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 838                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 839                }
 840                kfree(buf);
 841        }
 842
 843        if (drv_data->quirks & LG_FF)
 844                ret = lgff_init(hdev);
 845        else if (drv_data->quirks & LG_FF2)
 846                ret = lg2ff_init(hdev);
 847        else if (drv_data->quirks & LG_FF3)
 848                ret = lg3ff_init(hdev);
 849        else if (drv_data->quirks & LG_FF4)
 850                ret = lg4ff_init(hdev);
 851
 852        if (ret)
 853                goto err_stop;
 854
 855        return 0;
 856
 857err_stop:
 858        hid_hw_stop(hdev);
 859err_free:
 860        kfree(drv_data);
 861        return ret;
 862}
 863
 864static void lg_remove(struct hid_device *hdev)
 865{
 866        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 867        if (drv_data->quirks & LG_FF4)
 868                lg4ff_deinit(hdev);
 869        hid_hw_stop(hdev);
 870        kfree(drv_data);
 871}
 872
 873static const struct hid_device_id lg_devices[] = {
 874        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
 875                .driver_data = LG_RDESC | LG_WIRELESS },
 876
 877        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
 878                .driver_data = LG_BAD_RELATIVE_KEYS },
 879
 880        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
 881                .driver_data = LG_DUPLICATE_USAGES },
 882        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
 883                .driver_data = LG_DUPLICATE_USAGES },
 884        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
 885                .driver_data = LG_DUPLICATE_USAGES },
 886
 887        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
 888                .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 889        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
 890                .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 891
 892        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
 893                .driver_data = LG_NOGET },
 894        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
 895                .driver_data = LG_NOGET },
 896        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
 897                .driver_data = LG_NOGET | LG_FF4 },
 898
 899        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
 900                .driver_data = LG_FF2 },
 901        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
 902                .driver_data = LG_FF },
 903        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
 904                .driver_data = LG_FF },
 905        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
 906                .driver_data = LG_FF4 },
 907        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
 908                .driver_data = LG_FF },
 909        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
 910                .driver_data = LG_FF },
 911        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
 912                .driver_data = LG_NOGET | LG_FF4 },
 913        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
 914                .driver_data = LG_FF4 },
 915        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
 916                .driver_data = LG_FF2 },
 917        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
 918                .driver_data = LG_FF4 },
 919        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
 920                .driver_data = LG_FF4 },
 921        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
 922                .driver_data = LG_FF4 },
 923        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
 924                .driver_data = LG_NOGET | LG_FF4 },
 925        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
 926                .driver_data = LG_FF4 },
 927        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
 928                .driver_data = LG_NOGET },
 929        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
 930                .driver_data = LG_NOGET | LG_FF4 },
 931        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
 932                .driver_data = LG_NOGET | LG_FF2 },
 933        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
 934                .driver_data = LG_FF3 },
 935        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
 936                .driver_data = LG_RDESC_REL_ABS },
 937        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
 938                .driver_data = LG_RDESC_REL_ABS },
 939        { }
 940};
 941
 942MODULE_DEVICE_TABLE(hid, lg_devices);
 943
 944static struct hid_driver lg_driver = {
 945        .name = "logitech",
 946        .id_table = lg_devices,
 947        .report_fixup = lg_report_fixup,
 948        .input_mapping = lg_input_mapping,
 949        .input_mapped = lg_input_mapped,
 950        .event = lg_event,
 951        .raw_event = lg_raw_event,
 952        .probe = lg_probe,
 953        .remove = lg_remove,
 954};
 955module_hid_driver(lg_driver);
 956
 957#ifdef CONFIG_LOGIWHEELS_FF
 958int lg4ff_no_autoswitch = 0;
 959module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
 960MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
 961#endif
 962
 963MODULE_LICENSE("GPL");
 964