Selaa lähdekoodia

Fix handling control transfer

kkitayam 4 vuotta sitten
vanhempi
sitoutus
cdab869472
1 muutettua tiedostoa jossa 90 lisäystä ja 45 poistoa
  1. 90 45
      src/portable/nxp/khci/hcd_khci.c

+ 90 - 45
src/portable/nxp/khci/hcd_khci.c

@@ -88,10 +88,9 @@ typedef struct TU_ATTR_PACKED
   union {
   union {
     uint32_t state;
     uint32_t state;
     struct {
     struct {
-      uint32_t max_packet_size :11;
-      uint32_t                 : 5;
-      uint32_t odd             : 1;
-      uint32_t                 :15;
+      uint32_t pipenum:16;
+      uint32_t odd    : 1;
+      uint32_t        : 0;
     };
     };
   };
   };
   uint16_t length;
   uint16_t length;
@@ -125,6 +124,7 @@ typedef struct
   };
   };
   endpoint_state_t endpoint[2];
   endpoint_state_t endpoint[2];
   pipe_state_t pipe[HCD_MAX_XFER];
   pipe_state_t pipe[HCD_MAX_XFER];
+  bool         need_reset;     /* The device has not been reset after connection. */
 } hcd_data_t;
 } hcd_data_t;
 
 
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
@@ -135,31 +135,34 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static hcd_data_t _hcd;
 
 
 TU_VERIFY_STATIC( sizeof(_hcd.bdt) == 512, "size is not correct" );
 TU_VERIFY_STATIC( sizeof(_hcd.bdt) == 512, "size is not correct" );
 
 
-static pipe_state_t *find_pipe(uint8_t dev_addr, uint8_t ep_addr)
+int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
 {
 {
   /* Find the target pipe */
   /* Find the target pipe */
-  pipe_state_t *p   = _hcd.pipe;
-  pipe_state_t *end = p + HCD_MAX_XFER;
-  for (;p != end; ++p) {
-    if ((p->dev_addr == dev_addr) && (p->ep_addr != ep_addr))
-      return p;
+  int num;
+  if (0 == tu_edpt_number(ep_addr)) ep_addr = 0;
+  for (num = 0; num < HCD_MAX_XFER; ++num) {
+    pipe_state_t *p = &_hcd.pipe[num];
+    if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
+      return num;
   }
   }
-  return NULL;
+  return -1;
 }
 }
 
 
