| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * The MIT License (MIT) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
					
						
							|  |  |  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file is part of the TinyUSB stack. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "tusb_option.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-08 13:36:05 +07:00
										 |  |  | #if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "pico.h"
 | 
					
						
							| 
									
										
										
										
											2023-03-10 14:01:51 -05:00
										 |  |  | #include "hardware/sync.h"
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | #include "rp2040_usb.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
 | 
					
						
							|  |  |  | #include "pico/fix/rp2040_usb_device_enumeration.h"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "device/dcd.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | // 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /* Low level controller
 | 
					
						
							|  |  |  |  *------------------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Init these in dcd_init
 | 
					
						
							|  |  |  | static uint8_t *next_buffer_ptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 09:15:42 -06:00
										 |  |  | // USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
 | 
					
						
							| 
									
										
										
										
											2021-08-12 15:40:26 +07:00
										 |  |  | static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2]; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  | // SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
 | 
					
						
							|  |  |  | static bool _sof_enable = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 16:08:27 +07:00
										 |  |  | TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint *hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  |   return &hw_endpoints[num][dir]; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-02-23 12:06:41 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  | static void _hw_endpoint_alloc(struct hw_endpoint *ep, uint8_t transfer_type) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  |   // size must be multiple of 64
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  |   uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 15:40:26 +07:00
										 |  |  |   // double buffered Bulk endpoint
 | 
					
						
							|  |  |  |   if ( transfer_type == TUSB_XFER_BULK ) | 
					
						
							| 
									
										
										
										
											2021-06-13 18:30:26 +07:00
										 |  |  |   { | 
					
						
							|  |  |  |     size *= 2u; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   ep->hw_data_buf = next_buffer_ptr; | 
					
						
							|  |  |  |   next_buffer_ptr += size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0); | 
					
						
							|  |  |  |   uint dpram_offset = hw_data_offset(ep->hw_data_buf); | 
					
						
							| 
									
										
										
										
											2021-12-04 16:04:48 +02:00
										 |  |  |   hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-05 21:26:22 +08:00
										 |  |  |   pico_info("  Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf); | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Fill in endpoint control register with buffer offset
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  |   uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset; | 
					
						
							| 
									
										
										
										
											2021-06-13 17:19:14 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   *ep->endpoint_control = reg; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:11:04 +07:00
										 |  |  | 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)); | 
					
						
							| 
									
										
										
										
											2021-12-04 16:04:48 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 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]; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-12 00:11:04 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); | 
					
						
							| 
									
										
										
										
											2021-08-12 00:11:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   const uint8_t num = tu_edpt_number(ep_addr); | 
					
						
							|  |  |  |   const tusb_dir_t dir = tu_edpt_dir(ep_addr); | 
					
						
							| 
									
										
										
										
											2021-06-13 16:16:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   ep->ep_addr = ep_addr; | 
					
						
							| 
									
										
										
										
											2021-06-13 16:16:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   // For device, IN is a tx transfer and OUT is an rx transfer
 | 
					
						
							|  |  |  |   ep->rx = (dir == TUSB_DIR_OUT); | 
					
						
							| 
									
										
										
										
											2021-06-13 16:16:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  |   ep->next_pid = 0u; | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   ep->wMaxPacketSize = wMaxPacketSize; | 
					
						
							|  |  |  |   ep->transfer_type = transfer_type; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   // 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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   // Clear existing buffer control state
 | 
					
						
							|  |  |  |   *ep->buffer_control = 0; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   if ( num == 0 ) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |     // EP0 has no endpoint control register because the buffer offsets are fixed
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |     ep->endpoint_control = NULL; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 15:40:26 +07:00
										 |  |  |     // Buffer offset is fixed (also double buffered)
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |       ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |     // alloc a buffer and fill in endpoint control register
 | 
					
						
							| 
									
										
										
										
											2021-08-12 15:40:26 +07:00
										 |  |  |     _hw_endpoint_alloc(ep, transfer_type); | 
					
						
							| 
									
										
										
										
											2021-08-12 00:12:15 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 17:05:49 +07:00
										 |  |  | static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); | 
					
						
							| 
									
										
										
										
											2021-06-11 17:34:51 +07:00
										 |  |  |     hw_endpoint_xfer_start(ep, buffer, total_bytes); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-16 11:03:53 -05:00
										 |  |  | static void __tusb_irq_path_func(hw_handle_buff_status)(void) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     uint32_t remaining_buffers = usb_hw->buf_status; | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |     pico_trace("buf_status = 0x%08x\n", remaining_buffers); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     uint bit = 1u; | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  |     for (uint8_t i = 0; remaining_buffers && i < USB_MAX_ENDPOINTS * 2; i++) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (remaining_buffers & bit) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // clear this in advance
 | 
					
						
							|  |  |  |             usb_hw_clear->buf_status = bit; | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |             // IN transfer for even i, OUT transfer for odd i
 | 
					
						
							| 
									
										
										
										
											2023-03-17 23:53:38 +07:00
										 |  |  |             struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN); | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |             // Continue xfer
 | 
					
						
							| 
									
										
										
										
											2021-06-11 17:34:51 +07:00
										 |  |  |             bool done = hw_endpoint_xfer_continue(ep); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |             if (done) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Notify
 | 
					
						
							| 
									
										
										
										
											2021-06-11 17:58:29 +07:00
										 |  |  |                 dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |                 hw_endpoint_reset_transfer(ep); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             remaining_buffers &= ~bit; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         bit <<= 1u; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-08 16:08:27 +07:00
										 |  |  | TU_ATTR_ALWAYS_INLINE static inline void reset_ep0_pid(void) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     // If we have finished this transfer on EP0 set pid back to 1 for next
 | 
					
						
							|  |  |  |     // setup transfer. Also clear a stall in case
 | 
					
						
							|  |  |  |     uint8_t addrs[] = {0x0, 0x80}; | 
					
						
							| 
									
										
										
										
											2021-01-23 20:21:58 -06:00
										 |  |  |     for (uint i = 0 ; i < TU_ARRAY_SIZE(addrs); i++) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     { | 
					
						
							|  |  |  |         struct hw_endpoint *ep = hw_endpoint_get_by_addr(addrs[i]); | 
					
						
							|  |  |  |         ep->next_pid = 1u; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-16 11:03:53 -05:00
										 |  |  | static void __tusb_irq_path_func(reset_non_control_endpoints)(void) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  |   // Disable all non-control
 | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  |   // clear non-control hw endpoints
 | 
					
						
							|  |  |  |   tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2*sizeof(hw_endpoint_t)); | 
					
						
							| 
									
										
										
										
											2021-12-04 16:04:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-07 15:35:30 +02:00
										 |  |  |   // reclaim buffer space
 | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  |   next_buffer_ptr = &usb_dpram->epx_data[0]; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-16 11:03:53 -05:00
										 |  |  | static void __tusb_irq_path_func(dcd_rp2040_irq)(void) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   uint32_t const status = usb_hw->ints; | 
					
						
							|  |  |  |   uint32_t handled = 0; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   if ( status & USB_INTF_DEV_SOF_BITS ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     bool keep_sof_alive = false; | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     handled |= USB_INTF_DEV_SOF_BITS; | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  | #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
 | 
					
						
							| 
									
										
										
										
											2023-01-31 19:03:31 +07:00
										 |  |  |     // Errata 15 workaround for Device Bulk-In endpoint
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     e15_last_sof = time_us_32(); | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     for ( uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++ ) | 
					
						
							| 
									
										
										
										
											2021-12-08 12:33:30 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |       struct hw_endpoint * ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN); | 
					
						
							| 
									
										
										
										
											2021-12-08 12:33:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |       // Active Bulk IN endpoint requires SOF
 | 
					
						
							|  |  |  |       if ( (ep->transfer_type == TUSB_XFER_BULK) && ep->active ) | 
					
						
							| 
									
										
										
										
											2023-01-31 11:38:15 +07:00
										 |  |  |       { | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |         keep_sof_alive = true; | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |         hw_endpoint_lock_update(ep, 1); | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  |         // Deferred enable?
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |         if ( ep->pending ) | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  |           ep->pending = 0; | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |           hw_endpoint_start_next_buffer(ep); | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  |         hw_endpoint_lock_update(ep, -1); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     // 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; | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   // 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 ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     handled |= USB_INTS_BUFF_STATUS_BITS; | 
					
						
							|  |  |  |     hw_handle_buff_status(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-12-08 12:33:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   if ( status & USB_INTS_SETUP_REQ_BITS ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     handled |= USB_INTS_SETUP_REQ_BITS; | 
					
						
							| 
									
										
										
										
											2023-03-02 14:32:22 -06:00
										 |  |  |     uint8_t const * setup = remove_volatile_cast(uint8_t const*, &usb_dpram->setup_packet); | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     // reset pid to both 1 (data and ack)
 | 
					
						
							|  |  |  |     reset_ep0_pid(); | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     // Pass setup packet to tiny usb
 | 
					
						
							|  |  |  |     dcd_event_setup_received(0, setup, true); | 
					
						
							|  |  |  |     usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | #if FORCE_VBUS_DETECT == 0
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   // 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; | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Connected: nothing to do
 | 
					
						
							|  |  |  |     }else | 
					
						
							| 
									
										
										
										
											2021-03-04 18:36:18 +07:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |       // Disconnected
 | 
					
						
							|  |  |  |       dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   // SE0 for 2.5 us or more (will last at least 10ms)
 | 
					
						
							|  |  |  |   if ( status & USB_INTS_BUS_RESET_BITS ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     pico_trace("BUS RESET\n"); | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     handled |= USB_INTS_BUS_RESET_BITS; | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     usb_hw->dev_addr_ctrl = 0; | 
					
						
							|  |  |  |     reset_non_control_endpoints(); | 
					
						
							|  |  |  |     dcd_event_bus_reset(0, TUSB_SPEED_FULL, true); | 
					
						
							|  |  |  |     usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS; | 
					
						
							| 
									
										
										
										
											2021-03-04 18:36:18 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
 | 
					
						
							| 
									
										
										
										
											2023-01-31 19:03:31 +07:00
										 |  |  |     // Only run enumeration workaround if pull up is enabled
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |     if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix(); | 
					
						
							| 
									
										
										
										
											2021-03-04 18:36:18 +07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-03-04 18:36:18 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   /* 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 | 
					
						
							|  |  |  |    * the host begins sending start of frame packets. You will also see a suspend interrupt | 
					
						
							|  |  |  |    * when the device is disconnected if you do not have a VBUS detect circuit connected. This is | 
					
						
							|  |  |  |    * because without VBUS detection, it is impossible to tell the difference between | 
					
						
							|  |  |  |    * being disconnected and suspended. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-03-02 23:24:36 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 14:48:11 +07:00
										 |  |  |   if ( status ^ handled ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define USB_INTS_ERROR_BITS ( \
 | 
					
						
							|  |  |  |     USB_INTS_ERROR_DATA_SEQ_BITS      |  \ | 
					
						
							|  |  |  |     USB_INTS_ERROR_BIT_STUFF_BITS     |  \ | 
					
						
							|  |  |  |     USB_INTS_ERROR_CRC_BITS           |  \ | 
					
						
							|  |  |  |     USB_INTS_ERROR_RX_OVERFLOW_BITS   |  \ | 
					
						
							|  |  |  |     USB_INTS_ERROR_RX_TIMEOUT_BITS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /* Controller API
 | 
					
						
							|  |  |  |  *------------------------------------------------------------------*/ | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-10 14:39:57 +07:00
										 |  |  | // older SDK
 | 
					
						
							|  |  |  | #ifndef PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY
 | 
					
						
							|  |  |  | #define PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY 0xff
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | void dcd_init (uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  |   assert(rhport == 0); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  |   // Reset hardware to default state
 | 
					
						
							|  |  |  |   rp2040_usb_init(); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | #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
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 09:13:40 -05:00
										 |  |  |   irq_add_shared_handler(USBCTRL_IRQ, dcd_rp2040_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY); | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  |   // Init control endpoints
 | 
					
						
							|  |  |  |   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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Init non-control endpoints
 | 
					
						
							|  |  |  |   reset_non_control_endpoints(); | 
					
						
							| 
									
										
										
										
											2021-08-11 20:06:57 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // 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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_int_enable(__unused uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(rhport == 0); | 
					
						
							|  |  |  |     irq_set_enabled(USBCTRL_IRQ, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_int_disable(__unused uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(rhport == 0); | 
					
						
							|  |  |  |     irq_set_enabled(USBCTRL_IRQ, false); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_set_address (__unused uint8_t rhport, __unused uint8_t dev_addr) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-12 00:11:04 +07:00
										 |  |  |   assert(rhport == 0); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:11:04 +07:00
										 |  |  |   // Can't set device address in hardware until status xfer has complete
 | 
					
						
							|  |  |  |   // Send 0len complete response on EP0 IN
 | 
					
						
							|  |  |  |   hw_endpoint_xfer(0x80, NULL, 0); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_remote_wakeup(__unused uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  |   pico_info("dcd_remote_wakeup %d\n", rhport); | 
					
						
							|  |  |  |   assert(rhport == 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // since RESUME interrupt is not triggered if we are the one initiate
 | 
					
						
							|  |  |  |   // briefly enable SOF to notify usbd when bus is ready
 | 
					
						
							|  |  |  |   usb_hw_set->inte = USB_INTS_DEV_SOF_BITS; | 
					
						
							|  |  |  |   usb_hw_set->sie_ctrl = USB_SIE_CTRL_RESUME_BITS; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // disconnect by disabling internal pull-up resistor on D+/D-
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_disconnect(__unused uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-31 17:41:08 +07:00
										 |  |  |   (void) rhport; | 
					
						
							|  |  |  |   usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // connect by enabling internal pull-up resistor on D+/D-
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | void dcd_connect(__unused uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-31 17:41:08 +07:00
										 |  |  |   (void) rhport; | 
					
						
							|  |  |  |   usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  | void dcd_sof_enable(uint8_t rhport, bool en) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  |   _sof_enable = en; | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (en) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  |     usb_hw_set->inte = USB_INTS_DEV_SOF_BITS; | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  |   }else | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  |     // 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
 | 
					
						
							| 
									
										
										
										
											2022-06-30 15:45:04 +07:00
										 |  |  |     usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS; | 
					
						
							| 
									
										
										
										
											2023-01-05 13:36:51 +00:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2022-03-07 23:04:47 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | /*------------------------------------------------------------------*/ | 
					
						
							|  |  |  | /* DCD Endpoint port
 | 
					
						
							|  |  |  |  *------------------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-13 18:30:26 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-13 18:30:26 +07:00
										 |  |  |   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; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | bool dcd_edpt_open (__unused uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(rhport == 0); | 
					
						
							| 
									
										
										
										
											2021-10-24 13:11:21 +07:00
										 |  |  |     hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-26 17:02:24 +07:00
										 |  |  | void dcd_edpt_close_all (uint8_t rhport) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2021-09-01 19:42:40 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // may need to use EP Abort
 | 
					
						
							|  |  |  |   reset_non_control_endpoints(); | 
					
						
							| 
									
										
										
										
											2021-08-26 17:02:24 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-14 15:20:32 -05:00
										 |  |  | bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(rhport == 0); | 
					
						
							| 
									
										
										
										
											2021-06-11 17:05:49 +07:00
										 |  |  |     hw_endpoint_xfer(ep_addr, buffer, total_bytes); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |   // stall and clear current pending buffer
 | 
					
						
							|  |  |  |   // may need to use EP_ABORT
 | 
					
						
							|  |  |  |   _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  | void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |   (void) rhport; | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  |   if (tu_edpt_number(ep_addr)) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-01 16:52:27 +07:00
										 |  |  |     // clear stall also reset toggle to DATA0, ready for next transfer
 | 
					
						
							|  |  |  |     ep->next_pid = 0; | 
					
						
							|  |  |  |     _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL); | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-06-17 01:55:35 +07:00
										 |  |  |     (void) rhport; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pico_trace("dcd_edpt_close %02x\n", ep_addr); | 
					
						
							| 
									
										
										
										
											2021-12-04 16:04:48 +02:00
										 |  |  |     hw_endpoint_close(ep_addr); | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-16 11:03:53 -05:00
										 |  |  | void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) | 
					
						
							| 
									
										
										
										
											2021-01-23 20:21:58 -06:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-11 20:29:39 +07:00
										 |  |  |   (void) rhport; | 
					
						
							|  |  |  |   dcd_rp2040_irq(); | 
					
						
							| 
									
										
										
										
											2021-01-23 20:21:58 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-19 19:52:07 -06:00
										 |  |  | #endif
 |