aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/usbhid/hid-quirks.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2007-06-19 08:09:14 -0400
committerJiri Kosina <jkosina@suse.cz>2007-07-09 08:13:34 -0400
commitea9a4a8b0e5a34eca6613e39d21be879d92ecff5 (patch)
treef9e816b5a7719e0528b2c0426aeac6d32d7b422f /drivers/hid/usbhid/hid-quirks.c
parentb8e98f1c47b743e56f8ebe21006199cefd577ce5 (diff)
HID: separate quirks for report descriptor fixup
Lately there have been quite a lot of bug reports against broken devices which require us to fix their report descriptor in the runtime, before it is passed to the HID parser. Those devices have eaten quite an amount of our quirks space, which isn't particularly necessary - the quirks are not needed after the report descriptor is parsed, and they just consume bits. Therefore this patch separates the quirks for report descriptor fixup, and moves their handling into separate code. The quirks are then forgotten as soon as the report descriptor has been parsed. Module parameter 'rdesc_quirks' is introduced to be able to modify these quirks in runtime in a similar way to 'quirks' parameter for ordinary HID quirks. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/usbhid/hid-quirks.c')
-rw-r--r--drivers/hid/usbhid/hid-quirks.c155
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 */
466static 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 */
726static 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 */
741static 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 */
753static 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 */
771static 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
792static 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 */
817void 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 &paramVendor, &paramProduct, &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}