Przeglądaj źródła

Merge pull request #1020 from hathach/rp2040-disconnect-suspend

Add Rp2040 suspend & resume support
Ha Thach 4 lat temu
rodzic
commit
830757d9ce

+ 1 - 0
src/device/dcd.h

@@ -152,6 +152,7 @@ bool dcd_edpt_xfer_fifo       (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff,
 void dcd_edpt_stall           (uint8_t rhport, uint8_t ep_addr);
 void dcd_edpt_stall           (uint8_t rhport, uint8_t ep_addr);
 
 
 // clear stall, data toggle is also reset to DATA0
 // clear stall, data toggle is also reset to DATA0
+// This API never calls with control endpoints, since it is auto cleared when receiving setup packet
 void dcd_edpt_clear_stall     (uint8_t rhport, uint8_t ep_addr);
 void dcd_edpt_clear_stall     (uint8_t rhport, uint8_t ep_addr);
 
 
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+

+ 6 - 0
src/device/usbd.c

@@ -1220,6 +1220,9 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
 {
 {
   (void) rhport;
   (void) rhport;
 
 
+  // TODO add this check later, also make sure we don't starve an out endpoint while suspending
+  // TU_VERIFY(tud_ready());
+
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
 
 
@@ -1273,6 +1276,9 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
 
 
+  // TODO skip ready() check for now since enumeration also use this API
+  // TU_VERIFY(tud_ready());
+
   TU_LOG2("  Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
   TU_LOG2("  Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
 
 
   // Attempt to transfer on a busy endpoint, sound like an race condition !
   // Attempt to transfer on a busy endpoint, sound like an race condition !

+ 143 - 165
src/portable/raspberrypi/rp2040/dcd_rp2040.c

@@ -37,6 +37,11 @@
 
 
 #include "device/dcd.h"
 #include "device/dcd.h"
 
 
+// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
+// Therefore it cannot detect disconnect event, mistaken it as suspend.
+// Note: won't work if change to 0 (for now)
+#define FORCE_VBUS_DETECT   1
+
 /*------------------------------------------------------------------*/
 /*------------------------------------------------------------------*/
 /* Low level controller
 /* Low level controller
  *------------------------------------------------------------------*/
  *------------------------------------------------------------------*/
@@ -48,27 +53,27 @@
 static uint8_t *next_buffer_ptr;
 static uint8_t *next_buffer_ptr;
 
 
 // USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
 // USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
-static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2] = {0};
+static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
 
 
 static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
 static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
 {
 {
-    return &hw_endpoints[num][dir];
+  return &hw_endpoints[num][dir];
 }
 }
 
 
 static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
 static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr)
 {
 {
-    uint8_t num = tu_edpt_number(ep_addr);
-    tusb_dir_t dir = tu_edpt_dir(ep_addr);
-    return hw_endpoint_get_by_num(num, dir);
+  uint8_t num = tu_edpt_number(ep_addr);
+  tusb_dir_t dir = tu_edpt_dir(ep_addr);
+  return hw_endpoint_get_by_num(num, dir);
 }
 }
 
 
-static void _hw_endpoint_alloc(struct hw_endpoint *ep)
+static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
 {
 {
   // size must be multiple of 64
   // size must be multiple of 64
   uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
   uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
 
 
-  // double buffered for Control and Bulk endpoint
-  if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK)
+  // double buffered Bulk endpoint
+  if ( transfer_type == TUSB_XFER_BULK )
   {
   {
     size *= 2u;
     size *= 2u;
   }
   }
@@ -80,81 +85,14 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep)
   uint dpram_offset = hw_data_offset(ep->hw_data_buf);
   uint dpram_offset = hw_data_offset(ep->hw_data_buf);
   assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
   assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
 
 
-  pico_info("Alloced %d bytes at offset 0x%x (0x%p) for ep %d %s\n",
-            size,
-            dpram_offset,
-            ep->hw_data_buf,
-            tu_edpt_number(ep->ep_addr),
-            ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
+  pico_info("  Alloced %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
 
 
   // Fill in endpoint control register with buffer offset
   // Fill in endpoint control register with buffer offset
-  uint32_t const reg = EP_CTRL_ENABLE_BITS | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
+  uint32_t const reg = EP_CTRL_ENABLE_BITS | (transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
 
 
   *ep->endpoint_control = reg;
   *ep->endpoint_control = reg;
 }
 }
 
 
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
-{
-    const uint8_t num = tu_edpt_number(ep_addr);
-    const tusb_dir_t dir = tu_edpt_dir(ep_addr);
-
-    ep->ep_addr = ep_addr;
-
-    // For device, IN is a tx transfer and OUT is an rx transfer
-    ep->rx = (dir == TUSB_DIR_OUT);
-
-    // Response to a setup packet on EP0 starts with pid of 1
-    ep->next_pid = num == 0 ? 1u : 0u;
-
-    ep->wMaxPacketSize = wMaxPacketSize;
-    ep->transfer_type = transfer_type;
-
-    // Every endpoint has a buffer control register in dpram
-    if (dir == TUSB_DIR_IN)
-    {
-        ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
-    }
-    else
-    {
-        ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
-    }
-
-    // Clear existing buffer control state
-    *ep->buffer_control = 0;
-
-    if (num == 0)
-    {
-        // EP0 has no endpoint control register because
-        // the buffer offsets are fixed
-        ep->endpoint_control = NULL;
-
-        // Buffer offset is fixed
-        ep->hw_data_buf = (uint8_t*)&usb_dpram->ep0_buf_a[0];
-    }
-    else
-    {
-        // Set the endpoint control register (starts at EP1, hence num-1)
-        if (dir == TUSB_DIR_IN)
-        {
-            ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].in;
-        }
-        else
-        {
-            ep->endpoint_control = &usb_dpram->ep_ctrl[num-1].out;
-        }
-
-        // Now if it hasn't already been done
-        //alloc a buffer and fill in endpoint control register
-        // TODO device may change configuration (dynamic), should clear and reallocate
-        if(!(ep->configured))
-        {
-            _hw_endpoint_alloc(ep);
-        }
-    }
-
-    ep->configured = true;
-}
-
 #if 0 // todo unused
 #if 0 // todo unused
 static void _hw_endpoint_close(struct hw_endpoint *ep)
 static void _hw_endpoint_close(struct hw_endpoint *ep)
 {
 {
@@ -174,10 +112,61 @@ static void hw_endpoint_close(uint8_t ep_addr)
 }
 }
 #endif
 #endif
 
 
-static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t bmAttributes)
+static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type)
 {
 {
-    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
-    _hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes);
+  struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+
+  const uint8_t num = tu_edpt_number(ep_addr);
+  const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+
+  ep->ep_addr = ep_addr;
+
+  // For device, IN is a tx transfer and OUT is an rx transfer
+  ep->rx = (dir == TUSB_DIR_OUT);
+
+  // Response to a setup packet on EP0 starts with pid of 1
+  ep->next_pid = (num == 0 ? 1u : 0u);
+
+  ep->wMaxPacketSize = wMaxPacketSize;
+  ep->transfer_type = transfer_type;
+
+  // Every endpoint has a buffer control register in dpram
+  if ( dir == TUSB_DIR_IN )
+  {
+    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
+  }
+  else
+  {
+    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
+  }
+
+  // Clear existing buffer control state
+  *ep->buffer_control = 0;
+
+  if ( num == 0 )
+  {
+    // EP0 has no endpoint control register because
+    // the buffer offsets are fixed
+    ep->endpoint_control = NULL;
+
+    // Buffer offset is fixed (also double buffered)
+    ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
+  }
+  else
+  {
+    // Set the endpoint control register (starts at EP1, hence num-1)
+    if ( dir == TUSB_DIR_IN )
+    {
+      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
+    }
+    else
+    {
+      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
+    }
+
+    // alloc a buffer and fill in endpoint control register
+    _hw_endpoint_alloc(ep, transfer_type);
+  }
 }
 }
 
 
 static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
 static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
