From 3a54ad4c0d4e31bf9a13cebb771ccc9e9f4f6449 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 1 Nov 2013 12:11:26 +0700 Subject: implement msc device class usbd auto stall control for not supported return from class control request usbd implement xfer isr callback mechanism DCD - implement dcd multiple qtd support - dcd dcd_pipe_stall - implement dcd_pipe_queue_xfer - xfer_complete_isr - flush control endpoint if received new setup while previous transfer is not complete change msc_cmd_block_wrapper_t flags field to dir force full speed for easy testing NOTEs: somehow unable to get endpoint IN interrupt with ioc --- tinyusb/device/dcd.h | 18 +-- tinyusb/device/dcd_lpc175x_6x.c | 4 +- tinyusb/device/dcd_lpc43xx.c | 277 +++++++++++++++++++++++++++++----------- tinyusb/device/usbd.c | 108 ++++++++++------ tinyusb/device/usbd.h | 2 +- tinyusb/device/usbd_dcd.h | 6 +- 6 files changed, 287 insertions(+), 128 deletions(-) (limited to 'tinyusb/device') diff --git a/tinyusb/device/dcd.h b/tinyusb/device/dcd.h index 73cbeb2cb..fa947bf11 100644 --- a/tinyusb/device/dcd.h +++ b/tinyusb/device/dcd.h @@ -53,21 +53,21 @@ typedef struct { uint8_t coreid; - uint8_t xfer_type; // cannot be control as control uses separated API + uint8_t xfer_type; // TODO redundant, cannot be control as control uses separated API uint8_t index; - uint8_t reserved; + uint8_t class_code; } endpoint_handle_t; -static inline bool endpointhandle_is_valid(endpoint_handle_t endpoint_handle) ATTR_CONST ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; -static inline bool endpointhandle_is_valid(endpoint_handle_t endpoint_handle) +static inline bool endpointhandle_is_valid(endpoint_handle_t edpt_hdl) ATTR_CONST ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; +static inline bool endpointhandle_is_valid(endpoint_handle_t edpt_hdl) { - return endpoint_handle.xfer_type != TUSB_XFER_CONTROL; + return (edpt_hdl.xfer_type != TUSB_XFER_CONTROL) && (edpt_hdl.class_code != 0); } static inline bool endpointhandle_is_equal(endpoint_handle_t x, endpoint_handle_t y) ATTR_CONST ATTR_ALWAYS_INLINE ATTR_WARN_UNUSED_RESULT; static inline bool endpointhandle_is_equal(endpoint_handle_t x, endpoint_handle_t y) { - return (x.coreid == y.coreid) && (x.xfer_type == y.xfer_type) && (x.index == y.index); + return (x.coreid == y.coreid) && (x.xfer_type == y.xfer_type) && (x.index == y.index) && (x.class_code == y.class_code); } tusb_error_t dcd_init(void) ATTR_WARN_UNUSED_RESULT; @@ -89,8 +89,10 @@ void dcd_pipe_control_stall(uint8_t coreid); //tusb_error_t dcd_pipe_control_read(uint8_t coreid, void * buffer, uint16_t length); //void dcd_pipe_control_write_zero_length(uint8_t coreid); -endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const * p_endpoint_desc) ATTR_WARN_UNUSED_RESULT; -tusb_error_t dcd_pipe_xfer(endpoint_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; +endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const * p_endpoint_desc, uint8_t class_code) ATTR_WARN_UNUSED_RESULT; +tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes) ATTR_WARN_UNUSED_RESULT; // only queue, not transferring yet +tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes, bool int_on_complete) ATTR_WARN_UNUSED_RESULT; +tusb_error_t dcd_pipe_stall(endpoint_handle_t edpt_hdl) ATTR_WARN_UNUSED_RESULT; #ifdef __cplusplus } diff --git a/tinyusb/device/dcd_lpc175x_6x.c b/tinyusb/device/dcd_lpc175x_6x.c index b231d62dc..b9be0bc5c 100644 --- a/tinyusb/device/dcd_lpc175x_6x.c +++ b/tinyusb/device/dcd_lpc175x_6x.c @@ -187,8 +187,8 @@ tusb_error_t dcd_init(void) { //------------- user manual 11.13 usb device controller initialization -------------// LPC_USB->USBEpInd = 0; // step 6 : set up control endpoint - endpoint_set_max_packet_size(0, TUSB_CFG_DEVICE_CONTROL_PACKET_SIZE); - endpoint_set_max_packet_size(1, TUSB_CFG_DEVICE_CONTROL_PACKET_SIZE); + endpoint_set_max_packet_size(0, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE); + endpoint_set_max_packet_size(1, TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE); // step 7 : slave mode set up LPC_USB->USBEpIntEn = (uint32_t) BIN8(11); // control endpoint cannot use DMA, non-control all use DMA diff --git a/tinyusb/device/dcd_lpc43xx.c b/tinyusb/device/dcd_lpc43xx.c index c60c60be8..fc594d4b5 100644 --- a/tinyusb/device/dcd_lpc43xx.c +++ b/tinyusb/device/dcd_lpc43xx.c @@ -57,8 +57,38 @@ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ #define DCD_QHD_MAX 12 -#define QTD_INVALID 0x01 -#define CONTROL_ENDOINT_SIZE 64 +#define DCD_QTD_MAX 12 +#define DCD_QTD_PER_QHD_MAX 2 // maximum number of qtd that are linked into one queue head at a time + +#define QTD_NEXT_INVALID 0x01 + +/*---------- ENDPTCTRL ----------*/ +enum { + ENDPTCTRL_MASK_STALL = BIT_(0), + ENDPTCTRL_MASK_TOGGLE_INHIBIT = BIT_(5), ///< used for test only + ENDPTCTRL_MASK_TOGGLE_RESET = BIT_(6), + ENDPTCTRL_MASK_ENABLE = BIT_(7) +}; + +/*---------- USBCMD ----------*/ +enum { + USBCMD_MASK_RUN_STOP = BIT_(0), + USBCMD_MASK_RESET = BIT_(1), + USBCMD_MASK_SETUP_TRIPWIRE = BIT_(13), + USBCMD_MASK_ADD_QTD_TRIPWIRE = BIT_(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD +}; +// Interrupt Threshold bit 23:16 + +/*---------- USBSTS, USBINTR ----------*/ +enum { + INT_MASK_USB = BIT_(0), + INT_MASK_ERROR = BIT_(1), + INT_MASK_PORT_CHANGE = BIT_(2), + INT_MASK_RESET = BIT_(6), + INT_MASK_SOF = BIT_(7), + INT_MASK_SUSPEND = BIT_(8), + INT_MASK_NAK = BIT_(16) +}; typedef struct { // Word 0: Next QTD Pointer @@ -81,8 +111,10 @@ typedef struct { // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous - //------------- -------------// - uint32_t reserved; + //------------- DCD Area -------------// + uint16_t expected_bytes; + uint8_t used; + uint8_t reserved; } dcd_qtd_t; STATIC_ASSERT( sizeof(dcd_qtd_t) == 32, "size is not correct"); @@ -110,15 +142,18 @@ typedef struct { /// Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes /// thus there are 16 bytes padding free that we can make use of. //--------------------------------------------------------------------+ - uint8_t reserved[16]; + uint8_t class_code; // Class code that endpoint belongs to + uint8_t xfer_type; + uint8_t list_qtd_idx[DCD_QTD_PER_QHD_MAX]; + uint8_t reserved[14-DCD_QTD_PER_QHD_MAX]; } ATTR_ALIGNED(64) dcd_qhd_t; STATIC_ASSERT( sizeof(dcd_qhd_t) == 64, "size is not correct"); typedef struct { dcd_qhd_t qhd[DCD_QHD_MAX]; ///< Must be at 2K alignment - dcd_qtd_t qtd[DCD_QHD_MAX] ATTR_ALIGNED(32); + dcd_qtd_t qtd[DCD_QTD_MAX] ATTR_ALIGNED(32); }dcd_data_t; @@ -129,7 +164,7 @@ ATTR_ALIGNED(2048) dcd_data_t dcd_data TUSB_CFG_ATTR_USBRAM; //--------------------------------------------------------------------+ //--------------------------------------------------------------------+ -// USBD-DCD API +// CONTROLLER API //--------------------------------------------------------------------+ tusb_error_t dcd_controller_reset(uint8_t coreid) { @@ -154,37 +189,6 @@ void dcd_controller_connect(uint8_t coreid) (*p_reg_usbcmd) |= BIT_(0); } -/*---------- ENDPTCTRL ----------*/ -enum { - ENDPTCTRL_MASK_STALL = BIT_(0), - ENDPTCTRL_MASK_TOGGLE_INHIBIT = BIT_(5), ///< used for test only - ENDPTCTRL_MASK_TOGGLE_RESET = BIT_(6), - ENDPTCTRL_MASK_ENABLE = BIT_(7) -}; - -/*---------- USBCMD ----------*/ -enum { - USBCMD_MASK_RUN_STOP = BIT_(0), - USBCMD_MASK_RESET = BIT_(1), - USBCMD_MASK_SETUP_TRIPWIRE = BIT_(13), - USBCMD_MASK_ADD_QTD_TRIPWIRE = BIT_(14) ///< This bit is used as a semaphore to ensure the to proper addition of a new dTD to an active (primed) endpoint’s linked list. This bit is set and cleared by software during the process of adding a new dTD -}; -// Interrupt Threshold bit 23:16 - -/*---------- USBSTS, USBINTR ----------*/ -enum { - INT_MASK_USB = BIT_(0), - INT_MASK_ERROR = BIT_(1), - INT_MASK_PORT_CHANGE = BIT_(2), - INT_MASK_RESET = BIT_(6), - INT_MASK_SOF = BIT_(7), - INT_MASK_SUSPEND = BIT_(8), - INT_MASK_NAK = BIT_(16) -}; - -//--------------------------------------------------------------------+ -// CONTROLLER API -//--------------------------------------------------------------------+ void dcd_controller_set_address(uint8_t coreid, uint8_t dev_addr) { LPC_USB0->DEVICEADDR = (dev_addr << 25) | BIT_(24); @@ -226,8 +230,8 @@ void bus_reset(uint8_t coreid) //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------// dcd_data.qhd[0].zero_length_termination = dcd_data.qhd[1].zero_length_termination = 1; - dcd_data.qhd[0].max_package_size = dcd_data.qhd[1].max_package_size = CONTROL_ENDOINT_SIZE; - dcd_data.qhd[0].qtd_overlay.next = dcd_data.qhd[1].qtd_overlay.next = QTD_INVALID; + dcd_data.qhd[0].max_package_size = dcd_data.qhd[1].max_package_size = TUSB_CFG_DEVICE_CONTROL_ENDOINT_SIZE; + dcd_data.qhd[0].qtd_overlay.next = dcd_data.qhd[1].qtd_overlay.next = QTD_NEXT_INVALID; dcd_data.qhd[0].int_on_setup = 1; // OUT only } @@ -247,39 +251,41 @@ tusb_error_t dcd_init(void) } //--------------------------------------------------------------------+ -// PIPE API +// PIPE HELPER //--------------------------------------------------------------------+ -static inline uint8_t endpoint_to_pos(uint8_t logical_endpoint, tusb_direction_t dir) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t endpoint_to_pos(uint8_t logical_endpoint, tusb_direction_t dir) -{ - return logical_endpoint + (dir == TUSB_DIR_HOST_TO_DEV ? 0 : 16); +static inline uint8_t edpt_pos2phy(uint8_t pos) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t edpt_pos2phy(uint8_t pos) +{ // 0-5 --> OUT, 16-21 IN + return (pos < DCD_QHD_MAX/2) ? (2*pos) : (2*(pos-16)+1); } -static inline uint8_t endpoint_phy2pos(uint8_t physical_endpoint) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t endpoint_phy2pos(uint8_t physical_endpoint) +static inline uint8_t edpt_phy2pos(uint8_t physical_endpoint) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t edpt_phy2pos(uint8_t physical_endpoint) { return physical_endpoint/2 + ( (physical_endpoint%2) ? 16 : 0); } -static inline uint8_t endpoint_log2phy(uint8_t logical_endpoint, tusb_direction_t dir) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t endpoint_log2phy(uint8_t logical_endpoint, tusb_direction_t dir) +static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t edpt_addr2phy(uint8_t endpoint_addr) { - return 2*logical_endpoint + (dir == TUSB_DIR_DEV_TO_HOST ? 1 : 0); + return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_DEV_TO_HOST_MASK) ? 1 : 0); } -static inline uint8_t endpoint_addr2phy(uint8_t endpoint_addr) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t endpoint_addr2phy(uint8_t endpoint_addr) +static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t edpt_phy2log(uint8_t physical_endpoint) { - return 2*(endpoint_addr & 0x0F) + ((endpoint_addr & TUSB_DIR_DEV_TO_HOST_MASK) ? 1 : 0); + return physical_endpoint/2; } static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) { memclr_(p_qtd, sizeof(dcd_qtd_t)); - p_qtd->next = QTD_INVALID; + p_qtd->used = 1; + + p_qtd->next = QTD_NEXT_INVALID; p_qtd->active = 1; - p_qtd->total_bytes = total_bytes; + p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; if (data_ptr != NULL) { @@ -291,23 +297,39 @@ static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) } } +// retval 0: invalid +static inline uint8_t qtd_find_free(uint8_t coreid) ATTR_PURE ATTR_ALWAYS_INLINE; +static inline uint8_t qtd_find_free(uint8_t coreid) +{ + for(uint8_t i=2; iENDPTCTRL0 |= (ENDPTCTRL_MASK_STALL << 16); // stall Control IN } +// control transfer does not need to use qtd find function tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, void * buffer, uint16_t length) { uint8_t const endpoint_data = (dir == TUSB_DIR_DEV_TO_HOST) ? 1 : 0; // IN xfer --> data phase on Control IN, other Control OUT + ASSERT_FALSE(dcd_data.qhd[0].qtd_overlay.active || dcd_data.qhd[1].qtd_overlay.active, TUSB_ERROR_FAILED); + //------------- Data Phase -------------// if (length) { dcd_qtd_t* p_data = &dcd_data.qtd[0]; qtd_init(p_data, buffer, length); dcd_data.qhd[endpoint_data].qtd_overlay.next = (uint32_t) p_data; - - LPC_USB0->ENDPTPRIME |= BIT_( endpoint_phy2pos(endpoint_data) ); } //------------- Status Phase (other endpoint, opposite direction) -------------// @@ -315,12 +337,26 @@ tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, void * qtd_init(p_status, NULL, 0); // zero length xfer dcd_data.qhd[1 - endpoint_data].qtd_overlay.next = (uint32_t) p_status; - LPC_USB0->ENDPTPRIME |= BIT_( endpoint_phy2pos(1 - endpoint_data) ); + //------------- Prime Endpoint -------------// + LPC_USB0->ENDPTPRIME |= BIT_( edpt_phy2pos(1 - endpoint_data) ) | + (length ? BIT_( edpt_phy2pos(endpoint_data) ) : 0) ; + + return TUSB_ERROR_NONE; +} + +//--------------------------------------------------------------------+ +// BULK/INTERRUPT/ISOCHRONOUS PIPE API +//--------------------------------------------------------------------+ +tusb_error_t dcd_pipe_stall(endpoint_handle_t edpt_hdl) +{ + volatile uint32_t * reg_control = (&LPC_USB0->ENDPTCTRL0) + edpt_phy2log(edpt_hdl.index); + + (*reg_control) |= ENDPTCTRL_MASK_STALL << (edpt_hdl.index & 0x01 ? 16 : 0); return TUSB_ERROR_NONE; } -endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const * p_endpoint_desc) +endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const * p_endpoint_desc, uint8_t class_code) { // TODO USB1 only has 4 non-control enpoint (USB0 has 5) endpoint_handle_t const null_handle = { .coreid = 0, .xfer_type = 0, .index = 0 }; @@ -336,53 +372,123 @@ endpoint_handle_t dcd_pipe_open(uint8_t coreid, tusb_descriptor_endpoint_t const ASSERT_FALSE( (*reg_control) & (ENDPTCTRL_MASK_ENABLE << (dir ? 16 : 0)), null_handle ); // endpoint must not be already enabled //------------- Prepare Queue Head -------------// - uint8_t ep_idx = endpoint_addr2phy(p_endpoint_desc->bEndpointAddress); + uint8_t ep_idx = edpt_addr2phy(p_endpoint_desc->bEndpointAddress); dcd_qhd_t * p_qhd = &dcd_data.qhd[ep_idx]; memclr_(p_qhd, sizeof(dcd_qhd_t)); + p_qhd->class_code = class_code; + p_qhd->xfer_type = p_endpoint_desc->bmAttributes.xfer; p_qhd->zero_length_termination = 1; - p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size; - p_qhd->qtd_overlay.next = QTD_INVALID; + p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size; + p_qhd->qtd_overlay.next = QTD_NEXT_INVALID; (*reg_control) |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_MASK_ENABLE | ENDPTCTRL_MASK_TOGGLE_RESET) << (dir ? 16 : 0); - return (endpoint_handle_t) { .coreid = coreid, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = ep_idx }; -} - -STATIC_ INLINE_ dcd_qhd_t* qhd_get_from_endpoint_handle(endpoint_handle_t edpt_hdl) ATTR_PURE ATTR_ALWAYS_INLINE; -STATIC_ INLINE_ dcd_qhd_t* qhd_get_from_endpoint_handle(endpoint_handle_t edpt_hdl) -{ - return &dcd_data.qhd[edpt_hdl.index]; + return (endpoint_handle_t) { .coreid = coreid, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = ep_idx, .class_code = class_code}; } bool dcd_pipe_is_busy(endpoint_handle_t edpt_hdl) { - dcd_qhd_t* p_qhd = qhd_get_from_endpoint_handle(edpt_hdl); + dcd_qhd_t* p_qhd = &dcd_data.qhd[edpt_hdl.index]; // LPC_USB0->ENDPTSTAT & endpoint_phy2pos(edpt_hdl.index) return !p_qhd->qtd_overlay.halted && p_qhd->qtd_overlay.active; } -tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) +// add only, controller virtually cannot know +static tusb_error_t pipe_add_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes, bool int_on_complete) { - dcd_qhd_t* p_qhd = qhd_get_from_endpoint_handle(edpt_hdl); - dcd_qtd_t* p_qtd = &dcd_data.qtd[edpt_hdl.index]; // TODO allocate qtd - ASSERT(edpt_hdl.xfer_type != TUSB_XFER_ISOCHRONOUS, TUSB_ERROR_NOT_SUPPORTED_YET); + uint8_t qtd_idx = qtd_find_free(edpt_hdl.coreid); + ASSERT(qtd_idx != 0, TUSB_ERROR_DCD_NOT_ENOUGH_QTD); + + dcd_qhd_t* p_qhd = &dcd_data.qhd[edpt_hdl.index]; + dcd_qtd_t* p_qtd = &dcd_data.qtd[qtd_idx]; + + //------------- Find free slot in qhd's array list -------------// + uint8_t free_slot; + for(free_slot=0; free_slot < DCD_QTD_PER_QHD_MAX; free_slot++) + { + if ( p_qhd->list_qtd_idx[free_slot] == 0 ) break; // found free slot + } + ASSERT(free_slot < DCD_QTD_PER_QHD_MAX, TUSB_ERROR_DCD_NOT_ENOUGH_QTD); + + p_qhd->list_qtd_idx[free_slot] = qtd_idx; // add new qtd to qhd's array list + //------------- Prepare qtd -------------// qtd_init(p_qtd, buffer, total_bytes); p_qtd->int_on_complete = int_on_complete; - p_qhd->qtd_overlay.next = (uint32_t) p_qtd; + if ( free_slot > 0 ) dcd_data.qtd[ p_qhd->list_qtd_idx[free_slot-1] ].next = (uint32_t) p_qtd; + + return TUSB_ERROR_NONE; +} + +tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes) +{ + return pipe_add_xfer( edpt_hdl, buffer, total_bytes, false); +} + +tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, void* buffer, uint16_t total_bytes, bool int_on_complete) +{ + ASSERT_STATUS ( pipe_add_xfer(edpt_hdl, buffer, total_bytes, int_on_complete) ); + + dcd_qhd_t* p_qhd = &dcd_data.qhd[ edpt_hdl.index ]; + dcd_qtd_t* p_qtd = &dcd_data.qtd[ p_qhd->list_qtd_idx[0] ]; - LPC_USB0->ENDPTPRIME |= BIT_( endpoint_phy2pos(edpt_hdl.index) ) ; + p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // attach head QTD to QHD start transferring + + LPC_USB0->ENDPTPRIME |= BIT_( edpt_phy2pos(edpt_hdl.index) ) ; return TUSB_ERROR_NONE; } //------------- Device Controller Driver's Interrupt Handler -------------// +void xfer_complete_isr(uint8_t coreid, uint8_t reg_complete) +{ + if (reg_complete & BIT_(3+16)) + { + hal_debugger_breakpoint(); + } + + // TODO currently exclude control + for(uint8_t ep_idx = 2; ep_idx < DCD_QHD_MAX; ep_idx++) + { + if ( BIT_TEST_(reg_complete, edpt_phy2pos(ep_idx)) ) + { // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set + dcd_qhd_t * p_qhd = &dcd_data.qhd[ep_idx]; + + endpoint_handle_t edpt_hdl = + { + .coreid = coreid, + .xfer_type = p_qhd->xfer_type, + .index = ep_idx, + .class_code = p_qhd->class_code + }; + + // retire all QTDs in array list, up to 1st still-active QTD + while( p_qhd->list_qtd_idx[0] != 0 ) + { + dcd_qtd_t * p_qtd = &dcd_data.qtd[ p_qhd->list_qtd_idx[0] ]; + + if (p_qtd->active) break; // stop immediately if found still-active QTD and shift array list + + //------------- Free QTD and shift array list -------------// + p_qtd->used = 0; // free QTD + memmove(p_qhd->list_qtd_idx, p_qhd->list_qtd_idx+1, DCD_QTD_PER_QHD_MAX-1); + + if (p_qtd->int_on_complete) + { + tusb_event_t event = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? TUSB_EVENT_XFER_ERROR : TUSB_EVENT_XFER_COMPLETE; + usbd_xfer_isr(edpt_hdl, event, p_qtd->expected_bytes - p_qtd->total_bytes); // only number of bytes in the IOC qtd + } + } + } + } +} + void dcd_isr(uint8_t coreid) { uint32_t int_status = LPC_USB0->USBSTS_D; @@ -405,13 +511,28 @@ void dcd_isr(uint8_t coreid) tusb_control_request_t control_request = dcd_data.qhd[0].setup_request; LPC_USB0->ENDPTSETUPSTAT = LPC_USB0->ENDPTSETUPSTAT; + + //------------- Flush if previous transfer is not done -------------// + if (dcd_data.qhd[0].qtd_overlay.active || dcd_data.qhd[1].qtd_overlay.active) + { + do + { + LPC_USB0->ENDPTFLUSH = BIT_(0) | BIT_(16); + while(LPC_USB0->ENDPTFLUSH) {} // TODO refractor later + }while( LPC_USB0->ENDPTSTAT & (BIT_(0) | BIT_(16)) ); + + dcd_data.qhd[0].qtd_overlay.active = dcd_data.qhd[1].qtd_overlay.active = 0; + } + usbd_setup_received_isr(coreid, &control_request); } if (LPC_USB0->ENDPTCOMPLETE) { -// hal_debugger_breakpoint(); - LPC_USB0->ENDPTCOMPLETE = LPC_USB0->ENDPTCOMPLETE; + uint32_t edpt_complete = LPC_USB0->ENDPTCOMPLETE; + LPC_USB0->ENDPTCOMPLETE = edpt_complete; // acknowledge + + xfer_complete_isr(coreid, edpt_complete); } } diff --git a/tinyusb/device/usbd.c b/tinyusb/device/usbd.c index e9fe26b90..88b85a8d9 100644 --- a/tinyusb/device/usbd.c +++ b/tinyusb/device/usbd.c @@ -61,8 +61,18 @@ static device_class_driver_t const usbd_class_drivers[TUSB_CLASS_MAPPED_INDEX_ST [TUSB_CLASS_HID] = { .open = hidd_open, .control_request = hidd_control_request, + .isr = hidd_isr }, #endif + +#if TUSB_CFG_DEVICE_MSC + [TUSB_CLASS_MSC] = { + .open = mscd_open, + .control_request = mscd_control_request, + .isr = mscd_isr + }, +#endif + }; //--------------------------------------------------------------------+ @@ -86,39 +96,6 @@ void usbd_bus_reset(uint32_t coreid) memclr_(&usbd_devices[coreid], sizeof(usbd_device_info_t)); } -void std_get_descriptor(uint8_t coreid, tusb_control_request_t * p_request) -{ - tusb_std_descriptor_type_t const desc_type = p_request->wValue >> 8; - uint8_t const desc_index = u16_low_u8( p_request->wValue ); - switch ( desc_type ) - { - case TUSB_DESC_TYPE_DEVICE: - dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, &app_tusb_desc_device, - min16_of( p_request->wLength, sizeof(tusb_descriptor_device_t)) ); - break; - - case TUSB_DESC_TYPE_CONFIGURATION: - dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, &app_tusb_desc_configuration, - min16_of( p_request->wLength, sizeof(app_tusb_desc_configuration)) ); - break; - - case TUSB_DESC_TYPE_STRING: - { - uint8_t *p_string = (uint8_t*) &app_tusb_desc_strings; - for(uint8_t index =0; index < desc_index; index++) - { - p_string += (*p_string); - } - dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, p_string, *p_string); - } - break; - - default: -// ASSERT(false, (void) 0); // descriptors that is not supported yet - return; - } -} - tusb_error_t usbh_set_configure_received(uint8_t coreid, uint8_t config_number) { dcd_controller_set_configuration(coreid, config_number); @@ -154,9 +131,45 @@ tusb_error_t usbh_set_configure_received(uint8_t coreid, uint8_t config_number) return TUSB_ERROR_NONE; } +tusb_error_t std_get_descriptor(uint8_t coreid, tusb_control_request_t * p_request) +{ + tusb_std_descriptor_type_t const desc_type = p_request->wValue >> 8; + uint8_t const desc_index = u16_low_u8( p_request->wValue ); + switch ( desc_type ) + { + case TUSB_DESC_TYPE_DEVICE: + dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, &app_tusb_desc_device, + min16_of( p_request->wLength, sizeof(tusb_descriptor_device_t)) ); + break; + + case TUSB_DESC_TYPE_CONFIGURATION: + dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, &app_tusb_desc_configuration, + min16_of( p_request->wLength, sizeof(app_tusb_desc_configuration)) ); + break; + + case TUSB_DESC_TYPE_STRING: + { + uint8_t *p_string = (uint8_t*) &app_tusb_desc_strings; + for(uint8_t index =0; index < desc_index; index++) + { + p_string += (*p_string); + } + dcd_pipe_control_xfer(coreid, TUSB_DIR_DEV_TO_HOST, p_string, *p_string); + } + break; + + default: + return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; + } + + return TUSB_ERROR_NONE; +} + void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request) { usbd_device_info_t *p_device = &usbd_devices[coreid]; + tusb_error_t error = TUSB_ERROR_NONE; + switch(p_request->bmRequestType_bit.recipient) { //------------- Standard Control such as those in enumeration -------------// @@ -164,7 +177,7 @@ void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request) switch ( p_request->bRequest ) { case TUSB_REQUEST_GET_DESCRIPTOR: - std_get_descriptor(coreid, p_request); + error = std_get_descriptor(coreid, p_request); break; case TUSB_REQUEST_SET_ADDRESS: @@ -176,10 +189,11 @@ void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request) case TUSB_REQUEST_SET_CONFIGURATION: usbh_set_configure_received(coreid, (uint8_t) p_request->wValue); + dcd_pipe_control_xfer(coreid, TUSB_DIR_HOST_TO_DEV, NULL, 0); // zero length break; - default: ASSERT(false, VOID_RETURN); break; + default: error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; break; } break; @@ -191,12 +205,18 @@ void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request) if ( usbd_class_drivers[class_code].control_request ) { - usbd_class_drivers[class_code].control_request(coreid, p_request); + error = usbd_class_drivers[class_code].control_request(coreid, p_request); } } break; - default: ASSERT(false, VOID_RETURN); break; + default: error = TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; break; + } + + if(TUSB_ERROR_NONE != error) + { // Response with Protocol Stall if request is not supported + dcd_pipe_control_stall(coreid); + ASSERT(error == TUSB_ERROR_NONE, VOID_RETURN); } } @@ -224,7 +244,19 @@ tusb_error_t usbd_pipe_open(uint8_t coreid, tusb_descriptor_interface_t const * //--------------------------------------------------------------------+ void usbd_xfer_isr(endpoint_handle_t edpt_hdl, tusb_event_t event, uint32_t xferred_bytes) { - usbd_device_info_t *p_device = &usbd_devices[edpt_hdl.coreid]; +// usbd_device_info_t *p_device = &usbd_devices[edpt_hdl.coreid]; + uint8_t class_index = std_class_code_to_index(edpt_hdl.class_code); + + if (class_index == 0) // Control Transfer + { + + }else if (usbd_class_drivers[class_index].isr) + { + usbd_class_drivers[class_index].isr(edpt_hdl, event, xferred_bytes); + }else + { + ASSERT(false, VOID_RETURN); // something wrong, no one claims the isr's source + } } //void usbd_isr(uint8_t coreid, tusb_event_t event) diff --git a/tinyusb/device/usbd.h b/tinyusb/device/usbd.h index be389f182..fe385fedc 100644 --- a/tinyusb/device/usbd.h +++ b/tinyusb/device/usbd.h @@ -65,7 +65,7 @@ typedef struct { tusb_error_t (* const open)(uint8_t, tusb_descriptor_interface_t const *, uint16_t*); tusb_error_t (* const control_request) (uint8_t, tusb_control_request_t const *); -// void (* const isr) (pipe_handle_t, tusb_event_t); + void (* const isr) (endpoint_handle_t, tusb_event_t, uint32_t); // void (* const close) (uint8_t); } device_class_driver_t; diff --git a/tinyusb/device/usbd_dcd.h b/tinyusb/device/usbd_dcd.h index 27e4d737f..e2a8ad24a 100644 --- a/tinyusb/device/usbd_dcd.h +++ b/tinyusb/device/usbd_dcd.h @@ -57,6 +57,8 @@ #define USBD_MAX_INTERFACE 16 // TODO refractor later #define USBD_MAX_ENDPOINT 32 // TODO refractor later + + typedef struct { volatile uint8_t state; uint8_t interface2class[USBD_MAX_INTERFACE]; // determine interface number belongs to which class @@ -66,7 +68,9 @@ extern usbd_device_info_t usbd_devices[CONTROLLER_DEVICE_NUMBER]; //--------------------------------------------------------------------+ // callback from DCD ISR //--------------------------------------------------------------------+ -void usbd_xfer_isr(endpoint_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes); +void usbd_xfer_isr(endpoint_handle_t edpt_hdl, tusb_event_t event, uint32_t xferred_bytes); +void usbd_bus_reset(uint32_t coreid); +void usbd_setup_received_isr(uint8_t coreid, tusb_control_request_t * p_request); #ifdef __cplusplus } -- cgit v1.3.1