Merge branch 'master' into fix-rp2040-ctrl-xfer
This commit is contained in:
		@@ -48,7 +48,7 @@
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
// Init these in dcd_init
 | 
			
		||||
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.
 | 
			
		||||
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
 | 
			
		||||
@@ -56,79 +56,70 @@ static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
 | 
			
		||||
// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
 | 
			
		||||
static bool _sof_enable = false;
 | 
			
		||||
 | 
			
		||||
TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir)
 | 
			
		||||
{
 | 
			
		||||
TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_num(uint8_t num, tusb_dir_t 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type)
 | 
			
		||||
{
 | 
			
		||||
static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
 | 
			
		||||
  // size must be multiple of 64
 | 
			
		||||
  uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
 | 
			
		||||
 | 
			
		||||
  // double buffered Bulk endpoint
 | 
			
		||||
  if ( transfer_type == TUSB_XFER_BULK )
 | 
			
		||||
  {
 | 
			
		||||
  if (transfer_type == TUSB_XFER_BULK) {
 | 
			
		||||
    size *= 2u;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ep->hw_data_buf = next_buffer_ptr;
 | 
			
		||||
  next_buffer_ptr += size;
 | 
			
		||||
 | 
			
		||||
  assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0);
 | 
			
		||||
  assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
 | 
			
		||||
  uint dpram_offset = hw_data_offset(ep->hw_data_buf);
 | 
			
		||||
  hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
 | 
			
		||||
 | 
			
		||||
  pico_info("  Allocated %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
 | 
			
		||||
  uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
 | 
			
		||||
  uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
 | 
			
		||||
 | 
			
		||||
  *ep->endpoint_control = reg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void _hw_endpoint_close(struct hw_endpoint *ep)
 | 
			
		||||
{
 | 
			
		||||
    // Clear hardware registers and then zero the struct
 | 
			
		||||
    // Clears endpoint enable
 | 
			
		||||
    *ep->endpoint_control = 0;
 | 
			
		||||
    // Clears buffer available, etc
 | 
			
		||||
    *ep->buffer_control = 0;
 | 
			
		||||
    // Clear any endpoint state
 | 
			
		||||
    memset(ep, 0, sizeof(struct hw_endpoint));
 | 
			
		||||
static void _hw_endpoint_close(struct hw_endpoint* ep) {
 | 
			
		||||
  // Clear hardware registers and then zero the struct
 | 
			
		||||
  // Clears endpoint enable
 | 
			
		||||
  *ep->endpoint_control = 0;
 | 
			
		||||
  // Clears buffer available, etc
 | 
			
		||||
  *ep->buffer_control = 0;
 | 
			
		||||
  // Clear any endpoint state
 | 
			
		||||
  memset(ep, 0, sizeof(struct hw_endpoint));
 | 
			
		||||
 | 
			
		||||
    // Reclaim buffer space if all endpoints are closed
 | 
			
		||||
    bool reclaim_buffers = true;
 | 
			
		||||
    for ( uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++ )
 | 
			
		||||
    {
 | 
			
		||||
        if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL || hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL)
 | 
			
		||||
        {
 | 
			
		||||
            reclaim_buffers = false;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (reclaim_buffers)
 | 
			
		||||
    {
 | 
			
		||||
        next_buffer_ptr = &usb_dpram->epx_data[0];
 | 
			
		||||
  // Reclaim buffer space if all endpoints are closed
 | 
			
		||||
  bool reclaim_buffers = true;
 | 
			
		||||
  for (uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++) {
 | 
			
		||||
    if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL ||
 | 
			
		||||
        hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL) {
 | 
			
		||||
      reclaim_buffers = false;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (reclaim_buffers) {
 | 
			
		||||
    next_buffer_ptr = &usb_dpram->epx_data[0];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void hw_endpoint_close(uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
    _hw_endpoint_close(ep);
 | 
			
		||||
static void hw_endpoint_close(uint8_t ep_addr) {
 | 
			
		||||
  struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
  _hw_endpoint_close(ep);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
  const uint8_t num = tu_edpt_number(ep_addr);
 | 
			
		||||
  const tusb_dir_t dir = tu_edpt_dir(ep_addr);
 | 
			
		||||
@@ -143,35 +134,26 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
 | 
			
		||||
  ep->transfer_type = transfer_type;
 | 
			
		||||
 | 
			
		||||
  // Every endpoint has a buffer control register in dpram
 | 
			
		||||
  if ( dir == TUSB_DIR_IN )
 | 
			
		||||
  {
 | 
			
		||||
  if (dir == TUSB_DIR_IN) {
 | 
			
		||||
    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
  } else {
 | 
			
		||||
    ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Clear existing buffer control state
 | 
			
		||||
  *ep->buffer_control = 0;
 | 
			
		||||
 | 
			
		||||
  if ( num == 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
 | 
			
		||||
  {
 | 
			
		||||
  } else {
 | 
			
		||||
    // Set the endpoint control register (starts at EP1, hence num-1)
 | 
			
		||||
    if ( dir == TUSB_DIR_IN )
 | 
			
		||||
    {
 | 
			
		||||
    if (dir == TUSB_DIR_IN) {
 | 
			
		||||
      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
    } else {
 | 
			
		||||
      ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -180,39 +162,34 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
 | 
			
		||||
{
 | 
			
		||||
    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
    hw_endpoint_xfer_start(ep, buffer, total_bytes);
 | 
			
		||||
static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
 | 
			
		||||
  struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
  hw_endpoint_xfer_start(ep, buffer, total_bytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __tusb_irq_path_func(hw_handle_buff_status)(void)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t remaining_buffers = usb_hw->buf_status;
 | 
			
		||||
    pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
 | 
			
		||||
    uint bit = 1u;
 | 
			
		||||
    for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++)
 | 
			
		||||
    {
 | 
			
		||||
        if (remaining_buffers & bit)
 | 
			
		||||
        {
 | 
			
		||||
            // clear this in advance
 | 
			
		||||
            usb_hw_clear->buf_status = bit;
 | 
			
		||||
static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
 | 
			
		||||
  uint32_t remaining_buffers = usb_hw->buf_status;
 | 
			
		||||
  pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
 | 
			
		||||
  uint bit = 1u;
 | 
			
		||||
  for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++) {
 | 
			
		||||
    if (remaining_buffers & bit) {
 | 
			
		||||
      // clear this in advance
 | 
			
		||||
      usb_hw_clear->buf_status = bit;
 | 
			
		||||
 | 
			
		||||
            // IN transfer for even i, OUT transfer for odd i
 | 
			
		||||
            struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
 | 
			
		||||
      // IN transfer for even i, OUT transfer for odd i
 | 
			
		||||
      struct hw_endpoint* ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
 | 
			
		||||
 | 
			
		||||
            // Continue xfer
 | 
			
		||||
            bool done = hw_endpoint_xfer_continue(ep);
 | 
			
		||||
            if (done)
 | 
			
		||||
            {
 | 
			
		||||
                // Notify
 | 
			
		||||
                dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
 | 
			
		||||
                hw_endpoint_reset_transfer(ep);
 | 
			
		||||
            }
 | 
			
		||||
            remaining_buffers &= ~bit;
 | 
			
		||||
        }
 | 
			
		||||
        bit <<= 1u;
 | 
			
		||||
      // Continue xfer
 | 
			
		||||
      bool done = hw_endpoint_xfer_continue(ep);
 | 
			
		||||
      if (done) {
 | 
			
		||||
        // Notify
 | 
			
		||||
        dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true);
 | 
			
		||||
        hw_endpoint_reset_transfer(ep);
 | 
			
		||||
      }
 | 
			
		||||
      remaining_buffers &= ~bit;
 | 
			
		||||
    }
 | 
			
		||||
    bit <<= 1u;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
 | 
			
		||||
@@ -258,29 +235,25 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __tusb_irq_path_func(reset_non_control_endpoints)(void)
 | 
			
		||||
{
 | 
			
		||||
static void __tusb_irq_path_func(reset_non_control_endpoints)(void) {
 | 
			
		||||
  // Disable all non-control
 | 
			
		||||
  for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS-1; i++ )
 | 
			
		||||
  {
 | 
			
		||||
  for (uint8_t i = 0; i < USB_MAX_ENDPOINTS - 1; i++) {
 | 
			
		||||
    usb_dpram->ep_ctrl[i].in = 0;
 | 
			
		||||
    usb_dpram->ep_ctrl[i].out = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // clear non-control hw endpoints
 | 
			
		||||
  tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t));
 | 
			
		||||
  tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t));
 | 
			
		||||
 | 
			
		||||
  // reclaim buffer space
 | 
			
		||||
  next_buffer_ptr = &usb_dpram->epx_data[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
{
 | 
			
		||||
static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
 | 
			
		||||
  uint32_t const status = usb_hw->ints;
 | 
			
		||||
  uint32_t handled = 0;
 | 
			
		||||
 | 
			
		||||
  if ( status & USB_INTF_DEV_SOF_BITS )
 | 
			
		||||
  {
 | 
			
		||||
  if (status & USB_INTF_DEV_SOF_BITS) {
 | 
			
		||||
    bool keep_sof_alive = false;
 | 
			
		||||
 | 
			
		||||
    handled |= USB_INTF_DEV_SOF_BITS;
 | 
			
		||||
@@ -289,20 +262,17 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
    // Errata 15 workaround for Device Bulk-In endpoint
 | 
			
		||||
    e15_last_sof = time_us_32();
 | 
			
		||||
 | 
			
		||||
    for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++ )
 | 
			
		||||
    {
 | 
			
		||||
      struct hw_endpoint * ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
 | 
			
		||||
    for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++) {
 | 
			
		||||
      struct hw_endpoint* ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
 | 
			
		||||
 | 
			
		||||
      // Active Bulk IN endpoint requires SOF
 | 
			
		||||
      if ( (ep->transfer_type == TUSB_XFER_BULK) && ep->active )
 | 
			
		||||
      {
 | 
			
		||||
      if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) {
 | 
			
		||||
        keep_sof_alive = true;
 | 
			
		||||
 | 
			
		||||
        hw_endpoint_lock_update(ep, 1);
 | 
			
		||||
 | 
			
		||||
        // Deferred enable?
 | 
			
		||||
        if ( ep->pending )
 | 
			
		||||
        {
 | 
			
		||||
        if (ep->pending) {
 | 
			
		||||
          ep->pending = 0;
 | 
			
		||||
          hw_endpoint_start_next_buffer(ep);
 | 
			
		||||
        }
 | 
			
		||||
@@ -313,23 +283,21 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // disable SOF interrupt if it is used for RESUME in remote wakeup
 | 
			
		||||
    if ( !keep_sof_alive && !_sof_enable ) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
 | 
			
		||||
    if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
 | 
			
		||||
 | 
			
		||||
    dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // xfer events are handled before setup req. So if a transfer completes immediately
 | 
			
		||||
  // before closing the EP, the events will be delivered in same order.
 | 
			
		||||
  if ( status & USB_INTS_BUFF_STATUS_BITS )
 | 
			
		||||
  {
 | 
			
		||||
  if (status & USB_INTS_BUFF_STATUS_BITS) {
 | 
			
		||||
    handled |= USB_INTS_BUFF_STATUS_BITS;
 | 
			
		||||
    hw_handle_buff_status();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( status & USB_INTS_SETUP_REQ_BITS )
 | 
			
		||||
  {
 | 
			
		||||
  if (status & USB_INTS_SETUP_REQ_BITS) {
 | 
			
		||||
    handled |= USB_INTS_SETUP_REQ_BITS;
 | 
			
		||||
    uint8_t const * setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet);
 | 
			
		||||
    uint8_t const* setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet);
 | 
			
		||||
 | 
			
		||||
    // reset pid to both 1 (data and ack)
 | 
			
		||||
    reset_ep0_pid();
 | 
			
		||||
@@ -360,8 +328,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // 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\r\n");
 | 
			
		||||
 | 
			
		||||
    handled |= USB_INTS_BUS_RESET_BITS;
 | 
			
		||||
@@ -373,7 +340,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
 | 
			
		||||
#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
 | 
			
		||||
    // Only run enumeration workaround if pull up is enabled
 | 
			
		||||
    if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix();
 | 
			
		||||
    if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix();
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -385,22 +352,19 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
   * because without VBUS detection, it is impossible to tell the difference between
 | 
			
		||||
   * being disconnected and suspended.
 | 
			
		||||
   */
 | 
			
		||||
  if ( status & USB_INTS_DEV_SUSPEND_BITS )
 | 
			
		||||
  {
 | 
			
		||||
  if (status & USB_INTS_DEV_SUSPEND_BITS) {
 | 
			
		||||
    handled |= USB_INTS_DEV_SUSPEND_BITS;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
 | 
			
		||||
    usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( status & USB_INTS_DEV_RESUME_FROM_HOST_BITS )
 | 
			
		||||
  {
 | 
			
		||||
  if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS) {
 | 
			
		||||
    handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
 | 
			
		||||
    usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( status ^ handled )
 | 
			
		||||
  {
 | 
			
		||||
  if (status ^ handled) {
 | 
			
		||||
    panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -421,8 +385,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void)
 | 
			
		||||
#define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void dcd_init (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void dcd_init(uint8_t rhport) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
 | 
			
		||||
  // Reset hardware to default state
 | 
			
		||||
@@ -436,7 +399,7 @@ void dcd_init (uint8_t rhport)
 | 
			
		||||
  irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
 | 
			
		||||
 | 
			
		||||
  // Init control endpoints
 | 
			
		||||
  tu_memclr(hw_endpoints[0], 2*sizeof(hw_endpoint_t));
 | 
			
		||||
  tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
 | 
			
		||||
  hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
 | 
			
		||||
  hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
 | 
			
		||||
 | 
			
		||||
@@ -451,27 +414,24 @@ void dcd_init (uint8_t rhport)
 | 
			
		||||
  // 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);
 | 
			
		||||
  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(__unused uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
    assert(rhport == 0);
 | 
			
		||||
    irq_set_enabled(USBCTRL_IRQ, true);
 | 
			
		||||
void dcd_int_enable(__unused uint8_t rhport) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
  irq_set_enabled(USBCTRL_IRQ, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_int_disable(__unused uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
    assert(rhport == 0);
 | 
			
		||||
    irq_set_enabled(USBCTRL_IRQ, false);
 | 
			
		||||
void dcd_int_disable(__unused uint8_t rhport) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
  irq_set_enabled(USBCTRL_IRQ, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
 | 
			
		||||
{
 | 
			
		||||
void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
 | 
			
		||||
  // Can't set device address in hardware until status xfer has complete
 | 
			
		||||
@@ -479,8 +439,7 @@ void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr)
 | 
			
		||||
  hw_endpoint_xfer(0x80, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_remote_wakeup(__unused uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void dcd_remote_wakeup(__unused uint8_t rhport) {
 | 
			
		||||
  pico_info("dcd_remote_wakeup %d\n", rhport);
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
 | 
			
		||||
@@ -491,100 +450,88 @@ void dcd_remote_wakeup(__unused uint8_t rhport)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// disconnect by disabling internal pull-up resistor on D+/D-
 | 
			
		||||
void dcd_disconnect(__unused uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void dcd_disconnect(__unused uint8_t rhport) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// connect by enabling internal pull-up resistor on D+/D-
 | 
			
		||||
void dcd_connect(__unused uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void dcd_connect(__unused uint8_t rhport) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_sof_enable(uint8_t rhport, bool en)
 | 
			
		||||
{
 | 
			
		||||
void dcd_sof_enable(uint8_t rhport, bool en) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  _sof_enable = en;
 | 
			
		||||
 | 
			
		||||
  if (en)
 | 
			
		||||
  {
 | 
			
		||||
  if (en) {
 | 
			
		||||
    usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
  }
 | 
			
		||||
#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
 | 
			
		||||
  else {
 | 
			
		||||
    // Don't clear immediately if the SOF workaround is in use.
 | 
			
		||||
    // The SOF handler will conditionally disable the interrupt.
 | 
			
		||||
#if !TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
 | 
			
		||||
    usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* DCD Endpoint port
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
 | 
			
		||||
{
 | 
			
		||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
 | 
			
		||||
       request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
 | 
			
		||||
       request->bRequest == TUSB_REQ_SET_ADDRESS )
 | 
			
		||||
  {
 | 
			
		||||
  if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
 | 
			
		||||
      request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
 | 
			
		||||
      request->bRequest == TUSB_REQ_SET_ADDRESS) {
 | 
			
		||||
    usb_hw->dev_addr_ctrl = (uint8_t) request->wValue;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_open (__unused uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 | 
			
		||||
{
 | 
			
		||||
    assert(rhport == 0);
 | 
			
		||||
    hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
 | 
			
		||||
    return true;
 | 
			
		||||
bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
  hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_close_all (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void dcd_edpt_close_all(uint8_t rhport) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  // may need to use EP Abort
 | 
			
		||||
  reset_non_control_endpoints();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 | 
			
		||||
{
 | 
			
		||||
    assert(rhport == 0);
 | 
			
		||||
    hw_endpoint_xfer(ep_addr, buffer, total_bytes);
 | 
			
		||||
    return true;
 | 
			
		||||
bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
 | 
			
		||||
  assert(rhport == 0);
 | 
			
		||||
  hw_endpoint_xfer(ep_addr, buffer, total_bytes);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  if ( tu_edpt_number(ep_addr) == 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;
 | 
			
		||||
    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);
 | 
			
		||||
  struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
 | 
			
		||||
  // stall and clear current pending buffer
 | 
			
		||||
  // may need to use EP_ABORT
 | 
			
		||||
  _hw_endpoint_buffer_control_set_value32(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) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  if (tu_edpt_number(ep_addr))
 | 
			
		||||
  {
 | 
			
		||||
    struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
  if (tu_edpt_number(ep_addr)) {
 | 
			
		||||
    struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
 | 
			
		||||
 | 
			
		||||
    // clear stall also reset toggle to DATA0, ready for next transfer
 | 
			
		||||
    ep->next_pid = 0;
 | 
			
		||||
@@ -592,16 +539,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
    (void) rhport;
 | 
			
		||||
 | 
			
		||||
    pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
 | 
			
		||||
    hw_endpoint_close(ep_addr);
 | 
			
		||||
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
 | 
			
		||||
  hw_endpoint_close(ep_addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  dcd_rp2040_irq();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user