-static int prepare_packets(uint8_t rhport, uint_fast8_t dir_in, uint8_t* buffer, uint_fast16_t total_bytes)
+static int prepare_packets(int pipenum,
+                           uint_fast8_t dir_in, uint8_t* buffer,
+                           uint_fast16_t total_bytes)
 {
 {
-  (void)rhport;
   const unsigned dir_tx   = dir_in ? 0 : 1;
   const unsigned dir_tx   = dir_in ? 0 : 1;
   endpoint_state_t    *ep = &_hcd.endpoint[dir_tx];
   endpoint_state_t    *ep = &_hcd.endpoint[dir_tx];
   buffer_descriptor_t *bd = &_hcd.bdt[0][dir_tx][ep->odd];
   buffer_descriptor_t *bd = &_hcd.bdt[0][dir_tx][ep->odd];
   TU_ASSERT(0 == bd->own, 0);
   TU_ASSERT(0 == bd->own, 0);
 
 
+  ep->pipenum   = pipenum;
   ep->length    = total_bytes;
   ep->length    = total_bytes;
   ep->remaining = total_bytes;
   ep->remaining = total_bytes;
 
 
   int num_pkts = 0; /* The number of prepared packets */
   int num_pkts = 0; /* The number of prepared packets */
-  const unsigned mps = ep->max_packet_size;
+  const unsigned mps = _hcd.pipe[pipenum].max_packet_size;
   if (total_bytes > mps) {
   if (total_bytes > mps) {
     buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
     buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
     /* When total_bytes is greater than the max packet size,
     /* When total_bytes is greater than the max packet size,
@@ -174,6 +177,7 @@ static int prepare_packets(uint8_t rhport, uint_fast8_t dir_in, uint8_t* buffer,
   __DSB();
   __DSB();
   bd->own  = 1; /* This bit must be set last */
   bd->own  = 1; /* This bit must be set last */
   ++num_pkts;
   ++num_pkts;
+  // TU_LOG1("BD pipe=%d %d %lx %x\n", pipenum, num_pkts, bd->head, (uintptr_t)bd->addr);
   return num_pkts;
   return num_pkts;
 }
 }
 
 
@@ -182,12 +186,13 @@ static void process_tokdne(uint8_t rhport)
   (void)rhport;
   (void)rhport;
   const unsigned s = KHCI->STAT;
   const unsigned s = KHCI->STAT;
   KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
   KHCI->ISTAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
-
   uint8_t const epnum  = (s >> USB_STAT_ENDP_SHIFT);
   uint8_t const epnum  = (s >> USB_STAT_ENDP_SHIFT);
   TU_ASSERT(0 == epnum,);
   TU_ASSERT(0 == epnum,);
   uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
   uint8_t const dir_in = (s & USB_STAT_TX_MASK) ? TUSB_DIR_OUT: TUSB_DIR_IN;
   unsigned const odd   = (s & USB_STAT_ODD_MASK) ? 1 : 0;
   unsigned const odd   = (s & USB_STAT_ODD_MASK) ? 1 : 0;
 
 
+  // TU_LOG1("TOKDNE %x\n", s);
+
   buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
   buffer_descriptor_t *bd = (buffer_descriptor_t *)&_hcd.bda[s];
   endpoint_state_t    *ep = &_hcd.endpoint[s >> 3];
   endpoint_state_t    *ep = &_hcd.endpoint[s >> 3];
 
 
@@ -204,19 +209,24 @@ static void process_tokdne(uint8_t rhport)
 
 
   const unsigned bc = bd->bc;
   const unsigned bc = bd->bc;
   const unsigned remaining = ep->remaining - bc;
   const unsigned remaining = ep->remaining - bc;
+  pipe_state_t *pipe = &_hcd.pipe[ep->pipenum];
+
+  // TU_LOG1("  pid %x bc %x remaining %d\n", pid, bc, remaining);
   if ((TOK_PID_DATA0 == pid) || (TOK_PID_DATA1 == pid) || (TOK_PID_ACK == pid)) {
   if ((TOK_PID_DATA0 == pid) || (TOK_PID_DATA1 == pid) || (TOK_PID_ACK == pid)) {
     /* Go on the next packet transfer */
     /* Go on the next packet transfer */
-    if (remaining && bc == ep->max_packet_size) {
+    if (remaining && bc == pipe->max_packet_size) {
       ep->remaining = remaining;
       ep->remaining = remaining;
-      const int next_remaining = remaining - ep->max_packet_size;
+      const int next_remaining = remaining - pipe->max_packet_size;
       if (next_remaining > 0) {
       if (next_remaining > 0) {
         /* Prepare to the after next transfer */
         /* Prepare to the after next transfer */
-        bd->addr += ep->max_packet_size * 2;
-        bd->bc    = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+        bd->addr += pipe->max_packet_size * 2;
+        bd->bc    = next_remaining > pipe->max_packet_size ? pipe->max_packet_size: next_remaining;
         __DSB();
         __DSB();
         bd->own   = 1; /* This bit must be set last */
         bd->own   = 1; /* This bit must be set last */
         while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
         while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
         KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
         KHCI->TOKEN = KHCI->TOKEN; /* Queue the same token as the last */
+      } else if (dir_in) {
+        KHCI->TOKEN = KHCI->TOKEN;
       }
       }
       return;
       return;
     }
     }
@@ -236,7 +246,7 @@ static void process_tokdne(uint8_t rhport)
       result = XFER_RESULT_FAILED;
       result = XFER_RESULT_FAILED;
       break;
       break;
   }
   }
-  hcd_event_xfer_complete(KHCI->ADDR & USB_ADDR_ADDR_MASK,
+  hcd_event_xfer_complete(pipe->dev_addr,
                           tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
                           tu_edpt_addr(KHCI->TOKEN & USB_TOKEN_TOKENENDPT_MASK, dir_in),
                           length - remaining, result, true);
                           length - remaining, result, true);
 }
 }
@@ -252,6 +262,21 @@ static void process_attach(uint8_t rhport)
   hcd_event_device_attach(rhport, true);
   hcd_event_device_attach(rhport, true);
 }
 }
 
 
