ChangeSet 1.781.21.17, 2002/10/18 09:34:20-07:00, [EMAIL PROTECTED]
[PATCH] uhci interrupt resubmit fixes
After the interrupt queueing was added, I don't think the old way of
resetting interrupts will work anymore. This patch changes it to simply
do a full unlink and resubmission automatically. Note that since
usb_hcd_giveback_urb() is never called for a resubmitting interrupt URB,
that means whatever gets released in usb_hcd_giveback_urb() won't get
released for that URB. The only way to work around that is call
usb_hcd_giveback_urb after the user unlinks in their completion handler,
which will call the completion handler again with -ECONNRESET
status...which wouldn't be all that bad, but the drivers have to expect
it.
Hopefully the interrupt resubmission will go away soon...
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c Fri Oct 18 14:43:10 2002
+++ b/drivers/usb/host/uhci-hcd.c Fri Oct 18 14:43:10 2002
@@ -1230,26 +1230,6 @@
return ret;
}
-static void uhci_reset_interrupt(struct uhci_hcd *uhci, struct urb *urb)
-{
- struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
- struct uhci_td *td;
- unsigned long flags;
-
- spin_lock_irqsave(&urb->lock, flags);
-
- td = list_entry(urbp->td_list.next, struct uhci_td, list);
-
- td->status = (td->status & cpu_to_le32(0x2F000000)) |
cpu_to_le32(TD_CTRL_ACTIVE | TD_CTRL_IOC);
- td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
- td->token |= cpu_to_le32(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT);
- usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
-
- urb->status = -EINPROGRESS;
-
- spin_unlock_irqrestore(&urb->lock, flags);
-}
-
static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb
*eurb)
{
int ret;
@@ -1568,16 +1548,16 @@
uhci_unlink_generic(uhci, urb);
break;
case PIPE_INTERRUPT:
- /* Interrupts are an exception */
- if (urb->interval)
- goto out_complete;
-
/* Release bandwidth for Interrupt or Isoc. transfers */
/* Make sure we don't release if we have a queued URB */
spin_lock(&uhci->frame_list_lock);
/* Spinlock needed ? */
if (list_empty(&urbp->queue_list) && urb->bandwidth)
usb_release_bandwidth(urb->dev, urb, 0);
+ else
+ /* bandwidth was passed on to queued URB, */
+ /* so don't let usb_unlink_urb() release it */
+ urb->bandwidth = 0;
spin_unlock(&uhci->frame_list_lock);
uhci_unlink_generic(uhci, urb);
break;
@@ -1589,7 +1569,6 @@
/* Remove it from uhci->urb_list */
list_del_init(&urbp->urb_list);
-out_complete:
uhci_add_complete(uhci, urb);
out:
@@ -1658,6 +1637,13 @@
unsigned long flags;
struct urb_priv *urbp = urb->hcpriv;
+ /* If this is an interrupt URB that is being killed in urb->complete, */
+ /* then just set its status and return */
+ if (!urbp) {
+ urb->status = -ECONNRESET;
+ return 0;
+ }
+
spin_lock_irqsave(&uhci->urb_list_lock, flags);
list_del_init(&urbp->urb_list);
@@ -1820,38 +1806,42 @@
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct usb_device *dev = urb->dev;
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int killed, resubmit_interrupt, status;
+ int killed, resubmit_interrupt, status, ret;
unsigned long flags;
spin_lock_irqsave(&urb->lock, flags);
killed = (urb->status == -ENOENT || urb->status == -ECONNRESET);
resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
- urb->interval);
+ urb->interval && !killed);
status = urbp->status;
- if (!resubmit_interrupt || killed)
- /* We don't need urb_priv anymore */
- uhci_destroy_urb_priv(uhci, urb);
+ uhci_destroy_urb_priv(uhci, urb);
if (!killed)
urb->status = status;
spin_unlock_irqrestore(&urb->lock, flags);
- if (resubmit_interrupt)
+ if (resubmit_interrupt) {
urb->complete(urb);
- else
- usb_hcd_giveback_urb(hcd, urb);
- if (resubmit_interrupt)
/* Recheck the status. The completion handler may have */
- /* unlinked the resubmitting interrupt URB */
- killed = (urb->status == -ENOENT || urb->status == -ECONNRESET);
+ /* unlinked the resubmitting interrupt URB */
+ /* Note that this doesn't do what usb_hcd_giveback_urb() */
+ /* normally does, so that doesn't ever get done. */
+ if (urb->status == -ECONNRESET) {
+ usb_put_urb(urb);
+ return;
+ }
- if (resubmit_interrupt && !killed) {
urb->dev = dev;
- uhci_reset_interrupt(uhci, urb);
- }
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->bandwidth = 0;
+ if ((ret = uhci_urb_enqueue(&uhci->hcd, urb, 0)))
+ printk(KERN_ERR __FILE__ ": could not resubmit interrupt URB :
+%d\n", ret);
+ } else
+ usb_hcd_giveback_urb(hcd, urb);
}
static void uhci_finish_completion(struct usb_hcd *hcd)
-------------------------------------------------------
This sf.net email is sponsored by:
Access Your PC Securely with GoToMyPC. Try Free Now
https://www.gotomypc.com/s/OSND/DD
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel