From a9a5146108946b060b34b833ea8dd720bcb6fc02 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 1 Dec 2013 15:48:49 +0700 Subject: correct stall & clear stall behavior for non-control pipe fix data_residue when read10, write10 return 0 (no need for BE conversion) --- tinyusb/class/msc_device.c | 3 ++- tinyusb/device/dcd_lpc_11uxx_13uxx.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 10 deletions(-) (limited to 'tinyusb') diff --git a/tinyusb/class/msc_device.c b/tinyusb/class/msc_device.c index 6fc36fc03..f69907503 100644 --- a/tinyusb/class/msc_device.c +++ b/tinyusb/class/msc_device.c @@ -158,7 +158,7 @@ static bool read10_write10_data_xfer(mscd_interface_t* p_msc) if ( 0 == xferred_block ) { // xferred_block is zero will cause pipe is stalled & status in CSW set to failed - p_csw->data_residue = __n2be(p_cbw->xfer_bytes); + p_csw->data_residue = p_cbw->xfer_bytes; p_csw->status = MSC_CSW_STATUS_FAILED; (void) dcd_pipe_stall(edpt_hdl); @@ -239,6 +239,7 @@ tusb_error_t mscd_xfer_cb(endpoint_handle_t edpt_hdl, tusb_event_t event, uint32 } //------------- Status Phase -------------// + // Either bulk in & out can be stalled in the data phase, dcd must make sure these queued transfer will be resumed after host clear stall if (!is_waiting_read10_write10) { ASSERT_STATUS( dcd_pipe_xfer( p_msc->edpt_in , p_csw, sizeof(msc_cmd_status_wrapper_t), true) ); // need to be true for dcd to clean up qtd !! diff --git a/tinyusb/device/dcd_lpc_11uxx_13uxx.c b/tinyusb/device/dcd_lpc_11uxx_13uxx.c index 09ff7a58a..b2681c40a 100644 --- a/tinyusb/device/dcd_lpc_11uxx_13uxx.c +++ b/tinyusb/device/dcd_lpc_11uxx_13uxx.c @@ -144,6 +144,7 @@ static inline uint16_t addr_offset(void const * p_buffer) static void queue_xfer_to_buffer(uint8_t ep_id, uint8_t buff_idx, uint16_t buff_addr_offset, uint16_t total_bytes); static void pipe_queue_xfer(uint8_t ep_id, uint16_t buff_addr_offset, uint16_t total_bytes); +static void queue_xfer_in_next_td(uint8_t ep_id); //--------------------------------------------------------------------+ // CONTROLLER API @@ -315,11 +316,7 @@ void dcd_isr(uint8_t coreid) //------------- Next TD is available -------------// if ( dcd_data.next_td[ep_id].total_bytes != 0 ) { - dcd_data.current_ioc |= ( dcd_data.next_ioc & BIT_(ep_id) ); // copy next IOC to current IOC - - pipe_queue_xfer(ep_id, dcd_data.next_td[ep_id].buff_addr_offset, dcd_data.next_td[ep_id].total_bytes); - - dcd_data.next_td[ep_id].total_bytes = 0; // clear this field as it is used to indicate next TD available + queue_xfer_in_next_td(ep_id); } } } @@ -370,13 +367,16 @@ static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) //--------------------------------------------------------------------+ tusb_error_t dcd_pipe_stall(endpoint_handle_t edpt_hdl) { -// ASSERT( !dcd_pipe_is_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring - dcd_data.qhd[edpt_hdl.index][0].stall = dcd_data.qhd[edpt_hdl.index][1].stall = 1; return TUSB_ERROR_NONE; } +bool dcd_pipe_is_stalled(endpoint_handle_t edpt_hdl) +{ + return dcd_data.qhd[edpt_hdl.index][0].stall || dcd_data.qhd[edpt_hdl.index][1].stall; +} + tusb_error_t dcd_pipe_clear_stall(uint8_t coreid, uint8_t edpt_addr) { uint8_t ep_id = edpt_addr2phy(edpt_addr); @@ -387,6 +387,12 @@ tusb_error_t dcd_pipe_clear_stall(uint8_t coreid, uint8_t edpt_addr) dcd_data.qhd[ep_id][active_buffer].toggle_reset = 1; dcd_data.qhd[ep_id][active_buffer].feedback_toggle = 0; + //------------- clear stall must carry on any previously queued transfer -------------// + if ( dcd_data.next_td[ep_id].total_bytes != 0 ) + { + queue_xfer_in_next_td(ep_id); + } + return TUSB_ERROR_NONE; } @@ -460,6 +466,15 @@ static void pipe_queue_xfer(uint8_t ep_id, uint16_t buff_addr_offset, uint16_t t queue_xfer_to_buffer(ep_id, 0, buff_addr_offset, total_bytes); } +static void queue_xfer_in_next_td(uint8_t ep_id) +{ + dcd_data.current_ioc |= ( dcd_data.next_ioc & BIT_(ep_id) ); // copy next IOC to current IOC + + pipe_queue_xfer(ep_id, dcd_data.next_td[ep_id].buff_addr_offset, dcd_data.next_td[ep_id].total_bytes); + + dcd_data.next_td[ep_id].total_bytes = 0; // clear this field as it is used to indicate whehther next TD available +} + tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes) { ASSERT( !dcd_pipe_is_busy(edpt_hdl), TUSB_ERROR_INTERFACE_IS_BUSY); // endpoint must not in transferring @@ -473,8 +488,8 @@ tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, void* buffer, uint16_t total_bytes, bool int_on_complete) { - if( dcd_pipe_is_busy(edpt_hdl) ) - { // save this transfer data to next td + if( dcd_pipe_is_busy(edpt_hdl) || dcd_pipe_is_stalled(edpt_hdl) ) + { // save this transfer data to next td if pipe is busy or already been stalled dcd_data.next_td[edpt_hdl.index].buff_addr_offset = addr_offset(buffer); dcd_data.next_td[edpt_hdl.index].total_bytes = total_bytes; -- cgit v1.3.1