X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Finput%2Fhid-core.c;h=2280d13986e646ae1f1024a3df899fbbff6802b5;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=35baacd7706dd24a6fa1608ef6e15ba912365e03;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 35baacd77..2280d1398 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -94,7 +94,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage) + values * sizeof(unsigned)); - report->field[report->maxfield++] = field; + field->index = report->maxfield++; + report->field[field->index] = field; field->usage = (struct hid_usage *)(field + 1); field->value = (unsigned *)(field->usage + usages); field->report = report; @@ -675,7 +676,7 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size) parser->device = device; end = start + size; - while ((start = fetch_item(start, end, &item)) != 0) { + while ((start = fetch_item(start, end, &item)) != NULL) { if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); @@ -924,7 +925,9 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) break; case -ECONNRESET: /* unlink */ case -ENOENT: - case -ESHUTDOWN: + case -EPERM: + case -ESHUTDOWN: /* unplug */ + case -EILSEQ: /* unplug timeout on uhci */ return; case -ETIMEDOUT: /* NAK */ break; @@ -1134,12 +1137,15 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) { struct hid_device *hid = urb->context; unsigned long flags; + int unplug = 0; switch (urb->status) { case 0: /* success */ + case -ESHUTDOWN: /* unplug */ + case -EILSEQ: /* unplug timeout on uhci */ + unplug = 1; case -ECONNRESET: /* unlink */ case -ENOENT: - case -ESHUTDOWN: break; default: /* error */ warn("output irq status %d received", urb->status); @@ -1147,7 +1153,10 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) spin_lock_irqsave(&hid->outlock, flags); - hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); + if (unplug) + hid->outtail = hid->outhead; + else + hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) { if (hid_submit_out(hid)) { @@ -1171,6 +1180,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) { struct hid_device *hid = urb->context; unsigned long flags; + int unplug = 0; spin_lock_irqsave(&hid->ctrllock, flags); @@ -1178,16 +1188,21 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) case 0: /* success */ if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + case -ESHUTDOWN: /* unplug */ + case -EILSEQ: /* unplug timectrl on uhci */ + unplug = 1; case -ECONNRESET: /* unlink */ case -ENOENT: - case -ESHUTDOWN: case -EPIPE: /* report not available */ break; default: /* error */ warn("ctrl urb status %d received", urb->status); } - hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + if (unplug) + hid->ctrltail = hid->ctrlhead; + else + hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->ctrlhead != hid->ctrltail) { if (hid_submit_ctrl(hid)) { @@ -1260,8 +1275,10 @@ int hid_wait_io(struct hid_device *hid) add_wait_queue(&hid->wait, &wait); while (timeout && (test_bit(HID_CTRL_RUNNING, &hid->iofl) || - test_bit(HID_OUT_RUNNING, &hid->iofl))) + test_bit(HID_OUT_RUNNING, &hid->iofl))) { + set_current_state(TASK_UNINTERRUPTIBLE); timeout = schedule_timeout(timeout); + } set_current_state(TASK_RUNNING); remove_wait_queue(&hid->wait, &wait); @@ -1277,9 +1294,17 @@ int hid_wait_io(struct hid_device *hid) static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char type, void *buf, int size) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, - (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT); + int result, retries = 4; + + memset(buf,0,size); // Make sure we parse really received data + + do { + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, + (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT); + retries--; + } while (result < size && retries); + return result; } int hid_open(struct hid_device *hid) @@ -1310,7 +1335,7 @@ void hid_init_reports(struct hid_device *hid) struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; - int err, ret; + int err, ret, size; /* * The Set_Idle request is supposed to affect only the @@ -1333,6 +1358,10 @@ void hid_init_reports(struct hid_device *hid) list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; + size = ((report->size - 1) >> 3) + 1 + report_enum->numbered; + if (size > HID_BUFFER_SIZE) size = HID_BUFFER_SIZE; + if (size > hid->urbin->transfer_buffer_length) + hid->urbin->transfer_buffer_length = size; hid_submit_report(hid, report, USB_DIR_IN); list = list->next; } @@ -1350,9 +1379,9 @@ void hid_init_reports(struct hid_device *hid) while (ret) { err |= ret; if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) - usb_unlink_urb(hid->urbctrl); + usb_kill_urb(hid->urbctrl); if (test_bit(HID_OUT_RUNNING, &hid->iofl)) - usb_unlink_urb(hid->urbout); + usb_kill_urb(hid->urbout); ret = hid_wait_io(hid); } @@ -1428,6 +1457,7 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 +#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 @@ -1458,7 +1488,11 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_CODEMERCS 0x07c0 #define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 +#define USB_DEVICE_ID_CODEMERCS_IOW48 0x1502 +#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1503 +#define USB_VENDOR_ID_DELORME 0x1163 +#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 static struct hid_blacklist { __u16 idVendor; @@ -1476,8 +1510,16 @@ static struct hid_blacklist { { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, @@ -1513,15 +1555,9 @@ static struct hid_blacklist { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE }, - - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, @@ -1530,8 +1566,9 @@ static struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_BACK }, - { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_EXTRA }, + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD }, { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD }, @@ -1542,6 +1579,13 @@ static 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_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, + + { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, + { 0, 0 } }; @@ -1582,8 +1626,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) int n; for (n = 0; hid_blacklist[n].idVendor; n++) - if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) + if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && + (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct))) quirks = hid_blacklist[n].quirks; if (quirks & HID_QUIRK_IGNORE) @@ -1622,7 +1666,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) printk("\n"); #endif - if (!(hid = hid_parse_report(rdesc, rsize))) { + if (!(hid = hid_parse_report(rdesc, n))) { dbg("parsing report descriptor failed"); kfree(rdesc); return NULL; @@ -1652,17 +1696,12 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) interval = 1 << (interval - 1); if (endpoint->bEndpointAddress & USB_DIR_IN) { - int len; - if (hid->urbin) continue; if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - len = usb_maxpacket(dev, pipe, 0); - if (len > HID_BUFFER_SIZE) - len = HID_BUFFER_SIZE; - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, + usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, interval); hid->urbin->transfer_dma = hid->inbuf_dma; hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); @@ -1686,8 +1725,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) init_waitqueue_head(&hid->wait); - hid->outlock = SPIN_LOCK_UNLOCKED; - hid->ctrllock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&hid->outlock); + spin_lock_init(&hid->ctrllock); hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; @@ -1704,10 +1743,12 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) strcat(hid->name, buf); if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) snprintf(hid->name, 64, "%s %s", hid->name, buf); - } else if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0) { + } else if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) { snprintf(hid->name, 128, "%s", buf); } else - snprintf(hid->name, 128, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); + snprintf(hid->name, 128, "%04x:%04x", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); usb_make_path(dev, buf, 64); snprintf(hid->phys, 64, "%s/input%d", buf, @@ -1825,6 +1866,30 @@ static int hid_probe (struct usb_interface *intf, const struct usb_device_id *id return 0; } +static int hid_suspend(struct usb_interface *intf, u32 state) +{ + struct hid_device *hid = usb_get_intfdata (intf); + + usb_kill_urb(hid->urbin); + intf->dev.power.power_state = state; + dev_dbg(&intf->dev, "suspend\n"); + return 0; +} + +static int hid_resume(struct usb_interface *intf) +{ + struct hid_device *hid = usb_get_intfdata (intf); + int status; + + intf->dev.power.power_state = PM_SUSPEND_ON; + if (hid->open) + status = usb_submit_urb(hid->urbin, GFP_NOIO); + else + status = 0; + dev_dbg(&intf->dev, "resume status %d\n", status); + return status; +} + static struct usb_device_id hid_usb_ids [] = { { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_INTERFACE_CLASS_HID }, @@ -1838,6 +1903,8 @@ static struct usb_driver hid_driver = { .name = "usbhid", .probe = hid_probe, .disconnect = hid_disconnect, + .suspend = hid_suspend, + .resume = hid_resume, .id_table = hid_usb_ids, };