@@ -222,55 +211,22 @@ static void reset_ep0(void)
     {
     {
         struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
         struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
         ep->next_pid = 1u;
         ep->next_pid = 1u;
-        ep->stalled  = 0;
     }
     }
 }
 }
 
 
-static void ep0_0len_status(void)
+static void reset_all_endpoints(void)
 {
 {
-    // Send 0len complete response on EP0 IN
-    reset_ep0();
-    hw_endpoint_xfer(0x80, NULL, 0);
-}
+  memset(hw_endpoints, 0, sizeof(hw_endpoints));
+  next_buffer_ptr = &usb_dpram->epx_data[0];
 
 
-static void _hw_endpoint_stall(struct hw_endpoint *ep)
-{
-    assert(!ep->stalled);
-    if (tu_edpt_number(ep->ep_addr) == 0)
-    {
-        // A stall on EP0 has to be armed so it can be cleared on the next setup packet
-        usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
-    }
-    _hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
-    ep->stalled = true;
-}
-
-static void hw_endpoint_stall(uint8_t ep_addr)
-{
-    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
-    _hw_endpoint_stall(ep);
-}
-
-static void _hw_endpoint_clear_stall(struct hw_endpoint *ep)
-{
-    if (tu_edpt_number(ep->ep_addr) == 0)
-    {
-        // Probably already been cleared but no harm
-        usb_hw_clear->ep_stall_arm = (tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
-    }
-    _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
-    ep->stalled = false;
-}
-
-static void hw_endpoint_clear_stall(uint8_t ep_addr)
-{
-    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
-    _hw_endpoint_clear_stall(ep);
+  // Init Control endpoint out & in
+  hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
+  hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
 }
 }
 
 
 static void dcd_rp2040_irq(void)
 static void dcd_rp2040_irq(void)
 {
 {
-    uint32_t status = usb_hw->ints;
+    uint32_t const status = usb_hw->ints;
     uint32_t handled = 0;
     uint32_t handled = 0;
 
 
     if (status & USB_INTS_SETUP_REQ_BITS)
     if (status & USB_INTS_SETUP_REQ_BITS)
@@ -290,7 +246,9 @@ static void dcd_rp2040_irq(void)
         hw_handle_buff_status();
         hw_handle_buff_status();
     }
     }
 
 
-    // SE0 for 2 us or more, usually together with Bus Reset
+#if FORCE_VBUS_DETECT == 0
+    // Since we force VBUS detect On, device will always think it is connected and
+    // couldn't distinguish between disconnect and suspend
     if (status & USB_INTS_DEV_CONN_DIS_BITS)
     if (status & USB_INTS_DEV_CONN_DIS_BITS)
     {
     {
         handled |= USB_INTS_DEV_CONN_DIS_BITS;
         handled |= USB_INTS_DEV_CONN_DIS_BITS;
@@ -306,13 +264,17 @@ static void dcd_rp2040_irq(void)
 
 
         usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
         usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
     }
     }
+#endif
 
 
-    // SE0 for 2.5 us or more
+    // SE0 for 2.5 us or more (will last at least 10ms)
     if (status & USB_INTS_BUS_RESET_BITS)
     if (status & USB_INTS_BUS_RESET_BITS)
     {
     {
         pico_trace("BUS RESET\n");
         pico_trace("BUS RESET\n");
-        usb_hw->dev_addr_ctrl = 0;
+
         handled |= USB_INTS_BUS_RESET_BITS;
         handled |= USB_INTS_BUS_RESET_BITS;
+
+        usb_hw->dev_addr_ctrl = 0;
+        reset_all_endpoints();
         dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
         dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
         usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
         usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
 
 
@@ -322,9 +284,6 @@ static void dcd_rp2040_irq(void)
 #endif
 #endif
     }
     }
 
 
-#if 0
-    // TODO Enable SUSPEND & RESUME interrupt and test later on with/without VBUS detection
-
     /* Note from pico datasheet 4.1.2.6.4 (v1.2)
     /* Note from pico datasheet 4.1.2.6.4 (v1.2)
      * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
      * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
      * the device is first connected but the bus is idle. The bus can be idle for a few ms before
      * the device is first connected but the bus is idle. The bus can be idle for a few ms before
@@ -346,7 +305,6 @@ static void dcd_rp2040_irq(void)
         dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
         dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
         usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
         usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
     }
     }
-#endif
 
 
     if (status ^ handled)
     if (status ^ handled)
     {
     {
@@ -364,36 +322,38 @@ static void dcd_rp2040_irq(void)
 /*------------------------------------------------------------------*/
 /*------------------------------------------------------------------*/
 /* Controller API
 /* Controller API
  *------------------------------------------------------------------*/
  *------------------------------------------------------------------*/
+
 void dcd_init (uint8_t rhport)
 void dcd_init (uint8_t rhport)
 {
 {
-    pico_trace("dcd_init %d\n", rhport);
-    assert(rhport == 0);
+  pico_trace("dcd_init %d\n", rhport);
+  assert(rhport == 0);
 
 
-    // Reset hardware to default state
-    rp2040_usb_init();
+  // Reset hardware to default state
+  rp2040_usb_init();
 
 
-    irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
-    memset(hw_endpoints, 0, sizeof(hw_endpoints));
-    next_buffer_ptr = &usb_dpram->epx_data[0];
+#if FORCE_VBUS_DETECT
+  // Force VBUS detect so the device thinks it is plugged into a host
+  usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+#endif
 
 
-    // EP0 always exists so init it now
-    // EP0 OUT
-    hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
-    // EP0 IN
-    hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
+  irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);
 
 
-    // Initializes the USB peripheral for device mode and enables it.
-    // Don't need to enable the pull up here. Force VBUS
-    usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
+  // reset endpoints
+  reset_all_endpoints();
 
 
-    // Enable individual controller IRQS here. Processor interrupt enable will be used
-    // for the global interrupt enable...
-    // TODO Enable SUSPEND & RESUME interrupt
-    usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS; 
-    usb_hw->inte     = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
-                       USB_INTS_DEV_CONN_DIS_BITS /* | USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS */  ;
+  // Initializes the USB peripheral for device mode and enables it.
+  // Don't need to enable the pull up here. Force VBUS
+  usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
 
 
-    dcd_connect(rhport);
+  // Enable individual controller IRQS here. Processor interrupt enable will be used
+  // for the global interrupt enable...
+  // Note: Force VBUS detect cause disconnection not detectable
+  usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS;
+  usb_hw->inte     = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
+                     USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
+                     (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
+
+  dcd_connect(rhport);
 }
 }
 
 
 void dcd_int_enable(uint8_t rhport)
 void dcd_int_enable(uint8_t rhport)
@@ -410,11 +370,13 @@ void dcd_int_disable(uint8_t rhport)
 
 
 void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 {
 {
-    pico_trace("dcd_set_address %d %d\n", rhport, dev_addr);
-    assert(rhport == 0);
+  pico_trace("dcd_set_address %d %d\n", rhport, dev_addr);
+  assert(rhport == 0);
 
 
-    // Can't set device address in hardware until status xfer has complete
-    ep0_0len_status();
+  // Can't set device address in hardware until status xfer has complete
+  // Send 0len complete response on EP0 IN
+  reset_ep0();
+  hw_endpoint_xfer(0x80, NULL, 0);
 }
 }
 
 
 void dcd_remote_wakeup(uint8_t rhport)
 void dcd_remote_wakeup(uint8_t rhport)
@@ -461,7 +423,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re
 
 
 bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 {
 {
-    pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress);
     assert(rhport == 0);
     assert(rhport == 0);
     hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
     hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
     return true;
     return true;
@@ -474,20 +435,37 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
     return true;
     return true;
 }
 }
 
 
