From: Pekka Sarnila Date: Thu, 6 Mar 2008 12:23:14 +0000 (+0100) Subject: HID: fixup fullspeed interval on highspeed Afatech DVB-T IR kbd X-Git-Tag: v2.6.26-rc1~1107^2~18 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f345c37c37641beceb0e52f61bb4cbc72904ee09;p=linux-2.6 HID: fixup fullspeed interval on highspeed Afatech DVB-T IR kbd Many vendors highspeed devices give erroneously fullspeed interval value in endpoint descriptor for interrupt endpoints. This quirk fixes up that by recalculating the right value for highspeed device. At the time of hid configuration this quirk calculates which highspeed interval value gives same interval delay as, or next smaller then, what it would be if the original value would be interpreted as fullspeed value. In subsequent urbs that new value is used instead. Forming the 'hid->name' in usb_hid_config() was moved up to accommodate more descriptive printk reporting the fixup. In this patch the quirk is set for one such device: Afatech DVB-T 2 infrared HID-keyboard. It reports value 16 which means 4,069s in highspeed while obviously 16ms was intended. In this case quirk calculates new value to be 8 which gives when interpreted as highspeed value 16ms as wanted. The behavior of the device was verified to be what expected both before and after the patch. Signed-off-by: Pekka Sarnila Signed-off-by: Jiri Kosina --- diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index d95979f0e0..b4ad5d1752 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -800,6 +800,22 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) goto fail; } + hid->name[0] = 0; + + if (dev->manufacturer) + strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); + + if (dev->product) { + if (dev->manufacturer) + strlcat(hid->name, " ", sizeof(hid->name)); + strlcat(hid->name, dev->product, sizeof(hid->name)); + } + + if (!strlen(hid->name)) + snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); + for (n = 0; n < interface->desc.bNumEndpoints; n++) { struct usb_endpoint_descriptor *endpoint; @@ -812,6 +828,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) interval = endpoint->bInterval; + /* Some vendors give fullspeed interval on highspeed devides */ + if (quirks & HID_QUIRK_FULLSPEED_INTERVAL && + dev->speed == USB_SPEED_HIGH) { + interval = fls(endpoint->bInterval*8); + printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n", + hid->name, endpoint->bInterval, interval); + } + /* Change the polling interval of mice. */ if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) interval = hid_mousepoll_interval; @@ -859,22 +883,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usbhid->intf = intf; usbhid->ifnum = interface->desc.bInterfaceNumber; - hid->name[0] = 0; - - if (dev->manufacturer) - strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); - - if (dev->product) { - if (dev->manufacturer) - strlcat(hid->name, " ", sizeof(hid->name)); - strlcat(hid->name, dev->product, sizeof(hid->name)); - } - - if (!strlen(hid->name)) - snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - hid->bus = BUS_USB; hid->vendor = le16_to_cpu(dev->descriptor.idVendor); hid->product = le16_to_cpu(dev->descriptor.idProduct); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index e29a057cbe..54b8f8311f 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -32,6 +32,9 @@ #define USB_VENDOR_ID_ADS_TECH 0x06e1 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 +#define USB_VENDOR_ID_AFATECH 0x15a4 +#define USB_DEVICE_ID_AFATECH_AF9016 0x9016 + #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_DEVICE_ID_AIPTEK_01 0x0001 #define USB_DEVICE_ID_AIPTEK_10 0x0010 @@ -436,6 +439,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, + { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, + { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, diff --git a/include/linux/hid.h b/include/linux/hid.h index 74ff57596e..af1f7e57a1 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -284,6 +284,7 @@ struct hid_item { #define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000 #define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000 #define HID_QUIRK_MICROSOFT_KEYS 0x08000000 +#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 /* * Separate quirks for runtime report descriptor fixup