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_wireless_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_CONSUMER)
 575                return 0;
 576
 577        switch (usage->hid & HID_USAGE) {
 578        case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
 579        case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
 580        case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
 581        case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
 582        case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
 583        /* The following two entries are Playlist 1 and 2 on the MX3200 */
 584        case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
 585        case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
 586        case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
 587        case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
 588        case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
 589        case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
 590        case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
 591        case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
 592        case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
 593        case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
 594        case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
 595        case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
 596        case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
 597        case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 598        case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
 599        case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
 600        case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
 601        case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
 602        case 0x1027: lg_map_key_clear(KEY_MENU);                break;
 603        /* this one is marked as 'Rotate' */
 604        case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
 605        case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
 606        case 0x102a: lg_map_key_clear(KEY_BACK);                break;
 607        case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 608        case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
 609        /* The following two are 'Start/answer call' and 'End/reject call'
 610           on the MX3200 */
 611        case 0x1031: lg_map_key_clear(KEY_OK);                  break;
 612        case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
 613        case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
 614        case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
 615        case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
 616        case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
 617        case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
 618        case 0x1046: lg_map_key_clear(KEY_REDO);                break;
 619        case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
 620        case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
 621        case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
 622        case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
 623        case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
 624        case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
 625
 626        default:
 627                return 0;
 628        }
 629        return 1;
 630}
 631
 632static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 633                struct hid_field *field, struct hid_usage *usage,
 634                unsigned long **bit, int *max)
 635{
 636        /* extended mapping for certain Logitech hardware (Logitech cordless
 637           desktop LX500) */
 638        static const u8 e_keymap[] = {
 639                  0,216,  0,213,175,156,  0,  0,  0,  0,
 640                144,  0,  0,  0,  0,  0,  0,  0,  0,212,
 641                174,167,152,161,112,  0,  0,  0,154,  0,
 642                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 643                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 644                  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 645                  0,  0,  0,  0,  0,183,184,185,186,187,
 646                188,189,190,191,192,193,194,  0,  0,  0
 647        };
 648        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 649        unsigned int hid = usage->hid;
 650
 651        if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
 652                        lg_ultrax_remote_mapping(hi, usage, bit, max))
 653                return 1;
 654
 655        if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
 656                return 1;
 657
 658        if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
 659                return 0;
 660
 661        hid &= HID_USAGE;
 662
 663        /* Special handling for Logitech Cordless Desktop */
 664        if (field->application == HID_GD_MOUSE) {
 665                if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
 666                                (hid == 7 || hid == 8))
 667                        return -1;
 668        } else {
 669                if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
 670                                hid < ARRAY_SIZE(e_keymap) &&
 671                                e_keymap[hid] != 0) {
 672                        hid_map_usage(hi, usage, bit, max, EV_KEY,
 673                                        e_keymap[hid]);
 674                        return 1;
 675                }
 676        }
 677
 678        return 0;
 679}
 680
 681static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 682                struct hid_field *field, struct hid_usage *usage,
 683                unsigned long **bit, int *max)
 684{
 685        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 686
 687        if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 688                        (field->flags & HID_MAIN_ITEM_RELATIVE))
 689                field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 690
 691        if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
 692                         usage->type == EV_REL || usage->type == EV_ABS))
 693                clear_bit(usage->code, *bit);
 694
 695        /* Ensure that Logitech wheels are not given a default fuzz/flat value */
 696        if (usage->type == EV_ABS && (usage->code == ABS_X ||
 697                        usage->code == ABS_Y || usage->code == ABS_Z ||
 698                        usage->code == ABS_RZ)) {
 699                switch (hdev->product) {
 700                case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 701                case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
 702                case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
 703                case USB_DEVICE_ID_LOGITECH_WHEEL:
 704                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 705                case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 706                case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 707                case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 708                case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 709                case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
 710                case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 711                case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 712                        field->application = HID_GD_MULTIAXIS;
 713                        break;
 714                default:
 715                        break;
 716                }
 717        }
 718
 719        return 0;
 720}
 721
 722static int lg_event(struct hid_device *hdev, struct hid_field *field,
 723                struct hid_usage *usage, __s32 value)
 724{
 725        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 726
 727        if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 728                input_event(field->hidinput->input, usage->type, usage->code,
 729                                -value);
 730                return 1;
 731        }
 732        if (drv_data->quirks & LG_FF4) {
 733                return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
 734        }
 735
 736        return 0;
 737}
 738
 739static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
 740                u8 *rd, int size)
 741{
 742        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 743
 744        if (drv_data->quirks & LG_FF4)
 745                return lg4ff_raw_event(hdev, report, rd, size, drv_data);
 746
 747        return 0;
 748}
 749
 750static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 751{
 752        struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 753        __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
 754        unsigned int connect_mask = HID_CONNECT_DEFAULT;
 755        struct lg_drv_data *drv_data;
 756        int ret;
 757
 758        /* G29 only work with the 1st interface */
 759        if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
 760            (iface_num != 0)) {
 761                dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
 762                return -ENODEV;
 763        }
 764
 765        drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
 766        if (!drv_data) {
 767                hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
 768                return -ENOMEM;
 769        }
 770        drv_data->quirks = id->driver_data;
 771
 772        hid_set_drvdata(hdev, (void *)drv_data);
 773
 774        if (drv_data->quirks & LG_NOGET)
 775                hdev->quirks |= HID_QUIRK_NOGET;
 776
 777        ret = hid_parse(hdev);
 778        if (ret) {
 779                hid_err(hdev, "parse failed\n");
 780                goto err_free;
 781        }
 782
 783        if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
 784                connect_mask &= ~HID_CONNECT_FF;
 785
 786        ret = hid_hw_start(hdev, connect_mask);
 787        if (ret) {
 788                hid_err(hdev, "hw start failed\n");
 789                goto err_free;
 790        }
 791
 792        /* Setup wireless link with Logitech Wii wheel */
 793        if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
 794                static const unsigned char cbuf[] = {
 795                        0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 796                };
 797                u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
 798
 799                if (!buf) {
 800                        ret = -ENOMEM;
 801                        goto err_stop;
 802                }
 803
 804                ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 805                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 806                if (ret >= 0) {
 807                        /* insert a little delay of 10 jiffies ~ 40ms */
 808                        wait_queue_head_t wait;
 809                        init_waitqueue_head (&wait);
 810                        wait_event_interruptible_timeout(wait, 0,
 811                                                         msecs_to_jiffies(40));
 812
 813                        /* Select random Address */
 814                        buf[1] = 0xB2;
 815                        get_random_bytes(&buf[2], 2);
 816
 817                        ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 818                                        HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 819                }
 820                kfree(buf);
 821        }
 822
 823        if (drv_data->quirks & LG_FF)
 824                ret = lgff_init(hdev);
 825        else if (drv_data->quirks & LG_FF2)
 826                ret = lg2ff_init(hdev);
 827        else if (drv_data->quirks & LG_FF3)
 828                ret = lg3ff_init(hdev);
 829        else if (drv_data->quirks & LG_FF4)
 830                ret = lg4ff_init(hdev);
 831
 832        if (ret)
 833                goto err_stop;
 834
 835        return 0;
 836
 837err_stop:
 838        hid_hw_stop(hdev);
 839err_free:
 840        kfree(drv_data);
 841        return ret;
 842}
 843
 844static void lg_remove(struct hid_device *hdev)
 845{
 846        struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 847        if (drv_data->quirks & LG_FF4)
 848                lg4ff_deinit(hdev);
 849        hid_hw_stop(hdev);
 850        kfree(drv_data);
 851}
 852
 853static const struct hid_device_id lg_devices[] = {
 854        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
 855                .driver_data = LG_RDESC | LG_WIRELESS },
 856
 857        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
 858                .driver_data = LG_BAD_RELATIVE_KEYS },
 859
 860        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
 861                .driver_data = LG_DUPLICATE_USAGES },
 862
 863        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
 864                .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 865        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
 866                .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 867
 868        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
 869                .driver_data = LG_NOGET },
 870        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
 871                .driver_data = LG_NOGET },
 872        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
 873                .driver_data = LG_NOGET | LG_FF4 },
 874
 875        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
 876                .driver_data = LG_FF2 },
 877        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
 878                .driver_data = LG_FF },
 879        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
 880                .driver_data = LG_FF },
 881        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
 882                .driver_data = LG_FF4 },
 883        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
 884                .driver_data = LG_FF },
 885        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
 886                .driver_data = LG_FF },
 887        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
 888                .driver_data = LG_NOGET | LG_FF4 },
 889        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
 890                .driver_data = LG_FF4 },
 891        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
 892                .driver_data = LG_FF2 },
 893        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
 894                .driver_data = LG_FF4 },
 895        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
 896                .driver_data = LG_FF4 },
 897        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
 898                .driver_data = LG_FF4 },
 899        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
 900                .driver_data = LG_NOGET | LG_FF4 },
 901        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
 902                .driver_data = LG_FF4 },
 903        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
 904                .driver_data = LG_NOGET },
 905        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
 906                .driver_data = LG_NOGET | LG_FF4 },
 907        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
 908                .driver_data = LG_NOGET | LG_FF2 },
 909        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
 910                .driver_data = LG_FF3 },
 911        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
 912                .driver_data = LG_RDESC_REL_ABS },
 913        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
 914                .driver_data = LG_RDESC_REL_ABS },
 915        { }
 916};
 917
 918MODULE_DEVICE_TABLE(hid, lg_devices);
 919
 920static struct hid_driver lg_driver = {
 921        .name = "logitech",
 922        .id_table = lg_devices,
 923        .report_fixup = lg_report_fixup,
 924        .input_mapping = lg_input_mapping,
 925        .input_mapped = lg_input_mapped,
 926        .event = lg_event,
 927        .raw_event = lg_raw_event,
 928        .probe = lg_probe,
 929        .remove = lg_remove,
 930};
 931module_hid_driver(lg_driver);
 932
 933#ifdef CONFIG_LOGIWHEELS_FF
 934int lg4ff_no_autoswitch = 0;
 935module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
 936MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
 937#endif
 938
 939MODULE_LICENSE("GPL");
 940