From cfdc7999f661ecc5d978073f2808d4319ee44426 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 11 Mar 2018 15:20:27 +0700 Subject: [PATCH] refactor dcd API, drop edpt_hdl_t in favor of endpoint address for easy port --- hw/mcu/nxp/lpc43xx/tusb_port/dcd_lpc43xx.c | 65 +++++++++++----------- tinyusb/class/cdc/cdc_device.c | 41 ++++++++------ tinyusb/class/cdc/cdc_device.h | 2 +- tinyusb/common/verify.h | 2 +- tinyusb/device/usbd.c | 12 ++-- tinyusb/device/usbd.h | 4 +- tinyusb/tusb_dcd.h | 21 ++----- 7 files changed, 70 insertions(+), 77 deletions(-) diff --git a/hw/mcu/nxp/lpc43xx/tusb_port/dcd_lpc43xx.c b/hw/mcu/nxp/lpc43xx/tusb_port/dcd_lpc43xx.c index aca5e529..26463c70 100644 --- a/hw/mcu/nxp/lpc43xx/tusb_port/dcd_lpc43xx.c +++ b/hw/mcu/nxp/lpc43xx/tusb_port/dcd_lpc43xx.c @@ -183,6 +183,11 @@ static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_DEV_TO_HOST_MASK) ? 1 : 0); } +static inline uint8_t edpt_phy2addr(uint8_t ep_idx) +{ + return (ep_idx/2) | ( ep_idx & 0x01 ? TUSB_DIR_DEV_TO_HOST_MASK : 0 ); +} + static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) { return physical_endpoint/2; @@ -273,11 +278,12 @@ static inline volatile uint32_t * get_reg_control_addr(uint8_t port, uint8_t phy return &(LPC_USB[port]->ENDPTCTRL0) + edpt_phy2log(physical_endpoint); } -void tusb_dcd_edpt_stall(edpt_hdl_t edpt_hdl) +void tusb_dcd_edpt_stall(uint8_t port, uint8_t edpt_addr) { - volatile uint32_t * reg_control = get_reg_control_addr(edpt_hdl.port, edpt_hdl.index); + uint8_t ep_idx = edpt_addr2phy(edpt_addr); + volatile uint32_t * reg_control = get_reg_control_addr(port, ep_idx); - (*reg_control) |= ENDPTCTRL_MASK_STALL << (edpt_hdl.index & 0x01 ? 16 : 0); + (*reg_control) |= ENDPTCTRL_MASK_STALL << (ep_idx & 0x01 ? 16 : 0); } void tusb_dcd_edpt_clear_stall(uint8_t port, uint8_t edpt_addr) @@ -289,7 +295,7 @@ void tusb_dcd_edpt_clear_stall(uint8_t port, uint8_t edpt_addr) (*reg_control) &= ~(ENDPTCTRL_MASK_STALL << ((edpt_addr & TUSB_DIR_DEV_TO_HOST_MASK) ? 16 : 0)); } -bool tusb_dcd_edpt_open(uint8_t port, tusb_descriptor_endpoint_t const * p_endpoint_desc, edpt_hdl_t* eh) +bool tusb_dcd_edpt_open(uint8_t port, tusb_descriptor_endpoint_t const * p_endpoint_desc) { // TODO USB1 only has 4 non-control enpoint (USB0 has 5) // TODO not support ISO yet @@ -315,28 +321,26 @@ bool tusb_dcd_edpt_open(uint8_t port, tusb_descriptor_endpoint_t const * p_endpo (*reg_control) |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_MASK_ENABLE | ENDPTCTRL_MASK_TOGGLE_RESET) << (dir ? 16 : 0); - eh->port = port; - eh->index = ep_idx; - return true; } -bool tusb_dcd_edpt_busy(edpt_hdl_t edpt_hdl) +bool tusb_dcd_edpt_busy(uint8_t port, uint8_t edpt_addr) { - dcd_qhd_t const * p_qhd = &dcd_data_ptr[edpt_hdl.port]->qhd[edpt_hdl.index]; + uint8_t ep_idx = edpt_addr2phy(edpt_addr); + dcd_qhd_t const * p_qhd = &dcd_data_ptr[port]->qhd[ep_idx]; return p_qhd->list_qtd_idx[0] != 0; // qtd list is not empty // return !p_qhd->qtd_overlay.halted && p_qhd->qtd_overlay.active; } // add only, controller virtually cannot know -static tusb_error_t pipe_add_xfer(edpt_hdl_t edpt_hdl, void * buffer, uint16_t total_bytes, bool int_on_complete) +static tusb_error_t pipe_add_xfer(uint8_t port, uint8_t ed_idx, void * buffer, uint16_t total_bytes, bool int_on_complete) { - uint8_t qtd_idx = qtd_find_free(edpt_hdl.port); + uint8_t qtd_idx = qtd_find_free(port); ASSERT(qtd_idx != 0, TUSB_ERROR_DCD_NOT_ENOUGH_QTD); - dcd_data_t* p_dcd = dcd_data_ptr[edpt_hdl.port]; - dcd_qhd_t * p_qhd = &p_dcd->qhd[edpt_hdl.index]; + dcd_data_t* p_dcd = dcd_data_ptr[port]; + dcd_qhd_t * p_qhd = &p_dcd->qhd[ed_idx]; dcd_qtd_t * p_qtd = &p_dcd->qtd[qtd_idx]; //------------- Find free slot in qhd's array list -------------// @@ -358,21 +362,24 @@ static tusb_error_t pipe_add_xfer(edpt_hdl_t edpt_hdl, void * buffer, uint16_t t return TUSB_ERROR_NONE; } -tusb_error_t tusb_dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes) +tusb_error_t tusb_dcd_edpt_queue_xfer(uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes) { - return pipe_add_xfer( edpt_hdl, buffer, total_bytes, false); + uint8_t ep_idx = edpt_addr2phy(edpt_addr); + return pipe_add_xfer(port, ep_idx, buffer, total_bytes, false); } -tusb_error_t tusb_dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete) +tusb_error_t tusb_dcd_edpt_xfer(uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete) { - ASSERT_STATUS ( pipe_add_xfer(edpt_hdl, buffer, total_bytes, int_on_complete) ); + uint8_t ep_idx = edpt_addr2phy(edpt_addr); - dcd_qhd_t* p_qhd = &dcd_data_ptr[edpt_hdl.port]->qhd[ edpt_hdl.index ]; - dcd_qtd_t* p_qtd = &dcd_data_ptr[edpt_hdl.port]->qtd[ p_qhd->list_qtd_idx[0] ]; + ASSERT_STATUS ( pipe_add_xfer(port, ep_idx, buffer, total_bytes, int_on_complete) ); + + dcd_qhd_t* p_qhd = &dcd_data_ptr[port]->qhd[ ep_idx ]; + dcd_qtd_t* p_qtd = &dcd_data_ptr[port]->qtd[ p_qhd->list_qtd_idx[0] ]; p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // attach head QTD to QHD start transferring - LPC_USB[edpt_hdl.port]->ENDPTPRIME = BIT_( edpt_phy2pos(edpt_hdl.index) ) ; + LPC_USB[port]->ENDPTPRIME = BIT_( edpt_phy2pos(ep_idx) ) ; return TUSB_ERROR_NONE; } @@ -386,12 +393,6 @@ void xfer_complete_isr(uint8_t port, uint32_t reg_complete) { // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set dcd_qhd_t * p_qhd = &dcd_data_ptr[port]->qhd[ep_idx]; - edpt_hdl_t edpt_hdl = - { - .port = port, - .index = ep_idx, - }; - // retire all QTDs in array list, up to 1st still-active QTD while( p_qhd->list_qtd_idx[0] != 0 ) { @@ -407,7 +408,9 @@ void xfer_complete_isr(uint8_t port, uint32_t reg_complete) if (p_qtd->int_on_complete) { bool succeeded = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? false : true; - tusb_dcd_xfer_complete(edpt_hdl, p_qtd->expected_bytes - p_qtd->total_bytes, succeeded); // only number of bytes in the IOC qtd + + uint8_t edpt_addr = edpt_phy2addr(ep_idx); + tusb_dcd_xfer_complete(port, edpt_addr, p_qtd->expected_bytes - p_qtd->total_bytes, succeeded); // only number of bytes in the IOC qtd } } } @@ -476,14 +479,8 @@ void hal_dcd_isr(uint8_t port) if ( p_qtd->int_on_complete ) { - edpt_hdl_t edpt_hdl = - { - .port = port, - .index = 0, - }; bool succeeded = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? false : true; - - tusb_dcd_xfer_complete(edpt_hdl, 0, succeeded); // TODO xferred bytes for control xfer is not needed yet !!!! + tusb_dcd_xfer_complete(port, 0, 0, succeeded); // TODO xferred bytes for control xfer is not needed yet !!!! } } } diff --git a/tinyusb/class/cdc/cdc_device.c b/tinyusb/class/cdc/cdc_device.c index 43aad2d7..056b9147 100644 --- a/tinyusb/class/cdc/cdc_device.c +++ b/tinyusb/class/cdc/cdc_device.c @@ -55,10 +55,8 @@ TUSB_CFG_ATTR_USBRAM STATIC_VAR cdc_line_coding_t cdcd_line_coding[CONTROLLER_DE typedef struct { uint8_t interface_number; cdc_acm_capability_t acm_capability; - bool connected; - - edpt_hdl_t edpt_hdl[3]; // notification, data in, data out + uint8_t edpt_addr[3]; // notification, data in, data out }cdcd_data_t; // TODO multiple port @@ -157,7 +155,9 @@ tusb_error_t cdcd_open(uint8_t port, tusb_descriptor_interface_t const * p_inter if ( TUSB_DESC_TYPE_ENDPOINT == p_desc[DESCRIPTOR_OFFSET_TYPE]) { // notification endpoint if any - VERIFY( tusb_dcd_edpt_open(port, (tusb_descriptor_endpoint_t const *) p_desc, &p_cdc->edpt_hdl[CDC_PIPE_NOTIFICATION]), TUSB_ERROR_DCD_OPEN_PIPE_FAILED); + TU_ASSERT( tusb_dcd_edpt_open(port, (tusb_descriptor_endpoint_t const *) p_desc), TUSB_ERROR_DCD_OPEN_PIPE_FAILED); + + p_cdc->edpt_addr[CDC_PIPE_NOTIFICATION] = ((tusb_descriptor_endpoint_t const *) p_desc)->bEndpointAddress; (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH]; p_desc = descriptor_next(p_desc); @@ -174,13 +174,18 @@ tusb_error_t cdcd_open(uint8_t port, tusb_descriptor_interface_t const * p_inter for(uint32_t i=0; i<2; i++) { tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) p_desc; - ASSERT_(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_DESCRIPTOR_CORRUPTED); - ASSERT_(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED); + TU_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType, TUSB_ERROR_DESCRIPTOR_CORRUPTED); + TU_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED); - edpt_hdl_t * p_edpt_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) ? - &p_cdc->edpt_hdl[CDC_PIPE_DATA_IN] : &p_cdc->edpt_hdl[CDC_PIPE_DATA_OUT] ; + TU_ASSERT( tusb_dcd_edpt_open(port, p_endpoint), TUSB_ERROR_DCD_OPEN_PIPE_FAILED); - ASSERT_( tusb_dcd_edpt_open(port, p_endpoint, p_edpt_hdl), TUSB_ERROR_DCD_OPEN_PIPE_FAILED); + if ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) + { + p_cdc->edpt_addr[CDC_PIPE_DATA_IN] = p_endpoint->bEndpointAddress; + }else + { + p_cdc->edpt_addr[CDC_PIPE_DATA_OUT] = p_endpoint->bEndpointAddress; + } (*p_length) += p_desc[DESCRIPTOR_OFFSET_LENGTH]; p_desc = descriptor_next( p_desc ); @@ -190,7 +195,7 @@ tusb_error_t cdcd_open(uint8_t port, tusb_descriptor_interface_t const * p_inter p_cdc->interface_number = p_interface_desc->bInterfaceNumber; // Prepare for incoming data - tusb_dcd_edpt_xfer(p_cdc->edpt_hdl[CDC_PIPE_DATA_OUT], _tmp_rx_buf, sizeof(_tmp_rx_buf), true); + tusb_dcd_edpt_xfer(port, p_cdc->edpt_addr[CDC_PIPE_DATA_OUT], _tmp_rx_buf, sizeof(_tmp_rx_buf), true); return TUSB_ERROR_NONE; @@ -255,19 +260,19 @@ tusb_error_t cdcd_control_request_subtask(uint8_t port, tusb_control_request_t c return TUSB_ERROR_NONE; } -tusb_error_t cdcd_xfer_cb(edpt_hdl_t edpt_hdl, tusb_event_t event, uint32_t xferred_bytes) +tusb_error_t cdcd_xfer_cb(uint8_t port, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) { - cdcd_data_t const * p_cdc = &cdcd_data[edpt_hdl.port]; + cdcd_data_t const * p_cdc = &cdcd_data[port]; - if ( edpt_equal(edpt_hdl, p_cdc->edpt_hdl[CDC_PIPE_DATA_OUT]) ) + if ( edpt_addr == p_cdc->edpt_addr[CDC_PIPE_DATA_OUT] ) { fifo_write_n(&_rx_ff, _tmp_rx_buf, xferred_bytes); // preparing for next - tusb_dcd_edpt_xfer(p_cdc->edpt_hdl[CDC_PIPE_DATA_OUT], _tmp_rx_buf, sizeof(_tmp_rx_buf), true); + tusb_dcd_edpt_xfer(port, p_cdc->edpt_addr[CDC_PIPE_DATA_OUT], _tmp_rx_buf, sizeof(_tmp_rx_buf), true); // fire callback - tud_cdc_rx_cb(edpt_hdl.port); + tud_cdc_rx_cb(port); } return TUSB_ERROR_NONE; @@ -277,13 +282,13 @@ void cdcd_sof(uint8_t port) { if ( !tud_cdc_connected(port) ) return; - edpt_hdl_t ep = cdcd_data[port].edpt_hdl[CDC_PIPE_DATA_IN]; + uint8_t edpt = cdcd_data[port].edpt_addr[CDC_PIPE_DATA_IN]; - if ( !tusb_dcd_edpt_busy( ep ) ) + if ( !tusb_dcd_edpt_busy(port, edpt) ) { uint16_t count = fifo_read_n(&_tx_ff, _tmp_tx_buf, sizeof(_tmp_tx_buf)); - tusb_dcd_edpt_xfer(ep, _tmp_tx_buf, count, false); + tusb_dcd_edpt_xfer(port, edpt, _tmp_tx_buf, count, false); } } diff --git a/tinyusb/class/cdc/cdc_device.h b/tinyusb/class/cdc/cdc_device.h index aaf7920a..db1ef04b 100644 --- a/tinyusb/class/cdc/cdc_device.h +++ b/tinyusb/class/cdc/cdc_device.h @@ -79,7 +79,7 @@ void tud_cdc_rx_cb(uint8_t port); void cdcd_init(void); tusb_error_t cdcd_open(uint8_t port, tusb_descriptor_interface_t const * p_interface_desc, uint16_t *p_length); tusb_error_t cdcd_control_request_subtask(uint8_t port, tusb_control_request_t const * p_request); -tusb_error_t cdcd_xfer_cb(edpt_hdl_t edpt_hdl, tusb_event_t event, uint32_t xferred_bytes); +tusb_error_t cdcd_xfer_cb(uint8_t port, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void cdcd_close(uint8_t port); void cdcd_sof(uint8_t port); diff --git a/tinyusb/common/verify.h b/tinyusb/common/verify.h index 3aec0a9f..50915cf9 100644 --- a/tinyusb/common/verify.h +++ b/tinyusb/common/verify.h @@ -155,7 +155,7 @@ #define ASSERT_1ARGS(cond) do { if (!(cond)) { tusb_hal_dbg_breakpoint(); _ASSERT_MESS() return false; } } while(0) #define ASSERT_2ARGS(cond, _error) do { if (!(cond)) { tusb_hal_dbg_breakpoint(); _ASSERT_MESS() return _error;} } while(0) -#define ASSERT_(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS)(__VA_ARGS__) +#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS)(__VA_ARGS__) #ifdef __cplusplus } diff --git a/tinyusb/device/usbd.c b/tinyusb/device/usbd.c index 9e0a5721..2ae86ef8 100644 --- a/tinyusb/device/usbd.c +++ b/tinyusb/device/usbd.c @@ -138,7 +138,7 @@ typedef struct ATTR_ALIGNED(4) tusb_control_request_t setup_received; struct { // USBD_EVENTID_XFER_DONE - edpt_hdl_t edpt_hdl; + uint8_t edpt_addr; uint32_t xferred_byte; }xfer_done; }; @@ -252,7 +252,7 @@ static tusb_error_t usbd_body_subtask(void) { if ( usbd_class_drivers[class_code].xfer_cb ) { - usbd_class_drivers[class_code].xfer_cb( event.xfer_done.edpt_hdl, (tusb_event_t) event.sub_event_id, event.xfer_done.xferred_byte); + usbd_class_drivers[class_code].xfer_cb( event.port, event.xfer_done.edpt_addr, (tusb_event_t) event.sub_event_id, event.xfer_done.xferred_byte); } } }else if (USBD_EVENTID_SOF == event.event_id) @@ -498,9 +498,9 @@ void tusb_dcd_setup_received(uint8_t port, uint8_t const* p_request) osal_queue_send(usbd_queue_hdl, &task_event); } -void tusb_dcd_xfer_complete(edpt_hdl_t edpt_hdl, uint32_t xferred_bytes, bool succeeded) +void tusb_dcd_xfer_complete(uint8_t port, uint8_t edpt_addr, uint32_t xferred_bytes, bool succeeded) { - if (edpt_hdl.index == 0 ) + if (edpt_addr == 0 ) { // Control Transfer osal_semaphore_post( usbd_control_xfer_sem_hdl ); @@ -508,13 +508,13 @@ void tusb_dcd_xfer_complete(edpt_hdl_t edpt_hdl, uint32_t xferred_bytes, bool su { usbd_task_event_t task_event = { - .port = edpt_hdl.port, + .port = port, .event_id = USBD_EVENTID_XFER_DONE, .sub_event_id = succeeded ? TUSB_EVENT_XFER_COMPLETE : TUSB_EVENT_XFER_ERROR }; + task_event.xfer_done.edpt_addr = edpt_addr; task_event.xfer_done.xferred_byte = xferred_bytes; - task_event.xfer_done.edpt_hdl = edpt_hdl; osal_queue_send(usbd_queue_hdl, &task_event); } diff --git a/tinyusb/device/usbd.h b/tinyusb/device/usbd.h index 3fb6a625..8258abfd 100644 --- a/tinyusb/device/usbd.h +++ b/tinyusb/device/usbd.h @@ -78,9 +78,9 @@ extern tusbd_descriptor_pointer_t tusbd_descriptor_pointers; typedef struct { void (* init) (void); - tusb_error_t (* open)(uint8_t, tusb_descriptor_interface_t const *, uint16_t*); + tusb_error_t (* open)(uint8_t port, tusb_descriptor_interface_t const * desc_intf, uint16_t* p_length); tusb_error_t (* control_request_subtask) (uint8_t port, tusb_control_request_t const *); - tusb_error_t (* xfer_cb) (edpt_hdl_t, tusb_event_t, uint32_t); + tusb_error_t (* xfer_cb) (uint8_t port, uint8_t edpt_addr, tusb_event_t, uint32_t); // void (* routine)(void); void (* sof)(uint8_t port); void (* close) (uint8_t); diff --git a/tinyusb/tusb_dcd.h b/tinyusb/tusb_dcd.h index f35523bf..611511f2 100644 --- a/tinyusb/tusb_dcd.h +++ b/tinyusb/tusb_dcd.h @@ -58,15 +58,6 @@ typedef enum USBD_BUS_EVENT_RESUME }usbd_bus_event_type_t; -typedef struct { - uint8_t port; - uint8_t index; // must be zero to indicate control -} edpt_hdl_t; - -static inline bool edpt_equal(edpt_hdl_t x, edpt_hdl_t y) -{ - return (x.port == y.port) && (x.index == y.index); -} //------------- Controller API -------------// bool tusb_dcd_init (uint8_t port); @@ -81,7 +72,7 @@ void tusb_dcd_set_config (uint8_t port, uint8_t config_num); *------------------------------------------------------------------*/ void tusb_dcd_bus_event(uint8_t port, usbd_bus_event_type_t bus_event); void tusb_dcd_setup_received(uint8_t port, uint8_t const* p_request); -void tusb_dcd_xfer_complete(edpt_hdl_t edpt_hdl, uint32_t xferred_bytes, bool succeeded); +void tusb_dcd_xfer_complete(uint8_t port, uint8_t edpt_addr, uint32_t xferred_bytes, bool succeeded); /*------------------------------------------------------------------*/ /* API @@ -90,14 +81,14 @@ void tusb_dcd_xfer_complete(edpt_hdl_t edpt_hdl, uint32_t xferred_bytes, bool su bool tusb_dcd_control_xfer(uint8_t port, tusb_direction_t dir, uint8_t * p_buffer, uint16_t length, bool int_on_complete); void tusb_dcd_control_stall(uint8_t port); -bool tusb_dcd_edpt_open(uint8_t port, tusb_descriptor_endpoint_t const * p_endpoint_desc, edpt_hdl_t* eh); -tusb_error_t tusb_dcd_edpt_queue_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes); // only queue, not transferring yet -tusb_error_t tusb_dcd_edpt_xfer(edpt_hdl_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete); +bool tusb_dcd_edpt_open(uint8_t port, tusb_descriptor_endpoint_t const * p_endpoint_desc); +tusb_error_t tusb_dcd_edpt_queue_xfer(uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes); // only queue, not transferring yet +tusb_error_t tusb_dcd_edpt_xfer(uint8_t port, uint8_t edpt_addr, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete); -bool tusb_dcd_edpt_busy(edpt_hdl_t edpt_hdl); +bool tusb_dcd_edpt_busy(uint8_t port, uint8_t edpt_addr); // TODO port + endpoint address are part of endpoint handle, not endpoint handle, data toggle also need to be reset -void tusb_dcd_edpt_stall(edpt_hdl_t edpt_hdl); +void tusb_dcd_edpt_stall(uint8_t port, uint8_t edpt_addr); void tusb_dcd_edpt_clear_stall(uint8_t port, uint8_t edpt_addr); #ifdef __cplusplus