From 95cd6c3a2f01ec418de6bf7534c519dd53943503 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 14 Nov 2018 23:39:58 +0700 Subject: [PATCH 01/13] remove control from class driver array --- src/device/control.c | 3 --- src/device/control.h | 2 -- src/device/usbd.c | 26 +++++++++++--------------- 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/device/control.c b/src/device/control.c index 26dd8fb35..35ae536e1 100644 --- a/src/device/control.c +++ b/src/device/control.c @@ -54,9 +54,6 @@ void controld_reset(uint8_t rhport) { control_state.current_stage = CONTROL_STAGE_SETUP; } -void controld_init(void) { -} - // Helper to send STATUS (zero length) packet // Note dir is value of direction bit in setup packet (i.e DATA stage direction) static inline bool dcd_control_status(uint8_t rhport, uint8_t dir) diff --git a/src/device/control.h b/src/device/control.h index 633ccb60c..e8dcf76f9 100644 --- a/src/device/control.h +++ b/src/device/control.h @@ -76,8 +76,6 @@ tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, //--------------------------------------------------------------------+ // INTERNAL API //--------------------------------------------------------------------+ - -void controld_init(void); tusb_error_t controld_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); // This tracks the state of a control request. diff --git a/src/device/usbd.c b/src/device/usbd.c index 451494633..13cc7f332 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -104,16 +104,6 @@ typedef struct { static usbd_class_driver_t const usbd_class_drivers[] = { - { - .class_code = TUSB_CLASS_UNSPECIFIED, - .init = controld_init, - .open = NULL, - .control_request = NULL, - .control_request_complete = NULL, - .xfer_cb = controld_xfer_cb, - .sof = NULL, - .reset = controld_reset - }, #if CFG_TUD_CDC { .class_code = TUSB_CLASS_CDC, @@ -223,9 +213,8 @@ static void usbd_reset(uint8_t rhport) tu_varclr(&_usbd_dev); memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping - // Always map the 0th endpoint to the control driver. - _usbd_dev.ep2drv[TUSB_DIR_IN][0] = 0; - _usbd_dev.ep2drv[TUSB_DIR_OUT][0] = 0; + + controld_reset(rhport); for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) { @@ -253,10 +242,17 @@ static void usbd_task_body(void) { // Invoke the class callback associated with the endpoint address uint8_t const ep_addr = event.xfer_complete.ep_addr; - uint8_t const drv_id = _usbd_dev.ep2drv[edpt_dir(ep_addr)][edpt_number(ep_addr)]; - if ( drv_id < USBD_CLASS_DRIVER_COUNT ) + if ( 0 == edpt_number(ep_addr) ) { + // control transfer + controld_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + } + else + { + uint8_t const drv_id = _usbd_dev.ep2drv[edpt_dir(ep_addr)][edpt_number(ep_addr)]; + TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,); + usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); } } From b62ca2e5cdacc2f49cce6a0352ee740e4bac64a9 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 21:52:10 +0700 Subject: [PATCH 02/13] nrf5x: correct control transfer direction added dcd description. --- src/portable/nordic/nrf5x/dcd_nrf5x.c | 116 ++++++++++++++++++-------- 1 file changed, 81 insertions(+), 35 deletions(-) diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index 74b7bb7b8..fad96acf3 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -186,9 +186,17 @@ static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir) */ static void xact_out_prepare(uint8_t epnum) { - // Write zero value to SIZE register will allow hw to ACK (accept data) - // If it is not already done by DMA - NRF_USBD->SIZE.EPOUT[epnum] = 0; + if ( epnum == 0 ) + { + NRF_USBD->TASKS_EP0RCVOUT = 1; + } + else + { + // Write zero value to SIZE register will allow hw to ACK (accept data) + // If it is not already done by DMA + NRF_USBD->SIZE.EPOUT[epnum] = 0; + } + __ISB(); __DSB(); } @@ -253,16 +261,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) return true; } -void control_status_token(uint8_t addr) { - NRF_USBD->EPIN[0].PTR = 0; - NRF_USBD->EPIN[0].MAXCNT = 0; - // Status Phase also require Easy DMA has to be free as well !!!! - NRF_USBD->TASKS_EP0STATUS = 1; - - // The nRF doesn't interrupt on status transmit so we queue up a success response. - dcd_event_xfer_complete(0, addr, 0, DCD_XFER_SUCCESS, false); -} - bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { (void) rhport; @@ -276,21 +274,30 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t xfer->total_len = total_bytes; xfer->actual_len = 0; - // How does the control endpoint handle a ZLP in the data phase? - if (epnum == 0 && total_bytes == 0) { - control_status_token(ep_addr); - } else if ( dir == TUSB_DIR_OUT ) + // Control endpoint with zero-length packet --> status stage + if ( epnum == 0 && total_bytes == 0 ) + { + // Status Phase also require Easy DMA has to be free as well !!!! + edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS); + edpt_dma_end(); + + // The nRF doesn't interrupt on status transmit so we queue up a success response. + dcd_event_xfer_complete(0, ep_addr, 0, DCD_XFER_SUCCESS, false); + } + else if ( dir == TUSB_DIR_OUT ) { if ( xfer->data_received ) { // nrf52840 auto ACK OUT packet after DMA is done // Data already received previously --> trigger DMA to copy to SRAM xact_out_dma(epnum); - }else + } + else { xact_out_prepare(epnum); } - }else + } + else { xact_in_prepare(epnum); } @@ -313,7 +320,7 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if ( ep_addr == 0) + if ( edpt_number(ep_addr) == 0 ) { NRF_USBD->TASKS_EP0STALL = 1; }else @@ -328,7 +335,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr) { (void) rhport; - if ( ep_addr ) + if ( edpt_number(ep_addr) ) { NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr; __ISB(); __DSB(); @@ -340,7 +347,7 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr) (void) rhport; // USBD shouldn't check control endpoint state - if ( 0 == ep_addr ) return false; + if ( 0 == edpt_number(ep_addr) ) return false; uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); @@ -388,19 +395,52 @@ void USBD_IRQHandler(void) // Setup tokens are specific to the Control endpoint. if ( int_status & USBD_INTEN_EP0SETUP_Msk ) { - uint8_t setup[8] = { + uint8_t const setup[8] = { NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH, NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH }; - if (setup[1] != TUSB_REQ_SET_ADDRESS) { + + // nrf5x hw auto handle set address, there is no need to inform usb stack + tusb_control_request_t const * request = (tusb_control_request_t const *) setup; + + if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient && + TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type && + TUSB_REQ_SET_ADDRESS == request->bRequest) ) + { dcd_event_setup_received(0, setup, true); } } - /*------------- Bulk/Interrupt Transfer -------------*/ + //--------------------------------------------------------------------+ + /* Control/Bulk/Interrupt (CBI) Transfer + * + * Data flow is: + * (bus) (dma) + * Host <-------> Endpoint <-------> RAM + * + * For CBI OUT: + * - Host -> Endpoint + * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i] + * to start DMA. This step can occur automatically (without sw), + * which means data may or may not ready (data_received flag). + * - Endpoint -> RAM + * ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction + * + * For CBI IN: + * - RAM -> Endpoint + * ENDEPIN[i] interrupted indicate DMA is complete. HW will start + * to move daat to host + * - Endpoint -> Host + * EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i]. + * Transaction is complete, sw prepare next transaction + * + * Note: in both Control In and Out of Data stage from Host <-> Endpoint + * EP0DATADONE will be set as interrupt source + */ + //--------------------------------------------------------------------+ - /* Bulk/Int OUT: data from DMA -> SRAM - * Note: Since nrf controller auto ACK next packet without SW awareness + /* CBI OUT: Endpoint -> SRAM (aka transaction complete) + * Note: Since nRF controller auto ACK next packet without SW awareness * We must handle this stage before Host -> Endpoint just in case * 2 event happens at once */ @@ -409,9 +449,9 @@ void USBD_IRQHandler(void) if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum)) { nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); - uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT; + // Data in endpoint has been consumed xfer->data_received = false; // Transfer complete if transaction len < Max Packet Size or total len is transferred @@ -428,19 +468,25 @@ void USBD_IRQHandler(void) } } - // Ended event for Bulk/Int : nothing to do + // Ended event for CBI IN : nothing to do } - if ( int_status & USBD_INTEN_EPDATA_Msk || int_status & USBD_INTEN_EP0DATADONE_Msk) + // Endpoint <-> Host + if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) ) { uint32_t data_status = NRF_USBD->EPDATASTATUS; - nrf_usbd_epdatastatus_clear(data_status); - // Bulk/Int In: data from Endpoint -> Host + // EP0DATADONE is set with either Control Out on IN Data + // Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN. + // We will use BMREQUESTTYPE in setup packet to determine the direction + bool const is_control_in = (int_status & USBD_INTEN_EP0DATADONE_Msk) && (NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK); + bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK); + + // CBI In: Endpoint -> Host (transaction complete) for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(data_status, epnum ) || (epnum == 0 && BIT_TEST_(int_status, USBD_INTEN_EP0DATADONE_Pos))) + if ( BIT_TEST_(data_status, epnum ) || ( epnum == 0 && is_control_in) ) { nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); @@ -458,10 +504,10 @@ void USBD_IRQHandler(void) } } - // Bulk/Int OUT: data from Host -> Endpoint + // CBI OUT: Host -> Endpoint for(uint8_t epnum=0; epnum<8; epnum++) { - if ( BIT_TEST_(data_status, 16+epnum ) ) + if ( BIT_TEST_(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) ) { nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); From 215f8603b14cc29e08d8a25e08f8eca44ed90826 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 21:56:39 +0700 Subject: [PATCH 03/13] nrf5x: refactor device control transfer. - make control transfer as part of usbd. Class driver must use usbd_control_ API() instead of dcd_ api. - change the signature of class driver's control_request - allow control request complete to stall in staus stage - move control request parser & handling to usbd. --- src/class/cdc/cdc_device.c | 88 +++++----- src/class/cdc/cdc_device.h | 4 +- src/class/custom/custom_device.c | 4 +- src/class/custom/custom_device.h | 4 +- src/class/hid/hid_device.c | 143 ++++++++-------- src/class/hid/hid_device.h | 5 +- src/class/msc/msc_device.c | 71 +++++--- src/class/msc/msc_device.h | 30 +--- src/common/tusb_types.h | 6 +- src/device/control.c | 283 +++++++++++-------------------- src/device/control.h | 38 ----- src/device/dcd.h | 4 + src/device/usbd.c | 242 ++++++++++++++++++++------ src/device/usbd_pvt.h | 17 +- src/tusb_option.h | 4 +- 15 files changed, 491 insertions(+), 452 deletions(-) diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index bc16699f1..d8ade9c7f 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -45,7 +45,6 @@ // INCLUDE //--------------------------------------------------------------------+ #include "cdc_device.h" -#include "device/control.h" #include "device/usbd_pvt.h" //--------------------------------------------------------------------+ @@ -63,7 +62,7 @@ typedef struct /*------------- From this point, data is not cleared by bus reset -------------*/ char wanted_char; - CFG_TUSB_MEM_ALIGN cdc_line_coding_t line_coding; + cdc_line_coding_t line_coding; // FIFO tu_fifo_t rx_ff; @@ -199,23 +198,23 @@ void cdcd_init(void) for(uint8_t i=0; iwanted_char = -1; + p_cdc->wanted_char = -1; // default line coding is : stop bit = 1, parity = none, data bits = 8 - ser->line_coding.bit_rate = 115200; - ser->line_coding.stop_bits = 0; - ser->line_coding.parity = 0; - ser->line_coding.data_bits = 8; + p_cdc->line_coding.bit_rate = 115200; + p_cdc->line_coding.stop_bits = 0; + p_cdc->line_coding.parity = 0; + p_cdc->line_coding.data_bits = 8; // config fifo - tu_fifo_config(&ser->rx_ff, ser->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, true); - tu_fifo_config(&ser->tx_ff, ser->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false); + tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, true); + tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false); #if CFG_FIFO_MUTEX - tu_fifo_config_mutex(&ser->rx_ff, osal_mutex_create(&ser->rx_ff_mutex)); - tu_fifo_config_mutex(&ser->tx_ff, osal_mutex_create(&ser->tx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex)); + tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex)); #endif } } @@ -299,57 +298,64 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface return TUSB_ERROR_NONE; } -void cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +// Invoked when class request DATA stage is finished. +// return false to stall control endpoint (e.g Host send non-sense DATA) +bool cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * request) { //------------- Class Specific Request -------------// - if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return; + TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); // TODO Support multiple interfaces uint8_t const itf = 0; cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; // Invoke callback - if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) { + if ( CDC_REQUEST_SET_LINE_CODING == request->bRequest ) + { if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding); } + + return true; } -tusb_error_t cdcd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent) +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request) { //------------- Class Specific Request -------------// - if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; + TU_ASSERT(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); // TODO Support multiple interfaces uint8_t const itf = 0; cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; - if ((CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) ) + switch ( request->bRequest ) { - uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength); - dcd_edpt_xfer(rhport, 0, (uint8_t*) &p_cdc->line_coding, len); - } - else if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest)) - { - uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength); - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, (uint8_t*) &p_cdc->line_coding, len); - } - else if (CDC_REQUEST_SET_CONTROL_LINE_STATE == p_request->bRequest ) - { - // CDC PSTN v1.2 section 6.3.12 - // Bit 0: Indicates if DTE is present or not. - // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) - // Bit 1: Carrier control for half-duplex modems. - // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send) - p_cdc->line_state = (uint8_t) p_request->wValue; + case CDC_REQUEST_SET_LINE_CODING: + usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + break; - // Invoke callback - if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, BIT_TEST_(p_request->wValue, 0), BIT_TEST_(p_request->wValue, 1)); + case CDC_REQUEST_GET_LINE_CODING: + usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t)); + break; + + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + // CDC PSTN v1.2 section 6.3.12 + // Bit 0: Indicates if DTE is present or not. + // This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready) + // Bit 1: Carrier control for half-duplex modems. + // This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send) + p_cdc->line_state = (uint8_t) request->wValue; + + // Invoke callback + if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, BIT_TEST_(request->wValue, 0), BIT_TEST_(request->wValue, 1)); + usbd_control_status(rhport, request); + break; + + default: return false; // stall unsupported request } - else - { - return TUSB_ERROR_FAILED; // stall unsupported request - } - return TUSB_ERROR_NONE; + + return true; } tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes) diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 9d0b93c6d..749351a54 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -114,8 +114,8 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li void cdcd_init (void); tusb_error_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); -tusb_error_t cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); -void cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); +bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request); +bool cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t cdcd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void cdcd_reset (uint8_t rhport); diff --git a/src/class/custom/custom_device.c b/src/class/custom/custom_device.c index 1b36f1331..cc440fc7e 100644 --- a/src/class/custom/custom_device.c +++ b/src/class/custom/custom_device.c @@ -89,9 +89,9 @@ tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, return TUSB_ERROR_NONE; } -tusb_error_t cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +bool cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { - return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; + return false; } tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) diff --git a/src/class/custom/custom_device.h b/src/class/custom/custom_device.h index 116c6897d..704c4127b 100644 --- a/src/class/custom/custom_device.h +++ b/src/class/custom/custom_device.h @@ -64,8 +64,8 @@ void cusd_init(void); tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); -tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request); -void cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); +bool cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request); +bool cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void cusd_reset(uint8_t rhport); #endif diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c index efa602ad6..b5586a488 100644 --- a/src/class/hid/hid_device.c +++ b/src/class/hid/hid_device.c @@ -46,7 +46,6 @@ //--------------------------------------------------------------------+ #include "common/tusb_common.h" #include "hid_device.h" -#include "device/control.h" #include "device/usbd_pvt.h" //--------------------------------------------------------------------+ @@ -403,110 +402,112 @@ tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, u return TUSB_ERROR_NONE; } -tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent) +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex ); - TU_ASSERT(p_hid, TUSB_ERROR_FAILED); + TU_ASSERT(p_hid); - //------------- STD Request -------------// if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) { + //------------- STD Request -------------// uint8_t const desc_type = tu_u16_high(p_request->wValue); uint8_t const desc_index = tu_u16_low (p_request->wValue); (void) desc_index; if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) { - // TODO: Handle zero length packet. - uint16_t remaining_bytes = p_hid->desc_len - bytes_already_sent; - if (remaining_bytes > 64) { - remaining_bytes = 64; - } - memcpy(_shared_control_buffer, p_hid->desc_report + bytes_already_sent, remaining_bytes); - - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, remaining_bytes); + usbd_control_xfer(rhport, p_request, p_hid->desc_report, p_hid->desc_len); }else { - return TUSB_ERROR_FAILED; + return false; // stall unsupported request } } - //------------- Class Specific Request -------------// else if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) { - if( HID_REQ_CONTROL_GET_REPORT == p_request->bRequest ) + //------------- Class Specific Request -------------// + switch( p_request->bRequest ) { - // wValue = Report Type | Report ID - uint8_t const report_type = tu_u16_high(p_request->wValue); - uint8_t const report_id = tu_u16_low(p_request->wValue); + case HID_REQ_CONTROL_GET_REPORT: + { + // wValue = Report Type | Report ID + uint8_t const report_type = tu_u16_high(p_request->wValue); + uint8_t const report_id = tu_u16_low(p_request->wValue); - uint16_t xferlen; - if ( p_hid->get_report_cb ) - { - xferlen = p_hid->get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength); - }else - { - // For boot Interface only: re-use report_buf -> report has no change - xferlen = p_request->wLength; + uint16_t xferlen; + if ( p_hid->get_report_cb ) + { + xferlen = p_hid->get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength); + }else + { + // For boot Interface only: re-use report_buf -> report has no change + xferlen = p_request->wLength; + } + + TU_ASSERT( xferlen > 0 ); + usbd_control_xfer(rhport, p_request, p_hid->report_buf, xferlen); } + break; - TU_ASSERT( xferlen > 0 ); - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, xferlen); - } - else if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest ) - { - dcd_edpt_xfer(rhport, 0, _shared_control_buffer, p_request->wLength); - } - else if (HID_REQ_CONTROL_SET_IDLE == p_request->bRequest) - { - // TODO idle rate of report - p_hid->idle_rate = tu_u16_high(p_request->wValue); - } - else if (HID_REQ_CONTROL_GET_IDLE == p_request->bRequest) - { - // TODO idle rate of report - _shared_control_buffer[0] = p_hid->idle_rate; - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1); - } - else if (HID_REQ_CONTROL_GET_PROTOCOL == p_request->bRequest ) - { - _shared_control_buffer[0] = 1-p_hid->boot_protocol; // 0 is Boot, 1 is Report protocol - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1); - } - else if (HID_REQ_CONTROL_SET_PROTOCOL == p_request->bRequest ) - { - p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol - }else - { - return TUSB_ERROR_FAILED; + case HID_REQ_CONTROL_SET_REPORT: + usbd_control_xfer(rhport, p_request, p_hid->report_buf, p_request->wLength); + break; + + case HID_REQ_CONTROL_SET_IDLE: + // TODO idle rate of report + p_hid->idle_rate = tu_u16_high(p_request->wValue); + usbd_control_status(rhport, p_request); + break; + + case HID_REQ_CONTROL_GET_IDLE: + // TODO idle rate of report + usbd_control_xfer(rhport, p_request, &p_hid->idle_rate, 1); + break; + + case HID_REQ_CONTROL_GET_PROTOCOL: + { + uint8_t protocol = 1-p_hid->boot_protocol; // 0 is Boot, 1 is Report protocol + usbd_control_xfer(rhport, p_request, &protocol, 1); + } + break; + + case HID_REQ_CONTROL_SET_PROTOCOL: + p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol + usbd_control_status(rhport, p_request); + break; + + default: return false; // stall unsupported request } }else { - return TUSB_ERROR_FAILED; + return false; // stall unsupported request } - return TUSB_ERROR_NONE; + + return true; } -void hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +// Invoked when class request DATA stage is finished. +// return false to stall control endpoint (e.g Host send non-sense DATA) +bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) { hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex ); - if (p_hid == NULL) { - return; - } + TU_ASSERT(p_hid); - if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) + if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && + p_request->bRequest == HID_REQ_CONTROL_SET_REPORT) { - if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest ) - { - // wValue = Report Type | Report ID - uint8_t const report_type = tu_u16_high(p_request->wValue); - uint8_t const report_id = tu_u16_low(p_request->wValue); + // wValue = Report Type | Report ID + uint8_t const report_type = tu_u16_high(p_request->wValue); + uint8_t const report_id = tu_u16_low(p_request->wValue); - if ( p_hid->set_report_cb ) - { - p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _shared_control_buffer, p_request->wLength); - } + if ( p_hid->set_report_cb ) + { + p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength); } } + + return true; } tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h index 1dc40af57..7f8cd0fa7 100644 --- a/src/class/hid/hid_device.h +++ b/src/class/hid/hid_device.h @@ -378,8 +378,8 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t void hidd_init(void); tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); -tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); -void hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); +bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +bool hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void hidd_reset(uint8_t rhport); @@ -390,3 +390,4 @@ void hidd_reset(uint8_t rhport); #endif #endif /* _TUSB_HID_DEVICE_H_ */ + diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 32ad90102..92bc4c6c8 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -47,7 +47,6 @@ #include "common/tusb_common.h" #include "msc_device.h" -#include "device/control.h" #include "device/usbd_pvt.h" //--------------------------------------------------------------------+ @@ -60,7 +59,31 @@ enum MSC_STAGE_STATUS }; -CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN mscd_interface_t _mscd_itf; +typedef struct { + CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; + +//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX) +// uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member +//#endif + + CFG_TUSB_MEM_ALIGN msc_csw_t csw; + + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + // Bulk Only Transfer (BOT) Protocol + uint8_t stage; + uint32_t total_len; + uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage + + // Sense Response Data + uint8_t sense_key; + uint8_t add_sense_code; + uint8_t add_sense_qualifier; +}mscd_interface_t; + +CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf; CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE]; //--------------------------------------------------------------------+ @@ -147,29 +170,39 @@ tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf, return TUSB_ERROR_NONE; } -tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent) +// Handle class control request +// return false to stall control endpoint (e.g unsupported request) +bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request) { - TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS, TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT); + TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - if(MSC_REQ_RESET == p_request->bRequest) + switch ( p_request->bRequest ) { - // TODO: Actually reset. + case MSC_REQ_RESET: + // TODO: Actually reset interface. + usbd_control_status(rhport, p_request); + break; + + case MSC_REQ_GET_MAX_LUN: + { + // returned MAX LUN is minus 1 by specs + uint8_t maxlun = CFG_TUD_MSC_MAXLUN-1; + usbd_control_xfer(rhport, p_request, &maxlun, 1); + } + break; + + default: return false; // stall unsupported request } - else if (MSC_REQ_GET_MAX_LUN == p_request->bRequest) - { - // returned MAX LUN is minus 1 by specs - _shared_control_buffer[0] = CFG_TUD_MSC_MAXLUN-1; - dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1); - }else - { - return TUSB_ERROR_FAILED; // stall unsupported request - } - return TUSB_ERROR_NONE; + + return true; } -void mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) +// Invoked when class request DATA stage is finished. +// return false to stall control endpoint (e.g Host send non-sense DATA) +bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request) { - return; + // nothing to do + return true; } // For backwards compatibility we support static block counts. @@ -296,7 +329,7 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf return ret; } -tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, uint8_t event, uint32_t xferred_bytes) +tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes) { mscd_interface_t* p_msc = &_mscd_itf; msc_cbw_t const * p_cbw = &p_msc->cbw; diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index ac3eade22..d08d9f9cb 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -81,32 +81,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct"); extern "C" { #endif -typedef struct { - CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; - -//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX) -// uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member -//#endif - - CFG_TUSB_MEM_ALIGN msc_csw_t csw; - - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - // Bulk Only Transfer (BOT) Protocol - uint8_t stage; - uint32_t total_len; - uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage - - // Sense Response Data - uint8_t sense_key; - uint8_t add_sense_code; - uint8_t add_sense_qualifier; -}mscd_interface_t; - -extern mscd_interface_t _mscd_itf; - /** \addtogroup ClassDriver_MSC * @{ * \defgroup MSC_Device Device @@ -198,8 +172,8 @@ ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uin void mscd_init(void); tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); -tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); -void mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); +bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +bool mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request); tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); void mscd_reset(uint8_t rhport); diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 5c226f556..32632cd90 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -203,12 +203,14 @@ typedef enum TUSB_EVENT_XFER_STALLED, }tusb_event_t; -enum { +enum +{ DESC_OFFSET_LEN = 0, DESC_OFFSET_TYPE = 1 }; -enum { +enum +{ INTERFACE_INVALID_NUMBER = 0xff }; diff --git a/src/device/control.c b/src/device/control.c index 35ae536e1..7ab1e16ab 100644 --- a/src/device/control.c +++ b/src/device/control.c @@ -46,216 +46,125 @@ #include "control.h" #include "device/usbd_pvt.h" +enum +{ + EDPT_CTRL_OUT = 0x00, + EDPT_CTRL_IN = 0x80 +}; + +typedef struct { + tusb_control_request_t request; + + void* buffer; + uint16_t total_len; + uint16_t total_transferred; + + bool (*complete_cb) (uint8_t, tusb_control_request_t const * ); +} control_t; + control_t control_state; -CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _shared_control_buffer[64]; +CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _usbd_ctrl_buf[CFG_TUD_ENDOINT0_SIZE]; -void controld_reset(uint8_t rhport) { - control_state.current_stage = CONTROL_STAGE_SETUP; +void usbd_control_reset (uint8_t rhport) +{ + tu_varclr(&control_state); } -// Helper to send STATUS (zero length) packet -// Note dir is value of direction bit in setup packet (i.e DATA stage direction) -static inline bool dcd_control_status(uint8_t rhport, uint8_t dir) +void usbd_control_stall(uint8_t rhport) +{ + dcd_edpt_stall(rhport, 0); +} + +bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request) { - uint8_t ep_addr = 0; - // Invert the direction. - if (dir == TUSB_DIR_OUT) { - ep_addr |= TUSB_DIR_IN_MASK; - } // status direction is reversed to one in the setup packet - return dcd_edpt_xfer(rhport, ep_addr, NULL, 0); -} - -static inline void dcd_control_stall(uint8_t rhport) -{ - dcd_edpt_stall(rhport, 0 | TUSB_DIR_IN_MASK); + return dcd_edpt_xfer(rhport, request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN, NULL, 0); } -// return len of descriptor and change pointer to descriptor's buffer -static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer) +// Each transaction is up to endpoint0's max packet size +static bool start_control_data_xact(uint8_t rhport) { - (void) rhport; + uint16_t const xact_len = tu_min16(control_state.total_len - control_state.total_transferred, CFG_TUD_ENDOINT0_SIZE); - tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue); - uint8_t const desc_index = tu_u16_low( p_request->wValue ); + uint8_t ep_addr = EDPT_CTRL_OUT; - uint8_t const * desc_data = NULL ; - uint16_t len = 0; - - switch(desc_type) + if ( control_state.request.bmRequestType_bit.direction == TUSB_DIR_IN ) { - case TUSB_DESC_DEVICE: - desc_data = (uint8_t const *) usbd_desc_set->device; - len = sizeof(tusb_desc_device_t); - break; - - case TUSB_DESC_CONFIGURATION: - desc_data = (uint8_t const *) usbd_desc_set->config; - len = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength; - break; - - case TUSB_DESC_STRING: - // String Descriptor always uses the desc set from user - if ( desc_index < tud_desc_set.string_count ) - { - desc_data = tud_desc_set.string_arr[desc_index]; - TU_VERIFY( desc_data != NULL, 0 ); - - len = desc_data[0]; // first byte of descriptor is its size - }else - { - // out of range - /* The 0xee string is indeed a Microsoft USB extension. - * It can be used to tell Windows what driver it should use for the device !!! - */ - return 0; - } - break; - - case TUSB_DESC_DEVICE_QUALIFIER: - // TODO If not highspeed capable stall this request otherwise - // return the descriptor that could work in highspeed - return 0; - break; - - default: return 0; + ep_addr = EDPT_CTRL_IN; + memcpy(_usbd_ctrl_buf, control_state.buffer, xact_len); } - TU_ASSERT( desc_data != NULL, 0); - - // up to Host's length - len = tu_min16(p_request->wLength, len ); - (*pp_buffer) = desc_data; - - return len; + return dcd_edpt_xfer(rhport, ep_addr, _usbd_ctrl_buf, xact_len); } -tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) { - if (control_state.current_stage == CONTROL_STAGE_STATUS && xferred_bytes == 0) { - control_state.current_stage = CONTROL_STAGE_SETUP; - return TUSB_ERROR_NONE; - } - tusb_error_t error = TUSB_ERROR_NONE; - control_state.total_transferred += xferred_bytes; - tusb_control_request_t const *p_request = &control_state.current_request; - - if (p_request->wLength == control_state.total_transferred || xferred_bytes < 64) { - control_state.current_stage = CONTROL_STAGE_STATUS; - dcd_control_status(rhport, p_request->bmRequestType_bit.direction); - - // Do the user callback after queueing the STATUS packet because the callback could be slow. - if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) - { - tud_control_interface_control_complete_cb(rhport, tu_u16_low(p_request->wIndex), p_request); - } - } else { - if (TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient) { - error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, control_state.total_transferred); - } else { - error = controld_process_control_request(rhport, p_request, control_state.total_transferred); - } - } - return error; -} - -// This tracks the state of a control request. -tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request) { - tusb_error_t error = TUSB_ERROR_NONE; - memcpy(&control_state.current_request, p_request, sizeof(tusb_control_request_t)); - if (p_request->wLength == 0) { - control_state.current_stage = CONTROL_STAGE_STATUS; - } else { - control_state.current_stage = CONTROL_STAGE_DATA; - control_state.total_transferred = 0; - } - - if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) - { - error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, 0); - } else { - error = controld_process_control_request(rhport, p_request, 0); - } - - if (error != TUSB_ERROR_NONE) { - dcd_control_stall(rhport); // Stall errored requests - } else if (control_state.current_stage == CONTROL_STAGE_STATUS) { - dcd_control_status(rhport, p_request->bmRequestType_bit.direction); - } - return error; -} - -// This handles the actual request and its response. -tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent) +// TODO may find a better way +void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) ) { - tusb_error_t error = TUSB_ERROR_NONE; - uint8_t ep_addr = 0; - if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) { - ep_addr |= TUSB_DIR_IN_MASK; + control_state.complete_cb = fp; +} + +bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) +{ + control_state.request = (*request); + control_state.buffer = buffer; + control_state.total_len = tu_min16(len, request->wLength); + control_state.total_transferred = 0; + + if ( buffer != NULL && len ) + { + // Data stage + TU_ASSERT( start_control_data_xact(rhport) ); + }else + { + // Status stage + TU_ASSERT( usbd_control_status(rhport, request) ); } - //------------- Standard Request e.g in enumeration -------------// - if( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient && - TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ) { - switch (p_request->bRequest) { - case TUSB_REQ_GET_DESCRIPTOR: { - uint8_t const * buffer = NULL; - uint16_t const len = get_descriptor(rhport, p_request, &buffer); + return true; +} - if (len) { - uint16_t remaining_bytes = len - bytes_already_sent; - if (remaining_bytes > 64) { - remaining_bytes = 64; - } - memcpy(_shared_control_buffer, buffer + bytes_already_sent, remaining_bytes); - dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, remaining_bytes); - } else { - return TUSB_ERROR_FAILED; - } - break; - } - case TUSB_REQ_GET_CONFIGURATION: - memcpy(_shared_control_buffer, &control_state.config, 1); - dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 1); - break; - case TUSB_REQ_SET_ADDRESS: - dcd_set_address(rhport, (uint8_t) p_request->wValue); - break; - case TUSB_REQ_SET_CONFIGURATION: - control_state.config = p_request->wValue; - tud_control_set_config_cb (rhport, control_state.config); - break; - default: - return TUSB_ERROR_FAILED; - } - } else if (p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT && - p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) { - //------------- Endpoint Request -------------// - switch (p_request->bRequest) { - case TUSB_REQ_GET_STATUS: { - uint16_t status = dcd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000; - memcpy(_shared_control_buffer, &status, 2); - - dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 2); - break; - } - case TUSB_REQ_CLEAR_FEATURE: - // only endpoint feature is halted/stalled - dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); - break; - case TUSB_REQ_SET_FEATURE: - // only endpoint feature is halted/stalled - dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); - break; - default: - return TUSB_ERROR_FAILED; - } - } else { - //------------- Unsupported Request -------------// - return TUSB_ERROR_FAILED; +// callback when a transaction complete on DATA stage of control endpoint +tusb_error_t usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes) +{ + if ( control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) + { + memcpy(control_state.buffer, _usbd_ctrl_buf, xferred_bytes); } - return error; + + control_state.total_transferred += xferred_bytes; + control_state.buffer += xferred_bytes; + + if ( control_state.total_len == control_state.total_transferred || xferred_bytes < CFG_TUD_ENDOINT0_SIZE ) + { + // DATA stage is complete + bool is_ok = true; + + // invoke complete callback if set + // callback can still stall control in status phase e.g out data does not make sense + if ( control_state.complete_cb ) + { + is_ok = control_state.complete_cb(rhport, &control_state.request); + } + + if ( is_ok ) + { + // Send status + TU_ASSERT( usbd_control_status(rhport, &control_state.request), TUSB_ERROR_FAILED ); + }else + { + // stall due to callback + usbd_control_stall(rhport); + } + } + else + { + // More data to transfer + TU_ASSERT(start_control_data_xact(rhport), TUSB_ERROR_FAILED); + } + + return TUSB_ERROR_NONE; } #endif diff --git a/src/device/control.h b/src/device/control.h index e8dcf76f9..e1709bcee 100644 --- a/src/device/control.h +++ b/src/device/control.h @@ -48,44 +48,6 @@ #include "tusb.h" -typedef enum { - CONTROL_STAGE_SETUP, // Waiting for a setup token. - CONTROL_STAGE_DATA, // In the process of sending or receiving data. - CONTROL_STAGE_STATUS // In the process of transmitting the STATUS ZLP. -} control_stage_t; - -typedef struct { - control_stage_t current_stage; - tusb_control_request_t current_request; - uint16_t total_transferred; - uint8_t config; -} control_t; - -extern uint8_t _shared_control_buffer[64]; - -tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * const p_request); - -// Callback when the configuration of the device is changed. -tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number); - -// Called when the DATA stage of a control transaction is complete. -void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request); - -tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent); - -//--------------------------------------------------------------------+ -// INTERNAL API -//--------------------------------------------------------------------+ -tusb_error_t controld_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length); - -// This tracks the state of a control request. -tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request); - -// This handles the actual request and its response. -tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent); - -tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes); -void controld_reset(uint8_t rhport); #ifdef __cplusplus } diff --git a/src/device/dcd.h b/src/device/dcd.h index ff836f405..bd0ea852e 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -124,6 +124,10 @@ void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_ /*------------------------------------------------------------------*/ /* Endpoint API + * Note: + * - Address of control endpoint OUT is 0x00, In is 0x80 + * - When stalling control endpoint both control OUT and IN must be stalled + * (according to USB spec, stalled control is only recovered with setup token) *------------------------------------------------------------------*/ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); diff --git a/src/device/usbd.c b/src/device/usbd.c index 13cc7f332..e9ac24c4b 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -68,11 +68,10 @@ typedef struct { uint8_t config_num; - // map interface number to driver (0xff is invalid) - uint8_t itf2drv[16]; + uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) + uint8_t ep2drv[2][8]; // map endpoint to driver ( 0xff is invalid ) + - // map endpoint to driver ( 0xff is invalid ) - uint8_t ep2drv[2][8]; }usbd_device_t; static usbd_device_t _usbd_dev; @@ -94,9 +93,8 @@ typedef struct { void (* init ) (void); tusb_error_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length); - // Control request is called one or more times for a request and can queue multiple data packets. - tusb_error_t (* control_request ) (uint8_t rhport, tusb_control_request_t const *, uint16_t bytes_already_sent); - void (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const *); + bool (* control_request ) (uint8_t rhport, tusb_control_request_t const * request); + bool (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const * request); tusb_error_t (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t); void (* sof ) (uint8_t rhport); void (* reset ) (uint8_t); @@ -171,9 +169,16 @@ OSAL_QUEUE_DEF(_usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); static osal_queue_t _usbd_q; //--------------------------------------------------------------------+ -// INTERNAL FUNCTION +// Prototypes //--------------------------------------------------------------------+ static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id); +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request); +static bool process_set_config(uint8_t rhport, uint8_t config_number); +static void const* get_descriptor(tusb_control_request_t const * p_request, uint16_t* desc_len); + +void usbd_control_reset (uint8_t rhport); +tusb_error_t usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes); +void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) ); //--------------------------------------------------------------------+ // APPLICATION API @@ -184,7 +189,7 @@ bool tud_mounted(void) } //--------------------------------------------------------------------+ -// IMPLEMENTATION +// USBD Task //--------------------------------------------------------------------+ tusb_error_t usbd_init (void) { @@ -214,7 +219,7 @@ static void usbd_reset(uint8_t rhport) memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping - controld_reset(rhport); + usbd_control_reset(rhport); for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) { @@ -222,20 +227,24 @@ static void usbd_reset(uint8_t rhport) } } +// Main device task implementation static void usbd_task_body(void) { - dcd_event_t event; - // Loop until there is no more events in the queue while (1) { + dcd_event_t event; + if ( !osal_queue_receive(_usbd_q, &event) ) return; switch ( event.event_id ) { case DCD_EVENT_SETUP_RECEIVED: - // Setup tokens are unique to the Control endpoint so we delegate to it directly. - controld_process_setup_request(event.rhport, &event.setup_received); + // Process control request, if failed control endpoint is stalled + if ( !process_control_request(event.rhport, &event.setup_received) ) + { + usbd_control_stall(event.rhport); + } break; case DCD_EVENT_XFER_COMPLETE: @@ -245,8 +254,8 @@ static void usbd_task_body(void) if ( 0 == edpt_number(ep_addr) ) { - // control transfer - controld_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + // control transfer DATA stage callback + usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len); } else { @@ -312,66 +321,142 @@ void usbd_task( void* param) #endif } -void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request) { - if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT) - { - const usbd_class_driver_t *driver = &usbd_class_drivers[_usbd_dev.itf2drv[interface]]; - if (driver->control_request_complete != NULL) { - driver->control_request_complete(rhport, p_request); - } - } -} +//--------------------------------------------------------------------+ +// Control Request Parser & Handling +//--------------------------------------------------------------------+ -tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent) { - if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT) +// This handles the actual request and its response. +// return false will cause its caller to stall control endpoint +static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) +{ + usbd_control_set_complete_callback(NULL); + + if ( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient && + TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ) + { + //------------- Standard Device Requests e.g in enumeration -------------// + void* data_buf = NULL; + uint16_t data_len = 0; + + switch ( p_request->bRequest ) { - return usbd_class_drivers[_usbd_dev.itf2drv[interface]].control_request(rhport, p_request, bytes_already_sent); + case TUSB_REQ_SET_ADDRESS: + dcd_set_address(rhport, (uint8_t) p_request->wValue); + break; + + case TUSB_REQ_GET_CONFIGURATION: + data_buf = &_usbd_dev.config_num; + data_len = 1; + break; + + case TUSB_REQ_SET_CONFIGURATION: + { + uint8_t const config = (uint8_t) p_request->wValue; + + dcd_set_config(rhport, config); + _usbd_dev.config_num = config; + + TU_ASSERT( TUSB_ERROR_NONE == process_set_config(rhport, config) ); + } + break; + + case TUSB_REQ_GET_DESCRIPTOR: + data_buf = (void*) get_descriptor(p_request, &data_len); + if ( data_buf == NULL || data_len == 0 ) return false; + break; + + default: return false; } - return TUSB_ERROR_FAILED; + + usbd_control_xfer(rhport, p_request, data_buf, data_len); + } + else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient ) + { + //------------- Class/Interface Specific Request -------------// + uint8_t const itf = tu_u16_low(p_request->wIndex); + uint8_t const drvid = _usbd_dev.itf2drv[ itf ]; + + TU_VERIFY (drvid < USBD_CLASS_DRIVER_COUNT ); + + usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete ); + + // control endpoint will be stalled if driver return false + return usbd_class_drivers[drvid].control_request(rhport, p_request); + } + else if ( p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT && + p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD ) + { + //------------- Endpoint Request -------------// + switch ( p_request->bRequest ) + { + case TUSB_REQ_GET_STATUS: + { + uint16_t status = dcd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000; + usbd_control_xfer(rhport, p_request, &status, 2); + } + break; + + case TUSB_REQ_CLEAR_FEATURE: + // only endpoint feature is halted/stalled + dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + break; + + case TUSB_REQ_SET_FEATURE: + // only endpoint feature is halted/stalled + dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex)); + usbd_control_status(rhport, p_request); + break; + + default: return false; + } + } + else + { + //------------- Unsupported Request -------------// + return false; + } + + return true; } // Process Set Configure Request -// TODO Host (windows) can get HID report descriptor before set configured -// may need to open interface before set configured -tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number) +// This function parse configuration descriptor & open drivers accordingly +static bool process_set_config(uint8_t rhport, uint8_t config_number) { - dcd_set_config(rhport, config_number); - - _usbd_dev.config_num = config_number; - - //------------- parse configuration & open drivers -------------// uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config; - TU_ASSERT(desc_cfg != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED); + TU_ASSERT(desc_cfg != NULL); + uint8_t const * p_desc = desc_cfg + sizeof(tusb_desc_configuration_t); uint16_t const cfg_len = ((tusb_desc_configuration_t*)desc_cfg)->wTotalLength; while( p_desc < desc_cfg + cfg_len ) { + // Each interface always starts with Interface or Association descriptor if ( TUSB_DESC_INTERFACE_ASSOCIATION == descriptor_type(p_desc) ) { p_desc = descriptor_next(p_desc); // ignore Interface Association }else { - TU_ASSERT( TUSB_DESC_INTERFACE == descriptor_type(p_desc), TUSB_ERROR_NOT_SUPPORTED_YET ); + TU_ASSERT( TUSB_DESC_INTERFACE == descriptor_type(p_desc) ); - tusb_desc_interface_t* p_desc_itf = (tusb_desc_interface_t*) p_desc; - uint8_t const class_code = p_desc_itf->bInterfaceClass; + tusb_desc_interface_t* desc_itf = (tusb_desc_interface_t*) p_desc; // Check if class is supported uint8_t drv_id; for (drv_id = 0; drv_id < USBD_CLASS_DRIVER_COUNT; drv_id++) { - if ( usbd_class_drivers[drv_id].class_code == class_code ) break; + if ( usbd_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; } - TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT, TUSB_ERROR_NOT_SUPPORTED_YET ); + TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT ); // unsupported class - // Interface number must not be used - TU_ASSERT( 0xff == _usbd_dev.itf2drv[p_desc_itf->bInterfaceNumber], TUSB_ERROR_FAILED); - _usbd_dev.itf2drv[p_desc_itf->bInterfaceNumber] = drv_id; + // Interface number must not be used already TODO alternate interface + TU_ASSERT( 0xff == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] ); + _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id; uint16_t len=0; - TU_ASSERT_ERR( usbd_class_drivers[drv_id].open( rhport, p_desc_itf, &len ) ); - TU_ASSERT( len >= sizeof(tusb_desc_interface_t), TUSB_ERROR_FAILED ); + TU_ASSERT_ERR( usbd_class_drivers[drv_id].open( rhport, desc_itf, &len ), false ); + TU_ASSERT( len >= sizeof(tusb_desc_interface_t) ); mark_interface_endpoint(p_desc, len, drv_id); @@ -404,8 +489,62 @@ static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, ui } } +// return descriptor's buffer and update desc_len +static void const* get_descriptor(tusb_control_request_t const * p_request, uint16_t* desc_len) +{ + tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue); + uint8_t const desc_index = tu_u16_low( p_request->wValue ); + + uint8_t const * desc_data = NULL; + uint16_t len = 0; + + *desc_len = 0; + + switch(desc_type) + { + case TUSB_DESC_DEVICE: + desc_data = (uint8_t const *) usbd_desc_set->device; + len = sizeof(tusb_desc_device_t); + break; + + case TUSB_DESC_CONFIGURATION: + desc_data = (uint8_t const *) usbd_desc_set->config; + len = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength; + break; + + case TUSB_DESC_STRING: + // String Descriptor always uses the desc set from user + if ( desc_index < tud_desc_set.string_count ) + { + desc_data = tud_desc_set.string_arr[desc_index]; + TU_VERIFY( desc_data != NULL, NULL ); + + len = desc_data[0]; // first byte of descriptor is its size + }else + { + // out of range + /* The 0xEE index string is a Microsoft USB extension. + * It can be used to tell Windows what driver it should use for the device !!! + */ + return NULL; + } + break; + + case TUSB_DESC_DEVICE_QUALIFIER: + // TODO If not highspeed capable stall this request otherwise + // return the descriptor that could work in highspeed + return NULL; + break; + + default: return NULL; + } + + *desc_len = len; + return desc_data; +} + //--------------------------------------------------------------------+ -// USBD-DCD Callback API +// DCD Event Handler //--------------------------------------------------------------------+ void dcd_event_handler(dcd_event_t const * event, bool in_isr) { @@ -430,6 +569,9 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) break; case DCD_EVENT_XFER_COMPLETE: + // skip zero-length control status complete event, should dcd notifies us. + if ( 0 == edpt_number(event->xfer_complete.ep_addr) && event->xfer_complete.len == 0) break; + osal_queue_send(_usbd_q, event, in_isr); TU_ASSERT(event->xfer_complete.result == DCD_XFER_SUCCESS,); break; @@ -438,8 +580,6 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) } } -void dcd_event_handler(dcd_event_t const * event, bool in_isr); - // helper to send bus signal event void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) { diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index bbbe0a604..30f010887 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -54,15 +54,24 @@ extern tud_desc_set_t const* usbd_desc_set; tusb_error_t usbd_init (void); void usbd_task (void* param); + +// Carry out Data and Status stage of control transfer +// - If len = 0, it is equivalent to sending status only +// - If len > wLength : it will be truncated +bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len); + +// Send STATUS (zero length) packet +bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request); + +// Stall control endpoint until new setup packet arrived +void usbd_control_stall(uint8_t rhport); + /*------------------------------------------------------------------*/ -/* Endpoint helper +/* Helper *------------------------------------------------------------------*/ // helper to parse an pair of In and Out endpoint descriptors. They must be consecutive tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in); -/*------------------------------------------------------------------*/ -/* Other Helpers - *------------------------------------------------------------------*/ void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr ); diff --git a/src/tusb_option.h b/src/tusb_option.h index d027ea0e6..f19ff4076 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -148,10 +148,8 @@ #define CFG_TUD_ENDOINT0_SIZE 64 #endif - #ifndef CFG_TUD_ENUM_BUFFER_SIZE + #ifndef CFG_TUD_CTRL_BUFSIZE #define CFG_TUD_CTRL_BUFSIZE 256 - #else - #define CFG_TUD_CTRL_BUFSIZE CFG_TUD_ENUM_BUFFER_SIZE #endif #ifndef CFG_TUD_DESC_AUTO From 1640e7590ef1f7883e4474b228a08144879780cd Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 21:58:35 +0700 Subject: [PATCH 04/13] remove control.h (move prototype to usbd_pvt.h) --- src/device/control.c | 1 - src/device/control.h | 58 -------------------------------------------- src/device/usbd.c | 1 - 3 files changed, 60 deletions(-) delete mode 100644 src/device/control.h diff --git a/src/device/control.c b/src/device/control.c index 7ab1e16ab..8a6c9339d 100644 --- a/src/device/control.c +++ b/src/device/control.c @@ -43,7 +43,6 @@ #define _TINY_USB_SOURCE_FILE_ #include "tusb.h" -#include "control.h" #include "device/usbd_pvt.h" enum diff --git a/src/device/control.h b/src/device/control.h deleted file mode 100644 index e1709bcee..000000000 --- a/src/device/control.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************/ -/*! - @file usbd.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holders nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - This file is part of the tinyusb stack. -*/ -/**************************************************************************/ - -/** \ingroup group_usbd - * @{ */ - -#ifndef _TUSB_CONTROL_H_ -#define _TUSB_CONTROL_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -#include "tusb.h" - - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_CONTROL_H_ */ - -/** @} */ diff --git a/src/device/usbd.c b/src/device/usbd.c index e9ac24c4b..bf6aa665f 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -44,7 +44,6 @@ #define _TINY_USB_SOURCE_FILE_ -#include "control.h" #include "tusb.h" #include "usbd.h" #include "device/usbd_pvt.h" From 7219ef8ed62f668a5313aba1a14fd342ce262750 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 22:00:16 +0700 Subject: [PATCH 05/13] rename control.c to usbd_control --- src/device/{control.c => usbd_control.c} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/device/{control.c => usbd_control.c} (96%) diff --git a/src/device/control.c b/src/device/usbd_control.c similarity index 96% rename from src/device/control.c rename to src/device/usbd_control.c index 8a6c9339d..ee60e3c87 100644 --- a/src/device/control.c +++ b/src/device/usbd_control.c @@ -1,6 +1,6 @@ /**************************************************************************/ /*! - @file usbd.c + @file usbd_control.c @author hathach (tinyusb.org) @section LICENSE From 00694b56c58956bfd5c5cf33c8ba76defb849210 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 22:17:11 +0700 Subject: [PATCH 06/13] nrf5x: clean up dcd, add comment --- src/device/usbd.c | 2 - src/portable/nordic/nrf5x/dcd_nrf5x.c | 249 +++++++++++++------------- 2 files changed, 122 insertions(+), 129 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index bf6aa665f..eac1a6a20 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -70,12 +70,10 @@ typedef struct { uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[2][8]; // map endpoint to driver ( 0xff is invalid ) - }usbd_device_t; static usbd_device_t _usbd_dev; - // Auto descriptor is enabled, descriptor set point to auto generated one #if CFG_TUD_DESC_AUTO extern tud_desc_set_t const _usbd_auto_desc_set; diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c index fad96acf3..816ff62ae 100644 --- a/src/portable/nordic/nrf5x/dcd_nrf5x.c +++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c @@ -64,9 +64,7 @@ enum USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk }; -/*------------------------------------------------------------------*/ -/* VARIABLE DECLARATION - *------------------------------------------------------------------*/ +// Transfer descriptor typedef struct { uint8_t* buffer; @@ -78,35 +76,119 @@ typedef struct // indicate packet is already ACK volatile bool data_received; -} nom_xfer_t; +} xfer_td_t; -/*static*/ struct +// Data for managing dcd +static struct { // All 8 endpoints including control IN & OUT (offset 1) - nom_xfer_t xfer[8][2]; + xfer_td_t xfer[8][2]; + // Only one DMA can run at a time volatile bool dma_running; }_dcd; -void bus_reset(void) +/*------------------------------------------------------------------*/ +/* Control / Bulk / Interrupt (CBI) Transfer + *------------------------------------------------------------------*/ + +// helper to start DMA +static void edpt_dma_start(volatile uint32_t* reg_startep) { - for(int i=0; i<8; i++) + // Only one dma can be active + if ( _dcd.dma_running ) { - NRF_USBD->TASKS_STARTEPIN[i] = 0; - NRF_USBD->TASKS_STARTEPOUT[i] = 0; + if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) + { + // If called within ISR, use usbd task to defer later + usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true ); + return; + } + else + { + // Otherwise simply block wait + while ( _dcd.dma_running ) { } + } } - NRF_USBD->TASKS_STARTISOIN = 0; - NRF_USBD->TASKS_STARTISOOUT = 0; + _dcd.dma_running = true; - tu_varclr(&_dcd); - _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE; - _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE; + (*reg_startep) = 1; + __ISB(); __DSB(); } -/*------------------------------------------------------------------*/ -/* Controller API - *------------------------------------------------------------------*/ +// DMA is complete +static void edpt_dma_end(void) +{ + TU_ASSERT(_dcd.dma_running, ); + _dcd.dma_running = false; +} + +// helper getting td +static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir) +{ + return &_dcd.xfer[epnum][dir]; +} + +/*------------- CBI OUT Transfer -------------*/ + +// Prepare for a CBI transaction OUT, call at the start +// Allow ACK incoming data +static void xact_out_prepare(uint8_t epnum) +{ + if ( epnum == 0 ) + { + NRF_USBD->TASKS_EP0RCVOUT = 1; + } + else + { + // Write zero value to SIZE register will allow hw to ACK (accept data) + // If it is not already done by DMA + NRF_USBD->SIZE.EPOUT[epnum] = 0; + } + + __ISB(); __DSB(); +} + +// Start DMA to move data from Endpoint -> RAM +static void xact_out_dma(uint8_t epnum) +{ + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); + + uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum]; + + // Trigger DMA move data from Endpoint -> SRAM + NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer; + NRF_USBD->EPOUT[epnum].MAXCNT = xact_len; + + edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]); + + xfer->buffer += xact_len; + xfer->actual_len += xact_len; +} + +/*------------- CBI IN Transfer -------------*/ + +// Prepare for a CBI transaction IN, call at the start +// it start DMA to transfer data from RAM -> Endpoint +static void xact_in_prepare(uint8_t epnum) +{ + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); + + // Each transaction is up to Max Packet Size + uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps); + + NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer; + NRF_USBD->EPIN[epnum].MAXCNT = xact_len; + + xfer->buffer += xact_len; + + edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]); +} + +//--------------------------------------------------------------------+ +// Tinyusb DCD API +//--------------------------------------------------------------------+ bool dcd_init (uint8_t rhport) { (void) rhport; @@ -135,109 +217,6 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) // Nothing to do } -/*------------------------------------------------------------------*/ -/* Control - *------------------------------------------------------------------*/ -static void edpt_dma_start(volatile uint32_t* reg_startep) -{ - // Only one dma can be active - if ( _dcd.dma_running ) - { - if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) - { - // If called within ISR, use usbd task to defer later - usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true ); - return; - } - else - { - // Otherwise simply block wait - while ( _dcd.dma_running ) { } - } - } - - _dcd.dma_running = true; - - (*reg_startep) = 1; - __ISB(); __DSB(); -} - -static void edpt_dma_end(void) -{ - TU_ASSERT(_dcd.dma_running, ); - - _dcd.dma_running = false; -} - -/*------------------------------------------------------------------*/ -/* - *------------------------------------------------------------------*/ - -static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir) -{ - return &_dcd.xfer[epnum][dir]; -} - -/*------------- Bulk/Int OUT transfer -------------*/ - -/** - * Prepare Bulk/Int out transaction, Endpoint start to accept/ACK Data - * @param epnum - */ -static void xact_out_prepare(uint8_t epnum) -{ - if ( epnum == 0 ) - { - NRF_USBD->TASKS_EP0RCVOUT = 1; - } - else - { - // Write zero value to SIZE register will allow hw to ACK (accept data) - // If it is not already done by DMA - NRF_USBD->SIZE.EPOUT[epnum] = 0; - } - - __ISB(); __DSB(); -} - -static void xact_out_dma(uint8_t epnum) -{ - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); - - uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum]; - - // Trigger DMA move data from Endpoint -> SRAM - NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer; - NRF_USBD->EPOUT[epnum].MAXCNT = xact_len; - - edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]); - - xfer->buffer += xact_len; - xfer->actual_len += xact_len; -} - - -/*------------- Bulk/Int IN transfer -------------*/ - -/** - * Prepare Bulk/Int in transaction, use DMA to transfer data from Memory -> Endpoint - * @param epnum - */ -static void xact_in_prepare(uint8_t epnum) -{ - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); - - // Each transaction is up to Max Packet Size - uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps); - - NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer; - NRF_USBD->EPIN[epnum].MAXCNT = xact_len; - - xfer->buffer += xact_len; - - edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]); -} - bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt) { (void) rhport; @@ -268,7 +247,7 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - nom_xfer_t* xfer = get_td(epnum, dir); + xfer_td_t* xfer = get_td(epnum, dir); xfer->buffer = buffer; xfer->total_len = total_bytes; @@ -352,14 +331,30 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr) uint8_t const epnum = edpt_number(ep_addr); uint8_t const dir = edpt_dir(ep_addr); - nom_xfer_t* xfer = get_td(epnum, dir); + xfer_td_t* xfer = get_td(epnum, dir); return xfer->actual_len < xfer->total_len; } /*------------------------------------------------------------------*/ -/* +/* Interrupt Handler *------------------------------------------------------------------*/ +void bus_reset(void) +{ + for(int i=0; i<8; i++) + { + NRF_USBD->TASKS_STARTEPIN[i] = 0; + NRF_USBD->TASKS_STARTEPOUT[i] = 0; + } + + NRF_USBD->TASKS_STARTISOIN = 0; + NRF_USBD->TASKS_STARTISOOUT = 0; + + tu_varclr(&_dcd); + _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE; + _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE; +} + void USBD_IRQHandler(void) { uint32_t const inten = NRF_USBD->INTEN; @@ -448,7 +443,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum)) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT; // Data in endpoint has been consumed @@ -488,7 +483,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(data_status, epnum ) || ( epnum == 0 && is_control_in) ) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN); xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT; @@ -509,7 +504,7 @@ void USBD_IRQHandler(void) { if ( BIT_TEST_(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) ) { - nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT); + xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT); if (xfer->actual_len < xfer->total_len) { From cb37b819d90ad54a7e6b7c7edb83c9a8333876d7 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 16 Nov 2018 22:20:13 +0700 Subject: [PATCH 07/13] rename control_state --- src/device/usbd_control.c | 51 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index ee60e3c87..a9687a3e6 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -51,23 +51,24 @@ enum EDPT_CTRL_IN = 0x80 }; -typedef struct { - tusb_control_request_t request; +typedef struct +{ + tusb_control_request_t request; - void* buffer; - uint16_t total_len; - uint16_t total_transferred; + void* buffer; + uint16_t total_len; + uint16_t total_transferred; - bool (*complete_cb) (uint8_t, tusb_control_request_t const * ); -} control_t; + bool (*complete_cb) (uint8_t, tusb_control_request_t const *); +} usbd_control_xfer_t; -control_t control_state; +static usbd_control_xfer_t _control_state; CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _usbd_ctrl_buf[CFG_TUD_ENDOINT0_SIZE]; void usbd_control_reset (uint8_t rhport) { - tu_varclr(&control_state); + tu_varclr(&_control_state); } void usbd_control_stall(uint8_t rhport) @@ -85,14 +86,14 @@ bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request) // Each transaction is up to endpoint0's max packet size static bool start_control_data_xact(uint8_t rhport) { - uint16_t const xact_len = tu_min16(control_state.total_len - control_state.total_transferred, CFG_TUD_ENDOINT0_SIZE); + uint16_t const xact_len = tu_min16(_control_state.total_len - _control_state.total_transferred, CFG_TUD_ENDOINT0_SIZE); uint8_t ep_addr = EDPT_CTRL_OUT; - if ( control_state.request.bmRequestType_bit.direction == TUSB_DIR_IN ) + if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_IN ) { ep_addr = EDPT_CTRL_IN; - memcpy(_usbd_ctrl_buf, control_state.buffer, xact_len); + memcpy(_usbd_ctrl_buf, _control_state.buffer, xact_len); } return dcd_edpt_xfer(rhport, ep_addr, _usbd_ctrl_buf, xact_len); @@ -101,15 +102,15 @@ static bool start_control_data_xact(uint8_t rhport) // TODO may find a better way void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) ) { - control_state.complete_cb = fp; + _control_state.complete_cb = fp; } bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len) { - control_state.request = (*request); - control_state.buffer = buffer; - control_state.total_len = tu_min16(len, request->wLength); - control_state.total_transferred = 0; + _control_state.request = (*request); + _control_state.buffer = buffer; + _control_state.total_len = tu_min16(len, request->wLength); + _control_state.total_transferred = 0; if ( buffer != NULL && len ) { @@ -127,30 +128,30 @@ bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, v // callback when a transaction complete on DATA stage of control endpoint tusb_error_t usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes) { - if ( control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) + if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT ) { - memcpy(control_state.buffer, _usbd_ctrl_buf, xferred_bytes); + memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes); } - control_state.total_transferred += xferred_bytes; - control_state.buffer += xferred_bytes; + _control_state.total_transferred += xferred_bytes; + _control_state.buffer += xferred_bytes; - if ( control_state.total_len == control_state.total_transferred || xferred_bytes < CFG_TUD_ENDOINT0_SIZE ) + if ( _control_state.total_len == _control_state.total_transferred || xferred_bytes < CFG_TUD_ENDOINT0_SIZE ) { // DATA stage is complete bool is_ok = true; // invoke complete callback if set // callback can still stall control in status phase e.g out data does not make sense - if ( control_state.complete_cb ) + if ( _control_state.complete_cb ) { - is_ok = control_state.complete_cb(rhport, &control_state.request); + is_ok = _control_state.complete_cb(rhport, &_control_state.request); } if ( is_ok ) { // Send status - TU_ASSERT( usbd_control_status(rhport, &control_state.request), TUSB_ERROR_FAILED ); + TU_ASSERT( usbd_control_status(rhport, &_control_state.request), TUSB_ERROR_FAILED ); }else { // stall due to callback From 027d9ef4bda78ff2baff1181682b61e4fa328f94 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 17 Nov 2018 12:40:23 +0700 Subject: [PATCH 08/13] pass mcu option from compiler --- .../device/device_composite/ses/device_composite.emProject | 4 ++-- examples/device/device_composite/src/tusb_config.h | 7 ++++++- .../nrf52840_freertos/segger/nrf5x_freertos.emProject | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/device/device_composite/ses/device_composite.emProject b/examples/device/device_composite/ses/device_composite.emProject index 35463b25d..f2f052ed2 100644 --- a/examples/device/device_composite/ses/device_composite.emProject +++ b/examples/device/device_composite/ses/device_composite.emProject @@ -19,7 +19,7 @@ arm_target_device_name="nRF52840_xxAA" arm_target_interface_type="SWD" build_treat_warnings_as_errors="Yes" - c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056" + c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056;CFG_TUSB_MCU=OPT_MCU_NRF5X" c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include" debug_register_definition_file="ses_nrf5x/nrf52840_Registers.xml" debug_target_connection="J-Link" @@ -118,7 +118,7 @@ arm_target_device_name="ATSAMD51J19" arm_target_interface_type="SWD" build_treat_warnings_as_errors="Yes" - c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_METRO_M4_EXPRESS;USE_SIMPLE_ASSERT" + c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;USE_SIMPLE_ASSERT;BOARD_METRO_M4_EXPRESS;CFG_TUSB_MCU=OPT_MCU_SAMD51" c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(asf4Dir);$(asf4Dir)/include;$(asf4Dir)/hri;$(asf4Dir)/hal/include;$(asf4Dir)/hal/utils/include;$(asf4Dir)/hpl/port" debug_register_definition_file="ses_samd51/ATSAME51J19A_Registers.xml" debug_target_connection="J-Link" diff --git a/examples/device/device_composite/src/tusb_config.h b/examples/device/device_composite/src/tusb_config.h index 680036859..b802a4131 100644 --- a/examples/device/device_composite/src/tusb_config.h +++ b/examples/device/device_composite/src/tusb_config.h @@ -48,7 +48,12 @@ //-------------------------------------------------------------------- // COMMON CONFIGURATION //-------------------------------------------------------------------- -#define CFG_TUSB_MCU OPT_MCU_NRF5X + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU should be defined using compiler flags +#endif + #define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE #define CFG_TUSB_DEBUG 2 diff --git a/examples/device/nrf52840_freertos/segger/nrf5x_freertos.emProject b/examples/device/nrf52840_freertos/segger/nrf5x_freertos.emProject index 661dc12a6..f36a76fed 100644 --- a/examples/device/nrf52840_freertos/segger/nrf5x_freertos.emProject +++ b/examples/device/nrf52840_freertos/segger/nrf5x_freertos.emProject @@ -19,7 +19,7 @@ arm_target_device_name="nRF52840_xxAA" arm_target_interface_type="SWD" build_treat_warnings_as_errors="Yes" - c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056" + c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056;CFG_TUSB_MCU=OPT_MCU_NRF5X" c_user_include_directories="../src;$(tusbDir)/hw/cmsis/Include;$(tusbDir)/hw;$(tusbDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include;$(freertosDir)/Source/include;$(freertosDir)/Source/portable/GCC/ARM_CM4F" debug_register_definition_file="$(ProjectDir)/nrf52840_Registers.xml" debug_target_connection="J-Link" From 99f758ecd9bffd0c8da35e5ffd906eb09e5fb7f7 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 17 Nov 2018 12:58:27 +0700 Subject: [PATCH 09/13] samd51 project update --- .../ses/device_composite.emProject | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/device/device_composite/ses/device_composite.emProject b/examples/device/device_composite/ses/device_composite.emProject index f2f052ed2..df41c7f1e 100644 --- a/examples/device/device_composite/ses/device_composite.emProject +++ b/examples/device/device_composite/ses/device_composite.emProject @@ -163,15 +163,6 @@ - - - - - - - - - @@ -181,5 +172,11 @@ + From 4e2c357579629c10bad92f2f76161b2073fab107 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 17 Nov 2018 13:26:14 +0700 Subject: [PATCH 10/13] clean up --- examples/device/device_composite/src/main.c | 63 ++++++++++----------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/examples/device/device_composite/src/main.c b/examples/device/device_composite/src/main.c index 11b73ebf9..4c8730242 100644 --- a/examples/device/device_composite/src/main.c +++ b/examples/device/device_composite/src/main.c @@ -36,9 +36,6 @@ */ /**************************************************************************/ -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ #include #include #include @@ -47,15 +44,39 @@ #include "tusb.h" //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION +// MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ void print_greeting(void); void led_blinking_task(void); +/*------------- MAIN -------------*/ +int main(void) +{ + board_init(); + print_greeting(); + + tusb_init(); + + while (1) + { + tusb_task(); + + led_blinking_task(); + +#if CFG_TUD_CDC + extern void virtual_com_task(void); + virtual_com_task(); +#endif + +#if CFG_TUD_HID + extern void usb_hid_task(void); + usb_hid_task(); +#endif + } + + return 0; +} + //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ @@ -90,8 +111,6 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) tud_cdc_write_str("tinyusb usb cdc\n"); } } -#else -#define virtual_com_task() #endif //--------------------------------------------------------------------+ @@ -151,32 +170,8 @@ void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_t { // TODO not Implemented } - -#else -#define usb_hid_task() #endif - -/*------------- MAIN -------------*/ -int main(void) -{ - board_init(); - print_greeting(); - - tusb_init(); - - while (1) - { - tusb_task(); - - led_blinking_task(); - virtual_com_task(); - usb_hid_task(); - } - - return 0; -} - //--------------------------------------------------------------------+ // tinyusb callbacks //--------------------------------------------------------------------+ From 6c842338d6c5900a1c327a18ff2d2bccb5697459 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 20 Nov 2018 00:57:34 +0700 Subject: [PATCH 11/13] remove samd-peripherals submodule --- .gitmodules | 3 --- hw/mcu/microchip/samd/samd-peripherals | 1 - 2 files changed, 4 deletions(-) delete mode 160000 hw/mcu/microchip/samd/samd-peripherals diff --git a/.gitmodules b/.gitmodules index 30abb53e8..c0dd4dd1d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "hw/mcu/microchip/samd/asf4"] path = hw/mcu/microchip/samd/asf4 url = https://github.com/adafruit/asf4.git -[submodule "hw/mcu/microchip/samd/samd-peripherals"] - path = hw/mcu/microchip/samd/samd-peripherals - url = https://github.com/adafruit/samd-peripherals.git diff --git a/hw/mcu/microchip/samd/samd-peripherals b/hw/mcu/microchip/samd/samd-peripherals deleted file mode 160000 index f20fcf642..000000000 --- a/hw/mcu/microchip/samd/samd-peripherals +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f20fcf642b5654ee68d7d551ea7db39716ef83bf From c503d48ec476a978aec1289212d3f7d5f69e07dd Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 20 Nov 2018 01:20:39 +0700 Subject: [PATCH 12/13] clean up --- src/portable/microchip/samd51/hal_samd51.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/portable/microchip/samd51/hal_samd51.c b/src/portable/microchip/samd51/hal_samd51.c index d8c71a7fe..775c29001 100644 --- a/src/portable/microchip/samd51/hal_samd51.c +++ b/src/portable/microchip/samd51/hal_samd51.c @@ -44,13 +44,6 @@ #include "tusb_hal.h" -/*------------------------------------------------------------------*/ -/* MACRO TYPEDEF CONSTANT ENUM - *------------------------------------------------------------------*/ -#define USB_NVIC_PRIO 7 - -void tusb_hal_nrf_power_event(uint32_t event); - /*------------------------------------------------------------------*/ /* TUSB HAL *------------------------------------------------------------------*/ From 5e65886fdd2bc5bac4ee9335fff1726f9382c109 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 20 Nov 2018 01:21:54 +0700 Subject: [PATCH 13/13] samd51 metro m4 add init_mcu() and usb init - device regconized on bus but doesnt response with setup packet. - temp disable msc --- .../ses/device_composite.emProject | 21 +++++++++++++-- .../device/device_composite/src/tusb_config.h | 2 +- .../metro_m4_express/board_metro_m4_express.c | 27 ++++++++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/examples/device/device_composite/ses/device_composite.emProject b/examples/device/device_composite/ses/device_composite.emProject index df41c7f1e..371ef8bb7 100644 --- a/examples/device/device_composite/ses/device_composite.emProject +++ b/examples/device/device_composite/ses/device_composite.emProject @@ -118,8 +118,8 @@ arm_target_device_name="ATSAMD51J19" arm_target_interface_type="SWD" build_treat_warnings_as_errors="Yes" - c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;USE_SIMPLE_ASSERT;BOARD_METRO_M4_EXPRESS;CFG_TUSB_MCU=OPT_MCU_SAMD51" - c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(asf4Dir);$(asf4Dir)/include;$(asf4Dir)/hri;$(asf4Dir)/hal/include;$(asf4Dir)/hal/utils/include;$(asf4Dir)/hpl/port" + c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;USE_SIMPLE_ASSERT;BOARD_METRO_M4_EXPRESS;CIRCUITPY_GCLK_INIT_1ST=0xffff;CFG_TUSB_MCU=OPT_MCU_SAMD51" + c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(asf4Dir);$(asf4Dir)/include;$(asf4Dir)/config;$(asf4Dir)/hri;$(asf4Dir)/hal/include;$(asf4Dir)/hal/utils/include;$(asf4Dir)/hpl/port;$(asf4Dir)/hpl/gclk" debug_register_definition_file="ses_samd51/ATSAME51J19A_Registers.xml" debug_target_connection="J-Link" gcc_entry_point="Reset_Handler" @@ -156,6 +156,23 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/device/device_composite/src/tusb_config.h b/examples/device/device_composite/src/tusb_config.h index b802a4131..b5b4fe088 100644 --- a/examples/device/device_composite/src/tusb_config.h +++ b/examples/device/device_composite/src/tusb_config.h @@ -87,7 +87,7 @@ //------------- CLASS -------------// #define CFG_TUD_CDC 1 -#define CFG_TUD_MSC 1 +#define CFG_TUD_MSC 0 #define CFG_TUD_HID 0 #define CFG_TUD_HID_KEYBOARD 0 diff --git a/hw/bsp/metro_m4_express/board_metro_m4_express.c b/hw/bsp/metro_m4_express/board_metro_m4_express.c index a4af9cec3..23b9e987d 100644 --- a/hw/bsp/metro_m4_express/board_metro_m4_express.c +++ b/hw/bsp/metro_m4_express/board_metro_m4_express.c @@ -37,7 +37,12 @@ /**************************************************************************/ #include "bsp/board.h" + +#include "sam.h" #include "hal/include/hal_gpio.h" +#include "hal/include/hal_init.h" +#include "peripheral_clk_config.h" + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION @@ -46,6 +51,8 @@ void board_init(void) { + init_mcu(); + gpio_set_pin_direction(BOARD_LED0, GPIO_DIRECTION_OUT); gpio_set_pin_level(BOARD_LED0, 1-LED_STATE_ON); @@ -53,6 +60,24 @@ void board_init(void) // Tick init SysTick_Config(SystemCoreClock/1000); #endif + + /* USB Clock init + * The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock + * for low speed and full speed operation. */ + hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, CONF_GCLK_USB_SRC | GCLK_PCHCTRL_CHEN); + hri_mclk_set_AHBMASK_USB_bit(MCLK); + hri_mclk_set_APBBMASK_USB_bit(MCLK); + + // USB Pin Init + gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT); + gpio_set_pin_level(PIN_PA24, false); + gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF); + gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT); + gpio_set_pin_level(PIN_PA25, false); + gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF); + + gpio_set_pin_function(PIN_PA24, PINMUX_PA24H_USB_DM); + gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP); } void board_led_control(uint32_t led_id, bool state) @@ -76,4 +101,4 @@ uint32_t tusb_hal_millis(void) { return board_tick2ms(system_ticks); } -#endif \ No newline at end of file +#endif