#define        ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
+/* Process and recycle a completed ITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
 static unsigned
 itd_complete (
        struct ehci_hcd *ehci,
        int                                     urb_index = -1;
        struct ehci_iso_stream                  *stream = itd->stream;
        struct usb_device                       *dev;
+       unsigned                                retval = false;
 
        /* for each uframe with a packet */
        for (uframe = 0; uframe < 8; uframe++) {
                }
        }
 
-       usb_put_urb (urb);
-       itd->urb = NULL;
-       itd->stream = NULL;
-       list_move (&itd->itd_list, &stream->free_list);
-       iso_stream_put (ehci, stream);
-
        /* handle completion now? */
        if (likely ((urb_index + 1) != urb->number_of_packets))
-               return 0;
+               goto done;
 
        /* ASSERT: it's really the last itd for this urb
        list_for_each_entry (itd, &stream->td_list, itd_list)
        /* give urb back to the driver ... can be out-of-order */
        dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
+       retval = true;
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
+       /* OK to recycle this ITD now that its completion callback ran. */
+done:
+       usb_put_urb(urb);
+       itd->urb = NULL;
+       itd->stream = NULL;
+       list_move(&itd->itd_list, &stream->free_list);
+       iso_stream_put(ehci, stream);
 
-       return 1;
+       return retval;
 }
 
 /*-------------------------------------------------------------------------*/
 #define        SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
                                | SITD_STS_XACT | SITD_STS_MMF)
 
+/* Process and recycle a completed SITD.  Return true iff its urb completed,
+ * and hence its completion callback probably added things to the hardware
+ * schedule.
+ *
+ * Note that we carefully avoid recycling this descriptor until after any
+ * completion callback runs, so that it won't be reused quickly.  That is,
+ * assuming (a) no more than two urbs per frame on this endpoint, and also
+ * (b) only this endpoint's completions submit URBs.  It seems some silicon
+ * corrupts things if you reuse completed descriptors very quickly...
+ */
 static unsigned
 sitd_complete (
        struct ehci_hcd         *ehci,
        int                                     urb_index = -1;
        struct ehci_iso_stream                  *stream = sitd->stream;
        struct usb_device                       *dev;
+       unsigned                                retval = false;
 
        urb_index = sitd->index;
        desc = &urb->iso_frame_desc [urb_index];
                desc->status = 0;
                desc->actual_length = desc->length - SITD_LENGTH (t);
        }
-
-       usb_put_urb (urb);
-       sitd->urb = NULL;
-       sitd->stream = NULL;
-       list_move (&sitd->sitd_list, &stream->free_list);
        stream->depth -= stream->interval << 3;
-       iso_stream_put (ehci, stream);
 
        /* handle completion now? */
        if ((urb_index + 1) != urb->number_of_packets)
-               return 0;
+               goto done;
 
        /* ASSERT: it's really the last sitd for this urb
        list_for_each_entry (sitd, &stream->td_list, sitd_list)
        /* give urb back to the driver */
        dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
+       retval = true;
        urb = NULL;
 
        /* defer stopping schedule; completion can submit */
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
+       /* OK to recycle this SITD now that its completion callback ran. */
+done:
+       usb_put_urb(urb);
+       sitd->urb = NULL;
+       sitd->stream = NULL;
+       list_move(&sitd->sitd_list, &stream->free_list);
+       iso_stream_put(ehci, stream);
 
-       return 1;
+       return retval;
 }