diff options
author | Jiri Kosina <jkosina@suse.cz> | 2007-06-19 08:09:14 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2007-07-09 08:13:34 -0400 |
commit | ea9a4a8b0e5a34eca6613e39d21be879d92ecff5 (patch) | |
tree | f9e816b5a7719e0528b2c0426aeac6d32d7b422f /drivers/hid/usbhid/hid-core.c | |
parent | b8e98f1c47b743e56f8ebe21006199cefd577ce5 (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-core.c')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 89 |
1 files changed, 9 insertions, 80 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ef7b881aab3..3efc3734cec 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -60,6 +60,12 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying " | |||
60 | " quirks=vendorID:productID:quirks" | 60 | " quirks=vendorID:productID:quirks" |
61 | " where vendorID, productID, and quirks are all in" | 61 | " where vendorID, productID, and quirks are all in" |
62 | " 0x-prefixed hex"); | 62 | " 0x-prefixed hex"); |
63 | static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; | ||
64 | module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444); | ||
65 | MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying " | ||
66 | " rdesc_quirks=vendorID:productID:rdesc_quirks" | ||
67 | " where vendorID, productID, and rdesc_quirks are all in" | ||
68 | " 0x-prefixed hex"); | ||
63 | /* | 69 | /* |
64 | * Input submission and I/O error handler. | 70 | * Input submission and I/O error handler. |
65 | */ | 71 | */ |
@@ -633,20 +639,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | |||
633 | } | 639 | } |
634 | 640 | ||
635 | /* | 641 | /* |
636 | * Cherry Cymotion keyboard have an invalid HID report descriptor, | ||
637 | * that needs fixing before we can parse it. | ||
638 | */ | ||
639 | |||
640 | static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize) | ||
641 | { | ||
642 | if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { | ||
643 | info("Fixing up Cherry Cymotion report descriptor"); | ||
644 | rdesc[11] = rdesc[16] = 0xff; | ||
645 | rdesc[12] = rdesc[17] = 0x03; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | /* | ||
650 | * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller | 642 | * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller |
651 | * to "operational". Without this, the ps3 controller will not report any | 643 | * to "operational". Without this, the ps3 controller will not report any |
652 | * events. | 644 | * events. |
@@ -672,61 +664,6 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) | |||
672 | kfree(buf); | 664 | kfree(buf); |
673 | } | 665 | } |
674 | 666 | ||
675 | /* | ||
676 | * Certain Logitech keyboards send in report #3 keys which are far | ||
677 | * above the logical maximum described in descriptor. This extends | ||
678 | * the original value of 0x28c of logical maximum to 0x104d | ||
679 | */ | ||
680 | static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) | ||
681 | { | ||
682 | if (rsize >= 90 && rdesc[83] == 0x26 | ||
683 | && rdesc[84] == 0x8c | ||
684 | && rdesc[85] == 0x02) { | ||
685 | info("Fixing up Logitech keyboard report descriptor"); | ||
686 | rdesc[84] = rdesc[89] = 0x4d; | ||
687 | rdesc[85] = rdesc[90] = 0x10; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | /* Petalynx Maxter Remote has maximum for consumer page set too low */ | ||
692 | static void hid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) | ||
693 | { | ||
694 | if (rsize >= 60 && rdesc[39] == 0x2a | ||
695 | && rdesc[40] == 0xf5 | ||
696 | && rdesc[41] == 0x00 | ||
697 | && rdesc[59] == 0x26 | ||
698 | && rdesc[60] == 0xf9 | ||
699 | && rdesc[61] == 0x00) { | ||
700 | info("Fixing up Petalynx Maxter Remote report descriptor"); | ||
701 | rdesc[60] = 0xfa; | ||
702 | rdesc[40] = 0xfa; | ||
703 | } | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | * Some USB barcode readers from cypress have usage min and usage max in | ||
708 | * the wrong order | ||
709 | */ | ||
710 | static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) | ||
711 | { | ||
712 | short fixed = 0; | ||
713 | int i; | ||
714 | |||
715 | for (i = 0; i < rsize - 4; i++) { | ||
716 | if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { | ||
717 | unsigned char tmp; | ||
718 | |||
719 | rdesc[i] = 0x19; rdesc[i+2] = 0x29; | ||
720 | tmp = rdesc[i+3]; | ||
721 | rdesc[i+3] = rdesc[i+1]; | ||
722 | rdesc[i+1] = tmp; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | if (fixed) | ||
727 | info("Fixing up Cypress report descriptor"); | ||
728 | } | ||
729 | |||
730 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) | 667 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) |
731 | { | 668 | { |
732 | struct usb_host_interface *interface = intf->cur_altsetting; | 669 | struct usb_host_interface *interface = intf->cur_altsetting; |
@@ -787,17 +724,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
787 | return NULL; | 724 | return NULL; |
788 | } | 725 | } |
789 | 726 | ||
790 | if ((quirks & HID_QUIRK_CYMOTION)) | 727 | usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor), |
791 | hid_fixup_cymotion_descriptor(rdesc, rsize); | 728 | le16_to_cpu(dev->descriptor.idProduct), rdesc, |
792 | 729 | rsize, rdesc_quirks_param); | |
793 | if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) | ||
794 | hid_fixup_logitech_descriptor(rdesc, rsize); | ||
795 | |||
796 | if (quirks & HID_QUIRK_SWAPPED_MIN_MAX) | ||
797 | hid_fixup_cypress_descriptor(rdesc, rsize); | ||
798 | |||
799 | if (quirks & HID_QUIRK_PETALYNX_DESCRIPTOR) | ||
800 | hid_fixup_petalynx_descriptor(rdesc, rsize); | ||
801 | 730 | ||
802 | #ifdef CONFIG_HID_DEBUG | 731 | #ifdef CONFIG_HID_DEBUG |
803 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); | 732 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); |