Commit e9df41c5 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: make HCDs responsible for managing endpoint queues

This patch (as954) implements a suggestion of David Brownell's.  Now
the host controller drivers are responsible for linking and unlinking
URBs to/from their endpoint queues.  This eliminates the possiblity of
strange situations where usbcore thinks an URB is linked but the HCD
thinks it isn't.  It also means HCDs no longer have to check for URBs
being dequeued before they were fully enqueued.

In addition to the core changes, this requires changing every host
controller driver and the root-hub URB handler.  For the most part the
required changes are fairly small; drivers have to call
usb_hcd_link_urb_to_ep() in their urb_enqueue method,
usb_hcd_check_unlink_urb() in their urb_dequeue method, and
usb_hcd_unlink_urb_from_ep() before giving URBs back.  A few HCDs make
matters more complicated by the way they split up the flow of control.

In addition some method interfaces get changed.  The endpoint argument
for urb_enqueue is now redundant so it is removed.  The unlink status
is required by usb_hcd_check_unlink_urb(), so it has been added to
urb_dequeue.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
CC: David Brownell <david-b@pacbell.net>
CC: Olav Kongas <ok@artecdesign.ee>
CC: Tony Olech <tony.olech@elandigitalsystems.com>
CC: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b0e396e3
This diff is collapsed.
......@@ -189,11 +189,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue) (struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags);
int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
......@@ -211,6 +210,11 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
......
......@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
......@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) {
kfree(urbp);
goto done;
}
if (!dum->udev) {
dum->udev = urb->dev;
......@@ -997,22 +1002,28 @@ static int dummy_urb_enqueue (
mod_timer (&dum->timer, jiffies + 1);
spin_unlock_irqrestore (&dum->lock, flags);
return 0;
done:
return rc;
}
static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct dummy *dum;
unsigned long flags;
int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
spin_unlock_irqrestore (&dum->lock, flags);
return 0;
return rc;
}
static void maybe_set_status (struct urb *urb, int status)
......@@ -1511,6 +1522,7 @@ return_urb:
if (ep)
ep->already_seen = ep->setup_stage = 0;
usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
spin_lock (&dum->lock);
......
......@@ -719,7 +719,6 @@ dead:
*/
static int ehci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
......@@ -734,12 +733,12 @@ static int ehci_urb_enqueue (
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
return submit_async(ehci, urb, &qtd_list, mem_flags);
case PIPE_INTERRUPT:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
return intr_submit(ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
......@@ -777,13 +776,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
* completions normally happen asynchronously
*/
static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
int rc;
spin_lock_irqsave (&ehci->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
// case PIPE_BULK:
......@@ -838,7 +842,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
return 0;
return rc;
}
/*-------------------------------------------------------------------------*/
......
......@@ -262,6 +262,7 @@ __acquires(ehci->lock)
#endif
/* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
spin_lock (&ehci->lock);
......@@ -913,7 +914,6 @@ static struct ehci_qh *qh_append_tds (
static int
submit_async (
struct ehci_hcd *ehci,
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
......@@ -922,10 +922,10 @@ submit_async (
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
int rc = 0;
int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = ep->desc.bEndpointAddress;
epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
......@@ -933,7 +933,7 @@ submit_async (
__FUNCTION__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
qtd, ep->hcpriv);
qtd, urb->ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
......@@ -942,9 +942,13 @@ submit_async (
rc = -ESHUTDOWN;
goto done;
}
rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(rc))
goto done;
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
if (unlikely(qh == NULL)) {
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
rc = -ENOMEM;
goto done;
}
......
......@@ -797,7 +797,6 @@ done:
static int intr_submit (
struct ehci_hcd *ehci,
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
......@@ -805,23 +804,26 @@ static int intr_submit (
unsigned epnum;
unsigned long flags;
struct ehci_qh *qh;
int status = 0;
int status;
struct list_head empty;
/* get endpoint and transfer/schedule data */
epnum = ep->desc.bEndpointAddress;
epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
goto done;
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
/* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty);
qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
......@@ -832,13 +834,16 @@ static int intr_submit (
}
/* then queue the urb's tds to the qh */
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
done:
if (unlikely(status))
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
if (status)
qtd_list_free (ehci, urb, qtd_list);
......@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
......@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
......
......@@ -290,6 +290,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
urb_dbg(urb, "Finish");
usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
spin_unlock(&isp116x->lock);
usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
spin_lock(&isp116x->lock);
......@@ -673,7 +674,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
/*-----------------------------------------------------------------*/
static int isp116x_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep, struct urb *urb,
struct urb *urb,
gfp_t mem_flags)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
......@@ -682,6 +683,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
int is_out = !usb_pipein(pipe);
int type = usb_pipetype(pipe);
int epnum = usb_pipeendpoint(pipe);
struct usb_host_endpoint *hep = urb->ep;
struct isp116x_ep *ep = NULL;
unsigned long flags;
int i;
......@@ -705,7 +707,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
if (!HC_IS_RUNNING(hcd->state)) {
kfree(ep);
ret = -ENODEV;
goto fail;
goto fail_not_linked;
}
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret) {
kfree(ep);
goto fail_not_linked;
}
if (hep->hcpriv)
......@@ -818,6 +825,9 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
start_atl_transfers(isp116x);
fail:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
fail_not_linked:
spin_unlock_irqrestore(&isp116x->lock, flags);
return ret;
}
......@@ -825,20 +835,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
/*
Dequeue URBs.
*/
static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
struct usb_host_endpoint *hep;
struct isp116x_ep *ep, *ep_act;
unsigned long flags;
int rc;
spin_lock_irqsave(&isp116x->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
hep = urb->hcpriv;
/* URB already unlinked (or never linked)? */
if (!hep) {
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
}
ep = hep->hcpriv;
WARN_ON(hep != ep->hep);
......@@ -856,9 +867,9 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
if (urb)
finish_request(isp116x, ep, urb);
done:
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
return rc;
}
static void isp116x_endpoint_disable(struct usb_hcd *hcd,
......
......@@ -117,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
......@@ -134,7 +133,7 @@ static int ohci_urb_enqueue (
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */
......@@ -199,22 +198,17 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
/* in case of unlink-during-submit */
spin_lock (&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock (&urb->lock);
urb->hcpriv = urb_priv;
finish_urb (ohci, urb);
retval = 0;
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval)
goto fail;
}
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
if (retval < 0)
goto fail0;
if (retval < 0) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
goto fail;
}
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
......@@ -238,8 +232,6 @@ static int ohci_urb_enqueue (
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
fail0:
spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
......@@ -253,17 +245,21 @@ fail:
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
int rc;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
#endif
spin_lock_irqsave (&ohci->lock, flags);
if (HC_IS_RUNNING(hcd->state)) {
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc) {
; /* Do nothing */
} else if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
......@@ -284,7 +280,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
finish_urb (ohci, urb);
}
spin_unlock_irqrestore (&ohci->lock, flags);
return 0;
return rc;
}
/*-------------------------------------------------------------------------*/
......
......@@ -74,6 +74,7 @@ __acquires(ohci->lock)
#endif
/* urb->complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
spin_unlock (&ohci->lock);
usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
spin_lock (&ohci->lock);
......
......@@ -784,6 +784,9 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
if (urb) {
urb->status = -ENODEV;
urb->hcpriv = NULL;
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
spin_lock(&r8a66597->lock);
......@@ -1131,6 +1134,8 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
urb->start_frame = r8a66597_get_frame(hcd);
urb->hcpriv = NULL;
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(hcd, urb);
spin_lock(&r8a66597->lock);
......@@ -1722,21 +1727,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
int ret = 0, request = 0;
int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
goto error;
goto error_not_linked;
}
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret)
goto error_not_linked;
if (!hep->hcpriv) {
hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
GFP_ATOMIC);
......@@ -1761,15 +1770,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
ret = -EPIPE;
goto error;
}
urb->hcpriv = td;
spin_unlock(&urb->lock);
if (request) {
ret = start_transfer(r8a66597, td);
......@@ -1781,17 +1782,26 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
set_td_timer(r8a66597, td);
error:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
......@@ -1799,8 +1809,9 @@ static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
disable_irq_empty(r8a66597, td->pipenum);
done(r8a66597, td, td->pipenum, urb);
}
done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return 0;
return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
......
......@@ -441,6 +441,7 @@ static void finish_request(
urb->hcpriv = NULL;
spin_unlock(&urb->lock);
usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
spin_unlock(&sl811->lock);
usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
spin_lock(&sl811->lock);
......@@ -807,7 +808,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags
) {
......@@ -820,7 +820,8 @@ static int sl811h_urb_enqueue(
struct sl811h_ep *ep = NULL;
unsigned long flags;
int i;
int retval = 0;
int retval;
struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
if (type == PIPE_ISOCHRONOUS)
......@@ -838,7 +839,12 @@ static int sl811h_urb_enqueue(
|| !HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
kfree(ep);
goto fail;
goto fail_not_linked;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval) {
kfree(ep);
goto fail_not_linked;
}
if (hep->hcpriv) {
......@@ -965,23 +971,27 @@ static int sl811h_urb_enqueue(
start_transfer(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
fail:
if (retval)
usb_hcd_unlink_urb_from_ep(hcd, urb);
fail_not_linked:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
int retval = 0;
int retval;
spin_lock_irqsave(&sl811->lock, flags);
hep = urb->hcpriv;
if (!hep)
retval = usb_hcd_check_unlink_urb(hcd, urb, status);
if (retval)
goto fail;
hep = urb->hcpriv;
ep = hep->hcpriv;
if (ep) {
/* finish right away if this urb can't be active ...
......@@ -1029,8 +1039,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
fail:
retval = -EINVAL;
fail:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
......
This diff is collapsed.
......@@ -1376,7 +1376,6 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
}
static int uhci_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
{
int ret;
......@@ -1387,19 +1386,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&uhci->lock, flags);
ret = urb->status;
if (ret != -EINPROGRESS) /* URB already unlinked! */
goto done;
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret)
goto done_not_linked;
ret = -ENOMEM;
urbp = uhci_alloc_urb_priv(uhci, urb);
if (!urbp)
goto done;
if (hep->hcpriv)
qh = (struct uhci_qh *) hep->hcpriv;
if (urb->ep->hcpriv)
qh = urb->ep->hcpriv;
else {
qh = uhci_alloc_qh(uhci, urb->dev, hep);
qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
if (!qh)
goto err_no_qh;
}
......@@ -1440,27 +1439,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
err_submit_failed:
if (qh->state == QH_STATE_IDLE)
uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
err_no_qh:
uhci_free_urb_priv(uhci, urbp);
done:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
done_not_linked:
spin_unlock_irqrestore(&uhci->lock, flags);
return ret;
}
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
int rc;
spin_lock_irqsave(&uhci->lock, flags);
urbp = urb->hcpriv;
if (!urbp) /* URB was never linked! */
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
qh = urbp->qh;
qh = ((struct urb_priv *) urb->hcpriv)->qh;
/* Remove Isochronous TDs from the frame list ASAP */
if (qh->type == USB_ENDPOINT_XFER_ISOC) {
......@@ -1477,7 +1478,7 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
done:
spin_unlock_irqrestore(&uhci->lock, flags);
return 0;
return rc;
}
/*
......@@ -1529,6 +1530,7 @@ __acquires(uhci->lock)
}
uhci_free_urb_priv(uhci, urbp);
usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment