# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.593 -> 1.594 # drivers/usb/hcd/ehci-q.c 1.5 -> 1.6 # drivers/usb/hcd/ehci-sched.c 1.4 -> 1.5 # drivers/usb/hub.c 1.16 -> 1.17 # drivers/usb/hcd/ehci-hcd.c 1.5 -> 1.6 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/08/20 greg@kroah.com 1.594 # USB: fix some USB 2.0 hub bugs. # -------------------------------------------- # diff -Nru a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c --- a/drivers/usb/hcd/ehci-hcd.c Wed Aug 21 11:47:20 2002 +++ b/drivers/usb/hcd/ehci-hcd.c Wed Aug 21 11:47:20 2002 @@ -434,10 +434,6 @@ scan_async (ehci); if (ehci->next_uframe != -1) scan_periodic (ehci); - - // FIXME: when nothing is connected to the root hub, - // turn off the RUN bit so the host can enter C3 "sleep" power - // saving mode; make root hub code scan memory less often. } /*-------------------------------------------------------------------------*/ @@ -582,7 +578,10 @@ return 0; case PIPE_INTERRUPT: - intr_deschedule (ehci, urb->start_frame, qh, urb->interval); + intr_deschedule (ehci, urb->start_frame, qh, + (urb->dev->speed == USB_SPEED_HIGH) + ? urb->interval + : (urb->interval << 3)); if (ehci->hcd.state == USB_STATE_HALT) urb->status = -ESHUTDOWN; qh_completions (ehci, qh, 1); diff -Nru a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c --- a/drivers/usb/hcd/ehci-q.c Wed Aug 21 11:47:20 2002 +++ b/drivers/usb/hcd/ehci-q.c Wed Aug 21 11:47:20 2002 @@ -681,6 +681,8 @@ default: #ifdef DEBUG BUG (); +#else + ; #endif } @@ -817,9 +819,9 @@ } else { // dbg_qh ("empty qh", ehci, qh); -// FIXME: how handle usb_clear_halt() for an EP with queued URBs? -// usbcore may not let us handle that cleanly... -// likely must cancel them all first! + /* NOTE: we already canceled any queued URBs + * when the endpoint halted. + */ /* usb_clear_halt() means qh data toggle gets reset */ if (usb_pipebulk (urb->pipe) diff -Nru a/drivers/usb/hcd/ehci-sched.c b/drivers/usb/hcd/ehci-sched.c --- a/drivers/usb/hcd/ehci-sched.c Wed Aug 21 11:47:20 2002 +++ b/drivers/usb/hcd/ehci-sched.c Wed Aug 21 11:47:20 2002 @@ -919,17 +919,9 @@ return flags; /* - * For now, always give the urb back to the driver ... expect it - * to submit a new urb (or resubmit this), and to have another - * already queued when un-interrupted transfers are needed. - * No, that's not what OHCI or UHCI are now doing. - * - * FIXME Revisit the ISO URB model. It's cleaner not to have all - * the special case magic, but it'd be faster to reuse existing - * ITD/DMA setup and schedule state. Easy to dma_sync/complete(), - * then either reschedule or, if unlinking, free and giveback(). - * But we can't overcommit like the full and low speed HCs do, and - * there's no clean way to report an error when rescheduling... + * Always give the urb back to the driver ... expect it to submit + * a new urb (or resubmit this), and to have another already queued + * when un-interrupted transfers are needed. * * NOTE that for now we don't accelerate ISO unlinks; they just * happen according to the current schedule. Means a delay of @@ -964,15 +956,6 @@ if (urb->iso_frame_desc [0].offset != 0) return -EINVAL; - /* - * NOTE doing this for now, anticipating periodic URB models - * get updated to be "explicit resubmit". - */ - if (urb->next) { - dbg ("use explicit resubmit for ISO"); - return -EINVAL; - } - /* allocate ITDs w/o locking anything */ status = itd_urb_transaction (ehci, urb, mem_flags); if (status < 0) diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c --- a/drivers/usb/hub.c Wed Aug 21 11:47:20 2002 +++ b/drivers/usb/hub.c Wed Aug 21 11:47:20 2002 @@ -155,7 +155,7 @@ static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { struct usb_device *dev = hub->dev; - struct usb_hub_status hubstatus; + struct usb_hub_status *hubstatus; char portstr[USB_MAXCHILDREN + 1]; unsigned int pipe; int i, maxp, ret; @@ -258,20 +258,29 @@ dbg("port removable status: %s", portstr); - ret = usb_get_hub_status(dev, &hubstatus); + hubstatus = kmalloc(sizeof *hubstatus, GFP_KERNEL); + if (!hubstatus) { + err("Unable to allocate hubstatus"); + kfree(hub->descriptor); + return -1; + } + ret = usb_get_hub_status(dev, hubstatus); if (ret < 0) { err("Unable to get hub status (err = %d)", ret); + kfree(hubstatus); kfree(hub->descriptor); return -1; } - le16_to_cpus(&hubstatus.wHubStatus); + le16_to_cpus(&hubstatus->wHubStatus); dbg("local power source is %s", - (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); + (hubstatus->wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); dbg("%sover-current condition exists", - (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); + (hubstatus->wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); + + kfree(hubstatus); /* Start the interrupt endpoint */ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); @@ -287,8 +296,11 @@ return -1; } - FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, - hub, endpoint->bInterval); + FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, hub, + /* NOTE: in 2.5 fill_int_urb() converts the encoding */ + (dev->speed == USB_SPEED_HIGH) + ? 1 << (endpoint->bInterval - 1) + : endpoint->bInterval); ret = usb_submit_urb(hub->urb); if (ret) { err("usb_submit_urb failed (%d)", ret); @@ -782,7 +794,7 @@ struct list_head *tmp; struct usb_device *dev; struct usb_hub *hub; - struct usb_hub_status hubsts; + struct usb_hub_status *hubsts; u16 hubstatus; u16 hubchange; u16 portstatus; @@ -872,21 +884,27 @@ } /* end for i */ /* deal with hub status changes */ - if (usb_get_hub_status(dev, &hubsts) < 0) - err("get_hub_status failed"); - else { - hubstatus = le16_to_cpup(&hubsts.wHubStatus); - hubchange = le16_to_cpup(&hubsts.wHubChange); - if (hubchange & HUB_CHANGE_LOCAL_POWER) { - dbg("hub power change"); - usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); - } - if (hubchange & HUB_CHANGE_OVERCURRENT) { - dbg("hub overcurrent change"); - wait_ms(500); /* Cool down */ - usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); - usb_hub_power_on(hub); + hubsts = kmalloc(sizeof *hubsts, GFP_KERNEL); + if (!hubsts) { + err("couldn't allocate hubsts"); + } else { + if (usb_get_hub_status(dev, hubsts) < 0) + err("get_hub_status failed"); + else { + hubstatus = le16_to_cpup(&hubsts->wHubStatus); + hubchange = le16_to_cpup(&hubsts->wHubChange); + if (hubchange & HUB_CHANGE_LOCAL_POWER) { + dbg("hub power change"); + usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); + } + if (hubchange & HUB_CHANGE_OVERCURRENT) { + dbg("hub overcurrent change"); + wait_ms(500); /* Cool down */ + usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); + usb_hub_power_on(hub); + } } + kfree(hubsts); } up(&hub->khubd_sem); } /* end while (1) */ @@ -995,7 +1013,7 @@ int usb_reset_device(struct usb_device *dev) { struct usb_device *parent = dev->parent; - struct usb_device_descriptor descriptor; + struct usb_device_descriptor *descriptor; int i, ret, port = -1; if (!parent) { @@ -1044,17 +1062,22 @@ * If nothing changed, we reprogram the configuration and then * the alternate settings. */ + descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); + if (!descriptor) { + return -ENOMEM; + } ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor, sizeof(descriptor)); if (ret < 0) return ret; - le16_to_cpus(&descriptor.bcdUSB); - le16_to_cpus(&descriptor.idVendor); - le16_to_cpus(&descriptor.idProduct); - le16_to_cpus(&descriptor.bcdDevice); + le16_to_cpus(&descriptor->bcdUSB); + le16_to_cpus(&descriptor->idVendor); + le16_to_cpus(&descriptor->idProduct); + le16_to_cpus(&descriptor->bcdDevice); - if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) { + if (memcmp(&dev->descriptor, descriptor, sizeof(descriptor))) { + kfree(descriptor); usb_destroy_configuration(dev); ret = usb_get_device_descriptor(dev); @@ -1083,6 +1106,8 @@ return 1; } + + kfree(descriptor); ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue); if (ret < 0) {