Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  HID driver for some logitech "special" devices
0004  *
0005  *  Copyright (c) 1999 Andreas Gal
0006  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
0007  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
0008  *  Copyright (c) 2006-2007 Jiri Kosina
0009  *  Copyright (c) 2008 Jiri Slaby
0010  *  Copyright (c) 2010 Hendrik Iben
0011  */
0012 
0013 /*
0014  */
0015 
0016 #include <linux/device.h>
0017 #include <linux/hid.h>
0018 #include <linux/module.h>
0019 #include <linux/random.h>
0020 #include <linux/sched.h>
0021 #include <linux/usb.h>
0022 #include <linux/wait.h>
0023 
0024 #include "usbhid/usbhid.h"
0025 #include "hid-ids.h"
0026 #include "hid-lg.h"
0027 #include "hid-lg4ff.h"
0028 
0029 #define LG_RDESC        0x001
0030 #define LG_BAD_RELATIVE_KEYS    0x002
0031 #define LG_DUPLICATE_USAGES 0x004
0032 #define LG_EXPANDED_KEYMAP  0x010
0033 #define LG_IGNORE_DOUBLED_WHEEL 0x020
0034 #define LG_WIRELESS     0x040
0035 #define LG_INVERT_HWHEEL    0x080
0036 #define LG_NOGET        0x100
0037 #define LG_FF           0x200
0038 #define LG_FF2          0x400
0039 #define LG_RDESC_REL_ABS    0x800
0040 #define LG_FF3          0x1000
0041 #define LG_FF4          0x2000
0042 
0043 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
0044 #define DF_RDESC_ORIG_SIZE  130
0045 #define DFP_RDESC_ORIG_SIZE 97
0046 #define FV_RDESC_ORIG_SIZE  130
0047 #define MOMO_RDESC_ORIG_SIZE    87
0048 #define MOMO2_RDESC_ORIG_SIZE   87
0049 #define FFG_RDESC_ORIG_SIZE 85
0050 #define FG_RDESC_ORIG_SIZE  82
0051 
0052 /* Fixed report descriptors for Logitech Driving Force (and Pro)
0053  * wheel controllers
0054  *
0055  * The original descriptors hide the separate throttle and brake axes in
0056  * a custom vendor usage page, providing only a combined value as
0057  * GenericDesktop.Y.
0058  * These descriptors remove the combined Y axis and instead report
0059  * separate throttle (Y) and brake (RZ).
0060  */
0061 static __u8 df_rdesc_fixed[] = {
0062 0x05, 0x01,         /*  Usage Page (Desktop),                   */
0063 0x09, 0x04,         /*  Usage (Joystick),                       */
0064 0xA1, 0x01,         /*  Collection (Application),               */
0065 0xA1, 0x02,         /*      Collection (Logical),               */
0066 0x95, 0x01,         /*          Report Count (1),               */
0067 0x75, 0x0A,         /*          Report Size (10),               */
0068 0x14,               /*          Logical Minimum (0),            */
0069 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
0070 0x34,               /*          Physical Minimum (0),           */
0071 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
0072 0x09, 0x30,         /*          Usage (X),                      */
0073 0x81, 0x02,         /*          Input (Variable),               */
0074 0x95, 0x0C,         /*          Report Count (12),              */
0075 0x75, 0x01,         /*          Report Size (1),                */
0076 0x25, 0x01,         /*          Logical Maximum (1),            */
0077 0x45, 0x01,         /*          Physical Maximum (1),           */
0078 0x05, 0x09,         /*          Usage (Buttons),                */
0079 0x19, 0x01,         /*          Usage Minimum (1),              */
0080 0x29, 0x0c,         /*          Usage Maximum (12),             */
0081 0x81, 0x02,         /*          Input (Variable),               */
0082 0x95, 0x02,         /*          Report Count (2),               */
0083 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
0084 0x09, 0x01,         /*          Usage (?: 1),                   */
0085 0x81, 0x02,         /*          Input (Variable),               */
0086 0x05, 0x01,         /*          Usage Page (Desktop),           */
0087 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0088 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0089 0x95, 0x01,         /*          Report Count (1),               */
0090 0x75, 0x08,         /*          Report Size (8),                */
0091 0x81, 0x02,         /*          Input (Variable),               */
0092 0x25, 0x07,         /*          Logical Maximum (7),            */
0093 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
0094 0x75, 0x04,         /*          Report Size (4),                */
0095 0x65, 0x14,         /*          Unit (Degrees),                 */
0096 0x09, 0x39,         /*          Usage (Hat Switch),             */
0097 0x81, 0x42,         /*          Input (Variable, Null State),   */
0098 0x75, 0x01,         /*          Report Size (1),                */
0099 0x95, 0x04,         /*          Report Count (4),               */
0100 0x65, 0x00,         /*          Unit (none),                    */
0101 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
0102 0x09, 0x01,         /*          Usage (?: 1),                   */
0103 0x25, 0x01,         /*          Logical Maximum (1),            */
0104 0x45, 0x01,         /*          Physical Maximum (1),           */
0105 0x81, 0x02,         /*          Input (Variable),               */
0106 0x05, 0x01,         /*          Usage Page (Desktop),           */
0107 0x95, 0x01,         /*          Report Count (1),               */
0108 0x75, 0x08,         /*          Report Size (8),                */
0109 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0110 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0111 0x09, 0x31,         /*          Usage (Y),                      */
0112 0x81, 0x02,         /*          Input (Variable),               */
0113 0x09, 0x35,         /*          Usage (Rz),                     */
0114 0x81, 0x02,         /*          Input (Variable),               */
0115 0xC0,               /*      End Collection,                     */
0116 0xA1, 0x02,         /*      Collection (Logical),               */
0117 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0118 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0119 0x95, 0x07,         /*          Report Count (7),               */
0120 0x75, 0x08,         /*          Report Size (8),                */
0121 0x09, 0x03,         /*          Usage (?: 3),                   */
0122 0x91, 0x02,         /*          Output (Variable),              */
0123 0xC0,               /*      End Collection,                     */
0124 0xC0                /*  End Collection                          */
0125 };
0126 
0127 static __u8 dfp_rdesc_fixed[] = {
0128 0x05, 0x01,         /*  Usage Page (Desktop),                   */
0129 0x09, 0x04,         /*  Usage (Joystick),                       */
0130 0xA1, 0x01,         /*  Collection (Application),               */
0131 0xA1, 0x02,         /*      Collection (Logical),               */
0132 0x95, 0x01,         /*          Report Count (1),               */
0133 0x75, 0x0E,         /*          Report Size (14),               */
0134 0x14,               /*          Logical Minimum (0),            */
0135 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
0136 0x34,               /*          Physical Minimum (0),           */
0137 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
0138 0x09, 0x30,         /*          Usage (X),                      */
0139 0x81, 0x02,         /*          Input (Variable),               */
0140 0x95, 0x0E,         /*          Report Count (14),              */
0141 0x75, 0x01,         /*          Report Size (1),                */
0142 0x25, 0x01,         /*          Logical Maximum (1),            */
0143 0x45, 0x01,         /*          Physical Maximum (1),           */
0144 0x05, 0x09,         /*          Usage Page (Button),            */
0145 0x19, 0x01,         /*          Usage Minimum (01h),            */
0146 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
0147 0x81, 0x02,         /*          Input (Variable),               */
0148 0x05, 0x01,         /*          Usage Page (Desktop),           */
0149 0x95, 0x01,         /*          Report Count (1),               */
0150 0x75, 0x04,         /*          Report Size (4),                */
0151 0x25, 0x07,         /*          Logical Maximum (7),            */
0152 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
0153 0x65, 0x14,         /*          Unit (Degrees),                 */
0154 0x09, 0x39,         /*          Usage (Hat Switch),             */
0155 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
0156 0x65, 0x00,         /*          Unit,                           */
0157 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0158 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0159 0x75, 0x08,         /*          Report Size (8),                */
0160 0x81, 0x01,         /*          Input (Constant),               */
0161 0x09, 0x31,         /*          Usage (Y),                      */
0162 0x81, 0x02,         /*          Input (Variable),               */
0163 0x09, 0x35,         /*          Usage (Rz),                     */
0164 0x81, 0x02,         /*          Input (Variable),               */
0165 0x81, 0x01,         /*          Input (Constant),               */
0166 0xC0,               /*      End Collection,                     */
0167 0xA1, 0x02,         /*      Collection (Logical),               */
0168 0x09, 0x02,         /*          Usage (02h),                    */
0169 0x95, 0x07,         /*          Report Count (7),               */
0170 0x91, 0x02,         /*          Output (Variable),              */
0171 0xC0,               /*      End Collection,                     */
0172 0xC0                /*  End Collection                          */
0173 };
0174 
0175 static __u8 fv_rdesc_fixed[] = {
0176 0x05, 0x01,         /*  Usage Page (Desktop),                   */
0177 0x09, 0x04,         /*  Usage (Joystick),                       */
0178 0xA1, 0x01,         /*  Collection (Application),               */
0179 0xA1, 0x02,         /*      Collection (Logical),               */
0180 0x95, 0x01,         /*          Report Count (1),               */
0181 0x75, 0x0A,         /*          Report Size (10),               */
0182 0x15, 0x00,         /*          Logical Minimum (0),            */
0183 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
0184 0x35, 0x00,         /*          Physical Minimum (0),           */
0185 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
0186 0x09, 0x30,         /*          Usage (X),                      */
0187 0x81, 0x02,         /*          Input (Variable),               */
0188 0x95, 0x0C,         /*          Report Count (12),              */
0189 0x75, 0x01,         /*          Report Size (1),                */
0190 0x25, 0x01,         /*          Logical Maximum (1),            */
0191 0x45, 0x01,         /*          Physical Maximum (1),           */
0192 0x05, 0x09,         /*          Usage Page (Button),            */
0193 0x19, 0x01,         /*          Usage Minimum (01h),            */
0194 0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
0195 0x81, 0x02,         /*          Input (Variable),               */
0196 0x95, 0x02,         /*          Report Count (2),               */
0197 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
0198 0x09, 0x01,         /*          Usage (01h),                    */
0199 0x81, 0x02,         /*          Input (Variable),               */
0200 0x09, 0x02,         /*          Usage (02h),                    */
0201 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0202 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0203 0x95, 0x01,         /*          Report Count (1),               */
0204 0x75, 0x08,         /*          Report Size (8),                */
0205 0x81, 0x02,         /*          Input (Variable),               */
0206 0x05, 0x01,         /*          Usage Page (Desktop),           */
0207 0x25, 0x07,         /*          Logical Maximum (7),            */
0208 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
0209 0x75, 0x04,         /*          Report Size (4),                */
0210 0x65, 0x14,         /*          Unit (Degrees),                 */
0211 0x09, 0x39,         /*          Usage (Hat Switch),             */
0212 0x81, 0x42,         /*          Input (Variable, Null State),   */
0213 0x75, 0x01,         /*          Report Size (1),                */
0214 0x95, 0x04,         /*          Report Count (4),               */
0215 0x65, 0x00,         /*          Unit,                           */
0216 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
0217 0x09, 0x01,         /*          Usage (01h),                    */
0218 0x25, 0x01,         /*          Logical Maximum (1),            */
0219 0x45, 0x01,         /*          Physical Maximum (1),           */
0220 0x81, 0x02,         /*          Input (Variable),               */
0221 0x05, 0x01,         /*          Usage Page (Desktop),           */
0222 0x95, 0x01,         /*          Report Count (1),               */
0223 0x75, 0x08,         /*          Report Size (8),                */
0224 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0225 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0226 0x09, 0x31,         /*          Usage (Y),                      */
0227 0x81, 0x02,         /*          Input (Variable),               */
0228 0x09, 0x32,         /*          Usage (Z),                      */
0229 0x81, 0x02,         /*          Input (Variable),               */
0230 0xC0,               /*      End Collection,                     */
0231 0xA1, 0x02,         /*      Collection (Logical),               */
0232 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
0233 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
0234 0x95, 0x07,         /*          Report Count (7),               */
0235 0x75, 0x08,         /*          Report Size (8),                */
0236 0x09, 0x03,         /*          Usage (03h),                    */
0237 0x91, 0x02,         /*          Output (Variable),              */
0238 0xC0,               /*      End Collection,                     */
0239 0xC0                /*  End Collection                          */
0240 };
0241 
0242 static __u8 momo_rdesc_fixed[] = {
0243 0x05, 0x01,         /*  Usage Page (Desktop),               */
0244 0x09, 0x04,         /*  Usage (Joystick),                   */
0245 0xA1, 0x01,         /*  Collection (Application),           */
0246 0xA1, 0x02,         /*      Collection (Logical),           */
0247 0x95, 0x01,         /*          Report Count (1),           */
0248 0x75, 0x0A,         /*          Report Size (10),           */
0249 0x15, 0x00,         /*          Logical Minimum (0),        */
0250 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0251 0x35, 0x00,         /*          Physical Minimum (0),       */
0252 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
0253 0x09, 0x30,         /*          Usage (X),                  */
0254 0x81, 0x02,         /*          Input (Variable),           */
0255 0x95, 0x08,         /*          Report Count (8),           */
0256 0x75, 0x01,         /*          Report Size (1),            */
0257 0x25, 0x01,         /*          Logical Maximum (1),        */
0258 0x45, 0x01,         /*          Physical Maximum (1),       */
0259 0x05, 0x09,         /*          Usage Page (Button),        */
0260 0x19, 0x01,         /*          Usage Minimum (01h),        */
0261 0x29, 0x08,         /*          Usage Maximum (08h),        */
0262 0x81, 0x02,         /*          Input (Variable),           */
0263 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0264 0x75, 0x0E,         /*          Report Size (14),           */
0265 0x95, 0x01,         /*          Report Count (1),           */
0266 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
0267 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
0268 0x09, 0x00,         /*          Usage (00h),                */
0269 0x81, 0x02,         /*          Input (Variable),           */
0270 0x05, 0x01,         /*          Usage Page (Desktop),       */
0271 0x75, 0x08,         /*          Report Size (8),            */
0272 0x09, 0x31,         /*          Usage (Y),                  */
0273 0x81, 0x02,         /*          Input (Variable),           */
0274 0x09, 0x32,         /*          Usage (Z),                  */
0275 0x81, 0x02,         /*          Input (Variable),           */
0276 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0277 0x09, 0x01,         /*          Usage (01h),                */
0278 0x81, 0x02,         /*          Input (Variable),           */
0279 0xC0,               /*      End Collection,                 */
0280 0xA1, 0x02,         /*      Collection (Logical),           */
0281 0x09, 0x02,         /*          Usage (02h),                */
0282 0x95, 0x07,         /*          Report Count (7),           */
0283 0x91, 0x02,         /*          Output (Variable),          */
0284 0xC0,               /*      End Collection,                 */
0285 0xC0                /*  End Collection                      */
0286 };
0287 
0288 static __u8 momo2_rdesc_fixed[] = {
0289 0x05, 0x01,         /*  Usage Page (Desktop),               */
0290 0x09, 0x04,         /*  Usage (Joystick),                   */
0291 0xA1, 0x01,         /*  Collection (Application),           */
0292 0xA1, 0x02,         /*      Collection (Logical),           */
0293 0x95, 0x01,         /*          Report Count (1),           */
0294 0x75, 0x0A,         /*          Report Size (10),           */
0295 0x15, 0x00,         /*          Logical Minimum (0),        */
0296 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0297 0x35, 0x00,         /*          Physical Minimum (0),       */
0298 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
0299 0x09, 0x30,         /*          Usage (X),                  */
0300 0x81, 0x02,         /*          Input (Variable),           */
0301 0x95, 0x0A,         /*          Report Count (10),          */
0302 0x75, 0x01,         /*          Report Size (1),            */
0303 0x25, 0x01,         /*          Logical Maximum (1),        */
0304 0x45, 0x01,         /*          Physical Maximum (1),       */
0305 0x05, 0x09,         /*          Usage Page (Button),        */
0306 0x19, 0x01,         /*          Usage Minimum (01h),        */
0307 0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
0308 0x81, 0x02,         /*          Input (Variable),           */
0309 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0310 0x09, 0x00,         /*          Usage (00h),                */
0311 0x95, 0x04,         /*          Report Count (4),           */
0312 0x81, 0x02,         /*          Input (Variable),           */
0313 0x95, 0x01,         /*          Report Count (1),           */
0314 0x75, 0x08,         /*          Report Size (8),            */
0315 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
0316 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
0317 0x09, 0x01,         /*          Usage (01h),                */
0318 0x81, 0x02,         /*          Input (Variable),           */
0319 0x05, 0x01,         /*          Usage Page (Desktop),       */
0320 0x09, 0x31,         /*          Usage (Y),                  */
0321 0x81, 0x02,         /*          Input (Variable),           */
0322 0x09, 0x32,         /*          Usage (Z),                  */
0323 0x81, 0x02,         /*          Input (Variable),           */
0324 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0325 0x09, 0x00,         /*          Usage (00h),                */
0326 0x81, 0x02,         /*          Input (Variable),           */
0327 0xC0,               /*      End Collection,                 */
0328 0xA1, 0x02,         /*      Collection (Logical),           */
0329 0x09, 0x02,         /*          Usage (02h),                */
0330 0x95, 0x07,         /*          Report Count (7),           */
0331 0x91, 0x02,         /*          Output (Variable),          */
0332 0xC0,               /*      End Collection,                 */
0333 0xC0                /*  End Collection                      */
0334 };
0335 
0336 static __u8 ffg_rdesc_fixed[] = {
0337 0x05, 0x01,         /*  Usage Page (Desktop),               */
0338 0x09, 0x04,         /*  Usage (Joystik),                    */
0339 0xA1, 0x01,         /*  Collection (Application),           */
0340 0xA1, 0x02,         /*      Collection (Logical),           */
0341 0x95, 0x01,         /*          Report Count (1),           */
0342 0x75, 0x0A,         /*          Report Size (10),           */
0343 0x15, 0x00,         /*          Logical Minimum (0),        */
0344 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0345 0x35, 0x00,         /*          Physical Minimum (0),       */
0346 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
0347 0x09, 0x30,         /*          Usage (X),                  */
0348 0x81, 0x02,         /*          Input (Variable),           */
0349 0x95, 0x06,         /*          Report Count (6),           */
0350 0x75, 0x01,         /*          Report Size (1),            */
0351 0x25, 0x01,         /*          Logical Maximum (1),        */
0352 0x45, 0x01,         /*          Physical Maximum (1),       */
0353 0x05, 0x09,         /*          Usage Page (Button),        */
0354 0x19, 0x01,         /*          Usage Minimum (01h),        */
0355 0x29, 0x06,         /*          Usage Maximum (06h),        */
0356 0x81, 0x02,         /*          Input (Variable),           */
0357 0x95, 0x01,         /*          Report Count (1),           */
0358 0x75, 0x08,         /*          Report Size (8),            */
0359 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
0360 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
0361 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0362 0x09, 0x01,         /*          Usage (01h),                */
0363 0x81, 0x02,         /*          Input (Variable),           */
0364 0x05, 0x01,         /*          Usage Page (Desktop),       */
0365 0x81, 0x01,         /*          Input (Constant),           */
0366 0x09, 0x31,         /*          Usage (Y),                  */
0367 0x81, 0x02,         /*          Input (Variable),           */
0368 0x09, 0x32,         /*          Usage (Z),                  */
0369 0x81, 0x02,         /*          Input (Variable),           */
0370 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
0371 0x09, 0x01,         /*          Usage (01h),                */
0372 0x81, 0x02,         /*          Input (Variable),           */
0373 0xC0,               /*      End Collection,                 */
0374 0xA1, 0x02,         /*      Collection (Logical),           */
0375 0x09, 0x02,         /*          Usage (02h),                */
0376 0x95, 0x07,         /*          Report Count (7),           */
0377 0x91, 0x02,         /*          Output (Variable),          */
0378 0xC0,               /*      End Collection,                 */
0379 0xC0                /*  End Collection                      */
0380 };
0381 
0382 static __u8 fg_rdesc_fixed[] = {
0383 0x05, 0x01,         /*  Usage Page (Desktop),               */
0384 0x09, 0x04,         /*  Usage (Joystik),                    */
0385 0xA1, 0x01,         /*  Collection (Application),           */
0386 0xA1, 0x02,         /*      Collection (Logical),           */
0387 0x15, 0x00,         /*          Logical Minimum (0),        */
0388 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
0389 0x35, 0x00,         /*          Physical Minimum (0),       */
0390 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
0391 0x75, 0x08,         /*          Report Size (8),            */
0392 0x95, 0x01,         /*          Report Count (1),           */
0393 0x09, 0x30,         /*          Usage (X),                  */
0394 0x81, 0x02,         /*          Input (Variable),           */
0395 0xA4,               /*  Push,                               */
0396 0x25, 0x01,         /*          Logical Maximum (1),        */
0397 0x45, 0x01,         /*          Physical Maximum (1),       */
0398 0x75, 0x01,         /*          Report Size (1),            */
0399 0x95, 0x02,         /*          Report Count (2),           */
0400 0x81, 0x01,         /*          Input (Constant),           */
0401 0x95, 0x06,         /*          Report Count (6),           */
0402 0x05, 0x09,         /*          Usage Page (Button),        */
0403 0x19, 0x01,         /*          Usage Minimum (01h),        */
0404 0x29, 0x06,         /*          Usage Maximum (06h),        */
0405 0x81, 0x02,         /*          Input (Variable),           */
0406 0x05, 0x01,         /*          Usage Page (Desktop),       */
0407 0xB4,               /*  Pop,                                */
0408 0x81, 0x02,         /*          Input (Constant),           */
0409 0x09, 0x31,         /*          Usage (Y),                  */
0410 0x81, 0x02,         /*          Input (Variable),           */
0411 0x09, 0x32,         /*          Usage (Z),                  */
0412 0x81, 0x02,         /*          Input (Variable),           */
0413 0xC0,               /*      End Collection,                 */
0414 0xA1, 0x02,         /*      Collection (Logical),           */
0415 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
0416 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
0417 0x75, 0x08,         /*          Report Size (8),            */
0418 0x95, 0x04,         /*          Report Count (4),           */
0419 0x09, 0x02,         /*          Usage (02h),                */
0420 0xB1, 0x02,         /*          Feature (Variable),         */
0421 0xC0,               /*      End Collection,                 */
0422 0xC0                /*  End Collection,                     */
0423 };
0424 
0425 /*
0426  * Certain Logitech keyboards send in report #3 keys which are far
0427  * above the logical maximum described in descriptor. This extends
0428  * the original value of 0x28c of logical maximum to 0x104d
0429  */
0430 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
0431         unsigned int *rsize)
0432 {
0433     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0434 
0435     if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
0436             rdesc[84] == 0x8c && rdesc[85] == 0x02) {
0437         hid_info(hdev,
0438              "fixing up Logitech keyboard report descriptor\n");
0439         rdesc[84] = rdesc[89] = 0x4d;
0440         rdesc[85] = rdesc[90] = 0x10;
0441     }
0442     if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
0443             rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
0444             rdesc[49] == 0x81 && rdesc[50] == 0x06) {
0445         hid_info(hdev,
0446              "fixing up rel/abs in Logitech report descriptor\n");
0447         rdesc[33] = rdesc[50] = 0x02;
0448     }
0449 
0450     switch (hdev->product) {
0451 
0452     case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
0453         if (*rsize == FG_RDESC_ORIG_SIZE) {
0454             hid_info(hdev,
0455                 "fixing up Logitech Wingman Formula GP report descriptor\n");
0456             rdesc = fg_rdesc_fixed;
0457             *rsize = sizeof(fg_rdesc_fixed);
0458         } else {
0459             hid_info(hdev,
0460                 "rdesc size test failed for formula gp\n");
0461         }
0462         break;
0463 
0464 
0465     case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
0466         if (*rsize == FFG_RDESC_ORIG_SIZE) {
0467             hid_info(hdev,
0468                 "fixing up Logitech Wingman Formula Force GP report descriptor\n");
0469             rdesc = ffg_rdesc_fixed;
0470             *rsize = sizeof(ffg_rdesc_fixed);
0471         }
0472         break;
0473 
0474     /* Several wheels report as this id when operating in emulation mode. */
0475     case USB_DEVICE_ID_LOGITECH_WHEEL:
0476         if (*rsize == DF_RDESC_ORIG_SIZE) {
0477             hid_info(hdev,
0478                 "fixing up Logitech Driving Force report descriptor\n");
0479             rdesc = df_rdesc_fixed;
0480             *rsize = sizeof(df_rdesc_fixed);
0481         }
0482         break;
0483 
0484     case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
0485         if (*rsize == MOMO_RDESC_ORIG_SIZE) {
0486             hid_info(hdev,
0487                 "fixing up Logitech Momo Force (Red) report descriptor\n");
0488             rdesc = momo_rdesc_fixed;
0489             *rsize = sizeof(momo_rdesc_fixed);
0490         }
0491         break;
0492 
0493     case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
0494         if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
0495             hid_info(hdev,
0496                 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
0497             rdesc = momo2_rdesc_fixed;
0498             *rsize = sizeof(momo2_rdesc_fixed);
0499         }
0500         break;
0501 
0502     case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
0503         if (*rsize == FV_RDESC_ORIG_SIZE) {
0504             hid_info(hdev,
0505                 "fixing up Logitech Formula Vibration report descriptor\n");
0506             rdesc = fv_rdesc_fixed;
0507             *rsize = sizeof(fv_rdesc_fixed);
0508         }
0509         break;
0510 
0511     case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
0512         if (*rsize == DFP_RDESC_ORIG_SIZE) {
0513             hid_info(hdev,
0514                 "fixing up Logitech Driving Force Pro report descriptor\n");
0515             rdesc = dfp_rdesc_fixed;
0516             *rsize = sizeof(dfp_rdesc_fixed);
0517         }
0518         break;
0519 
0520     case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
0521         if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
0522                 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
0523             hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
0524             rdesc[41] = 0x05;
0525             rdesc[42] = 0x09;
0526             rdesc[47] = 0x95;
0527             rdesc[48] = 0x0B;
0528         }
0529         break;
0530     }
0531 
0532     return rdesc;
0533 }
0534 
0535 #define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
0536         EV_KEY, (c))
0537 
0538 static int lg_ultrax_remote_mapping(struct hid_input *hi,
0539         struct hid_usage *usage, unsigned long **bit, int *max)
0540 {
0541     if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
0542         return 0;
0543 
0544     set_bit(EV_REP, hi->input->evbit);
0545     switch (usage->hid & HID_USAGE) {
0546     /* Reported on Logitech Ultra X Media Remote */
0547     case 0x004: lg_map_key_clear(KEY_AGAIN);    break;
0548     case 0x00d: lg_map_key_clear(KEY_HOME);     break;
0549     case 0x024: lg_map_key_clear(KEY_SHUFFLE);  break;
0550     case 0x025: lg_map_key_clear(KEY_TV);       break;
0551     case 0x026: lg_map_key_clear(KEY_MENU);     break;
0552     case 0x031: lg_map_key_clear(KEY_AUDIO);    break;
0553     case 0x032: lg_map_key_clear(KEY_TEXT);     break;
0554     case 0x033: lg_map_key_clear(KEY_LAST);     break;
0555     case 0x047: lg_map_key_clear(KEY_MP3);      break;
0556     case 0x048: lg_map_key_clear(KEY_DVD);      break;
0557     case 0x049: lg_map_key_clear(KEY_MEDIA);    break;
0558     case 0x04a: lg_map_key_clear(KEY_VIDEO);    break;
0559     case 0x04b: lg_map_key_clear(KEY_ANGLE);    break;
0560     case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
0561     case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
0562     case 0x051: lg_map_key_clear(KEY_RED);      break;
0563     case 0x052: lg_map_key_clear(KEY_CLOSE);    break;
0564 
0565     default:
0566         return 0;
0567     }
0568     return 1;
0569 }
0570 
0571 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
0572         unsigned long **bit, int *max)
0573 {
0574     if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
0575         return 0;
0576 
0577     switch (usage->hid & HID_USAGE) {
0578     case 0x1001: lg_map_key_clear(KEY_MESSENGER);       break;
0579     case 0x1003: lg_map_key_clear(KEY_SOUND);       break;
0580     case 0x1004: lg_map_key_clear(KEY_VIDEO);       break;
0581     case 0x1005: lg_map_key_clear(KEY_AUDIO);       break;
0582     case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);       break;
0583     /* The following two entries are Playlist 1 and 2 on the MX3200 */
0584     case 0x100f: lg_map_key_clear(KEY_FN_1);        break;
0585     case 0x1010: lg_map_key_clear(KEY_FN_2);        break;
0586     case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);    break;
0587     case 0x1012: lg_map_key_clear(KEY_NEXTSONG);        break;
0588     case 0x1013: lg_map_key_clear(KEY_CAMERA);      break;
0589     case 0x1014: lg_map_key_clear(KEY_MESSENGER);       break;
0590     case 0x1015: lg_map_key_clear(KEY_RECORD);      break;
0591     case 0x1016: lg_map_key_clear(KEY_PLAYER);      break;
0592     case 0x1017: lg_map_key_clear(KEY_EJECTCD);     break;
0593     case 0x1018: lg_map_key_clear(KEY_MEDIA);       break;
0594     case 0x1019: lg_map_key_clear(KEY_PROG1);       break;
0595     case 0x101a: lg_map_key_clear(KEY_PROG2);       break;
0596     case 0x101b: lg_map_key_clear(KEY_PROG3);       break;
0597     case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);    break;
0598     case 0x101f: lg_map_key_clear(KEY_ZOOMIN);      break;
0599     case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);     break;
0600     case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);       break;
0601     case 0x1023: lg_map_key_clear(KEY_CLOSE);       break;
0602     case 0x1027: lg_map_key_clear(KEY_MENU);        break;
0603     /* this one is marked as 'Rotate' */
0604     case 0x1028: lg_map_key_clear(KEY_ANGLE);       break;
0605     case 0x1029: lg_map_key_clear(KEY_SHUFFLE);     break;
0606     case 0x102a: lg_map_key_clear(KEY_BACK);        break;
0607     case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);    break;
0608     case 0x102d: lg_map_key_clear(KEY_WWW);         break;
0609     /* The following two are 'Start/answer call' and 'End/reject call'
0610        on the MX3200 */
0611     case 0x1031: lg_map_key_clear(KEY_OK);          break;
0612     case 0x1032: lg_map_key_clear(KEY_CANCEL);      break;
0613     case 0x1041: lg_map_key_clear(KEY_BATTERY);     break;
0614     case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);   break;
0615     case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);     break;
0616     case 0x1044: lg_map_key_clear(KEY_PRESENTATION);    break;
0617     case 0x1045: lg_map_key_clear(KEY_UNDO);        break;
0618     case 0x1046: lg_map_key_clear(KEY_REDO);        break;
0619     case 0x1047: lg_map_key_clear(KEY_PRINT);       break;
0620     case 0x1048: lg_map_key_clear(KEY_SAVE);        break;
0621     case 0x1049: lg_map_key_clear(KEY_PROG1);       break;
0622     case 0x104a: lg_map_key_clear(KEY_PROG2);       break;
0623     case 0x104b: lg_map_key_clear(KEY_PROG3);       break;
0624     case 0x104c: lg_map_key_clear(KEY_PROG4);       break;
0625 
0626     default:
0627         return 0;
0628     }
0629     return 1;
0630 }
0631 
0632 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0633         struct hid_field *field, struct hid_usage *usage,
0634         unsigned long **bit, int *max)
0635 {
0636     /* extended mapping for certain Logitech hardware (Logitech cordless
0637        desktop LX500) */
0638     static const u8 e_keymap[] = {
0639           0,216,  0,213,175,156,  0,  0,  0,  0,
0640         144,  0,  0,  0,  0,  0,  0,  0,  0,212,
0641         174,167,152,161,112,  0,  0,  0,154,  0,
0642           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0643           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0644           0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
0645           0,  0,  0,  0,  0,183,184,185,186,187,
0646         188,189,190,191,192,193,194,  0,  0,  0
0647     };
0648     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0649     unsigned int hid = usage->hid;
0650 
0651     if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
0652             lg_ultrax_remote_mapping(hi, usage, bit, max))
0653         return 1;
0654 
0655     if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
0656         return 1;
0657 
0658     if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
0659         return 0;
0660 
0661     hid &= HID_USAGE;
0662 
0663     /* Special handling for Logitech Cordless Desktop */
0664     if (field->application == HID_GD_MOUSE) {
0665         if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
0666                 (hid == 7 || hid == 8))
0667             return -1;
0668     } else {
0669         if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
0670                 hid < ARRAY_SIZE(e_keymap) &&
0671                 e_keymap[hid] != 0) {
0672             hid_map_usage(hi, usage, bit, max, EV_KEY,
0673                     e_keymap[hid]);
0674             return 1;
0675         }
0676     }
0677 
0678     return 0;
0679 }
0680 
0681 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
0682         struct hid_field *field, struct hid_usage *usage,
0683         unsigned long **bit, int *max)
0684 {
0685     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0686 
0687     if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
0688             (field->flags & HID_MAIN_ITEM_RELATIVE))
0689         field->flags &= ~HID_MAIN_ITEM_RELATIVE;
0690 
0691     if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
0692              usage->type == EV_REL || usage->type == EV_ABS))
0693         clear_bit(usage->code, *bit);
0694 
0695     /* Ensure that Logitech wheels are not given a default fuzz/flat value */
0696     if (usage->type == EV_ABS && (usage->code == ABS_X ||
0697             usage->code == ABS_Y || usage->code == ABS_Z ||
0698             usage->code == ABS_RZ)) {
0699         switch (hdev->product) {
0700         case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
0701         case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
0702         case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
0703         case USB_DEVICE_ID_LOGITECH_WHEEL:
0704         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
0705         case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
0706         case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
0707         case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
0708         case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
0709         case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
0710         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
0711         case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
0712             field->application = HID_GD_MULTIAXIS;
0713             break;
0714         default:
0715             break;
0716         }
0717     }
0718 
0719     return 0;
0720 }
0721 
0722 static int lg_event(struct hid_device *hdev, struct hid_field *field,
0723         struct hid_usage *usage, __s32 value)
0724 {
0725     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0726 
0727     if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
0728         input_event(field->hidinput->input, usage->type, usage->code,
0729                 -value);
0730         return 1;
0731     }
0732     if (drv_data->quirks & LG_FF4) {
0733         return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
0734     }
0735 
0736     return 0;
0737 }
0738 
0739 static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
0740         u8 *rd, int size)
0741 {
0742     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0743 
0744     if (drv_data->quirks & LG_FF4)
0745         return lg4ff_raw_event(hdev, report, rd, size, drv_data);
0746 
0747     return 0;
0748 }
0749 
0750 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
0751 {
0752     struct usb_interface *iface;
0753     __u8 iface_num;
0754     unsigned int connect_mask = HID_CONNECT_DEFAULT;
0755     struct lg_drv_data *drv_data;
0756     int ret;
0757 
0758     if (!hid_is_usb(hdev))
0759         return -EINVAL;
0760 
0761     iface = to_usb_interface(hdev->dev.parent);
0762     iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
0763 
0764     /* G29 only work with the 1st interface */
0765     if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
0766         (iface_num != 0)) {
0767         dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
0768         return -ENODEV;
0769     }
0770 
0771     drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
0772     if (!drv_data) {
0773         hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
0774         return -ENOMEM;
0775     }
0776     drv_data->quirks = id->driver_data;
0777 
0778     hid_set_drvdata(hdev, (void *)drv_data);
0779 
0780     if (drv_data->quirks & LG_NOGET)
0781         hdev->quirks |= HID_QUIRK_NOGET;
0782 
0783     ret = hid_parse(hdev);
0784     if (ret) {
0785         hid_err(hdev, "parse failed\n");
0786         goto err_free;
0787     }
0788 
0789     if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
0790         connect_mask &= ~HID_CONNECT_FF;
0791 
0792     ret = hid_hw_start(hdev, connect_mask);
0793     if (ret) {
0794         hid_err(hdev, "hw start failed\n");
0795         goto err_free;
0796     }
0797 
0798     /* Setup wireless link with Logitech Wii wheel */
0799     if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
0800         static const unsigned char cbuf[] = {
0801             0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
0802         };
0803         u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
0804 
0805         if (!buf) {
0806             ret = -ENOMEM;
0807             goto err_stop;
0808         }
0809 
0810         ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
0811                     HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
0812         if (ret >= 0) {
0813             /* insert a little delay of 10 jiffies ~ 40ms */
0814             wait_queue_head_t wait;
0815             init_waitqueue_head (&wait);
0816             wait_event_interruptible_timeout(wait, 0,
0817                              msecs_to_jiffies(40));
0818 
0819             /* Select random Address */
0820             buf[1] = 0xB2;
0821             get_random_bytes(&buf[2], 2);
0822 
0823             ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
0824                     HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
0825         }
0826         kfree(buf);
0827     }
0828 
0829     if (drv_data->quirks & LG_FF)
0830         ret = lgff_init(hdev);
0831     else if (drv_data->quirks & LG_FF2)
0832         ret = lg2ff_init(hdev);
0833     else if (drv_data->quirks & LG_FF3)
0834         ret = lg3ff_init(hdev);
0835     else if (drv_data->quirks & LG_FF4)
0836         ret = lg4ff_init(hdev);
0837 
0838     if (ret)
0839         goto err_stop;
0840 
0841     return 0;
0842 
0843 err_stop:
0844     hid_hw_stop(hdev);
0845 err_free:
0846     kfree(drv_data);
0847     return ret;
0848 }
0849 
0850 static void lg_remove(struct hid_device *hdev)
0851 {
0852     struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
0853     if (drv_data->quirks & LG_FF4)
0854         lg4ff_deinit(hdev);
0855     hid_hw_stop(hdev);
0856     kfree(drv_data);
0857 }
0858 
0859 static const struct hid_device_id lg_devices[] = {
0860     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
0861         .driver_data = LG_RDESC | LG_WIRELESS },
0862 
0863     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
0864         .driver_data = LG_BAD_RELATIVE_KEYS },
0865 
0866     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
0867         .driver_data = LG_DUPLICATE_USAGES },
0868 
0869     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
0870         .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
0871     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
0872         .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
0873 
0874     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
0875         .driver_data = LG_NOGET },
0876     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
0877         .driver_data = LG_NOGET },
0878     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
0879         .driver_data = LG_NOGET | LG_FF4 },
0880 
0881     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
0882         .driver_data = LG_FF2 },
0883     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
0884         .driver_data = LG_FF },
0885     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
0886         .driver_data = LG_FF },
0887     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
0888         .driver_data = LG_FF4 },
0889     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
0890         .driver_data = LG_FF },
0891     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
0892         .driver_data = LG_FF },
0893     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
0894         .driver_data = LG_NOGET | LG_FF4 },
0895     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
0896         .driver_data = LG_FF4 },
0897     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
0898         .driver_data = LG_FF2 },
0899     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
0900         .driver_data = LG_FF4 },
0901     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
0902         .driver_data = LG_FF4 },
0903     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
0904         .driver_data = LG_FF4 },
0905     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
0906         .driver_data = LG_NOGET | LG_FF4 },
0907     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
0908         .driver_data = LG_FF4 },
0909     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
0910         .driver_data = LG_NOGET },
0911     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
0912         .driver_data = LG_NOGET | LG_FF4 },
0913     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
0914         .driver_data = LG_NOGET | LG_FF2 },
0915     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
0916         .driver_data = LG_FF3 },
0917     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
0918         .driver_data = LG_RDESC_REL_ABS },
0919     { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
0920         .driver_data = LG_RDESC_REL_ABS },
0921     { }
0922 };
0923 
0924 MODULE_DEVICE_TABLE(hid, lg_devices);
0925 
0926 static struct hid_driver lg_driver = {
0927     .name = "logitech",
0928     .id_table = lg_devices,
0929     .report_fixup = lg_report_fixup,
0930     .input_mapping = lg_input_mapping,
0931     .input_mapped = lg_input_mapped,
0932     .event = lg_event,
0933     .raw_event = lg_raw_event,
0934     .probe = lg_probe,
0935     .remove = lg_remove,
0936 };
0937 module_hid_driver(lg_driver);
0938 
0939 #ifdef CONFIG_LOGIWHEELS_FF
0940 int lg4ff_no_autoswitch = 0;
0941 module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
0942 MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
0943 #endif
0944 
0945 MODULE_LICENSE("GPL");