diff options
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r-- | drivers/hid/hid-input.c | 92 |
1 files changed, 83 insertions, 9 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 8edbd30cf795..0c3e12c1794c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = { | |||
53 | 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, | 53 | 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, |
54 | 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 54 | 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
55 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 55 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
56 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 56 | unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, |
57 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 57 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
58 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, | 58 | unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, |
59 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, | 59 | 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, |
@@ -86,6 +86,10 @@ static const struct { | |||
86 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) | 86 | #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) |
87 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) | 87 | #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) |
88 | 88 | ||
89 | /* hardware needing special handling due to colliding MSVENDOR page usages */ | ||
90 | #define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418) | ||
91 | #define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9)) | ||
92 | |||
89 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK | 93 | #ifdef CONFIG_USB_HIDINPUT_POWERBOOK |
90 | 94 | ||
91 | struct hidinput_key_translation { | 95 | struct hidinput_key_translation { |
@@ -295,7 +299,7 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode, | |||
295 | { | 299 | { |
296 | struct hid_device *hid = dev->private; | 300 | struct hid_device *hid = dev->private; |
297 | struct hid_usage *usage; | 301 | struct hid_usage *usage; |
298 | 302 | ||
299 | usage = hidinput_find_key(hid, scancode, 0); | 303 | usage = hidinput_find_key(hid, scancode, 0); |
300 | if (usage) { | 304 | if (usage) { |
301 | *keycode = usage->code; | 305 | *keycode = usage->code; |
@@ -310,15 +314,15 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, | |||
310 | struct hid_device *hid = dev->private; | 314 | struct hid_device *hid = dev->private; |
311 | struct hid_usage *usage; | 315 | struct hid_usage *usage; |
312 | int old_keycode; | 316 | int old_keycode; |
313 | 317 | ||
314 | if (keycode < 0 || keycode > KEY_MAX) | 318 | if (keycode < 0 || keycode > KEY_MAX) |
315 | return -EINVAL; | 319 | return -EINVAL; |
316 | 320 | ||
317 | usage = hidinput_find_key(hid, scancode, 0); | 321 | usage = hidinput_find_key(hid, scancode, 0); |
318 | if (usage) { | 322 | if (usage) { |
319 | old_keycode = usage->code; | 323 | old_keycode = usage->code; |
320 | usage->code = keycode; | 324 | usage->code = keycode; |
321 | 325 | ||
322 | clear_bit(old_keycode, dev->keybit); | 326 | clear_bit(old_keycode, dev->keybit); |
323 | set_bit(usage->code, dev->keybit); | 327 | set_bit(usage->code, dev->keybit); |
324 | dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); | 328 | dbg_hid(KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); |
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode, | |||
326 | * by another key */ | 330 | * by another key */ |
327 | if (hidinput_find_key (hid, 0, old_keycode)) | 331 | if (hidinput_find_key (hid, 0, old_keycode)) |
328 | set_bit(old_keycode, dev->keybit); | 332 | set_bit(old_keycode, dev->keybit); |
329 | 333 | ||
330 | return 0; | 334 | return 0; |
331 | } | 335 | } |
332 | 336 | ||
333 | return -EINVAL; | 337 | return -EINVAL; |
334 | } | 338 | } |
335 | 339 | ||
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
351 | if (field->flags & HID_MAIN_ITEM_CONSTANT) | 355 | if (field->flags & HID_MAIN_ITEM_CONSTANT) |
352 | goto ignore; | 356 | goto ignore; |
353 | 357 | ||
358 | /* only LED usages are supported in output fields */ | ||
359 | if (field->report_type == HID_OUTPUT_REPORT && | ||
360 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { | ||
361 | dbg_hid_line(" [non-LED output field] "); | ||
362 | goto ignore; | ||
363 | } | ||
364 | |||
354 | switch (usage->hid & HID_USAGE_PAGE) { | 365 | switch (usage->hid & HID_USAGE_PAGE) { |
355 | 366 | ||
356 | case HID_UP_UNDEFINED: | 367 | case HID_UP_UNDEFINED: |
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
595 | case 0x0f6: map_key_clear(KEY_NEXT); break; | 606 | case 0x0f6: map_key_clear(KEY_NEXT); break; |
596 | case 0x0fa: map_key_clear(KEY_BACK); break; | 607 | case 0x0fa: map_key_clear(KEY_BACK); break; |
597 | 608 | ||
609 | case 0x182: map_key_clear(KEY_BOOKMARKS); break; | ||
598 | case 0x183: map_key_clear(KEY_CONFIG); break; | 610 | case 0x183: map_key_clear(KEY_CONFIG); break; |
599 | case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; | 611 | case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; |
600 | case 0x185: map_key_clear(KEY_EDITOR); break; | 612 | case 0x185: map_key_clear(KEY_EDITOR); break; |
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
611 | case 0x192: map_key_clear(KEY_CALC); break; | 623 | case 0x192: map_key_clear(KEY_CALC); break; |
612 | case 0x194: map_key_clear(KEY_FILE); break; | 624 | case 0x194: map_key_clear(KEY_FILE); break; |
613 | case 0x196: map_key_clear(KEY_WWW); break; | 625 | case 0x196: map_key_clear(KEY_WWW); break; |
626 | case 0x19c: map_key_clear(KEY_LOGOFF); break; | ||
614 | case 0x19e: map_key_clear(KEY_COFFEE); break; | 627 | case 0x19e: map_key_clear(KEY_COFFEE); break; |
615 | case 0x1a6: map_key_clear(KEY_HELP); break; | 628 | case 0x1a6: map_key_clear(KEY_HELP); break; |
616 | case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; | 629 | case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; |
630 | case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; | ||
631 | case 0x1b6: map_key_clear(KEY_MEDIA); break; | ||
632 | case 0x1b7: map_key_clear(KEY_SOUND); break; | ||
617 | case 0x1bc: map_key_clear(KEY_MESSENGER); break; | 633 | case 0x1bc: map_key_clear(KEY_MESSENGER); break; |
618 | case 0x1bd: map_key_clear(KEY_INFO); break; | 634 | case 0x1bd: map_key_clear(KEY_INFO); break; |
619 | case 0x201: map_key_clear(KEY_NEW); break; | 635 | case 0x201: map_key_clear(KEY_NEW); break; |
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
720 | 736 | ||
721 | case HID_UP_MSVENDOR: | 737 | case HID_UP_MSVENDOR: |
722 | 738 | ||
723 | /* special case - Chicony Chicony KU-0418 tactical pad */ | 739 | /* Unfortunately, there are multiple devices which |
724 | if (device->vendor == 0x04f2 && device->product == 0x0418) { | 740 | * emit usages from MSVENDOR page that require different |
741 | * handling. If this list grows too much in the future, | ||
742 | * more general handling will have to be introduced here | ||
743 | * (i.e. another blacklist). | ||
744 | */ | ||
745 | |||
746 | /* Chicony Chicony KU-0418 tactical pad */ | ||
747 | if (IS_CHICONY_TACTICAL_PAD(device)) { | ||
725 | set_bit(EV_REP, input->evbit); | 748 | set_bit(EV_REP, input->evbit); |
726 | switch(usage->hid & HID_USAGE) { | 749 | switch(usage->hid & HID_USAGE) { |
727 | case 0xff01: map_key_clear(BTN_1); break; | 750 | case 0xff01: map_key_clear(BTN_1); break; |
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
737 | case 0xff0b: map_key_clear(BTN_B); break; | 760 | case 0xff0b: map_key_clear(BTN_B); break; |
738 | default: goto ignore; | 761 | default: goto ignore; |
739 | } | 762 | } |
763 | |||
764 | /* Microsoft Natural Ergonomic Keyboard 4000 */ | ||
765 | } else if (IS_MS_KB(device)) { | ||
766 | switch(usage->hid & HID_USAGE) { | ||
767 | case 0xfd06: | ||
768 | map_key_clear(KEY_CHAT); | ||
769 | break; | ||
770 | case 0xfd07: | ||
771 | map_key_clear(KEY_PHONE); | ||
772 | break; | ||
773 | case 0xff05: | ||
774 | set_bit(EV_REP, input->evbit); | ||
775 | map_key_clear(KEY_F13); | ||
776 | set_bit(KEY_F14, input->keybit); | ||
777 | set_bit(KEY_F15, input->keybit); | ||
778 | set_bit(KEY_F16, input->keybit); | ||
779 | set_bit(KEY_F17, input->keybit); | ||
780 | set_bit(KEY_F18, input->keybit); | ||
781 | default: goto ignore; | ||
782 | } | ||
740 | } else { | 783 | } else { |
741 | goto ignore; | 784 | goto ignore; |
742 | } | 785 | } |
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
888 | set_bit(KEY_VOLUMEDOWN, input->keybit); | 931 | set_bit(KEY_VOLUMEDOWN, input->keybit); |
889 | } | 932 | } |
890 | 933 | ||
934 | if (usage->type == EV_KEY) { | ||
935 | set_bit(EV_MSC, input->evbit); | ||
936 | set_bit(MSC_SCAN, input->mscbit); | ||
937 | } | ||
938 | |||
891 | hid_resolv_event(usage->type, usage->code); | 939 | hid_resolv_event(usage->type, usage->code); |
892 | 940 | ||
893 | dbg_hid_line("\n"); | 941 | dbg_hid_line("\n"); |
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
991 | return; | 1039 | return; |
992 | } | 1040 | } |
993 | 1041 | ||
1042 | /* Handling MS keyboards special buttons */ | ||
1043 | if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { | ||
1044 | int key = 0; | ||
1045 | static int last_key = 0; | ||
1046 | switch (value) { | ||
1047 | case 0x01: key = KEY_F14; break; | ||
1048 | case 0x02: key = KEY_F15; break; | ||
1049 | case 0x04: key = KEY_F16; break; | ||
1050 | case 0x08: key = KEY_F17; break; | ||
1051 | case 0x10: key = KEY_F18; break; | ||
1052 | default: break; | ||
1053 | } | ||
1054 | if (key) { | ||
1055 | input_event(input, usage->type, key, 1); | ||
1056 | last_key = key; | ||
1057 | } else { | ||
1058 | input_event(input, usage->type, last_key, 0); | ||
1059 | } | ||
1060 | } | ||
1061 | /* report the usage code as scancode if the key status has changed */ | ||
1062 | if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) | ||
1063 | input_event(input, EV_MSC, MSC_SCAN, usage->hid); | ||
1064 | |||
994 | input_event(input, usage->type, usage->code, value); | 1065 | input_event(input, usage->type, usage->code, value); |
995 | 1066 | ||
996 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) | 1067 | if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) |
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid) | |||
1051 | int i, j, k; | 1122 | int i, j, k; |
1052 | int max_report_type = HID_OUTPUT_REPORT; | 1123 | int max_report_type = HID_OUTPUT_REPORT; |
1053 | 1124 | ||
1125 | if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT) | ||
1126 | return -1; | ||
1127 | |||
1054 | INIT_LIST_HEAD(&hid->inputs); | 1128 | INIT_LIST_HEAD(&hid->inputs); |
1055 | 1129 | ||
1056 | for (i = 0; i < hid->maxcollection; i++) | 1130 | for (i = 0; i < hid->maxcollection; i++) |