-void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
 {
 {
-    pico_trace("dcd_edpt_stall %02x\n", ep_addr);
-    assert(rhport == 0);
-    hw_endpoint_stall(ep_addr);
+  pico_trace("dcd_edpt_stall %02x\n", ep_addr);
+  assert(rhport == 0);
+
+  if ( tu_edpt_number(ep_addr) == 0 )
+  {
+    // A stall on EP0 has to be armed so it can be cleared on the next setup packet
+    usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
+  }
+
+  struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+
+  // TODO check with double buffered
+  _hw_endpoint_buffer_control_set_mask32(ep, USB_BUF_CTRL_STALL);
 }
 }
 
 
-void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
 {
 {
-    pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr);
-    assert(rhport == 0);
-    hw_endpoint_clear_stall(ep_addr);
-}
+  pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr);
+  assert(rhport == 0);
+
+  if (tu_edpt_number(ep_addr))
+  {
+    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
 
 
+    // clear stall also reset toggle to DATA0
+    // TODO check with double buffered
+    _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL | USB_BUF_CTRL_DATA1_PID);
+  }
+}
 
 
 void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
 void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
 {
 {
@@ -500,8 +478,8 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
 
 
 void dcd_int_handler(uint8_t rhport)
 void dcd_int_handler(uint8_t rhport)
 {
 {
-    (void) rhport;
-    dcd_rp2040_irq();
+  (void) rhport;
+  dcd_rp2040_irq();
 }
 }
 
 
 #endif
 #endif

+ 5 - 2
src/portable/raspberrypi/rp2040/hcd_rp2040.c

@@ -61,8 +61,8 @@ static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS];
 
 
 // Flags we set by default in sie_ctrl (we add other bits on top)
 // Flags we set by default in sie_ctrl (we add other bits on top)
 enum {
 enum {
-  SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS        | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
-                  USB_SIE_CTRL_PULLDOWN_EN_BITS   | USB_SIE_CTRL_EP0_INT_1BUF_BITS
+  SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS      | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS |
+                  USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
 };
 };
 
 
 static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
 static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
@@ -360,6 +360,9 @@ bool hcd_init(uint8_t rhport)
     // Reset any previous state
     // Reset any previous state
     rp2040_usb_init();
     rp2040_usb_init();
 
 
+    // Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
+    usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+
     irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
     irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq);
 
 
     // clear epx and interrupt eps
     // clear epx and interrupt eps

