These patches are against kernels 2.6.18 through at least 2.6.18-git7.

patch 10: Drops in complete implementation of the shadow budget
abstraction, but does not yet call this code in any way.  The shadow
budget is a means of indefinitely reserving bandwidth requested by a
periodic endpoint as well as logic for making scheduling decisions
based on previously budgeted allocations.

Signed-off-by: Christopher "Monty" Montgomery <[EMAIL PROTECTED]>

---

diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci.h
b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h   2006-09-26 22:29:36.000000000 -0400
+++ b/drivers/usb/host/ehci.h   2006-09-26 22:29:47.000000000 -0400
@@ -72,6 +72,10 @@ struct ehci_hcd {                    /* one per controlle
        int                     next_uframe;    /* scan periodic, start here */
        unsigned                periodic_sched; /* periodic activity count */

+        kmem_cache_t            *budget_pool;   /* Pool for shadow budget */
+        struct ehci_shadow_budget **budget;     /* pointer to the
shadow budget
+                                                  of bandwidth placeholders */
+
        /* per root hub port */
        unsigned long           reset_done [EHCI_MAX_ROOT_PORTS];

@@ -155,8 +159,8 @@ timer_action (struct ehci_hcd *ehci, enu
                // to go OFF neither can matter, and afterwards the IO
                // watchdog stops unless there's still periodic traffic.
                if (action != TIMER_IAA_WATCHDOG
-                               && t > ehci->watchdog.expires
-                               && timer_pending (&ehci->watchdog))
+                   && t > ehci->watchdog.expires
+                   && timer_pending (&ehci->watchdog))
                        return;
                mod_timer (&ehci->watchdog, t);
        }
