Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions src/host/usbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ void tuh_task(void)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const ep_dir = tu_edpt_dir(ep_addr);

TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
TU_LOG2("on dev %d EP %02X with %u bytes\r\n", event.dev_addr, ep_addr, (unsigned int) event.xfer_complete.len);

if (event.dev_addr == 0)
{
Expand Down Expand Up @@ -739,6 +739,12 @@ static bool enum_request_addr0_device_desc(void)
return true;
}

static bool hub_port_reset_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
return true;
}

// After Get Device Descriptor of Address 0
static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
Expand Down Expand Up @@ -773,12 +779,8 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
else
{
// after RESET_DELAY the hub_port_reset() already complete
TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, NULL) );
TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, hub_port_reset_complete) );
osal_task_delay(RESET_DELAY);

tuh_task(); // FIXME temporarily to clean up port_reset control transfer

TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
}
#endif

Expand Down Expand Up @@ -1140,7 +1142,7 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_

usbh_device_t* dev = get_device(dev_addr);

TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
TU_LOG2(" Queue dev %d EP %02X with %u bytes ...\n", dev_addr, ep_addr, total_bytes);

// Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
Expand All @@ -1151,14 +1153,14 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_

if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
{
TU_LOG2("OK\r\n");
TU_LOG2(" Queue OK\r\n");
return true;
}else
{
// HCD error, mark endpoint as ready to allow next transfer
dev->ep_status[epnum][dir].busy = false;
dev->ep_status[epnum][dir].claimed = 0;
TU_LOG2("failed\r\n");
TU_LOG2(" Queue failed\r\n");
TU_BREAKPOINT();
return false;
}
Expand Down
83 changes: 67 additions & 16 deletions src/portable/raspberrypi/rp2040/hcd_rp2040.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,41 @@ static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t 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;
if ( ep->configured && (ep->dev_addr == dev_addr) && (tu_edpt_number(ep->ep_addr) == num) ) return ep;
}

return NULL;
}

static struct hw_endpoint *get_epx_ep(void)
{
uint8_t dev_addr = (usb_hw->dev_addr_ctrl & USB_ADDR_ENDP_ADDRESS_BITS) >> USB_ADDR_ENDP_ADDRESS_LSB;
uint8_t ep_addr = (usb_hw->dev_addr_ctrl & USB_ADDR_ENDP_ENDPOINT_BITS) >> USB_ADDR_ENDP_ENDPOINT_LSB;
pico_trace(" epx dev %d ep %d\n", dev_addr, ep_addr);

return get_dev_ep(dev_addr, ep_addr);
}

static uint8_t ep_slot(struct hw_endpoint *ep)
{
return (ep - &epx);
}

static const char* xfer_type_str(uint8_t xfer_type)
{
const char *str[] = {
"control",
"iso",
"bulk",
"int"
};

if (xfer_type > TUSB_XFER_INTERRUPT)
return "INVALID";
else
return str[xfer_type];
}

