Greg:

This patch (as689) stores the period for periodic transfers (interrupt and 
ISO) in the queue header.  This is necessary for proper bandwidth 
tracking (not yet implemented).  It also makes the scheduling of ISO 
transfers a bit more rigorous, with checks for out-of-bounds frame 
numbers.

Alan Stern



Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

---

Index: usb-2.6/drivers/usb/host/uhci-q.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/uhci-q.c
+++ usb-2.6/drivers/usb/host/uhci-q.c
@@ -763,6 +763,7 @@ static int uhci_submit_common(struct uhc
        wmb();
        qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
        qh->dummy_td = td;
+       qh->period = urb->interval;
 
        usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe), toggle);
@@ -790,14 +791,30 @@ static inline int uhci_submit_bulk(struc
        return ret;
 }
 
-static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
+static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
+       int exponent;
+
        /* USB 1.1 interrupt transfers only involve one packet per interval.
         * Drivers can submit URBs of any length, but longer ones will need
         * multiple intervals to complete.
         */
-       qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)];
+
+       /* Figure out which power-of-two queue to use */
+       for (exponent = 7; exponent >= 0; --exponent) {
+               if ((1 << exponent) <= urb->interval)
+                       break;
+       }
+       if (exponent < 0)
+               return -EINVAL;
+       urb->interval = 1 << exponent;
+
+       if (qh->period == 0)
+               qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
+       else if (qh->period != urb->interval)
+               return -EINVAL;         /* Can't change the period */
+
        return uhci_submit_common(uhci, urb, qh);
 }
 
@@ -937,31 +954,50 @@ static int uhci_submit_isochronous(struc
        unsigned long destination, status;
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
-       if (urb->number_of_packets > 900)       /* 900? Why? */
+       /* Values must not be too big (could overflow below) */
+       if (urb->interval >= UHCI_NUMFRAMES ||
+                       urb->number_of_packets >= UHCI_NUMFRAMES)
                return -EFBIG;
 
-       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
-       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+       /* Check the period and figure out the starting frame number */
+       uhci_get_current_frame_number(uhci);
+       if (qh->period == 0) {
+               if (urb->transfer_flags & URB_ISO_ASAP) {
+                       urb->start_frame = uhci->frame_number + 10;
+               } else {
+                       i = urb->start_frame - uhci->frame_number;
+                       if (i <= 0 || i >= UHCI_NUMFRAMES)
+                               return -EINVAL;
+               }
+       } else if (qh->period != urb->interval) {
+               return -EINVAL;         /* Can't change the period */
 
-       /* Figure out the starting frame number */
-       if (urb->transfer_flags & URB_ISO_ASAP) {
+       } else {        /* Pick up where the last URB leaves off */
                if (list_empty(&qh->queue)) {
-                       uhci_get_current_frame_number(uhci);
-                       urb->start_frame = (uhci->frame_number + 10);
-
-               } else {                /* Go right after the last one */
-                       struct urb *last_urb;
+                       frame = uhci->frame_number + 10;
+               } else {
+                       struct urb *lurb;
 
-                       last_urb = list_entry(qh->queue.prev,
+                       lurb = list_entry(qh->queue.prev,
                                        struct urb_priv, node)->urb;
-                       urb->start_frame = (last_urb->start_frame +
-                                       last_urb->number_of_packets *
-                                       last_urb->interval);
+                       frame = lurb->start_frame +
+                                       lurb->number_of_packets *
+                                       lurb->interval;
                }
-       } else {
+               if (urb->transfer_flags & URB_ISO_ASAP)
+                       urb->start_frame = frame;
                /* FIXME: Sanity check */
        }
 
+       /* Make sure we won't have to go too far into the future */
+       if (uhci_frame_before_eq(uhci->frame_number + UHCI_NUMFRAMES,
+                       urb->start_frame + urb->number_of_packets *
+                               urb->interval))
+               return -EFBIG;
+
+       status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+       destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
        for (i = 0; i < urb->number_of_packets; i++) {
                td = uhci_alloc_td(uhci);
                if (!td)
@@ -978,6 +1014,7 @@ static int uhci_submit_isochronous(struc
        td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
        qh->skel = uhci->skel_iso_qh;
+       qh->period = urb->interval;
 
        /* Add the TDs to the frame list */
        frame = urb->start_frame;
@@ -1206,6 +1243,7 @@ __acquires(uhci->lock)
                uhci_unlink_qh(uhci, qh);
 
                /* Bandwidth stuff not yet implemented */
+               qh->period = 0;
        }
 }
 
Index: usb-2.6/drivers/usb/host/uhci-hcd.h
===================================================================
--- usb-2.6.orig/drivers/usb/host/uhci-hcd.h
+++ usb-2.6/drivers/usb/host/uhci-hcd.h
@@ -140,6 +140,8 @@ struct uhci_qh {
 
        unsigned long advance_jiffies;  /* Time of last queue advance */
        unsigned int unlink_frame;      /* When the QH was unlinked */
+       unsigned int period;            /* For Interrupt and Isochronous QHs */
+
        int state;                      /* QH_STATE_xxx; see above */
        int type;                       /* Queue type (control, bulk, etc) */
 
@@ -315,38 +317,8 @@ static inline u32 td_status(struct uhci_
 #define skel_bulk_qh           skelqh[12]
 #define skel_term_qh           skelqh[13]
 
-/*
- * Search tree for determining where <interval> fits in the skelqh[]
- * skeleton.
- *
- * An interrupt request should be placed into the slowest skelqh[]
- * which meets the interval/period/frequency requirement.
- * An interrupt request is allowed to be faster than <interval> but not slower.
- *
- * For a given <interval>, this function returns the appropriate/matching
- * skelqh[] index value.
- */
-static inline int __interval_to_skel(int interval)
-{
-       if (interval < 16) {
-               if (interval < 4) {
-                       if (interval < 2)
-                               return 9;       /* int1 for 0-1 ms */
-                       return 8;               /* int2 for 2-3 ms */
-               }
-               if (interval < 8)
-                       return 7;               /* int4 for 4-7 ms */
-               return 6;                       /* int8 for 8-15 ms */
-       }
-       if (interval < 64) {
-               if (interval < 32)
-                       return 5;               /* int16 for 16-31 ms */
-               return 4;                       /* int32 for 32-63 ms */
-       }
-       if (interval < 128)
-               return 3;                       /* int64 for 64-127 ms */
-       return 2;                               /* int128 for 128-255 ms (Max.) 
*/
-}
+/* Find the skelqh entry corresponding to an interval exponent */
+#define UHCI_SKEL_INDEX(exponent)      (9 - exponent)
 
 
 /*
Index: usb-2.6/drivers/usb/host/uhci-debug.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/uhci-debug.c
+++ usb-2.6/drivers/usb/host/uhci-debug.c
@@ -153,7 +153,7 @@ static int uhci_show_qh(struct uhci_qh *
        char *qtype;
 
        /* Try to make sure there's enough memory */
-       if (len < 80 * 6)
+       if (len < 80 * 7)
                return 0;
 
        switch (qh->type) {
@@ -167,6 +167,9 @@ static int uhci_show_qh(struct uhci_qh *
        out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n",
                        space, "", qh, qtype,
                        le32_to_cpu(qh->link), le32_to_cpu(element));
+       if (qh->type == USB_ENDPOINT_XFER_ISOC)
+               out += sprintf(out, "%*s    period %d\n",
+                               space, "", qh->period);
 
        if (element & UHCI_PTR_QH)
                out += sprintf(out, "%*s  Element points to QH (bug?)\n", 
space, "");



-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to