+static void process_bus_reset(uint8_t rhport)
+{
+  KHCI->USBCTRL &= ~USB_USBCTRL_SUSP_MASK;
+  KHCI->CTL     &= ~USB_CTL_USBENSOFEN_MASK;
+  KHCI->ADDR     = 0;
+  KHCI->ENDPOINT[0].ENDPT = 0;
+
+  hcd_event_device_remove(rhport, true);
+
+  buffer_descriptor_t *bd = _hcd.bdt[0][0];
+  for (unsigned i = 0; i < 2; ++i, ++bd) {
+    bd->head = 0;
+  }
+}
+
 /*------------------------------------------------------------------*/
 /*------------------------------------------------------------------*/
 /* Host API
 /* Host API
  *------------------------------------------------------------------*/
  *------------------------------------------------------------------*/
@@ -273,14 +298,6 @@ bool hcd_init(uint8_t rhport)
   for (unsigned i = 0; i < 16; ++i) {
   for (unsigned i = 0; i < 16; ++i) {
     KHCI->ENDPOINT[i].ENDPT = 0;
     KHCI->ENDPOINT[i].ENDPT = 0;
   }
   }
-  const endpoint_state_t ep0 = {
-    .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
-    .odd             = 0,
-    .length          = 0,
-    .remaining       = 0,
-  };
-  _hcd.endpoint[0] = ep0;
-  _hcd.endpoint[1] = ep0;
   KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
   KHCI->CTL &= ~USB_CTL_ODDRST_MASK;
 
 
   KHCI->SOFTHLD = 74; /* for 64-byte packets */
   KHCI->SOFTHLD = 74; /* for 64-byte packets */
@@ -288,7 +305,8 @@ bool hcd_init(uint8_t rhport)
   KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
   KHCI->USBCTRL = USB_USBCTRL_PDE_MASK;
 
 
   NVIC_ClearPendingIRQ(USB0_IRQn);
   NVIC_ClearPendingIRQ(USB0_IRQn);
-  KHCI->INTEN = USB_INTEN_ATTACHEN_MASK;
+  KHCI->INTEN = USB_INTEN_ATTACHEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+    USB_INTEN_USBRSTEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
   return true;
   return true;
 }
 }
 
 
