diff options
Diffstat (limited to 'drivers/hid/usbhid/hid-quirks.c')
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 155 |
1 files changed, 144 insertions, 11 deletions
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a78f5187b6ef..a75c236fcafc 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
@@ -299,8 +299,6 @@ static const struct hid_blacklist { | |||
299 | { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, | 299 | { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, |
300 | { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, | 300 | { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, |
301 | 301 | ||
302 | { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, | ||
303 | |||
304 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, | 302 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, |
305 | 303 | ||
306 | { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, | 304 | { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, |
@@ -424,17 +422,11 @@ static const struct hid_blacklist { | |||
424 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, | 422 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, |
425 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, | 423 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, |
426 | 424 | ||
427 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, | ||
428 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, | ||
429 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR }, | ||
430 | |||
431 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, | 425 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, |
432 | 426 | ||
433 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, | 427 | { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, |
434 | { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, | 428 | { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, |
435 | 429 | ||
436 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_PETALYNX_DESCRIPTOR | HID_QUIRK_NOGET }, | ||
437 | |||
438 | { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, | 430 | { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, |
439 | 431 | ||
440 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, | 432 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, |
@@ -443,6 +435,7 @@ static const struct hid_blacklist { | |||
443 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | 435 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, |
444 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, | 436 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, |
445 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, | 437 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, |
438 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, | ||
446 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | 439 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
447 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, | 440 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, |
448 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, | 441 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, |
@@ -466,8 +459,26 @@ static const struct hid_blacklist { | |||
466 | 459 | ||
467 | { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, | 460 | { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, |
468 | 461 | ||
469 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX }, | 462 | { 0, 0 } |
470 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX }, | 463 | }; |
464 | |||
465 | /* Quirks for devices which require report descriptor fixup go here */ | ||
466 | static const struct hid_rdesc_blacklist { | ||
467 | __u16 idVendor; | ||
468 | __u16 idProduct; | ||
469 | __u32 quirks; | ||
470 | } hid_rdesc_blacklist[] = { | ||
471 | |||
472 | { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION }, | ||
473 | |||
474 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, | ||
475 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, | ||
476 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, | ||
477 | |||
478 | { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, | ||
479 | |||
480 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, | ||
481 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, | ||
471 | 482 | ||
472 | { 0, 0 } | 483 | { 0, 0 } |
473 | }; | 484 | }; |
@@ -576,7 +587,6 @@ int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, | |||
576 | return 0; | 587 | return 0; |
577 | } | 588 | } |
578 | 589 | ||
579 | |||
580 | /** | 590 | /** |
581 | * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory | 591 | * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory |
582 | * | 592 | * |
@@ -709,3 +719,126 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) | |||
709 | return quirks; | 719 | return quirks; |
710 | } | 720 | } |
711 | 721 | ||
722 | /* | ||
723 | * Cherry Cymotion keyboard have an invalid HID report descriptor, | ||
724 | * that needs fixing before we can parse it. | ||
725 | */ | ||
726 | static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize) | ||
727 | { | ||
728 | if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { | ||
729 | printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n"); | ||
730 | rdesc[11] = rdesc[16] = 0xff; | ||
731 | rdesc[12] = rdesc[17] = 0x03; | ||
732 | } | ||
733 | } | ||
734 | |||
735 | |||
736 | /* | ||
737 | * Certain Logitech keyboards send in report #3 keys which are far | ||
738 | * above the logical maximum described in descriptor. This extends | ||
739 | * the original value of 0x28c of logical maximum to 0x104d | ||
740 | */ | ||
741 | static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) | ||
742 | { | ||
743 | if (rsize >= 90 && rdesc[83] == 0x26 | ||
744 | && rdesc[84] == 0x8c | ||
745 | && rdesc[85] == 0x02) { | ||
746 | printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n"); | ||
747 | rdesc[84] = rdesc[89] = 0x4d; | ||
748 | rdesc[85] = rdesc[90] = 0x10; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | /* Petalynx Maxter Remote has maximum for consumer page set too low */ | ||
753 | static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) | ||
754 | { | ||
755 | if (rsize >= 60 && rdesc[39] == 0x2a | ||
756 | && rdesc[40] == 0xf5 | ||
757 | && rdesc[41] == 0x00 | ||
758 | && rdesc[59] == 0x26 | ||
759 | && rdesc[60] == 0xf9 | ||
760 | && rdesc[61] == 0x00) { | ||
761 | printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n"); | ||
762 | rdesc[60] = 0xfa; | ||
763 | rdesc[40] = 0xfa; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * Some USB barcode readers from cypress have usage min and usage max in | ||
769 | * the wrong order | ||
770 | */ | ||
771 | static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) | ||
772 | { | ||
773 | short fixed = 0; | ||
774 | int i; | ||
775 | |||
776 | for (i = 0; i < rsize - 4; i++) { | ||
777 | if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { | ||
778 | unsigned char tmp; | ||
779 | |||
780 | rdesc[i] = 0x19; rdesc[i+2] = 0x29; | ||
781 | tmp = rdesc[i+3]; | ||
782 | rdesc[i+3] = rdesc[i+1]; | ||
783 | rdesc[i+1] = tmp; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (fixed) | ||
788 | printk(KERN_INFO "Fixing up Cypress report descriptor\n"); | ||
789 | } | ||
790 | |||
791 | |||
792 | static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) | ||
793 | { | ||
794 | if ((quirks & HID_QUIRK_RDESC_CYMOTION)) | ||
795 | usbhid_fixup_cymotion_descriptor(rdesc, rsize); | ||
796 | |||
797 | if (quirks & HID_QUIRK_RDESC_LOGITECH) | ||
798 | usbhid_fixup_logitech_descriptor(rdesc, rsize); | ||
799 | |||
800 | if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX) | ||
801 | usbhid_fixup_cypress_descriptor(rdesc, rsize); | ||
802 | |||
803 | if (quirks & HID_QUIRK_RDESC_PETALYNX) | ||
804 | usbhid_fixup_petalynx_descriptor(rdesc, rsize); | ||
805 | } | ||
806 | |||
807 | /** | ||
808 | * usbhid_fixup_report_descriptor: check if report descriptor needs fixup | ||
809 | * | ||
810 | * Description: | ||
811 | * Walks the hid_rdesc_blacklist[] array and checks whether the device | ||
812 | * is known to have broken report descriptor that needs to be fixed up | ||
813 | * prior to entering the HID parser | ||
814 | * | ||
815 | * Returns: nothing | ||
816 | */ | ||
817 | void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct, | ||
818 | char *rdesc, unsigned rsize, char **quirks_param) | ||
819 | { | ||
820 | int n, m; | ||
821 | u16 paramVendor, paramProduct; | ||
822 | u32 quirks; | ||
823 | |||
824 | /* static rdesc quirk entries */ | ||
825 | for (n = 0; hid_rdesc_blacklist[n].idVendor; n++) | ||
826 | if (hid_rdesc_blacklist[n].idVendor == idVendor && | ||
827 | hid_rdesc_blacklist[n].idProduct == idProduct) | ||
828 | __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks, | ||
829 | rdesc, rsize); | ||
830 | |||
831 | /* runtime rdesc quirk entries handling */ | ||
832 | for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { | ||
833 | m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", | ||
834 | ¶mVendor, ¶mProduct, &quirks); | ||
835 | |||
836 | if (m != 3) | ||
837 | printk(KERN_WARNING | ||
838 | "Could not parse HID quirk module param %s\n", | ||
839 | quirks_param[n]); | ||
840 | else if (paramVendor == idVendor && paramProduct == idProduct) | ||
841 | __usbhid_fixup_report_descriptor(quirks, rdesc, rsize); | ||
842 | } | ||
843 | |||
844 | } | ||