diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 6a3db38..f806a20 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -28,14 +28,11 @@
 #include "usb-ehci.h"
 #include "monitor.h"
 
-#define EHCI_DEBUG   1
-#define TDEBUG       0
-#define DEBUG_PACKET 0
-#define STATE_DEBUG  0
-
-#if EHCI_DEBUG || TDEBUG || DEBUG_PACKET || STATE_DEBUG
-//#define DPRINTF printf
-#define DPRINTF timed_printf
+#define EHCI_DEBUG   0
+#define STATE_DEBUG  0       /* state transitions  */
+
+#if EHCI_DEBUG || STATE_DEBUG
+#define DPRINTF printf
 #else
 #define DPRINTF(...)
 #endif
@@ -46,16 +43,17 @@
 #define DPRINTF_ST(...)
 #endif
 
-#define ASSERT(x) { if (!(x)) { printf("Assertion failed in usb-echi.c line %d\n", __LINE__); exit(1); } }
+/* internal processing - reset HC to try and recover */
+#define USB_RET_PROCERR   (-99)
 
 #define MMIO_SIZE        0x1000
 
-#define CAPREGBASE       0x0000        // Capability Registers Base Address
-
-#define CAPLENGTH        CAPREGBASE + 0x0000
-#define HCIVERSION       CAPREGBASE + 0x0002
-#define HCSPARAMS        CAPREGBASE + 0x0004
-#define HCCPARAMS        CAPREGBASE + 0x0008
+/* Capability Registers Base Address - section 2.2 */
+#define CAPREGBASE       0x0000        
+#define CAPLENGTH        CAPREGBASE + 0x0000  // 1-byte, 0x0001 reserved
+#define HCIVERSION       CAPREGBASE + 0x0002  // 2-bytes, i/f version #
+#define HCSPARAMS        CAPREGBASE + 0x0004  // 4-bytes, structural params 
+#define HCCPARAMS        CAPREGBASE + 0x0008  // 4-bytes, capability params
 #define EECP             HCCPARAMS + 1
 #define HCSPPORTROUTE1   CAPREGBASE + 0x000c
 #define HCSPPORTROUTE2   CAPREGBASE + 0x0010
@@ -83,7 +81,7 @@
 #define USBSTS_PCD       (1 << 2)      // Port Change Detect
 #define USBSTS_FLR       (1 << 3)      // Frame List Rollover
 #define USBSTS_HSE       (1 << 4)      // Host System Error
-#define USBSTS_IAA       (1 << 5)      // Interrupt Async Advance
+#define USBSTS_IAA       (1 << 5)      // Interrupt on Async Advance
 #define USBSTS_HALT      (1 << 12)     // HC Halted
 #define USBSTS_REC       (1 << 13)     // Reclamation
 #define USBSTS_PSS       (1 << 14)     // Periodic Schedule Status
@@ -137,7 +135,7 @@
 //#define EHCI_NOMICROFRAMES
 
 #ifdef EHCI_NOMICROFRAMES
-#define FRAME_TIMER_FREQ 2000
+#define FRAME_TIMER_FREQ 1000
 #else
 #define FRAME_TIMER_FREQ 8000
 #endif
@@ -145,9 +143,9 @@
 
 #define NB_MAXINTRATE    8        // Max rate at which controller issues ints
 #define NB_PORTS         4        // Number of downstream ports
-#define BUFF_SIZE        20480    // Max bytes to transfer per transaction
-#define MAX_ITERATIONS   1000     // Max number of states before we abort
-#define MAX_QH           1000     // Max allowable queue heads in a chain
+#define BUFF_SIZE        5*4096   // Max bytes to transfer per transaction
+#define MAX_ITERATIONS   50       // Max number of states before we abort
+#define MAX_QH           100      // Max allowable queue heads in a chain
 
 /*  Internal periodic / asynchronous schedule state machine states
  */
