Merge tag 'v3.10.107' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / hid / hid-lg.c
... / ...
CommitLineData
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
31#define LG_RDESC 0x001
32#define LG_BAD_RELATIVE_KEYS 0x002
33#define LG_DUPLICATE_USAGES 0x004
34#define LG_EXPANDED_KEYMAP 0x010
35#define LG_IGNORE_DOUBLED_WHEEL 0x020
36#define LG_WIRELESS 0x040
37#define LG_INVERT_HWHEEL 0x080
38#define LG_NOGET 0x100
39#define LG_FF 0x200
40#define LG_FF2 0x400
41#define LG_RDESC_REL_ABS 0x800
42#define LG_FF3 0x1000
43#define LG_FF4 0x2000
44
45/* Size of the original descriptors of the Driving Force (and Pro) wheels */
46#define DF_RDESC_ORIG_SIZE 130
47#define DFP_RDESC_ORIG_SIZE 97
48#define FV_RDESC_ORIG_SIZE 130
49#define MOMO_RDESC_ORIG_SIZE 87
50#define MOMO2_RDESC_ORIG_SIZE 87
51
52/* Fixed report descriptors for Logitech Driving Force (and Pro)
53 * wheel controllers
54 *
55 * The original descriptors hide the separate throttle and brake axes in
56 * a custom vendor usage page, providing only a combined value as
57 * GenericDesktop.Y.
58 * These descriptors remove the combined Y axis and instead report
59 * separate throttle (Y) and brake (RZ).
60 */
61static __u8 df_rdesc_fixed[] = {
620x05, 0x01, /* Usage Page (Desktop), */
630x09, 0x04, /* Usage (Joystik), */
640xA1, 0x01, /* Collection (Application), */
650xA1, 0x02, /* Collection (Logical), */
660x95, 0x01, /* Report Count (1), */
670x75, 0x0A, /* Report Size (10), */
680x14, /* Logical Minimum (0), */
690x26, 0xFF, 0x03, /* Logical Maximum (1023), */
700x34, /* Physical Minimum (0), */
710x46, 0xFF, 0x03, /* Physical Maximum (1023), */
720x09, 0x30, /* Usage (X), */
730x81, 0x02, /* Input (Variable), */
740x95, 0x0C, /* Report Count (12), */
750x75, 0x01, /* Report Size (1), */
760x25, 0x01, /* Logical Maximum (1), */
770x45, 0x01, /* Physical Maximum (1), */
780x05, 0x09, /* Usage (Buttons), */
790x19, 0x01, /* Usage Minimum (1), */
800x29, 0x0c, /* Usage Maximum (12), */
810x81, 0x02, /* Input (Variable), */
820x95, 0x02, /* Report Count (2), */
830x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
840x09, 0x01, /* Usage (?: 1), */
850x81, 0x02, /* Input (Variable), */
860x05, 0x01, /* Usage Page (Desktop), */
870x26, 0xFF, 0x00, /* Logical Maximum (255), */
880x46, 0xFF, 0x00, /* Physical Maximum (255), */
890x95, 0x01, /* Report Count (1), */
900x75, 0x08, /* Report Size (8), */
910x81, 0x02, /* Input (Variable), */
920x25, 0x07, /* Logical Maximum (7), */
930x46, 0x3B, 0x01, /* Physical Maximum (315), */
940x75, 0x04, /* Report Size (4), */
950x65, 0x14, /* Unit (Degrees), */
960x09, 0x39, /* Usage (Hat Switch), */
970x81, 0x42, /* Input (Variable, Null State), */
980x75, 0x01, /* Report Size (1), */
990x95, 0x04, /* Report Count (4), */
1000x65, 0x00, /* Unit (none), */
1010x06, 0x00, 0xFF, /* Usage Page (Vendor: 65280), */
1020x09, 0x01, /* Usage (?: 1), */
1030x25, 0x01, /* Logical Maximum (1), */
1040x45, 0x01, /* Physical Maximum (1), */
1050x81, 0x02, /* Input (Variable), */
1060x05, 0x01, /* Usage Page (Desktop), */
1070x95, 0x01, /* Report Count (1), */
1080x75, 0x08, /* Report Size (8), */
1090x26, 0xFF, 0x00, /* Logical Maximum (255), */
1100x46, 0xFF, 0x00, /* Physical Maximum (255), */
1110x09, 0x31, /* Usage (Y), */
1120x81, 0x02, /* Input (Variable), */
1130x09, 0x35, /* Usage (Rz), */
1140x81, 0x02, /* Input (Variable), */
1150xC0, /* End Collection, */
1160xA1, 0x02, /* Collection (Logical), */
1170x26, 0xFF, 0x00, /* Logical Maximum (255), */
1180x46, 0xFF, 0x00, /* Physical Maximum (255), */
1190x95, 0x07, /* Report Count (7), */
1200x75, 0x08, /* Report Size (8), */
1210x09, 0x03, /* Usage (?: 3), */
1220x91, 0x02, /* Output (Variable), */
1230xC0, /* End Collection, */
1240xC0 /* End Collection */
125};
126
127static __u8 dfp_rdesc_fixed[] = {
1280x05, 0x01, /* Usage Page (Desktop), */
1290x09, 0x04, /* Usage (Joystik), */
1300xA1, 0x01, /* Collection (Application), */
1310xA1, 0x02, /* Collection (Logical), */
1320x95, 0x01, /* Report Count (1), */
1330x75, 0x0E, /* Report Size (14), */
1340x14, /* Logical Minimum (0), */
1350x26, 0xFF, 0x3F, /* Logical Maximum (16383), */
1360x34, /* Physical Minimum (0), */
1370x46, 0xFF, 0x3F, /* Physical Maximum (16383), */
1380x09, 0x30, /* Usage (X), */
1390x81, 0x02, /* Input (Variable), */
1400x95, 0x0E, /* Report Count (14), */
1410x75, 0x01, /* Report Size (1), */
1420x25, 0x01, /* Logical Maximum (1), */
1430x45, 0x01, /* Physical Maximum (1), */
1440x05, 0x09, /* Usage Page (Button), */
1450x19, 0x01, /* Usage Minimum (01h), */
1460x29, 0x0E, /* Usage Maximum (0Eh), */
1470x81, 0x02, /* Input (Variable), */
1480x05, 0x01, /* Usage Page (Desktop), */
1490x95, 0x01, /* Report Count (1), */
1500x75, 0x04, /* Report Size (4), */
1510x25, 0x07, /* Logical Maximum (7), */
1520x46, 0x3B, 0x01, /* Physical Maximum (315), */
1530x65, 0x14, /* Unit (Degrees), */
1540x09, 0x39, /* Usage (Hat Switch), */
1550x81, 0x42, /* Input (Variable, Nullstate), */
1560x65, 0x00, /* Unit, */
1570x26, 0xFF, 0x00, /* Logical Maximum (255), */
1580x46, 0xFF, 0x00, /* Physical Maximum (255), */
1590x75, 0x08, /* Report Size (8), */
1600x81, 0x01, /* Input (Constant), */
1610x09, 0x31, /* Usage (Y), */
1620x81, 0x02, /* Input (Variable), */
1630x09, 0x35, /* Usage (Rz), */
1640x81, 0x02, /* Input (Variable), */
1650x81, 0x01, /* Input (Constant), */
1660xC0, /* End Collection, */
1670xA1, 0x02, /* Collection (Logical), */
1680x09, 0x02, /* Usage (02h), */
1690x95, 0x07, /* Report Count (7), */
1700x91, 0x02, /* Output (Variable), */
1710xC0, /* End Collection, */
1720xC0 /* End Collection */
173};
174
175static __u8 fv_rdesc_fixed[] = {
1760x05, 0x01, /* Usage Page (Desktop), */
1770x09, 0x04, /* Usage (Joystik), */
1780xA1, 0x01, /* Collection (Application), */
1790xA1, 0x02, /* Collection (Logical), */
1800x95, 0x01, /* Report Count (1), */
1810x75, 0x0A, /* Report Size (10), */
1820x15, 0x00, /* Logical Minimum (0), */
1830x26, 0xFF, 0x03, /* Logical Maximum (1023), */
1840x35, 0x00, /* Physical Minimum (0), */
1850x46, 0xFF, 0x03, /* Physical Maximum (1023), */
1860x09, 0x30, /* Usage (X), */
1870x81, 0x02, /* Input (Variable), */
1880x95, 0x0C, /* Report Count (12), */
1890x75, 0x01, /* Report Size (1), */
1900x25, 0x01, /* Logical Maximum (1), */
1910x45, 0x01, /* Physical Maximum (1), */
1920x05, 0x09, /* Usage Page (Button), */
1930x19, 0x01, /* Usage Minimum (01h), */
1940x29, 0x0C, /* Usage Maximum (0Ch), */
1950x81, 0x02, /* Input (Variable), */
1960x95, 0x02, /* Report Count (2), */
1970x06, 0x00, 0xFF, /* Usage Page (FF00h), */
1980x09, 0x01, /* Usage (01h), */
1990x81, 0x02, /* Input (Variable), */
2000x09, 0x02, /* Usage (02h), */
2010x26, 0xFF, 0x00, /* Logical Maximum (255), */
2020x46, 0xFF, 0x00, /* Physical Maximum (255), */
2030x95, 0x01, /* Report Count (1), */
2040x75, 0x08, /* Report Size (8), */
2050x81, 0x02, /* Input (Variable), */
2060x05, 0x01, /* Usage Page (Desktop), */
2070x25, 0x07, /* Logical Maximum (7), */
2080x46, 0x3B, 0x01, /* Physical Maximum (315), */
2090x75, 0x04, /* Report Size (4), */
2100x65, 0x14, /* Unit (Degrees), */
2110x09, 0x39, /* Usage (Hat Switch), */
2120x81, 0x42, /* Input (Variable, Null State), */
2130x75, 0x01, /* Report Size (1), */
2140x95, 0x04, /* Report Count (4), */
2150x65, 0x00, /* Unit, */
2160x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2170x09, 0x01, /* Usage (01h), */
2180x25, 0x01, /* Logical Maximum (1), */
2190x45, 0x01, /* Physical Maximum (1), */
2200x81, 0x02, /* Input (Variable), */
2210x05, 0x01, /* Usage Page (Desktop), */
2220x95, 0x01, /* Report Count (1), */
2230x75, 0x08, /* Report Size (8), */
2240x26, 0xFF, 0x00, /* Logical Maximum (255), */
2250x46, 0xFF, 0x00, /* Physical Maximum (255), */
2260x09, 0x31, /* Usage (Y), */
2270x81, 0x02, /* Input (Variable), */
2280x09, 0x32, /* Usage (Z), */
2290x81, 0x02, /* Input (Variable), */
2300xC0, /* End Collection, */
2310xA1, 0x02, /* Collection (Logical), */
2320x26, 0xFF, 0x00, /* Logical Maximum (255), */
2330x46, 0xFF, 0x00, /* Physical Maximum (255), */
2340x95, 0x07, /* Report Count (7), */
2350x75, 0x08, /* Report Size (8), */
2360x09, 0x03, /* Usage (03h), */
2370x91, 0x02, /* Output (Variable), */
2380xC0, /* End Collection, */
2390xC0 /* End Collection */
240};
241
242static __u8 momo_rdesc_fixed[] = {
2430x05, 0x01, /* Usage Page (Desktop), */
2440x09, 0x04, /* Usage (Joystik), */
2450xA1, 0x01, /* Collection (Application), */
2460xA1, 0x02, /* Collection (Logical), */
2470x95, 0x01, /* Report Count (1), */
2480x75, 0x0A, /* Report Size (10), */
2490x15, 0x00, /* Logical Minimum (0), */
2500x26, 0xFF, 0x03, /* Logical Maximum (1023), */
2510x35, 0x00, /* Physical Minimum (0), */
2520x46, 0xFF, 0x03, /* Physical Maximum (1023), */
2530x09, 0x30, /* Usage (X), */
2540x81, 0x02, /* Input (Variable), */
2550x95, 0x08, /* Report Count (8), */
2560x75, 0x01, /* Report Size (1), */
2570x25, 0x01, /* Logical Maximum (1), */
2580x45, 0x01, /* Physical Maximum (1), */
2590x05, 0x09, /* Usage Page (Button), */
2600x19, 0x01, /* Usage Minimum (01h), */
2610x29, 0x08, /* Usage Maximum (08h), */
2620x81, 0x02, /* Input (Variable), */
2630x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2640x75, 0x0E, /* Report Size (14), */
2650x95, 0x01, /* Report Count (1), */
2660x26, 0xFF, 0x00, /* Logical Maximum (255), */
2670x46, 0xFF, 0x00, /* Physical Maximum (255), */
2680x09, 0x00, /* Usage (00h), */
2690x81, 0x02, /* Input (Variable), */
2700x05, 0x01, /* Usage Page (Desktop), */
2710x75, 0x08, /* Report Size (8), */
2720x09, 0x31, /* Usage (Y), */
2730x81, 0x02, /* Input (Variable), */
2740x09, 0x32, /* Usage (Z), */
2750x81, 0x02, /* Input (Variable), */
2760x06, 0x00, 0xFF, /* Usage Page (FF00h), */
2770x09, 0x01, /* Usage (01h), */
2780x81, 0x02, /* Input (Variable), */
2790xC0, /* End Collection, */
2800xA1, 0x02, /* Collection (Logical), */
2810x09, 0x02, /* Usage (02h), */
2820x95, 0x07, /* Report Count (7), */
2830x91, 0x02, /* Output (Variable), */
2840xC0, /* End Collection, */
2850xC0 /* End Collection */
286};
287
288static __u8 momo2_rdesc_fixed[] = {
2890x05, 0x01, /* Usage Page (Desktop), */
2900x09, 0x04, /* Usage (Joystik), */
2910xA1, 0x01, /* Collection (Application), */
2920xA1, 0x02, /* Collection (Logical), */
2930x95, 0x01, /* Report Count (1), */
2940x75, 0x0A, /* Report Size (10), */
2950x15, 0x00, /* Logical Minimum (0), */
2960x26, 0xFF, 0x03, /* Logical Maximum (1023), */
2970x35, 0x00, /* Physical Minimum (0), */
2980x46, 0xFF, 0x03, /* Physical Maximum (1023), */
2990x09, 0x30, /* Usage (X), */
3000x81, 0x02, /* Input (Variable), */
3010x95, 0x0A, /* Report Count (10), */
3020x75, 0x01, /* Report Size (1), */
3030x25, 0x01, /* Logical Maximum (1), */
3040x45, 0x01, /* Physical Maximum (1), */
3050x05, 0x09, /* Usage Page (Button), */
3060x19, 0x01, /* Usage Minimum (01h), */
3070x29, 0x0A, /* Usage Maximum (0Ah), */
3080x81, 0x02, /* Input (Variable), */
3090x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3100x09, 0x00, /* Usage (00h), */
3110x95, 0x04, /* Report Count (4), */
3120x81, 0x02, /* Input (Variable), */
3130x95, 0x01, /* Report Count (1), */
3140x75, 0x08, /* Report Size (8), */
3150x26, 0xFF, 0x00, /* Logical Maximum (255), */
3160x46, 0xFF, 0x00, /* Physical Maximum (255), */
3170x09, 0x01, /* Usage (01h), */
3180x81, 0x02, /* Input (Variable), */
3190x05, 0x01, /* Usage Page (Desktop), */
3200x09, 0x31, /* Usage (Y), */
3210x81, 0x02, /* Input (Variable), */
3220x09, 0x32, /* Usage (Z), */
3230x81, 0x02, /* Input (Variable), */
3240x06, 0x00, 0xFF, /* Usage Page (FF00h), */
3250x09, 0x00, /* Usage (00h), */
3260x81, 0x02, /* Input (Variable), */
3270xC0, /* End Collection, */
3280xA1, 0x02, /* Collection (Logical), */
3290x09, 0x02, /* Usage (02h), */
3300x95, 0x07, /* Report Count (7), */
3310x91, 0x02, /* Output (Variable), */
3320xC0, /* End Collection, */
3330xC0 /* End Collection */
334};
335
336/*
337 * Certain Logitech keyboards send in report #3 keys which are far
338 * above the logical maximum described in descriptor. This extends
339 * the original value of 0x28c of logical maximum to 0x104d
340 */
341static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
342 unsigned int *rsize)
343{
344 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
345 struct usb_device_descriptor *udesc;
346 __u16 bcdDevice, rev_maj, rev_min;
347
348 if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
349 rdesc[84] == 0x8c && rdesc[85] == 0x02) {
350 hid_info(hdev,
351 "fixing up Logitech keyboard report descriptor\n");
352 rdesc[84] = rdesc[89] = 0x4d;
353 rdesc[85] = rdesc[90] = 0x10;
354 }
355 if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
356 rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
357 rdesc[49] == 0x81 && rdesc[50] == 0x06) {
358 hid_info(hdev,
359 "fixing up rel/abs in Logitech report descriptor\n");
360 rdesc[33] = rdesc[50] = 0x02;
361 }
362
363 switch (hdev->product) {
364
365 /* Several wheels report as this id when operating in emulation mode. */
366 case USB_DEVICE_ID_LOGITECH_WHEEL:
367 udesc = &(hid_to_usb_dev(hdev)->descriptor);
368 if (!udesc) {
369 hid_err(hdev, "NULL USB device descriptor\n");
370 break;
371 }
372 bcdDevice = le16_to_cpu(udesc->bcdDevice);
373 rev_maj = bcdDevice >> 8;
374 rev_min = bcdDevice & 0xff;
375
376 /* Update the report descriptor for only the Driving Force wheel */
377 if (rev_maj == 1 && rev_min == 2 &&
378 *rsize == DF_RDESC_ORIG_SIZE) {
379 hid_info(hdev,
380 "fixing up Logitech Driving Force report descriptor\n");
381 rdesc = df_rdesc_fixed;
382 *rsize = sizeof(df_rdesc_fixed);
383 }
384 break;
385
386 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
387 if (*rsize == MOMO_RDESC_ORIG_SIZE) {
388 hid_info(hdev,
389 "fixing up Logitech Momo Force (Red) report descriptor\n");
390 rdesc = momo_rdesc_fixed;
391 *rsize = sizeof(momo_rdesc_fixed);
392 }
393 break;
394
395 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
396 if (*rsize == MOMO2_RDESC_ORIG_SIZE) {
397 hid_info(hdev,
398 "fixing up Logitech Momo Racing Force (Black) report descriptor\n");
399 rdesc = momo2_rdesc_fixed;
400 *rsize = sizeof(momo2_rdesc_fixed);
401 }
402 break;
403
404 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
405 if (*rsize == FV_RDESC_ORIG_SIZE) {
406 hid_info(hdev,
407 "fixing up Logitech Formula Vibration report descriptor\n");
408 rdesc = fv_rdesc_fixed;
409 *rsize = sizeof(fv_rdesc_fixed);
410 }
411 break;
412
413 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
414 if (*rsize == DFP_RDESC_ORIG_SIZE) {
415 hid_info(hdev,
416 "fixing up Logitech Driving Force Pro report descriptor\n");
417 rdesc = dfp_rdesc_fixed;
418 *rsize = sizeof(dfp_rdesc_fixed);
419 }
420 break;
421
422 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
423 if (*rsize >= 101 && rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
424 rdesc[47] == 0x05 && rdesc[48] == 0x09) {
425 hid_info(hdev, "fixing up Logitech Speed Force Wireless report descriptor\n");
426 rdesc[41] = 0x05;
427 rdesc[42] = 0x09;
428 rdesc[47] = 0x95;
429 rdesc[48] = 0x0B;
430 }
431 break;
432 }
433
434 return rdesc;
435}
436
437#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
438 EV_KEY, (c))
439
440static int lg_ultrax_remote_mapping(struct hid_input *hi,
441 struct hid_usage *usage, unsigned long **bit, int *max)
442{
443 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
444 return 0;
445
446 set_bit(EV_REP, hi->input->evbit);
447 switch (usage->hid & HID_USAGE) {
448 /* Reported on Logitech Ultra X Media Remote */
449 case 0x004: lg_map_key_clear(KEY_AGAIN); break;
450 case 0x00d: lg_map_key_clear(KEY_HOME); break;
451 case 0x024: lg_map_key_clear(KEY_SHUFFLE); break;
452 case 0x025: lg_map_key_clear(KEY_TV); break;
453 case 0x026: lg_map_key_clear(KEY_MENU); break;
454 case 0x031: lg_map_key_clear(KEY_AUDIO); break;
455 case 0x032: lg_map_key_clear(KEY_TEXT); break;
456 case 0x033: lg_map_key_clear(KEY_LAST); break;
457 case 0x047: lg_map_key_clear(KEY_MP3); break;
458 case 0x048: lg_map_key_clear(KEY_DVD); break;
459 case 0x049: lg_map_key_clear(KEY_MEDIA); break;
460 case 0x04a: lg_map_key_clear(KEY_VIDEO); break;
461 case 0x04b: lg_map_key_clear(KEY_ANGLE); break;
462 case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
463 case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
464 case 0x051: lg_map_key_clear(KEY_RED); break;
465 case 0x052: lg_map_key_clear(KEY_CLOSE); break;
466
467 default:
468 return 0;
469 }
470 return 1;
471}
472
473static int lg_dinovo_mapping(struct hid_input *hi, struct hid_usage *usage,
474 unsigned long **bit, int *max)
475{
476 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
477 return 0;
478
479 switch (usage->hid & HID_USAGE) {
480
481 case 0x00d: lg_map_key_clear(KEY_MEDIA); break;
482 default:
483 return 0;
484
485 }
486 return 1;
487}
488
489static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
490 unsigned long **bit, int *max)
491{
492 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
493 return 0;
494
495 switch (usage->hid & HID_USAGE) {
496 case 0x1001: lg_map_key_clear(KEY_MESSENGER); break;
497 case 0x1003: lg_map_key_clear(KEY_SOUND); break;
498 case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
499 case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
500 case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
501 /* The following two entries are Playlist 1 and 2 on the MX3200 */
502 case 0x100f: lg_map_key_clear(KEY_FN_1); break;
503 case 0x1010: lg_map_key_clear(KEY_FN_2); break;
504 case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
505 case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
506 case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
507 case 0x1014: lg_map_key_clear(KEY_MESSENGER); break;
508 case 0x1015: lg_map_key_clear(KEY_RECORD); break;
509 case 0x1016: lg_map_key_clear(KEY_PLAYER); break;
510 case 0x1017: lg_map_key_clear(KEY_EJECTCD); break;
511 case 0x1018: lg_map_key_clear(KEY_MEDIA); break;
512 case 0x1019: lg_map_key_clear(KEY_PROG1); break;
513 case 0x101a: lg_map_key_clear(KEY_PROG2); break;
514 case 0x101b: lg_map_key_clear(KEY_PROG3); break;
515 case 0x101c: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
516 case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
517 case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
518 case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
519 case 0x1023: lg_map_key_clear(KEY_CLOSE); break;
520 case 0x1027: lg_map_key_clear(KEY_MENU); break;
521 /* this one is marked as 'Rotate' */
522 case 0x1028: lg_map_key_clear(KEY_ANGLE); break;
523 case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
524 case 0x102a: lg_map_key_clear(KEY_BACK); break;
525 case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
526 case 0x102d: lg_map_key_clear(KEY_WWW); break;
527 /* The following two are 'Start/answer call' and 'End/reject call'
528 on the MX3200 */
529 case 0x1031: lg_map_key_clear(KEY_OK); break;
530 case 0x1032: lg_map_key_clear(KEY_CANCEL); break;
531 case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
532 case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
533 case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
534 case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break;
535 case 0x1045: lg_map_key_clear(KEY_UNDO); break;
536 case 0x1046: lg_map_key_clear(KEY_REDO); break;
537 case 0x1047: lg_map_key_clear(KEY_PRINT); break;
538 case 0x1048: lg_map_key_clear(KEY_SAVE); break;
539 case 0x1049: lg_map_key_clear(KEY_PROG1); break;
540 case 0x104a: lg_map_key_clear(KEY_PROG2); break;
541 case 0x104b: lg_map_key_clear(KEY_PROG3); break;
542 case 0x104c: lg_map_key_clear(KEY_PROG4); break;
543
544 default:
545 return 0;
546 }
547 return 1;
548}
549
550static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
551 struct hid_field *field, struct hid_usage *usage,
552 unsigned long **bit, int *max)
553{
554 /* extended mapping for certain Logitech hardware (Logitech cordless
555 desktop LX500) */
556 static const u8 e_keymap[] = {
557 0,216, 0,213,175,156, 0, 0, 0, 0,
558 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
559 174,167,152,161,112, 0, 0, 0,154, 0,
560 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,183,184,185,186,187,
564 188,189,190,191,192,193,194, 0, 0, 0
565 };
566 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
567 unsigned int hid = usage->hid;
568
569 if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
570 lg_ultrax_remote_mapping(hi, usage, bit, max))
571 return 1;
572
573 if (hdev->product == USB_DEVICE_ID_DINOVO_MINI &&
574 lg_dinovo_mapping(hi, usage, bit, max))
575 return 1;
576
577 if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
578 return 1;
579
580 if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
581 return 0;
582
583 hid &= HID_USAGE;
584
585 /* Special handling for Logitech Cordless Desktop */
586 if (field->application == HID_GD_MOUSE) {
587 if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
588 (hid == 7 || hid == 8))
589 return -1;
590 } else {
591 if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
592 hid < ARRAY_SIZE(e_keymap) &&
593 e_keymap[hid] != 0) {
594 hid_map_usage(hi, usage, bit, max, EV_KEY,
595 e_keymap[hid]);
596 return 1;
597 }
598 }
599
600 return 0;
601}
602
603static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
604 struct hid_field *field, struct hid_usage *usage,
605 unsigned long **bit, int *max)
606{
607 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
608
609 if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
610 (field->flags & HID_MAIN_ITEM_RELATIVE))
611 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
612
613 if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
614 usage->type == EV_REL || usage->type == EV_ABS))
615 clear_bit(usage->code, *bit);
616
617 /* Ensure that Logitech wheels are not given a default fuzz/flat value */
618 if (usage->type == EV_ABS && (usage->code == ABS_X ||
619 usage->code == ABS_Y || usage->code == ABS_Z ||
620 usage->code == ABS_RZ)) {
621 switch (hdev->product) {
622 case USB_DEVICE_ID_LOGITECH_WHEEL:
623 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL:
624 case USB_DEVICE_ID_LOGITECH_DFP_WHEEL:
625 case USB_DEVICE_ID_LOGITECH_G25_WHEEL:
626 case USB_DEVICE_ID_LOGITECH_DFGT_WHEEL:
627 case USB_DEVICE_ID_LOGITECH_G27_WHEEL:
628 case USB_DEVICE_ID_LOGITECH_WII_WHEEL:
629 case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2:
630 case USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL:
631 field->application = HID_GD_MULTIAXIS;
632 break;
633 default:
634 break;
635 }
636 }
637
638 return 0;
639}
640
641static int lg_event(struct hid_device *hdev, struct hid_field *field,
642 struct hid_usage *usage, __s32 value)
643{
644 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
645
646 if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
647 input_event(field->hidinput->input, usage->type, usage->code,
648 -value);
649 return 1;
650 }
651 if (drv_data->quirks & LG_FF4) {
652 return lg4ff_adjust_input_event(hdev, field, usage, value, drv_data);
653 }
654
655 return 0;
656}
657
658static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
659{
660 unsigned int connect_mask = HID_CONNECT_DEFAULT;
661 struct lg_drv_data *drv_data;
662 int ret;
663
664 drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
665 if (!drv_data) {
666 hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
667 return -ENOMEM;
668 }
669 drv_data->quirks = id->driver_data;
670
671 hid_set_drvdata(hdev, (void *)drv_data);
672
673 if (drv_data->quirks & LG_NOGET)
674 hdev->quirks |= HID_QUIRK_NOGET;
675
676 ret = hid_parse(hdev);
677 if (ret) {
678 hid_err(hdev, "parse failed\n");
679 goto err_free;
680 }
681
682 if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
683 connect_mask &= ~HID_CONNECT_FF;
684
685 ret = hid_hw_start(hdev, connect_mask);
686 if (ret) {
687 hid_err(hdev, "hw start failed\n");
688 goto err_free;
689 }
690
691 /* Setup wireless link with Logitech Wii wheel */
692 if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
693 unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
694
695 ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
696
697 if (ret >= 0) {
698 /* insert a little delay of 10 jiffies ~ 40ms */
699 wait_queue_head_t wait;
700 init_waitqueue_head (&wait);
701 wait_event_interruptible_timeout(wait, 0, 10);
702
703 /* Select random Address */
704 buf[1] = 0xB2;
705 get_random_bytes(&buf[2], 2);
706
707 ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
708 }
709 }
710
711 if (drv_data->quirks & LG_FF)
712 lgff_init(hdev);
713 if (drv_data->quirks & LG_FF2)
714 lg2ff_init(hdev);
715 if (drv_data->quirks & LG_FF3)
716 lg3ff_init(hdev);
717 if (drv_data->quirks & LG_FF4)
718 lg4ff_init(hdev);
719
720 return 0;
721err_free:
722 kfree(drv_data);
723 return ret;
724}
725
726static void lg_remove(struct hid_device *hdev)
727{
728 struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
729 if (drv_data->quirks & LG_FF4)
730 lg4ff_deinit(hdev);
731
732 hid_hw_stop(hdev);
733 kfree(drv_data);
734}
735
736static const struct hid_device_id lg_devices[] = {
737 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
738 .driver_data = LG_RDESC | LG_WIRELESS },
739 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
740 .driver_data = LG_RDESC | LG_WIRELESS },
741 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
742 .driver_data = LG_RDESC | LG_WIRELESS },
743
744 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
745 .driver_data = LG_BAD_RELATIVE_KEYS },
746
747 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
748 .driver_data = LG_DUPLICATE_USAGES },
749 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
750 .driver_data = LG_DUPLICATE_USAGES },
751 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
752 .driver_data = LG_DUPLICATE_USAGES },
753
754 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
755 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
756 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
757 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
758
759 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
760 .driver_data = LG_NOGET },
761 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
762 .driver_data = LG_NOGET | LG_FF4 },
763
764 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD),
765 .driver_data = LG_FF2 },
766 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
767 .driver_data = LG_FF },
768 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
769 .driver_data = LG_FF },
770 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
771 .driver_data = LG_FF },
772 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
773 .driver_data = LG_FF },
774 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
775 .driver_data = LG_NOGET | LG_FF4 },
776 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
777 .driver_data = LG_FF4 },
778 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL),
779 .driver_data = LG_FF2 },
780 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
781 .driver_data = LG_FF4 },
782 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL),
783 .driver_data = LG_FF4 },
784 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
785 .driver_data = LG_FF4 },
786 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
787 .driver_data = LG_NOGET | LG_FF4 },
788 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
789 .driver_data = LG_FF4 },
790 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
791 .driver_data = LG_FF },
792 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
793 .driver_data = LG_NOGET | LG_FF2 },
794 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
795 .driver_data = LG_FF3 },
796 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
797 .driver_data = LG_RDESC_REL_ABS },
798 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
799 .driver_data = LG_RDESC_REL_ABS },
800 { }
801};
802
803MODULE_DEVICE_TABLE(hid, lg_devices);
804
805static struct hid_driver lg_driver = {
806 .name = "logitech",
807 .id_table = lg_devices,
808 .report_fixup = lg_report_fixup,
809 .input_mapping = lg_input_mapping,
810 .input_mapped = lg_input_mapped,
811 .event = lg_event,
812 .probe = lg_probe,
813 .remove = lg_remove,
814};
815module_hid_driver(lg_driver);
816
817MODULE_LICENSE("GPL");