root/drivers/hid/hid-lg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lg_report_fixup
  2. lg_ultrax_remote_mapping
  3. lg_dinovo_mapping
  4. lg_wireless_mapping
  5. lg_input_mapping
  6. lg_input_mapped
  7. lg_event
  8. lg_raw_event
  9. lg_probe
  10. lg_remove

   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  */
  61 static __u8 df_rdesc_fixed[] = {
  62 0x05, 0x01,         /*  Usage Page (Desktop),                   */
  63 0x09, 0x04,         /*  Usage (Joystick),                       */
  64 0xA1, 0x01,         /*  Collection (Application),               */
  65 0xA1, 0x02,         /*      Collection (Logical),               */
  66 0x95, 0x01,         /*          Report Count (1),               */
  67 0x75, 0x0A,         /*          Report Size (10),               */
  68 0x14,               /*          Logical Minimum (0),            */
  69 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
  70 0x34,               /*          Physical Minimum (0),           */
  71 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
  72 0x09, 0x30,         /*          Usage (X),                      */
  73 0x81, 0x02,         /*          Input (Variable),               */
  74 0x95, 0x0C,         /*          Report Count (12),              */
  75 0x75, 0x01,         /*          Report Size (1),                */
  76 0x25, 0x01,         /*          Logical Maximum (1),            */
  77 0x45, 0x01,         /*          Physical Maximum (1),           */
  78 0x05, 0x09,         /*          Usage (Buttons),                */
  79 0x19, 0x01,         /*          Usage Minimum (1),              */
  80 0x29, 0x0c,         /*          Usage Maximum (12),             */
  81 0x81, 0x02,         /*          Input (Variable),               */
  82 0x95, 0x02,         /*          Report Count (2),               */
  83 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
  84 0x09, 0x01,         /*          Usage (?: 1),                   */
  85 0x81, 0x02,         /*          Input (Variable),               */
  86 0x05, 0x01,         /*          Usage Page (Desktop),           */
  87 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
  88 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
  89 0x95, 0x01,         /*          Report Count (1),               */
  90 0x75, 0x08,         /*          Report Size (8),                */
  91 0x81, 0x02,         /*          Input (Variable),               */
  92 0x25, 0x07,         /*          Logical Maximum (7),            */
  93 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
  94 0x75, 0x04,         /*          Report Size (4),                */
  95 0x65, 0x14,         /*          Unit (Degrees),                 */
  96 0x09, 0x39,         /*          Usage (Hat Switch),             */
  97 0x81, 0x42,         /*          Input (Variable, Null State),   */
  98 0x75, 0x01,         /*          Report Size (1),                */
  99 0x95, 0x04,         /*          Report Count (4),               */
 100 0x65, 0x00,         /*          Unit (none),                    */
 101 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
 102 0x09, 0x01,         /*          Usage (?: 1),                   */
 103 0x25, 0x01,         /*          Logical Maximum (1),            */
 104 0x45, 0x01,         /*          Physical Maximum (1),           */
 105 0x81, 0x02,         /*          Input (Variable),               */
 106 0x05, 0x01,         /*          Usage Page (Desktop),           */
 107 0x95, 0x01,         /*          Report Count (1),               */
 108 0x75, 0x08,         /*          Report Size (8),                */
 109 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 110 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 111 0x09, 0x31,         /*          Usage (Y),                      */
 112 0x81, 0x02,         /*          Input (Variable),               */
 113 0x09, 0x35,         /*          Usage (Rz),                     */
 114 0x81, 0x02,         /*          Input (Variable),               */
 115 0xC0,               /*      End Collection,                     */
 116 0xA1, 0x02,         /*      Collection (Logical),               */
 117 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 118 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 119 0x95, 0x07,         /*          Report Count (7),               */
 120 0x75, 0x08,         /*          Report Size (8),                */
 121 0x09, 0x03,         /*          Usage (?: 3),                   */
 122 0x91, 0x02,         /*          Output (Variable),              */
 123 0xC0,               /*      End Collection,                     */
 124 0xC0                /*  End Collection                          */
 125 };
 126 
 127 static __u8 dfp_rdesc_fixed[] = {
 128 0x05, 0x01,         /*  Usage Page (Desktop),                   */
 129 0x09, 0x04,         /*  Usage (Joystick),                       */
 130 0xA1, 0x01,         /*  Collection (Application),               */
 131 0xA1, 0x02,         /*      Collection (Logical),               */
 132 0x95, 0x01,         /*          Report Count (1),               */
 133 0x75, 0x0E,         /*          Report Size (14),               */
 134 0x14,               /*          Logical Minimum (0),            */
 135 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
 136 0x34,               /*          Physical Minimum (0),           */
 137 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
 138 0x09, 0x30,         /*          Usage (X),                      */
 139 0x81, 0x02,         /*          Input (Variable),               */
 140 0x95, 0x0E,         /*          Report Count (14),              */
 141 0x75, 0x01,         /*          Report Size (1),                */
 142 0x25, 0x01,         /*          Logical Maximum (1),            */
 143 0x45, 0x01,         /*          Physical Maximum (1),           */
 144 0x05, 0x09,         /*          Usage Page (Button),            */
 145 0x19, 0x01,         /*          Usage Minimum (01h),            */
 146 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
 147 0x81, 0x02,         /*          Input (Variable),               */
 148 0x05, 0x01,         /*          Usage Page (Desktop),           */
 149 0x95, 0x01,         /*          Report Count (1),               */
 150 0x75, 0x04,         /*          Report Size (4),                */
 151 0x25, 0x07,         /*          Logical Maximum (7),            */
 152 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 153 0x65, 0x14,         /*          Unit (Degrees),                 */
 154 0x09, 0x39,         /*          Usage (Hat Switch),             */
 155 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
 156 0x65, 0x00,         /*          Unit,                           */
 157 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 158 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 159 0x75, 0x08,         /*          Report Size (8),                */
 160 0x81, 0x01,         /*          Input (Constant),               */
 161 0x09, 0x31,         /*          Usage (Y),                      */
 162 0x81, 0x02,         /*          Input (Variable),               */
 163 0x09, 0x35,         /*          Usage (Rz),                     */
 164 0x81, 0x02,         /*          Input (Variable),               */
 165 0x81, 0x01,         /*          Input (Constant),               */
 166 0xC0,               /*      End Collection,                     */
 167 0xA1, 0x02,         /*      Collection (Logical),               */
 168 0x09, 0x02,         /*          Usage (02h),                    */
 169 0x95, 0x07,         /*          Report Count (7),               */
 170 0x91, 0x02,         /*          Output (Variable),              */
 171 0xC0,               /*      End Collection,                     */
 172 0xC0                /*  End Collection                          */
 173 };
 174 
 175 static __u8 fv_rdesc_fixed[] = {
 176 0x05, 0x01,         /*  Usage Page (Desktop),                   */
 177 0x09, 0x04,         /*  Usage (Joystick),                       */
 178 0xA1, 0x01,         /*  Collection (Application),               */
 179 0xA1, 0x02,         /*      Collection (Logical),               */
 180 0x95, 0x01,         /*          Report Count (1),               */
 181 0x75, 0x0A,         /*          Report Size (10),               */
 182 0x15, 0x00,         /*          Logical Minimum (0),            */
 183 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
 184 0x35, 0x00,         /*          Physical Minimum (0),           */
 185 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
 186 0x09, 0x30,         /*          Usage (X),                      */
 187 0x81, 0x02,         /*          Input (Variable),               */
 188 0x95, 0x0C,         /*          Report Count (12),              */
 189 0x75, 0x01,         /*          Report Size (1),                */
 190 0x25, 0x01,         /*          Logical Maximum (1),            */
 191 0x45, 0x01,         /*          Physical Maximum (1),           */
 192 0x05, 0x09,         /*          Usage Page (Button),            */
 193 0x19, 0x01,         /*          Usage Minimum (01h),            */
 194 0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
 195 0x81, 0x02,         /*          Input (Variable),               */
 196 0x95, 0x02,         /*          Report Count (2),               */
 197 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
 198 0x09, 0x01,         /*          Usage (01h),                    */
 199 0x81, 0x02,         /*          Input (Variable),               */
 200 0x09, 0x02,         /*          Usage (02h),                    */
 201 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 202 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 203 0x95, 0x01,         /*          Report Count (1),               */
 204 0x75, 0x08,         /*          Report Size (8),                */
 205 0x81, 0x02,         /*          Input (Variable),               */
 206 0x05, 0x01,         /*          Usage Page (Desktop),           */
 207 0x25, 0x07,         /*          Logical Maximum (7),            */
 208 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 209 0x75, 0x04,         /*          Report Size (4),                */
 210 0x65, 0x14,         /*          Unit (Degrees),                 */
 211 0x09, 0x39,         /*          Usage (Hat Switch),             */
 212 0x81, 0x42,         /*          Input (Variable, Null State),   */
 213 0x75, 0x01,         /*          Report Size (1),                */
 214 0x95, 0x04,         /*          Report Count (4),               */
 215 0x65, 0x00,         /*          Unit,                           */
 216 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
 217 0x09, 0x01,         /*          Usage (01h),                    */
 218 0x25, 0x01,         /*          Logical Maximum (1),            */
 219 0x45, 0x01,         /*          Physical Maximum (1),           */
 220 0x81, 0x02,         /*          Input (Variable),               */
 221 0x05, 0x01,         /*          Usage Page (Desktop),           */
 222 0x95, 0x01,         /*          Report Count (1),               */
 223 0x75, 0x08,         /*          Report Size (8),                */
 224 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 225 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 226 0x09, 0x31,         /*          Usage (Y),                      */
 227 0x81, 0x02,         /*          Input (Variable),               */
 228 0x09, 0x32,         /*          Usage (Z),                      */
 229 0x81, 0x02,         /*          Input (Variable),               */
 230 0xC0,               /*      End Collection,                     */
 231 0xA1, 0x02,         /*      Collection (Logical),               */
 232 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 233 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 234 0x95, 0x07,         /*          Report Count (7),               */
 235 0x75, 0x08,         /*          Report Size (8),                */
 236 0x09, 0x03,         /*          Usage (03h),                    */
 237 0x91, 0x02,         /*          Output (Variable),              */
 238 0xC0,               /*      End Collection,                     */
 239 0xC0                /*  End Collection                          */
 240 };
 241 
 242 static __u8 momo_rdesc_fixed[] = {
 243 0x05, 0x01,         /*  Usage Page (Desktop),               */
 244 0x09, 0x04,         /*  Usage (Joystick),                   */
 245 0xA1, 0x01,         /*  Collection (Application),           */
 246 0xA1, 0x02,         /*      Collection (Logical),           */
 247 0x95, 0x01,         /*          Report Count (1),           */
 248 0x75, 0x0A,         /*          Report Size (10),           */
 249 0x15, 0x00,         /*          Logical Minimum (0),        */
 250 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 251 0x35, 0x00,         /*          Physical Minimum (0),       */
 252 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 253 0x09, 0x30,         /*          Usage (X),                  */
 254 0x81, 0x02,         /*          Input (Variable),           */
 255 0x95, 0x08,         /*          Report Count (8),           */
 256 0x75, 0x01,         /*          Report Size (1),            */
 257 0x25, 0x01,         /*          Logical Maximum (1),        */
 258 0x45, 0x01,         /*          Physical Maximum (1),       */
 259 0x05, 0x09,         /*          Usage Page (Button),        */
 260 0x19, 0x01,         /*          Usage Minimum (01h),        */
 261 0x29, 0x08,         /*          Usage Maximum (08h),        */
 262 0x81, 0x02,         /*          Input (Variable),           */
 263 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 264 0x75, 0x0E,         /*          Report Size (14),           */
 265 0x95, 0x01,         /*          Report Count (1),           */
 266 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 267 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 268 0x09, 0x00,         /*          Usage (00h),                */
 269 0x81, 0x02,         /*          Input (Variable),           */
 270 0x05, 0x01,         /*          Usage Page (Desktop),       */
 271 0x75, 0x08,         /*          Report Size (8),            */
 272 0x09, 0x31,         /*          Usage (Y),                  */
 273 0x81, 0x02,         /*          Input (Variable),           */
 274 0x09, 0x32,         /*          Usage (Z),                  */
 275 0x81, 0x02,         /*          Input (Variable),           */
 276 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 277 0x09, 0x01,         /*          Usage (01h),                */
 278 0x81, 0x02,         /*          Input (Variable),           */
 279 0xC0,               /*      End Collection,                 */
 280 0xA1, 0x02,         /*      Collection (Logical),           */
 281 0x09, 0x02,         /*          Usage (02h),                */
 282 0x95, 0x07,         /*          Report Count (7),           */
 283 0x91, 0x02,         /*          Output (Variable),          */
 284 0xC0,               /*      End Collection,                 */
 285 0xC0                /*  End Collection                      */
 286 };
 287 
 288 static __u8 momo2_rdesc_fixed[] = {
 289 0x05, 0x01,         /*  Usage Page (Desktop),               */
 290 0x09, 0x04,         /*  Usage (Joystick),                   */
 291 0xA1, 0x01,         /*  Collection (Application),           */
 292 0xA1, 0x02,         /*      Collection (Logical),           */
 293 0x95, 0x01,         /*          Report Count (1),           */
 294 0x75, 0x0A,         /*          Report Size (10),           */
 295 0x15, 0x00,         /*          Logical Minimum (0),        */
 296 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 297 0x35, 0x00,         /*          Physical Minimum (0),       */
 298 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 299 0x09, 0x30,         /*          Usage (X),                  */
 300 0x81, 0x02,         /*          Input (Variable),           */
 301 0x95, 0x0A,         /*          Report Count (10),          */
 302 0x75, 0x01,         /*          Report Size (1),            */
 303 0x25, 0x01,         /*          Logical Maximum (1),        */
 304 0x45, 0x01,         /*          Physical Maximum (1),       */
 305 0x05, 0x09,         /*          Usage Page (Button),        */
 306 0x19, 0x01,         /*          Usage Minimum (01h),        */
 307 0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
 308 0x81, 0x02,         /*          Input (Variable),           */
 309 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 310 0x09, 0x00,         /*          Usage (00h),                */
 311 0x95, 0x04,         /*          Report Count (4),           */
 312 0x81, 0x02,         /*          Input (Variable),           */
 313 0x95, 0x01,         /*          Report Count (1),           */
 314 0x75, 0x08,         /*          Report Size (8),            */
 315 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 316 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 317 0x09, 0x01,         /*          Usage (01h),                */
 318 0x81, 0x02,         /*          Input (Variable),           */
 319 0x05, 0x01,         /*          Usage Page (Desktop),       */
 320 0x09, 0x31,         /*          Usage (Y),                  */
 321 0x81, 0x02,         /*          Input (Variable),           */
 322 0x09, 0x32,         /*          Usage (Z),                  */
 323 0x81, 0x02,         /*          Input (Variable),           */
 324 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 325 0x09, 0x00,         /*          Usage (00h),                */
 326 0x81, 0x02,         /*          Input (Variable),           */
 327 0xC0,               /*      End Collection,                 */
 328 0xA1, 0x02,         /*      Collection (Logical),           */
 329 0x09, 0x02,         /*          Usage (02h),                */
 330 0x95, 0x07,         /*          Report Count (7),           */
 331 0x91, 0x02,         /*          Output (Variable),          */
 332 0xC0,               /*      End Collection,                 */
 333 0xC0                /*  End Collection                      */
 334 };
 335 
 336 static __u8 ffg_rdesc_fixed[] = {
 337 0x05, 0x01,         /*  Usage Page (Desktop),               */
 338 0x09, 0x04,         /*  Usage (Joystik),                    */
 339 0xA1, 0x01,         /*  Collection (Application),           */
 340 0xA1, 0x02,         /*      Collection (Logical),           */
 341 0x95, 0x01,         /*          Report Count (1),           */
 342 0x75, 0x0A,         /*          Report Size (10),           */
 343 0x15, 0x00,         /*          Logical Minimum (0),        */
 344 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 345 0x35, 0x00,         /*          Physical Minimum (0),       */
 346 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
 347 0x09, 0x30,         /*          Usage (X),                  */
 348 0x81, 0x02,         /*          Input (Variable),           */
 349 0x95, 0x06,         /*          Report Count (6),           */
 350 0x75, 0x01,         /*          Report Size (1),            */
 351 0x25, 0x01,         /*          Logical Maximum (1),        */
 352 0x45, 0x01,         /*          Physical Maximum (1),       */
 353 0x05, 0x09,         /*          Usage Page (Button),        */
 354 0x19, 0x01,         /*          Usage Minimum (01h),        */
 355 0x29, 0x06,         /*          Usage Maximum (06h),        */
 356 0x81, 0x02,         /*          Input (Variable),           */
 357 0x95, 0x01,         /*          Report Count (1),           */
 358 0x75, 0x08,         /*          Report Size (8),            */
 359 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 360 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 361 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 362 0x09, 0x01,         /*          Usage (01h),                */
 363 0x81, 0x02,         /*          Input (Variable),           */
 364 0x05, 0x01,         /*          Usage Page (Desktop),       */
 365 0x81, 0x01,         /*          Input (Constant),           */
 366 0x09, 0x31,         /*          Usage (Y),                  */
 367 0x81, 0x02,         /*          Input (Variable),           */
 368 0x09, 0x32,         /*          Usage (Z),                  */
 369 0x81, 0x02,         /*          Input (Variable),           */
 370 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
 371 0x09, 0x01,         /*          Usage (01h),                */
 372 0x81, 0x02,         /*          Input (Variable),           */
 373 0xC0,               /*      End Collection,                 */
 374 0xA1, 0x02,         /*      Collection (Logical),           */
 375 0x09, 0x02,         /*          Usage (02h),                */
 376 0x95, 0x07,         /*          Report Count (7),           */
 377 0x91, 0x02,         /*          Output (Variable),          */
 378 0xC0,               /*      End Collection,                 */
 379 0xC0                /*  End Collection                      */
 380 };
 381 
 382 static __u8 fg_rdesc_fixed[] = {
 383 0x05, 0x01,         /*  Usage Page (Desktop),               */
 384 0x09, 0x04,         /*  Usage (Joystik),                    */
 385 0xA1, 0x01,         /*  Collection (Application),           */
 386 0xA1, 0x02,         /*      Collection (Logical),           */
 387 0x15, 0x00,         /*          Logical Minimum (0),        */
 388 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 389 0x35, 0x00,         /*          Physical Minimum (0),       */
 390 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 391 0x75, 0x08,         /*          Report Size (8),            */
 392 0x95, 0x01,         /*          Report Count (1),           */
 393 0x09, 0x30,         /*          Usage (X),                  */
 394 0x81, 0x02,         /*          Input (Variable),           */
 395 0xA4,               /*  Push,                               */
 396 0x25, 0x01,         /*          Logical Maximum (1),        */
 397 0x45, 0x01,         /*          Physical Maximum (1),       */
 398 0x75, 0x01,         /*          Report Size (1),            */
 399 0x95, 0x02,         /*          Report Count (2),           */
 400 0x81, 0x01,         /*          Input (Constant),           */
 401 0x95, 0x06,         /*          Report Count (6),           */
 402 0x05, 0x09,         /*          Usage Page (Button),        */
 403 0x19, 0x01,         /*          Usage Minimum (01h),        */
 404 0x29, 0x06,         /*          Usage Maximum (06h),        */
 405 0x81, 0x02,         /*          Input (Variable),           */
 406 0x05, 0x01,         /*          Usage Page (Desktop),       */
 407 0xB4,               /*  Pop,                                */
 408 0x81, 0x02,         /*          Input (Constant),           */
 409 0x09, 0x31,         /*          Usage (Y),                  */
 410 0x81, 0x02,         /*          Input (Variable),           */
 411 0x09, 0x32,         /*          Usage (Z),                  */
 412 0x81, 0x02,         /*          Input (Variable),           */
 413 0xC0,               /*      End Collection,                 */
 414 0xA1, 0x02,         /*      Collection (Logical),           */
 415 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
 416 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
 417 0x75, 0x08,         /*          Report Size (8),            */
 418 0x95, 0x04,         /*          Report Count (4),           */
 419 0x09, 0x02,         /*          Usage (02h),                */
 420 0xB1, 0x02,         /*          Feature (Variable),         */
 421 0xC0,               /*      End Collection,                 */
 422 0xC0                /*  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  */
 430 static __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 
 538 static 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 
 571 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
 572                 unsigned long **bit, int *max)
 573 {
 574         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 575                 return 0;
 576 
 577         switch (usage->hid & HID_USAGE) {
 578 
 579         case 0x00d: lg_map_key_clear(KEY_MEDIA);        break;
 580         default:
 581                 return 0;
 582 
 583         }
 584         return 1;
 585 }
 586 
 587 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
 588                 unsigned long **bit, int *max)
 589 {
 590         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 591                 return 0;
 592 
 593         switch (usage->hid & HID_USAGE) {
 594         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
 595         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
 596         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
 597         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
 598         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
 599         /* The following two entries are Playlist 1 and 2 on the MX3200 */
 600         case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
 601         case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
 602         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
 603         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
 604         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
 605         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
 606         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
 607         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
 608         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
 609         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
 610         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
 611         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
 612         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
 613         case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 614         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
 615         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
 616         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
 617         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
 618         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
 619         /* this one is marked as 'Rotate' */
 620         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
 621         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
 622         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
 623         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 624         case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
 625         /* The following two are 'Start/answer call' and 'End/reject call'
 626            on the MX3200 */
 627         case 0x1031: lg_map_key_clear(KEY_OK);                  break;
 628         case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
 629         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
 630         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
 631         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
 632         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
 633         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
 634         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
 635         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
 636         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
 637         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
 638         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
 639         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
 640         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
 641 
 642         default:
 643                 return 0;
 644         }
 645         return 1;
 646 }
 647 
 648 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 649                 struct hid_field *field, struct hid_usage *usage,
 650                 unsigned long **bit, int *max)
 651 {
 652         /* extended mapping for certain Logitech hardware (Logitech cordless
 653            desktop LX500) */
 654         static const u8 e_keymap[] = {
 655                   0,216,  0,213,175,156,  0,  0,  0,  0,
 656                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
 657                 174,167,152,161,112,  0,  0,  0,154,  0,
 658                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 659                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 660                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 661                   0,  0,  0,  0,  0,183,184,185,186,187,
 662                 188,189,190,191,192,193,194,  0,  0,  0
 663         };
 664         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 665         unsigned int hid = usage->hid;
 666 
 667         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
 668                         lg_ultrax_remote_mapping(hi, usage, bit, max))
 669                 return 1;
 670 
 671         if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
 672                         lg_dinovo_mapping(hi, usage, bit, max))
 673                 return 1;
 674 
 675         if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
 676                 return 1;
 677 
 678         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
 679                 return 0;
 680 
 681         hid &= HID_USAGE;
 682 
 683         /* Special handling for Logitech Cordless Desktop */
 684         if (field->application == HID_GD_MOUSE) {
 685                 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
 686                                 (hid == 7 || hid == 8))
 687                         return -1;
 688         } else {
 689                 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
 690                                 hid < ARRAY_SIZE(e_keymap) &&
 691                                 e_keymap[hid] != 0) {
 692                         hid_map_usage(hi, usage, bit, max, EV_KEY,
 693                                         e_keymap[hid]);
 694                         return 1;
 695                 }
 696         }
 697 
 698         return 0;
 699 }
 700 
 701 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 702                 struct hid_field *field, struct hid_usage *usage,
 703                 unsigned long **bit, int *max)
 704 {
 705         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 706 
 707         if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 708                         (field->flags & HID_MAIN_ITEM_RELATIVE))
 709                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 710 
 711         if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
 712                          usage->type == EV_REL || usage->type == EV_ABS))
 713                 clear_bit(usage->code, *bit);
 714 
 715         /* Ensure that Logitech wheels are not given a default fuzz/flat value */
 716         if (usage->type == EV_ABS && (usage->code == ABS_X ||
 717                         usage->code == ABS_Y || usage->code == ABS_Z ||
 718                         usage->code == ABS_RZ)) {
 719                 switch (hdev->product) {
 720                 case USB_DEVICE_ID_LOGITECH_G29_WHEEL:
 721                 case USB_DEVICE_ID_LOGITECH_WINGMAN_FG:
 722                 case USB_DEVICE_ID_LOGITECH_WINGMAN_FFG:
 723                 case USB_DEVICE_ID_LOGITECH_WHEEL:
 724                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
 725                 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
 726                 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
 727                 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
 728                 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
 729                 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
 730                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
 731                 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
 732                         field->application = HID_GD_MULTIAXIS;
 733                         break;
 734                 default:
 735                         break;
 736                 }
 737         }
 738 
 739         return 0;
 740 }
 741 
 742 static int lg_event(struct hid_device *hdev, struct hid_field *field,
 743                 struct hid_usage *usage, __s32 value)
 744 {
 745         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 746 
 747         if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 748                 input_event(field->hidinput->input, usage->type, usage->code,
 749                                 -value);
 750                 return 1;
 751         }
 752         if (drv_data->quirks & LG_FF4) {
 753                 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
 754         }
 755 
 756         return 0;
 757 }
 758 
 759 static int lg_raw_event(struct hid_device *hdev, struct hid_report *report,
 760                 u8 *rd, int size)
 761 {
 762         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 763 
 764         if (drv_data->quirks & LG_FF4)
 765                 return lg4ff_raw_event(hdev, report, rd, size, drv_data);
 766 
 767         return 0;
 768 }
 769 
 770 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 771 {
 772         struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 773         __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
 774         unsigned int connect_mask = HID_CONNECT_DEFAULT;
 775         struct lg_drv_data *drv_data;
 776         int ret;
 777 
 778         /* G29 only work with the 1st interface */
 779         if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
 780             (iface_num != 0)) {
 781                 dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
 782                 return -ENODEV;
 783         }
 784 
 785         drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
 786         if (!drv_data) {
 787                 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
 788                 return -ENOMEM;
 789         }
 790         drv_data->quirks = id->driver_data;
 791 
 792         hid_set_drvdata(hdev, (void *)drv_data);
 793 
 794         if (drv_data->quirks & LG_NOGET)
 795                 hdev->quirks |= HID_QUIRK_NOGET;
 796 
 797         ret = hid_parse(hdev);
 798         if (ret) {
 799                 hid_err(hdev, "parse failed\n");
 800                 goto err_free;
 801         }
 802 
 803         if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
 804                 connect_mask &= ~HID_CONNECT_FF;
 805 
 806         ret = hid_hw_start(hdev, connect_mask);
 807         if (ret) {
 808                 hid_err(hdev, "hw start failed\n");
 809                 goto err_free;
 810         }
 811 
 812         /* Setup wireless link with Logitech Wii wheel */
 813         if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
 814                 static const unsigned char cbuf[] = {
 815                         0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 816                 };
 817                 u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL);
 818 
 819                 if (!buf) {
 820                         ret = -ENOMEM;
 821                         goto err_stop;
 822                 }
 823 
 824                 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 825                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 826                 if (ret >= 0) {
 827                         /* insert a little delay of 10 jiffies ~ 40ms */
 828                         wait_queue_head_t wait;
 829                         init_waitqueue_head (&wait);
 830                         wait_event_interruptible_timeout(wait, 0,
 831                                                          msecs_to_jiffies(40));
 832 
 833                         /* Select random Address */
 834                         buf[1] = 0xB2;
 835                         get_random_bytes(&buf[2], 2);
 836 
 837                         ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
 838                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 839                 }
 840                 kfree(buf);
 841         }
 842 
 843         if (drv_data->quirks & LG_FF)
 844                 ret = lgff_init(hdev);
 845         else if (drv_data->quirks & LG_FF2)
 846                 ret = lg2ff_init(hdev);
 847         else if (drv_data->quirks & LG_FF3)
 848                 ret = lg3ff_init(hdev);
 849         else if (drv_data->quirks & LG_FF4)
 850                 ret = lg4ff_init(hdev);
 851 
 852         if (ret)
 853                 goto err_stop;
 854 
 855         return 0;
 856 
 857 err_stop:
 858         hid_hw_stop(hdev);
 859 err_free:
 860         kfree(drv_data);
 861         return ret;
 862 }
 863 
 864 static void lg_remove(struct hid_device *hdev)
 865 {
 866         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
 867         if (drv_data->quirks & LG_FF4)
 868                 lg4ff_deinit(hdev);
 869         hid_hw_stop(hdev);
 870         kfree(drv_data);
 871 }
 872 
 873 static const struct hid_device_id lg_devices[] = {
 874         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
 875                 .driver_data = LG_RDESC | LG_WIRELESS },
 876 
 877         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
 878                 .driver_data = LG_BAD_RELATIVE_KEYS },
 879 
 880         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
 881                 .driver_data = LG_DUPLICATE_USAGES },
 882         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
 883                 .driver_data = LG_DUPLICATE_USAGES },
 884         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
 885                 .driver_data = LG_DUPLICATE_USAGES },
 886 
 887         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
 888                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 889         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
 890                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 891 
 892         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
 893                 .driver_data = LG_NOGET },
 894         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
 895                 .driver_data = LG_NOGET },
 896         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
 897                 .driver_data = LG_NOGET | LG_FF4 },
 898 
 899         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
 900                 .driver_data = LG_FF2 },
 901         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
 902                 .driver_data = LG_FF },
 903         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
 904                 .driver_data = LG_FF },
 905         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL),
 906                 .driver_data = LG_FF4 },
 907         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
 908                 .driver_data = LG_FF },
 909         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
 910                 .driver_data = LG_FF },
 911         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
 912                 .driver_data = LG_NOGET | LG_FF4 },
 913         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
 914                 .driver_data = LG_FF4 },
 915         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
 916                 .driver_data = LG_FF2 },
 917         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
 918                 .driver_data = LG_FF4 },
 919         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
 920                 .driver_data = LG_FF4 },
 921         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
 922                 .driver_data = LG_FF4 },
 923         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
 924                 .driver_data = LG_NOGET | LG_FF4 },
 925         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
 926                 .driver_data = LG_FF4 },
 927         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG),
 928                 .driver_data = LG_NOGET },
 929         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
 930                 .driver_data = LG_NOGET | LG_FF4 },
 931         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
 932                 .driver_data = LG_NOGET | LG_FF2 },
 933         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
 934                 .driver_data = LG_FF3 },
 935         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
 936                 .driver_data = LG_RDESC_REL_ABS },
 937         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
 938                 .driver_data = LG_RDESC_REL_ABS },
 939         { }
 940 };
 941 
 942 MODULE_DEVICE_TABLE(hid, lg_devices);
 943 
 944 static struct hid_driver lg_driver = {
 945         .name = "logitech",
 946         .id_table = lg_devices,
 947         .report_fixup = lg_report_fixup,
 948         .input_mapping = lg_input_mapping,
 949         .input_mapped = lg_input_mapped,
 950         .event = lg_event,
 951         .raw_event = lg_raw_event,
 952         .probe = lg_probe,
 953         .remove = lg_remove,
 954 };
 955 module_hid_driver(lg_driver);
 956 
 957 #ifdef CONFIG_LOGIWHEELS_FF
 958 int lg4ff_no_autoswitch = 0;
 959 module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
 960 MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
 961 #endif
 962 
 963 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */