diff options
Diffstat (limited to 'drivers/hid/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 120 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-lgff.c | 10 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-pidff.c | 1 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 185 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-tmff.c | 2 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-zpff.c | 8 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 2 | ||||
-rw-r--r-- | drivers/hid/usbhid/usbkbd.c | 6 |
8 files changed, 220 insertions, 114 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index d91b9dac6df..b2baeaeba9b 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 " " quirks=vendorID:productID:quirks" " where vendorID, productID, and quirks are all in" " 0x-prefixed hex"); +static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL }; +module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444); +MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying " + " rdesc_quirks=vendorID:productID:rdesc_quirks" + " where vendorID, productID, and rdesc_quirks are all in" + " 0x-prefixed hex"); /* * Input submission and I/O error handler. */ @@ -127,7 +133,7 @@ static void hid_reset(struct work_struct *work) hid_io_error(hid); break; default: - err("can't reset device, %s-%s/input%d, status %d", + err_hid("can't reset device, %s-%s/input%d, status %d", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, rc); @@ -220,7 +226,7 @@ static void hid_irq_in(struct urb *urb) if (status) { clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { - err("can't resubmit intr, %s-%s/input%d, status %d", + err_hid("can't resubmit intr, %s-%s/input%d, status %d", hid_to_usb_dev(hid)->bus->bus_name, hid_to_usb_dev(hid)->devpath, usbhid->ifnum, status); @@ -240,10 +246,10 @@ static int hid_submit_out(struct hid_device *hid) usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); usbhid->urbout->dev = hid_to_usb_dev(hid); - dbg("submitting out urb"); + dbg_hid("submitting out urb\n"); if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { - err("usb_submit_urb(out) failed"); + err_hid("usb_submit_urb(out) failed"); return -1; } @@ -287,12 +293,12 @@ static int hid_submit_ctrl(struct hid_device *hid) usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); usbhid->cr->wLength = cpu_to_le16(len); - dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", + dbg_hid("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u\n", usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { - err("usb_submit_urb(ctrl) failed"); + err_hid("usb_submit_urb(ctrl) failed"); return -1; } @@ -474,7 +480,7 @@ int usbhid_wait_io(struct hid_device *hid) if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { - dbg("timeout waiting for ctrl or out queue to clear"); + dbg_hid("timeout waiting for ctrl or out queue to clear\n"); return -1; } @@ -633,20 +639,6 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) } /* - * Cherry Cymotion keyboard have an invalid HID report descriptor, - * that needs fixing before we can parse it. - */ - -static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize) -{ - if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { - info("Fixing up Cherry Cymotion report descriptor"); - rdesc[11] = rdesc[16] = 0xff; - rdesc[12] = rdesc[17] = 0x03; - } -} - -/* * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller * to "operational". Without this, the ps3 controller will not report any * events. @@ -667,51 +659,11 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) USB_CTRL_GET_TIMEOUT); if (result < 0) - err("%s failed: %d\n", __func__, result); + err_hid("%s failed: %d\n", __func__, result); kfree(buf); } -/* - * Certain Logitech keyboards send in report #3 keys which are far - * above the logical maximum described in descriptor. This extends - * the original value of 0x28c of logical maximum to 0x104d - */ -static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) -{ - if (rsize >= 90 && rdesc[83] == 0x26 - && rdesc[84] == 0x8c - && rdesc[85] == 0x02) { - info("Fixing up Logitech keyboard report descriptor"); - rdesc[84] = rdesc[89] = 0x4d; - rdesc[85] = rdesc[90] = 0x10; - } -} - -/* - * Some USB barcode readers from cypress have usage min and usage max in - * the wrong order - */ -static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) -{ - short fixed = 0; - int i; - - for (i = 0; i < rsize - 4; i++) { - if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { - unsigned char tmp; - - rdesc[i] = 0x19; rdesc[i+2] = 0x29; - tmp = rdesc[i+3]; - rdesc[i+3] = rdesc[i+1]; - rdesc[i+1] = tmp; - } - } - - if (fixed) - info("Fixing up Cypress report descriptor"); -} - static struct hid_device *usb_hid_configure(struct usb_interface *intf) { struct usb_host_interface *interface = intf->cur_altsetting; @@ -746,7 +698,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && (!interface->desc.bNumEndpoints || usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { - dbg("class descriptor not present\n"); + dbg_hid("class descriptor not present\n"); return NULL; } @@ -755,41 +707,34 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { - dbg("weird size of report descriptor (%u)", rsize); + dbg_hid("weird size of report descriptor (%u)\n", rsize); return NULL; } if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { - dbg("couldn't allocate rdesc memory"); + dbg_hid("couldn't allocate rdesc memory\n"); return NULL; } hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0); if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { - dbg("reading report descriptor failed"); + dbg_hid("reading report descriptor failed\n"); kfree(rdesc); return NULL; } - if ((quirks & HID_QUIRK_CYMOTION)) - hid_fixup_cymotion_descriptor(rdesc, rsize); - - if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) - hid_fixup_logitech_descriptor(rdesc, rsize); + usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct), rdesc, + rsize, rdesc_quirks_param); - if (quirks & HID_QUIRK_SWAPPED_MIN_MAX) - hid_fixup_cypress_descriptor(rdesc, rsize); - -#ifdef CONFIG_HID_DEBUG - printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); + dbg_hid("report descriptor (size %u, read %d) = ", rsize, n); for (n = 0; n < rsize; n++) - printk(" %02x", (unsigned char) rdesc[n]); - printk("\n"); -#endif + dbg_hid_line(" %02x", (unsigned char) rdesc[n]); + dbg_hid_line("\n"); if (!(hid = hid_parse_report(rdesc, n))) { - dbg("parsing report descriptor failed"); + dbg_hid("parsing report descriptor failed\n"); kfree(rdesc); return NULL; } @@ -861,7 +806,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) } if (!usbhid->urbin) { - err("couldn't find an input interrupt endpoint"); + err_hid("couldn't find an input interrupt endpoint"); goto fail; } @@ -956,7 +901,7 @@ static void hid_disconnect(struct usb_interface *intf) usb_kill_urb(usbhid->urbctrl); del_timer_sync(&usbhid->io_retry); - flush_scheduled_work(); + cancel_work_sync(&usbhid->reset_work); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); @@ -978,7 +923,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) int i; char *c; - dbg("HID probe called for ifnum %d", + dbg_hid("HID probe called for ifnum %d\n", intf->altsetting->desc.bInterfaceNumber); if (!(hid = usb_hid_configure(intf))) @@ -1064,20 +1009,22 @@ static int hid_resume(struct usb_interface *intf) } /* Treat USB reset pretty much the same as suspend/resume */ -static void hid_pre_reset(struct usb_interface *intf) +static int hid_pre_reset(struct usb_interface *intf) { /* FIXME: What if the interface is already suspended? */ hid_suspend(intf, PMSG_ON); + return 0; } -static void hid_post_reset(struct usb_interface *intf) +/* Same routine used for post_reset and reset_resume */ +static int hid_post_reset(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); /* FIXME: Any more reinitialization needed? */ - hid_resume(intf); + return hid_resume(intf); } static struct usb_device_id hid_usb_ids [] = { @@ -1094,6 +1041,7 @@ static struct usb_driver hid_driver = { .disconnect = hid_disconnect, .suspend = hid_suspend, .resume = hid_resume, + .reset_resume = hid_post_reset, .pre_reset = hid_pre_reset, .post_reset = hid_post_reset, .id_table = hid_usb_ids, diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c index c5cd4107d6a..4b7ab6a46d9 100644 --- a/drivers/hid/usbhid/hid-lgff.c +++ b/drivers/hid/usbhid/hid-lgff.c @@ -78,7 +78,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[1] = 0x08; report->field[0]->value[2] = x; report->field[0]->value[3] = y; - dbg("(x, y)=(%04x, %04x)", x, y); + dbg_hid("(x, y)=(%04x, %04x)\n", x, y); usbhid_submit_report(hid, report, USB_DIR_OUT); break; @@ -93,7 +93,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[1] = 0x00; report->field[0]->value[2] = left; report->field[0]->value[3] = right; - dbg("(left, right)=(%04x, %04x)", left, right); + dbg_hid("(left, right)=(%04x, %04x)\n", left, right); usbhid_submit_report(hid, report, USB_DIR_OUT); break; } @@ -113,20 +113,20 @@ int hid_lgff_init(struct hid_device* hid) /* Find the report to use */ if (list_empty(report_list)) { - err("No output report found"); + err_hid("No output report found"); return -1; } /* Check that the report looks ok */ report = list_entry(report_list->next, struct hid_report, list); if (!report) { - err("NULL output report"); + err_hid("NULL output report"); return -1; } field = report->field[0]; if (!field) { - err("NULL field"); + err_hid("NULL field"); return -1; } diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index f5a90e950e6..011326178c0 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -738,6 +738,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0; pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0; pidff_set(&pidff->set_effect[PID_GAIN], magnitude); + pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1; pidff->set_effect[PID_START_DELAY].value[0] = 0; usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index f6c4145dc20..775b9f3b8ce 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -105,6 +105,9 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +#define USB_VENDOR_ID_GAMERON 0x0810 +#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 + #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 #define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 @@ -196,8 +199,10 @@ #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 +#define USB_DEVICE_ID_LOGITECH_KBD 0xc311 #define USB_DEVICE_ID_S510_RECEIVER 0xc50c #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 +#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 #define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 #define USB_DEVICE_ID_DINOVO_EDGE 0xc714 @@ -209,6 +214,13 @@ #define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS1 0x0001 +#define USB_VENDOR_ID_MICROSOFT 0x045e +#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b + +#define USB_VENDOR_ID_NCR 0x0404 +#define USB_DEVICE_ID_NCR_FIRST 0x0300 +#define USB_DEVICE_ID_NCR_LAST 0x03ff + #define USB_VENDOR_ID_NEC 0x073e #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 @@ -220,6 +232,9 @@ #define USB_VENDOR_ID_PANTHERLORD 0x0810 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 +#define USB_VENDOR_ID_PETALYNX 0x18b1 +#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 + #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 @@ -278,6 +293,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT }, @@ -285,11 +301,10 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, @@ -409,9 +424,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR }, - { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, @@ -426,6 +439,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, @@ -448,9 +462,28 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX }, + { 0, 0 } +}; + +/* Quirks for devices which require report descriptor fixup go here */ +static const struct hid_rdesc_blacklist { + __u16 idVendor; + __u16 idProduct; + __u32 quirks; +} hid_rdesc_blacklist[] = { + + { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION }, + + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, + + { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, + + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, { 0, 0 } }; @@ -493,7 +526,7 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor, } if (bl_entry != NULL) - dbg("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", + dbg_hid("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", bl_entry->quirks, bl_entry->idVendor, bl_entry->idProduct); @@ -521,13 +554,13 @@ int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, int list_edited = 0; if (!idVendor) { - dbg("Cannot add a quirk with idVendor = 0"); + dbg_hid("Cannot add a quirk with idVendor = 0\n"); return -EINVAL; } q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL); if (!q_new) { - dbg("Could not allocate quirks_list_struct"); + dbg_hid("Could not allocate quirks_list_struct\n"); return -ENOMEM; } @@ -559,7 +592,6 @@ int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, return 0; } - /** * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory * @@ -643,7 +675,7 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor, bl_entry = &hid_blacklist[n]; if (bl_entry != NULL) - dbg("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", + dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", bl_entry->quirks, bl_entry->idVendor, bl_entry->idProduct); return bl_entry; @@ -675,6 +707,12 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) return HID_QUIRK_IGNORE; + /* NCR devices must not be queried for reports */ + if (idVendor == USB_VENDOR_ID_NCR && + idProduct >= USB_DEVICE_ID_NCR_FIRST && + idProduct <= USB_DEVICE_ID_NCR_LAST) + return HID_QUIRK_NOGET; + down_read(&dquirks_rwsem); bl_entry = usbhid_exists_dquirk(idVendor, idProduct); if (!bl_entry) @@ -686,3 +724,126 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) return quirks; } +/* + * Cherry Cymotion keyboard have an invalid HID report descriptor, + * that needs fixing before we can parse it. + */ +static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize) +{ + if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) { + printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n"); + rdesc[11] = rdesc[16] = 0xff; + rdesc[12] = rdesc[17] = 0x03; + } +} + + +/* + * Certain Logitech keyboards send in report #3 keys which are far + * above the logical maximum described in descriptor. This extends + * the original value of 0x28c of logical maximum to 0x104d + */ +static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 90 && rdesc[83] == 0x26 + && rdesc[84] == 0x8c + && rdesc[85] == 0x02) { + printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n"); + rdesc[84] = rdesc[89] = 0x4d; + rdesc[85] = rdesc[90] = 0x10; + } +} + +/* Petalynx Maxter Remote has maximum for consumer page set too low */ +static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 60 && rdesc[39] == 0x2a + && rdesc[40] == 0xf5 + && rdesc[41] == 0x00 + && rdesc[59] == 0x26 + && rdesc[60] == 0xf9 + && rdesc[61] == 0x00) { + printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n"); + rdesc[60] = 0xfa; + rdesc[40] = 0xfa; + } +} + +/* + * Some USB barcode readers from cypress have usage min and usage max in + * the wrong order + */ +static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) +{ + short fixed = 0; + int i; + + for (i = 0; i < rsize - 4; i++) { + if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { + unsigned char tmp; + + rdesc[i] = 0x19; rdesc[i+2] = 0x29; + tmp = rdesc[i+3]; + rdesc[i+3] = rdesc[i+1]; + rdesc[i+1] = tmp; + } + } + + if (fixed) + printk(KERN_INFO "Fixing up Cypress report descriptor\n"); +} + + +static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) +{ + if ((quirks & HID_QUIRK_RDESC_CYMOTION)) + usbhid_fixup_cymotion_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_LOGITECH) + usbhid_fixup_logitech_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX) + usbhid_fixup_cypress_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_PETALYNX) + usbhid_fixup_petalynx_descriptor(rdesc, rsize); +} + +/** + * usbhid_fixup_report_descriptor: check if report descriptor needs fixup + * + * Description: + * Walks the hid_rdesc_blacklist[] array and checks whether the device + * is known to have broken report descriptor that needs to be fixed up + * prior to entering the HID parser + * + * Returns: nothing + */ +void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct, + char *rdesc, unsigned rsize, char **quirks_param) +{ + int n, m; + u16 paramVendor, paramProduct; + u32 quirks; + + /* static rdesc quirk entries */ + for (n = 0; hid_rdesc_blacklist[n].idVendor; n++) + if (hid_rdesc_blacklist[n].idVendor == idVendor && + hid_rdesc_blacklist[n].idProduct == idProduct) + __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks, + rdesc, rsize); + + /* runtime rdesc quirk entries handling */ + for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { + m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", + ¶mVendor, ¶mProduct, &quirks); + + if (m != 3) + printk(KERN_WARNING + "Could not parse HID quirk module param %s\n", + quirks_param[n]); + else if (paramVendor == idVendor && paramProduct == idProduct) + __usbhid_fixup_report_descriptor(quirks, rdesc, rsize); + } + +} diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index ab5ba6ef891..555bb48b429 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c @@ -70,7 +70,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef tmff->rumble->value[0] = left; tmff->rumble->value[1] = right; - dbg("(left,right)=(%08x, %08x)", left, right); + dbg_hid("(left,right)=(%08x, %08x)\n", left, right); usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); return 0; diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c index a7fbffcdaf3..5a688274f6a 100644 --- a/drivers/hid/usbhid/hid-zpff.c +++ b/drivers/hid/usbhid/hid-zpff.c @@ -21,10 +21,6 @@ */ -/* #define DEBUG */ - -#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg) - #include <linux/input.h> #include <linux/usb.h> #include <linux/hid.h> @@ -49,14 +45,14 @@ static int hid_zpff_play(struct input_dev *dev, void *data, left = effect->u.rumble.strong_magnitude; right = effect->u.rumble.weak_magnitude; - debug("called with 0x%04x 0x%04x", left, right); + dbg_hid("called with 0x%04x 0x%04x\n", left, right); left = left * 0x7f / 0xffff; right = right * 0x7f / 0xffff; zpff->report->field[2]->value[0] = left; zpff->report->field[3]->value[0] = right; - debug("running with 0x%02x 0x%02x", left, right); + dbg_hid("running with 0x%02x 0x%02x\n", left, right); usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); return 0; diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 488d61bdbf2..e793127f971 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -779,7 +779,7 @@ int hiddev_connect(struct hid_device *hid) retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { - err("Not able to get a minor for this device."); + err_hid("Not able to get a minor for this device."); kfree(hiddev); return -1; } diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 13097878071..b76b02f7b52 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -125,7 +125,7 @@ static void usb_kbd_irq(struct urb *urb) resubmit: i = usb_submit_urb (urb, GFP_ATOMIC); if (i) - err ("can't resubmit intr, %s-%s/input0, status %d", + err_hid ("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus->bus_name, kbd->usbdev->devpath, i); } @@ -151,7 +151,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type, *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err("usb_submit_urb(leds) failed"); + err_hid("usb_submit_urb(leds) failed"); return 0; } @@ -169,7 +169,7 @@ static void usb_kbd_led(struct urb *urb) *(kbd->leds) = kbd->newleds; kbd->led->dev = kbd->usbdev; if (usb_submit_urb(kbd->led, GFP_ATOMIC)) - err("usb_submit_urb(leds) failed"); + err_hid("usb_submit_urb(leds) failed"); } static int usb_kbd_open(struct input_dev *dev) |