From b9c44eea76f92cf3719fd68c9a10b8662faf23b5 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 10 Feb 2024 17:08:29 +0100 Subject: [PATCH 001/101] improved tusb_config.h comment --- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- examples/host/cdc_msc_hid_freertos/src/tusb_config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 76d59c316..e4d74077f 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -102,7 +102,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 1 // CDC ACM +#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index bb7c3388d..9dc89dc55 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -107,7 +107,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 1 // CDC ACM +#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API From 069c68ad04bd6210fc50dbc2aeb2c62448c1731d Mon Sep 17 00:00:00 2001 From: IngHK Date: Fri, 23 Feb 2024 23:27:38 +0100 Subject: [PATCH 002/101] sorted driver functions into Control Request, Driver API, Enumeration and Helper. no functional changes --- src/class/cdc/cdc_host.c | 365 ++++++++++++++++++++------------------- 1 file changed, 192 insertions(+), 173 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2fb37d835..26eb70c9b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -782,6 +782,94 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { // ACM //--------------------------------------------------------------------+ +//------------- Driver API -------------// + +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_LOG_DRV("CDC ACM Set Control Line State\r\n"); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = tu_htole16(line_state), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), + .wLength = 0 + }; + + p_cdc->user_control_cb = complete_cb; + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); + return true; +} + +static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); + + tusb_control_request_t const request = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_LINE_CODING, + .wValue = 0, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + }; + + // use usbh enum buf to hold line coding since user line_coding variable does not live long enough + uint8_t* enum_buf = usbh_get_enum_buf(); + memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + + p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request, + .buffer = enum_buf, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .user_data = user_data + }; + + TU_ASSERT(tuh_control_xfer(&xfer)); + return true; +} + +static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_LOG_DRV("CDC ACM Set Data Format\r\n"); + + cdc_line_coding_t line_coding; + line_coding.bit_rate = p_cdc->line_coding.bit_rate; + line_coding.stop_bits = stop_bits; + line_coding.parity = parity; + line_coding.data_bits = data_bits; + + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + +static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + cdc_line_coding_t line_coding = p_cdc->line_coding; + line_coding.bit_rate = baudrate; + return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); +} + +//------------- Enumeration -------------// + enum { CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, CONFIG_ACM_SET_LINE_CODING, @@ -869,120 +957,14 @@ static void acm_process_config(tuh_xfer_t* xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_LOG_DRV("CDC ACM Set Control Line State\r\n"); - - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(line_state), - .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), - .wLength = 0 - }; - - p_cdc->user_control_cb = complete_cb; - - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call - .user_data = user_data - }; - - TU_ASSERT(tuh_control_xfer(&xfer)); - return true; -} - -static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); - - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = CDC_REQUEST_SET_LINE_CODING, - .wValue = 0, - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), - .wLength = tu_htole16(sizeof(cdc_line_coding_t)) - }; - - // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t* enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); - - p_cdc->user_control_cb = complete_cb; - tuh_xfer_t xfer = { - .daddr = p_cdc->daddr, - .ep_addr = 0, - .setup = &request, - .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call - .user_data = user_data - }; - - TU_ASSERT(tuh_control_xfer(&xfer)); - return true; -} - -static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC ACM Set Data Format\r\n"); - - cdc_line_coding_t line_coding; - line_coding.bit_rate = p_cdc->line_coding.bit_rate; - line_coding.stop_bits = stop_bits; - line_coding.parity = parity; - line_coding.data_bits = data_bits; - - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); -} - -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - cdc_line_coding_t line_coding = p_cdc->line_coding; - line_coding.bit_rate = baudrate; - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); -} - //--------------------------------------------------------------------+ // FTDI //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -enum { - CONFIG_FTDI_RESET = 0, - CONFIG_FTDI_MODEM_CTRL, - CONFIG_FTDI_SET_BAUDRATE, - CONFIG_FTDI_SET_DATA, - CONFIG_FTDI_COMPLETE -}; +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud); -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { - // FTDI Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); - - TU_LOG_DRV("FTDI opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_FTDI; - - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); -} +//------------- Control Request -------------// // set request without data static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1014,6 +996,20 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); } +//------------- Driver API -------------// + +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); + TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); + + p_cdc->user_control_cb = complete_cb; + p_cdc->requested_line_coding.bit_rate = baudrate; + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, + complete_cb ? cdch_internal_control_complete : NULL, user_data)); + + return true; +} + static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; @@ -1043,40 +1039,32 @@ static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state return true; } -static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; - uint32_t divisor; +//------------- Enumeration -------------// - /* divisor shifted 3 bits to the left */ - uint32_t divisor3 = base / (2 * baud); - divisor = (divisor3 >> 3); - divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; +enum { + CONFIG_FTDI_RESET = 0, + CONFIG_FTDI_MODEM_CTRL, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_COMPLETE +}; - /* Deal with special cases for highest baud rates. */ - if (divisor == 1) { /* 1.0 */ - divisor = 0; - } - else if (divisor == 0x4001) { /* 1.5 */ - divisor = 1; - } +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { + // FTDI Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); - return divisor; -} + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { - return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); -} + TU_LOG_DRV("FTDI opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_FTDI; -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - p_cdc->user_control_cb = complete_cb; - p_cdc->requested_line_coding.bit_rate = baudrate; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); - - return true; + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); } static void ftdi_process_config(tuh_xfer_t* xfer) { @@ -1131,39 +1119,40 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { } } +//------------- Helper -------------// + +static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { + const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint32_t divisor; + + /* divisor shifted 3 bits to the left */ + uint32_t divisor3 = base / (2 * baud); + divisor = (divisor3 >> 3); + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; + + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) { /* 1.0 */ + divisor = 0; + } + else if (divisor == 0x4001) { /* 1.5 */ + divisor = 1; + } + + return divisor; +} + +static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { + return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +} + #endif //--------------------------------------------------------------------+ // CP210x //--------------------------------------------------------------------+ - #if CFG_TUH_CDC_CP210X -enum { - CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE, - CONFIG_CP210X_SET_LINE_CTL, - CONFIG_CP210X_SET_DTR_RTS, - CONFIG_CP210X_COMPLETE -}; - -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { - // CP210x Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); - - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY(p_cdc); - - TU_LOG_DRV("CP210x opened\r\n"); - p_cdc->serial_drid = SERIAL_DRIVER_CP210X; - - // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); - - // data endpoints expected to be in pairs - return open_ep_stream_pair(p_cdc, desc_ep); -} +//------------- Control Request -------------// static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { @@ -1202,14 +1191,7 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // TODO implement later - (void) p_cdc; - (void) line_coding; - (void) complete_cb; - (void) user_data; - return false; -} +//------------- Driver API -------------// static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); @@ -1231,6 +1213,15 @@ static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, u return false; } +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // TODO implement later + (void) p_cdc; + (void) line_coding; + (void) complete_cb; + (void) user_data; + return false; +} + static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; @@ -1238,6 +1229,34 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, complete_cb ? cdch_internal_control_complete : NULL, user_data); } +//------------- Enumeration -------------// + +enum { + CONFIG_CP210X_IFC_ENABLE = 0, + CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_LINE_CTL, + CONFIG_CP210X_SET_DTR_RTS, + CONFIG_CP210X_COMPLETE +}; + +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + // CP210x Interface includes 1 vendor interface + 2 bulk endpoints + TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + TU_LOG_DRV("CP210x opened\r\n"); + p_cdc->serial_drid = SERIAL_DRIVER_CP210X; + + // endpoint pair + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + + // data endpoints expected to be in pairs + return open_ep_stream_pair(p_cdc, desc_ep); +} + static void cp210x_process_config(tuh_xfer_t* xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); @@ -1296,7 +1315,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); -//------------- control request -------------// +//------------- Control Request -------------// static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1471,6 +1490,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, } //------------- Enumeration -------------// + enum { CONFIG_CH34X_READ_VERSION = 0, CONFIG_CH34X_SERIAL_INIT, @@ -1565,7 +1585,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { } } -//------------- CH34x helper -------------// +//------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { @@ -1654,7 +1674,6 @@ static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bit return lcr; } - #endif // CFG_TUH_CDC_CH34X #endif From 47777a63050f9438d79364436c25d0f6a80dfd55 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 20 Feb 2024 22:08:51 +0100 Subject: [PATCH 003/101] improved TU_LOGs --- src/class/cdc/cdc_host.c | 86 +++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 26eb70c9b..856db32ff 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -41,7 +41,11 @@ #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(TXT,DADDR,ITF_NUM,NAME,...) TU_LOG_DRV("[:%u:%u] CDCh %s " TXT "\r\n", \ + DADDR, ITF_NUM, NAME, ##__VA_ARGS__) +#define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ + serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface @@ -169,6 +173,9 @@ typedef struct { bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + uint8_t const * name; + #endif } cdch_serial_driver_t; // Note driver list must be in the same order as SERIAL_DRIVER enum @@ -181,7 +188,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, - .set_line_coding = acm_set_line_coding + .set_line_coding = acm_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "ACM" + #endif }, #if CFG_TUH_CDC_FTDI @@ -193,7 +203,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_control_line_state = ftdi_sio_set_modem_ctrl, .set_baudrate = ftdi_sio_set_baudrate, .set_data_format = ftdi_set_data_format, - .set_line_coding = ftdi_set_line_coding + .set_line_coding = ftdi_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "FTDI" + #endif }, #endif @@ -206,7 +219,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, - .set_line_coding = cp210x_set_line_coding + .set_line_coding = cp210x_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "CP210x" + #endif }, #endif @@ -219,7 +235,10 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, - .set_line_coding = ch34x_set_line_coding + .set_line_coding = ch34x_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "CH34x" + #endif }, #endif }; @@ -408,8 +427,10 @@ static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); uint16_t const value = tu_le16toh(xfer->setup->wValue); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); - if (xfer->result == XFER_RESULT_SUCCESS) { + if (success) { switch (p_cdc->serial_drid) { case SERIAL_DRIVER_ACM: switch (xfer->setup->bRequest) { @@ -525,6 +546,7 @@ static void cdch_internal_control_complete(tuh_xfer_t* xfer) { bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -548,6 +570,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set baudrate = %lu", baudrate); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -572,6 +595,8 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", + data_bits, parity, stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if (complete_cb) { @@ -597,6 +622,8 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", + line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; if ( complete_cb ) { @@ -641,7 +668,7 @@ void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t* p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { - TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx); + TU_LOG_P_CDC("close"); // Invoke application callback if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx); @@ -722,33 +749,42 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; + cdch_serial_driver_t const * driver_detected = NULL; // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { - return acm_open(daddr, itf_desc, max_len); - } - else if (SERIAL_DRIVER_COUNT > 1 && - TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + driver_detected = &serial_drivers[0]; + } else if (SERIAL_DRIVER_COUNT > 1 && TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { uint16_t vid, pid; TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - cdch_serial_driver_t const* driver = &serial_drivers[dr]; + cdch_serial_driver_t const * driver = &serial_drivers[dr]; for (size_t i = 0; i < driver->vid_pid_count; i++) { if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { - return driver->open(daddr, itf_desc, max_len); + driver_detected = driver; + break; } } + if (driver_detected) { + break; + } } } + if (driver_detected) { + TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); + bool ret = driver_detected->open(daddr, itf_desc, max_len); + return ret; + } + return false; } static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { - TU_LOG_DRV("CDCh Set Configure complete\r\n"); + TU_LOG_P_CDC("set config complete"); p_cdc->mounted = true; if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); @@ -762,6 +798,10 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); + uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set config"); // fake transfer to kick-off process tuh_xfer_t xfer; @@ -770,10 +810,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.setup = &request; xfer.user_data = 0; // initial state - uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); return true; } @@ -786,7 +822,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_LOG_DRV("CDC ACM Set Control Line State\r\n"); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -816,8 +851,6 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st } static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC ACM Set Line Conding\r\n"); - tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -850,7 +883,6 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC ACM Set Data Format\r\n"); cdc_line_coding_t line_coding; line_coding.bit_rate = p_cdc->line_coding.bit_rate; @@ -1000,7 +1032,6 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); - TU_LOG_DRV("CDC FTDI Set BaudRate = %lu, divisor = 0x%04x\r\n", baudrate, divisor); p_cdc->user_control_cb = complete_cb; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -1032,7 +1063,6 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t cons } static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC FTDI Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, complete_cb ? cdch_internal_control_complete : NULL, user_data)); @@ -1057,7 +1087,6 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_DRV("FTDI opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair @@ -1194,7 +1223,6 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe //------------- Driver API -------------// static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CP210x Set BaudRate = %lu\r\n", baudrate); uint32_t baud_le = tu_htole32(baudrate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, @@ -1223,7 +1251,6 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t co } static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_LOG_DRV("CDC CP210x Set Control Line State\r\n"); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, complete_cb ? cdch_internal_control_complete : NULL, user_data); @@ -1247,7 +1274,6 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); - TU_LOG_DRV("CP210x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CP210X; // endpoint pair @@ -1508,7 +1534,6 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY (p_cdc); - TU_LOG_DRV ("CH34x opened\r\n"); p_cdc->serial_drid = SERIAL_DRIVER_CH34X; tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); @@ -1538,14 +1563,13 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: - TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr); TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version); + TU_LOG_P_CDC("Chip Version = %02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); // init CH34x with line coding From 829ea52873387f6fe269c44089c339cfd6d7c64e Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 08:56:15 +0100 Subject: [PATCH 004/101] splitted cdch_internal_control_complete() into driver's _internal_control_complete() and moved them into driver's sections. no functional change --- src/class/cdc/cdc_host.c | 289 +++++++++++++++++++++------------------ 1 file changed, 154 insertions(+), 135 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 856db32ff..e39122e8f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -286,7 +286,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); -static void cdch_internal_control_complete(tuh_xfer_t* xfer); //--------------------------------------------------------------------+ // APPLICATION API @@ -422,127 +421,6 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -static void process_internal_control_complete(tuh_xfer_t* xfer, uint8_t itf_num) { - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - uint16_t const value = tu_le16toh(xfer->setup->wValue); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); - - if (success) { - switch (p_cdc->serial_drid) { - case SERIAL_DRIVER_ACM: - switch (xfer->setup->bRequest) { - case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) value; - break; - - case CDC_REQUEST_SET_LINE_CODING: { - uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); - memcpy(&p_cdc->line_coding, xfer->buffer, len); - break; - } - - default: break; - } - break; - - #if CFG_TUH_CDC_FTDI - case SERIAL_DRIVER_FTDI: - switch (xfer->setup->bRequest) { - case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) value; - break; - - case FTDI_SIO_SET_BAUD_RATE: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - default: break; - } - break; - #endif - - #if CFG_TUH_CDC_CP210X - case SERIAL_DRIVER_CP210X: - switch(xfer->setup->bRequest) { - case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) value; - break; - - case CP210X_SET_BAUDRATE: { - uint32_t baudrate; - memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); - p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); - break; - } - - default: break; - } - break; - #endif - - #if CFG_TUH_CDC_CH34X - case SERIAL_DRIVER_CH34X: - switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: - // register write request - switch (value) { - case CH34X_REG16_DIVISOR_PRESCALER: - // baudrate - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - case CH32X_REG16_LCR2_LCR: - // data format - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; - break; - - default: break; - } - break; - - case CH34X_REQ_MODEM_CTRL: { - // set modem controls RTS/DTR request. Note: signals are inverted - uint16_t const modem_signal = ~value; - if (modem_signal & CH34X_BIT_RTS) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; - } - - if (modem_signal & CH34X_BIT_DTR) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; - } - break; - } - - default: break; - } - break; - #endif - - default: break; - } - } - - xfer->complete_cb = p_cdc->user_control_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } -} - -// internal control complete to update state such as line state, encoding -static void cdch_internal_control_complete(tuh_xfer_t* xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - process_internal_control_complete(xfer, itf_num); -} - bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); @@ -820,6 +698,36 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { //------------- Driver API -------------// +// internal control complete to update state such as line state, encoding +static void acm_internal_control_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + case CDC_REQUEST_SET_LINE_CODING: + uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); + memcpy(&p_cdc->line_coding, xfer->buffer, len); + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); @@ -842,7 +750,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call .user_data = user_data }; @@ -873,7 +781,7 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call .user_data = user_data }; @@ -1030,13 +938,42 @@ static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, u //------------- Driver API -------------// +// internal control complete to update state such as line state, line_coding +static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case FTDI_SIO_MODEM_CTRL: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + case FTDI_SIO_SET_BAUD_RATE: + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); p_cdc->user_control_cb = complete_cb; p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); + complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1065,7 +1002,7 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t cons static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, - complete_cb ? cdch_internal_control_complete : NULL, user_data)); + complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1222,11 +1159,42 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe //------------- Driver API -------------// +// internal control complete to update state such as line state, encoding +static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch(xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + break; + + case CP210X_SET_BAUDRATE: + uint32_t baudrate; + memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); + p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint32_t baud_le = tu_htole32(baudrate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, - complete_cb ? cdch_internal_control_complete : NULL, user_data); + complete_cb ? cp210x_internal_control_complete : NULL, user_data); } static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -1253,7 +1221,7 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t co static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, - complete_cb ? cdch_internal_control_complete : NULL, user_data); + complete_cb ? cp210x_internal_control_complete : NULL, user_data); } //------------- Enumeration -------------// @@ -1412,9 +1380,60 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void ch34x_control_complete(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber - process_internal_control_complete(xfer, 0); +static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (tu_le16toh(xfer->setup->wValue)) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + break; + + case CH32X_REG16_LCR2_LCR: + // data format + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + + default: break; + } + break; + + case CH34X_REQ_MODEM_CTRL: + // set modem controls RTS/DTR request. Note: signals are inverted + uint16_t const modem_signal = ~tu_le16toh(xfer->setup->wValue); + if (modem_signal & CH34X_BIT_RTS) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; + } + + if (modem_signal & CH34X_BIT_DTR) { + p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; + } else { + p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; + } + break; + + default: break; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } } static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -1426,7 +1445,7 @@ static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, ui uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); TU_VERIFY(lcr); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, - complete_cb ? ch34x_control_complete : NULL, user_data)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1435,7 +1454,7 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, p_cdc->requested_line_coding.bit_rate = baudrate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, - complete_cb ? ch34x_control_complete : NULL, user_data)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1450,7 +1469,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { // stage 1 success, continue to stage 2 p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity, - p_cdc->requested_line_coding.data_bits, ch34x_control_complete, xfer->user_data), ); + p_cdc->requested_line_coding.data_bits, ch34x_internal_control_complete, xfer->user_data), ); } else { // stage 1 failed, notify user xfer->complete_cb = p_cdc->user_control_cb; @@ -1511,7 +1530,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, p_cdc->user_control_cb = complete_cb; TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, - complete_cb ? ch34x_control_complete : NULL, user_data)); + complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } From 2f50f5a4263dc3d65f3bf96b593edac5ac271a5a Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 14:59:16 +0100 Subject: [PATCH 005/101] changed to use of p_cdc->requested_line_coding --- src/class/cdc/cdc_host.c | 215 +++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 119 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e39122e8f..b2ba7c9ea 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -63,12 +63,10 @@ typedef struct { cdc_acm_capability_t acm_capability; TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - uint8_t line_state; // DTR (bit0), RTS (bit1) - - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - cdc_line_coding_t requested_line_coding; + TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; // 1 byte padding - #endif + + uint8_t line_state; // DTR (bit0), RTS (bit1) tuh_xfer_cb_t user_control_cb; @@ -95,9 +93,9 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void acm_process_config(tuh_xfer_t* xfer); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// @@ -109,9 +107,9 @@ static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -124,9 +122,9 @@ static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIS static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); static void cp210x_process_config(tuh_xfer_t* xfer); -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -139,9 +137,9 @@ static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST} static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); static void ch34x_process_config(tuh_xfer_t* xfer); -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -170,9 +168,9 @@ typedef struct { bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); void (*const process_set_config)(tuh_xfer_t* xfer); bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_data_format)(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_line_coding)(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL uint8_t const * name; #endif @@ -276,6 +274,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; + p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; p_cdc->line_state = 0; return p_cdc; } @@ -451,12 +450,14 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_LOG_P_CDC("set baudrate = %lu", baudrate); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_coding.bit_rate = baudrate; + if (complete_cb) { - return driver->set_baudrate(p_cdc, baudrate, complete_cb, user_data); + return driver->set_baudrate(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_baudrate(p_cdc, baudrate, complete_cb, (uintptr_t) &result); + bool ret = driver->set_baudrate(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -477,12 +478,16 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin data_bits, parity, stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_coding.stop_bits = stop_bits; + p_cdc->requested_line_coding.parity = parity; + p_cdc->requested_line_coding.data_bits = data_bits; + if (complete_cb) { - return driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, user_data); + return driver->set_data_format(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_data_format(p_cdc, stop_bits, parity, data_bits, complete_cb, (uintptr_t) &result); + bool ret = driver->set_data_format(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -491,7 +496,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); p_cdc->line_coding.stop_bits = stop_bits; - p_cdc->line_coding.parity = parity; + p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; return true; } @@ -504,12 +509,14 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_coding = *line_coding; + if ( complete_cb ) { - return driver->set_line_coding(p_cdc, line_coding, complete_cb, user_data); + return driver->set_line_coding(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_line_coding(p_cdc, line_coding, complete_cb, (uintptr_t) &result); + bool ret = driver->set_line_coding(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -714,8 +721,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { break; case CDC_REQUEST_SET_LINE_CODING: - uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength)); - memcpy(&p_cdc->line_coding, xfer->buffer, len); + p_cdc->line_coding = p_cdc->requested_line_coding; break; default: break; @@ -758,7 +764,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st return true; } -static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -773,7 +779,7 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const // use usbh enum buf to hold line coding since user line_coding variable does not live long enough uint8_t* enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t)); + memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; tuh_xfer_t xfer = { @@ -789,23 +795,19 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const return true; } -static bool acm_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; - cdc_line_coding_t line_coding; - line_coding.bit_rate = p_cdc->line_coding.bit_rate; - line_coding.stop_bits = stop_bits; - line_coding.parity = parity; - line_coding.data_bits = data_bits; - - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); + return acm_set_line_coding(p_cdc, complete_cb, user_data); } -static bool acm_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; + p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; + p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; TU_VERIFY(p_cdc->acm_capability.support_line_request); - cdc_line_coding_t line_coding = p_cdc->line_coding; - line_coding.bit_rate = baudrate; - return acm_set_line_coding(p_cdc, &line_coding, complete_cb, user_data); + + return acm_set_line_coding(p_cdc, complete_cb, user_data); } //------------- Enumeration -------------// @@ -879,11 +881,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { case CONFIG_ACM_SET_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, &line_coding, acm_process_config, CONFIG_ACM_COMPLETE),); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE),); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -902,7 +904,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud); +static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc); //------------- Control Request -------------// @@ -967,32 +969,26 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(baudrate); +static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(p_cdc); p_cdc->user_control_cb = complete_cb; - p_cdc->requested_line_coding.bit_rate = baudrate; TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; - (void) stop_bits; - (void) parity; - (void) data_bits; (void) complete_cb; (void) user_data; // TODO not implemented yet return false; } -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; - (void) line_coding; (void) complete_cb; (void) user_data; // TODO not implemented yet @@ -1056,11 +1052,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, line_coding.bit_rate, ftdi_process_config, CONFIG_FTDI_SET_DATA),); - break; + p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; + TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif } @@ -1107,8 +1103,8 @@ static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { return divisor; } -static uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { - return ftdi_232bm_baud_base_to_divisor(baud, 48000000u); +static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc) { + return ftdi_232bm_baud_base_to_divisor(p_cdc->requested_line_coding.bit_rate, 48000000u); } #endif @@ -1175,9 +1171,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { break; case CP210X_SET_BAUDRATE: - uint32_t baudrate; - memcpy(&baudrate, xfer->buffer, sizeof(uint32_t)); - p_cdc->line_coding.bit_rate = tu_le32toh(baudrate); + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; default: break; @@ -1190,29 +1184,24 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint32_t baud_le = tu_htole32(baudrate); +static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); p_cdc->user_control_cb = complete_cb; return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb ? cp210x_internal_control_complete : NULL, user_data); } -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { (void) p_cdc; - (void) stop_bits; - (void) parity; - (void) data_bits; (void) complete_cb; (void) user_data; // TODO not implemented yet return false; } -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // TODO implement later (void) p_cdc; - (void) line_coding; (void) complete_cb; (void) user_data; return false; @@ -1265,11 +1254,11 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(cp210x_set_baudrate(p_cdc, line_coding.bit_rate, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); - break; + p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; + TU_ASSERT(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif } @@ -1306,8 +1295,8 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { #if CFG_TUH_CDC_CH34X -static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits); -static uint16_t ch34x_get_divisor_prescaler(uint32_t baval); +static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc); +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); //------------- Control Request -------------// @@ -1368,9 +1357,8 @@ static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(baudrate); +static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data)); @@ -1436,25 +1424,17 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.stop_bits = stop_bits; - p_cdc->requested_line_coding.parity = parity; - p_cdc->requested_line_coding.data_bits = data_bits; - - uint8_t const lcr = ch34x_get_lcr(stop_bits, parity, data_bits); +static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_VERIFY(lcr); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = baudrate; +static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, baudrate, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } @@ -1468,8 +1448,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { if (xfer->result == XFER_RESULT_SUCCESS) { // stage 1 success, continue to stage 2 p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - TU_ASSERT(ch34x_set_data_format(p_cdc, p_cdc->requested_line_coding.stop_bits, p_cdc->requested_line_coding.parity, - p_cdc->requested_line_coding.data_bits, ch34x_internal_control_complete, xfer->user_data), ); + TU_ASSERT(ch34x_set_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data), ); } else { // stage 1 failed, notify user xfer->complete_cb = p_cdc->user_control_cb; @@ -1480,31 +1459,24 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { } // 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding = *line_coding; +static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; if (complete_cb) { // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, - ch34x_set_line_coding_stage1_complete, user_data)); + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, ch34x_set_line_coding_stage1_complete, user_data)); } else { // sync call xfer_result_t result; // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, line_coding->bit_rate, NULL, (uintptr_t) &result)); + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result)); TU_VERIFY(result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = line_coding->bit_rate; + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; // stage 2 set data format - TU_ASSERT(ch34x_set_data_format(p_cdc, line_coding->stop_bits, line_coding->parity, line_coding->data_bits, - NULL, (uintptr_t) &result)); + TU_ASSERT(ch34x_set_data_format(p_cdc, NULL, (uintptr_t) &result)); TU_VERIFY(result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.stop_bits = line_coding->stop_bits; - p_cdc->line_coding.parity = line_coding->parity; - p_cdc->line_coding.data_bits = line_coding->data_bits; // update transfer result, user_data is expected to point to xfer_result_t if (user_data) { @@ -1592,10 +1564,10 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT (version >= 0x30,); // init CH34x with line coding - cdc_line_coding_t const line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint16_t const div_ps = ch34x_get_divisor_prescaler(line_coding.bit_rate); + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_ASSERT(div_ps, ); - uint8_t const lcr = ch34x_get_lcr(line_coding.stop_bits, line_coding.parity, line_coding.data_bits); + uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_ASSERT(lcr, ); TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); @@ -1604,7 +1576,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SPECIAL_REG_WRITE: // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver - p_cdc->line_coding = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X); + p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); break; @@ -1631,7 +1603,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { //------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value -static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { + uint32_t const baval = p_cdc->requested_line_coding.bit_rate; uint8_t a; uint8_t b; uint32_t c; @@ -1680,7 +1653,11 @@ static uint16_t ch34x_get_divisor_prescaler(uint32_t baval) { } // calculate lcr value from data coding -static uint8_t ch34x_get_lcr(uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { +static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { + uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; + uint8_t const parity = p_cdc->requested_line_coding.parity; + uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; + uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); lcr |= (uint8_t) (data_bits - 5); From 7dd435cb877f5d3e0b9576dfcdb8c40e9a03c399 Mon Sep 17 00:00:00 2001 From: IngHK Date: Tue, 20 Feb 2024 20:45:50 +0100 Subject: [PATCH 006/101] changed to use of p_cdc->requested_line_state --- src/class/cdc/cdc_host.c | 82 +++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b2ba7c9ea..0af429e4b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -67,6 +67,7 @@ typedef struct { // 1 byte padding uint8_t line_state; // DTR (bit0), RTS (bit1) + uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; @@ -96,7 +97,7 @@ static void acm_process_config(tuh_xfer_t* xfer); static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI @@ -110,7 +111,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer); static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// @@ -125,7 +126,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer); static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// @@ -140,7 +141,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer); static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- Common -------------// @@ -167,7 +168,7 @@ typedef struct { uint16_t const vid_pid_count; bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); void (*const process_set_config)(tuh_xfer_t* xfer); - bool (*const set_control_line_state)(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_control_line_state)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -426,12 +427,14 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line_state = (uint8_t) line_state; + if (complete_cb) { - return driver->set_control_line_state(p_cdc, line_state, complete_cb, user_data); + return driver->set_control_line_state(p_cdc, complete_cb, user_data); } else { // blocking xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_control_line_state(p_cdc, line_state, complete_cb, (uintptr_t) &result); + bool ret = driver->set_control_line_state(p_cdc, complete_cb, (uintptr_t) &result); if (user_data) { // user_data is not NULL, return result via user_data @@ -717,7 +720,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = p_cdc->requested_line_state; break; case CDC_REQUEST_SET_LINE_CODING: @@ -734,7 +737,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -744,7 +747,7 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, uint16_t line_st .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(line_state), + .wValue = tu_htole16(p_cdc->requested_line_state), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -872,10 +875,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - TU_ASSERT(acm_set_control_line_state(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -952,7 +956,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch (xfer->setup->bRequest) { case FTDI_SIO_MODEM_CTRL: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = p_cdc->requested_line_state; break; case FTDI_SIO_SET_BAUD_RATE: @@ -995,9 +999,9 @@ static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete return false; } -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | line_state, + TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | p_cdc->requested_line_state, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } @@ -1044,10 +1048,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); - break; + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_SET_BAUDRATE: { @@ -1167,7 +1172,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch(xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue); + p_cdc->line_state = p_cdc->requested_line_state; break; case CP210X_SET_BAUDRATE: @@ -1207,9 +1212,9 @@ static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t comple return false; } -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | line_state, NULL, 0, + return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | p_cdc->requested_line_state, NULL, 0, complete_cb ? cp210x_internal_control_complete : NULL, user_data); } @@ -1273,10 +1278,11 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, cp210x_process_config, CONFIG_CP210X_COMPLETE),); - break; + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: @@ -1399,19 +1405,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { break; case CH34X_REQ_MODEM_CTRL: - // set modem controls RTS/DTR request. Note: signals are inverted - uint16_t const modem_signal = ~tu_le16toh(xfer->setup->wValue); - if (modem_signal & CH34X_BIT_RTS) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_RTS; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_RTS; - } - - if (modem_signal & CH34X_BIT_DTR) { - p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR; - } else { - p_cdc->line_state &= (uint8_t) ~CDC_CONTROL_LINE_STATE_DTR; - } + p_cdc->line_state = p_cdc->requested_line_state; break; default: break; @@ -1487,13 +1481,12 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet return true; } -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, uint16_t line_state, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t control = 0; - if (line_state & CDC_CONTROL_LINE_STATE_RTS) { + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { control |= CH34X_BIT_RTS; } - if (line_state & CDC_CONTROL_LINE_STATE_DTR) { + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { control |= CH34X_BIT_DTR; } @@ -1587,7 +1580,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),); + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE),); break; case CONFIG_CH34X_COMPLETE: From dcadf8c2a2a79b838cfccf32612fadcb15216c77 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:04:24 +0100 Subject: [PATCH 007/101] created set_function_call() --- src/class/cdc/cdc_host.c | 110 +++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 62 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 0af429e4b..6a650071d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -421,115 +421,101 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state line_state = %u", line_state); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; - - p_cdc->requested_line_state = (uint8_t) line_state; - +// call of (non-)blocking set-functions (to set line state, baudrate, ...) +static bool set_function_call ( + cdch_interface_t * p_cdc, + bool (*set_function)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { - return driver->set_control_line_state(p_cdc, complete_cb, user_data); + // non-blocking with call back + return set_function(p_cdc, complete_cb, user_data); } else { // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_control_line_state(p_cdc, complete_cb, (uintptr_t) &result); + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = set_function(p_cdc, NULL, (uintptr_t) &result); if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; + *((xfer_result_t *) user_data) = result; } - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); - p_cdc->line_state = (uint8_t) line_state; - return true; + return (ret && result == XFER_RESULT_SUCCESS); } } +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t * p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_P_CDC("set control line state line_state = %u", line_state); + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + + p_cdc->requested_line_state = (uint8_t) line_state; + + bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); + + if (ret && !complete_cb) { + p_cdc->line_state = (uint8_t) line_state; + } + + return ret; +} + bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set baudrate = %lu", baudrate); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; - if (complete_cb) { - return driver->set_baudrate(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_baudrate(p_cdc, complete_cb, (uintptr_t) &result); + bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; - return true; } + + return ret; } bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", data_bits, parity, stop_bits); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.stop_bits = stop_bits; p_cdc->requested_line_coding.parity = parity; p_cdc->requested_line_coding.data_bits = data_bits; - if (complete_cb) { - return driver->set_data_format(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_data_format(p_cdc, complete_cb, (uintptr_t) &result); + bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + if (ret && !complete_cb) { p_cdc->line_coding.stop_bits = stop_bits; p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; - return true; } + + return ret; } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t* p_cdc = get_itf(idx); +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); - cdch_serial_driver_t const* driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; - if ( complete_cb ) { - return driver->set_line_coding(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; - bool ret = driver->set_line_coding(p_cdc, complete_cb, (uintptr_t) &result); + bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); - if (user_data) { - // user_data is not NULL, return result via user_data - *((xfer_result_t*) user_data) = result; - } - - TU_VERIFY(ret && result == XFER_RESULT_SUCCESS); + if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; - return true; } + + return ret; } //--------------------------------------------------------------------+ From ea86bbe5f742344b307e52945c0977143522810b Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 21 Feb 2024 16:30:02 +0100 Subject: [PATCH 008/101] added continue enum after config fail --- src/class/cdc/cdc_host.c | 109 ++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 42 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 6a650071d..226f389e3 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -47,6 +47,16 @@ #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) +#define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ + do { \ + if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ + } while(0) + +#define TU_ASSERT_COMPLETE_1ARGS(_cond) TU_ASSERT_COMPLETE_DEFINE(_cond, 0) +#define TU_ASSERT_COMPLETE_2ARGS(_cond, _itf_offset) TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) + +#define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) + //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -285,7 +295,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const } static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num); //--------------------------------------------------------------------+ // APPLICATION API @@ -657,16 +666,26 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return false; } -static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) { - TU_LOG_P_CDC("set config complete"); - p_cdc->mounted = true; - if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); +static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + TU_LOG_P_CDC("set config complete success = %u", success); - // Prepare for incoming data - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + if (success) { + p_cdc->mounted = true; + if (tuh_cdc_mount_cb) { + tuh_cdc_mount_cb(idx); + } + // Prepare for incoming data + tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + } else { + // clear the interface entry + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + } // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(p_cdc->daddr, itf_num); + usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { @@ -856,14 +875,14 @@ static void acm_process_config(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING),); + TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } #endif @@ -873,7 +892,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE),); + TU_ASSERT_COMPLETE(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE), 1); break; } #endif @@ -881,10 +900,11 @@ static void acm_process_config(tuh_xfer_t* xfer) { case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, idx, itf_num + 1); + set_config_complete(idx, 1, true); break; default: + set_config_complete(idx, 1, false); break; } } @@ -1024,18 +1044,18 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch(state) { // Note may need to read FTDI eeprom case CONFIG_FTDI_RESET: - TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),); + TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),); + TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1044,7 +1064,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { case CONFIG_FTDI_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA),); + TU_ASSERT_COMPLETE(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); break; #else TU_ATTR_FALLTHROUGH; @@ -1055,7 +1075,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { #if 0 // TODO set data format #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),); + TU_ASSERT_COMPLETE(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE)); break; #endif #endif @@ -1064,10 +1084,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { } case CONFIG_FTDI_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; default: + set_config_complete(idx, 0, false); break; } } @@ -1150,8 +1171,8 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1236,17 +1257,17 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),); + TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE)); break; case CONFIG_CP210X_SET_BAUDRATE: { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),); + TU_ASSERT_COMPLETE(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1265,17 +1286,19 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { case CONFIG_CP210X_SET_DTR_RTS: #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE),); + TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; - default: break; + default: + set_config_complete(idx, 0, false); + break; } } @@ -1361,11 +1384,11 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t comp // internal control complete to update state such as line state, encoding static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1526,14 +1549,14 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); + TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); uintptr_t const state = xfer->user_data; uint8_t buffer[2]; // TODO remove - TU_ASSERT (p_cdc,); - TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,); switch (state) { case CONFIG_CH34X_READ_VERSION: - TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),); + TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, + ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -1541,41 +1564,43 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { uint8_t const version = xfer->buffer[0]; TU_LOG_P_CDC("Chip Version = %02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD - TU_ASSERT (version >= 0x30,); + TU_ASSERT_COMPLETE(version >= 0x30); // init CH34x with line coding p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_ASSERT(div_ps, ); + TU_ASSERT_COMPLETE(div_ps); uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_ASSERT(lcr, ); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),); + TU_ASSERT_COMPLETE(lcr); + TU_ASSERT_COMPLETE(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE)); break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),); + TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, + ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),); + TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, + ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE),); + TU_ASSERT_COMPLETE(ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE)); break; case CONFIG_CH34X_COMPLETE: - set_config_complete(p_cdc, idx, itf_num); + set_config_complete(idx, 0, true); break; default: - TU_ASSERT (false,); + set_config_complete(idx, 0, false); break; } } From 22a12c76689399bd1a67e52531171876e5d88a28 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 09:28:06 +0100 Subject: [PATCH 009/101] improved ACM checks --- src/class/cdc/cdc_host.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 226f389e3..ae8245b0e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -773,6 +773,11 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co } static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); + TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || + p_cdc->requested_line_coding.data_bits == 16); + tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -813,7 +818,6 @@ static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; - TU_VERIFY(p_cdc->acm_capability.support_line_request); return acm_set_line_coding(p_cdc, complete_cb, user_data); } From 138567af3e39e08742b3d1edf5b83d27d8526a4a Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 18 Feb 2024 20:33:54 +0100 Subject: [PATCH 010/101] fixed #2448 CH34x ch34x_set_line_coding() callback bug --- src/class/cdc/cdc_host.c | 135 +++++++++++++++++++++++---------------- 1 file changed, 79 insertions(+), 56 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ae8245b0e..f6804ca2b 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -80,6 +80,9 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; + #if CFG_TUH_CDC_CH34X + tuh_xfer_cb_t requested_complete_cb; + #endif struct { tu_edpt_stream_t tx; @@ -1376,12 +1379,33 @@ static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t const lcr = ch34x_get_lcr(p_cdc); + TU_VERIFY(lcr); + + return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); +} + +static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); - TU_ASSERT(ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, - complete_cb, user_data)); - return true; + + return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); +} + +static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = 0; + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { + control |= CH34X_BIT_RTS; + } + if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { + control |= CH34X_BIT_DTR; + } + + // CH34x signals are inverted + control = ~control; + + return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Driver API -------------// @@ -1431,34 +1455,34 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_VERIFY(lcr); - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, CH32X_REG16_LCR2_LCR, lcr, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); +static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } -static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); if (xfer->result == XFER_RESULT_SUCCESS) { - // stage 1 success, continue to stage 2 - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - TU_ASSERT(ch34x_set_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data), ); + // stage 1 success, continue with stage 2 + p_cdc->user_control_cb = p_cdc->requested_complete_cb; + ch34x_write_reg_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data); } else { // stage 1 failed, notify user - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->requested_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } @@ -1466,49 +1490,46 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t* xfer) { } // 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; - +static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, ch34x_set_line_coding_stage1_complete, user_data)); + p_cdc->requested_complete_cb = complete_cb; + p_cdc->user_control_cb = ch34x_set_line_coding_stage1_complete; + return ch34x_write_reg_baudrate(p_cdc, ch34x_internal_control_complete, user_data); } else { - // sync call - xfer_result_t result; - + // blocking sequence // stage 1 set baudrate - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result)); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result); - // stage 2 set data format - TU_ASSERT(ch34x_set_data_format(p_cdc, NULL, (uintptr_t) &result)); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - - // update transfer result, user_data is expected to point to xfer_result_t + // store/check results if (user_data) { *((xfer_result_t*) user_data) = result; } - } + TU_ASSERT(ret); + TU_VERIFY(result == XFER_RESULT_SUCCESS); - return true; + // overtake baudrate + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + + // stage 2 set data format + result = XFER_RESULT_INVALID; + ret = ch34x_write_reg_data_format(p_cdc, NULL, (uintptr_t) &result); + + // store/check results + if (user_data) { + *((xfer_result_t*) user_data) = result; + } + TU_ASSERT(ret); + return (result == XFER_RESULT_SUCCESS); + // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() + } } -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = 0; - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { - control |= CH34X_BIT_RTS; - } - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { - control |= CH34X_BIT_DTR; - } - - // CH34x signals are inverted - control = ~control; - +static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, - complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); + return true; } @@ -1549,25 +1570,27 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and use wIndex as payload and not for bInterfaceNumber + // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + uintptr_t const state = xfer->user_data; uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - uintptr_t const state = xfer->user_data; uint8_t buffer[2]; // TODO remove switch (state) { case CONFIG_CH34X_READ_VERSION: + p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); + ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; TU_LOG_P_CDC("Chip Version = %02x", version); - // only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD + // only versions >= 0x30 are tested, below 0x30 seems having other programming + // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); // init CH34x with line coding p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; @@ -1584,19 +1607,19 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE)); + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; case CONFIG_CH34X_COMPLETE: @@ -1668,7 +1691,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; - TU_VERIFY(data_bits >= 5 && data_bits <= 8, 0); + TU_VERIFY(data_bits >= 5 && data_bits <= 8); lcr |= (uint8_t) (data_bits - 5); switch(parity) { @@ -1695,7 +1718,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { } // 1.5 stop bits not supported - TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5, 0); + TU_VERIFY(stop_bits != CDC_LINE_CODING_STOP_BITS_1_5); if (stop_bits == CDC_LINE_CODING_STOP_BITS_2) { lcr |= CH34X_LCR_STOP_BITS_2; } From db511fb2f3df190f538d84d08b6be83746adae0e Mon Sep 17 00:00:00 2001 From: IngHK Date: Mon, 19 Feb 2024 08:05:16 +0100 Subject: [PATCH 011/101] fixed CFG_TUH_CDC_LINE_CONTROL_ON_ENUM handling. only set if defined. value 0 is also valid --- src/class/cdc/cdc_host.c | 17 ++++++++++------- src/class/cdc/cdc_host.h | 10 ---------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f6804ca2b..850c1fceb 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -886,7 +886,7 @@ static void acm_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); @@ -1060,7 +1060,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); break; @@ -1291,7 +1291,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { } case CONFIG_CP210X_SET_DTR_RTS: - #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); break; @@ -1617,10 +1617,13 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - // !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT) - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); - break; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif case CONFIG_CH34X_COMPLETE: set_config_complete(idx, 0, true); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index d512a23a5..ca6567453 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -37,16 +37,6 @@ // Class Driver Configuration //--------------------------------------------------------------------+ -// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1) -#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0 -#endif - -// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t -//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM -//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CODING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } -//#endif - // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE #define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX From 0b5f85eee0f34a80dd8debe2f764607070293119 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 21 Feb 2024 17:25:13 +0100 Subject: [PATCH 012/101] created set_line_coding_sequence() and void set_line_coding_stage1_complete() to be reused by FTDI & CP210x --- src/class/cdc/cdc_host.c | 131 ++++++++++++++++++++++++--------------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 850c1fceb..8deeffc37 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -433,6 +433,77 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ +// set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) +static bool set_line_coding_sequence( + cdch_interface_t * p_cdc, + // control request function to set baudrate + bool (*set_baudrate_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // control request function to set data format + bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // function to be called after stage 1 completed + void (*set_line_coding_stage1_complete)(tuh_xfer_t * xfer), + // control complete function to be called after request + void (*internal_control_complete)(tuh_xfer_t * xfer), + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + if (complete_cb) { + // non-blocking + // stage 1 set baudrate + p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() + p_cdc->user_control_cb = set_line_coding_stage1_complete; + return set_baudrate_request(p_cdc, internal_control_complete, user_data); + } else { + // blocking sequence + // stage 1 set baudrate + xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL + bool ret = set_baudrate_request(p_cdc, NULL, (uintptr_t) &result); + + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + + TU_ASSERT(ret); + TU_VERIFY(result == XFER_RESULT_SUCCESS); + + // overtake baudrate after successful request + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + + // stage 2 set data format + result = XFER_RESULT_INVALID; + ret = set_data_format_request(p_cdc, NULL, (uintptr_t) &result); + + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + + TU_ASSERT(ret); + return (result == XFER_RESULT_SUCCESS); + // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() + } +} + +static void set_line_coding_stage1_complete( + tuh_xfer_t * xfer, uint8_t const itf_num, + // control request function to set data format + bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), + // control complete function to be called after request + void (*internal_control_complete)(tuh_xfer_t * xfer)) { + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + + if (xfer->result == XFER_RESULT_SUCCESS) { + // stage 1 success, continue with stage 2 + p_cdc->user_control_cb = p_cdc->requested_complete_cb; + set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); + } else { + // stage 1 failed, notify user + xfer->complete_cb = p_cdc->requested_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + // call of (non-)blocking set-functions (to set line state, baudrate, ...) static bool set_function_call ( cdch_interface_t * p_cdc, @@ -1470,60 +1541,20 @@ static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_ } static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - - if (xfer->result == XFER_RESULT_SUCCESS) { - // stage 1 success, continue with stage 2 - p_cdc->user_control_cb = p_cdc->requested_complete_cb; - ch34x_write_reg_data_format(p_cdc, ch34x_internal_control_complete, xfer->user_data); - } else { - // stage 1 failed, notify user - xfer->complete_cb = p_cdc->requested_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } + uint8_t const itf_num = 0; // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + set_line_coding_stage1_complete(xfer, itf_num, + ch34x_write_reg_data_format, // control request function to set data format + ch34x_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // stage 1 set baudrate - p_cdc->requested_complete_cb = complete_cb; - p_cdc->user_control_cb = ch34x_set_line_coding_stage1_complete; - return ch34x_write_reg_baudrate(p_cdc, ch34x_internal_control_complete, user_data); - } else { - // blocking sequence - // stage 1 set baudrate - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = ch34x_write_reg_baudrate(p_cdc, NULL, (uintptr_t) &result); - - // store/check results - if (user_data) { - *((xfer_result_t*) user_data) = result; - } - TU_ASSERT(ret); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - - // overtake baudrate - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - - // stage 2 set data format - result = XFER_RESULT_INVALID; - ret = ch34x_write_reg_data_format(p_cdc, NULL, (uintptr_t) &result); - - // store/check results - if (user_data) { - *((xfer_result_t*) user_data) = result; - } - TU_ASSERT(ret); - return (result == XFER_RESULT_SUCCESS); - // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() - } + return set_line_coding_sequence(p_cdc, + ch34x_write_reg_baudrate, // control request function to set baudrate + ch34x_write_reg_data_format, // control request function to set data format + ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed + ch34x_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { From 7fef5943eff0d7f1b7122e878cf2caa78bea06aa Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 12:58:45 +0100 Subject: [PATCH 013/101] improved FTDI support --- src/class/cdc/cdc_host.c | 529 ++++++++++++++++++++++++++------ src/class/cdc/serial/ftdi_sio.h | 371 +++++++++++----------- src/tusb_option.h | 19 +- 3 files changed, 622 insertions(+), 297 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 8deeffc37..f9540efbe 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -35,6 +35,9 @@ #include "host/usbh_pvt.h" #include "cdc_host.h" +#include "serial/ftdi_sio.h" +#include "serial/cp210x.h" +#include "serial/ch34x.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -80,10 +83,14 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; - #if CFG_TUH_CDC_CH34X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif + #if CFG_TUH_CDC_FTDI + ftdi_private_t ftdi; + #endif + struct { tu_edpt_stream_t tx; tu_edpt_stream_t rx; @@ -98,6 +105,9 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; +#if CFG_TUH_CDC_FTDI + static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; +#endif //--------------------------------------------------------------------+ // Serial Driver @@ -114,23 +124,22 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI -#include "serial/ftdi_sio.h" - static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; +#if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL +static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; +#endif static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); static void ftdi_process_config(tuh_xfer_t* xfer); -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// #if CFG_TUH_CDC_CP210X -#include "serial/cp210x.h" - static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); @@ -144,8 +153,6 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet //------------- CH34x prototypes -------------// #if CFG_TUH_CDC_CH34X -#include "serial/ch34x.h" - static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); @@ -212,8 +219,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), .open = ftdi_open, .process_set_config = ftdi_process_config, - .set_control_line_state = ftdi_sio_set_modem_ctrl, - .set_baudrate = ftdi_sio_set_baudrate, + .set_control_line_state = ftdi_set_modem_ctrl, + .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding, #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL @@ -992,28 +999,27 @@ static void acm_process_config(tuh_xfer_t* xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc); +static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx); +static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); +static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); //------------- Control Request -------------// // set request without data -static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - tusb_control_request_t const request = { - .bmRequestType_bit = { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_VENDOR, - .direction = TUSB_DIR_OUT - }, - .bRequest = command, - .wValue = tu_htole16(value), - .wIndex = 0, - .wLength = 0 +static bool ftdi_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, + uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request_setup = { + .bmRequestType = requesttype, + .bRequest = request, + .wValue = tu_htole16(value), + .wIndex = tu_htole16(index), + .wLength = 0 }; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, - .setup = &request, + .setup = &request_setup, .buffer = NULL, .complete_cb = complete_cb, .user_data = user_data @@ -1022,16 +1028,57 @@ static bool ftdi_sio_set_request(cdch_interface_t* p_cdc, uint8_t command, uint1 return tuh_control_xfer(&xfer); } -static bool ftdi_sio_reset(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return ftdi_sio_set_request(p_cdc, FTDI_SIO_RESET, FTDI_SIO_RESET_SIO, complete_cb, user_data); +#ifdef CFG_TUH_CDC_FTDI_LATENCY +static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latency, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + if (p_cdc->ftdi.chip_type == SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) + return FTDI_NOT_POSSIBLE; + return ftdi_set_request(p_cdc, FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, + latency, p_cdc->ftdi.channel, complete_cb, user_data) ? FTDI_REQUESTED : FTDI_FAIL; +} +#endif + +static inline bool ftdi_sio_reset(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return ftdi_set_request(p_cdc, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, + p_cdc->ftdi.channel, complete_cb, user_data); +} + +static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint32_t index_value = ftdi_get_divisor(p_cdc); + TU_VERIFY(index_value); + uint16_t value = (uint16_t) index_value; + uint16_t index = (uint16_t) (index_value >> 16); + if (p_cdc->ftdi.channel) { + index = (uint16_t)((index << 8) | p_cdc->ftdi.channel); + } + + return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + value, index, complete_cb, user_data); +} + +static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ( + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) | // data bit quantity is stored in bits 0-3 + ((uint32_t) p_cdc->requested_line_coding.parity & 0x7) << 8 | // parity is stored in bits 8-10, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits + + return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, + value, p_cdc->ftdi.channel, complete_cb, user_data); +} + +static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // FTDI has the same bit coding + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + p_cdc->requested_line_state, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); @@ -1039,11 +1086,17 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { if (success) { switch (xfer->setup->bRequest) { - case FTDI_SIO_MODEM_CTRL: + case FTDI_SIO_SET_MODEM_CTRL_REQUEST: p_cdc->line_state = p_cdc->requested_line_state; break; - case FTDI_SIO_SET_BAUD_RATE: + case FTDI_SIO_SET_DATA_REQUEST: + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + + case FTDI_SIO_SET_BAUDRATE_REQUEST: p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -1057,52 +1110,62 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ftdi_sio_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const divisor = (uint16_t) ftdi_232bm_baud_to_divisor(p_cdc); - +static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_SET_BAUD_RATE, divisor, - complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; -} - -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; -} - -static bool ftdi_sio_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - TU_ASSERT(ftdi_sio_set_request(p_cdc, FTDI_SIO_MODEM_CTRL, 0x0300 | p_cdc->requested_line_state, - complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + + return true; +} + +static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + set_line_coding_stage1_complete(xfer, itf_num, + ftdi_set_data_request, // control request function to set data format + ftdi_internal_control_complete); // control complete function to be called after request +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) +static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return set_line_coding_sequence(p_cdc, + ftdi_change_speed, // control request function to set baudrate + ftdi_set_data_request, // control request function to set data format + ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed + ftdi_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); +} + +static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + return true; } //------------- Enumeration -------------// enum { - CONFIG_FTDI_RESET = 0, - CONFIG_FTDI_MODEM_CTRL, - CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_GET_DESC = 0, + CONFIG_FTDI_DETERMINE_TYPE, + CONFIG_FTDI_WRITE_LATENCY, + CONFIG_FTDI_SIO_RESET, CONFIG_FTDI_SET_DATA, + CONFIG_FTDI_SET_BAUDRATE, + CONFIG_FTDI_FLOW_CONTROL, + CONFIG_FTDI_MODEM_CTRL, CONFIG_FTDI_COMPLETE }; -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len) { // FTDI Interface includes 1 vendor interface + 2 bulk endpoints - TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); + TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && + itf_desc->bNumEndpoints == 2); TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); @@ -1113,54 +1176,97 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint // endpoint pair tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + /* + * NOTE: Some customers have programmed FT232R/FT245R devices + * with an endpoint size of 0 - not good. + */ + TU_ASSERT(desc_ep->wMaxPacketSize != 0); + // data endpoints expected to be in pairs return open_ep_stream_pair(p_cdc, desc_ep); } -static void ftdi_process_config(tuh_xfer_t* xfer) { +static void ftdi_process_config(tuh_xfer_t * xfer) { uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + uint8_t const itf_num = p_cdc->bInterfaceNumber; switch(state) { - // Note may need to read FTDI eeprom - case CONFIG_FTDI_RESET: - TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + + // from here sequence overtaken from Linux Kernel function ftdi_port_probe() + case CONFIG_FTDI_GET_DESC: + // get device descriptor + p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config + if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); + break; + } + TU_ATTR_FALLTHROUGH; + + case CONFIG_FTDI_DETERMINE_TYPE: + // determine type + if (itf_num == 0) { + TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc, idx)); + } else { + // other interfaces have same type as interface 0 + uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); + cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + } + TU_ATTR_FALLTHROUGH; + + case CONFIG_FTDI_WRITE_LATENCY: + #ifdef CFG_TUH_CDC_FTDI_LATENCY + int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, + CONFIG_FTDI_SIO_RESET); + TU_ASSERT_COMPLETE(result != FTDI_FAIL); + if(result == FTDI_REQUESTED) { + break; + } // else FTDI_NOT_POSSIBLE => continue directly with next state + #endif + TU_ATTR_FALLTHROUGH; + + // from here sequence overtaken from Linux Kernel function ftdi_open() + case CONFIG_FTDI_SIO_RESET: + TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); + break; + + // from here sequence overtaken from Linux Kernel function ftdi_set_termios() + case CONFIG_FTDI_SET_DATA: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_FTDI_SET_BAUDRATE: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT_COMPLETE(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_FTDI_FLOW_CONTROL: + // disable flow control + TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, + 0, FTDI_SIO_DISABLE_FLOW_CTRL, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE)); + TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif - case CONFIG_FTDI_SET_BAUDRATE: { - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT_COMPLETE(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - } - - case CONFIG_FTDI_SET_DATA: { - #if 0 // TODO set data format - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE)); - break; - #endif - #endif - - TU_ATTR_FALLTHROUGH; - } - case CONFIG_FTDI_COMPLETE: set_config_complete(idx, 0, true); break; @@ -1173,28 +1279,249 @@ static void ftdi_process_config(tuh_xfer_t* xfer) { //------------- Helper -------------// +static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) +{ + uint16_t const version = desc_dev[idx]->bcdDevice; + uint8_t const itf_num = p_cdc->bInterfaceNumber; + + p_cdc->ftdi.chip_type = UNKNOWN; + + /* Assume Hi-Speed type */ + p_cdc->ftdi.channel = CHANNEL_A + itf_num; + + switch (version) { + case 0x200: + // FT232A not supported to keep it simple (no extra _read_latency_timer()) + // not testable + // p_cdc->ftdi.chip_type = FT232A; + // p_cdc->ftdi.baud_base = 48000000 / 2; + // p_cdc->ftdi.channel = 0; + // /* + // * FT232B devices have a bug where bcdDevice gets set to 0x200 + // * when iSerialNumber is 0. Assume it is an FT232B in case the + // * latency timer is readable. + // */ + // if (desc->iSerialNumber == 0 && + // _read_latency_timer(port) >= 0) { + // p_cdc->ftdi.chip_type = FT232B; + // } + break; + case 0x400: + p_cdc->ftdi.chip_type = FT232B; + p_cdc->ftdi.channel = 0; + break; + case 0x500: + p_cdc->ftdi.chip_type = FT2232C; + break; + case 0x600: + p_cdc->ftdi.chip_type = FT232R; + p_cdc->ftdi.channel = 0; + break; + case 0x700: + p_cdc->ftdi.chip_type = FT2232H; + break; + case 0x800: + p_cdc->ftdi.chip_type = FT4232H; + break; + case 0x900: + p_cdc->ftdi.chip_type = FT232H; + break; + case 0x1000: + p_cdc->ftdi.chip_type = FTX; + break; + case 0x2800: + p_cdc->ftdi.chip_type = FT2233HP; + break; + case 0x2900: + p_cdc->ftdi.chip_type = FT4233HP; + break; + case 0x3000: + p_cdc->ftdi.chip_type = FT2232HP; + break; + case 0x3100: + p_cdc->ftdi.chip_type = FT4232HP; + break; + case 0x3200: + p_cdc->ftdi.chip_type = FT233HP; + break; + case 0x3300: + p_cdc->ftdi.chip_type = FT232HP; + break; + case 0x3600: + p_cdc->ftdi.chip_type = FT4232HA; + break; + default: + if (version < 0x200) { + p_cdc->ftdi.chip_type = SIO; + p_cdc->ftdi.channel = 0; + } + break; + } + + TU_LOG_P_CDC("%s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + + return (p_cdc->ftdi.chip_type != UNKNOWN); +} + +// FT232A not supported +//static uint32_t ftdi_232am_baud_base_to_divisor(uint32_t baud, uint32_t base) +//{ +// uint32_t divisor; +// /* divisor shifted 3 bits to the left */ +// uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); +// if ((divisor3 & 0x7) == 7) +// divisor3++; /* round x.7/8 up to x+1 */ +// divisor = divisor3 >> 3; +// divisor3 &= 0x7; +// if (divisor3 == 1) +// divisor |= 0xc000; /* +0.125 */ +// else if (divisor3 >= 4) +// divisor |= 0x4000; /* +0.5 */ +// else if (divisor3 != 0) +// divisor |= 0x8000; /* +0.25 */ +// else if (divisor == 1) +// divisor = 0; /* special case for maximum baud rate */ +// return divisor; +//} + +// FT232A not supported +//static inline uint32_t ftdi_232am_baud_to_divisor(uint32_t baud) +//{ +// return ftdi_232am_baud_base_to_divisor(baud, (uint32_t) 48000000); +//} + static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - const uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; uint32_t divisor; - /* divisor shifted 3 bits to the left */ - uint32_t divisor3 = base / (2 * baud); - divisor = (divisor3 >> 3); - divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; - + uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); + divisor = divisor3 >> 3; + divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) { /* 1.0 */ + if (divisor == 1) /* 1.0 */ divisor = 0; - } - else if (divisor == 0x4001) { /* 1.5 */ + else if (divisor == 0x4001) /* 1.5 */ divisor = 1; - } - return divisor; } -static uint32_t ftdi_232bm_baud_to_divisor(cdch_interface_t* p_cdc) { - return ftdi_232bm_baud_base_to_divisor(p_cdc->requested_line_coding.bit_rate, 48000000u); +static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) +{ + return ftdi_232bm_baud_base_to_divisor(baud, 48000000); +} + +static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) +{ + static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint32_t divisor; + uint32_t divisor3; + + /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ + divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); + + divisor = divisor3 >> 3; + divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) /* 1.0 */ + divisor = 0; + else if (divisor == 0x4001) /* 1.5 */ + divisor = 1; + /* + * Set this bit to turn off a divide by 2.5 on baud rate generator + * This enables baud rates up to 12Mbaud but cannot reach below 1200 + * baud with this bit set + */ + divisor |= 0x00020000; + return divisor; +} + +static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) +{ + return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); +} + +static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) +{ + uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t div_value = 0; + TU_VERIFY(baud); + + switch (p_cdc->ftdi.chip_type) { + case UNKNOWN: + return 0; + case SIO: + switch (baud) { + case 300: div_value = ftdi_sio_b300; break; + case 600: div_value = ftdi_sio_b600; break; + case 1200: div_value = ftdi_sio_b1200; break; + case 2400: div_value = ftdi_sio_b2400; break; + case 4800: div_value = ftdi_sio_b4800; break; + case 9600: div_value = ftdi_sio_b9600; break; + case 19200: div_value = ftdi_sio_b19200; break; + case 38400: div_value = ftdi_sio_b38400; break; + case 57600: div_value = ftdi_sio_b57600; break; + case 115200: div_value = ftdi_sio_b115200; break; + default: + // Baudrate not supported + return 0; + break; + } + break; + // FT232A not supported + // case FT232A: + // if (baud <= 3000000) { + // div_value = ftdi_232am_baud_to_divisor(baud); + // } else { + // // Baud rate too high! + // baud = 9600; + // div_value = ftdi_232am_baud_to_divisor(9600); + // div_okay = false; + // } + // break; + case FT232B: + case FT2232C: + case FT232R: + case FTX: + TU_VERIFY(baud <= 3000000); // else Baud rate too high! + div_value = ftdi_232bm_baud_to_divisor(baud); + break; + case FT232H: + case FT2232H: + case FT4232H: + case FT4232HA: + case FT232HP: + case FT233HP: + case FT2232HP: + case FT2233HP: + case FT4232HP: + case FT4233HP: + default: + TU_VERIFY(baud <= 12000000); // else Baud rate too high! + if (baud >= 1200) { + div_value = ftdi_2232h_baud_to_divisor(baud); + } else { + div_value = ftdi_232bm_baud_to_divisor(baud); + } + break; + } + + TU_LOG_P_CDC("Baudrate divisor 0x%lu", div_value); + + return div_value; +} + +static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { + uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); // channel index, or 0 for legacy types + for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { + const cdch_interface_t * p_cdc = &cdch_data[i]; + if (p_cdc->daddr == xfer->daddr && + (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) + channel == p_cdc->ftdi.channel)) { // or multi-channel types (interfaces 0..n) + return i; + } + } + + return TUSB_INDEX_INVALID_8; } #endif diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 0825f0719..42716f73e 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -25,222 +25,207 @@ #ifndef TUSB_FTDI_SIO_H #define TUSB_FTDI_SIO_H -// VID for matching FTDI devices -#define TU_FTDI_VID 0x0403 +#include // Commands -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ -#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 0x0a /* Get the latency timer */ -#define FTDI_SIO_SET_BITMODE 0x0b /* Set bitbang mode */ -#define FTDI_SIO_READ_PINS 0x0c /* Read immediate value of pins */ -#define FTDI_SIO_READ_EEPROM 0x90 /* Read EEPROM */ +#define FTDI_SIO_RESET 0 // Reset the port +#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register +#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register +#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate +#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port +#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register +#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character +#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character +#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer +#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer +#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode +#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins +#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM -/* FTDI_SIO_RESET */ +// Channel indices for FT2232, FT2232H and FT4232H devices +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 + +// Port Identifier Table +#define PIT_DEFAULT 0 // SIOA +#define PIT_SIOA 1 // SIOA +// The device this driver is tested with one has only one port +#define PIT_SIOB 2 // SIOB +#define PIT_PARALLEL 3 // Parallel + +// FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 #define FTDI_SIO_RESET_SIO 0 #define FTDI_SIO_RESET_PURGE_RX 1 #define FTDI_SIO_RESET_PURGE_TX 2 -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_RESET - * wValue: Control Value - * 0 = Reset SIO - * 1 = Purge RX buffer - * 2 = Purge TX buffer - * wIndex: Port - * wLength: 0 - * Data: None - * - * The Reset SIO command has this effect: - * - * Sets flow control set to 'none' - * Event char = $0D - * Event trigger = disabled - * Purge RX buffer - * Purge TX buffer - * Clear DTR - * Clear RTS - * baud and data format not reset - * - * The Purge RX and TX buffer commands affect nothing except the buffers - * - */ +// FTDI_SIO_SET_BAUDRATE +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 -/* FTDI_SIO_MODEM_CTRL */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_MODEM_CTRL - * wValue: ControlValue (see below) - * wIndex: Port - * wLength: 0 - * Data: None - * - * NOTE: If the device is in RTS/CTS flow control, the RTS set by this - * command will be IGNORED without an error being returned - * Also - you can not set DTR and RTS with one control message - */ +enum ftdi_sio_baudrate { + ftdi_sio_b300 = 0, + ftdi_sio_b600 = 1, + ftdi_sio_b1200 = 2, + ftdi_sio_b2400 = 3, + ftdi_sio_b4800 = 4, + ftdi_sio_b9600 = 5, + ftdi_sio_b19200 = 6, + ftdi_sio_b38400 = 7, + ftdi_sio_b57600 = 8, + ftdi_sio_b115200 = 9 +}; + +// FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) + +// FTDI_SIO_MODEM_CTRL +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL #define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) #define FTDI_SIO_SET_RTS_MASK 0x2 #define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) #define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) -/* - * ControlValue - * B0 DTR state - * 0 = reset - * 1 = set - * B1 RTS state - * 0 = reset - * 1 = set - * B2..7 Reserved - * B8 DTR state enable - * 0 = ignore - * 1 = use DTR state - * B9 RTS state enable - * 0 = ignore - * 1 = use RTS state - * B10..15 Reserved - */ - -/* FTDI_SIO_SET_FLOW_CTRL */ +// FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 #define FTDI_SIO_RTS_CTS_HS (0x1 << 8) #define FTDI_SIO_DTR_DSR_HS (0x2 << 8) #define FTDI_SIO_XON_XOFF_HS (0x4 << 8) -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_FLOW_CTRL - * wValue: Xoff/Xon - * wIndex: Protocol/Port - hIndex is protocol / lIndex is port - * wLength: 0 - * Data: None - * - * hIndex protocol is: - * B0 Output handshaking using RTS/CTS - * 0 = disabled - * 1 = enabled - * B1 Output handshaking using DTR/DSR - * 0 = disabled - * 1 = enabled - * B2 Xon/Xoff handshaking - * 0 = disabled - * 1 = enabled - * - * A value of zero in the hIndex field disables handshaking - * - * If Xon/Xoff handshaking is specified, the hValue field should contain the - * XOFF character and the lValue field contains the XON character. - */ +// FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 -/* FTDI_SIO_SET_BAUD_RATE */ -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_BAUDRATE - * wValue: BaudDivisor value - see below - * wIndex: Port - * wLength: 0 - * Data: None - * The BaudDivisor values are calculated as follows (too complicated): - */ +// FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 -/* FTDI_SIO_SET_DATA */ -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) +// FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_DATA - * wValue: Data characteristics (see below) - * wIndex: Port - * wLength: 0 - * Data: No - * - * Data characteristics - * - * B0..7 Number of data bits - * B8..10 Parity - * 0 = None - * 1 = Odd - * 2 = Even - * 3 = Mark - * 4 = Space - * B11..13 Stop Bits - * 0 = 1 - * 1 = 1.5 - * 2 = 2 - * B14 - * 1 = TX ON (break) - * 0 = TX OFF (normal state) - * B15 Reserved - * - */ +// FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 -/* -* DATA FORMAT -* -* IN Endpoint -* -* The device reserves the first two bytes of data on this endpoint to contain -* the current values of the modem and line status registers. In the absence of -* data, the device generates a message consisting of these two status bytes - * every 40 ms - * - * Byte 0: Modem Status -* -* Offset Description -* B0 Reserved - must be 1 -* B1 Reserved - must be 0 -* B2 Reserved - must be 0 -* B3 Reserved - must be 0 -* B4 Clear to Send (CTS) -* B5 Data Set Ready (DSR) -* B6 Ring Indicator (RI) -* B7 Receive Line Signal Detect (RLSD) -* -* Byte 1: Line Status -* -* Offset Description -* B0 Data Ready (DR) -* B1 Overrun Error (OE) -* B2 Parity Error (PE) -* B3 Framing Error (FE) -* B4 Break Interrupt (BI) -* B5 Transmitter Holding Register (THRE) -* B6 Transmitter Empty (TEMT) -* B7 Error in RCVR FIFO -* -*/ -#define FTDI_RS0_CTS (1 << 4) -#define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) -#define FTDI_RS0_RLSD (1 << 7) +// FTDI_SIO_SET_BITMODE +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) +// Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 + +// FTDI_SIO_READ_PINS +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS + +// FTDI_SIO_READ_EEPROM +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM + +#define FTDI_FTX_CBUS_MUX_GPIO 0x8 +#define FTDI_FT232R_CBUS_MUX_GPIO 0xa + +#define FTDI_RS0_CTS (1 << 4) +#define FTDI_RS0_DSR (1 << 5) +#define FTDI_RS0_RI (1 << 6) +#define FTDI_RS0_RLSD (1 << 7) + +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1<<1) +#define FTDI_RS_PE (1<<2) +#define FTDI_RS_FE (1<<3) +#define FTDI_RS_BI (1<<4) +#define FTDI_RS_THRE (1<<5) +#define FTDI_RS_TEMT (1<<6) +#define FTDI_RS_FIFO (1<<7) + +// chip types and names +enum ftdi_chip_type { + SIO = 0, +// FT232A, + FT232B, + FT2232C, + FT232R, + FT232H, + FT2232H, + FT4232H, + FT4232HA, + FT232HP, + FT233HP, + FT2232HP, + FT2233HP, + FT4232HP, + FT4233HP, + FTX, + UNKNOWN +}; + +#define FTDI_CHIP_NAMES \ + [SIO] = (uint8_t const*) "SIO", /* the serial part of FT8U100AX */ \ +/* [FT232A] = (uint8_t const*) "FT232A", */ \ + [FT232B] = (uint8_t const*) "FT232B", \ + [FT2232C] = (uint8_t const*) "FT2232C/D", \ + [FT232R] = (uint8_t const*) "FT232R", \ + [FT232H] = (uint8_t const*) "FT232H", \ + [FT2232H] = (uint8_t const*) "FT2232H", \ + [FT4232H] = (uint8_t const*) "FT4232H", \ + [FT4232HA] = (uint8_t const*) "FT4232HA", \ + [FT232HP] = (uint8_t const*) "FT232HP", \ + [FT233HP] = (uint8_t const*) "FT233HP", \ + [FT2232HP] = (uint8_t const*) "FT2232HP", \ + [FT2233HP] = (uint8_t const*) "FT2233HP", \ + [FT4232HP] = (uint8_t const*) "FT4232HP", \ + [FT4233HP] = (uint8_t const*) "FT4233HP", \ + [FTX] = (uint8_t const*) "FT-X", \ + [UNKNOWN] = (uint8_t const*) "UNKNOWN" + +// private interface data +typedef struct ftdi_private { + enum ftdi_chip_type chip_type; + uint8_t channel; // channel index, or 0 for legacy types +} ftdi_private_t; + +#define FTDI_OK true +#define FTDI_FAIL false +#define FTDI_NOT_POSSIBLE -1 +#define FTDI_REQUESTED -2 + +// division and round function overtaken from math.h +#define DIV_ROUND_CLOSEST(x, divisor)( \ +{ \ + typeof(x) __x = x; \ + typeof(divisor) __d = divisor; \ + (((typeof(x))-1) > 0 || \ + ((typeof(divisor))-1) > 0 || \ + (((__x) > 0) == ((__d) > 0))) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ +} \ +) #endif //TUSB_FTDI_SIO_H diff --git a/src/tusb_option.h b/src/tusb_option.h index 767323bdd..ebf9a4d4d 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -456,9 +456,22 @@ #ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID #define CFG_TUH_CDC_FTDI_VID_PID_LIST \ - {0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \ - {0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \ - {0x0403, 0xCD18} + {0x0403, 0x6001}, /* Similar device to SIO above */ \ + {0x0403, 0x6006}, /* FTDI's alternate PID for above */ \ + {0x0403, 0x6010}, /* Dual channel device */ \ + {0x0403, 0x6011}, /* Quad channel hi-speed device */ \ + {0x0403, 0x6014}, /* Single channel hi-speed device */ \ + {0x0403, 0x6015}, /* FT-X series (FT201X, FT230X, FT231X, etc) */ \ + {0x0403, 0x6040}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6041}, /* Quad channel hi-speed device with PD */ \ + {0x0403, 0x6042}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6043}, /* Quad channel hi-speed device with PD */ \ + {0x0403, 0x6044}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6045}, /* Dual channel hi-speed device with PD */ \ + {0x0403, 0x6048}, /* Quad channel automotive grade hi-speed device */ \ + {0x0403, 0x8372}, /* Product Id SIO application of 8U100AX */ \ + {0x0403, 0xFBFA}, /* Product ID for FT232RL */ \ + {0x0403, 0xCD18}, /* ??? */ #endif #ifndef CFG_TUH_CDC_CP210X From 4547737833de0368354cb4823d908c6b250f92df Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:42:33 +0100 Subject: [PATCH 014/101] improved CP210x support --- src/class/cdc/cdc_host.c | 143 +++++++++++++++++++++++----------- src/class/cdc/serial/cp210x.h | 63 ++++++++++++++- src/tusb_option.h | 4 +- 3 files changed, 163 insertions(+), 47 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f9540efbe..86c010fa7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -83,7 +83,7 @@ typedef struct { uint8_t requested_line_state; tuh_xfer_cb_t user_control_cb; - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CH34X + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif @@ -1533,7 +1533,8 @@ static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { //------------- Control Request -------------// -static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_t value, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16_t value, + uint8_t * buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, @@ -1542,12 +1543,12 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_ }, .bRequest = command, .wValue = tu_htole16(value), - .wIndex = p_cdc->bInterfaceNumber, + .wIndex = tu_htole16(p_cdc->bInterfaceNumber), .wLength = tu_htole16(length) }; // use usbh enum buf since application variable does not live long enough - uint8_t* enum_buf = NULL; + uint8_t * enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1566,18 +1567,52 @@ static bool cp210x_set_request(cdch_interface_t* p_cdc, uint8_t command, uint16_ return tuh_control_xfer(&xfer); } -static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } +static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // Check baudrate is supported. It's only a specific list. reference: datasheets and AN205 "CP210x Baud Rate Support" + uint32_t const supported_baudrates_list[] = CP210X_SUPPORTED_BAUDRATES_LIST; + uint8_t i; + for ( i=0; supported_baudrates_list[i]; i++ ){ + if (p_cdc->requested_line_coding.bit_rate == supported_baudrates_list[i]) { + break; + } + } + TU_VERIFY(supported_baudrates_list[i]); + uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); + + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); +} + +static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); + uint16_t lcr = (uint16_t) ( + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) << 8 | // data bit quantity is stored in bits 8-11 + ((uint32_t) p_cdc->requested_line_coding.parity & 0xf) << 4 | // parity is stored in bits 4-7, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xf)); // parity is stored in bits 0-3, same coding + + return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); +} + +static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // CP210x has the same bit coding + return cp210x_set_request(p_cdc, CP210X_SET_MHS, + (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | + (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state), + NULL, 0, complete_cb, user_data); +} + //------------- Driver API -------------// // internal control complete to update state such as line state, encoding static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1587,6 +1622,12 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { p_cdc->line_state = p_cdc->requested_line_state; break; + case CP210X_SET_LINE_CTL: + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + break; + case CP210X_SET_BAUDRATE: p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; break; @@ -1601,46 +1642,55 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); +static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, - complete_cb ? cp210x_internal_control_complete : NULL, user_data); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; } -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - (void) p_cdc; - (void) complete_cb; - (void) user_data; - // TODO not implemented yet - return false; -} - -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // TODO implement later - (void) p_cdc; - (void) complete_cb; - (void) user_data; - return false; -} - -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; - return cp210x_set_request(p_cdc, CP210X_SET_MHS, 0x0300 | p_cdc->requested_line_state, NULL, 0, - complete_cb ? cp210x_internal_control_complete : NULL, user_data); + TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; +} + +static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + set_line_coding_stage1_complete(xfer, itf_num, + cp210x_set_line_ctl, // control request function to set data format + cp210x_internal_control_complete); // control complete function to be called after request +} + +// 2 stages: set baudrate (stage1) + set data format (stage2) +static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return set_line_coding_sequence(p_cdc, + cp210x_set_baudrate_request, // control request function to set baudrate + cp210x_set_line_ctl, // control request function to set data format + cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed + cp210x_internal_control_complete, // control complete function to be called after request + complete_cb, user_data); +} + +static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); + + return true; } //------------- Enumeration -------------// enum { CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE, + CONFIG_CP210X_SET_BAUDRATE_REQUEST, CONFIG_CP210X_SET_LINE_CTL, CONFIG_CP210X_SET_DTR_RTS, CONFIG_CP210X_COMPLETE }; -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { // CP210x Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); @@ -1657,7 +1707,7 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return open_ep_stream_pair(p_cdc, desc_ep); } -static void cp210x_process_config(tuh_xfer_t* xfer) { +static void cp210x_process_config(tuh_xfer_t * xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); @@ -1666,32 +1716,35 @@ static void cp210x_process_config(tuh_xfer_t* xfer) { switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE)); + p_cdc->user_control_cb = cp210x_process_config; // set once for whole process config + TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cp210x_process_config, + CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; - case CONFIG_CP210X_SET_BAUDRATE: { + case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate; - TU_ASSERT_COMPLETE(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL)); + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; #endif - } - case CONFIG_CP210X_SET_LINE_CTL: { - #if defined(CFG_TUH_CDC_LINE_CODING_ON_ENUM) && 0 // skip for now - cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM; - break; + case CONFIG_CP210X_SET_LINE_CTL: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + TU_ASSERT_COMPLETE(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_SET_DTR_RTS)); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif - } case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE)); + TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, + CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index 2c749f522..e18da7d51 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -28,7 +28,8 @@ // Protocol details can be found at AN571: CP210x Virtual COM Port Interface // https://www.silabs.com/documents/public/application-notes/AN571.pdf -#define TU_CP210X_VID 0x10C4 +// parts are overtaken from vendors driver +// https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 @@ -59,4 +60,64 @@ #define CP210X_SET_BAUDRATE 0x1E #define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device +/* SILABSER_IFC_ENABLE_REQUEST_CODE */ +#define CP210X_UART_ENABLE 0x0001 +#define CP210X_UART_DISABLE 0x0000 + +/* SILABSER_SET_BAUDDIV_REQUEST_CODE */ +#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 + +/*SILABSER_SET_LINE_CTL_REQUEST_CODE */ +#define CP210X_BITS_DATA_MASK 0x0f00 +#define CP210X_BITS_DATA_5 0x0500 +#define CP210X_BITS_DATA_6 0x0600 +#define CP210X_BITS_DATA_7 0x0700 +#define CP210X_BITS_DATA_8 0x0800 +#define CP210X_BITS_DATA_9 0x0900 + +#define CP210X_BITS_PARITY_MASK 0x00f0 +#define CP210X_BITS_PARITY_NONE 0x0000 +#define CP210X_BITS_PARITY_ODD 0x0010 +#define CP210X_BITS_PARITY_EVEN 0x0020 +#define CP210X_BITS_PARITY_MARK 0x0030 +#define CP210X_BITS_PARITY_SPACE 0x0040 + +#define CP210X_BITS_STOP_MASK 0x000f +#define CP210X_BITS_STOP_1 0x0000 +#define CP210X_BITS_STOP_1_5 0x0001 +#define CP210X_BITS_STOP_2 0x0002 + +/* SILABSER_SET_BREAK_REQUEST_CODE */ +#define CP210X_BREAK_ON 0x0001 +#define CP210X_BREAK_OFF 0x0000 + +/* SILABSER_SET_MHS_REQUEST_CODE */ +#define CP210X_MCR_DTR 0x0001 +#define CP210X_MCR_RTS 0x0002 +#define CP210X_MCR_ALL 0x0003 +#define CP210X_MSR_CTS 0x0010 +#define CP210X_MSR_DSR 0x0020 +#define CP210X_MSR_RING 0x0040 +#define CP210X_MSR_DCD 0x0080 +#define CP210X_MSR_ALL 0x00F0 + +#define CP210X_CONTROL_WRITE_DTR 0x0100 +#define CP210X_CONTROL_WRITE_RTS 0x0200 + +#define CP210X_LSR_BREAK 0x0001 +#define CP210X_LSR_FRAMING_ERROR 0x0002 +#define CP210X_LSR_HW_OVERRUN 0x0004 +#define CP210X_LSR_QUEUE_OVERRUN 0x0008 +#define CP210X_LSR_PARITY_ERROR 0x0010 +#define CP210X_LSR_ALL 0x001F + +// supported baudrates +// reference: datasheets and AN205 "CP210x Baud Rate Support" +#define CP210X_SUPPORTED_BAUDRATES_LIST { \ + 300, 600, \ + 1200, 1800, 2400, 4000, 4800, 7200, 9600, \ + 14400, 16000, 19200, 28800, 38400, 51200, 56000, 57600, 64000, 76800, \ + 115200, 128000, 153600, 230400, 250000, 256000, 460800, 500000, 576000, 921600, \ + 0 } + #endif //TUSB_CP210X_H diff --git a/src/tusb_option.h b/src/tusb_option.h index ebf9a4d4d..281341685 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -482,7 +482,9 @@ #ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID #define CFG_TUH_CDC_CP210X_VID_PID_LIST \ - {0x10C4, 0xEA60}, {0x10C4, 0xEA70} + { 0x10C4, 0xEA60 }, /* Silicon Labs factory default */ \ + { 0x10C4, 0xEA61 }, /* Silicon Labs factory default */ \ + { 0x10C4, 0xEA70 } /* Silicon Labs Dual Port factory default */ #endif #ifndef CFG_TUH_CDC_CH34X From aabee25e189d2a05cb52e5c54329ab1ec875f084 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 11:45:38 +0100 Subject: [PATCH 015/101] added PL2303 support --- examples/host/cdc_msc_hid/src/tusb_config.h | 1 + .../cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 754 +++++++++++++++++- src/class/cdc/serial/pl2303.h | 172 ++++ src/tusb_option.h | 18 + 5 files changed, 942 insertions(+), 4 deletions(-) create mode 100644 src/class/cdc/serial/pl2303.h diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e4d74077f..fc956c6d3 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -106,6 +106,7 @@ #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 9dc89dc55..dd732c700 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -111,6 +111,7 @@ #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API +#define CFG_TUH_CDC_PL2303 1 // PL2303 Serial. PL2303 is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_HID (3*CFG_TUH_DEVICE_MAX) // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 1 #define CFG_TUH_VENDOR 0 diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 86c010fa7..429d0a113 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -38,6 +38,7 @@ #include "serial/ftdi_sio.h" #include "serial/cp210x.h" #include "serial/ch34x.h" +#include "serial/pl2303.h" // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL @@ -91,6 +92,10 @@ typedef struct { ftdi_private_t ftdi; #endif + #if CFG_TUH_CDC_PL2303 + pl2303_private_t pl2303; + #endif + struct { tu_edpt_stream_t tx; tu_edpt_stream_t rx; @@ -105,7 +110,7 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; -#if CFG_TUH_CDC_FTDI +#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; #endif @@ -164,6 +169,22 @@ static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complet static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif +//------------- PL2303 prototypes -------------// +#if CFG_TUH_CDC_PL2303 +static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; +static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; + +CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN + +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +static void pl2303_process_config(tuh_xfer_t * xfer); + +static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +#endif + //------------- Common -------------// enum { SERIAL_DRIVER_ACM = 0, @@ -180,6 +201,10 @@ enum { SERIAL_DRIVER_CH34X, #endif +#if CFG_TUH_CDC_PL2303 + SERIAL_DRIVER_PL2303, +#endif + SERIAL_DRIVER_COUNT }; @@ -260,6 +285,22 @@ static const cdch_serial_driver_t serial_drivers[] = { #endif }, #endif + + #if CFG_TUH_CDC_PL2303 + { + .vid_pid_list = pl2303_vid_pid_list, + .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), + .open = pl2303_open, + .process_set_config = pl2303_process_config, + .set_control_line_state = pl2303_set_modem_ctrl, + .set_baudrate = pl2303_set_baudrate, + .set_data_format = pl2303_set_data_format, + .set_line_coding = pl2303_set_line_coding, + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + .name = (uint8_t const *) "PL2303" + #endif + } + #endif }; TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial driver count mismatch"); @@ -1863,7 +1904,7 @@ static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t com // internal control complete to update state such as line state, encoding static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { - // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t* p_cdc = get_itf(idx); @@ -1921,7 +1962,8 @@ static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_ } static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - uint8_t const itf_num = 0; // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, ch34x_write_reg_data_format, // control request function to set data format ch34x_internal_control_complete); // control complete function to be called after request @@ -1981,7 +2023,7 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uintptr_t const state = xfer->user_data; uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); @@ -2142,4 +2184,708 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { #endif // CFG_TUH_CDC_CH34X +//--------------------------------------------------------------------+ +// PL2303 +//--------------------------------------------------------------------+ +#if CFG_TUH_CDC_PL2303 + +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); + +//------------- Control Request -------------// + +static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, + uint16_t value, uint16_t index, uint8_t * buffer, uint16_t length, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + tusb_control_request_t const request_setup = { + .bmRequestType = requesttype, + .bRequest = request, + .wValue = tu_htole16 (value), + .wIndex = tu_htole16 (index), + .wLength = tu_htole16 (length) + }; + + // use usbh enum buf since application variable does not live long enough + uint8_t * enum_buf = NULL; + + if (buffer && length > 0) { + enum_buf = usbh_get_enum_buf(); + if (request_setup.bmRequestType_bit.direction == TUSB_DIR_OUT) { + tu_memcpy_s(enum_buf, CFG_TUH_ENUMERATION_BUFSIZE, buffer, length); + } + } + + tuh_xfer_t xfer = { + .daddr = p_cdc->daddr, + .ep_addr = 0, + .setup = &request_setup, + .buffer = enum_buf, + .complete_cb = complete_cb, + .user_data = user_data + }; + + return tuh_control_xfer(&xfer); +} + +static bool pl2303_vendor_read(cdch_interface_t * p_cdc, uint16_t value, uint8_t * buf, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? + PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; + + return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); +} + +static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? + PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; + + return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); +} + +static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + uint8_t buf; + + return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, + &buf, 1, complete_cb, user_data); +} + +static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, + p_cdc->requested_line_state, 0, NULL, 0, complete_cb, user_data); +} + +//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) +//{ +// return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); +//} + +static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // the caller has to precheck, that the new line coding different than the current, else false returned + uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; + /* + * Some PL2303 are known to lose bytes if you change serial settings + * even to the same values as before. Thus we actually need to filter + * in this specific case. + */ + // TODO really necessary to check? what to do in this case when no transfer will happen? + // callback is not called... + TU_VERIFY(memcmp(&p_cdc->requested_line_coding, &p_cdc->line_coding, sizeof(cdc_line_coding_t) ) != 0); + + /* For reference buf[6] data bits value */ + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); + buf[6] = p_cdc->requested_line_coding.data_bits; + + /* For reference buf[0]:buf[3] baud rate value */ + TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0])); + + /* For reference buf[4]=0 is 1 stop bits */ + /* For reference buf[4]=1 is 1.5 stop bits */ + /* For reference buf[4]=2 is 2 stop bits */ + buf[4] = p_cdc->requested_line_coding.stop_bits; // PL2303 has the same coding + + /* For reference buf[5]=0 is none parity */ + /* For reference buf[5]=1 is odd parity */ + /* For reference buf[5]=2 is even parity */ + /* For reference buf[5]=3 is mark parity */ + /* For reference buf[5]=4 is space parity */ + buf[5] = p_cdc->requested_line_coding.parity; // PL2303 has the same coding + + return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0, + buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); +} + +//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) +//{ +// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; +// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); +//} + +static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) +{ + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, + NULL, 0, complete_cb, user_data); +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { + // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + bool const success = (xfer->result == XFER_RESULT_SUCCESS); + TU_LOG_P_CDC("control complete success = %u", success); + + if (success) { + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line_coding = p_cdc->requested_line_coding; + } + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line_state = p_cdc->requested_line_state; + } + } + + xfer->complete_cb = p_cdc->user_control_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + +static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; + p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; + p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // PL2303 has the same bit coding + p_cdc->user_control_cb = complete_cb; + TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + + return true; +} + +//------------- Enumeration -------------// + +enum { + CONFIG_PL2303_GET_DESC = 0, + CONFIG_PL2303_DETECT_TYPE, + CONFIG_PL2303_READ1, + CONFIG_PL2303_WRITE1, + CONFIG_PL2303_READ2, + CONFIG_PL2303_READ3, + CONFIG_PL2303_READ4, + CONFIG_PL2303_WRITE2, + CONFIG_PL2303_READ5, + CONFIG_PL2303_READ6, + CONFIG_PL2303_WRITE3, + CONFIG_PL2303_WRITE4, + CONFIG_PL2303_WRITE5, + CONFIG_PL2303_RESET_ENDP1, + CONFIG_PL2303_RESET_ENDP2, + CONFIG_PL2303_LINE_CODING, + CONFIG_PL2303_MODEM_CONTROL, + CONFIG_PL2303_FLOW_CTRL_READ, + CONFIG_PL2303_FLOW_CTRL_WRITE, + CONFIG_PL2303_COMPLETE +}; + +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { + // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk + TU_VERIFY(itf_desc->bNumEndpoints == 3); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); + + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); + + p_cdc->serial_drid = SERIAL_DRIVER_PL2303; + p_cdc->pl2303.serial_private.quirks = 0; + p_cdc->pl2303.supports_hx_status = false; + + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const * ) tu_desc_next(itf_desc); + + // Interrupt endpoint: not used for now + TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && + TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer); + TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); + p_cdc->ep_notif = desc_ep->bEndpointAddress; + desc_ep += 1; + + // data endpoints expected to be in pairs + TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); + + return true; +} + +static void pl2303_process_config(tuh_xfer_t * xfer) { + // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber + uint8_t const itf_num = 0; + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); + cdch_interface_t * p_cdc = get_itf(idx); + // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() + TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); + uint8_t buf; + int8_t type; + + switch (xfer->user_data) { + + // from here sequence overtaken from Linux Kernel function pl2303_startup() + case CONFIG_PL2303_GET_DESC: + p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config + // get device descriptor + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); + break; + + case CONFIG_PL2303_DETECT_TYPE: + // get type and quirks (step 1) + type = pl2303_detect_type (p_cdc, idx, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 + TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { + break; + } // else: no transfer triggered and continue with CONFIG_PL2303_READ1 + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ1: + // get supports_hx_status, type and quirks (step 2), do special read + p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case + xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); + type = pl2303_detect_type (p_cdc, idx, 2, NULL, 0); // step 2 now with supports_hx_status + TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; + p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary + TU_LOG(CFG_TUH_CDC_LOG_LEVEL, "PL2303 bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + uint16_t vid, pid; + TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); + TU_LOG(CFG_TUH_CDC_LOG_LEVEL, " vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + #endif + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE1)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE1: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 0, pl2303_process_config, CONFIG_PL2303_READ2)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ2: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ3)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ3: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_READ4)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ4: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE2)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE2: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 1, pl2303_process_config, CONFIG_PL2303_READ5)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ5: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ6)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_READ6: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_WRITE3)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE3: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, 1, pl2303_process_config, CONFIG_PL2303_WRITE4)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE4: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 1, 0, pl2303_process_config, CONFIG_PL2303_WRITE5)); + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + case CONFIG_PL2303_WRITE5: + // purpose unknown, overtaken from Linux Kernel driver + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x24, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x44, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); + } + break; + } // else: continue with next step + TU_ATTR_FALLTHROUGH; + + // from here sequence overtaken from Linux Kernel function pl2303_open() + case CONFIG_PL2303_RESET_ENDP1: + // step 1 + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2)); + } else { + /* reset upstream data pipes */ + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG, // skip CONFIG_PL2303_RESET_ENDP2, no 2nd step + PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, + pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } else { + pl2303_vendor_write(p_cdc, 8, 0, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2); + } + } + break; + + case CONFIG_PL2303_RESET_ENDP2: + // step 2 + if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_IN_EP, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } else { + /* reset upstream data pipes */ + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // here nothing to do, only structure of previous step overtaken for better reading and comparison + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 9, 0, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + } + } + break; + + // from here sequence overtaken from Linux Kernel function pl2303_set_termios() + // unnecessary pl2303_get_line_request() is skipped due to a stall + case CONFIG_PL2303_LINE_CODING: + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT_COMPLETE( pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_PL2303_MODEM_CONTROL: + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case CONFIG_PL2303_FLOW_CTRL_READ: + // read flow control register for modify & write back in next step + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, + CONFIG_PL2303_FLOW_CTRL_WRITE)); + } else { + TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + } + break; + + case CONFIG_PL2303_FLOW_CTRL_WRITE: + // no flow control + buf = xfer->buffer[0]; + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + buf |= PL2303_HXN_FLOWCTRL_NONE; + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, + CONFIG_PL2303_COMPLETE)); + } else { + buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); + } + break; + + case CONFIG_PL2303_COMPLETE: + set_config_complete(idx, 0, true); + break; + + default: + set_config_complete(idx, 0, false); + break; + } +} + +//------------- Helper -------------// + +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data ) +{ + /* + * Legacy PL2303H, variants 0 and 1 (difference unknown). + */ + if (desc_dev[idx]->bDeviceClass == 0x02) { + return TYPE_H; /* variant 0 */ + } + + if (desc_dev[idx]->bMaxPacketSize0 != 0x40) { + if (desc_dev[idx]->bDeviceClass == 0x00 || desc_dev[idx]->bDeviceClass == 0xff) { + return TYPE_H; /* variant 1 */ + } + return TYPE_H; /* variant 0 */ + } + + switch (desc_dev[idx]->bcdUSB) { + case 0x101: + /* USB 1.0.1? Let's assume they meant 1.1... */ + TU_ATTR_FALLTHROUGH; + case 0x110: + switch (desc_dev[idx]->bcdDevice) { + case 0x300: + return TYPE_HX; + case 0x400: + return TYPE_HXD; + default: + return TYPE_HX; + } + break; + case 0x200: + switch (desc_dev[idx]->bcdDevice) { + case 0x100: /* GC */ + case 0x105: + return TYPE_HXN; + case 0x300: /* GT / TA */ + if (step == 1) { + // step 1 trigger pl2303_supports_hx_status() request + TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + } else { + // step 2 use supports_hx_status + if (p_cdc->pl2303.supports_hx_status) { + return TYPE_TA; + } + } + TU_ATTR_FALLTHROUGH; + case 0x305: + case 0x400: /* GL */ + case 0x405: + return TYPE_HXN; + case 0x500: /* GE / TB */ + if (step == 1) { + // step 1 trigger pl2303_supports_hx_status() request + TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + } else { + // step 2 use supports_hx_status + if (p_cdc->pl2303.supports_hx_status) { + return TYPE_TB; + } + } + TU_ATTR_FALLTHROUGH; + case 0x505: + case 0x600: /* GS */ + case 0x605: + case 0x700: /* GR */ + case 0x705: + return TYPE_HXN; + default: + break; + } + break; + default: break; + } + + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + + return PL2303_DETECT_TYPE_FAILED; +} + +/* + * Returns the nearest supported baud rate that can be set directly without + * using divisors. + */ +static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) +{ + static const uint32_t baud_sup[] = { + 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, + 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, + 614400, 921600, 1228800, 2457600, 3000000, 6000000 + }; + + uint8_t i; + for (i = 0; i < TU_ARRAY_SIZE(baud_sup); ++i) { + if (baud_sup[i] > baud) { + break; + } + } + + if (i == TU_ARRAY_SIZE(baud_sup)) { + baud = baud_sup[i - 1]; + } else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1])) { + baud = baud_sup[i - 1]; + } else { + baud = baud_sup[i]; + } + + return baud; +} + +/* + * NOTE: If unsupported baud rates are set directly, the PL2303 seems to + * use 9600 baud. + */ +static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baud_le = tu_htole32(baud); + buf[0] = (uint8_t) ( baud_le & 0xff); + buf[1] = (uint8_t) ((baud_le >> 8) & 0xff); + buf[2] = (uint8_t) ((baud_le >> 16) & 0xff); + buf[3] = (uint8_t) ((baud_le >> 24) & 0xff); + + return baud; +} + +static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baseline, mantissa, exponent; + + /* + * Apparently the formula is: + * baudrate = 12M * 32 / (mantissa * 4^exponent) + * where + * mantissa = buf[8:0] + * exponent = buf[11:9] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + exponent = 0; + while (mantissa >= 512) { + if (exponent < 7) { + mantissa >>= 2; /* divide by 4 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 511; + break; + } + } + + buf[3] = 0x80; + buf[2] = 0; + buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); + buf[0] = (uint8_t) (mantissa & 0xff); + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> (exponent << 1); + + return baud; +} + +static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) +{ + uint32_t baseline, mantissa, exponent; + + /* + * Apparently, for the TA version the formula is: + * baudrate = 12M * 32 / (mantissa * 2^exponent) + * where + * mantissa = buf[10:0] + * exponent = buf[15:13 16] + */ + baseline = 12000000 * 32; + mantissa = baseline / baud; + if (mantissa == 0) { + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + } + exponent = 0; + while (mantissa >= 2048) { + if (exponent < 15) { + mantissa >>= 1; /* divide by 2 */ + exponent++; + } else { + /* Exponent is maxed. Trim mantissa and leave. */ + mantissa = 2047; + break; + } + } + + buf[3] = 0x80; + buf[2] = (uint8_t) (exponent & 0x01); + buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8 ) & 0xff); + buf[0] = (uint8_t) (mantissa & 0xff); + + /* Calculate and return the exact baud rate. */ + baud = (baseline / mantissa) >> exponent; + + return baud; +} + +static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) +{ + uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud_sup; + + TU_VERIFY(baud && baud <= p_cdc->pl2303.serial_private.type->max_baud_rate); + /* + * Use direct method for supported baud rates, otherwise use divisors. + * Newer chip types do not support divisor encoding. + */ + if (p_cdc->pl2303.serial_private.type->no_divisors) { + baud_sup = baud; + } else { + baud_sup = pl2303_get_supported_baud_rate(baud); + } + + if (baud == baud_sup) { + baud = pl2303_encode_baud_rate_direct(buf, baud); + } else if (p_cdc->pl2303.serial_private.type->alt_divisors) { + baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); + } else { + baud = pl2303_encode_baud_rate_divisor(buf, baud); + } + TU_LOG_P_CDC("real baudrate = %lu", baud); + + return true; +} + +#endif // CFG_TUH_CDC_PL2303 + #endif diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h new file mode 100644 index 000000000..bf264191b --- /dev/null +++ b/src/class/cdc/serial/pl2303.h @@ -0,0 +1,172 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Heiko Kuester + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _PL2303_H_ +#define _PL2303_H_ + +#include +#include + +// There is no official documentation for the PL2303 chips. +// Reference can be found +// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.h and +// https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c +// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c + +/* quirks */ +#define PL2303_QUIRK_UART_STATE_IDX0 1 +#define PL2303_QUIRK_LEGACY 2 +#define PL2303_QUIRK_ENDPOINT_HACK 4 + +/* requests and bits */ +#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 + +#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 +#define PL2303_CONTROL_DTR 0x01 // dec 1 +#define PL2303_CONTROL_RTS 0x02 // dec 2 + +#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_BREAK_REQUEST 0x23 // dec 35 +#define PL2303_BREAK_ON 0xffff +#define PL2303_BREAK_OFF 0x0000 + +#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface +#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 + +#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface +#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 + +#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface +#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 + +#define PL2303_UART_STATE_INDEX 8 +#define PL2303_UART_STATE_MSR_MASK 0x8b +#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 +#define PL2303_UART_DCD 0x01 +#define PL2303_UART_DSR 0x02 +#define PL2303_UART_BREAK_ERROR 0x04 +#define PL2303_UART_RING 0x08 +#define PL2303_UART_FRAME_ERROR 0x10 +#define PL2303_UART_PARITY_ERROR 0x20 +#define PL2303_UART_OVERRUN_ERROR 0x40 +#define PL2303_UART_CTS 0x80 + +#define PL2303_FLOWCTRL_MASK 0xf0 + +#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint + +/* registers via vendor read/write requests */ +#define PL2303_READ_TYPE_HX_STATUS 0x8080 + +#define PL2303_HXN_RESET_REG 0x07 +#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 +#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 + +#define PL2303_HXN_FLOWCTRL_REG 0x0a +#define PL2303_HXN_FLOWCTRL_MASK 0x1c +#define PL2303_HXN_FLOWCTRL_NONE 0x1c +#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 +#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c + +/* type data */ +enum pl2303_type { + TYPE_H, + TYPE_HX, + TYPE_TA, + TYPE_TB, + TYPE_HXD, + TYPE_HXN, + TYPE_COUNT +}; + +struct pl2303_type_data { + uint8_t const *name; + uint32_t const max_baud_rate; + uint8_t const quirks; + uint16_t const no_autoxonxoff:1; + uint16_t const no_divisors:1; + uint16_t const alt_divisors:1; +}; + +#define PL2303_TYPE_DATA \ + [TYPE_H] = { \ + .name = (uint8_t const*)"H", \ + .max_baud_rate = 1228800, \ + .quirks = PL2303_QUIRK_LEGACY, \ + .no_autoxonxoff = true, \ + }, \ + [TYPE_HX] = { \ + .name = (uint8_t const*)"HX", \ + .max_baud_rate = 6000000, \ + }, \ + [TYPE_TA] = { \ + .name = (uint8_t const*)"TA", \ + .max_baud_rate = 6000000, \ + .alt_divisors = true, \ + }, \ + [TYPE_TB] = { \ + .name = (uint8_t const*)"TB", \ + .max_baud_rate = 12000000, \ + .alt_divisors = true, \ + }, \ + [TYPE_HXD] = { \ + .name = (uint8_t const*)"HXD", \ + .max_baud_rate = 12000000, \ + }, \ + [TYPE_HXN] = { \ + .name = (uint8_t const*)"G (HXN)", \ + .max_baud_rate = 12000000, \ + .no_divisors = true, \ + } + +/* private data types */ +struct pl2303_serial_private { + const struct pl2303_type_data* type; + uint8_t quirks; +}; + +typedef struct TU_ATTR_PACKED { + struct pl2303_serial_private serial_private; + bool supports_hx_status; +} pl2303_private_t; + +/* buffer sizes for line coding data */ +#define PL2303_LINE_CODING_BUFSIZE 7 +#define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4 + +/* bulk endpoints */ +#define PL2303_OUT_EP 0x02 +#define PL2303_IN_EP 0x83 + +/* return values of pl2303_detect_type() */ +#define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 +#define PL2303_DETECT_TYPE_FAILED -2 + +#endif /* _PL2303_H_ */ diff --git a/src/tusb_option.h b/src/tusb_option.h index 281341685..f023b490a 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -504,6 +504,24 @@ { 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ #endif +#ifndef CFG_TUH_CDC_PL2303 + // PL2303 is not part of CDC class, only to re-use CDC driver API + #define CFG_TUH_CDC_PL2303 0 +#endif + +#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST + // List of product IDs that can use the PL2303 CDC driver + #define CFG_TUH_CDC_PL2303_VID_PID_LIST \ + { 0x067b, 0x2303 }, /* initial 2303 */ \ + { 0x067b, 0x2304 }, /* TB */ \ + { 0x067b, 0x23a3 }, /* GC */ \ + { 0x067b, 0x23b3 }, /* GB */ \ + { 0x067b, 0x23c3 }, /* GT */ \ + { 0x067b, 0x23d3 }, /* GL */ \ + { 0x067b, 0x23e3 }, /* GE */ \ + { 0x067b, 0x23f3 } /* GS */ +#endif + #ifndef CFG_TUH_HID #define CFG_TUH_HID 0 #endif From ea175a78aad5bd258954aa61550aae0162bc884b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 13:00:46 +0100 Subject: [PATCH 016/101] updated contribution, readme and some comments --- CONTRIBUTORS.rst | 7 +++++++ README.rst | 2 +- src/class/cdc/cdc_host.c | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 085f8082a..451ac0783 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -31,6 +31,13 @@ Notable contributors - Most features development +`Heiko Kuester `__ +-------------------------------------------- + +- Add CH34x and PL2303 support (CDC host) +- Improve FTDI and CP210x support (CDC host) + + `Hristo Gochkov `__ ------------------------------------------------- diff --git a/README.rst b/README.rst index fe2417451..6922c231e 100644 --- a/README.rst +++ b/README.rst @@ -77,7 +77,7 @@ Host Stack - Human Interface Device (HID): Keyboard, Mouse, Generic - Mass Storage Class (MSC) - Communication Device Class: CDC-ACM -- Vendor serial over USB: FTDI, CP210x +- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303 - Hub with multiple-level support Similar to the Device Stack, if you have a special requirement, `usbh_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 429d0a113..b35a8fd93 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -24,7 +24,7 @@ * This file is part of the TinyUSB stack. * * Contribution - * - Heiko Kuester: CH34x support + * - Heiko Kuester: add support of CH34x & PL2303, improve support of FTDI & CP210x */ #include "tusb_option.h" @@ -818,12 +818,12 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set config"); - // fake transfer to kick-off process + // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; - xfer.user_data = 0; // initial state + xfer.user_data = 0; // initial state 0 serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); return true; From 2b507dba4d9901d1208c4166bbc6026bb6062c9b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 24 Feb 2024 13:01:38 +0100 Subject: [PATCH 017/101] small changes & code style --- src/class/cdc/cdc_host.c | 236 ++++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 112 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b35a8fd93..50aa4b6f0 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -85,7 +85,7 @@ typedef struct { tuh_xfer_cb_t user_control_cb; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X - tuh_xfer_cb_t requested_complete_cb; + tuh_xfer_cb_t requested_complete_cb; #endif #if CFG_TUH_CDC_FTDI @@ -119,54 +119,54 @@ static cdch_interface_t cdch_data[CFG_TUH_CDC]; //--------------------------------------------------------------------+ //------------- ACM prototypes -------------// -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); -static void acm_process_config(tuh_xfer_t* xfer); +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +static void acm_process_config(tuh_xfer_t * xfer); -static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL -static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; + static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; #endif -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); -static void ftdi_process_config(tuh_xfer_t* xfer); +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); +static void ftdi_process_config(tuh_xfer_t * xfer); -static bool ftdi_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CP210X prototypes -------------// #if CFG_TUH_CDC_CP210X static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len); -static void cp210x_process_config(tuh_xfer_t* xfer); +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +static void cp210x_process_config(tuh_xfer_t * xfer); -static bool cp210x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- CH34x prototypes -------------// #if CFG_TUH_CDC_CH34X static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; -static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len); -static void ch34x_process_config(tuh_xfer_t* xfer); +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); +static void ch34x_process_config(tuh_xfer_t * xfer); -static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_modem_ctrl(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif //------------- PL2303 prototypes -------------// @@ -211,14 +211,14 @@ enum { typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; - bool (*const open)(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len); - void (*const process_set_config)(tuh_xfer_t* xfer); - bool (*const set_control_line_state)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_data_format)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_line_coding)(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); + void (*const process_set_config)(tuh_xfer_t * xfer); + bool (*const set_control_line_state)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + bool (*const set_line_coding)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - uint8_t const * name; + uint8_t const * name; #endif } cdch_serial_driver_t; @@ -309,17 +309,17 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t* get_itf(uint8_t idx) { +static inline cdch_interface_t * get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); - cdch_interface_t* p_cdc = &cdch_data[idx]; + cdch_interface_t * p_cdc = &cdch_data[idx]; return (p_cdc->daddr != 0) ? p_cdc : NULL; } static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr == daddr) && + cdch_interface_t * p_cdc = &cdch_data[i]; + if ((p_cdc->daddr == daddr) && (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr)) { return i; } @@ -328,10 +328,10 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { return TUSB_INDEX_INVALID_8; } -static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const *itf_desc) { +static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t const * itf_desc) { for(uint8_t i=0; idaddr = daddr; p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; @@ -345,7 +345,7 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const return NULL; } -static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep); +static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t const *desc_ep); //--------------------------------------------------------------------+ // APPLICATION API @@ -353,21 +353,21 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t c uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t* p_cdc = &cdch_data[i]; + const cdch_interface_t * p_cdc = &cdch_data[i]; if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; } return TUSB_INDEX_INVALID_8; } -bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { - cdch_interface_t* p_cdc = get_itf(idx); +bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t * info) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && info); info->daddr = p_cdc->daddr; // re-construct descriptor - tusb_desc_interface_t* desc = &info->desc; + tusb_desc_interface_t * desc = &info->desc; desc->bLength = sizeof(tusb_desc_interface_t); desc->bDescriptorType = TUSB_DESC_INTERFACE; @@ -383,27 +383,27 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info) { } bool tuh_cdc_mounted(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return p_cdc->mounted; } bool tuh_cdc_get_dtr(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; } bool tuh_cdc_get_rts(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; } -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) { - cdch_interface_t* p_cdc = get_itf(idx); +bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); *line_coding = p_cdc->line_coding; @@ -415,29 +415,29 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding) // Write //--------------------------------------------------------------------+ -uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { - cdch_interface_t* p_cdc = get_itf(idx); +uint32_t tuh_cdc_write(uint8_t idx, void const * buffer, uint32_t bufsize) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); } uint32_t tuh_cdc_write_flush(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); } bool tuh_cdc_write_clear(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_clear(&p_cdc->stream.tx); } uint32_t tuh_cdc_write_available(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_write_available(&p_cdc->stream.tx); @@ -447,33 +447,34 @@ uint32_t tuh_cdc_write_available(uint8_t idx) { // Read //--------------------------------------------------------------------+ -uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { - cdch_interface_t* p_cdc = get_itf(idx); +uint32_t tuh_cdc_read (uint8_t idx, void * buffer, uint32_t bufsize) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); } uint32_t tuh_cdc_read_available(uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_read_available(&p_cdc->stream.rx); } -bool tuh_cdc_peek(uint8_t idx, uint8_t* ch) { - cdch_interface_t* p_cdc = get_itf(idx); +bool tuh_cdc_peek(uint8_t idx, uint8_t * ch) { + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } bool tuh_cdc_read_clear (uint8_t idx) { - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + return ret; } @@ -657,7 +658,7 @@ void cdch_init(void) { tu_memclr(cdch_data, sizeof(cdch_data)); for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; + cdch_interface_t * p_cdc = &cdch_data[i]; tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, @@ -671,7 +672,7 @@ void cdch_init(void) { void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { - cdch_interface_t* p_cdc = &cdch_data[idx]; + cdch_interface_t * p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { TU_LOG_P_CDC("close"); @@ -695,35 +696,37 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc); - if ( ep_addr == p_cdc->stream.tx.ep_addr ) { + if (ep_addr == p_cdc->stream.tx.ep_addr) { // invoke tx complete callback to possibly refill tx fifo if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { + if (0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); } - } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { + } else if (ep_addr == p_cdc->stream.rx.ep_addr) { #if CFG_TUH_CDC_FTDI if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { // FTDI reserve 2 bytes for status // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; tu_edpt_stream_read_xfer_complete_offset(&p_cdc->stream.rx, xferred_bytes, 2); - }else + } else #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); } // invoke receive callback - if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); + } // prepare for next transfer if needed tu_edpt_stream_read_xfer(&p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) { + } else if (ep_addr == p_cdc->ep_notif) { // TODO handle notification endpoint - }else { + } else { TU_ASSERT(false); } @@ -734,7 +737,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t const* desc_ep) { +static bool open_ep_stream_pair(cdch_interface_t * p_cdc, tusb_desc_endpoint_t const * desc_ep) { for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); @@ -746,13 +749,13 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); } - desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); + desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(desc_ep); } return true; } -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { (void) rhport; cdch_serial_driver_t const * driver_detected = NULL; @@ -826,6 +829,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.user_data = 0; // initial state 0 serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + return true; } @@ -864,7 +868,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -886,15 +890,16 @@ static bool acm_set_control_line_state(cdch_interface_t* p_cdc, tuh_xfer_cb_t co .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, .user_data = user_data }; TU_ASSERT(tuh_control_xfer(&xfer)); + return true; } -static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || @@ -913,30 +918,32 @@ static bool acm_set_line_coding(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_ }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t* enum_buf = usbh_get_enum_buf(); + uint8_t * enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; + tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, // complete_cb is NULL for sync call + .complete_cb = complete_cb ? acm_internal_control_complete : NULL, .user_data = user_data }; TU_ASSERT(tuh_control_xfer(&xfer)); + return true; } -static bool acm_set_data_format(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } -static bool acm_set_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -952,21 +959,22 @@ enum { CONFIG_ACM_COMPLETE, }; -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { - uint8_t const* p_desc_end = ((uint8_t const*) itf_desc) + max_len; +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { + uint8_t const * p_desc_end = ((uint8_t const *) itf_desc) + max_len; - cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); + p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// - uint8_t const* p_desc = tu_desc_next(itf_desc); + uint8_t const * p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const*) p_desc)->bmCapabilities; + p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } p_desc = tu_desc_next(p_desc); @@ -975,7 +983,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 // Open notification endpoint of control interface if any if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); p_cdc->ep_notif = desc_ep->bEndpointAddress; @@ -985,22 +993,22 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint1 //------------- Data Interface (if any) -------------// if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && - (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) { + (TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass)) { // next to endpoint descriptor p_desc = tu_desc_next(p_desc); // data endpoints expected to be in pairs - TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const*) p_desc)); + TU_ASSERT(open_ep_stream_pair(p_cdc, (tusb_desc_endpoint_t const *) p_desc)); } return true; } -static void acm_process_config(tuh_xfer_t* xfer) { +static void acm_process_config(tuh_xfer_t * xfer) { uintptr_t const state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); switch (state) { @@ -1814,8 +1822,9 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); //------------- Control Request -------------// -static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_t request, uint16_t value, - uint16_t index, uint8_t* buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8_t request, + uint16_t value, uint16_t index, uint8_t * buffer, uint16_t length, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1829,7 +1838,7 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ }; // use usbh enum buf since application variable does not live long enough - uint8_t* enum_buf = NULL; + uint8_t * enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1850,22 +1859,23 @@ static bool ch34x_set_request(cdch_interface_t* p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -static inline bool ch34x_control_out(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, +static inline bool ch34x_control_out(cdch_interface_t * p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); } -static inline bool ch34x_control_in(cdch_interface_t* p_cdc, uint8_t request, uint16_t value, uint16_t index, - uint8_t* buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ch34x_control_in(cdch_interface_t * p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t * buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data); } -static inline bool ch34x_write_reg(cdch_interface_t* p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ch34x_write_reg(cdch_interface_t * p_cdc, uint16_t reg, uint16_t reg_value, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } -//static bool ch34x_read_reg_request ( cdch_interface_t* p_cdc, uint16_t reg, +//static bool ch34x_read_reg_request ( cdch_interface_t * p_cdc, uint16_t reg, // uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) //{ // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); @@ -1907,8 +1917,8 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC("control complete success = %u", success); @@ -1997,17 +2007,17 @@ enum { CONFIG_CH34X_COMPLETE }; -static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uint16_t max_len) { +static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { // CH34x Interface includes 1 vendor interface + 2 bulk + 1 interrupt endpoints - TU_VERIFY (itf_desc->bNumEndpoints == 3); - TU_VERIFY (sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); + TU_VERIFY(itf_desc->bNumEndpoints == 3); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t* p_cdc = make_new_itf(daddr, itf_desc); - TU_VERIFY (p_cdc); + cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_CH34X; - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(itf_desc); + tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); // data endpoints expected to be in pairs TU_ASSERT(open_ep_stream_pair(p_cdc, desc_ep)); @@ -2023,11 +2033,11 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const* itf_desc, uin } static void ch34x_process_config(tuh_xfer_t* xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uintptr_t const state = xfer->user_data; + // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t* p_cdc = get_itf(idx); + cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); uint8_t buffer[2]; // TODO remove @@ -2035,7 +2045,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_READ_VERSION: p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); + ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2060,19 +2070,20 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, + CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2431,6 +2442,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u } static void pl2303_process_config(tuh_xfer_t * xfer) { + uintptr_t const state = xfer->user_data; // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); @@ -2440,7 +2452,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { uint8_t buf; int8_t type; - switch (xfer->user_data) { + switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_GET_DESC: From da93fcfc6dbe51ceb73e990aefea9c8d55d3fc94 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 15:09:25 +0100 Subject: [PATCH 018/101] improved TU_LOGs --- src/class/cdc/cdc_host.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 50aa4b6f0..f3fbe88ea 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,6 +50,7 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) +#define TU_LOG_RESULT(TXT,RESULT) TU_LOG_P_CDC(TXT " " #RESULT " = %s", RESULT ? "true" : "FALSE" ) #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ @@ -587,6 +588,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c if (ret && !complete_cb) { p_cdc->line_state = (uint8_t) line_state; } + TU_LOG_RESULT("set control line state", ret); return ret; } @@ -604,6 +606,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; } + TU_LOG_RESULT("set baudrate", ret); return ret; } @@ -627,6 +630,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; } + TU_LOG_RESULT("set data format", ret); return ret; } @@ -646,6 +650,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; } + TU_LOG_RESULT("set line coding", ret); return ret; } @@ -785,6 +790,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); + TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -794,7 +800,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); - TU_LOG_P_CDC("set config complete success = %u", success); + TU_LOG_RESULT("set config complete", success); if (success) { p_cdc->mounted = true; @@ -846,7 +852,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1131,7 +1137,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1407,7 +1413,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) break; } - TU_LOG_P_CDC("%s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + TU_LOG_P_CDC(" %s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -1554,7 +1560,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC("Baudrate divisor 0x%lu", div_value); + TU_LOG_P_CDC(" Baudrate divisor 0x%lu", div_value); return div_value; } @@ -1663,7 +1669,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch(xfer->setup->bRequest) { @@ -1920,7 +1926,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2051,7 +2057,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_P_CDC("Chip Version = %02x", version); + TU_LOG_P_CDC(" Chip Version = %02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); @@ -2337,7 +2343,7 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC("control complete success = %u", success); + TU_LOG_RESULT(" control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2743,7 +2749,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } @@ -2893,7 +2899,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303 } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC("real baudrate = %lu", baud); + TU_LOG_P_CDC(" real baudrate = %lu", baud); return true; } From 46a861b0e31a7382d620986079abd0c373dfe6da Mon Sep 17 00:00:00 2001 From: IngHK Date: Fri, 23 Feb 2024 08:30:50 +0100 Subject: [PATCH 019/101] improved PL2303 TU_LOGs --- src/class/cdc/cdc_host.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f3fbe88ea..9d27b1e79 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2486,13 +2486,14 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG(CFG_TUH_CDC_LOG_LEVEL, "PL2303 bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, + desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG(CFG_TUH_CDC_LOG_LEVEL, " vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { From f97e31226a959944785122d4c0c10d4b3304704c Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:07:40 +0100 Subject: [PATCH 020/101] FTDI fixed itf_num and some improvement --- src/class/cdc/cdc_host.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 9d27b1e79..33d201c07 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1140,22 +1140,19 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { TU_LOG_RESULT(" control complete", success); if (success) { - switch (xfer->setup->bRequest) { - case FTDI_SIO_SET_MODEM_CTRL_REQUEST: - p_cdc->line_state = p_cdc->requested_line_state; - break; - - case FTDI_SIO_SET_DATA_REQUEST: - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; - break; - - case FTDI_SIO_SET_BAUDRATE_REQUEST: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; - break; - - default: break; + if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { + p_cdc->line_state = p_cdc->requested_line_state; + } + if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { + p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; + p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; + p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + } + if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && + xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { + p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; } } @@ -1180,7 +1177,10 @@ static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c } static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = ftdi_get_idx(xfer); + cdch_interface_t * p_cdc = get_itf(idx); + TU_ASSERT(p_cdc,); + uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format ftdi_internal_control_complete); // control complete function to be called after request @@ -1413,7 +1413,8 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) break; } - TU_LOG_P_CDC(" %s detected", ftdi_chip_name[p_cdc->ftdi.chip_type]); + TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", + ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev[idx]->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); } From d3d61da0384d066b9930e8e5b658717983f02efb Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 25 Feb 2024 17:20:02 +0100 Subject: [PATCH 021/101] improved & fixed compiler warnings device descriptor handling --- src/class/cdc/cdc_host.c | 44 +++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 33d201c07..c222e11db 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -111,8 +111,10 @@ typedef struct { CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; + #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - static tusb_desc_device_t desc_dev[CFG_TUH_CDC][CFG_TUH_ENUMERATION_BUFSIZE]; + CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN + static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; #endif //--------------------------------------------------------------------+ @@ -1054,7 +1056,7 @@ static void acm_process_config(tuh_xfer_t * xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx); +static bool ftdi_determine_type(cdch_interface_t * p_cdc); static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); @@ -1255,7 +1257,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { // get device descriptor p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); break; } @@ -1264,7 +1266,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { - TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc, idx)); + TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); @@ -1334,9 +1336,9 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { //------------- Helper -------------// -static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) +static bool ftdi_determine_type(cdch_interface_t * p_cdc) { - uint16_t const version = desc_dev[idx]->bcdDevice; + uint16_t const version = desc_dev->bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; p_cdc->ftdi.chip_type = UNKNOWN; @@ -1414,7 +1416,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc, uint8_t const idx) } TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", - ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev[idx]->bcdDevice); + ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -2207,7 +2209,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); @@ -2465,13 +2467,13 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_GET_DESC: p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config // get device descriptor - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, desc_dev[idx], sizeof(tusb_desc_device_t), + TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type (p_cdc, idx, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 + type = pl2303_detect_type (p_cdc, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; @@ -2482,14 +2484,14 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { // get supports_hx_status, type and quirks (step 2), do special read p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); - type = pl2303_detect_type (p_cdc, idx, 2, NULL, 0); // step 2 now with supports_hx_status + type = pl2303_detect_type (p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev[idx]->bDeviceClass, desc_dev[idx]->bMaxPacketSize0, - desc_dev[idx]->bcdUSB, desc_dev[idx]->bcdDevice ); + desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, + desc_dev->bcdUSB, desc_dev->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", @@ -2674,29 +2676,29 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data ) { /* * Legacy PL2303H, variants 0 and 1 (difference unknown). */ - if (desc_dev[idx]->bDeviceClass == 0x02) { + if (desc_dev->bDeviceClass == 0x02) { return TYPE_H; /* variant 0 */ } - if (desc_dev[idx]->bMaxPacketSize0 != 0x40) { - if (desc_dev[idx]->bDeviceClass == 0x00 || desc_dev[idx]->bDeviceClass == 0xff) { + if (desc_dev->bMaxPacketSize0 != 0x40) { + if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { return TYPE_H; /* variant 1 */ } return TYPE_H; /* variant 0 */ } - switch (desc_dev[idx]->bcdUSB) { + switch (desc_dev->bcdUSB) { case 0x101: /* USB 1.0.1? Let's assume they meant 1.1... */ TU_ATTR_FALLTHROUGH; case 0x110: - switch (desc_dev[idx]->bcdDevice) { + switch (desc_dev->bcdDevice) { case 0x300: return TYPE_HX; case 0x400: @@ -2706,7 +2708,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui } break; case 0x200: - switch (desc_dev[idx]->bcdDevice) { + switch (desc_dev->bcdDevice) { case 0x100: /* GC */ case 0x105: return TYPE_HXN; @@ -2751,7 +2753,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t const idx, ui default: break; } - TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev[idx]->bcdUSB); + TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } From edf13203916931962a53af50abc548dd3eded278 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:13:18 +0100 Subject: [PATCH 022/101] removed expendable ACM check --- src/class/cdc/cdc_host.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index c222e11db..4d2134f9d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -909,7 +909,6 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_VERIFY(p_cdc->requested_line_coding.data_bits && p_cdc->requested_line_coding.bit_rate); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || p_cdc->requested_line_coding.data_bits == 16); From 3cf9cb98e630a0cb26bc28a2e4c67fb6df19a884 Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:15:37 +0100 Subject: [PATCH 023/101] small PL2303 improvements --- src/class/cdc/cdc_host.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4d2134f9d..130993547 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2292,9 +2292,10 @@ static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comp * even to the same values as before. Thus we actually need to filter * in this specific case. */ - // TODO really necessary to check? what to do in this case when no transfer will happen? - // callback is not called... - TU_VERIFY(memcmp(&p_cdc->requested_line_coding, &p_cdc->line_coding, sizeof(cdc_line_coding_t) ) != 0); + TU_VERIFY(p_cdc->requested_line_coding.data_bits != p_cdc->line_coding.data_bits || + p_cdc->requested_line_coding.stop_bits != p_cdc->line_coding.stop_bits || + p_cdc->requested_line_coding.parity != p_cdc->line_coding.parity || + p_cdc->requested_line_coding.bit_rate != p_cdc->line_coding.bit_rate ); /* For reference buf[6] data bits value */ TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); From e7308e313a1fb5482dbbb34cdfc6b7b11a54fd6b Mon Sep 17 00:00:00 2001 From: IngHK Date: Wed, 28 Feb 2024 13:28:38 +0100 Subject: [PATCH 024/101] improved TU_LOGs --- src/class/cdc/cdc.h | 12 ++++++++ src/class/cdc/cdc_host.c | 65 ++++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 5cbd658fe..b1dca1ad8 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -192,6 +192,11 @@ typedef enum { CDC_LINE_CODING_STOP_BITS_2 = 2, // 2 bits } cdc_line_coding_stopbits_t; +#define CDC_LINE_CODING_STOP_BITS_TEXT(STOP_BITS) ( \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_1 ? "1" : \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_1_5 ? "1.5" : \ + STOP_BITS == CDC_LINE_CODING_STOP_BITS_2 ? "2" : "?" ) + // TODO Backward compatible for typos. Maybe removed in the future release #define CDC_LINE_CONDING_STOP_BITS_1 CDC_LINE_CODING_STOP_BITS_1 #define CDC_LINE_CONDING_STOP_BITS_1_5 CDC_LINE_CODING_STOP_BITS_1_5 @@ -205,6 +210,13 @@ typedef enum { CDC_LINE_CODING_PARITY_SPACE = 4, } cdc_line_coding_parity_t; +#define CDC_LINE_CODING_PARITY_CHAR(PARITY) ( \ + PARITY == CDC_LINE_CODING_PARITY_NONE ? 'N' : \ + PARITY == CDC_LINE_CODING_PARITY_ODD ? 'O' : \ + PARITY == CDC_LINE_CODING_PARITY_EVEN ? 'E' : \ + PARITY == CDC_LINE_CODING_PARITY_MARK ? 'M' : \ + PARITY == CDC_LINE_CODING_PARITY_SPACE ? 'S' : '?' ) + //--------------------------------------------------------------------+ // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 130993547..d2bc63d64 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,7 +50,7 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_RESULT(TXT,RESULT) TU_LOG_P_CDC(TXT " " #RESULT " = %s", RESULT ? "true" : "FALSE" ) +#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %s", VAL ? "true" : "false" ) #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ @@ -395,14 +395,20 @@ bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false; + bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR); +// TU_LOG_P_CDC_BOOL("get DTR", ret); + + return ret; } bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false; + bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS); +// TU_LOG_P_CDC_BOOL("get RTS", ret); + + return ret; } bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) { @@ -410,6 +416,10 @@ bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) TU_VERIFY(p_cdc); *line_coding = p_cdc->line_coding; + TU_LOG_P_CDC("get line coding %lu %u%c%s", + p_cdc->line_coding.bit_rate, p_cdc->line_coding.data_bits, + CDC_LINE_CODING_PARITY_CHAR(p_cdc->line_coding.parity), + CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); return true; } @@ -590,7 +600,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c if (ret && !complete_cb) { p_cdc->line_state = (uint8_t) line_state; } - TU_LOG_RESULT("set control line state", ret); +// TU_LOG_P_CDC_BOOL("set control line state", ret); return ret; } @@ -598,7 +608,7 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set baudrate = %lu", baudrate); + TU_LOG_P_CDC("set baudrate %lu", baudrate); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -608,7 +618,7 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete if (ret && !complete_cb) { p_cdc->line_coding.bit_rate = baudrate; } - TU_LOG_RESULT("set baudrate", ret); +// TU_LOG_P_CDC_BOOL("set baudrate", ret); return ret; } @@ -617,8 +627,9 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set data format data_bits = %u parity = %u stop_bits = %u (indexes!)", - data_bits, parity, stop_bits); + TU_LOG_P_CDC("set data format %u%c%s", + data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), + CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.stop_bits = stop_bits; @@ -632,7 +643,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->line_coding.parity = parity; p_cdc->line_coding.data_bits = data_bits; } - TU_LOG_RESULT("set data format", ret); +// TU_LOG_P_CDC_BOOL("set data format", ret); return ret; } @@ -641,8 +652,10 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set line coding baudrate = %lu data_bits = %u parity = %u stop_bits = %u (indexes!)", - line_coding->bit_rate, line_coding->data_bits, line_coding->parity, line_coding->stop_bits); + TU_LOG_P_CDC("set line coding %lu %u%c%s", + line_coding->bit_rate, line_coding->data_bits, + CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), + CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; @@ -652,7 +665,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, if (ret && !complete_cb) { p_cdc->line_coding = *line_coding; } - TU_LOG_RESULT("set line coding", ret); +// TU_LOG_P_CDC_BOOL("set line coding", ret); return ret; } @@ -792,7 +805,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); - TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); +// TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -802,7 +815,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); - TU_LOG_RESULT("set config complete", success); + TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { p_cdc->mounted = true; @@ -854,7 +867,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1138,7 +1151,7 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1414,7 +1427,7 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC(" %s detected (bcdDevice = 0x%04x)", + TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); return (p_cdc->ftdi.chip_type != UNKNOWN); @@ -1562,7 +1575,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) break; } - TU_LOG_P_CDC(" Baudrate divisor 0x%lu", div_value); + TU_LOG_P_CDC("Baudrate divisor = 0x%lu", div_value); return div_value; } @@ -1671,7 +1684,7 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch(xfer->setup->bRequest) { @@ -1928,7 +1941,7 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2059,7 +2072,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_P_CDC(" Chip Version = %02x", version); + TU_LOG_P_CDC("Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD TU_ASSERT_COMPLETE(version >= 0x30); @@ -2346,7 +2359,7 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); TU_ASSERT(p_cdc,); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_RESULT(" control complete", success); + TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2489,12 +2502,12 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG_P_CDC(" bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, desc_dev->bcdUSB, desc_dev->bcdDevice ); uint16_t vid, pid; TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC(" vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", vid, pid, p_cdc->pl2303.supports_hx_status, p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif @@ -2753,7 +2766,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, default: break; } - TU_LOG_P_CDC(" unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); return PL2303_DETECT_TYPE_FAILED; } @@ -2903,7 +2916,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303 } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC(" real baudrate = %lu", baud); + TU_LOG_P_CDC("real baudrate %lu", baud); return true; } From e6d27b6d3e8fc928cc00ab08898243c7e037ba35 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 29 Feb 2024 20:19:35 +0100 Subject: [PATCH 025/101] fixed IAR compile error --- src/class/cdc/cdc_host.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d2bc63d64..dfe078de4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -113,7 +113,6 @@ CFG_TUH_MEM_SECTION static cdch_interface_t cdch_data[CFG_TUH_CDC]; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; #endif From dea27d28bceeaaa23d3daa6468373cb536390108 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 29 Feb 2024 20:24:13 +0100 Subject: [PATCH 026/101] added explicite (uint16_t) casts inside tu_htole16() --- src/class/cdc/cdc_host.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index dfe078de4..d71cda124 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -932,8 +932,8 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete }, .bRequest = CDC_REQUEST_SET_LINE_CODING, .wValue = 0, - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), - .wLength = tu_htole16(sizeof(cdc_line_coding_t)) + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), + .wLength = tu_htole16((uint16_t) sizeof(cdc_line_coding_t)) }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough @@ -1612,7 +1612,7 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 }, .bRequest = command, .wValue = tu_htole16(value), - .wIndex = tu_htole16(p_cdc->bInterfaceNumber), + .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = tu_htole16(length) }; @@ -1852,9 +1852,9 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 .direction = direction & 0x01u }, .bRequest = request, - .wValue = tu_htole16 (value), - .wIndex = tu_htole16 (index), - .wLength = tu_htole16 (length) + .wValue = tu_htole16(value), + .wIndex = tu_htole16(index), + .wLength = tu_htole16(length) }; // use usbh enum buf since application variable does not live long enough @@ -2232,9 +2232,9 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ tusb_control_request_t const request_setup = { .bmRequestType = requesttype, .bRequest = request, - .wValue = tu_htole16 (value), - .wIndex = tu_htole16 (index), - .wLength = tu_htole16 (length) + .wValue = tu_htole16(value), + .wIndex = tu_htole16(index), + .wLength = tu_htole16(length) }; // use usbh enum buf since application variable does not live long enough From e0551043ca8a6b3be92fed57f5e34d6d8014406b Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:02:58 +0100 Subject: [PATCH 027/101] added use of cdc_line_control_state_t type in CDCh --- src/class/cdc/cdc.h | 14 +++++++----- src/class/cdc/cdc_device.c | 2 ++ src/class/cdc/cdc_host.c | 45 ++++++++++++++++---------------------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index b1dca1ad8..10aed79ab 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -414,15 +414,17 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); -typedef struct TU_ATTR_PACKED +typedef union TU_ATTR_PACKED { - uint16_t dtr : 1; - uint16_t rts : 1; - uint16_t : 6; - uint16_t : 8; + struct { + uint8_t dtr : 1; + uint8_t rts : 1; + uint8_t : 6; + }; + uint8_t all; } cdc_line_control_state_t; -TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); +TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct"); TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index c26264e60..9f51a6d4b 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -56,6 +56,7 @@ typedef struct uint8_t ep_out; // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) + // TODO use cdc_line_control_state_t instead of uint8_t uint8_t line_state; /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -124,6 +125,7 @@ bool tud_cdc_n_connected(uint8_t itf) } uint8_t tud_cdc_n_get_line_state (uint8_t itf) +// TODO use cdc_line_control_state_t instead of uint8_t { return _cdcd_itf[itf].line_state; } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d71cda124..a3407a5f9 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -81,8 +81,8 @@ typedef struct { TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; // 1 byte padding - uint8_t line_state; // DTR (bit0), RTS (bit1) - uint8_t requested_line_state; + cdc_line_control_state_t line_state; + cdc_line_control_state_t requested_line_state; tuh_xfer_cb_t user_control_cb; #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X @@ -339,7 +339,7 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state = 0; + p_cdc->line_state.all = 0; return p_cdc; } } @@ -394,7 +394,7 @@ bool tuh_cdc_get_dtr(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR); + bool ret = p_cdc->line_state.dtr; // TU_LOG_P_CDC_BOOL("get DTR", ret); return ret; @@ -404,7 +404,7 @@ bool tuh_cdc_get_rts(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - bool ret = (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS); + bool ret = p_cdc->line_state.rts; // TU_LOG_P_CDC_BOOL("get RTS", ret); return ret; @@ -592,12 +592,12 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_LOG_P_CDC("set control line state line_state = %u", line_state); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state = (uint8_t) line_state; + p_cdc->requested_line_state.all = (uint8_t) line_state; bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = (uint8_t) line_state; + p_cdc->line_state.all = (uint8_t) line_state; } // TU_LOG_P_CDC_BOOL("set control line state", ret); @@ -898,7 +898,7 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16(p_cdc->requested_line_state), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.all), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -1034,7 +1034,7 @@ static void acm_process_config(tuh_xfer_t * xfer) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } @@ -1139,7 +1139,7 @@ static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // FTDI has the same bit coding return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - p_cdc->requested_line_state, p_cdc->ftdi.channel, complete_cb, user_data); + p_cdc->requested_line_state.all, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// @@ -1328,7 +1328,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1670,7 +1670,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | - (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state), + (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state.all), NULL, 0, complete_cb, user_data); } @@ -1811,7 +1811,7 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -1916,16 +1916,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t com } static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = 0; - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_RTS) { - control |= CH34X_BIT_RTS; - } - if (p_cdc->requested_line_state & CDC_CONTROL_LINE_STATE_DTR) { - control |= CH34X_BIT_DTR; - } - - // CH34x signals are inverted - control = ~control; + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | // CH34x signals are inverted + (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -2101,7 +2093,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2287,8 +2279,9 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_ static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2645,7 +2638,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); break; #else From a9cc07fc83599fab4d9576e6f5b793bc1bf2bf35 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 10 Mar 2024 08:20:12 +0100 Subject: [PATCH 028/101] added line control function using cdc_line_control_state_t --- src/class/cdc/cdc_host.c | 35 ++++++++++++++++++++++++++++++----- src/class/cdc/cdc_host.h | 10 ++++++++-- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index a3407a5f9..86b874b1e 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -50,8 +50,9 @@ DADDR, ITF_NUM, NAME, ##__VA_ARGS__) #define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %s", VAL ? "true" : "false" ) +#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) +// assert and set config complete #define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ do { \ if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ @@ -586,24 +587,48 @@ static bool set_function_call ( } } -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // uses cdc_line_control_state_t union for line_state cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state line_state = %u", line_state); + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts ); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state.all = (uint8_t) line_state; + p_cdc->requested_line_state = line_state; bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state.all = (uint8_t) line_state; + p_cdc->line_state = line_state; } // TU_LOG_P_CDC_BOOL("set control line state", ret); return ret; } +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) + + return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .all = (uint8_t) line_state }, + complete_cb, user_data); +} + +bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t * p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdc_line_control_state_t const line_state = { .dtr = dtr_state, .rts = p_cdc->line_state.rts }; + + return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); +} + +bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdch_interface_t * p_cdc = get_itf(idx); + TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + cdc_line_control_state_t const line_state = { .rts = rts_state, .dtr = p_cdc->line_state.dtr }; + + return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); +} + bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index ca6567453..77081d3b0 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -132,8 +132,14 @@ bool tuh_cdc_read_clear (uint8_t idx); // - The function will return true if transfer is successful, false otherwise. //--------------------------------------------------------------------+ -// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); +// Request to Set Control Line State +bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, // uses cdc_line_control_state_t union for line_state + tuh_xfer_cb_t complete_cb, uintptr_t user_data); +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, // uses uint16_t for line_state (legacy function) + tuh_xfer_cb_t complete_cb, uintptr_t user_data); // DTR (bit 0), RTS (bit 1) + +bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set DTR +bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set RTS // Request to set baudrate bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); From ee92e582b38e36df53381f8c98a0be54c2caef3e Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:12:10 +0100 Subject: [PATCH 029/101] added defines CFG_TUH_CDC_DTR_CONTROL_ON_ENUM & CFG_TUH_CDC_RTS_CONTROL_ON_ENUM --- examples/host/cdc_msc_hid/src/tusb_config.h | 4 +- .../cdc_msc_hid_freertos/src/tusb_config.h | 4 +- src/class/cdc/cdc_host.c | 40 ++++++++++++++----- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index fc956c6d3..32a29bd4f 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -121,8 +121,8 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index dd732c700..88b341e95 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -126,8 +126,8 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -// DTR ( bit 0), RTS (bit 1) -#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0x03 +#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 86b874b1e..5b74d031d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -63,6 +63,26 @@ #define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) +// handle line control defines +#if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ + (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) + TU_VERIFY_STATIC(false, "Contradictory line control defines"); +#endif + +#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #define LINE_CONTROL_ON_ENUM CFG_TUH_CDC_LINE_CONTROL_ON_ENUM +#elif defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM) + #ifndef CFG_TUH_CDC_DTR_CONTROL_ON_ENUM + #define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM 0 + #endif + #ifndef CFG_TUH_CDC_RTS_CONTROL_ON_ENUM + #define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM 0 + #endif + #define LINE_CONTROL_ON_ENUM ( ( CFG_TUH_CDC_DTR_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_DTR : 0 ) | \ + ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) +#endif + + //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -1057,9 +1077,9 @@ static void acm_process_config(tuh_xfer_t * xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + #ifdef LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); break; } @@ -1352,8 +1372,8 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1835,8 +1855,8 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { #endif case CONFIG_CP210X_SET_DTR_RTS: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -2117,8 +2137,8 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2662,8 +2682,8 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); break; #else From 2786a61e8b9811b1065cf1f36502eb4744e9d772 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:25:04 +0100 Subject: [PATCH 030/101] fixed FTDI set control line --- src/class/cdc/cdc_host.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5b74d031d..6121e59f0 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -82,7 +82,6 @@ ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) #endif - //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -1172,19 +1171,21 @@ static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t value = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) | // data bit quantity is stored in bits 0-3 - ((uint32_t) p_cdc->requested_line_coding.parity & 0x7) << 8 | // parity is stored in bits 8-10, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3) << 11 ); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) | // data bit quantity is stored in bits 0-3 + ((uint32_t) p_cdc->requested_line_coding.parity & 0x7u) << 8 | // parity is stored in bits 8-10, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3u) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); } static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // FTDI has the same bit coding + uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? (uint32_t) FTDI_SIO_SET_DTR_HIGH : (uint32_t) FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line_state.rts ? (uint32_t) FTDI_SIO_SET_RTS_HIGH : (uint32_t) FTDI_SIO_SET_RTS_LOW)); + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - p_cdc->requested_line_state.all, p_cdc->ftdi.channel, complete_cb, user_data); + value, p_cdc->ftdi.channel, complete_cb, user_data); } //------------- Driver API -------------// @@ -1704,9 +1705,9 @@ static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); uint16_t lcr = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xf) << 8 | // data bit quantity is stored in bits 8-11 - ((uint32_t) p_cdc->requested_line_coding.parity & 0xf) << 4 | // parity is stored in bits 4-7, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xf)); // parity is stored in bits 0-3, same coding + ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) << 8 | // data bit quantity is stored in bits 8-11 + ((uint32_t) p_cdc->requested_line_coding.parity & 0xfu) << 4 | // parity is stored in bits 4-7, same coding + ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xfu)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } From cb69ed0d0423b8e09ae77307fcc01165ae4c9386 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 21 Mar 2024 08:29:28 +0100 Subject: [PATCH 031/101] code style and clean up CDC serial header files --- src/class/cdc/serial/ch34x.h | 70 ++++++------- src/class/cdc/serial/cp210x.h | 86 ++++++++-------- src/class/cdc/serial/ftdi_sio.h | 172 ++++++++++++++++---------------- src/class/cdc/serial/pl2303.h | 120 +++++++++++----------- 4 files changed, 224 insertions(+), 224 deletions(-) diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index c18066f57..7d91f01fe 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _CH34X_H_ -#define _CH34X_H_ +#ifndef TUSB_CH34X_H +#define TUSB_CH34X_H // There is no official documentation for the CH34x (CH340, CH341) chips. Reference can be found // - https://github.com/WCHSoftGroup/ch341ser_linux @@ -40,45 +40,45 @@ #endif // USB requests -#define CH34X_REQ_READ_VERSION 0x5F // dec 95 -#define CH34X_REQ_WRITE_REG 0x9A // dec 154 -#define CH34X_REQ_READ_REG 0x95 // dec 149 -#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 -#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 +#define CH34X_REQ_READ_VERSION 0x5F // dec 95 +#define CH34X_REQ_WRITE_REG 0x9A // dec 154 +#define CH34X_REQ_READ_REG 0x95 // dec 149 +#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161 +#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164 // registers -#define CH34X_REG_BREAK 0x05 -#define CH34X_REG_PRESCALER 0x12 -#define CH34X_REG_DIVISOR 0x13 -#define CH34X_REG_LCR 0x18 -#define CH34X_REG_LCR2 0x25 -#define CH34X_REG_MCR_MSR 0x06 -#define CH34X_REG_MCR_MSR2 0x07 -#define CH34X_NBREAK_BITS 0x01 +#define CH34X_REG_BREAK 0x05 +#define CH34X_REG_PRESCALER 0x12 +#define CH34X_REG_DIVISOR 0x13 +#define CH34X_REG_LCR 0x18 +#define CH34X_REG_LCR2 0x25 +#define CH34X_REG_MCR_MSR 0x06 +#define CH34X_REG_MCR_MSR2 0x07 +#define CH34X_NBREAK_BITS 0x01 -#define CH341_REG_0x0F 0x0F // undocumented register -#define CH341_REG_0x2C 0x2C // undocumented register -#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) +#define CH341_REG_0x0F 0x0F // undocumented register +#define CH341_REG_0x2C 0x2C // undocumented register +#define CH341_REG_0x27 0x27 // hardware flow control (cts/rts) -#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) -#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) +#define CH34X_REG16_DIVISOR_PRESCALER TU_U16(CH34X_REG_DIVISOR, CH34X_REG_PRESCALER) +#define CH32X_REG16_LCR2_LCR TU_U16(CH34X_REG_LCR2, CH34X_REG_LCR) // modem control bits -#define CH34X_BIT_RTS ( 1 << 6 ) -#define CH34X_BIT_DTR ( 1 << 5 ) +#define CH34X_BIT_RTS (1 << 6) +#define CH34X_BIT_DTR (1 << 5) // line control bits -#define CH34X_LCR_ENABLE_RX 0x80 -#define CH34X_LCR_ENABLE_TX 0x40 -#define CH34X_LCR_MARK_SPACE 0x20 -#define CH34X_LCR_PAR_EVEN 0x10 -#define CH34X_LCR_ENABLE_PAR 0x08 -#define CH34X_LCR_PAR_MASK 0x38 // all parity bits -#define CH34X_LCR_STOP_BITS_2 0x04 -#define CH34X_LCR_CS8 0x03 -#define CH34X_LCR_CS7 0x02 -#define CH34X_LCR_CS6 0x01 -#define CH34X_LCR_CS5 0x00 -#define CH34X_LCR_CS_MASK 0x03 // all CSx bits +#define CH34X_LCR_ENABLE_RX 0x80 +#define CH34X_LCR_ENABLE_TX 0x40 +#define CH34X_LCR_MARK_SPACE 0x20 +#define CH34X_LCR_PAR_EVEN 0x10 +#define CH34X_LCR_ENABLE_PAR 0x08 +#define CH34X_LCR_PAR_MASK 0x38 // all parity bits +#define CH34X_LCR_STOP_BITS_2 0x04 +#define CH34X_LCR_CS8 0x03 +#define CH34X_LCR_CS7 0x02 +#define CH34X_LCR_CS6 0x01 +#define CH34X_LCR_CS5 0x00 +#define CH34X_LCR_CS_MASK 0x03 // all CSx bits -#endif /* _CH34X_H_ */ +#endif // TUSB_CH34X_H diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index e18da7d51..a553a54da 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -31,7 +31,7 @@ // parts are overtaken from vendors driver // https://www.silabs.com/documents/public/software/cp210x-3.1.0.tar.gz -/* Config request codes */ +// Config request codes #define CP210X_IFC_ENABLE 0x00 #define CP210X_SET_BAUDDIV 0x01 #define CP210X_GET_BAUDDIV 0x02 @@ -60,56 +60,56 @@ #define CP210X_SET_BAUDRATE 0x1E #define CP210X_VENDOR_SPECIFIC 0xFF // GPIO, Recipient must be Device -/* SILABSER_IFC_ENABLE_REQUEST_CODE */ -#define CP210X_UART_ENABLE 0x0001 -#define CP210X_UART_DISABLE 0x0000 +// SILABSER_IFC_ENABLE_REQUEST_CODE +#define CP210X_UART_ENABLE 0x0001 +#define CP210X_UART_DISABLE 0x0000 -/* SILABSER_SET_BAUDDIV_REQUEST_CODE */ -#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 +// SILABSER_SET_BAUDDIV_REQUEST_CODE +#define CP210X_BAUD_RATE_GEN_FREQ 0x384000 -/*SILABSER_SET_LINE_CTL_REQUEST_CODE */ -#define CP210X_BITS_DATA_MASK 0x0f00 -#define CP210X_BITS_DATA_5 0x0500 -#define CP210X_BITS_DATA_6 0x0600 -#define CP210X_BITS_DATA_7 0x0700 -#define CP210X_BITS_DATA_8 0x0800 -#define CP210X_BITS_DATA_9 0x0900 +// SILABSER_SET_LINE_CTL_REQUEST_CODE +#define CP210X_BITS_DATA_MASK 0x0f00 +#define CP210X_BITS_DATA_5 0x0500 +#define CP210X_BITS_DATA_6 0x0600 +#define CP210X_BITS_DATA_7 0x0700 +#define CP210X_BITS_DATA_8 0x0800 +#define CP210X_BITS_DATA_9 0x0900 -#define CP210X_BITS_PARITY_MASK 0x00f0 -#define CP210X_BITS_PARITY_NONE 0x0000 -#define CP210X_BITS_PARITY_ODD 0x0010 -#define CP210X_BITS_PARITY_EVEN 0x0020 -#define CP210X_BITS_PARITY_MARK 0x0030 -#define CP210X_BITS_PARITY_SPACE 0x0040 +#define CP210X_BITS_PARITY_MASK 0x00f0 +#define CP210X_BITS_PARITY_NONE 0x0000 +#define CP210X_BITS_PARITY_ODD 0x0010 +#define CP210X_BITS_PARITY_EVEN 0x0020 +#define CP210X_BITS_PARITY_MARK 0x0030 +#define CP210X_BITS_PARITY_SPACE 0x0040 -#define CP210X_BITS_STOP_MASK 0x000f -#define CP210X_BITS_STOP_1 0x0000 -#define CP210X_BITS_STOP_1_5 0x0001 -#define CP210X_BITS_STOP_2 0x0002 +#define CP210X_BITS_STOP_MASK 0x000f +#define CP210X_BITS_STOP_1 0x0000 +#define CP210X_BITS_STOP_1_5 0x0001 +#define CP210X_BITS_STOP_2 0x0002 -/* SILABSER_SET_BREAK_REQUEST_CODE */ -#define CP210X_BREAK_ON 0x0001 -#define CP210X_BREAK_OFF 0x0000 +// SILABSER_SET_BREAK_REQUEST_CODE +#define CP210X_BREAK_ON 0x0001 +#define CP210X_BREAK_OFF 0x0000 -/* SILABSER_SET_MHS_REQUEST_CODE */ -#define CP210X_MCR_DTR 0x0001 -#define CP210X_MCR_RTS 0x0002 -#define CP210X_MCR_ALL 0x0003 -#define CP210X_MSR_CTS 0x0010 -#define CP210X_MSR_DSR 0x0020 -#define CP210X_MSR_RING 0x0040 -#define CP210X_MSR_DCD 0x0080 -#define CP210X_MSR_ALL 0x00F0 +// SILABSER_SET_MHS_REQUEST_CODE +#define CP210X_MCR_DTR 0x0001 +#define CP210X_MCR_RTS 0x0002 +#define CP210X_MCR_ALL 0x0003 +#define CP210X_MSR_CTS 0x0010 +#define CP210X_MSR_DSR 0x0020 +#define CP210X_MSR_RING 0x0040 +#define CP210X_MSR_DCD 0x0080 +#define CP210X_MSR_ALL 0x00F0 -#define CP210X_CONTROL_WRITE_DTR 0x0100 -#define CP210X_CONTROL_WRITE_RTS 0x0200 +#define CP210X_CONTROL_WRITE_DTR 0x0100 +#define CP210X_CONTROL_WRITE_RTS 0x0200 -#define CP210X_LSR_BREAK 0x0001 -#define CP210X_LSR_FRAMING_ERROR 0x0002 -#define CP210X_LSR_HW_OVERRUN 0x0004 -#define CP210X_LSR_QUEUE_OVERRUN 0x0008 -#define CP210X_LSR_PARITY_ERROR 0x0010 -#define CP210X_LSR_ALL 0x001F +#define CP210X_LSR_BREAK 0x0001 +#define CP210X_LSR_FRAMING_ERROR 0x0002 +#define CP210X_LSR_HW_OVERRUN 0x0004 +#define CP210X_LSR_QUEUE_OVERRUN 0x0008 +#define CP210X_LSR_PARITY_ERROR 0x0010 +#define CP210X_LSR_ALL 0x001F // supported baudrates // reference: datasheets and AN205 "CP210x Baud Rate Support" diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 42716f73e..4afedec9b 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -28,43 +28,43 @@ #include // Commands -#define FTDI_SIO_RESET 0 // Reset the port -#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register -#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register -#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate -#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port -#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register -#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character -#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character -#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer -#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer -#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode -#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins -#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM +#define FTDI_SIO_RESET 0 // Reset the port +#define FTDI_SIO_MODEM_CTRL 1 // Set the modem control register +#define FTDI_SIO_SET_FLOW_CTRL 2 // Set flow control register +#define FTDI_SIO_SET_BAUD_RATE 3 // Set baud rate +#define FTDI_SIO_SET_DATA 4 // Set the data characteristics of the port +#define FTDI_SIO_GET_MODEM_STATUS 5 // Retrieve current value of modem status register +#define FTDI_SIO_SET_EVENT_CHAR 6 // Set the event character +#define FTDI_SIO_SET_ERROR_CHAR 7 // Set the error character +#define FTDI_SIO_SET_LATENCY_TIMER 9 // Set the latency timer +#define FTDI_SIO_GET_LATENCY_TIMER 10 // Get the latency timer +#define FTDI_SIO_SET_BITMODE 11 // Set bitbang mode +#define FTDI_SIO_READ_PINS 12 // Read immediate value of pins +#define FTDI_SIO_READ_EEPROM 0x90 // Read EEPROM // Channel indices for FT2232, FT2232H and FT4232H devices -#define CHANNEL_A 1 -#define CHANNEL_B 2 -#define CHANNEL_C 3 -#define CHANNEL_D 4 +#define CHANNEL_A 1 +#define CHANNEL_B 2 +#define CHANNEL_C 3 +#define CHANNEL_D 4 // Port Identifier Table -#define PIT_DEFAULT 0 // SIOA -#define PIT_SIOA 1 // SIOA +#define PIT_DEFAULT 0 // SIOA +#define PIT_SIOA 1 // SIOA // The device this driver is tested with one has only one port -#define PIT_SIOB 2 // SIOB -#define PIT_PARALLEL 3 // Parallel +#define PIT_SIOB 2 // SIOB +#define PIT_PARALLEL 3 // Parallel // FTDI_SIO_RESET -#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET -#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 -#define FTDI_SIO_RESET_SIO 0 -#define FTDI_SIO_RESET_PURGE_RX 1 -#define FTDI_SIO_RESET_PURGE_TX 2 +#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET +#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 +#define FTDI_SIO_RESET_SIO 0 +#define FTDI_SIO_RESET_PURGE_RX 1 +#define FTDI_SIO_RESET_PURGE_TX 2 // FTDI_SIO_SET_BAUDRATE -#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 +#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 enum ftdi_sio_baudrate { ftdi_sio_b300 = 0, @@ -80,89 +80,89 @@ enum ftdi_sio_baudrate { }; // FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) +#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA +#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) +#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) +#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) +#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) +#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) +#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) // same coding as ACM +#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) // 1.5 not supported, for future use? +#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) +#define FTDI_SIO_SET_BREAK (0x1 << 14) // FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) -#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_MASK 0x1 +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) +#define FTDI_SIO_SET_RTS_MASK 0x2 +#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) +#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) // FTDI_SIO_SET_FLOW_CTRL -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 -#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) -#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) -#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) +#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) +#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) +#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) // FTDI_SIO_GET_LATENCY_TIMER -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER +#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 // FTDI_SIO_SET_LATENCY_TIMER -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER +#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 // FTDI_SIO_SET_EVENT_CHAR -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR +#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 // FTDI_SIO_GET_MODEM_STATUS -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS -#define FTDI_SIO_CTS_MASK 0x10 -#define FTDI_SIO_DSR_MASK 0x20 -#define FTDI_SIO_RI_MASK 0x40 -#define FTDI_SIO_RLSD_MASK 0x80 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS +#define FTDI_SIO_CTS_MASK 0x10 +#define FTDI_SIO_DSR_MASK 0x20 +#define FTDI_SIO_RI_MASK 0x40 +#define FTDI_SIO_RLSD_MASK 0x80 // FTDI_SIO_SET_BITMODE -#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE +#define FTDI_SIO_SET_BITMODE_REQUEST_TYPE 0x40 +#define FTDI_SIO_SET_BITMODE_REQUEST FTDI_SIO_SET_BITMODE // Possible bitmodes for FTDI_SIO_SET_BITMODE_REQUEST -#define FTDI_SIO_BITMODE_RESET 0x00 -#define FTDI_SIO_BITMODE_CBUS 0x20 +#define FTDI_SIO_BITMODE_RESET 0x00 +#define FTDI_SIO_BITMODE_CBUS 0x20 // FTDI_SIO_READ_PINS -#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 -#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS +#define FTDI_SIO_READ_PINS_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_PINS_REQUEST FTDI_SIO_READ_PINS // FTDI_SIO_READ_EEPROM -#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 -#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM +#define FTDI_SIO_READ_EEPROM_REQUEST_TYPE 0xc0 +#define FTDI_SIO_READ_EEPROM_REQUEST FTDI_SIO_READ_EEPROM #define FTDI_FTX_CBUS_MUX_GPIO 0x8 #define FTDI_FT232R_CBUS_MUX_GPIO 0xa #define FTDI_RS0_CTS (1 << 4) #define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) +#define FTDI_RS0_RI (1 << 6) #define FTDI_RS0_RLSD (1 << 7) -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1 << 1) +#define FTDI_RS_PE (1 << 2) +#define FTDI_RS_FE (1 << 3) +#define FTDI_RS_BI (1 << 4) +#define FTDI_RS_THRE (1 << 5) +#define FTDI_RS_TEMT (1 << 6) +#define FTDI_RS_FIFO (1 << 7) // chip types and names enum ftdi_chip_type { @@ -206,14 +206,14 @@ enum ftdi_chip_type { // private interface data typedef struct ftdi_private { - enum ftdi_chip_type chip_type; - uint8_t channel; // channel index, or 0 for legacy types + enum ftdi_chip_type chip_type; + uint8_t channel; // channel index, or 0 for legacy types } ftdi_private_t; -#define FTDI_OK true -#define FTDI_FAIL false +#define FTDI_OK true +#define FTDI_FAIL false #define FTDI_NOT_POSSIBLE -1 -#define FTDI_REQUESTED -2 +#define FTDI_REQUESTED -2 // division and round function overtaken from math.h #define DIV_ROUND_CLOSEST(x, divisor)( \ diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index bf264191b..d69bdbfae 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -24,8 +24,8 @@ * This file is part of the TinyUSB stack. */ -#ifndef _PL2303_H_ -#define _PL2303_H_ +#ifndef TUSB_PL2303_H +#define TUSB_PL2303_H #include #include @@ -36,66 +36,66 @@ // https://github.com/torvalds/linux/blob/master/drivers/usb/serial/pl2303.c // - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uplcom.c -/* quirks */ -#define PL2303_QUIRK_UART_STATE_IDX0 1 -#define PL2303_QUIRK_LEGACY 2 -#define PL2303_QUIRK_ENDPOINT_HACK 4 +// quirks +#define PL2303_QUIRK_UART_STATE_IDX0 1 +#define PL2303_QUIRK_LEGACY 2 +#define PL2303_QUIRK_ENDPOINT_HACK 4 -/* requests and bits */ -#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 +// requests and bits +#define PL2303_SET_LINE_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_LINE_REQUEST 0x20 // dec 32 -#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 -#define PL2303_CONTROL_DTR 0x01 // dec 1 -#define PL2303_CONTROL_RTS 0x02 // dec 2 +#define PL2303_SET_CONTROL_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_SET_CONTROL_REQUEST 0x22 // dec 34 +#define PL2303_CONTROL_DTR 0x01 // dec 1 +#define PL2303_CONTROL_RTS 0x02 // dec 2 -#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface -#define PL2303_BREAK_REQUEST 0x23 // dec 35 -#define PL2303_BREAK_ON 0xffff -#define PL2303_BREAK_OFF 0x0000 +#define PL2303_BREAK_REQUEST_TYPE 0x21 // class request host to device interface +#define PL2303_BREAK_REQUEST 0x23 // dec 35 +#define PL2303_BREAK_ON 0xffff +#define PL2303_BREAK_OFF 0x0000 -#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface -#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 +#define PL2303_GET_LINE_REQUEST_TYPE 0xa1 // class request device to host interface +#define PL2303_GET_LINE_REQUEST 0x21 // dec 33 -#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface -#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 -#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 +#define PL2303_VENDOR_WRITE_REQUEST_TYPE 0x40 // vendor request host to device interface +#define PL2303_VENDOR_WRITE_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_WRITE_NREQUEST 0x80 // dec 128 -#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface -#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 -#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 +#define PL2303_VENDOR_READ_REQUEST_TYPE 0xc0 // vendor request device to host interface +#define PL2303_VENDOR_READ_REQUEST 0x01 // dec 1 +#define PL2303_VENDOR_READ_NREQUEST 0x81 // dec 129 -#define PL2303_UART_STATE_INDEX 8 -#define PL2303_UART_STATE_MSR_MASK 0x8b -#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 -#define PL2303_UART_DCD 0x01 -#define PL2303_UART_DSR 0x02 -#define PL2303_UART_BREAK_ERROR 0x04 -#define PL2303_UART_RING 0x08 -#define PL2303_UART_FRAME_ERROR 0x10 -#define PL2303_UART_PARITY_ERROR 0x20 -#define PL2303_UART_OVERRUN_ERROR 0x40 -#define PL2303_UART_CTS 0x80 +#define PL2303_UART_STATE_INDEX 8 +#define PL2303_UART_STATE_MSR_MASK 0x8b +#define PL2303_UART_STATE_TRANSIENT_MASK 0x74 +#define PL2303_UART_DCD 0x01 +#define PL2303_UART_DSR 0x02 +#define PL2303_UART_BREAK_ERROR 0x04 +#define PL2303_UART_RING 0x08 +#define PL2303_UART_FRAME_ERROR 0x10 +#define PL2303_UART_PARITY_ERROR 0x20 +#define PL2303_UART_OVERRUN_ERROR 0x40 +#define PL2303_UART_CTS 0x80 -#define PL2303_FLOWCTRL_MASK 0xf0 +#define PL2303_FLOWCTRL_MASK 0xf0 -#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint +#define PL2303_CLEAR_HALT_REQUEST_TYPE 0x02 // standard request host to device endpoint -/* registers via vendor read/write requests */ -#define PL2303_READ_TYPE_HX_STATUS 0x8080 +// registers via vendor read/write requests +#define PL2303_READ_TYPE_HX_STATUS 0x8080 -#define PL2303_HXN_RESET_REG 0x07 -#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 -#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 +#define PL2303_HXN_RESET_REG 0x07 +#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 +#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 -#define PL2303_HXN_FLOWCTRL_REG 0x0a -#define PL2303_HXN_FLOWCTRL_MASK 0x1c -#define PL2303_HXN_FLOWCTRL_NONE 0x1c -#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 -#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c +#define PL2303_HXN_FLOWCTRL_REG 0x0a +#define PL2303_HXN_FLOWCTRL_MASK 0x1c +#define PL2303_HXN_FLOWCTRL_NONE 0x1c +#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 +#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c -/* type data */ +// type data enum pl2303_type { TYPE_H, TYPE_HX, @@ -107,9 +107,9 @@ enum pl2303_type { }; struct pl2303_type_data { - uint8_t const *name; + uint8_t const *name; uint32_t const max_baud_rate; - uint8_t const quirks; + uint8_t const quirks; uint16_t const no_autoxonxoff:1; uint16_t const no_divisors:1; uint16_t const alt_divisors:1; @@ -146,7 +146,7 @@ struct pl2303_type_data { .no_divisors = true, \ } -/* private data types */ +// private data types struct pl2303_serial_private { const struct pl2303_type_data* type; uint8_t quirks; @@ -157,16 +157,16 @@ typedef struct TU_ATTR_PACKED { bool supports_hx_status; } pl2303_private_t; -/* buffer sizes for line coding data */ -#define PL2303_LINE_CODING_BUFSIZE 7 +// buffer sizes for line coding data +#define PL2303_LINE_CODING_BUFSIZE 7 #define PL2303_LINE_CODING_BAUDRATE_BUFSIZE 4 -/* bulk endpoints */ -#define PL2303_OUT_EP 0x02 -#define PL2303_IN_EP 0x83 +// bulk endpoints +#define PL2303_OUT_EP 0x02 +#define PL2303_IN_EP 0x83 -/* return values of pl2303_detect_type() */ +// return values of pl2303_detect_type() #define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 -#define PL2303_DETECT_TYPE_FAILED -2 +#define PL2303_DETECT_TYPE_FAILED -2 -#endif /* _PL2303_H_ */ +#endif // TUSB_PL2303_H From 5e67b92b8c398d6fee92010ecd63cf50b51f8f9a Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:10:31 +0200 Subject: [PATCH 032/101] fixed compile warnings --- src/class/cdc/cdc_host.c | 29 ++++++++++++++++------------- src/class/cdc/serial/cp210x.h | 4 ++-- src/class/cdc/serial/ftdi_sio.h | 14 +++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e6579ad82..2d900a753 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1181,9 +1181,9 @@ static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_c static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t value = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) | // data bit quantity is stored in bits 0-3 - ((uint32_t) p_cdc->requested_line_coding.parity & 0x7u) << 8 | // parity is stored in bits 8-10, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0x3u) << 11 ); // stop bits quantity is stored in bits 11-12, same coding + (p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11 ); // stop bits quantity is stored in bits 11-12, same coding // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, @@ -1191,8 +1191,8 @@ static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple } static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? (uint32_t) FTDI_SIO_SET_DTR_HIGH : (uint32_t) FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line_state.rts ? (uint32_t) FTDI_SIO_SET_RTS_HIGH : (uint32_t) FTDI_SIO_SET_RTS_LOW)); + uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); @@ -1338,7 +1338,10 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); - p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + TU_ASSERT_COMPLETE(p_cdc_itf0); + if (p_cdc_itf0) { + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; + } } TU_ATTR_FALLTHROUGH; @@ -1715,9 +1718,9 @@ static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); uint16_t lcr = (uint16_t) ( - ((uint32_t) p_cdc->requested_line_coding.data_bits & 0xfu) << 8 | // data bit quantity is stored in bits 8-11 - ((uint32_t) p_cdc->requested_line_coding.parity & 0xfu) << 4 | // parity is stored in bits 4-7, same coding - ((uint32_t) p_cdc->requested_line_coding.stop_bits & 0xfu)); // parity is stored in bits 0-3, same coding + (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } @@ -1725,8 +1728,8 @@ static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, - (uint16_t) ((uint32_t) CP210X_CONTROL_WRITE_DTR | - (uint32_t) CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line_state.all), + (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | + p_cdc->requested_line_state.all), NULL, 0, complete_cb, user_data); } @@ -2327,7 +2330,7 @@ static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16 static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t buf; + uint8_t buf = 0; return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); @@ -2519,7 +2522,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { cdch_interface_t * p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); - uint8_t buf; + uint8_t buf = 0; int8_t type; switch (state) { diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index a553a54da..ac9c27330 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -101,8 +101,8 @@ #define CP210X_MSR_DCD 0x0080 #define CP210X_MSR_ALL 0x00F0 -#define CP210X_CONTROL_WRITE_DTR 0x0100 -#define CP210X_CONTROL_WRITE_RTS 0x0200 +#define CP210X_CONTROL_WRITE_DTR 0x0100UL +#define CP210X_CONTROL_WRITE_RTS 0x0200UL #define CP210X_LSR_BREAK 0x0001 #define CP210X_LSR_FRAMING_ERROR 0x0002 diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index 4afedec9b..f621b3912 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -96,17 +96,17 @@ enum ftdi_sio_baudrate { #define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 #define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1) -#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2) -#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0) +#define FTDI_SIO_SET_DTR_MASK 0x1UL +#define FTDI_SIO_SET_DTR_HIGH ((FTDI_SIO_SET_DTR_MASK << 8) | 1UL) +#define FTDI_SIO_SET_DTR_LOW ((FTDI_SIO_SET_DTR_MASK << 8) | 0UL) +#define FTDI_SIO_SET_RTS_MASK 0x2UL +#define FTDI_SIO_SET_RTS_HIGH ((FTDI_SIO_SET_RTS_MASK << 8) | 2UL) +#define FTDI_SIO_SET_RTS_LOW ((FTDI_SIO_SET_RTS_MASK << 8) | 0UL) // FTDI_SIO_SET_FLOW_CTRL #define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 #define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 +#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 #define FTDI_SIO_RTS_CTS_HS (0x1 << 8) #define FTDI_SIO_DTR_DSR_HS (0x2 << 8) #define FTDI_SIO_XON_XOFF_HS (0x4 << 8) From e07ee4a7b1f7c7d18f385d605dd41e08962ddba4 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:12:14 +0200 Subject: [PATCH 033/101] CP210x removed baudrate check, fixed data bits check --- src/class/cdc/cdc_host.c | 12 ++---------- src/class/cdc/serial/cp210x.h | 9 --------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2d900a753..73d800469 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1701,22 +1701,14 @@ static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, } static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // Check baudrate is supported. It's only a specific list. reference: datasheets and AN205 "CP210x Baud Rate Support" - uint32_t const supported_baudrates_list[] = CP210X_SUPPORTED_BAUDRATES_LIST; - uint8_t i; - for ( i=0; supported_baudrates_list[i]; i++ ){ - if (p_cdc->requested_line_coding.bit_rate == supported_baudrates_list[i]) { - break; - } - } - TU_VERIFY(supported_baudrates_list[i]); + // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 9, 0); + TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); uint16_t lcr = (uint16_t) ( (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding diff --git a/src/class/cdc/serial/cp210x.h b/src/class/cdc/serial/cp210x.h index ac9c27330..a0eff9e40 100644 --- a/src/class/cdc/serial/cp210x.h +++ b/src/class/cdc/serial/cp210x.h @@ -111,13 +111,4 @@ #define CP210X_LSR_PARITY_ERROR 0x0010 #define CP210X_LSR_ALL 0x001F -// supported baudrates -// reference: datasheets and AN205 "CP210x Baud Rate Support" -#define CP210X_SUPPORTED_BAUDRATES_LIST { \ - 300, 600, \ - 1200, 1800, 2400, 4000, 4800, 7200, 9600, \ - 14400, 16000, 19200, 28800, 38400, 51200, 56000, 57600, 64000, 76800, \ - 115200, 128000, 153600, 230400, 250000, 256000, 460800, 500000, 576000, 921600, \ - 0 } - #endif //TUSB_CP210X_H From a1b1c1f552d944da1bf309ce002b7c07f5a270a0 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:13:24 +0200 Subject: [PATCH 034/101] foxed FTDI flow control config --- src/class/cdc/cdc_host.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 73d800469..6006730b7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1382,7 +1382,8 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, FTDI_SIO_DISABLE_FLOW_CTRL, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + FTDI_SIO_DISABLE_FLOW_CTRL, p_cdc->ftdi.channel, + ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: From e02a309f1dc09377fe5123c21ecfe36eb6a032c7 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:14:41 +0200 Subject: [PATCH 035/101] disable PL2303 flow control config --- src/class/cdc/cdc_host.c | 55 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 6006730b7..b9915f583 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2475,8 +2475,8 @@ enum { CONFIG_PL2303_RESET_ENDP2, CONFIG_PL2303_LINE_CODING, CONFIG_PL2303_MODEM_CONTROL, - CONFIG_PL2303_FLOW_CTRL_READ, - CONFIG_PL2303_FLOW_CTRL_WRITE, +// CONFIG_PL2303_FLOW_CTRL_READ, +// CONFIG_PL2303_FLOW_CTRL_WRITE, CONFIG_PL2303_COMPLETE }; @@ -2691,35 +2691,38 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_FLOW_CTRL_READ)); + TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif - case CONFIG_PL2303_FLOW_CTRL_READ: - // read flow control register for modify & write back in next step - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, - CONFIG_PL2303_FLOW_CTRL_WRITE)); - } else { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - } - break; - - case CONFIG_PL2303_FLOW_CTRL_WRITE: - // no flow control - buf = xfer->buffer[0]; - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; - buf |= PL2303_HXN_FLOWCTRL_NONE; - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, - CONFIG_PL2303_COMPLETE)); - } else { - buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); - } - break; +// skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program +// case CONFIG_PL2303_FLOW_CTRL_READ: +// // read flow control register for modify & write back in next step +// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { +// TU_LOG_P_CDC ( "1\r\n" ); +// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, +// CONFIG_PL2303_FLOW_CTRL_WRITE)); +// } else { +// TU_LOG_P_CDC ( "2\r\n" ); +// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); +// } +// break; +// +// case CONFIG_PL2303_FLOW_CTRL_WRITE: +// // no flow control +// buf = xfer->buffer[0]; +// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { +// buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; +// buf |= PL2303_HXN_FLOWCTRL_NONE; +// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, +// CONFIG_PL2303_COMPLETE)); +// } else { +// buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; +// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); +// } +// break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); From 68602e4adda941ab11826afbd7b82e44134a97ae Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:16:02 +0200 Subject: [PATCH 036/101] small change process config complete --- src/class/cdc/cdc_host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b9915f583..fbe0cc9ca 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1400,7 +1400,7 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -1876,7 +1876,7 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -2158,7 +2158,7 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } @@ -2729,7 +2729,7 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 0, false); + TU_ASSERT_COMPLETE(false); break; } } From 0c5e14cdaa98b3d801fcaf05e3b6c941031a55b2 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 4 Apr 2024 14:16:39 +0200 Subject: [PATCH 037/101] updated doc --- docs/reference/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 9ecdf619b..509babef2 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -27,7 +27,7 @@ Supports multiple device configurations by dynamically changing USB descriptors, - Audio Class 2.0 (UAC2) - Bluetooth Host Controller Interface (BTH HCI) -- Communication Device Class (CDC) +- Communications Device Class (CDC) - Device Firmware Update (DFU): DFU mode (WIP) and Runtime - Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ... - Mass Storage Class (MSC): with multiple LUNs @@ -45,8 +45,8 @@ Host Stack - Human Interface Device (HID): Keyboard, Mouse, Generic - Mass Storage Class (MSC) -- Communication Device Class: CDC-ACM -- Vendor serial over USB: FTDI, CP210x +- Communications Device Class (CDC): Abstract Control Model (ACM) +- Vendor serial over USB: FTDI, CP210x, CH34x, PL230x - Hub with multiple-level support Similar to the Device Stack, if you have a special requirement, `usbh_app_driver_get_cb()` can be used to write your own class driver without modifying the stack. From 8b4ca69e56860e12596e2bef63fc155f8dce338c Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 12 Apr 2024 01:14:30 +0200 Subject: [PATCH 038/101] cdc_device : save rhport. --- src/class/cdc/cdc_device.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 2e0a0c30d..e856963f5 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -47,6 +47,7 @@ typedef struct { + uint8_t rhport; uint8_t itf_num; uint8_t ep_notif; uint8_t ep_in; @@ -84,7 +85,6 @@ CFG_TUD_MEM_SECTION tu_static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC]; static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { - uint8_t const rhport = 0; uint16_t available = tu_fifo_remaining(&p_cdc->rx_ff); // Prepare for incoming data but only allow what we can store in the ring buffer. @@ -94,18 +94,18 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) TU_VERIFY(available >= sizeof(p_cdc->epout_buf)); // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out)); + TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_out)); // fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&p_cdc->rx_ff); if ( available >= sizeof(p_cdc->epout_buf) ) { - return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); + return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf)); }else { // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_cdc->ep_out); + usbd_edpt_release(p_cdc->rhport, p_cdc->ep_out); return false; } @@ -135,7 +135,6 @@ void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) _cdcd_itf[itf].wanted_char = wanted; } - //--------------------------------------------------------------------+ // READ API //--------------------------------------------------------------------+ @@ -194,23 +193,21 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf) // No data to send if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; - uint8_t const rhport = 0; - // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_cdc->ep_in), 0 ); + TU_VERIFY( usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0 ); // Pull data from FIFO uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); if ( count ) { - TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); + TU_ASSERT( usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); return count; }else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected - usbd_edpt_release(rhport, p_cdc->ep_in); + usbd_edpt_release(p_cdc->rhport, p_cdc->ep_in); return 0; } } @@ -319,6 +316,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 TU_ASSERT(p_cdc, 0); //------------- Control Interface -------------// + p_cdc->rhport = rhport; p_cdc->itf_num = itf_desc->bInterfaceNumber; uint16_t drv_len = sizeof(tusb_desc_interface_t); From 67f32da1b9a460262e028784ffb0386edd507612 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 12 Apr 2024 01:15:46 +0200 Subject: [PATCH 039/101] cdc: add uart status notification support. --- src/class/cdc/cdc.h | 29 +++++++++++++++++++++++++++++ src/class/cdc/cdc_device.c | 24 +++++++++++++++++++++++- src/class/cdc/cdc_device.h | 9 +++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 5cbd658fe..f92ab9231 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -412,6 +412,35 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); +//--------------------------------------------------------------------+ +// Notifications +//--------------------------------------------------------------------+ +typedef struct TU_ATTR_PACKED +{ + uint16_t bRxCarrier : 1; + uint16_t bTxCarrier : 1; + uint16_t bBreak : 1; + uint16_t bRingSignal : 1; + uint16_t bFraming : 1; + uint16_t bParity : 1; + uint16_t bOverRun : 1; + uint16_t : 9; +} cdc_uart_state_t; + +typedef struct TU_ATTR_PACKED +{ + uint8_t bmRequestType; + uint8_t bNotification; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + cdc_uart_state_t bmUartState; +} cdc_notif_serial_state_t; + +TU_VERIFY_STATIC(sizeof(cdc_notif_serial_state_t) == 10, "size is not correct"); + +#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface + TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index e856963f5..5057805e2 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -71,6 +71,7 @@ typedef struct OSAL_MUTEX_DEF(tx_ff_mutex); // Endpoint Transfer buffer + CFG_TUSB_MEM_ALIGN cdc_notif_serial_state_t serial_state_buf; CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; @@ -130,6 +131,27 @@ void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding) (*coding) = _cdcd_itf[itf].line_coding; } +bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state) +{ + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notif)); + + p_cdc->serial_state_buf.bmRequestType = CDC_REQ_TYPE_NOTIF; + p_cdc->serial_state_buf.bNotification = CDC_NOTIF_SERIAL_STATE; + p_cdc->serial_state_buf.wValue = 0; + p_cdc->serial_state_buf.wIndex = p_cdc->itf_num; + p_cdc->serial_state_buf.wLength = 2; + p_cdc->serial_state_buf.bmUartState = state; + + // transfer + return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notif, (uint8_t *)&p_cdc->serial_state_buf, sizeof(p_cdc->serial_state_buf)); +} + void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted) { _cdcd_itf[itf].wanted_char = wanted; @@ -457,7 +479,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ for (itf = 0; itf < CFG_TUD_CDC; itf++) { p_cdc = &_cdcd_itf[itf]; - if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) ) break; + if ( ( ep_addr == p_cdc->ep_out ) || ( ep_addr == p_cdc->ep_in ) || ( ep_addr == p_cdc->ep_notif )) break; } TU_ASSERT(itf < CFG_TUD_CDC); diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 20e908451..92131f159 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -64,6 +64,9 @@ uint8_t tud_cdc_n_get_line_state (uint8_t itf); // Get current line encoding: bit rate, stop bits parity etc .. void tud_cdc_n_get_line_coding (uint8_t itf, cdc_line_coding_t* coding); +// Send UART status notification: DCD, DSR etc .. +bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state); + // Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving void tud_cdc_n_set_wanted_char (uint8_t itf, char wanted); @@ -109,6 +112,7 @@ bool tud_cdc_n_write_clear (uint8_t itf); static inline bool tud_cdc_connected (void); static inline uint8_t tud_cdc_get_line_state (void); static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding); +static inline bool tud_cdc_send_uart_state (cdc_uart_state_t state); static inline void tud_cdc_set_wanted_char (char wanted); static inline uint32_t tud_cdc_available (void); @@ -180,6 +184,11 @@ static inline void tud_cdc_get_line_coding (cdc_line_coding_t* coding) tud_cdc_n_get_line_coding(0, coding); } +static inline bool tud_cdc_send_uart_state (cdc_uart_state_t state) +{ + return tud_cdc_n_send_uart_state(0, state); +} + static inline void tud_cdc_set_wanted_char (char wanted) { tud_cdc_n_set_wanted_char(0, wanted); From 418b8b2f133d695362c735f271c966af10b5d251 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 12 Apr 2024 01:17:50 +0200 Subject: [PATCH 040/101] Add uart status notif to cdc_dual_ports example. --- examples/device/cdc_dual_ports/src/main.c | 11 ++++++++++- examples/device/cdc_dual_ports/src/usb_descriptors.c | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c index 1167a5d50..2190b984a 100644 --- a/examples/device/cdc_dual_ports/src/main.c +++ b/examples/device/cdc_dual_ports/src/main.c @@ -94,7 +94,6 @@ void tud_umount_cb(void) { blink_interval_ms = BLINK_NOT_MOUNTED; } - //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ @@ -115,6 +114,16 @@ static void cdc_task(void) { echo_serial_port(0, buf, count); echo_serial_port(1, buf, count); } + + // Press on-board button to send Uart status notification + static uint32_t btn_prev = 0; + static cdc_uart_state_t state = {0}; + uint32_t btn = board_button_read(); + if (!btn_prev && btn) { + state.bTxCarrier ^= 1; + tud_cdc_send_uart_state(state); + } + btn_prev = btn; } } } diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index de2505c07..76907de09 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -136,10 +136,10 @@ uint8_t const desc_fs_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), }; #if TUD_OPT_HIGH_SPEED @@ -151,10 +151,10 @@ uint8_t const desc_hs_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512), }; // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed From d1ee2bf18fced22364537949c4a18e1c15c99b6d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 15:14:25 +0100 Subject: [PATCH 041/101] Fix Auto speed display. Signed-off-by: HiFiPhile --- src/device/usbd.c | 23 ++++++++++++++++++++--- src/host/usbh.c | 23 ++++++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 2a6081673..8435b5c02 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -464,13 +464,30 @@ bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; // skip if already initialized } TU_ASSERT(rh_init); - - TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, - rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full"); +#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL + char const* speed_str = 0; + switch (rh_init->speed) { + case TUSB_SPEED_HIGH: + speed_str = "High"; + break; + case TUSB_SPEED_FULL: + speed_str = "Full"; + break; + case TUSB_SPEED_LOW: + speed_str = "Low"; + break; + case TUSB_SPEED_AUTO: + speed_str = "Auto"; + break; + default: + break; + } + TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, speed_str); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); +#endif tu_varclr(&_usbd_dev); _usbd_queued_setup = 0; diff --git a/src/host/usbh.c b/src/host/usbh.c index a2994cde7..f022d93f1 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -365,9 +365,26 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { if (tuh_rhport_is_active(rhport)) { return true; // skip if already initialized } - - TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport, - rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full"); +#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL + char const* speed_str = 0; + switch (rh_init->speed) { + case TUSB_SPEED_HIGH: + speed_str = "High"; + break; + case TUSB_SPEED_FULL: + speed_str = "Full"; + break; + case TUSB_SPEED_LOW: + speed_str = "Low"; + break; + case TUSB_SPEED_AUTO: + speed_str = "Auto"; + break; + default: + break; + } + TU_LOG_USBH("USBH init on controller %u, speed = %s\r\n", rhport, speed_str); +#endif // Init host stack if not already if (!tuh_inited()) { From cc626f35d212aef86b0aa7275eea016ae69b5de4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 15:16:02 +0100 Subject: [PATCH 042/101] msc_device: add async IO support. Signed-off-by: HiFiPhile --- src/class/msc/msc_device.c | 182 ++++++++++++++++++++++++++----------- src/class/msc/msc_device.h | 16 ++++ 2 files changed, 146 insertions(+), 52 deletions(-) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index dd66bfb6f..c7c926f4e 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -52,10 +52,18 @@ enum { MSC_STAGE_NEED_RESET, }; +enum { + MSC_NEXT_OP_NONE = 0, + MSC_NEXT_OP_READ10, + MSC_NEXT_OP_WRITE10, + MSC_NEXT_OP_STATUS +}; + typedef struct { TU_ATTR_ALIGNED(4) msc_cbw_t cbw; TU_ATTR_ALIGNED(4) msc_csw_t csw; + uint8_t rhport; uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -70,6 +78,10 @@ typedef struct { uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; +#if CFG_TUD_MSC_ASYNC_IO + uint8_t next_op; + uint32_t xferred_bytes; +#endif }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -82,31 +94,39 @@ CFG_TUD_MEM_SECTION static struct { // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc); - -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_read10_cmd(mscd_interface_t* p_msc); +static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes); +static void proc_write10_cmd(mscd_interface_t* p_msc); +static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); +static bool proc_stage_status(mscd_interface_t* p_msc); +#if CFG_TUD_MSC_ASYNC_IO +static void tud_msc_async_io_done_cb(void* bytes_processed); +#endif TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); } -static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) { +static inline bool send_csw(mscd_interface_t* p_msc) { // Data residue is always = host expect - actual transferred + uint8_t rhport = p_msc->rhport; p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; p_msc->stage = MSC_STAGE_STATUS_SENT; memcpy(_mscd_epbuf.buf, &p_msc->csw, sizeof(msc_csw_t)); return usbd_edpt_xfer(rhport, p_msc->ep_in , _mscd_epbuf.buf, sizeof(msc_csw_t)); } -static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) { +static inline bool prepare_cbw(mscd_interface_t* p_msc) { + uint8_t rhport = p_msc->rhport; p_msc->stage = MSC_STAGE_CMD; return usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, sizeof(msc_cbw_t)); } -static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) { +static void fail_scsi_op(mscd_interface_t* p_msc, uint8_t status) { msc_cbw_t const * p_cbw = &p_msc->cbw; msc_csw_t * p_csw = &p_msc->csw; + uint8_t rhport = p_msc->rhport; p_csw->status = status; p_csw->data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; @@ -177,6 +197,32 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) { return status; } +static bool proc_stage_status(mscd_interface_t* p_msc) { + uint8_t rhport = p_msc->rhport; + msc_cbw_t const* p_cbw = &p_msc->cbw; + // skip status if epin is currently stalled, will do it when received Clear Stall request + if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { + if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + } else { + TU_ASSERT(send_csw(p_msc)); + } + } + + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(p_msc); + } + #endif + return true; +} + //--------------------------------------------------------------------+ // Debug //--------------------------------------------------------------------+ @@ -219,6 +265,32 @@ static inline void set_sense_medium_not_present(uint8_t lun) { tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } +#if CFG_TUD_MSC_ASYNC_IO +void tud_msc_async_io_done(int32_t bytes_processed) { + // Precheck to avoid queueing multiple RW done callback + TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); + // Call usbd_edpt_xfer() in tud_task() to avoid racing condition + usbd_defer_func(tud_msc_async_io_done_cb, (void*) bytes_processed, false); +} + +static void tud_msc_async_io_done_cb(void* bytes_processed) { + TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); + uint8_t next_op = _mscd_itf.next_op; + _mscd_itf.next_op = MSC_NEXT_OP_NONE; + int32_t nbytes = (int32_t)bytes_processed; + // READ10 + if (next_op == MSC_NEXT_OP_READ10) { + proc_read10_next(&_mscd_itf, nbytes); + } else if (next_op == MSC_NEXT_OP_WRITE10) { + proc_write10_next(&_mscd_itf, _mscd_itf.xferred_bytes, nbytes); + // Need to manually invoke CSW transfer + if (_mscd_itf.stage == MSC_STAGE_STATUS) { + proc_stage_status(&_mscd_itf); + } + } +} +#endif + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -245,12 +317,13 @@ uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 mscd_interface_t * p_msc = &_mscd_itf; p_msc->itf_num = itf_desc->bInterfaceNumber; + p_msc->rhport = rhport; // Open endpoint pair TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(itf_desc), 2, TUSB_XFER_BULK, &p_msc->ep_out, &p_msc->ep_in), 0); // Prepare for Command Block Wrapper - TU_ASSERT(prepare_cbw(rhport, p_msc), drv_len); + TU_ASSERT(prepare_cbw(p_msc), drv_len); return drv_len; } @@ -289,14 +362,14 @@ bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t if (ep_addr == p_msc->ep_in) { if (p_msc->stage == MSC_STAGE_STATUS) { // resume sending SCSI status if we are in this stage previously before stalled - TU_ASSERT(send_csw(rhport, p_msc)); + TU_ASSERT(send_csw(p_msc)); } } else if (ep_addr == p_msc->ep_out) { if (p_msc->stage == MSC_STAGE_CMD) { // part of reset recovery (probably due to invalid CBW) -> prepare for new command // Note: skip if already queued previously if (usbd_edpt_ready(rhport, p_msc->ep_out)) { - TU_ASSERT(prepare_cbw(rhport, p_msc)); + TU_ASSERT(prepare_cbw(p_msc)); } } } @@ -344,7 +417,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t msc_csw_t * p_csw = &p_msc->csw; switch (p_msc->stage) { - case MSC_STAGE_CMD: + case MSC_STAGE_CMD: { //------------- new CBW received -------------// // Complete IN while waiting for CMD is usually Status of previous SCSI op, ignore it if (ep_addr != p_msc->ep_out) { @@ -382,12 +455,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t uint8_t const status = rdwr10_validate_cmd(p_cbw); if (status != MSC_CSW_STATUS_PASSED) { - fail_scsi_op(rhport, p_msc, status); + fail_scsi_op(p_msc, status); } else if (p_cbw->total_bytes) { if (SCSI_CMD_READ_10 == p_cbw->command[0]) { - proc_read10_cmd(rhport, p_msc); + proc_read10_cmd(p_msc); } else { - proc_write10_cmd(rhport, p_msc); + proc_write10_cmd(p_msc); } } else { // no data transfer, only exist in complaint test suite @@ -400,7 +473,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if ((p_cbw->total_bytes > 0) && !is_data_in(p_cbw->dir)) { if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE) { TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first // but it is OK to just receive data then responded with failed status @@ -418,12 +491,12 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (resplen < 0) { // unsupported command TU_LOG_DRV(" SCSI unsupported or failed command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (resplen == 0) { if (p_cbw->total_bytes) { // 6.7 The 13 Cases: case 4 (Hi > Dn) // TU_LOG(MSC_DEBUG, " SCSI case 4 (Hi > Dn): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // case 1 Hn = Dn: all good p_msc->stage = MSC_STAGE_STATUS; @@ -432,7 +505,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if (p_cbw->total_bytes == 0) { // 6.7 The 13 Cases: case 2 (Hn < Di) // TU_LOG(MSC_DEBUG, " SCSI case 2 (Hn < Di): %lu\r\n", p_cbw->total_bytes); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // cannot return more than host expect p_msc->total_len = tu_min32((uint32_t)resplen, p_cbw->total_bytes); @@ -441,6 +514,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } } } + } break; case MSC_STAGE_DATA: @@ -454,10 +528,10 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t // Data Stage is complete p_msc->stage = MSC_STAGE_STATUS; }else { - proc_read10_cmd(rhport, p_msc); + proc_read10_cmd(p_msc); } } else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) { - proc_write10_new_data(rhport, p_msc, xferred_bytes); + proc_write10_new_data(p_msc, xferred_bytes); } else { p_msc->xferred_len += xferred_bytes; @@ -468,7 +542,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t if ( cb_result < 0 ) { // unsupported command TU_LOG_DRV(" SCSI unsupported command\r\n"); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); }else { // TODO haven't implement this scenario any further yet } @@ -517,7 +591,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; } - TU_ASSERT(prepare_cbw(rhport, p_msc)); + TU_ASSERT(prepare_cbw(p_msc)); } else { // Any xfer ended here is consider unknown error, ignore it TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); @@ -528,26 +602,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t } if (p_msc->stage == MSC_STAGE_STATUS) { - // skip status if epin is currently stalled, will do it when received Clear Stall request - if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { - if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG(MSC_DEBUG, " SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - } else { - TU_ASSERT(send_csw(rhport, p_msc)); - } - } - - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(rhport, p_msc); - } - #endif + TU_ASSERT(proc_stage_status(p_msc)); } return true; @@ -751,7 +806,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ return resplen; } -static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { +static void proc_read10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; // block size already verified not zero @@ -765,16 +820,27 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { // Application can consume smaller bytes uint32_t const offset = p_msc->xferred_len % block_sz; - nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); +#if CFG_TUD_MSC_ASYNC_IO + p_msc->next_op = MSC_NEXT_OP_READ10; + tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); +#else + nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); + proc_read10_next(p_msc, nbytes); +#endif +} + +static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { + uint8_t rhport = p_msc->rhport; if (nbytes < 0) { // negative means error -> endpoint is stalled & status in CSW set to failed TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n"); // set sense + msc_cbw_t const* p_cbw = &p_msc->cbw; set_sense_medium_not_present(p_cbw->lun); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (nbytes == 0) { // zero means not ready -> simulate an transfer complete so that this driver callback will fired again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); @@ -783,7 +849,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { } } -static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { +static void proc_write10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; bool writable = true; @@ -795,19 +861,19 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc) { // Not writable, complete this SCSI op with error // Sense = Write protected tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_DATA_PROTECT, 0x27, 0x00); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); return; } // remaining bytes capped at class buffer uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); - // Write10 callback will be called later when usb transfer complete + uint8_t rhport = p_msc->rhport; TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); } // process new data arrived from WRITE10 -static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes) { +static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { msc_cbw_t const* p_cbw = &p_msc->cbw; // block size already verified not zero @@ -818,8 +884,18 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; - int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); +#if CFG_TUD_MSC_ASYNC_IO + p_msc->next_op = MSC_NEXT_OP_WRITE10; + p_msc->xferred_bytes = xferred_bytes; + tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); +#else + int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); + proc_write10_next(p_msc, xferred_bytes, nbytes); +#endif +} + +static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { // negative means error -> failed this scsi op TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n"); @@ -828,9 +904,10 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 p_msc->xferred_len += xferred_bytes; // Set sense + msc_cbw_t const* p_cbw = &p_msc->cbw; set_sense_medium_not_present(p_cbw->lun); - fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { // Application consume less than what we got (including zero) if ((uint32_t)nbytes < xferred_bytes) { @@ -841,6 +918,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 } // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter + uint8_t rhport = p_msc->rhport; dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); } else { // Application consume all bytes in our buffer @@ -851,7 +929,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3 p_msc->stage = MSC_STAGE_STATUS; } else { // prepare to receive more data from host - proc_write10_cmd(rhport, p_msc); + proc_write10_cmd(p_msc); } } } diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 29acd280a..407fe241c 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -48,6 +48,11 @@ #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better #endif +// Enable asynchronous read/write, once operation is finished tud_msc_async_io_done() must be called +#ifndef CFG_TUD_MSC_ASYNC_IO +#define CFG_TUD_MSC_ASYNC_IO 0 +#endif + TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); //--------------------------------------------------------------------+ @@ -73,6 +78,9 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u // // - read < 0 : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. +// +// - In case of asynchronous IO enabled, application should passing reading parameters to background IO +// task and return immediately. Once reading is done, tud_msc_async_io_done() must be called. int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); // Invoked when received SCSI WRITE10 command @@ -88,6 +96,8 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf // - write < 0 : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. // +// - In case of asynchronous IO enabled, application should passing writing parameters to background IO +// task and return immediately. Once writing is done, tud_msc_async_io_done() must be called. // TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); @@ -121,6 +131,12 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz */ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); +#if CFG_TUD_MSC_ASYNC_IO +// Called once asynchronous read/write operation is done +// bytes_processed has the same meaning of tud_msc_read10_cb() / +// tud_msc_write10_cb() return value +void tud_msc_async_io_done(int32_t bytes_processed); +#endif /*------------- Optional callbacks -------------*/ // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation From 04b9e203107ef5f8b9d44f9b8a302cf6504ae3ae Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 15:20:44 +0100 Subject: [PATCH 043/101] msc_disk: fix overflow check when EP buffer size > 512. Signed-off-by: HiFiPhile --- examples/device/cdc_msc/src/msc_disk.c | 11 +++++++++-- examples/device/cdc_msc_freertos/src/msc_disk.c | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/examples/device/cdc_msc/src/msc_disk.c b/examples/device/cdc_msc/src/msc_disk.c index d325d77fa..6fc0760b6 100644 --- a/examples/device/cdc_msc/src/msc_disk.c +++ b/examples/device/cdc_msc/src/msc_disk.c @@ -195,7 +195,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff } // Check for overflow of offset + bufsize - if ( offset + bufsize > DISK_BLOCK_SIZE ) { + if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { return -1; } @@ -223,7 +223,14 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if ( lba >= DISK_BLOCK_NUM ) { + return -1; + } + + // Check for overflow of offset + bufsize + if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + return -1; + } #ifndef CFG_EXAMPLE_MSC_READONLY uint8_t* addr = msc_disk[lba] + offset; diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index d325d77fa..6fc0760b6 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -195,7 +195,7 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff } // Check for overflow of offset + bufsize - if ( offset + bufsize > DISK_BLOCK_SIZE ) { + if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { return -1; } @@ -223,7 +223,14 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if ( lba >= DISK_BLOCK_NUM ) { + return -1; + } + + // Check for overflow of offset + bufsize + if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + return -1; + } #ifndef CFG_EXAMPLE_MSC_READONLY uint8_t* addr = msc_disk[lba] + offset; From f43100bdfd5611c2ba463a05960ea5569a53a20b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 15:28:19 +0100 Subject: [PATCH 044/101] cdc_msc_freertos: add async IO support. Signed-off-by: HiFiPhile --- examples/device/cdc_msc_freertos/src/main.c | 3 +- .../device/cdc_msc_freertos/src/msc_disk.c | 70 ++++++++++++++++--- .../device/cdc_msc_freertos/src/tusb_config.h | 4 ++ 3 files changed, 66 insertions(+), 11 deletions(-) diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index c51e8ea81..4dada9801 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -72,7 +72,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; static void usb_device_task(void *param); void led_blinking_task(void* param); void cdc_task(void *params); - +extern void msc_disk_init(void); //--------------------------------------------------------------------+ // Main //--------------------------------------------------------------------+ @@ -123,6 +123,7 @@ static void usb_device_task(void *param) { board_init_after_tusb(); } + msc_disk_init(); // RTOS forever loop while (1) { // put this thread to waiting state until there is new events diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index 6fc0760b6..b0324911c 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,6 +28,20 @@ #if CFG_TUD_MSC +#if CFG_TUD_MSC_ASYNC_IO +// Simulate read/write operation time +#define SIM_IO_TIME_MS 20 + +TimerHandle_t sim_io_ops_timer; +static int32_t bytes_processed; +#if configSUPPORT_STATIC_ALLOCATION +StaticTimer_t sim_io_ops_timer_buf; +#endif +static void sim_io_ops_done_cb(TimerHandle_t xTimer); +#endif + +void msc_disk_init(void); + // whether host does safe-eject static bool ejected = false; @@ -119,6 +133,24 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = README_CONTENTS }; +#if CFG_TUD_MSC_ASYNC_IO +void msc_disk_init() { + +#if configSUPPORT_DYNAMIC_ALLOCATION + sim_io_ops_timer = xTimerCreate("sim_io_ops", pdMS_TO_TICKS(SIM_IO_TIME_MS), pdFALSE, NULL, sim_io_ops_done_cb); +#else + sim_io_ops_timer = xTimerCreateStatic("sim_io_ops", pdMS_TO_TICKS(SIM_IO_TIME_MS), pdFALSE, NULL, sim_io_ops_done_cb, &sim_io_ops_timer_buf); +#endif +} + +static void sim_io_ops_done_cb(TimerHandle_t xTimer) { + (void) xTimer; + tud_msc_async_io_done(bytes_processed); +} +#else +void msc_disk_init() {} +#endif + // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) @@ -188,21 +220,30 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; + int32_t ret = bufsize; // out of ramdisk if ( lba >= DISK_BLOCK_NUM ) { - return -1; + ret = -1; } // Check for overflow of offset + bufsize if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { - return -1; + ret = -1; } - uint8_t const* addr = msc_disk[lba] + offset; - memcpy(buffer, addr, bufsize); + if (ret != -1) { + uint8_t const* addr = msc_disk[lba] + offset; + memcpy(buffer, addr, bufsize); + } - return (int32_t) bufsize; +#if CFG_TUD_MSC_ASYNC_IO + // Simulate read operation + bytes_processed = ret; + xTimerStart(sim_io_ops_timer, 0); +#endif + + return ret; } bool tud_msc_is_writable_cb (uint8_t lun) @@ -221,25 +262,34 @@ bool tud_msc_is_writable_cb (uint8_t lun) int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { (void) lun; + int32_t ret = bufsize; // out of ramdisk if ( lba >= DISK_BLOCK_NUM ) { - return -1; + ret = -1; } // Check for overflow of offset + bufsize if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { - return -1; + ret = -1; } #ifndef CFG_EXAMPLE_MSC_READONLY - uint8_t* addr = msc_disk[lba] + offset; - memcpy(addr, buffer, bufsize); + if (ret != -1) { + uint8_t* addr = msc_disk[lba] + offset; + memcpy(addr, buffer, bufsize); + } #else (void) lba; (void) offset; (void) buffer; #endif - return (int32_t) bufsize; +#if CFG_TUD_MSC_ASYNC_IO + // Simulate read operation + bytes_processed = ret; + xTimerStart(sim_io_ops_timer, 0); +#endif + + return ret; } // Callback invoked when received an SCSI command not in built-in list below diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index c3f2f7fb5..eb4798017 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -114,6 +114,10 @@ // MSC Buffer size of Device Mass storage #define CFG_TUD_MSC_EP_BUFSIZE 512 +// Enable Async IO on MSC +#define CFG_TUD_MSC_ASYNC_IO 0 + + #ifdef __cplusplus } #endif From a40722b221f878f0d182c602f6d6db8d35031e19 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Wed, 29 Jan 2025 17:12:09 +0100 Subject: [PATCH 045/101] Enable SIM_IO_TIME_MS for normal operation. Signed-off-by: HiFiPhile --- examples/device/cdc_msc_freertos/src/msc_disk.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index b0324911c..2f3a1c30b 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,10 +28,10 @@ #if CFG_TUD_MSC -#if CFG_TUD_MSC_ASYNC_IO // Simulate read/write operation time -#define SIM_IO_TIME_MS 20 +#define SIM_IO_TIME_MS 0 +#if CFG_TUD_MSC_ASYNC_IO TimerHandle_t sim_io_ops_timer; static int32_t bytes_processed; #if configSUPPORT_STATIC_ALLOCATION @@ -238,9 +238,12 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff } #if CFG_TUD_MSC_ASYNC_IO - // Simulate read operation + // Simulate background read operation bytes_processed = ret; xTimerStart(sim_io_ops_timer, 0); +#elif SIM_IO_TIME_MS > 0 + // Simulate read operation + tusb_time_delay_ms_api(SIM_IO_TIME_MS); #endif return ret; @@ -284,9 +287,12 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* #endif #if CFG_TUD_MSC_ASYNC_IO - // Simulate read operation + // Simulate background write operation bytes_processed = ret; xTimerStart(sim_io_ops_timer, 0); +#elif SIM_IO_TIME_MS > 0 + // Simulate write operation + tusb_time_delay_ms_api(SIM_IO_TIME_MS); #endif return ret; From 84f8876c7c3639ef4ac707956831311791aefd76 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 16:26:10 +0100 Subject: [PATCH 046/101] Use return code to choose async io. Signed-off-by: HiFiPhile --- src/class/msc/msc_device.c | 26 +++++++----------- src/class/msc/msc_device.h | 56 +++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index c7c926f4e..e3fe5a078 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -78,10 +78,10 @@ typedef struct { uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; -#if CFG_TUD_MSC_ASYNC_IO + + // Async IO uint8_t next_op; uint32_t xferred_bytes; -#endif }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -100,9 +100,7 @@ static void proc_write10_cmd(mscd_interface_t* p_msc); static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); static bool proc_stage_status(mscd_interface_t* p_msc); -#if CFG_TUD_MSC_ASYNC_IO static void tud_msc_async_io_done_cb(void* bytes_processed); -#endif TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); @@ -265,7 +263,6 @@ static inline void set_sense_medium_not_present(uint8_t lun) { tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -#if CFG_TUD_MSC_ASYNC_IO void tud_msc_async_io_done(int32_t bytes_processed) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); @@ -289,7 +286,6 @@ static void tud_msc_async_io_done_cb(void* bytes_processed) { } } } -#endif //--------------------------------------------------------------------+ // USBD Driver API @@ -821,13 +817,12 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { // Application can consume smaller bytes uint32_t const offset = p_msc->xferred_len % block_sz; -#if CFG_TUD_MSC_ASYNC_IO p_msc->next_op = MSC_NEXT_OP_READ10; - tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); -#else nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); - proc_read10_next(p_msc, nbytes); -#endif + if (nbytes != TUD_MSC_RET_ASYNC) { + p_msc->next_op = MSC_NEXT_OP_NONE; + proc_read10_next(p_msc, nbytes); + } } static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { @@ -885,14 +880,13 @@ static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_byte // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; -#if CFG_TUD_MSC_ASYNC_IO p_msc->next_op = MSC_NEXT_OP_WRITE10; p_msc->xferred_bytes = xferred_bytes; - tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); -#else int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); - proc_write10_next(p_msc, xferred_bytes, nbytes); -#endif + if (nbytes != TUD_MSC_RET_ASYNC) { + p_msc->next_op = MSC_NEXT_OP_NONE; + proc_write10_next(p_msc, xferred_bytes, nbytes); + } } static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 407fe241c..7162b11e4 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -48,10 +48,11 @@ #error CFG_TUD_MSC_EP_BUFSIZE must be defined, value of a block size should work well, the more the better #endif -// Enable asynchronous read/write, once operation is finished tud_msc_async_io_done() must be called -#ifndef CFG_TUD_MSC_ASYNC_IO -#define CFG_TUD_MSC_ASYNC_IO 0 -#endif +// Return value of callback functions +// Error +#define TUD_MSC_RET_ERROR -1 +// Asynchronous IO +#define TUD_MSC_RET_ASYNC -16 TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); @@ -62,6 +63,11 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); // Set SCSI sense response bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); +// Called once asynchronous read/write operation is done +// bytes_processed has the same meaning of tud_msc_read10_cb() / +// tud_msc_write10_cb() return value +void tud_msc_async_io_done(int32_t bytes_processed); + //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ @@ -70,34 +76,40 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u // - Address = lba * BLOCK_SIZE + offset // - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. // -// - Application fill the buffer (up to bufsize) with address contents and return number of read byte. If -// - read < bufsize : These bytes are transferred first and callback invoked again for remaining data. +// - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. // -// - read == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. +// - ret < bufsize : These bytes are transferred first and callback will be invoked again for remaining data. // -// - read < 0 : Indicate application error e.g invalid address. This request will be STALLed +// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback will be invoked again with the same parameters later on. +// +// - ret == TUD_MSC_RET_ERROR (-1) +// : Indicate application error e.g invalid address. This request will be STALLed // and return failed status in command status wrapper phase. // -// - In case of asynchronous IO enabled, application should passing reading parameters to background IO -// task and return immediately. Once reading is done, tud_msc_async_io_done() must be called. +// - ret == TUD_MSC_RET_ASYNC (-16) +// : Data reading will be done asynchronously in a background task. Application should return immediately. +// tud_msc_async_io_done() must be called once reading is done to signal completion. int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); // Invoked when received SCSI WRITE10 command // - Address = lba * BLOCK_SIZE + offset // - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. // -// - Application write data from buffer to address contents (up to bufsize) and return number of written byte. If -// - write < bufsize : callback invoked again with remaining data later on. +// - Application writes data from buffer to address contents (up to bufsize) and returns the number of bytes written or status. // -// - write == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback invoked again with the same parameters later on. +// - ret < bufsize : Callback will be invoked again with remaining data later on. // -// - write < 0 : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. +// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. +// Callback will be invoked again with the same parameters later on. // -// - In case of asynchronous IO enabled, application should passing writing parameters to background IO -// task and return immediately. Once writing is done, tud_msc_async_io_done() must be called. +// - ret == TUD_MSC_RET_ERROR (-1) +// : Indicate application error e.g invalid address. This request will be STALLed +// and return failed status in command status wrapper phase. +// +// - ret == TUD_MSC_RET_ASYNC (-16) +// : Data writing will be done asynchronously in a background task. Application should return immediately. +// tud_msc_async_io_done() must be called once writing is done to signal completion. // TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); @@ -131,12 +143,6 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz */ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize); -#if CFG_TUD_MSC_ASYNC_IO -// Called once asynchronous read/write operation is done -// bytes_processed has the same meaning of tud_msc_read10_cb() / -// tud_msc_write10_cb() return value -void tud_msc_async_io_done(int32_t bytes_processed); -#endif /*------------- Optional callbacks -------------*/ // Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation From 2707347decb0ea362fd0a6e4d58102c77f366429 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 16:29:09 +0100 Subject: [PATCH 047/101] Update example. Signed-off-by: HiFiPhile --- .../device/cdc_msc_freertos/src/msc_disk.c | 126 +++++++++++------- .../device/cdc_msc_freertos/src/tusb_config.h | 6 +- 2 files changed, 79 insertions(+), 53 deletions(-) diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index 2f3a1c30b..c75b9ae34 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,16 +28,28 @@ #if CFG_TUD_MSC -// Simulate read/write operation time -#define SIM_IO_TIME_MS 0 +#if CFG_EXAMPLE_MSC_ASYNC_IO -#if CFG_TUD_MSC_ASYNC_IO -TimerHandle_t sim_io_ops_timer; -static int32_t bytes_processed; +#define IO_STACK_SIZE configMINIMAL_STACK_SIZE + +typedef struct { + uint8_t lun; + bool is_read; + uint32_t lba; + uint32_t offset; + void* buffer; + uint32_t bufsize; +} io_ops_t; + +QueueHandle_t io_queue; #if configSUPPORT_STATIC_ALLOCATION -StaticTimer_t sim_io_ops_timer_buf; +uint8_t io_queue_buf[sizeof(io_ops_t)]; +StaticQueue_t io_queue_static; +StackType_t io_stack[IO_STACK_SIZE]; +StaticTask_t io_taskdef; #endif -static void sim_io_ops_done_cb(TimerHandle_t xTimer); + +static void io_task(void *params); #endif void msc_disk_init(void); @@ -133,20 +145,37 @@ uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = README_CONTENTS }; -#if CFG_TUD_MSC_ASYNC_IO +#if CFG_EXAMPLE_MSC_ASYNC_IO void msc_disk_init() { -#if configSUPPORT_DYNAMIC_ALLOCATION - sim_io_ops_timer = xTimerCreate("sim_io_ops", pdMS_TO_TICKS(SIM_IO_TIME_MS), pdFALSE, NULL, sim_io_ops_done_cb); +#if configSUPPORT_STATIC_ALLOCATION + io_queue = xQueueCreateStatic(1, sizeof(io_ops_t), io_queue_buf, &io_queue_static); + xTaskCreateStatic(io_task, "io", IO_STACK_SIZE, NULL, 2, io_stack, &io_taskdef); #else - sim_io_ops_timer = xTimerCreateStatic("sim_io_ops", pdMS_TO_TICKS(SIM_IO_TIME_MS), pdFALSE, NULL, sim_io_ops_done_cb, &sim_io_ops_timer_buf); + io_queue = xQueueCreate(1, sizeof(io_ops_t)); + xTaskCreate(io_task, "io", IO_STACK_SIZE, NULL, 2, NULL); #endif } -static void sim_io_ops_done_cb(TimerHandle_t xTimer) { - (void) xTimer; - tud_msc_async_io_done(bytes_processed); +static void io_task(void *params) { + (void) params; + io_ops_t io_ops; + while (1) { + if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { + if (io_ops.is_read) { + uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset; + memcpy(io_ops.buffer, addr, io_ops.bufsize); + } else { + uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; + memcpy(addr, io_ops.buffer, io_ops.bufsize); + } + + tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); + tud_msc_async_io_done(io_ops.bufsize); + } + } } + #else void msc_disk_init() {} #endif @@ -220,33 +249,31 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; - int32_t ret = bufsize; // out of ramdisk if ( lba >= DISK_BLOCK_NUM ) { - ret = -1; + return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { - ret = -1; + return TUD_MSC_RET_ERROR; } - if (ret != -1) { - uint8_t const* addr = msc_disk[lba] + offset; - memcpy(buffer, addr, bufsize); - } +#if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = { .is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; -#if CFG_TUD_MSC_ASYNC_IO - // Simulate background read operation - bytes_processed = ret; - xTimerStart(sim_io_ops_timer, 0); -#elif SIM_IO_TIME_MS > 0 - // Simulate read operation - tusb_time_delay_ms_api(SIM_IO_TIME_MS); + // Send IO operation to IO task + TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); + + return TUD_MSC_RET_ASYNC; +#else + uint8_t const* addr = msc_disk[lba] + offset; + memcpy(buffer, addr, bufsize); + tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); + + return bufsize; #endif - - return ret; } bool tud_msc_is_writable_cb (uint8_t lun) @@ -264,38 +291,35 @@ bool tud_msc_is_writable_cb (uint8_t lun) // Process data in buffer to disk's storage and return number of written bytes int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { - (void) lun; - int32_t ret = bufsize; - // out of ramdisk if ( lba >= DISK_BLOCK_NUM ) { - ret = -1; + return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { - ret = -1; + return TUD_MSC_RET_ERROR; } -#ifndef CFG_EXAMPLE_MSC_READONLY - if (ret != -1) { - uint8_t* addr = msc_disk[lba] + offset; - memcpy(addr, buffer, bufsize); - } +#ifdef CFG_EXAMPLE_MSC_READONLY + (void) lun; (void) buffer; + return bufsize; +#endif + +#if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = { .is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; + + // Send IO operation to IO task + TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); + + return TUD_MSC_RET_ASYNC; #else - (void) lba; (void) offset; (void) buffer; -#endif + uint8_t* addr = msc_disk[lba] + offset; + memcpy(addr, buffer, bufsize); + tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); -#if CFG_TUD_MSC_ASYNC_IO - // Simulate background write operation - bytes_processed = ret; - xTimerStart(sim_io_ops_timer, 0); -#elif SIM_IO_TIME_MS > 0 - // Simulate write operation - tusb_time_delay_ms_api(SIM_IO_TIME_MS); + return bufsize; #endif - - return ret; } // Callback invoked when received an SCSI command not in built-in list below diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index eb4798017..d70456287 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -114,9 +114,11 @@ // MSC Buffer size of Device Mass storage #define CFG_TUD_MSC_EP_BUFSIZE 512 -// Enable Async IO on MSC -#define CFG_TUD_MSC_ASYNC_IO 0 +// Use async IO in example or not +#define CFG_EXAMPLE_MSC_ASYNC_IO 1 +// Simulate read/write operation delay +#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 #ifdef __cplusplus } From 8d2310247c47160bf8de6e5f754284360ad7e937 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 16:31:47 +0100 Subject: [PATCH 048/101] Fix CI. Signed-off-by: HiFiPhile --- examples/device/cdc_msc_freertos/src/msc_disk.c | 2 ++ src/class/msc/msc_device.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index c75b9ae34..c2aaca847 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -166,8 +166,10 @@ static void io_task(void *params) { uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(io_ops.buffer, addr, io_ops.bufsize); } else { +#ifndef CFG_EXAMPLE_MSC_READONLY uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(addr, io_ops.buffer, io_ops.bufsize); +#endif } tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index e3fe5a078..72c3747fc 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -267,14 +267,14 @@ void tud_msc_async_io_done(int32_t bytes_processed) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); // Call usbd_edpt_xfer() in tud_task() to avoid racing condition - usbd_defer_func(tud_msc_async_io_done_cb, (void*) bytes_processed, false); + usbd_defer_func(tud_msc_async_io_done_cb, (void*) (intptr_t)bytes_processed, false); } static void tud_msc_async_io_done_cb(void* bytes_processed) { TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); uint8_t next_op = _mscd_itf.next_op; _mscd_itf.next_op = MSC_NEXT_OP_NONE; - int32_t nbytes = (int32_t)bytes_processed; + int32_t nbytes = (int32_t)(intptr_t)bytes_processed; // READ10 if (next_op == MSC_NEXT_OP_READ10) { proc_read10_next(&_mscd_itf, nbytes); From c61dfc7c7a4744458b77caa4043af8b05a65fadc Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 9 Sep 2024 18:04:00 +0900 Subject: [PATCH 049/101] Add ch32v20x usbfs hcd initial support. --- hw/bsp/ch32v20x/family.c | 3 + hw/bsp/ch32v20x/family.mk | 3 + src/portable/wch/hcd_ch32_usbfs.c | 618 ++++++++++++++++++++++++++++++ 3 files changed, 624 insertions(+) create mode 100644 src/portable/wch/hcd_ch32_usbfs.c diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 5f52d9447..8a9ee6819 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -32,6 +32,9 @@ void USBHD_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif + #if CFG_TUH_WCH_USBIP_USBFS + tuh_int_handler(0); + #endif } __attribute__((interrupt)) __attribute__((used)) diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 08761dc0d..16fc537ac 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -30,6 +30,8 @@ CFLAGS += -Wno-error=strict-prototypes ifeq ($(PORT),0) $(info "Using FSDEV driver") CFLAGS += -DCFG_TUD_WCH_USBIP_FSDEV=1 + $(info "Using USBFS Host driver") + CFLAGS += -DCFG_TUH_WCH_USBIP_USBFS=1 else $(info "Using USBFS driver") CFLAGS += -DCFG_TUD_WCH_USBIP_USBFS=1 @@ -43,6 +45,7 @@ LD_FILE = $(FAMILY_PATH)/linker/${CH32_FAMILY}.ld SRC_C += \ src/portable/wch/dcd_ch32_usbfs.c \ + src/portable/wch/hcd_ch32_usbfs.c \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ $(SDK_SRC_DIR)/Core/core_riscv.c \ $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_gpio.c \ diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c new file mode 100644 index 000000000..534edb22b --- /dev/null +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -0,0 +1,618 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Mitsumine Suzu (verylowfreq) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUH_WCH_USBIP_USBFS + +#include "host/hcd.h" +#include "host/usbh.h" +#include "host/usbh_pvt.h" + +#include "bsp/board_api.h" + +#include "ch32v20x.h" +#include "ch32v20x_usb.h" + + +#define USBFS_RX_BUF_LEN 64 +#define USBFS_TX_BUF_LEN 64 +__attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; +__attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; + +#define USB_XFER_TIMEOUT_MILLIS 500 + +#define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) + +#define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) + +// Busywait for delay microseconds/nanoseconds +// static void loopdelay(uint32_t count) +// { +// volatile uint32_t c = count / 3; +// // while (c-- != 0); +// asm volatile( +// "1: \n" // loop label +// " addi %0, %0, -1 \n" // c-- +// " bne %0, zero, 1b \n" // if (c != 0) goto loop +// : "+r"(c) // c is input/output operand +// ); +// } + + +// Endpoint status +typedef struct usb_edpt +{ + // Is this a valid struct + bool configured; + + uint8_t dev_addr; + uint8_t ep_addr; + uint16_t max_packet_size; + + // Data toggle (0 or not 0) for DATA0/1 + uint8_t data_toggle; + + // Xfer started time in millis for timeout + uint32_t current_xfer_packet_start_millis; + uint8_t* current_xfer_buffer; + uint16_t current_xfer_bufferlen; + uint16_t current_xfer_xferred_len; + +} usb_edpt_t; + + +static usb_edpt_t usb_edpt_list[8] = { }; + + +static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + usb_edpt_t* cur = &usb_edpt_list[i]; + if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) + { + return cur; + } + } + return NULL; +} + +static usb_edpt_t* get_empty_record_slot(void) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + if (!usb_edpt_list[i].configured) + { + return &usb_edpt_list[i]; + } + } + return NULL; +} + +static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +{ + usb_edpt_t* slot = get_empty_record_slot(); + TU_ASSERT(slot != NULL, NULL); + + slot->dev_addr = dev_addr; + slot->ep_addr = ep_addr; + slot->max_packet_size = max_packet_size; + slot->data_toggle = 0; + slot->current_xfer_packet_start_millis = 0; + slot->current_xfer_buffer = NULL; + slot->current_xfer_bufferlen = 0; + slot->current_xfer_xferred_len = 0; + + slot->configured = true; + + return slot; +} + +static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +{ + usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); + if (ret != NULL) + { + return ret; + } + else + { + return add_edpt_record(dev_addr, ep_addr, max_packet_size); + } +} + + +static void remove_edpt_record_for_device(uint8_t dev_addr) +{ + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) + { + if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) + { + usb_edpt_list[i].configured = false; + } + } +} + + +/** Enable or disable USBFS Host function */ +static void hardware_init_host(bool enabled) +{ + // Reset USBOTG module + USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; + + osal_task_delay(1); + USBOTG_H_FS->BASE_CTRL = 0; + + if (!enabled) + { + // Disable all feature + USBOTG_H_FS->BASE_CTRL = 0; + } + else + { + // Enable USB Host features + NVIC_DisableIRQ(USBFS_IRQn); + USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; + USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; + USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; + USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; + USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + } +} + +static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) +{ + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", + pid, ep_addr, data_toggle); + + if (pid == USB_PID_IN) + { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + } + + uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); + USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; + USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; + USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + return true; +} + + +/** Set device address to communicate */ +static void update_device_address(uint8_t dev_addr) +{ + // Keep the bit of GP_BIT. Other 7bits are actual device address. + USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); +} + +/** Set port speed */ +static void update_port_speed(tusb_speed_t speed) +{ + LOG_CH32_USBFSH("update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); + switch (speed) { + case TUSB_SPEED_LOW: + USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; + return; + case TUSB_SPEED_FULL: + USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; + return; + default: + PANIC("update_port_speed(%d)\r\n", speed); + } +} + +static bool hardware_device_attached(void) +{ + return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; +} + + +//--------------------------------------------------------------------+ +// HCD API +//--------------------------------------------------------------------+ +bool hcd_init(uint8_t rhport) +{ + (void)rhport; + hardware_init_host(true); + + return true; +} + +bool hcd_deinit(uint8_t rhport) +{ + (void)rhport; + hardware_init_host(false); + + return true; +} + +void hcd_port_reset(uint8_t rhport) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_port_reset()\r\n"); + NVIC_DisableIRQ(USBFS_IRQn); + update_device_address( 0x00 ); + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; + osal_task_delay(15); + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + osal_task_delay(2); + + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) + { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) + { + update_port_speed(TUSB_SPEED_LOW); + } + } + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + + return; +} + +void hcd_port_reset_end(uint8_t rhport) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); + // Suppress the attached event + USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; + NVIC_EnableIRQ(USBFS_IRQn); + + return; +} + +bool hcd_port_connect_status(uint8_t rhport) +{ + (void)rhport; + + return hardware_device_attached(); +} + +tusb_speed_t hcd_port_speed_get(uint8_t rhport) +{ + (void)rhport; + if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) + { + return TUSB_SPEED_LOW; + } + else + { + return TUSB_SPEED_FULL; + } +} + +// Close all opened endpoint belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); + remove_edpt_record_for_device(dev_addr); + + return; +} + +uint32_t hcd_frame_number(uint8_t rhport) +{ + (void)rhport; + + return board_millis(); +} + +void hcd_int_enable(uint8_t rhport) +{ + (void)rhport; + NVIC_EnableIRQ(USBFS_IRQn); + + return; +} + +void hcd_int_disable(uint8_t rhport) +{ + (void)rhport; + NVIC_DisableIRQ(USBFS_IRQn); + + return; +} + +void hcd_int_handler(uint8_t rhport, bool in_isr) +{ + (void)rhport; + (void)in_isr; + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) + { + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; + // Read the detection state + bool attached = hardware_device_attached(); + LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); + if (attached) + { + hcd_event_device_attach(rhport, true); + } + else + { + hcd_event_device_remove(rhport, true); + } + return; + } + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) + { + // Copy PID and Endpoint + uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; + uint8_t status = USBOTG_H_FS->INT_ST; + // Clear register to stop transfer + USBOTG_H_FS->HOST_EP_PID = 0; + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + + LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); + + uint8_t request_pid = pid_edpt >> 4; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR; + uint8_t ep_addr = pid_edpt & 0x0f; + if (request_pid == USB_PID_IN) + { + ep_addr |= 0x80; + } + + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) + { + PANIC("\r\nget_edpt_record() returned NULL in USBHD_IRQHandler\r\n"); + } + + if (status & USBFS_UIS_TOG_OK) + { + edpt_info->data_toggle ^= 0x01; + + switch (request_pid) + { + case USB_PID_SETUP: + case USB_PID_OUT: + { + uint16_t xferred_len = edpt_info->current_xfer_bufferlen; + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + case USB_PID_IN: + { + uint16_t received_len = USBOTG_H_FS->RX_LEN; + edpt_info->current_xfer_xferred_len += received_len; + uint16_t xferred_len = edpt_info->current_xfer_xferred_len; + LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); + // if (received_len > 0 && (edpt_info->current_xfer_buffer == NULL || edpt_info->current_xfer_bufferlen == 0)) { + // PANIC("Data received but buffer not set\r\n"); + // } + memcpy(edpt_info->current_xfer_buffer, USBFS_RX_Buf, received_len); + edpt_info->current_xfer_buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == edpt_info->current_xfer_bufferlen)) + { + // USB device sent all data. + LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + else + { + // USB device may send more data. + LOG_CH32_USBFSH("Read more data\r\n"); + hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + return; + } + } + default: + { + PANIC("Unknown PID: 0x%02x\n", request_pid); + } + } + } + else + { + if (response_pid == USB_PID_STALL) + { + LOG_CH32_USBFSH("Data toggle mismatched and STALL\r\n"); + hcd_edpt_clear_stall(0, dev_addr, ep_addr); + edpt_info->data_toggle = 0; + hardware_start_xfer(request_pid, ep_addr, 0); + return; + } + else if (response_pid == USB_PID_NAK) + { + LOG_CH32_USBFSH("Data toggle mismatched and NAK\r\n"); + uint32_t elapsed_time = board_millis() - edpt_info->current_xfer_packet_start_millis; + if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + { + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + } + else + { + hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); + } + return; + } + else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) + { + LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } + else + { + LOG_CH32_USBFSH("\r\nIn USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } + } + } +} + +//--------------------------------------------------------------------+ +// Endpoint API +//--------------------------------------------------------------------+ + +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) +{ + (void)rhport; + uint8_t ep_addr = ep_desc->bEndpointAddress; + uint8_t ep_num = tu_edpt_number(ep_addr); + uint16_t max_packet_size = ep_desc->wMaxPacketSize; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size); + + if (ep_num == 0x00) + { + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size) != NULL, false); + } + else + { + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size) != NULL, false); + } + + update_device_address(dev_addr); + + if (dev_addr == 0x00 && ep_num == 0x00) + { + // It assumes first open for the device, so make the port enable + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + } + + return true; +} + +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) +{ + (void)rhport; + + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) + { + PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); + } + + edpt_info->current_xfer_buffer = buffer; + edpt_info->current_xfer_bufferlen = buflen; + + edpt_info->current_xfer_packet_start_millis = board_millis(); + edpt_info->current_xfer_xferred_len = 0; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + { + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + } + else + { + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + USBOTG_H_FS->HOST_TX_LEN = buflen; + memcpy(USBFS_TX_Buf, buffer, buflen); + return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + } +} + +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) +{ + (void) rhport; + (void) dev_addr; + (void) ep_addr; + LOG_CH32_USBFSH("hcd_edpt_abort_xfer(%d, 0x%02x, 0x%02x)\r\n", rhport, dev_addr, ep_addr); + + return false; +} + +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) +{ + (void)rhport; + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + + + usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); + usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); + TU_ASSERT(edpt_info_tx != NULL, false); + TU_ASSERT(edpt_info_rx != NULL, false); + + // Initialize data toggle (SETUP always starts with DATA0) + // Data toggle for OUT is toggled in hcd_int_handler() + edpt_info_tx->data_toggle = 0; + // Data toggle for IN must be set 0x01 manually. + edpt_info_rx->data_toggle = 0x01; + const uint16_t setup_packet_datalen = 8; + memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); + USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; + + edpt_info_tx->current_xfer_packet_start_millis = board_millis(); + edpt_info_tx->current_xfer_buffer = USBFS_TX_Buf; + edpt_info_tx->current_xfer_bufferlen = setup_packet_datalen; + edpt_info_tx->current_xfer_xferred_len = 0; + + hardware_start_xfer(USB_PID_SETUP, 0, 0); + + return true; +} + +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) +{ + (void) rhport; + (void) dev_addr; + LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); + // PANIC("\r\nstall\r\n"); + uint8_t edpt_num = tu_edpt_number(ep_addr); + uint8_t setup_request_clear_stall[8] = { + 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 + }; + memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); + USBOTG_H_FS->HOST_TX_LEN = 8; + + hcd_int_disable(0); + + USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; + USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; + while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) { } + USBOTG_H_FS->HOST_EP_PID = 0; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + (void)response_pid; + LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + + hcd_int_enable(0); + + return true; +} + +#endif From dc3e6a59a9f50182c09e6301a4f8fcc9a4089722 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 9 Sep 2024 19:00:46 +0900 Subject: [PATCH 050/101] Repeat xfer on USB_PID_OUT if data is larger than MaxPacketSize --- src/portable/wch/hcd_ch32_usbfs.c | 34 ++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 534edb22b..93c5ce519 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -405,9 +405,28 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_SETUP: case USB_PID_OUT: { - uint16_t xferred_len = edpt_info->current_xfer_bufferlen; - hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); - return; + uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; + edpt_info->current_xfer_bufferlen -= tx_len; + edpt_info->current_xfer_xferred_len += tx_len; + if (edpt_info->current_xfer_bufferlen == 0) + { + LOG_CH32_USBFSH("USB_PID_OUT completed %d bytes\r\n", edpt_info->current_xfer_xferred_len); + hcd_event_xfer_complete(dev_addr, ep_addr, edpt_info->current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + return; + } + else + { + LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); + edpt_info->current_xfer_buffer += tx_len; + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > edpt_info->current_xfer_bufferlen) + { + copylen = edpt_info->current_xfer_bufferlen; + } + memcpy(USBFS_TX_Buf, edpt_info->current_xfer_buffer, copylen); + hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + return; + } } case USB_PID_IN: { @@ -541,8 +560,13 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * else { LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); - USBOTG_H_FS->HOST_TX_LEN = buflen; - memcpy(USBFS_TX_Buf, buffer, buflen); + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > buflen) + { + copylen = buflen; + } + USBOTG_H_FS->HOST_TX_LEN = copylen; + memcpy(USBFS_TX_Buf, buffer, copylen); return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); } } From 879f78a91df08f0b3c6df7f56d6dd2293455dbcd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 11 Sep 2024 18:34:48 +0700 Subject: [PATCH 051/101] fix pre-commmit --- src/portable/wch/hcd_ch32_usbfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 93c5ce519..b775d6eee 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -186,7 +186,7 @@ static void hardware_init_host(bool enabled) static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { - LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", pid, ep_addr, data_toggle); @@ -342,7 +342,7 @@ void hcd_int_disable(uint8_t rhport) { (void)rhport; NVIC_DisableIRQ(USBFS_IRQn); - + return; } @@ -492,7 +492,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) } else { - LOG_CH32_USBFSH("\r\nIn USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } @@ -616,7 +616,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void) rhport; (void) dev_addr; LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); - // PANIC("\r\nstall\r\n"); + // PANIC("\r\install\r\n"); uint8_t edpt_num = tu_edpt_number(ep_addr); uint8_t setup_request_clear_stall[8] = { 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 From 7ed5503a5c2bc0b755d97303064614275e74ffb2 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:25:49 +0900 Subject: [PATCH 052/101] Fix the condition related to CFG_TUH_WCH_USBIP_USBFS macro --- hw/bsp/ch32v20x/family.c | 2 +- src/portable/wch/hcd_ch32_usbfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 8a9ee6819..d674ccd6f 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -32,7 +32,7 @@ void USBHD_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif - #if CFG_TUH_WCH_USBIP_USBFS + #if defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS tuh_int_handler(0); #endif } diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index b775d6eee..7e73f686f 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUH_WCH_USBIP_USBFS +#if CFG_TUH_ENABLED && defined(TUP_USBIP_WCH_USBFS) && defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS #include "host/hcd.h" #include "host/usbh.h" From 382dcca5d63c9eff5ade0cf402fc113c68a57857 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Wed, 11 Sep 2024 23:33:19 +0900 Subject: [PATCH 053/101] Update ch32v20x family.cmake --- hw/bsp/ch32v20x/family.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index a5976e0ea..6092abc8d 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -61,6 +61,7 @@ function(add_board_target BOARD_TARGET) if (PORT EQUAL 0) target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_FSDEV=1 + CFG_TUH_WCH_USBIP_USBFS=1 ) elseif (PORT EQUAL 1) target_compile_definitions(${BOARD_TARGET} PUBLIC @@ -127,6 +128,7 @@ function(family_configure_example TARGET RTOS) target_sources(${TARGET} PUBLIC ${TOP}/src/portable/wch/dcd_ch32_usbfs.c + ${TOP}/src/portable/wch/hcd_ch32_usbfs.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) From 426588d947b5c9ac789571019fc2b8da5d756669 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:28:15 +0900 Subject: [PATCH 054/101] Fix for timing, timeout, and device switching issues --- src/portable/wch/hcd_ch32_usbfs.c | 193 ++++++++++++++++++++---------- 1 file changed, 127 insertions(+), 66 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 7e73f686f..ddd366b4f 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -43,24 +43,26 @@ __attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; -#define USB_XFER_TIMEOUT_MILLIS 500 +#define USB_XFER_TIMEOUT_MILLIS 100 +#define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 #define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) // Busywait for delay microseconds/nanoseconds -// static void loopdelay(uint32_t count) -// { -// volatile uint32_t c = count / 3; -// // while (c-- != 0); -// asm volatile( -// "1: \n" // loop label -// " addi %0, %0, -1 \n" // c-- -// " bne %0, zero, 1b \n" // if (c != 0) goto loop -// : "+r"(c) // c is input/output operand -// ); -// } +static void loopdelay(uint32_t count) +{ + volatile uint32_t c = count / 3; + if (c == 0) { return; } + // while (c-- != 0); + asm volatile( + "1: \n" // loop label + " addi %0, %0, -1 \n" // c-- + " bne %0, zero, 1b \n" // if (c != 0) goto loop + : "+r"(c) // c is input/output operand + ); +} // Endpoint status @@ -71,21 +73,30 @@ typedef struct usb_edpt uint8_t dev_addr; uint8_t ep_addr; - uint16_t max_packet_size; + uint8_t max_packet_size; + + uint8_t xfer_type; // Data toggle (0 or not 0) for DATA0/1 uint8_t data_toggle; +} usb_edpt_t; + +static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; + + +typedef struct usb_current_xfer_st { + bool is_busy; + uint8_t dev_addr; + uint8_t ep_addr; // Xfer started time in millis for timeout uint32_t current_xfer_packet_start_millis; uint8_t* current_xfer_buffer; uint16_t current_xfer_bufferlen; uint16_t current_xfer_xferred_len; +} usb_current_xfer_t; -} usb_edpt_t; - - -static usb_edpt_t usb_edpt_list[8] = { }; +static volatile usb_current_xfer_t usb_current_xfer_info = {}; static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) @@ -113,26 +124,26 @@ static usb_edpt_t* get_empty_record_slot(void) return NULL; } -static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { usb_edpt_t* slot = get_empty_record_slot(); + if (slot == NULL) { + PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); + } TU_ASSERT(slot != NULL, NULL); slot->dev_addr = dev_addr; slot->ep_addr = ep_addr; slot->max_packet_size = max_packet_size; + slot->xfer_type = xfer_type; slot->data_toggle = 0; - slot->current_xfer_packet_start_millis = 0; - slot->current_xfer_buffer = NULL; - slot->current_xfer_bufferlen = 0; - slot->current_xfer_xferred_len = 0; slot->configured = true; return slot; } -static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size) +static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); if (ret != NULL) @@ -141,7 +152,7 @@ static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uin } else { - return add_edpt_record(dev_addr, ep_addr, max_packet_size); + return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); } } @@ -157,6 +168,17 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) } } +// static void dump_edpt_record_list() { +// for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { +// usb_edpt_t* cur = &usb_edpt_list[i]; +// if (cur->configured) { +// printf("[%2d] Device 0x%02x Endpoint 0x%02x\r\n", i, cur->dev_addr, cur->ep_addr); +// } else { +// printf("[%2d] not configured\r\n", i); +// } +// } +// } + /** Enable or disable USBFS Host function */ static void hardware_init_host(bool enabled) @@ -180,7 +202,8 @@ static void hardware_init_host(bool enabled) USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; - USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; } } @@ -199,6 +222,7 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; return true; } @@ -371,19 +395,21 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) { + // Disable transfer interrupt + USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; + // Clear the flag + // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; // Copy PID and Endpoint uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; uint8_t status = USBOTG_H_FS->INT_ST; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; // Clear register to stop transfer - USBOTG_H_FS->HOST_EP_PID = 0; - // Clear the flag - USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + // USBOTG_H_FS->HOST_EP_PID = 0x00; LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); uint8_t request_pid = pid_edpt >> 4; - uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; - uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR; + uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; uint8_t ep_addr = pid_edpt & 0x0f; if (request_pid == USB_PID_IN) { @@ -393,7 +419,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); if (edpt_info == NULL) { - PANIC("\r\nget_edpt_record() returned NULL in USBHD_IRQHandler\r\n"); + PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); } if (status & USBFS_UIS_TOG_OK) @@ -406,24 +432,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_OUT: { uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - edpt_info->current_xfer_bufferlen -= tx_len; - edpt_info->current_xfer_xferred_len += tx_len; - if (edpt_info->current_xfer_bufferlen == 0) + usb_current_xfer_info.current_xfer_bufferlen -= tx_len; + usb_current_xfer_info.current_xfer_xferred_len += tx_len; + if (usb_current_xfer_info.current_xfer_bufferlen == 0) { - LOG_CH32_USBFSH("USB_PID_OUT completed %d bytes\r\n", edpt_info->current_xfer_xferred_len); - hcd_event_xfer_complete(dev_addr, ep_addr, edpt_info->current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.current_xfer_xferred_len); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); return; } else { LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - edpt_info->current_xfer_buffer += tx_len; + usb_current_xfer_info.current_xfer_buffer += tx_len; uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > edpt_info->current_xfer_bufferlen) + if (copylen > usb_current_xfer_info.current_xfer_bufferlen) { - copylen = edpt_info->current_xfer_bufferlen; + copylen = usb_current_xfer_info.current_xfer_bufferlen; } - memcpy(USBFS_TX_Buf, edpt_info->current_xfer_buffer, copylen); + memcpy(USBFS_TX_Buf, usb_current_xfer_info.current_xfer_buffer, copylen); hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); return; } @@ -431,18 +458,19 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_IN: { uint16_t received_len = USBOTG_H_FS->RX_LEN; - edpt_info->current_xfer_xferred_len += received_len; - uint16_t xferred_len = edpt_info->current_xfer_xferred_len; + usb_current_xfer_info.current_xfer_xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.current_xfer_xferred_len; LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (edpt_info->current_xfer_buffer == NULL || edpt_info->current_xfer_bufferlen == 0)) { + // if (received_len > 0 && (usb_current_xfer_info.current_xfer_buffer == NULL || usb_current_xfer_info.current_xfer_bufferlen == 0)) { // PANIC("Data received but buffer not set\r\n"); // } - memcpy(edpt_info->current_xfer_buffer, USBFS_RX_Buf, received_len); - edpt_info->current_xfer_buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == edpt_info->current_xfer_bufferlen)) + memcpy(usb_current_xfer_info.current_xfer_buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.current_xfer_buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.current_xfer_bufferlen)) { // USB device sent all data. LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); return; } @@ -464,7 +492,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { if (response_pid == USB_PID_STALL) { - LOG_CH32_USBFSH("Data toggle mismatched and STALL\r\n"); + LOG_CH32_USBFSH("STALL response\r\n"); hcd_edpt_clear_stall(0, dev_addr, ep_addr); edpt_info->data_toggle = 0; hardware_start_xfer(request_pid, ep_addr, 0); @@ -472,10 +500,16 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) } else if (response_pid == USB_PID_NAK) { - LOG_CH32_USBFSH("Data toggle mismatched and NAK\r\n"); - uint32_t elapsed_time = board_millis() - edpt_info->current_xfer_packet_start_millis; - if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + LOG_CH32_USBFSH("NAK reposense\r\n"); + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.current_xfer_packet_start_millis; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT && (elapsed_time > USB_INTERRUPT_XFER_TIMEOUT_MILLIS)) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); + } + else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) + { + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); } else @@ -487,12 +521,14 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) { LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } else { LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); return; } @@ -510,16 +546,17 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const uint8_t ep_addr = ep_desc->bEndpointAddress; uint8_t ep_num = tu_edpt_number(ep_addr); uint16_t max_packet_size = ep_desc->wMaxPacketSize; - LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size); + uint8_t xfer_type = ep_desc->bmAttributes.xfer; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); if (ep_num == 0x00) { - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size) != NULL, false); - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); } else { - TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); } update_device_address(dev_addr); @@ -540,26 +577,36 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * { (void)rhport; + while (usb_current_xfer_info.is_busy) { + osal_task_delay(1); + } + usb_current_xfer_info.is_busy = true; + usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); if (edpt_info == NULL) { PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); } + + update_device_address(dev_addr); + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); - edpt_info->current_xfer_buffer = buffer; - edpt_info->current_xfer_bufferlen = buflen; - - edpt_info->current_xfer_packet_start_millis = board_millis(); - edpt_info->current_xfer_xferred_len = 0; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.current_xfer_buffer = buffer; + usb_current_xfer_info.current_xfer_bufferlen = buflen; + usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); + usb_current_xfer_info.current_xfer_xferred_len = 0; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { - LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); } else { - LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, ep_addr=0x%02x, len=%d\r\n", ep_addr, buflen); + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); uint16_t copylen = USBFS_TX_BUF_LEN; if (copylen > buflen) { @@ -584,8 +631,20 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; + + if (usb_current_xfer_info.is_busy) { + osal_task_delay(1); + } + usb_current_xfer_info.is_busy = true; + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + // loopdelay(SystemCoreClock / 1000000 * 100); + loopdelay(1); + + update_device_address(dev_addr); + tusb_speed_t device_speed = hcd_port_speed_get(rhport); + update_port_speed(device_speed); usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); @@ -600,11 +659,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet const uint16_t setup_packet_datalen = 8; memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; - - edpt_info_tx->current_xfer_packet_start_millis = board_millis(); - edpt_info_tx->current_xfer_buffer = USBFS_TX_Buf; - edpt_info_tx->current_xfer_bufferlen = setup_packet_datalen; - edpt_info_tx->current_xfer_xferred_len = 0; + uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); + usb_current_xfer_info.current_xfer_buffer = USBFS_TX_Buf; + usb_current_xfer_info.current_xfer_bufferlen = setup_packet_datalen; + usb_current_xfer_info.current_xfer_xferred_len = 0; hardware_start_xfer(USB_PID_SETUP, 0, 0); From 9ca4bc89a7e285796e8102eb7a8fd1bbc6fb9938 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:53:58 +0900 Subject: [PATCH 055/101] Update hcd_init() signature. Add osal_task_delay() implementation for none os. --- src/portable/wch/hcd_ch32_usbfs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index ddd366b4f..cbbf90da6 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -37,6 +37,10 @@ #include "ch32v20x.h" #include "ch32v20x_usb.h" +void osal_task_delay(uint32_t msec) { + unsigned long start = board_millis(); + while (board_millis() - start < msec) {} +} #define USBFS_RX_BUF_LEN 64 #define USBFS_TX_BUF_LEN 64 @@ -264,9 +268,10 @@ static bool hardware_device_attached(void) //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport) +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void)rhport; + (void)rh_init; hardware_init_host(true); return true; From cd2b3a53217857930bd8519d074b355ae8933982 Mon Sep 17 00:00:00 2001 From: verylowfreq <60875431+verylowfreq@users.noreply.github.com> Date: Sun, 16 Mar 2025 10:06:27 +0900 Subject: [PATCH 056/101] Fix interupt, LowSpeed switching and rename --- src/portable/wch/hcd_ch32_usbfs.c | 204 ++++++++++++++++-------------- 1 file changed, 111 insertions(+), 93 deletions(-) diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index cbbf90da6..800390989 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -38,7 +38,7 @@ #include "ch32v20x_usb.h" void osal_task_delay(uint32_t msec) { - unsigned long start = board_millis(); + uint32_t start = board_millis(); while (board_millis() - start < msec) {} } @@ -48,25 +48,25 @@ __attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; #define USB_XFER_TIMEOUT_MILLIS 100 -#define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 +// #define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 -#define PANIC(...) do { printf("\r\nPANIC: " __VA_ARGS__); while (true) { } } while (false) +#define PANIC(...) do { printf("%s() L%d: ", __func__, __LINE__); printf("\r\n[PANIC] " __VA_ARGS__); while (true) { } } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) // Busywait for delay microseconds/nanoseconds -static void loopdelay(uint32_t count) -{ - volatile uint32_t c = count / 3; - if (c == 0) { return; } - // while (c-- != 0); - asm volatile( - "1: \n" // loop label - " addi %0, %0, -1 \n" // c-- - " bne %0, zero, 1b \n" // if (c != 0) goto loop - : "+r"(c) // c is input/output operand - ); -} +// static void loopdelay(uint32_t count) +// { +// volatile uint32_t c = count / 3; +// if (c == 0) { return; } +// // while (c-- != 0); +// asm volatile( +// "1: \n" // loop label +// " addi %0, %0, -1 \n" // c-- +// " bne %0, zero, 1b \n" // if (c != 0) goto loop +// : "+r"(c) // c is input/output operand +// ); +// } // Endpoint status @@ -94,10 +94,10 @@ typedef struct usb_current_xfer_st { uint8_t dev_addr; uint8_t ep_addr; // Xfer started time in millis for timeout - uint32_t current_xfer_packet_start_millis; - uint8_t* current_xfer_buffer; - uint16_t current_xfer_bufferlen; - uint16_t current_xfer_xferred_len; + uint32_t start_ms; + uint8_t* buffer; + uint16_t bufferlen; + uint16_t xferred_len; } usb_current_xfer_t; static volatile usb_current_xfer_t usb_current_xfer_info = {}; @@ -184,6 +184,8 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) // } +static bool interrupt_enabled = false; + /** Enable or disable USBFS Host function */ static void hardware_init_host(bool enabled) { @@ -201,7 +203,8 @@ static void hardware_init_host(bool enabled) else { // Enable USB Host features - NVIC_DisableIRQ(USBFS_IRQn); + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(0); USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; @@ -217,10 +220,10 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", pid, ep_addr, data_toggle); - if (pid == USB_PID_IN) - { // FIXME: long delay needed (at release build) about 30msec - // loopdelay(SystemCoreClock / 1000 * 30); - } + // if (pid == USB_PID_IN) + // { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + // } uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; @@ -233,16 +236,16 @@ static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggl /** Set device address to communicate */ -static void update_device_address(uint8_t dev_addr) +static void hardware_update_device_address(uint8_t dev_addr) { // Keep the bit of GP_BIT. Other 7bits are actual device address. USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); } /** Set port speed */ -static void update_port_speed(tusb_speed_t speed) +static void hardware_update_port_speed(tusb_speed_t speed) { - LOG_CH32_USBFSH("update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); + LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); switch (speed) { case TUSB_SPEED_LOW: USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; @@ -255,10 +258,22 @@ static void update_port_speed(tusb_speed_t speed) USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; return; default: - PANIC("update_port_speed(%d)\r\n", speed); + PANIC("hardware_update_port_speed(%d)\r\n", speed); } } + +static void hardware_set_port_address_speed(uint8_t dev_addr) { + hardware_update_device_address(dev_addr); + tusb_speed_t rhport_speed = hcd_port_speed_get(0); + tusb_speed_t dev_speed = tuh_speed_get(dev_addr); + hardware_update_port_speed(dev_speed); + if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + } +} + + static bool hardware_device_attached(void) { return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; @@ -285,28 +300,21 @@ bool hcd_deinit(uint8_t rhport) return true; } + +static bool int_state_for_portreset = false; + void hcd_port_reset(uint8_t rhport) { (void)rhport; LOG_CH32_USBFSH("hcd_port_reset()\r\n"); - NVIC_DisableIRQ(USBFS_IRQn); - update_device_address( 0x00 ); + int_state_for_portreset = interrupt_enabled; + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(rhport); + hardware_update_device_address(0x00); + + // USBOTG_H_FS->HOST_SETUP = 0x00; USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; - osal_task_delay(15); - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; - osal_task_delay(2); - - if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) - { - if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) - { - update_port_speed(TUSB_SPEED_LOW); - } - } - - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; return; } @@ -315,9 +323,27 @@ void hcd_port_reset_end(uint8_t rhport) { (void)rhport; LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); + + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + osal_task_delay(2); + + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) + { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) + { + hardware_update_port_speed(TUSB_SPEED_LOW); + } + } + + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + // Suppress the attached event USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; - NVIC_EnableIRQ(USBFS_IRQn); + + if (int_state_for_portreset) { + hcd_int_enable(rhport); + } return; } @@ -363,6 +389,7 @@ void hcd_int_enable(uint8_t rhport) { (void)rhport; NVIC_EnableIRQ(USBFS_IRQn); + interrupt_enabled = true; return; } @@ -371,6 +398,7 @@ void hcd_int_disable(uint8_t rhport) { (void)rhport; NVIC_DisableIRQ(USBFS_IRQn); + interrupt_enabled = false; return; } @@ -437,25 +465,25 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_OUT: { uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - usb_current_xfer_info.current_xfer_bufferlen -= tx_len; - usb_current_xfer_info.current_xfer_xferred_len += tx_len; - if (usb_current_xfer_info.current_xfer_bufferlen == 0) + usb_current_xfer_info.bufferlen -= tx_len; + usb_current_xfer_info.xferred_len += tx_len; + if (usb_current_xfer_info.bufferlen == 0) { - LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.current_xfer_xferred_len); + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.current_xfer_xferred_len, XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); return; } else { LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - usb_current_xfer_info.current_xfer_buffer += tx_len; + usb_current_xfer_info.buffer += tx_len; uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > usb_current_xfer_info.current_xfer_bufferlen) + if (copylen > usb_current_xfer_info.bufferlen) { - copylen = usb_current_xfer_info.current_xfer_bufferlen; + copylen = usb_current_xfer_info.bufferlen; } - memcpy(USBFS_TX_Buf, usb_current_xfer_info.current_xfer_buffer, copylen); + memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); return; } @@ -463,15 +491,15 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) case USB_PID_IN: { uint16_t received_len = USBOTG_H_FS->RX_LEN; - usb_current_xfer_info.current_xfer_xferred_len += received_len; - uint16_t xferred_len = usb_current_xfer_info.current_xfer_xferred_len; + usb_current_xfer_info.xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.xferred_len; LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (usb_current_xfer_info.current_xfer_buffer == NULL || usb_current_xfer_info.current_xfer_bufferlen == 0)) { + // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { // PANIC("Data received but buffer not set\r\n"); // } - memcpy(usb_current_xfer_info.current_xfer_buffer, USBFS_RX_Buf, received_len); - usb_current_xfer_info.current_xfer_buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.current_xfer_bufferlen)) + memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) { // USB device sent all data. LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); @@ -506,8 +534,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) else if (response_pid == USB_PID_NAK) { LOG_CH32_USBFSH("NAK reposense\r\n"); - uint32_t elapsed_time = board_millis() - usb_current_xfer_info.current_xfer_packet_start_millis; - if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT && (elapsed_time > USB_INTERRUPT_XFER_TIMEOUT_MILLIS)) + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) { usb_current_xfer_info.is_busy = false; hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); @@ -564,16 +592,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); } - update_device_address(dev_addr); - if (dev_addr == 0x00 && ep_num == 0x00) - { - // It assumes first open for the device, so make the port enable - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - } + + hardware_set_port_address_speed(dev_addr); return true; } @@ -582,9 +605,10 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * { (void)rhport; - while (usb_current_xfer_info.is_busy) { - osal_task_delay(1); - } + LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); + + while (usb_current_xfer_info.is_busy) { } + usb_current_xfer_info.is_busy = true; usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); @@ -593,16 +617,14 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); } - update_device_address(dev_addr); - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); + hardware_set_port_address_speed(dev_addr); usb_current_xfer_info.dev_addr = dev_addr; usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.current_xfer_buffer = buffer; - usb_current_xfer_info.current_xfer_bufferlen = buflen; - usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); - usb_current_xfer_info.current_xfer_xferred_len = 0; + usb_current_xfer_info.buffer = buffer; + usb_current_xfer_info.bufferlen = buflen; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.xferred_len = 0; if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { @@ -628,7 +650,6 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void) rhport; (void) dev_addr; (void) ep_addr; - LOG_CH32_USBFSH("hcd_edpt_abort_xfer(%d, 0x%02x, 0x%02x)\r\n", rhport, dev_addr, ep_addr); return false; } @@ -637,19 +658,13 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet { (void)rhport; - if (usb_current_xfer_info.is_busy) { - osal_task_delay(1); - } + while (usb_current_xfer_info.is_busy) { } + usb_current_xfer_info.is_busy = true; LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); - // loopdelay(SystemCoreClock / 1000000 * 100); - loopdelay(1); - - update_device_address(dev_addr); - tusb_speed_t device_speed = hcd_port_speed_get(rhport); - update_port_speed(device_speed); + hardware_set_port_address_speed(dev_addr); usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); @@ -667,10 +682,10 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; usb_current_xfer_info.dev_addr = dev_addr; usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.current_xfer_packet_start_millis = board_millis(); - usb_current_xfer_info.current_xfer_buffer = USBFS_TX_Buf; - usb_current_xfer_info.current_xfer_bufferlen = setup_packet_datalen; - usb_current_xfer_info.current_xfer_xferred_len = 0; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.buffer = USBFS_TX_Buf; + usb_current_xfer_info.bufferlen = setup_packet_datalen; + usb_current_xfer_info.xferred_len = 0; hardware_start_xfer(USB_PID_SETUP, 0, 0); @@ -690,6 +705,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); USBOTG_H_FS->HOST_TX_LEN = 8; + bool prev_int_state = interrupt_enabled; hcd_int_disable(0); USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; @@ -700,7 +716,9 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) (void)response_pid; LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + if (prev_int_state) { hcd_int_enable(0); + } return true; } From e84efd2771858b9f00d78824ccf8b1fade5f103c Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 25 Jan 2025 13:00:41 +0100 Subject: [PATCH 057/101] Add STM32 DWC2 cache support Signed-off-by: HiFiPhile --- src/common/tusb_mcu.h | 15 +++++ src/portable/synopsys/dwc2/dcd_dwc2.c | 2 +- src/portable/synopsys/dwc2/dwc2_stm32.h | 73 +++++++++++++++++++++++++ src/portable/synopsys/dwc2/hcd_dwc2.c | 2 +- 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 2ee2132bf..8b30c98cd 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -220,12 +220,23 @@ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS #endif + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + #elif TU_CHECK_MCU(OPT_MCU_STM32H7) + #include "stm32h7xx.h" #define TUP_USBIP_DWC2 #define TUP_USBIP_DWC2_STM32 #define TUP_DCD_ENDPOINT_MAX 9 + #if __CORTEX_M == 7 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + #endif + #elif TU_CHECK_MCU(OPT_MCU_STM32H5) #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_STM32 @@ -322,6 +333,10 @@ // MCU with on-chip HS Phy #define TUP_RHPORT_HIGHSPEED 1 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + //--------------------------------------------------------------------+ // Sony //--------------------------------------------------------------------+ diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index 5f86d6b76..f7e9aacfe 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -88,7 +88,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc //-------------------------------------------------------------------- // DMA //-------------------------------------------------------------------- -#if CFG_TUD_MEM_DCACHE_ENABLE +#if CFG_TUD_MEM_DCACHE_ENABLE && CFG_TUD_DWC2_DMA_ENABLE bool dcd_dcache_clean(const void* addr, uint32_t data_size) { TU_VERIFY(addr && data_size); return dwc2_dcache_clean(addr, data_size); diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index dc4251c29..f01d11fe8 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -279,6 +279,79 @@ static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { } } +//------------- DCache -------------// +#if (CFG_TUD_MEM_DCACHE_ENABLE && CFG_TUD_DWC2_DMA_ENABLE) || (CFG_TUH_MEM_DCACHE_ENABLE && CFG_TUH_DWC2_DMA_ENABLE) + +typedef struct +{ + uintptr_t start; + uintptr_t end; +} mem_region_t; + +// Can be used to define additional uncached regions +#ifndef CFG_DWC2_MEM_UNCACHED_REGIONS +#define CFG_DWC2_MEM_UNCACHED_REGIONS +#endif + +static mem_region_t uncached_regions[] = { + // DTCM (although USB DMA can't transfer to/from DTCM) +#if CFG_TUSB_MCU == OPT_MCU_STM32H7 + {.start = 0x20000000, .end = 0x2001FFFF}, +#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS + // DTCM (although USB DMA can't transfer to/from DTCM) + {.start = 0x20000000, .end = 0x2002FFFF}, +#elif CFG_TUSB_MCU == OPT_MCU_STM32F7 + // DTCM + {.start = 0x20000000, .end = 0x2000FFFF}, +#else +#error "Cache maintenance is not supported yet" +#endif + CFG_DWC2_MEM_UNCACHED_REGIONS +}; + +TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) { + if (size & (CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) { + size = (size & ~(CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) + CFG_TUD_MEM_DCACHE_LINE_SIZE; + } + return size; +} + +TU_ATTR_ALWAYS_INLINE static inline bool is_cache_mem(uintptr_t addr) { + for (unsigned int i = 0; i < TU_ARRAY_SIZE(uncached_regions); i++) { + if (addr >= uncached_regions[i].start && addr <= uncached_regions[i].end) + return false; + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(void const* addr, uint32_t data_size) { + const uintptr_t addr32 = (uintptr_t) addr; + if (is_cache_mem(addr32)) { + data_size = round_up_to_cache_line_size(data_size); + SCB_CleanDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(void const* addr, uint32_t data_size) { + const uintptr_t addr32 = (uintptr_t) addr; + if (is_cache_mem(addr32)) { + data_size = round_up_to_cache_line_size(data_size); + SCB_InvalidateDCache_by_Addr((void*) addr32, (int32_t) data_size); + } + return true; +} + +TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(void const* addr, uint32_t data_size) { + const uintptr_t addr32 = (uintptr_t) addr; + if (is_cache_mem(addr32)) { + data_size = round_up_to_cache_line_size(data_size); + SCB_CleanInvalidateDCache_by_Addr((uint32_t *) addr32, (int32_t) data_size); + } + return true; +} +#endif + #ifdef __cplusplus } #endif diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 257fa2833..6b48c2346 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -141,7 +141,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } -#if CFG_TUH_MEM_DCACHE_ENABLE +#if CFG_TUH_MEM_DCACHE_ENABLE && CFG_TUH_DWC2_DMA_ENABLE bool hcd_dcache_clean(const void* addr, uint32_t data_size) { TU_VERIFY(addr && data_size); return dwc2_dcache_clean(addr, data_size); From e19ff3ecae3b5a04756749a3d8496e6284f37d85 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 13 Jun 2025 13:17:41 +0200 Subject: [PATCH 058/101] Add cache line size alignment to buffer macro Signed-off-by: HiFiPhile --- src/common/tusb_types.h | 12 ++++++------ src/tusb_option.h | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index fd7f01b67..2099e1af8 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -36,39 +36,39 @@ #endif //------------- Device DCache declaration -------------// -#define TUD_EPBUF_DCACHE_SIZE(_size) (CFG_TUD_MEM_DCACHE_ENABLE ? \ +#define TUD_EPBUF_DCACHE_SIZE(_size) (TUD_EPBUF_DCACHE_ALIGNED ? \ (TU_DIV_CEIL(_size, CFG_TUD_MEM_DCACHE_LINE_SIZE) * CFG_TUD_MEM_DCACHE_LINE_SIZE) : (_size)) // Declare an endpoint buffer with uint8_t[size] #define TUD_EPBUF_DEF(_name, _size) \ union { \ CFG_TUD_MEM_ALIGN uint8_t _name[_size]; \ - uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \ + TU_ATTR_ALIGNED(TUD_EPBUF_DCACHE_ALIGNED ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \ } // Declare an endpoint buffer with a type #define TUD_EPBUF_TYPE_DEF(_type, _name) \ union { \ CFG_TUD_MEM_ALIGN _type _name; \ - uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ + TU_ATTR_ALIGNED(TUD_EPBUF_DCACHE_ALIGNED ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ } //------------- Host DCache declaration -------------// -#define TUH_EPBUF_DCACHE_SIZE(_size) (CFG_TUH_MEM_DCACHE_ENABLE ? \ +#define TUH_EPBUF_DCACHE_SIZE(_size) (TUH_EPBUF_DCACHE_ALIGNED ? \ (TU_DIV_CEIL(_size, CFG_TUH_MEM_DCACHE_LINE_SIZE) * CFG_TUH_MEM_DCACHE_LINE_SIZE) : (_size)) // Declare an endpoint buffer with uint8_t[size] #define TUH_EPBUF_DEF(_name, _size) \ union { \ CFG_TUH_MEM_ALIGN uint8_t _name[_size]; \ - uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \ + TU_ATTR_ALIGNED(TUH_EPBUF_DCACHE_ALIGNED ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \ } // Declare an endpoint buffer with a type #define TUH_EPBUF_TYPE_DEF(_type, _name) \ union { \ CFG_TUH_MEM_ALIGN _type _name; \ - uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ + TU_ATTR_ALIGNED(TUH_EPBUF_DCACHE_ALIGNED ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ } diff --git a/src/tusb_option.h b/src/tusb_option.h index cca6096c6..42c2e650f 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -465,6 +465,13 @@ #define CFG_TUD_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE #endif +#if CFG_TUD_MEM_DCACHE_ENABLE && \ + (CFG_TUD_DWC2_DMA_ENABLE || defined(TUP_USBIP_CHIPIDEA_HS)) + #define TUD_EPBUF_DCACHE_ALIGNED 1 +#else + #define TUD_EPBUF_DCACHE_ALIGNED 0 +#endif + #ifndef CFG_TUD_ENDPOINT0_SIZE #define CFG_TUD_ENDPOINT0_SIZE 64 #endif @@ -584,6 +591,13 @@ #define CFG_TUH_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE #endif +#if CFG_TUH_MEM_DCACHE_ENABLE && \ + (CFG_TUH_DWC2_DMA_ENABLE || defined(TUP_USBIP_CHIPIDEA_HS)) + #define TUH_EPBUF_DCACHE_ALIGNED 1 +#else + #define TUH_EPBUF_DCACHE_ALIGNED 0 +#endif + //------------- CLASS -------------// #ifndef CFG_TUH_HUB From 37316e057d811767f63427ab619cfb08e844ec75 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 25 Jan 2025 13:02:08 +0100 Subject: [PATCH 059/101] hw/h7rs: Enable D-Cache in BSP Signed-off-by: HiFiPhile --- hw/bsp/stm32f7/family.c | 5 +++++ hw/bsp/stm32h7/family.c | 5 +++++ hw/bsp/stm32h7rs/family.c | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/hw/bsp/stm32f7/family.c b/hw/bsp/stm32f7/family.c index 5f63834d0..b82ab7d51 100644 --- a/hw/bsp/stm32f7/family.c +++ b/hw/bsp/stm32f7/family.c @@ -78,6 +78,11 @@ void OTG_HS_IRQHandler(void) { //--------------------------------------------------------------------+ void board_init(void) { + SCB_EnableICache(); + SCB_EnableDCache(); + + HAL_Init(); + board_clock_init(); // Enable All GPIOs clocks diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index f8723b0c7..23bfcb90e 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -98,6 +98,11 @@ static void trace_etm_init(void) { #endif void board_init(void) { + SCB_EnableICache(); + SCB_EnableDCache(); + + HAL_Init(); + // Implemented in board.h SystemClock_Config(); diff --git a/hw/bsp/stm32h7rs/family.c b/hw/bsp/stm32h7rs/family.c index 4b81deea0..b6b2d70e9 100644 --- a/hw/bsp/stm32h7rs/family.c +++ b/hw/bsp/stm32h7rs/family.c @@ -124,9 +124,13 @@ void log_swo_init(void) #endif void board_init(void) { + SCB_EnableICache(); + SCB_EnableDCache(); + HAL_Init(); HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); + // Implemented in board.h SystemClock_Config(); From 424d74373981a75d127889866848bb4aef7a46a6 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 31 Jan 2025 23:52:01 +0100 Subject: [PATCH 060/101] hw/h7rs: Update linker to put RTT in DTCM Signed-off-by: HiFiPhile --- .../boards/stm32h7s3nucleo/board.cmake | 2 -- .../stm32h7rs/boards/stm32h7s3nucleo/board.mk | 4 --- hw/bsp/stm32h7rs/family.cmake | 7 +++-- hw/bsp/stm32h7rs/family.mk | 7 +++-- .../stm32h7s3xx_flash.icf | 6 ++--- .../stm32h7s3xx_flash.ld | 26 ++++++++++++------- 6 files changed, 25 insertions(+), 27 deletions(-) rename hw/bsp/stm32h7rs/{boards/stm32h7s3nucleo => linker}/stm32h7s3xx_flash.icf (93%) rename hw/bsp/stm32h7rs/{boards/stm32h7s3nucleo => linker}/stm32h7s3xx_flash.ld (86%) diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake index f52b70408..aae820aee 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake +++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.cmake @@ -1,9 +1,7 @@ set(MCU_VARIANT stm32h7s3xx) set(JLINK_DEVICE stm32h7s3xx) -set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/stm32h7s3xx_flash.ld) set(LD_FILE_Clang ${LD_FILE_GNU}) -set(LD_FILE_IAR ${CMAKE_CURRENT_LIST_DIR}/stm32h7s3xx_flash.icf) function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk index cf0c2ff54..47055a108 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk +++ b/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/board.mk @@ -7,10 +7,6 @@ JLINK_DEVICE = stm32h7s3xx # flash target using on-board stlink flash: flash-stlink -# Linker -LD_FILE_GCC = $(BOARD_PATH)/stm32h7s3xx_flash.ld -LD_FILE_IAR = $(BOARD_PATH)/stm32h7s3xx_flash.icf - SRC_C += \ $(ST_TCPP0203)/tcpp0203.c \ $(ST_TCPP0203)/tcpp0203_reg.c \ diff --git a/hw/bsp/stm32h7rs/family.cmake b/hw/bsp/stm32h7rs/family.cmake index e5e98f914..e70d37777 100644 --- a/hw/bsp/stm32h7rs/family.cmake +++ b/hw/bsp/stm32h7rs/family.cmake @@ -54,11 +54,11 @@ function(add_board_target BOARD_TARGET) set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s) if(NOT DEFINED LD_FILE_GNU) - set(LD_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/linker/${MCU_VARIANT}_flash.ld) + set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT}_flash.ld) endif() set(LD_FILE_Clang ${LD_FILE_GNU}) if(NOT DEFINED LD_FILE_IAR) - set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf) + set(LD_FILE_IAR ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT}_flash.icf) endif() add_library(${BOARD_TARGET} STATIC @@ -87,8 +87,7 @@ function(add_board_target BOARD_TARGET) BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} BOARD_TUH_RHPORT=${RHPORT_HOST} BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} - SEGGER_RTT_SECTION="noncacheable_buffer" - BUFFER_SIZE_UP=0x3000 + SEGGER_RTT_SECTION=\"dtcm_data\" ) update_board(${BOARD_TARGET}) diff --git a/hw/bsp/stm32h7rs/family.mk b/hw/bsp/stm32h7rs/family.mk index 9970059f8..c60a5c00d 100644 --- a/hw/bsp/stm32h7rs/family.mk +++ b/hw/bsp/stm32h7rs/family.mk @@ -43,8 +43,7 @@ CFLAGS += \ -DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \ -DBOARD_TUH_RHPORT=${RHPORT_HOST} \ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \ - -DSEGGER_RTT_SECTION=\"noncacheable_buffer\" \ - -DBUFFER_SIZE_UP=0x3000 \ + -DSEGGER_RTT_SECTION="dtcm_data" \ # GCC Flags CFLAGS_GCC += \ @@ -91,5 +90,5 @@ SRC_S_GCC += $(ST_CMSIS)/Source/Templates/gcc/startup_$(MCU_VARIANT).s SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s # Linker -LD_FILE_GCC ?= $(ST_CMSIS)/Source/Templates/gcc/linker/$(MCU_VARIANT)_flash.ld -LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf +LD_FILE_GCC ?= $(FAMILY_PATH)/linker/$(MCU_VARIANT)_flash.ld +LD_FILE_IAR ?= $(FAMILY_PATH)/linker/$(MCU_VARIANT)_flash.icf diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf similarity index 93% rename from hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf rename to hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf index 8ffaa74a7..8398fa07b 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.icf +++ b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf @@ -4,7 +4,7 @@ /*-Specials-*/ define symbol __ICFEDIT_intvec_start__ = 0x08000000; /*-Memory Regions-*/ -define symbol NONCACHEABLEBUFFER_size = 0x4000; +define symbol NONCACHEABLEBUFFER_size = 0x400; define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; define symbol __ICFEDIT_region_ROM_end__ = 0x0800FFFF; define symbol __ICFEDIT_region_RAM_start__ = 0x24000000; @@ -14,7 +14,7 @@ define symbol NONCACHEABLEBUFFER_end = __ICFEDIT_region_RAM_end__ + NONCAC /*-Sizes-*/ -define symbol __ICFEDIT_size_cstack__ = 0x800; +define symbol __ICFEDIT_size_cstack__ = 0x400; define symbol __ICFEDIT_size_heap__ = 0x200; /**** End of ICF editor section. ###ICF###*/ @@ -51,5 +51,5 @@ place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; place in ROM_region { readonly }; place in RAM_region { readwrite }; +place in DTCM_region { block CSTACK, block HEAP, section dtcm_data }; place in NONCACHEABLE_region { section noncacheable_buffer }; -place in DTCM_region { block CSTACK, block HEAP }; diff --git a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld similarity index 86% rename from hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld rename to hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld index 3bd7f0b89..86acf9742 100644 --- a/hw/bsp/stm32h7rs/boards/stm32h7s3nucleo/stm32h7s3xx_flash.ld +++ b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld @@ -35,15 +35,19 @@ /* Entry Point */ ENTRY(Reset_Handler) +/* Highest address of the user mode stack */ +_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of "DTCM" Ram type memory */ + _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */ __FLASH_BEGIN = 0x08000000; __FLASH_SIZE = 0x00010000; + __RAM_BEGIN = 0x24000000; __RAM_SIZE = 0x4FC00; -__RAM_NONCACHEABLEBUFFER_SIZE = 0x4000; +__RAM_NONCACHEABLEBUFFER_SIZE = 0x400; /* Memories definition */ MEMORY @@ -59,9 +63,6 @@ MEMORY FLASH (xrw) : ORIGIN = __FLASH_BEGIN, LENGTH = __FLASH_SIZE } -/* Highest address of the user mode stack */ -_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of "DTCM" Ram type memory */ - /* Sections */ SECTIONS { @@ -99,14 +100,14 @@ SECTIONS . = ALIGN(4); } >FLASH - .ARM.extab : + .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ { . = ALIGN(4); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } >FLASH - .ARM : + .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ { . = ALIGN(4); __exidx_start = .; @@ -115,7 +116,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .preinit_array : + .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ { . = ALIGN(4); PROVIDE_HIDDEN (__preinit_array_start = .); @@ -124,7 +125,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .init_array : + .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ { . = ALIGN(4); PROVIDE_HIDDEN (__init_array_start = .); @@ -134,7 +135,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .fini_array : + .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ { . = ALIGN(4); PROVIDE_HIDDEN (__fini_array_start = .); @@ -182,7 +183,7 @@ SECTIONS { __NONCACHEABLEBUFFER_BEGIN = .;/* create symbol for start of section */ KEEP(*(noncacheable_buffer)) - __NONCACHEABLEBUFFER_END = .; /* create symbol for start of section */ + __NONCACHEABLEBUFFER_END = .; /* create symbol for end of section */ } > RAM_NONCACHEABLEBUFFER /* User_heap_stack section, used to check that there is enough "DTCM" Ram type memory left */ @@ -196,6 +197,11 @@ SECTIONS . = ALIGN(8); } >DTCM + .dtcm_data : + { + *(dtcm_data) + } >DTCM + /* Remove information from the compiler libraries */ /DISCARD/ : { From ea02e929b4daafb28be30b08609a6f68f64e2a0d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 13 Jun 2025 18:44:05 +0200 Subject: [PATCH 061/101] audio: buffer macro update Signed-off-by: HiFiPhile --- src/class/audio/audio_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 11a3d4a73..dc45a72bc 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -109,14 +109,14 @@ // Put swap buffer in USB section only if necessary #if USE_LINEAR_BUFFER - #define IN_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) + #define IN_SW_BUF_MEM_ATTR #else - #define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN + #define IN_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION #endif #if USE_LINEAR_BUFFER - #define OUT_SW_BUF_MEM_ATTR TU_ATTR_ALIGNED(4) + #define OUT_SW_BUF_MEM_ATTR #else - #define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN + #define OUT_SW_BUF_MEM_ATTR CFG_TUD_MEM_SECTION #endif // EP IN software buffers and mutexes From d4abf43f226b5594c935c60c38d05a90359763e1 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Jun 2025 22:16:13 +0700 Subject: [PATCH 062/101] add common cdch_process_set_config() to safely complete set_config() when it failed. driver_process_set_config() also pass drv index with user_data --- examples/host/cdc_msc_hid/src/cdc_app.c | 13 +- src/class/cdc/cdc_host.c | 887 ++++++++++++------------ 2 files changed, 453 insertions(+), 447 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index e68ec383b..6f4433f22 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -31,8 +31,7 @@ static size_t get_console_inputs(uint8_t* buf, size_t bufsize) { size_t count = 0; while (count < bufsize) { int ch = board_getchar(); - if (ch <= 0) break; - + if (ch <= 0) { break; } buf[count] = (uint8_t) ch; count++; } @@ -69,10 +68,12 @@ void tuh_cdc_rx_cb(uint8_t idx) { uint32_t const bufsize = sizeof(buf) - 1; // forward cdc interfaces -> console - uint32_t count = tuh_cdc_read(idx, buf, bufsize); - buf[count] = 0; - - printf("%s", (char*) buf); + const uint32_t count = tuh_cdc_read(idx, buf, bufsize); + if (count) { + buf[count] = 0; + printf("%s", (char*) buf); + fflush(stdout); + } } // Invoked when a device with CDC interface is mounted diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 5d5da9796..b6e9cb297 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,17 +52,6 @@ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) #define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) -// assert and set config complete -#define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \ - do { \ - if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \ - } while(0) - -#define TU_ASSERT_COMPLETE_1ARGS(_cond) TU_ASSERT_COMPLETE_DEFINE(_cond, 0) -#define TU_ASSERT_COMPLETE_2ARGS(_cond, _itf_offset) TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) - -#define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__) - // handle line control defines #if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) @@ -142,9 +131,14 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ +// for process_set_config user_data: idx (byte1) and state (byte0) +#define PROCESS_CONFIG_STATE(_idx, _state) tu_u16(_idx, _state) + +static void cdch_process_set_config(tuh_xfer_t *xfer); + //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static void acm_process_config(tuh_xfer_t * xfer); +static bool acm_process_set_config(tuh_xfer_t * xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -159,7 +153,7 @@ static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; #endif static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); -static void ftdi_process_config(tuh_xfer_t * xfer); +static bool ftdi_proccess_set_config(tuh_xfer_t * xfer); static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -172,7 +166,7 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static void cp210x_process_config(tuh_xfer_t * xfer); +static bool cp210x_process_set_config(tuh_xfer_t * xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -185,7 +179,7 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static void ch34x_process_config(tuh_xfer_t * xfer); +static bool ch34x_process_set_config(tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -201,7 +195,7 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static void pl2303_process_config(tuh_xfer_t * xfer); +static bool pl2303_process_set_config(tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -236,7 +230,7 @@ typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); - void (*const process_set_config)(tuh_xfer_t * xfer); + bool (*const process_set_config)(tuh_xfer_t * xfer); bool (*const set_control_line_state)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -252,7 +246,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = NULL, .vid_pid_count = 0, .open = acm_open, - .process_set_config = acm_process_config, + .process_set_config = acm_process_set_config, .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, @@ -267,7 +261,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = ftdi_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), .open = ftdi_open, - .process_set_config = ftdi_process_config, + .process_set_config = ftdi_proccess_set_config, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -283,7 +277,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = cp210x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), .open = cp210x_open, - .process_set_config = cp210x_process_config, + .process_set_config = cp210x_process_set_config, .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, @@ -299,7 +293,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = ch34x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), .open = ch34x_open, - .process_set_config = ch34x_process_config, + .process_set_config = ch34x_process_set_config, .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, @@ -315,7 +309,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), .open = pl2303_open, - .process_set_config = pl2303_process_config, + .process_set_config = pl2303_process_set_config, .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -378,9 +372,8 @@ static bool open_ep_stream_pair(cdch_interface_t * p_cdc , tusb_desc_endpoint_t uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num) { for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { const cdch_interface_t * p_cdc = &cdch_data[i]; - if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i; + if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) { return i; } } - return TUSB_INDEX_INVALID_8; } @@ -642,18 +635,18 @@ bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uin } bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdc_line_control_state_t const line_state = { .rts = rts_state, .dtr = p_cdc->line_state.dtr }; + cdc_line_control_state_t const line_state = {.rts = rts_state, .dtr = p_cdc->line_state.dtr}; return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set baudrate %lu", baudrate); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.bit_rate = baudrate; @@ -669,12 +662,12 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding.stop_bits = stop_bits; p_cdc->requested_line_coding.parity = parity; @@ -692,15 +685,15 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin return ret; } -bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const * line_coding, +bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set line coding %lu %u%c%s", line_coding->bit_rate, line_coding->data_bits, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_coding = *line_coding; @@ -722,8 +715,8 @@ bool cdch_init(void) { TU_LOG_DRV("sizeof(cdch_interface_t) = %u\r\n", sizeof(cdch_interface_t)); tu_memclr(cdch_data, sizeof(cdch_data)); for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; - cdch_epbuf_t* epbuf = &cdch_epbuf[i]; + cdch_interface_t *p_cdc = &cdch_data[i]; + cdch_epbuf_t *epbuf = &cdch_epbuf[i]; tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false, p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE, epbuf->tx, CFG_TUH_CDC_TX_EPSIZE); @@ -738,7 +731,7 @@ bool cdch_init(void) { bool cdch_deinit(void) { for (size_t i = 0; i < CFG_TUH_CDC; i++) { - cdch_interface_t* p_cdc = &cdch_data[i]; + cdch_interface_t *p_cdc = &cdch_data[i]; tu_edpt_stream_deinit(&p_cdc->stream.tx); tu_edpt_stream_deinit(&p_cdc->stream.rx); } @@ -747,7 +740,7 @@ bool cdch_deinit(void) { void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { - cdch_interface_t * p_cdc = &cdch_data[idx]; + cdch_interface_t *p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { TU_LOG_P_CDC("close"); @@ -770,7 +763,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t TU_VERIFY(event == XFER_RESULT_SUCCESS); uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr); - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc); if (ep_addr == p_cdc->stream.tx.ep_addr) { @@ -779,31 +772,36 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t tuh_cdc_tx_complete_cb(idx); } - if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { + if (0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx)) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); } } else if (ep_addr == p_cdc->stream.rx.ep_addr) { #if CFG_TUH_CDC_FTDI - if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI && xferred_bytes > 2) { + if (p_cdc->serial_drid == SERIAL_DRIVER_FTDI) { // FTDI reserve 2 bytes for status // uint8_t status[2] = {p_cdc->stream.rx.ep_buf[0], p_cdc->stream.rx.ep_buf[1]}; - tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf+2, xferred_bytes-2); - }else + if (xferred_bytes > 2) { + tu_edpt_stream_read_xfer_complete_with_buf(&p_cdc->stream.rx, p_cdc->stream.rx.ep_buf + 2, xferred_bytes - 2); + + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); // invoke receive callback + } + } + } else #endif { tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes); - } - // invoke receive callback - if (tuh_cdc_rx_cb) { - tuh_cdc_rx_cb(idx); + if (tuh_cdc_rx_cb) { + tuh_cdc_rx_cb(idx); // invoke receive callback + } } // prepare for next transfer if needed tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); - }else if ( ep_addr == p_cdc->ep_notif ) { + } else if (ep_addr == p_cdc->ep_notif) { // TODO handle notification endpoint } else { TU_ASSERT(false); @@ -816,7 +814,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // Enumeration //--------------------------------------------------------------------+ -static bool open_ep_stream_pair(cdch_interface_t * p_cdc, tusb_desc_endpoint_t const * desc_ep) { +static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t const *desc_ep) { for (size_t i = 0; i < 2; i++) { TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); @@ -834,9 +832,9 @@ static bool open_ep_stream_pair(cdch_interface_t * p_cdc, tusb_desc_endpoint_t c return true; } -bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { +bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - cdch_serial_driver_t const * driver_detected = NULL; + cdch_serial_driver_t const *driver_detected = NULL; // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device @@ -849,7 +847,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - cdch_serial_driver_t const * driver = &serial_drivers[dr]; + cdch_serial_driver_t const *driver = &serial_drivers[dr]; for (size_t i = 0; i < driver->vid_pid_count; i++) { if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { driver_detected = driver; @@ -865,7 +863,7 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ if (driver_detected) { TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); bool ret = driver_detected->open(daddr, itf_desc, max_len); -// TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); + // TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); return ret; } @@ -873,8 +871,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const * itf_ } static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { @@ -894,22 +892,32 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } +static void cdch_process_set_config(tuh_xfer_t *xfer) { + const uint8_t idx = tu_u32_byte1(xfer->user_data); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + + if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(idx, itf_offset, false); + } +} + bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_P_CDC("set config"); // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; - xfer.daddr = daddr; + xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; - xfer.setup = &request; - xfer.user_data = 0; // initial state 0 - - serial_drivers[p_cdc->serial_drid].process_set_config(&xfer); + xfer.setup = &request; + xfer.user_data = PROCESS_CONFIG_STATE(idx, 0); // initial state 0 + cdch_process_set_config(&xfer); return true; } @@ -921,11 +929,11 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void acm_internal_control_complete(tuh_xfer_t * xfer) { +static void acm_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -949,7 +957,7 @@ static void acm_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); tusb_control_request_t const request = { @@ -980,10 +988,10 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c return true; } -static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm_capability.support_line_request); TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || - p_cdc->requested_line_coding.data_bits == 16); + p_cdc->requested_line_coding.data_bits == 16); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -998,7 +1006,7 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete }; // use usbh enum buf to hold line coding since user line_coding variable does not live long enough - uint8_t * enum_buf = usbh_get_enum_buf(); + uint8_t *enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); p_cdc->user_control_cb = complete_cb; @@ -1017,13 +1025,13 @@ static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete return true; } -static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } -static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -1036,19 +1044,19 @@ static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb enum { CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE, + CONFIG_ACM_COMPLETE }; -static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { - uint8_t const * p_desc_end = ((uint8_t const *) itf_desc) + max_len; +static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { + uint8_t const *p_desc_end = ((uint8_t const *) itf_desc) + max_len; - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_ACM; //------------- Control Interface -------------// - uint8_t const * p_desc = tu_desc_next(itf_desc); + uint8_t const *p_desc = tu_desc_next(itf_desc); // Communication Functional Descriptors while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { @@ -1063,7 +1071,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint // Open notification endpoint of control interface if any if (itf_desc->bNumEndpoints == 1) { TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)); - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; TU_ASSERT(tuh_edpt_open(daddr, desc_ep)); p_cdc->ep_notif = desc_ep->bEndpointAddress; @@ -1084,31 +1092,31 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint return true; } -static void acm_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool acm_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_SET_LINE_CODING))); + break; + } #endif TU_ATTR_FALLTHROUGH; case CONFIG_ACM_SET_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE), 1); - break; - } + if (p_cdc->acm_capability.support_line_request) { + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_COMPLETE))); + break; + } #endif TU_ATTR_FALLTHROUGH; @@ -1118,9 +1126,10 @@ static void acm_process_config(tuh_xfer_t * xfer) { break; default: - set_config_complete(idx, 1, false); - break; + return false; // invalid state } + + return true; } //--------------------------------------------------------------------+ @@ -1128,14 +1137,14 @@ static void acm_process_config(tuh_xfer_t * xfer) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_FTDI -static bool ftdi_determine_type(cdch_interface_t * p_cdc); -static uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc); -static uint8_t ftdi_get_idx(tuh_xfer_t * xfer); +static bool ftdi_determine_type(cdch_interface_t *p_cdc); +static uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc); +static uint8_t ftdi_get_idx(tuh_xfer_t *xfer); //------------- Control Request -------------// // set request without data -static bool ftdi_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, +static bool ftdi_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType = requesttype, @@ -1167,37 +1176,36 @@ static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latenc } #endif -static inline bool ftdi_sio_reset(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ftdi_set_request(p_cdc, FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, p_cdc->ftdi.channel, complete_cb, user_data); } -static bool ftdi_change_speed(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint32_t index_value = ftdi_get_divisor(p_cdc); TU_VERIFY(index_value); uint16_t value = (uint16_t) index_value; uint16_t index = (uint16_t) (index_value >> 16); if (p_cdc->ftdi.channel) { - index = (uint16_t)((index << 8) | p_cdc->ftdi.channel); + index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); } return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, value, index, complete_cb, user_data); } -static bool ftdi_set_data_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ( - (p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11 ); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits + uint16_t value = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); } -static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); @@ -1208,10 +1216,10 @@ static inline bool ftdi_update_mctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t com //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding -static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { +static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -1238,24 +1246,24 @@ static void ftdi_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } -static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format @@ -1272,7 +1280,7 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet complete_cb, user_data); } -static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); @@ -1293,19 +1301,19 @@ enum { CONFIG_FTDI_COMPLETE }; -static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len) { +static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint16_t max_len) { // FTDI Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0xff && itf_desc->bInterfaceProtocol == 0xff && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_FTDI; // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); /* * NOTE: Some customers have programmed FT232R/FT245R devices @@ -1317,22 +1325,20 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uin return open_ep_stream_pair(p_cdc, desc_ep); } -static void ftdi_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + cdch_interface_t *p_cdc = get_itf(idx); uint8_t const itf_num = p_cdc->bInterfaceNumber; + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch(state) { - + switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() case CONFIG_FTDI_GET_DESC: // get device descriptor - p_cdc->user_control_cb = ftdi_process_config; // set once for whole process config - if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - ftdi_process_config, CONFIG_FTDI_DETERMINE_TYPE)); + if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 + TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_DETERMINE_TYPE))); break; } TU_ATTR_FALLTHROUGH; @@ -1340,66 +1346,67 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { - TU_ASSERT_COMPLETE(ftdi_determine_type(p_cdc)); + TU_ASSERT(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 uint8_t const idx_itf0 = tuh_cdc_itf_get_index(xfer->daddr, 0); - cdch_interface_t const * p_cdc_itf0 = get_itf(idx_itf0); - TU_ASSERT_COMPLETE(p_cdc_itf0); - if (p_cdc_itf0) { - p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; - } + cdch_interface_t const *p_cdc_itf0 = get_itf(idx_itf0); + TU_ASSERT(p_cdc_itf0); + p_cdc->ftdi.chip_type = p_cdc_itf0->ftdi.chip_type; } TU_ATTR_FALLTHROUGH; case CONFIG_FTDI_WRITE_LATENCY: #ifdef CFG_TUH_CDC_FTDI_LATENCY - int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, - CONFIG_FTDI_SIO_RESET); - TU_ASSERT_COMPLETE(result != FTDI_FAIL); - if(result == FTDI_REQUESTED) { - break; - } // else FTDI_NOT_POSSIBLE => continue directly with next state + int8_t result = ftdi_write_latency_timer(p_cdc, CFG_TUH_CDC_FTDI_LATENCY, ftdi_process_config, + CONFIG_FTDI_SIO_RESET); + TU_ASSERT(result != FTDI_FAIL); + if (result == FTDI_REQUESTED) { + break; + }// else FTDI_NOT_POSSIBLE => continue directly with next state #endif TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function ftdi_open() + // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA)); + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_DATA))); break; - // from here sequence overtaken from Linux Kernel function ftdi_set_termios() + // from here sequence overtaken from Linux Kernel function ftdi_set_termios() case CONFIG_FTDI_SET_DATA: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); - break; + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_BAUDRATE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT_COMPLETE(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); - break; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_FLOW_CONTROL))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_FLOW_CONTROL: // disable flow control - TU_ASSERT_COMPLETE(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - FTDI_SIO_DISABLE_FLOW_CTRL, p_cdc->ftdi.channel, - ftdi_process_config, CONFIG_FTDI_MODEM_CTRL)); + TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, + p_cdc->ftdi.channel, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_MODEM_CTRL))); break; case CONFIG_FTDI_MODEM_CTRL: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_COMPLETE: @@ -1407,15 +1414,15 @@ static void ftdi_process_config(tuh_xfer_t * xfer) { break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } //------------- Helper -------------// -static bool ftdi_determine_type(cdch_interface_t * p_cdc) -{ +static bool ftdi_determine_type(cdch_interface_t *p_cdc) { uint16_t const version = desc_dev->bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; @@ -1527,28 +1534,27 @@ static bool ftdi_determine_type(cdch_interface_t * p_cdc) //} static uint32_t ftdi_232bm_baud_base_to_divisor(uint32_t baud, uint32_t base) { - uint8_t divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; + uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7}; uint32_t divisor; /* divisor shifted 3 bits to the left */ uint32_t divisor3 = DIV_ROUND_CLOSEST(base, 2 * baud); divisor = divisor3 >> 3; - divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) /* 1.0 */ + if (divisor == 1) /* 1.0 */ { divisor = 0; - else if (divisor == 0x4001) /* 1.5 */ + } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } return divisor; } -static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) -{ - return ftdi_232bm_baud_base_to_divisor(baud, 48000000); +static inline uint32_t ftdi_232bm_baud_to_divisor(uint32_t baud) { + return ftdi_232bm_baud_base_to_divisor(baud, 48000000); } -static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) -{ - static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; +static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) { + static const unsigned char divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7}; uint32_t divisor; uint32_t divisor3; @@ -1556,12 +1562,13 @@ static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) divisor3 = DIV_ROUND_CLOSEST(8 * base, 10 * baud); divisor = divisor3 >> 3; - divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14; + divisor |= (uint32_t) divfrac[divisor3 & 0x7] << 14; /* Deal with special cases for highest baud rates. */ - if (divisor == 1) /* 1.0 */ + if (divisor == 1) /* 1.0 */ { divisor = 0; - else if (divisor == 0x4001) /* 1.5 */ + } else if (divisor == 0x4001) /* 1.5 */ { divisor = 1; + } /* * Set this bit to turn off a divide by 2.5 on baud rate generator * This enables baud rates up to 12Mbaud but cannot reach below 1200 @@ -1571,13 +1578,11 @@ static uint32_t ftdi_2232h_baud_base_to_divisor(uint32_t baud, uint32_t base) return divisor; } -static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) -{ - return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); +static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) { + return ftdi_2232h_baud_base_to_divisor(baud, (uint32_t) 120000000); } -static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) -{ +static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t div_value = 0; TU_VERIFY(baud); @@ -1646,13 +1651,13 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t * p_cdc) return div_value; } -static uint8_t ftdi_get_idx(tuh_xfer_t * xfer) { - uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); // channel index, or 0 for legacy types +static uint8_t ftdi_get_idx(tuh_xfer_t *xfer) { + uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex);// channel index, or 0 for legacy types for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t * p_cdc = &cdch_data[i]; + const cdch_interface_t *p_cdc = &cdch_data[i]; if (p_cdc->daddr == xfer->daddr && (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) - channel == p_cdc->ftdi.channel)) { // or multi-channel types (interfaces 0..n) + channel == p_cdc->ftdi.channel)) {// or multi-channel types (interfaces 0..n) return i; } } @@ -1703,29 +1708,28 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 return tuh_control_xfer(&xfer); } -static inline bool cp210x_ifc_enable(cdch_interface_t * p_cdc, uint16_t enabled, +static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } -static bool cp210x_set_baudrate_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } -static bool cp210x_set_line_ctl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ( - (p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding + uint16_t lcr = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } -static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | @@ -1736,16 +1740,16 @@ static inline bool cp210x_set_mhs(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { +static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); if (success) { - switch(xfer->setup->bRequest) { + switch (xfer->setup->bRequest) { case CP210X_SET_MHS: p_cdc->line_state = p_cdc->requested_line_state; break; @@ -1770,21 +1774,21 @@ static void cp210x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } -static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } -static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); set_line_coding_stage1_complete(xfer, itf_num, cp210x_set_line_ctl, // control request function to set data format @@ -1792,7 +1796,7 @@ static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { } // 2 stages: set baudrate (stage1) + set data format (stage2) -static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return set_line_coding_sequence(p_cdc, cp210x_set_baudrate_request, // control request function to set baudrate cp210x_set_line_ctl, // control request function to set data format @@ -1801,7 +1805,7 @@ static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t compl complete_cb, user_data); } -static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); @@ -1818,64 +1822,66 @@ enum { CONFIG_CP210X_COMPLETE }; -static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { +static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { // CP210x Interface includes 1 vendor interface + 2 bulk endpoints TU_VERIFY(itf_desc->bInterfaceSubClass == 0 && itf_desc->bInterfaceProtocol == 0 && itf_desc->bNumEndpoints == 2); - TU_VERIFY(sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t) <= max_len); + TU_VERIFY(sizeof(tusb_desc_interface_t) + 2 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_CP210X; // endpoint pair - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); // data endpoints expected to be in pairs return open_ep_stream_pair(p_cdc, desc_ep); } -static void cp210x_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); +static bool cp210x_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: - p_cdc->user_control_cb = cp210x_process_config; // set once for whole process config - TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cp210x_process_config, - CONFIG_CP210X_SET_BAUDRATE_REQUEST)); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_BAUDRATE_REQUEST))); break; case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_SET_LINE_CTL)); - break; + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_LINE_CTL))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - TU_ASSERT_COMPLETE(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_SET_DTR_RTS)); - break; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_DTR_RTS))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_SET_DTR_RTS: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, - CONFIG_CP210X_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CP210X_COMPLETE: @@ -1883,9 +1889,10 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } #endif @@ -1896,13 +1903,13 @@ static void cp210x_process_config(tuh_xfer_t * xfer) { #if CFG_TUH_CDC_CH34X -static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc); -static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc); +static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc); +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc); //------------- Control Request -------------// -static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8_t request, - uint16_t value, uint16_t index, uint8_t * buffer, uint16_t length, +static bool ch34x_set_request(cdch_interface_t *p_cdc, uint8_t direction, uint8_t request, + uint16_t value, uint16_t index, uint8_t *buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType_bit = { @@ -1917,7 +1924,7 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 }; // use usbh enum buf since application variable does not live long enough - uint8_t * enum_buf = NULL; + uint8_t *enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -1938,18 +1945,18 @@ static bool ch34x_set_request(cdch_interface_t * p_cdc, uint8_t direction, uint8 return tuh_control_xfer(&xfer); } -static inline bool ch34x_control_out(cdch_interface_t * p_cdc, uint8_t request, uint16_t value, uint16_t index, +static inline bool ch34x_control_out(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); } -static inline bool ch34x_control_in(cdch_interface_t * p_cdc, uint8_t request, uint16_t value, uint16_t index, - uint8_t * buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static inline bool ch34x_control_in(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data); } -static inline bool ch34x_write_reg(cdch_interface_t * p_cdc, uint16_t reg, uint16_t reg_value, +static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16_t reg_value, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } @@ -1960,36 +1967,33 @@ static inline bool ch34x_write_reg(cdch_interface_t * p_cdc, uint16_t reg, uint1 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_VERIFY(lcr); - return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); } -static bool ch34x_write_reg_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); TU_VERIFY(div_ps); - return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); } -static bool ch34x_modem_ctrl_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | // CH34x signals are inverted +static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) |// CH34x signals are inverted (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); - return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { +static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); @@ -2028,21 +2032,21 @@ static void ch34x_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } -static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t * xfer) { +static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, @@ -2103,20 +2107,19 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui return true; } -static void ch34x_process_config(tuh_xfer_t* xfer) { - uintptr_t const state = xfer->user_data; - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; +static bool ch34x_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; + uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - uint8_t buffer[2]; // TODO remove + cdch_interface_t *p_cdc = get_itf(idx); + uint8_t buffer[2];// TODO remove + + TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CH34X_READ_VERSION: - p_cdc->user_control_cb = ch34x_process_config; // set once for whole process config - TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - ch34x_process_config, CONFIG_CH34X_SERIAL_INIT)); + TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SERIAL_INIT))); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2125,39 +2128,39 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { TU_LOG_P_CDC("Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD - TU_ASSERT_COMPLETE(version >= 0x30); - // init CH34x with line coding - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_ASSERT_COMPLETE(div_ps); - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_ASSERT_COMPLETE(lcr); - TU_ASSERT_COMPLETE(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE)); + if (version >= 0x30) { + // init CH34x with line coding + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); + uint8_t const lcr = ch34x_get_lcr(p_cdc); + TU_ASSERT(div_ps != 0 && lcr != 0); + TU_ASSERT(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SPECIAL_REG_WRITE))); + } break; } case CONFIG_CH34X_SPECIAL_REG_WRITE: // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; - TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL)); + TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_FLOW_CONTROL))); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control - TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL)); + TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_MODEM_CONTROL))); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, - CONFIG_CH34X_COMPLETE)); - break; + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->user_control_cb = cdch_process_set_config; + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_COMPLETE))); + break; #else - TU_ATTR_FALLTHROUGH; + TU_ATTR_FALLTHROUGH; #endif case CONFIG_CH34X_COMPLETE: @@ -2165,15 +2168,16 @@ static void ch34x_process_config(tuh_xfer_t* xfer) { break; default: - TU_ASSERT_COMPLETE(false); break; } + + return true; } //------------- Helper -------------// // calculate divisor and prescaler for baudrate, return it as 16-bit combined value -static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { +static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { uint32_t const baval = p_cdc->requested_line_coding.bit_rate; uint8_t a; uint8_t b; @@ -2219,20 +2223,20 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t * p_cdc) { // reg divisor = a, reg prescaler = b // According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, // otherwise the chip will buffer data. - return (uint16_t) ((uint16_t)a << 8 | 0x80 | b); + return (uint16_t) ((uint16_t) a << 8 | 0x80 | b); } // calculate lcr value from data coding -static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { +static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; - uint8_t const parity = p_cdc->requested_line_coding.parity; + uint8_t const parity = p_cdc->requested_line_coding.parity; uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8); lcr |= (uint8_t) (data_bits - 5); - switch(parity) { + switch (parity) { case CDC_LINE_CODING_PARITY_NONE: break; @@ -2271,14 +2275,13 @@ static uint8_t ch34x_get_lcr(cdch_interface_t * p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); +static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// - -static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_t requesttype, - uint16_t value, uint16_t index, uint8_t * buffer, uint16_t length, +static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t requesttype, + uint16_t value, uint16_t index, uint8_t *buffer, uint16_t length, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request_setup = { .bmRequestType = requesttype, @@ -2289,7 +2292,7 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ }; // use usbh enum buf since application variable does not live long enough - uint8_t * enum_buf = NULL; + uint8_t *enum_buf = NULL; if (buffer && length > 0) { enum_buf = usbh_get_enum_buf(); @@ -2310,34 +2313,28 @@ static bool pl2303_set_request(cdch_interface_t * p_cdc, uint8_t request, uint8_ return tuh_control_xfer(&xfer); } -static bool pl2303_vendor_read(cdch_interface_t * p_cdc, uint16_t value, uint8_t * buf, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? - PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; +static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } -static bool pl2303_vendor_write(cdch_interface_t * p_cdc, uint16_t value, uint16_t index, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? - PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; +static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } -static inline bool pl2303_supports_hx_status(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t buf = 0; return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); } -static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); @@ -2348,7 +2345,7 @@ static inline bool pl2303_set_control_lines(cdch_interface_t * p_cdc, tuh_xfer_c // return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); //} -static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // the caller has to precheck, that the new line coding different than the current, else false returned uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; /* @@ -2390,8 +2387,7 @@ static bool pl2303_set_line_request(cdch_interface_t * p_cdc, tuh_xfer_cb_t comp // return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); //} -static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) -{ +static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { /* we don't care if it wasn't halted first. in fact some devices * (like some ibmcam model 1 units) seem to expect hosts to make * this request for iso endpoints, which can't halt! @@ -2403,22 +2399,22 @@ static inline int pl2303_clear_halt(cdch_interface_t * p_cdc, uint8_t endp, tuh_ //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { +static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); + cdch_interface_t *p_cdc = get_itf(idx); + TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { p_cdc->line_coding = p_cdc->requested_line_coding; } if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { p_cdc->line_state = p_cdc->requested_line_state; } } @@ -2429,14 +2425,14 @@ static void pl2303_internal_control_complete(tuh_xfer_t * xfer) { } } -static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } -static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); @@ -2444,7 +2440,7 @@ static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t compl return true; } -static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; @@ -2454,7 +2450,7 @@ static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete return true; } -static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); @@ -2487,19 +2483,19 @@ enum { CONFIG_PL2303_COMPLETE }; -static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len) { +static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { // PL2303 Interface includes 1 vendor interface + 1 interrupt endpoints + 2 bulk TU_VERIFY(itf_desc->bNumEndpoints == 3); TU_VERIFY(sizeof(tusb_desc_interface_t) + 3 * sizeof(tusb_desc_endpoint_t) <= max_len); - cdch_interface_t * p_cdc = make_new_itf(daddr, itf_desc); + cdch_interface_t *p_cdc = make_new_itf(daddr, itf_desc); TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_PL2303; p_cdc->pl2303.serial_private.quirks = 0; p_cdc->pl2303.supports_hx_status = false; - tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const * ) tu_desc_next(itf_desc); + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); // Interrupt endpoint: not used for now TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(desc_ep) && @@ -2514,158 +2510,167 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u return true; } -static void pl2303_process_config(tuh_xfer_t * xfer) { - uintptr_t const state = xfer->user_data; +static bool pl2303_process_set_config(tuh_xfer_t *xfer) { + const uint8_t state = (uint8_t) xfer->user_data; // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() - TU_ASSERT_COMPLETE(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); uint8_t buf = 0; int8_t type; + TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); switch (state) { - // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_GET_DESC: - p_cdc->user_control_cb = pl2303_process_config; // set once for whole process config + p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get device descriptor - TU_ASSERT_COMPLETE(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - pl2303_process_config, CONFIG_PL2303_DETECT_TYPE)); + TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_DETECT_TYPE))); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type (p_cdc, 1, pl2303_process_config, CONFIG_PL2303_READ1); // step 1 - TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ1)); + TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; - } // else: no transfer triggered and continue with CONFIG_PL2303_READ1 + }// else: no transfer triggered and continue with CONFIG_PL2303_READ1 TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ1: // get supports_hx_status, type and quirks (step 2), do special read - p_cdc->pl2303.supports_hx_status = ( // will not be true, if coming directly from previous case - xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS ); - type = pl2303_detect_type (p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status - TU_ASSERT_COMPLETE(type!=PL2303_DETECT_TYPE_FAILED); + p_cdc->pl2303.supports_hx_status = (// will not be true, if coming directly from previous case + xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS); + type = pl2303_detect_type(p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status + TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; - #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0 // can be activated if necessary - TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, - desc_dev->bcdUSB, desc_dev->bcdDevice ); - uint16_t vid, pid; - TU_ASSERT_COMPLETE(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary + TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", + desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, + desc_dev->bcdUSB, desc_dev->bcdDevice); + uint16_t vid, pid; + TU_ASSERT(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); + TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", + vid, pid, p_cdc->pl2303.supports_hx_status, + p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE1)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE1))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 0, pl2303_process_config, CONFIG_PL2303_READ2)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ2))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ3))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_READ4)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ4))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_WRITE2)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE2))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0x0404, 1, pl2303_process_config, CONFIG_PL2303_READ5)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ5))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8484, &buf, pl2303_process_config, CONFIG_PL2303_READ6)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ6))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0x8383, &buf, pl2303_process_config, CONFIG_PL2303_WRITE3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE3))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, 1, pl2303_process_config, CONFIG_PL2303_WRITE4)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE4))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 1, 0, pl2303_process_config, CONFIG_PL2303_WRITE5)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE5))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x24, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); - } else { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 2, 0x44, pl2303_process_config, CONFIG_PL2303_RESET_ENDP1)); - } + uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; + TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP1))); break; - } // else: continue with next step + }// else: continue with next step TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function pl2303_open() + // from here sequence overtaken from Linux Kernel function pl2303_open() case CONFIG_PL2303_RESET_ENDP1: // step 1 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2))); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG, // skip CONFIG_PL2303_RESET_ENDP2, no 2nd step + TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } else { - pl2303_vendor_write(p_cdc, 8, 0, pl2303_process_config, CONFIG_PL2303_RESET_ENDP2); + pl2303_vendor_write(p_cdc, 8, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2)); } } break; @@ -2673,91 +2678,96 @@ static void pl2303_process_config(tuh_xfer_t * xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT_COMPLETE(pl2303_clear_halt(p_cdc, PL2303_IN_EP, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 9, 0, pl2303_process_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, + cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); } } break; - // from here sequence overtaken from Linux Kernel function pl2303_set_termios() - // unnecessary pl2303_get_line_request() is skipped due to a stall + // from here sequence overtaken from Linux Kernel function pl2303_set_termios() + // unnecessary pl2303_get_line_request() is skipped due to a stall case CONFIG_PL2303_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT_COMPLETE( pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_MODEM_CONTROL))); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT_COMPLETE(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif + #ifdef LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, + PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif -// skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program -// case CONFIG_PL2303_FLOW_CTRL_READ: -// // read flow control register for modify & write back in next step -// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { -// TU_LOG_P_CDC ( "1\r\n" ); -// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, pl2303_process_config, -// CONFIG_PL2303_FLOW_CTRL_WRITE)); -// } else { -// TU_LOG_P_CDC ( "2\r\n" ); -// TU_ASSERT_COMPLETE(pl2303_vendor_read(p_cdc, 0, &buf, pl2303_process_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); -// } -// break; -// -// case CONFIG_PL2303_FLOW_CTRL_WRITE: -// // no flow control -// buf = xfer->buffer[0]; -// if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { -// buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; -// buf |= PL2303_HXN_FLOWCTRL_NONE; -// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, pl2303_process_config, -// CONFIG_PL2303_COMPLETE)); -// } else { -// buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; -// TU_ASSERT_COMPLETE(pl2303_vendor_write(p_cdc, 0, buf, pl2303_process_config, CONFIG_PL2303_COMPLETE)); -// } -// break; + // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program + // case CONFIG_PL2303_FLOW_CTRL_READ: + // // read flow control register for modify & write back in next step + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // TU_LOG_P_CDC ( "1\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_FLOW_CTRL_WRITE))); + // } else { + // TU_LOG_P_CDC ( "2\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } + // break; + // + // case CONFIG_PL2303_FLOW_CTRL_WRITE: + // // no flow control + // buf = xfer->buffer[0]; + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + // buf |= PL2303_HXN_FLOWCTRL_NONE; + // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // } else { + // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, + // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // } + // break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); break; default: - TU_ASSERT_COMPLETE(false); - break; + return false; } + + return true; } //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data ) -{ +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { /* * Legacy PL2303H, variants 0 and 1 (difference unknown). */ if (desc_dev->bDeviceClass == 0x02) { - return TYPE_H; /* variant 0 */ + return TYPE_H; /* variant 0 */ } if (desc_dev->bMaxPacketSize0 != 0x40) { if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { - return TYPE_H; /* variant 1 */ + return TYPE_H; /* variant 1 */ } - return TYPE_H; /* variant 0 */ + return TYPE_H; /* variant 0 */ } switch (desc_dev->bcdUSB) { @@ -2782,7 +2792,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; } else { // step 2 use supports_hx_status @@ -2798,7 +2808,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status (p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); + TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; } else { // step 2 use supports_hx_status @@ -2829,8 +2839,7 @@ static int8_t pl2303_detect_type(cdch_interface_t * p_cdc, uint8_t step, * Returns the nearest supported baud rate that can be set directly without * using divisors. */ -static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) -{ +static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) { static const uint32_t baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, @@ -2859,8 +2868,7 @@ static uint32_t pl2303_get_supported_baud_rate(uint32_t baud) * NOTE: If unsupported baud rates are set directly, the PL2303 seems to * use 9600 baud. */ -static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baud_le = tu_htole32(baud); buf[0] = (uint8_t) ( baud_le & 0xff); buf[1] = (uint8_t) ((baud_le >> 8) & 0xff); @@ -2870,8 +2878,7 @@ static uint32_t pl2303_encode_baud_rate_direct(uint8_t buf[PL2303_LINE_CODING_BA return baud; } -static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baseline, mantissa, exponent; /* @@ -2899,7 +2906,7 @@ static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_B buf[3] = 0x80; buf[2] = 0; - buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); + buf[1] = (uint8_t) ((exponent << 1 | mantissa >> 8) & 0xff); buf[0] = (uint8_t) (mantissa & 0xff); /* Calculate and return the exact baud rate. */ @@ -2908,8 +2915,7 @@ static uint32_t pl2303_encode_baud_rate_divisor(uint8_t buf[PL2303_LINE_CODING_B return baud; } -static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) -{ +static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE], uint32_t baud) { uint32_t baseline, mantissa, exponent; /* @@ -2922,7 +2928,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI baseline = 12000000 * 32; mantissa = baseline / baud; if (mantissa == 0) { - mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ + mantissa = 1; /* Avoid dividing by zero if baud > 32 * 12M. */ } exponent = 0; while (mantissa >= 2048) { @@ -2938,7 +2944,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI buf[3] = 0x80; buf[2] = (uint8_t) (exponent & 0x01); - buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8 ) & 0xff); + buf[1] = (uint8_t) (((exponent & (uint32_t) ~0x01) << 4 | mantissa >> 8) & 0xff); buf[0] = (uint8_t) (mantissa & 0xff); /* Calculate and return the exact baud rate. */ @@ -2947,8 +2953,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI return baud; } -static bool pl2303_encode_baud_rate(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) -{ +static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t baud_sup; From 506edc626709ca92dd9c38d6c6f5813f30a27692 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Jun 2025 18:55:31 +0700 Subject: [PATCH 063/101] add get_itf_by_xfer() to better determine cdc interface from xfer complete callback --- src/class/cdc/cdc_host.c | 182 ++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 77 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index b6e9cb297..3be61e654 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -131,9 +131,6 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ -// for process_set_config user_data: idx (byte1) and state (byte0) -#define PROCESS_CONFIG_STATE(_idx, _state) tu_u16(_idx, _state) - static void cdch_process_set_config(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// @@ -327,13 +324,16 @@ TU_VERIFY_STATIC(TU_ARRAY_SIZE(serial_drivers) == SERIAL_DRIVER_COUNT, "Serial d // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -static inline cdch_interface_t * get_itf(uint8_t idx) { +TU_ATTR_ALWAYS_INLINE static inline cdch_interface_t * get_itf(uint8_t idx) { TU_ASSERT(idx < CFG_TUH_CDC, NULL); cdch_interface_t * p_cdc = &cdch_data[idx]; - return (p_cdc->daddr != 0) ? p_cdc : NULL; } +TU_ATTR_ALWAYS_INLINE static inline uint8_t get_idx_by_ptr(cdch_interface_t* p_cdc) { + return p_cdc - cdch_data; +} + static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { for(uint8_t i=0; idaddr != 0, NULL); + for(uint8_t i=0; idaddr == xfer->daddr) { + switch (p_cdc->serial_drid) { + #if CFG_TUH_CDC_CP210X + case SERIAL_DRIVER_CP210X: + #endif + case SERIAL_DRIVER_ACM: { + // Driver use wIndex for bInterfaceNumber + const uint8_t itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + if (p_cdc->bInterfaceNumber == itf_num) { + return p_cdc; + } + break; + } + + #if CFG_TUH_CDC_FTDI + case SERIAL_DRIVER_FTDI: { + // FTDI uses wIndex for channel number, if channel is 0 then it is the default channel + const uint8_t channel = (uint8_t) tu_le16toh(xfer->setup->wIndex); + if (p_cdc->ftdi.channel == 0 || p_cdc->ftdi.channel == channel) { + return p_cdc; + } + break; + } + #endif + + #if CFG_TUH_CDC_CH34X + case SERIAL_DRIVER_CH34X: + // ch34x has only one interface + return p_cdc; + #endif + + #if CFG_TUH_CDC_PL2303 + case SERIAL_DRIVER_PL2303: + // pl2303 has only one interface + return p_cdc; + #endif + + default: + break; + } + } + } + + return NULL; +} + static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t const * itf_desc) { for(uint8_t i=0; iserial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts ); + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line_state = line_state; @@ -614,8 +665,6 @@ bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line if (ret && !complete_cb) { p_cdc->line_state = line_state; } -// TU_LOG_P_CDC_BOOL("set control line state", ret); - return ret; } @@ -893,9 +942,9 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { } static void cdch_process_set_config(tuh_xfer_t *xfer) { - const uint8_t idx = tu_u32_byte1(xfer->user_data); - cdch_interface_t *p_cdc = get_itf(idx); + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + const uint8_t idx = get_idx_by_ptr(p_cdc); if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; @@ -916,7 +965,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { xfer.daddr = daddr; xfer.result = XFER_RESULT_SUCCESS; xfer.setup = &request; - xfer.user_data = PROCESS_CONFIG_STATE(idx, 0); // initial state 0 + xfer.user_data = 0; // initial state 0 cdch_process_set_config(&xfer); return true; @@ -1093,7 +1142,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 } static bool acm_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); @@ -1104,7 +1153,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { #ifdef LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_SET_LINE_CODING))); + TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } #endif @@ -1114,7 +1163,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM if (p_cdc->acm_capability.support_line_request) { p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_ACM_COMPLETE))); + TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); break; } #endif @@ -1326,7 +1375,7 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint } static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const idx = ftdi_get_idx(xfer); cdch_interface_t *p_cdc = get_itf(idx); uint8_t const itf_num = p_cdc->bInterfaceNumber; @@ -1338,7 +1387,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // get device descriptor if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_DETERMINE_TYPE))); + cdch_process_set_config, CONFIG_FTDI_DETERMINE_TYPE)); break; } TU_ATTR_FALLTHROUGH; @@ -1370,7 +1419,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_DATA))); + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); break; // from here sequence overtaken from Linux Kernel function ftdi_set_termios() @@ -1378,7 +1427,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_SET_BAUDRATE))); + TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1387,7 +1436,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_FLOW_CONTROL))); + TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1396,14 +1445,14 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, - p_cdc->ftdi.channel, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_MODEM_CTRL))); + p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_MODEM_CTRL)); break; case CONFIG_FTDI_MODEM_CTRL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_FTDI_COMPLETE))); + TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1840,7 +1889,7 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui } static bool cp210x_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); @@ -1848,16 +1897,14 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_BAUDRATE_REQUEST))); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_LINE_CTL))); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1866,8 +1913,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_SET_DTR_RTS))); + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else TU_ATTR_FALLTHROUGH; @@ -1877,8 +1923,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_CP210X_COMPLETE))); + TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2108,7 +2153,7 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui } static bool ch34x_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); @@ -2119,7 +2164,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_CH34X_READ_VERSION: TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SERIAL_INIT))); + cdch_process_set_config, CONFIG_CH34X_SERIAL_INIT)); break; case CONFIG_CH34X_SERIAL_INIT: { @@ -2135,7 +2180,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_ASSERT(div_ps != 0 && lcr != 0); TU_ASSERT(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_SPECIAL_REG_WRITE))); + cdch_process_set_config, CONFIG_CH34X_SPECIAL_REG_WRITE)); } break; } @@ -2144,20 +2189,20 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_FLOW_CONTROL))); + cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL)); break; case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_MODEM_CONTROL))); + cdch_process_set_config, CONFIG_CH34X_MODEM_CONTROL)); break; case CONFIG_CH34X_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, PROCESS_CONFIG_STATE(idx, CONFIG_CH34X_COMPLETE))); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2511,7 +2556,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui } static bool pl2303_process_set_config(tuh_xfer_t *xfer) { - const uint8_t state = (uint8_t) xfer->user_data; + const uintptr_t state = xfer->user_data; // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber uint8_t const itf_num = 0; uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); @@ -2527,12 +2572,12 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get device descriptor TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_DETECT_TYPE))); + cdch_process_set_config, CONFIG_PL2303_DETECT_TYPE)); break; case CONFIG_PL2303_DETECT_TYPE: // get type and quirks (step 1) - type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ1)); + type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { break; @@ -2559,8 +2604,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { #endif // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE1))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2568,8 +2612,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ2))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2577,8 +2620,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ3))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2586,8 +2628,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ4))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2595,8 +2636,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE2))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2604,8 +2644,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ5))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2613,8 +2652,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_READ6))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2622,8 +2660,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE3))); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2631,8 +2668,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE4))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2640,8 +2676,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { - TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_WRITE5))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2650,8 +2685,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; - TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP1))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2660,17 +2694,15 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP1: // step 1 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2))); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { - pl2303_vendor_write(p_cdc, 8, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_RESET_ENDP2)); + pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2); } } break; @@ -2678,15 +2710,13 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, - cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_LINE_CODING))); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } } break; @@ -2696,8 +2726,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_MODEM_CONTROL))); + TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -2706,8 +2735,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef LINE_CONTROL_ON_ENUM p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, - PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2719,7 +2747,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { // TU_LOG_P_CDC ( "1\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_FLOW_CTRL_WRITE))); + // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); // } else { // TU_LOG_P_CDC ( "2\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); @@ -2733,11 +2761,11 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; // buf |= PL2303_HXN_FLOWCTRL_NONE; // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); // } else { // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, - // cdch_process_set_config, PROCESS_CONFIG_STATE(idx, CONFIG_PL2303_COMPLETE))); + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); // } // break; From 9503883ba7f99523a14082ce68a5f900585747b0 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 18 Jun 2025 23:35:44 +0700 Subject: [PATCH 064/101] usbh: add new API tuh_descriptor_get_device_local() cdc host: remove the local desc_dev and the get_device descriptor call for ftdi and pl2303 --- src/class/cdc/cdc_host.c | 141 ++++++++++++--------------------------- src/common/tusb_types.h | 1 - src/host/usbh.c | 58 ++++++++++++---- src/host/usbh.h | 3 + 4 files changed, 91 insertions(+), 112 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 3be61e654..d704d82d7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -123,10 +123,6 @@ typedef struct { static cdch_interface_t cdch_data[CFG_TUH_CDC]; CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; -#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_PL2303 - static tusb_desc_device_t desc_dev[CFG_TUH_ENUMERATION_BUFSIZE]; -#endif - //--------------------------------------------------------------------+ // Serial Driver //--------------------------------------------------------------------+ @@ -189,8 +185,6 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; -CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN - static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(tuh_xfer_t *xfer); @@ -331,7 +325,7 @@ TU_ATTR_ALWAYS_INLINE static inline cdch_interface_t * get_itf(uint8_t idx) { } TU_ATTR_ALWAYS_INLINE static inline uint8_t get_idx_by_ptr(cdch_interface_t* p_cdc) { - return p_cdc - cdch_data; + return (uint8_t) (p_cdc - cdch_data); } static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { @@ -434,7 +428,7 @@ bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t * info) { info->daddr = p_cdc->daddr; - // re-construct descriptor + // re-construct interface descriptor tusb_desc_interface_t * desc = &info->desc; desc->bLength = sizeof(tusb_desc_interface_t); desc->bDescriptorType = TUSB_DESC_INTERFACE; @@ -975,8 +969,6 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { // ACM //--------------------------------------------------------------------+ -//------------- Driver API -------------// - // internal control complete to update state such as line state, encoding static void acm_internal_control_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); @@ -1089,7 +1081,6 @@ static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, } //------------- Enumeration -------------// - enum { CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, CONFIG_ACM_SET_LINE_CODING, @@ -1339,8 +1330,7 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ //------------- Enumeration -------------// enum { - CONFIG_FTDI_GET_DESC = 0, - CONFIG_FTDI_DETERMINE_TYPE, + CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, CONFIG_FTDI_SIO_RESET, CONFIG_FTDI_SET_DATA, @@ -1383,15 +1373,6 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() - case CONFIG_FTDI_GET_DESC: - // get device descriptor - if (itf_num == 0) { // only necessary for 1st interface. other interface overtake type from interface 0 - TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, CONFIG_FTDI_DETERMINE_TYPE)); - break; - } - TU_ATTR_FALLTHROUGH; - case CONFIG_FTDI_DETERMINE_TYPE: // determine type if (itf_num == 0) { @@ -1472,7 +1453,9 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// static bool ftdi_determine_type(cdch_interface_t *p_cdc) { - uint16_t const version = desc_dev->bcdDevice; + tusb_desc_device_t desc_dev; + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev)); + uint16_t const version = desc_dev.bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; p_cdc->ftdi.chip_type = UNKNOWN; @@ -1482,8 +1465,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { switch (version) { case 0x200: - // FT232A not supported to keep it simple (no extra _read_latency_timer()) - // not testable + // FT232A not supported to keep it simple (no extra _read_latency_timer()) not testable // p_cdc->ftdi.chip_type = FT232A; // p_cdc->ftdi.baud_base = 48000000 / 2; // p_cdc->ftdi.channel = 0; @@ -1497,50 +1479,20 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { // p_cdc->ftdi.chip_type = FT232B; // } break; - case 0x400: - p_cdc->ftdi.chip_type = FT232B; - p_cdc->ftdi.channel = 0; - break; - case 0x500: - p_cdc->ftdi.chip_type = FT2232C; - break; - case 0x600: - p_cdc->ftdi.chip_type = FT232R; - p_cdc->ftdi.channel = 0; - break; - case 0x700: - p_cdc->ftdi.chip_type = FT2232H; - break; - case 0x800: - p_cdc->ftdi.chip_type = FT4232H; - break; - case 0x900: - p_cdc->ftdi.chip_type = FT232H; - break; - case 0x1000: - p_cdc->ftdi.chip_type = FTX; - break; - case 0x2800: - p_cdc->ftdi.chip_type = FT2233HP; - break; - case 0x2900: - p_cdc->ftdi.chip_type = FT4233HP; - break; - case 0x3000: - p_cdc->ftdi.chip_type = FT2232HP; - break; - case 0x3100: - p_cdc->ftdi.chip_type = FT4232HP; - break; - case 0x3200: - p_cdc->ftdi.chip_type = FT233HP; - break; - case 0x3300: - p_cdc->ftdi.chip_type = FT232HP; - break; - case 0x3600: - p_cdc->ftdi.chip_type = FT4232HA; - break; + case 0x400: p_cdc->ftdi.chip_type = FT232B; p_cdc->ftdi.channel = 0; break; + case 0x500: p_cdc->ftdi.chip_type = FT2232C; break; + case 0x600: p_cdc->ftdi.chip_type = FT232R; p_cdc->ftdi.channel = 0; break; + case 0x700: p_cdc->ftdi.chip_type = FT2232H; break; + case 0x800: p_cdc->ftdi.chip_type = FT4232H; break; + case 0x900: p_cdc->ftdi.chip_type = FT232H; break; + case 0x1000: p_cdc->ftdi.chip_type = FTX; break; + case 0x2800: p_cdc->ftdi.chip_type = FT2233HP; break; + case 0x2900: p_cdc->ftdi.chip_type = FT4233HP; break; + case 0x3000: p_cdc->ftdi.chip_type = FT2232HP; break; + case 0x3100: p_cdc->ftdi.chip_type = FT4232HP; break; + case 0x3200: p_cdc->ftdi.chip_type = FT233HP; break; + case 0x3300: p_cdc->ftdi.chip_type = FT232HP; break; + case 0x3600: p_cdc->ftdi.chip_type = FT4232HA; break; default: if (version < 0x200) { p_cdc->ftdi.chip_type = SIO; @@ -1550,7 +1502,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { } TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", - ftdi_chip_name[p_cdc->ftdi.chip_type], desc_dev->bcdDevice); + ftdi_chip_name[p_cdc->ftdi.chip_type], version); return (p_cdc->ftdi.chip_type != UNKNOWN); } @@ -2025,7 +1977,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp } static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) |// CH34x signals are inverted + // CH34x signals are inverted + uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -2506,8 +2459,7 @@ static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet //------------- Enumeration -------------// enum { - CONFIG_PL2303_GET_DESC = 0, - CONFIG_PL2303_DETECT_TYPE, + CONFIG_PL2303_DETECT_TYPE = 0, CONFIG_PL2303_READ1, CONFIG_PL2303_WRITE1, CONFIG_PL2303_READ2, @@ -2568,14 +2520,8 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() - case CONFIG_PL2303_GET_DESC: - p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config - // get device descriptor - TU_ASSERT(tuh_descriptor_get_device(xfer->daddr, &desc_dev, sizeof(tusb_desc_device_t), - cdch_process_set_config, CONFIG_PL2303_DETECT_TYPE)); - break; - case CONFIG_PL2303_DETECT_TYPE: + p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); @@ -2784,39 +2730,39 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - /* - * Legacy PL2303H, variants 0 and 1 (difference unknown). - */ - if (desc_dev->bDeviceClass == 0x02) { + tusb_desc_device_t desc_dev; + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_DETECT_TYPE_FAILED); + + // Legacy PL2303H, variants 0 and 1 (difference unknown). + if (desc_dev.bDeviceClass == 0x02) { return TYPE_H; /* variant 0 */ } - if (desc_dev->bMaxPacketSize0 != 0x40) { - if (desc_dev->bDeviceClass == 0x00 || desc_dev->bDeviceClass == 0xff) { + if (desc_dev.bMaxPacketSize0 != 0x40) { + if (desc_dev.bDeviceClass == 0x00 || desc_dev.bDeviceClass == 0xff) { return TYPE_H; /* variant 1 */ } return TYPE_H; /* variant 0 */ } - switch (desc_dev->bcdUSB) { + switch (desc_dev.bcdUSB) { case 0x101: /* USB 1.0.1? Let's assume they meant 1.1... */ TU_ATTR_FALLTHROUGH; case 0x110: - switch (desc_dev->bcdDevice) { - case 0x300: - return TYPE_HX; - case 0x400: - return TYPE_HXD; - default: - return TYPE_HX; + switch (desc_dev.bcdDevice) { + case 0x300: return TYPE_HX; + case 0x400: return TYPE_HXD; + default: return TYPE_HX; } break; + case 0x200: - switch (desc_dev->bcdDevice) { + switch (desc_dev.bcdDevice) { case 0x100: /* GC */ case 0x105: return TYPE_HXN; + case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request @@ -2833,6 +2779,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x400: /* GL */ case 0x405: return TYPE_HXN; + case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request @@ -2851,6 +2798,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x700: /* GR */ case 0x705: return TYPE_HXN; + default: break; } @@ -2858,8 +2806,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev->bcdUSB); - + TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); return PL2303_DETECT_TYPE_FAILED; } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index fd7f01b67..ff5d8b66a 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -345,7 +345,6 @@ typedef struct TU_ATTR_PACKED { uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer. uint8_t iProduct ; ///< Index of string descriptor describing product. uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number. - uint8_t bNumConfigurations ; ///< Number of possible configurations. } tusb_desc_device_t; diff --git a/src/host/usbh.c b/src/host/usbh.c index f2e5c1f0e..08c362171 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -94,6 +94,20 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si typedef struct { tuh_bus_info_t bus_info; + // Device Descriptor + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; + // Device State struct TU_ATTR_PACKED { volatile uint8_t connected : 1; // After 1st transfer @@ -103,18 +117,6 @@ typedef struct { // volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh }; - // Device Descriptor - uint8_t ep0_size; - uint16_t idVendor; - uint16_t idProduct; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; - uint8_t bNumConfigurations; - - // Configuration Descriptor - // uint8_t interface_count; // bNumInterfaces alias - // Endpoint & Interface uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid) uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each @@ -373,6 +375,28 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { return true; } +bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device) { + usbh_device_t *dev = get_device(daddr); + TU_VERIFY(dev && desc_device); + + desc_device->bLength = sizeof(tusb_desc_device_t); + desc_device->bDescriptorType = TUSB_DESC_DEVICE; + desc_device->bcdUSB = dev->bcdUSB; + desc_device->bDeviceClass = dev->bDeviceClass; + desc_device->bDeviceSubClass = dev->bDeviceSubClass; + desc_device->bDeviceProtocol = dev->bDeviceProtocol; + desc_device->bMaxPacketSize0 = dev->bMaxPacketSize0; + desc_device->idVendor = dev->idVendor; + desc_device->idProduct = dev->idProduct; + desc_device->bcdDevice = dev->bcdDevice; + desc_device->iManufacturer = dev->iManufacturer; + desc_device->iProduct = dev->iProduct; + desc_device->iSerialNumber = dev->iSerialNumber; + desc_device->bNumConfigurations = dev->bNumConfigurations; + + return true; +} + tusb_speed_t tuh_speed_get(uint8_t daddr) { tuh_bus_info_t bus_info; tuh_bus_info_get(daddr, &bus_info); @@ -1579,7 +1603,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { usbh_device_t* new_dev = get_device(new_addr); new_dev->bus_info = *dev0_bus; new_dev->connected = 1; - new_dev->ep0_size = desc_device->bMaxPacketSize0; + new_dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0; TU_ASSERT(tuh_address_set(0, new_addr, process_enumeration, ENUM_GET_DEVICE_DESC),); break; @@ -1596,7 +1620,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { usbh_device_close(dev0_bus->rhport, 0); // close dev0 - TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint + TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->bMaxPacketSize0),); // open new control endpoint TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), @@ -1609,8 +1633,14 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_GET_STRING_LANGUAGE_ID_LEN: { // save the received device descriptor tusb_desc_device_t const *desc_device = (tusb_desc_device_t const *) _usbh_epbuf.ctrl; + dev->bcdUSB = desc_device->bcdUSB; + dev->bDeviceClass = desc_device->bDeviceClass; + dev->bDeviceSubClass = desc_device->bDeviceSubClass; + dev->bDeviceProtocol = desc_device->bDeviceProtocol; + dev->bMaxPacketSize0 = desc_device->bMaxPacketSize0; dev->idVendor = desc_device->idVendor; dev->idProduct = desc_device->idProduct; + dev->bcdDevice = desc_device->bcdDevice; dev->iManufacturer = desc_device->iManufacturer; dev->iProduct = desc_device->iProduct; dev->iSerialNumber = desc_device->iSerialNumber; diff --git a/src/host/usbh.h b/src/host/usbh.h index 13eede869..1ee511722 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -204,6 +204,9 @@ bool tuh_rhport_reset_bus(uint8_t rhport, bool active); // Get VID/PID of device bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid); +// Get local (cached) device descriptor once device is enumerated +bool tuh_descriptor_get_device_local(uint8_t daddr, tusb_desc_device_t* desc_device); + // Get speed of device tusb_speed_t tuh_speed_get(uint8_t daddr); From 2adb305ea71f69b38c6c01cc054d8e323dd25e0e Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 15:30:02 +0700 Subject: [PATCH 065/101] house keeping --- src/class/cdc/cdc_host.c | 183 ++++++++++++++++---------------- src/class/cdc/serial/ftdi_sio.h | 74 ++++++------- src/class/cdc/serial/pl2303.h | 40 +++---- 3 files changed, 150 insertions(+), 147 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index d704d82d7..ce98e3b3d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -111,13 +111,13 @@ typedef struct { tu_edpt_stream_t rx; uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; - uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE]; + uint8_t rx_ff_buf[CFG_TUH_CDC_RX_BUFSIZE]; } stream; } cdch_interface_t; typedef struct { TUH_EPBUF_DEF(tx, CFG_TUH_CDC_TX_EPSIZE); - TUH_EPBUF_DEF(rx, CFG_TUH_CDC_TX_EPSIZE); + TUH_EPBUF_DEF(rx, CFG_TUH_CDC_RX_EPSIZE); } cdch_epbuf_t; static cdch_interface_t cdch_data[CFG_TUH_CDC]; @@ -141,10 +141,6 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c //------------- FTDI prototypes -------------// #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; -#if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - static uint8_t const * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; -#endif - static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); static bool ftdi_proccess_set_config(tuh_xfer_t * xfer); @@ -183,7 +179,7 @@ static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet //------------- PL2303 prototypes -------------// #if CFG_TUH_CDC_PL2303 static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIST}; -static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = {PL2303_TYPE_DATA}; +static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TYPE_DATA}; static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(tuh_xfer_t *xfer); @@ -1209,7 +1205,7 @@ static bool ftdi_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t r #ifdef CFG_TUH_CDC_FTDI_LATENCY static int8_t ftdi_write_latency_timer(cdch_interface_t * p_cdc, uint16_t latency, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (p_cdc->ftdi.chip_type == SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) + if (p_cdc->ftdi.chip_type == FTDI_SIO /* || p_cdc->ftdi.chip_type == FT232A */ ) return FTDI_NOT_POSSIBLE; return ftdi_set_request(p_cdc, FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, latency, p_cdc->ftdi.channel, complete_cb, user_data) ? FTDI_REQUESTED : FTDI_FAIL; @@ -1458,7 +1454,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { uint16_t const version = desc_dev.bcdDevice; uint8_t const itf_num = p_cdc->bInterfaceNumber; - p_cdc->ftdi.chip_type = UNKNOWN; + p_cdc->ftdi.chip_type = FTDI_UNKNOWN; /* Assume Hi-Speed type */ p_cdc->ftdi.channel = CHANNEL_A + itf_num; @@ -1476,35 +1472,40 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { // */ // if (desc->iSerialNumber == 0 && // _read_latency_timer(port) >= 0) { - // p_cdc->ftdi.chip_type = FT232B; + // p_cdc->ftdi.chip_type = FTDI_FT232B; // } break; - case 0x400: p_cdc->ftdi.chip_type = FT232B; p_cdc->ftdi.channel = 0; break; - case 0x500: p_cdc->ftdi.chip_type = FT2232C; break; - case 0x600: p_cdc->ftdi.chip_type = FT232R; p_cdc->ftdi.channel = 0; break; - case 0x700: p_cdc->ftdi.chip_type = FT2232H; break; - case 0x800: p_cdc->ftdi.chip_type = FT4232H; break; - case 0x900: p_cdc->ftdi.chip_type = FT232H; break; - case 0x1000: p_cdc->ftdi.chip_type = FTX; break; - case 0x2800: p_cdc->ftdi.chip_type = FT2233HP; break; - case 0x2900: p_cdc->ftdi.chip_type = FT4233HP; break; - case 0x3000: p_cdc->ftdi.chip_type = FT2232HP; break; - case 0x3100: p_cdc->ftdi.chip_type = FT4232HP; break; - case 0x3200: p_cdc->ftdi.chip_type = FT233HP; break; - case 0x3300: p_cdc->ftdi.chip_type = FT232HP; break; - case 0x3600: p_cdc->ftdi.chip_type = FT4232HA; break; + + case 0x400 : p_cdc->ftdi.chip_type = FTDI_FT232B; p_cdc->ftdi.channel = 0; break; + case 0x500 : p_cdc->ftdi.chip_type = FTDI_FT2232C; break; + case 0x600 : p_cdc->ftdi.chip_type = FTDI_FT232R; p_cdc->ftdi.channel = 0; break; + case 0x700 : p_cdc->ftdi.chip_type = FTDI_FT2232H; break; + case 0x800 : p_cdc->ftdi.chip_type = FTDI_FT4232H; break; + case 0x900 : p_cdc->ftdi.chip_type = FTDI_FT232H; break; + case 0x1000: p_cdc->ftdi.chip_type = FTDI_FTX; break; + case 0x2800: p_cdc->ftdi.chip_type = FTDI_FT2233HP; break; + case 0x2900: p_cdc->ftdi.chip_type = FTDI_FT4233HP; break; + case 0x3000: p_cdc->ftdi.chip_type = FTDI_FT2232HP; break; + case 0x3100: p_cdc->ftdi.chip_type = FTDI_FT4232HP; break; + case 0x3200: p_cdc->ftdi.chip_type = FTDI_FT233HP; break; + case 0x3300: p_cdc->ftdi.chip_type = FTDI_FT232HP; break; + case 0x3600: p_cdc->ftdi.chip_type = FTDI_FT4232HA; break; + default: if (version < 0x200) { - p_cdc->ftdi.chip_type = SIO; + p_cdc->ftdi.chip_type = FTDI_SIO; p_cdc->ftdi.channel = 0; } break; } + #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + const char * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], version); + #endif - return (p_cdc->ftdi.chip_type != UNKNOWN); + return (p_cdc->ftdi.chip_type != FTDI_UNKNOWN); } // FT232A not supported @@ -1589,9 +1590,9 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { TU_VERIFY(baud); switch (p_cdc->ftdi.chip_type) { - case UNKNOWN: + case FTDI_UNKNOWN: return 0; - case SIO: + case FTDI_SIO: switch (baud) { case 300: div_value = ftdi_sio_b300; break; case 600: div_value = ftdi_sio_b600; break; @@ -1620,23 +1621,23 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { // div_okay = false; // } // break; - case FT232B: - case FT2232C: - case FT232R: - case FTX: + case FTDI_FT232B: + case FTDI_FT2232C: + case FTDI_FT232R: + case FTDI_FTX: TU_VERIFY(baud <= 3000000); // else Baud rate too high! div_value = ftdi_232bm_baud_to_divisor(baud); break; - case FT232H: - case FT2232H: - case FT4232H: - case FT4232HA: - case FT232HP: - case FT233HP: - case FT2232HP: - case FT2233HP: - case FT4232HP: - case FT4233HP: + case FTDI_FT232H: + case FTDI_FT2232H: + case FTDI_FT4232H: + case FTDI_FT4232HA: + case FTDI_FT232HP: + case FTDI_FT233HP: + case FTDI_FT2232HP: + case FTDI_FT2233HP: + case FTDI_FT4232HP: + case FTDI_FT4233HP: default: TU_VERIFY(baud <= 12000000); // else Baud rate too high! if (baud >= 1200) { @@ -2273,8 +2274,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data); +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// @@ -2313,14 +2313,13 @@ static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; - + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; + uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } @@ -2517,25 +2516,30 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { uint8_t buf = 0; int8_t type; - TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || xfer->user_data == CONFIG_PL2303_READ1)); + TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) - type = pl2303_detect_type(p_cdc, 1, cdch_process_set_config, CONFIG_PL2303_READ1); - TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); - if (type == PL2303_SUPPORTS_HX_STATUS_TRIGGERED) { + type = pl2303_detect_type(p_cdc, 1); + TU_ASSERT(type != PL2303_TYPE_UNKNOWN); + if (type == PL2303_TYPE_NEED_SUPPORTS_HX_STATUS) { + TU_ASSERT(pl2303_supports_hx_status(p_cdc, cdch_process_set_config, CONFIG_PL2303_READ1)); break; - }// else: no transfer triggered and continue with CONFIG_PL2303_READ1 - TU_ATTR_FALLTHROUGH; + } else { + // no transfer triggered and continue with CONFIG_PL2303_READ1 + TU_ATTR_FALLTHROUGH; + } case CONFIG_PL2303_READ1: // get supports_hx_status, type and quirks (step 2), do special read - p_cdc->pl2303.supports_hx_status = (// will not be true, if coming directly from previous case - xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS); - type = pl2303_detect_type(p_cdc, 2, NULL, 0); // step 2 now with supports_hx_status - TU_ASSERT(type != PL2303_DETECT_TYPE_FAILED); + // will not be true, if coming directly from previous case + if (xfer->user_data == CONFIG_PL2303_READ1 && xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->pl2303.supports_hx_status = true; + } + type = pl2303_detect_type(p_cdc, 2); // step 2 now with supports_hx_status + TU_ASSERT(type != PL2303_TYPE_UNKNOWN); p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary @@ -2549,7 +2553,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); #endif // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step @@ -2557,7 +2561,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step @@ -2565,7 +2569,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step @@ -2573,7 +2577,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step @@ -2581,7 +2585,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step @@ -2589,7 +2593,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step @@ -2597,7 +2601,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step @@ -2605,7 +2609,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step @@ -2613,7 +2617,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step @@ -2621,7 +2625,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step @@ -2629,7 +2633,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; @@ -2643,7 +2647,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2659,7 +2663,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2690,7 +2694,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program // case CONFIG_PL2303_FLOW_CTRL_READ: // // read flow control register for modify & write back in next step - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // TU_LOG_P_CDC ( "1\r\n" ); // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); @@ -2703,7 +2707,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // case CONFIG_PL2303_FLOW_CTRL_WRITE: // // no flow control // buf = xfer->buffer[0]; - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[TYPE_HXN]) { + // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; // buf |= PL2303_HXN_FLOWCTRL_NONE; // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, @@ -2728,21 +2732,20 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { tusb_desc_device_t desc_dev; - TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_DETECT_TYPE_FAILED); + TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_TYPE_UNKNOWN); // Legacy PL2303H, variants 0 and 1 (difference unknown). if (desc_dev.bDeviceClass == 0x02) { - return TYPE_H; /* variant 0 */ + return PL2303_TYPE_H; /* variant 0 */ } if (desc_dev.bMaxPacketSize0 != 0x40) { if (desc_dev.bDeviceClass == 0x00 || desc_dev.bDeviceClass == 0xff) { - return TYPE_H; /* variant 1 */ + return PL2303_TYPE_H; /* variant 1 */ } - return TYPE_H; /* variant 0 */ + return PL2303_TYPE_H; /* variant 0 */ } switch (desc_dev.bcdUSB) { @@ -2751,9 +2754,9 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, TU_ATTR_FALLTHROUGH; case 0x110: switch (desc_dev.bcdDevice) { - case 0x300: return TYPE_HX; - case 0x400: return TYPE_HXD; - default: return TYPE_HX; + case 0x300: return PL2303_TYPE_HX; + case 0x400: return PL2303_TYPE_HXD; + default: return PL2303_TYPE_HX; } break; @@ -2761,34 +2764,32 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, switch (desc_dev.bcdDevice) { case 0x100: /* GC */ case 0x105: - return TYPE_HXN; + return PL2303_TYPE_HXN; case 0x300: /* GT / TA */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); - return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS; } else { // step 2 use supports_hx_status if (p_cdc->pl2303.supports_hx_status) { - return TYPE_TA; + return PL2303_TYPE_TA; } } TU_ATTR_FALLTHROUGH; case 0x305: case 0x400: /* GL */ case 0x405: - return TYPE_HXN; + return PL2303_TYPE_HXN; case 0x500: /* GE / TB */ if (step == 1) { // step 1 trigger pl2303_supports_hx_status() request - TU_ASSERT(pl2303_supports_hx_status(p_cdc, complete_cb, user_data), PL2303_DETECT_TYPE_FAILED); - return PL2303_SUPPORTS_HX_STATUS_TRIGGERED; + return PL2303_TYPE_NEED_SUPPORTS_HX_STATUS; } else { // step 2 use supports_hx_status if (p_cdc->pl2303.supports_hx_status) { - return TYPE_TB; + return PL2303_TYPE_TB; } } TU_ATTR_FALLTHROUGH; @@ -2797,7 +2798,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, case 0x605: case 0x700: /* GR */ case 0x705: - return TYPE_HXN; + return PL2303_TYPE_HXN; default: break; @@ -2807,7 +2808,7 @@ static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step, } TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); - return PL2303_DETECT_TYPE_FAILED; + return PL2303_TYPE_UNKNOWN; } /* diff --git a/src/class/cdc/serial/ftdi_sio.h b/src/class/cdc/serial/ftdi_sio.h index f621b3912..8abf74f11 100644 --- a/src/class/cdc/serial/ftdi_sio.h +++ b/src/class/cdc/serial/ftdi_sio.h @@ -165,48 +165,48 @@ enum ftdi_sio_baudrate { #define FTDI_RS_FIFO (1 << 7) // chip types and names -enum ftdi_chip_type { - SIO = 0, -// FT232A, - FT232B, - FT2232C, - FT232R, - FT232H, - FT2232H, - FT4232H, - FT4232HA, - FT232HP, - FT233HP, - FT2232HP, - FT2233HP, - FT4232HP, - FT4233HP, - FTX, - UNKNOWN -}; +typedef enum ftdi_chip_type { + FTDI_SIO = 0, +// FTDI_FT232A, + FTDI_FT232B, + FTDI_FT2232C, + FTDI_FT232R, + FTDI_FT232H, + FTDI_FT2232H, + FTDI_FT4232H, + FTDI_FT4232HA, + FTDI_FT232HP, + FTDI_FT233HP, + FTDI_FT2232HP, + FTDI_FT2233HP, + FTDI_FT4232HP, + FTDI_FT4233HP, + FTDI_FTX, + FTDI_UNKNOWN +} ftdi_chip_type_t; #define FTDI_CHIP_NAMES \ - [SIO] = (uint8_t const*) "SIO", /* the serial part of FT8U100AX */ \ -/* [FT232A] = (uint8_t const*) "FT232A", */ \ - [FT232B] = (uint8_t const*) "FT232B", \ - [FT2232C] = (uint8_t const*) "FT2232C/D", \ - [FT232R] = (uint8_t const*) "FT232R", \ - [FT232H] = (uint8_t const*) "FT232H", \ - [FT2232H] = (uint8_t const*) "FT2232H", \ - [FT4232H] = (uint8_t const*) "FT4232H", \ - [FT4232HA] = (uint8_t const*) "FT4232HA", \ - [FT232HP] = (uint8_t const*) "FT232HP", \ - [FT233HP] = (uint8_t const*) "FT233HP", \ - [FT2232HP] = (uint8_t const*) "FT2232HP", \ - [FT2233HP] = (uint8_t const*) "FT2233HP", \ - [FT4232HP] = (uint8_t const*) "FT4232HP", \ - [FT4233HP] = (uint8_t const*) "FT4233HP", \ - [FTX] = (uint8_t const*) "FT-X", \ - [UNKNOWN] = (uint8_t const*) "UNKNOWN" + [FTDI_SIO] = "SIO", /* the serial part of FT8U100AX */ \ +/* [FTDI_FT232A] = "FT232A", */ \ + [FTDI_FT232B] = "FT232B", \ + [FTDI_FT2232C] = "FT2232C/D", \ + [FTDI_FT232R] = "FT232R", \ + [FTDI_FT232H] = "FT232H", \ + [FTDI_FT2232H] = "FTDI_FT2232H", \ + [FTDI_FT4232H] = "FT4232H", \ + [FTDI_FT4232HA] = "FT4232HA", \ + [FTDI_FT232HP] = "FT232HP", \ + [FTDI_FT233HP] = "FT233HP", \ + [FTDI_FT2232HP] = "FT2232HP", \ + [FTDI_FT2233HP] = "FT2233HP", \ + [FTDI_FT4232HP] = "FT4232HP", \ + [FTDI_FT4233HP] = "FT4233HP", \ + [FTDI_FTX] = "FT-X", \ + [FTDI_UNKNOWN] = "UNKNOWN" // private interface data typedef struct ftdi_private { - enum ftdi_chip_type chip_type; + ftdi_chip_type_t chip_type; uint8_t channel; // channel index, or 0 for legacy types } ftdi_private_t; diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index d69bdbfae..40311260d 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -96,51 +96,53 @@ #define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c // type data -enum pl2303_type { - TYPE_H, - TYPE_HX, - TYPE_TA, - TYPE_TB, - TYPE_HXD, - TYPE_HXN, - TYPE_COUNT -}; +typedef enum pl2303_type { + PL2303_TYPE_H, + PL2303_TYPE_HX, + PL2303_TYPE_TA, + PL2303_TYPE_TB, + PL2303_TYPE_HXD, + PL2303_TYPE_HXN, + // PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, + // PL2303_TYPE_UNKNOWN, + PL2303_TYPE_COUNT +} pl2303_type_t; -struct pl2303_type_data { +typedef struct pl2303_type_data { uint8_t const *name; uint32_t const max_baud_rate; uint8_t const quirks; uint16_t const no_autoxonxoff:1; uint16_t const no_divisors:1; uint16_t const alt_divisors:1; -}; +} pl2303_type_data_t; #define PL2303_TYPE_DATA \ - [TYPE_H] = { \ + [PL2303_TYPE_H] = { \ .name = (uint8_t const*)"H", \ .max_baud_rate = 1228800, \ .quirks = PL2303_QUIRK_LEGACY, \ .no_autoxonxoff = true, \ }, \ - [TYPE_HX] = { \ + [PL2303_TYPE_HX] = { \ .name = (uint8_t const*)"HX", \ .max_baud_rate = 6000000, \ }, \ - [TYPE_TA] = { \ + [PL2303_TYPE_TA] = { \ .name = (uint8_t const*)"TA", \ .max_baud_rate = 6000000, \ .alt_divisors = true, \ }, \ - [TYPE_TB] = { \ + [PL2303_TYPE_TB] = { \ .name = (uint8_t const*)"TB", \ .max_baud_rate = 12000000, \ .alt_divisors = true, \ }, \ - [TYPE_HXD] = { \ + [PL2303_TYPE_HXD] = { \ .name = (uint8_t const*)"HXD", \ .max_baud_rate = 12000000, \ }, \ - [TYPE_HXN] = { \ + [PL2303_TYPE_HXN] = { \ .name = (uint8_t const*)"G (HXN)", \ .max_baud_rate = 12000000, \ .no_divisors = true, \ @@ -166,7 +168,7 @@ typedef struct TU_ATTR_PACKED { #define PL2303_IN_EP 0x83 // return values of pl2303_detect_type() -#define PL2303_SUPPORTS_HX_STATUS_TRIGGERED -1 -#define PL2303_DETECT_TYPE_FAILED -2 +#define PL2303_TYPE_NEED_SUPPORTS_HX_STATUS -1 +#define PL2303_TYPE_UNKNOWN -2 #endif // TUSB_PL2303_H From ec1a26251d0161d5e7c11f4ca552af154cf08dbd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:05:21 +0700 Subject: [PATCH 066/101] clean up pl2303 type data --- src/class/cdc/cdc_host.c | 130 +++++++++++++++------------------- src/class/cdc/serial/pl2303.h | 46 ++++-------- 2 files changed, 74 insertions(+), 102 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ce98e3b3d..dae38ba42 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -2274,7 +2274,7 @@ static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { //--------------------------------------------------------------------+ #if CFG_TUH_CDC_PL2303 -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); +static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step); static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]); //------------- Control Request -------------// @@ -2313,20 +2313,18 @@ static bool pl2303_set_request(cdch_interface_t *p_cdc, uint8_t request, uint8_t static bool pl2303_vendor_read(cdch_interface_t *p_cdc, uint16_t value, uint8_t *buf, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; + uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_READ_NREQUEST : PL2303_VENDOR_READ_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, complete_cb, user_data); } static bool pl2303_vendor_write(cdch_interface_t *p_cdc, uint16_t value, uint16_t index, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t request = p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN] ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; - + uint8_t request = p_cdc->pl2303.type == PL2303_TYPE_HXN ? PL2303_VENDOR_WRITE_NREQUEST : PL2303_VENDOR_WRITE_REQUEST; return pl2303_set_request(p_cdc, request, PL2303_VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, complete_cb, user_data); } static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint8_t buf = 0; - return pl2303_set_request(p_cdc, PL2303_VENDOR_READ_REQUEST, PL2303_VENDOR_READ_REQUEST_TYPE, PL2303_READ_TYPE_HX_STATUS, 0, &buf, 1, complete_cb, user_data); } @@ -2425,7 +2423,6 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2433,7 +2430,6 @@ static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2443,7 +2439,6 @@ static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2451,7 +2446,6 @@ static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // PL2303 has the same bit coding p_cdc->user_control_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); - return true; } @@ -2488,7 +2482,7 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui TU_VERIFY(p_cdc); p_cdc->serial_drid = SERIAL_DRIVER_PL2303; - p_cdc->pl2303.serial_private.quirks = 0; + p_cdc->pl2303.quirks = 0; p_cdc->pl2303.supports_hx_status = false; tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); @@ -2514,7 +2508,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() uint8_t buf = 0; - int8_t type; + pl2303_type_t type; TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); switch (state) { @@ -2540,20 +2534,13 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { } type = pl2303_detect_type(p_cdc, 2); // step 2 now with supports_hx_status TU_ASSERT(type != PL2303_TYPE_UNKNOWN); - p_cdc->pl2303.serial_private.type = &pl2303_type_data[type]; - p_cdc->pl2303.serial_private.quirks |= p_cdc->pl2303.serial_private.type->quirks; - #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL && 0// can be activated if necessary - TU_LOG_P_CDC("bDeviceClass = 0x%02x bMaxPacketSize0 = %u bcdUSB = 0x%04x bcdDevice = 0x%04x", - desc_dev->bDeviceClass, desc_dev->bMaxPacketSize0, - desc_dev->bcdUSB, desc_dev->bcdDevice); - uint16_t vid, pid; - TU_ASSERT(tuh_vid_pid_get(p_cdc->daddr, &vid, &pid)); - TU_LOG_P_CDC("vid = 0x%04x pid = 0x%04x supports_hx_status = %u type = %s quirks = %u", - vid, pid, p_cdc->pl2303.supports_hx_status, - p_cdc->pl2303.serial_private.type->name, p_cdc->pl2303.serial_private.quirks); - #endif + TU_LOG_DRV(" PL2303 type detected: %u\r\n", type); + + p_cdc->pl2303.type = type; + p_cdc->pl2303.quirks |= pl2303_type_data[type].quirks; + // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step @@ -2561,7 +2548,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE1: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 0, cdch_process_set_config, CONFIG_PL2303_READ2)); break; }// else: continue with next step @@ -2569,7 +2556,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step @@ -2577,7 +2564,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step @@ -2585,7 +2572,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step @@ -2593,7 +2580,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE2: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0x0404, 1, cdch_process_set_config, CONFIG_PL2303_READ5)); break; }// else: continue with next step @@ -2601,7 +2588,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step @@ -2609,7 +2596,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step @@ -2617,7 +2604,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE3: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 0, 1, cdch_process_set_config, CONFIG_PL2303_WRITE4)); break; }// else: continue with next step @@ -2625,7 +2612,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE4: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, 1, 0, cdch_process_set_config, CONFIG_PL2303_WRITE5)); break; }// else: continue with next step @@ -2633,21 +2620,21 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_WRITE5: // purpose unknown, overtaken from Linux Kernel driver - if (p_cdc->pl2303.serial_private.type != &pl2303_type_data[PL2303_TYPE_HXN]) { - uint16_t const windex = (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; + if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { + uint16_t const windex = (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) ? 0x24 : 0x44; TU_ASSERT(pl2303_vendor_write(p_cdc, 2, windex, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; - // from here sequence overtaken from Linux Kernel function pl2303_open() + // from here sequence overtaken from Linux Kernel function pl2303_open() case CONFIG_PL2303_RESET_ENDP1: // step 1 - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_OUT_EP, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2659,11 +2646,11 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_RESET_ENDP2: // step 2 - if (p_cdc->pl2303.serial_private.quirks & PL2303_QUIRK_LEGACY) { + if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); } else { /* reset upstream data pipes */ - if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { + if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); @@ -2691,33 +2678,33 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { TU_ATTR_FALLTHROUGH; #endif - // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program - // case CONFIG_PL2303_FLOW_CTRL_READ: - // // read flow control register for modify & write back in next step - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { - // TU_LOG_P_CDC ( "1\r\n" ); - // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, - // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - // } else { - // TU_LOG_P_CDC ( "2\r\n" ); - // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); - // } - // break; - // - // case CONFIG_PL2303_FLOW_CTRL_WRITE: - // // no flow control - // buf = xfer->buffer[0]; - // if (p_cdc->pl2303.serial_private.type == &pl2303_type_data[PL2303_TYPE_HXN]) { - // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; - // buf |= PL2303_HXN_FLOWCTRL_NONE; - // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, - // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); - // } else { - // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; - // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, - // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); - // } - // break; + // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program + // case CONFIG_PL2303_FLOW_CTRL_READ: + // // read flow control register for modify & write back in next step + // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { + // TU_LOG_P_CDC ( "1\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, PL2303_HXN_FLOWCTRL_REG, &buf, + // cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } else { + // TU_LOG_P_CDC ( "2\r\n" ); + // TU_ASSERT(pl2303_vendor_read(p_cdc, 0, &buf, cdch_process_set_config, CONFIG_PL2303_FLOW_CTRL_WRITE)); + // } + // break; + // + // case CONFIG_PL2303_FLOW_CTRL_WRITE: + // // no flow control + // buf = xfer->buffer[0]; + // if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { + // buf &= (uint8_t) ~PL2303_HXN_FLOWCTRL_MASK; + // buf |= PL2303_HXN_FLOWCTRL_NONE; + // TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_FLOWCTRL_REG, buf, + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); + // } else { + // buf &= (uint8_t) ~PL2303_FLOWCTRL_MASK; + // TU_ASSERT(pl2303_vendor_write(p_cdc, 0, buf, + // cdch_process_set_config, CONFIG_PL2303_COMPLETE)); + // } + // break; case CONFIG_PL2303_COMPLETE: set_config_complete(idx, 0, true); @@ -2732,7 +2719,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { //------------- Helper -------------// -static int8_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { +static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { tusb_desc_device_t desc_dev; TU_VERIFY(tuh_descriptor_get_device_local(p_cdc->daddr, &desc_dev), PL2303_TYPE_UNKNOWN); @@ -2932,13 +2919,14 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { uint32_t baud = p_cdc->requested_line_coding.bit_rate; uint32_t baud_sup; + const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type]; - TU_VERIFY(baud && baud <= p_cdc->pl2303.serial_private.type->max_baud_rate); + TU_VERIFY(baud && baud <= type_data->max_baud_rate); /* * Use direct method for supported baud rates, otherwise use divisors. * Newer chip types do not support divisor encoding. */ - if (p_cdc->pl2303.serial_private.type->no_divisors) { + if (type_data->no_divisors) { baud_sup = baud; } else { baud_sup = pl2303_get_supported_baud_rate(baud); @@ -2946,7 +2934,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ if (baud == baud_sup) { baud = pl2303_encode_baud_rate_direct(buf, baud); - } else if (p_cdc->pl2303.serial_private.type->alt_divisors) { + } else if (type_data->alt_divisors) { baud = pl2303_encode_baud_rate_divisor_alt(buf, baud); } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index 40311260d..c01dac0e1 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -97,65 +97,53 @@ // type data typedef enum pl2303_type { - PL2303_TYPE_H, - PL2303_TYPE_HX, - PL2303_TYPE_TA, - PL2303_TYPE_TB, - PL2303_TYPE_HXD, - PL2303_TYPE_HXN, - // PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, - // PL2303_TYPE_UNKNOWN, - PL2303_TYPE_COUNT + PL2303_TYPE_H = 0, // 0 + PL2303_TYPE_HX, // 1 + PL2303_TYPE_TA, // 2 + PL2303_TYPE_TB, // 3 + PL2303_TYPE_HXD, // 4 + PL2303_TYPE_HXN, // 5 + PL2303_TYPE_COUNT, + PL2303_TYPE_NEED_SUPPORTS_HX_STATUS, + PL2303_TYPE_UNKNOWN, } pl2303_type_t; typedef struct pl2303_type_data { - uint8_t const *name; uint32_t const max_baud_rate; - uint8_t const quirks; - uint16_t const no_autoxonxoff:1; - uint16_t const no_divisors:1; - uint16_t const alt_divisors:1; + uint8_t const quirks; + uint8_t const no_autoxonxoff : 1; + uint8_t const no_divisors : 1; + uint8_t const alt_divisors : 1; } pl2303_type_data_t; #define PL2303_TYPE_DATA \ [PL2303_TYPE_H] = { \ - .name = (uint8_t const*)"H", \ .max_baud_rate = 1228800, \ .quirks = PL2303_QUIRK_LEGACY, \ .no_autoxonxoff = true, \ }, \ [PL2303_TYPE_HX] = { \ - .name = (uint8_t const*)"HX", \ .max_baud_rate = 6000000, \ }, \ [PL2303_TYPE_TA] = { \ - .name = (uint8_t const*)"TA", \ .max_baud_rate = 6000000, \ .alt_divisors = true, \ }, \ [PL2303_TYPE_TB] = { \ - .name = (uint8_t const*)"TB", \ .max_baud_rate = 12000000, \ .alt_divisors = true, \ }, \ [PL2303_TYPE_HXD] = { \ - .name = (uint8_t const*)"HXD", \ .max_baud_rate = 12000000, \ }, \ [PL2303_TYPE_HXN] = { \ - .name = (uint8_t const*)"G (HXN)", \ .max_baud_rate = 12000000, \ .no_divisors = true, \ } -// private data types -struct pl2303_serial_private { - const struct pl2303_type_data* type; - uint8_t quirks; -}; - typedef struct TU_ATTR_PACKED { - struct pl2303_serial_private serial_private; + pl2303_type_t type; + uint8_t quirks; bool supports_hx_status; } pl2303_private_t; @@ -167,8 +155,4 @@ typedef struct TU_ATTR_PACKED { #define PL2303_OUT_EP 0x02 #define PL2303_IN_EP 0x83 -// return values of pl2303_detect_type() -#define PL2303_TYPE_NEED_SUPPORTS_HX_STATUS -1 -#define PL2303_TYPE_UNKNOWN -2 - #endif // TUSB_PL2303_H From fa3ec44533ff986688318c3f80e9f373f55318f0 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:22:26 +0700 Subject: [PATCH 067/101] revert CFG_TUH_CDC_DTR/RTS_CONTROL_ON_ENUM --- examples/host/cdc_msc_hid/src/tusb_config.h | 5 +- .../cdc_msc_hid_freertos/src/tusb_config.h | 3 +- src/class/cdc/cdc.h | 14 +++--- src/class/cdc/cdc_host.c | 49 ++++++------------- 4 files changed, 24 insertions(+), 47 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 4bd5b0472..e610c5672 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -103,7 +103,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 1 // number of supported CDC devices. also activates CDC ACM +#define CFG_TUH_CDC 4 // number of supported CDC devices. also activates CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API @@ -122,8 +122,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true -#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 94b121672..05deecba0 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -127,8 +127,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: -#define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM true -#define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM true +#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t // bit rate = 115200, 1 stop bit, no parity, 8 bit data width diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index 10aed79ab..9f3ace63c 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -404,8 +404,7 @@ static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) //--------------------------------------------------------------------+ // Requests //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint32_t bit_rate; uint8_t stop_bits; ///< 0: 1 stop bit - 1: 1.5 stop bits - 2: 2 stop bits uint8_t parity; ///< 0: None - 1: Odd - 2: Even - 3: Mark - 4: Space @@ -414,14 +413,13 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); -typedef union TU_ATTR_PACKED -{ +typedef union TU_ATTR_PACKED { struct { - uint8_t dtr : 1; - uint8_t rts : 1; - uint8_t : 6; + uint8_t dtr : 1; + uint8_t rts : 1; + uint8_t : 6; }; - uint8_t all; + uint8_t value; } cdc_line_control_state_t; TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct"); diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index dae38ba42..7259e819f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -52,25 +52,6 @@ serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) #define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) -// handle line control defines -#if defined(CFG_TUH_CDC_LINE_CONTROL_ON_ENUM) && \ - (defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM)) - TU_VERIFY_STATIC(false, "Contradictory line control defines"); -#endif - -#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - #define LINE_CONTROL_ON_ENUM CFG_TUH_CDC_LINE_CONTROL_ON_ENUM -#elif defined(CFG_TUH_CDC_DTR_CONTROL_ON_ENUM) || defined(CFG_TUH_CDC_RTS_CONTROL_ON_ENUM) - #ifndef CFG_TUH_CDC_DTR_CONTROL_ON_ENUM - #define CFG_TUH_CDC_DTR_CONTROL_ON_ENUM 0 - #endif - #ifndef CFG_TUH_CDC_RTS_CONTROL_ON_ENUM - #define CFG_TUH_CDC_RTS_CONTROL_ON_ENUM 0 - #endif - #define LINE_CONTROL_ON_ENUM ( ( CFG_TUH_CDC_DTR_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_DTR : 0 ) | \ - ( CFG_TUH_CDC_RTS_CONTROL_ON_ENUM ? CDC_CONTROL_LINE_STATE_RTS : 0 ) ) -#endif - //--------------------------------------------------------------------+ // Host CDC Interface //--------------------------------------------------------------------+ @@ -396,7 +377,7 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state.all = 0; + p_cdc->line_state.value = 0; return p_cdc; } } @@ -661,7 +642,7 @@ bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) - return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .all = (uint8_t) line_state }, + return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .value = (uint8_t) line_state }, complete_cb, user_data); } @@ -1004,7 +985,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.all), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.value), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; @@ -1137,9 +1118,9 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef LINE_CONTROL_ON_ENUM + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } @@ -1426,8 +1407,8 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { break; case CONFIG_FTDI_MODEM_CTRL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; @@ -1735,7 +1716,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line_state.all), + p_cdc->requested_line_state.value), NULL, 0, complete_cb, user_data); } @@ -1873,8 +1854,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CP210X_SET_DTR_RTS: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; @@ -2153,8 +2134,8 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { break; case CONFIG_CH34X_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_control_cb = cdch_process_set_config; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; @@ -2332,7 +2313,7 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state.all, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line_state.value, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2670,8 +2651,8 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_PL2303_MODEM_CONTROL: - #ifdef LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.all = LINE_CONTROL_ON_ENUM; + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else From ce9140a150f685ae228362c5fcd0b85a7900e67a Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:57:21 +0700 Subject: [PATCH 068/101] rename tuh_cdc_get_local_line_coding to tuh_cdc_get_line_coding_local add tuh_cdc_get_control_line_state_local() implement tuh_cdc_get/set_dtr/rts() as inline --- src/class/cdc/cdc_host.c | 55 +++++++--------------------------------- src/class/cdc/cdc_host.h | 45 ++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7259e819f..80b01f928 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -427,27 +427,14 @@ bool tuh_cdc_mounted(uint8_t idx) { return p_cdc->mounted; } -bool tuh_cdc_get_dtr(uint8_t idx) { +bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - - bool ret = p_cdc->line_state.dtr; -// TU_LOG_P_CDC_BOOL("get DTR", ret); - - return ret; + *line_state = p_cdc->line_state.value; + return true; } -bool tuh_cdc_get_rts(uint8_t idx) { - cdch_interface_t * p_cdc = get_itf(idx); - TU_VERIFY(p_cdc); - - bool ret = p_cdc->line_state.rts; -// TU_LOG_P_CDC_BOOL("get RTS", ret); - - return ret; -} - -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t * line_coding) { +bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); @@ -622,46 +609,22 @@ static bool set_function_call ( } } -bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // uses cdc_line_control_state_t union for line_state +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", line_state.dtr, line_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state = line_state; + p_cdc->requested_line_state.value = (uint8_t) line_state; + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line_state.dtr, p_cdc->requested_line_state.rts); - bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); + const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = line_state; + p_cdc->line_state = p_cdc->requested_line_state; } return ret; } -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // uses uint16_t for line_state => DTR (bit 0), RTS (bit 1) - - return tuh_cdc_set_control_line_state_u(idx, (cdc_line_control_state_t) { .value = (uint8_t) line_state }, - complete_cb, user_data); -} - -bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t * p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdc_line_control_state_t const line_state = { .dtr = dtr_state, .rts = p_cdc->line_state.rts }; - - return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); -} - -bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - cdch_interface_t *p_cdc = get_itf(idx); - TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - cdc_line_control_state_t const line_state = {.rts = rts_state, .dtr = p_cdc->line_state.dtr}; - - return tuh_cdc_set_control_line_state_u(idx, line_state, complete_cb, user_data); -} - bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 63eb1fc0f..688164cb2 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -69,14 +69,27 @@ uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num); // return true if index is correct and interface is currently mounted bool tuh_cdc_itf_get_info(uint8_t idx, tuh_itf_info_t* info); -// Check if a interface is mounted +// Check if an interface is mounted bool tuh_cdc_mounted(uint8_t idx); +// Get local (cached) line state +// This function should return correct values if tuh_cdc_set_control_line_state() / tuh_cdc_get_control_line_state() +// are invoked previously or CFG_TUH_CDC_LINE_STATE_ON_ENUM is defined. +bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state); + // Get current DTR status -bool tuh_cdc_get_dtr(uint8_t idx); +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_dtr(uint8_t idx) { + uint16_t line_state; + TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state)); + return (line_state & CDC_CONTROL_LINE_STATE_DTR) != 0; +} // Get current RTS status -bool tuh_cdc_get_rts(uint8_t idx); +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_get_rts(uint8_t idx) { + uint16_t line_state; + TU_VERIFY(tuh_cdc_get_control_line_state_local(idx, &line_state)); + return (line_state & CDC_CONTROL_LINE_STATE_RTS) != 0; +} // Check if interface is connected (DTR active) TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { @@ -87,7 +100,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) { // This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() // are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined. // NOTE: This function does not make any USB transfer request to device. -bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding); +bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t* line_coding); + +#define tuh_cdc_get_local_line_coding tuh_cdc_get_line_coding_local // backward compatibility //--------------------------------------------------------------------+ // Write API @@ -131,14 +146,22 @@ bool tuh_cdc_read_clear (uint8_t idx); // - The function will return true if transfer is successful, false otherwise. //--------------------------------------------------------------------+ -// Request to Set Control Line State -bool tuh_cdc_set_control_line_state_u(uint8_t idx, cdc_line_control_state_t line_state, // uses cdc_line_control_state_t union for line_state - tuh_xfer_cb_t complete_cb, uintptr_t user_data); -bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, // uses uint16_t for line_state (legacy function) - tuh_xfer_cb_t complete_cb, uintptr_t user_data); // DTR (bit 0), RTS (bit 1) +// Request to Set Control Line State: DTR (bit 0), RTS (bit 1) +bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set DTR -bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data); // Request to Set RTS +// Request to Set DTR +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_dtr(uint8_t idx, bool dtr_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdc_line_control_state_t line_state = { .dtr = dtr_state }; + line_state.rts = tuh_cdc_get_rts(idx); + return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data); +} + +// Request to Set RTS +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_set_rts(uint8_t idx, bool rts_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + cdc_line_control_state_t line_state = { .rts = rts_state }; + line_state.dtr = tuh_cdc_get_dtr(idx); + return tuh_cdc_set_control_line_state(idx, line_state.value, complete_cb, user_data); +} // Request to set baudrate bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data); From 221b5288e43feff140c695af4481b7815f1b56cd Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 18:14:24 +0700 Subject: [PATCH 069/101] union ftdi/pl2303/acm data to save memory. --- src/class/cdc/cdc_host.c | 283 ++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 140 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 80b01f928..2fe2c85bc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -65,27 +65,30 @@ typedef struct { uint8_t ep_notif; uint8_t serial_drid; // Serial Driver ID bool mounted; // Enumeration is complete - cdc_acm_capability_t acm_capability; - TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width - TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding; - // 1 byte padding + struct { + TU_ATTR_ALIGNED(4) cdc_line_coding_t coding; // Baudrate, stop bits, parity, data width + cdc_line_control_state_t control_state; // DTR, RTS + } line, requested_line; - cdc_line_control_state_t line_state; - cdc_line_control_state_t requested_line_state; - - tuh_xfer_cb_t user_control_cb; + tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X tuh_xfer_cb_t requested_complete_cb; #endif - #if CFG_TUH_CDC_FTDI - ftdi_private_t ftdi; - #endif + union { + struct { + cdc_acm_capability_t capability; + } acm; - #if CFG_TUH_CDC_PL2303 + #if CFG_TUH_CDC_FTDI + ftdi_private_t ftdi; + #endif + + #if CFG_TUH_CDC_PL2303 pl2303_private_t pl2303; - #endif + #endif + }; struct { tu_edpt_stream_t tx; @@ -376,8 +379,8 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber; p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass; p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol; - p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; - p_cdc->line_state.value = 0; + p_cdc->line.coding = (cdc_line_coding_t) { 0, 0, 0, 0 }; + p_cdc->line.control_state.value = 0; return p_cdc; } } @@ -430,7 +433,7 @@ bool tuh_cdc_mounted(uint8_t idx) { bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_state = p_cdc->line_state.value; + *line_state = p_cdc->line.control_state.value; return true; } @@ -438,10 +441,10 @@ bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_coding = p_cdc->line_coding; + *line_coding = p_cdc->line.coding; TU_LOG_P_CDC("get line coding %lu %u%c%s", - p_cdc->line_coding.bit_rate, p_cdc->line_coding.data_bits, - CDC_LINE_CODING_PARITY_CHAR(p_cdc->line_coding.parity), + p_cdc->line.coding.bit_rate, p_cdc->line.coding.data_bits, + CDC_LINE_CODING_PARITY_CHAR(p_cdc->line.coding.parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); return true; @@ -533,7 +536,7 @@ static bool set_line_coding_sequence( // non-blocking // stage 1 set baudrate p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() - p_cdc->user_control_cb = set_line_coding_stage1_complete; + p_cdc->user_complete_cb = set_line_coding_stage1_complete; return set_baudrate_request(p_cdc, internal_control_complete, user_data); } else { // blocking sequence @@ -549,7 +552,7 @@ static bool set_line_coding_sequence( TU_VERIFY(result == XFER_RESULT_SUCCESS); // overtake baudrate after successful request - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // stage 2 set data format result = XFER_RESULT_INVALID; @@ -577,7 +580,7 @@ static void set_line_coding_stage1_complete( if (xfer->result == XFER_RESULT_SUCCESS) { // stage 1 success, continue with stage 2 - p_cdc->user_control_cb = p_cdc->requested_complete_cb; + p_cdc->user_complete_cb = p_cdc->requested_complete_cb; set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); } else { // stage 1 failed, notify user @@ -614,13 +617,13 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_state.value = (uint8_t) line_state; - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line_state.dtr, p_cdc->requested_line_state.rts); + p_cdc->requested_line.control_state.value = (uint8_t) line_state; + TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } return ret; } @@ -631,12 +634,12 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete TU_LOG_P_CDC("set baudrate %lu", baudrate); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_coding.bit_rate = baudrate; + p_cdc->requested_line.coding.bit_rate = baudrate; bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding.bit_rate = baudrate; + p_cdc->line.coding.bit_rate = baudrate; } // TU_LOG_P_CDC_BOOL("set baudrate", ret); @@ -652,16 +655,16 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_coding.stop_bits = stop_bits; - p_cdc->requested_line_coding.parity = parity; - p_cdc->requested_line_coding.data_bits = data_bits; + p_cdc->requested_line.coding.stop_bits = stop_bits; + p_cdc->requested_line.coding.parity = parity; + p_cdc->requested_line.coding.data_bits = data_bits; bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding.stop_bits = stop_bits; - p_cdc->line_coding.parity = parity; - p_cdc->line_coding.data_bits = data_bits; + p_cdc->line.coding.stop_bits = stop_bits; + p_cdc->line.coding.parity = parity; + p_cdc->line.coding.data_bits = data_bits; } // TU_LOG_P_CDC_BOOL("set data format", ret); @@ -678,12 +681,12 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line_coding = *line_coding; + p_cdc->requested_line.coding = *line_coding; bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line_coding = *line_coding; + p_cdc->line.coding = *line_coding; } // TU_LOG_P_CDC_BOOL("set line coding", ret); @@ -921,25 +924,25 @@ static void acm_internal_control_complete(tuh_xfer_t *xfer) { if (success) { switch (xfer->setup->bRequest) { case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; case CDC_REQUEST_SET_LINE_CODING: - p_cdc->line_coding = p_cdc->requested_line_coding; + p_cdc->line.coding = p_cdc->requested_line.coding; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); + TU_VERIFY(p_cdc->acm.capability.support_line_request); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -948,12 +951,12 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .direction = TUSB_DIR_OUT }, .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.value), + .wValue = tu_htole16((uint16_t) p_cdc->requested_line.control_state.value), .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber), .wLength = 0 }; - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, @@ -970,9 +973,9 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->acm_capability.support_line_request); - TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) || - p_cdc->requested_line_coding.data_bits == 16); + TU_VERIFY(p_cdc->acm.capability.support_line_request); + TU_VERIFY((p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8) || + p_cdc->requested_line.coding.data_bits == 16); tusb_control_request_t const request = { .bmRequestType_bit = { @@ -988,9 +991,9 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ // use usbh enum buf to hold line coding since user line_coding variable does not live long enough uint8_t *enum_buf = usbh_get_enum_buf(); - memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t)); + memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t)); - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; tuh_xfer_t xfer = { .daddr = p_cdc->daddr, @@ -1007,15 +1010,15 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; + p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; return acm_set_line_coding(p_cdc, complete_cb, user_data); } static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; - p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; - p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; + p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; + p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; + p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; return acm_set_line_coding(p_cdc, complete_cb, user_data); } @@ -1042,7 +1045,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) { if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) { // save ACM bmCapabilities - p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; + p_cdc->acm.capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities; } p_desc = tu_desc_next(p_desc); @@ -1082,8 +1085,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + if (p_cdc->acm.capability.support_line_request) { + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); break; } @@ -1092,8 +1095,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { case CONFIG_ACM_SET_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm_capability.support_line_request) { - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + if (p_cdc->acm.capability.support_line_request) { + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); break; } @@ -1175,10 +1178,10 @@ static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb } static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding // not each FTDI supports 1.5 stop bits return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, @@ -1186,8 +1189,8 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet } static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); + uint16_t value = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, value, p_cdc->ftdi.channel, complete_cb, user_data); @@ -1206,35 +1209,35 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; + p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; + p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; } if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; @@ -1261,7 +1264,7 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); return true; @@ -1339,15 +1342,15 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); break; // from here sequence overtaken from Linux Kernel function ftdi_set_termios() case CONFIG_FTDI_SET_DATA: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else @@ -1356,7 +1359,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else @@ -1371,8 +1374,8 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); break; #else @@ -1529,7 +1532,7 @@ static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) { } static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { - uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud = p_cdc->requested_line.coding.bit_rate; uint32_t div_value = 0; TU_VERIFY(baud); @@ -1661,16 +1664,16 @@ static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" - uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate); + uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } @@ -1679,7 +1682,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line_state.value), + p_cdc->requested_line.control_state.value), NULL, 0, complete_cb, user_data); } @@ -1697,38 +1700,38 @@ static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { if (success) { switch (xfer->setup->bRequest) { case CP210X_SET_MHS: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; case CP210X_SET_LINE_CTL: - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; + p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; + p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; break; case CP210X_SET_BAUDRATE: - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; @@ -1752,7 +1755,7 @@ static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); return true; @@ -1799,8 +1802,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_BAUDRATE_REQUEST: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else @@ -1809,7 +1812,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else @@ -1818,8 +1821,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CP210X_SET_DTR_RTS: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else @@ -1923,8 +1926,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CH34x signals are inverted - uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) | - (p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0)); + uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | + (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } @@ -1947,14 +1950,14 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { switch (tu_le16toh(xfer->setup->wValue)) { case CH34X_REG16_DIVISOR_PRESCALER: // baudrate - p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate; + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; break; case CH32X_REG16_LCR2_LCR: // data format - p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits; - p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity; - p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits; + p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; + p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; + p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; break; default: break; @@ -1962,28 +1965,28 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { break; case CH34X_REQ_MODEM_CTRL: - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; break; default: break; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; @@ -2008,7 +2011,7 @@ static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); return true; @@ -2073,7 +2076,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // see drivers from WCH vendor, Linux kernel and FreeBSD if (version >= 0x30) { // init CH34x with line coding - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); uint8_t const lcr = ch34x_get_lcr(p_cdc); TU_ASSERT(div_ps != 0 && lcr != 0); @@ -2085,7 +2088,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_SPECIAL_REG_WRITE: // overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver - p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; + p_cdc->line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X; TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL)); break; @@ -2098,8 +2101,8 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_control_cb = cdch_process_set_config; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->user_complete_cb = cdch_process_set_config; TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else @@ -2121,7 +2124,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { // calculate divisor and prescaler for baudrate, return it as 16-bit combined value static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { - uint32_t const baval = p_cdc->requested_line_coding.bit_rate; + uint32_t const baval = p_cdc->requested_line.coding.bit_rate; uint8_t a; uint8_t b; uint32_t c; @@ -2171,9 +2174,9 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) { // calculate lcr value from data coding static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) { - uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits; - uint8_t const parity = p_cdc->requested_line_coding.parity; - uint8_t const data_bits = p_cdc->requested_line_coding.data_bits; + uint8_t const stop_bits = p_cdc->requested_line.coding.stop_bits; + uint8_t const parity = p_cdc->requested_line.coding.parity; + uint8_t const data_bits = p_cdc->requested_line.coding.data_bits; uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX; TU_VERIFY(data_bits >= 5 && data_bits <= 8); @@ -2276,7 +2279,7 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line_state.value, 0, NULL, 0, complete_cb, user_data); + p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); } //static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) @@ -2292,14 +2295,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl * even to the same values as before. Thus we actually need to filter * in this specific case. */ - TU_VERIFY(p_cdc->requested_line_coding.data_bits != p_cdc->line_coding.data_bits || - p_cdc->requested_line_coding.stop_bits != p_cdc->line_coding.stop_bits || - p_cdc->requested_line_coding.parity != p_cdc->line_coding.parity || - p_cdc->requested_line_coding.bit_rate != p_cdc->line_coding.bit_rate ); + TU_VERIFY(p_cdc->requested_line.coding.data_bits != p_cdc->line.coding.data_bits || + p_cdc->requested_line.coding.stop_bits != p_cdc->line.coding.stop_bits || + p_cdc->requested_line.coding.parity != p_cdc->line.coding.parity || + p_cdc->requested_line.coding.bit_rate != p_cdc->line.coding.bit_rate ); /* For reference buf[6] data bits value */ - TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0); - buf[6] = p_cdc->requested_line_coding.data_bits; + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + buf[6] = p_cdc->requested_line.coding.data_bits; /* For reference buf[0]:buf[3] baud rate value */ TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0])); @@ -2307,14 +2310,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl /* For reference buf[4]=0 is 1 stop bits */ /* For reference buf[4]=1 is 1.5 stop bits */ /* For reference buf[4]=2 is 2 stop bits */ - buf[4] = p_cdc->requested_line_coding.stop_bits; // PL2303 has the same coding + buf[4] = p_cdc->requested_line.coding.stop_bits; // PL2303 has the same coding /* For reference buf[5]=0 is none parity */ /* For reference buf[5]=1 is odd parity */ /* For reference buf[5]=2 is even parity */ /* For reference buf[5]=3 is mark parity */ /* For reference buf[5]=4 is space parity */ - buf[5] = p_cdc->requested_line_coding.parity; // PL2303 has the same coding + buf[5] = p_cdc->requested_line.coding.parity; // PL2303 has the same coding return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); @@ -2350,45 +2353,45 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line_coding = p_cdc->requested_line_coding; + p_cdc->line.coding = p_cdc->requested_line.coding; } if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line_state = p_cdc->requested_line_state; + p_cdc->line.control_state = p_cdc->requested_line.control_state; } } - xfer->complete_cb = p_cdc->user_control_cb; + xfer->complete_cb = p_cdc->user_complete_cb; if (xfer->complete_cb) { xfer->complete_cb(xfer); } } static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate; - p_cdc->user_control_cb = complete_cb; + p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits; - p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity; - p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits; - p_cdc->user_control_cb = complete_cb; + p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; + p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; + p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding - p_cdc->user_control_cb = complete_cb; + p_cdc->user_complete_cb = complete_cb; TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); return true; } @@ -2458,7 +2461,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: - p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config + p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1); TU_ASSERT(type != PL2303_TYPE_UNKNOWN); @@ -2606,7 +2609,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // unnecessary pl2303_get_line_request() is skipped due to a stall case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else @@ -2615,7 +2618,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; + p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else @@ -2861,7 +2864,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI } static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) { - uint32_t baud = p_cdc->requested_line_coding.bit_rate; + uint32_t baud = p_cdc->requested_line.coding.bit_rate; uint32_t baud_sup; const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type]; From 5c974cee23e9ece208df43b60070740fc2eda0c3 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 12:51:29 +0700 Subject: [PATCH 070/101] usbh make TU_API_SYNC() public, to implement sync() API, change return of sync API from uint8_t to tusb_xfer_result_t --- src/common/tusb_types.h | 2 ++ src/host/usbh.c | 47 ++------------------------ src/host/usbh.h | 73 ++++++++++++++++++++++++++--------------- 3 files changed, 51 insertions(+), 71 deletions(-) diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index ff5d8b66a..ec7aad796 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -278,6 +278,8 @@ typedef enum { XFER_RESULT_INVALID } xfer_result_t; +#define tusb_xfer_result_t xfer_result_t + // TODO remove enum { DESC_OFFSET_LEN = 0, diff --git a/src/host/usbh.c b/src/host/usbh.c index 08c362171..adaeef092 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1092,8 +1092,9 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) // generic helper to get a descriptor // if blocking, user_data is pointed to xfer_result -static bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline +bool _get_descriptor(uint8_t daddr, uint8_t type, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { tusb_control_request_t const request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, @@ -1134,7 +1135,6 @@ bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer } //------------- String Descriptor -------------// - bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return _get_descriptor(daddr, TUSB_DESC_STRING, index, language_id, buffer, len, complete_cb, user_data); @@ -1272,47 +1272,6 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt, return tuh_control_xfer(&xfer); } -//--------------------------------------------------------------------+ -// Descriptor Sync -//--------------------------------------------------------------------+ - -#define _CONTROL_SYNC_API(_async_func, ...) \ - xfer_result_t result = XFER_RESULT_INVALID;\ - TU_VERIFY(_async_func(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \ - return (uint8_t) result - -uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get, daddr, type, index, buffer, len); -} - -uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_device, daddr, buffer, len); -} - -uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_configuration, daddr, index, buffer, len); -} - -uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len); -} - -uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_string, daddr, index, language_id, buffer, len); -} - -uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len); -} - -uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_product_string, daddr, language_id, buffer, len); -} - -uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { - _CONTROL_SYNC_API(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len); -} - //--------------------------------------------------------------------+ // Detaching //--------------------------------------------------------------------+ diff --git a/src/host/usbh.h b/src/host/usbh.h index 1ee511722..1e9bb26bc 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -234,8 +234,18 @@ bool tuh_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info); //--------------------------------------------------------------------+ // Transfer API +// Each Function will make a USB transfer request to device. If +// - complete_cb != NULL, the function will return immediately and invoke the callback when request is complete. +// - complete_cb == NULL, the function will block until request is complete. +// In this case, user_data should be tusb_xfer_result_t* to hold the transfer result. //--------------------------------------------------------------------+ +// Helper to make Sync API from async one +#define TU_API_SYNC(_async_api, ...) \ + xfer_result_t result = XFER_RESULT_INVALID;\ + TU_VERIFY(_async_api(__VA_ARGS__, NULL, (uintptr_t) &result), XFER_RESULT_TIMEOUT); \ + return result + // Submit a control transfer // - async: complete callback invoked when finished. // - sync : blocking if complete callback is NULL. @@ -327,45 +337,54 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* //--------------------------------------------------------------------+ // Descriptors Synchronous (blocking) +// Sync API which is blocking until transfer is complete. +// return transfer result //--------------------------------------------------------------------+ -// Sync (blocking) version of tuh_descriptor_get() -// return transfer result -uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get, daddr, type, index, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_device() -// return transfer result -uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_device() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_device, daddr, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_configuration() -// return transfer result -uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_configuration() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_configuration, daddr, index, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_hid_report() -// return transfer result -uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_hid_report() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_hid_report, daddr, itf_num, desc_type, index, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_string() -// return transfer result -uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_string() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_string, daddr, index, language_id, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_string_langid() -TU_ATTR_ALWAYS_INLINE static inline -uint8_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) { +// Sync version of tuh_descriptor_get_string_langid() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) { return tuh_descriptor_get_string_sync(daddr, 0, 0, buffer, len); } -// Sync (blocking) version of tuh_descriptor_get_manufacturer_string() -// return transfer result -uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_manufacturer_string() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_manufacturer_string, daddr, language_id, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_product_string() -// return transfer result -uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_product_string() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_product_string, daddr, language_id, buffer, len); +} -// Sync (blocking) version of tuh_descriptor_get_serial_string() -// return transfer result -uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len); +// Sync version of tuh_descriptor_get_serial_string() +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len) { + TU_API_SYNC(tuh_descriptor_get_serial_string, daddr, language_id, buffer, len); +} #ifdef __cplusplus } From adf6cbfe03523cd8f7e23cb7f2edbb4304a6cd89 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 12:52:34 +0700 Subject: [PATCH 071/101] cdch clean up and refactor, add explicit sync() API --- examples/host/cdc_msc_hid/src/cdc_app.c | 2 +- src/class/cdc/cdc_host.c | 172 ++++++++++-------------- src/class/cdc/cdc_host.h | 48 ++++++- src/class/cdc/serial/pl2303.h | 33 ++--- 4 files changed, 127 insertions(+), 128 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 6f4433f22..2fa9a8560 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -89,7 +89,7 @@ void tuh_cdc_mount_cb(uint8_t idx) { // If CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined, line coding will be set by tinyusb stack // while eneumerating new cdc device cdc_line_coding_t line_coding = {0}; - if (tuh_cdc_get_local_line_coding(idx, &line_coding)) { + if (tuh_cdc_get_line_coding_local(idx, &line_coding)) { printf(" Baudrate: %" PRIu32 ", Stop Bits : %u\r\n", line_coding.bit_rate, line_coding.stop_bits); printf(" Parity : %u, Data Width: %u\r\n", line_coding.parity, line_coding.data_bits); } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 2fe2c85bc..50d0a020d 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -42,15 +42,15 @@ // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL - #define CFG_TUH_CDC_LOG_LEVEL CFG_TUH_LOG_LEVEL + #define CFG_TUH_CDC_LOG_LEVEL 1 #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) -#define TU_LOG_CDC(TXT,DADDR,ITF_NUM,NAME,...) TU_LOG_DRV("[:%u:%u] CDCh %s " TXT "\r\n", \ - DADDR, ITF_NUM, NAME, ##__VA_ARGS__) -#define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \ - serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__) -#define TU_LOG_P_CDC_BOOL(TXT,VAL) TU_LOG_P_CDC(TXT " " #VAL " = %d", VAL) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ + serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) + +// Driver that need to set line coding in two stages: baudrate then data format. +#define DRIVER_2STAGE_SET_LINE_CODING (CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X) //--------------------------------------------------------------------+ // Host CDC Interface @@ -72,7 +72,8 @@ typedef struct { } line, requested_line; tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first - #if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X + + #if DRIVER_2STAGE_SET_LINE_CODING tuh_xfer_cb_t requested_complete_cb; #endif @@ -197,49 +198,57 @@ enum { SERIAL_DRIVER_COUNT }; +typedef bool (*serial_driver_func_t)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; + bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately + bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); bool (*const process_set_config)(tuh_xfer_t * xfer); - bool (*const set_control_line_state)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_baudrate)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_data_format)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); - bool (*const set_line_coding)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); + const serial_driver_func_t set_control_line_state; + const serial_driver_func_t set_baudrate; + const serial_driver_func_t set_data_format; + const serial_driver_func_t set_line_coding; #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - uint8_t const * name; + const char * name; #endif } cdch_serial_driver_t; +#if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL + #define DRIVER_NAME_DECLARE(_str) .name = _str +#else + #define DRIVER_NAME_DECLARE(_str) +#endif + // Note driver list must be in the same order as SERIAL_DRIVER enum static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = NULL, .vid_pid_count = 0, + .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_config, .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, .set_line_coding = acm_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "ACM" - #endif + DRIVER_NAME_DECLARE("ACM") }, #if CFG_TUH_CDC_FTDI { .vid_pid_list = ftdi_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), + .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, .set_line_coding = ftdi_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "FTDI" - #endif + DRIVER_NAME_DECLARE("FTDI") }, #endif @@ -247,15 +256,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = cp210x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), + .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_config, .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, .set_line_coding = cp210x_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "CP210x" - #endif + DRIVER_NAME_DECLARE("CP210x") }, #endif @@ -263,15 +271,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ch34x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), + .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_config, .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, .set_line_coding = ch34x_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "CH34x" - #endif + DRIVER_NAME_DECLARE("CH34x") }, #endif @@ -279,15 +286,14 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), + .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, .set_line_coding = pl2303_set_line_coding, - #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL - .name = (uint8_t const *) "PL2303" - #endif + DRIVER_NAME_DECLARE("PL2303") } #endif }; @@ -440,13 +446,7 @@ bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) { bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - *line_coding = p_cdc->line.coding; - TU_LOG_P_CDC("get line coding %lu %u%c%s", - p_cdc->line.coding.bit_rate, p_cdc->line.coding.data_bits, - CDC_LINE_CODING_PARITY_CHAR(p_cdc->line.coding.parity), - CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); - return true; } @@ -520,29 +520,27 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ +#if DRIVER_2STAGE_SET_LINE_CODING + // set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) static bool set_line_coding_sequence( cdch_interface_t * p_cdc, - // control request function to set baudrate - bool (*set_baudrate_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // control request function to set data format - bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // function to be called after stage 1 completed - void (*set_line_coding_stage1_complete)(tuh_xfer_t * xfer), - // control complete function to be called after request - void (*internal_control_complete)(tuh_xfer_t * xfer), + serial_driver_func_t set_baudrate, + serial_driver_func_t set_data_format, + tuh_xfer_cb_t set_line_coding_stage1_complete, // function to be called after stage 1 completed + tuh_xfer_cb_t internal_control_complete, // control complete function to be called after request tuh_xfer_cb_t complete_cb, uintptr_t user_data) { if (complete_cb) { // non-blocking // stage 1 set baudrate p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() p_cdc->user_complete_cb = set_line_coding_stage1_complete; - return set_baudrate_request(p_cdc, internal_control_complete, user_data); + return set_baudrate(p_cdc, internal_control_complete, user_data); } else { // blocking sequence // stage 1 set baudrate xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_baudrate_request(p_cdc, NULL, (uintptr_t) &result); + bool ret = set_baudrate(p_cdc, NULL, (uintptr_t) &result); if (user_data) { *((xfer_result_t *) user_data) = result; @@ -556,7 +554,7 @@ static bool set_line_coding_sequence( // stage 2 set data format result = XFER_RESULT_INVALID; - ret = set_data_format_request(p_cdc, NULL, (uintptr_t) &result); + ret = set_data_format(p_cdc, NULL, (uintptr_t) &result); if (user_data) { *((xfer_result_t *) user_data) = result; @@ -590,58 +588,35 @@ static void set_line_coding_stage1_complete( } } } - -// call of (non-)blocking set-functions (to set line state, baudrate, ...) -static bool set_function_call ( - cdch_interface_t * p_cdc, - bool (*set_function)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // non-blocking with call back - return set_function(p_cdc, complete_cb, user_data); - } else { - // blocking - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_function(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - return (ret && result == XFER_RESULT_SUCCESS); - } -} +#endif bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); + TU_LOG_CDC(p_cdc, "set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.control_state.value = (uint8_t) line_state; - TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); - - const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data); - + const bool ret = driver->set_control_line_state(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; + // blocking, update line state if request was successful + p_cdc->line.control_state.value = (uint8_t) line_state; } + return ret; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set baudrate %lu", baudrate); + TU_LOG_CDC(p_cdc, "set baudrate %lu", baudrate); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.coding.bit_rate = baudrate; - - bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data); - + const bool ret = driver->set_baudrate(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding.bit_rate = baudrate; } -// TU_LOG_P_CDC_BOOL("set baudrate", ret); return ret; } @@ -650,7 +625,7 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set data format %u%c%s", + TU_LOG_CDC(p_cdc, "set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; @@ -659,15 +634,13 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin p_cdc->requested_line.coding.parity = parity; p_cdc->requested_line.coding.data_bits = data_bits; - bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data); + const bool ret = driver->set_data_format(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding.stop_bits = stop_bits; p_cdc->line.coding.parity = parity; p_cdc->line.coding.data_bits = data_bits; } -// TU_LOG_P_CDC_BOOL("set data format", ret); - return ret; } @@ -675,7 +648,7 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set line coding %lu %u%c%s", + TU_LOG_CDC(p_cdc, "set line coding %lu %u%c%s", line_coding->bit_rate, line_coding->data_bits, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); @@ -683,12 +656,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, p_cdc->requested_line.coding = *line_coding; - bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data); + const bool ret = driver->set_line_coding(p_cdc, complete_cb, user_data); if (ret && !complete_cb) { p_cdc->line.coding = *line_coding; } -// TU_LOG_P_CDC_BOOL("set line coding", ret); return ret; } @@ -728,7 +700,7 @@ void cdch_close(uint8_t daddr) { for (uint8_t idx = 0; idx < CFG_TUH_CDC; idx++) { cdch_interface_t *p_cdc = &cdch_data[idx]; if (p_cdc->daddr == daddr) { - TU_LOG_P_CDC("close"); + TU_LOG_CDC(p_cdc, "close"); // Invoke application callback if (tuh_cdc_umount_cb) { @@ -847,9 +819,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d } if (driver_detected) { - TU_LOG_CDC("open", daddr, itf_desc->bInterfaceNumber, driver_detected->name); - bool ret = driver_detected->open(daddr, itf_desc, max_len); - // TU_LOG_CDC("opened ret = %s", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "true" : "FALSE" ); + const bool ret = driver_detected->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "OK" : "FAILED"); return ret; } @@ -859,7 +830,6 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); - TU_LOG_P_CDC_BOOL("set config complete", success); if (success) { p_cdc->mounted = true; @@ -883,6 +853,8 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); const uint8_t idx = get_idx_by_ptr(p_cdc); + TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; set_config_complete(idx, itf_offset, false); @@ -895,7 +867,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { uint8_t const idx = tuh_cdc_itf_get_index(daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); - TU_LOG_P_CDC("set config"); + TU_LOG_CDC(p_cdc, "set config"); // fake transfer to kick-off process_set_config() tuh_xfer_t xfer; @@ -919,7 +891,6 @@ static void acm_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1204,7 +1175,6 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1232,14 +1202,12 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - return true; } @@ -1271,7 +1239,6 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } //------------- Enumeration -------------// - enum { CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, @@ -1448,7 +1415,7 @@ static bool ftdi_determine_type(cdch_interface_t *p_cdc) { #if CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL const char * ftdi_chip_name[] = { FTDI_CHIP_NAMES }; - TU_LOG_P_CDC("%s detected (bcdDevice = 0x%04x)", + TU_LOG_CDC(p_cdc, "%s detected (bcdDevice = 0x%04x)", ftdi_chip_name[p_cdc->ftdi.chip_type], version); #endif @@ -1595,7 +1562,7 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { break; } - TU_LOG_P_CDC("Baudrate divisor = 0x%lu", div_value); + TU_LOG_CDC(p_cdc, "Baudrate divisor = 0x%lu", div_value); return div_value; } @@ -1695,7 +1662,6 @@ static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -1795,7 +1761,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { + switch (state) { case CONFIG_CP210X_IFC_ENABLE: TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); break; @@ -1941,7 +1907,6 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { switch (xfer->setup->bRequest) { @@ -2059,7 +2024,6 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); cdch_interface_t *p_cdc = get_itf(idx); uint8_t buffer[2];// TODO remove - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { @@ -2071,7 +2035,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) uint8_t const version = xfer->buffer[0]; - TU_LOG_P_CDC("Chip Version = 0x%02x", version); + TU_LOG_CDC(p_cdc, "Chip Version = 0x%02x", version); // only versions >= 0x30 are tested, below 0x30 seems having other programming // see drivers from WCH vendor, Linux kernel and FreeBSD if (version >= 0x30) { @@ -2348,7 +2312,6 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf(idx); TU_ASSERT(p_cdc, ); bool const success = (xfer->result == XFER_RESULT_SUCCESS); - TU_LOG_P_CDC_BOOL("control complete", success); if (success) { if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && @@ -2458,6 +2421,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { pl2303_type_t type; TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); + switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: @@ -2741,7 +2705,7 @@ static pl2303_type_t pl2303_detect_type(cdch_interface_t *p_cdc, uint8_t step) { default: break; } - TU_LOG_P_CDC("unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); + TU_LOG_CDC(p_cdc, "unknown device type bcdUSB = 0x%04x", desc_dev.bcdUSB); return PL2303_TYPE_UNKNOWN; } @@ -2886,7 +2850,7 @@ static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_ } else { baud = pl2303_encode_baud_rate_divisor(buf, baud); } - TU_LOG_P_CDC("real baudrate %lu", baud); + TU_LOG_CDC(p_cdc, "real baudrate %lu", baud); return true; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 688164cb2..37bfca270 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -137,13 +137,12 @@ bool tuh_cdc_peek(uint8_t idx, uint8_t* ch); bool tuh_cdc_read_clear (uint8_t idx); //--------------------------------------------------------------------+ -// Control Endpoint (Request) API +// Control Request API // Each Function will make a USB control transfer request to/from device // - If complete_cb is provided, the function will return immediately and invoke // the callback when request is complete. // - If complete_cb is NULL, the function will block until request is complete. -// - In this case, user_data should be pointed to xfer_result_t to hold the transfer result. -// - The function will return true if transfer is successful, false otherwise. +// In this case, user_data should be usb_xfer_result_t* to hold the transfer result. //--------------------------------------------------------------------+ // Request to Set Control Line State: DTR (bit 0), RTS (bit 1) @@ -179,17 +178,52 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, // bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding); // Connect by set both DTR, RTS -TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data); } // Disconnect by clear both DTR, RTS -TU_ATTR_ALWAYS_INLINE static inline -bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data); } +//--------------------------------------------------------------------+ +// Control Request Sync API +// Each Function will make a USB control transfer request to/from device the function will block until request is +// complete. The function will return the transfer request result +//--------------------------------------------------------------------+ +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_control_line_state_sync(uint8_t idx, uint16_t line_state) { + TU_API_SYNC(tuh_cdc_set_control_line_state, idx, line_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_dtr_sync(uint8_t idx, bool dtr_state) { + TU_API_SYNC(tuh_cdc_set_dtr, idx, dtr_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_rts_sync(uint8_t idx, bool rts_state) { + TU_API_SYNC(tuh_cdc_set_rts, idx, rts_state); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_baudrate_sync(uint8_t idx, uint32_t baudrate) { + TU_API_SYNC(tuh_cdc_set_baudrate, idx, baudrate); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_data_format_sync(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits) { + TU_API_SYNC(tuh_cdc_set_data_format, idx, stop_bits, parity, data_bits); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_set_line_coding_sync(uint8_t idx, cdc_line_coding_t const* line_coding) { + TU_API_SYNC(tuh_cdc_set_line_coding, idx, line_coding); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_connect_sync(uint8_t idx) { + TU_API_SYNC(tuh_cdc_connect, idx); +} + +TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_cdc_disconnect_sync(uint8_t idx) { + TU_API_SYNC(tuh_cdc_disconnect, idx); +} + //--------------------------------------------------------------------+ // CDC APPLICATION CALLBACKS //--------------------------------------------------------------------+ diff --git a/src/class/cdc/serial/pl2303.h b/src/class/cdc/serial/pl2303.h index c01dac0e1..63910c7bb 100644 --- a/src/class/cdc/serial/pl2303.h +++ b/src/class/cdc/serial/pl2303.h @@ -109,36 +109,37 @@ typedef enum pl2303_type { } pl2303_type_t; typedef struct pl2303_type_data { - uint32_t const max_baud_rate; - uint8_t const quirks; - uint8_t const no_autoxonxoff : 1; - uint8_t const no_divisors : 1; - uint8_t const alt_divisors : 1; + uint32_t max_baud_rate; + uint8_t quirks; + uint8_t no_autoxonxoff : 1; + uint8_t no_divisors : 1; + uint8_t alt_divisors : 1; } pl2303_type_data_t; #define PL2303_TYPE_DATA \ [PL2303_TYPE_H] = { \ - .max_baud_rate = 1228800, \ - .quirks = PL2303_QUIRK_LEGACY, \ - .no_autoxonxoff = true, \ + .max_baud_rate = 1228800, .quirks = PL2303_QUIRK_LEGACY, \ + .no_autoxonxoff = 1, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_HX] = { \ - .max_baud_rate = 6000000, \ + .max_baud_rate = 6000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_TA] = { \ - .max_baud_rate = 6000000, \ - .alt_divisors = true, \ + .max_baud_rate = 6000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \ }, \ [PL2303_TYPE_TB] = { \ - .max_baud_rate = 12000000, \ - .alt_divisors = true, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 1 \ }, \ [PL2303_TYPE_HXD] = { \ - .max_baud_rate = 12000000, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 0, .alt_divisors = 0 \ }, \ [PL2303_TYPE_HXN] = { \ - .max_baud_rate = 12000000, \ - .no_divisors = true, \ + .max_baud_rate = 12000000, .quirks = 0, \ + .no_autoxonxoff = 0, .no_divisors = 1, .alt_divisors = 0 \ } typedef struct TU_ATTR_PACKED { From 900d0d974b177959ffeaa1f34de72daf2ef72694 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 17:04:40 +0700 Subject: [PATCH 072/101] refactor change signature of serial driver's process_set_config adding serial driver's request_complete() --- src/class/cdc/cdc_host.c | 185 ++++++++++++++++++--------------------- 1 file changed, 84 insertions(+), 101 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 50d0a020d..f36487758 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -112,11 +112,13 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // Serial Driver //--------------------------------------------------------------------+ +// General driver static void cdch_process_set_config(tuh_xfer_t *xfer); +static void cdch_internal_control_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool acm_process_set_config(tuh_xfer_t * xfer); +static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -127,7 +129,8 @@ static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t c #if CFG_TUH_CDC_FTDI static uint16_t const ftdi_vid_pid_list[][2] = {CFG_TUH_CDC_FTDI_VID_PID_LIST}; static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); -static bool ftdi_proccess_set_config(tuh_xfer_t * xfer); +static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer); static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -140,7 +143,9 @@ static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIST}; static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool cp210x_process_set_config(tuh_xfer_t * xfer); +static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void acm_internal_control_complete(tuh_xfer_t *xfer); +static void cp210x_internal_control_complete(tuh_xfer_t *xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -153,7 +158,8 @@ static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST}; static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool ch34x_process_set_config(tuh_xfer_t *xfer); +static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void ch34x_internal_control_complete(tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -167,7 +173,8 @@ static uint16_t const pl2303_vid_pid_list[][2] = {CFG_TUH_CDC_PL2303_VID_PID_LIS static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TYPE_DATA}; static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); -static bool pl2303_process_set_config(tuh_xfer_t *xfer); +static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void pl2303_internal_control_complete(tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -206,11 +213,11 @@ typedef struct { bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); - bool (*const process_set_config)(tuh_xfer_t * xfer); - const serial_driver_func_t set_control_line_state; - const serial_driver_func_t set_baudrate; - const serial_driver_func_t set_data_format; - const serial_driver_func_t set_line_coding; + bool (*const process_set_config)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); + void (*const request_complete)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); // internal request complete handler to update line state + + serial_driver_func_t set_control_line_state, set_baudrate, set_data_format, set_line_coding; + #if CFG_TUSB_DEBUG && CFG_TUSB_DEBUG >= CFG_TUH_CDC_LOG_LEVEL const char * name; #endif @@ -244,6 +251,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, + .request_complete = ftdi_internal_control_complete, .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -827,11 +835,9 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d return false; } -static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - +static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { if (success) { + const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; if (tuh_cdc_mount_cb) { tuh_cdc_mount_cb(idx); @@ -848,19 +854,6 @@ static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) { usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } -static void cdch_process_set_config(tuh_xfer_t *xfer) { - cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); - TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - const uint8_t idx = get_idx_by_ptr(p_cdc); - - TU_LOG_DRV(" state = %u\r\n", xfer->user_data); - - if (!serial_drivers[p_cdc->serial_drid].process_set_config(xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(idx, itf_offset, false); - } -} - bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); @@ -880,6 +873,32 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } + +static void cdch_process_set_config(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + + if (!serial_drivers[p_cdc->serial_drid].process_set_config(p_cdc, xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, false); + } +} + +static void cdch_internal_control_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + + TU_LOG_DRV(" request result = %u\r\n", xfer->result); + serial_drivers[p_cdc->serial_drid].request_complete(p_cdc, xfer); + + // Invoke application callback + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + //--------------------------------------------------------------------+ // ACM //--------------------------------------------------------------------+ @@ -1046,13 +1065,9 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 return true; } -static bool acm_process_set_config(tuh_xfer_t *xfer) { +static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { case CONFIG_ACM_SET_CONTROL_LINE_STATE: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM @@ -1076,7 +1091,7 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) { case CONFIG_ACM_COMPLETE: // itf_num+1 to account for data interface as well - set_config_complete(idx, 1, true); + set_config_complete(p_cdc, 1, true); break; default: @@ -1159,55 +1174,38 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet value, p_cdc->ftdi.channel, complete_cb, user_data); } -static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t value = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | - (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - value, p_cdc->ftdi.channel, complete_cb, user_data); -} - //------------- Driver API -------------// // internal control complete to update state such as line state, line_coding -static void ftdi_internal_control_complete(tuh_xfer_t *xfer) { - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { +static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer) { + const tusb_control_request_t * setup = xfer->setup; + if (xfer->result == XFER_RESULT_SUCCESS) { + if (setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) { p_cdc->line.control_state = p_cdc->requested_line.control_state; } - if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { + if (setup->bRequest == FTDI_SIO_SET_DATA_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) { p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; } - if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && - xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { + if (setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST && + setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) { p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; } } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); + TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1218,7 +1216,7 @@ static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = p_cdc->bInterfaceNumber; set_line_coding_stage1_complete(xfer, itf_num, ftdi_set_data_request, // control request function to set data format - ftdi_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1227,15 +1225,16 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet ftdi_change_speed, // control request function to set baudrate ftdi_set_data_request, // control request function to set data format ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed - ftdi_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + uint16_t line_state = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | + (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data)); - - return true; + return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, + line_state, p_cdc->ftdi.channel, complete_cb ? cdch_internal_control_complete : NULL, user_data); } //------------- Enumeration -------------// @@ -1274,18 +1273,14 @@ static bool ftdi_open(uint8_t daddr, const tusb_desc_interface_t *itf_desc, uint return open_ep_stream_pair(p_cdc, desc_ep); } -static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { +static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - uint8_t const itf_num = p_cdc->bInterfaceNumber; - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); - switch (state) { // from here sequence overtaken from Linux Kernel function ftdi_port_probe() case CONFIG_FTDI_DETERMINE_TYPE: // determine type - if (itf_num == 0) { + if (p_cdc->bInterfaceNumber == 0) { TU_ASSERT(ftdi_determine_type(p_cdc)); } else { // other interfaces have same type as interface 0 @@ -1318,7 +1313,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); + TU_ASSERT(ftdi_set_data_request(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1327,7 +1322,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_SET_BAUDRATE: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); + TU_ASSERT(ftdi_change_speed(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1342,15 +1337,14 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) { case CONFIG_FTDI_MODEM_CTRL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE)); + TU_ASSERT(ftdi_set_modem_ctrl(p_cdc, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; #endif case CONFIG_FTDI_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -1754,12 +1748,9 @@ static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return open_ep_stream_pair(p_cdc, desc_ep); } -static bool cp210x_process_set_config(tuh_xfer_t *xfer) { +static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); switch (state) { case CONFIG_CP210X_IFC_ENABLE: @@ -1796,7 +1787,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CP210X_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -2018,13 +2009,10 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui return true; } -static bool ch34x_process_set_config(tuh_xfer_t *xfer) { - const uintptr_t state = xfer->user_data; - uint8_t const itf_num = 0; // CH34x has only interface 0, since wIndex is used as payload - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); +static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { uint8_t buffer[2];// TODO remove - TU_ASSERT(p_cdc && xfer->result == XFER_RESULT_SUCCESS); + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); + const uintptr_t state = xfer->user_data; switch (state) { case CONFIG_CH34X_READ_VERSION: @@ -2074,7 +2062,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) { #endif case CONFIG_CH34X_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: @@ -2410,18 +2398,13 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, ui return true; } -static bool pl2303_process_set_config(tuh_xfer_t *xfer) { - const uintptr_t state = xfer->user_data; - // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); +static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() + const uintptr_t state = xfer->user_data; + TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1); uint8_t buf = 0; pl2303_type_t type; - TU_ASSERT(p_cdc && (xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1)); - switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: @@ -2618,7 +2601,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) { // break; case CONFIG_PL2303_COMPLETE: - set_config_complete(idx, 0, true); + set_config_complete(p_cdc, 0, true); break; default: From 470e12febca6e371de03120508ef44db28e8501d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 17:25:58 +0700 Subject: [PATCH 073/101] refactor, add cdch_internal_control_complete() --- src/class/cdc/cdc_host.c | 233 ++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 138 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index f36487758..1786f7815 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -119,6 +119,7 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); +static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -144,8 +145,7 @@ static uint16_t const cp210x_vid_pid_list[][2] = {CFG_TUH_CDC_CP210X_VID_PID_LIS static bool cp210x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void acm_internal_control_complete(tuh_xfer_t *xfer); -static void cp210x_internal_control_complete(tuh_xfer_t *xfer); +static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -159,7 +159,7 @@ static uint16_t const ch34x_vid_pid_list[][2] = {CFG_TUH_CDC_CH34X_VID_PID_LIST} static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void ch34x_internal_control_complete(tuh_xfer_t *xfer); +static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -174,7 +174,7 @@ static const pl2303_type_data_t pl2303_type_data[PL2303_TYPE_COUNT] = {PL2303_TY static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static void pl2303_internal_control_complete(tuh_xfer_t *xfer); +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -237,6 +237,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_config, + .request_complete = acm_internal_control_complete, + .set_control_line_state = acm_set_control_line_state, .set_baudrate = acm_set_baudrate, .set_data_format = acm_set_data_format, @@ -252,6 +254,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .request_complete = ftdi_internal_control_complete, + .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, @@ -267,6 +270,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_config, + .request_complete = cp210x_internal_control_complete, + .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, @@ -282,6 +287,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_config, + .request_complete = ch34x_internal_control_complete, + .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, @@ -297,6 +304,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, + .request_complete = pl2303_internal_control_complete, + .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -904,37 +913,28 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer) { //--------------------------------------------------------------------+ // internal control complete to update state such as line state, encoding -static void acm_internal_control_complete(tuh_xfer_t *xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); +static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY (xfer->result == XFER_RESULT_SUCCESS,); + const tusb_control_request_t * setup = xfer->setup; - if (success) { - switch (xfer->setup->bRequest) { - case CDC_REQUEST_SET_CONTROL_LINE_STATE: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; + switch (setup->bRequest) { + case CDC_REQUEST_SET_CONTROL_LINE_STATE: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - case CDC_REQUEST_SET_LINE_CODING: - p_cdc->line.coding = p_cdc->requested_line.coding; - break; + case CDC_REQUEST_SET_LINE_CODING: + p_cdc->line.coding = p_cdc->requested_line.coding; + break; - default: break; - } - } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: + break; } } static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { TU_VERIFY(p_cdc->acm.capability.support_line_request); - tusb_control_request_t const request = { + const tusb_control_request_t request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, @@ -953,7 +953,7 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, .user_data = user_data }; @@ -990,7 +990,7 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? acm_internal_control_complete : NULL, + .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, .user_data = user_data }; @@ -1178,6 +1178,7 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet // internal control complete to update state such as line state, line_coding static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); const tusb_control_request_t * setup = xfer->setup; if (xfer->result == XFER_RESULT_SUCCESS) { if (setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST && @@ -1650,50 +1651,36 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void cp210x_internal_control_complete(tuh_xfer_t *xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); +static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + switch (xfer->setup->bRequest) { + case CP210X_SET_MHS: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - if (success) { - switch (xfer->setup->bRequest) { - case CP210X_SET_MHS: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; + case CP210X_SET_LINE_CTL: + p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; + p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; + p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; + break; - case CP210X_SET_LINE_CTL: - p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; - p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; - p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; - break; + case CP210X_SET_BAUDRATE: + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; + break; - case CP210X_SET_BAUDRATE: - p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; - break; - - default: break; - } - } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: break; } } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1701,7 +1688,7 @@ static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); set_line_coding_stage1_complete(xfer, itf_num, cp210x_set_line_ctl, // control request function to set data format - cp210x_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1710,14 +1697,13 @@ static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple cp210x_set_baudrate_request, // control request function to set baudrate cp210x_set_line_ctl, // control request function to set data format cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cp210x_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1761,7 +1747,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); + TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); break; #else TU_ATTR_FALLTHROUGH; @@ -1770,7 +1756,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_CP210X_SET_LINE_CTL: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); + TU_ASSERT(cp210x_set_line_ctl(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); break; #else TU_ATTR_FALLTHROUGH; @@ -1780,7 +1766,7 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE)); + TU_ASSERT(cp210x_set_mhs(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -1891,60 +1877,45 @@ static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void ch34x_internal_control_complete(tuh_xfer_t *xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); +static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + switch (xfer->setup->bRequest) { + case CH34X_REQ_WRITE_REG: + // register write request + switch (tu_le16toh(xfer->setup->wValue)) { + case CH34X_REG16_DIVISOR_PRESCALER: + // baudrate + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; + break; - if (success) { - switch (xfer->setup->bRequest) { - case CH34X_REQ_WRITE_REG: - // register write request - switch (tu_le16toh(xfer->setup->wValue)) { - case CH34X_REG16_DIVISOR_PRESCALER: - // baudrate - p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; - break; + case CH32X_REG16_LCR2_LCR: + // data format + p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; + p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; + p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; + break; - case CH32X_REG16_LCR2_LCR: - // data format - p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits; - p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity; - p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits; - break; + default: break; + } + break; - default: break; - } - break; + case CH34X_REQ_MODEM_CTRL: + p_cdc->line.control_state = p_cdc->requested_line.control_state; + break; - case CH34X_REQ_MODEM_CTRL: - p_cdc->line.control_state = p_cdc->requested_line.control_state; - break; - - default: break; - } - } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + default: break; } } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -1953,7 +1924,7 @@ static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { uint8_t const itf_num = 0; set_line_coding_stage1_complete(xfer, itf_num, ch34x_write_reg_data_format, // control request function to set data format - ch34x_internal_control_complete); // control complete function to be called after request + cdch_internal_control_complete); // control complete function to be called after request } // 2 stages: set baudrate (stage1) + set data format (stage2) @@ -1962,14 +1933,13 @@ static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple ch34x_write_reg_baudrate, // control request function to set baudrate ch34x_write_reg_data_format, // control request function to set data format ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - ch34x_internal_control_complete, // control complete function to be called after request + cdch_internal_control_complete, // control complete function to be called after request complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data)); - + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2055,7 +2025,7 @@ static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE)); + TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, cdch_internal_control_complete, CONFIG_CH34X_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; @@ -2293,41 +2263,28 @@ static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_x //------------- Driver API -------------// // internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(tuh_xfer_t *xfer) { - // PL2303 has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - bool const success = (xfer->result == XFER_RESULT_SUCCESS); - - if (success) { - if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line.coding = p_cdc->requested_line.coding; - } - if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; - } +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line.coding = p_cdc->requested_line.coding; } - - xfer->complete_cb = p_cdc->user_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line.control_state = p_cdc->requested_line.control_state; } } static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2336,14 +2293,14 @@ static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data)); + TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); return true; } @@ -2557,7 +2514,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_LINE_CODING: #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); + TU_ASSERT(pl2303_set_line_request(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); break; #else TU_ATTR_FALLTHROUGH; @@ -2566,7 +2523,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_MODEM_CONTROL: #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE)); + TU_ASSERT(pl2303_set_control_lines(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_COMPLETE)); break; #else TU_ATTR_FALLTHROUGH; From 2843eb405252ba4f8475c86d346b95547fb4020c Mon Sep 17 00:00:00 2001 From: milek7 Date: Thu, 26 Jun 2025 00:03:25 +0200 Subject: [PATCH 074/101] audio_device: Fix data IN endpoints with implicit feedback --- src/class/audio/audio_device.c | 37 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 11a3d4a73..a877dc900 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1003,20 +1003,22 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint ep_fb = desc_ep->bEndpointAddress; } #endif - // Data EP - if (desc_ep->bmAttributes.usage == 0) { - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { #if CFG_TUD_AUDIO_ENABLE_EP_IN - ep_in = desc_ep->bEndpointAddress; - ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); - #endif - } else { - #if CFG_TUD_AUDIO_ENABLE_EP_OUT - ep_out = desc_ep->bEndpointAddress; - ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); - #endif - } + // Data or data with implicit feedback IN EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN + && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { + ep_in = desc_ep->bEndpointAddress; + ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size); } + #endif + #if CFG_TUD_AUDIO_ENABLE_EP_OUT + // Data OUT EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT + && desc_ep->bmAttributes.usage == 0) { + ep_out = desc_ep->bEndpointAddress; + ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size); + } + #endif } } @@ -1052,10 +1054,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { - if (desc_ep->bmAttributes.usage == 0) { - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - _audiod_fct[i].interval_tx = desc_ep->bInterval; - } + // For data or data with implicit feedback IN EP + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN + && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { + _audiod_fct[i].interval_tx = desc_ep->bInterval; } } } else if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL) { @@ -1227,7 +1229,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p usbd_edpt_clear_stall(rhport, ep_addr); #if CFG_TUD_AUDIO_ENABLE_EP_IN - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00)// Check if usage is data EP + // For data or data with implicit feedback IN EP + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && (desc_ep->bmAttributes.usage == 0 || desc_ep->bmAttributes.usage == 2)) { // Save address audio->ep_in = ep_addr; From 8b5d703f74153c75dd9e4cfb224dbe74e4e262fa Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 15:57:18 +0700 Subject: [PATCH 075/101] major refactor to generalize cdch serial driver - add common 2 stage set line coding for driver without direct set_line_coding support e.g ftdi, cp210x, ch34x - add common cdch_process_line_state_on_enum() to handle cfg line state on enum e.g CFG_TUH_CDC_LINE_CONTROL/CODING_ON_ENUM - refactor cdch_internal_control_complete and user_complete_cb to be managed by tuh_cdc_ API instead of serial driver --- src/class/cdc/cdc_host.c | 663 +++++++++++++---------------------- src/class/cdc/serial/ch34x.h | 4 +- 2 files changed, 246 insertions(+), 421 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 1786f7815..7926aa9fc 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -45,12 +45,9 @@ #define CFG_TUH_CDC_LOG_LEVEL 1 #endif -#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) -#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ - serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) - -// Driver that need to set line coding in two stages: baudrate then data format. -#define DRIVER_2STAGE_SET_LINE_CODING (CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X) +#define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) +#define TU_LOG_CDC(_cdc, _format, ...) TU_LOG_DRV("[:%u:%u] CDCh %s " _format "\r\n", _cdc->daddr, _cdc->bInterfaceNumber, \ + serial_drivers[_cdc->serial_drid].name, ##__VA_ARGS__) //--------------------------------------------------------------------+ // Host CDC Interface @@ -73,10 +70,6 @@ typedef struct { tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first - #if DRIVER_2STAGE_SET_LINE_CODING - tuh_xfer_cb_t requested_complete_cb; - #endif - union { struct { cdc_acm_capability_t capability; @@ -114,7 +107,10 @@ CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC]; // General driver static void cdch_process_set_config(tuh_xfer_t *xfer); +static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer); // invoked after set config is processed static void cdch_internal_control_complete(tuh_xfer_t *xfer); +static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer); +static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer); //------------- ACM prototypes -------------// static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint16_t max_len); @@ -135,7 +131,6 @@ static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t * static bool ftdi_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ftdi_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -149,7 +144,6 @@ static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t static bool cp210x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool cp210x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool cp210x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -163,7 +157,6 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t static bool ch34x_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -210,8 +203,6 @@ typedef bool (*serial_driver_func_t)(cdch_interface_t * p_cdc, tuh_xfer_cb_t com typedef struct { uint16_t const (*vid_pid_list)[2]; uint16_t const vid_pid_count; - bool is_2stage_line_coding; // true if driver requires to set baudrate then data format separately - bool (*const open)(uint8_t daddr, const tusb_desc_interface_t * itf_desc, uint16_t max_len); bool (*const process_set_config)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); void (*const request_complete)(cdch_interface_t * p_cdc, tuh_xfer_t * xfer); // internal request complete handler to update line state @@ -234,7 +225,6 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = NULL, .vid_pid_count = 0, - .is_2stage_line_coding = false, .open = acm_open, .process_set_config = acm_process_set_config, .request_complete = acm_internal_control_complete, @@ -250,15 +240,13 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ftdi_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ftdi_vid_pid_list), - .is_2stage_line_coding = true, .open = ftdi_open, .process_set_config = ftdi_proccess_set_config, .request_complete = ftdi_internal_control_complete, - .set_control_line_state = ftdi_set_modem_ctrl, .set_baudrate = ftdi_set_baudrate, .set_data_format = ftdi_set_data_format, - .set_line_coding = ftdi_set_line_coding, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("FTDI") }, #endif @@ -267,15 +255,13 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = cp210x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(cp210x_vid_pid_list), - .is_2stage_line_coding = true, .open = cp210x_open, .process_set_config = cp210x_process_set_config, .request_complete = cp210x_internal_control_complete, - .set_control_line_state = cp210x_set_modem_ctrl, .set_baudrate = cp210x_set_baudrate, .set_data_format = cp210x_set_data_format, - .set_line_coding = cp210x_set_line_coding, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("CP210x") }, #endif @@ -284,7 +270,6 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = ch34x_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(ch34x_vid_pid_list), - .is_2stage_line_coding = true, .open = ch34x_open, .process_set_config = ch34x_process_set_config, .request_complete = ch34x_internal_control_complete, @@ -292,7 +277,7 @@ static const cdch_serial_driver_t serial_drivers[] = { .set_control_line_state = ch34x_set_modem_ctrl, .set_baudrate = ch34x_set_baudrate, .set_data_format = ch34x_set_data_format, - .set_line_coding = ch34x_set_line_coding, + .set_line_coding = NULL, // 2 stage set line coding DRIVER_NAME_DECLARE("CH34x") }, #endif @@ -301,11 +286,9 @@ static const cdch_serial_driver_t serial_drivers[] = { { .vid_pid_list = pl2303_vid_pid_list, .vid_pid_count = TU_ARRAY_SIZE(pl2303_vid_pid_list), - .is_2stage_line_coding = false, .open = pl2303_open, .process_set_config = pl2303_process_set_config, .request_complete = pl2303_internal_control_complete, - .set_control_line_state = pl2303_set_modem_ctrl, .set_baudrate = pl2303_set_baudrate, .set_data_format = pl2303_set_data_format, @@ -474,28 +457,24 @@ bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding) uint32_t tuh_cdc_write(uint8_t idx, void const * buffer, uint32_t bufsize) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize); } uint32_t tuh_cdc_write_flush(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); } bool tuh_cdc_write_clear(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_clear(&p_cdc->stream.tx); } uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx); } @@ -506,21 +485,18 @@ uint32_t tuh_cdc_write_available(uint8_t idx) { uint32_t tuh_cdc_read (uint8_t idx, void * buffer, uint32_t bufsize) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize); } uint32_t tuh_cdc_read_available(uint8_t idx) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_read_available(&p_cdc->stream.rx); } bool tuh_cdc_peek(uint8_t idx, uint8_t * ch) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_peek(&p_cdc->stream.rx, ch); } @@ -537,105 +513,40 @@ bool tuh_cdc_read_clear (uint8_t idx) { // Control Endpoint API //--------------------------------------------------------------------+ -#if DRIVER_2STAGE_SET_LINE_CODING - -// set line coding using sequence with 2 stages: set baudrate (stage1) + set data format (stage2) -static bool set_line_coding_sequence( - cdch_interface_t * p_cdc, - serial_driver_func_t set_baudrate, - serial_driver_func_t set_data_format, - tuh_xfer_cb_t set_line_coding_stage1_complete, // function to be called after stage 1 completed - tuh_xfer_cb_t internal_control_complete, // control complete function to be called after request - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - if (complete_cb) { - // non-blocking - // stage 1 set baudrate - p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete() - p_cdc->user_complete_cb = set_line_coding_stage1_complete; - return set_baudrate(p_cdc, internal_control_complete, user_data); - } else { - // blocking sequence - // stage 1 set baudrate - xfer_result_t result = XFER_RESULT_INVALID; // use local result, because user_data ptr may be NULL - bool ret = set_baudrate(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - TU_ASSERT(ret); - TU_VERIFY(result == XFER_RESULT_SUCCESS); - - // overtake baudrate after successful request - p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; - - // stage 2 set data format - result = XFER_RESULT_INVALID; - ret = set_data_format(p_cdc, NULL, (uintptr_t) &result); - - if (user_data) { - *((xfer_result_t *) user_data) = result; - } - - TU_ASSERT(ret); - return (result == XFER_RESULT_SUCCESS); - // the overtaking of remaining requested_line_coding will be done in tuh_cdc_set_line_coding() - } -} - -static void set_line_coding_stage1_complete( - tuh_xfer_t * xfer, uint8_t const itf_num, - // control request function to set data format - bool (*set_data_format_request)(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data), - // control complete function to be called after request - void (*internal_control_complete)(tuh_xfer_t * xfer)) { - uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num); - cdch_interface_t * p_cdc = get_itf(idx); - TU_ASSERT(p_cdc,); - - if (xfer->result == XFER_RESULT_SUCCESS) { - // stage 1 success, continue with stage 2 - p_cdc->user_complete_cb = p_cdc->requested_complete_cb; - set_data_format_request(p_cdc, internal_control_complete, xfer->user_data); - } else { - // stage 1 failed, notify user - xfer->complete_cb = p_cdc->requested_complete_cb; - if (xfer->complete_cb) { - xfer->complete_cb(xfer); - } - } -} -#endif - bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t * p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_CDC(p_cdc, "set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts); - cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t * driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.control_state.value = (uint8_t) line_state; - const bool ret = driver->set_control_line_state(p_cdc, complete_cb, user_data); - if (ret && !complete_cb) { + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_control_line_state(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); + + if (!complete_cb) { // blocking, update line state if request was successful p_cdc->line.control_state.value = (uint8_t) line_state; } - return ret; + return true; } bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { cdch_interface_t *p_cdc = get_itf(idx); TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT); TU_LOG_CDC(p_cdc, "set baudrate %lu", baudrate); - cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line = p_cdc->line; // keep current line coding p_cdc->requested_line.coding.bit_rate = baudrate; - const bool ret = driver->set_baudrate(p_cdc, complete_cb, user_data); - if (ret && !complete_cb) { + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); + + if (!complete_cb) { p_cdc->line.coding.bit_rate = baudrate; } - return ret; + return true; } bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uint8_t data_bits, @@ -645,20 +556,24 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin TU_LOG_CDC(p_cdc, "set data format %u%c%s", data_bits, CDC_LINE_CODING_PARITY_CHAR(parity), CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits)); - cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + p_cdc->requested_line = p_cdc->line; // keep current line coding p_cdc->requested_line.coding.stop_bits = stop_bits; p_cdc->requested_line.coding.parity = parity; p_cdc->requested_line.coding.data_bits = data_bits; - const bool ret = driver->set_data_format(p_cdc, complete_cb, user_data); + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - if (ret && !complete_cb) { + if (!complete_cb) { + // blocking p_cdc->line.coding.stop_bits = stop_bits; p_cdc->line.coding.parity = parity; p_cdc->line.coding.data_bits = data_bits; } - return ret; + + return true; } bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, @@ -670,16 +585,43 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_PARITY_CHAR(line_coding->parity), CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; - p_cdc->requested_line.coding = *line_coding; - const bool ret = driver->set_line_coding(p_cdc, complete_cb, user_data); + if (driver->set_line_coding) { + // driver support set_line_coding request + TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb, user_data)); - if (ret && !complete_cb) { - p_cdc->line.coding = *line_coding; + if (!complete_cb) { + p_cdc->line.coding = *line_coding; + } + } else { + // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately + if (complete_cb) { + // non-blocking + p_cdc->user_complete_cb = complete_cb; + TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); + } else { + // blocking + xfer_result_t result = XFER_RESULT_INVALID; + + TU_VERIFY(driver->set_baudrate(p_cdc, NULL, (uintptr_t) &result)); + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate + + result = XFER_RESULT_INVALID; + TU_VERIFY(driver->set_data_format(p_cdc, NULL, (uintptr_t) &result)); + if (user_data) { + *((xfer_result_t *) user_data) = result; + } + TU_VERIFY(result == XFER_RESULT_SUCCESS); + p_cdc->line.coding = p_cdc->requested_line.coding; // update data format + } } - return ret; + return true; } //--------------------------------------------------------------------+ @@ -809,60 +751,31 @@ static bool open_ep_stream_pair(cdch_interface_t *p_cdc, tusb_desc_endpoint_t co bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { (void) rhport; - cdch_serial_driver_t const *driver_detected = NULL; - // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); - } else if (SERIAL_DRIVER_COUNT > 1 && - TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { - uint16_t vid, pid; - TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); + } else if (SERIAL_DRIVER_COUNT > 1 && + TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + uint16_t vid, pid; + TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - cdch_serial_driver_t const *driver = &serial_drivers[dr]; - for (size_t i = 0; i < driver->vid_pid_count; i++) { - if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { - driver_detected = driver; - break; + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + const cdch_serial_driver_t *driver = &serial_drivers[dr]; + for (size_t i = 0; i < driver->vid_pid_count; i++) { + if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { + const bool ret = driver->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); + return ret; + } + } } - } - if (driver_detected) { - break; - } - } - } - - if (driver_detected) { - const bool ret = driver_detected->open(daddr, itf_desc, max_len); - TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver_detected->name, ret ? "OK" : "FAILED"); - return ret; - } + } return false; } -static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { - if (success) { - const uint8_t idx = get_idx_by_ptr(p_cdc); - p_cdc->mounted = true; - if (tuh_cdc_mount_cb) { - tuh_cdc_mount_cb(idx); - } - // Prepare for incoming data - tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); - } else { - // clear the interface entry - p_cdc->daddr = 0; - p_cdc->bInterfaceNumber = 0; - } - - // notify usbh that driver enumeration is complete - usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); -} - bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { tusb_control_request_t request; request.wIndex = tu_htole16((uint16_t) itf_num); @@ -882,24 +795,100 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } +static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { + if (success) { + const uint8_t idx = get_idx_by_ptr(p_cdc); + p_cdc->mounted = true; + if (tuh_cdc_mount_cb) { + tuh_cdc_mount_cb(idx); + } + // Prepare for incoming data + tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); + } else { + // clear the interface entry + p_cdc->daddr = 0; + p_cdc->bInterfaceNumber = 0; + } + + // notify usbh that driver enumeration is complete + usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); +} static void cdch_process_set_config(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); TU_LOG_DRV(" state = %u\r\n", xfer->user_data); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; - if (!serial_drivers[p_cdc->serial_drid].process_set_config(p_cdc, xfer)) { + if (!driver->process_set_config(p_cdc, xfer)) { const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; set_config_complete(p_cdc, itf_offset, false); } } +static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + enum { + ENUM_SET_LINE_CODING = 0, + ENUM_SET_LINE_CONTROL, + ENUM_SET_LINE_COMPLETE, + }; + const uint8_t idx = get_idx_by_ptr(p_cdc); + const uintptr_t state = xfer->user_data; + + switch (state) { + case ENUM_SET_LINE_CODING: { + #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM + // ch34x already set line coding in serial init + if (p_cdc->serial_drid != SERIAL_DRIVER_CH34X) { + const cdc_line_coding_t line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; + TU_ASSERT(tuh_cdc_set_line_coding(idx, &line_coding, + cdch_process_line_state_on_enum, ENUM_SET_LINE_CONTROL)); + break; + } + #endif + TU_ATTR_FALLTHROUGH; + } + + case ENUM_SET_LINE_CONTROL: + #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM + TU_ASSERT(tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, + cdch_process_line_state_on_enum, ENUM_SET_LINE_COMPLETE)); + break; + #else + TU_ATTR_FALLTHROUGH; + #endif + + case ENUM_SET_LINE_COMPLETE: { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, true); + break; + } + + default: + return false; + } + + return true; +} + +static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" xfer result = %u\r\n", xfer->result); + + if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) { + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; + set_config_complete(p_cdc, itf_offset, false); + } +} + + static void cdch_internal_control_complete(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" request result = %u\r\n", xfer->result); - serial_drivers[p_cdc->serial_drid].request_complete(p_cdc, xfer); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + driver->request_complete(p_cdc, xfer); // Invoke application callback xfer->complete_cb = p_cdc->user_complete_cb; @@ -908,6 +897,38 @@ static void cdch_internal_control_complete(tuh_xfer_t *xfer) { } } +static void cdch_set_line_coding_stage1_baudrate_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" stage1 set baudrate result = %u\r\n", xfer->result); + const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; + + if (xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate; // update baudrate + TU_ASSERT(driver->set_data_format(p_cdc, cdch_set_line_coding_stage2_data_format_complete, xfer->user_data),); + } else { + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } + } +} + +static void cdch_set_line_coding_stage2_data_format_complete(tuh_xfer_t *xfer) { + cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); + TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); + TU_LOG_DRV(" stage2 set data format result = %u\r\n", xfer->result); + + if (xfer->result == XFER_RESULT_SUCCESS) { + p_cdc->line.coding = p_cdc->requested_line.coding; // update data format + } + + xfer->complete_cb = p_cdc->user_complete_cb; + if (xfer->complete_cb) { + xfer->complete_cb(xfer); + } +} + //--------------------------------------------------------------------+ // ACM //--------------------------------------------------------------------+ @@ -1000,16 +1021,10 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ } static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; - return acm_set_line_coding(p_cdc, complete_cb, user_data); } static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; - p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; - p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; - return acm_set_line_coding(p_cdc, complete_cb, user_data); } @@ -1108,7 +1123,6 @@ static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { static bool ftdi_determine_type(cdch_interface_t *p_cdc); static uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc); -static uint8_t ftdi_get_idx(tuh_xfer_t *xfer); //------------- Control Request -------------// @@ -1150,29 +1164,6 @@ static inline bool ftdi_sio_reset(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet p_cdc->ftdi.channel, complete_cb, user_data); } -static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint32_t index_value = ftdi_get_divisor(p_cdc); - TU_VERIFY(index_value); - uint16_t value = (uint16_t) index_value; - uint16_t index = (uint16_t) (index_value >> 16); - if (p_cdc->ftdi.channel) { - index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); - } - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, - value, index, complete_cb, user_data); -} - -static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); - uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 - (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding - (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding - // not each FTDI supports 1.5 stop bits - - return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, - value, p_cdc->ftdi.channel, complete_cb, user_data); -} //------------- Driver API -------------// @@ -1199,41 +1190,31 @@ static void ftdi_internal_control_complete(cdch_interface_t* p_cdc, tuh_xfer_t * } static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3 + (p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding + (p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding + // not each FTDI supports 1.5 stop bits + return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, + value, p_cdc->ftdi.channel, complete_cb, user_data); } static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} + uint32_t index_value = ftdi_get_divisor(p_cdc); + TU_VERIFY(index_value); + uint16_t value = (uint16_t) index_value; + uint16_t index = (uint16_t) (index_value >> 16); + if (p_cdc->ftdi.channel) { + index = (uint16_t) ((index << 8) | p_cdc->ftdi.channel); + } -static void ftdi_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - uint8_t const idx = ftdi_get_idx(xfer); - cdch_interface_t *p_cdc = get_itf(idx); - TU_ASSERT(p_cdc, ); - uint8_t const itf_num = p_cdc->bInterfaceNumber; - set_line_coding_stage1_complete(xfer, itf_num, - ftdi_set_data_request, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} - -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - ftdi_change_speed, // control request function to set baudrate - ftdi_set_data_request, // control request function to set data format - ftdi_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + return ftdi_set_request(p_cdc, FTDI_SIO_SET_BAUDRATE_REQUEST, FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, + value, index, complete_cb, user_data); } static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { uint16_t line_state = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) | (p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW)); - p_cdc->user_complete_cb = complete_cb; return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, line_state, p_cdc->ftdi.channel, complete_cb ? cdch_internal_control_complete : NULL, user_data); } @@ -1243,10 +1224,7 @@ enum { CONFIG_FTDI_DETERMINE_TYPE = 0, CONFIG_FTDI_WRITE_LATENCY, CONFIG_FTDI_SIO_RESET, - CONFIG_FTDI_SET_DATA, - CONFIG_FTDI_SET_BAUDRATE, CONFIG_FTDI_FLOW_CONTROL, - CONFIG_FTDI_MODEM_CTRL, CONFIG_FTDI_COMPLETE }; @@ -1305,48 +1283,20 @@ static bool ftdi_proccess_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // from here sequence overtaken from Linux Kernel function ftdi_open() case CONFIG_FTDI_SIO_RESET: - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA)); + TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_FLOW_CONTROL)); break; - // from here sequence overtaken from Linux Kernel function ftdi_set_termios() - case CONFIG_FTDI_SET_DATA: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_set_data_request(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_FTDI_SET_BAUDRATE: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ftdi_change_speed(p_cdc, cdch_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - case CONFIG_FTDI_FLOW_CONTROL: // disable flow control TU_ASSERT(ftdi_set_request(p_cdc, FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, FTDI_SIO_DISABLE_FLOW_CTRL, - p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_MODEM_CTRL)); + p_cdc->ftdi.channel, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); break; - case CONFIG_FTDI_MODEM_CTRL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(ftdi_set_modem_ctrl(p_cdc, cdch_process_set_config, CONFIG_FTDI_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_FTDI_COMPLETE: - set_config_complete(p_cdc, 0, true); + case CONFIG_FTDI_COMPLETE: { + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; + } default: return false; @@ -1562,20 +1512,6 @@ static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) { return div_value; } -static uint8_t ftdi_get_idx(tuh_xfer_t *xfer) { - uint8_t const channel = (uint8_t) tu_le16toh(xfer->setup->wIndex);// channel index, or 0 for legacy types - for (uint8_t i = 0; i < CFG_TUH_CDC; i++) { - const cdch_interface_t *p_cdc = &cdch_data[i]; - if (p_cdc->daddr == xfer->daddr && - (!p_cdc->ftdi.channel || // 0 for legacy types (only interface 0) - channel == p_cdc->ftdi.channel)) {// or multi-channel types (interfaces 0..n) - return i; - } - } - - return TUSB_INDEX_INVALID_8; -} - #endif //--------------------------------------------------------------------+ @@ -1619,32 +1555,14 @@ static bool cp210x_set_request(cdch_interface_t * p_cdc, uint8_t command, uint16 return tuh_control_xfer(&xfer); } -static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return cp210x_set_request(p_cdc, CP210X_IFC_ENABLE, enabled, NULL, 0, complete_cb, user_data); } -static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" - uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); - - return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); -} - -static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); - uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 - (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding - (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding - - return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); -} - -static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // CP210x has the same bit coding return cp210x_set_request(p_cdc, CP210X_SET_MHS, - (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | - p_cdc->requested_line.control_state.value), + (uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS | p_cdc->requested_line.control_state.value), NULL, 0, complete_cb, user_data); } @@ -1673,47 +1591,28 @@ static void cp210x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t } static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + // Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support" + uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate); + return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data); } static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} + TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0); + uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11 + (p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding + (p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding -static void cp210x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); - set_line_coding_stage1_complete(xfer, itf_num, - cp210x_set_line_ctl, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} - -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - cp210x_set_baudrate_request, // control request function to set baudrate - cp210x_set_line_ctl, // control request function to set data format - cp210x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data); } static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + return cp210x_set_mhs(p_cdc, complete_cb, user_data); } //------------- Enumeration -------------// enum { CONFIG_CP210X_IFC_ENABLE = 0, - CONFIG_CP210X_SET_BAUDRATE_REQUEST, - CONFIG_CP210X_SET_LINE_CTL, - CONFIG_CP210X_SET_DTR_RTS, CONFIG_CP210X_COMPLETE }; @@ -1740,40 +1639,12 @@ static bool cp210x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) switch (state) { case CONFIG_CP210X_IFC_ENABLE: - TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_SET_BAUDRATE_REQUEST)); + TU_ASSERT(cp210x_ifc_enable(p_cdc, CP210X_UART_ENABLE, cdch_process_set_config, CONFIG_CP210X_COMPLETE)); break; - case CONFIG_CP210X_SET_BAUDRATE_REQUEST: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_CP210X_SET_LINE_CTL: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_line_ctl(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_CP210X_SET_DTR_RTS: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(cp210x_set_mhs(p_cdc, cdch_internal_control_complete, CONFIG_CP210X_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - case CONFIG_CP210X_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0;// kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: @@ -1833,19 +1704,19 @@ static bool ch34x_set_request(cdch_interface_t *p_cdc, uint8_t direction, uint8_ return tuh_control_xfer(&xfer); } -static inline bool ch34x_control_out(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool ch34x_control_out(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_OUT, request, value, index, NULL, 0, complete_cb, user_data); } -static inline bool ch34x_control_in(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, - uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool ch34x_control_in(cdch_interface_t *p_cdc, uint8_t request, uint16_t value, uint16_t index, + uint8_t *buffer, uint16_t buffersize, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_set_request(p_cdc, TUSB_DIR_IN, request, value, index, buffer, buffersize, complete_cb, user_data); } -static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16_t reg_value, - tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +TU_ATTR_ALWAYS_INLINE static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16_t reg_value, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { return ch34x_control_out(p_cdc, CH34X_REQ_WRITE_REG, reg, reg_value, complete_cb, user_data); } @@ -1855,25 +1726,6 @@ static inline bool ch34x_write_reg(cdch_interface_t *p_cdc, uint16_t reg, uint16 // return ch34x_control_in ( p_cdc, CH34X_REQ_READ_REG, reg, 0, buffer, buffersize, complete_cb, user_data ); //} -static bool ch34x_write_reg_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint8_t const lcr = ch34x_get_lcr(p_cdc); - TU_VERIFY(lcr); - return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); -} - -static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc); - TU_VERIFY(div_ps); - return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); -} - -static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // CH34x signals are inverted - uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | - (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); - return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); -} - //------------- Driver API -------------// // internal control complete to update state such as line state, encoding @@ -1908,39 +1760,22 @@ static void ch34x_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t } static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + const uint8_t lcr = ch34x_get_lcr(p_cdc); + TU_VERIFY(lcr); + return ch34x_write_reg(p_cdc, CH32X_REG16_LCR2_LCR, lcr, complete_cb, user_data); } static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static void ch34x_set_line_coding_stage1_complete(tuh_xfer_t *xfer) { - // CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber - uint8_t const itf_num = 0; - set_line_coding_stage1_complete(xfer, itf_num, - ch34x_write_reg_data_format, // control request function to set data format - cdch_internal_control_complete); // control complete function to be called after request -} - -// 2 stages: set baudrate (stage1) + set data format (stage2) -static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return set_line_coding_sequence(p_cdc, - ch34x_write_reg_baudrate, // control request function to set baudrate - ch34x_write_reg_data_format, // control request function to set data format - ch34x_set_line_coding_stage1_complete, // function to be called after stage 1 completed - cdch_internal_control_complete, // control complete function to be called after request - complete_cb, user_data); + const uint16_t div_ps = ch34x_get_divisor_prescaler(p_cdc); + TU_VERIFY(div_ps); + return ch34x_write_reg(p_cdc, CH34X_REG16_DIVISOR_PRESCALER, div_ps, complete_cb, user_data); } static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + // CH34x signals are inverted + uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) | + (p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0)); + return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data); } //------------- Enumeration -------------// @@ -1950,7 +1785,6 @@ enum { CONFIG_CH34X_SERIAL_INIT, CONFIG_CH34X_SPECIAL_REG_WRITE, CONFIG_CH34X_FLOW_CONTROL, - CONFIG_CH34X_MODEM_CONTROL, CONFIG_CH34X_COMPLETE }; @@ -2018,25 +1852,16 @@ static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_CH34X_FLOW_CONTROL: // no hardware flow control TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, - cdch_process_set_config, CONFIG_CH34X_MODEM_CONTROL)); + cdch_process_set_config, CONFIG_CH34X_COMPLETE)); break; - case CONFIG_CH34X_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - p_cdc->user_complete_cb = cdch_process_set_config; - TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, cdch_internal_control_complete, CONFIG_CH34X_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - case CONFIG_CH34X_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: - break; + return false; } return true; diff --git a/src/class/cdc/serial/ch34x.h b/src/class/cdc/serial/ch34x.h index 7d91f01fe..0e08b0acd 100644 --- a/src/class/cdc/serial/ch34x.h +++ b/src/class/cdc/serial/ch34x.h @@ -34,9 +34,9 @@ // set line_coding @ enumeration #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM + #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X CFG_TUH_CDC_LINE_CODING_ON_ENUM #else // this default is necessary to work properly -#define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } + #define CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X { 9600, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 } #endif // USB requests From f4d049e61ba12c8ba6fcd23c18fe5089ff899186 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:05:49 +0700 Subject: [PATCH 076/101] update acm and pl2303 to match the rest of drivers --- src/class/cdc/cdc_host.c | 218 +++++++++++---------------------------- 1 file changed, 59 insertions(+), 159 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7926aa9fc..81337cde4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -117,8 +117,6 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -169,8 +167,6 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -228,10 +224,9 @@ static const cdch_serial_driver_t serial_drivers[] = { .open = acm_open, .process_set_config = acm_process_set_config, .request_complete = acm_internal_control_complete, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate, - .set_data_format = acm_set_data_format, + .set_baudrate = acm_set_line_coding, + .set_data_format = acm_set_line_coding, .set_line_coding = acm_set_line_coding, DRIVER_NAME_DECLARE("ACM") }, @@ -290,8 +285,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = pl2303_process_set_config, .request_complete = pl2303_internal_control_complete, .set_control_line_state = pl2303_set_modem_ctrl, - .set_baudrate = pl2303_set_baudrate, - .set_data_format = pl2303_set_data_format, + .set_baudrate = pl2303_set_line_coding, + .set_data_format = pl2303_set_line_coding, .set_line_coding = pl2303_set_line_coding, DRIVER_NAME_DECLARE("PL2303") } @@ -586,10 +581,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.coding = *line_coding; + p_cdc->user_complete_cb = complete_cb; if (driver->set_line_coding) { // driver support set_line_coding request - TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb, user_data)); + TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); if (!complete_cb) { p_cdc->line.coding = *line_coding; @@ -598,7 +594,6 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately if (complete_cb) { // non-blocking - p_cdc->user_complete_cb = complete_cb; TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); } else { // blocking @@ -795,7 +790,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } -static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { +static void set_config_complete(cdch_interface_t *p_cdc, bool success) { if (success) { const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; @@ -811,6 +806,7 @@ static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, boo } // notify usbh that driver enumeration is complete + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } @@ -821,8 +817,7 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; if (!driver->process_set_config(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -858,11 +853,9 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ATTR_FALLTHROUGH; #endif - case ENUM_SET_LINE_COMPLETE: { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, true); + case ENUM_SET_LINE_COMPLETE: + set_config_complete(p_cdc, true); break; - } default: return false; @@ -874,11 +867,8 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" xfer result = %u\r\n", xfer->result); - if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -967,20 +957,16 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .wLength = 0 }; - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; + return tuh_control_xfer(&xfer); } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1004,35 +990,21 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ uint8_t *enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t)); - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; -} - -static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); -} - -static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); + return tuh_control_xfer(&xfer); } //------------- Enumeration -------------// enum { - CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, - CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE + CONFIG_ACM_COMPLETE = 0 }; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { @@ -1084,30 +1056,11 @@ static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; switch (state) { - case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm.capability.support_line_request) { - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm.capability.support_line_request) { - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_COMPLETE: - // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, 1, true); + case CONFIG_ACM_COMPLETE: { + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; + } default: return false; // invalid state @@ -2023,18 +1976,40 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c &buf, 1, complete_cb, user_data); } -static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // PL2303 has the same bit coding - return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); -} - -//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) -//{ +//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) { // return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); //} -static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) { +// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; +// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); +//} + +static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, + NULL, 0, complete_cb, user_data); +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line.coding = p_cdc->requested_line.coding; + } + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line.control_state = p_cdc->requested_line.control_state; + } +} + +static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // the caller has to precheck, that the new line coding different than the current, else false returned uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; /* @@ -2070,63 +2045,10 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); } -//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) -//{ -// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; -// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); -//} - -static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - /* we don't care if it wasn't halted first. in fact some devices - * (like some ibmcam model 1 units) seem to expect hosts to make - * this request for iso endpoints, which can't halt! - */ - return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, - NULL, 0, complete_cb, user_data); -} - -//------------- Driver API -------------// - -// internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { - TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); - if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line.coding = p_cdc->requested_line.coding; - } - if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; - } -} - -static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; - p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; - p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, + p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); } //------------- Enumeration -------------// @@ -2146,8 +2068,6 @@ enum { CONFIG_PL2303_WRITE5, CONFIG_PL2303_RESET_ENDP1, CONFIG_PL2303_RESET_ENDP2, - CONFIG_PL2303_LINE_CODING, - CONFIG_PL2303_MODEM_CONTROL, // CONFIG_PL2303_FLOW_CTRL_READ, // CONFIG_PL2303_FLOW_CTRL_WRITE, CONFIG_PL2303_COMPLETE @@ -2190,7 +2110,6 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: - p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1); TU_ASSERT(type != PL2303_TYPE_UNKNOWN); @@ -2313,7 +2232,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2); } @@ -2323,37 +2242,17 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } } break; - // from here sequence overtaken from Linux Kernel function pl2303_set_termios() - // unnecessary pl2303_get_line_request() is skipped due to a stall - case CONFIG_PL2303_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_PL2303_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program // case CONFIG_PL2303_FLOW_CTRL_READ: // // read flow control register for modify & write back in next step @@ -2383,7 +2282,8 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // break; case CONFIG_PL2303_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: From 0194b8434f318b2bd7357ba954291d03d3b26286 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:25:20 +0700 Subject: [PATCH 077/101] use enum buf for process_set_config for ch34x and pl2303 --- src/class/cdc/cdc_host.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 81337cde4..ebbd9c18c 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -1054,7 +1054,9 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1 static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); + (void) p_cdc; const uintptr_t state = xfer->user_data; + switch (state) { case CONFIG_ACM_COMPLETE: { xfer->user_data = 0; // kick-off set line state on enum @@ -1767,15 +1769,16 @@ static bool ch34x_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, ui } static bool ch34x_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { - uint8_t buffer[2];// TODO remove TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; switch (state) { - case CONFIG_CH34X_READ_VERSION: - TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, + case CONFIG_CH34X_READ_VERSION: { + uint8_t* enum_buf = usbh_get_enum_buf(); + TU_ASSERT(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, enum_buf, 2, cdch_process_set_config, CONFIG_CH34X_SERIAL_INIT)); break; + } case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, set CH34x line coding (incl. baudrate) @@ -2104,7 +2107,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // state CONFIG_PL2303_READ1 may have no success due to expected stall by pl2303_supports_hx_status() const uintptr_t state = xfer->user_data; TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS || state == CONFIG_PL2303_READ1); - uint8_t buf = 0; + uint8_t* enum_buf = usbh_get_enum_buf(); pl2303_type_t type; switch (state) { @@ -2136,7 +2139,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE1)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2152,7 +2155,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ2: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2160,7 +2163,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ3: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_READ4)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ4)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2168,7 +2171,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ4: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE2)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2184,7 +2187,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ5: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, &buf, cdch_process_set_config, CONFIG_PL2303_READ6)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8484, enum_buf, cdch_process_set_config, CONFIG_PL2303_READ6)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; @@ -2192,7 +2195,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_READ6: // purpose unknown, overtaken from Linux Kernel driver if (p_cdc->pl2303.type != PL2303_TYPE_HXN) { - TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, &buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); + TU_ASSERT(pl2303_vendor_read(p_cdc, 0x8383, enum_buf, cdch_process_set_config, CONFIG_PL2303_WRITE3)); break; }// else: continue with next step TU_ATTR_FALLTHROUGH; From d86362414e9c467d93f37672228e220a718de81d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:57:26 +0700 Subject: [PATCH 078/101] clean up --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- .../cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 32 +++++++++---------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index e610c5672..2f8cb5e03 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -103,7 +103,7 @@ #define CFG_TUH_ENUMERATION_BUFSIZE 256 #define CFG_TUH_HUB 1 // number of supported hubs -#define CFG_TUH_CDC 4 // number of supported CDC devices. also activates CDC ACM +#define CFG_TUH_CDC 2 // number of supported CDC devices. also activates CDC ACM #define CFG_TUH_CDC_FTDI 1 // FTDI Serial. FTDI is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CP210X 1 // CP210x Serial. CP210X is not part of CDC class, only to re-use CDC driver API #define CFG_TUH_CDC_CH34X 1 // CH340 or CH341 Serial. CH34X is not part of CDC class, only to re-use CDC driver API @@ -122,6 +122,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index 05deecba0..bc8887211 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -127,6 +127,7 @@ //------------- CDC -------------// // Set Line Control state on enumeration/mounted: +// DTR ( bit 0), RTS (bit 1) #define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM (CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS) // Set Line Coding on enumeration/mounted, value for cdc_line_coding_t diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ebbd9c18c..f4567fac4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -42,7 +42,7 @@ // Level where CFG_TUSB_DEBUG must be at least for this driver is logged #ifndef CFG_TUH_CDC_LOG_LEVEL - #define CFG_TUH_CDC_LOG_LEVEL 1 + #define CFG_TUH_CDC_LOG_LEVEL 2 #endif #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_CDC_LOG_LEVEL, __VA_ARGS__) @@ -748,25 +748,25 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d (void) rhport; // For CDC: only support ACM subclass // Note: Protocol 0xFF can be RNDIS device - if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && + if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass && CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) { return acm_open(daddr, itf_desc, max_len); - } else if (SERIAL_DRIVER_COUNT > 1 && - TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { - uint16_t vid, pid; - TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); + } else if (SERIAL_DRIVER_COUNT > 1 && + TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) { + uint16_t vid, pid; + TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid)); - for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { - const cdch_serial_driver_t *driver = &serial_drivers[dr]; - for (size_t i = 0; i < driver->vid_pid_count; i++) { - if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { - const bool ret = driver->open(daddr, itf_desc, max_len); - TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); - return ret; - } - } + for (size_t dr = 1; dr < SERIAL_DRIVER_COUNT; dr++) { + const cdch_serial_driver_t *driver = &serial_drivers[dr]; + for (size_t i = 0; i < driver->vid_pid_count; i++) { + if (driver->vid_pid_list[i][0] == vid && driver->vid_pid_list[i][1] == pid) { + const bool ret = driver->open(daddr, itf_desc, max_len); + TU_LOG_DRV("[:%u:%u] CDCh %s open %s\r\n", daddr, itf_desc->bInterfaceNumber, driver->name, ret ? "OK" : "FAILED"); + return ret; } - } + } + } + } return false; } From d22cbe4cb5b88c869754e91c97eff513ed8b7b33 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 20:13:21 +0700 Subject: [PATCH 079/101] refactor async io, add in_isr argument to tud_msc_async_io_done() use cbw.command[0] for pending IO command --- src/class/msc/msc_device.c | 211 +++++++++++++++++-------------------- src/class/msc/msc_device.h | 70 +++++------- 2 files changed, 123 insertions(+), 158 deletions(-) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index e583f6ba8..709734b87 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -52,36 +52,27 @@ enum { MSC_STAGE_NEED_RESET, }; -enum { - MSC_NEXT_OP_NONE = 0, - MSC_NEXT_OP_READ10, - MSC_NEXT_OP_WRITE10, - MSC_NEXT_OP_STATUS -}; - typedef struct { - TU_ATTR_ALIGNED(4) msc_cbw_t cbw; - TU_ATTR_ALIGNED(4) msc_csw_t csw; - + TU_ATTR_ALIGNED(4) msc_cbw_t cbw; // 31 bytes uint8_t rhport; + + TU_ATTR_ALIGNED(4) msc_csw_t csw; // 13 bytes uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; - // Bulk Only Transfer (BOT) Protocol - uint8_t stage; - uint32_t total_len; // byte to be transferred, can be smaller than total_bytes in cbw uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage - // Sense Response Data + // Bulk Only Transfer (BOT) Protocol + uint8_t stage; + + // SCSI Sense Response Data uint8_t sense_key; uint8_t add_sense_code; uint8_t add_sense_qualifier; - // Async IO - uint8_t next_op; - uint32_t xferred_bytes; + uint8_t pending_io; // pending async IO }mscd_interface_t; static mscd_interface_t _mscd_itf; @@ -95,12 +86,11 @@ CFG_TUD_MEM_SECTION static struct { //--------------------------------------------------------------------+ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_t* buffer, uint32_t bufsize); static void proc_read10_cmd(mscd_interface_t* p_msc); -static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes); +static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes); static void proc_write10_cmd(mscd_interface_t* p_msc); -static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); -static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); +static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes); +static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes); static bool proc_stage_status(mscd_interface_t* p_msc); -static void tud_msc_async_io_done_cb(void* bytes_processed); TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) { return tu_bit_test(dir, 7); @@ -195,30 +185,31 @@ static uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) { return status; } -static bool proc_stage_status(mscd_interface_t* p_msc) { +static bool proc_stage_status(mscd_interface_t *p_msc) { uint8_t rhport = p_msc->rhport; - msc_cbw_t const* p_cbw = &p_msc->cbw; - // skip status if epin is currently stalled, will do it when received Clear Stall request - if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { - if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { - // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status - // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); - usbd_edpt_stall(rhport, p_msc->ep_in); - } else { - TU_ASSERT(send_csw(p_msc)); - } - } + msc_cbw_t const *p_cbw = &p_msc->cbw; - #if TU_CHECK_MCU(OPT_MCU_CXD56) - // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. - // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and - // hope everything will work - if ( usbd_edpt_stalled(rhport, p_msc->ep_in) ) { - usbd_edpt_clear_stall(rhport, p_msc->ep_in); - send_csw(p_msc); + // skip status if epin is currently stalled, will do it when received Clear Stall request + if (!usbd_edpt_stalled(rhport, p_msc->ep_in)) { + if ((p_cbw->total_bytes > p_msc->xferred_len) && is_data_in(p_cbw->dir)) { + // 6.7 The 13 Cases: case 5 (Hi > Di): STALL before status + // TU_LOG_DRV(" SCSI case 5 (Hi > Di): %lu > %lu\r\n", p_cbw->total_bytes, p_msc->xferred_len); + usbd_edpt_stall(rhport, p_msc->ep_in); + } else { + TU_ASSERT(send_csw(p_msc)); } - #endif - return true; + } + + #if TU_CHECK_MCU(OPT_MCU_CXD56) + // WORKAROUND: cxd56 has its own nuttx usb stack which does not forward Set/ClearFeature(Endpoint) to DCD. + // There is no way for us to know when EP is un-stall, therefore we will unconditionally un-stall here and + // hope everything will work + if (usbd_edpt_stalled(rhport, p_msc->ep_in)) { + usbd_edpt_clear_stall(rhport, p_msc->ep_in); + send_csw(p_msc); + } + #endif + return true; } //--------------------------------------------------------------------+ @@ -258,39 +249,57 @@ bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, u return true; } -static inline void set_sense_medium_not_present(uint8_t lun) { +TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lun) { // default sense is NOT READY, MEDIUM NOT PRESENT tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -void tud_msc_async_io_done(int32_t bytes_processed) { - // Precheck to avoid queueing multiple RW done callback - TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); - // Call usbd_edpt_xfer() in tud_task() to avoid racing condition - usbd_defer_func(tud_msc_async_io_done_cb, (void*) (intptr_t)bytes_processed, false); +static void proc_async_io_done(void *bytes_processed) { + mscd_interface_t *p_msc = &_mscd_itf; + TU_VERIFY(p_msc->pending_io, ); + const int32_t nbytes = (int32_t) (intptr_t) bytes_processed; + const uint8_t cmd = p_msc->cbw.command[0]; + + p_msc->pending_io = 0; + switch (cmd) { + case SCSI_CMD_READ_10: + proc_read_io_data(p_msc, nbytes); + break; + + case SCSI_CMD_WRITE_10: + proc_write_io_data(p_msc, (uint32_t) nbytes, nbytes); + break; + + default: break; + } + + // send status if stage is transitioned to STATUS + if (p_msc->stage == MSC_STAGE_STATUS) { + proc_stage_status(p_msc); + } } -static void tud_msc_async_io_done_cb(void* bytes_processed) { - TU_VERIFY(_mscd_itf.next_op != MSC_NEXT_OP_NONE,); - uint8_t next_op = _mscd_itf.next_op; - _mscd_itf.next_op = MSC_NEXT_OP_NONE; - int32_t nbytes = (int32_t)(intptr_t)bytes_processed; - // READ10 - if (next_op == MSC_NEXT_OP_READ10) { - proc_read10_next(&_mscd_itf, nbytes); - } else if (next_op == MSC_NEXT_OP_WRITE10) { - proc_write10_next(&_mscd_itf, _mscd_itf.xferred_bytes, nbytes); - // Need to manually invoke CSW transfer - if (_mscd_itf.stage == MSC_STAGE_STATUS) { - proc_stage_status(&_mscd_itf); - } +bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) { + // Precheck to avoid queueing multiple RW done callback + TU_VERIFY(_mscd_itf.pending_io); + if (bytes_io == 0) { + bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no sense to call this with BUSY here } + + if (in_isr) { + usbd_defer_func(proc_async_io_done, (void*) (intptr_t)bytes_io, in_isr); + } else { + proc_async_io_done((void*)(intptr_t) bytes_io); + } + + return true; } //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ void mscd_init(void) { + TU_LOG_INT(CFG_TUD_MSC_LOG_LEVEL, sizeof(mscd_interface_t)); tu_memclr(&_mscd_itf, sizeof(mscd_interface_t)); } @@ -528,7 +537,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t proc_read10_cmd(p_msc); } } else if (SCSI_CMD_WRITE_10 == p_cbw->command[0]) { - proc_write10_new_data(p_msc, xferred_bytes); + proc_write10_host_data(p_msc, xferred_bytes); } else { p_msc->xferred_len += xferred_bytes; @@ -560,7 +569,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t break; case MSC_STAGE_STATUS_SENT: - // Wait for the Status phase to complete + // Status phase is complete if ((ep_addr == p_msc->ep_in) && (xferred_bytes == sizeof(msc_csw_t))) { TU_LOG_DRV(" SCSI Status [Lun%u] = %u\r\n", p_cbw->lun, p_csw->status); // TU_LOG_MEM(CFG_TUD_MSC_LOG_LEVEL, p_csw, xferred_bytes, 2); @@ -590,7 +599,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t TU_ASSERT(prepare_cbw(p_msc)); } else { - // Any xfer ended here is consider unknown error, ignore it + // Any xfer ended here is considered unknown error, ignore it TU_LOG1(" Warning expect SCSI Status but received unknown data\r\n"); } break; @@ -696,8 +705,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_READ_FORMAT_CAPACITY: { - scsi_read_format_capacity_data_t read_fmt_capa = - { + scsi_read_format_capacity_data_t read_fmt_capa = { .list_length = 8, .block_num = 0, .descriptor_type = 2, // formatted media @@ -729,8 +737,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_INQUIRY: { - scsi_inquiry_resp_t inquiry_rsp = - { + scsi_inquiry_resp_t inquiry_rsp = { .is_removable = 1, .version = 2, .response_data_format = 2, @@ -750,8 +757,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_MODE_SENSE_6: { - scsi_mode_sense6_resp_t mode_resp = - { + scsi_mode_sense6_resp_t mode_resp = { .data_len = 3, .medium_type = 0, .write_protected = false, @@ -772,8 +778,7 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ break; case SCSI_CMD_REQUEST_SENSE: { - scsi_sense_fixed_resp_t sense_rsp = - { + scsi_sense_fixed_resp_t sense_rsp = { .response_code = 0x70, // current, fixed format .valid = 1 }; @@ -805,32 +810,27 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_ static void proc_read10_cmd(mscd_interface_t* p_msc) { msc_cbw_t const* p_cbw = &p_msc->cbw; - - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero + // Adjust lba & offset with transferred bytes uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); + uint32_t const offset = p_msc->xferred_len % block_sz; // remaining bytes capped at class buffer int32_t nbytes = (int32_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); - // Application can consume smaller bytes - uint32_t const offset = p_msc->xferred_len % block_sz; - - p_msc->next_op = MSC_NEXT_OP_READ10; + p_msc->pending_io = 1; nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, (uint32_t)nbytes); if (nbytes != TUD_MSC_RET_ASYNC) { - p_msc->next_op = MSC_NEXT_OP_NONE; - proc_read10_next(p_msc, nbytes); + p_msc->pending_io = 0; + proc_read_io_data(p_msc, nbytes); } } -static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { +static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { uint8_t rhport = p_msc->rhport; if (nbytes < 0) { // negative means error -> endpoint is stalled & status in CSW set to failed - TU_LOG_DRV(" tud_msc_read10_cb() return -1\r\n"); + TU_LOG_DRV(" IO read() failed\r\n"); // set sense msc_cbw_t const* p_cbw = &p_msc->cbw; @@ -838,7 +838,7 @@ static void proc_read10_next(mscd_interface_t* p_msc, int32_t nbytes) { fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else if (nbytes == 0) { - // zero means not ready -> simulate an transfer complete so that this driver callback will fired again + // zero means not ready -> fake a transfer complete so that this driver callback will fire again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); } else { TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),); @@ -864,55 +864,42 @@ static void proc_write10_cmd(mscd_interface_t* p_msc) { // remaining bytes capped at class buffer uint16_t nbytes = (uint16_t)tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes - p_msc->xferred_len); // Write10 callback will be called later when usb transfer complete - uint8_t rhport = p_msc->rhport; - TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); + TU_ASSERT(usbd_edpt_xfer(p_msc->rhport, p_msc->ep_out, _mscd_epbuf.buf, nbytes),); } // process new data arrived from WRITE10 -static void proc_write10_new_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { +static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_bytes) { msc_cbw_t const* p_cbw = &p_msc->cbw; + uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); // already verified non-zero - // block size already verified not zero - uint16_t const block_sz = rdwr10_get_blocksize(p_cbw); - - // Adjust lba with transferred bytes + // Adjust lba & offset with transferred bytes uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); - - // Invoke callback to consume new data uint32_t const offset = p_msc->xferred_len % block_sz; - p_msc->next_op = MSC_NEXT_OP_WRITE10; - p_msc->xferred_bytes = xferred_bytes; + p_msc->pending_io = 1; int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_epbuf.buf, xferred_bytes); if (nbytes != TUD_MSC_RET_ASYNC) { - p_msc->next_op = MSC_NEXT_OP_NONE; - proc_write10_next(p_msc, xferred_bytes, nbytes); + p_msc->pending_io = 0; + proc_write_io_data(p_msc, xferred_bytes, nbytes); } } -static void proc_write10_next(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { +static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { // negative means error -> failed this scsi op - TU_LOG_DRV(" tud_msc_write10_cb() return -1\r\n"); - - // update actual byte before failed - p_msc->xferred_len += xferred_bytes; - - msc_cbw_t const* p_cbw = &p_msc->cbw; - set_sense_medium_not_present(p_cbw->lun); + TU_LOG_DRV(" IO write() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); } else { if ((uint32_t)nbytes < xferred_bytes) { // Application consume less than what we got (including zero) const uint32_t left_over = xferred_bytes - (uint32_t)nbytes; if (nbytes > 0) { - p_msc->xferred_len += (uint16_t)nbytes; memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over); } - // simulate a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter - uint8_t rhport = p_msc->rhport; - dcd_event_xfer_complete(rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); + // fake a transfer complete with adjusted parameters --> callback will be invoked with adjusted parameters + dcd_event_xfer_complete(p_msc->rhport, p_msc->ep_out, left_over, XFER_RESULT_SUCCESS, false); } else { // Application consume all bytes in our buffer p_msc->xferred_len += xferred_bytes; diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 7162b11e4..2ad31c245 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -49,10 +49,11 @@ #endif // Return value of callback functions -// Error -#define TUD_MSC_RET_ERROR -1 -// Asynchronous IO -#define TUD_MSC_RET_ASYNC -16 +enum { + TUD_MSC_RET_BUSY = 0, // Busy, e.g disk I/O is not ready + TUD_MSC_RET_ERROR = -1, + TUD_MSC_RET_ASYNC = -2, // Asynchronous IO +}; TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); @@ -63,54 +64,31 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_EP_BUFSIZE < UINT16_MAX, "Size is not correct"); // Set SCSI sense response bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier); -// Called once asynchronous read/write operation is done -// bytes_processed has the same meaning of tud_msc_read10_cb() / -// tud_msc_write10_cb() return value -void tud_msc_async_io_done(int32_t bytes_processed); +// Called by Application once asynchronous I/O operation is done +// bytes_io is number of bytes in I/O op, typically the bufsize in read/write_cb() or +// TUD_MSC_RET_ERROR (-1) for error. Note TUD_MSC_RET_BUSY (0) will be treated as error as well. +bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr); //--------------------------------------------------------------------+ // Application Callbacks (WEAK is optional) //--------------------------------------------------------------------+ -// Invoked when received SCSI READ10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. -// -// - ret < bufsize : These bytes are transferred first and callback will be invoked again for remaining data. -// -// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback will be invoked again with the same parameters later on. -// -// - ret == TUD_MSC_RET_ERROR (-1) -// : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// - ret == TUD_MSC_RET_ASYNC (-16) -// : Data reading will be done asynchronously in a background task. Application should return immediately. -// tud_msc_async_io_done() must be called once reading is done to signal completion. +/* + Invoked when received SCSI READ10/WRITE10 command + - Address = lba * BLOCK_SIZE + offset + - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. + - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. + - 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data. + - ret == TUD_MSC_RET_BUSY + Application is buys e.g disk I/O not ready. + Callback will be invoked again with the same parameters later on. + - ret == TUD_MSC_RET_ERROR + error such as invalid address. This request will be STALLed and scsi command will be failed + - ret == TUD_MSC_RET_ASYNC + Data I/O will be done asynchronously in a background task. Application should return immediately. + tud_msc_async_io_done() must be called once IO/ is done to signal completion. +*/ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize); - -// Invoked when received SCSI WRITE10 command -// - Address = lba * BLOCK_SIZE + offset -// - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. -// -// - Application writes data from buffer to address contents (up to bufsize) and returns the number of bytes written or status. -// -// - ret < bufsize : Callback will be invoked again with remaining data later on. -// -// - ret == 0 : Indicate application is not ready yet e.g disk I/O busy. -// Callback will be invoked again with the same parameters later on. -// -// - ret == TUD_MSC_RET_ERROR (-1) -// : Indicate application error e.g invalid address. This request will be STALLed -// and return failed status in command status wrapper phase. -// -// - ret == TUD_MSC_RET_ASYNC (-16) -// : Data writing will be done asynchronously in a background task. Application should return immediately. -// tud_msc_async_io_done() must be called once writing is done to signal completion. -// TODO change buffer to const uint8_t* int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize); // Invoked when received SCSI_CMD_INQUIRY From 216a35e59a095e6ccb70f7c9bd4f7bc737f44140 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 20:15:16 +0700 Subject: [PATCH 080/101] update example --- .../device/cdc_msc_freertos/src/msc_disk.c | 117 ++++++++---------- .../device/cdc_msc_freertos/src/tusb_config.h | 6 - src/class/msc/msc_device.c | 6 +- 3 files changed, 55 insertions(+), 74 deletions(-) diff --git a/examples/device/cdc_msc_freertos/src/msc_disk.c b/examples/device/cdc_msc_freertos/src/msc_disk.c index c2aaca847..d1ff2f71b 100644 --- a/examples/device/cdc_msc_freertos/src/msc_disk.c +++ b/examples/device/cdc_msc_freertos/src/msc_disk.c @@ -28,8 +28,13 @@ #if CFG_TUD_MSC -#if CFG_EXAMPLE_MSC_ASYNC_IO +// Use async IO in example or not +#define CFG_EXAMPLE_MSC_ASYNC_IO 1 +// Simulate read/write operation delay +#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 + +#if CFG_EXAMPLE_MSC_ASYNC_IO #define IO_STACK_SIZE configMINIMAL_STACK_SIZE typedef struct { @@ -66,8 +71,7 @@ static bool ejected = false; If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -enum -{ +enum { DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount DISK_BLOCK_SIZE = 512 }; @@ -162,18 +166,20 @@ static void io_task(void *params) { io_ops_t io_ops; while (1) { if (xQueueReceive(io_queue, &io_ops, portMAX_DELAY)) { + const uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; + int32_t nbytes = io_ops.bufsize; if (io_ops.is_read) { - uint8_t const* addr = msc_disk[io_ops.lba] + io_ops.offset; memcpy(io_ops.buffer, addr, io_ops.bufsize); } else { #ifndef CFG_EXAMPLE_MSC_READONLY - uint8_t* addr = msc_disk[io_ops.lba] + io_ops.offset; - memcpy(addr, io_ops.buffer, io_ops.bufsize); + memcpy((uint8_t*) addr, io_ops.buffer, io_ops.bufsize); +#else + nbytes = -1; // failed to write #endif } tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - tud_msc_async_io_done(io_ops.bufsize); + tud_msc_async_io_done(nbytes, false); } } } @@ -184,14 +190,11 @@ void msc_disk_init() {} // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) -{ +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { (void) lun; - const char vid[] = "TinyUSB"; const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - memcpy(vendor_id , vid, strlen(vid)); memcpy(product_id , pid, strlen(pid)); memcpy(product_rev, rev, strlen(rev)); @@ -199,8 +202,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) -{ +bool tud_msc_test_unit_ready_cb(uint8_t lun) { (void) lun; // RAM disk is ready until ejected @@ -215,10 +217,8 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) -{ +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { (void) lun; - *block_count = DISK_BLOCK_NUM; *block_size = DISK_BLOCK_SIZE; } @@ -226,18 +226,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz // Invoked when received Start Stop Unit command // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) -{ +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { (void) lun; (void) power_condition; - if ( load_eject ) - { - if (start) - { + if (load_eject) { + if (start) { // load disk storage - }else - { + } else { // unload disk storage ejected = true; } @@ -248,116 +244,107 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo // Callback invoked when received READ10 command. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) -{ +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { (void) lun; // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) { + if (lba >= DISK_BLOCK_NUM) { return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize - if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { return TUD_MSC_RET_ERROR; } -#if CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = { .is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; + #if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = true, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; // Send IO operation to IO task TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); return TUD_MSC_RET_ASYNC; -#else - uint8_t const* addr = msc_disk[lba] + offset; + #else + uint8_t const *addr = msc_disk[lba] + offset; memcpy(buffer, addr, bufsize); - tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); - return bufsize; -#endif + #endif } -bool tud_msc_is_writable_cb (uint8_t lun) -{ +bool tud_msc_is_writable_cb (uint8_t lun) { (void) lun; -#ifdef CFG_EXAMPLE_MSC_READONLY + #ifdef CFG_EXAMPLE_MSC_READONLY return false; -#else + #else return true; -#endif + #endif } // Callback invoked when received WRITE10 command. // Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) -{ +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) { + if (lba >= DISK_BLOCK_NUM) { return TUD_MSC_RET_ERROR; } // Check for overflow of offset + bufsize - if ( lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE ) { + if (lba * DISK_BLOCK_SIZE + offset + bufsize > DISK_BLOCK_NUM * DISK_BLOCK_SIZE) { return TUD_MSC_RET_ERROR; } -#ifdef CFG_EXAMPLE_MSC_READONLY - (void) lun; (void) buffer; + #ifdef CFG_EXAMPLE_MSC_READONLY + (void) lun; + (void) buffer; return bufsize; -#endif + #endif -#if CFG_EXAMPLE_MSC_ASYNC_IO - io_ops_t io_ops = { .is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize }; + #if CFG_EXAMPLE_MSC_ASYNC_IO + io_ops_t io_ops = {.is_read = false, .lun = lun, .lba = lba, .offset = offset, .buffer = buffer, .bufsize = bufsize}; // Send IO operation to IO task TU_ASSERT(xQueueSend(io_queue, &io_ops, 0) == pdPASS); return TUD_MSC_RET_ASYNC; -#else - uint8_t* addr = msc_disk[lba] + offset; + #else + uint8_t *addr = msc_disk[lba] + offset; memcpy(addr, buffer, bufsize); tusb_time_delay_ms_api(CFG_EXAMPLE_MSC_IO_DELAY_MS); return bufsize; -#endif + #endif } // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) -{ +int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { // read10 & write10 has their own callback and MUST not be handled here - void const* response = NULL; + void const *response = NULL; int32_t resplen = 0; // most scsi handled is input bool in_xfer = true; - switch (scsi_cmd[0]) - { + switch (scsi_cmd[0]) { default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // negative means error -> tinyusb could stall and/or response with failed status resplen = -1; - break; + break; } // return resplen must not larger than bufsize - if ( resplen > bufsize ) resplen = bufsize; + if (resplen > bufsize) { resplen = bufsize; } - if ( response && (resplen > 0) ) - { - if(in_xfer) - { + if (response && (resplen > 0)) { + if (in_xfer) { memcpy(buffer, response, (size_t) resplen); - }else - { + } else { // SCSI output } } diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index d70456287..c3f2f7fb5 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -114,12 +114,6 @@ // MSC Buffer size of Device Mass storage #define CFG_TUD_MSC_EP_BUFSIZE 512 -// Use async IO in example or not -#define CFG_EXAMPLE_MSC_ASYNC_IO 1 - -// Simulate read/write operation delay -#define CFG_EXAMPLE_MSC_IO_DELAY_MS 0 - #ifdef __cplusplus } #endif diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index 709734b87..a8c52b6bd 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -828,8 +828,8 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { uint8_t rhport = p_msc->rhport; - if (nbytes < 0) { - // negative means error -> endpoint is stalled & status in CSW set to failed + if (nbytes == TUD_MSC_RET_ERROR) { + // error -> endpoint is stalled & status in CSW set to failed TU_LOG_DRV(" IO read() failed\r\n"); // set sense @@ -837,7 +837,7 @@ static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { set_sense_medium_not_present(p_cbw->lun); fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); - } else if (nbytes == 0) { + } else if (nbytes == TUD_MSC_RET_BUSY) { // zero means not ready -> fake a transfer complete so that this driver callback will fire again dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); } else { From c96cc4369f1b97efe85575f3e5633e38598e9fc2 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 1 Jul 2025 21:52:57 +0700 Subject: [PATCH 081/101] defer proc_async_io_done() --- src/class/msc/msc_device.c | 64 +++++++++++++++++++++----------------- src/class/msc/msc_device.h | 9 +++--- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c index a8c52b6bd..747ad03ed 100644 --- a/src/class/msc/msc_device.c +++ b/src/class/msc/msc_device.c @@ -254,10 +254,10 @@ TU_ATTR_ALWAYS_INLINE static inline void set_sense_medium_not_present(uint8_t lu tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); } -static void proc_async_io_done(void *bytes_processed) { +static void proc_async_io_done(void *bytes_io) { mscd_interface_t *p_msc = &_mscd_itf; TU_VERIFY(p_msc->pending_io, ); - const int32_t nbytes = (int32_t) (intptr_t) bytes_processed; + const int32_t nbytes = (int32_t) (intptr_t) bytes_io; const uint8_t cmd = p_msc->cbw.command[0]; p_msc->pending_io = 0; @@ -283,15 +283,9 @@ bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr) { // Precheck to avoid queueing multiple RW done callback TU_VERIFY(_mscd_itf.pending_io); if (bytes_io == 0) { - bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no sense to call this with BUSY here + bytes_io = TUD_MSC_RET_ERROR; // 0 is treated as error, no reason to call this with BUSY here } - - if (in_isr) { - usbd_defer_func(proc_async_io_done, (void*) (intptr_t)bytes_io, in_isr); - } else { - proc_async_io_done((void*)(intptr_t) bytes_io); - } - + usbd_defer_func(proc_async_io_done, (void *) (intptr_t) bytes_io, in_isr); return true; } @@ -827,21 +821,26 @@ static void proc_read10_cmd(mscd_interface_t* p_msc) { } static void proc_read_io_data(mscd_interface_t* p_msc, int32_t nbytes) { - uint8_t rhport = p_msc->rhport; - if (nbytes == TUD_MSC_RET_ERROR) { - // error -> endpoint is stalled & status in CSW set to failed - TU_LOG_DRV(" IO read() failed\r\n"); - - // set sense - msc_cbw_t const* p_cbw = &p_msc->cbw; - set_sense_medium_not_present(p_cbw->lun); - - fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); - } else if (nbytes == TUD_MSC_RET_BUSY) { - // zero means not ready -> fake a transfer complete so that this driver callback will fire again - dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); - } else { + const uint8_t rhport = p_msc->rhport; + if (nbytes > 0) { TU_ASSERT(usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_epbuf.buf, (uint16_t) nbytes),); + } else { + // nbytes is status + switch (nbytes) { + case TUD_MSC_RET_ERROR: + // error -> endpoint is stalled & status in CSW set to failed + TU_LOG_DRV(" IO read() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + break; + + case TUD_MSC_RET_BUSY: + // not ready yet -> fake a transfer complete so that this driver callback will fire again + dcd_event_xfer_complete(rhport, p_msc->ep_in, 0, XFER_RESULT_SUCCESS, false); + break; + + default: break; + } } } @@ -886,13 +885,20 @@ static void proc_write10_host_data(mscd_interface_t* p_msc, uint32_t xferred_byt static void proc_write_io_data(mscd_interface_t* p_msc, uint32_t xferred_bytes, int32_t nbytes) { if (nbytes < 0) { - // negative means error -> failed this scsi op - TU_LOG_DRV(" IO write() failed\r\n"); - set_sense_medium_not_present(p_msc->cbw.lun); - fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + // nbytes is status + switch (nbytes) { + case TUD_MSC_RET_ERROR: + // IO error -> failed this scsi op + TU_LOG_DRV(" IO write() failed\r\n"); + set_sense_medium_not_present(p_msc->cbw.lun); + fail_scsi_op(p_msc, MSC_CSW_STATUS_FAILED); + break; + + default: break; + } } else { if ((uint32_t)nbytes < xferred_bytes) { - // Application consume less than what we got (including zero) + // Application consume less than what we got including TUD_MSC_RET_BUSY (0) const uint32_t left_over = xferred_bytes - (uint32_t)nbytes; if (nbytes > 0) { memmove(_mscd_epbuf.buf, _mscd_epbuf.buf + nbytes, left_over); diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h index 2ad31c245..f2ea256b4 100644 --- a/src/class/msc/msc_device.h +++ b/src/class/msc/msc_device.h @@ -79,12 +79,11 @@ bool tud_msc_async_io_done(int32_t bytes_io, bool in_isr); - offset is only needed if CFG_TUD_MSC_EP_BUFSIZE is smaller than BLOCK_SIZE. - Application fill the buffer (up to bufsize) with address contents and return number of bytes read or status. - 0 < ret < bufsize: These bytes are transferred first and callback will be invoked again for remaining data. - - ret == TUD_MSC_RET_BUSY - Application is buys e.g disk I/O not ready. - Callback will be invoked again with the same parameters later on. - - ret == TUD_MSC_RET_ERROR + - TUD_MSC_RET_BUSY + Application is buys e.g disk I/O not ready. Callback will be invoked again with the same parameters later on. + - TUD_MSC_RET_ERROR error such as invalid address. This request will be STALLed and scsi command will be failed - - ret == TUD_MSC_RET_ASYNC + - TUD_MSC_RET_ASYNC Data I/O will be done asynchronously in a background task. Application should return immediately. tud_msc_async_io_done() must be called once IO/ is done to signal completion. */ From a42184b6fec468e8524b1f1152bed4285a79cfc7 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 11:02:37 +0700 Subject: [PATCH 082/101] remove legacy DEPS_SUBMODULES in make --- examples/device/net_lwip_webserver/Makefile | 2 -- hw/bsp/brtmm90x/family.mk | 1 - hw/bsp/ch32f20x/family.mk | 1 - hw/bsp/espressif/family.mk | 2 -- hw/bsp/imxrt/family.mk | 1 - hw/bsp/kinetis_k/family.mk | 1 - hw/bsp/kinetis_kl/family.mk | 1 - hw/bsp/lpc13/boards/lpcxpresso1347/board.mk | 2 -- hw/bsp/lpc13/family.mk | 2 -- hw/bsp/lpc15/family.mk | 2 -- hw/bsp/lpc17/family.mk | 2 -- hw/bsp/lpc18/family.mk | 1 - hw/bsp/lpc40/family.mk | 2 -- hw/bsp/lpc43/family.mk | 1 - hw/bsp/lpc54/family.mk | 1 - hw/bsp/lpc55/family.mk | 1 - hw/bsp/mcx/family.mk | 2 -- hw/bsp/msp430/family.mk | 1 - hw/bsp/nutiny_nuc121s/board.mk | 2 -- hw/bsp/nutiny_nuc125s/board.mk | 2 -- hw/bsp/nutiny_nuc126v/board.mk | 2 -- hw/bsp/nutiny_sdk_nuc120/board.mk | 2 -- hw/bsp/nutiny_sdk_nuc505/board.mk | 2 -- hw/bsp/rp2040/family.mk | 2 -- hw/bsp/rx/family.mk | 2 -- hw/bsp/same70_qmtech/board.mk | 1 - hw/bsp/same70_xplained/board.mk | 1 - hw/bsp/sltb009a/board.mk | 3 --- hw/bsp/spresense/board.mk | 2 -- hw/bsp/stm32c0/family.mk | 2 -- hw/bsp/stm32f0/family.mk | 2 -- hw/bsp/stm32f1/family.mk | 2 -- hw/bsp/stm32f2/family.mk | 5 ----- hw/bsp/stm32f7/family.mk | 1 - hw/bsp/stm32g0/family.mk | 1 - hw/bsp/stm32l4/family.mk | 1 - hw/bsp/stm32u5/family.mk | 1 - hw/bsp/xmc4000/family.mk | 2 -- test/fuzz/device/net/Makefile | 2 -- test/fuzz/rules.mk | 2 +- 40 files changed, 1 insertion(+), 67 deletions(-) diff --git a/examples/device/net_lwip_webserver/Makefile b/examples/device/net_lwip_webserver/Makefile index 141532466..4ad110dec 100644 --- a/examples/device/net_lwip_webserver/Makefile +++ b/examples/device/net_lwip_webserver/Makefile @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += lib/lwip - include ../../build_system/make/make.mk # suppress warning caused by lwip diff --git a/hw/bsp/brtmm90x/family.mk b/hw/bsp/brtmm90x/family.mk index 6df0bfdfe..2de4dc760 100644 --- a/hw/bsp/brtmm90x/family.mk +++ b/hw/bsp/brtmm90x/family.mk @@ -13,7 +13,6 @@ else # The submodule BRTSG-FOSS/ft90x-sdk contains header files and source # code for the Bridgetek SDK. This can be used instead of the prebuilt # library. -DEPS_SUBMODULES += hw/mcu/bridgetek/ft9xx/ft90x-sdk # The SDK can be used to load specific files from the Bridgetek SDK. FT9XX_SDK = hw/mcu/bridgetek/ft9xx/ft90x-sdk/Source INC += "$(TOP)/$(FT9XX_SDK)/include" diff --git a/hw/bsp/ch32f20x/family.mk b/hw/bsp/ch32f20x/family.mk index c08451b9c..2ff9f79e3 100644 --- a/hw/bsp/ch32f20x/family.mk +++ b/hw/bsp/ch32f20x/family.mk @@ -1,6 +1,5 @@ # Submodules CH32F20X_SDK = hw/mcu/wch/ch32f20x -DEPS_SUBMODULES += $(CH32F20X_SDK) # WCH-SDK paths CH32F20X_SDK_SRC = $(CH32F20X_SDK)/EVT/EXAM/SRC diff --git a/hw/bsp/espressif/family.mk b/hw/bsp/espressif/family.mk index 0dc21b8eb..d955a2b4c 100644 --- a/hw/bsp/espressif/family.mk +++ b/hw/bsp/espressif/family.mk @@ -1,5 +1,3 @@ -#DEPS_SUBMODULES += - UF2_FAMILY_ID_esp32s2 = 0xbfdd4eee UF2_FAMILY_ID_esp32s3 = 0xc47e5767 diff --git a/hw/bsp/imxrt/family.mk b/hw/bsp/imxrt/family.mk index 0cf84a4ae..9a2c37121 100644 --- a/hw/bsp/imxrt/family.mk +++ b/hw/bsp/imxrt/family.mk @@ -1,6 +1,5 @@ UF2_FAMILY_ID = 0x4fb2d5bd SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5 include $(TOP)/$(BOARD_PATH)/board.mk diff --git a/hw/bsp/kinetis_k/family.mk b/hw/bsp/kinetis_k/family.mk index 844ce332e..e95cdb717 100644 --- a/hw/bsp/kinetis_k/family.mk +++ b/hw/bsp/kinetis_k/family.mk @@ -1,5 +1,4 @@ SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5 MCU_DIR = $(SDK_DIR)/devices/${MCU_VARIANT} include $(TOP)/$(BOARD_PATH)/board.mk diff --git a/hw/bsp/kinetis_kl/family.mk b/hw/bsp/kinetis_kl/family.mk index 1fdce981a..8d113aecf 100644 --- a/hw/bsp/kinetis_kl/family.mk +++ b/hw/bsp/kinetis_kl/family.mk @@ -1,5 +1,4 @@ SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5 MCU_DIR = $(SDK_DIR)/devices/$(MCU) include $(TOP)/$(BOARD_PATH)/board.mk diff --git a/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk b/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk index 31eb2f28f..8513c24ca 100644 --- a/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk +++ b/hw/bsp/lpc13/boards/lpcxpresso1347/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen - CFLAGS += \ -DCFG_TUSB_MEM_SECTION='__attribute__((section(".data.$$RAM2")))' diff --git a/hw/bsp/lpc13/family.mk b/hw/bsp/lpc13/family.mk index 4f8b48c4b..7ff2c058a 100644 --- a/hw/bsp/lpc13/family.mk +++ b/hw/bsp/lpc13/family.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen - MCU_DIR = hw/mcu/nxp/lpcopen/lpc13xx/lpc_chip_13xx include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m3 diff --git a/hw/bsp/lpc15/family.mk b/hw/bsp/lpc15/family.mk index 3b63580c0..3267e973a 100644 --- a/hw/bsp/lpc15/family.mk +++ b/hw/bsp/lpc15/family.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen - include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m3 diff --git a/hw/bsp/lpc17/family.mk b/hw/bsp/lpc17/family.mk index 551eb9e62..e8d707ea5 100644 --- a/hw/bsp/lpc17/family.mk +++ b/hw/bsp/lpc17/family.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen - MCU_DIR = hw/mcu/nxp/lpcopen/lpc175x_6x/lpc_chip_175x_6x include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m3 diff --git a/hw/bsp/lpc18/family.mk b/hw/bsp/lpc18/family.mk index 87b831255..3bbafed11 100644 --- a/hw/bsp/lpc18/family.mk +++ b/hw/bsp/lpc18/family.mk @@ -1,4 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen MCU_DIR = hw/mcu/nxp/lpcopen/lpc18xx/lpc_chip_18xx include $(TOP)/$(BOARD_PATH)/board.mk diff --git a/hw/bsp/lpc40/family.mk b/hw/bsp/lpc40/family.mk index 06155c760..c72631235 100644 --- a/hw/bsp/lpc40/family.mk +++ b/hw/bsp/lpc40/family.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen - MCU_DIR = hw/mcu/nxp/lpcopen/lpc40xx/lpc_chip_40xx include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 diff --git a/hw/bsp/lpc43/family.mk b/hw/bsp/lpc43/family.mk index 4a2ba6ec3..39be867d1 100644 --- a/hw/bsp/lpc43/family.mk +++ b/hw/bsp/lpc43/family.mk @@ -1,4 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nxp/lpcopen SDK_DIR = hw/mcu/nxp/lpcopen/lpc43xx/lpc_chip_43xx include ${TOP}/${BOARD_PATH}/board.mk diff --git a/hw/bsp/lpc54/family.mk b/hw/bsp/lpc54/family.mk index 8dc70f621..94168f6b2 100644 --- a/hw/bsp/lpc54/family.mk +++ b/hw/bsp/lpc54/family.mk @@ -1,5 +1,4 @@ SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5 include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 diff --git a/hw/bsp/lpc55/family.mk b/hw/bsp/lpc55/family.mk index b83942c87..fadf852cd 100644 --- a/hw/bsp/lpc55/family.mk +++ b/hw/bsp/lpc55/family.mk @@ -1,6 +1,5 @@ UF2_FAMILY_ID = 0x2abc77ec SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += lib/CMSIS_5 lib/sct_neopixel $(SDK_DIR) include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m33 diff --git a/hw/bsp/mcx/family.mk b/hw/bsp/mcx/family.mk index 676475cc9..a16f4b6c0 100644 --- a/hw/bsp/mcx/family.mk +++ b/hw/bsp/mcx/family.mk @@ -1,8 +1,6 @@ UF2_FAMILY_ID = 0x2abc77ec SDK_DIR = hw/mcu/nxp/mcux-sdk -DEPS_SUBMODULES += $(SDK_DIR) lib/CMSIS_5 - include $(TOP)/$(BOARD_PATH)/board.mk # Default to Highspeed PORT1 diff --git a/hw/bsp/msp430/family.mk b/hw/bsp/msp430/family.mk index 06508ab2c..c973d9dcd 100644 --- a/hw/bsp/msp430/family.mk +++ b/hw/bsp/msp430/family.mk @@ -1,5 +1,4 @@ CROSS_COMPILE = msp430-elf- -DEPS_SUBMODULES += hw/mcu/ti SKIP_NANOLIB = 1 SDK_DIR = hw/mcu/ti/msp430/msp430-gcc-support-files/include diff --git a/hw/bsp/nutiny_nuc121s/board.mk b/hw/bsp/nutiny_nuc121s/board.mk index 161ff9041..06c47d544 100644 --- a/hw/bsp/nutiny_nuc121s/board.mk +++ b/hw/bsp/nutiny_nuc121s/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nuvoton - CFLAGS += \ -flto \ -mthumb \ diff --git a/hw/bsp/nutiny_nuc125s/board.mk b/hw/bsp/nutiny_nuc125s/board.mk index 081764fd3..50b9d866a 100644 --- a/hw/bsp/nutiny_nuc125s/board.mk +++ b/hw/bsp/nutiny_nuc125s/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nuvoton - CFLAGS += \ -flto \ -mthumb \ diff --git a/hw/bsp/nutiny_nuc126v/board.mk b/hw/bsp/nutiny_nuc126v/board.mk index 2466b3a31..e87d1aad0 100644 --- a/hw/bsp/nutiny_nuc126v/board.mk +++ b/hw/bsp/nutiny_nuc126v/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nuvoton - CFLAGS += \ -flto \ -mthumb \ diff --git a/hw/bsp/nutiny_sdk_nuc120/board.mk b/hw/bsp/nutiny_sdk_nuc120/board.mk index b54895b58..d982bdc06 100644 --- a/hw/bsp/nutiny_sdk_nuc120/board.mk +++ b/hw/bsp/nutiny_sdk_nuc120/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nuvoton - CFLAGS += \ -flto \ -mthumb \ diff --git a/hw/bsp/nutiny_sdk_nuc505/board.mk b/hw/bsp/nutiny_sdk_nuc505/board.mk index f3b389354..1dc8b244e 100644 --- a/hw/bsp/nutiny_sdk_nuc505/board.mk +++ b/hw/bsp/nutiny_sdk_nuc505/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/nuvoton - CFLAGS += \ -flto \ -mthumb \ diff --git a/hw/bsp/rp2040/family.mk b/hw/bsp/rp2040/family.mk index 25d1ad9c5..813683c54 100644 --- a/hw/bsp/rp2040/family.mk +++ b/hw/bsp/rp2040/family.mk @@ -1,8 +1,6 @@ JLINK_DEVICE = rp2040_m0_0 PYOCD_TARGET = rp2040 -DEPS_SUBMODULES += hw/mcu/raspberry_pi/Pico-PIO-USB - ifeq ($(DEBUG), 1) CMAKE_DEFSYM += -DCMAKE_BUILD_TYPE=Debug endif diff --git a/hw/bsp/rx/family.mk b/hw/bsp/rx/family.mk index 02ea0dfa4..4ecf80409 100644 --- a/hw/bsp/rx/family.mk +++ b/hw/bsp/rx/family.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/renesas/rx - # Cross Compiler for RX CROSS_COMPILE = rx-elf- diff --git a/hw/bsp/same70_qmtech/board.mk b/hw/bsp/same70_qmtech/board.mk index 281a947f3..7e949e135 100644 --- a/hw/bsp/same70_qmtech/board.mk +++ b/hw/bsp/same70_qmtech/board.mk @@ -1,4 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/microchip ASF_DIR = hw/mcu/microchip/same70 CFLAGS += \ diff --git a/hw/bsp/same70_xplained/board.mk b/hw/bsp/same70_xplained/board.mk index 60702f14a..2d97ecdc1 100644 --- a/hw/bsp/same70_xplained/board.mk +++ b/hw/bsp/same70_xplained/board.mk @@ -1,4 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/microchip ASF_DIR = hw/mcu/microchip/same70 CFLAGS += \ diff --git a/hw/bsp/sltb009a/board.mk b/hw/bsp/sltb009a/board.mk index 687761364..5dd7a158f 100644 --- a/hw/bsp/sltb009a/board.mk +++ b/hw/bsp/sltb009a/board.mk @@ -16,9 +16,6 @@ CFLAGS += \ SILABS_FAMILY = efm32gg12b SILABS_CMSIS = hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY)/Device/SiliconLabs/$(shell echo $(SILABS_FAMILY) | tr a-z A-Z) -DEPS_SUBMODULES += hw/mcu/silabs/cmsis-dfp-$(SILABS_FAMILY) -DEPS_SUBMODULES += lib/CMSIS_5 - LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs # All source paths should be relative to the top level. diff --git a/hw/bsp/spresense/board.mk b/hw/bsp/spresense/board.mk index 15fa0ff20..24f39d2b6 100644 --- a/hw/bsp/spresense/board.mk +++ b/hw/bsp/spresense/board.mk @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += hw/mcu/sony/cxd56/spresense-exported-sdk - # Platforms are: Linux, Darwin, MSYS, CYGWIN PLATFORM := $(firstword $(subst _, ,$(shell uname -s 2>/dev/null))) diff --git a/hw/bsp/stm32c0/family.mk b/hw/bsp/stm32c0/family.mk index 9ff3a2fdf..bdb34454e 100644 --- a/hw/bsp/stm32c0/family.mk +++ b/hw/bsp/stm32c0/family.mk @@ -1,6 +1,4 @@ ST_FAMILY = c0 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver - ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32f0/family.mk b/hw/bsp/stm32f0/family.mk index 431709de0..9b8305874 100644 --- a/hw/bsp/stm32f0/family.mk +++ b/hw/bsp/stm32f0/family.mk @@ -1,7 +1,5 @@ UF2_FAMILY_ID = 0x647824b6 ST_FAMILY = f0 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver - ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32f1/family.mk b/hw/bsp/stm32f1/family.mk index 364616304..ca95f2315 100644 --- a/hw/bsp/stm32f1/family.mk +++ b/hw/bsp/stm32f1/family.mk @@ -1,6 +1,4 @@ ST_FAMILY = f1 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_${ST_FAMILY} hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver - ST_CMSIS = hw/mcu/st/cmsis_device_${ST_FAMILY} ST_HAL_DRIVER = hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver diff --git a/hw/bsp/stm32f2/family.mk b/hw/bsp/stm32f2/family.mk index e8f02548d..ef14a9d67 100644 --- a/hw/bsp/stm32f2/family.mk +++ b/hw/bsp/stm32f2/family.mk @@ -2,11 +2,6 @@ ST_FAMILY = f2 ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver -DEPS_SUBMODULES += \ - lib/CMSIS_5 \ - $(ST_CMSIS) \ - $(ST_HAL_DRIVER) - include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m3 diff --git a/hw/bsp/stm32f7/family.mk b/hw/bsp/stm32f7/family.mk index abeea784c..d3422e03c 100644 --- a/hw/bsp/stm32f7/family.mk +++ b/hw/bsp/stm32f7/family.mk @@ -1,6 +1,5 @@ UF2_FAMILY_ID = 0x53b80f00 ST_FAMILY = f7 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32g0/family.mk b/hw/bsp/stm32g0/family.mk index 95b8e537d..d735ca92d 100644 --- a/hw/bsp/stm32g0/family.mk +++ b/hw/bsp/stm32g0/family.mk @@ -1,5 +1,4 @@ ST_FAMILY = g0 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32l4/family.mk b/hw/bsp/stm32l4/family.mk index 950b6f9cb..01d059236 100644 --- a/hw/bsp/stm32l4/family.mk +++ b/hw/bsp/stm32l4/family.mk @@ -1,5 +1,4 @@ ST_FAMILY = l4 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk index 7fc728dcf..3694b1ca0 100644 --- a/hw/bsp/stm32u5/family.mk +++ b/hw/bsp/stm32u5/family.mk @@ -1,5 +1,4 @@ ST_FAMILY = u5 -DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver diff --git a/hw/bsp/xmc4000/family.mk b/hw/bsp/xmc4000/family.mk index a1679a2f0..4eed7360a 100644 --- a/hw/bsp/xmc4000/family.mk +++ b/hw/bsp/xmc4000/family.mk @@ -1,8 +1,6 @@ UF2_FAMILY_ID = 0x00 SDK_DIR = hw/mcu/infineon/mtb-xmclib-cat3 -DEPS_SUBMODULES += ${SDK_DIR} - include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m4 diff --git a/test/fuzz/device/net/Makefile b/test/fuzz/device/net/Makefile index 4e99604ad..2161ad3f1 100644 --- a/test/fuzz/device/net/Makefile +++ b/test/fuzz/device/net/Makefile @@ -1,5 +1,3 @@ -DEPS_SUBMODULES += lib/lwip - include ../../make.mk # suppress warning caused by lwip diff --git a/test/fuzz/rules.mk b/test/fuzz/rules.mk index ee91c706d..562969663 100644 --- a/test/fuzz/rules.mk +++ b/test/fuzz/rules.mk @@ -142,7 +142,7 @@ endif # get depenecies .PHONY: get-deps get-deps: - $(PYTHON) $(TOP)/tools/get_deps.py $(DEPS_SUBMODULES) + $(PYTHON) $(TOP)/tools/get_deps.py $(FAMILY) size: $(BUILD)/$(PROJECT) -@echo '' From 4579b4f8255a5ed06e276978474fab7c7567445a Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 14:41:16 +0700 Subject: [PATCH 083/101] add doc for building examples with cmake build system change ci matrix build: - github build make/cmake one per family on push only - circicle do full cmake build for all toolchain (missing rx-gcc) --- .circleci/config.yml | 9 ++-- .github/workflows/build.yml | 69 +++++++++++++--------------- docs/reference/getting_started.rst | 72 ++++++++++++++++++++---------- hw/bsp/espressif/family.cmake | 2 - hw/bsp/espressif/family.mk | 32 ------------- hw/bsp/msp430/family.cmake | 48 ++++++++++---------- 6 files changed, 107 insertions(+), 125 deletions(-) delete mode 100644 hw/bsp/espressif/family.mk diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b11b50e4..3b4389ab4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,13 +19,12 @@ jobs: echo "MATRIX_JSON=$MATRIX_JSON" BUILDSYSTEM_TOOLCHAIN=( + "cmake aarch64-gcc" "cmake arm-clang" + "cmake arm-gcc" "cmake esp-idf" - "make aarch64-gcc" - "make arm-gcc" - "make msp430-gcc" - "make riscv-gcc" - "make rx-gcc" + "cmake msp430-gcc" + "cmake riscv-gcc" ) # only build IAR if not forked PR, since IAR token is not shared diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fe2ed61c9..58963013b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,11 +36,6 @@ env: HIL_JSON: test/hil/tinyusb.json jobs: - # --------------------------------------- - # - # Build - # - # --------------------------------------- set-matrix: runs-on: ubuntu-latest outputs: @@ -63,28 +58,31 @@ jobs: echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT # --------------------------------------- - # Build CMake + # Build CMake: only build on push with one-per-family. + # Full built is done by CircleCI in PR # --------------------------------------- cmake: + if: github.event_name == 'push' needs: set-matrix uses: ./.github/workflows/build_util.yml strategy: fail-fast: false matrix: toolchain: - # - 'arm-clang' is built by circle-ci in PR - 'aarch64-gcc' + - 'arm-clang' - 'arm-gcc' + - 'esp-idf' - 'msp430-gcc' - 'riscv-gcc' with: build-system: 'cmake' toolchain: ${{ matrix.toolchain }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }} - one-per-family: ${{ github.event_name == 'push' }} + one-per-family: true # --------------------------------------- - # Build Make (built by circle-ci in PR, only build on push here) + # Build Make: only build on push with one-per-family # --------------------------------------- make: if: github.event_name == 'push' @@ -94,19 +92,39 @@ jobs: fail-fast: false matrix: toolchain: - # 'arm-clang' - - 'arm-gcc' - 'aarch64-gcc' + - 'arm-clang' + - 'arm-gcc' - 'msp430-gcc' - 'riscv-gcc' - 'rx-gcc' - - 'esp-idf' with: build-system: 'make' toolchain: ${{ matrix.toolchain }} build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }} one-per-family: true + # --------------------------------------- + # Build IAR + # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make. + # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family + # --------------------------------------- + arm-iar: + if: github.event_name == 'push' && github.repository_owner == 'hathach' + needs: set-matrix + uses: ./.github/workflows/build_util.yml + secrets: inherit + strategy: + fail-fast: false + matrix: + build-system: + - 'make' + with: + build-system: ${{ matrix.build-system }} + toolchain: 'arm-iar' + build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} + one-per-family: true + # --------------------------------------- # Build Make on Windows/MacOS # --------------------------------------- @@ -124,28 +142,6 @@ jobs: build-args: '["stm32h7"]' one-per-family: true - # --------------------------------------- - # Build IAR - # Since IAR Token secret is not passed to forked PR, only build non-forked PR with make. - # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family - # --------------------------------------- - arm-iar: - if: false # disable for now since we got reach capacity limit too often - #if: github.event_name == 'push' && github.repository_owner == 'hathach' - needs: set-matrix - uses: ./.github/workflows/build_util.yml - secrets: inherit - strategy: - fail-fast: false - matrix: - build-system: - - 'make' - with: - build-system: ${{ matrix.build-system }} - toolchain: 'arm-iar' - build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)['arm-iar']) }} - one-per-family: true - # --------------------------------------- # Zephyr # --------------------------------------- @@ -168,14 +164,9 @@ jobs: west build -b pca10056 -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr # --------------------------------------- - # # Hardware in the loop (HIL) # Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR # --------------------------------------- - - # --------------------------------------- - # Build arm-gcc - # --------------------------------------- hil-build: if: | github.repository_owner == 'hathach' && diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst index 37745d6a1..ee68f6386 100644 --- a/docs/reference/getting_started.rst +++ b/docs/reference/getting_started.rst @@ -5,12 +5,12 @@ Getting Started Add TinyUSB to your project --------------------------- -It is relatively simple to incorporate tinyusb to your project +To incorporate tinyusb to your project * Copy or ``git submodule`` this repo into your project in a subfolder. Let's say it is ``your_project/tinyusb`` * Add all the ``.c`` in the ``tinyusb/src`` folder to your project * Add ``your_project/tinyusb/src`` to your include path. Also make sure your current include path also contains the configuration file ``tusb_config.h``. -* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by IDE/compiler to maintain a unique configure for all boards). +* Make sure all required macros are all defined properly in ``tusb_config.h`` (configure file in demo application is sufficient, but you need to add a few more such as ``CFG_TUSB_MCU``, ``CFG_TUSB_OS`` since they are passed by make/cmake to maintain a unique configure for all boards). * If you use the device stack, make sure you have created/modified usb descriptors for your own need. Ultimately you need to implement all **tud descriptor** callbacks for the stack to work. * Add ``tusb_init(rhport, role)`` call to your reset initialization code. * Call ``tusb_int_handler(rhport, in_isr)`` in your USB IRQ Handler @@ -75,24 +75,36 @@ The hardware code is located in ``hw/bsp`` folder, and is organized by family/bo .. code-block:: bash $ cd examples/device/cdc_msc - $ make BOARD=raspberry_pi_pico get-deps + $ make BOARD=feather_nrf52840_express get-deps You only need to do this once per family. Check out `complete list of dependencies and their designated path here `_ -Build -^^^^^ +Build Examples +^^^^^^^^^^^^^^ -To build example, first change directory to an example folder. +Examples support make and cmake build system, though some MCU family such as espressif/rp2040 only support cmake. First change directory to an example folder. .. code-block:: bash $ cd examples/device/cdc_msc -Then compile with ``make BOARD={board_name} all`` , for example +Then compile with make or cmake .. code-block:: bash - $ make BOARD=raspberry_pi_pico all + $ # make + $ make BOARD=feather_nrf52840_express all + + $ # cmake + $ mkdir build && cd build + $ cmake -DBOARD=raspberry_pi_pico .. + $ make + +To list all available targets with cmake + +.. code-block:: bash + + $ cmake --build . --target help Note: some examples especially those that uses Vendor class (e.g webUSB) may requires udev permission on Linux (and/or macOS) to access usb device. It depends on your OS distro, typically copy ``99-tinyusb.rules`` and reload your udev is good to go @@ -104,20 +116,24 @@ Note: some examples especially those that uses Vendor class (e.g webUSB) may req RootHub Port Selection ~~~~~~~~~~~~~~~~~~~~~~ -If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``PORT=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use: +If a board has several ports, one port is chosen by default in the individual board.mk file. Use option ``RHPORT_DEVICE=x`` or ``RHPORT_HOST=x`` To choose another port. For example to select the HS port of a STM32F746Disco board, use: .. code-block:: bash - $ make BOARD=stm32f746disco PORT=1 all + $ make BOARD=stm32f746disco RHPORT_DEVICE=1 all + + $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE=1 .. Port Speed ~~~~~~~~~~ -A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``SPEED=full/high`` e.g To force F723 operate at full instead of default high speed +A MCU can support multiple operational speed. By default, the example build system will use the fastest supported on the board. Use option ``RHPORT_DEVICE_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` or ``RHPORT_HOST_SPEED=OPT_MODE_FULL/HIGH_SPEED/`` e.g To force F723 operate at full instead of default high speed .. code-block:: bash - $ make BOARD=stm32f746disco SPEED=full all + $ make BOARD=stm32f746disco RHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED all + + $ cmake -DBOARD=stm32f746disco -DRHPORT_DEVICE_SPEED=OPT_MODE_FULL_SPEED .. Size Analysis ~~~~~~~~~~~~~ @@ -137,6 +153,8 @@ To compile for debugging add ``DEBUG=1``\ , for example $ make BOARD=feather_nrf52840_express DEBUG=1 all + $ cmake -DBOARD=feather_nrf52840_express -DCMAKE_BUILD_TYPE=Debug .. + Log ~~~ @@ -146,6 +164,8 @@ Should you have an issue running example and/or submitting an bug report. You co $ make BOARD=feather_nrf52840_express LOG=2 all + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 .. + Logger ~~~~~~ @@ -169,6 +189,9 @@ By default log message is printed via on-board UART which is slow and take lots $ make BOARD=feather_nrf52840_express LOG=2 LOGGER=rtt all $ make BOARD=feather_nrf52840_express LOG=2 LOGGER=swo all + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=rtt .. + $ cmake -DBOARD=feather_nrf52840_express -DLOG=2 -DLOGGER=swo .. + Flash ^^^^^ @@ -179,11 +202,15 @@ Flash $ make BOARD=feather_nrf52840_express flash $ make SERIAL=/dev/ttyACM0 BOARD=feather_nrf52840_express flash -Since jlink can be used with most of the boards, there is also ``flash-jlink`` target for your convenience. +Since jlink/openocd can be used with most of the boards, there is also ``flash-jlink/openocd`` (make) and ``EXAMPLE-jlink/openocd`` target for your convenience. Note for stm32 board with stlink, you can use ``flash-stlink`` target as well. .. code-block:: bash $ make BOARD=feather_nrf52840_express flash-jlink + $ make BOARD=feather_nrf52840_express flash-openocd + + $ cmake --build . --target cdc_msc-jlink + $ cmake --build . --target cdc_msc-openocd Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can be generated with ``uf2`` target @@ -191,17 +218,18 @@ Some board use uf2 bootloader for drag & drop in to mass storage device, uf2 can $ make BOARD=feather_nrf52840_express all uf2 + $ cmake --build . --target cdc_msc-uf2 + IAR Support ------------ +^^^^^^^^^^^ Use project connection -^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~ IAR Project Connection files are provided to import TinyUSB stack into your project. * A buildable project of your MCU need to be created in advance. - * Take example of STM32F0: - You need ``stm32l0xx.h``, ``startup_stm32f0xx.s``, ``system_stm32f0xx.c``. @@ -212,15 +240,13 @@ IAR Project Connection files are provided to import TinyUSB stack into your proj Click ``New Group ...``, name it to ``TUSB``, Click ``Add Variable ...``, name it to ``TUSB_DIR``, change it's value to the path of your TinyUSB stack, for example ``C:\\tinyusb`` -Import stack only -~~~~~~~~~~~~~~~~~ +**Import stack only** -1. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``. +Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\tools\\iar_template.ipcf``. -Run examples -~~~~~~~~~~~~ +**Run examples** -1. (Python3 is needed) Run ``iar_gen.py`` to generate .ipcf files of examples: +1. Run ``iar_gen.py`` to generate .ipcf files of examples: .. code-block:: @@ -231,7 +257,7 @@ Run examples For example ``C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf`` Native CMake support (9.50.1+) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project. diff --git a/hw/bsp/espressif/family.cmake b/hw/bsp/espressif/family.cmake index 2aad7d185..ca9eadaf6 100644 --- a/hw/bsp/espressif/family.cmake +++ b/hw/bsp/espressif/family.cmake @@ -1,5 +1,3 @@ -cmake_minimum_required(VERSION 3.5) - # Apply board specific content i.e IDF_TARGET must be set before project.cmake is included include("${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake") string(TOUPPER ${IDF_TARGET} FAMILY_MCUS) diff --git a/hw/bsp/espressif/family.mk b/hw/bsp/espressif/family.mk deleted file mode 100644 index d955a2b4c..000000000 --- a/hw/bsp/espressif/family.mk +++ /dev/null @@ -1,32 +0,0 @@ -UF2_FAMILY_ID_esp32s2 = 0xbfdd4eee -UF2_FAMILY_ID_esp32s3 = 0xc47e5767 - -BOARD_CMAKE := $(file < $(TOP)/$(BOARD_PATH)/board.cmake) -ifneq ($(findstring esp32s2,$(BOARD_CMAKE)),) - IDF_TARGET = esp32s2 -else -ifneq ($(findstring esp32s3,$(BOARD_CMAKE)),) - IDF_TARGET = esp32s3 -endif -endif - -.PHONY: all clean flash bootloader-flash app-flash erase monitor dfu-flash dfu - -all: - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) build - -build: all - -fullclean: - if test -f sdkconfig; then $(RM) -f sdkconfig ; fi - if test -d $(BUILD); then $(RM) -rf $(BUILD) ; fi - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@ - -clean flash bootloader-flash app-flash erase monitor dfu-flash dfu size size-components size-files: - idf.py -B$(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) $(CMAKE_DEFSYM) $@ - -uf2: $(BUILD)/$(PROJECT).uf2 - -$(BUILD)/$(PROJECT).uf2: $(BUILD)/$(PROJECT).bin - @echo CREATE $@ - $(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0 -c -o $@ $^ diff --git a/hw/bsp/msp430/family.cmake b/hw/bsp/msp430/family.cmake index ddd54b675..d9b4bf770 100644 --- a/hw/bsp/msp430/family.cmake +++ b/hw/bsp/msp430/family.cmake @@ -11,36 +11,37 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/msp430_${T set(FAMILY_MCUS MSP430x5xx CACHE INTERNAL "") - #------------------------------------ # BOARD_TARGET #------------------------------------ # only need to be built ONCE for all examples function(add_board_target BOARD_TARGET) - if (NOT TARGET ${BOARD_TARGET}) - add_library(${BOARD_TARGET} INTERFACE) - target_compile_definitions(${BOARD_TARGET} INTERFACE - CFG_TUD_ENDPOINT0_SIZE=8 - CFG_EXAMPLE_VIDEO_READONLY - CFG_EXAMPLE_MSC_READONLY - ) - target_include_directories(${BOARD_TARGET} INTERFACE - ${CMAKE_CURRENT_FUNCTION_LIST_DIR} - ${SDK_DIR} - ) + if (TARGET ${BOARD_TARGET}) + return() + endif () - update_board(${BOARD_TARGET}) + add_library(${BOARD_TARGET} INTERFACE) + target_compile_definitions(${BOARD_TARGET} INTERFACE + CFG_TUD_ENDPOINT0_SIZE=8 + CFG_EXAMPLE_VIDEO_READONLY + CFG_EXAMPLE_MSC_READONLY + ) + target_include_directories(${BOARD_TARGET} INTERFACE + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${SDK_DIR} + ) - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") - target_link_options(${BOARD_TARGET} INTERFACE - "LINKER:--script=${LD_FILE_GNU}" - -L${SDK_DIR} - ) - elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") - target_link_options(${BOARD_TARGET} INTERFACE - "LINKER:--config=${LD_FILE_IAR}" - ) - endif () + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_link_options(${BOARD_TARGET} INTERFACE + "LINKER:--script=${LD_FILE_GNU}" + -L${SDK_DIR} + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${BOARD_TARGET} INTERFACE + "LINKER:--config=${LD_FILE_IAR}" + ) endif () endfunction() @@ -75,7 +76,6 @@ function(family_configure_example TARGET RTOS) ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) - # Flashing family_add_bin_hex(${TARGET}) family_flash_msp430flasher(${TARGET}) From 0388700ad7c0fc8565457a56d7e7bd5744ac0d1d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 15:32:12 +0700 Subject: [PATCH 084/101] update esp build, replace TUSB_MCU_VENDOR_ESPRESSIF by ESP_PLATFORM --- .github/workflows/build.yml | 2 +- .../device/audio_4_channel_mic_freertos/src/main.c | 11 +++++------ .../audio_4_channel_mic_freertos/src/tusb_config.h | 2 +- examples/device/audio_test_freertos/src/main.c | 8 ++++---- examples/device/audio_test_freertos/src/tusb_config.h | 2 +- examples/device/board_test/src/tusb_config.h | 2 +- examples/device/cdc_msc_freertos/src/main.c | 8 ++++---- examples/device/cdc_msc_freertos/src/tusb_config.h | 2 +- examples/device/hid_composite_freertos/src/main.c | 11 +++++------ .../device/hid_composite_freertos/src/tusb_config.h | 2 +- examples/device/midi_test_freertos/src/main.c | 8 ++++---- examples/device/video_capture/src/main.c | 6 +++--- examples/device/video_capture/src/tusb_config.h | 2 +- examples/device/video_capture_2ch/src/main.c | 6 +++--- examples/device/video_capture_2ch/src/tusb_config.h | 2 +- examples/host/cdc_msc_hid_freertos/src/cdc_app.c | 2 +- examples/host/cdc_msc_hid_freertos/src/main.c | 8 ++++---- examples/host/cdc_msc_hid_freertos/src/tusb_config.h | 2 +- examples/host/device_info/src/main.c | 8 ++++---- examples/host/device_info/src/tusb_config.h | 2 +- examples/host/midi_rx/src/tusb_config.h | 2 +- examples/typec/power_delivery/src/main.c | 5 ++--- hw/bsp/board.c | 7 ++++--- hw/bsp/board_api.h | 3 ++- hw/bsp/espressif/boards/family.c | 4 ++++ tools/build.py | 6 ++---- tools/build_utils.py | 2 ++ 27 files changed, 64 insertions(+), 61 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 58963013b..97f219e6f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -93,7 +93,7 @@ jobs: matrix: toolchain: - 'aarch64-gcc' - - 'arm-clang' + #- 'arm-clang' - 'arm-gcc' - 'msp430-gcc' - 'riscv-gcc' diff --git a/examples/device/audio_4_channel_mic_freertos/src/main.c b/examples/device/audio_4_channel_mic_freertos/src/main.c index 99278b5cc..d5a34b194 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/main.c +++ b/examples/device/audio_4_channel_mic_freertos/src/main.c @@ -39,7 +39,7 @@ #include "bsp/board_api.h" #include "tusb.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM // ESP-IDF need "freertos/" prefix in include path. // CFG_TUSB_OS_INC_PATH should be defined accordingly. #include "freertos/FreeRTOS.h" @@ -158,17 +158,16 @@ int main(void) xTaskCreate(audio_task, "audio", AUDIO_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); #endif - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 - #if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu + #ifndef ESP_PLATFORM vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF -void app_main(void) -{ +#ifdef ESP_PLATFORM +void app_main(void) { main(); } #endif diff --git a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h index 5ac51b153..f7c0efe08 100644 --- a/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h +++ b/examples/device/audio_4_channel_mic_freertos/src/tusb_config.h @@ -59,7 +59,7 @@ extern "C" { #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/audio_test_freertos/src/main.c b/examples/device/audio_test_freertos/src/main.c index c5143c3fc..3831be87f 100644 --- a/examples/device/audio_test_freertos/src/main.c +++ b/examples/device/audio_test_freertos/src/main.c @@ -38,7 +38,7 @@ #include "bsp/board_api.h" #include "tusb.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM // ESP-IDF need "freertos/" prefix in include path. // CFG_TUSB_OS_INC_PATH should be defined accordingly. #include "freertos/FreeRTOS.h" @@ -132,15 +132,15 @@ int main(void) xTaskCreate(usb_device_task, "usbd", USBD_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); #endif - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 - #if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu + #ifndef ESP_PLATFORM vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } diff --git a/examples/device/audio_test_freertos/src/tusb_config.h b/examples/device/audio_test_freertos/src/tusb_config.h index 61c5cbb96..0fb2106e2 100644 --- a/examples/device/audio_test_freertos/src/tusb_config.h +++ b/examples/device/audio_test_freertos/src/tusb_config.h @@ -59,7 +59,7 @@ extern "C" { #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/board_test/src/tusb_config.h b/examples/device/board_test/src/tusb_config.h index 8ac3bc8de..81829d450 100644 --- a/examples/device/board_test/src/tusb_config.h +++ b/examples/device/board_test/src/tusb_config.h @@ -44,7 +44,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 4dada9801..6fe964153 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -30,7 +30,7 @@ #include "bsp/board_api.h" #include "tusb.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USBD_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled @@ -91,15 +91,15 @@ int main(void) { xTaskCreate(cdc_task, "cdc", CDC_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL); #endif -#if !TUSB_MCU_VENDOR_ESPRESSIF - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 +#ifndef ESP_PLATFORM + // only start scheduler for non-espressif mcu vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index c3f2f7fb5..71a0e985a 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -59,7 +59,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/hid_composite_freertos/src/main.c b/examples/device/hid_composite_freertos/src/main.c index 30c0331ef..3f5e8a91c 100644 --- a/examples/device/hid_composite_freertos/src/main.c +++ b/examples/device/hid_composite_freertos/src/main.c @@ -31,7 +31,7 @@ #include "tusb.h" #include "usb_descriptors.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM // ESP-IDF need "freertos/" prefix in include path. // CFG_TUSB_OS_INC_PATH should be defined accordingly. #include "freertos/FreeRTOS.h" @@ -112,17 +112,16 @@ int main(void) xTimerStart(blinky_tm, 0); - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 -#if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu +#ifndef ESP_PLATFORM vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF -void app_main(void) -{ +#ifdef ESP_PLATFORM +void app_main(void) { main(); } #endif diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h index 6ec38b95c..b28033a0c 100644 --- a/examples/device/hid_composite_freertos/src/tusb_config.h +++ b/examples/device/hid_composite_freertos/src/tusb_config.h @@ -59,7 +59,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/midi_test_freertos/src/main.c b/examples/device/midi_test_freertos/src/main.c index dbe89080c..3e406d38d 100644 --- a/examples/device/midi_test_freertos/src/main.c +++ b/examples/device/midi_test_freertos/src/main.c @@ -40,7 +40,7 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USBD_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled @@ -95,15 +95,15 @@ int main(void) { xTaskCreate(midi_task, "midi", MIDI_STACK_SIZE, NULL, configMAX_PRIORITIES - 2, NULL); #endif -#if !TUSB_MCU_VENDOR_ESPRESSIF - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 +#ifndef ESP_PLATFORM + // only start scheduler for non-espressif mcu vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } diff --git a/examples/device/video_capture/src/main.c b/examples/device/video_capture/src/main.c index 04d4af4e5..0406279fd 100644 --- a/examples/device/video_capture/src/main.c +++ b/examples/device/video_capture/src/main.c @@ -292,7 +292,7 @@ void led_blinking_task(void* param) { #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE #define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4) -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USBD_STACK_SIZE 4096 int main(void); void app_main(void) { @@ -351,8 +351,8 @@ void freertos_init_task(void) { xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL); #endif - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 - #if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu + #ifndef ESP_PLATFORM vTaskStartScheduler(); #endif } diff --git a/examples/device/video_capture/src/tusb_config.h b/examples/device/video_capture/src/tusb_config.h index 6dbd6f2a5..4ba86ca65 100644 --- a/examples/device/video_capture/src/tusb_config.h +++ b/examples/device/video_capture/src/tusb_config.h @@ -58,7 +58,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/device/video_capture_2ch/src/main.c b/examples/device/video_capture_2ch/src/main.c index 245e7abb8..dc616e3fa 100644 --- a/examples/device/video_capture_2ch/src/main.c +++ b/examples/device/video_capture_2ch/src/main.c @@ -300,7 +300,7 @@ void led_blinking_task(void* param) { #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE #define VIDEO_STACK_SIZE (configMINIMAL_STACK_SIZE*4) -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USBD_STACK_SIZE 4096 int main(void); void app_main(void) { @@ -359,8 +359,8 @@ void freertos_init_task(void) { xTaskCreate(video_task, "video", VIDEO_STACK_SZIE, NULL, configMAX_PRIORITIES - 2, NULL); #endif - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 - #if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu + #ifndef ESP_PLATFORM vTaskStartScheduler(); #endif } diff --git a/examples/device/video_capture_2ch/src/tusb_config.h b/examples/device/video_capture_2ch/src/tusb_config.h index 91775a327..e84e49879 100644 --- a/examples/device/video_capture_2ch/src/tusb_config.h +++ b/examples/device/video_capture_2ch/src/tusb_config.h @@ -58,7 +58,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c index e279ad509..d99760a02 100644 --- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c @@ -27,7 +27,7 @@ #include "tusb.h" #include "bsp/board_api.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CDC_STACK_SZIE 2048 #else #define CDC_STACK_SZIE (3*configMINIMAL_STACK_SIZE/2) diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c index 64a108254..0bcb355ec 100644 --- a/examples/host/cdc_msc_hid_freertos/src/main.c +++ b/examples/host/cdc_msc_hid_freertos/src/main.c @@ -30,7 +30,7 @@ #include "bsp/board_api.h" #include "tusb.h" -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USBH_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled @@ -86,15 +86,15 @@ int main(void) { xTimerStart(blinky_tm, 0); - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 -#if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu +#ifndef ESP_PLATFORM vTaskStartScheduler(); #endif return 0; } -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } diff --git a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h index bc8887211..3cdb227e2 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -44,7 +44,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c index e924a137b..7189972d6 100644 --- a/examples/host/device_info/src/main.c +++ b/examples/host/device_info/src/main.c @@ -268,7 +268,7 @@ void led_blinking_task(void* param) { #define BLINKY_STACK_SIZE configMINIMAL_STACK_SIZE -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define USB_STACK_SIZE 4096 #else // Increase stack size when debug log is enabled @@ -285,7 +285,7 @@ StackType_t usb_stack[USB_STACK_SIZE]; StaticTask_t usb_taskdef; #endif -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } @@ -308,8 +308,8 @@ void init_freertos_task(void) { xTaskCreate(usb_host_task, "usbh", USB_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL); #endif - // skip starting scheduler (and return) for ESP32-S2 or ESP32-S3 -#if !TUSB_MCU_VENDOR_ESPRESSIF + // only start scheduler for non-espressif mcu +#ifndef ESP_PLATFORM vTaskStartScheduler(); #endif } diff --git a/examples/host/device_info/src/tusb_config.h b/examples/host/device_info/src/tusb_config.h index e12970c12..e4ca2528e 100644 --- a/examples/host/device_info/src/tusb_config.h +++ b/examples/host/device_info/src/tusb_config.h @@ -40,7 +40,7 @@ #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/host/midi_rx/src/tusb_config.h b/examples/host/midi_rx/src/tusb_config.h index c9b430388..76bdf87f3 100644 --- a/examples/host/midi_rx/src/tusb_config.h +++ b/examples/host/midi_rx/src/tusb_config.h @@ -40,7 +40,7 @@ extern "C" { #endif // Espressif IDF requires "freertos/" prefix in include path -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM #define CFG_TUSB_OS_INC_PATH freertos/ #endif diff --git a/examples/typec/power_delivery/src/main.c b/examples/typec/power_delivery/src/main.c index 068dbbeb1..de0db4721 100644 --- a/examples/typec/power_delivery/src/main.c +++ b/examples/typec/power_delivery/src/main.c @@ -71,9 +71,8 @@ int main(void) } } -#if TUSB_MCU_VENDOR_ESPRESSIF -void app_main(void) -{ +#ifdef ESP_PLATFORM +void app_main(void) { main(); } #endif diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 4b8e5950f..8f2f93306 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -66,7 +66,6 @@ int sys_read(int fhdl, char *buf, size_t count) { #elif defined(LOGGER_SWO) #define ITM_BASE 0xE0000000 - #define ITM_STIM0 (*((volatile uint8_t*)(ITM_BASE + 0))) #define ITM_TER *((volatile uint32_t*)(ITM_BASE + 0xE00)) #define ITM_TCR *((volatile uint32_t*)(ITM_BASE + 0xE80)) @@ -150,6 +149,9 @@ int board_getchar(void) { return (sys_read(0, &c, 1) > 0) ? (int) c : (-1); } +void board_putchar(int c) { + sys_write(0, (const char*)&c, 1); +} uint32_t tusb_time_millis_api(void) { return board_millis(); @@ -158,7 +160,7 @@ uint32_t tusb_time_millis_api(void) { //-------------------------------------------------------------------- // FreeRTOS hooks //-------------------------------------------------------------------- -#if CFG_TUSB_OS == OPT_OS_FREERTOS && !TUSB_MCU_VENDOR_ESPRESSIF +#if CFG_TUSB_OS == OPT_OS_FREERTOS && !defined(ESP_PLATFORM) #include "FreeRTOS.h" #include "task.h" @@ -240,5 +242,4 @@ void vApplicationSetupTimerInterrupt(void) { } #endif - #endif diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h index 9cdbbf0d3..328fe9363 100644 --- a/hw/bsp/board_api.h +++ b/hw/bsp/board_api.h @@ -41,7 +41,7 @@ extern "C" { #if CFG_TUSB_OS == OPT_OS_ZEPHYR #include #elif CFG_TUSB_OS == OPT_OS_FREERTOS - #if TUSB_MCU_VENDOR_ESPRESSIF + #ifdef ESP_PLATFORM // ESP-IDF need "freertos/" prefix in include path. // CFG_TUSB_OS_INC_PATH should be defined accordingly. #include "freertos/FreeRTOS.h" @@ -195,6 +195,7 @@ static inline void board_delay(uint32_t ms) { // stdio getchar() is blocking, this is non-blocking version int board_getchar(void); +void board_putchar(int c); #ifdef __cplusplus } diff --git a/hw/bsp/espressif/boards/family.c b/hw/bsp/espressif/boards/family.c index 8f6c4bee2..2a5deed26 100644 --- a/hw/bsp/espressif/boards/family.c +++ b/hw/bsp/espressif/boards/family.c @@ -156,6 +156,10 @@ int board_getchar(void) { return getchar(); } +void board_putchar(int c) { + putchar(c); +} + //-------------------------------------------------------------------- // PHY Init //-------------------------------------------------------------------- diff --git a/tools/build.py b/tools/build.py index 6e73681fe..eaa383d73 100755 --- a/tools/build.py +++ b/tools/build.py @@ -101,10 +101,8 @@ def cmake_board(board, toolchain, build_flags_on): if build_utils.skip_example(example, board): ret[2] += 1 else: - rcmd = run_cmd(f'cmake examples/{example} -B {build_dir}/{example} -G Ninja ' - f'-DBOARD={board} {build_flags}') - if rcmd.returncode == 0: - rcmd = run_cmd(f'cmake --build {build_dir}/{example}') + rcmd = run_cmd(f'idf.py -C examples/{example} -B {build_dir}/{example} -G Ninja ' + f'-DBOARD={board} {build_flags} build') ret[0 if rcmd.returncode == 0 else 1] += 1 else: rcmd = run_cmd(f'cmake examples -B {build_dir} -G Ninja -DBOARD={board} -DCMAKE_BUILD_TYPE=MinSizeRel ' diff --git a/tools/build_utils.py b/tools/build_utils.py index 2998f940d..d80ceea7c 100755 --- a/tools/build_utils.py +++ b/tools/build_utils.py @@ -26,6 +26,8 @@ def skip_example(example, board): # family.mk family_mk = family_dir / "family.mk" + if not family_mk.exists(): + family_mk = family_dir / "family.cmake" mk_contents = family_mk.read_text() # Find the mcu, first in family mk then board mk From a8b5e2bfc0a2d35ba775f7b2de81d531ed525e41 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 15:38:14 +0700 Subject: [PATCH 085/101] update example --- examples/device/board_test/src/main.c | 21 ++++++++++++--------- examples/host/cdc_msc_hid/src/cdc_app.c | 5 ++++- hw/bsp/rp2040/family.c | 6 +++++- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c index 2269d45f1..2c6ab6288 100644 --- a/examples/device/board_test/src/main.c +++ b/examples/device/board_test/src/main.c @@ -49,25 +49,28 @@ int main(void) { while (1) { uint32_t interval_ms = board_button_read() ? BLINK_PRESSED : BLINK_UNPRESSED; + int ch = board_getchar(); + if (ch > 0) { + board_putchar(ch); + } + // Blink and print every interval ms if (!(board_millis() - start_ms < interval_ms)) { - board_uart_write(HELLO_STR, strlen(HELLO_STR)); - start_ms = board_millis(); + if (ch < 0) { + // skip if echoing + printf(HELLO_STR); + board_uart_write(HELLO_STR, strlen(HELLO_STR)); + } + board_led_write(led_state); led_state = 1 - led_state; // toggle } - - // echo - uint8_t ch; - if (board_uart_read(&ch, 1) > 0) { - board_uart_write(&ch, 1); - } } } -#if TUSB_MCU_VENDOR_ESPRESSIF +#ifdef ESP_PLATFORM void app_main(void) { main(); } diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 2fa9a8560..97f1a96d6 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -72,7 +72,10 @@ void tuh_cdc_rx_cb(uint8_t idx) { if (count) { buf[count] = 0; printf("%s", (char*) buf); - fflush(stdout); + + #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? + fflush(stdout);// flush right away, else nanolib will wait for newline + #endif } } diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c index 8c85c5cc8..a22924131 100644 --- a/hw/bsp/rp2040/family.c +++ b/hw/bsp/rp2040/family.c @@ -254,7 +254,7 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { int board_uart_read(uint8_t *buf, int len) { #ifdef UART_DEV int count = 0; - while ( (count < len) && uart_is_readable(uart_inst) ) { + while ((count < len) && uart_is_readable(uart_inst)) { buf[count] = uart_getc(uart_inst); count++; } @@ -282,6 +282,10 @@ int board_getchar(void) { return getchar_timeout_us(0); } +void board_putchar(int c) { + stdio_putchar(c); +} + //--------------------------------------------------------------------+ // USB Interrupt Handler // rp2040 implementation will install appropriate handler when initializing From 014d6b2f2647b5135e22d219b61b727cb9a20ae6 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 15:55:42 +0700 Subject: [PATCH 086/101] remove cmake arm-clang and make iar to reduce concurrent jobs --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 97f219e6f..5e11f8a29 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -70,7 +70,7 @@ jobs: matrix: toolchain: - 'aarch64-gcc' - - 'arm-clang' + #- 'arm-clang' - 'arm-gcc' - 'esp-idf' - 'msp430-gcc' @@ -110,7 +110,8 @@ jobs: # cmake is built by circle-ci. Due to IAR limit capacity, only build oe per family # --------------------------------------- arm-iar: - if: github.event_name == 'push' && github.repository_owner == 'hathach' + if: false # disable for now since we got reach capacity limit too often + #if: github.event_name == 'push' && github.repository_owner == 'hathach' needs: set-matrix uses: ./.github/workflows/build_util.yml secrets: inherit From 52f0427096a9e20b62dc3055a153a60e50317297 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 16:34:17 +0700 Subject: [PATCH 087/101] remove make wrapper for rp2040/espressif --- docs/reference/getting_started.rst | 2 +- hw/bsp/rp2040/family.mk | 16 ---------------- tools/build.py | 21 +++++++++++++-------- 3 files changed, 14 insertions(+), 25 deletions(-) delete mode 100644 hw/bsp/rp2040/family.mk diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst index ee68f6386..5b009f21e 100644 --- a/docs/reference/getting_started.rst +++ b/docs/reference/getting_started.rst @@ -82,7 +82,7 @@ You only need to do this once per family. Check out `complete list of dependenci Build Examples ^^^^^^^^^^^^^^ -Examples support make and cmake build system, though some MCU family such as espressif/rp2040 only support cmake. First change directory to an example folder. +Examples support make and cmake build system for most MCUs, however some MCU families such as espressif or rp2040 only support cmake. First change directory to an example folder. .. code-block:: bash diff --git a/hw/bsp/rp2040/family.mk b/hw/bsp/rp2040/family.mk deleted file mode 100644 index 813683c54..000000000 --- a/hw/bsp/rp2040/family.mk +++ /dev/null @@ -1,16 +0,0 @@ -JLINK_DEVICE = rp2040_m0_0 -PYOCD_TARGET = rp2040 - -ifeq ($(DEBUG), 1) -CMAKE_DEFSYM += -DCMAKE_BUILD_TYPE=Debug -endif - -$(BUILD): - cmake -S . -B $(BUILD) -DFAMILY=$(FAMILY) -DBOARD=$(BOARD) -DPICO_BUILD_DOCS=0 $(CMAKE_DEFSYM) - -all: $(BUILD) - $(MAKE) -C $(BUILD) - -flash: flash-pyocd -flash-uf2: - @$(CP) $(BUILD)/$(PROJECT).uf2 /media/$(USER)/RPI-RP2 diff --git a/tools/build.py b/tools/build.py index eaa383d73..f639fba81 100755 --- a/tools/build.py +++ b/tools/build.py @@ -154,16 +154,21 @@ def make_one_example(example, board, make_option): def make_board(board, toolchain): print(build_separator) - all_examples = get_examples(find_family(board)) + family = find_family(board); + all_examples = get_examples(family) start_time = time.monotonic() ret = [0, 0, 0] - with Pool(processes=os.cpu_count()) as pool: - pool_args = list((map(lambda e, b=board, o=f"TOOLCHAIN={toolchain}": [e, b, o], all_examples))) - r = pool.starmap(make_one_example, pool_args) - # sum all element of same index (column sum) - ret = list(map(sum, list(zip(*r)))) - example = 'all' - print_build_result(board, example, 0 if ret[1] == 0 else 1, time.monotonic() - start_time) + if family == 'espressif' or family == 'rp2040': + # espressif and rp2040 do not support make, use cmake instead + final_status = 2 + else: + with Pool(processes=os.cpu_count()) as pool: + pool_args = list((map(lambda e, b=board, o=f"TOOLCHAIN={toolchain}": [e, b, o], all_examples))) + r = pool.starmap(make_one_example, pool_args) + # sum all element of same index (column sum) + ret = list(map(sum, list(zip(*r)))) + final_status = 0 if ret[1] == 0 else 1 + print_build_result(board, 'all', final_status, time.monotonic() - start_time) return ret From a64e3eb0aa661db14eb647e2f75059815741112f Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 17:27:03 +0700 Subject: [PATCH 088/101] update board_test always output to uart regardless of LOGGER option --- docs/reference/getting_started.rst | 4 ++-- examples/build_system/make/make.mk | 19 ++++++++----------- examples/device/board_test/src/main.c | 6 ++++++ hw/bsp/board.c | 1 - hw/bsp/family_support.cmake | 2 ++ test/fuzz/make.mk | 6 ------ 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/reference/getting_started.rst b/docs/reference/getting_started.rst index 5b009f21e..bb9ff1cb4 100644 --- a/docs/reference/getting_started.rst +++ b/docs/reference/getting_started.rst @@ -256,8 +256,8 @@ Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\ 2. Open ``Project -> Add project Connection ...``, click ``OK``, choose ``tinyusb\\examples\\(.ipcf of example)``. For example ``C:\\tinyusb\\examples\\device\\cdc_msc\\iar_cdc_msc.ipcf`` -Native CMake support (9.50.1+) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Native CMake support +~~~~~~~~~~~~~~~~~~~~ With 9.50.1 release, IAR added experimental native CMake support (strangely not mentioned in public release note). Now it's possible to import CMakeLists.txt then build and debug as a normal project. diff --git a/examples/build_system/make/make.mk b/examples/build_system/make/make.mk index dbc73903e..f70748d34 100644 --- a/examples/build_system/make/make.mk +++ b/examples/build_system/make/make.mk @@ -123,27 +123,24 @@ endif ifeq (${MAX3421_HOST},1) SRC_C += src/portable/analog/max3421/hcd_max3421.c CFLAGS += -DCFG_TUH_MAX3421=1 - CMAKE_DEFSYM += -DMAX3421_HOST=1 endif # Log level is mapped to TUSB DEBUG option ifneq ($(LOG),) - CMAKE_DEFSYM += -DLOG=$(LOG) CFLAGS += -DCFG_TUSB_DEBUG=$(LOG) endif # Logger: default is uart, can be set to rtt or swo -ifneq ($(LOGGER),) - CMAKE_DEFSYM += -DLOGGER=$(LOGGER) -endif - ifeq ($(LOGGER),rtt) - CFLAGS += -DLOGGER_RTT -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL - RTT_SRC = lib/SEGGER_RTT - INC += $(TOP)/$(RTT_SRC)/RTT - SRC_C += $(RTT_SRC)/RTT/SEGGER_RTT.c -else ifeq ($(LOGGER),swo) + CFLAGS += -DLOGGER_RTT + #CFLAGS += -DSEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL + INC += $(TOP)/$(lib/SEGGER_RTT)/RTT + SRC_C += $(lib/SEGGER_RTT)/RTT/SEGGER_RTT.c +endif +ifeq ($(LOGGER),swo) CFLAGS += -DLOGGER_SWO +else + CFLAGS += -DLOGGER_UART endif # CPU specific flags diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c index 2c6ab6288..d91a8760e 100644 --- a/examples/device/board_test/src/main.c +++ b/examples/device/board_test/src/main.c @@ -52,6 +52,9 @@ int main(void) { int ch = board_getchar(); if (ch > 0) { board_putchar(ch); + #ifndef LOGGER_UART + board_uart_write(&ch, 1); + #endif } // Blink and print every interval ms @@ -61,7 +64,10 @@ int main(void) { if (ch < 0) { // skip if echoing printf(HELLO_STR); + + #ifndef LOGGER_UART board_uart_write(HELLO_STR, strlen(HELLO_STR)); + #endif } board_led_write(led_state); diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 8f2f93306..1ba5a1b9d 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -60,7 +60,6 @@ int sys_read(int fhdl, char *buf, size_t count) { int rd = (int) SEGGER_RTT_Read(0, buf, count); return (rd > 0) ? rd : -1; } - #endif #elif defined(LOGGER_SWO) diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 0509fdc28..9ec80df91 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -221,6 +221,8 @@ function(family_configure_common TARGET RTOS) target_include_directories(${TARGET} PUBLIC ${TOP}/lib/SEGGER_RTT/RTT) # target_compile_definitions(${TARGET} PUBLIC SEGGER_RTT_MODE_DEFAULT=SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) endif () + else () + target_compile_definitions(${TARGET} PUBLIC LOGGER_UART) endif () if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") diff --git a/test/fuzz/make.mk b/test/fuzz/make.mk index b7b6d6a75..e9aa80bf1 100644 --- a/test/fuzz/make.mk +++ b/test/fuzz/make.mk @@ -124,11 +124,5 @@ endif # Log level is mapped to TUSB DEBUG option ifneq ($(LOG),) - CMAKE_DEFSYM += -DLOG=$(LOG) CFLAGS += -DCFG_TUSB_DEBUG=$(LOG) endif - -# Logger: default is uart, can be set to rtt or swo -ifneq ($(LOGGER),) - CMAKE_DEFSYM += -DLOGGER=$(LOGGER) -endif From a52e5ce99aa4fba305e5b8639360d5b3990d7475 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 17:43:38 +0700 Subject: [PATCH 089/101] build iar with circleci large resource --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3b4389ab4..c2f6c4356 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -66,7 +66,7 @@ jobs: FAMILY_LARGE=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[])))') FAMILY=$(jq -n --argjson family "$FAMILY" --argjson resource "$RESOURCE_LARGE" '$family | map(select(IN($resource[]) | not))') - if [[ $toolchain == esp-idf ]]; then + if [[ $toolchain == esp-idf || $toolchain == arm-iar ]]; then gen_build_entry "$build_system" "$toolchain" "$FAMILY" "large" else gen_build_entry "$build_system" "$toolchain" "$FAMILY" "medium+" From 41606a533dbe4bb7e031267d2869401243d2a0aa Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 3 Jul 2025 13:42:05 +0700 Subject: [PATCH 090/101] make notify API and memory configurable with CFG_TUD_CDC_NOTIFY add tud_cdc_n_notify_conn_speed_change() add tud_cdc_notify_complete_cb() --- examples/device/cdc_dual_ports/src/main.c | 13 +-- .../device/cdc_dual_ports/src/tusb_config.h | 2 + .../cdc_dual_ports/src/usb_descriptors.c | 47 ++++----- src/class/cdc/cdc.h | 95 ++++++++++--------- src/class/cdc/cdc_device.c | 79 ++++++++------- src/class/cdc/cdc_device.h | 34 +++++-- 6 files changed, 149 insertions(+), 121 deletions(-) diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c index e5432eb23..5a3e18358 100644 --- a/examples/device/cdc_dual_ports/src/main.c +++ b/examples/device/cdc_dual_ports/src/main.c @@ -102,16 +102,13 @@ void tud_umount_cb(void) { // USB CDC //--------------------------------------------------------------------+ static void cdc_task(void) { - uint8_t itf; - - for (itf = 0; itf < CFG_TUD_CDC; itf++) { + for (uint8_t itf = 0; itf < CFG_TUD_CDC; itf++) { // connected() check for DTR bit // Most but not all terminal client set this when making connection // if ( tud_cdc_n_connected(itf) ) { if (tud_cdc_n_available(itf)) { uint8_t buf[64]; - uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf)); // echo back to both serial ports @@ -121,11 +118,11 @@ static void cdc_task(void) { // Press on-board button to send Uart status notification static uint32_t btn_prev = 0; - static cdc_uart_state_t state = {0}; - uint32_t btn = board_button_read(); + static cdc_notify_uart_state_t uart_state = { .value = 0 }; + const uint32_t btn = board_button_read(); if (!btn_prev && btn) { - state.bTxCarrier ^= 1; - tud_cdc_send_uart_state(state); + uart_state.dsr ^= 1; + tud_cdc_notify_uart_state(&uart_state); } btn_prev = btn; } diff --git a/examples/device/cdc_dual_ports/src/tusb_config.h b/examples/device/cdc_dual_ports/src/tusb_config.h index 070f08ed1..7f7df3909 100644 --- a/examples/device/cdc_dual_ports/src/tusb_config.h +++ b/examples/device/cdc_dual_ports/src/tusb_config.h @@ -97,6 +97,8 @@ #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0 +#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint + // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index 68eedd964..87309abbb 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -130,36 +130,32 @@ enum #define EPNUM_CDC_1_IN 0x84 #endif -uint8_t const desc_fs_configuration[] = -{ +uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64), // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64), }; #if TUD_OPT_HIGH_SPEED // Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration - -uint8_t const desc_hs_configuration[] = -{ +uint8_t const desc_hs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 10, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 16, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512), // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 10, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 16, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512), }; // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed -tusb_desc_device_qualifier_t const desc_device_qualifier = -{ +tusb_desc_device_qualifier_t const desc_device_qualifier = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, @@ -177,34 +173,31 @@ tusb_desc_device_qualifier_t const desc_device_qualifier = // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -uint8_t const* tud_descriptor_device_qualifier_cb(void) -{ - return (uint8_t const*) &desc_device_qualifier; +uint8_t const *tud_descriptor_device_qualifier_cb(void) { + return (uint8_t const *) &desc_device_qualifier; } // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations +uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index;// for multiple configurations // if link speed is high return fullspeed config, and vice versa - return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; } -#endif // highspeed +#endif// highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ - (void) index; // for multiple configurations +uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { + (void) index;// for multiple configurations #if TUD_OPT_HIGH_SPEED // Although we are highspeed, host may be fullspeed. - return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; #else return desc_fs_configuration; #endif @@ -223,8 +216,7 @@ enum { }; // array of pointer to string descriptors -char const *string_desc_arr[] = -{ +char const *string_desc_arr[] = { (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) "TinyUSB", // 1: Manufacturer "TinyUSB Device", // 2: Product @@ -254,14 +246,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; } const char *str = string_desc_arr[index]; // Cap at max char chr_count = strlen(str); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if ( chr_count > max_count ) { chr_count = max_count; } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { @@ -272,6 +264,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // first byte is length (including header), second byte is string type _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - return _desc_str; } diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index a403d77fa..10ba16a7c 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -221,18 +221,20 @@ typedef enum { // Management Element Notification (Notification Endpoint) //--------------------------------------------------------------------+ +#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface + /// 6.3 Notification Codes typedef enum { - CDC_NOTIF_NETWORK_CONNECTION = 0x00, ///< This notification allows the device to notify the host about network connection status. - CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, ///< This notification allows the device to notify the hostthat a response is available. This response can be retrieved with a subsequent \ref CDC_REQUEST_GET_ENCAPSULATED_RESPONSE request. + CDC_NOTIF_NETWORK_CONNECTION = 0x00, // notify the host about network connection status. + CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, // notify the host that a response is available. CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, CDC_NOTIF_RING_DETECT = 0x09, CDC_NOTIF_SERIAL_STATE = 0x20, CDC_NOTIF_CALL_STATE_CHANGE = 0x28, CDC_NOTIF_LINE_STATE_CHANGE = 0x29, - CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, ///< This notification allows the device to inform the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred + CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, // notify the host-networking driver that a change in either the upstream or the downstream bit rate of the connection has occurred CDC_NOTIF_MDLM_SEMANTIC_MODEL_NOTIFICATION = 0x40, -}cdc_notification_request_t; +} cdc_notify_request_t; //--------------------------------------------------------------------+ // Class Specific Functional Descriptor (Communication Interface) @@ -243,8 +245,7 @@ TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN /// Header Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUNC_DESC_ @@ -252,8 +253,7 @@ typedef struct TU_ATTR_PACKED }cdc_desc_func_header_t; /// Union Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ @@ -271,14 +271,13 @@ typedef struct TU_ATTR_PACKED } /// Country Selection Functional Descriptor (Communication Interface) -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ uint8_t iCountryCodeRelDate ; ///< Index of a string giving the release date for the implemented ISO 3166 Country Codes. uint16_t wCountryCode ; ///< Country code in the format as defined in [ISO3166], release date as specified inoffset 3 for the first supported country. -}cdc_desc_func_country_selection_t; +} cdc_desc_func_country_selection_t; #define cdc_desc_func_country_selection_n_t(no_country) \ struct TU_ATTR_PACKED { \ @@ -295,8 +294,7 @@ typedef struct TU_ATTR_PACKED /// \brief Call Management Functional Descriptor /// \details This functional descriptor describes the processing of calls for the Communications Class interface. -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ @@ -310,8 +308,7 @@ typedef struct TU_ATTR_PACKED uint8_t bDataInterface; }cdc_desc_func_call_management_t; -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t support_comm_request : 1; ///< Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. uint8_t support_line_request : 1; ///< Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. uint8_t support_send_break : 1; ///< Device supports the request Send_Break @@ -323,8 +320,7 @@ TU_VERIFY_STATIC(sizeof(cdc_acm_capability_t) == 1, "mostly problem with compile /// Abstract Control Management Functional Descriptor /// This functional descriptor describes the commands supported by by the Communications Class interface with SubClass code of \ref CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ @@ -333,8 +329,7 @@ typedef struct TU_ATTR_PACKED /// \brief Direct Line Management Functional Descriptor /// \details This functional descriptor describes the commands supported by the Communications Class interface with SubClass code of \ref CDC_FUNC_DESC_DIRECT_LINE_MANAGEMENT -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes. uint8_t bDescriptorType ; ///< Descriptor Type, must be Class-Specific uint8_t bDescriptorSubType ; ///< Descriptor SubType one of above CDC_FUCN_DESC_ @@ -396,8 +391,7 @@ typedef struct TU_ATTR_PACKED }cdc_desc_func_telephone_call_state_reporting_capabilities_t; // TODO remove -static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) -{ +TU_ATTR_ALWAYS_INLINE static inline uint8_t cdc_functional_desc_typeof(uint8_t const * p_desc) { return p_desc[2]; } @@ -414,7 +408,7 @@ typedef struct TU_ATTR_PACKED { TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct"); typedef union TU_ATTR_PACKED { - struct { + struct TU_ATTR_PACKED { uint8_t dtr : 1; uint8_t rts : 1; uint8_t : 6; @@ -427,31 +421,44 @@ TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 1, "size is not correct"); //--------------------------------------------------------------------+ // Notifications //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED -{ - uint16_t bRxCarrier : 1; - uint16_t bTxCarrier : 1; - uint16_t bBreak : 1; - uint16_t bRingSignal : 1; - uint16_t bFraming : 1; - uint16_t bParity : 1; - uint16_t bOverRun : 1; - uint16_t : 9; -} cdc_uart_state_t; +// PSTN 1.2 section 6.5.4 table 31 +typedef union TU_ATTR_PACKED { + struct TU_ATTR_PACKED { + uint16_t bRxCarrier : 1; // DCD + uint16_t bTxCarrier : 1; // DSR + uint16_t bBreak : 1; // Break Detected + uint16_t bRingSignal : 1; + uint16_t bFraming : 1; + uint16_t bParity : 1; + uint16_t bOverRun : 1; + uint16_t : 9; + }; + struct TU_ATTR_PACKED { + uint16_t dcd : 1; + uint16_t dsr : 1; + uint16_t brk : 1; + uint16_t :13; + }; + uint16_t value; +} cdc_notify_uart_state_t; -typedef struct TU_ATTR_PACKED -{ - uint8_t bmRequestType; - uint8_t bNotification; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; - cdc_uart_state_t bmUartState; -} cdc_notif_serial_state_t; +TU_VERIFY_STATIC(sizeof(cdc_notify_uart_state_t) == 2, "size is not correct"); -TU_VERIFY_STATIC(sizeof(cdc_notif_serial_state_t) == 10, "size is not correct"); +// CDC 1.2 section 6.3.3 table 21 +typedef struct TU_ATTR_PACKED { + uint32_t upstream_bitrate; + uint32_t downstream_bitrate; +} cdc_notify_conn_speed_change_t; -#define CDC_REQ_TYPE_NOTIF 0xA1 ///< Direction IN; Type Class; Recipient Interface +typedef struct TU_ATTR_PACKED { + tusb_control_request_t request; + union { + cdc_notify_uart_state_t serial_state; + cdc_notify_conn_speed_change_t conn_speed_change; + }; +} cdc_notify_msg_t; + +TU_VERIFY_STATIC(sizeof(cdc_notify_msg_t) == 16, "size is not correct"); TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 786c3aa55..4e4e01eaf 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -48,12 +48,11 @@ typedef struct { uint8_t rhport; uint8_t itf_num; - uint8_t ep_notif; uint8_t ep_in; uint8_t ep_out; - // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) - uint8_t line_state; + uint8_t ep_notify; + uint8_t line_state; // Bit 0: DTR, Bit 1: RTS /*------------- From this point, data is not cleared by bus reset -------------*/ char wanted_char; @@ -75,7 +74,10 @@ typedef struct { typedef struct { TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE); TUD_EPBUF_DEF(epin, CFG_TUD_CDC_EP_BUFSIZE); - TUD_EPBUF_TYPE_DEF(cdc_notif_serial_state_t, epnotif); + + #if CFG_TUD_CDC_NOTIFY + TUD_EPBUF_TYPE_DEF(cdc_notify_msg_t, epnotify); + #endif } cdcd_epbuf_t; //--------------------------------------------------------------------+ @@ -120,7 +122,6 @@ static bool _prep_out_transaction(uint8_t itf) { //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ - bool tud_cdc_configure(const tud_cdc_configure_t* driver_cfg) { TU_VERIFY(driver_cfg); _cdcd_cfg = *driver_cfg; @@ -144,27 +145,42 @@ void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) { (*coding) = _cdcd_itf[itf].line_coding; } -bool tud_cdc_n_send_uart_state (uint8_t itf, cdc_uart_state_t state) { +#if CFG_TUD_CDC_NOTIFY +bool tud_cdc_n_notify_uart_state (uint8_t itf, const cdc_notify_uart_state_t *state) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; + TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0); + TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify)); - // Skip if usb is not ready yet - TU_VERIFY(tud_ready(), 0); + cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify; + notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF; + notify_msg->request.bRequest = CDC_NOTIF_SERIAL_STATE; + notify_msg->request.wValue = 0; + notify_msg->request.wIndex = p_cdc->itf_num; + notify_msg->request.wLength = sizeof(cdc_notify_uart_state_t); + notify_msg->serial_state = *state; - // claim endpoint - TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notif)); - - p_epbuf->epnotif.bmRequestType = CDC_REQ_TYPE_NOTIF; - p_epbuf->epnotif.bNotification = CDC_NOTIF_SERIAL_STATE; - p_epbuf->epnotif.wValue = 0; - p_epbuf->epnotif.wIndex = p_cdc->itf_num; - p_epbuf->epnotif.wLength = 2; - p_epbuf->epnotif.bmUartState = state; - - // transfer - return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notif, (uint8_t *)&p_epbuf->epnotif, sizeof(cdc_notif_serial_state_t)); + return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_uart_state_t)); } +bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change) { + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; + TU_VERIFY(tud_ready() && p_cdc->ep_notify != 0); + TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_notify)); + + cdc_notify_msg_t* notify_msg = &p_epbuf->epnotify; + notify_msg->request.bmRequestType = CDC_REQ_TYPE_NOTIF; + notify_msg->request.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE; + notify_msg->request.wValue = 0; + notify_msg->request.wIndex = p_cdc->itf_num; + notify_msg->request.wLength = sizeof(cdc_notify_conn_speed_change_t); + notify_msg->conn_speed_change = *conn_speed_change; + + return usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_notify, (uint8_t *)notify_msg, 8 + sizeof(cdc_notify_conn_speed_change_t)); +} +#endif + void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted) { _cdcd_itf[itf].wanted_char = wanted; } @@ -215,25 +231,20 @@ uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) { uint32_t tud_cdc_n_write_flush(uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf]; - - // Skip if usb is not ready yet - TU_VERIFY(tud_ready(), 0); + TU_VERIFY(tud_ready(), 0); // Skip if usb is not ready yet // No data to send if (!tu_fifo_count(&p_cdc->tx_ff)) { return 0; } - const uint8_t rhport = 0; - - // Claim the endpoint - TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0); + TU_VERIFY(usbd_edpt_claim(p_cdc->rhport, p_cdc->ep_in), 0); // Claim the endpoint // Pull data from FIFO const uint16_t count = tu_fifo_read_n(&p_cdc->tx_ff, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE); if (count) { - TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_epbuf->epin, count), 0); + TU_ASSERT(usbd_edpt_xfer(p_cdc->rhport, p_cdc->ep_in, p_epbuf->epin, count), 0); return count; } else { // Release endpoint since we don't make any transfer @@ -357,9 +368,8 @@ uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16 if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { // notification endpoint const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); - p_cdc->ep_notif = desc_ep->bEndpointAddress; + p_cdc->ep_notify = desc_ep->bEndpointAddress; drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); @@ -479,7 +489,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Identify which interface to use for (itf = 0; itf < CFG_TUD_CDC; itf++) { p_cdc = &_cdcd_itf[itf]; - if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notif)) { + if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notify)) { break; } } @@ -528,7 +538,12 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } } - // nothing to do with notif endpoint for now + // Sent notification to host + if (ep_addr == p_cdc->ep_notify) { + if (tud_cdc_notify_complete_cb) { + tud_cdc_notify_complete_cb(itf); + } + } return true; } diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index f6fa5abf8..a34e07e1d 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -32,6 +32,10 @@ //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ +#ifndef CFG_TUD_CDC_NOTIFY + #define CFG_TUD_CDC_NOTIFY 0 +#endif + #if !defined(CFG_TUD_CDC_EP_BUFSIZE) && defined(CFG_TUD_CDC_EPSIZE) #warning CFG_TUD_CDC_EPSIZE is renamed to CFG_TUD_CDC_EP_BUFSIZE, please update to use the new name #define CFG_TUD_CDC_EP_BUFSIZE CFG_TUD_CDC_EPSIZE @@ -83,9 +87,6 @@ uint8_t tud_cdc_n_get_line_state(uint8_t itf); // Get current line encoding: bit rate, stop bits parity etc .. void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding); -// Send UART status notification: DCD, DSR etc .. -bool tud_cdc_n_send_uart_state(uint8_t itf, cdc_uart_state_t state); - // Set special character that will trigger tud_cdc_rx_wanted_cb() callback on receiving void tud_cdc_n_set_wanted_char(uint8_t itf, char wanted); @@ -129,6 +130,23 @@ uint32_t tud_cdc_n_write_available(uint8_t itf); // Clear the transmit FIFO bool tud_cdc_n_write_clear(uint8_t itf); + +#if CFG_TUD_CDC_NOTIFY +// Send UART status notification: DCD, DSR etc .. +bool tud_cdc_n_notify_uart_state(uint8_t itf, const cdc_notify_uart_state_t *state); + +// Send connection speed change notification +bool tud_cdc_n_notify_conn_speed_change(uint8_t itf, const cdc_notify_conn_speed_change_t* conn_speed_change); + +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_uart_state(const cdc_notify_uart_state_t* state) { + return tud_cdc_n_notify_uart_state(0, state); +} + +TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_notify_conn_speed_change(const cdc_notify_conn_speed_change_t* conn_speed_change) { + return tud_cdc_n_notify_conn_speed_change(0, conn_speed_change); +} +#endif + //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ @@ -149,11 +167,6 @@ TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding tud_cdc_n_get_line_coding(0, coding); } -TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_send_uart_state(cdc_uart_state_t state) { - return tud_cdc_n_send_uart_state(0, state); -} - - TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_wanted_char(char wanted) { tud_cdc_n_set_wanted_char(0, wanted); } @@ -203,7 +216,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_cdc_write_clear(void) { } //--------------------------------------------------------------------+ -// Application Callback API (weak is optional) +// Application Callback API //--------------------------------------------------------------------+ // Invoked when received new data @@ -215,6 +228,9 @@ TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char); // Invoked when a TX is complete and therefore space becomes available in TX buffer TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf); +// Invoked when a notification is sent to host +TU_ATTR_WEAK void tud_cdc_notify_complete_cb(uint8_t itf); + // Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts); From 0df3bfb81d33d11432824bbf91ab0eb260f6f14f Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 3 Jul 2025 14:28:19 +0700 Subject: [PATCH 091/101] update cdc_msc/cdc_msc_freertos to also support notification --- .../cdc_dual_ports/src/usb_descriptors.c | 11 ++++----- examples/device/cdc_msc/src/main.c | 10 ++++++++ examples/device/cdc_msc/src/tusb_config.h | 4 +++- examples/device/cdc_msc/src/usb_descriptors.c | 11 ++++----- examples/device/cdc_msc_freertos/src/main.c | 10 ++++++++ .../device/cdc_msc_freertos/src/tusb_config.h | 2 ++ .../cdc_msc_freertos/src/usb_descriptors.c | 24 +++++++------------ 7 files changed, 42 insertions(+), 30 deletions(-) diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index 87309abbb..bbcb479f5 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -42,8 +42,7 @@ //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ -tusb_desc_device_t const desc_device = -{ +tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, .bcdUSB = USB_BCD, @@ -68,16 +67,14 @@ tusb_desc_device_t const desc_device = // Invoked when received GET DEVICE DESCRIPTOR // Application return pointer to descriptor -uint8_t const * tud_descriptor_device_cb(void) -{ +uint8_t const *tud_descriptor_device_cb(void) { return (uint8_t const *) &desc_device; } //--------------------------------------------------------------------+ // Configuration Descriptor //--------------------------------------------------------------------+ -enum -{ +enum { ITF_NUM_CDC_0 = 0, ITF_NUM_CDC_0_DATA, ITF_NUM_CDC_1, @@ -193,7 +190,7 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete uint8_t const *tud_descriptor_configuration_cb(uint8_t index) { - (void) index;// for multiple configurations + (void) index; // for multiple configurations #if TUD_OPT_HIGH_SPEED // Although we are highspeed, host may be fullspeed. diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c index f36c910d7..5cd93e7dd 100644 --- a/examples/device/cdc_msc/src/main.c +++ b/examples/device/cdc_msc/src/main.c @@ -119,6 +119,16 @@ void cdc_task(void) { tud_cdc_write(buf, count); tud_cdc_write_flush(); } + + // Press on-board button to send Uart status notification + static uint32_t btn_prev = 0; + static cdc_notify_uart_state_t uart_state = { .value = 0 }; + const uint32_t btn = board_button_read(); + if (!btn_prev && btn) { + uart_state.dsr ^= 1; + tud_cdc_notify_uart_state(&uart_state); + } + btn_prev = btn; } } diff --git a/examples/device/cdc_msc/src/tusb_config.h b/examples/device/cdc_msc/src/tusb_config.h index 03e0e649c..811d464e9 100644 --- a/examples/device/cdc_msc/src/tusb_config.h +++ b/examples/device/cdc_msc/src/tusb_config.h @@ -87,7 +87,7 @@ //-------------------------------------------------------------------- #ifndef CFG_TUD_ENDPOINT0_SIZE -#define CFG_TUD_ENDPOINT0_SIZE 64 +#define CFG_TUD_ENDPOINT0_SIZE 64 #endif //------------- CLASS -------------// @@ -97,6 +97,8 @@ #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0 +#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint + // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c index 4b6b88041..edcee0462 100644 --- a/examples/device/cdc_msc/src/usb_descriptors.c +++ b/examples/device/cdc_msc/src/usb_descriptors.c @@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = { .bDeviceClass = TUSB_CLASS_MISC, .bDeviceSubClass = MISC_SUBCLASS_COMMON, .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = USB_VID, @@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), @@ -146,7 +145,7 @@ uint8_t const desc_hs_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), @@ -197,7 +196,6 @@ uint8_t const *tud_descriptor_other_speed_configuration_cb(uint8_t index) { #endif // highspeed - // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete @@ -256,14 +254,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; } const char *str = string_desc_arr[index]; // Cap at max char chr_count = strlen(str); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if ( chr_count > max_count ) { chr_count = max_count; } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { @@ -274,6 +272,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // first byte is length (including header), second byte is string type _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - return _desc_str; } diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 6fe964153..09ccc9bf3 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -189,6 +189,16 @@ void cdc_task(void *params) { } tud_cdc_write_flush(); + + // Press on-board button to send Uart status notification + static uint32_t btn_prev = 0; + static cdc_notify_uart_state_t uart_state = { .value = 0 }; + const uint32_t btn = board_button_read(); + if (!btn_prev && btn) { + uart_state.dsr ^= 1; + tud_cdc_notify_uart_state(&uart_state); + } + btn_prev = btn; } // For ESP32-Sx this delay is essential to allow idle how to run and reset watchdog diff --git a/examples/device/cdc_msc_freertos/src/tusb_config.h b/examples/device/cdc_msc_freertos/src/tusb_config.h index 71a0e985a..9cc3a18d1 100644 --- a/examples/device/cdc_msc_freertos/src/tusb_config.h +++ b/examples/device/cdc_msc_freertos/src/tusb_config.h @@ -104,6 +104,8 @@ #define CFG_TUD_MIDI 0 #define CFG_TUD_VENDOR 0 +#define CFG_TUD_CDC_NOTIFY 1 // Enable use of notification endpoint + // CDC FIFO size of TX and RX #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c index 405a57fe4..a55fa3675 100644 --- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c +++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c @@ -52,7 +52,6 @@ tusb_desc_device_t const desc_device = { .bDeviceClass = TUSB_CLASS_MISC, .bDeviceSubClass = MISC_SUBCLASS_COMMON, .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, .idVendor = USB_VID, @@ -131,7 +130,7 @@ uint8_t const desc_fs_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), @@ -147,7 +146,7 @@ uint8_t const desc_hs_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP notification address and size, EP data address (out, in) and size. - TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 16, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), @@ -176,16 +175,14 @@ tusb_desc_device_qualifier_t const desc_device_qualifier = // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -uint8_t const* tud_descriptor_device_qualifier_cb(void) -{ +uint8_t const* tud_descriptor_device_qualifier_cb(void) { return (uint8_t const*) &desc_device_qualifier; } // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) -{ +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { (void) index; // for multiple configurations // if link speed is high return fullspeed config, and vice versa @@ -204,13 +201,12 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete -uint8_t const * tud_descriptor_configuration_cb(uint8_t index) -{ +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations #if TUD_OPT_HIGH_SPEED // Although we are highspeed, host may be fullspeed. - return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; #else return desc_fs_configuration; #endif @@ -229,8 +225,7 @@ enum { }; // array of pointer to string descriptors -char const *string_desc_arr[] = -{ +char const *string_desc_arr[] = { (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) "TinyUSB", // 1: Manufacturer "TinyUSB Device", // 2: Product @@ -261,14 +256,14 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors - if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) return NULL; + if ( !(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])) ) { return NULL; } const char *str = string_desc_arr[index]; // Cap at max char chr_count = strlen(str); size_t const max_count = sizeof(_desc_str) / sizeof(_desc_str[0]) - 1; // -1 for string type - if ( chr_count > max_count ) chr_count = max_count; + if ( chr_count > max_count ) { chr_count = max_count; } // Convert ASCII string into UTF-16 for ( size_t i = 0; i < chr_count; i++ ) { @@ -279,6 +274,5 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { // first byte is length (including header), second byte is string type _desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * chr_count + 2)); - return _desc_str; } From 89da5a724dbd692527ee1d25d5ae71226d1dae56 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 3 Jul 2025 14:28:44 +0700 Subject: [PATCH 092/101] reduce bInterval for default CDC descriptor from 16ms to 1ms --- src/device/usbd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/usbd.h b/src/device/usbd.h index de6007fb3..e5a848809 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -244,7 +244,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ /* CDC Union */\ 5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\ /* Endpoint Notification */\ - 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 16,\ + 7, TUSB_DESC_ENDPOINT, _ep_notif, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_notif_size), 1,\ /* CDC Data Interface */\ 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum)+1), 0, 2, TUSB_CLASS_CDC_DATA, 0, 0, 0,\ /* Endpoint Out */\ From 211c2e380fb5744bef484ad9b59b2579e91d30b4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 3 Jul 2025 18:03:19 +0700 Subject: [PATCH 093/101] fix build with clang --- hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld index 86acf9742..b33838180 100644 --- a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld +++ b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld @@ -35,16 +35,12 @@ /* Entry Point */ ENTRY(Reset_Handler) -/* Highest address of the user mode stack */ -_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of "DTCM" Ram type memory */ - _Min_Heap_Size = 0x200; /* required amount of heap */ _Min_Stack_Size = 0x400; /* required amount of stack */ __FLASH_BEGIN = 0x08000000; __FLASH_SIZE = 0x00010000; - __RAM_BEGIN = 0x24000000; __RAM_SIZE = 0x4FC00; __RAM_NONCACHEABLEBUFFER_SIZE = 0x400; @@ -63,6 +59,9 @@ MEMORY FLASH (xrw) : ORIGIN = __FLASH_BEGIN, LENGTH = __FLASH_SIZE } +/* Highest address of the user mode stack */ +_estack = ORIGIN(DTCM) + LENGTH(DTCM); /* end of "DTCM" Ram type memory */ + /* Sections */ SECTIONS { @@ -100,14 +99,14 @@ SECTIONS . = ALIGN(4); } >FLASH - .ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + .ARM.extab : { . = ALIGN(4); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } >FLASH - .ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + .ARM : { . = ALIGN(4); __exidx_start = .; @@ -116,7 +115,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + .preinit_array : { . = ALIGN(4); PROVIDE_HIDDEN (__preinit_array_start = .); @@ -125,7 +124,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + .init_array : { . = ALIGN(4); PROVIDE_HIDDEN (__init_array_start = .); @@ -135,7 +134,7 @@ SECTIONS . = ALIGN(4); } >FLASH - .fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + .fini_array : { . = ALIGN(4); PROVIDE_HIDDEN (__fini_array_start = .); From ffab23cf0f9e5422f55311e0b9f95d05e68082a6 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 4 Jul 2025 12:10:56 +0200 Subject: [PATCH 094/101] Revise DCache with RTT section Signed-off-by: HiFiPhile --- hw/bsp/stm32f7/family.c | 1 - hw/bsp/stm32h7/family.c | 1 - hw/bsp/stm32h7rs/family.c | 149 +++++++++++++++++- hw/bsp/stm32h7rs/family.cmake | 3 +- hw/bsp/stm32h7rs/family.mk | 3 +- hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf | 2 +- hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld | 5 - 7 files changed, 152 insertions(+), 12 deletions(-) diff --git a/hw/bsp/stm32f7/family.c b/hw/bsp/stm32f7/family.c index b82ab7d51..bf2d28e42 100644 --- a/hw/bsp/stm32f7/family.c +++ b/hw/bsp/stm32f7/family.c @@ -79,7 +79,6 @@ void OTG_HS_IRQHandler(void) { void board_init(void) { SCB_EnableICache(); - SCB_EnableDCache(); HAL_Init(); diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index 23bfcb90e..382b878b7 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -99,7 +99,6 @@ static void trace_etm_init(void) { void board_init(void) { SCB_EnableICache(); - SCB_EnableDCache(); HAL_Init(); diff --git a/hw/bsp/stm32h7rs/family.c b/hw/bsp/stm32h7rs/family.c index b6b2d70e9..b506a02ab 100644 --- a/hw/bsp/stm32h7rs/family.c +++ b/hw/bsp/stm32h7rs/family.c @@ -123,12 +123,157 @@ void log_swo_init(void) #define log_swo_init() #endif +static void MPU_AdjustRegionAddressSize(uint32_t Address, uint32_t Size, MPU_Region_InitTypeDef* pInit); +static void MPU_Config(void) +{ + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + uint32_t index = MPU_REGION_NUMBER0; + uint32_t address; + uint32_t size; + + /* Disable the MPU */ + HAL_MPU_Disable(); + + /* Initialize the background region */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = index; + MPU_InitStruct.BaseAddress = 0x0; + MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; + MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + index++; + + /* Initialize the non cacheable region */ +#if defined ( __ICCARM__ ) + /* get the region attribute form the icf file */ + extern uint32_t NONCACHEABLEBUFFER_start; + extern uint32_t NONCACHEABLEBUFFER_size; + + address = (uint32_t)&NONCACHEABLEBUFFER_start; + size = (uint32_t)&NONCACHEABLEBUFFER_size; + +#elif defined (__CC_ARM) || defined(__ARMCC_VERSION) + extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Base; + extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$Length; + extern uint32_t Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length; + + address = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Base; + size = (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$Length + (uint32_t)&Image$$RW_NONCACHEABLEBUFFER$$ZI$$Length; +#elif defined ( __GNUC__ ) + extern int __NONCACHEABLEBUFFER_BEGIN; + extern int __NONCACHEABLEBUFFER_END; + + address = (uint32_t)&__NONCACHEABLEBUFFER_BEGIN; + size = (uint32_t)&__NONCACHEABLEBUFFER_END - (uint32_t)&__NONCACHEABLEBUFFER_BEGIN; +#else +#error "Compiler toolchain is unsupported" +#endif + + if (size != 0) + { + /* Configure the MPU attributes as Normal Non Cacheable */ + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; + MPU_InitStruct.Number = index; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.SubRegionDisable = 0x00; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct); + HAL_MPU_ConfigRegion(&MPU_InitStruct); + index++; + } + + /* Initialize the region corresponding to the execution area + (external or internal flash or external or internal RAM + depending on scatter file definition) */ +#if defined ( __ICCARM__ ) + extern uint32_t __ICFEDIT_region_ROM_start__; + extern uint32_t __ICFEDIT_region_ROM_end__; + address = (uint32_t)&__ICFEDIT_region_ROM_start__; + size = (uint32_t)&__ICFEDIT_region_ROM_end__ - (uint32_t)&__ICFEDIT_region_ROM_start__ + 1; +#elif defined (__CC_ARM) || defined(__ARMCC_VERSION) + extern uint32_t Image$$ER_ROM$$Base; + extern uint32_t Image$$ER_ROM$$Limit; + address = (uint32_t)&Image$$ER_ROM$$Base; + size = (uint32_t)&Image$$ER_ROM$$Limit-(uint32_t)&Image$$ER_ROM$$Base; +#elif defined ( __GNUC__ ) + extern uint32_t __FLASH_BEGIN; + extern uint32_t __FLASH_SIZE; + address = (uint32_t)&__FLASH_BEGIN; + size = (uint32_t)&__FLASH_SIZE; +#else +#error "Compiler toolchain is unsupported" +#endif + + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = index; + MPU_InitStruct.SubRegionDisable = 0u; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + MPU_AdjustRegionAddressSize(address, size, &MPU_InitStruct); + HAL_MPU_ConfigRegion(&MPU_InitStruct); + index++; + + /* Reset unused MPU regions */ + for(; index < __MPU_REGIONCOUNT ; index++) + { + /* All unused regions disabled */ + MPU_InitStruct.Enable = MPU_REGION_DISABLE; + MPU_InitStruct.Number = index; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + } + + /* Enable the MPU */ + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); +} + +/** + * @brief This function adjusts the MPU region Address and Size within an MPU configuration. + * @param Address memory address + * @param Size memory size + * @param pInit pointer to an MPU initialization structure + * @retval None + */ +static void MPU_AdjustRegionAddressSize(uint32_t Address, uint32_t Size, MPU_Region_InitTypeDef* pInit) +{ + /* Compute the MPU region size */ + pInit->Size = ((31 - __CLZ(Size)) - 1); + if (Size > (1u << (pInit->Size + 1))) + { + pInit->Size++; + } + uint32_t Modulo = Address % (1 << (pInit->Size - 1)); + if (0 != Modulo) + { + /* Align address with MPU region size considering there is no need to increase the size */ + pInit->BaseAddress = Address - Modulo; + } + else + { + pInit->BaseAddress = Address; + } +} + void board_init(void) { + HAL_Init(); + + MPU_Config(); SCB_EnableICache(); SCB_EnableDCache(); - HAL_Init(); - HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); // Implemented in board.h diff --git a/hw/bsp/stm32h7rs/family.cmake b/hw/bsp/stm32h7rs/family.cmake index e70d37777..6b7915c93 100644 --- a/hw/bsp/stm32h7rs/family.cmake +++ b/hw/bsp/stm32h7rs/family.cmake @@ -87,7 +87,8 @@ function(add_board_target BOARD_TARGET) BOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} BOARD_TUH_RHPORT=${RHPORT_HOST} BOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} - SEGGER_RTT_SECTION=\"dtcm_data\" + SEGGER_RTT_SECTION=\"noncacheable_buffer\" + BUFFER_SIZE_UP=0x300 ) update_board(${BOARD_TARGET}) diff --git a/hw/bsp/stm32h7rs/family.mk b/hw/bsp/stm32h7rs/family.mk index c60a5c00d..45d4da0cf 100644 --- a/hw/bsp/stm32h7rs/family.mk +++ b/hw/bsp/stm32h7rs/family.mk @@ -43,7 +43,8 @@ CFLAGS += \ -DBOARD_TUD_MAX_SPEED=${RHPORT_DEVICE_SPEED} \ -DBOARD_TUH_RHPORT=${RHPORT_HOST} \ -DBOARD_TUH_MAX_SPEED=${RHPORT_HOST_SPEED} \ - -DSEGGER_RTT_SECTION="dtcm_data" \ + -DSEGGER_RTT_SECTION="noncacheable_buffer" \ + -DBUFFER_SIZE_UP=0x300 \ # GCC Flags CFLAGS_GCC += \ diff --git a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf index 8398fa07b..786be3560 100644 --- a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf +++ b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf @@ -51,5 +51,5 @@ place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; place in ROM_region { readonly }; place in RAM_region { readwrite }; -place in DTCM_region { block CSTACK, block HEAP, section dtcm_data }; +place in DTCM_region { block CSTACK, block HEAP }; place in NONCACHEABLE_region { section noncacheable_buffer }; diff --git a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld index b33838180..a96e1f211 100644 --- a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld +++ b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld @@ -196,11 +196,6 @@ SECTIONS . = ALIGN(8); } >DTCM - .dtcm_data : - { - *(dtcm_data) - } >DTCM - /* Remove information from the compiler libraries */ /DISCARD/ : { From 6e88895dbc2b09e60b971f1587d19d3a2487c2f8 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Jul 2025 11:26:48 +0700 Subject: [PATCH 095/101] always define CFG_TUH_WCH_USBIP_USBFS=1 for ch32v20x since only port1 support host mode reformat hcd usbfs add uart rx for ch32v20x bsp --- hw/bsp/ch32v20x/family.c | 91 +-- hw/bsp/ch32v20x/family.cmake | 28 +- src/common/tusb_mcu.h | 8 +- src/portable/wch/dcd_ch32_usbhs.c | 2 +- src/portable/wch/hcd_ch32_usbfs.c | 931 +++++++++++++----------------- 5 files changed, 483 insertions(+), 577 deletions(-) diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 2c212a82b..510f82981 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -20,59 +20,56 @@ manufacturer: WCH #include "bsp/board_api.h" #include "board.h" -/* CH32v203 depending on variants can support 2 USB IPs: FSDEV and USBFS. +/* CH32v203 depending on variants can support 2 USB IPs: FSDEV (port0) and USBFS (port1). * By default, we use FSDEV, but you can explicitly select by define: * - CFG_TUD_WCH_USBIP_FSDEV * - CFG_TUD_WCH_USBIP_USBFS */ -// USBFS -__attribute__((interrupt)) __attribute__((used)) -void USBHD_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_USBFS +// Port0: USBD (fsdev) +__attribute__((interrupt)) __attribute__((used)) void USB_LP_CAN1_RX0_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV tud_int_handler(0); #endif - #if defined(CFG_TUH_WCH_USBIP_USBFS) && CFG_TUH_WCH_USBIP_USBFS - tuh_int_handler(0); - #endif } -__attribute__((interrupt)) __attribute__((used)) -void USBHDWakeUp_IRQHandler(void) { +__attribute__((interrupt)) __attribute__((used)) void USB_HP_CAN1_TX_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV + tud_int_handler(0); + #endif + +} + +__attribute__((interrupt)) __attribute__((used)) void USBWakeUp_IRQHandler(void) { + #if CFG_TUD_WCH_USBIP_FSDEV + tud_int_handler(0); + #endif +} + +// Port1: USBFS +__attribute__((interrupt)) __attribute__((used)) void USBHD_IRQHandler(void) { + #if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_USBFS + tud_int_handler(1); + #endif + + #if CFG_TUH_ENABLED + tuh_int_handler(1); + #endif +} + +__attribute__((interrupt)) __attribute__((used)) void USBHDWakeUp_IRQHandler(void) { #if CFG_TUD_WCH_USBIP_USBFS tud_int_handler(0); #endif } -// USBD (fsdev) -__attribute__((interrupt)) __attribute__((used)) -void USB_LP_CAN1_RX0_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif -} - -__attribute__((interrupt)) __attribute__((used)) -void USB_HP_CAN1_TX_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif - -} - -__attribute__((interrupt)) __attribute__((used)) -void USBWakeUp_IRQHandler(void) { - #if CFG_TUD_WCH_USBIP_FSDEV - tud_int_handler(0); - #endif -} - - +//--------------------------------------------------------------------+ +// Board API +//--------------------------------------------------------------------+ #if CFG_TUSB_OS == OPT_OS_NONE volatile uint32_t system_ticks = 0; -__attribute__((interrupt)) -void SysTick_Handler(void) { +__attribute__((interrupt)) void SysTick_Handler(void) { SysTick->SR = 0; system_ticks++; } @@ -111,7 +108,7 @@ void board_init(void) { #ifdef UART_DEV UART_CLOCK_EN(); GPIO_InitTypeDef usart_init = { - .GPIO_Pin = UART_TX_PIN, + .GPIO_Pin = UART_TX_PIN | UART_RX_PIN, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_AF_PP, }; @@ -122,7 +119,7 @@ void board_init(void) { .USART_WordLength = USART_WordLength_8b, .USART_StopBits = USART_StopBits_1, .USART_Parity = USART_Parity_No, - .USART_Mode = USART_Mode_Tx, + .USART_Mode = USART_Mode_Tx | USART_Mode_Rx, .USART_HardwareFlowControl = USART_HardwareFlowControl_None, }; USART_Init(UART_DEV, &usart); @@ -192,9 +189,19 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { } int board_uart_read(uint8_t *buf, int len) { - (void) buf; - (void) len; +#ifdef UART_DEV + int count; + for (count = 0; count < len; count++) { + if (USART_GetFlagStatus(UART_DEV, USART_FLAG_RXNE) == RESET) { + break; + } + buf[count] = USART_ReceiveData(UART_DEV); + } + return count; +#else + (void) buf; (void) len; return 0; +#endif } int board_uart_write(void const *buf, int len) { @@ -210,7 +217,3 @@ int board_uart_write(void const *buf, int len) { return len; } - -//-------------------------------------------------------------------- -// Neopixel -//-------------------------------------------------------------------- diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index 6092abc8d..10044d5b3 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -16,9 +16,12 @@ set(FAMILY_MCUS CH32V20X CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") # Port0 use FSDev, Port1 use USBFS -if (NOT DEFINED PORT) - set(PORT 0) -endif() +if (NOT DEFINED RHPORT_DEVICE) + set(RHPORT_DEVICE 0) +endif () + +# only port1 support host mode +set(RHPORT_HOST 1) #------------------------------------ # BOARD_TARGET @@ -56,19 +59,16 @@ function(add_board_target BOARD_TARGET) ) target_compile_definitions(${BOARD_TARGET} PUBLIC CH32V20x_${MCU_VARIANT} + BOARD_TUD_RHPORT=${RHPORT_DEVICE} + BOARD_TUH_RHPORT=${RHPORT_HOST} ) - if (PORT EQUAL 0) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CFG_TUD_WCH_USBIP_FSDEV=1 - CFG_TUH_WCH_USBIP_USBFS=1 - ) - elseif (PORT EQUAL 1) - target_compile_definitions(${BOARD_TARGET} PUBLIC - CFG_TUD_WCH_USBIP_USBFS=1 - ) + if (RHPORT_DEVICE EQUAL 0) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUD_WCH_USBIP_FSDEV=1) + elseif (RHPORT_DEVICE EQUAL 1) + target_compile_definitions(${BOARD_TARGET} PUBLIC CFG_TUH_WCH_USBIP_USBFS=1) else() - message(FATAL_ERROR "Invalid PORT ${PORT}") + message(FATAL_ERROR "Invalid RHPORT_DEVICE ${RHPORT_DEVICE}") endif() update_board(${BOARD_TARGET}) @@ -133,8 +133,6 @@ function(family_configure_example TARGET RTOS) ) target_link_libraries(${TARGET} PUBLIC board_${BOARD}) - - # Flashing family_add_bin_hex(${TARGET}) family_flash_openocd_wch(${TARGET}) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 2ee2132bf..a08ed79c8 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -503,11 +503,17 @@ #define TUP_DCD_ENDPOINT_MAX 8 #elif TU_CHECK_MCU(OPT_MCU_CH32V20X) - // v20x support both FSDEV (USBD) and USBFS, default to FSDEV + // v20x support both port0 FSDEV (USBD) and port1 USBFS #define TUP_USBIP_WCH_USBFS + + #ifndef CFG_TUH_WCH_USBIP_USBFS + #define CFG_TUH_WCH_USBIP_USBFS 1 + #endif + #define TUP_USBIP_FSDEV #define TUP_USBIP_FSDEV_CH32 + // default to FSDEV for device #if !defined(CFG_TUD_WCH_USBIP_USBFS) #define CFG_TUD_WCH_USBIP_USBFS 0 #endif diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index f8bf3c889..4a208b9df 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -27,7 +27,7 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && defined(CFG_TUD_WCH_USBIP_USBHS) && CFG_TUD_WCH_USBIP_USBHS #include "ch32_usbhs_reg.h" #include "device/dcd.h" diff --git a/src/portable/wch/hcd_ch32_usbfs.c b/src/portable/wch/hcd_ch32_usbfs.c index 800390989..d176f40c5 100644 --- a/src/portable/wch/hcd_ch32_usbfs.c +++ b/src/portable/wch/hcd_ch32_usbfs.c @@ -37,20 +37,20 @@ #include "ch32v20x.h" #include "ch32v20x_usb.h" -void osal_task_delay(uint32_t msec) { - uint32_t start = board_millis(); - while (board_millis() - start < msec) {} -} - #define USBFS_RX_BUF_LEN 64 #define USBFS_TX_BUF_LEN 64 -__attribute__((aligned(4))) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; -__attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; +TU_ATTR_ALIGNED(4) static uint8_t USBFS_RX_Buf[USBFS_RX_BUF_LEN]; +TU_ATTR_ALIGNED(4) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; #define USB_XFER_TIMEOUT_MILLIS 100 // #define USB_INTERRUPT_XFER_TIMEOUT_MILLIS 1 -#define PANIC(...) do { printf("%s() L%d: ", __func__, __LINE__); printf("\r\n[PANIC] " __VA_ARGS__); while (true) { } } while (false) +#define PANIC(...) \ + do { \ + printf("%s() L%d: ", __func__, __LINE__); \ + printf("\r\n[PANIC] " __VA_ARGS__); \ + while (true) {} \ + } while (false) #define LOG_CH32_USBFSH(...) TU_LOG3(__VA_ARGS__) @@ -70,106 +70,87 @@ __attribute__((aligned(4))) static uint8_t USBFS_TX_Buf[USBFS_TX_BUF_LEN]; // Endpoint status -typedef struct usb_edpt -{ - // Is this a valid struct - bool configured; +typedef struct usb_edpt { + // Is this a valid struct + bool configured; - uint8_t dev_addr; - uint8_t ep_addr; - uint8_t max_packet_size; + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t max_packet_size; - uint8_t xfer_type; + uint8_t xfer_type; - // Data toggle (0 or not 0) for DATA0/1 - uint8_t data_toggle; + // Data toggle (0 or not 0) for DATA0/1 + uint8_t data_toggle; } usb_edpt_t; - static usb_edpt_t usb_edpt_list[CFG_TUH_DEVICE_MAX * 6] = {}; - typedef struct usb_current_xfer_st { - bool is_busy; - uint8_t dev_addr; - uint8_t ep_addr; - // Xfer started time in millis for timeout - uint32_t start_ms; - uint8_t* buffer; - uint16_t bufferlen; - uint16_t xferred_len; + bool is_busy; + uint8_t dev_addr; + uint8_t ep_addr; + // Xfer started time in millis for timeout + uint32_t start_ms; + uint8_t *buffer; + uint16_t bufferlen; + uint16_t xferred_len; } usb_current_xfer_t; static volatile usb_current_xfer_t usb_current_xfer_info = {}; - -static usb_edpt_t* get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - usb_edpt_t* cur = &usb_edpt_list[i]; - if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) - { - return cur; - } +static usb_edpt_t *get_edpt_record(uint8_t dev_addr, uint8_t ep_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + usb_edpt_t *cur = &usb_edpt_list[i]; + if (cur->configured && cur->dev_addr == dev_addr && cur->ep_addr == ep_addr) { + return cur; } - return NULL; + } + return NULL; } -static usb_edpt_t* get_empty_record_slot(void) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - if (!usb_edpt_list[i].configured) - { - return &usb_edpt_list[i]; - } +static usb_edpt_t *get_empty_record_slot(void) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + if (!usb_edpt_list[i].configured) { + return &usb_edpt_list[i]; } - return NULL; + } + return NULL; } -static usb_edpt_t* add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) -{ - usb_edpt_t* slot = get_empty_record_slot(); - if (slot == NULL) { - PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); - } - TU_ASSERT(slot != NULL, NULL); +static usb_edpt_t *add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { + usb_edpt_t *slot = get_empty_record_slot(); + if (slot == NULL) { + PANIC("add_edpt_record(0x%02x, 0x%02x, ...) no slot for new record\r\n", dev_addr, ep_addr); + } + TU_ASSERT(slot != NULL, NULL); - slot->dev_addr = dev_addr; - slot->ep_addr = ep_addr; - slot->max_packet_size = max_packet_size; - slot->xfer_type = xfer_type; - slot->data_toggle = 0; + slot->dev_addr = dev_addr; + slot->ep_addr = ep_addr; + slot->max_packet_size = max_packet_size; + slot->xfer_type = xfer_type; + slot->data_toggle = 0; - slot->configured = true; + slot->configured = true; - return slot; + return slot; } -static usb_edpt_t* get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) -{ - usb_edpt_t* ret = get_edpt_record(dev_addr, ep_addr); - if (ret != NULL) - { - return ret; - } - else - { - return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); - } +static usb_edpt_t *get_or_add_edpt_record(uint8_t dev_addr, uint8_t ep_addr, uint16_t max_packet_size, uint8_t xfer_type) { + usb_edpt_t *ret = get_edpt_record(dev_addr, ep_addr); + if (ret != NULL) { + return ret; + } else { + return add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type); + } } - -static void remove_edpt_record_for_device(uint8_t dev_addr) -{ - for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) - { - if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) - { - usb_edpt_list[i].configured = false; - } +static void remove_edpt_record_for_device(uint8_t dev_addr) { + for (size_t i = 0; i < TU_ARRAY_SIZE(usb_edpt_list); i++) { + if (usb_edpt_list[i].configured && usb_edpt_list[i].dev_addr == dev_addr) { + usb_edpt_list[i].configured = false; } + } } // static void dump_edpt_record_list() { @@ -183,544 +164,462 @@ static void remove_edpt_record_for_device(uint8_t dev_addr) // } // } - static bool interrupt_enabled = false; /** Enable or disable USBFS Host function */ -static void hardware_init_host(bool enabled) -{ - // Reset USBOTG module - USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; +static void hardware_init_host(bool enabled) { + // Reset USBOTG module + USBOTG_H_FS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; - osal_task_delay(1); + tusb_time_delay_ms_api(1); + USBOTG_H_FS->BASE_CTRL = 0; + + if (!enabled) { + // Disable all feature USBOTG_H_FS->BASE_CTRL = 0; - - if (!enabled) - { - // Disable all feature - USBOTG_H_FS->BASE_CTRL = 0; - } - else - { - // Enable USB Host features - // NVIC_DisableIRQ(USBFS_IRQn); - hcd_int_disable(0); - USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; - USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; - USBOTG_H_FS->HOST_RX_DMA = (uint32_t)USBFS_RX_Buf; - USBOTG_H_FS->HOST_TX_DMA = (uint32_t)USBFS_TX_Buf; - // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; - USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; - } + } else { + // Enable USB Host features + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(0); + USBOTG_H_FS->BASE_CTRL = USBFS_UC_HOST_MODE | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; + USBOTG_H_FS->HOST_EP_MOD = USBFS_UH_EP_TX_EN | USBFS_UH_EP_RX_EN; + USBOTG_H_FS->HOST_RX_DMA = (uint32_t) USBFS_RX_Buf; + USBOTG_H_FS->HOST_TX_DMA = (uint32_t) USBFS_TX_Buf; + // USBOTG_H_FS->INT_EN = USBFS_UIE_TRANSFER | USBFS_UIE_DETECT; + USBOTG_H_FS->INT_EN = USBFS_UIE_DETECT; + } } -static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) -{ - LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", - pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" : pid == USB_PID_SETUP ? "SETUP" : "(other)", - pid, ep_addr, data_toggle); +static bool hardware_start_xfer(uint8_t pid, uint8_t ep_addr, uint8_t data_toggle) { + LOG_CH32_USBFSH("hardware_start_xfer(pid=%s(0x%02x), ep_addr=0x%02x, toggle=%d)\r\n", + pid == USB_PID_IN ? "IN" : pid == USB_PID_OUT ? "OUT" + : pid == USB_PID_SETUP ? "SETUP" + : "(other)", + pid, ep_addr, data_toggle); - // if (pid == USB_PID_IN) - // { // FIXME: long delay needed (at release build) about 30msec - // loopdelay(SystemCoreClock / 1000 * 30); - // } + // if (pid == USB_PID_IN) + // { // FIXME: long delay needed (at release build) about 30msec + // loopdelay(SystemCoreClock / 1000 * 30); + // } - uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); - USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; - USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; - USBOTG_H_FS->HOST_EP_PID = pid_edpt; - USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; - USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; - return true; + uint8_t pid_edpt = (pid << 4) | (tu_edpt_number(ep_addr) & 0x0f); + USBOTG_H_FS->HOST_TX_CTRL = (data_toggle != 0) ? USBFS_UH_T_TOG : 0; + USBOTG_H_FS->HOST_RX_CTRL = (data_toggle != 0) ? USBFS_UH_R_TOG : 0; + USBOTG_H_FS->HOST_EP_PID = pid_edpt; + USBOTG_H_FS->INT_EN |= USBFS_UIE_TRANSFER; + USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + return true; } /** Set device address to communicate */ -static void hardware_update_device_address(uint8_t dev_addr) -{ - // Keep the bit of GP_BIT. Other 7bits are actual device address. - USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); +static void hardware_update_device_address(uint8_t dev_addr) { + // Keep the bit of GP_BIT. Other 7bits are actual device address. + USBOTG_H_FS->DEV_ADDR = (USBOTG_H_FS->DEV_ADDR & USBFS_UDA_GP_BIT) | (dev_addr & USBFS_USB_ADDR_MASK); } /** Set port speed */ -static void hardware_update_port_speed(tusb_speed_t speed) -{ - LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" : "(invalid)"); - switch (speed) { +static void hardware_update_port_speed(tusb_speed_t speed) { + LOG_CH32_USBFSH("hardware_update_port_speed(%s)\r\n", speed == TUSB_SPEED_FULL ? "Full" : speed == TUSB_SPEED_LOW ? "Low" + : "(invalid)"); + switch (speed) { case TUSB_SPEED_LOW: - USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; - return; + USBOTG_H_FS->BASE_CTRL |= USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_PRE_PID_EN; + return; case TUSB_SPEED_FULL: - USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; - USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; - return; + USBOTG_H_FS->BASE_CTRL &= ~USBFS_UC_LOW_SPEED; + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + USBOTG_H_FS->HOST_SETUP &= ~USBFS_UH_PRE_PID_EN; + return; default: - PANIC("hardware_update_port_speed(%d)\r\n", speed); - } + PANIC("hardware_update_port_speed(%d)\r\n", speed); + } } - static void hardware_set_port_address_speed(uint8_t dev_addr) { - hardware_update_device_address(dev_addr); - tusb_speed_t rhport_speed = hcd_port_speed_get(0); - tusb_speed_t dev_speed = tuh_speed_get(dev_addr); - hardware_update_port_speed(dev_speed); - if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; - } + hardware_update_device_address(dev_addr); + tusb_speed_t rhport_speed = hcd_port_speed_get(0); + tusb_speed_t dev_speed = tuh_speed_get(dev_addr); + hardware_update_port_speed(dev_speed); + if (rhport_speed == TUSB_SPEED_FULL && dev_speed == TUSB_SPEED_LOW) { + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_LOW_SPEED; + } } - -static bool hardware_device_attached(void) -{ - return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; +static bool hardware_device_attached(void) { + return USBOTG_H_FS->MIS_ST & USBFS_UMS_DEV_ATTACH; } - //--------------------------------------------------------------------+ // HCD API //--------------------------------------------------------------------+ -bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) -{ - (void)rhport; - (void)rh_init; - hardware_init_host(true); +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { + (void) rhport; + (void) rh_init; + hardware_init_host(true); - return true; + return true; } -bool hcd_deinit(uint8_t rhport) -{ - (void)rhport; - hardware_init_host(false); +bool hcd_deinit(uint8_t rhport) { + (void) rhport; + hardware_init_host(false); - return true; + return true; } - static bool int_state_for_portreset = false; -void hcd_port_reset(uint8_t rhport) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_port_reset()\r\n"); - int_state_for_portreset = interrupt_enabled; - // NVIC_DisableIRQ(USBFS_IRQn); - hcd_int_disable(rhport); - hardware_update_device_address(0x00); +void hcd_port_reset(uint8_t rhport) { + (void) rhport; + LOG_CH32_USBFSH("hcd_port_reset()\r\n"); + int_state_for_portreset = interrupt_enabled; + // NVIC_DisableIRQ(USBFS_IRQn); + hcd_int_disable(rhport); + hardware_update_device_address(0x00); - // USBOTG_H_FS->HOST_SETUP = 0x00; + // USBOTG_H_FS->HOST_SETUP = 0x00; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_BUS_RESET; - return; + return; } -void hcd_port_reset_end(uint8_t rhport) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; + LOG_CH32_USBFSH("hcd_port_reset_end()\r\n"); - USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; - osal_task_delay(2); + USBOTG_H_FS->HOST_CTRL &= ~USBFS_UH_BUS_RESET; + tusb_time_delay_ms_api(2); - if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) - { - if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) - { - hardware_update_port_speed(TUSB_SPEED_LOW); - } + if ((USBOTG_H_FS->HOST_CTRL & USBFS_UH_PORT_EN) == 0) { + if (hcd_port_speed_get(0) == TUSB_SPEED_LOW) { + hardware_update_port_speed(TUSB_SPEED_LOW); } + } - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - // Suppress the attached event - USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; + // Suppress the attached event + USBOTG_H_FS->INT_FG |= USBFS_UIF_DETECT; - if (int_state_for_portreset) { - hcd_int_enable(rhport); - } - - return; + if (int_state_for_portreset) { + hcd_int_enable(rhport); + } } -bool hcd_port_connect_status(uint8_t rhport) -{ - (void)rhport; +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; - return hardware_device_attached(); + return hardware_device_attached(); } -tusb_speed_t hcd_port_speed_get(uint8_t rhport) -{ - (void)rhport; - if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) - { - return TUSB_SPEED_LOW; - } - else - { - return TUSB_SPEED_FULL; - } +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + if (USBOTG_H_FS->MIS_ST & USBFS_UMS_DM_LEVEL) { + return TUSB_SPEED_LOW; + } else { + return TUSB_SPEED_FULL; + } } // Close all opened endpoint belong to this device -void hcd_device_close(uint8_t rhport, uint8_t dev_addr) -{ - (void)rhport; - LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); - remove_edpt_record_for_device(dev_addr); +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + LOG_CH32_USBFSH("hcd_device_close(%d, 0x%02x)\r\n", rhport, dev_addr); + remove_edpt_record_for_device(dev_addr); +} +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + + return board_millis(); +} + +void hcd_int_enable(uint8_t rhport) { + (void) rhport; + NVIC_EnableIRQ(USBFS_IRQn); + interrupt_enabled = true; +} + +void hcd_int_disable(uint8_t rhport) { + (void) rhport; + NVIC_DisableIRQ(USBFS_IRQn); + interrupt_enabled = false; +} + +void hcd_int_handler(uint8_t rhport, bool in_isr) { + (void) rhport; + (void) in_isr; + + if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) { + // Clear the flag + USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; + // Read the detection state + bool attached = hardware_device_attached(); + LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); + if (attached) { + hcd_event_device_attach(rhport, true); + } else { + hcd_event_device_remove(rhport, true); + } return; -} + } -uint32_t hcd_frame_number(uint8_t rhport) -{ - (void)rhport; + if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) { + // Disable transfer interrupt + USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; + // Clear the flag + // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; + // Copy PID and Endpoint + uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; + uint8_t status = USBOTG_H_FS->INT_ST; + uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; + // Clear register to stop transfer + // USBOTG_H_FS->HOST_EP_PID = 0x00; - return board_millis(); -} + LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); -void hcd_int_enable(uint8_t rhport) -{ - (void)rhport; - NVIC_EnableIRQ(USBFS_IRQn); - interrupt_enabled = true; + uint8_t request_pid = pid_edpt >> 4; + uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; + uint8_t ep_addr = pid_edpt & 0x0f; + if (request_pid == USB_PID_IN) { + ep_addr |= 0x80; + } - return; -} + usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) { + PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); + } -void hcd_int_disable(uint8_t rhport) -{ - (void)rhport; - NVIC_DisableIRQ(USBFS_IRQn); - interrupt_enabled = false; + if (status & USBFS_UIS_TOG_OK) { + edpt_info->data_toggle ^= 0x01; - return; -} - -void hcd_int_handler(uint8_t rhport, bool in_isr) -{ - (void)rhport; - (void)in_isr; - - if (USBOTG_H_FS->INT_FG & USBFS_UIF_DETECT) - { - // Clear the flag - USBOTG_H_FS->INT_FG = USBFS_UIF_DETECT; - // Read the detection state - bool attached = hardware_device_attached(); - LOG_CH32_USBFSH("hcd_int_handler() attached = %d\r\n", attached ? 1 : 0); - if (attached) - { - hcd_event_device_attach(rhport, true); + switch (request_pid) { + case USB_PID_SETUP: + case USB_PID_OUT: { + uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; + usb_current_xfer_info.bufferlen -= tx_len; + usb_current_xfer_info.xferred_len += tx_len; + if (usb_current_xfer_info.bufferlen == 0) { + LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); + return; + } else { + LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); + usb_current_xfer_info.buffer += tx_len; + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > usb_current_xfer_info.bufferlen) { + copylen = usb_current_xfer_info.bufferlen; + } + memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); + hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + return; + } } - else - { - hcd_event_device_remove(rhport, true); + case USB_PID_IN: { + uint16_t received_len = USBOTG_H_FS->RX_LEN; + usb_current_xfer_info.xferred_len += received_len; + uint16_t xferred_len = usb_current_xfer_info.xferred_len; + LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); + // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { + // PANIC("Data received but buffer not set\r\n"); + // } + memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); + usb_current_xfer_info.buffer += received_len; + if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) { + // USB device sent all data. + LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); + return; + } else { + // USB device may send more data. + LOG_CH32_USBFSH("Read more data\r\n"); + hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + return; + } + } + default: { + PANIC("Unknown PID: 0x%02x\n", request_pid); + } + } + } else { + if (response_pid == USB_PID_STALL) { + LOG_CH32_USBFSH("STALL response\r\n"); + hcd_edpt_clear_stall(0, dev_addr, ep_addr); + edpt_info->data_toggle = 0; + hardware_start_xfer(request_pid, ep_addr, 0); + return; + } else if (response_pid == USB_PID_NAK) { + LOG_CH32_USBFSH("NAK reposense\r\n"); + uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; + if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); + } else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) { + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + } else { + hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); } return; + } else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) { + LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } else { + LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); + usb_current_xfer_info.is_busy = false; + hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); + return; + } } - - if (USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) - { - // Disable transfer interrupt - USBOTG_H_FS->INT_EN &= ~USBFS_UIE_TRANSFER; - // Clear the flag - // USBOTG_H_FS->INT_FG = USBFS_UIF_TRANSFER; - // Copy PID and Endpoint - uint8_t pid_edpt = USBOTG_H_FS->HOST_EP_PID; - uint8_t status = USBOTG_H_FS->INT_ST; - uint8_t dev_addr = USBOTG_H_FS->DEV_ADDR & USBFS_USB_ADDR_MASK; - // Clear register to stop transfer - // USBOTG_H_FS->HOST_EP_PID = 0x00; - - LOG_CH32_USBFSH("hcd_int_handler() pid_edpt=0x%02x\r\n", pid_edpt); - - uint8_t request_pid = pid_edpt >> 4; - uint8_t response_pid = status & USBFS_UIS_H_RES_MASK; - uint8_t ep_addr = pid_edpt & 0x0f; - if (request_pid == USB_PID_IN) - { - ep_addr |= 0x80; - } - - usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); - if (edpt_info == NULL) - { - PANIC("\r\nget_edpt_record(0x%02x, 0x%02x) returned NULL in USBHD_IRQHandler\r\n", dev_addr, ep_addr); - } - - if (status & USBFS_UIS_TOG_OK) - { - edpt_info->data_toggle ^= 0x01; - - switch (request_pid) - { - case USB_PID_SETUP: - case USB_PID_OUT: - { - uint16_t tx_len = USBOTG_H_FS->HOST_TX_LEN; - usb_current_xfer_info.bufferlen -= tx_len; - usb_current_xfer_info.xferred_len += tx_len; - if (usb_current_xfer_info.bufferlen == 0) - { - LOG_CH32_USBFSH("USB_PID_%s completed %d bytes\r\n", request_pid == USB_PID_OUT ? "OUT" : "SETUP", usb_current_xfer_info.xferred_len); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, usb_current_xfer_info.xferred_len, XFER_RESULT_SUCCESS, true); - return; - } - else - { - LOG_CH32_USBFSH("USB_PID_OUT continue...\r\n"); - usb_current_xfer_info.buffer += tx_len; - uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > usb_current_xfer_info.bufferlen) - { - copylen = usb_current_xfer_info.bufferlen; - } - memcpy(USBFS_TX_Buf, usb_current_xfer_info.buffer, copylen); - hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); - return; - } - } - case USB_PID_IN: - { - uint16_t received_len = USBOTG_H_FS->RX_LEN; - usb_current_xfer_info.xferred_len += received_len; - uint16_t xferred_len = usb_current_xfer_info.xferred_len; - LOG_CH32_USBFSH("Read %d bytes\r\n", received_len); - // if (received_len > 0 && (usb_current_xfer_info.buffer == NULL || usb_current_xfer_info.bufferlen == 0)) { - // PANIC("Data received but buffer not set\r\n"); - // } - memcpy(usb_current_xfer_info.buffer, USBFS_RX_Buf, received_len); - usb_current_xfer_info.buffer += received_len; - if ((received_len < edpt_info->max_packet_size) || (xferred_len == usb_current_xfer_info.bufferlen)) - { - // USB device sent all data. - LOG_CH32_USBFSH("USB_PID_IN completed\r\n"); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, XFER_RESULT_SUCCESS, true); - return; - } - else - { - // USB device may send more data. - LOG_CH32_USBFSH("Read more data\r\n"); - hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); - return; - } - } - default: - { - PANIC("Unknown PID: 0x%02x\n", request_pid); - } - } - } - else - { - if (response_pid == USB_PID_STALL) - { - LOG_CH32_USBFSH("STALL response\r\n"); - hcd_edpt_clear_stall(0, dev_addr, ep_addr); - edpt_info->data_toggle = 0; - hardware_start_xfer(request_pid, ep_addr, 0); - return; - } - else if (response_pid == USB_PID_NAK) - { - LOG_CH32_USBFSH("NAK reposense\r\n"); - uint32_t elapsed_time = board_millis() - usb_current_xfer_info.start_ms; - if (edpt_info->xfer_type == TUSB_XFER_INTERRUPT) - { - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_SUCCESS, true); - } - else if (elapsed_time > USB_XFER_TIMEOUT_MILLIS) - { - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - } - else - { - hardware_start_xfer(request_pid, ep_addr, edpt_info->data_toggle); - } - return; - } - else if (response_pid == USB_PID_DATA0 || response_pid == USB_PID_DATA1) - { - LOG_CH32_USBFSH("Data toggle mismatched and DATA0/1 (not STALL). RX_LEN=%d\r\n", USBOTG_H_FS->RX_LEN); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - return; - } - else - { - LOG_CH32_USBFSH("In USBHD_IRQHandler, unexpected response PID: 0x%02x\r\n", response_pid); - usb_current_xfer_info.is_busy = false; - hcd_event_xfer_complete(dev_addr, ep_addr, 0, XFER_RESULT_FAILED, true); - return; - } - } - } + } } //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ -bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc) -{ - (void)rhport; - uint8_t ep_addr = ep_desc->bEndpointAddress; - uint8_t ep_num = tu_edpt_number(ep_addr); - uint16_t max_packet_size = ep_desc->wMaxPacketSize; - uint8_t xfer_type = ep_desc->bmAttributes.xfer; - LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) { + (void) rhport; + uint8_t ep_addr = ep_desc->bEndpointAddress; + uint8_t ep_num = tu_edpt_number(ep_addr); + uint16_t max_packet_size = ep_desc->wMaxPacketSize; + uint8_t xfer_type = ep_desc->bmAttributes.xfer; + LOG_CH32_USBFSH("hcd_edpt_open(rhport=%d, dev_addr=0x%02x, %p) EndpointAdderss=0x%02x,maxPacketSize=%d,xfer_type=%d\r\n", rhport, dev_addr, ep_desc, ep_addr, max_packet_size, xfer_type); - if (ep_num == 0x00) - { - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); - TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); - } - else - { - TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); - } + if (ep_num == 0x00) { + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x00, max_packet_size, xfer_type) != NULL, false); + TU_ASSERT(get_or_add_edpt_record(dev_addr, 0x80, max_packet_size, xfer_type) != NULL, false); + } else { + TU_ASSERT(get_or_add_edpt_record(dev_addr, ep_addr, max_packet_size, xfer_type) != NULL, false); + } + USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; + USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; - USBOTG_H_FS->HOST_CTRL |= USBFS_UH_PORT_EN; - USBOTG_H_FS->HOST_SETUP |= USBFS_UH_SOF_EN; + hardware_set_port_address_speed(dev_addr); - hardware_set_port_address_speed(dev_addr); - - return true; + return true; } -bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) -{ - (void)rhport; +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { + (void) rhport; - LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); + LOG_CH32_USBFSH("hcd_edpt_xfer(%d, 0x%02x, 0x%02x, ...)\r\n", rhport, dev_addr, ep_addr); - while (usb_current_xfer_info.is_busy) { } + while (usb_current_xfer_info.is_busy) {} + usb_current_xfer_info.is_busy = true; - usb_current_xfer_info.is_busy = true; + usb_edpt_t *edpt_info = get_edpt_record(dev_addr, ep_addr); + if (edpt_info == NULL) { + PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); + } - usb_edpt_t* edpt_info = get_edpt_record(dev_addr, ep_addr); - if (edpt_info == NULL) - { - PANIC("get_edpt_record() returned NULL in hcd_edpt_xfer()\r\n"); - } - - hardware_set_port_address_speed(dev_addr); - - usb_current_xfer_info.dev_addr = dev_addr; - usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.buffer = buffer; - usb_current_xfer_info.bufferlen = buflen; - usb_current_xfer_info.start_ms = board_millis(); - usb_current_xfer_info.xferred_len = 0; - - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) - { - LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); - return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); - } - else - { - LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); - uint16_t copylen = USBFS_TX_BUF_LEN; - if (copylen > buflen) - { - copylen = buflen; - } - USBOTG_H_FS->HOST_TX_LEN = copylen; - memcpy(USBFS_TX_Buf, buffer, copylen); - return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + hardware_set_port_address_speed(dev_addr); + + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.buffer = buffer; + usb_current_xfer_info.bufferlen = buflen; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.xferred_len = 0; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + LOG_CH32_USBFSH("hcd_edpt_xfer(): READ, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); + return hardware_start_xfer(USB_PID_IN, ep_addr, edpt_info->data_toggle); + } else { + LOG_CH32_USBFSH("hcd_edpt_xfer(): WRITE, dev_addr=0x%02x, ep_addr=0x%02x, len=%d\r\n", dev_addr, ep_addr, buflen); + uint16_t copylen = USBFS_TX_BUF_LEN; + if (copylen > buflen) { + copylen = buflen; } + USBOTG_H_FS->HOST_TX_LEN = copylen; + memcpy(USBFS_TX_Buf, buffer, copylen); + return hardware_start_xfer(USB_PID_OUT, ep_addr, edpt_info->data_toggle); + } } -bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) -{ - (void) rhport; - (void) dev_addr; - (void) ep_addr; +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; - return false; + return false; } -bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) -{ - (void)rhport; - - while (usb_current_xfer_info.is_busy) { } +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; - usb_current_xfer_info.is_busy = true; + while (usb_current_xfer_info.is_busy) {} - LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); + usb_current_xfer_info.is_busy = true; - hardware_set_port_address_speed(dev_addr); + LOG_CH32_USBFSH("hcd_setup_send(rhport=%d, dev_addr=0x%02x, %p)\r\n", rhport, dev_addr, setup_packet); - usb_edpt_t* edpt_info_tx = get_edpt_record(dev_addr, 0x00); - usb_edpt_t* edpt_info_rx = get_edpt_record(dev_addr, 0x80); - TU_ASSERT(edpt_info_tx != NULL, false); - TU_ASSERT(edpt_info_rx != NULL, false); + hardware_set_port_address_speed(dev_addr); - // Initialize data toggle (SETUP always starts with DATA0) - // Data toggle for OUT is toggled in hcd_int_handler() - edpt_info_tx->data_toggle = 0; - // Data toggle for IN must be set 0x01 manually. - edpt_info_rx->data_toggle = 0x01; - const uint16_t setup_packet_datalen = 8; - memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); - USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; - uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; - usb_current_xfer_info.dev_addr = dev_addr; - usb_current_xfer_info.ep_addr = ep_addr; - usb_current_xfer_info.start_ms = board_millis(); - usb_current_xfer_info.buffer = USBFS_TX_Buf; - usb_current_xfer_info.bufferlen = setup_packet_datalen; - usb_current_xfer_info.xferred_len = 0; + usb_edpt_t *edpt_info_tx = get_edpt_record(dev_addr, 0x00); + usb_edpt_t *edpt_info_rx = get_edpt_record(dev_addr, 0x80); + TU_ASSERT(edpt_info_tx != NULL, false); + TU_ASSERT(edpt_info_rx != NULL, false); - hardware_start_xfer(USB_PID_SETUP, 0, 0); + // Initialize data toggle (SETUP always starts with DATA0) + // Data toggle for OUT is toggled in hcd_int_handler() + edpt_info_tx->data_toggle = 0; + // Data toggle for IN must be set 0x01 manually. + edpt_info_rx->data_toggle = 0x01; + const uint16_t setup_packet_datalen = 8; + memcpy(USBFS_TX_Buf, setup_packet, setup_packet_datalen); + USBOTG_H_FS->HOST_TX_LEN = setup_packet_datalen; + uint8_t ep_addr = (setup_packet[0] & 0x80) ? 0x80 : 0x00; + usb_current_xfer_info.dev_addr = dev_addr; + usb_current_xfer_info.ep_addr = ep_addr; + usb_current_xfer_info.start_ms = board_millis(); + usb_current_xfer_info.buffer = USBFS_TX_Buf; + usb_current_xfer_info.bufferlen = setup_packet_datalen; + usb_current_xfer_info.xferred_len = 0; - return true; + hardware_start_xfer(USB_PID_SETUP, 0, 0); + + return true; } -bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) -{ - (void) rhport; - (void) dev_addr; - LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); - // PANIC("\r\install\r\n"); - uint8_t edpt_num = tu_edpt_number(ep_addr); - uint8_t setup_request_clear_stall[8] = { - 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 - }; - memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); - USBOTG_H_FS->HOST_TX_LEN = 8; +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + LOG_CH32_USBFSH("hcd_edpt_clear_stall(rhport=%d, dev_addr=0x%02x, ep_addr=0x%02x)\r\n", rhport, dev_addr, ep_addr); + // PANIC("\r\install\r\n"); + uint8_t edpt_num = tu_edpt_number(ep_addr); + uint8_t setup_request_clear_stall[8] = { + 0x02, 0x01, 0x00, 0x00, edpt_num, 0x00, 0x00, 0x00 + }; + memcpy(USBFS_TX_Buf, setup_request_clear_stall, 8); + USBOTG_H_FS->HOST_TX_LEN = 8; - bool prev_int_state = interrupt_enabled; - hcd_int_disable(0); + bool prev_int_state = interrupt_enabled; + hcd_int_disable(0); - USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; - USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; - while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) { } - USBOTG_H_FS->HOST_EP_PID = 0; - uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; - (void)response_pid; - LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); + USBOTG_H_FS->HOST_EP_PID = (USB_PID_SETUP << 4) | 0x00; + USBOTG_H_FS->INT_FG |= USBFS_UIF_TRANSFER; + while ((USBOTG_H_FS->INT_FG & USBFS_UIF_TRANSFER) == 0) {} + USBOTG_H_FS->HOST_EP_PID = 0; + uint8_t response_pid = USBOTG_H_FS->INT_ST & USBFS_UIS_H_RES_MASK; + (void) response_pid; + LOG_CH32_USBFSH("hcd_edpt_clear_stall() response pid=0x%02x\r\n", response_pid); - if (prev_int_state) { + if (prev_int_state) { hcd_int_enable(0); - } + } - return true; + return true; } #endif From 4b95a70bee078ad34bd916ed83b41cdaa4b00dbc Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Jul 2025 11:37:19 +0700 Subject: [PATCH 096/101] enable ci host and dual build for ch32v20x --- examples/dual/host_hid_to_device_cdc/only.txt | 1 + examples/dual/host_info_to_device_cdc/only.txt | 1 + examples/host/bare_api/only.txt | 1 + examples/host/cdc_msc_hid/only.txt | 1 + examples/host/device_info/only.txt | 1 + examples/host/hid_controller/only.txt | 1 + examples/host/midi_rx/only.txt | 1 + examples/host/msc_file_explorer/only.txt | 1 + 8 files changed, 8 insertions(+) diff --git a/examples/dual/host_hid_to_device_cdc/only.txt b/examples/dual/host_hid_to_device_cdc/only.txt index 3f40b4e7c..35f896f1e 100644 --- a/examples/dual/host_hid_to_device_cdc/only.txt +++ b/examples/dual/host_hid_to_device_cdc/only.txt @@ -1,6 +1,7 @@ board:mimxrt1060_evk board:mimxrt1064_evk board:mcb1800 +mcu:CH32V20X mcu:RP2040 mcu:ra6m5 mcu:MAX3421 diff --git a/examples/dual/host_info_to_device_cdc/only.txt b/examples/dual/host_info_to_device_cdc/only.txt index 3f40b4e7c..35f896f1e 100644 --- a/examples/dual/host_info_to_device_cdc/only.txt +++ b/examples/dual/host_info_to_device_cdc/only.txt @@ -1,6 +1,7 @@ board:mimxrt1060_evk board:mimxrt1064_evk board:mcb1800 +mcu:CH32V20X mcu:RP2040 mcu:ra6m5 mcu:MAX3421 diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index b5a4b6739..94ddc73c3 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:ESP32S2 mcu:ESP32S3 mcu:ESP32P4 diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/hid_controller/only.txt +++ b/examples/host/hid_controller/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index b5a4b6739..94ddc73c3 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:ESP32S2 mcu:ESP32S3 mcu:ESP32P4 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index dcdaf41c7..31dcb108c 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X From 3287cfaf76fb37644aa17c2e639d7d59b2764e59 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sat, 5 Jul 2025 12:35:47 +0200 Subject: [PATCH 097/101] Use DMA enable for DCache condition Signed-off-by: HiFiPhile --- src/common/tusb_mcu.h | 15 +++++++++------ src/common/tusb_types.h | 12 ++++++------ src/portable/synopsys/dwc2/dcd_dwc2.c | 2 +- src/portable/synopsys/dwc2/dwc2_stm32.h | 2 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 2 +- src/tusb_option.h | 14 -------------- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 8b30c98cd..4205239f1 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -220,8 +220,9 @@ #define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS #endif - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + // Enable dcache if DMA is enabled + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 #elif TU_CHECK_MCU(OPT_MCU_STM32H7) @@ -232,8 +233,9 @@ #define TUP_DCD_ENDPOINT_MAX 9 #if __CORTEX_M == 7 - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + // Enable dcache if DMA is enabled + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 #endif @@ -333,8 +335,9 @@ // MCU with on-chip HS Phy #define TUP_RHPORT_HIGHSPEED 1 - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + // Enable dcache if DMA is enabled + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 //--------------------------------------------------------------------+ diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 4735c983a..ee97069bd 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -36,39 +36,39 @@ #endif //------------- Device DCache declaration -------------// -#define TUD_EPBUF_DCACHE_SIZE(_size) (TUD_EPBUF_DCACHE_ALIGNED ? \ +#define TUD_EPBUF_DCACHE_SIZE(_size) (CFG_TUD_MEM_DCACHE_ENABLE ? \ (TU_DIV_CEIL(_size, CFG_TUD_MEM_DCACHE_LINE_SIZE) * CFG_TUD_MEM_DCACHE_LINE_SIZE) : (_size)) // Declare an endpoint buffer with uint8_t[size] #define TUD_EPBUF_DEF(_name, _size) \ union { \ CFG_TUD_MEM_ALIGN uint8_t _name[_size]; \ - TU_ATTR_ALIGNED(TUD_EPBUF_DCACHE_ALIGNED ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \ + TU_ATTR_ALIGNED(CFG_TUD_MEM_DCACHE_ENABLE ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \ } // Declare an endpoint buffer with a type #define TUD_EPBUF_TYPE_DEF(_type, _name) \ union { \ CFG_TUD_MEM_ALIGN _type _name; \ - TU_ATTR_ALIGNED(TUD_EPBUF_DCACHE_ALIGNED ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ + TU_ATTR_ALIGNED(CFG_TUD_MEM_DCACHE_ENABLE ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ } //------------- Host DCache declaration -------------// -#define TUH_EPBUF_DCACHE_SIZE(_size) (TUH_EPBUF_DCACHE_ALIGNED ? \ +#define TUH_EPBUF_DCACHE_SIZE(_size) (CFG_TUH_MEM_DCACHE_ENABLE ? \ (TU_DIV_CEIL(_size, CFG_TUH_MEM_DCACHE_LINE_SIZE) * CFG_TUH_MEM_DCACHE_LINE_SIZE) : (_size)) // Declare an endpoint buffer with uint8_t[size] #define TUH_EPBUF_DEF(_name, _size) \ union { \ CFG_TUH_MEM_ALIGN uint8_t _name[_size]; \ - TU_ATTR_ALIGNED(TUH_EPBUF_DCACHE_ALIGNED ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \ + TU_ATTR_ALIGNED(CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \ } // Declare an endpoint buffer with a type #define TUH_EPBUF_TYPE_DEF(_type, _name) \ union { \ CFG_TUH_MEM_ALIGN _type _name; \ - TU_ATTR_ALIGNED(TUH_EPBUF_DCACHE_ALIGNED ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ + TU_ATTR_ALIGNED(CFG_TUH_MEM_DCACHE_ENABLE ? CFG_TUH_MEM_DCACHE_LINE_SIZE : 1) uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \ } diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index f7e9aacfe..5f86d6b76 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -88,7 +88,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t dwc2_ep_count(const dwc2_regs_t* dwc //-------------------------------------------------------------------- // DMA //-------------------------------------------------------------------- -#if CFG_TUD_MEM_DCACHE_ENABLE && CFG_TUD_DWC2_DMA_ENABLE +#if CFG_TUD_MEM_DCACHE_ENABLE bool dcd_dcache_clean(const void* addr, uint32_t data_size) { TU_VERIFY(addr && data_size); return dwc2_dcache_clean(addr, data_size); diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index f01d11fe8..f9aa5301b 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -280,7 +280,7 @@ static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { } //------------- DCache -------------// -#if (CFG_TUD_MEM_DCACHE_ENABLE && CFG_TUD_DWC2_DMA_ENABLE) || (CFG_TUH_MEM_DCACHE_ENABLE && CFG_TUH_DWC2_DMA_ENABLE) +#if CFG_TUD_MEM_DCACHE_ENABLE || CFG_TUH_MEM_DCACHE_ENABLE typedef struct { diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 6b48c2346..257fa2833 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -141,7 +141,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool dma_host_enabled(const dwc2_regs_t* dwc return CFG_TUH_DWC2_DMA_ENABLE && ghwcfg2.arch == GHWCFG2_ARCH_INTERNAL_DMA; } -#if CFG_TUH_MEM_DCACHE_ENABLE && CFG_TUH_DWC2_DMA_ENABLE +#if CFG_TUH_MEM_DCACHE_ENABLE bool hcd_dcache_clean(const void* addr, uint32_t data_size) { TU_VERIFY(addr && data_size); return dwc2_dcache_clean(addr, data_size); diff --git a/src/tusb_option.h b/src/tusb_option.h index b8a4059a8..867babc33 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -465,13 +465,6 @@ #define CFG_TUD_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE #endif -#if CFG_TUD_MEM_DCACHE_ENABLE && \ - (CFG_TUD_DWC2_DMA_ENABLE || defined(TUP_USBIP_CHIPIDEA_HS)) - #define TUD_EPBUF_DCACHE_ALIGNED 1 -#else - #define TUD_EPBUF_DCACHE_ALIGNED 0 -#endif - #ifndef CFG_TUD_ENDPOINT0_SIZE #define CFG_TUD_ENDPOINT0_SIZE 64 #endif @@ -591,13 +584,6 @@ #define CFG_TUH_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE #endif -#if CFG_TUH_MEM_DCACHE_ENABLE && \ - (CFG_TUH_DWC2_DMA_ENABLE || defined(TUP_USBIP_CHIPIDEA_HS)) - #define TUH_EPBUF_DCACHE_ALIGNED 1 -#else - #define TUH_EPBUF_DCACHE_ALIGNED 0 -#endif - //------------- CLASS -------------// #ifndef CFG_TUH_HUB From 59a3720795681ad05157016bd21090340a298af7 Mon Sep 17 00:00:00 2001 From: YixingShen Date: Mon, 7 Jul 2025 00:26:12 +0800 Subject: [PATCH 098/101] fixed CFG_TUD_VENDOR > 1 vendord_open tud_vendor_n_write_flush tud_vendor_n_write_flush argument should be 0,1,2,..., but p_vendor - _vendord_itf is 0, sizeof(vendord_interface_t), 2*sizeof(vendord_interface_t), ... --- src/class/vendor/vendor_device.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 7f1fd8c41..df1518111 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -201,9 +201,10 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin // Find available interface vendord_interface_t* p_vendor = NULL; - for(uint8_t i=0; ibEndpointAddress) == TUSB_DIR_IN) { if (p_vendor->tx.stream.ep_addr == 0) { tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); - tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + tud_vendor_n_write_flush(itf); } } else { if (p_vendor->rx.stream.ep_addr == 0) { From 7b995267d6c5fb59719e9c652ab53186fa42c8b4 Mon Sep 17 00:00:00 2001 From: YixingShen Date: Mon, 7 Jul 2025 15:46:37 +0800 Subject: [PATCH 099/101] update --- src/class/vendor/vendor_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index df1518111..6f109c321 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -202,7 +202,7 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uin // Find available interface vendord_interface_t* p_vendor = NULL; uint8_t itf; - for(itf=0; i Date: Mon, 7 Jul 2025 12:33:14 +0700 Subject: [PATCH 100/101] change CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT (not defined) to 1 use stock iar linker --- hw/bsp/stm32h7rs/family.cmake | 2 +- hw/bsp/stm32h7rs/family.mk | 2 +- hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf | 55 ------------------- src/common/tusb_mcu.h | 30 +++++----- src/portable/synopsys/dwc2/dwc2_stm32.h | 10 ++-- src/tusb_option.h | 4 +- 6 files changed, 23 insertions(+), 80 deletions(-) delete mode 100644 hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf diff --git a/hw/bsp/stm32h7rs/family.cmake b/hw/bsp/stm32h7rs/family.cmake index 6b7915c93..40230ef12 100644 --- a/hw/bsp/stm32h7rs/family.cmake +++ b/hw/bsp/stm32h7rs/family.cmake @@ -58,7 +58,7 @@ function(add_board_target BOARD_TARGET) endif() set(LD_FILE_Clang ${LD_FILE_GNU}) if(NOT DEFINED LD_FILE_IAR) - set(LD_FILE_IAR ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${MCU_VARIANT}_flash.icf) + set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf) endif() add_library(${BOARD_TARGET} STATIC diff --git a/hw/bsp/stm32h7rs/family.mk b/hw/bsp/stm32h7rs/family.mk index 45d4da0cf..fba38448d 100644 --- a/hw/bsp/stm32h7rs/family.mk +++ b/hw/bsp/stm32h7rs/family.mk @@ -92,4 +92,4 @@ SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_$(MCU_VARIANT).s # Linker LD_FILE_GCC ?= $(FAMILY_PATH)/linker/$(MCU_VARIANT)_flash.ld -LD_FILE_IAR ?= $(FAMILY_PATH)/linker/$(MCU_VARIANT)_flash.icf +LD_FILE_IAR ?= $(ST_CMSIS)/Source/Templates/iar/linker/$(MCU_VARIANT)_flash.icf diff --git a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf b/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf deleted file mode 100644 index 786be3560..000000000 --- a/hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.icf +++ /dev/null @@ -1,55 +0,0 @@ -/*###ICF### Section handled by ICF editor, don't touch! ****/ -/*-Editor annotation file-*/ -/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ -/*-Specials-*/ -define symbol __ICFEDIT_intvec_start__ = 0x08000000; -/*-Memory Regions-*/ -define symbol NONCACHEABLEBUFFER_size = 0x400; -define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; -define symbol __ICFEDIT_region_ROM_end__ = 0x0800FFFF; -define symbol __ICFEDIT_region_RAM_start__ = 0x24000000; -define symbol __ICFEDIT_region_RAM_end__ = 0x2404FFFF - NONCACHEABLEBUFFER_size; -define symbol NONCACHEABLEBUFFER_start = __ICFEDIT_region_RAM_end__ + 1; -define symbol NONCACHEABLEBUFFER_end = __ICFEDIT_region_RAM_end__ + NONCACHEABLEBUFFER_size; - - -/*-Sizes-*/ -define symbol __ICFEDIT_size_cstack__ = 0x400; -define symbol __ICFEDIT_size_heap__ = 0x200; -/**** End of ICF editor section. ###ICF###*/ - -define symbol __region_ITCM_start__ = 0x00000000; -define symbol __region_ITCM_end__ = 0x0000FFFF; -define symbol __region_DTCM_start__ = 0x20000000; -define symbol __region_DTCM_end__ = 0x2000FFFF; -define symbol __region_SRAMAHB_start__ = 0x30000000; -define symbol __region_SRAMAHB_end__ = 0x30007FFF; -define symbol __region_BKPSRAM_start__ = 0x38800000; -define symbol __region_BKPSRAM_end__ = 0x38800FFF; - -export symbol NONCACHEABLEBUFFER_start; -export symbol NONCACHEABLEBUFFER_size; - -export symbol __ICFEDIT_region_ROM_start__; -export symbol __ICFEDIT_region_ROM_end__; -define memory mem with size = 4G; -define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; -define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; -define region NONCACHEABLE_region = mem:[from NONCACHEABLEBUFFER_start to NONCACHEABLEBUFFER_end]; -define region ITCM_region = mem:[from __region_ITCM_start__ to __region_ITCM_end__]; -define region DTCM_region = mem:[from __region_DTCM_start__ to __region_DTCM_end__]; -define region SRAMAHB_region = mem:[from __region_SRAMAHB_start__ to __region_SRAMAHB_end__]; -define region BKPSRAM_region = mem:[from __region_BKPSRAM_start__ to __region_BKPSRAM_end__]; - -define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; -define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; - -initialize by copy { readwrite }; -do not initialize { section .noinit }; - -place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; - -place in ROM_region { readonly }; -place in RAM_region { readwrite }; -place in DTCM_region { block CSTACK, block HEAP }; -place in NONCACHEABLE_region { section noncacheable_buffer }; diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 4205239f1..94eeb1294 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -117,9 +117,9 @@ #define TUP_RHPORT_HIGHSPEED 1 #if __CORTEX_M == 7 - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif #elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K) @@ -221,9 +221,9 @@ #endif // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #elif TU_CHECK_MCU(OPT_MCU_STM32H7) #include "stm32h7xx.h" @@ -233,10 +233,10 @@ #define TUP_DCD_ENDPOINT_MAX 9 #if __CORTEX_M == 7 - // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + // Enable dcache if DMA is enabled + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 #endif #elif TU_CHECK_MCU(OPT_MCU_STM32H5) @@ -336,9 +336,9 @@ #define TUP_RHPORT_HIGHSPEED 1 // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32 + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 //--------------------------------------------------------------------+ // Sony @@ -410,8 +410,8 @@ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // Enable dcache if DMA is enabled - #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE - #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE + #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE + #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64 #elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) diff --git a/src/portable/synopsys/dwc2/dwc2_stm32.h b/src/portable/synopsys/dwc2/dwc2_stm32.h index f9aa5301b..5f2b8419c 100644 --- a/src/portable/synopsys/dwc2/dwc2_stm32.h +++ b/src/portable/synopsys/dwc2/dwc2_stm32.h @@ -282,8 +282,7 @@ static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) { //------------- DCache -------------// #if CFG_TUD_MEM_DCACHE_ENABLE || CFG_TUH_MEM_DCACHE_ENABLE -typedef struct -{ +typedef struct { uintptr_t start; uintptr_t end; } mem_region_t; @@ -310,16 +309,15 @@ static mem_region_t uncached_regions[] = { }; TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) { - if (size & (CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) { - size = (size & ~(CFG_TUD_MEM_DCACHE_LINE_SIZE-1)) + CFG_TUD_MEM_DCACHE_LINE_SIZE; + if (size & (CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT-1)) { + size = (size & ~(CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT-1)) + CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT; } return size; } TU_ATTR_ALWAYS_INLINE static inline bool is_cache_mem(uintptr_t addr) { for (unsigned int i = 0; i < TU_ARRAY_SIZE(uncached_regions); i++) { - if (addr >= uncached_regions[i].start && addr <= uncached_regions[i].end) - return false; + if (uncached_regions[i].start <= addr && addr <= uncached_regions[i].end) { return false; } } return true; } diff --git a/src/tusb_option.h b/src/tusb_option.h index 867babc33..e6f5004b6 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -420,7 +420,7 @@ #ifndef CFG_TUSB_MEM_DCACHE_LINE_SIZE #ifndef CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT - #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32 + #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 1 #endif #define CFG_TUSB_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT @@ -428,7 +428,7 @@ // OS selection #ifndef CFG_TUSB_OS - #define CFG_TUSB_OS OPT_OS_NONE + #define CFG_TUSB_OS OPT_OS_NONE #endif #ifndef CFG_TUSB_OS_INC_PATH From 7909b503c4a6e93868bffa399a4bfa37898ea149 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 7 Jul 2025 20:56:05 +0700 Subject: [PATCH 101/101] re-add max32666fthr to hil pool --- test/hil/tinyusb.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 11b118cea..8a835e4c0 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -46,6 +46,18 @@ "args": "-device nrf52840_xxaa" } }, + { + "name": "max32666fthr", + "uid": "0C81464124010B20FF0A08CC2C", + "tests": { + "device": true, "host": false, "dual": false + }, + "flasher": { + "name": "openocd_adi", + "uid": "E6614C311B597D32", + "args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg" + } + }, { "name": "metro_m4_express", "uid": "9995AD485337433231202020FF100A34", @@ -199,18 +211,6 @@ } ], "boards-skip": [ - { - "name": "max32666fthr", - "uid": "0C81464124010B20FF0A08CC2C", - "tests": { - "device": true, "host": false, "dual": false - }, - "flasher": { - "name": "openocd_adi", - "uid": "E6614C311B597D32", - "args": "-f interface/cmsis-dap.cfg -f target/max32665.cfg" - } - }, { "name": "stm32f769disco", "uid": "21002F000F51363531383437",