@@ -377,6 +381,56 @@ union ehci_shadow {

 /*-------------------------------------------------------------------------*/

+/* the shadow budget is a means of reserving bandwidth throughout the
+   periodic schedule (the hardware schedule is currently used as a
+   sliding window by the current transaction code). The shadow budget
+   follows the same list-then-tree structure as the hardware schedule. */
+
+/* must be equal to or smaller than PERIODIC_QH_MAX_PERIOD */
+#define BUDGET_SLOTS 32
+#define BUDGET_SLOT_MASK (BUDGET_SLOTS-1)
+
+/* Because EHCI cannot issue ssplits in uframe 7 and USB 2.0 does not
+   allow ssplits in uframe 6, EHCI can only generate an efficient FS
+   frame by scheduling according to best-case (not worst-case) bit
+   stuffing.  Thus we purposely 'overcommit' the FS frame budget
+   within the buffering ability of the TT to buffer, and within the
+   limits of the 90/10 rule.  The TT will catch up in the microframes
+   where we cannot issue start splits.
+*/
+
+#define BUDGET_WRAP_P(b) ((b)->cmask & (~0xff))
+
+struct ehci_shadow_budget {
+       struct ehci_shadow_budget *next;
+
+       u16 s_usecs;  /* highspeed usecs */
+       u16 c_usecs;  /* highspeed completion usecs (FS/LS)*/
+       u16 tt_bytes; /* bytes to budget at TT (FS/LS)*/
+       u16 cmask;    /* 16 bits: a 'too big' mask indicates the need for a
+                        frame wrap (FSTN or dummy SITD) */
+       u8  smask;
+
+#define BUDGET_TYPE_ITD 1 /* ITD or SITD; budgets early */
+#define BUDGET_TYPE_QH  2 /* QH; budgets late */
+       u8 type;
+
+       /* QHs and FSTNs are persistent in the periodic schedule, so they
+          own their own budget placeholders.  [s]ITD placeholders are owned
+          by an ehci_iso_stream. */
+       union {
+               struct ehci_qh *qh;          /* needed to extract
+                                               period and specific
+                                               TT */
+               struct ehci_iso_stream *iso; /* needed to extract
+                                               period and specific
+                                               TT */
+               void *ptr;                   /* used as an ID */
+       } owner;
+};
+
+/*-------------------------------------------------------------------------*/
+
 /*
  * EHCI Specification 0.95 Section 3.6
  * QH: describes control/bulk/interrupt endpoints
@@ -388,7 +442,9 @@ union ehci_shadow {
 /* as per ehci spec guidelines, replicate QH tree linkage of a maximum
    size that is less than the full periodic schedule size. This is
    also necessary to limit memory usage of FSTN support. */
-#define PERIODIC_QH_MAX_PERIOD 256 // 32 frames * 8 uFrames/Frame
+/* must be equal to or larger than BUDGET_SLOTS*8, otherwise the budget
+   will overcommit */
+#define PERIODIC_QH_MAX_PERIOD (BUDGET_SLOTS*8)

 struct ehci_qh {
        /* first part defined by EHCI spec */
@@ -433,10 +489,12 @@ struct ehci_qh {
        u8                      gap_uf;         /* uframes split/csplit gap */
        u8                      c_usecs;        /* ... split completion bw */
        u16                     tt_usecs;       /* tt downstream bandwidth */
+       u16                     tt_bytes;       /* tt downstream bandwidth */
        unsigned short          period;         /* polling interval */
        unsigned short          start;          /* where polling starts */
 #define NO_FRAME ((unsigned short)~0)                  /* pick new start */
        struct usb_device       *dev;           /* access to TT */
+       struct ehci_shadow_budget *budget;      /* pointer to budget 
placeholder */
 } __attribute__ ((aligned (32)));

 /*-------------------------------------------------------------------------*/
@@ -493,6 +551,7 @@ struct ehci_iso_stream {
        u16                     interval;
        u8                      usecs, c_usecs;
        u16                     tt_usecs;
+       u16                     tt_bytes;
        u16                     raw_mask;
        unsigned                bandwidth;

@@ -542,6 +601,7 @@ struct ehci_itd {
        unsigned                pg;
        unsigned                index[8];       /* in urb->iso_frame_desc */
        u8                      usecs[8];
+       struct ehci_shadow_budget *budget;      /* pointer to budget 
placeholder */
 } __attribute__ ((aligned (32)));

 /*-------------------------------------------------------------------------*/
@@ -585,6 +645,7 @@ struct ehci_sitd {
        struct list_head        sitd_list;      /* list of stream's sitds */
        unsigned                frame;
        unsigned                index;
+       struct ehci_shadow_budget *budget;      /* pointer to budget 
placeholder */
 } __attribute__ ((aligned (32)));

 /*-------------------------------------------------------------------------*/
diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-mem.c
b/drivers/usb/host/ehci-mem.c
--- a/drivers/usb/host/ehci-mem.c       2006-08-07 00:18:54.000000000 -0400
+++ b/drivers/usb/host/ehci-mem.c       2006-09-26 22:29:47.000000000 -0400
@@ -154,6 +154,13 @@ static void ehci_mem_cleanup (struct ehc
                        ehci->periodic, ehci->periodic_dma);
        ehci->periodic = NULL;

+       if(ehci->budget)
+               kfree(ehci->budget);
+       ehci->budget = NULL;
+       if(ehci->budget_pool)
+               kmem_cache_destroy(ehci->budget_pool);
+       ehci->budget_pool = NULL;
+
        /* shadow periodic table */
        kfree(ehci->pshadow);
        ehci->pshadow = NULL;
@@ -219,6 +226,19 @@ static int ehci_mem_init (struct ehci_hc
        for (i = 0; i < ehci->periodic_size; i++)
                ehci->periodic [i] = EHCI_LIST_END;

+       /* budgeting placeholders */
+       ehci->budget = kcalloc(BUDGET_SLOTS, sizeof(*ehci->budget), flags);
+       if (ehci->budget == NULL){
+               goto fail;
+       }
+       ehci->budget_pool =
+         kmem_cache_create ("ehci_budget",
+                            sizeof(struct ehci_shadow_budget),
+                            0,0,NULL,NULL);
+       if (!ehci->budget_pool) {
+               goto fail;
+       }
+
        /* software shadow of hardware table */
        ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
        if (ehci->pshadow != NULL)
diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-sched.c
b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c     2006-09-26 22:29:36.000000000 -0400
+++ b/drivers/usb/host/ehci-sched.c     2006-09-26 22:29:47.000000000 -0400
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2001-2004 by David Brownell
  * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
+ * Copyright (c) 2006 Monty (budgeting code)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -22,19 +23,85 @@
 /*-------------------------------------------------------------------------*/

 /*
- * EHCI scheduled transaction support:  interrupt, iso, split iso
- * These are called "periodic" transactions in the EHCI spec.
+ * EHCI scheduled transaction support: interrupt, iso, split
+ * iso. These are called "periodic" transactions in the EHCI spec.  It
+ * should be noted that the Linux USB subsystem has no high-level
+ * notion of periodically serviced transfers; bandwidth is reserved
+ * periodically [the shadow budget], but transfers are still entirely
+ * single-request/single-response. To avoid over/underruns, periodic
+ * streaming relies on upper layers to make a new request before the
+ * next schedule slot passes.  Any such xruns are reported as
+ * -EL2NSYNC if they occur.
+ *
+ * The shadow budget consists of placeholders for reserving bandwidth
+ * throughout the periodic schedule for any given active endpoint.
+ * This avoids both underallocation errors (spurious ENOSPC during a
+ * transfer that began successfully) and overallocation errors (lost
+ * frames or HC/hub/irq errors and resets during transfers) due to
+ * basing bandwidth allocation on the always-incomplete hardware
+ * schedule. Although it would be conceptually simpler to place
+ * inactive [s]ITDs and QHs into the actual hardware budget (to be
+ * activated when a transfer makes use of that segment of the periodic
+ * schedule), the additional memory overhead of populating the
+ * complete 1024 frame periodic schedule is not insignificant.
+ * Therefore, a relatively small shadow budget (BUDGET_SLOTS) is
+ * projected ('translated') onto the full (1024 slot) hardware
+ * schedule.  Budgeting is fully computed upon the first transfer
+ * attempt with an endpoint and remains in the shadow budget until the
+ * endpoint is closed [disabled].  Transfer descriptors are linked
+ * into the hardware schedule on demand using the precomputed
+ * information in the shadow budget.
+ *
+ * Interrupt transfers share the QH/QTD manipulation with the
+ * "asynchronous" transaction support (control/bulk transfers) in
+ * ehci-q.c, although all toplevel interrupt control originates here.
+ * The only real difference is in how interrupt transfers are
+ * scheduled.
+ *
+ * For isochronous, an "iso_stream" head serves the same role as a QH.
+ * It keeps track of every ITD (or SITD) that's scheduled.
+ *
+ *
+ * The transfer ordering in the shadow schedule looks like:
+ *
+ * .              |      Level N       |  N/2  | ...   |       Level 1
+ * .              |                    |       |       |
+ * .              |                    |       |       |
+ * Frame 2: [iso]
+ *               \_ [save FSTN]; [QHs] |       |       |
+ *               /                    \_ [QHs] |       |
+ * Frame 1: [iso]                ... _/       \_ ... _ |
+ *                                       ... _/       \_ [restore FSTN]; [QHs]
+ *                                               ... _/
+ * Frame 0: [iso]...
+ *
+ * Each [iso] block is ordered [dummy sITDs]; [sITDs/ITDs]
  *
- * Note that for interrupt transfers, the QH/QTD manipulation is shared
- * with the "asynchronous" transaction support (control/bulk transfers).
- * The only real difference is in how interrupt transfers are scheduled.
+ * The shadow budget is structured like the shadow schedule, however
+ * it is both smaller (to save memory) and simpler, containing only
+ * QHs and normal [s]ITDs.  dummy sITDs and FSTNs are intuited in
+ * budgeting calculations and do not appear explicitly in the shadow
+ * budget:
+ *
+ * .                     |Level N|  N/2  | ...   |Level 1
+ * .                     |       |       |       |
+ * .          append     |       |       |       |
+ *           --------->  |prepend|       |       |
+ * Frame 2: [sITDs/ITDs] | <---- |prepend|       |
+ *                      \_ [QHs] | <---- |       |
+ *                      /       \_ [QHs] |       |prepend
+ * Frame 1: [sITDs/ITDs]   ... _/       \_ ... _ | <----
+ *                                 ... _/       \_ [QHs]
+ *                                         ... _/
+ * Frame 0: [sITDs/ITDs]...
+ *
+ *
+ * Transaction ordering is determined by the budgeting code and set in
+ * the budget.  Transactions are linked into the actual hardware
+ * schedule in the order specified by the budget.
  *
- * For ISO, we make an "iso_stream" head to serve the same role as a QH.
- * It keeps track of every ITD (or SITD) that's linked, and holds enough
- * pre-calculated schedule data to make appending to the queue be quick.
  */

-static int ehci_get_frame (struct usb_hcd *hcd);

 /* enable/disable shedule-specific debugging output */
 static unsigned sched_verbose = 0;
@@ -44,10 +111,44 @@ MODULE_PARM_DESC (sched_verbose,
                  "debugging information to syslog.  Incurs large latencies in"
                  " near-realtime code; default is 0 (off)");

+/* set limit on periodic load per TT uframe */
+static unsigned fs_bytes_per_uframe = 188;
+module_param (fs_bytes_per_uframe, uint, S_IRUGO);
+MODULE_PARM_DESC (fs_bytes_per_uframe,
+                 "full-speed bytes per high-speed uframe: set the "
+                 "maximum number of periodic full-speed bytes to schedule "
+                 "per TT per microframe; default [spec] is 188");
+
+/* set limit on periodic load per TT frame */
+static unsigned fs_bytes_per_fullframe = 1157;
+module_param (fs_bytes_per_fullframe, uint, S_IRUGO);
+MODULE_PARM_DESC (fs_bytes_per_uframe,
+                 "full-speed bytes per full-speed frame: set the "
+                 "maximum number of periodic full-speed bytes to schedule "
+                 "per frame; default [spec] is 1157");
+
+/* set limit on periodic load per high-speed uframe */
+static unsigned hs_usec_per_uframe = 100;
+module_param (hs_usec_per_uframe, uint, S_IRUGO);
+MODULE_PARM_DESC (hs_usec_per_uframe,
+                 "high-speed usec per uframe: set the maximum "
+                 "number of usec to use for periodic high-speed transfers; "
+                 "default [spec] is 100");
+
+/* set limit on unique endpoints per uframe */
+static unsigned endpoints_per_uframe = 16;
+module_param (endpoints_per_uframe, uint, S_IRUGO);
+MODULE_PARM_DESC (endpoints_per_uframe,
+                 "endpoints per uframe: maximum number of unique "
+                 "transfers to attemps during a microframe; default "
+                 "[spec] is 16");
+
 /*-------------------------------------------------------------------------*/
+/* shadow schedule positioning, as this is needed throughout */

 /*
  * periodic_next_shadow - return "next" pointer on shadow list
+ *
  * @periodic: host pointer to qh/itd/sitd
  * @tag: hardware tag for type of this record
  */
@@ -67,6 +168,68 @@ periodic_next_shadow (union ehci_shadow
        }
 }

+/* the following are merely frame-structure dumpers to aid in
+   debugging.  Be careful of their use; they will introduce extreme
+   latencies in what is [essentially] realtime code. */
+static void print_budget_frame (struct ehci_hcd *ehci, int frame,
+                               struct ehci_shadow_budget *insert,
+                               void *owner)
+{
+       struct ehci_shadow_budget *here =
+               ehci->budget [frame & BUDGET_SLOT_MASK];
+       printk(KERN_INFO "  slot %d: ",frame & BUDGET_SLOT_MASK);
+
+       while(here){
+               if(here == insert || here->owner.ptr == owner)
+                       printk(">>");
+               
+               switch(here->type){
+               case BUDGET_TYPE_ITD:
+                       if(here->tt_bytes)
+                               printk("[SITD %p 0x%x 0x%x]",
+                                      here,
+                                      (unsigned)here->cmask,
+                                      (unsigned)here->smask);
+                       else
+                               printk("[ITD %p 0x%x 0x%x]",
+                                      here,
+                                      (unsigned)here->cmask,
+                                      (unsigned)here->smask);
+                       break;
+               case BUDGET_TYPE_QH:
+                       printk("[QH (%s) %p %d 0x%x 0x%x]",
+                              (here->tt_bytes?"FS/LS":"HS"),
+                              here,
+                              here->owner.qh->period,
+                              (unsigned)here->cmask,
+                              (unsigned)here->smask);
+                       break;
+               }
+               
+               if(here == insert || here->owner.ptr == owner)
+                       printk("<<");
+               
+               if(here == here->next){
+                       printk("\nERROR: schedule entry linked "
+                              "to itself!\n");
+                       return;
+               }
+
+               here=here->next;
+
+       }
+       printk("\n");
+}
+
+static void print_budget (struct ehci_hcd *ehci,
+                         struct ehci_shadow_budget *insert,
+                         void *owner)
+{
+       int i;
+       for(i=0; i<BUDGET_SLOTS; i++)
+               print_budget_frame(ehci,i,insert,owner);
+}
+
 /* find position of a specific entry in the periodic schedule (ie,
  * returns pointers such that we can update the predecessor's
  * linkage); here->ptr == NULL indicates the find failed.
@@ -78,14 +241,15 @@ periodic_next_shadow (union ehci_shadow
  */
 static union ehci_shadow *
 periodic_find_entry(struct ehci_hcd *ehci,
-                    unsigned frame,
-                    void *ptr,
-                    __le32 **hw_p)
+                   unsigned frame,
+                   void *ptr,
+                   __le32 **hw_p)
 {
-       union ehci_shadow *here = &ehci->pshadow [frame % ehci->periodic_size];
+       union ehci_shadow *here =
+               &ehci->pshadow [frame & (ehci->periodic_size-1)];
        __le32 type;
        
-       *hw_p = &ehci->periodic [frame % ehci->periodic_size];
+       *hw_p = &ehci->periodic [frame & (ehci->periodic_size-1)];
        type = Q_NEXT_TYPE (**hw_p);
        
        while (here->ptr && here->ptr != ptr) {
@@ -96,6 +260,9 @@ periodic_find_entry(struct ehci_hcd *ehc
        return here;
 }

+/*-------------------------------------------------------------------------*/
+/* shadow budget implementation: low-level manipulation machinery */
+
 /* covert a QH's period [expressed in uFrames] to tree level.
  *
  * @period: period (uFrames) of a QH
@@ -109,6 +276,943 @@ static int _period_to_level(int period)
        return period>>3;
 }

+/* budget_position_new_itd - determine and return proper insertion position
+ * in the shadow budget for a new itd or sitd (both position into the
+ * same segment of the frame)
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number in the shadow/hardware schedule into which new
+ *         transaction is to be inserted.
+ */
+static struct ehci_shadow_budget **
+budget_position_new_itd(struct ehci_hcd *ehci, int frame)
+{
+       struct ehci_shadow_budget **here =
+               &ehci->budget [(frame & BUDGET_SLOT_MASK)];
+       
+       /* skip to the end of any dummies or [s]ITDs at list head */
+       while ( (*here) &&
+               (*here)->type == BUDGET_TYPE_ITD ){
+               here = &(*here)->next;
+       }
+       
+       return here;
+}
+
+/* budget_position_new_qh - determine and return proper insertion position
+ * in the shadow budget for a newly queued qh
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number in the shadow/hardware schedule into which new
+ *         transaction is to be inserted.
+ * @period: the endpoint period (in uFrames)
+ */
+static struct ehci_shadow_budget **
+budget_position_new_qh(struct ehci_hcd *ehci, int frame, int period)
+{
+       struct ehci_shadow_budget **here =
+               budget_position_new_itd(ehci, frame);
+       
+       while (*here){
+
+               /* skip past higher (but not same) period QH entries */
+               /* > 8 to left of restore FSTN, <= 8 to right */
+               if ( (*here)->type == BUDGET_TYPE_QH &&
+                    period >= (*here)->owner.qh->period) break;
+
+               here = &(*here)->next;
+       }
+       return here;
+}
+
+/* budget_position_new - determine and return proper insertion position
+ * in the shadow budget for a new budget entry
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number in the shadow/hardware schedule into which new
+ *         transaction is to be inserted.
+ * @new: new,populated  budget entry to insert
+ */
+static struct ehci_shadow_budget **
+budget_position_new(struct ehci_hcd *ehci,
+                   int frame,
+                   struct ehci_shadow_budget *new)
+{
+       switch(new->type){
+       case BUDGET_TYPE_QH:
+               return budget_position_new_qh(ehci,frame,
+                                             new->owner.qh->period);
+
+       case BUDGET_TYPE_ITD:
+               return budget_position_new_itd(ehci,frame);
+
+       default:
+               return NULL;
+
+       }
+}
+
+/* budget_find_entry_by_owner - find position of a specific entry in
+ * the shadow budget by looking for the single entry in the frame
+ * belonging to the passed in owner.  return == NULL indicates the
+ * entry was not found.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number in the shadow budget to search; masked to
+ *         prevent overflow of the shadow budget
+ * @owner: the owner of the placeholder (qh or ehci_iso_stream)
+ */
+static struct ehci_shadow_budget *
+budget_find_entry_by_owner(struct ehci_hcd *ehci,
+                          unsigned frame,
+                          void *owner)
+{
+       struct ehci_shadow_budget *here =
+               ehci->budget [(frame & BUDGET_SLOT_MASK)];
+
+       /* invariant: any one budget frame will contain at most a single entry
+          for a given owner; the budget does not explicitly contain spanning
+          elements, it only declares them in the transaction's cmask.  Thus
+          searching by owner is unique.  */
+       while (here){
+               if(here->owner.ptr == owner) break;
+               here = here->next;
+       }
+       return here;
+}
+
+static void *periodic_shadow_owner(struct ehci_hcd *ehci,
+                                  union ehci_shadow *ptr,
+                                  __le32 type){
+       switch(type){
+       case Q_TYPE_FSTN:
+               return NULL;
+       case Q_TYPE_QH:
+               return ptr;
+       case Q_TYPE_ITD:
+               return ((struct ehci_itd *)ptr)->stream;
+       case Q_TYPE_SITD:
+               return ((struct ehci_sitd *)ptr)->stream;
+       default:
+               return NULL;
+       }
+}
+
+/* periodic_translate_budget - Finds the position in the
+ * hardware/shadow schedule to insert a new hardware schedule entry
+ * based on the position in the shadow budget of the passed in budget
+ * entry. This handles positioning non-dummy sITD, ITD and QH
+ * entries; FSTN position has nothing to do with the budget and is
+ * handled by code specific to FSTNs.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number in the hardware schedule to search; masked to
+ *         prevent overflow
+ * @translate: budget entry to translate to hardware schedule
+ * @hw_p: return a pointer to the predecessor's hw_next field
+ */
+static union ehci_shadow *
+periodic_translate_budget (struct ehci_hcd *ehci,
+                          unsigned frame,
+                          struct ehci_shadow_budget *translate,
+                          __le32 **hw_p)
+{
+       struct ehci_shadow_budget *budget_curr =
+               ehci->budget [(frame & BUDGET_SLOT_MASK)];
+       union ehci_shadow *shadow =
+               &ehci->pshadow [frame & (ehci->periodic_size-1)];
+       __le32 type;
+
+       /* Complete/Inactive entries that have not yet been processed
+          by scan_periodic may yet be present, that will not affect
+          this algorithm (they will have entries present in the
+          budget, even waiting for final urb completion). */
+       
+       *hw_p = &ehci->periodic [frame & (ehci->periodic_size-1)];
+       type = Q_NEXT_TYPE (**hw_p);
+
+       /* Everything in the shadow schedule will be there in the budget
+          [except for FSTNs] */
+       while (shadow->ptr){
+
+               if(type != Q_TYPE_FSTN){
+                       
+                       /* advance past all dummy sITDs before doing anything 
else. */
+                       if(type == Q_TYPE_SITD &&
+                          shadow->sitd->hw_backpointer != EHCI_LIST_END)
+                               goto advance;
+
+                       while(budget_curr &&
+                             budget_curr != translate &&
+                             budget_curr->owner.ptr !=
+                             periodic_shadow_owner(ehci,shadow->ptr,type)){
+                               budget_curr = budget_curr->next;
+                       }
+                       if(budget_curr == translate){
+                               return shadow; /* a match! */
+                       }
+
+                       /* falling off the end of the budget indicates
+                        * an internal logic error */
+                       if(budget_curr == NULL){
+                               ehci_err(ehci,
+                                        "schedule contains "
+                                        "unbudgeted transaction\n");
+                               return NULL;
+                       }
+               }else{
+                       struct ehci_fstn *fstn = shadow->fstn;
+                       /* restore fstn:
+                          ITD/sITD must go before
+                          QH of period > 8 must go before
+                          QH of period <=8 must go after
+                       */
+                       /* save fstn:
+                          all ITD/sITD must go before
+                          all QH must go after
+                       */
+                       
+                       if(translate->type == BUDGET_TYPE_ITD){
+                               return shadow;
+                       }
+                       
+                       if(fstn->hw_prev == EHCI_LIST_END)
+                               if(translate->owner.qh->period > 8)
+                                       return shadow;
+                       
+               }
+               
+       advance:
+               /* advance shadow and hardware schedule by one, then
+                  loop to test this position */
+               *hw_p = shadow->hw_next;
+               shadow = periodic_next_shadow (shadow, type);
+               type = Q_NEXT_TYPE (**hw_p);
+
+       }
+
+       /* nothing queued or fell off the end looking for stopping point.
+          Append to end. */
+       return shadow;
+
+}
+
+/* budget_unlink_entries_by_owner - scan the complete shadow budget
+ *  and unlink/free all entries owned by passed in owner ptr.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @owner: pointer to owner
+ */
+static void budget_unlink_entries_by_owner(struct ehci_hcd *ehci,void *owner)
+{
+       struct ehci_shadow_budget *qh = NULL;
+       int frame;
+       
+       if(sched_verbose){
+               ehci_info(ehci, "Releasing bandwidth for owner %p\n",
+                         owner);
+               ehci_info(ehci, "  Budget before: \n");
+               print_budget(ehci,NULL,owner);
+       }
+
+       for(frame=0; frame<BUDGET_SLOTS; frame++){
+               struct ehci_shadow_budget **budget = &ehci->budget[frame];
+               
+               while(*budget){
+                       if((*budget)->owner.ptr == owner){
+                               struct ehci_shadow_budget *next =
+                                       ((*budget)->next);
+                               
+                               switch((*budget)->type){
+                               default:
+                               case BUDGET_TYPE_ITD:
+                                       
+                                       kmem_cache_free(ehci->budget_pool,
+                                                       *budget);
+                                       *budget = next;
+                                       
+                                       break;
+                               case BUDGET_TYPE_QH:
+                                       if(!qh || (*budget)==qh){
+                                               qh = *budget;
+                                               *budget = next;
+                                               break;
+                                       }
+
+                                       /* another qh with the same
+                                          owner is an internal error;
+                                          not fatal, but shouldn't
+                                          happen. We will leak the
+                                          memory rather than risk a
+                                          double-free. */
+                                       ehci_err(ehci,
+                                                "multiple unique QH budget "
+                                                "entries with same endpoint "
+                                                "owner.\n");
+
+                                       break;
+                               }
+                               /* do not advance; need to process the
+                                  replacement which is now *budget */
+                       }else
+                               budget = &((*budget)->next);
+                       
+               }
+       }
+
+       if(qh)kmem_cache_free(ehci->budget_pool,qh);    
+
+       if(sched_verbose){
+               ehci_info(ehci, "  Budget after: \n");
+               print_budget(ehci,NULL,owner);
+       }
+
+}
+
+/*-------------------------------------------------------------------------*/
+/* Shadow budget constraint/metric calculation routines */
+
+/* determine the TT relevant to this shadow budget entry
+ *
+ * @b: pointer to shadow budget entry
+ */
+static int
+budget_same_tt (struct ehci_shadow_budget *b1,struct ehci_shadow_budget *b2)
+{
+       struct usb_device *dev1;
+       struct usb_device *dev2;
+
+       switch (b1->type) {
+       case BUDGET_TYPE_QH:
+               dev1 = b1->owner.qh->dev;
+               break;
+       case BUDGET_TYPE_ITD:
+               dev1 = b1->owner.iso->udev;
+               break;
+       default:
+               return 0;
+       }
+
+       switch (b2->type) {
+       case BUDGET_TYPE_QH:
+               dev2 = b2->owner.qh->dev;
+               break;
+       case BUDGET_TYPE_ITD:
+               dev2 = b2->owner.iso->udev;
+               break;
+       default:
+               return 0;
+       }
+
+       if(dev1->tt != dev2->tt)
+               return 0;
+        if (dev1->tt->multi)
+                return dev1->ttport == dev2->ttport;
+        else
+                return 1;
+       
+}
+
+/* _calc_hs_uframe - count usecs used in the HS schedule of the
+ * specified frame/uFrame.  *new is a new proposed shadow budget entry
+ * to be treated as if it is already linked into the shadow budget at
+ * position **insert.  Returns abolute usec count, not metric or
+ * remaining available usecs.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame position in the shadow budget (masked to shadow budget size)
+ * @uFrame: uFrame position within full frame; may be 8 or 9 to access
+ *          spanning c_mask
+ * @insert: position of *new [NULL if new is NULL]
+ * @new: a proposed shadow entry to be treated as appearing at position
+ *       *insert; may be NULL
+ */
+static int _calc_hs_uframe(struct ehci_hcd *ehci,
+                          int frame,
+                          int uFrame,
+                          struct ehci_shadow_budget **insert,
+                          struct ehci_shadow_budget *new)
+{
+       struct ehci_shadow_budget **budget =
+               &ehci->budget [(frame & BUDGET_SLOT_MASK)];
+       int usec = 0;
+       if(budget == insert) budget = &new;
+       
+       while(*budget){
+               struct ehci_shadow_budget *budgetp = *budget;
+
+               /* is it in the S-mask? */
+               if (budgetp->smask & (1 << uFrame))
+                       usec += budgetp->s_usecs;
+
+               /* ... or C-mask? */
+               if (budgetp->cmask & (1 << uFrame))
+                       usec += budgetp->c_usecs;
+
+               /* advance */
+               if(budget == &new)
+                       budget = insert;
+               else{
+                       budget = &(budgetp->next);
+                       if(budget == insert) budget = &new;
+               }
+       }
+
+       return usec;
+}
+
+/* budget_calc_hs_frame - returns the budget 'load' metric for a given
+ * high speed frame, range -1 (invalid schedule), 0 (lowest good
+ * score) to 100 (best possible score).  HS scheduling uses this to
+ * choose between possbile slots.  FS/LS scheduling uses it as a check
+ * to make sure the FS budgeting choice is valid in the context of the
+ * HS schedule.  *new is a new proposed shadow budget entry
+ * to be treated as if it is already linked into the shadow budget at
+ * position **insert.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame position in the shadow budget (masked to shadow budget size)
+ * @insert: position to use for *new; in other functions that take an
+ *          insertion point as a marker, *insert=NULL indicates insert at end
+ *          of list.  budget_calc_hs_frame checks more than one frame (because
+ *          of transactions that can span frames), so a simple NULL would be
+ *          ambiguous.  Thus the pointer to the insertion point, which would
+ *          uniquely point to only one frame's list, even in the case of
+ *          insertion.
+ * @new: a proposed shadow entry to be treated as appearing at position
+ *       *insert;
+ *       may be NULL
+ */
+
+static int budget_calc_hs_frame(struct ehci_hcd *ehci,
+                               int frame,
+                               struct ehci_shadow_budget **insert,
+                               struct ehci_shadow_budget *new)
+{
+       int max=0, uFrame;
+       for(uFrame=0; uFrame<8; uFrame++){
+
+               /* first verify we've not overcommitted any uFrames */
+               /* If uFrame < 2, count the cmask contribution of
+                * spanning from prior frame */
+               int val = _calc_hs_uframe(ehci,frame,uFrame,insert,new);
+               if(uFrame<2)
+                       val += _calc_hs_uframe(ehci,frame-1,
+                                              uFrame+8,insert,new);
+
+               if(val>max)max=val;
+               if(max>hs_usec_per_uframe){
+                       return -1;
+               }
+       }
+       return 100-(max*100/hs_usec_per_uframe);
+}
+
+/* periodic_budget_fs_frame - test a proposed new addition to the
+ * periodic schedule of a given frame.  Returns <0 if the frame is
+ * unsuitable, else a positive value indicating the relative space
+ * remaining in that frame after the new transaction would be
+ * scheduled; 0 is lowest score, 100 is best possible score. This
+ * return value is a metric used for breadth-first allocation of
+ * bandwidth.  As a side efect, determine and set appropriate s_mask
+ * and c_mask for the passed in *new entry.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame position in the shadow budget (masked to shadow
+ *         budget size)
+ * @earliest_uFrame: prevent *new from scheduling into any uframe
+ *                   earlier than this
+ * @insert: position of *new
+ * @new: a proposed shadow entry to be treated as appearing at
+ *       position *insert
+ */
+static int budget_calc_fs_frame(struct ehci_hcd *ehci,
+                               int frame,
+                               unsigned earliest_uFrame,
+                               struct ehci_shadow_budget *insert,
+                               struct ehci_shadow_budget *new)
+{
+       struct ehci_shadow_budget *budget =
+               ehci->budget [(frame & BUDGET_SLOT_MASK)];
+
+       /* Scheduling through a TT is done by byte counting, not usec
+          counting.  Because we cannot issue a FS/LS start split in
+          uFrame 6 or 7, the only way to get anywhere near a full 90%
+          of a FS frame for periodic transactions is to 'overcommit'
+          the FS scheduling of each microframe [when considered by
+          usecs needed for the transfer].  This is not actually
+          overcommitting as the TT will buffer the 'excess' from any
+          uFrame and schedule it to transmit in a later uFrame. USB
+          2.0 11.18.4: "Scheduling of split transactions is done by
+          the host (typically in software) based on a best-case
+          estimate of how the full-/low-speed transacitons can be run
+          on the downstream facing bus." */
+
+        /* per uFrame best-case byte budget; USB 2.0 11.18.1 */
+       int remaining_tt_bytes = fs_bytes_per_uframe;
+
+        /* max full-frame bytes for enforcing worst-case 90/10 */
+       int remaining_frame_bytes = fs_bytes_per_fullframe;
+
+       /* track max ssplits per uframe per TT */
+       int remaining_tt_transactions = endpoints_per_uframe;
+
+       /* track the amount of frame spanned (likely > used) by ISO */
+       int load_frame_bytes = 0;
+
+       int uFrame=0;
+       int load = remaining_frame_bytes;
+       int spanned_gap = 0;
+       
+       if(budget == insert) budget = new;
+       earliest_uFrame &= 0x7;
+       
+       while(budget){
+               int start_frame = uFrame;
+               u8 smask=0;
+               u16 cmask=0;
+               
+               /* exclude other TTs as well as HS transfers, which
+                  have no bearing on FS sched. */
+               if(!budget_same_tt(new,budget))
+                       goto advance;
+               
+               if(budget != new){
+
+                       /* For a variety of reasons, the preexisting
+                          FS budget may contain holes where something
+                          could be scheduled but nothing is.  In this
+                          case, the current budget placeholder's
+                          smask will exist entirely in the future.
+                          Test for this case and advance the counters
+                          if true. */
+                       if( ((budget->smask >> (uFrame+1)) << (uFrame+1)) ==
+                           budget->smask){
+                               remaining_tt_bytes =
+                                       fs_bytes_per_uframe;
+                               remaining_tt_transactions =
+                                       endpoints_per_uframe;
+                               uFrame++;
+                               continue;
+                       }
+                               
+                       /* For now, the scheduler holds invariant that
+                          transactions appear in a frame in smask
+                          order; that is, that FS transactions appear
+                          in the frame budget in the same order that
+                          they are run by the host controller.
+
+                          Thus, the current transaction must not have
+                          already been scheduled into the hardware
+                          schedule to start before now.  */
+                       
+                       if( ((budget->smask >> uFrame) << uFrame) !=
+                           budget->smask)
+                               return -1;
+               
+                       
+               }else{
+                       if(uFrame < earliest_uFrame){
+                               remaining_tt_bytes =
+                                       fs_bytes_per_uframe;
+                               remaining_tt_transactions =
+                                       endpoints_per_uframe;
+                               uFrame++;
+                               continue;
+                       }
+               }
+
+               if(!spanned_gap && budget->type == BUDGET_TYPE_QH){
+                       load = fs_bytes_per_uframe * (uFrame+1) -
+                               load_frame_bytes;
+                       
+                       if(load<1)load=1;
+                       spanned_gap=1;
+               }
+               
+               remaining_frame_bytes -= budget->tt_bytes;
+               remaining_tt_bytes -= budget->tt_bytes;
+               remaining_tt_transactions--;
+               
+               if(remaining_tt_transactions<0 || remaining_frame_bytes<0)
+                       return -1;
+               
+               while(remaining_tt_bytes <= 0){
+                       remaining_tt_bytes += fs_bytes_per_uframe;
+                       remaining_tt_transactions = endpoints_per_uframe;
+                       uFrame++;
+               }
+               
+               if(!spanned_gap){
+                       load_frame_bytes =
+                               fs_bytes_per_uframe * (uFrame+1) -
+                               remaining_tt_bytes;
+                       load = fs_bytes_per_fullframe -
+                               load_frame_bytes;
+               }
+               
+               if(budget != new) goto advance;
+
+               /* Generate smask/cmask for new entry */
+                                       
+               if(budget->type == BUDGET_TYPE_QH){
+                       smask = (0x01 << start_frame);
+                       /* cmask purposely overflows the frame by some
+                          amount if FSTN is needed for frame
+                          spanning */
+                       /* USB 2.0 11.18.4.3.b */
+                       cmask = (0x1c << start_frame);
+                       
+                       /* don't allow spanning yet */
+                       if(cmask&(~0xff))
+                               return -1;
+                       
+               }else{
+                       /* sitd */
+                       if(budget->owner.iso->bEndpointAddress & USB_DIR_IN){
+                               /* cmask purposely overflows the frame
+                                  by some amount if dummy SITD is
+                                  needed for frame spanning */
+                               smask = (0x01 << start_frame);
+                               cmask = ((1<<(uFrame-start_frame+3)) - 1) <<
+                                       (2 + start_frame);
+                       }else{
+                               /* ISO OUT */
+                               smask = ((1 << (uFrame-start_frame+1)) - 1) <<
+                                       start_frame;
+                               cmask = 0;
+                       }
+                       
+                       /* don't allow spanning yet */
+                       if(cmask&(~0xff))
+                               return -1;
+               
+               }
+               
+               /* FS/LS ssplit in uFrame 6 or 7 is illegal */
+               if(smask & 0xffc0)
+                       return -1;
+               
+               new->smask=smask;
+               new->cmask=cmask;
+
+       advance:
+               
+               if(budget == new)
+                       budget = insert;
+               else{
+                       budget = budget->next;
+                       if(budget == insert) budget = new;
+               }
+       }
+       
+       return (load * 100 / fs_bytes_per_fullframe);
+}
+
+/* _make_hs_smask - convenience function for generating a HS smask
+ *
+ * @period: trnsaction interval (in uFrames)
+ * @uFrame: intraframe offset
+ */
+static unsigned _make_hs_smask(int period, int uFrame)
+{
+       switch(period){
+       case 1:
+               return 0xff;
+       case 2:
+               return 0x55 << (uFrame & 0x1);
+       case 4:
+               return 0x11 << (uFrame & 0x3);
+       default:
+               return 0x01 << (uFrame & 0x7);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+/* Top-level shadow budget query and controlling logic */
+
+/* budget_add_endpoint - create a new shadow budget entry for a
+ * transaction of passed in type, owner and interval, and add it to
+ * the shadow budget (or return nonzero if the request is
+ * impossible,eg, no room in the bandwidth budget).
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @owner: pointer to transaction owner (ehci_qh or ehci_iso_stream)
+ * @type: BUDGET_TYPE_QH (intr) or BUDGET_TYPE_ITD (itd or sitd)
+ * @interval: endpoint interval (always in uFrames)
+ */
+static int budget_add_endpoint (struct ehci_hcd *ehci,
+                               void *owner,
+                               u8 type,
+                               int interval)
+{
+       int status = 0;
+       int frame,uFrame;
+       int best_choice = -1;
+       int best_metric = -1;
+       int period = (interval ?
+                     (interval > BUDGET_SLOTS*8 ? BUDGET_SLOTS*8 : interval) :
+                     1);
+       int period_8 = ( (period>>3) ? (period>>3) : 1); // always <=
+                                                        // _period_to_level
+       struct ehci_shadow_budget new, *new_p = NULL;
+       memset(&new,0,sizeof(new));
+       new.owner.ptr = owner;
+       new.type = type;
+       
+       switch (type){
+       case BUDGET_TYPE_ITD:
+       {
+               struct ehci_iso_stream *stream =
+                       (struct ehci_iso_stream *)owner;
+               new.s_usecs = stream->usecs;
+               new.c_usecs = stream->c_usecs;
+               new.tt_bytes = stream->tt_bytes;
+               if(sched_verbose){
+                       ehci_info(ehci, "Budgeting new [s]ITD: owner %p, "
+                                 "timing %u,%u,%u, interval %d\n",
+                                 owner,new.s_usecs,new.c_usecs,new.tt_bytes,
+                                 interval);
+               }                       
+       }
+       break;
+       case BUDGET_TYPE_QH:
+       {
+               struct ehci_qh *qh = (struct ehci_qh *)owner;
+               new.s_usecs = qh->usecs;
+               new.c_usecs = qh->c_usecs;
+               new.tt_bytes = qh->tt_bytes;
+               if(sched_verbose){
+                       ehci_info(ehci, "Budgeting new QH: owner %p, "
+                                 "timing %u,%u,%u, interval %d\n",
+                                 owner,new.s_usecs,new.c_usecs,new.tt_bytes,
+                                 interval);
+               }                       
+       }
+       break;
+       default:
+               status = -ENOSYS;
+               goto out;
+       }
+
+       if(sched_verbose){
+               if(new.tt_bytes)
+                       printk(KERN_INFO "  FS/LS strategy, Metrics:\n");
+               else
+                       printk(KERN_INFO "  HS strategy, Metrics:\n");
+       }
+       
+       /* determine best 'slot' */
+       for(uFrame = 0; uFrame < period; uFrame++){
+               int frame = (uFrame >> 3);
+               int min_metric = 100; /* percent */
+               
+               if(sched_verbose)       
+                       printk(KERN_INFO "  uFrame slot %d : ",uFrame);
+
+               /* scan entirety of slot */
+               for(; frame<BUDGET_SLOTS; frame+=period_8){
+                       struct ehci_shadow_budget **insert =
+                               budget_position_new(ehci,frame,&new);
+                       int hs_metric=0, fs_metric=0;
+                       
+                       if(new.tt_bytes){
+                               /* FS/LS endpoint; budget against FS
+                                * frame as the primary constraint */
+                               /* periodic_budget_fs_frame side
+                                * effect: fills in prospective
+                                * masks */
+                               fs_metric = budget_calc_fs_frame(
+                                       ehci, frame, uFrame, *insert, &new);
+                               hs_metric = budget_calc_hs_frame(
+                                       ehci, frame, insert, &new);
+
+                               if(fs_metric < min_metric)
+                                       min_metric = fs_metric;
+                               if(hs_metric < 0)
+                                       min_metric = -1;
+
+                       }else{
+                               new.smask = _make_hs_smask(period,uFrame);
+                               hs_metric = budget_calc_hs_frame(
+                                       ehci, frame, insert, &new);
+                               if(hs_metric < min_metric)
+                                       min_metric = hs_metric;
+                       }
+
+                       if(sched_verbose){
+                               printk(" %d:%d|%d",
+                                      frame, fs_metric,hs_metric);
+                       }
+                       
+                       
+                       /* If the c_mask 'overflowed', this indicates
+                          a frame wrap either FSTN or dummy sITD.
+                          Verify it will fit into the next frame's HS
+                          budget. */
+                       if(BUDGET_WRAP_P(&new)){
+                               int span_metric = budget_calc_hs_frame(
+                                       ehci, frame+1, insert, &new);
+                               if(span_metric < 0) min_metric = -1;
+                               if(sched_verbose)
+                                       printk("|%d",span_metric);
+
+                       }
+
+                       if(min_metric <= best_metric)
+                               break; // already no better than
+                                      // previous best; no reason to
+                                      // keep looking
+
+               }
+               if(sched_verbose)
+                       printk("\n");
+
+               if(min_metric>best_metric){
+                       best_metric = min_metric;
+                       best_choice = uFrame;
+               }
+               
+               if(best_metric == 100)
+                       break; // best possible result; no reason to
+                              // keep looking
+       }
+
+       if(sched_verbose)
+               ehci_info(ehci,"  Budgeting slot choice: %d\n",best_choice);
+
+       if(best_choice < 0){
+               status = -ENOSPC;
+               goto out;
+       }
+
+       /* All checks pass.  Add necessary budget placeholder[s] to
+          shadow budget */
+       uFrame = best_choice;
+       frame = (uFrame >> 3);
+       for(; frame<BUDGET_SLOTS; frame += period_8){
+               struct ehci_shadow_budget **insert = NULL;
+               
+               /* QH uses only one entry that's connected into the
+                  tree part of the budget.  ISO streams use one entry
+                  per slot, just like in the hardware budget. */
+               if(new_p == NULL || type != BUDGET_TYPE_QH)
+                       new_p = kmem_cache_zalloc(ehci->budget_pool,
+                                                 GFP_ATOMIC);
+               if(new_p == NULL){
+                       /* clean up; remove partially complete
+                        * budgeting and error out*/
+                       budget_unlink_entries_by_owner(ehci,owner);
+                       status = -ENOMEM;
+                       goto out;
+               }
+               memcpy(new_p,&new,sizeof(new));
+
+               /* reconstruct best budget masks and positioning
+                  (saves on storage not to save all the possibilities
+                  from above) */
+               insert = budget_position_new(ehci,frame,new_p);
+               if(*insert != new_p){
+                       if(new.tt_bytes){
+                               /* FS/LS */
+                               budget_calc_fs_frame(ehci, frame, uFrame,
+                                                    *insert, new_p);
+                       }else{
+                               /* HS */
+                               new_p->smask = _make_hs_smask(period,uFrame);
+                       }
+                       
+                       if(type == BUDGET_TYPE_QH)
+                               ((struct ehci_qh *)owner)->budget = new_p;
+                       
+                       /* link new entry */
+                       new_p->next = *insert;
+                       *insert = new_p;
+                       
+               }else
+                       ehci_err(ehci,"Should not have seen same QH "
+                                "while linking in budget tree\n");
+       }
+out:
+       if(sched_verbose){
+               ehci_info(ehci, "  Budgeting status: %d\n",
+                         status);
+               ehci_info(ehci, "  Budget after: \n");
+               print_budget(ehci,NULL,owner);
+       }
+
+       return status;
+}
+
+/* budget_schedule_next - Return the proper frame number and position
+ * in the shadow schedule of the next transaction belonging to owner
+ * in the shadow budget. If the transaction is already in the
+ * shadow/hard schedule, here->ptr will point to it.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @startframe: frame number in the shadow schedule at which to begin search
+ * @owner: pointer to transaction owner (ehci_qh or ehci_iso_stream)
+ * @b: returns pointer to matching shadow budget entry (NULL if none)
+ * @here: returns pointer to insertion position in shadow schedule
+ * @hw_p: returns pointer to insertion position in hardware schedule
+ */
+static int budget_schedule_next (struct ehci_hcd *ehci,
+                                int startframe,
+                                void *owner,
+                                struct ehci_shadow_budget **b,
+                                union ehci_shadow **here,
+                                __le32 **hw_p)
+{
+       int i;
+       for(i=startframe; i < startframe+BUDGET_SLOTS; i++){
+               int pframe = i & (ehci->periodic_size-1);
+
+               /* search for it in this frame's budget; we're only
+                  searching for sITD, ITD and QH.  Finding a spanning
+                  element reuses the discovered *b elsewhere */
+               *b = budget_find_entry_by_owner(ehci, i, owner);
+               if(*b){
+                       *here = periodic_translate_budget(ehci,pframe,*b,hw_p);
+                       if(*here){
+                               return i;
+                       }
+               }
+       }
+       
+       *here = NULL;
+       *b = NULL;
+       ehci_err(ehci,"tried to schedule an endpoint that doesn't "
+                "appear in the budget\n");
+       return -1;
+}
+
+/* budget_schedule_next - Return the number of the next frame for
+ * which there's a budgeted transaction for owner.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @startframe: frame number in the shadow schedule at which to begin search
+ * @owner: pointer to transaction owner (ehci_qh or ehci_iso_stream)
+ */
+static int budget_schedule_next_frame (struct ehci_hcd *ehci,
+                                      int startframe,
+                                      void *owner)
+{
+       int i;
+       for(i=startframe; i < startframe+BUDGET_SLOTS; i++){
+               struct ehci_shadow_budget *b;
+               int bframe = i & BUDGET_SLOT_MASK;
+               b = budget_find_entry_by_owner(ehci, bframe, owner);
+               if(b){
+                       return i;
+               }
+       }
+       return -1;
+}
+
+/* end of shadow budget implementation */
+
+/*-------------------------------------------------------------------------*/
+
 /* how many of the uframe's 125 usecs are allocated? */
 static unsigned short
 periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
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