Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

Linux/drivers/hid/hid-lg.c

  1 /*
  2  *  HID driver for some logitech "special" devices
  3  *
  4  *  Copyright (c) 1999 Andreas Gal
  5  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  6  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  7  *  Copyright (c) 2006-2007 Jiri Kosina
  8  *  Copyright (c) 2008 Jiri Slaby
  9  *  Copyright (c) 2010 Hendrik Iben
 10  */
 11 
 12 /*
 13  * This program is free software; you can redistribute it and/or modify it
 14  * under the terms of the GNU General Public License as published by the Free
 15  * Software Foundation; either version 2 of the License, or (at your option)
 16  * any later version.
 17  */
 18 
 19 #include <linux/device.h>
 20 #include <linux/hid.h>
 21 #include <linux/module.h>
 22 #include <linux/random.h>
 23 #include <linux/sched.h>
 24 #include <linux/usb.h>
 25 #include <linux/wait.h>
 26 
 27 #include "usbhid/usbhid.h"
 28 #include "hid-ids.h"
 29 #include "hid-lg.h"
 30 #include "hid-lg4ff.h"
 31 
 32 #define LG_RDESC                0x001
 33 #define LG_BAD_RELATIVE_KEYS    0x002
 34 #define LG_DUPLICATE_USAGES     0x004
 35 #define LG_EXPANDED_KEYMAP      0x010
 36 #define LG_IGNORE_DOUBLED_WHEEL 0x020
 37 #define LG_WIRELESS             0x040
 38 #define LG_INVERT_HWHEEL        0x080
 39 #define LG_NOGET                0x100
 40 #define LG_FF                   0x200
 41 #define LG_FF2                  0x400
 42 #define LG_RDESC_REL_ABS        0x800
 43 #define LG_FF3                  0x1000
 44 #define LG_FF4                  0x2000
 45 
 46 /* Size of the original descriptors of the Driving Force (and Pro) wheels */
 47 #define DF_RDESC_ORIG_SIZE      130
 48 #define DFP_RDESC_ORIG_SIZE     97
 49 #define FV_RDESC_ORIG_SIZE      130
 50 #define MOMO_RDESC_ORIG_SIZE    87
 51 #define MOMO2_RDESC_ORIG_SIZE   87
 52 
 53 /* Fixed report descriptors for Logitech Driving Force (and Pro)
 54  * wheel controllers
 55  *
 56  * The original descriptors hide the separate throttle and brake axes in
 57  * a custom vendor usage page, providing only a combined value as
 58  * GenericDesktop.Y.
 59  * These descriptors remove the combined Y axis and instead report
 60  * separate throttle (Y) and brake (RZ).
 61  */
 62 static __u8 df_rdesc_fixed[] = {
 63 0x05, 0x01,         /*  Usage Page (Desktop),                   */
 64 0x09, 0x04,         /*  Usage (Joystik),                        */
 65 0xA1, 0x01,         /*  Collection (Application),               */
 66 0xA1, 0x02,         /*      Collection (Logical),               */
 67 0x95, 0x01,         /*          Report Count (1),               */
 68 0x75, 0x0A,         /*          Report Size (10),               */
 69 0x14,               /*          Logical Minimum (0),            */
 70 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
 71 0x34,               /*          Physical Minimum (0),           */
 72 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
 73 0x09, 0x30,         /*          Usage (X),                      */
 74 0x81, 0x02,         /*          Input (Variable),               */
 75 0x95, 0x0C,         /*          Report Count (12),              */
 76 0x75, 0x01,         /*          Report Size (1),                */
 77 0x25, 0x01,         /*          Logical Maximum (1),            */
 78 0x45, 0x01,         /*          Physical Maximum (1),           */
 79 0x05, 0x09,         /*          Usage (Buttons),                */
 80 0x19, 0x01,         /*          Usage Minimum (1),              */
 81 0x29, 0x0c,         /*          Usage Maximum (12),             */
 82 0x81, 0x02,         /*          Input (Variable),               */
 83 0x95, 0x02,         /*          Report Count (2),               */
 84 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
 85 0x09, 0x01,         /*          Usage (?: 1),                   */
 86 0x81, 0x02,         /*          Input (Variable),               */
 87 0x05, 0x01,         /*          Usage Page (Desktop),           */
 88 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
 89 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
 90 0x95, 0x01,         /*          Report Count (1),               */
 91 0x75, 0x08,         /*          Report Size (8),                */
 92 0x81, 0x02,         /*          Input (Variable),               */
 93 0x25, 0x07,         /*          Logical Maximum (7),            */
 94 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
 95 0x75, 0x04,         /*          Report Size (4),                */
 96 0x65, 0x14,         /*          Unit (Degrees),                 */
 97 0x09, 0x39,         /*          Usage (Hat Switch),             */
 98 0x81, 0x42,         /*          Input (Variable, Null State),   */
 99 0x75, 0x01,         /*          Report Size (1),                */
100 0x95, 0x04,         /*          Report Count (4),               */
101 0x65, 0x00,         /*          Unit (none),                    */
102 0x06, 0x00, 0xFF,   /*          Usage Page (Vendor: 65280),     */
103 0x09, 0x01,         /*          Usage (?: 1),                   */
104 0x25, 0x01,         /*          Logical Maximum (1),            */
105 0x45, 0x01,         /*          Physical Maximum (1),           */
106 0x81, 0x02,         /*          Input (Variable),               */
107 0x05, 0x01,         /*          Usage Page (Desktop),           */
108 0x95, 0x01,         /*          Report Count (1),               */
109 0x75, 0x08,         /*          Report Size (8),                */
110 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
111 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
112 0x09, 0x31,         /*          Usage (Y),                      */
113 0x81, 0x02,         /*          Input (Variable),               */
114 0x09, 0x35,         /*          Usage (Rz),                     */
115 0x81, 0x02,         /*          Input (Variable),               */
116 0xC0,               /*      End Collection,                     */
117 0xA1, 0x02,         /*      Collection (Logical),               */
118 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
119 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
120 0x95, 0x07,         /*          Report Count (7),               */
121 0x75, 0x08,         /*          Report Size (8),                */
122 0x09, 0x03,         /*          Usage (?: 3),                   */
123 0x91, 0x02,         /*          Output (Variable),              */
124 0xC0,               /*      End Collection,                     */
125 0xC0                /*  End Collection                          */
126 };
127 
128 static __u8 dfp_rdesc_fixed[] = {
129 0x05, 0x01,         /*  Usage Page (Desktop),                   */
130 0x09, 0x04,         /*  Usage (Joystik),                        */
131 0xA1, 0x01,         /*  Collection (Application),               */
132 0xA1, 0x02,         /*      Collection (Logical),               */
133 0x95, 0x01,         /*          Report Count (1),               */
134 0x75, 0x0E,         /*          Report Size (14),               */
135 0x14,               /*          Logical Minimum (0),            */
136 0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),        */
137 0x34,               /*          Physical Minimum (0),           */
138 0x46, 0xFF, 0x3F,   /*          Physical Maximum (16383),       */
139 0x09, 0x30,         /*          Usage (X),                      */
140 0x81, 0x02,         /*          Input (Variable),               */
141 0x95, 0x0E,         /*          Report Count (14),              */
142 0x75, 0x01,         /*          Report Size (1),                */
143 0x25, 0x01,         /*          Logical Maximum (1),            */
144 0x45, 0x01,         /*          Physical Maximum (1),           */
145 0x05, 0x09,         /*          Usage Page (Button),            */
146 0x19, 0x01,         /*          Usage Minimum (01h),            */
147 0x29, 0x0E,         /*          Usage Maximum (0Eh),            */
148 0x81, 0x02,         /*          Input (Variable),               */
149 0x05, 0x01,         /*          Usage Page (Desktop),           */
150 0x95, 0x01,         /*          Report Count (1),               */
151 0x75, 0x04,         /*          Report Size (4),                */
152 0x25, 0x07,         /*          Logical Maximum (7),            */
153 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
154 0x65, 0x14,         /*          Unit (Degrees),                 */
155 0x09, 0x39,         /*          Usage (Hat Switch),             */
156 0x81, 0x42,         /*          Input (Variable, Nullstate),    */
157 0x65, 0x00,         /*          Unit,                           */
158 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
159 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
160 0x75, 0x08,         /*          Report Size (8),                */
161 0x81, 0x01,         /*          Input (Constant),               */
162 0x09, 0x31,         /*          Usage (Y),                      */
163 0x81, 0x02,         /*          Input (Variable),               */
164 0x09, 0x35,         /*          Usage (Rz),                     */
165 0x81, 0x02,         /*          Input (Variable),               */
166 0x81, 0x01,         /*          Input (Constant),               */
167 0xC0,               /*      End Collection,                     */
168 0xA1, 0x02,         /*      Collection (Logical),               */
169 0x09, 0x02,         /*          Usage (02h),                    */
170 0x95, 0x07,         /*          Report Count (7),               */
171 0x91, 0x02,         /*          Output (Variable),              */
172 0xC0,               /*      End Collection,                     */
173 0xC0                /*  End Collection                          */
174 };
175 
176 static __u8 fv_rdesc_fixed[] = {
177 0x05, 0x01,         /*  Usage Page (Desktop),                   */
178 0x09, 0x04,         /*  Usage (Joystik),                        */
179 0xA1, 0x01,         /*  Collection (Application),               */
180 0xA1, 0x02,         /*      Collection (Logical),               */
181 0x95, 0x01,         /*          Report Count (1),               */
182 0x75, 0x0A,         /*          Report Size (10),               */
183 0x15, 0x00,         /*          Logical Minimum (0),            */
184 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),         */
185 0x35, 0x00,         /*          Physical Minimum (0),           */
186 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),        */
187 0x09, 0x30,         /*          Usage (X),                      */
188 0x81, 0x02,         /*          Input (Variable),               */
189 0x95, 0x0C,         /*          Report Count (12),              */
190 0x75, 0x01,         /*          Report Size (1),                */
191 0x25, 0x01,         /*          Logical Maximum (1),            */
192 0x45, 0x01,         /*          Physical Maximum (1),           */
193 0x05, 0x09,         /*          Usage Page (Button),            */
194 0x19, 0x01,         /*          Usage Minimum (01h),            */
195 0x29, 0x0C,         /*          Usage Maximum (0Ch),            */
196 0x81, 0x02,         /*          Input (Variable),               */
197 0x95, 0x02,         /*          Report Count (2),               */
198 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
199 0x09, 0x01,         /*          Usage (01h),                    */
200 0x81, 0x02,         /*          Input (Variable),               */
201 0x09, 0x02,         /*          Usage (02h),                    */
202 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
203 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
204 0x95, 0x01,         /*          Report Count (1),               */
205 0x75, 0x08,         /*          Report Size (8),                */
206 0x81, 0x02,         /*          Input (Variable),               */
207 0x05, 0x01,         /*          Usage Page (Desktop),           */
208 0x25, 0x07,         /*          Logical Maximum (7),            */
209 0x46, 0x3B, 0x01,   /*          Physical Maximum (315),         */
210 0x75, 0x04,         /*          Report Size (4),                */
211 0x65, 0x14,         /*          Unit (Degrees),                 */
212 0x09, 0x39,         /*          Usage (Hat Switch),             */
213 0x81, 0x42,         /*          Input (Variable, Null State),   */
214 0x75, 0x01,         /*          Report Size (1),                */
215 0x95, 0x04,         /*          Report Count (4),               */
216 0x65, 0x00,         /*          Unit,                           */
217 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),             */
218 0x09, 0x01,         /*          Usage (01h),                    */
219 0x25, 0x01,         /*          Logical Maximum (1),            */
220 0x45, 0x01,         /*          Physical Maximum (1),           */
221 0x81, 0x02,         /*          Input (Variable),               */
222 0x05, 0x01,         /*          Usage Page (Desktop),           */
223 0x95, 0x01,         /*          Report Count (1),               */
224 0x75, 0x08,         /*          Report Size (8),                */
225 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
226 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
227 0x09, 0x31,         /*          Usage (Y),                      */
228 0x81, 0x02,         /*          Input (Variable),               */
229 0x09, 0x32,         /*          Usage (Z),                      */
230 0x81, 0x02,         /*          Input (Variable),               */
231 0xC0,               /*      End Collection,                     */
232 0xA1, 0x02,         /*      Collection (Logical),               */
233 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),          */
234 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),         */
235 0x95, 0x07,         /*          Report Count (7),               */
236 0x75, 0x08,         /*          Report Size (8),                */
237 0x09, 0x03,         /*          Usage (03h),                    */
238 0x91, 0x02,         /*          Output (Variable),              */
239 0xC0,               /*      End Collection,                     */
240 0xC0                /*  End Collection                          */
241 };
242 
243 static __u8 momo_rdesc_fixed[] = {
244 0x05, 0x01,         /*  Usage Page (Desktop),               */
245 0x09, 0x04,         /*  Usage (Joystik),                    */
246 0xA1, 0x01,         /*  Collection (Application),           */
247 0xA1, 0x02,         /*      Collection (Logical),           */
248 0x95, 0x01,         /*          Report Count (1),           */
249 0x75, 0x0A,         /*          Report Size (10),           */
250 0x15, 0x00,         /*          Logical Minimum (0),        */
251 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
252 0x35, 0x00,         /*          Physical Minimum (0),       */
253 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
254 0x09, 0x30,         /*          Usage (X),                  */
255 0x81, 0x02,         /*          Input (Variable),           */
256 0x95, 0x08,         /*          Report Count (8),           */
257 0x75, 0x01,         /*          Report Size (1),            */
258 0x25, 0x01,         /*          Logical Maximum (1),        */
259 0x45, 0x01,         /*          Physical Maximum (1),       */
260 0x05, 0x09,         /*          Usage Page (Button),        */
261 0x19, 0x01,         /*          Usage Minimum (01h),        */
262 0x29, 0x08,         /*          Usage Maximum (08h),        */
263 0x81, 0x02,         /*          Input (Variable),           */
264 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
265 0x75, 0x0E,         /*          Report Size (14),           */
266 0x95, 0x01,         /*          Report Count (1),           */
267 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
268 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
269 0x09, 0x00,         /*          Usage (00h),                */
270 0x81, 0x02,         /*          Input (Variable),           */
271 0x05, 0x01,         /*          Usage Page (Desktop),       */
272 0x75, 0x08,         /*          Report Size (8),            */
273 0x09, 0x31,         /*          Usage (Y),                  */
274 0x81, 0x02,         /*          Input (Variable),           */
275 0x09, 0x32,         /*          Usage (Z),                  */
276 0x81, 0x02,         /*          Input (Variable),           */
277 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
278 0x09, 0x01,         /*          Usage (01h),                */
279 0x81, 0x02,         /*          Input (Variable),           */
280 0xC0,               /*      End Collection,                 */
281 0xA1, 0x02,         /*      Collection (Logical),           */
282 0x09, 0x02,         /*          Usage (02h),                */
283 0x95, 0x07,         /*          Report Count (7),           */
284 0x91, 0x02,         /*          Output (Variable),          */
285 0xC0,               /*      End Collection,                 */
286 0xC0                /*  End Collection                      */
287 };
288 
289 static __u8 momo2_rdesc_fixed[] = {
290 0x05, 0x01,         /*  Usage Page (Desktop),               */
291 0x09, 0x04,         /*  Usage (Joystik),                    */
292 0xA1, 0x01,         /*  Collection (Application),           */
293 0xA1, 0x02,         /*      Collection (Logical),           */
294 0x95, 0x01,         /*          Report Count (1),           */
295 0x75, 0x0A,         /*          Report Size (10),           */
296 0x15, 0x00,         /*          Logical Minimum (0),        */
297 0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
298 0x35, 0x00,         /*          Physical Minimum (0),       */
299 0x46, 0xFF, 0x03,   /*          Physical Maximum (1023),    */
300 0x09, 0x30,         /*          Usage (X),                  */
301 0x81, 0x02,         /*          Input (Variable),           */
302 0x95, 0x0A,         /*          Report Count (10),          */
303 0x75, 0x01,         /*          Report Size (1),            */
304 0x25, 0x01,         /*          Logical Maximum (1),        */
305 0x45, 0x01,         /*          Physical Maximum (1),       */
306 0x05, 0x09,         /*          Usage Page (Button),        */
307 0x19, 0x01,         /*          Usage Minimum (01h),        */
308 0x29, 0x0A,         /*          Usage Maximum (0Ah),        */
309 0x81, 0x02,         /*          Input (Variable),           */
310 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
311 0x09, 0x00,         /*          Usage (00h),                */
312 0x95, 0x04,         /*          Report Count (4),           */
313 0x81, 0x02,         /*          Input (Variable),           */
314 0x95, 0x01,         /*          Report Count (1),           */
315 0x75, 0x08,         /*          Report Size (8),            */
316 0x26, 0xFF, 0x00,   /*          Logical Maximum (255),      */
317 0x46, 0xFF, 0x00,   /*          Physical Maximum (255),     */
318 0x09, 0x01,         /*          Usage (01h),                */
319 0x81, 0x02,         /*          Input (Variable),           */
320 0x05, 0x01,         /*          Usage Page (Desktop),       */
321 0x09, 0x31,         /*          Usage (Y),                  */
322 0x81, 0x02,         /*          Input (Variable),           */
323 0x09, 0x32,         /*          Usage (Z),                  */
324 0x81, 0x02,         /*          Input (Variable),           */
325 0x06, 0x00, 0xFF,   /*          Usage Page (FF00h),         */
326 0x09, 0x00,         /*          Usage (00h),                */
327 0x81, 0x02,         /*          Input (Variable),           */
328 0xC0,               /*      End Collection,                 */
329 0xA1, 0x02,         /*      Collection (Logical),           */
330 0x09, 0x02,         /*          Usage (02h),                */
331 0x95, 0x07,         /*          Report Count (7),           */
332 0x91, 0x02,         /*          Output (Variable),          */
333 0xC0,               /*      End Collection,                 */
334 0xC0                /*  End Collection                      */
335 };
336 
337 /*
338  * Certain Logitech keyboards send in report #3 keys which are far
339  * above the logical maximum described in descriptor. This extends
340  * the original value of 0x28c of logical maximum to 0x104d
341  */
342 static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
343                 unsigned int *rsize)
344 {
345         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
346         struct usb_device_descriptor *udesc;
347         __u16 bcdDevice, rev_maj, rev_min;
348 
349         if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
350                         rdesc[84] == 0x8c && rdesc[85] == 0x02) {
351                 hid_info(hdev,
352                          "fixing up Logitech keyboard report descriptor\n");
353                 rdesc[84] = rdesc[89] = 0x4d;
354                 rdesc[85] = rdesc[90] = 0x10;
355         }
356         if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
357                         rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
358                         rdesc[49] == 0x81 && rdesc[50] == 0x06) {
359                 hid_info(hdev,
360                          "fixing up rel/abs in Logitech report descriptor\n");
361                 rdesc[33] = rdesc[50] = 0x02;
362         }
363 
364         switch (hdev->product) {
365 
366         /* Several wheels report as this id when operating in emulation mode. */
367         case USB_DEVICE_ID_LOGITECH_WHEEL:
368                 udesc = &(hid_to_usb_dev(hdev)->descriptor);
369                 if (!udesc) {
370                         hid_err(hdev, "NULL USB device descriptor\n");
371                         break;
372                 }
373                 bcdDevice = le16_to_cpu(udesc->bcdDevice);
374                 rev_maj = bcdDevice >> 8;
375                 rev_min = bcdDevice & 0xff;
376 
377                 /* Update the report descriptor for only the Driving Force wheel */
378                 if (rev_maj == 1 && rev_min == 2 &&
379                                 *rsize == DF_RDESC_ORIG_SIZE) {
380                         hid_info(hdev,
381                                 "fixing up Logitech Driving Force report descriptor\n");
382                         rdesc = df_rdesc_fixed;
383                         *rsize = sizeof(df_rdesc_fixed);
384                 }
385                 break;
386 
387         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
388                 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
389                         hid_info(hdev,
390                                 "fixing up Logitech Momo Force (Red) report descriptor\n");
391                         rdesc = momo_rdesc_fixed;
392                         *rsize = sizeof(momo_rdesc_fixed);
393                 }
394                 break;
395 
396         case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
397                 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
398                         hid_info(hdev,
399                                 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
400                         rdesc = momo2_rdesc_fixed;
401                         *rsize = sizeof(momo2_rdesc_fixed);
402                 }
403                 break;
404 
405         case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
406                 if (*rsize == FV_RDESC_ORIG_SIZE) {
407                         hid_info(hdev,
408                                 "fixing up Logitech Formula Vibration report descriptor\n");
409                         rdesc = fv_rdesc_fixed;
410                         *rsize = sizeof(fv_rdesc_fixed);
411                 }
412                 break;
413 
414         case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
415                 if (*rsize == DFP_RDESC_ORIG_SIZE) {
416                         hid_info(hdev,
417                                 "fixing up Logitech Driving Force Pro report descriptor\n");
418                         rdesc = dfp_rdesc_fixed;
419                         *rsize = sizeof(dfp_rdesc_fixed);
420                 }
421                 break;
422 
423         case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
424                 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
425                                 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
426                         hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
427                         rdesc[41] = 0x05;
428                         rdesc[42] = 0x09;
429                         rdesc[47] = 0x95;
430                         rdesc[48] = 0x0B;
431                 }
432                 break;
433         }
434 
435         return rdesc;
436 }
437 
438 #define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
439                 EV_KEY, (c))
440 
441 static int lg_ultrax_remote_mapping(struct hid_input *hi,
442                 struct hid_usage *usage, unsigned long **bit, int *max)
443 {
444         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
445                 return 0;
446 
447         set_bit(EV_REP, hi->input->evbit);
448         switch (usage->hid & HID_USAGE) {
449         /* Reported on Logitech Ultra X Media Remote */
450         case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
451         case 0x00d: lg_map_key_clear(KEY_HOME);         break;
452         case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
453         case 0x025: lg_map_key_clear(KEY_TV);           break;
454         case 0x026: lg_map_key_clear(KEY_MENU);         break;
455         case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
456         case 0x032: lg_map_key_clear(KEY_TEXT);         break;
457         case 0x033: lg_map_key_clear(KEY_LAST);         break;
458         case 0x047: lg_map_key_clear(KEY_MP3);          break;
459         case 0x048: lg_map_key_clear(KEY_DVD);          break;
460         case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
461         case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
462         case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
463         case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
464         case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
465         case 0x051: lg_map_key_clear(KEY_RED);          break;
466         case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
467 
468         default:
469                 return 0;
470         }
471         return 1;
472 }
473 
474 static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
475                 unsigned long **bit, int *max)
476 {
477         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
478                 return 0;
479 
480         switch (usage->hid & HID_USAGE) {
481 
482         case 0x00d: lg_map_key_clear(KEY_MEDIA);        break;
483         default:
484                 return 0;
485 
486         }
487         return 1;
488 }
489 
490 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
491                 unsigned long **bit, int *max)
492 {
493         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
494                 return 0;
495 
496         switch (usage->hid & HID_USAGE) {
497         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
498         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
499         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
500         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
501         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
502         /* The following two entries are Playlist 1 and 2 on the MX3200 */
503         case 0x100f: lg_map_key_clear(KEY_FN_1);                break;
504         case 0x1010: lg_map_key_clear(KEY_FN_2);                break;
505         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
506         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
507         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
508         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
509         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
510         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
511         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
512         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
513         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
514         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
515         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
516         case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
517         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
518         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
519         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
520         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
521         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
522         /* this one is marked as 'Rotate' */
523         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
524         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
525         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
526         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
527         case 0x102d: lg_map_key_clear(KEY_WWW);                 break;
528         /* The following two are 'Start/answer call' and 'End/reject call'
529            on the MX3200 */
530         case 0x1031: lg_map_key_clear(KEY_OK);                  break;
531         case 0x1032: lg_map_key_clear(KEY_CANCEL);              break;
532         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
533         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
534         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
535         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
536         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
537         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
538         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
539         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
540         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
541         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
542         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
543         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
544 
545         default:
546                 return 0;
547         }
548         return 1;
549 }
550 
551 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
552                 struct hid_field *field, struct hid_usage *usage,
553                 unsigned long **bit, int *max)
554 {
555         /* extended mapping for certain Logitech hardware (Logitech cordless
556            desktop LX500) */
557         static const u8 e_keymap[] = {
558                   0,216,  0,213,175,156,  0,  0,  0,  0,
559                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
560                 174,167,152,161,112,  0,  0,  0,154,  0,
561                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
562                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
563                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
564                   0,  0,  0,  0,  0,183,184,185,186,187,
565                 188,189,190,191,192,193,194,  0,  0,  0
566         };
567         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
568         unsigned int hid = usage->hid;
569 
570         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
571                         lg_ultrax_remote_mapping(hi, usage, bit, max))
572                 return 1;
573 
574         if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
575                         lg_dinovo_mapping(hi, usage, bit, max))
576                 return 1;
577 
578         if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
579                 return 1;
580 
581         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
582                 return 0;
583 
584         hid &= HID_USAGE;
585 
586         /* Special handling for Logitech Cordless Desktop */
587         if (field->application == HID_GD_MOUSE) {
588                 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
589                                 (hid == 7 || hid == 8))
590                         return -1;
591         } else {
592                 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
593                                 hid < ARRAY_SIZE(e_keymap) &&
594                                 e_keymap[hid] != 0) {
595                         hid_map_usage(hi, usage, bit, max, EV_KEY,
596                                         e_keymap[hid]);
597                         return 1;
598                 }
599         }
600 
601         return 0;
602 }
603 
604 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
605                 struct hid_field *field, struct hid_usage *usage,
606                 unsigned long **bit, int *max)
607 {
608         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
609 
610         if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
611                         (field->flags & HID_MAIN_ITEM_RELATIVE))
612                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
613 
614         if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
615                          usage->type == EV_REL || usage->type == EV_ABS))
616                 clear_bit(usage->code, *bit);
617 
618         /* Ensure that Logitech wheels are not given a default fuzz/flat value */
619         if (usage->type == EV_ABS && (usage->code == ABS_X ||
620                         usage->code == ABS_Y || usage->code == ABS_Z ||
621                         usage->code == ABS_RZ)) {
622                 switch (hdev->product) {
623                 case USB_DEVICE_ID_LOGITECH_WHEEL:
624                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
625                 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
626                 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
627                 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
628                 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
629                 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
630                 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
631                 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
632                         field->application = HID_GD_MULTIAXIS;
633                         break;
634                 default:
635                         break;
636                 }
637         }
638 
639         return 0;
640 }
641 
642 static int lg_event(struct hid_device *hdev, struct hid_field *field,
643                 struct hid_usage *usage, __s32 value)
644 {
645         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
646 
647         if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
648                 input_event(field->hidinput->input, usage->type, usage->code,
649                                 -value);
650                 return 1;
651         }
652         if (drv_data->quirks & LG_FF4) {
653                 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
654         }
655 
656         return 0;
657 }
658 
659 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
660 {
661         unsigned int connect_mask = HID_CONNECT_DEFAULT;
662         struct lg_drv_data *drv_data;
663         int ret;
664 
665         drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
666         if (!drv_data) {
667                 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
668                 return -ENOMEM;
669         }
670         drv_data->quirks = id->driver_data;
671 
672         hid_set_drvdata(hdev, (void *)drv_data);
673 
674         if (drv_data->quirks & LG_NOGET)
675                 hdev->quirks |= HID_QUIRK_NOGET;
676 
677         ret = hid_parse(hdev);
678         if (ret) {
679                 hid_err(hdev, "parse failed\n");
680                 goto err_free;
681         }
682 
683         if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
684                 connect_mask &= ~HID_CONNECT_FF;
685 
686         ret = hid_hw_start(hdev, connect_mask);
687         if (ret) {
688                 hid_err(hdev, "hw start failed\n");
689                 goto err_free;
690         }
691 
692         /* Setup wireless link with Logitech Wii wheel */
693         if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
694                 unsigned char buf[] = { 0x00, 0xAF,  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
695 
696                 ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
697                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
698 
699                 if (ret >= 0) {
700                         /* insert a little delay of 10 jiffies ~ 40ms */
701                         wait_queue_head_t wait;
702                         init_waitqueue_head (&wait);
703                         wait_event_interruptible_timeout(wait, 0, 10);
704 
705                         /* Select random Address */
706                         buf[1] = 0xB2;
707                         get_random_bytes(&buf[2], 2);
708 
709                         ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
710                                         HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
711                 }
712         }
713 
714         if (drv_data->quirks & LG_FF)
715                 lgff_init(hdev);
716         if (drv_data->quirks & LG_FF2)
717                 lg2ff_init(hdev);
718         if (drv_data->quirks & LG_FF3)
719                 lg3ff_init(hdev);
720         if (drv_data->quirks & LG_FF4)
721                 lg4ff_init(hdev);
722 
723         return 0;
724 err_free:
725         kfree(drv_data);
726         return ret;
727 }
728 
729 static void lg_remove(struct hid_device *hdev)
730 {
731         struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
732         if (drv_data->quirks & LG_FF4)
733                 lg4ff_deinit(hdev);
734 
735         hid_hw_stop(hdev);
736         kfree(drv_data);
737 }
738 
739 static const struct hid_device_id lg_devices[] = {
740         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
741                 .driver_data = LG_RDESC | LG_WIRELESS },
742         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
743                 .driver_data = LG_RDESC | LG_WIRELESS },
744         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
745                 .driver_data = LG_RDESC | LG_WIRELESS },
746 
747         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
748                 .driver_data = LG_BAD_RELATIVE_KEYS },
749 
750         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
751                 .driver_data = LG_DUPLICATE_USAGES },
752         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
753                 .driver_data = LG_DUPLICATE_USAGES },
754         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
755                 .driver_data = LG_DUPLICATE_USAGES },
756 
757         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
758                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
759         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
760                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
761 
762         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
763                 .driver_data = LG_NOGET },
764         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION),
765                 .driver_data = LG_NOGET },
766         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
767                 .driver_data = LG_NOGET | LG_FF4 },
768 
769         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
770                 .driver_data = LG_FF2 },
771         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
772                 .driver_data = LG_FF },
773         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
774                 .driver_data = LG_FF },
775         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
776                 .driver_data = LG_FF },
777         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
778                 .driver_data = LG_FF },
779         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
780                 .driver_data = LG_NOGET | LG_FF4 },
781         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
782                 .driver_data = LG_FF4 },
783         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
784                 .driver_data = LG_FF2 },
785         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
786                 .driver_data = LG_FF4 },
787         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
788                 .driver_data = LG_FF4 },
789         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
790                 .driver_data = LG_FF4 },
791         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
792                 .driver_data = LG_NOGET | LG_FF4 },
793         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
794                 .driver_data = LG_FF4 },
795         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
796                 .driver_data = LG_FF },
797         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
798                 .driver_data = LG_FF2 },
799         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
800                 .driver_data = LG_FF3 },
801         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
802                 .driver_data = LG_RDESC_REL_ABS },
803         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
804                 .driver_data = LG_RDESC_REL_ABS },
805         { }
806 };
807 
808 MODULE_DEVICE_TABLE(hid, lg_devices);
809 
810 static struct hid_driver lg_driver = {
811         .name = "logitech",
812         .id_table = lg_devices,
813         .report_fixup = lg_report_fixup,
814         .input_mapping = lg_input_mapping,
815         .input_mapped = lg_input_mapped,
816         .event = lg_event,
817         .probe = lg_probe,
818         .remove = lg_remove,
819 };
820 module_hid_driver(lg_driver);
821 
822 #ifdef CONFIG_LOGIWHEELS_FF
823 int lg4ff_no_autoswitch = 0;
824 module_param_named(lg4ff_no_autoswitch, lg4ff_no_autoswitch, int, S_IRUGO);
825 MODULE_PARM_DESC(lg4ff_no_autoswitch, "Do not switch multimode wheels to their native mode automatically");
826 #endif
827 
828 MODULE_LICENSE("GPL");
829 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us