From cf0a475a2e501f21638369eca6ceb090ef47bd51 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 10 Jun 2021 22:00:59 +0700 Subject: [PATCH 01/19] clean up --- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 101 ++++++++++--------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index b575c6afc..7042160ec 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -52,22 +52,23 @@ static_assert(PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS, ""); // Host mode uses one shared endpoint register for non-interrupt endpoint -struct hw_endpoint eps[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS]; -#define epx (eps[0]) +static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS]; +#define epx (ep_pool[0]) -#define usb_hw_set hw_set_alias(usb_hw) +#define usb_hw_set hw_set_alias(usb_hw) #define usb_hw_clear hw_clear_alias(usb_hw) -// Used for hcd pipe busy. // todo still a bit wasteful // top bit set if valid uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2]; // Flags we set by default in sie_ctrl (we add other bits on top) -static uint32_t sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS | - USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | - USB_SIE_CTRL_PULLDOWN_EN_BITS | - USB_SIE_CTRL_EP0_INT_1BUF_BITS; +enum { + sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS | + USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | + USB_SIE_CTRL_PULLDOWN_EN_BITS | + USB_SIE_CTRL_EP0_INT_1BUF_BITS +}; static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) { @@ -78,19 +79,22 @@ static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0; uint mapping = dev_ep_map[dev_addr-1][num][in]; pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping); - return mapping >= 128 ? eps + (mapping & 0x7fu) : NULL; + return mapping >= 128 ? ep_pool + (mapping & 0x7fu) : NULL; } static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep) { uint8_t num = tu_edpt_number(ep_addr); - uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0; - uint32_t index = ep - eps; - hard_assert(index < TU_ARRAY_SIZE(eps)); + uint8_t in = (uint8_t) tu_edpt_dir(ep_addr); + + uint32_t index = ep - ep_pool; + hard_assert(index < TU_ARRAY_SIZE(ep_pool)); + // todo revisit why dev_addr can be 0 here if (dev_addr) { dev_ep_map[dev_addr-1][num][in] = 128u | index; } + pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index); } @@ -153,7 +157,7 @@ static void hw_handle_buff_status(void) if (remaining_buffers & bit) { remaining_buffers &= ~bit; - _handle_buff_status_bit(bit, &eps[i]); + _handle_buff_status_bit(bit, &ep_pool[i]); } } @@ -206,13 +210,15 @@ static void hcd_rp2040_irq(void) { handled |= USB_INTS_TRANS_COMPLETE_BITS; usb_hw_clear->sie_status = USB_SIE_STATUS_TRANS_COMPLETE_BITS; + TU_LOG(2, "Transfer complete\n"); hw_trans_complete(); } if (status & USB_INTS_BUFF_STATUS_BITS) { handled |= USB_INTS_BUFF_STATUS_BITS; - // print_bufctrl32(*epx.buffer_control); + TU_LOG(2, "Buffer complete\n"); + print_bufctrl32(*epx.buffer_control); hw_handle_buff_status(); } @@ -234,7 +240,7 @@ static void hcd_rp2040_irq(void) if (status & USB_INTS_ERROR_DATA_SEQ_BITS) { usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS; - // print_bufctrl32(*epx.buffer_control); + print_bufctrl32(*epx.buffer_control); panic("Data Seq Error \n"); } @@ -247,9 +253,9 @@ static void hcd_rp2040_irq(void) static struct hw_endpoint *_next_free_interrupt_ep(void) { struct hw_endpoint *ep = NULL; - for (uint i = 1; i < TU_ARRAY_SIZE(eps); i++) + for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) { - ep = &eps[i]; + ep = &ep_pool[i]; if (!ep->configured) { // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate @@ -263,6 +269,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void) static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) { struct hw_endpoint *ep = NULL; + if (transfer_type == TUSB_XFER_INTERRUPT) { ep = _next_free_interrupt_ep(); @@ -283,6 +290,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) ep->endpoint_control = &usbh_dpram->epx_ctrl; ep->hw_data_buf = &usbh_dpram->epx_data[0]; } + return ep; } @@ -345,24 +353,9 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t // If it's an interrupt endpoint we need to set up the buffer control // register - } } -static void hw_endpoint_init(uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) -{ - // Allocated differently based on if it's an interrupt endpoint or not - struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); - _hw_endpoint_init(ep, - dev_addr, - ep_desc->bEndpointAddress, - ep_desc->wMaxPacketSize.size, - ep_desc->bmAttributes.xfer, - ep_desc->bInterval); - // Map this struct to ep@device address - set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); -} - //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ @@ -377,7 +370,7 @@ bool hcd_init(uint8_t rhport) irq_set_exclusive_handler(USBCTRL_IRQ, hcd_rp2040_irq); // clear epx and interrupt eps - memset(&eps, 0, sizeof(eps)); + memset(&ep_pool, 0, sizeof(ep_pool)); // Enable in host mode with SOF / Keep alive on usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS; @@ -420,6 +413,7 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) return TUSB_SPEED_FULL; default: panic("Invalid speed\n"); + return TUSB_SPEED_INVALID; } } @@ -444,7 +438,7 @@ void hcd_int_disable(uint8_t rhport) bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { - pico_info("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); + pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); // Get appropriate ep. Either EPX or interrupt endpoint struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr); @@ -452,13 +446,12 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * if (ep_addr != ep->ep_addr) { - // Direction has flipped so re init it but with same properties - // TODO treat IN and OUT as invidual endpoints + // Direction has flipped on endpoint control so re init it but with same properties _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); } // True indicates this is the start of the transfer - _hw_endpoint_xfer(ep, buffer, buflen, true); + _hw_endpoint_xfer_start(ep, buffer, buflen); // If a normal transfer (non-interrupt) then initiate using // sie ctrl registers. Otherwise interrupt ep registers should @@ -479,27 +472,30 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { - pico_info("hcd_setup_send dev_addr %d\n", dev_addr); - // Copy data into setup packet buffer memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8); // Configure EP0 struct with setup info for the trans complete struct hw_endpoint *ep = _hw_endpoint_allocate(0); + // EP0 out _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0); assert(ep->configured); - ep->total_len = 8; + + ep->total_len = 8; ep->transfer_size = 8; - ep->active = true; - ep->sent_setup = true; + ep->active = true; + ep->sent_setup = true; // Set device address usb_hw->dev_addr_ctrl = dev_addr; + // Set pre if we are a low speed device on full speed hub - uint32_t flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS; - flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; + uint32_t const flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS | + (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0); + usb_hw->sie_ctrl = flags; + return true; } @@ -510,8 +506,23 @@ uint32_t hcd_frame_number(uint8_t rhport) bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { + (void) rhport; + pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); - hw_endpoint_init(dev_addr, ep_desc); + + // Allocated differently based on if it's an interrupt endpoint or not + struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); + + _hw_endpoint_init(ep, + dev_addr, + ep_desc->bEndpointAddress, + ep_desc->wMaxPacketSize.size, + ep_desc->bmAttributes.xfer, + ep_desc->bInterval); + + // Map this struct to ep@device address + set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); + return true; } From 43656dc0a7a613f8d5f6533d2c68ca9f5824a5f4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 10 Jun 2021 23:29:02 +0700 Subject: [PATCH 02/19] more clean up --- src/host/usbh_control.c | 2 +- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 77 ++++++++++++-------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c index 4dbf8592a..aa82f14ba 100644 --- a/src/host/usbh_control.c +++ b/src/host/usbh_control.c @@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, _ctrl_xfer.stage = STAGE_SETUP; _ctrl_xfer.complete_cb = complete_cb; - TU_LOG2("Control Setup: "); + TU_LOG2("Send Setup to address %u: ", dev_addr); TU_LOG2_VAR(request); TU_LOG2("\r\n"); diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 7042160ec..d6bcf5b82 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -420,9 +420,18 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) // Close all opened endpoint belong to this device void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + (void) dev_addr; + pico_trace("hcd_device_close %d\n", dev_addr); } +uint32_t hcd_frame_number(uint8_t rhport) +{ + (void) rhport; + return usb_hw->sof_rd; +} + void hcd_int_enable(uint8_t rhport) { assert(rhport == 0); @@ -436,10 +445,37 @@ void hcd_int_disable(uint8_t rhport) irq_set_enabled(USBCTRL_IRQ, false); } +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) +{ + (void) rhport; + + pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); + + // Allocated differently based on if it's an interrupt endpoint or not + struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); + + _hw_endpoint_init(ep, + dev_addr, + ep_desc->bEndpointAddress, + ep_desc->wMaxPacketSize.size, + ep_desc->bmAttributes.xfer, + ep_desc->bInterval); + + // Map this struct to ep@device address + set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); + + return true; +} + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { + (void) rhport; + pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen); + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); + // Get appropriate ep. Either EPX or interrupt endpoint struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr); assert(ep); @@ -450,7 +486,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); } - // True indicates this is the start of the transfer + // Start the transfer _hw_endpoint_xfer_start(ep, buffer, buflen); // If a normal transfer (non-interrupt) then initiate using @@ -459,11 +495,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * if (ep == &epx) { // That has set up buffer control, endpoint control etc // for host we have to initiate the transfer - usb_hw->dev_addr_ctrl = dev_addr | (tu_edpt_number(ep_addr) << USB_ADDR_ENDP_ENDPOINT_LSB); - uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base; - flags |= ep->rx ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS; + usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB); + + uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base | + (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS); // Set pre if we are a low speed device on full speed hub flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; + usb_hw->sie_ctrl = flags; } @@ -472,6 +510,8 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; + // Copy data into setup packet buffer memcpy((void*)&usbh_dpram->setup_packet[0], setup_packet, 8); @@ -499,32 +539,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet return true; } -uint32_t hcd_frame_number(uint8_t rhport) -{ - return usb_hw->sof_rd; -} - -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) -{ - (void) rhport; - - pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress); - - // Allocated differently based on if it's an interrupt endpoint or not - struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer); - - _hw_endpoint_init(ep, - dev_addr, - ep_desc->bEndpointAddress, - ep_desc->wMaxPacketSize.size, - ep_desc->bmAttributes.xfer, - ep_desc->bInterval); - - // Map this struct to ep@device address - set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); - - return true; -} //bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) //{ @@ -542,6 +556,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + panic("hcd_clear_stall"); return true; } From a1a03c92f66e0c2cae5198341c322182302a1229 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 17:05:49 +0700 Subject: [PATCH 03/19] double buffered work with host --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 10 +- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 103 ++++++- src/portable/raspberrypi/rp2040/rp2040_usb.c | 267 +++++++++---------- src/portable/raspberrypi/rp2040/rp2040_usb.h | 15 +- 4 files changed, 233 insertions(+), 162 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 0048270a6..ccdbb9c01 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -198,10 +198,10 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t b _hw_endpoint_init(ep, ep_addr, wMaxPacketSize, bmAttributes); } -static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool start) +static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); - _hw_endpoint_xfer(ep, buffer, total_bytes, start); + _hw_endpoint_xfer_start(ep, buffer, total_bytes); } static void hw_handle_buff_status(void) @@ -251,7 +251,7 @@ static void ep0_0len_status(void) { // Send 0len complete response on EP0 IN reset_ep0(); - hw_endpoint_xfer(0x80, NULL, 0, true); + hw_endpoint_xfer(0x80, NULL, 0); } static void _hw_endpoint_stall(struct hw_endpoint *ep) @@ -477,7 +477,7 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * re request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) { - pico_trace("Set HW address %d\n", assigned_address); + pico_trace("Set HW address %d\n", request->wValue); usb_hw->dev_addr_ctrl = (uint8_t) request->wValue; } @@ -496,7 +496,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t { assert(rhport == 0); // True means start new xfer - hw_endpoint_xfer(ep_addr, buffer, total_bytes, true); + hw_endpoint_xfer(ep_addr, buffer, total_bytes); return true; } diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index d6bcf5b82..561656a10 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -115,9 +115,9 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result) // Mark transfer as done before we tell the tinyusb stack uint8_t dev_addr = ep->dev_addr; uint8_t ep_addr = ep->ep_addr; - uint total_len = ep->total_len; + uint xferred_len = ep->len; hw_endpoint_reset_transfer(ep); - hcd_event_xfer_complete(dev_addr, ep_addr, total_len, xfer_result, true); + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true); } static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep) @@ -141,6 +141,20 @@ static void hw_handle_buff_status(void) { remaining_buffers &= ~bit; struct hw_endpoint *ep = &epx; + + uint32_t ep_ctrl = *ep->endpoint_control; + if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS) + { + TU_LOG(2, "Double Buffered "); + }else + { + TU_LOG(2, "Single Buffered "); + } + + if (ep_ctrl & EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER) TU_LOG(2, "Interrupt per double "); + if (ep_ctrl & EP_CTRL_INTERRUPT_PER_BUFFER) TU_LOG(2, "Interrupt per single "); + TU_LOG_HEX(2, ep_ctrl); + _handle_buff_status_bit(bit, ep); } @@ -277,11 +291,11 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type) assert(ep); ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl; ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl; - // 0x180 for epx - // 0x1c0 for intep0 - // 0x200 for intep1 + // 0 for epx (double buffered): TODO increase to 1024 for ISO + // 2x64 for intep0 + // 3x64 for intep1 // etc - ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 1)]; + ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)]; } else { @@ -311,7 +325,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep->rx = (dir == TUSB_DIR_IN); // Response to a setup packet on EP0 starts with pid of 1 - ep->next_pid = num == 0 ? 1u : 0u; + ep->next_pid = (num == 0 ? 1u : 0u); ep->wMaxPacketSize = wMaxPacketSize; ep->transfer_type = transfer_type; @@ -340,6 +354,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t // preamble uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB); // Assert the interrupt endpoint is IN_TO_HOST + // TODO Interrupt can also be OUT assert(dir == TUSB_DIR_IN); if (need_pre(dev_addr)) @@ -402,7 +417,6 @@ bool hcd_port_connect_status(uint8_t rhport) tusb_speed_t hcd_port_speed_get(uint8_t rhport) { - pico_trace("hcd_port_speed_get\n"); assert(rhport == 0); // TODO: Should enumval this register switch (dev_speed()) @@ -445,6 +459,10 @@ void hcd_int_disable(uint8_t rhport) irq_set_enabled(USBCTRL_IRQ, false); } +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) { (void) rhport; @@ -467,6 +485,65 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const return true; } +// return true if double buffered +static bool xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) +{ + // Fill in info now that we're kicking off the hw + ep->total_len = total_len; + ep->len = 0; + + // Limit by packet size + ep->user_buf = buffer; + + // Buffer 0 + ep->transfer_size = tu_min16(total_len, ep->wMaxPacketSize); + total_len -= ep->transfer_size; + + // Buffer 1 + ep->buf_1_len = tu_min16(total_len, ep->wMaxPacketSize); + total_len -= ep->buf_1_len; + + ep->active = true; + + // Write buffer control + + // Buffer 0 + uint32_t bufctrl = ep->transfer_size | USB_BUF_CTRL_AVAIL; + + // Copy data to DPB if tx + if (!ep->rx) + { + // Copy data from user buffer to hw buffer + memcpy(ep->hw_data_buf, ep->user_buf, ep->transfer_size + ep->buf_1_len); + + // Mark as full + bufctrl |= USB_BUF_CTRL_FULL | (ep->buf_1_len ? (USB_BUF_CTRL_FULL << 16) : 0); + } + + // PID + bufctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; + ep->next_pid ^= 1u; + + if (ep->buf_1_len) + { + bufctrl |= (ep->buf_1_len | USB_BUF_CTRL_AVAIL) << 16; + bufctrl |= (ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID) << 16; + ep->next_pid ^= 1u; + } + + // determine which buffer is last + if (total_len == 0) + { + bufctrl |= USB_BUF_CTRL_LAST << (ep->buf_1_len ? 16 : 0); + } + + print_bufctrl32(bufctrl); + + _hw_endpoint_buffer_control_set_value32(ep, bufctrl); + + return ep->buf_1_len > 0; +} + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -486,13 +563,12 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); } - // Start the transfer - _hw_endpoint_xfer_start(ep, buffer, buflen); - // If a normal transfer (non-interrupt) then initiate using // sie ctrl registers. Otherwise interrupt ep registers should // already be configured if (ep == &epx) { + _hw_endpoint_xfer_start(ep, buffer, buflen); + // That has set up buffer control, endpoint control etc // for host we have to initiate the transfer usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB); @@ -503,6 +579,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; usb_hw->sie_ctrl = flags; + }else + { + _hw_endpoint_xfer_start(ep, buffer, buflen); } return true; @@ -556,8 +635,8 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) { - (void) rhport; (void) dev_addr; + (void) ep_addr; panic("hcd_clear_stall"); return true; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 31381e6c2..5f61f90c5 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -61,11 +61,11 @@ void rp2040_usb_init(void) memset(usb_dpram, 0, sizeof(*usb_dpram)); // Mux the controller to the onboard usb phy - usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; + usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; // Force VBUS detect so the device thinks it is plugged into a host // TODO support VBUs detect - usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; + usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; } void hw_endpoint_reset_transfer(struct hw_endpoint *ep) @@ -111,150 +111,157 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } +// Prepare buffer control register value void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) { - // Prepare buffer control register value - uint32_t val = ep->transfer_size | USB_BUF_CTRL_AVAIL; + uint16_t remaining = ep->total_len - ep->len; + uint32_t ep_ctrl = *ep->endpoint_control; + uint32_t buf_ctrl; - if (!ep->rx) - { - // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, &ep->user_buf[ep->len], ep->transfer_size); - // Mark as full - val |= USB_BUF_CTRL_FULL; - } + // Buffer 0 + ep->transfer_size = tu_min16(remaining, ep->wMaxPacketSize); + remaining -= ep->transfer_size; - // PID - val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; + buf_ctrl = ep->transfer_size | USB_BUF_CTRL_AVAIL; + if ( !ep->rx ) + { + // Copy data from user buffer to hw buffer + memcpy(ep->hw_data_buf, ep->user_buf+ep->len, ep->transfer_size); -#if TUSB_OPT_DEVICE_ENABLED + // Mark as full + buf_ctrl |= USB_BUF_CTRL_FULL; + } + + // PID + buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; + ep->next_pid ^= 1u; + + // Buffer 1 + ep->buf_1_len = tu_min16(remaining, ep->wMaxPacketSize); + remaining -= ep->buf_1_len; + + if (ep->buf_1_len) + { + buf_ctrl |= (ep->buf_1_len | USB_BUF_CTRL_AVAIL) << 16; + buf_ctrl |= (ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID) << 16; ep->next_pid ^= 1u; -#else - // For Host (also device but since we dictate the endpoint size, following scenario does not occur) - // Next PID depends on the number of packet in case wMaxPacketSize < 64 (e.g Interrupt Endpoint 8, or 12) - // Special case with control status stage where PID is always DATA1 - if ( ep->transfer_size == 0 ) + if ( !ep->rx ) { - // ZLP also toggle data - ep->next_pid ^= 1u; - }else - { - uint32_t packet_count = 1 + ((ep->transfer_size - 1) / ep->wMaxPacketSize); - - if ( packet_count & 0x01 ) - { - ep->next_pid ^= 1u; - } + // Copy data from user buffer to hw buffer + memcpy(ep->hw_data_buf+64, ep->user_buf+ep->len+ep->transfer_size, ep->buf_1_len); } -#endif + // Set endpoint control double buffered bit if needed + ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; + ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; + }else + { + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + } + + *ep->endpoint_control = ep_ctrl; #if TUSB_OPT_HOST_ENABLED - // Is this the last buffer? Only really matters for host mode. Will trigger - // the trans complete irq but also stop it polling. We only really care about - // trans complete for setup packets being sent - if (ep->last_buf) - { - pico_trace("Last buf (%d bytes left)\n", ep->transfer_size); - val |= USB_BUF_CTRL_LAST; - } + // Is this the last buffer? Only really matters for host mode. Will trigger + // the trans complete irq but also stop it polling. We only really care about + // trans complete for setup packets being sent + if (remaining == 0) + { + buf_ctrl |= USB_BUF_CTRL_LAST << (ep->buf_1_len ? 16 : 0); + } #endif - // Finally, write to buffer_control which will trigger the transfer - // the next time the controller polls this dpram address - _hw_endpoint_buffer_control_set_value32(ep, val); - pico_trace("buffer control (0x%p) <- 0x%x\n", ep->buffer_control, val); - //print_bufctrl16(val); + print_bufctrl32(buf_ctrl); + + // Finally, write to buffer_control which will trigger the transfer + // the next time the controller polls this dpram address + _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); } void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) { - _hw_endpoint_lock_update(ep, 1); - pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - if (ep->active) - { - // TODO: Is this acceptable for interrupt packets? - pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + _hw_endpoint_lock_update(ep, 1); + pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), + ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + if ( ep->active ) + { + // TODO: Is this acceptable for interrupt packets? + pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), + ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - hw_endpoint_reset_transfer(ep); - } + hw_endpoint_reset_transfer(ep); + } - // Fill in info now that we're kicking off the hw - ep->total_len = total_len; - ep->len = 0; + // Fill in info now that we're kicking off the hw + ep->total_len = total_len; + ep->len = 0; + ep->active = true; + ep->user_buf = buffer; - // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0) - ep->transfer_size = tu_min16(total_len, tu_max16(64, ep->wMaxPacketSize)); - - ep->active = true; - ep->user_buf = buffer; -#if TUSB_OPT_HOST_ENABLED - // Recalculate if this is the last buffer - _hw_endpoint_update_last_buf(ep); - ep->buf_sel = 0; -#endif - - _hw_endpoint_start_next_buffer(ep); - _hw_endpoint_lock_update(ep, -1); + _hw_endpoint_start_next_buffer(ep); + _hw_endpoint_lock_update(ep, -1); } -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep) +void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) { - // Update hw endpoint struct with info from hardware - // after a buff status interrupt + // Update hw endpoint struct with info from hardware + // after a buff status interrupt - uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + uint32_t const buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + print_bufctrl32(buf_ctrl); -#if TUSB_OPT_HOST_ENABLED - // RP2040-E4 - // tag::host_buf_sel_fix[] - // TODO need changes to support double buffering - if (ep->buf_sel == 1) + // Transferred bytes for each buffer + uint16_t xferred_bytes[2]; + + xferred_bytes[0] = buf_ctrl & USB_BUF_CTRL_LEN_MASK; + + // double buffered: take buffer1 into account as well + if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) + { + xferred_bytes[1] = (buf_ctrl >> 16) & USB_BUF_CTRL_LEN_MASK; + }else + { + xferred_bytes[1] = 0; + } + + TU_LOG_INT(2, xferred_bytes[0]); + TU_LOG_INT(2, xferred_bytes[1]); + + // We are continuing a transfer here. If we are TX, we have successfully + // sent some data can increase the length we have sent + if ( !ep->rx ) + { + assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); + ep->len += xferred_bytes[0] + xferred_bytes[1]; + } + else + { + // If we are OUT we have recieved some data, so can increase the length + // we have recieved AFTER we have copied it to the user buffer at the appropriate offset + assert(buf_ctrl & USB_BUF_CTRL_FULL); + + memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, xferred_bytes[0]); + ep->len += xferred_bytes[0]; + + if (xferred_bytes[1]) { - // Host can erroneously write status to top half of buf_ctrl register - buf_ctrl = buf_ctrl >> 16; - - // update buf1 -> buf0 to prevent panic with "already available" - *ep->buffer_control = buf_ctrl; + memcpy(&ep->user_buf[ep->len], ep->hw_data_buf+64, xferred_bytes[1]); + ep->len += xferred_bytes[1]; } - // Flip buf sel for host - ep->buf_sel ^= 1u; - // end::host_buf_sel_fix[] -#endif + } - // Get tranferred bytes after adjusted buf sel - uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; - - // We are continuing a transfer here. If we are TX, we have successfullly - // sent some data can increase the length we have sent - if (!ep->rx) - { - assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); - pico_trace("tx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl); - ep->len += transferred_bytes; - } - else - { - // If we are OUT we have recieved some data, so can increase the length - // we have recieved AFTER we have copied it to the user buffer at the appropriate - // offset - pico_trace("rx %d bytes (buf_ctrl 0x%08x)\n", transferred_bytes, buf_ctrl); - assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, transferred_bytes); - ep->len += transferred_bytes; - } - - // Sometimes the host will send less data than we expect... - // If this is a short out transfer update the total length of the transfer - // to be the current length - if ((ep->rx) && (transferred_bytes < ep->wMaxPacketSize)) - { - pico_trace("Short rx transfer\n"); - // Reduce total length as this is last packet - ep->total_len = ep->len; - } + // Sometimes the host will send less data than we expect... + // If this is a short out transfer update the total length of the transfer + // to be the current length + if ( (ep->rx) && ((xferred_bytes[0] < ep->wMaxPacketSize) || (xferred_bytes[1] && (xferred_bytes[1] < ep->wMaxPacketSize))) ) + { + pico_trace("Short rx transfer\n"); + // Reduce total length as this is last packet + ep->total_len = ep->len; + } } // Returns true if transfer is complete @@ -271,12 +278,11 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep) _hw_endpoint_xfer_sync(ep); // Now we have synced our state with the hardware. Is there more data to transfer? - // Limit by packet size but not less 64 (i.e low speed 8 bytes EP0) + // Limit by packet size uint16_t remaining_bytes = ep->total_len - ep->len; - ep->transfer_size = tu_min16(remaining_bytes, tu_max16(64, ep->wMaxPacketSize)); -#if TUSB_OPT_HOST_ENABLED - _hw_endpoint_update_last_buf(ep); -#endif + ep->transfer_size = tu_min16(remaining_bytes, ep->wMaxPacketSize); + + TU_LOG_INT(2, ep->transfer_size); // Can happen because of programmer error so check for it if (ep->len > ep->total_len) @@ -303,23 +309,4 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep) return false; } -void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start) -{ - // Trace - pico_trace("hw_endpoint_xfer ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - pico_trace(" total_len %d, start=%d\n", total_len, start); - - assert(ep->configured); - - - if (start) - { - _hw_endpoint_xfer_start(ep, buffer, total_len); - } - else - { - _hw_endpoint_xfer_continue(ep); - } -} - #endif diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 33f3ecd41..d27f4157a 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -17,7 +17,7 @@ #endif -#if false && !defined(NDEBUG) +#if true || false && !defined(NDEBUG) #define pico_trace(format,args...) printf(format, ## args) #else #define pico_trace(format,...) ((void)0) @@ -50,6 +50,7 @@ struct hw_endpoint // Endpoint control register io_rw_32 *endpoint_control; + // Buffer control register io_rw_32 *buffer_control; @@ -63,8 +64,11 @@ struct hw_endpoint bool active; uint16_t total_len; uint16_t len; + // Amount of data with the hardware - uint16_t transfer_size; + uint16_t transfer_size; // buf0_len; + uint16_t buf_1_len; + // User buffer in main memory uint8_t *user_buf; @@ -76,6 +80,7 @@ struct hw_endpoint #if TUSB_OPT_HOST_ENABLED // Only needed for host mode bool last_buf; + // RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer // control register when doing transfers > 1 packet uint8_t buf_sel; @@ -90,11 +95,11 @@ struct hw_endpoint void rp2040_usb_init(void); void hw_endpoint_reset_transfer(struct hw_endpoint *ep); -void _hw_endpoint_xfer(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len, bool start); void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep); + void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask); static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) { return *ep->buffer_control; @@ -149,11 +154,11 @@ static inline void print_bufctrl32(uint32_t u32) uint16_t u16; u16 = u32 >> 16; - TU_LOG(2, "Buffer Control 1 0x%x: ", u16); + TU_LOG(2, " Buffer Control 1 0x%x: ", u16); print_bufctrl16(u16); u16 = u32 & 0x0000ffff; - TU_LOG(2, "Buffer Control 0 0x%x: ", u16); + TU_LOG(2, " Buffer Control 0 0x%x: ", u16); print_bufctrl16(u16); } From 572d986a0260543ada22592e3f2216a152ac632d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 17:14:22 +0700 Subject: [PATCH 04/19] improve usbh --- examples/host/cdc_msc_hid/src/hid_app.c | 12 +++- src/class/hid/hid_host.c | 10 ---- src/common/tusb_common.h | 4 +- src/host/usbh.c | 78 +++++++++++++------------ src/host/usbh_control.c | 4 +- 5 files changed, 56 insertions(+), 52 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 23ab12404..817646dab 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -30,7 +30,8 @@ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ -// If your host terminal support ansi escape code, it can be use to simulate mouse cursor +// If your host terminal support ansi escape code such as TeraTerm +// it can be use to simulate mouse cursor movement within terminal #define USE_ANSI_ESCAPE 0 #define MAX_REPORT 4 @@ -113,6 +114,13 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons return; } + // For complete list of Usage Page & Usage checkout src/class/hid/hid.h. For examples: + // - Keyboard : Desktop, Keyboard + // - Mouse : Desktop, Mouse + // - Gamepad : Desktop, Gamepad + // - Consumer Control (Media Key) : Consumer, Consumer Control + // - System Control (Power key) : Desktop, System Control + // - Generic (vendor) : 0xFFxx, xx if ( rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP ) { switch (rpt_info->usage) @@ -164,7 +172,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report) }else { // not existed in previous report means the current key is pressed - bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); + bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0]; putchar(ch); if ( ch == '\r' ) putchar('\n'); // added new line for enter key diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index cde5e23a5..a227c2a86 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -37,16 +37,6 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -/* - "KEYBOARD" : in_len=8 , out_len=1, usage_page=0x01, usage=0x06 # Generic Desktop, Keyboard - "MOUSE" : in_len=4 , out_len=0, usage_page=0x01, usage=0x02 # Generic Desktop, Mouse - "CONSUMER" : in_len=2 , out_len=0, usage_page=0x0C, usage=0x01 # Consumer, Consumer Control - "SYS_CONTROL" : in_len=1 , out_len=0, usage_page=0x01, usage=0x80 # Generic Desktop, Sys Control - "GAMEPAD" : in_len=6 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "DIGITIZER" : in_len=5 , out_len=0, usage_page=0x0D, usage=0x02 # Digitizers, Pen - "XAC_COMPATIBLE_GAMEPAD" : in_len=3 , out_len=0, usage_page=0x01, usage=0x05 # Generic Desktop, Game Pad - "RAW" : in_len=64, out_len=0, usage_page=0xFFAF, usage=0xAF # Vendor 0xFFAF "Adafruit", 0xAF - */ typedef struct { uint8_t itf_num; diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 889ad7b25..fe5bf5f41 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -317,8 +317,8 @@ void tu_print_var(uint8_t const* buf, uint32_t bufsize) #define TU_LOG1 tu_printf #define TU_LOG1_MEM tu_print_mem #define TU_LOG1_VAR(_x) tu_print_var((uint8_t const*)(_x), sizeof(*(_x))) -#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\n", (uint32_t) (_x) ) -#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\n", (uint32_t) (_x) ) +#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (uint32_t) (_x) ) +#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (uint32_t) (_x) ) // Log Level 2: Warn #if CFG_TUSB_DEBUG >= 2 diff --git a/src/host/usbh.c b/src/host/usbh.c index 59246a663..81b9e84af 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -795,6 +795,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r return false; } + TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE); + // Reset device again before Set Address TU_LOG2("Port reset \r\n"); @@ -938,7 +940,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request // Parse configuration & set up drivers // Driver open aren't allowed to make any usb transfer yet - parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); + TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) ); TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM); tusb_control_request_t const new_request = @@ -988,49 +990,53 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura // parse each interfaces while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) { - // skip until we see interface descriptor - if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) - { - p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length - }else - { - tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; - // Check if class is supported - uint8_t drv_id; - for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) - { - if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; - } + // Class will always starts with Interface Association (if any) and then Interface descriptor + if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) + { + desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; + p_desc = tu_desc_next(p_desc); // next to Interface + } - if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); + + tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Check if class is supported + uint8_t drv_id; + for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) + { + if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; + } + + if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + { + // skip unsupported class + p_desc = tu_desc_next(p_desc); + } + else + { + usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; + + // Interface number must not be used already TODO alternate interface + TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff ); + dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; + + if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0) { - // skip unsupported class + // TODO Attach hub to Hub is not currently supported + // skip this interface p_desc = tu_desc_next(p_desc); } else { - usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; + TU_LOG2("%s open\r\n", driver->name); - // Interface number must not be used already TODO alternate interface - TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff ); - dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; - - if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0) - { - // TODO Attach hub to Hub is not currently supported - // skip this interface - p_desc = tu_desc_next(p_desc); - } - else - { - TU_LOG2("%s open\r\n", driver->name); - - uint16_t itf_len = 0; - TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) ); - TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); - p_desc += itf_len; - } + uint16_t itf_len = 0; + TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) ); + TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); + p_desc += itf_len; } } } diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c index aa82f14ba..91dbdfe99 100644 --- a/src/host/usbh_control.c +++ b/src/host/usbh_control.c @@ -68,7 +68,7 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, _ctrl_xfer.stage = STAGE_SETUP; _ctrl_xfer.complete_cb = complete_cb; - TU_LOG2("Send Setup to address %u: ", dev_addr); + TU_LOG2("Control Setup (addr = %u): ", dev_addr); TU_LOG2_VAR(request); TU_LOG2("\r\n"); @@ -119,7 +119,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu if (request->wLength) { - TU_LOG2("Control data:\r\n"); + TU_LOG2("Control data (addr = %u):\r\n", dev_addr); TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2); } From 5d6e381ef640fce9f590abe0ce304bf4c9474605 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 17:34:51 +0700 Subject: [PATCH 05/19] refactor rp2040 usb - make _hw_endpoint_xfer_sync and _hw_endpoint_start_next_buffer private - drop prefix _ from _hw_endpoint_xfer_continue and _hw_endpoint_reset_transfer --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 4 +- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 65 +-------------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 85 ++++++++++---------- src/portable/raspberrypi/rp2040/rp2040_usb.h | 6 +- 4 files changed, 48 insertions(+), 112 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index ccdbb9c01..c755c2e6f 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -201,7 +201,7 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t b static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) { struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr); - _hw_endpoint_xfer_start(ep, buffer, total_bytes); + hw_endpoint_xfer_start(ep, buffer, total_bytes); } static void hw_handle_buff_status(void) @@ -221,7 +221,7 @@ static void hw_handle_buff_status(void) // IN transfer for even i, OUT transfer for odd i struct hw_endpoint *ep = hw_endpoint_get_by_num(i >> 1u, !(i & 1u)); // Continue xfer - bool done = _hw_endpoint_xfer_continue(ep); + bool done = hw_endpoint_xfer_continue(ep); if (done) { // Notify diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 561656a10..1ba9725fe 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -123,7 +123,7 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result) static void _handle_buff_status_bit(uint bit, struct hw_endpoint *ep) { usb_hw_clear->buf_status = bit; - bool done = _hw_endpoint_xfer_continue(ep); + bool done = hw_endpoint_xfer_continue(ep); if (done) { hw_xfer_complete(ep, XFER_RESULT_SUCCESS); @@ -485,65 +485,6 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const return true; } -// return true if double buffered -static bool xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) -{ - // Fill in info now that we're kicking off the hw - ep->total_len = total_len; - ep->len = 0; - - // Limit by packet size - ep->user_buf = buffer; - - // Buffer 0 - ep->transfer_size = tu_min16(total_len, ep->wMaxPacketSize); - total_len -= ep->transfer_size; - - // Buffer 1 - ep->buf_1_len = tu_min16(total_len, ep->wMaxPacketSize); - total_len -= ep->buf_1_len; - - ep->active = true; - - // Write buffer control - - // Buffer 0 - uint32_t bufctrl = ep->transfer_size | USB_BUF_CTRL_AVAIL; - - // Copy data to DPB if tx - if (!ep->rx) - { - // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, ep->user_buf, ep->transfer_size + ep->buf_1_len); - - // Mark as full - bufctrl |= USB_BUF_CTRL_FULL | (ep->buf_1_len ? (USB_BUF_CTRL_FULL << 16) : 0); - } - - // PID - bufctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; - ep->next_pid ^= 1u; - - if (ep->buf_1_len) - { - bufctrl |= (ep->buf_1_len | USB_BUF_CTRL_AVAIL) << 16; - bufctrl |= (ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID) << 16; - ep->next_pid ^= 1u; - } - - // determine which buffer is last - if (total_len == 0) - { - bufctrl |= USB_BUF_CTRL_LAST << (ep->buf_1_len ? 16 : 0); - } - - print_bufctrl32(bufctrl); - - _hw_endpoint_buffer_control_set_value32(ep, bufctrl); - - return ep->buf_1_len > 0; -} - bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -567,7 +508,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * // sie ctrl registers. Otherwise interrupt ep registers should // already be configured if (ep == &epx) { - _hw_endpoint_xfer_start(ep, buffer, buflen); + hw_endpoint_xfer_start(ep, buffer, buflen); // That has set up buffer control, endpoint control etc // for host we have to initiate the transfer @@ -581,7 +522,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * usb_hw->sie_ctrl = flags; }else { - _hw_endpoint_xfer_start(ep, buffer, buflen); + hw_endpoint_xfer_start(ep, buffer, buflen); } return true; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 5f61f90c5..293325b8b 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -50,6 +50,13 @@ static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep) } #endif +//--------------------------------------------------------------------+ +// +//--------------------------------------------------------------------+ + +void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); +void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); + void rp2040_usb_init(void) { // Reset usb controller @@ -180,8 +187,7 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl); } - -void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) +void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) { _hw_endpoint_lock_update(ep, 1); pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), @@ -205,58 +211,34 @@ void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t t _hw_endpoint_lock_update(ep, -1); } -void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) +static void ep_sync_buf(struct hw_endpoint *ep, uint8_t buf_id) { - // Update hw endpoint struct with info from hardware - // after a buff status interrupt + uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + if (buf_id) buf_ctrl = buf_ctrl >> 16; - uint32_t const buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); - print_bufctrl32(buf_ctrl); + uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK; - // Transferred bytes for each buffer - uint16_t xferred_bytes[2]; - - xferred_bytes[0] = buf_ctrl & USB_BUF_CTRL_LEN_MASK; - - // double buffered: take buffer1 into account as well - if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) - { - xferred_bytes[1] = (buf_ctrl >> 16) & USB_BUF_CTRL_LEN_MASK; - }else - { - xferred_bytes[1] = 0; - } - - TU_LOG_INT(2, xferred_bytes[0]); - TU_LOG_INT(2, xferred_bytes[1]); - - // We are continuing a transfer here. If we are TX, we have successfully - // sent some data can increase the length we have sent if ( !ep->rx ) { + // We are continuing a transfer here. If we are TX, we have successfully + // sent some data can increase the length we have sent assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); - ep->len += xferred_bytes[0] + xferred_bytes[1]; - } - else + + ep->len += xferred_bytes; + }else { - // If we are OUT we have recieved some data, so can increase the length - // we have recieved AFTER we have copied it to the user buffer at the appropriate offset + // If we have received some data, so can increase the length + // we have received AFTER we have copied it to the user buffer at the appropriate offset assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(&ep->user_buf[ep->len], ep->hw_data_buf, xferred_bytes[0]); - ep->len += xferred_bytes[0]; - - if (xferred_bytes[1]) - { - memcpy(&ep->user_buf[ep->len], ep->hw_data_buf+64, xferred_bytes[1]); - ep->len += xferred_bytes[1]; - } + memcpy(&ep->user_buf[ep->len], ep->hw_data_buf + buf_id*64, xferred_bytes); + ep->len += xferred_bytes; } - // Sometimes the host will send less data than we expect... - // If this is a short out transfer update the total length of the transfer - // to be the current length - if ( (ep->rx) && ((xferred_bytes[0] < ep->wMaxPacketSize) || (xferred_bytes[1] && (xferred_bytes[1] < ep->wMaxPacketSize))) ) + // Short packet + // TODO what if we prepare double buffered but receive short packet on buffer 0 !!! + // would the buffer status or trans complete interrupt is triggered + if (xferred_bytes < ep->wMaxPacketSize) { pico_trace("Short rx transfer\n"); // Reduce total length as this is last packet @@ -264,8 +246,23 @@ void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) } } +void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) +{ + // Update hw endpoint struct with info from hardware + // after a buff status interrupt + + // always sync buffer 0 + ep_sync_buf(ep, 0); + + // sync buffer 1 if double buffered + if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) + { + ep_sync_buf(ep, 1); + } +} + // Returns true if transfer is complete -bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep) +bool hw_endpoint_xfer_continue(struct hw_endpoint *ep) { _hw_endpoint_lock_update(ep, 1); // Part way through a transfer diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index d27f4157a..b3fcb9417 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -94,11 +94,9 @@ struct hw_endpoint void rp2040_usb_init(void); +void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); +bool hw_endpoint_xfer_continue(struct hw_endpoint *ep); void hw_endpoint_reset_transfer(struct hw_endpoint *ep); -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); -void _hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len); -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); -bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep); void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask); static inline uint32_t _hw_endpoint_buffer_control_get_value32(struct hw_endpoint *ep) { From 1d48320d8aa85ebeae617be35614cd80011c37f4 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 17:58:29 +0700 Subject: [PATCH 06/19] rename hw endpoint - total_len to remaining_len - len to xferred_len --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 2 +- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 4 +- src/portable/raspberrypi/rp2040/rp2040_usb.c | 78 +++++++++----------- src/portable/raspberrypi/rp2040/rp2040_usb.h | 6 +- 4 files changed, 41 insertions(+), 49 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index c755c2e6f..3f2bf7810 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -225,7 +225,7 @@ static void hw_handle_buff_status(void) if (done) { // Notify - dcd_event_xfer_complete(0, ep->ep_addr, ep->len, XFER_RESULT_SUCCESS, true); + dcd_event_xfer_complete(0, ep->ep_addr, ep->xferred_len, XFER_RESULT_SUCCESS, true); hw_endpoint_reset_transfer(ep); } remaining_buffers &= ~bit; diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 1ba9725fe..6a1d7cff2 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -115,7 +115,7 @@ static void hw_xfer_complete(struct hw_endpoint *ep, xfer_result_t xfer_result) // Mark transfer as done before we tell the tinyusb stack uint8_t dev_addr = ep->dev_addr; uint8_t ep_addr = ep->ep_addr; - uint xferred_len = ep->len; + uint xferred_len = ep->xferred_len; hw_endpoint_reset_transfer(ep); hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true); } @@ -542,7 +542,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0); assert(ep->configured); - ep->total_len = 8; + ep->remaining_len = 8; ep->transfer_size = 8; ep->active = true; ep->sent_setup = true; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 293325b8b..037b24247 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -43,20 +43,13 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) { // sense to have worker and IRQ on same core, however I think using critsec is about equivalent. } -#if TUSB_OPT_HOST_ENABLED -static inline void _hw_endpoint_update_last_buf(struct hw_endpoint *ep) -{ - ep->last_buf = (ep->len + ep->transfer_size == ep->total_len); -} -#endif +void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); +void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); - void rp2040_usb_init(void) { // Reset usb controller @@ -82,8 +75,8 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep) #if TUSB_OPT_HOST_ENABLED ep->sent_setup = false; #endif - ep->total_len = 0; - ep->len = 0; + ep->remaining_len = 0; + ep->xferred_len = 0; ep->transfer_size = 0; ep->user_buf = 0; } @@ -118,22 +111,29 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } +//static void prepare_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) +//{ +// uint16_t buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); +// +// +//} + // Prepare buffer control register value void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) { - uint16_t remaining = ep->total_len - ep->len; uint32_t ep_ctrl = *ep->endpoint_control; uint32_t buf_ctrl; // Buffer 0 - ep->transfer_size = tu_min16(remaining, ep->wMaxPacketSize); - remaining -= ep->transfer_size; + ep->transfer_size = tu_min16(ep->remaining_len, ep->wMaxPacketSize); + ep->remaining_len -= ep->transfer_size; buf_ctrl = ep->transfer_size | USB_BUF_CTRL_AVAIL; if ( !ep->rx ) { // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, ep->user_buf+ep->len, ep->transfer_size); + memcpy(ep->hw_data_buf, ep->user_buf, ep->transfer_size); + ep->user_buf += ep->transfer_size; // Mark as full buf_ctrl |= USB_BUF_CTRL_FULL; @@ -144,8 +144,8 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) ep->next_pid ^= 1u; // Buffer 1 - ep->buf_1_len = tu_min16(remaining, ep->wMaxPacketSize); - remaining -= ep->buf_1_len; + ep->buf_1_len = tu_min16(ep->remaining_len, ep->wMaxPacketSize); + ep->remaining_len -= ep->buf_1_len; if (ep->buf_1_len) { @@ -156,7 +156,8 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) if ( !ep->rx ) { // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf+64, ep->user_buf+ep->len+ep->transfer_size, ep->buf_1_len); + memcpy(ep->hw_data_buf+64, ep->user_buf, ep->buf_1_len); + ep->user_buf += ep->buf_1_len; } // Set endpoint control double buffered bit if needed @@ -174,7 +175,7 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) // Is this the last buffer? Only really matters for host mode. Will trigger // the trans complete irq but also stop it polling. We only really care about // trans complete for setup packets being sent - if (remaining == 0) + if (ep->remaining_len == 0) { buf_ctrl |= USB_BUF_CTRL_LAST << (ep->buf_1_len ? 16 : 0); } @@ -202,16 +203,16 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to } // Fill in info now that we're kicking off the hw - ep->total_len = total_len; - ep->len = 0; - ep->active = true; - ep->user_buf = buffer; + ep->remaining_len = total_len; + ep->xferred_len = 0; + ep->active = true; + ep->user_buf = buffer; _hw_endpoint_start_next_buffer(ep); _hw_endpoint_lock_update(ep, -1); } -static void ep_sync_buf(struct hw_endpoint *ep, uint8_t buf_id) +static void sync_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) { uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); if (buf_id) buf_ctrl = buf_ctrl >> 16; @@ -224,15 +225,16 @@ static void ep_sync_buf(struct hw_endpoint *ep, uint8_t buf_id) // sent some data can increase the length we have sent assert(!(buf_ctrl & USB_BUF_CTRL_FULL)); - ep->len += xferred_bytes; + ep->xferred_len += xferred_bytes; }else { // If we have received some data, so can increase the length // we have received AFTER we have copied it to the user buffer at the appropriate offset assert(buf_ctrl & USB_BUF_CTRL_FULL); - memcpy(&ep->user_buf[ep->len], ep->hw_data_buf + buf_id*64, xferred_bytes); - ep->len += xferred_bytes; + memcpy(ep->user_buf, ep->hw_data_buf + buf_id*64, xferred_bytes); + ep->xferred_len += xferred_bytes; + ep->user_buf += xferred_bytes; } // Short packet @@ -242,7 +244,7 @@ static void ep_sync_buf(struct hw_endpoint *ep, uint8_t buf_id) { pico_trace("Short rx transfer\n"); // Reduce total length as this is last packet - ep->total_len = ep->len; + ep->remaining_len = 0; } } @@ -252,12 +254,12 @@ void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) // after a buff status interrupt // always sync buffer 0 - ep_sync_buf(ep, 0); + sync_ep_buf(ep, 0); // sync buffer 1 if double buffered if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) { - ep_sync_buf(ep, 1); + sync_ep_buf(ep, 1); } } @@ -275,23 +277,11 @@ bool hw_endpoint_xfer_continue(struct hw_endpoint *ep) _hw_endpoint_xfer_sync(ep); // Now we have synced our state with the hardware. Is there more data to transfer? - // Limit by packet size - uint16_t remaining_bytes = ep->total_len - ep->len; - ep->transfer_size = tu_min16(remaining_bytes, ep->wMaxPacketSize); - - TU_LOG_INT(2, ep->transfer_size); - - // Can happen because of programmer error so check for it - if (ep->len > ep->total_len) - { - panic("Transferred more data than expected"); - } - // If we are done then notify tinyusb - if (ep->len == ep->total_len) + if (ep->remaining_len == 0) { pico_trace("Completed transfer of %d bytes on ep %d %s\n", - ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); // Notify caller we are done so it can notify the tinyusb stack _hw_endpoint_lock_update(ep, -1); return true; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index b3fcb9417..d61a5a57f 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -62,10 +62,12 @@ struct hw_endpoint // Current transfer information bool active; - uint16_t total_len; - uint16_t len; + uint16_t remaining_len; + uint16_t xferred_len; // Amount of data with the hardware + uint16_t buflen[2]; + uint16_t transfer_size; // buf0_len; uint16_t buf_1_len; From 93cb2ff4cf5c9b95ed423be6b8dae498868ab435 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 18:14:11 +0700 Subject: [PATCH 07/19] more refactor double buffered rp2040 --- src/portable/raspberrypi/rp2040/rp2040_usb.c | 179 +++++++++---------- 1 file changed, 86 insertions(+), 93 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 037b24247..38a59d83a 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -52,33 +52,33 @@ void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); void rp2040_usb_init(void) { - // Reset usb controller - reset_block(RESETS_RESET_USBCTRL_BITS); - unreset_block_wait(RESETS_RESET_USBCTRL_BITS); + // Reset usb controller + reset_block(RESETS_RESET_USBCTRL_BITS); + unreset_block_wait(RESETS_RESET_USBCTRL_BITS); - // Clear any previous state just in case - memset(usb_hw, 0, sizeof(*usb_hw)); - memset(usb_dpram, 0, sizeof(*usb_dpram)); + // Clear any previous state just in case + memset(usb_hw, 0, sizeof(*usb_hw)); + memset(usb_dpram, 0, sizeof(*usb_dpram)); - // Mux the controller to the onboard usb phy - usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; + // Mux the controller to the onboard usb phy + usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; - // Force VBUS detect so the device thinks it is plugged into a host - // TODO support VBUs detect - usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; + // Force VBUS detect so the device thinks it is plugged into a host + // TODO support VBUs detect + usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS; } void hw_endpoint_reset_transfer(struct hw_endpoint *ep) { - ep->stalled = false; - ep->active = false; + ep->stalled = false; + ep->active = false; #if TUSB_OPT_HOST_ENABLED - ep->sent_setup = false; + ep->sent_setup = false; #endif - ep->remaining_len = 0; - ep->xferred_len = 0; - ep->transfer_size = 0; - ep->user_buf = 0; + ep->remaining_len = 0; + ep->xferred_len = 0; + ep->transfer_size = 0; + ep->user_buf = 0; } void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask) { @@ -111,76 +111,69 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } -//static void prepare_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) -//{ -// uint16_t buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); -// -// -//} - -// Prepare buffer control register value -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) +static uint32_t compute_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) { - uint32_t ep_ctrl = *ep->endpoint_control; - uint32_t buf_ctrl; + uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); + ep->remaining_len -= buflen; - // Buffer 0 - ep->transfer_size = tu_min16(ep->remaining_len, ep->wMaxPacketSize); - ep->remaining_len -= ep->transfer_size; - - buf_ctrl = ep->transfer_size | USB_BUF_CTRL_AVAIL; - if ( !ep->rx ) - { - // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, ep->user_buf, ep->transfer_size); - ep->user_buf += ep->transfer_size; - - // Mark as full - buf_ctrl |= USB_BUF_CTRL_FULL; - } + uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL; // PID buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID; ep->next_pid ^= 1u; - // Buffer 1 - ep->buf_1_len = tu_min16(ep->remaining_len, ep->wMaxPacketSize); - ep->remaining_len -= ep->buf_1_len; - - if (ep->buf_1_len) + if ( !ep->rx ) { - buf_ctrl |= (ep->buf_1_len | USB_BUF_CTRL_AVAIL) << 16; - buf_ctrl |= (ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID) << 16; - ep->next_pid ^= 1u; + // Copy data from user buffer to hw buffer + memcpy(ep->hw_data_buf, ep->user_buf, buflen); + ep->user_buf += buflen; - if ( !ep->rx ) - { - // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf+64, ep->user_buf, ep->buf_1_len); - ep->user_buf += ep->buf_1_len; - } - - // Set endpoint control double buffered bit if needed - ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; - ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; - }else - { - ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); - ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + // Mark as full + buf_ctrl |= USB_BUF_CTRL_FULL; } - *ep->endpoint_control = ep_ctrl; - #if TUSB_OPT_HOST_ENABLED // Is this the last buffer? Only really matters for host mode. Will trigger // the trans complete irq but also stop it polling. We only really care about // trans complete for setup packets being sent if (ep->remaining_len == 0) { - buf_ctrl |= USB_BUF_CTRL_LAST << (ep->buf_1_len ? 16 : 0); + buf_ctrl |= USB_BUF_CTRL_LAST; } #endif + if (buf_id) buf_ctrl = buf_ctrl << 16; + + return buf_ctrl; +} + +// Prepare buffer control register value +void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) +{ + uint32_t ep_ctrl = *ep->endpoint_control; + + // always compute buffer 0 + uint32_t buf_ctrl = compute_ep_buf(ep, 0); + + if(ep->remaining_len) + { + // Use buffer 1 (double buffered) if there is still data + // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) + + buf_ctrl |= compute_ep_buf(ep, 1); + + // Set endpoint control double buffered bit if needed + ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; + ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER; + }else + { + // Single buffered since 1 is enough + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + } + + *ep->endpoint_control = ep_ctrl; + print_bufctrl32(buf_ctrl); // Finally, write to buffer_control which will trigger the transfer @@ -266,34 +259,34 @@ void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) // Returns true if transfer is complete bool hw_endpoint_xfer_continue(struct hw_endpoint *ep) { - _hw_endpoint_lock_update(ep, 1); - // Part way through a transfer - if (!ep->active) - { - panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string); - } + _hw_endpoint_lock_update(ep, 1); + // Part way through a transfer + if (!ep->active) + { + panic("Can't continue xfer on inactive ep %d %s", tu_edpt_number(ep->ep_addr), ep_dir_string); + } - // Update EP struct from hardware state - _hw_endpoint_xfer_sync(ep); - - // Now we have synced our state with the hardware. Is there more data to transfer? - // If we are done then notify tinyusb - if (ep->remaining_len == 0) - { - pico_trace("Completed transfer of %d bytes on ep %d %s\n", - ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); - // Notify caller we are done so it can notify the tinyusb stack - _hw_endpoint_lock_update(ep, -1); - return true; - } - else - { - _hw_endpoint_start_next_buffer(ep); - } + // Update EP struct from hardware state + _hw_endpoint_xfer_sync(ep); + // Now we have synced our state with the hardware. Is there more data to transfer? + // If we are done then notify tinyusb + if (ep->remaining_len == 0) + { + pico_trace("Completed transfer of %d bytes on ep %d %s\n", + ep->xferred_len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + // Notify caller we are done so it can notify the tinyusb stack _hw_endpoint_lock_update(ep, -1); - // More work to do - return false; + return true; + } + else + { + _hw_endpoint_start_next_buffer(ep); + } + + _hw_endpoint_lock_update(ep, -1); + // More work to do + return false; } #endif From 66c8a13f137d54a2c140d04310cd4b7adba50401 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 18:26:41 +0700 Subject: [PATCH 08/19] remove unused variable in hw endpoint last_buf, buf_sel, transfer_size --- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 18 ++++++++-------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 22 ++++++++++---------- src/portable/raspberrypi/rp2040/rp2040_usb.h | 12 ----------- 3 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 6a1d7cff2..0bbd7e7c2 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -220,6 +221,14 @@ static void hcd_rp2040_irq(void) usb_hw_clear->sie_status = USB_SIE_STATUS_SPEED_BITS; } + if (status & USB_INTS_BUFF_STATUS_BITS) + { + handled |= USB_INTS_BUFF_STATUS_BITS; + TU_LOG(2, "Buffer complete\n"); + // print_bufctrl32(*epx.buffer_control); + hw_handle_buff_status(); + } + if (status & USB_INTS_TRANS_COMPLETE_BITS) { handled |= USB_INTS_TRANS_COMPLETE_BITS; @@ -228,14 +237,6 @@ static void hcd_rp2040_irq(void) hw_trans_complete(); } - if (status & USB_INTS_BUFF_STATUS_BITS) - { - handled |= USB_INTS_BUFF_STATUS_BITS; - TU_LOG(2, "Buffer complete\n"); - print_bufctrl32(*epx.buffer_control); - hw_handle_buff_status(); - } - if (status & USB_INTS_STALL_BITS) { // We have rx'd a stall from the device @@ -543,7 +544,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet assert(ep->configured); ep->remaining_len = 8; - ep->transfer_size = 8; ep->active = true; ep->sent_setup = true; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 38a59d83a..26c6e8b13 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * Copyright (c) 2021 Ha Thach (tinyusb.org) for Double Buffered * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,8 +44,8 @@ static inline void _hw_endpoint_lock_update(struct hw_endpoint *ep, int delta) { // sense to have worker and IRQ on same core, however I think using critsec is about equivalent. } -void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); +static void _hw_endpoint_xfer_sync(struct hw_endpoint *ep); +static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep); //--------------------------------------------------------------------+ // @@ -77,7 +78,6 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep) #endif ep->remaining_len = 0; ep->xferred_len = 0; - ep->transfer_size = 0; ep->user_buf = 0; } @@ -111,7 +111,7 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } -static uint32_t compute_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) +static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id) { uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); ep->remaining_len -= buflen; @@ -148,19 +148,19 @@ static uint32_t compute_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) } // Prepare buffer control register value -void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) +static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) { uint32_t ep_ctrl = *ep->endpoint_control; // always compute buffer 0 - uint32_t buf_ctrl = compute_ep_buf(ep, 0); + uint32_t buf_ctrl = compute_buffer_control(ep, 0); if(ep->remaining_len) { // Use buffer 1 (double buffered) if there is still data // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) - buf_ctrl |= compute_ep_buf(ep, 1); + buf_ctrl |= compute_buffer_control(ep, 1); // Set endpoint control double buffered bit if needed ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; @@ -205,7 +205,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to _hw_endpoint_lock_update(ep, -1); } -static void sync_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) +static void sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) { uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); if (buf_id) buf_ctrl = buf_ctrl >> 16; @@ -241,18 +241,18 @@ static void sync_ep_buf(struct hw_endpoint *ep, uint8_t buf_id) } } -void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) +static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) { // Update hw endpoint struct with info from hardware // after a buff status interrupt // always sync buffer 0 - sync_ep_buf(ep, 0); + sync_ep_buffer(ep, 0); // sync buffer 1 if double buffered if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) { - sync_ep_buf(ep, 1); + sync_ep_buffer(ep, 1); } } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index d61a5a57f..ada1dd750 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -65,12 +65,6 @@ struct hw_endpoint uint16_t remaining_len; uint16_t xferred_len; - // Amount of data with the hardware - uint16_t buflen[2]; - - uint16_t transfer_size; // buf0_len; - uint16_t buf_1_len; - // User buffer in main memory uint8_t *user_buf; @@ -80,12 +74,6 @@ struct hw_endpoint uint8_t transfer_type; #if TUSB_OPT_HOST_ENABLED - // Only needed for host mode - bool last_buf; - - // RP2040-E4: HOST BUG. Host will incorrect write status to top half of buffer - // control register when doing transfers > 1 packet - uint8_t buf_sel; // Only needed for host uint8_t dev_addr; bool sent_setup; From a6d22f5a6879388e657987378cecea827794ad1e Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 18:39:28 +0700 Subject: [PATCH 09/19] replace pico_warn by log level 1 --- src/portable/raspberrypi/rp2040/rp2040_usb.c | 2 +- src/portable/raspberrypi/rp2040/rp2040_usb.h | 24 +++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 26c6e8b13..cb46ad1b9 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -189,7 +189,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to if ( ep->active ) { // TODO: Is this acceptable for interrupt packets? - pico_warn("WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), + TU_LOG(1, "WARN: starting new transfer on already active ep %d %s\n", tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]); hw_endpoint_reset_transfer(ep); diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index ada1dd750..278ba59ec 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -29,12 +29,6 @@ #define pico_info(format,...) ((void)0) #endif -#if false && !defined(NDEBUG) -#define pico_warn(format,args...) printf(format, ## args) -#else -#define pico_warn(format,...) ((void)0) -#endif - // Hardware information per endpoint struct hw_endpoint { @@ -127,13 +121,14 @@ typedef union TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(rp2040_buffer_control_t) == 2, "size is not correct"); -static inline void print_bufctrl16(uint32_t __unused u16) +#if CFG_TUSB_DEBUG >= 3 +static inline void print_bufctrl16(uint32_t u16) { - rp2040_buffer_control_t __unused bufctrl = { + rp2040_buffer_control_t bufctrl = { .u16 = u16 }; - TU_LOG(2, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n", + TU_LOG(3, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n", bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full); } @@ -142,12 +137,19 @@ static inline void print_bufctrl32(uint32_t u32) uint16_t u16; u16 = u32 >> 16; - TU_LOG(2, " Buffer Control 1 0x%x: ", u16); + TU_LOG(3, " Buffer Control 1 0x%x: ", u16); print_bufctrl16(u16); u16 = u32 & 0x0000ffff; - TU_LOG(2, " Buffer Control 0 0x%x: ", u16); + TU_LOG(3, " Buffer Control 0 0x%x: ", u16); print_bufctrl16(u16); } +#else + +#define print_bufctrl16(u16) +#define print_bufctrl32(u32) + +#endif + #endif From b39faa15effec35dceb95655b0db75c3fe564f3d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 18:44:08 +0700 Subject: [PATCH 10/19] map pico_info to log2, pico_trace to log3 --- src/portable/raspberrypi/rp2040/rp2040_usb.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 278ba59ec..4c24b8dbe 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -17,17 +17,8 @@ #endif -#if true || false && !defined(NDEBUG) -#define pico_trace(format,args...) printf(format, ## args) -#else -#define pico_trace(format,...) ((void)0) -#endif - -#if false && !defined(NDEBUG) -#define pico_info(format,args...) printf(format, ## args) -#else -#define pico_info(format,...) ((void)0) -#endif +#define pico_info(...) TU_LOG(2, __VA_ARGS__) +#define pico_trace(...) TU_LOG(3, __VA_ARGS__) // Hardware information per endpoint struct hw_endpoint From dfe5a727c6b236c1b05b5447cdf0535545a6d32e Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 18:53:56 +0700 Subject: [PATCH 11/19] log clean up --- src/class/hid/hid_host.c | 6 +++--- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index a227c2a86..7444c10fe 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -442,9 +442,9 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr, uint8_t const data8 = desc_report[0]; - TU_LOG2("tag = %d, type = %d, size = %d, data = ", tag, type, size); - for(uint32_t i=0; iendpoint_control; if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS) { - TU_LOG(2, "Double Buffered "); + TU_LOG(3, "Double Buffered: "); }else { - TU_LOG(2, "Single Buffered "); + TU_LOG(3, "Single Buffered: "); } - if (ep_ctrl & EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER) TU_LOG(2, "Interrupt per double "); - if (ep_ctrl & EP_CTRL_INTERRUPT_PER_BUFFER) TU_LOG(2, "Interrupt per single "); - TU_LOG_HEX(2, ep_ctrl); + TU_LOG_HEX(3, ep_ctrl); _handle_buff_status_bit(bit, ep); } From 910e11a8aba7328a3cb61ecf8ac5a10f8a525377 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 11 Jun 2021 19:04:16 +0700 Subject: [PATCH 12/19] fix ci build --- src/host/usbh.c | 7 ++++--- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 81b9e84af..203f9fd54 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -990,13 +990,14 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura // parse each interfaces while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) { - tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; + // TODO Do we need to use IAD + // tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL; // Class will always starts with Interface Association (if any) and then Interface descriptor if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) ) { - desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; - p_desc = tu_desc_next(p_desc); // next to Interface + // desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc; + p_desc = tu_desc_next(p_desc); } TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) ); diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index c145082f2..ab8639861 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -151,7 +151,6 @@ static void hw_handle_buff_status(void) { TU_LOG(3, "Single Buffered: "); } - TU_LOG_HEX(3, ep_ctrl); _handle_buff_status_bit(bit, ep); From a4ad064e638679a7c8759a2c30ed555bd93e524b Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 12 Jun 2021 14:20:09 +0700 Subject: [PATCH 13/19] increase example CFG_TUH_HID from 2 to 4 --- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- src/common/tusb_verify.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 8253964c0..531bb2c30 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -76,7 +76,7 @@ #define CFG_TUH_HUB 1 #define CFG_TUH_CDC 1 -#define CFG_TUH_HID 2 +#define CFG_TUH_HID 4 #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h index 542809899..56ba8bcd1 100644 --- a/src/common/tusb_verify.h +++ b/src/common/tusb_verify.h @@ -75,7 +75,7 @@ #if CFG_TUSB_DEBUG #include #define _MESS_ERR(_err) tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err]) - #define _MESS_FAILED() tu_printf("%s %d: assert failed\r\n", __func__, __LINE__) + #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) #else #define _MESS_ERR(_err) do {} while (0) #define _MESS_FAILED() do {} while (0) From 289ccf3c938c8f2be0edf2a2c8a18c68e39880c0 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Jun 2021 13:18:32 +0700 Subject: [PATCH 14/19] remove dev_ep_map --- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 49 ++++++-------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index ab8639861..42d0839f6 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -59,44 +59,24 @@ static struct hw_endpoint ep_pool[1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS]; #define usb_hw_set hw_set_alias(usb_hw) #define usb_hw_clear hw_clear_alias(usb_hw) -// todo still a bit wasteful -// top bit set if valid -uint8_t dev_ep_map[CFG_TUSB_HOST_DEVICE_MAX][1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS][2]; - // Flags we set by default in sie_ctrl (we add other bits on top) enum { - sie_ctrl_base = USB_SIE_CTRL_SOF_EN_BITS | - USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | - USB_SIE_CTRL_PULLDOWN_EN_BITS | - USB_SIE_CTRL_EP0_INT_1BUF_BITS + SIE_CTRL_BASE = USB_SIE_CTRL_SOF_EN_BITS | USB_SIE_CTRL_KEEP_ALIVE_EN_BITS | + USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS }; static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) { - uint8_t num = tu_edpt_number(ep_addr); - if (num == 0) { - return &epx; - } - uint8_t in = (ep_addr & TUSB_DIR_IN_MASK) ? 1 : 0; - uint mapping = dev_ep_map[dev_addr-1][num][in]; - pico_trace("Get dev addr %d ep %d = %d\n", dev_addr, ep_addr, mapping); - return mapping >= 128 ? ep_pool + (mapping & 0x7fu) : NULL; -} + uint8_t num = tu_edpt_number(ep_addr); + if ( num == 0 ) return &epx; -static void set_dev_ep(uint8_t dev_addr, uint8_t ep_addr, struct hw_endpoint *ep) -{ - uint8_t num = tu_edpt_number(ep_addr); - uint8_t in = (uint8_t) tu_edpt_dir(ep_addr); + for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ ) + { + struct hw_endpoint *ep = &ep_pool[i]; + if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep; + } - uint32_t index = ep - ep_pool; - hard_assert(index < TU_ARRAY_SIZE(ep_pool)); - - // todo revisit why dev_addr can be 0 here - if (dev_addr) { - dev_ep_map[dev_addr-1][num][in] = 128u | index; - } - - pico_trace("Set dev addr %d ep %d = %d\n", dev_addr, ep_addr, index); + return NULL; } static inline uint8_t dev_speed(void) @@ -387,7 +367,7 @@ bool hcd_init(uint8_t rhport) // Enable in host mode with SOF / Keep alive on usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS | USB_MAIN_CTRL_HOST_NDEVICE_BITS; - usb_hw->sie_ctrl = sie_ctrl_base; + usb_hw->sie_ctrl = SIE_CTRL_BASE; usb_hw->inte = USB_INTE_BUFF_STATUS_BITS | USB_INTE_HOST_CONN_DIS_BITS | USB_INTE_HOST_RESUME_BITS | @@ -477,9 +457,6 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const ep_desc->bmAttributes.xfer, ep_desc->bInterval); - // Map this struct to ep@device address - set_dev_ep(dev_addr, ep_desc->bEndpointAddress, ep); - return true; } @@ -512,7 +489,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * // for host we have to initiate the transfer usb_hw->dev_addr_ctrl = dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB); - uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | sie_ctrl_base | + uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE | (ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS); // Set pre if we are a low speed device on full speed hub flags |= need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0; @@ -548,7 +525,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet usb_hw->dev_addr_ctrl = dev_addr; // Set pre if we are a low speed device on full speed hub - uint32_t const flags = sie_ctrl_base | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS | + uint32_t const flags = SIE_CTRL_BASE | USB_SIE_CTRL_SEND_SETUP_BITS | USB_SIE_CTRL_START_TRANS_BITS | (need_pre(dev_addr) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0); usb_hw->sie_ctrl = flags; From 1af64f9729f743f4fc9d8686af239c65f689630f Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Jun 2021 15:27:20 +0700 Subject: [PATCH 15/19] remove sent_setup from hw endpoint --- src/portable/raspberrypi/rp2040/hcd_rp2040.c | 34 +++++++++++--------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 3 -- src/portable/raspberrypi/rp2040/rp2040_usb.h | 3 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c index 42d0839f6..40a0805c6 100644 --- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c @@ -161,19 +161,19 @@ static void hw_handle_buff_status(void) static void hw_trans_complete(void) { - struct hw_endpoint *ep = &epx; - assert(ep->active); + struct hw_endpoint *ep = &epx; + assert(ep->active); - if (ep->sent_setup) - { - pico_trace("Sent setup packet\n"); - hw_xfer_complete(ep, XFER_RESULT_SUCCESS); - } - else - { - // Don't care. Will handle this in buff status - return; - } + if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS) + { + pico_trace("Sent setup packet\n"); + hw_xfer_complete(ep, XFER_RESULT_SUCCESS); + } + else + { + // Don't care. Will handle this in buff status + return; + } } static void hcd_rp2040_irq(void) @@ -473,10 +473,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr); assert(ep); - if (ep_addr != ep->ep_addr) + // Control endpoint can change direction 0x00 <-> 0x80 + if ( ep_addr != ep->ep_addr ) { - // Direction has flipped on endpoint control so re init it but with same properties - _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); + assert(ep_num == 0); + + // Direction has flipped on endpoint control so re init it but with same properties + _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0); } // If a normal transfer (non-interrupt) then initiate using @@ -519,7 +522,6 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet ep->remaining_len = 8; ep->active = true; - ep->sent_setup = true; // Set device address usb_hw->dev_addr_ctrl = dev_addr; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index cb46ad1b9..7430881e0 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -73,9 +73,6 @@ void hw_endpoint_reset_transfer(struct hw_endpoint *ep) { ep->stalled = false; ep->active = false; -#if TUSB_OPT_HOST_ENABLED - ep->sent_setup = false; -#endif ep->remaining_len = 0; ep->xferred_len = 0; ep->user_buf = 0; diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 4c24b8dbe..4c787f496 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -55,13 +55,14 @@ struct hw_endpoint // Data needed from EP descriptor uint16_t wMaxPacketSize; + // Interrupt, bulk, etc uint8_t transfer_type; #if TUSB_OPT_HOST_ENABLED // Only needed for host uint8_t dev_addr; - bool sent_setup; + // If interrupt endpoint uint8_t interrupt_num; #endif From bd039c8d37d7df05da992eb8afdcb31f782e1f23 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Jun 2021 16:16:25 +0700 Subject: [PATCH 16/19] fix build with log for device --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 35 +++++--------------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 2 +- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 3f2bf7810..63e129e53 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -69,6 +69,7 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep) // Assumes single buffered for now ep->hw_data_buf = next_buffer_ptr; next_buffer_ptr += size; + // Bits 0-5 are ignored by the controller so make sure these are 0 if ((uintptr_t)next_buffer_ptr & 0b111111u) { @@ -87,8 +88,8 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep) size, dpram_offset, ep->hw_data_buf, - ep->num, - ep_dir_string[ep->in]); + tu_edpt_number(ep->ep_addr), + ep_dir_string[tu_edpt_dir(ep->ep_addr)]); // Fill in endpoint control register with buffer offset uint32_t reg = EP_CTRL_ENABLE_BITS @@ -103,28 +104,15 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t { 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; - // Add some checks around the max packet size - if (transfer_type == TUSB_XFER_ISOCHRONOUS) - { - if (wMaxPacketSize > USB_MAX_ISO_PACKET_SIZE) - { - panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize); - } - } - else - { - if (wMaxPacketSize > USB_MAX_PACKET_SIZE) - { - panic("Isochronous wMaxPacketSize %d too large", wMaxPacketSize); - } - } - ep->wMaxPacketSize = wMaxPacketSize; ep->transfer_type = transfer_type; @@ -339,10 +327,7 @@ static void dcd_rp2040_irq(void) #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX // Only run enumeration walk-around if pull up is enabled - if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) - { - rp2040_usb_device_enumeration_fix(); - } + if ( usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS ) rp2040_usb_device_enumeration_fix(); #endif } @@ -402,9 +387,9 @@ void dcd_init (uint8_t rhport) // EP0 always exists so init it now // EP0 OUT - hw_endpoint_init(0x0, 64, 0); + hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL); // EP0 IN - hw_endpoint_init(0x80, 64, 0); + hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL); // Initializes the USB peripheral for device mode and enables it. // Don't need to enable the pull up here. Force VBUS @@ -495,7 +480,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { assert(rhport == 0); - // True means start new xfer hw_endpoint_xfer(ep_addr, buffer, total_bytes); return true; } @@ -519,7 +503,6 @@ void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { // usbd.c says: In progress transfers on this EP may be delivered after this call pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr); - } void dcd_int_handler(uint8_t rhport) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 7430881e0..de3a83be9 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -194,7 +194,7 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to // Fill in info now that we're kicking off the hw ep->remaining_len = total_len; - ep->xferred_len = 0; + ep->xferred_len = 0; ep->active = true; ep->user_buf = buffer; From f38c460433abc0c557f2035c7205b4f36bcbc677 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Jun 2021 17:19:14 +0700 Subject: [PATCH 17/19] fix ep tx with double buffered --- src/common/tusb_common.h | 2 +- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 48 ++++++++------------ src/portable/raspberrypi/rp2040/rp2040_usb.c | 11 ++--- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index fe5bf5f41..8490daad7 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -123,7 +123,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_align4k (uint32_t value) { retur TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); } //------------- Mathematics -------------// -TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_abs(int32_t value) { return (uint32_t)((value < 0) ? (-value) : value); } +TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; } /// inclusive range checking TODO remove TU_ATTR_ALWAYS_INLINE static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 63e129e53..4f70d60cc 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -64,40 +64,30 @@ static struct hw_endpoint *hw_endpoint_get_by_addr(uint8_t ep_addr) static void _hw_endpoint_alloc(struct hw_endpoint *ep) { - uint16_t size = tu_min16(64, ep->wMaxPacketSize); + // size must be multiple of 64 + uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; - // Assumes single buffered for now - ep->hw_data_buf = next_buffer_ptr; - next_buffer_ptr += size; + // double buffered for non-ISO endpoint + if ( ep->transfer_type != TUSB_XFER_ISOCHRONOUS ) size *= 2u; - // Bits 0-5 are ignored by the controller so make sure these are 0 - if ((uintptr_t)next_buffer_ptr & 0b111111u) - { - // Round up to the next 64 - uint32_t fixptr = (uintptr_t)next_buffer_ptr; - fixptr &= ~0b111111u; - fixptr += 64; - pico_info("Rounding non 64 byte boundary buffer up from %x to %x\n", (uintptr_t)next_buffer_ptr, fixptr); - next_buffer_ptr = (uint8_t*)fixptr; - } - assert(((uintptr_t)next_buffer_ptr & 0b111111u) == 0); - uint dpram_offset = hw_data_offset(ep->hw_data_buf); - assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); + ep->hw_data_buf = next_buffer_ptr; + next_buffer_ptr += size; - 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)]); + assert(((uintptr_t )next_buffer_ptr & 0b111111u) == 0); + uint dpram_offset = hw_data_offset(ep->hw_data_buf); + assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX); - // Fill in endpoint control register with buffer offset - uint32_t reg = EP_CTRL_ENABLE_BITS - | EP_CTRL_INTERRUPT_PER_BUFFER - | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) - | dpram_offset; + 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)]); - *ep->endpoint_control = reg; + // 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; + + *ep->endpoint_control = reg; } static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index de3a83be9..f8d36e5eb 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -108,7 +108,8 @@ void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_m *ep->buffer_control = value; } -static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id) +// prepare buffer, return buffer control +static uint32_t prepare_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) { uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize); ep->remaining_len -= buflen; @@ -122,14 +123,13 @@ static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id) if ( !ep->rx ) { // Copy data from user buffer to hw buffer - memcpy(ep->hw_data_buf, ep->user_buf, buflen); + memcpy(ep->hw_data_buf + buf_id*64, ep->user_buf, buflen); ep->user_buf += buflen; // Mark as full buf_ctrl |= USB_BUF_CTRL_FULL; } -#if TUSB_OPT_HOST_ENABLED // Is this the last buffer? Only really matters for host mode. Will trigger // the trans complete irq but also stop it polling. We only really care about // trans complete for setup packets being sent @@ -137,7 +137,6 @@ static uint32_t compute_buffer_control(struct hw_endpoint *ep, uint8_t buf_id) { buf_ctrl |= USB_BUF_CTRL_LAST; } -#endif if (buf_id) buf_ctrl = buf_ctrl << 16; @@ -150,14 +149,14 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) uint32_t ep_ctrl = *ep->endpoint_control; // always compute buffer 0 - uint32_t buf_ctrl = compute_buffer_control(ep, 0); + uint32_t buf_ctrl = prepare_ep_buffer(ep, 0); if(ep->remaining_len) { // Use buffer 1 (double buffered) if there is still data // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) - buf_ctrl |= compute_buffer_control(ep, 1); + buf_ctrl |= prepare_ep_buffer(ep, 1); // Set endpoint control double buffered bit if needed ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER; From 5c567129ea34ea78833cee2bf38e4e09cbdee389 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 13 Jun 2021 18:30:26 +0700 Subject: [PATCH 18/19] fix calculating xferred bytes with double buffer with short packet on buffer0 --- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 26 +++++++++++--------- src/portable/raspberrypi/rp2040/rp2040_usb.c | 22 +++++++++++------ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index 4f70d60cc..b87951421 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -67,8 +67,11 @@ static void _hw_endpoint_alloc(struct hw_endpoint *ep) // size must be multiple of 64 uint16_t size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u; - // double buffered for non-ISO endpoint - if ( ep->transfer_type != TUSB_XFER_ISOCHRONOUS ) size *= 2u; + // double buffered for Control and Bulk endpoint + if ( ep->transfer_type == TUSB_XFER_CONTROL || ep->transfer_type == TUSB_XFER_BULK) + { + size *= 2u; + } ep->hw_data_buf = next_buffer_ptr; next_buffer_ptr += size; @@ -445,18 +448,17 @@ void dcd_connect(uint8_t rhport) void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) { - pico_trace("dcd_edpt0_status_complete %d\n", rhport); - assert(rhport == 0); + (void) rhport; - if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && - request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && - request->bRequest == TUSB_REQ_SET_ADDRESS) - { - pico_trace("Set HW address %d\n", request->wValue); - usb_hw->dev_addr_ctrl = (uint8_t) request->wValue; - } + if ( request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE && + request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && + request->bRequest == TUSB_REQ_SET_ADDRESS ) + { + pico_trace("Set HW address %d\n", request->wValue); + usb_hw->dev_addr_ctrl = (uint8_t) request->wValue; + } - reset_ep0(); + reset_ep0(); } bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index f8d36e5eb..5b2a5f5a0 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -170,6 +170,7 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) *ep->endpoint_control = ep_ctrl; + TU_LOG(3, "Prepare Buffer Control:\r\n"); print_bufctrl32(buf_ctrl); // Finally, write to buffer_control which will trigger the transfer @@ -201,7 +202,8 @@ void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t to _hw_endpoint_lock_update(ep, -1); } -static void sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) +// sync endpoint buffer and return transferred bytes +static uint16_t sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) { uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); if (buf_id) buf_ctrl = buf_ctrl >> 16; @@ -227,14 +229,14 @@ static void sync_ep_buffer(struct hw_endpoint *ep, uint8_t buf_id) } // Short packet - // TODO what if we prepare double buffered but receive short packet on buffer 0 !!! - // would the buffer status or trans complete interrupt is triggered if (xferred_bytes < ep->wMaxPacketSize) { - pico_trace("Short rx transfer\n"); + pico_trace("Short rx transfer on buffer %d with %u bytes\n", buf_id, xferred_bytes); // Reduce total length as this is last packet ep->remaining_len = 0; } + + return xferred_bytes; } static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) @@ -242,11 +244,15 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) // Update hw endpoint struct with info from hardware // after a buff status interrupt - // always sync buffer 0 - sync_ep_buffer(ep, 0); + uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep); + TU_LOG(3, "_hw_endpoint_xfer_sync:\r\n"); + print_bufctrl32(buf_ctrl); - // sync buffer 1 if double buffered - if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) + // always sync buffer 0 + uint16_t buf0_bytes = sync_ep_buffer(ep, 0); + + // sync buffer 1 if double buffered and buffer 0 is not short packet + if ( ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) && (buf0_bytes == ep->wMaxPacketSize) ) { sync_ep_buffer(ep, 1); } From 832d22d7addf9b1e4b88556c544f60bd9fa32dd6 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 17 Jun 2021 01:55:35 +0700 Subject: [PATCH 19/19] force single buffered for device mode, out endpoint --- src/device/usbd.c | 3 +- src/portable/raspberrypi/rp2040/dcd_rp2040.c | 15 +++--- src/portable/raspberrypi/rp2040/rp2040_usb.c | 52 +++++++++++++++++--- src/portable/raspberrypi/rp2040/rp2040_usb.h | 4 +- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 2935defd0..587d487dc 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1254,14 +1254,13 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) ) { - TU_LOG2("OK\r\n"); return true; }else { // DCD error, mark endpoint as ready to allow next transfer _usbd_dev.ep_status[epnum][dir].busy = false; _usbd_dev.ep_status[epnum][dir].claimed = 0; - TU_LOG2("failed\r\n"); + TU_LOG2("FAILED\r\n"); TU_BREAKPOINT(); return false; } diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c index b87951421..f78a932f1 100644 --- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c +++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c @@ -145,6 +145,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t ep_addr, uint16_t // 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); @@ -194,9 +195,6 @@ static void hw_handle_buff_status(void) { if (remaining_buffers & bit) { - uint __unused which = (usb_hw->buf_cpu_should_handle & bit) ? 1 : 0; - // Should be single buffered - assert(which == 0); // clear this in advance usb_hw_clear->buf_status = bit; // IN transfer for even i, OUT transfer for odd i @@ -463,7 +461,7 @@ 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 %d %02x\n", rhport, desc_edpt->bEndpointAddress); + 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; @@ -478,14 +476,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { - pico_trace("dcd_edpt_stall %d %02x\n", rhport, ep_addr); + pico_trace("dcd_edpt_stall %02x\n", ep_addr); assert(rhport == 0); hw_endpoint_stall(ep_addr); } void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { - pico_trace("dcd_edpt_clear_stall %d %02x\n", rhport, ep_addr); + pico_trace("dcd_edpt_clear_stall %02x\n", ep_addr); assert(rhport == 0); hw_endpoint_clear_stall(ep_addr); } @@ -493,8 +491,11 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) { + (void) rhport; + (void) ep_addr; + // usbd.c says: In progress transfers on this EP may be delivered after this call - pico_trace("dcd_edpt_close %d %02x\n", rhport, ep_addr); + pico_trace("dcd_edpt_close %02x\n", ep_addr); } void dcd_int_handler(uint8_t rhport) diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c index 5b2a5f5a0..dc12e6d82 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.c +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c @@ -148,10 +148,15 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) { uint32_t ep_ctrl = *ep->endpoint_control; - // always compute buffer 0 - uint32_t buf_ctrl = prepare_ep_buffer(ep, 0); + // always compute and start with buffer 0 + uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL; - if(ep->remaining_len) + // For now: skip double buffered for Device mode, OUT endpoint since + // host could send < 64 bytes and cause short packet on buffer0 + // NOTE this could happen to Host mode IN endpoint + bool const force_single = !(usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) && !tu_edpt_dir(ep->ep_addr); + + if(ep->remaining_len && !force_single) { // Use buffer 1 (double buffered) if there is still data // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt) @@ -181,8 +186,7 @@ static void _hw_endpoint_start_next_buffer(struct hw_endpoint *ep) void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len) { _hw_endpoint_lock_update(ep, 1); - pico_trace("Start transfer of total len %d on ep %d %s\n", total_len, tu_edpt_number(ep->ep_addr), - ep_dir_string[tu_edpt_dir(ep->ep_addr)]); + if ( ep->active ) { // TODO: Is this acceptable for interrupt packets? @@ -251,10 +255,42 @@ static void _hw_endpoint_xfer_sync (struct hw_endpoint *ep) // always sync buffer 0 uint16_t buf0_bytes = sync_ep_buffer(ep, 0); - // sync buffer 1 if double buffered and buffer 0 is not short packet - if ( ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) && (buf0_bytes == ep->wMaxPacketSize) ) + // sync buffer 1 if double buffered + if ( (*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS ) { - sync_ep_buffer(ep, 1); + if (buf0_bytes == ep->wMaxPacketSize) + { + // sync buffer 1 if not short packet + sync_ep_buffer(ep, 1); + }else + { + // short packet on buffer 0 + // TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example + // At this time (currently trigger per 2 buffer), the buffer1 is probably filled with data from + // the next transfer (not current one). For now we disable double buffered for device OUT + // NOTE this could happen to Host IN +#if 0 + uint8_t const ep_num = tu_edpt_number(ep->ep_addr); + uint8_t const dir = (uint8_t) tu_edpt_dir(ep->ep_addr); + uint8_t const ep_id = 2*ep_num + (dir ? 0 : 1); + + // abort queued transfer on buffer 1 + usb_hw->abort |= TU_BIT(ep_id); + + while ( !(usb_hw->abort_done & TU_BIT(ep_id)) ) {} + + uint32_t ep_ctrl = *ep->endpoint_control; + ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER); + ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER; + + _hw_endpoint_buffer_control_set_value32(ep, 0); + + usb_hw->abort &= ~TU_BIT(ep_id); + + TU_LOG(3, "----SHORT PACKET buffer0 on EP %02X:\r\n", ep->ep_addr); + print_bufctrl32(buf_ctrl); +#endif + } } } diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h index 4c787f496..514152cd9 100644 --- a/src/portable/raspberrypi/rp2040/rp2040_usb.h +++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h @@ -120,8 +120,8 @@ static inline void print_bufctrl16(uint32_t u16) .u16 = u16 }; - TU_LOG(3, "len = %u, available = %u, stall = %u, reset = %u, toggle = %u, last = %u, full = %u\r\n", - bufctrl.xfer_len, bufctrl.available, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle, bufctrl.last_buf, bufctrl.full); + TU_LOG(3, "len = %u, available = %u, full = %u, last = %u, stall = %u, reset = %u, toggle = %u\r\n", + bufctrl.xfer_len, bufctrl.available, bufctrl.full, bufctrl.last_buf, bufctrl.stall, bufctrl.reset_bufsel, bufctrl.data_toggle); } static inline void print_bufctrl32(uint32_t u32)