static inline uint8_t dev_speed(void)
{
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
Expand Down Expand Up @@ -120,7 +149,10 @@ static void hw_handle_buff_status(void)
if (remaining_buffers & bit)
{
remaining_buffers &= ~bit;
struct hw_endpoint *ep = &epx;

struct hw_endpoint *ep = get_epx_ep();
assert(ep);
assert(ep->active);

uint32_t ep_ctrl = *ep->endpoint_control;
if (ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS)
Expand Down Expand Up @@ -163,8 +195,11 @@ static void hw_trans_complete(void)
if (usb_hw->sie_ctrl & USB_SIE_CTRL_SEND_SETUP_BITS)
{
pico_trace("Sent setup packet\n");
struct hw_endpoint *ep = &epx;

struct hw_endpoint *ep = get_epx_ep();
assert(ep);
assert(ep->active);

hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
else
Expand All @@ -179,6 +214,8 @@ static void hcd_rp2040_irq(void)
uint32_t status = usb_hw->ints;
uint32_t handled = 0;

TU_LOG(2, "+IRQ %08x %08x\n", status, usb_hw->intr);

if (status & USB_INTS_HOST_CONN_DIS_BITS)
{
handled |= USB_INTS_HOST_CONN_DIS_BITS;
Expand Down Expand Up @@ -214,16 +251,17 @@ static void hcd_rp2040_irq(void)
if (status & USB_INTS_STALL_BITS)
{
// We have rx'd a stall from the device
pico_trace("Stall REC\n");
TU_LOG(2, "Stall REC\n");
handled |= USB_INTS_STALL_BITS;
usb_hw_clear->sie_status = USB_SIE_STATUS_STALL_REC_BITS;
hw_xfer_complete(&epx, XFER_RESULT_STALLED);
hw_xfer_complete(get_epx_ep(), XFER_RESULT_STALLED);
}

if (status & USB_INTS_ERROR_RX_TIMEOUT_BITS)
{
handled |= USB_INTS_ERROR_RX_TIMEOUT_BITS;
usb_hw_clear->sie_status = USB_SIE_STATUS_RX_TIMEOUT_BITS;
TU_LOG(2, "Rx timeout\n");
}

if (status & USB_INTS_ERROR_DATA_SEQ_BITS)
Expand All @@ -237,33 +275,39 @@ static void hcd_rp2040_irq(void)
{
panic("Unhandled IRQ 0x%x\n", (uint) (status ^ handled));
}

TU_LOG(2, "-IRQ\n");
}

static struct hw_endpoint *_next_free_interrupt_ep(void)
static struct hw_endpoint *_next_free_ep(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;
if (transfer_type == TUSB_XFER_CONTROL)
return &epx;

for (uint i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
{
ep = &ep_pool[i];
struct hw_endpoint *ep = &ep_pool[i];
if (!ep->configured)
{
// Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
ep->transfer_type = transfer_type;
ep->interrupt_num = i - 1;
return ep;
}
}
return ep;
return NULL;
}

static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
{
struct hw_endpoint *ep = NULL;

ep = _next_free_ep(transfer_type);
assert(ep);

if (transfer_type == TUSB_XFER_INTERRUPT)
{
ep = _next_free_interrupt_ep();
pico_info("Allocate interrupt ep %d\n", ep->interrupt_num);
assert(ep);
pico_info("Allocate interrupt ep slot %d int %d\n", ep_slot(ep), ep->interrupt_num);
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;
// 0 for epx (double buffered): TODO increase to 1024 for ISO
Expand All @@ -274,7 +318,7 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
}
else
{
ep = &epx;
pico_info("Allocate ep slot %d\n", ep_slot(ep));
ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
ep->endpoint_control = &usbh_dpram->epx_ctrl;
ep->hw_data_buf = &usbh_dpram->epx_data[0];
Expand Down Expand Up @@ -304,7 +348,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->wMaxPacketSize = wMaxPacketSize;
ep->transfer_type = transfer_type;

pico_trace("hw_endpoint_init dev %d ep %d %s xfer %d\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->transfer_type);
pico_trace("hw_endpoint_init slot %d dev %d ep %d %s %s\n", ep_slot(ep), ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], xfer_type_str(ep->transfer_type));
pico_trace("dev %d ep %d %s setup buffer @ 0x%p\n", ep->dev_addr, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)], ep->hw_data_buf);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
// Bits 0-5 should be 0
Expand Down Expand Up @@ -376,6 +420,9 @@ bool hcd_init(uint8_t rhport)
USB_INTE_ERROR_RX_TIMEOUT_BITS |
USB_INTE_ERROR_DATA_SEQ_BITS ;

const uint32_t nak_poll_delay = 100; // increase the spacing between NAK auto-retries
usb_hw->nak_poll = (nak_poll_delay << USB_NAK_POLL_DELAY_FS_LSB) | (nak_poll_delay << USB_NAK_POLL_DELAY_LS_LSB);

return true;
}

Expand Down Expand Up @@ -500,10 +547,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);
}

pico_trace(" slot %d %s dev_addr %d, ep_addr 0x%x\n", ep_slot(ep), xfer_type_str(ep->transfer_type), dev_addr, ep_addr);

// If a normal transfer (non-interrupt) then initiate using
// sie ctrl registers. Otherwise interrupt ep registers should
// already be configured
if (ep == &epx) {
if (ep->transfer_type != TUSB_XFER_INTERRUPT) {
hw_endpoint_xfer_start(ep, buffer, buflen);

// That has set up buffer control, endpoint control etc
Expand All @@ -528,11 +577,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
{
(void) rhport;

pico_trace("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);
struct hw_endpoint *ep = _hw_endpoint_allocate(TUSB_XFER_CONTROL);

// EP0 out
_hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
Expand Down