@@ -307,9 +325,12 @@ void hcd_int_disable(uint8_t rhport)
 uint32_t hcd_frame_number(uint8_t rhport)
 uint32_t hcd_frame_number(uint8_t rhport)
 {
 {
   (void)rhport;
   (void)rhport;
+  /* The device must be reset at least once after connection 
+   * in order to start the frame counter. */
+  if (_hcd.need_reset) hcd_port_reset(rhport);
   uint32_t frmnum = KHCI->FRMNUML;
   uint32_t frmnum = KHCI->FRMNUML;
   frmnum |= KHCI->FRMNUMH << 8u;
   frmnum |= KHCI->FRMNUMH << 8u;
-  return frmnum;
+   return frmnum;
 }
 }
 
 
 /*--------------------------------------------------------------------+
 /*--------------------------------------------------------------------+
@@ -318,6 +339,8 @@ uint32_t hcd_frame_number(uint8_t rhport)
 bool hcd_port_connect_status(uint8_t rhport)
 bool hcd_port_connect_status(uint8_t rhport)
 {
 {
   (void)rhport;
   (void)rhport;
+  if (KHCI->ISTAT & USB_ISTAT_ATTACH_MASK)
+    return true;
   return false;
   return false;
 }
 }
 
 
@@ -330,6 +353,7 @@ void hcd_port_reset(uint8_t rhport)
   while (cnt--) __NOP();
   while (cnt--) __NOP();
   KHCI->CTL &= ~USB_CTL_RESET_MASK;
   KHCI->CTL &= ~USB_CTL_RESET_MASK;
   KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
   KHCI->CTL |= USB_CTL_USBENSOFEN_MASK;
+  _hcd.need_reset = false;
 }
 }
 
 
 tusb_speed_t hcd_port_speed_get(uint8_t rhport)
 tusb_speed_t hcd_port_speed_get(uint8_t rhport)
@@ -347,8 +371,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
 void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
 void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
 {
 {
   (void)rhport;
   (void)rhport;
-  pipe_state_t *p   = _hcd.pipe;
-  pipe_state_t *end = p + HCD_MAX_XFER;
+  pipe_state_t *p   = &_hcd.pipe[0];
+  pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER];
   for (;p != end; ++p) {
   for (;p != end; ++p) {
     if (p->dev_addr == dev_addr)
     if (p->dev_addr == dev_addr)
       tu_memclr(p, sizeof(*p));
       tu_memclr(p, sizeof(*p));
@@ -361,10 +385,14 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
 bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
 bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8])
 {
 {
   (void)rhport;
   (void)rhport;
+  // TU_LOG1("SETUP %u\n", dev_addr);
   const unsigned rx_odd = _hcd.endpoint[0].odd;
   const unsigned rx_odd = _hcd.endpoint[0].odd;
   const unsigned tx_odd = _hcd.endpoint[1].odd;
   const unsigned tx_odd = _hcd.endpoint[1].odd;
   TU_ASSERT(0 == _hcd.bdt[0][0][tx_odd].own);
   TU_ASSERT(0 == _hcd.bdt[0][0][tx_odd].own);
 
 
+  int num = find_pipe(dev_addr, 0);
+  if (num < 0) return false;
+
   const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
   const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
   NVIC_DisableIRQ(USB0_IRQn);
   NVIC_DisableIRQ(USB0_IRQn);
 
 
@@ -377,26 +405,31 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
   KHCI->ENDPOINT[0].ENDPT = hostwohub |
   KHCI->ENDPOINT[0].ENDPT = hostwohub |
     USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
     USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
   bool ret = false;
   bool ret = false;
-  if (prepare_packets(rhport, TUSB_DIR_OUT, (void*)(uintptr_t)setup_packet, 8)) {
+  if (prepare_packets(num, TUSB_DIR_OUT, (void*)(uintptr_t)setup_packet, 8)) {
     KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
     KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
     while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
     while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
     KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
     KHCI->TOKEN = (TOK_PID_SETUP << USB_TOKEN_TOKENPID_SHIFT);
     ret = true;
     ret = true;
   }
   }
   if (ie) NVIC_EnableIRQ(USB0_IRQn);
   if (ie) NVIC_EnableIRQ(USB0_IRQn);
+
   return ret;
   return ret;
 }
 }
 
 
 bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
 bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
 {
 {
   (void)rhport;
   (void)rhport;
+  uint8_t const ep_addr = ep_desc->bEndpointAddress;
+  // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
   /* Find a free pipe */
   /* Find a free pipe */
-  pipe_state_t *p   = _hcd.pipe;
-  pipe_state_t *end = p + HCD_MAX_XFER;
-  for (;p < end && p->dev_addr; ++p) ;
-  if (p == end) return false;
+  pipe_state_t *p = &_hcd.pipe[0];
+  if (dev_addr || ep_addr) {
+    pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER];
+    for (++p; p < end && (p->dev_addr || p->ep_addr); ++p) ;
+    if (p == end) return false;
+  }
   p->dev_addr        = dev_addr;
   p->dev_addr        = dev_addr;
-  p->ep_addr         = ep_desc->bEndpointAddress;
+  p->ep_addr         = ep_addr;
   p->max_packet_size = ep_desc->wMaxPacketSize;
   p->max_packet_size = ep_desc->wMaxPacketSize;
   p->xfer            = ep_desc->bmAttributes.xfer;
   p->xfer            = ep_desc->bmAttributes.xfer;
   p->data            = 0;
   p->data            = 0;
