| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -37,6 +37,11 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 *------------------------------------------------------------------*/
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -48,27 +53,27 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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] = {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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return &hw_endpoints[num][dir];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return &hw_endpoints[num][dir];
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -80,81 +85,14 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  uint dpram_offset = hw_data_offset(ep->hw_data_buf);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static void _hw_endpoint_close(struct hw_endpoint *ep)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -174,10 +112,61 @@ static void hw_endpoint_close(uint8_t ep_addr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#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)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -222,55 +211,22 @@ static void reset_ep0(void)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    uint32_t status = usb_hw->ints;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    uint32_t const status = usb_hw->ints;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    uint32_t handled = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (status & USB_INTS_SETUP_REQ_BITS)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -290,7 +246,9 @@ static void dcd_rp2040_irq(void)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pico_trace("BUS RESET\n");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        usb_hw->dev_addr_ctrl = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        handled |= USB_INTS_BUS_RESET_BITS;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        usb_hw->dev_addr_ctrl = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        reset_all_endpoints();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -322,9 +284,6 @@ static void dcd_rp2040_irq(void)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				     * 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
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -346,7 +305,6 @@ static void dcd_rp2040_irq(void)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (status ^ handled)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -364,36 +322,38 @@ static void dcd_rp2040_irq(void)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/*------------------------------------------------------------------*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/* Controller API
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 *------------------------------------------------------------------*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -410,11 +370,13 @@ void dcd_int_disable(uint8_t rhport)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    pico_info("dcd_edpt_open %02x\n", desc_edpt->bEndpointAddress);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assert(rhport == 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    hw_endpoint_init(desc_edpt->bEndpointAddress, desc_edpt->wMaxPacketSize.size, desc_edpt->bmAttributes.xfer);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    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;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				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)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -500,8 +478,8 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void dcd_int_handler(uint8_t rhport)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    (void) rhport;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    dcd_rp2040_irq();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  (void) rhport;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  dcd_rp2040_irq();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#endif
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |