2  *  HID driver for some logitech "special" devices
 
   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) 2007 Paul Walmsley
 
   9  *  Copyright (c) 2008 Jiri Slaby
 
  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)
 
  19 #include <linux/device.h>
 
  20 #include <linux/hid.h>
 
  21 #include <linux/module.h>
 
  26 #define LG_RDESC                0x001
 
  27 #define LG_BAD_RELATIVE_KEYS    0x002
 
  28 #define LG_DUPLICATE_USAGES     0x004
 
  29 #define LG_RESET_LEDS           0x008
 
  30 #define LG_EXPANDED_KEYMAP      0x010
 
  31 #define LG_IGNORE_DOUBLED_WHEEL 0x020
 
  32 #define LG_WIRELESS             0x040
 
  33 #define LG_INVERT_HWHEEL        0x080
 
  34 #define LG_NOGET                0x100
 
  39  * Certain Logitech keyboards send in report #3 keys which are far
 
  40  * above the logical maximum described in descriptor. This extends
 
  41  * the original value of 0x28c of logical maximum to 0x104d
 
  43 static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
  46         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
  48         if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
 
  49                         rdesc[84] == 0x8c && rdesc[85] == 0x02) {
 
  50                 dev_info(&hdev->dev, "fixing up Logitech keyboard report "
 
  52                 rdesc[84] = rdesc[89] = 0x4d;
 
  53                 rdesc[85] = rdesc[90] = 0x10;
 
  57 #define lg_map_key_clear(c)     hid_map_usage_clear(hi, usage, bit, max, \
 
  60 static int lg_ultrax_remote_mapping(struct hid_input *hi,
 
  61                 struct hid_usage *usage, unsigned long **bit, int *max)
 
  63         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
 
  66         set_bit(EV_REP, hi->input->evbit);
 
  67         switch (usage->hid & HID_USAGE) {
 
  68         /* Reported on Logitech Ultra X Media Remote */
 
  69         case 0x004: lg_map_key_clear(KEY_AGAIN);        break;
 
  70         case 0x00d: lg_map_key_clear(KEY_HOME);         break;
 
  71         case 0x024: lg_map_key_clear(KEY_SHUFFLE);      break;
 
  72         case 0x025: lg_map_key_clear(KEY_TV);           break;
 
  73         case 0x026: lg_map_key_clear(KEY_MENU);         break;
 
  74         case 0x031: lg_map_key_clear(KEY_AUDIO);        break;
 
  75         case 0x032: lg_map_key_clear(KEY_TEXT);         break;
 
  76         case 0x033: lg_map_key_clear(KEY_LAST);         break;
 
  77         case 0x047: lg_map_key_clear(KEY_MP3);          break;
 
  78         case 0x048: lg_map_key_clear(KEY_DVD);          break;
 
  79         case 0x049: lg_map_key_clear(KEY_MEDIA);        break;
 
  80         case 0x04a: lg_map_key_clear(KEY_VIDEO);        break;
 
  81         case 0x04b: lg_map_key_clear(KEY_ANGLE);        break;
 
  82         case 0x04c: lg_map_key_clear(KEY_LANGUAGE);     break;
 
  83         case 0x04d: lg_map_key_clear(KEY_SUBTITLE);     break;
 
  84         case 0x051: lg_map_key_clear(KEY_RED);          break;
 
  85         case 0x052: lg_map_key_clear(KEY_CLOSE);        break;
 
  93 static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
 
  94                 unsigned long **bit, int *max)
 
  96         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
 
  99         switch (usage->hid & HID_USAGE) {
 
 100         case 0x1001: lg_map_key_clear(KEY_MESSENGER);           break;
 
 101         case 0x1003: lg_map_key_clear(KEY_SOUND);               break;
 
 102         case 0x1004: lg_map_key_clear(KEY_VIDEO);               break;
 
 103         case 0x1005: lg_map_key_clear(KEY_AUDIO);               break;
 
 104         case 0x100a: lg_map_key_clear(KEY_DOCUMENTS);           break;
 
 105         case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG);        break;
 
 106         case 0x1012: lg_map_key_clear(KEY_NEXTSONG);            break;
 
 107         case 0x1013: lg_map_key_clear(KEY_CAMERA);              break;
 
 108         case 0x1014: lg_map_key_clear(KEY_MESSENGER);           break;
 
 109         case 0x1015: lg_map_key_clear(KEY_RECORD);              break;
 
 110         case 0x1016: lg_map_key_clear(KEY_PLAYER);              break;
 
 111         case 0x1017: lg_map_key_clear(KEY_EJECTCD);             break;
 
 112         case 0x1018: lg_map_key_clear(KEY_MEDIA);               break;
 
 113         case 0x1019: lg_map_key_clear(KEY_PROG1);               break;
 
 114         case 0x101a: lg_map_key_clear(KEY_PROG2);               break;
 
 115         case 0x101b: lg_map_key_clear(KEY_PROG3);               break;
 
 116         case 0x101f: lg_map_key_clear(KEY_ZOOMIN);              break;
 
 117         case 0x1020: lg_map_key_clear(KEY_ZOOMOUT);             break;
 
 118         case 0x1021: lg_map_key_clear(KEY_ZOOMRESET);           break;
 
 119         case 0x1023: lg_map_key_clear(KEY_CLOSE);               break;
 
 120         case 0x1027: lg_map_key_clear(KEY_MENU);                break;
 
 121         /* this one is marked as 'Rotate' */
 
 122         case 0x1028: lg_map_key_clear(KEY_ANGLE);               break;
 
 123         case 0x1029: lg_map_key_clear(KEY_SHUFFLE);             break;
 
 124         case 0x102a: lg_map_key_clear(KEY_BACK);                break;
 
 125         case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS);        break;
 
 126         case 0x1041: lg_map_key_clear(KEY_BATTERY);             break;
 
 127         case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR);       break;
 
 128         case 0x1043: lg_map_key_clear(KEY_SPREADSHEET);         break;
 
 129         case 0x1044: lg_map_key_clear(KEY_PRESENTATION);        break;
 
 130         case 0x1045: lg_map_key_clear(KEY_UNDO);                break;
 
 131         case 0x1046: lg_map_key_clear(KEY_REDO);                break;
 
 132         case 0x1047: lg_map_key_clear(KEY_PRINT);               break;
 
 133         case 0x1048: lg_map_key_clear(KEY_SAVE);                break;
 
 134         case 0x1049: lg_map_key_clear(KEY_PROG1);               break;
 
 135         case 0x104a: lg_map_key_clear(KEY_PROG2);               break;
 
 136         case 0x104b: lg_map_key_clear(KEY_PROG3);               break;
 
 137         case 0x104c: lg_map_key_clear(KEY_PROG4);               break;
 
 145 static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
 146                 struct hid_field *field, struct hid_usage *usage,
 
 147                 unsigned long **bit, int *max)
 
 149         /* extended mapping for certain Logitech hardware (Logitech cordless
 
 151         static const u8 e_keymap[] = {
 
 152                   0,216,  0,213,175,156,  0,  0,  0,  0,
 
 153                 144,  0,  0,  0,  0,  0,  0,  0,  0,212,
 
 154                 174,167,152,161,112,  0,  0,  0,154,  0,
 
 155                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
 156                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
 157                   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
 158                   0,  0,  0,  0,  0,183,184,185,186,187,
 
 159                 188,189,190,191,192,193,194,  0,  0,  0
 
 161         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
 162         unsigned int hid = usage->hid;
 
 164         if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
 
 165                         lg_ultrax_remote_mapping(hi, usage, bit, max))
 
 168         if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
 
 171         if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
 
 176         /* Special handling for Logitech Cordless Desktop */
 
 177         if (field->application == HID_GD_MOUSE) {
 
 178                 if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
 
 179                                 (hid == 7 || hid == 8))
 
 182                 if ((quirks & LG_EXPANDED_KEYMAP) &&
 
 183                                 hid < ARRAY_SIZE(e_keymap) &&
 
 184                                 e_keymap[hid] != 0) {
 
 185                         hid_map_usage(hi, usage, bit, max, EV_KEY,
 
 194 static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
 
 195                 struct hid_field *field, struct hid_usage *usage,
 
 196                 unsigned long **bit, int *max)
 
 198         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
 200         if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
 
 201                         (field->flags & HID_MAIN_ITEM_RELATIVE))
 
 202                 field->flags &= ~HID_MAIN_ITEM_RELATIVE;
 
 204         if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
 
 205                          usage->type == EV_REL || usage->type == EV_ABS))
 
 206                 clear_bit(usage->code, *bit);
 
 211 static int lg_event(struct hid_device *hdev, struct hid_field *field,
 
 212                 struct hid_usage *usage, __s32 value)
 
 214         unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
 
 216         if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
 
 217                 input_event(field->hidinput->input, usage->type, usage->code,
 
 225 static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 227         unsigned long quirks = id->driver_data;
 
 228         unsigned int connect_mask = HID_CONNECT_DEFAULT;
 
 231         hid_set_drvdata(hdev, (void *)quirks);
 
 233         if (quirks & LG_NOGET)
 
 234                 hdev->quirks |= HID_QUIRK_NOGET;
 
 236         ret = hid_parse(hdev);
 
 238                 dev_err(&hdev->dev, "parse failed\n");
 
 242         if (quirks & (LG_FF | LG_FF2))
 
 243                 connect_mask &= ~HID_CONNECT_FF;
 
 245         ret = hid_hw_start(hdev, connect_mask);
 
 247                 dev_err(&hdev->dev, "hw start failed\n");
 
 251         if (quirks & LG_RESET_LEDS)
 
 252                 usbhid_set_leds(hdev);
 
 264 static const struct hid_device_id lg_devices[] = {
 
 265         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
 
 266                 .driver_data = LG_RDESC | LG_WIRELESS },
 
 267         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
 
 268                 .driver_data = LG_RDESC | LG_WIRELESS },
 
 269         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
 
 270                 .driver_data = LG_RDESC | LG_WIRELESS },
 
 272         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
 
 273                 .driver_data = LG_BAD_RELATIVE_KEYS },
 
 275         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
 
 276                 .driver_data = LG_DUPLICATE_USAGES },
 
 277         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
 
 278                 .driver_data = LG_DUPLICATE_USAGES },
 
 279         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
 
 280                 .driver_data = LG_DUPLICATE_USAGES },
 
 282         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
 
 283                 .driver_data = LG_RESET_LEDS },
 
 285         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
 
 286                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 
 287         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
 
 288                 .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
 
 290         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
 
 291                 .driver_data = LG_NOGET },
 
 292         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
 
 293                 .driver_data = LG_NOGET | LG_FF },
 
 295         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
 
 296                 .driver_data = LG_FF },
 
 297         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
 
 298                 .driver_data = LG_FF },
 
 299         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
 
 300                 .driver_data = LG_FF },
 
 301         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
 
 302                 .driver_data = LG_FF },
 
 303         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
 
 304                 .driver_data = LG_FF },
 
 305         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
 
 306                 .driver_data = LG_FF },
 
 307         { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
 
 308                 .driver_data = LG_FF2 },
 
 311 MODULE_DEVICE_TABLE(hid, lg_devices);
 
 313 static struct hid_driver lg_driver = {
 
 315         .id_table = lg_devices,
 
 316         .report_fixup = lg_report_fixup,
 
 317         .input_mapping = lg_input_mapping,
 
 318         .input_mapped = lg_input_mapped,
 
 323 static int lg_init(void)
 
 325         return hid_register_driver(&lg_driver);
 
 328 static void lg_exit(void)
 
 330         hid_unregister_driver(&lg_driver);
 
 333 module_init(lg_init);
 
 334 module_exit(lg_exit);
 
 335 MODULE_LICENSE("GPL");
 
 337 HID_COMPAT_LOAD_DRIVER(logitech);