@@ -406,15 +439,18 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
 bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
 bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
 {
 {
   (void)rhport;
   (void)rhport;
+  // TU_LOG1("X %u %x %d\n", dev_addr, ep_addr, buflen);
   const unsigned dir_in   = tu_edpt_dir(ep_addr);
   const unsigned dir_in   = tu_edpt_dir(ep_addr);
   const unsigned odd      = _hcd.endpoint[dir_in ^ 1].odd;
   const unsigned odd      = _hcd.endpoint[dir_in ^ 1].odd;
   buffer_descriptor_t *bd = _hcd.bdt[0][dir_in ^ 1];
   buffer_descriptor_t *bd = _hcd.bdt[0][dir_in ^ 1];
   TU_ASSERT(0 == bd[odd].own);
   TU_ASSERT(0 == bd[odd].own);
 
 
+  int num = find_pipe(dev_addr, ep_addr);
+  if (num < 0) return false;
+
   unsigned flags = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
   unsigned flags = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
   if (tu_edpt_number(ep_addr)) {
   if (tu_edpt_number(ep_addr)) {
-    pipe_state_t *p = find_pipe(dev_addr, ep_addr);
-    if (!p) return false;
+    pipe_state_t *p  = &_hcd.pipe[num];
     bd[odd    ].data = p->data;
     bd[odd    ].data = p->data;
     bd[odd ^ 1].data = p->data ^ 1;
     bd[odd ^ 1].data = p->data ^ 1;
     bd[odd ^ 1].own  = 0;
     bd[odd ^ 1].own  = 0;
@@ -425,7 +461,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
   }
   }
   unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
   unsigned hostwohub = KHCI->ENDPOINT[0].ENDPT & USB_ENDPT_HOSTWOHUB_MASK;
   KHCI->ENDPOINT[0].ENDPT = hostwohub | flags;
   KHCI->ENDPOINT[0].ENDPT = hostwohub | flags;
-  int num_pkts = prepare_packets(rhport, dir_in, buffer, buflen);
+  int num_pkts = prepare_packets(num, dir_in, buffer, buflen);
   if (!num_pkts) return false;
   if (!num_pkts) return false;
   KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
   KHCI->ADDR  = (KHCI->ADDR & USB_ADDR_LSEN_MASK) | dev_addr;
   const unsigned token = tu_edpt_number(ep_addr) |
   const unsigned token = tu_edpt_number(ep_addr) |
@@ -435,7 +471,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
   do {
   do {
     while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
     while (KHCI->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) ;
     KHCI->TOKEN = token;
     KHCI->TOKEN = token;
-  } while (--num_pkts);
+  } while (--num_pkts && !dir_in);
   if (ie) NVIC_EnableIRQ(USB0_IRQn);
   if (ie) NVIC_EnableIRQ(USB0_IRQn);
   return true;
   return true;
 }
 }
@@ -443,8 +479,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
 {
 {
   if (!tu_edpt_number(ep_addr)) return true;
   if (!tu_edpt_number(ep_addr)) return true;
-  pipe_state_t *p = find_pipe(dev_addr, ep_addr);
-  if (!p) return false;
+  int num = find_pipe(dev_addr, ep_addr);
+  if (num < 0) return false;
+  pipe_state_t *p = &_hcd.pipe[num];
   p->data = 0; /* Reset data toggle */
   p->data = 0; /* Reset data toggle */
   return true;
   return true;
 }
 }
@@ -457,13 +494,21 @@ void hcd_int_handler(uint8_t rhport)
   uint32_t is  = KHCI->ISTAT;
   uint32_t is  = KHCI->ISTAT;
   uint32_t msk = KHCI->INTEN;
   uint32_t msk = KHCI->INTEN;
 
 
+  // TU_LOG1("S %lx\n", is);
+
   /* clear disabled interrupts */
   /* clear disabled interrupts */
-  KHCI->ISTAT = is & ~msk;
+  KHCI->ISTAT = is & ~msk & ~USB_ISTAT_TOKDNE_MASK;
   is &= msk;
   is &= msk;
 
 
   if (is & USB_ISTAT_ATTACH_MASK) {
   if (is & USB_ISTAT_ATTACH_MASK) {
+    KHCI->INTEN = (msk & ~USB_INTEN_ATTACHEN_MASK) | USB_INTEN_USBRSTEN_MASK;
+    _hcd.need_reset = true;
     process_attach(rhport);
     process_attach(rhport);
   }
   }
+  if (is & USB_ISTAT_USBRST_MASK) {
+    KHCI->INTEN = (msk & ~USB_INTEN_USBRSTEN_MASK) | USB_INTEN_ATTACHEN_MASK;
+    process_bus_reset(rhport);
+  }
   if (is & USB_ISTAT_STALL_MASK) {
   if (is & USB_ISTAT_STALL_MASK) {
     KHCI->ISTAT = USB_ISTAT_STALL_MASK;
     KHCI->ISTAT = USB_ISTAT_STALL_MASK;
   }
   }