mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-02 13:20:20 +00:00
Merge pull request #1062 from HiFiPhile/fifo_dcd_transdimension
Improvements for dcd_transdimension
This commit is contained in:
commit
03866ddf9b
@ -1041,6 +1041,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TUSB_DESC_DEVICE_QUALIFIER:
|
case TUSB_DESC_DEVICE_QUALIFIER:
|
||||||
|
{
|
||||||
TU_LOG2(" Device Qualifier\r\n");
|
TU_LOG2(" Device Qualifier\r\n");
|
||||||
|
|
||||||
TU_VERIFY( tud_descriptor_device_qualifier_cb );
|
TU_VERIFY( tud_descriptor_device_qualifier_cb );
|
||||||
@ -1050,6 +1051,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
|
|||||||
|
|
||||||
// first byte of descriptor is its size
|
// first byte of descriptor is its size
|
||||||
return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]);
|
return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: return false;
|
default: return false;
|
||||||
@ -1377,7 +1379,13 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
|
|||||||
TU_ASSERT(dcd_edpt_close, /**/);
|
TU_ASSERT(dcd_edpt_close, /**/);
|
||||||
TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
|
TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
|
||||||
|
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
dcd_edpt_close(rhport, ep_addr);
|
dcd_edpt_close(rhport, ep_addr);
|
||||||
|
_usbd_dev.ep_status[epnum][dir].stalled = false;
|
||||||
|
_usbd_dev.ep_status[epnum][dir].busy = false;
|
||||||
|
_usbd_dev.ep_status[epnum][dir].claimed = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,8 @@ typedef struct
|
|||||||
// QHD is 64 bytes aligned but occupies only 48 bytes
|
// QHD is 64 bytes aligned but occupies only 48 bytes
|
||||||
// Therefore there are 16 bytes padding that we can use.
|
// Therefore there are 16 bytes padding that we can use.
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
uint8_t reserved[16];
|
tu_fifo_t * ff;
|
||||||
|
uint8_t reserved[12];
|
||||||
} dcd_qhd_t;
|
} dcd_qhd_t;
|
||||||
|
|
||||||
TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
|
TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct");
|
||||||
@ -240,8 +241,9 @@ void dcd_init(uint8_t rhport)
|
|||||||
dcd_reg->USBMODE = USBMODE_CM_DEVICE;
|
dcd_reg->USBMODE = USBMODE_CM_DEVICE;
|
||||||
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
|
dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION;
|
||||||
|
|
||||||
// TODO Force fullspeed on non-highspeed port
|
#if !TUD_OPT_HIGH_SPEED
|
||||||
// dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
|
dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED;
|
||||||
|
#endif
|
||||||
|
|
||||||
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
||||||
|
|
||||||
@ -296,18 +298,30 @@ void dcd_disconnect(uint8_t rhport)
|
|||||||
|
|
||||||
static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
|
static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes)
|
||||||
{
|
{
|
||||||
|
// Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the
|
||||||
|
// address to 32-byte boundaries. Buffer must be word aligned
|
||||||
|
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31);
|
||||||
|
|
||||||
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
|
tu_memclr(p_qtd, sizeof(dcd_qtd_t));
|
||||||
|
|
||||||
p_qtd->next = QTD_NEXT_INVALID;
|
p_qtd->next = QTD_NEXT_INVALID;
|
||||||
p_qtd->active = 1;
|
p_qtd->active = 1;
|
||||||
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
|
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
|
||||||
|
p_qtd->int_on_complete = true;
|
||||||
|
|
||||||
if (data_ptr != NULL)
|
if (data_ptr != NULL)
|
||||||
{
|
{
|
||||||
p_qtd->buffer[0] = (uint32_t) data_ptr;
|
p_qtd->buffer[0] = (uint32_t) data_ptr;
|
||||||
|
|
||||||
|
uint32_t const bufend = p_qtd->buffer[0] + total_bytes;
|
||||||
for(uint8_t i=1; i<5; i++)
|
for(uint8_t i=1; i<5; i++)
|
||||||
{
|
{
|
||||||
p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096;
|
uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096;
|
||||||
|
if ( bufend <= next_page ) break;
|
||||||
|
|
||||||
|
p_qtd->buffer[i] = next_page;
|
||||||
|
|
||||||
|
// TODO page[1] FRAME_N for ISO transfer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -340,9 +354,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
|
|||||||
|
|
||||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||||
{
|
{
|
||||||
// TODO not support ISO yet
|
|
||||||
TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS);
|
|
||||||
|
|
||||||
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
|
uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress);
|
||||||
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
|
uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress);
|
||||||
|
|
||||||
@ -355,13 +366,27 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
|||||||
|
|
||||||
p_qhd->zero_length_termination = 1;
|
p_qhd->zero_length_termination = 1;
|
||||||
p_qhd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
|
p_qhd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size;
|
||||||
|
if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
|
||||||
|
{
|
||||||
|
p_qhd->iso_mult = 1;
|
||||||
|
}
|
||||||
|
|
||||||
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
|
p_qhd->qtd_overlay.next = QTD_NEXT_INVALID;
|
||||||
|
|
||||||
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
||||||
|
|
||||||
// Enable EP Control
|
// Enable EP Control
|
||||||
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||||
dcd_reg->ENDPTCTRL[epnum] |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
|
|
||||||
|
uint32_t const epctrl = (p_endpoint_desc->bmAttributes.xfer << ENDPTCTRL_TYPE_POS) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET;
|
||||||
|
|
||||||
|
if ( dir == TUSB_DIR_OUT )
|
||||||
|
{
|
||||||
|
dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0xFFFF0000u) | epctrl;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
dcd_reg->ENDPTCTRL[epnum] = (dcd_reg->ENDPTCTRL[epnum] & 0x0000FFFFu) | (epctrl << 16);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -381,12 +406,36 @@ void dcd_edpt_close_all (uint8_t rhport)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
|
||||||
{
|
{
|
||||||
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||||
|
|
||||||
|
_dcd_data.qhd[epnum][dir].qtd_overlay.halted = 1;
|
||||||
|
|
||||||
|
// Flush EP
|
||||||
|
uint32_t const flush_mask = TU_BIT(epnum + (dir ? 16 : 0));
|
||||||
|
dcd_reg->ENDPTFLUSH = flush_mask;
|
||||||
|
while(dcd_reg->ENDPTFLUSH & flush_mask);
|
||||||
|
|
||||||
|
// Clear EP enable
|
||||||
|
dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir)
|
||||||
|
{
|
||||||
|
dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs;
|
||||||
|
dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
|
||||||
|
dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
|
||||||
|
|
||||||
|
p_qhd->qtd_overlay.halted = false; // clear any previous error
|
||||||
|
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd
|
||||||
|
|
||||||
|
// flush cache
|
||||||
|
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
||||||
|
|
||||||
if ( epnum == 0 )
|
if ( epnum == 0 )
|
||||||
{
|
{
|
||||||
// follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
|
// follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism
|
||||||
@ -394,25 +443,87 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
|
|||||||
while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
|
while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start transfer
|
||||||
|
dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
|
dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir];
|
||||||
dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
|
dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir];
|
||||||
|
|
||||||
// Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the
|
// Prepare qtd
|
||||||
// address to 32-byte boundaries.
|
|
||||||
// void* cast to suppress cast-align warning, buffer must be
|
|
||||||
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31);
|
|
||||||
|
|
||||||
//------------- Prepare qtd -------------//
|
|
||||||
qtd_init(p_qtd, buffer, total_bytes);
|
qtd_init(p_qtd, buffer, total_bytes);
|
||||||
p_qtd->int_on_complete = true;
|
|
||||||
|
|
||||||
p_qhd->qtd_overlay.halted = false; // clear any previous error
|
// Start qhd transfer
|
||||||
p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // activate by linking qtd to qhd
|
p_qhd->ff = NULL;
|
||||||
|
qhd_start_xfer(rhport, epnum, dir);
|
||||||
|
|
||||||
CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t));
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// start transfer
|
// fifo has to be aligned to 4k boundary
|
||||||
dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0));
|
bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
|
||||||
|
{
|
||||||
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
|
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
|
||||||
|
dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
|
||||||
|
|
||||||
|
tu_fifo_buffer_info_t fifo_info;
|
||||||
|
|
||||||
|
if (dir)
|
||||||
|
{
|
||||||
|
tu_fifo_get_read_info(ff, &fifo_info);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
tu_fifo_get_write_info(ff, &fifo_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fifo_info.len_lin >= total_bytes )
|
||||||
|
{
|
||||||
|
// Linear length is enough for this transfer
|
||||||
|
qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// linear part is not enough
|
||||||
|
|
||||||
|
// prepare TD up to linear length
|
||||||
|
qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin);
|
||||||
|
|
||||||
|
if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) )
|
||||||
|
{
|
||||||
|
// If buffer is aligned to 4K & buffer size is multiple of 4K
|
||||||
|
// We can make use of buffer page array to also combine the linear + wrapped length
|
||||||
|
p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
|
||||||
|
|
||||||
|
for(uint8_t i = 1, page = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
// pick up buffer array where linear ends
|
||||||
|
if (p_qtd->buffer[i] == 0)
|
||||||
|
{
|
||||||
|
p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page;
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO we may need to carry the wrapped length after the linear part complete
|
||||||
|
// for now only transfer up to linear part
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start qhd transfer
|
||||||
|
p_qhd->ff = ff;
|
||||||
|
qhd_start_xfer(rhport, epnum, dir);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -423,6 +534,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
|
|||||||
|
|
||||||
static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
|
static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir)
|
||||||
{
|
{
|
||||||
|
dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir];
|
||||||
dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
|
dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir];
|
||||||
|
|
||||||
uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
|
uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED :
|
||||||
@ -435,8 +547,21 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir
|
|||||||
dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
|
dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t const xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes;
|
||||||
|
|
||||||
|
if (p_qhd->ff)
|
||||||
|
{
|
||||||
|
if (dir == TUSB_DIR_IN)
|
||||||
|
{
|
||||||
|
tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// only number of bytes in the IOC qtd
|
// only number of bytes in the IOC qtd
|
||||||
dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true);
|
dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dcd_int_handler(uint8_t rhport)
|
void dcd_int_handler(uint8_t rhport)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user