+ 1 - 5
src/portable/raspberrypi/rp2040/rp2040_usb.c

@@ -62,11 +62,7 @@ void rp2040_usb_init(void)
   memset(usb_dpram, 0, sizeof(*usb_dpram));
   memset(usb_dpram, 0, sizeof(*usb_dpram));
 
 
   // Mux the controller to the onboard usb phy
   // Mux the controller to the onboard usb phy
-  usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS    | USB_USB_MUXING_SOFTCON_BITS;
-
-  // Force VBUS detect so the device thinks it is plugged into a host
-  // TODO support VBUs detect
-  usb_hw->pwr    = USB_USB_PWR_VBUS_DETECT_BITS  | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
+  usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
 }
 }
 
 
 void hw_endpoint_reset_transfer(struct hw_endpoint *ep)
 void hw_endpoint_reset_transfer(struct hw_endpoint *ep)

+ 1 - 1
src/portable/raspberrypi/rp2040/rp2040_usb.h

@@ -42,7 +42,7 @@ struct hw_endpoint
     // Buffer pointer in usb dpram
     // Buffer pointer in usb dpram
     uint8_t *hw_data_buf;
     uint8_t *hw_data_buf;
 
 
-    // Have we been stalled
+    // Have we been stalled TODO remove later
     bool stalled;
     bool stalled;
 
 
     // Current transfer information
     // Current transfer information