HCDs always needed a per-endpoint queue; this makes usbcore implement it.
This patch changes the HCD glue code to use the URB queue now kept in usb_host_endpoint, and matching HCD API changes.
Signed-off-by: David Brownell <[EMAIL PROTECTED]> --- epmax/drivers/usb/core/config.c 2004-11-27 23:06:08.000000000 -0800 +++ hdev/drivers/usb/core/config.c 2004-11-28 01:49:39.000000000 -0800 @@ -88,6 +88,7 @@ memcpy(&endpoint->desc, d, n); le16_to_cpus(&endpoint->desc.wMaxPacketSize); + INIT_LIST_HEAD(&endpoint->urb_list); /* Skip over any Class Specific or Vendor Specific descriptors; * find the next endpoint or interface descriptor */ --- epmax/drivers/usb/core/hcd.c 2004-11-27 23:29:53.000000000 -0800 +++ hdev/drivers/usb/core/hcd.c 2004-11-28 03:03:48.343773272 -0800 @@ -1079,10 +1079,12 @@ { int status; struct usb_hcd *hcd = urb->dev->bus->hcpriv; - struct hcd_dev *dev = urb->dev->hcpriv; + struct usb_host_endpoint *ep; unsigned long flags; - if (!hcd || !dev) + ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!hcd || !ep) return -ENODEV; /* @@ -1109,7 +1111,7 @@ case USB_STATE_RUNNING: case USB_STATE_RESUMING: usb_get_dev (urb->dev); - list_add_tail (&urb->urb_list, &dev->urb_list); + list_add_tail (&urb->urb_list, &ep->urb_list); status = 0; break; default: @@ -1163,7 +1165,7 @@ : DMA_TO_DEVICE); } - status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); + status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); done: if (unlikely (status)) { urb_unlink (urb); @@ -1222,7 +1224,7 @@ */ static int hcd_unlink_urb (struct urb *urb, int status) { - struct hcd_dev *dev; + struct usb_host_endpoint *ep; struct usb_hcd *hcd = NULL; struct device *sys = NULL; unsigned long flags; @@ -1231,6 +1233,12 @@ if (!urb) return -EINVAL; + if (!urb->dev || !urb->dev->bus) + return -ENODEV; + ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return -ENODEV; /* * we contend for urb->status with the hcd core, @@ -1246,15 +1254,9 @@ spin_lock_irqsave (&urb->lock, flags); spin_lock (&hcd_data_lock); - if (!urb->dev || !urb->dev->bus) { - retval = -ENODEV; - goto done; - } - - dev = urb->dev->hcpriv; sys = &urb->dev->dev; hcd = urb->dev->bus->hcpriv; - if (!dev || !hcd) { + if (hcd == NULL) { retval = -ENODEV; goto done; } @@ -1266,7 +1268,7 @@ WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); /* insist the urb is still queued */ - list_for_each(tmp, &dev->urb_list) { + list_for_each(tmp, &ep->urb_list) { if (tmp == &urb->urb_list) break; } @@ -1319,40 +1321,36 @@ * the hcd to make sure all endpoint state is gone from hardware. use for * set_configuration, set_interface, driver removal, physical disconnect. * - * example: a qh stored in hcd_dev.ep[], holding state related to endpoint + * example: a qh stored in ep->hcpriv, holding state related to endpoint * type, maxpacket size, toggle, halt status, and scheduling. */ -static void hcd_endpoint_disable (struct usb_device *udev, int endpoint) +static void +hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep) { - struct hcd_dev *dev; - struct usb_hcd *hcd; - struct urb *urb; - unsigned epnum = endpoint & USB_ENDPOINT_NUMBER_MASK; + struct usb_hcd *hcd; + struct urb *urb; - dev = udev->hcpriv; hcd = udev->bus->hcpriv; WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT); local_irq_disable (); + /* FIXME move most of this into message.c as part of its + * endpoint disable logic + */ + /* ep is already gone from udev->ep_{in,out}[]; no more submits */ rescan: spin_lock (&hcd_data_lock); - list_for_each_entry (urb, &dev->urb_list, urb_list) { - int tmp = urb->pipe; - - /* ignore urbs for other endpoints */ - if (usb_pipeendpoint (tmp) != epnum) - continue; - /* NOTE assumption that only ep0 is a control endpoint */ - if (epnum != 0 && ((tmp ^ endpoint) & USB_DIR_IN)) - continue; + list_for_each_entry (urb, &ep->urb_list, urb_list) { + int tmp; /* another cpu may be in hcd, spinning on hcd_data_lock * to giveback() this urb. the races here should be * small, but a full fix needs a new "can't submit" * urb state. + * FIXME urb->reject should allow that... */ if (urb->status != -EINPROGRESS) continue; @@ -1394,7 +1392,7 @@ */ might_sleep (); if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable (hcd, dev, endpoint); + hcd->driver->endpoint_disable (hcd, ep); } /*-------------------------------------------------------------------------*/ --- epmax/drivers/usb/core/message.c 2004-11-27 23:33:11.000000000 -0800 +++ hdev/drivers/usb/core/message.c 2004-11-28 01:49:39.000000000 -0800 @@ -932,7 +932,7 @@ dev->ep_in[epnum] = NULL; } if (ep && dev->bus && dev->bus->op && dev->bus->op->disable) - dev->bus->op->disable(dev, ep->desc.bEndpointAddress); + dev->bus->op->disable(dev, ep); } /** --- epmax/drivers/usb/core/usb.c 2004-11-27 23:25:45.000000000 -0800 +++ hdev/drivers/usb/core/usb.c 2004-11-28 03:03:48.349772360 -0800 @@ -690,6 +690,7 @@ dev->dev.release = usb_release_dev; dev->state = USB_STATE_ATTACHED; + INIT_LIST_HEAD(&dev->ep0.urb_list); dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; /* ep0 maxpacket comes later, from device descriptor */