@@ -159,8 +157,6 @@ typedef enum {
     /*  The following states are internal to the state machine function
     */
     EST_WAITLISTHEAD,
-    EST_DORELOAD,
-    EST_WAITSTARTEVENT,
     EST_FETCHENTRY,
     EST_FETCHQH,
     EST_FETCHITD,
@@ -171,17 +167,22 @@ typedef enum {
     EST_HORIZONTALQH
 } EHCI_STATES;
 
+/* macros for accessing fields within next link pointer entry */
+#define NLPTR_GET(x)             ((x) & 0xffffffe0)
+#define NLPTR_TYPE_GET(x)        (((x) >> 1) & 3)
+#define NLPTR_TBIT(x)            ((x) & 1)  // 1=invalid, 0=valid
+
+/* link pointer types */
+#define NLPTR_TYPE_ITD           0     // isoc xfer descriptor
+#define NLPTR_TYPE_QH            1     // queue head
+#define NLPTR_TYPE_STITD         2     // split xaction, isoc xfer descriptor
+#define NLPTR_TYPE_FSTN          3     // frame span traversal node
+
+
 /*  EHCI spec version 1.0 Section 3.3
  */
 typedef struct EHCIitd {
     uint32_t next;
-#define NLPTR_GET(x)             ((x) & 0xffffffe0)
-#define NLPTR_TYPE_GET(x)        (((x) >> 1) & 3)
-#define NLPTR_TYPE_ITD           0
-#define NLPTR_TYPE_QH            1
-#define NLPTR_TYPE_STITD         2
-#define NLPTR_TYPE_FSTN          3
-#define NLPTR_TBIT(x)            ((x) & 1)
 
     uint32_t transact[8];
 #define ITD_XACT_ACTIVE          (1 << 31)
@@ -201,8 +202,10 @@ typedef struct EHCIitd {
 #define ITD_BUFPTR_EP_MASK       0x00000f00
 #define ITD_BUFPTR_EP_SH         8
 #define ITD_BUFPTR_DEVADDR_MASK  0x0000007f
+#define ITD_BUFPTR_DEVADDR_SH    0
 #define ITD_BUFPTR_DIRECTION     (1 << 11)
 #define ITD_BUFPTR_MAXPKT_MASK   0x000007ff
+#define ITD_BUFPTR_MAXPKT_SH     0
 #define ITD_BUFPTR_MULT_MASK     0x00000003
 } EHCIitd;
 
@@ -241,11 +244,11 @@ typedef struct EHCIsitd {
 #define SITD_RESULTS_SPLITXSTATE      (1 << 1)
 
     uint32_t bufptr[2];
-#define BUFPTR_MASK                   0xfffff000
-#define BUFPTR_CURROFF_MASK           0x00000fff
-#define BUFPTR_TPOS_MASK              0x00000018
-#define BUFPTR_TPOS_SH                3
-#define BUFPTR_TCNT_MASK              0x00000007
+#define SITD_BUFPTR_MASK              0xfffff000
+#define SITD_BUFPTR_CURROFF_MASK      0x00000fff
+#define SITD_BUFPTR_TPOS_MASK         0x00000018
+#define SITD_BUFPTR_TPOS_SH           3
+#define SITD_BUFPTR_TCNT_MASK         0x00000007
 
     uint32_t backptr;                 // Standard next link pointer
 } EHCIsitd;
@@ -276,6 +279,7 @@ typedef struct EHCIqtd {
 #define QTD_TOKEN_PING                (1 << 0)
 
     uint32_t bufptr[5];               // Standard buffer pointer
+#define QTD_BUFPTR_MASK               0xfffff000
 } EHCIqtd;
 
 /*  EHCI spec version 1.0 Section 3.6
@@ -283,6 +287,7 @@ typedef struct EHCIqtd {
 typedef struct EHCIqh {
     uint32_t next;                    // Standard next link pointer
 
+    /* endpoint characteristics */
     uint32_t epchar;
 #define QH_EPCHAR_RL_MASK             0xf0000000
 #define QH_EPCHAR_RL_SH               28
@@ -293,11 +298,18 @@ typedef struct EHCIqh {
 #define QH_EPCHAR_DTC                 (1 << 14)
 #define QH_EPCHAR_EPS_MASK            0x00003000
 #define QH_EPCHAR_EPS_SH              12
+#define EHCI_QH_EPS_FULL              0
+#define EHCI_QH_EPS_LOW               1
+#define EHCI_QH_EPS_HIGH              2
+#define EHCI_QH_EPS_RESERVED          3
+
 #define QH_EPCHAR_EP_MASK             0x00000f00
 #define QH_EPCHAR_EP_SH               8
 #define QH_EPCHAR_I                   (1 << 7)
 #define QH_EPCHAR_DEVADDR_MASK        0x0000007f
+#define QH_EPCHAR_DEVADDR_SH          0
 
+    /* endpoint capabilities */
     uint32_t epcap;
 #define QH_EPCAP_MULT_MASK            0xc0000000
 #define QH_EPCAP_MULT_SH              30
@@ -308,10 +320,11 @@ typedef struct EHCIqh {
 #define QH_EPCAP_CMASK_MASK           0x0000ff00
 #define QH_EPCAP_CMASK_SH             8
 #define QH_EPCAP_SMASK_MASK           0x000000ff
+#define QH_EPCAP_SMASK_SH             0
 
-    uint32_t current;                 // Standard next link pointer
-    uint32_t qtdnext;                 // Standard next link pointer
-    uint32_t altnext;
+    uint32_t current_qtd;             // Standard next link pointer
+    uint32_t next_qtd;                // Standard next link pointer
+    uint32_t altnext_qtd;
 #define QH_ALTNEXT_NAKCNT_MASK        0x0000001e
 #define QH_ALTNEXT_NAKCNT_SH          1
 
@@ -365,16 +378,27 @@ typedef struct {
     int astate;                        // Current state in asynchronous schedule
     int pstate;                        // Current state in periodic schedule
     USBPort ports[NB_PORTS];
-    unsigned char buffer[BUFF_SIZE];
-    EHCIqh qh;
-    EHCIqtd qtd;
+    uint8_t buffer[BUFF_SIZE];
+
+    int more;
+
+    /* cached data from guest - needs to be flushed 
+     * when guest removes an entry (doorbell, handshake sequence)
+     */
+    EHCIqh qh;             // copy of current QH (being worked on)
+    uint32_t qhaddr;       // address QH read from
+
+    EHCIqtd qtd;           // copy of current QTD (being worked on)
+    uint32_t qtdaddr;      // address QTD read from
+
+    uint32_t itdaddr;      // current ITD
+
+    uint32_t fetch_addr;   // which address to look at next
+
     USBBus bus;
     USBPacket usb_packet;
     int async_port_in_progress;
     int async_complete;
-    uint32_t qhaddr;
-    uint32_t itdaddr;
-    uint32_t qtdaddr;
     uint32_t tbytes;
     int pid;
     int exec_status;
@@ -383,46 +407,22 @@ typedef struct {
     uint32_t frame_end_usec;
 } EHCIState;
 
-#define SET_LAST_RUN_CLOCK(s)  (s)->last_run_usec = qemu_get_clock(vm_clock) / 1000;
-
-static inline uint32_t get_field(uint32_t data, uint32_t mask, int shift)
-{
-    return((data & mask) >> shift);
-}
-
-static inline void set_field(uint32_t *data, uint32_t val,
-                              uint32_t mask, int shift)
-{
-    *data &= ~mask;
-    *data |=(val << shift);
-}
-
-#if EHCI_DEBUG
-static int timed_printf(const char *fmt, ...)
-{
-    int msec, usec;
-    static int usec_last;
-    va_list ap;
+#define SET_LAST_RUN_CLOCK(s) \
+    (s)->last_run_usec = qemu_get_clock(vm_clock) / 1000;
 
-    usec = qemu_get_clock(vm_clock) / 1000;
+/* nifty macros from Arnon's EHCI version  */
+#define get_field(data, field) \
+    (((data) & field##_MASK) >> field##_SH)
 
-    msec = usec - usec_last;
-    usec_last = usec;
-    usec = msec;
+#define set_field(data, newval, field) do { \
+    uint32_t val = *data; \
+    val &= ~ field##_MASK; \
+    val |= ((newval) << field##_SH) & field##_MASK; \
+    *data = val; \
+    } while(0)
 
-    msec /= 1000;
-    msec %= 1000;
-
-    usec %= 1000;
-
-    va_start(ap, fmt);
-    printf("%03d.%03d ", msec, usec);
-    vprintf(fmt, ap);
-    va_end(ap);
-
-    return 0;
-}
 
+#if EHCI_DEBUG
 static const char *addr2str(unsigned addr)
 {
     const char *r = "   unknown";
@@ -459,186 +459,22 @@ static const char *addr2str(unsigned addr)
         case FRINDEX:
             r = " FRAME IDX";
             break;
-    }
-
-    return r;
-}
-
-static void dump_ptr(const char *s, uint32_t ptr, int has_type)
-{
-    int t = NLPTR_TYPE_GET(ptr);
-    DPRINTF("%s%08X", s, NLPTR_GET(ptr));
-
-    if (has_type) {
-        DPRINTF("(PTR type is %s)",
-            t == NLPTR_TYPE_ITD ? "ITD" :
-           (t == NLPTR_TYPE_QH ? "QH" :
-           (t == NLPTR_TYPE_STITD ? "STITD" :
-           (t == NLPTR_TYPE_FSTN ? "FSTN" : "****"))));
-    }
-
-    DPRINTF("%s\n", NLPTR_TBIT(ptr) ? " TBIT set" : "");
-}
-#else
-static inline void dump_ptr(const char *s, uint32_t ptr, int has_type)
-{
-}
-#endif
-
-#if EHCI_DEBUG || DEBUG_PACKET
-static void dump_qtd(EHCIqtd *qtd, uint32_t qtdaddr)
-{
-    int pid;
-
-    pid =(qtd->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
-
-    printf("    QTD analysis      %08X\n"
-            "    === ========      ========\n", qtdaddr);
-
-    printf("    NakCnt:           %d\n",
-             (qtd->altnext & QH_ALTNEXT_NAKCNT_MASK) >> QH_ALTNEXT_NAKCNT_SH);
-    dump_ptr("    Next:             ", qtd->next, 0);
-    dump_ptr("    Alternate:        ", qtd->altnext, 0);
-    printf("    Data Toggle:      %s        ",
-              qtd->token & QTD_TOKEN_DTOGGLE ? "Yes " : "No  ");
-    printf("    Total Bytes:      %d\n",
-             (qtd->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH);
-    printf("    IOC:              %s        ",
-              qtd->token & QTD_TOKEN_IOC ? "Yes " : "No  ");
-    printf("    C_Page:           %d\n",
-             (qtd->token & QTD_TOKEN_CPAGE_MASK) >> QTD_TOKEN_CPAGE_SH);
-    printf("    CErr:             %-4d        ",
-             (qtd->token & QTD_TOKEN_CERR_MASK) >> QTD_TOKEN_CERR_SH);
-    printf("    PID code:         %s\n",
-              pid == 0 ? "OUT" :
-             (pid == 1 ? "IN" :
-             (pid == 2 ? "SETUP" : "****")));
-    printf("    Flags:            %s%s%s%s%s%s%s%s\n",
-              qtd->token & QTD_TOKEN_ACTIVE ? "ACTIVE " : "",
-              qtd->token & QTD_TOKEN_HALT ? "HALT " : "",
-              qtd->token & QTD_TOKEN_DBERR ? "DBERR " : "",
-              qtd->token & QTD_TOKEN_BABBLE ? "BABBLE " : "",
-              qtd->token & QTD_TOKEN_XACTERR ? "XACTERR " : "",
-              qtd->token & QTD_TOKEN_MISSEDUF ? "MISSEDUF " : "",
-              qtd->token & QTD_TOKEN_SPLITXSTATE ? "SPLITXSTATE " : "",
-              qtd->token & QTD_TOKEN_PING ? "PING " : "");
-    printf("    Current Offset    %d\n",
-              qtd->bufptr[0] & BUFPTR_CURROFF_MASK);
-    printf("    === ========      ========\n");
-}
-#endif
-#if EHCI_DEBUG
-static void dump_qh(EHCIqh *qh, uint32_t qhaddr)
-{
-    int speed =(qh->epchar & QH_EPCHAR_EPS_MASK) >> QH_EPCHAR_EPS_SH;
-
-    printf("QH analysis       %08X\n"
-            "== ========       ========\n", qhaddr);
-
-    dump_ptr("Horizontal:       ", qh->next, 1);
-    printf("Nak Count Reload: %d\n",
-           (qh->epchar & QH_EPCHAR_RL_MASK) >> QH_EPCHAR_RL_SH);
-    printf("Max Pkt Len:      %d\n",
-           (qh->epchar & QH_EPCHAR_MPLEN_MASK) >> QH_EPCHAR_MPLEN_SH);
-    printf("Control Endpoint: %s        ",
-           (qh->epchar & QH_EPCHAR_C) ? "Yes " : "No  ");
-    printf("H-bit:            %s\n",
-           (qh->epchar & QH_EPCHAR_H) ? "Yes " : "No  ");
-    printf("DTC:              %s        ",
-           (qh->epchar & QH_EPCHAR_DTC) ? "Yes " : "No  ");
-    printf("EndPoint Speed:   %s\n",
-            speed == 0 ? "Full" :
-           (speed == 1 ? "Low " :
-           (speed == 2 ? "High" : "****")));
-    printf("EndPoint:         %-4d        ",
-           (qh->epchar & QH_EPCHAR_EP_MASK) >> QH_EPCHAR_EP_SH);
-    printf("Inactive on next: %s\n",
-           (qh->epchar & QH_EPCHAR_I) ? "Yes" : "No");
-    printf("DevAddr:          %-4d        ",
-             qh->epchar & QH_EPCHAR_DEVADDR_MASK);
-    printf("Mult:             %-4d\n",
-           (qh->epcap & QH_EPCAP_MULT_MASK) >> QH_EPCAP_MULT_SH);
-    printf("PortNum:          %-4d        ",
-           (qh->epcap & QH_EPCAP_PORTNUM_MASK) >> QH_EPCAP_PORTNUM_SH);
-    printf("HubAddr:          %d\n",
-           (qh->epcap & QH_EPCAP_HUBADDR_MASK) >> QH_EPCAP_HUBADDR_SH);
-    printf("C-mask:           %-4d        ",
-           (qh->epcap & QH_EPCAP_CMASK_MASK) >> QH_EPCAP_CMASK_SH);
-    printf("S-mask:           %d\n",
-              qh->epcap & QH_EPCAP_SMASK_MASK);
-    dump_ptr("Current:          ", qh->current, 0);
-
-    dump_qtd((EHCIqtd *)&qh->qtdnext, qhaddr + 16);
-
-    printf("C-prog mask:      %d\n",
-              qh->bufptr[1] & BUFPTR_CPROGMASK_MASK);
-    printf("S-bytes:          %d\n",
-              qh->bufptr[2] & BUFPTR_FRAMETAG_MASK);
-    printf("FrameTag:         %d\n",
-             (qh->bufptr[2] & BUFPTR_SBYTES_MASK) >> BUFPTR_SBYTES_SH);
-    printf("== ========       ========\n");
-}
-#else
-static inline void dump_qh(EHCIqh *qh, uint32_t qhaddr)
-{
-}
-#endif
-
-#if DEBUG_PACKET
-
-static void dump_itd(EHCIitd *itd, uint32_t addr)
-{
-    int i;
-
-    printf("ITD analysis       %08X\n"
-            "=== ========       ========\n", addr);
-
-    dump_ptr("Horizontal:       ", itd->next, 1);
-
-    for(i = 0; i < 8; i++) {
-        printf("Trans Desc %d, len %5d, off %03X, page sel %d, ioc:%s ",
-                  i,
-                  get_field(itd->transact[i], ITD_XACT_LENGTH_MASK,
-                             ITD_XACT_LENGTH_SH),
-                  get_field(itd->transact[i], ITD_XACT_OFFSET_MASK, 0),
-                  get_field(itd->transact[i], ITD_XACT_PGSEL_MASK,
-                             ITD_XACT_PGSEL_SH),
-                  itd->transact[i] & ITD_XACT_IOC ? "Yes" : "No ");
-
-        if (itd->transact[i] & ITD_XACT_ACTIVE)
-            printf("ACTIVE ");
-
-        if (itd->transact[i] & ITD_XACT_DBERROR)
-            printf("DATAERR ");
-
-        if (itd->transact[i] & ITD_XACT_BABBLE)
-            printf("BABBLE ");
-
-        if (itd->transact[i] & ITD_XACT_XACTERR)
-            printf("XACTERR ");
+    
+        case PERIODICLISTBASE:
+            r = "P-LIST BASE";
+            break;
+    
+        case ASYNCLISTADDR:
+            r = "A-LIST ADDR";
+            break;
 
-        printf("\n");
+        case PORTSC_BEGIN ... PORTSC_END:
+            r = "PORT STATUS";
+            break;
     }
 
-    printf("Device:     %d\n",
-            get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR_MASK, 0));
-
-    printf("Endpoint:   %d\n",
-            get_field(itd->bufptr[0], ITD_BUFPTR_EP_MASK, ITD_BUFPTR_EP_SH));
-
-    printf("Direction:  %s\n",
-            itd->bufptr[1] & ITD_BUFPTR_DIRECTION ? "IN" : "OUT");
-
-    printf("Max Packet: %d\n",
-            get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT_MASK, 0));
-
-    printf("Mult:       %d\n",
-            get_field(itd->bufptr[2], ITD_BUFPTR_MULT_MASK, 0));
-
-    for(i = 0; i < 7; i++)
-        printf("Buf Ptr %d: %05X\n", i, itd->bufptr[i] >> 12);
+    return r;
 }
-
 #endif
 
 
@@ -653,9 +489,6 @@ static inline void ehci_set_interrupt(EHCIState *s, int intr)
     if ((s->usbsts & USBINTR_MASK) & s->usbintr)
         level = 1;
 
-    DPRINTF("ehci_set_interrupt: intr x%x, STS x%x, INTR x%x, level %d\n",
-            intr, s->usbsts & USBINTR_MASK, s->usbintr, level);
-
     qemu_set_irq(s->irq, level);
 }
 
@@ -701,6 +534,7 @@ static void ehci_attach(USBPort *port, USBDevice *dev)
     }
 }
 
+/* 4.1 host controller initialization */
 static void ehci_reset(void *opaque)
 {
     EHCIState *s = opaque;
@@ -735,8 +569,6 @@ static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
     uint32_t val;
 
     val = s->mmio[addr];
-    DPRINTF("ehci_mem_readb:  %s (addr 0x%08X), val 0x%02X\n",
-            addr2str((unsigned) addr), (unsigned) addr, val);
 
     return val;
 }
@@ -746,9 +578,7 @@ static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
     EHCIState *s = ptr;
     uint32_t val;
 
-    val = s->mmio[addr] |(s->mmio[addr+1] << 8);
-    DPRINTF("ehci_mem_readw:  %s (addr 0x%08X), val 0x%04X\n",
-            addr2str((unsigned) addr), (unsigned) addr, val);
+    val = s->mmio[addr] | (s->mmio[addr+1] << 8);
 
     return val;
 }
@@ -758,12 +588,8 @@ static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
     EHCIState *s = ptr;
     uint32_t val;
 
-    val = s->mmio[addr] |(s->mmio[addr+1] << 8) |
-          (s->mmio[addr+2] << 16) |(s->mmio[addr+3] << 24);
-
-    if (addr != USBSTS)
-    DPRINTF("ehci_mem_readl:  %s (addr 0x%08X), val 0x%08X\n",
-            addr2str((unsigned) addr), (unsigned) addr, val);
+    val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
+          (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
 
     return val;
 }
@@ -833,6 +659,9 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
 {
     EHCIState *s = ptr;
     int i;
+#if EHCI_DEBUG
+    const char *str;
+#endif
 
     /* Only aligned reads are allowed on OHCI */
     if (addr & 3) {
@@ -846,14 +675,25 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
         return;
     }
 
-    /* Do any register specific pre-write processing here.  */
+    if (addr < OPREGBASE) {
+        fprintf(stderr, "usb-ehci: write attempt to read-only register"
+            TARGET_FMT_plx "\n", addr);
+        return;
+    }
+
 
+    /* Do any register specific pre-write processing here.  */
+#if EHCI_DEBUG
+    str = addr2str((unsigned) addr);
+#endif
     switch(addr)
     {
     case USBCMD:
-        DPRINTF("ehci_mem_writel: USBCMD val=0x%08X\n", val);
+        DPRINTF("ehci_mem_writel: USBCMD val=0x%08X, current cmd=0x%08X\n",
+                val, s->usbcmd);
+
         if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
-            DPRINTF("                        run, clear halt\n");
+            DPRINTF("ehci_mem_writel: %s run, clear halt\n", str);
             qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
             SET_LAST_RUN_CLOCK(s);
             s->usbsts &= ~USBSTS_HALT;
@@ -867,41 +707,90 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
         }
 
         if (val & USBCMD_HCRESET) {
-            DPRINTF("                        resetting ...\n");
+            DPRINTF("ehci_mem_writel: %s run, resetting\n", str);
             ehci_reset(s);
-            DPRINTF("                        reset done, clear reset request bit\n");
             val &= ~USBCMD_HCRESET;
         }
 
+        /* not supporting dynamic frame list size at the moment */
+        if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
+            fprintf(stderr, "attempt to set frame list size -- value %d\n",
+                    val & USBCMD_FLS);
+            val &= ~USBCMD_FLS;
+        }
+#if EHCI_DEBUG
+        if ((val & USBCMD_PSE) && !(s->usbcmd & USBCMD_PSE)) {
+            DPRINTF("periodic scheduling enabled\n");
+        }
+        if (!(val & USBCMD_PSE) && (s->usbcmd & USBCMD_PSE)) {
+            DPRINTF("periodic scheduling disabled\n");
+        }
+        if ((val & USBCMD_ASE) && !(s->usbcmd & USBCMD_ASE)) {
+            DPRINTF("asynchronous scheduling enabled\n");
+        }
+        if (!(val & USBCMD_ASE) && (s->usbcmd & USBCMD_ASE)) {
+            DPRINTF("asynchronous scheduling disabled\n");
+        }
+        if ((val & USBCMD_IAAD) && !(s->usbcmd & USBCMD_IAAD)) {
+            DPRINTF("doorbell request received\n");
+        }
+        if ((val & USBCMD_LHCR) && !(s->usbcmd & USBCMD_LHCR)) {
+            DPRINTF("light host controller reset received\n");
+        }
+        if ((val & USBCMD_ITC) != (s->usbcmd & USBCMD_ITC)) {
+            DPRINTF("interrupt threshold control set to %x\n",
+                    (val & USBCMD_ITC)>>USBCMD_ITC_SH);
+        }
+#endif
         break;
 
+
     case USBSTS:
         val &= USBSTS_RO_MASK;              // bits 6 thru 31 are RO
-        DPRINTF("mem_writel : USBSTS RWC set to 0x%08X\n", val);
+        DPRINTF("ehci_mem_writel: %s RWC set to 0x%08X\n", str, val);
+
+        val = (s->usbsts &= ~val);         // bits 0 thru 5 are R/WC
 
-        val =(s->usbsts &= ~val);         // bits 0 thru 5 are R/WC
-        DPRINTF("mem_writel : USBSTS updating interrupt condition\n");
+        DPRINTF("ehci_mem_writel: %s updating interrupt condition\n", str);
         ehci_set_interrupt(s, 0);
         break;
 
+
     case USBINTR:
         val &= USBINTR_MASK;
-        DPRINTF("ehci_mem_writel: USBINTR set to 0x%08X\n", val);
+        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         break;
 
     case FRINDEX:
         s->sofv = val >> 3;
-        DPRINTF("ehci_mem_writel: FRAME index set to 0x%08X\n",(unsigned) addr, val);
+        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         break;
 
     case CONFIGFLAG:
-        DPRINTF("ehci_mem_writel: CONFIGFLAG set to 0x%08X\n",(unsigned) addr, val);
+        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
         val &= 0x1;
         if (val) {
             for(i = 0; i < NB_PORTS; i++)
                 s->portsc[i] &= ~PORTSC_POWNER;
         }
+        break;
 
+    case PERIODICLISTBASE:
+        if (val & USBCMD_PSE) {
+            fprintf(stderr, "Guest OS should not be setting the periodic"
+                   " list base register while periodic schedule is enabled\n");
+            return;
+        }
+        DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
+        break;
+
+    case ASYNCLISTADDR:
+        if (val & USBCMD_ASE) {
+            fprintf(stderr, "Guest OS should not be setting the async list"
+                   " address register while async schedule is enabled\n");
+            return;
+        }
+        DPRINTF("ehci_mem_writel: A-LIST ADDR set to 0x%08X\n", val);
         break;
     }
 
@@ -939,38 +828,44 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
 
 // 4.10.2
 
-static void ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
+static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
 {
     int i;
     int dtoggle;
     int ping;
+    int eps;
+    int reload;
+
+    if (ehci->qtdaddr < 0x1000) {
+        fprintf(stderr, "invalid address for qTD. resetting\n");
+        return USB_RET_PROCERR;
+    }
 
     // remember values in fields to preserve in qh after overlay
 
     dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
-    ping = qh->token & QTD_TOKEN_PING;
+    ping    = qh->token & QTD_TOKEN_PING;
 
-    DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current,
+    DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current_qtd,
             ehci->qtdaddr);
-    qh->current  = ehci->qtdaddr;
-    qh->qtdnext  = qtd->next;
-    qh->altnext  = qtd->altnext;
-    qh->token    = qtd->token;
-
-    if (qh->current < 0x1000) {
-#if DEBUG_PACKET
-        dump_qh(qh, qh->current);
-#endif
-        ASSERT(1==2);
-    }
+    qh->current_qtd = ehci->qtdaddr;
+    qh->next_qtd    = qtd->next;
+    qh->altnext_qtd = qtd->altnext;
+    qh->token       = qtd->token;
 
-    if (((qh->epchar & QH_EPCHAR_EPS_MASK) >> QH_EPCHAR_EPS_SH) == 2) {
+
+    eps = get_field(qh->epchar, QH_EPCHAR_EPS);
+    if (eps == EHCI_QH_EPS_HIGH) {
         qh->token &= ~QTD_TOKEN_PING;
         qh->token |= ping;
     }
 
-    for (i = 0; i < 5; i++)
+    reload = get_field(qh->epchar, QH_EPCHAR_RL);
+    set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+
+    for (i = 0; i < 5; i++) {
         qh->bufptr[i] = qtd->bufptr[i];
+    }
 
     if (!(qh->epchar & QH_EPCHAR_DTC)) {
         // preserve QH DT bit
@@ -981,80 +876,102 @@ static void ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
     qh->bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
     qh->bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
 
-    // TODO NakCnt
+    put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+
+    return 0;
 }
 
-static void ehci_buffer_rw(EHCIState *ehci, EHCIqh *qh, int bytes, int rw)
+static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
 {
     int bufpos = 0;
-    int cpage;
+    int cpage, offset;
     uint32_t head;
     uint32_t tail;
 
-    cpage = get_field(qh->token, QTD_TOKEN_CPAGE_MASK, QTD_TOKEN_CPAGE_SH);
-    ASSERT(cpage == 0);
-
-    DPRINTF("exec: %sing %d bytes to/from %08x\n",
-           rw ? "writ" : "read", bytes, qh->bufptr[0]);
 
     if (!bytes)
-        return;
+        return 0;
+
+    cpage = get_field(qh->token, QTD_TOKEN_CPAGE);
+    if (cpage > 4) {
+        fprintf(stderr, "cpage out of range (%d)\n", cpage);
+        return USB_RET_PROCERR;
+    }
+
+    offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
+    DPRINTF("ehci_buffer_rw: %sing %d bytes %08x cpage %d offset\n",
+           rw ? "writ" : "read", bytes, qh->bufptr[0], cpage, offset);
 
     do {
-        head = qh->bufptr[cpage];
-        tail =(qh->bufptr[cpage] & 0xfffff000) + 0x1000;
+        /* start and end of this page */
+        head = qh->bufptr[cpage] & QTD_BUFPTR_MASK;
+        tail = head + ~QTD_BUFPTR_MASK + 1;
+        /* add offset into page */
+        head |= offset;
 
-        if (bytes <=(tail - head))
+        if (bytes <= (tail - head)) {
             tail = head + bytes;
+        }
 
         DPRINTF("DATA %s cpage:%d head:%08X tail:%08X target:%08X\n",
                 rw ? "WRITE" : "READ ", cpage, head, tail, bufpos);
 
-        ASSERT(bufpos + tail - head <= BUFF_SIZE);
-        ASSERT(tail - head > 0);
-
-        cpu_physical_memory_rw(qh->bufptr[cpage], &ehci->buffer[bufpos],
-                                tail - head, rw);
-
-        bufpos +=(tail - head);
-        bytes -=(tail - head);
+        cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
 
-        qh->bufptr[cpage] +=(tail - head);
+        bufpos += (tail - head);
+        bytes -= (tail - head);
 
-        if (bytes > 0)
+        if (bytes > 0) {
             cpage++;
+            offset = 0;
+        }
     } while (bytes > 0);
 
-    set_field(&qh->token, cpage, QTD_TOKEN_CPAGE_MASK, QTD_TOKEN_CPAGE_SH);
+    /* save cpage */
+    set_field(&qh->token, cpage, QTD_TOKEN_CPAGE);
+
+    /* save offset into cpage */
+    offset = tail - head;
+    qh->bufptr[0] &= ~QTD_BUFPTR_MASK;
+    qh->bufptr[0] |= offset;
+
+    return 0;
 }
 
 static void ehci_async_complete_packet(USBPacket *packet, void *opaque)
 {
     EHCIState *ehci = opaque;
-#if DEBUG_PACKET
+
     DPRINTF("Async packet complete\n");
-#endif
     ehci->async_complete = 1;
     ehci->exec_status = packet->len;
 }
 
-#if TDEBUG
-static int transactid;
-#endif
-
 static int ehci_execute_complete(EHCIState *ehci,
                                   EHCIqh *qh,
                                   int ret)
 {
+    int i, c_err, reload;
+
     if (ret == USB_RET_ASYNC && !ehci->async_complete) {
         DPRINTF("not done yet\n");
         return ret;
     }
 
     ehci->async_complete = 0;
+    i = ehci->async_port_in_progress;
     ehci->async_port_in_progress = -1;
 
+    DPRINTF("execute_complete: qhaddr 0x%x, qtdaddr 0x%x, status %d\n",
+           ehci->qhaddr, ehci->qtdaddr, ret);
+
     if (ret < 0) {
+err:
+        /* TO-DO: put this is in a function that can be invoked below as well */
+        c_err = get_field(qh->token, QTD_TOKEN_CERR);
+        c_err--;
+        set_field(&qh->token, c_err, QTD_TOKEN_CERR);
+
         switch(ret) {
         case USB_RET_NODEV:
             fprintf(stderr, "USB no device\n");
@@ -1064,154 +981,135 @@ static int ehci_execute_complete(EHCIState *ehci,
             qh->token |= QTD_TOKEN_HALT;
             break;
         case USB_RET_NAK:
-            DPRINTF("USBTRAN RSP NAK, returning without clear active\n");
+            reload = get_field(qh->epchar, QH_EPCHAR_RL);
+            if ((ehci->pid == USB_TOKEN_IN) && reload) {
+                int nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+                nakcnt--;
+                set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+            }
             return USB_RET_NAK;
             break;
         case USB_RET_BABBLE:
             fprintf(stderr, "USB babble TODO\n");
-            ASSERT(ret >= 0);
+            qh->token |= QTD_TOKEN_BABBLE;
             break;
         default:
             fprintf(stderr, "USB invalid response %d to handle\n", ret);
-            ASSERT(ret >= 0);
+            /* TO-DO: transaction error */
+            ret = USB_RET_PROCERR;
             break;
         }
     } else {
-        // if (ret < maxpkt)
-        // {
-        //     DPRINTF("Short packet condition\n");
-        //     // TODO check 4.12 for splits
-         // }
+        // DPRINTF("Short packet condition\n");
+        // TODO check 4.12 for splits
+
+        /* see if a follow-up rquest is needed - request for
+         * 20k yet OS only allows 16k requests at a time
+         */
+        if ((ret > 0) && (ehci->tbytes > 16384) && !ehci->more) {
+        /* TO-DO: put this in a function for use here and by execute */
+        USBPort *port = &ehci->ports[i];
+        USBDevice *dev = port->dev;
+
+        ehci->more = ret;
+
+        ehci->usb_packet.pid = ehci->pid;
+        ehci->usb_packet.devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
+        ehci->usb_packet.devep = get_field(qh->epchar, QH_EPCHAR_EP);
+        ehci->usb_packet.data = ehci->buffer + ret;
+        /* linux devio.c limits max to 16k */
+        ehci->usb_packet.len = ehci->tbytes - ret;
+        ehci->usb_packet.complete_cb = ehci_async_complete_packet;
+        ehci->usb_packet.complete_opaque = ehci;
+
+        ret = dev->info->handle_packet(dev, &ehci->usb_packet);
+
+        DPRINTF("submit followup: qh %x qtd %x pid %x len %d ret %d\n",
+                ehci->qhaddr, ehci->qtdaddr, ehci->pid,
+                ehci->usb_packet.len, ret);
+
+        if (ret == USB_RET_ASYNC) {
+            ehci->async_port_in_progress = i;
+            ehci->async_complete = 0;
+            return ret;
+        }
+        if (ret < 0) {
+            goto err;
+        }
+        }
+
+        ret += ehci->more;
+
+        if (ret > ehci->tbytes) {
+            ret = USB_RET_BABBLE;
+            goto err;
+        }
 
         if (ehci->tbytes && ehci->pid == USB_TOKEN_IN) {
-            ASSERT(ret > 0);
-            ehci_buffer_rw(ehci, qh, ret, 1);
-#if TDEBUG
-            printf("Data after execution:\n");
-            // dump_data(ehci->buffer, ehci->tbytes < 64 ? ehci->tbytes : 64);
-            // decode_data(ehci->pid, ehci->buffer, ret);
-#endif
+            if (ehci_buffer_rw(ehci->buffer, qh, ret, 1) != 0) {
+                return USB_RET_PROCERR;
+            }
             ehci->tbytes -= ret;
-        } else
+        } else {
             ehci->tbytes = 0;
+        }
 
-        ASSERT(ehci->tbytes >= 0);
-
-        set_field(&qh->token, ehci->tbytes,
-                   QTD_TOKEN_TBYTES_MASK, QTD_TOKEN_TBYTES_SH);
+        DPRINTF("updating tbytes to %d\n", ehci->tbytes);
+        set_field(&qh->token, ehci->tbytes, QTD_TOKEN_TBYTES);
     }
 
     qh->token ^= QTD_TOKEN_DTOGGLE;
     qh->token &= ~QTD_TOKEN_ACTIVE;
 
-    if (qh->token & QTD_TOKEN_IOC) {
+    if ((ret >= 0) && (qh->token & QTD_TOKEN_IOC)) {
         // TODO should do this after writeback to memory
         ehci_set_interrupt(ehci, USBSTS_INT);
     }
-#if DEBUG_PACKET
-    DPRINTF("QH after execute:-\n");
-    dump_qh(qh, NLPTR_GET(ehci->qhaddr));
-#endif
 
-#if TDEBUG
-    DPRINTF("USBTRAN RSP %3d                          return:(%5d) ",
-            transactid,
-            ret);
-
-    if (ehci->pid == USB_TOKEN_IN) {
-        DPRINTF("[%02X %02X %02X %02X ...]\n",
-            *ehci->buffer, *(ehci->buffer+1),
-            *(ehci->buffer+2), *(ehci->buffer+3));
-    }
-    else
-        DPRINTF("\n");
-#endif
     return ret;
 }
 
 // 4.10.3
 
-static int ehci_execute(EHCIState *ehci,
-                          uint32_t qhaddr,
-                          EHCIqh *qh)
+static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
 {
     USBPort *port;
     USBDevice *dev;
-    int smask;
-    int maxpkt;
     int ret;
     int i;
     int endp;
     int devadr;
 
-    smask = QH_EPCAP_SMASK_MASK & qh->epcap;
-    ehci->tbytes =(qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
-    ehci->pid =(qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
-    maxpkt = get_field(qh->epchar, QH_EPCHAR_MPLEN_MASK, QH_EPCHAR_MPLEN_SH);
-    endp = get_field(qh->epchar, QH_EPCHAR_EP_MASK, QH_EPCHAR_EP_SH);
-    devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR_MASK, 0);
-
     if ( !(qh->token & QTD_TOKEN_ACTIVE)) {
         fprintf(stderr, "Attempting to execute inactive QH\n");
-        exit(1);;
+        return USB_RET_PROCERR;
     }
 
-    if (smask) {
-        DPRINTF("active interrupt transfer frindex %d for dev %d EP %d\n",
-                ehci->frindex, devadr, endp);
-        // TODO are interrupt always IN ?
-        ehci->pid = USB_TOKEN_IN;
-    } else {
-        DPRINTF("Active non-interrupt QH, executing\n");
-
-        DPRINTF("pid is %2X\n", ehci->pid);
+    ehci->tbytes = (qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+    if (ehci->tbytes > BUFF_SIZE) {
+        fprintf(stderr, "Request for more bytes than allowed\n");
+        return USB_RET_PROCERR;
+    }
 
-        switch(ehci->pid) {
+    ehci->pid = (qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+    switch(ehci->pid) {
         case 0: ehci->pid = USB_TOKEN_OUT; break;
         case 1: ehci->pid = USB_TOKEN_IN; break;
         case 2: ehci->pid = USB_TOKEN_SETUP; break;
         default: fprintf(stderr, "bad token\n"); break;
-        }
     }
 
-    // TODO set reclam
-
-#if DEBUG_PACKET
-    DPRINTF("QH before execute:-\n");
-    dump_qh(qh, NLPTR_GET(qhaddr));
-#endif
-
-    if (ehci->tbytes && ehci->pid != USB_TOKEN_IN) {
-        ehci_buffer_rw(ehci, qh, ehci->tbytes, 0);
-#if TDEBUG
-        DPRINTF("Data before execution:\n");
-        // dump_data(ehci->buffer, ehci->tbytes < 64 ? ehci->tbytes : 64);
-        // decode_data(ehci->pid, ehci->buffer, ehci->tbytes);
-#endif
+    if ((ehci->tbytes && ehci->pid != USB_TOKEN_IN) &&
+        (ehci_buffer_rw(ehci->buffer, qh, ehci->tbytes, 0) != 0)) {
+        return USB_RET_PROCERR;
     }
 
-#if TDEBUG
-    DPRINTF("\nUSBTRAN REQ %3d dev:%d ep:%d pid:%02X %s bytes:(%5d) ",
-            ++transactid,
-            devadr,
-            endp,
-            ehci->pid,
-           (ehci->pid == USB_TOKEN_SETUP ? "(SETUP)" :
-           (ehci->pid == USB_TOKEN_IN ? "(IN)   " :
-           (ehci->pid == USB_TOKEN_OUT ? "(OUT)  " : "(*****)"))),
-            ehci->tbytes);
-
-    if (ehci->pid != USB_TOKEN_IN) {
-        DPRINTF("[%02X %02X %02X %02X ...]\n",
-            *ehci->buffer, *(ehci->buffer+1),
-            *(ehci->buffer+2), *(ehci->buffer+3));
-    }
-    else
-        DPRINTF("\n");
-#endif
+    endp = get_field(qh->epchar, QH_EPCHAR_EP);
+    devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
 
     ret = USB_RET_NODEV;
 
+    // TO-DO: associating device with ehci port
     for(i = 0; i < NB_PORTS; i++) {
         port = &ehci->ports[i];
         dev = port->dev;
@@ -1228,23 +1126,28 @@ static int ehci_execute(EHCIState *ehci,
         ehci->usb_packet.devaddr = devadr;
         ehci->usb_packet.devep = endp;
         ehci->usb_packet.data = ehci->buffer;
-        ehci->usb_packet.len = ehci->tbytes;
+        /* linux devio.c limits max to 16k */
+        if (ehci->tbytes > 16384) {
+            ehci->usb_packet.len = 16384;
+        } else {
+            ehci->usb_packet.len = ehci->tbytes;
+        }
         ehci->usb_packet.complete_cb = ehci_async_complete_packet;
         ehci->usb_packet.complete_opaque = ehci;
 
-        DPRINTF("calling dev->info->handle_packet\n");
         ret = dev->info->handle_packet(dev, &ehci->usb_packet);
 
+        DPRINTF("submit: qh %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+                ehci->qhaddr, ehci->qtdaddr, ehci->pid,
+                ehci->usb_packet.len, ehci->tbytes, endp, ret);
+
         if (ret != USB_RET_NODEV)
             break;
     }
 
-    DPRINTF("exit loop dev->info->handle_packet\n");
-
-    if (ret > BUFF_SIZE || ehci->tbytes > BUFF_SIZE) {
-        fprintf(stderr, "bogus QH byte count\n");
-        dump_qh(qh, NLPTR_GET(qhaddr));
-        ASSERT(ret <= BUFF_SIZE && ehci->tbytes <= BUFF_SIZE);
+    if (ret > BUFF_SIZE) {
+        fprintf(stderr, "ret from handle packet > BUFF_SIZE\n");
+        return USB_RET_PROCERR;
     }
 
     if (ret == USB_RET_ASYNC) {
@@ -1258,7 +1161,7 @@ static int ehci_execute(EHCIState *ehci,
 /*  4.7.2
  */
 
-static void ehci_process_itd(EHCIState *ehci,
+static int ehci_process_itd(EHCIState *ehci,
                              EHCIitd *itd)
 {
     USBPort *port;
@@ -1275,11 +1178,9 @@ static void ehci_process_itd(EHCIState *ehci,
     int maxpkt;
 
     dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
-    devadr = get_field(itd->bufptr[0],
-                        ITD_BUFPTR_DEVADDR_MASK, 0);
-    endp = get_field(itd->bufptr[0],
-                      ITD_BUFPTR_EP_MASK, ITD_BUFPTR_EP_SH);
-    maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT_MASK, 0);
+    devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+    endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
+    maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
 
 #ifdef EHCI_NOMICROFRAMES
     for(i = 0; i < 8; i++) {
@@ -1291,14 +1192,14 @@ static void ehci_process_itd(EHCIState *ehci,
         DPRINTF("ISOCHRONOUS active for frame %d, interval %d\n",
                 ehci->frindex >> 3, i);
 
-        pg = get_field(itd->transact[i], ITD_XACT_PGSEL_MASK,
-                        ITD_XACT_PGSEL_SH);
-        ptr =(itd->bufptr[pg] & ITD_BUFPTR_MASK) |
-             (itd->transact[i] & ITD_XACT_OFFSET_MASK);
-        len = get_field(itd->transact[i], ITD_XACT_LENGTH_MASK,
-                         ITD_XACT_LENGTH_SH);
+        pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
+        ptr = (itd->bufptr[pg] & ITD_BUFPTR_MASK) |
+                  (itd->transact[i] & ITD_XACT_OFFSET_MASK);
+        len = get_field(itd->transact[i], ITD_XACT_LENGTH);
 
-        ASSERT(len <= BUFF_SIZE);
+        if (len > BUFF_SIZE) {
+            return USB_RET_PROCERR;
+        }
 
         DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
 
@@ -1346,13 +1247,13 @@ static void ehci_process_itd(EHCIState *ehci,
             if (ehci->isoch_pause > 0) {
                 DPRINTF("ISOCH: received a NAK but paused so returning\n");
                 ehci->isoch_pause--;
-                return;
+                return 0;
             } else if (ehci->isoch_pause == -1) {
                 DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n");
                 // Pause frindex for up to 50 msec waiting for data from
                 // remote
                 ehci->isoch_pause = 50;
-                return;
+                return 0;
             } else {
                 DPRINTF("ISOCH: isoch pause timeout! return 0\n");
                 ret = 0;
@@ -1377,10 +1278,7 @@ static void ehci_process_itd(EHCIState *ehci,
             if (ret != len) {
                 DPRINTF("ISOCH IN expected %d, got %d\n",
                         len, ret);
-                set_field(&itd->transact[i],
-                           ret,
-                           ITD_XACT_LENGTH_MASK,
-                           ITD_XACT_LENGTH_SH);
+                set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
             }
         }
     }
@@ -1388,405 +1286,505 @@ static void ehci_process_itd(EHCIState *ehci,
 #ifdef EHCI_NOMICROFRAMES
     }
 #endif
+    return 0;
 }
 
-/* This is the state machine that is common to both async and periodic */
-
-static int ehci_advance_state(EHCIState *ehci,
-                                int async,
-                                int state,
-                                uint32_t entry)
+/*  This state is the entry point for asynchronous schedule
+ *  processing.  Entry here consitutes a EHCI start event state (4.8.5)
+ */
+static int ehci_state_waitlisthead(EHCIState *ehci,  int async, int *state)
 {
     EHCIqh *qh = &ehci->qh;
-    EHCIqtd *qtd = &ehci->qtd;
-    EHCIitd itd;
+    int i = 0;
     int again = 0;
-    int loopcount = 0;
-    int transactCtr;
-    int smask;
-    int reload;
-    int nakcnt;
+    uint32_t entry = ehci->asynclistaddr;
 
-    do {
-        DPRINTF_ST("advance_state: again=%d\n", again);
-        again = 0;
-        // ASSERT(loopcount++ < MAX_ITERATIONS);
+    /* set reclamation flag at start event (4.8.6) */
+    if (async) {
+        ehci->usbsts |= USBSTS_REC;
+    }
 
-        switch(state) {
-        /*  This state is the entry point for asynchronous schedule
-         *  processing.  Entry here consitutes a EHCI start event state(4.8.5)
-         */
-        case EST_WAITLISTHEAD:
-            DPRINTF_ST("WAITLISTHEAD\n");
+    /*  Find the head of the list (4.9.1.1) */
+    for(i = 0; i < MAX_QH; i++) {
+        get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
 
+        if (qh->epchar & QH_EPCHAR_H) {
+            DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
+                       entry);
             if (async)
-                ehci->usbsts |= USBSTS_REC;
+                entry |= (NLPTR_TYPE_QH << 1);
 
-            /*  Find the head of the list
-             */
+            ehci->fetch_addr = entry;
+            *state = EST_FETCHENTRY;
+            again = 1;
+            goto out;
+        }
 
-            for(loopcount = 0; loopcount < MAX_QH; loopcount++) {
-                get_dwords(NLPTR_GET(entry),(uint32_t *) qh,
-                            sizeof(EHCIqh) >> 2);
+        DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
+                   entry);
+        entry = qh->next;
+        if (entry == ehci->asynclistaddr) {
+            DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
+            break;
+        }
+    }
 
-                if (qh->epchar & QH_EPCHAR_H) {
-                    DPRINTF_ST("QH %08X is the HEAD of the list\n", entry);
-                    break;
-                }
+    /* no head found for list. */
 
-                DPRINTF_ST("QH %08X is NOT the HEAD of the list\n", entry);
-                entry = qh->next;
-            }
+    *state = EST_ACTIVE;
 
-            entry |=(NLPTR_TYPE_QH << 1);
-            ASSERT(loopcount < MAX_QH);
-            loopcount = 0;
+out:
+    return again;
+}
 
-            state = EST_FETCHENTRY;
-            again = 1;
-            break;
 
-        /*  This state is the entry point for periodic schedule
-         *  processing as well as being a continuation state for async
-         *  processing.
-         */
-        case EST_FETCHENTRY:
-            DPRINTF_ST("FETCHENTRY\n");
-
-            if (qemu_get_clock(vm_clock) / 1000 > ehci->frame_end_usec) {
-                if (async) {
-                    DPRINTF_ST("FRAME timer elapsed, exit state machine\n");
-                    state = EST_ACTIVE;
-                    break;
-                } else
-                    DPRINTF("WARNING - frame timer elapsed during periodic\n");
-            }
+/*  This state is the entry point for periodic schedule processing as 
+ *  well as being a continuation state for async processing.
+ */
+static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+{
+    int again = 0;
+    uint32_t entry = ehci->fetch_addr;
 
-            if (NLPTR_TBIT(entry)) {
-                state = EST_ACTIVE;
-                break;
-            }
+#if 0
+    if (qemu_get_clock(vm_clock) / 1000 > ehci->frame_end_usec) {
+        if (async) {
+/* TO-DO: supposed to be saving the horizontal QH and picking up
+ *        from there on next frame
+ */
+            printf("FETCHENTRY: FRAME timer elapsed, exit state machine\n");
+            *state = EST_ACTIVE;
+            goto out;
+        } else {
+            DPRINTF("FETCHENTRY: WARNING "
+                    "- frame timer elapsed during periodic\n");
+        }
+    }
+#endif
 
-            if (NLPTR_TYPE_GET(entry) == NLPTR_TYPE_QH) {
-                state = EST_FETCHQH;
-                ehci->qhaddr = entry;
-                again = 1;
-                break;
-            }
+    /* section 4.8, only QH in async schedule */
+    if (async && (NLPTR_TYPE_GET(entry) != NLPTR_TYPE_QH)) {
+        fprintf(stderr, "non queue head request in async schedule\n");
+        return -1;
+    }
 
-            if (NLPTR_TYPE_GET(entry) == NLPTR_TYPE_ITD) {
-                state = EST_FETCHITD;
-                ehci->itdaddr = entry;
-                again = 1;
-                break;
-            }
+    switch (NLPTR_TYPE_GET(entry)) {
+    case NLPTR_TYPE_QH:
+        DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", *entry);
+        *state = EST_FETCHQH;
+        ehci->qhaddr = entry;
+        again = 1;
+        break;
 
-            // TODO handle types other than QH
-            ASSERT(NLPTR_TYPE_GET(entry) == NLPTR_TYPE_QH);
-            break;
+    case NLPTR_TYPE_ITD:
+        DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", *entry);
+        *state = EST_FETCHITD;
+        ehci->itdaddr = entry;
+        again = 1;
+        break;
 
-        case EST_FETCHQH:
-            get_dwords(NLPTR_GET(ehci->qhaddr),(uint32_t *) qh, 
-                       sizeof(EHCIqh) >> 2);
-            DPRINTF_ST("FETCHQH: Fetched QH at address %08X "
-                    "(next is %08X, h-bit is %d)\n",
-                    ehci->qhaddr, qh->next, qh->epchar & QH_EPCHAR_H);
-
-#if DEBUG_PACKET
-            dump_qh(qh, NLPTR_GET(ehci->qhaddr));
-#endif
+    default:
+        // TODO: handle siTD and FSTN types
+        fprintf(stderr, "FETCHENTRY: entry at %X is of type %d "
+                "which is not supported yet\n", entry, NLPTR_TYPE_GET(entry));
+        return -1;
+    }
 
-            if (async) {
-                /*  EHCI spec version 1.0 Section 4.8.3
-                 */
-                if (qh->epchar & QH_EPCHAR_H) {
-                    DPRINTF_ST("h-bit set\n");
-
-                    if (!(ehci->usbsts & USBSTS_REC)) {
-                        DPRINTF_ST("h-bit and !reclam, done\n");
-                        state = EST_ACTIVE;
-                        break;
-                    }
-                }
-                /*  EHCI spec version 1.0 Section 4.10.1
-                 */
-                if ( !(qh->epcap & QH_EPCAP_SMASK_MASK)) {
-                    DPRINTF_ST("not intr, clear reclam\n");
-                    ehci->usbsts &= ~USBSTS_REC;
-                }
-            } else {
-                DPRINTF_ST("exec: qh check, frindex is %d,%d\n",
-                         (ehci->frindex >> 3),(ehci->frindex & 7));
-            }
+    return again;
+}
 
-            reload = get_field(qh->epchar, QH_EPCHAR_RL_MASK, QH_EPCHAR_RL_SH);
+static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+{
+    EHCIqh *qh = &ehci->qh;
+    int reload;
+    int again = 0;
 
-            if (reload) {
-                DPRINTF_ST("reloading nakcnt to %d\n",
-                        reload);
-                set_field(&qh->altnext, reload, QH_ALTNEXT_NAKCNT_MASK,
-                           QH_ALTNEXT_NAKCNT_SH);
-            }
+    get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
 
-            if (qh->token & QTD_TOKEN_ACTIVE) {
-                if ((qh->token & QTD_TOKEN_HALT)) {
-                    fprintf(stderr, "Active, Halt, ** ILLEGAL **\n");
-                    state = EST_ACTIVE;
-                } else {
-                    DPRINTF_ST("Active, !Halt, execute - fetchqtd\n");
-                    ehci->qtdaddr = qh->current;
-                    state = EST_FETCHQTD;
-                    again = 1;
-                }
-            } else {
-                if (qh->token & QTD_TOKEN_HALT) {
-                    DPRINTF_ST("!Active, Halt, go horiz\n");
-                    state = EST_HORIZONTALQH;
-                    again = 1;
-                } else {
-                    /*  EHCI spec version 1.0 Section 4.10.2
-                     */
-                    DPRINTF_ST("!Active, !Halt, adv q\n");
-                    state = EST_ADVANCEQUEUE;
-                    again = 1;
-                }
-            }
+    if (async && (qh->epchar & QH_EPCHAR_H)) {
 
-            break;
+        /*  EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
+        if (ehci->usbsts & USBSTS_REC) {
+            ehci->usbsts &= ~USBSTS_REC;
+        } else {
+            DPRINTF("FETCHQH:  QH 0x%08x. H-bit set, reclamation status reset"
+                       " - done processing\n", ehci->qhaddr);
+            *state = EST_ACTIVE;
+            goto out;
+        }
+    }
 
-        case EST_FETCHITD:
-            get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
-                        sizeof(EHCIitd) >> 2);
-            DPRINTF_ST("FETCHITD: Fetched ITD at address %08X "
-                    "(next is %08X)\n",
-                    ehci->itdaddr, itd.next);
-
-#if DEBUG_PACKET
-            dump_itd(&itd, NLPTR_GET(ehci->itdaddr));
+#if 0
+    if (ehci->qhaddr != qh->next) {
+    DPRINTF("FETCHQH:  QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
+               ehci->qhaddr, 
+               qh->epchar & QH_EPCHAR_H,
+               qh->token & QTD_TOKEN_HALT,
+               qh->token & QTD_TOKEN_ACTIVE,
+               qh->next);
+    }
 #endif
 
-            ehci_process_itd(ehci, &itd);
-#if DEBUG_PACKET
-            dump_itd(&itd, NLPTR_GET(ehci->itdaddr));
-#endif
-            put_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
-                        sizeof(EHCIitd) >> 2);
-            entry = itd.next;
-            state = EST_FETCHENTRY;
-            again = 1;
-            break;
+    reload = get_field(qh->epchar, QH_EPCHAR_RL);
+    if (reload) {
+        DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
+        set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+    }
 
-        case EST_ADVANCEQUEUE:
-            DPRINTF_ST("ADVANCEQUEUE\n");
-            if ((qh->token & QTD_TOKEN_TBYTES_MASK) != 0 &&
-                NLPTR_TBIT(qh->altnext) == 0) {
-                ehci->qtdaddr = qh->altnext;
-                DPRINTF_ST("tbytes!=0 and tbit = 0, go with altnext\n");
-            } else {
-                if (NLPTR_TBIT(qh->qtdnext)) {
-                    state = EST_HORIZONTALQH;
-                    again = 1;
-                    break;
-                }
+    if (qh->token & QTD_TOKEN_HALT) {
+        DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
+        *state = EST_HORIZONTALQH;
+        again = 1;
 
-                ehci->qtdaddr = qh->qtdnext;
-            }
-            state = EST_FETCHQTD;
-            again = 1;
-            break;
+    } else if (qh->token & QTD_TOKEN_ACTIVE) {
+        DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
+        ehci->qtdaddr = qh->current_qtd;
+        *state = EST_FETCHQTD;
+        again = 1;
 
-        case EST_FETCHQTD:
-            DPRINTF_ST("FETCHQTD: Fetching QTD at address %08X\n", ehci->qtdaddr);
-            get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd,
-                        sizeof(EHCIqtd) >> 2);
+    } else {
+        /*  EHCI spec version 1.0 Section 4.10.2 */
+        DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
+        *state = EST_ADVANCEQUEUE;
+        again = 1;
+    }
 
-            if (qtd->token & QTD_TOKEN_ACTIVE) {
-                state = EST_EXECUTE;
-                again = 1;
-                break;
-            } else {
-                DPRINTF_ST("abort advance, not active\n");
-                state = EST_HORIZONTALQH;
-                again = 1;
-                break;
-            }
+out:
+    return again;
+}
 
-            break;
+static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+{
+    EHCIitd itd;
 
-        case EST_HORIZONTALQH:
-            entry = qh->next;
-            state = EST_FETCHENTRY;
-            again = 1;
-            break;
+    get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
+               sizeof(EHCIitd) >> 2);
+    DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
+               ehci->itdaddr, itd.next);
 
-        case EST_EXECUTE:
-            if (async) {
-                DPRINTF("\n\n>>>>> ASYNC STATE MACHINE execute\n");
-            } else {
-                DPRINTF("\n\n>>>>> PERIODIC STATE MACHINE execute\n");
-            }
+    if (ehci_process_itd(ehci, &itd) != 0)
+        return -1;
 
-#if DEBUG_PACKET
-            dump_qh(qh, NLPTR_GET(ehci->qhaddr));
-            dump_qtd(qtd, NLPTR_GET(ehci->qtdaddr));
+    put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
+                sizeof(EHCIitd) >> 2);
+    ehci->itdaddr = itd.next;
+    *state = EST_FETCHITD;
+
+    return 1;
+}
+
+/* Section 4.10.2 - paragraph 3 */
+static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+{
+#if 0
+    /* TO-DO: 4.10.2 - paragraph 2
+     * if I-bit is set to 1 and QH is not active
+     * go to horizontal QH
+     */
+    if (I-bit set) {
+        *state = EST_HORIZONTALQH;
+        goto out;
+    }
 #endif
 
-            smask = QH_EPCAP_SMASK_MASK & qh->epcap;
+    /* 
+     * want data and alt-next qTD is valid
+     */
+    if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+        (NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
+        DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
+                   "curr 0x%08x next 0x%08x alt 0x%08x\n",
+                   ehci->qh.current_qtd, ehci->qh.altnext_qtd,
+                   ehci->qh.next_qtd);
+        ehci->qtdaddr = ehci->qh.altnext_qtd;
+        *state = EST_FETCHQTD;
+
+    /*
+     *  next qTD is valid
+     */
+    } else if (NLPTR_TBIT(ehci->qh.next_qtd) == 0) {
+        DPRINTF_ST("ADVQUEUE: next qTD. curr 0x%08x next 0x%08x alt 0x%08x\n",
+                   ehci->qh.current_qtd, ehci->qh.altnext_qtd, 
+                   ehci->qh.next_qtd);
+        ehci->qtdaddr = ehci->qh.next_qtd;
+        *state = EST_FETCHQTD;
 
+    /*
+     *  no valid qTD, try next QH
+     */
+    } else {
+        DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
+        *state = EST_HORIZONTALQH;
+    }
+
+    return 1;
+}
+
+/* Section 4.10.2 - paragraph 4 */
+static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+{
+    EHCIqtd *qtd = &ehci->qtd;
+    int again = 0;
+
+    get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+
+    if (qtd->token & QTD_TOKEN_ACTIVE) {
+        *state = EST_EXECUTE;
+        again = 1;
+    } else {
+        *state = EST_HORIZONTALQH;
+        again = 1;
+    }
+
+    return again;
+}
+
+static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+{
+    ehci->fetch_addr = ehci->qh.next;
+    *state = EST_FETCHENTRY;
+
+    return 1;
+}
+
+static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+{
+    EHCIqh *qh = &ehci->qh;
+    EHCIqtd *qtd = &ehci->qtd;
+    int again = 0;
+    int reload, nakcnt;
+    int smask;
+
+    if (async) {
+        DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
+                  ehci->qhaddr, ehci->qtdaddr);
+    } else {
+        DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
+    }
+
+    if (ehci_qh_do_overlay(ehci, qh, qtd) != 0)
+        return -1;
+
+    smask = get_field(qh->epcap, QH_EPCAP_SMASK);
 #ifndef EHCI_NOMICROFRAMES
-            if (smask &&(smask &(1 <<(ehci->frindex & 7))) == 0) {
-                DPRINTF("PERIODIC active not interval: "
-                        "mask is %d, "
-                        "frindex is %d,%d\n",
-                        smask,
-                        (ehci->frindex >> 3),(ehci->frindex & 7));
-
-                state = EST_HORIZONTALQH;
-                again = 1;
-                break;
-            }
+    if (smask && (smask & (1 << (ehci->frindex & 7))) == 0) {
+        DPRINTF_ST("PERIODIC active not interval: mask %x, frindex %d,%d\n",
+                   smask, (ehci->frindex >> 3),(ehci->frindex & 7));
+
+        *state = EST_HORIZONTALQH;
+        again = 1;
+        goto out;
+    }
 #endif
 
-            if (smask) {
-                DPRINTF("PERIODIC active !!! "
-                        "mask is %d, "
-                        "frindex is %d,%d\n",
-                        smask,
-                        (ehci->frindex >> 3),(ehci->frindex & 7));
-            }
+    if (!smask) {
+        reload = get_field(qh->epchar, QH_EPCHAR_RL);
+        nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+        if (reload && !nakcnt) {
+            DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
+            *state = EST_HORIZONTALQH;
+            again = 1;
+            goto out;
+        }
+    }
 
-            reload = get_field(qh->epchar, QH_EPCHAR_RL_MASK, QH_EPCHAR_RL_SH);
-            nakcnt = get_field(qh->altnext, QH_ALTNEXT_NAKCNT_MASK, 
-                               QH_ALTNEXT_NAKCNT_SH);
-            if (reload && !nakcnt) {
-                DPRINTF("RL != 0 but NakCnt == 0, no execute\n");
-                state = EST_HORIZONTALQH;
-                again = 1;
-                break;
-            }
+    // TODO verify enough time remains in the uframe as in 4.4.1.1
 
-            transactCtr = get_field(qh->epcap,
-                                     QH_EPCAP_MULT_MASK, QH_EPCAP_MULT_SH);
+    // TODO write back ptr to async list when done or out of time
 
-            // TODO verify enough time remains in the uframe as in 4.4.1.1
+    // TODO Windows does not seem to ever set the MULT field
 
-            // TODO write back ptr to async list when done or out of time
 
-            // TODO Windows does not seem to ever set the MULT field
+    if (!async)
+    {
+        int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+        if (!transactCtr) {
+            DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
+            *state = EST_HORIZONTALQH;
+            again = 1;
+            goto out;
+        }
+    }
 
-#if 0
-            if (!transactCtr &&(qh->epcap & QH_EPCAP_SMASK_MASK) > 0)
-            {
-                DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
-                *state = EST_HORIZONTALQH;
-                again = 1;
-                break;
-            }
-#endif
 
-            if (!transactCtr) {
-                transactCtr = 1; // TODO - check at what level do we repeat
+    if (async)
+        ehci->usbsts |= USBSTS_REC;
+    ehci->more = 0;
+    ehci->exec_status = ehci_execute(ehci, qh);
+    if (ehci->exec_status == USB_RET_PROCERR) {
+        again = -1;
+        goto out;
+    }
+    *state = EST_EXECUTING;
+
+    if (ehci->exec_status != USB_RET_ASYNC)
+        again = 1;
 
-                if (qh->epcap & QH_EPCAP_SMASK_MASK)
-                    DPRINTF("WARN - ZERO transactctr force to 1 for intr\n");
+out:
+    return again;
+}
+
+static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+{
+    EHCIqh *qh = &ehci->qh;
+    int again = 0;
+    int reload, nakcnt;
+
+    ehci->exec_status = ehci_execute_complete(ehci, qh, ehci->exec_status);
+    if (ehci->exec_status == USB_RET_ASYNC) {
+        goto out;
+    }
+    if (ehci->exec_status == USB_RET_PROCERR) {
+        again = -1;
+        goto out;
+    }
+
+    // 4.10.3
+    if (!async) {
+        int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+        transactCtr--;
+        set_field(&qh->epcap, transactCtr, QH_EPCAP_MULT);
+        // 4.10.3, bottom of page 82, should exit this state when transaction
+        // counter decrements to 0
+    }
+
+
+    reload = get_field(qh->epchar, QH_EPCHAR_RL);
+    if (reload) {
+        nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+        if (ehci->exec_status == USB_RET_NAK) {
+            if (nakcnt) {
+                nakcnt--;
             }
+            DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
+                    nakcnt);
+        } else {
+            nakcnt = reload;
+            DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
+                       nakcnt);
+        }
+        set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+    }
 
-            DPRINTF("exec: ctr is %d\n", transactCtr);
-            DPRINTF("exec: frindex is %d,%d\n",
-                   (ehci->frindex >> 3),(ehci->frindex & 7));
+    /*
+     *  Write the qh back to guest physical memory.  This step isn't
+     *  in the EHCI spec but we need to do it since we don't share
+     *  physical memory with our guest VM.
+     */
 
-            ehci_qh_do_overlay(ehci, qh, qtd);
-            ehci->exec_status = ehci_execute(ehci, ehci->qhaddr, qh);
-            state = EST_EXECUTING;
+    DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
+              ehci->qhaddr, qh->next);
+    put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
 
-            if (ehci->exec_status != USB_RET_ASYNC)
-                again = 1;
+    /* 4.10.5 */
+    if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
+        *state = EST_HORIZONTALQH;
+    } else {
+        *state = EST_WRITEBACK;
+    }
 
-            break;
+    again = 1;
 
-        case EST_EXECUTING:
-            DPRINTF("Enter EXECUTING\n");
-            ehci->exec_status = ehci_execute_complete(ehci, qh,
-                                                       ehci->exec_status);
+out:
+    return again;
+}
 
-            if (ehci->exec_status == USB_RET_ASYNC)
-                break;
 
-            DPRINTF("finishing exec\n");
-            transactCtr = get_field(qh->epcap,
-                                     QH_EPCAP_MULT_MASK, QH_EPCAP_MULT_SH);
+static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+{
+    EHCIqh *qh = &ehci->qh;
+    int again = 0;
 
-            if (transactCtr)
-                transactCtr--;
+    /*  Write back the QTD from the QH area */
+    DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
+    put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
+                sizeof(EHCIqtd) >> 2);
 
-            set_field(&qh->epcap, transactCtr,
-                       QH_EPCAP_MULT_MASK, QH_EPCAP_MULT_SH);
+    /* TODO confirm next state.  For now, keep going if async
+     * but stop after one qtd if periodic
+     */
+    //if (async) {
+        *state = EST_ADVANCEQUEUE;
+        again = 1;
+    //} else {
+    //    *state = EST_ACTIVE;
+    //}
+    return again;
+}
 
-            reload = get_field(qh->epchar, QH_EPCHAR_RL_MASK, QH_EPCHAR_RL_SH);
-            nakcnt = get_field(qh->altnext, QH_ALTNEXT_NAKCNT_MASK,
-                               QH_ALTNEXT_NAKCNT_SH);
+/* 
+ * This is the state machine that is common to both async and periodic 
+ */
 
-            if (reload != 0) {
-                if (ehci->exec_status == USB_RET_NAK) {
-                    nakcnt--;
+static int ehci_advance_state(EHCIState *ehci,
+                                int async,
+                                int state)
+{
+    int again;
+    int iter = 0;
 
-                    DPRINTF("Nak occured and RL != 0, dec NakCnt to %d\n",
-                            nakcnt);
-                } else {
-                    nakcnt = reload;
+    do {
+        iter++;
+        if (iter > MAX_ITERATIONS) {
+            DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n\n"); 
+            state = EST_ACTIVE;
+            break;
+        }
+        switch(state) {
+        case EST_WAITLISTHEAD:
+            again = ehci_state_waitlisthead(ehci, async, &state);
+            break;
 
-                    DPRINTF("Nak didn't occur, reloading to %d\n",
-                            nakcnt);
-                }
+        case EST_FETCHENTRY:
+            again = ehci_state_fetchentry(ehci, async, &state);
+            break;
 
-                set_field(&qh->altnext, nakcnt, QH_ALTNEXT_NAKCNT_MASK,
-                           QH_ALTNEXT_NAKCNT_SH);
-            }
+        case EST_FETCHQH:
+            again = ehci_state_fetchqh(ehci, async, &state);
+            break;
 
-            /*
-             *  Write the qh back to guest physical memory.  This step isn't
-             *  in the EHCI spec but we need to do it since we don't share
-             *  physical memory with our guest VM.
-             */
+        case EST_FETCHITD:
+            again = ehci_state_fetchitd(ehci, async, &state);
+            break;
 
-            DPRINTF("write QH to VM memory\n");
-#if DEBUG_PACKET
-            dump_qh(qh, NLPTR_GET(ehci->qhaddr));
-#endif
-            put_dwords(NLPTR_GET(ehci->qhaddr),(uint32_t *) qh,
-                        sizeof(EHCIqh) >> 2);
+        case EST_ADVANCEQUEUE:
+            again = ehci_state_advqueue(ehci, async, &state);
+            break;
 
-            // 4.10.5
+        case EST_FETCHQTD:
+            again = ehci_state_fetchqtd(ehci, async, &state);
+            break;
 
-            if (qh->token & QTD_TOKEN_ACTIVE)
-                state = EST_HORIZONTALQH;
-            else
-                state = EST_WRITEBACK;
+        case EST_HORIZONTALQH:
+            again = ehci_state_horizqh(ehci, async, &state);
+            break;
 
-            again = 1;
+        case EST_EXECUTE:
+            iter = 0;
+            again = ehci_state_execute(ehci, async, &state);
+            break;
+
+        case EST_EXECUTING:
+            iter = 0;
+            again = ehci_state_executing(ehci, async, &state);
             break;
 
         case EST_WRITEBACK:
-            /*  Write back the QTD from the QH area */
-            DPRINTF_ST("write QTD to VM memory\n");
-            put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->qtdnext,
-                        sizeof(EHCIqtd) >> 2);
-            /* TODO confirm next state.  For now, keep going if async
-             * but stop after one qtd if periodic
-             */
-            // if (async)
-            // {
-                state = EST_FETCHQH;
-                again = 1;
-            // }
-            // else
-           //          state = EST_ACTIVE;
+            iter = 0;
+            again = ehci_state_writeback(ehci, async, &state);
             break;
 
         default:
             fprintf(stderr, "Bad state!\n");
+            again = -1;
             break;
-            }
+        }
+
+        if (again < 0) {
+            fprintf(stderr, "processing error - resetting ehci HC\n");
+            ehci_reset(ehci);
+            again = 0;
+        }
     }
     while (again);
 
@@ -1795,47 +1793,58 @@ static int ehci_advance_state(EHCIState *ehci,
 
 static void ehci_advance_async_state(EHCIState *ehci)
 {
+    EHCIqh qh;
+
     switch(ehci->astate) {
     case EST_INACTIVE:
-        if (ehci->usbcmd & USBCMD_ASE) {
-            DPRINTF("ASYNC going active\n");
-            ehci->usbsts |= USBSTS_ASS;
-            ehci->astate = EST_ACTIVE;
-            // No break, fall through to ACTIVE
-        } else
+        if (!(ehci->usbcmd & USBCMD_ASE)) {
             break;
+        }
+        ehci->usbsts |= USBSTS_ASS;
+        ehci->astate = EST_ACTIVE;
+        // No break, fall through to ACTIVE
 
     case EST_ACTIVE:
         if ( !(ehci->usbcmd & USBCMD_ASE)) {
-            DPRINTF("ASYNC going inactive\n");
             ehci->usbsts &= ~USBSTS_ASS;
             ehci->astate = EST_INACTIVE;
             break;
         }
 
-        DPRINTF_ST("\n    ===   ===   ===   ===   ===   ===\n\n");
+        /* If the doorbell is set, the guest wants to make a change to the
+         * schedule. The host controller needs to release cached data.
+         * (section 4.8.2)
+         */
         if (ehci->usbcmd & USBCMD_IAAD) {
-            /*  Async advance doorbell interrupted requested
-             */
+            DPRINTF("ASYNC: doorbell request acknowledged\n");
             ehci->usbcmd &= ~USBCMD_IAAD;
             ehci_set_interrupt(ehci, USBSTS_IAA);
+            break;
         }
 
-        ehci->astate = ehci_advance_state(ehci, 1,
-                                           EST_WAITLISTHEAD,
-                                           ehci->asynclistaddr);
+        /* make sure guest has acknowledged */
+        /* TO-DO: is this really needed? */
+        if (ehci->usbsts & USBSTS_IAA) {
+            DPRINTF("IAA status bit still set.\n");
+            break;
+        }
+
+        DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
+                ehci->asynclistaddr);
+        ehci->astate = ehci_advance_state(ehci, 1, EST_WAITLISTHEAD);
         break;
 
     case EST_EXECUTING:
-        DPRINTF("async state adv for executing\n");
-        ehci->astate = ehci_advance_state(ehci, 1,
-                                           EST_EXECUTING, ehci->qhaddr);
+        get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
+                   sizeof(EHCIqh) >> 2);
+        ehci->astate = ehci_advance_state(ehci, 1, EST_EXECUTING);
         break;
 
     default:
-        fprintf(stderr, "Bad asynchronous state %d\n",
-                ehci->astate);
-        ASSERT(1==2);
+        /* this should only be due to a developer mistake */
+        fprintf(stderr, "ehci: Bad asynchronous state %d. "
+                "Resetting to active\n", ehci->astate);
+        ehci->astate = EST_ACTIVE;
     }
 }
 
@@ -1848,7 +1857,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
 
     switch(ehci->pstate) {
     case EST_INACTIVE:
-        if ( !(ehci->frindex & 7) &&(ehci->usbcmd & USBCMD_PSE)) {
+        if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
             DPRINTF("PERIODIC going active\n");
             ehci->usbsts |= USBSTS_PSS;
             ehci->pstate = EST_ACTIVE;
@@ -1865,27 +1874,27 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
         }
 
         list = ehci->periodiclistbase & 0xfffff000;
-        list |=((ehci->frindex & 0x1ff8) >> 1);
+        list |= ((ehci->frindex & 0x1ff8) >> 1);
 
-        cpu_physical_memory_rw(list,(uint8_t *) &entry, sizeof entry, 0);
+        cpu_physical_memory_rw(list, (uint8_t *) &entry, sizeof entry, 0);
         entry = le32_to_cpu(entry);
 
-        DPRINTF("periodic state adv fr=%d.  [%08X] -> %08X\n",
+        DPRINTF("PERIODIC state adv fr=%d.  [%08X] -> %08X\n",
                 ehci->frindex / 8, list, entry);
-        ehci->pstate = ehci_advance_state(ehci, 0,
-                                           EST_FETCHENTRY, entry);
+        ehci->fetch_addr = entry;
+        ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
         break;
 
     case EST_EXECUTING:
-        DPRINTF("periodic state adv for executing\n");
-        ehci->pstate = ehci_advance_state(ehci, 0,
-                                           EST_EXECUTING, ehci->qhaddr);
+        DPRINTF("PERIODIC state adv for executing\n");
+        ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
         break;
 
     default:
-        fprintf(stderr, "Bad periodic state %d\n",
-                ehci->pstate);
-        ASSERT(1==2);
+        /* this should only be due to a developer mistake */
+        fprintf(stderr, "ehci: Bad periodic state %d. "
+                "Resetting to active\n", ehci->pstate);
+        ehci->pstate = EST_ACTIVE;
     }
 }
 
@@ -1910,11 +1919,6 @@ static void ehci_frame_timer(void *opaque)
     frames = usec_elapsed / FRAME_TIMER_USEC;
     ehci->frame_end_usec = usec_now + FRAME_TIMER_USEC;
 
-#if TDEBUG
-    DPRINTF("Frame timer, usec elapsed since last %d, frames %d\n",
-            usec_elapsed, frames);
-#endif
-
     for(i = 0; i < frames; i++) {
         if ( !(ehci->usbsts & USBSTS_HALT)) {
             if (ehci->isoch_pause <= 0) {
@@ -1927,13 +1931,10 @@ static void ehci_frame_timer(void *opaque)
 
             if (ehci->frindex > 0x00001fff) {
                 ehci->frindex = 0;
-#if TDEBUG
-                DPRINTF("PERIODIC frindex rollover\n");
-#endif
                 ehci_set_interrupt(ehci, USBSTS_FLR);
             }
 
-            ehci->sofv =(ehci->frindex - 1) >> 3;
+            ehci->sofv = (ehci->frindex - 1) >> 3;
             ehci->sofv &= 0x000003ff;
         }
 
@@ -1961,11 +1962,6 @@ static void ehci_frame_timer(void *opaque)
         ehci_advance_async_state(ehci);
 
     qemu_mod_timer(ehci->frame_timer, expire_time);
-
-#if TDEBUG
-    usec_elapsed = qemu_get_clock(vm_clock) / 1000 - usec_now;
-    DPRINTF("TIMING: frame_timer used %d usec\n", usec_elapsed);
-#endif
 }
 
 static CPUReadMemoryFunc *ehci_readfn[3]={
@@ -2021,8 +2017,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
     //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
 
     pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); // interrupt pin 3
-    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0); // MaxLat
-    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0); // MinGnt
+    pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+    pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
 
     // pci_conf[0x50] = 0x01; // power management caps
 
@@ -2043,17 +2039,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
     pci_conf[0x6e] = 0x00;
     pci_conf[0x6f] = 0xc0;  // USBLEFCTLSTS
 
-    // 2.2.2 host controller interface version
-    pci_set_byte(&s->mmio[CAPLENGTH], OPREGBASE);
-    pci_set_word(&s->mmio[HCIVERSION], 0x0100);
-
-    // 2.2.3 host controller structural parameters
-    pci_set_word(&s->mmio[HCSPARAMS], NB_PORTS);
-
-    // 2.2.4 host controller capability parameters
-    // - 0x80 = can cache whole frame, not 64-bit capable
-    pci_set_word(&s->mmio[HCCPARAMS], 0x00000080);
-
+    // 2.2 host controller interface version
+    s->mmio[0x00] = (uint8_t) OPREGBASE;
+    s->mmio[0x01] = 0x00;
+    s->mmio[0x02] = 0x00;
+    s->mmio[0x03] = 0x01;        // HC version
+    s->mmio[0x04] = NB_PORTS;    // Number of downstream ports
+    s->mmio[0x05] = 0x00;        // No companion ports at present
+    s->mmio[0x06] = 0x00;
+    s->mmio[0x07] = 0x00;
+    s->mmio[0x08] = 0x80;        // We can cache whole frame, not 64-bit capable
+    s->mmio[0x09] = 0x68;        // EECP
+    s->mmio[0x0a] = 0x00;
+    s->mmio[0x0b] = 0x00;
 
     s->irq = s->dev.irq[3];
 
@@ -2075,7 +2073,6 @@ static int usb_ehci_initfn(PCIDevice *dev)
 
     s->frame_timer = qemu_new_timer(vm_clock, ehci_frame_timer, s);
 
-    DPRINTF("ehci_init: calling ehci_reset\n");
     qemu_register_reset(ehci_reset, s);
 
     s->mem = cpu_register_io_memory(ehci_readfn, ehci_writefn, s);
