From b9c44eea76f92cf3719fd68c9a10b8662faf23b5 Mon Sep 17 00:00:00 2001 From: IngHK Date: Sat, 10 Feb 2024 17:08:29 +0100 Subject: improved tusb_config.h comment --- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/host/cdc_msc_hid/src') 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 -- cgit v1.3.1 From aabee25e189d2a05cb52e5c54329ab1ec875f084 Mon Sep 17 00:00:00 2001 From: IngHK Date: Thu, 22 Feb 2024 11:45:38 +0100 Subject: added PL2303 support --- examples/host/cdc_msc_hid/src/tusb_config.h | 1 + .../host/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 (limited to 'examples/host/cdc_msc_hid/src') 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 -- cgit v1.3.1 From ee92e582b38e36df53381f8c98a0be54c2caef3e Mon Sep 17 00:00:00 2001 From: IngHK Date: Sun, 3 Mar 2024 13:12:10 +0100 Subject: 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 +-- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 4 +-- src/class/cdc/cdc_host.c | 40 ++++++++++++++++------ 3 files changed, 34 insertions(+), 14 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') 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 -- cgit v1.3.1 From d132044b7587f7e846bbec6e7b897d0842a21d13 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 24 Feb 2025 15:40:48 +0700 Subject: add tuh_midi_mount_cb_t struct for tuh_midi_mount_cb() change tuh_midi_rx/tx_cb() to have xferred_bytes rename tuh_midi_get_num_rx/tx_cables() to tuh_midi_get_rx/tx_cable_count() use default empty callback instead of weak null to be compatible with keil compiler --- examples/host/cdc_msc_hid/src/main.c | 4 +- examples/host/midi_rx/src/main.c | 13 +++--- src/class/cdc/cdc_host.h | 8 ++-- src/class/midi/midi_device.c | 5 --- src/class/midi/midi_host.c | 81 ++++++++++++++++-------------------- src/class/midi/midi_host.h | 34 +++++++++------ src/host/usbh_pvt.h | 4 -- 7 files changed, 70 insertions(+), 79 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 71257c0fe..2d5df23f9 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -82,12 +82,12 @@ int main(void) { void tuh_mount_cb(uint8_t dev_addr) { // application set-up - printf("A device with address %d is mounted\r\n", dev_addr); + printf("A device with address %u is mounted\r\n", dev_addr); } void tuh_umount_cb(uint8_t dev_addr) { // application tear-down - printf("A device with address %d is unmounted \r\n", dev_addr); + printf("A device with address %u is unmounted \r\n", dev_addr); } diff --git a/examples/host/midi_rx/src/main.c b/examples/host/midi_rx/src/main.c index 6db329ab5..d26321e5d 100644 --- a/examples/host/midi_rx/src/main.c +++ b/examples/host/midi_rx/src/main.c @@ -91,9 +91,9 @@ void midi_host_rx_task(void) { //--------------------------------------------------------------------+ // Invoked when device with MIDI interface is mounted. -void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx) { - printf("MIDI Interface Index = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", - idx, num_cables_rx, num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data) { + printf("MIDI Interface Index = %u, Address = %u, Number of RX cables = %u, Number of TX cables = %u\r\n", + idx, mount_cb_data->daddr, mount_cb_data->rx_cable_count, mount_cb_data->tx_cable_count); } // Invoked when device with hid interface is un-mounted @@ -101,8 +101,8 @@ void tuh_midi_umount_cb(uint8_t idx) { printf("MIDI Interface Index = %u is unmounted\r\n", idx); } -void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { - if (num_packets == 0) { +void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) { + if (xferred_bytes == 0) { return; } @@ -117,6 +117,7 @@ void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets) { printf("\r\n"); } -void tuh_midi_tx_cb(uint8_t idx) { +void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; + (void) xferred_bytes; } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index df975b2f0..8c5399534 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -49,22 +49,22 @@ // RX FIFO size #ifndef CFG_TUH_CDC_RX_BUFSIZE -#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif // RX Endpoint size #ifndef CFG_TUH_CDC_RX_EPSIZE -#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_RX_EPSIZE TUH_EPSIZE_BULK_MPS #endif // TX FIFO size #ifndef CFG_TUH_CDC_TX_BUFSIZE -#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif // TX Endpoint size #ifndef CFG_TUH_CDC_TX_EPSIZE -#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX +#define CFG_TUH_CDC_TX_EPSIZE TUH_EPSIZE_BULK_MPS #endif //--------------------------------------------------------------------+ diff --git a/src/class/midi/midi_device.c b/src/class/midi/midi_device.c index 7b6705640..0bbb3caf4 100644 --- a/src/class/midi/midi_device.c +++ b/src/class/midi/midi_device.c @@ -39,9 +39,6 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - - - typedef struct { uint8_t itf_num; uint8_t ep_in; @@ -440,8 +437,6 @@ uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint1 drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); } - } else { - TU_LOG2("Warning: MIDI Device has no Audio Control Interface"); } // 2nd Interface is MIDI Streaming diff --git a/src/class/midi/midi_host.c b/src/class/midi/midi_host.c index 770a39a8d..a4b1ebd2e 100644 --- a/src/class/midi/midi_host.c +++ b/src/class/midi/midi_host.c @@ -40,6 +40,15 @@ #define TU_LOG_DRV(...) TU_LOG(CFG_TUH_MIDI_LOG_LEVEL, __VA_ARGS__) +//--------------------------------------------------------------------+ +// Weak stubs: invoked if no strong implementation is available +//--------------------------------------------------------------------+ +TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb_data) { (void) idx; (void) desc_cb_data; } +TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data) { (void) idx; (void) mount_cb_data; } +TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx) { (void) idx; } +TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; (void) xferred_bytes; } +TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes) { (void) idx; (void) xferred_bytes; } + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -52,8 +61,8 @@ typedef struct { uint8_t ep_in; // IN endpoint address uint8_t ep_out; // OUT endpoint address - uint8_t num_cables_rx; // IN endpoint CS descriptor bNumEmbMIDIJack value - uint8_t num_cables_tx; // OUT endpoint CS descriptor bNumEmbMIDIJack value + uint8_t rx_cable_count; // IN endpoint CS descriptor bNumEmbMIDIJack value + uint8_t tx_cable_count; // OUT endpoint CS descriptor bNumEmbMIDIJack value #if CFG_TUH_MIDI_STREAM_API // For Stream read()/write() API @@ -135,16 +144,13 @@ void midih_close(uint8_t daddr) { midih_interface_t* p_midi = &_midi_host[idx]; if (p_midi->daddr == daddr) { TU_LOG_DRV(" MIDI close addr = %u index = %u\r\n", daddr, idx); - - if (tuh_midi_umount_cb) { - tuh_midi_umount_cb(idx); - } + tuh_midi_umount_cb(idx); p_midi->ep_in = 0; p_midi->ep_out = 0; p_midi->bInterfaceNumber = 0; - p_midi->num_cables_rx = 0; - p_midi->num_cables_tx = 0; + p_midi->rx_cable_count = 0; + p_midi->tx_cable_count = 0; p_midi->daddr = 0; p_midi->mounted = false; tu_memclr(&p_midi->stream_read, sizeof(p_midi->stream_read)); @@ -163,33 +169,16 @@ bool midih_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint midih_interface_t *p_midi_host = &_midi_host[idx]; if (ep_addr == p_midi_host->ep_stream.rx.ep_addr) { - // receive new data if available + // receive new data, put it into FIFO and invoke callback if available if (xferred_bytes) { - // put in the RX FIFO only non-zero MIDI IN 4-byte packets - uint32_t packets_queued = 0; - uint8_t *buf = _midi_epbuf->rx; - const uint32_t npackets = xferred_bytes / 4; - for (uint32_t p = 0; p < npackets; p++) { - // some devices send back all zero packets even if there is no data ready - const uint32_t packet = tu_unaligned_read32(buf); - if (packet != 0) { - tu_edpt_stream_read_xfer_complete_with_buf(&p_midi_host->ep_stream.rx, buf, 4); - ++packets_queued; - TU_LOG3("MIDI RX=%08x\r\n", packet); - } - buf += 4; - } - - if (tuh_midi_rx_cb) { - tuh_midi_rx_cb(idx, packets_queued); - } + tu_edpt_stream_read_xfer_complete(&p_midi_host->ep_stream.rx, xferred_bytes); + tuh_midi_rx_cb(idx, xferred_bytes); } tu_edpt_stream_read_xfer(dev_addr, &p_midi_host->ep_stream.rx); // prepare for next transfer } else if (ep_addr == p_midi_host->ep_stream.tx.ep_addr) { - if (tuh_midi_tx_cb) { - tuh_midi_tx_cb(idx); - } + tuh_midi_tx_cb(idx, xferred_bytes); + if (0 == tu_edpt_stream_write_xfer(dev_addr, &p_midi_host->ep_stream.tx)) { // If there is no data left, a ZLP should be sent if // xferred_bytes is multiple of EP size and not zero @@ -207,7 +196,6 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d (void) rhport; TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass); - // const uint8_t* p_start = ((uint8_t const*) desc_itf); const uint8_t *p_end = ((const uint8_t *) desc_itf) + max_len; const uint8_t *p_desc = (const uint8_t *) desc_itf; @@ -286,14 +274,14 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d TU_LOG_DRV(" Endpoint and CS_Endpoint descriptor %02x\r\n", p_ep->bEndpointAddress); if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { p_midi->ep_out = p_ep->bEndpointAddress; - p_midi->num_cables_tx = p_csep->bNumEmbMIDIJack; + p_midi->tx_cable_count = p_csep->bNumEmbMIDIJack; desc_cb.desc_epout = p_ep; TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); tu_edpt_stream_open(&p_midi->ep_stream.tx, p_ep); } else { p_midi->ep_in = p_ep->bEndpointAddress; - p_midi->num_cables_rx = p_csep->bNumEmbMIDIJack; + p_midi->rx_cable_count = p_csep->bNumEmbMIDIJack; desc_cb.desc_epin = p_ep; TU_ASSERT(tuh_edpt_open(dev_addr, p_ep)); @@ -309,10 +297,7 @@ bool midih_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *d desc_cb.desc_midi_total_len = (uint16_t) ((uintptr_t)p_desc - (uintptr_t) desc_itf); p_midi->daddr = dev_addr; - - if (tuh_midi_descriptor_cb) { - tuh_midi_descriptor_cb(idx, &desc_cb); - } + tuh_midi_descriptor_cb(idx, &desc_cb); return true; } @@ -323,9 +308,13 @@ bool midih_set_config(uint8_t dev_addr, uint8_t itf_num) { midih_interface_t *p_midi = &_midi_host[idx]; p_midi->mounted = true; - if (tuh_midi_mount_cb) { - tuh_midi_mount_cb(idx, p_midi->num_cables_rx, p_midi->num_cables_tx); - } + const tuh_midi_mount_cb_t mount_cb_data = { + .daddr = dev_addr, + .bInterfaceNumber = itf_num, + .rx_cable_count = p_midi->rx_cable_count, + .tx_cable_count = p_midi->tx_cable_count, + }; + tuh_midi_mount_cb(idx, &mount_cb_data); tu_edpt_stream_read_xfer(dev_addr, &p_midi->ep_stream.rx); // prepare for incoming data @@ -355,18 +344,18 @@ uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num) { return TUSB_INDEX_INVALID_8; } -uint8_t tuh_midi_get_num_tx_cables (uint8_t idx) { +uint8_t tuh_midi_get_tx_cable_count (uint8_t idx) { TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; TU_VERIFY(p_midi->ep_stream.tx.ep_addr != 0, 0); - return p_midi->num_cables_tx; + return p_midi->tx_cable_count; } -uint8_t tuh_midi_get_num_rx_cables (uint8_t idx) { +uint8_t tuh_midi_get_rx_cable_count (uint8_t idx) { TU_VERIFY(idx < CFG_TUH_MIDI); midih_interface_t *p_midi = &_midi_host[idx]; TU_VERIFY(p_midi->ep_stream.rx.ep_addr != 0, 0); - return p_midi->num_cables_rx; + return p_midi->rx_cable_count; } uint32_t tuh_midi_read_available(uint8_t idx) { @@ -410,7 +399,7 @@ uint32_t tuh_midi_packet_write_n(uint8_t idx, const uint8_t* buffer, uint32_t bu uint32_t tuh_midi_stream_write(uint8_t idx, uint8_t cable_num, uint8_t const *buffer, uint32_t bufsize) { TU_VERIFY(idx < CFG_TUH_MIDI && buffer && bufsize > 0); midih_interface_t *p_midi = &_midi_host[idx]; - TU_VERIFY(cable_num < p_midi->num_cables_tx); + TU_VERIFY(cable_num < p_midi->tx_cable_count); midi_driver_stream_t *stream = &p_midi->stream_write; uint32_t byte_count = 0; @@ -520,7 +509,7 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff while (nread == 4 && bytes_buffered < bufsize) { *p_cable_num = (p_midi->stream_read.buffer[0] >> 4) & 0x0f; uint8_t bytes_to_add_to_stream = 0; - if (*p_cable_num < p_midi->num_cables_rx) { + if (*p_cable_num < p_midi->rx_cable_count) { // ignore the CIN field; too many devices out there encode this wrong uint8_t status = p_midi->stream_read.buffer[1]; uint16_t cable_mask = (uint16_t) (1 << *p_cable_num); diff --git a/src/class/midi/midi_host.h b/src/class/midi/midi_host.h index 717e6ba67..b06bb43d7 100644 --- a/src/class/midi/midi_host.h +++ b/src/class/midi/midi_host.h @@ -37,10 +37,6 @@ //--------------------------------------------------------------------+ // Class Driver Configuration //--------------------------------------------------------------------+ -#ifndef CFG_TUH_MAX_CABLES -#define CFG_TUH_MAX_CABLES 16 -#endif - #ifndef CFG_TUH_MIDI_RX_BUFSIZE #define CFG_TUH_MIDI_RX_BUFSIZE TUH_EPSIZE_BULK_MPS #endif @@ -60,7 +56,7 @@ #endif //--------------------------------------------------------------------+ -// Application API +// Application Types //--------------------------------------------------------------------+ typedef struct { const tusb_desc_interface_t* desc_audio_control; @@ -76,6 +72,17 @@ typedef struct { const uint8_t* desc_jack[16]; // list of jack descriptors (embedded + external) } tuh_midi_descriptor_cb_t; +typedef struct { + uint8_t daddr; + uint8_t bInterfaceNumber; // interface number of MIDI streaming + uint8_t rx_cable_count; + uint8_t tx_cable_count; +} tuh_midi_mount_cb_t; + +//--------------------------------------------------------------------+ +// Application API +//--------------------------------------------------------------------+ + // Check if MIDI interface is mounted bool tuh_midi_mounted(uint8_t idx); @@ -84,10 +91,10 @@ bool tuh_midi_mounted(uint8_t idx); uint8_t tuh_midi_itf_get_index(uint8_t daddr, uint8_t itf_num); // return the number of virtual midi cables on the device's IN endpoint -uint8_t tuh_midi_get_num_rx_cables(uint8_t idx); +uint8_t tuh_midi_get_rx_cable_count(uint8_t idx); // return the number of virtual midi cables on the device's OUT endpoint -uint8_t tuh_midi_get_num_tx_cables(uint8_t idx); +uint8_t tuh_midi_get_tx_cable_count(uint8_t idx); // return the raw number of bytes available. // Note: this is related but not the same as number of stream bytes available. @@ -151,16 +158,19 @@ uint32_t tuh_midi_stream_read(uint8_t idx, uint8_t *p_cable_num, uint8_t *p_buff // Invoked when MIDI interface is detected in enumeration. Application can copy/parse descriptor if needed. // Note: may be fired before tuh_midi_mount_cb(), therefore midi interface is not mounted/ready. -TU_ATTR_WEAK void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb); +void tuh_midi_descriptor_cb(uint8_t idx, const tuh_midi_descriptor_cb_t * desc_cb_data); // Invoked when device with MIDI interface is mounted. -TU_ATTR_WEAK void tuh_midi_mount_cb(uint8_t idx, uint8_t num_cables_rx, uint16_t num_cables_tx); +void tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t* mount_cb_data); // Invoked when device with MIDI interface is un-mounted -TU_ATTR_WEAK void tuh_midi_umount_cb(uint8_t idx); +void tuh_midi_umount_cb(uint8_t idx); + +// Invoked when received new data +void tuh_midi_rx_cb(uint8_t idx, uint32_t xferred_bytes); -TU_ATTR_WEAK void tuh_midi_rx_cb(uint8_t idx, uint32_t num_packets); -TU_ATTR_WEAK void tuh_midi_tx_cb(uint8_t idx); +// Invoked when a TX is complete and therefore space becomes available in TX buffer +void tuh_midi_tx_cb(uint8_t idx, uint32_t xferred_bytes); //--------------------------------------------------------------------+ // Internal Class Driver API diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index d27c4baa2..bfa1fb2ba 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -41,10 +41,6 @@ #define TU_LOG_INT_USBH(...) TU_LOG_INT(CFG_TUH_LOG_LEVEL, __VA_ARGS__) #define TU_LOG_HEX_USBH(...) TU_LOG_HEX(CFG_TUH_LOG_LEVEL, __VA_ARGS__) -enum { - USBH_EPSIZE_BULK_MAX = (TUH_OPT_HIGH_SPEED ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS) -}; - //--------------------------------------------------------------------+ // Class Driver API //--------------------------------------------------------------------+ -- cgit v1.3.1 From 5f447b76ad23e8c977a5167b0b4dce93cd2980de Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 3 Mar 2025 23:22:23 +0700 Subject: - add tuh_descriptor_get_string_langid() API - host enumeration always get language id, manufacturer, product and serial string. Which is required by some device such as 8bitdo --- examples/host/cdc_msc_hid/src/hid_app.c | 80 +++++++++++---------------- src/common/tusb_types.h | 2 +- src/host/hub.c | 5 +- src/host/usbh.c | 95 ++++++++++++++++++++++++++------- src/host/usbh.h | 13 +++++ 5 files changed, 123 insertions(+), 72 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 3f98ec89f..5bae250cf 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -39,18 +39,16 @@ static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; // Each HID instance can has multiple reports -static struct -{ +static struct { uint8_t report_count; tuh_hid_report_info_t report_info[MAX_REPORT]; -}hid_info[CFG_TUH_HID]; +} hid_info[CFG_TUH_HID]; static void process_kbd_report(hid_keyboard_report_t const *report); static void process_mouse_report(hid_mouse_report_t const * report); static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); -void hid_app_task(void) -{ +void hid_app_task(void) { // nothing to do } @@ -63,64 +61,57 @@ void hid_app_task(void) // can be used to parse common/simple enough descriptor. // Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped // therefore report_desc = NULL, desc_len = 0 -void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) -{ +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) { printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); // Interface protocol (hid_interface_protocol_enum_t) - const char* protocol_str[] = { "None", "Keyboard", "Mouse" }; + const char *protocol_str[] = {"None", "Keyboard", "Mouse"}; uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]); // By default host stack will use activate boot protocol on supported interface. // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser) - if ( itf_protocol == HID_ITF_PROTOCOL_NONE ) - { + if (itf_protocol == HID_ITF_PROTOCOL_NONE) { hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len); printf("HID has %u reports \r\n", hid_info[instance].report_count); } // request to receive report // tuh_hid_report_received_cb() will be invoked when report is available - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { + if (!tuh_hid_receive_report(dev_addr, instance)) { printf("Error: cannot request to receive report\r\n"); } } // Invoked when device with hid interface is un-mounted -void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) -{ +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) { printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance); } // Invoked when received report from device via interrupt endpoint -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) -{ +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); - switch (itf_protocol) - { + switch (itf_protocol) { case HID_ITF_PROTOCOL_KEYBOARD: TU_LOG2("HID receive boot keyboard report\r\n"); - process_kbd_report( (hid_keyboard_report_t const*) report ); - break; + process_kbd_report((hid_keyboard_report_t const *) report); + break; case HID_ITF_PROTOCOL_MOUSE: TU_LOG2("HID receive boot mouse report\r\n"); - process_mouse_report( (hid_mouse_report_t const*) report ); - break; + process_mouse_report((hid_mouse_report_t const *) report); + break; default: // Generic report requires matching ReportID and contents with previous parsed report info process_generic_report(dev_addr, instance, report, len); - break; + break; } // continue to request to receive report - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { + if (!tuh_hid_receive_report(dev_addr, instance)) { printf("Error: cannot request to receive report\r\n"); } } @@ -231,29 +222,24 @@ static void process_mouse_report(hid_mouse_report_t const * report) //--------------------------------------------------------------------+ // Generic Report //--------------------------------------------------------------------+ -static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) -{ +static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { (void) dev_addr; (void) len; uint8_t const rpt_count = hid_info[instance].report_count; - tuh_hid_report_info_t* rpt_info_arr = hid_info[instance].report_info; - tuh_hid_report_info_t* rpt_info = NULL; + tuh_hid_report_info_t *rpt_info_arr = hid_info[instance].report_info; + tuh_hid_report_info_t *rpt_info = NULL; - if ( rpt_count == 1 && rpt_info_arr[0].report_id == 0) - { + if (rpt_count == 1 && rpt_info_arr[0].report_id == 0) { // Simple report without report ID as 1st byte rpt_info = &rpt_info_arr[0]; - }else - { + } else { // Composite report, 1st byte is report ID, data starts from 2nd byte uint8_t const rpt_id = report[0]; // Find report id in the array - for(uint8_t i=0; iusage_page == HID_USAGE_PAGE_DESKTOP ) - { - switch (rpt_info->usage) - { + if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) { + switch (rpt_info->usage) { case HID_USAGE_DESKTOP_KEYBOARD: TU_LOG1("HID receive keyboard report\r\n"); // Assume keyboard follow boot report layout - process_kbd_report( (hid_keyboard_report_t const*) report ); - break; + process_kbd_report((hid_keyboard_report_t const *) report); + break; case HID_USAGE_DESKTOP_MOUSE: TU_LOG1("HID receive mouse report\r\n"); // Assume mouse follow boot report layout - process_mouse_report( (hid_mouse_report_t const*) report ); - break; + process_mouse_report((hid_mouse_report_t const *) report); + break; - default: break; + default: + break; } } } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 42ce5fc12..71af132af 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -462,7 +462,7 @@ TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct typedef struct TU_ATTR_PACKED { uint8_t bLength ; ///< Size of this descriptor in bytes uint8_t bDescriptorType ; ///< Descriptor Type - uint16_t unicode_string[]; + uint16_t utf16le[]; } tusb_desc_string_t; // USB Binary Device Object Store (BOS) diff --git a/src/host/hub.c b/src/host/hub.c index 93b4a3a84..61efa8ba5 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -46,7 +46,7 @@ typedef struct { // from hub descriptor uint8_t bNbrPorts; - uint8_t bPwrOn2PwrGood; // port power on to good, in 2ms unit + uint8_t bPwrOn2PwrGood_2ms; // port power on to good, in 2ms unit // uint16_t wHubCharacteristics; hub_port_status_response_t port_status; @@ -279,7 +279,7 @@ static void config_set_port_power (tuh_xfer_t* xfer) { // only use number of ports in hub descriptor hub_desc_cs_t const* desc_hub = (hub_desc_cs_t const*) p_epbuf->ctrl_buf; p_hub->bNbrPorts = desc_hub->bNbrPorts; - p_hub->bPwrOn2PwrGood = desc_hub->bPwrOn2PwrGood; + p_hub->bPwrOn2PwrGood_2ms = desc_hub->bPwrOn2PwrGood; // May need to GET_STATUS @@ -301,7 +301,6 @@ static void config_port_power_complete (tuh_xfer_t* xfer) { TU_MESS_FAILED(); TU_BREAKPOINT(); } - // delay bPwrOn2PwrGood * 2 ms before set configuration complete usbh_driver_set_config_complete(daddr, p_hub->itf_num); } else { // power next port diff --git a/src/host/usbh.c b/src/host/usbh.c index c7a9a868f..dcd22ee31 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -1282,13 +1282,17 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX); } else { // Invoke callback before closing driver (maybe call it later ?) - if (tuh_umount_cb) tuh_umount_cb(daddr); + if (tuh_umount_cb) { + tuh_umount_cb(daddr); + } } // Close class driver for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { usbh_class_driver_t const* driver = get_driver(drv_id); - if (driver) driver->close(daddr); + if (driver) { + driver->close(daddr); + } } hcd_device_close(rhport, daddr); @@ -1345,8 +1349,11 @@ enum { ENUM_HUB_GET_STATUS_2, ENUM_HUB_CLEAR_RESET_2, ENUM_SET_ADDR, - ENUM_GET_DEVICE_DESC, + ENUM_GET_STRING_LANGUAGE_ID, + ENUM_GET_STRING_MANUFACTURER, + ENUM_GET_STRING_PRODUCT, + ENUM_GET_STRING_SERIAL, ENUM_GET_9BYTE_CONFIG_DESC, ENUM_GET_FULL_CONFIG_DESC, ENUM_SET_CONFIG, @@ -1359,25 +1366,25 @@ static void enum_full_complete(void); // process device enumeration static void process_enumeration(tuh_xfer_t* xfer) { - // Retry a few times with transfers in enumeration since device can be unstable when starting up - enum { - ATTEMPT_COUNT_MAX = 3, - ATTEMPT_DELAY_MS = 100 - }; + // Retry a few times while enumerating since device can be unstable when starting up static uint8_t failed_count = 0; + if (XFER_RESULT_FAILED == xfer->result) { + enum { + ATTEMPT_COUNT_MAX = 3, + ATTEMPT_DELAY_MS = 100 + }; - if (XFER_RESULT_SUCCESS != xfer->result) { // retry if not reaching max attempt + failed_count++; bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX); - if ( retry ) { - failed_count++; + if (retry) { tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit - TU_LOG1("Enumeration attempt %u\r\n", failed_count); + TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX); retry = tuh_control_xfer(xfer); } if (!retry) { - enum_full_complete(); + enum_full_complete(); // complete as failed } return; @@ -1386,6 +1393,8 @@ static void process_enumeration(tuh_xfer_t* xfer) { uint8_t const daddr = xfer->daddr; uintptr_t const state = xfer->user_data; + usbh_device_t* dev = get_device(daddr); + uint16_t langid = 0x0409; // default is English switch (state) { #if CFG_TUH_HUB @@ -1476,7 +1485,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { tusb_time_delay_ms_api(2); const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue); - usbh_device_t* new_dev = get_device(new_addr); TU_ASSERT(new_dev,); new_dev->addressed = 1; @@ -1490,21 +1498,69 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Get full device descriptor TU_LOG_USBH("Get Device Descriptor\r\n"); TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t), - process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC),); + process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),); break; } - case ENUM_GET_9BYTE_CONFIG_DESC: { - tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; - usbh_device_t* dev = get_device(daddr); + case ENUM_GET_STRING_LANGUAGE_ID: { + // save the received device descriptor TU_ASSERT(dev,); - + tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl; dev->vid = desc_device->idVendor; dev->pid = desc_device->idProduct; dev->i_manufacturer = desc_device->iManufacturer; dev->i_product = desc_device->iProduct; dev->i_serial = desc_device->iSerialNumber; + tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_MANUFACTURER); + break; + } + + case ENUM_GET_STRING_MANUFACTURER: { + TU_ASSERT(dev,); + const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl; + if (desc_langid->bLength >= 4) { + langid = tu_le16toh(desc_langid->utf16le[0]); + } + if (dev->i_manufacturer != 0) { + tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_PRODUCT); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_PRODUCT: { + TU_ASSERT(dev,); + if (state == ENUM_GET_STRING_PRODUCT) { + langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet + } + if (dev->i_product != 0) { + tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_STRING_SERIAL); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_STRING_SERIAL: { + TU_ASSERT(dev,); + if (state == ENUM_GET_STRING_SERIAL) { + langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet + } + if (dev->i_serial != 0) { + tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE, + process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC); + break; + } else { + TU_ATTR_FALLTHROUGH; + } + } + + case ENUM_GET_9BYTE_CONFIG_DESC: { // Get 9-byte for total length uint8_t const config_idx = CONFIG_NUM - 1; TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n"); @@ -1537,7 +1593,6 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_CONFIG_DRIVER: { TU_LOG_USBH("Device configured\r\n"); - usbh_device_t* dev = get_device(daddr); TU_ASSERT(dev,); dev->configured = 1; diff --git a/src/host/usbh.h b/src/host/usbh.h index c8b137173..0fbe39743 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -265,6 +265,13 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_ 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); +// Get language id string descriptor (control transfer) +TU_ATTR_ALWAYS_INLINE static inline +bool tuh_descriptor_get_string_langid(uint8_t daddr, void* buffer, uint16_t len, + tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + return tuh_descriptor_get_string(daddr, 0, 0, buffer, len, complete_cb, user_data); +} + // Get manufacturer string descriptor (control transfer) // true on success, false if there is on-going control transfer or incorrect parameters bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, @@ -304,6 +311,12 @@ uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8 // 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 (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) { + 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); -- cgit v1.3.1 From 65e44e0a51272f9d75719d90955f19209dbf1ea2 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 6 Mar 2025 22:46:21 +0700 Subject: fix(dwc2) host driver conflict with max3421e --- examples/host/bare_api/src/tusb_config.h | 3 ++- examples/host/cdc_msc_hid/src/tusb_config.h | 3 ++- examples/host/cdc_msc_hid_freertos/src/tusb_config.h | 3 ++- examples/host/device_info/src/tusb_config.h | 3 ++- examples/host/hid_controller/src/tusb_config.h | 3 ++- examples/host/msc_file_explorer/src/tusb_config.h | 3 ++- src/portable/synopsys/dwc2/hcd_dwc2.c | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') diff --git a/examples/host/bare_api/src/tusb_config.h b/examples/host/bare_api/src/tusb_config.h index fab233be0..a03675c5f 100644 --- a/examples/host/bare_api/src/tusb_config.h +++ b/examples/host/bare_api/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index a59a0ffb9..cc8d6e5c4 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) 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 02de4197b..682265f59 100644 --- a/examples/host/cdc_msc_hid_freertos/src/tusb_config.h +++ b/examples/host/cdc_msc_hid_freertos/src/tusb_config.h @@ -74,9 +74,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/device_info/src/tusb_config.h b/examples/host/device_info/src/tusb_config.h index 5190b5b1f..db02a97db 100644 --- a/examples/host/device_info/src/tusb_config.h +++ b/examples/host/device_info/src/tusb_config.h @@ -74,9 +74,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/hid_controller/src/tusb_config.h b/examples/host/hid_controller/src/tusb_config.h index 3ac591d8f..351fe0178 100644 --- a/examples/host/hid_controller/src/tusb_config.h +++ b/examples/host/hid_controller/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/examples/host/msc_file_explorer/src/tusb_config.h b/examples/host/msc_file_explorer/src/tusb_config.h index c798b4383..c1829c300 100644 --- a/examples/host/msc_file_explorer/src/tusb_config.h +++ b/examples/host/msc_file_explorer/src/tusb_config.h @@ -69,9 +69,10 @@ // Enable Host stack #define CFG_TUH_ENABLED 1 +// #define CFG_TUH_MAX3421 1 // use max3421 as host controller + #if CFG_TUSB_MCU == OPT_MCU_RP2040 // #define CFG_TUH_RPI_PIO_USB 1 // use pio-usb as host controller - // #define CFG_TUH_MAX3421 1 // use max3421 as host controller // host roothub port is 1 if using either pio-usb or max3421 #if (defined(CFG_TUH_RPI_PIO_USB) && CFG_TUH_RPI_PIO_USB) || (defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421) diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index ebbb6200a..b13479b02 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -26,7 +26,7 @@ #include "tusb_option.h" -#if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) +#if CFG_TUH_ENABLED && defined(TUP_USBIP_DWC2) && !CFG_TUH_MAX3421 #if !(CFG_TUH_DWC2_SLAVE_ENABLE || CFG_TUH_DWC2_DMA_ENABLE) #error DWC2 require either CFG_TUH_DWC2_SLAVE_ENABLE or CFG_TUH_DWC2_DMA_ENABLE to be enabled -- cgit v1.3.1 From 99673cdbb81b76f7020cf6aacb182ea86fdee3da Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 25 Mar 2025 17:36:15 +0700 Subject: fix wanings --- examples/host/cdc_msc_hid/src/cdc_app.c | 2 +- examples/host/cdc_msc_hid/src/hid_app.c | 3 +-- examples/host/cdc_msc_hid/src/main.c | 12 ++++-------- examples/host/cdc_msc_hid_freertos/src/cdc_app.c | 2 +- examples/host/cdc_msc_hid_freertos/src/main.c | 6 ------ examples/host/cdc_msc_hid_freertos/src/msc_app.c | 2 +- examples/host/hid_controller/src/hid_app.c | 17 ++++++----------- examples/host/msc_file_explorer/src/msc_app.c | 2 ++ 8 files changed, 16 insertions(+), 30 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index 4a13f8b27..e68ec383b 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c @@ -27,7 +27,7 @@ #include "tusb.h" #include "bsp/board_api.h" -size_t get_console_inputs(uint8_t* buf, size_t bufsize) { +static size_t get_console_inputs(uint8_t* buf, size_t bufsize) { size_t count = 0; while (count < bufsize) { int ch = board_getchar(); diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index 5bae250cf..a751c9c80 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -165,8 +165,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report) // Mouse //--------------------------------------------------------------------+ -void cursor_movement(int8_t x, int8_t y, int8_t wheel) -{ +static void cursor_movement(int8_t x, int8_t y, int8_t wheel) { #if USE_ANSI_ESCAPE // Move X using ansi escape if ( x < 0) diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 2d5df23f9..7b02e238e 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -31,18 +31,12 @@ #include "tusb.h" //--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES +// MACRO CONSTANT TYPEDEF PROTOTYPES //--------------------------------------------------------------------+ void led_blinking_task(void); extern void cdc_app_task(void); extern void hid_app_task(void); -#if CFG_TUH_ENABLED && CFG_TUH_MAX3421 -// API to read/rite MAX3421's register. Implemented by TinyUSB -extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr); -extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr); -#endif - /*------------- MAIN -------------*/ int main(void) { board_init(); @@ -101,7 +95,9 @@ void led_blinking_task(void) { static bool led_state = false; // Blink every interval ms - if (board_millis() - start_ms < interval_ms) return; // not enough time + if (board_millis() - start_ms < interval_ms) { + return;// not enough time + } start_ms += interval_ms; board_led_write(led_state); 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 7cbe1e03a..e279ad509 100644 --- a/examples/host/cdc_msc_hid_freertos/src/cdc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/cdc_app.c @@ -52,7 +52,7 @@ void cdc_app_init(void) { } // helper -size_t get_console_inputs(uint8_t *buf, size_t bufsize) { +static size_t get_console_inputs(uint8_t *buf, size_t bufsize) { size_t count = 0; while (count < bufsize) { int ch = board_getchar(); diff --git a/examples/host/cdc_msc_hid_freertos/src/main.c b/examples/host/cdc_msc_hid_freertos/src/main.c index 10d1b120b..64a108254 100644 --- a/examples/host/cdc_msc_hid_freertos/src/main.c +++ b/examples/host/cdc_msc_hid_freertos/src/main.c @@ -69,12 +69,6 @@ extern void cdc_app_init(void); extern void hid_app_init(void); extern void msc_app_init(void); -#if CFG_TUH_ENABLED && CFG_TUH_MAX3421 -// API to read/rite MAX3421's register. Implemented by TinyUSB -extern uint8_t tuh_max3421_reg_read(uint8_t rhport, uint8_t reg, bool in_isr); -extern bool tuh_max3421_reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr); -#endif - /*------------- MAIN -------------*/ int main(void) { board_init(); diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c index 6b9cdab85..6439495a8 100644 --- a/examples/host/cdc_msc_hid_freertos/src/msc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c @@ -34,7 +34,7 @@ void msc_app_init(void) { // nothing to do } -bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) { +static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const *cb_data) { msc_cbw_t const *cbw = cb_data->cbw; msc_csw_t const *csw = cb_data->csw; diff --git a/examples/host/hid_controller/src/hid_app.c b/examples/host/hid_controller/src/hid_app.c index 6ffe0b6d4..1d6ca8b07 100644 --- a/examples/host/hid_controller/src/hid_app.c +++ b/examples/host/hid_controller/src/hid_app.c @@ -231,14 +231,12 @@ void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) } // check if different than 2 -bool diff_than_2(uint8_t x, uint8_t y) -{ +static inline bool diff_than_2(uint8_t x, uint8_t y) { return (x - y > 2) || (y - x > 2); } // check if 2 reports are different enough -bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) -{ +static bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) { bool result; // x, y, z, rz must different than 2 to be counted @@ -251,7 +249,7 @@ bool diff_report(sony_ds4_report_t const* rpt1, sony_ds4_report_t const* rpt2) return result; } -void process_sony_ds4(uint8_t const* report, uint16_t len) +static void process_sony_ds4(uint8_t const* report, uint16_t len) { (void)len; const char* dpad_str[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "none" }; @@ -310,16 +308,13 @@ void process_sony_ds4(uint8_t const* report, uint16_t len) } // Invoked when received report from device via interrupt endpoint -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) -{ - if ( is_sony_ds4(dev_addr) ) - { +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { + if (is_sony_ds4(dev_addr)) { process_sony_ds4(report, len); } // continue to request to receive report - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { + if (!tuh_hid_receive_report(dev_addr, instance)) { printf("Error: cannot request to receive report\r\n"); } } diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 226c870ea..40a9ef57e 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -34,6 +34,8 @@ #define EMBEDDED_CLI_IMPL #include "embedded_cli.h" +#include "msc_app.h" + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION -- cgit v1.3.1 From 741cb3cf029e37682634eeb355c20420c0816c8d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 23 Apr 2025 12:35:32 +0700 Subject: rename hcd_devtree_info_t to tuh_bus_info_t, hcd_devtree_get_info to hcd_bus_info_get streamline bus info to usbh_devies, also replace dev0 (renamed to dev0_bus) --- .idea/debugServers/esp32s2.xml | 14 +++ .idea/debugServers/rp2350.xml | 2 +- .idea/debugServers/stm32f769.xml | 13 +++ .idea/debugServers/stm32h563.xml | 13 +++ .idea/debugServers/stm32h743.xml | 13 +++ examples/host/cdc_msc_hid/src/msc_app.c | 12 +-- src/host/hcd.h | 12 +-- src/host/usbh.c | 127 +++++++++++-------------- src/host/usbh_pvt.h | 2 +- src/portable/ehci/ehci.c | 10 +- src/portable/mentor/musb/hcd_musb.c | 24 ++--- src/portable/ohci/ohci.c | 6 +- src/portable/raspberrypi/pio_usb/hcd_pio_usb.c | 6 +- src/portable/renesas/rusb2/hcd_rusb2.c | 6 +- src/portable/synopsys/dwc2/hcd_dwc2.c | 18 ++-- 15 files changed, 152 insertions(+), 126 deletions(-) create mode 100644 .idea/debugServers/esp32s2.xml create mode 100644 .idea/debugServers/stm32f769.xml create mode 100644 .idea/debugServers/stm32h563.xml create mode 100644 .idea/debugServers/stm32h743.xml (limited to 'examples/host/cdc_msc_hid/src') diff --git a/.idea/debugServers/esp32s2.xml b/.idea/debugServers/esp32s2.xml new file mode 100644 index 000000000..6a4aff3da --- /dev/null +++ b/.idea/debugServers/esp32s2.xml @@ -0,0 +1,14 @@ + + + + $USER_HOME$/.espressif/tools/xtensa-esp-elf-gdb/14.2_20240403/xtensa-esp-elf-gdb/bin/xtensa-esp32s2-elf-gdb + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/rp2350.xml b/.idea/debugServers/rp2350.xml index 5e092f3c4..52243a297 100644 --- a/.idea/debugServers/rp2350.xml +++ b/.idea/debugServers/rp2350.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/debugServers/stm32f769.xml b/.idea/debugServers/stm32f769.xml new file mode 100644 index 000000000..2fb322a0f --- /dev/null +++ b/.idea/debugServers/stm32f769.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/stm32h563.xml b/.idea/debugServers/stm32h563.xml new file mode 100644 index 000000000..9bf6db6e9 --- /dev/null +++ b/.idea/debugServers/stm32h563.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/debugServers/stm32h743.xml b/.idea/debugServers/stm32h743.xml new file mode 100644 index 000000000..63680b78c --- /dev/null +++ b/.idea/debugServers/stm32h743.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 1d7e18e6e..0e9c99766 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -30,13 +30,11 @@ //--------------------------------------------------------------------+ static scsi_inquiry_resp_t inquiry_resp; -bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) -{ +static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data) { msc_cbw_t const* cbw = cb_data->cbw; msc_csw_t const* csw = cb_data->csw; - if (csw->status != 0) - { + if (csw->status != 0) { printf("Inquiry failed\r\n"); return false; } @@ -55,16 +53,14 @@ bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_da } //------------- IMPLEMENTATION -------------// -void tuh_msc_mount_cb(uint8_t dev_addr) -{ +void tuh_msc_mount_cb(uint8_t dev_addr) { printf("A MassStorage device is mounted\r\n"); uint8_t const lun = 0; tuh_msc_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb, 0); } -void tuh_msc_umount_cb(uint8_t dev_addr) -{ +void tuh_msc_umount_cb(uint8_t dev_addr) { (void) dev_addr; printf("A MassStorage device is unmounted\r\n"); } diff --git a/src/host/hcd.h b/src/host/hcd.h index b20d96d54..1f2704a10 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -95,7 +95,7 @@ typedef struct { uint8_t hub_addr; uint8_t hub_port; uint8_t speed; -} hcd_devtree_info_t; +} tuh_bus_info_t; //--------------------------------------------------------------------+ // Memory API @@ -186,12 +186,8 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr); // USBH implemented API //--------------------------------------------------------------------+ -// Get device tree information of a device -// USB device tree can be complicated and manged by USBH, this help HCD to retrieve -// needed topology info to carry out its work -extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info); - -//------------- Event API -------------// +// Get device port information +extern bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info); // Called by HCD to notify stack extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); @@ -239,4 +235,4 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred } #endif -#endif /* _TUSB_HCD_H_ */ +#endif diff --git a/src/host/usbh.c b/src/host/usbh.c index 0492fb2f2..c063c97f9 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -92,19 +92,7 @@ TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_si // USBH-HCD common data structure //--------------------------------------------------------------------+ typedef struct { - // port - uint8_t rhport; - uint8_t hub_addr; - uint8_t hub_port; - uint8_t speed; -} usbh_dev0_t; - -typedef struct { - // port, must be same layout as usbh_dev0_t - uint8_t rhport; - uint8_t hub_addr; - uint8_t hub_port; - uint8_t speed; + tuh_bus_info_t bus_info; // Device State struct TU_ATTR_PACKED { @@ -231,8 +219,8 @@ static usbh_class_driver_t const usbh_class_drivers[] = { enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; // Additional class drivers implemented by application -tu_static usbh_class_driver_t const * _app_driver = NULL; -tu_static uint8_t _app_driver_count = 0; +static usbh_class_driver_t const * _app_driver = NULL; +static uint8_t _app_driver_count = 0; #define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT) @@ -255,9 +243,6 @@ static inline usbh_class_driver_t const *get_driver(uint8_t drv_id) { // sum of end device + hub #define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB) -// Device with address = 0 for enumeration -static usbh_dev0_t _dev0; - // all devices excluding zero-address // hub address start from CFG_TUH_DEVICE_MAX+1 // TODO: hub can has its own simpler struct to save memory @@ -299,6 +284,8 @@ CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf; typedef struct { uint8_t controller_id; // controller ID uint8_t enumerating_daddr; // device address of the device being enumerated + + tuh_bus_info_t dev0_bus; // bus info for dev0 in enumeration } usbh_data_t; static usbh_data_t _usbh_data = { @@ -353,9 +340,10 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) { return true; } -tusb_speed_t tuh_speed_get(uint8_t dev_addr) { - usbh_device_t *dev = get_device(dev_addr); - return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed); +tusb_speed_t tuh_speed_get(uint8_t daddr) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(daddr, &bus_info); + return bus_info.speed; } bool tuh_rhport_is_active(uint8_t rhport) { @@ -423,9 +411,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } // Device - tu_memclr(&_dev0, sizeof(_dev0)); tu_memclr(_usbh_devices, sizeof(_usbh_devices)); tu_memclr(&_ctrl_xfer, sizeof(_ctrl_xfer)); + tu_memclr(&_usbh_data, sizeof(_usbh_data)); _usbh_data.controller_id = TUSB_INDEX_INVALID_8; _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; @@ -530,8 +518,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { // due to the shared control buffer, we must fully complete enumerating one device first. // TODO better to have an separated queue for newly attached devices if (_usbh_data.enumerating_daddr != TUSB_INDEX_INVALID_8) { - if (event.rhport == _dev0.rhport && - event.connection.hub_addr == _dev0.hub_addr && event.connection.hub_port == _dev0.hub_port) { + if (event.rhport == _usbh_data.dev0_bus.rhport && + event.connection.hub_addr == _usbh_data.dev0_bus.hub_addr && event.connection.hub_port == _usbh_data.dev0_bus.hub_port) { // Some device can cause multiple duplicated attach events // drop current enumerating and start over for a proper port reset // abort/cancel current enumeration and start new one @@ -859,7 +847,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { const uint8_t dir = tu_edpt_dir(ep_addr); if (epnum == 0) { - // Also include dev0 for aborting enumerating + // Also include dev0_bus for aborting enumerating const uint8_t rhport = usbh_get_rhport(daddr); // control transfer: only 1 control at a time, check if we are aborting the current one @@ -871,7 +859,7 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { TU_VERIFY(dev); TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy - hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr); + hcd_edpt_abort_xfer(dev->bus_info.rhport, daddr, ep_addr); // mark as ready and release endpoint if transfer is aborted dev->ep_status[epnum][dir].busy = false; @@ -885,9 +873,10 @@ bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) { // USBH API For Class Driver //--------------------------------------------------------------------+ -uint8_t usbh_get_rhport(uint8_t dev_addr) { - usbh_device_t *dev = get_device(dev_addr); - return dev ? dev->rhport : _dev0.rhport; +uint8_t usbh_get_rhport(uint8_t daddr) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(daddr, &bus_info); + return bus_info.rhport; } uint8_t *usbh_get_enum_buf(void) { @@ -972,7 +961,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t* bu dev->ep_callback[epnum][dir].user_data = user_data; #endif - if (hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes)) { + if (hcd_edpt_xfer(dev->bus_info.rhport, dev_addr, ep_addr, buffer, total_bytes)) { TU_LOG_USBH("OK\r\n"); return true; } else { @@ -1024,19 +1013,14 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr) { // HCD Event Handler //--------------------------------------------------------------------+ -void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info) { - usbh_device_t const* dev = get_device(dev_addr); +bool hcd_bus_info_get(uint8_t daddr, tuh_bus_info_t* bus_info) { + usbh_device_t const* dev = get_device(daddr); if (dev) { - devtree_info->rhport = dev->rhport; - devtree_info->hub_addr = dev->hub_addr; - devtree_info->hub_port = dev->hub_port; - devtree_info->speed = dev->speed; + *bus_info = dev->bus_info; } else { - devtree_info->rhport = _dev0.rhport; - devtree_info->hub_addr = _dev0.hub_addr; - devtree_info->hub_port = _dev0.hub_port; - devtree_info->speed = _dev0.speed; + *bus_info = _usbh_data.dev0_bus; } + return true; } TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr) { @@ -1269,10 +1253,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool is_hub_addr(uint8_t daddr) { // a device unplugged from rhport:hub_addr:hub_port static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) { - // dev0 is unplugged - if ((_usbh_data.enumerating_daddr == 0) && (rhport == _dev0.rhport) && - (hub_addr == _dev0.hub_addr) && (hub_port == _dev0.hub_port)) { - hcd_device_close(_dev0.rhport, 0); + // dev0_bus is unplugged + if ((_usbh_data.enumerating_daddr == 0) && (rhport == _usbh_data.dev0_bus.rhport) && + (hub_addr == _usbh_data.dev0_bus.hub_addr) && (hub_port == _usbh_data.dev0_bus.hub_port)) { + hcd_device_close(_usbh_data.dev0_bus.rhport, 0); if (_ctrl_xfer.daddr == 0) { _control_set_xfer_stage(CONTROL_STAGE_IDLE); } @@ -1288,9 +1272,9 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu uint8_t const daddr = dev_id + 1; // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub - if (dev->rhport == rhport && dev->connected && - (hub_addr == 0 || dev->hub_addr == hub_addr) && - (hub_port == 0 || dev->hub_port == hub_port)) { + if (dev->bus_info.rhport == rhport && dev->connected && + (hub_addr == 0 || dev->bus_info.hub_addr == hub_addr) && + (hub_port == 0 || dev->bus_info.hub_port == hub_port)) { TU_LOG_USBH("[%u:%u:%u] unplugged address = %u\r\n", rhport, hub_addr, hub_port, daddr); if (is_hub_addr(daddr)) { @@ -1439,12 +1423,12 @@ static void process_enumeration(tuh_xfer_t* xfer) { return; } - _dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + _usbh_data.dev0_bus.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : (port_status.status.low_speed) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; // Acknowledge Port Reset Change if (port_status.change.reset) { - hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, + hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, process_enumeration, ENUM_ADDR0_DEVICE_DESC); } break; @@ -1452,7 +1436,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { case ENUM_HUB_GET_STATUS_2: tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, + TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_2),); break; @@ -1462,7 +1446,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { // Acknowledge Port Reset Change if Reset Successful if (port_status.change.reset) { - TU_ASSERT(hub_port_clear_reset_change(_dev0.hub_addr, _dev0.hub_port, + TU_ASSERT(hub_port_clear_reset_change(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, process_enumeration, ENUM_SET_ADDR),); } break; @@ -1495,7 +1479,7 @@ static void process_enumeration(tuh_xfer_t* xfer) { new_dev->addressed = 1; _usbh_data.enumerating_daddr = new_addr; - hcd_device_close(_dev0.rhport, 0); // close dev0 + hcd_device_close(_usbh_data.dev0_bus.rhport, 0); // close dev0_bus TU_ASSERT(usbh_edpt_control_open(new_addr, new_dev->ep0_size),); // open new control endpoint @@ -1667,38 +1651,38 @@ static void process_enumeration(tuh_xfer_t* xfer) { } static bool enum_new_device(hcd_event_t* event) { - _dev0.rhport = event->rhport; - _dev0.hub_addr = event->connection.hub_addr; - _dev0.hub_port = event->connection.hub_port; + _usbh_data.dev0_bus.rhport = event->rhport; + _usbh_data.dev0_bus.hub_addr = event->connection.hub_addr; + _usbh_data.dev0_bus.hub_port = event->connection.hub_port; - if (_dev0.hub_addr == 0) { + if (_usbh_data.dev0_bus.hub_addr == 0) { // connected directly to roothub // wait until device connection is stable TODO non blocking tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // device unplugged while delaying - if (!hcd_port_connect_status(_dev0.rhport)) { + if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { enum_full_complete(); return true; } - hcd_port_reset(_dev0.rhport); // reset device + hcd_port_reset(_usbh_data.dev0_bus.rhport); // reset device // Since we are in middle of rhport reset, frame number is not available yet. // need to depend on tusb_time_millis_api() tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS); - hcd_port_reset_end(_dev0.rhport); + hcd_port_reset_end(_usbh_data.dev0_bus.rhport); // device unplugged while delaying - if (!hcd_port_connect_status(_dev0.rhport)) { + if (!hcd_port_connect_status(_usbh_data.dev0_bus.rhport)) { enum_full_complete(); return true; } - _dev0.speed = hcd_port_speed_get(_dev0.rhport); - TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]); + _usbh_data.dev0_bus.speed = hcd_port_speed_get(_usbh_data.dev0_bus.rhport); + TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_usbh_data.dev0.speed]); // fake transfer to kick-off the enumeration process tuh_xfer_t xfer; @@ -1715,7 +1699,7 @@ static bool enum_new_device(hcd_event_t* event) { tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS); // ENUM_HUB_GET_STATUS - TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl, + TU_ASSERT(hub_port_get_status(_usbh_data.dev0_bus.hub_addr, _usbh_data.dev0_bus.hub_port, _usbh_epbuf.ctrl, process_enumeration, ENUM_HUB_CLEAR_RESET_1)); } #endif // hub @@ -1749,10 +1733,7 @@ static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { TU_LOG_USBH("Set Address = %d\r\n", new_addr); usbh_device_t* new_dev = get_device(new_addr); - new_dev->rhport = _dev0.rhport; - new_dev->hub_addr = _dev0.hub_addr; - new_dev->hub_port = _dev0.hub_port; - new_dev->speed = _dev0.speed; + new_dev->bus_info = _usbh_data.dev0_bus; new_dev->connected = 1; new_dev->ep0_size = desc_device->bMaxPacketSize0; @@ -1768,7 +1749,7 @@ static bool enum_request_set_addr(tusb_desc_device_t const* desc_device) { .wLength = 0 }; tuh_xfer_t xfer = { - .daddr = 0, // dev0 + .daddr = 0, .ep_addr = 0, .setup = &request, .buffer = NULL, @@ -1841,7 +1822,7 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat // Find driver for this interface for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) { usbh_class_driver_t const * driver = get_driver(drv_id); - if (driver && driver->open(dev->rhport, dev_addr, desc_itf, drv_len) ) { + if (driver && driver->open(dev->bus_info.rhport, dev_addr, desc_itf, drv_len) ) { // open successfully TU_LOG_USBH(" %s opened\r\n", driver->name); @@ -1860,9 +1841,9 @@ static bool enum_parse_configuration_desc(uint8_t dev_addr, tusb_desc_configurat break; // exit driver find loop } - if ( drv_id == TOTAL_DRIVER_COUNT - 1 ) { + if (drv_id == TOTAL_DRIVER_COUNT - 1) { TU_LOG_USBH("[%u:%u] Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n", - dev->rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); + dev->bus_info.rhport, dev_addr, desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol); } } @@ -1909,8 +1890,8 @@ static void enum_full_complete(void) { _usbh_data.enumerating_daddr = TUSB_INDEX_INVALID_8; #if CFG_TUH_HUB - if (_dev0.hub_addr) { - hub_edpt_status_xfer(_dev0.hub_addr); // get next hub status + if (_usbh_data.dev0_bus.hub_addr != 0) { + hub_edpt_status_xfer(_usbh_data.dev0_bus.hub_addr); // get next hub status } #endif diff --git a/src/host/usbh_pvt.h b/src/host/usbh_pvt.h index bfa1fb2ba..61b012493 100644 --- a/src/host/usbh_pvt.h +++ b/src/host/usbh_pvt.h @@ -63,7 +63,7 @@ usbh_class_driver_t const* usbh_app_driver_get_cb(uint8_t* driver_count) TU_ATTR // Call by class driver to tell USBH that it has complete the enumeration void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); -uint8_t usbh_get_rhport(uint8_t dev_addr); +uint8_t usbh_get_rhport(uint8_t daddr); uint8_t* usbh_get_enum_buf(void); diff --git a/src/portable/ehci/ehci.c b/src/portable/ehci/ehci.c index 7451f69a3..141a2c026 100644 --- a/src/portable/ehci/ehci.c +++ b/src/portable/ehci/ehci.c @@ -837,8 +837,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c tu_memclr(p_qhd, sizeof(ehci_qhd_t)); } - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); uint8_t const xfer_type = ep_desc->bmAttributes.xfer; uint8_t const interval = ep_desc->bInterval; @@ -846,7 +846,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c p_qhd->dev_addr = dev_addr; p_qhd->fl_inactive_next_xact = 0; p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress); - p_qhd->ep_speed = devtree_info.speed; + p_qhd->ep_speed = bus_info.speed; p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0; p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static async list head p_qhd->max_packet_size = tu_edpt_packet_size(ep_desc); @@ -887,8 +887,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c default: break; } - p_qhd->fl_hub_addr = devtree_info.hub_addr; - p_qhd->fl_hub_port = devtree_info.hub_port; + p_qhd->fl_hub_addr = bus_info.hub_addr; + p_qhd->fl_hub_port = bus_info.hub_port; p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet //------------- HCD Management Data -------------// diff --git a/src/portable/mentor/musb/hcd_musb.c b/src/portable/mentor/musb/hcd_musb.c index 811043d74..97ef46152 100644 --- a/src/portable/mentor/musb/hcd_musb.c +++ b/src/portable/mentor/musb/hcd_musb.c @@ -695,16 +695,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet _hcd.pipe0.length = 8; _hcd.pipe0.remaining = 0; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); - switch (devtree.speed) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: USB0->TYPE0 = USB_TYPE0_SPEED_LOW; break; case TUSB_SPEED_FULL: USB0->TYPE0 = USB_TYPE0_SPEED_FULL; break; case TUSB_SPEED_HIGH: USB0->TYPE0 = USB_TYPE0_SPEED_HIGH; break; } - USB0->TXHUBADDR0 = devtree.hub_addr; - USB0->TXHUBPORT0 = devtree.hub_port; + USB0->TXHUBADDR0 = bus_info.hub_addr; + USB0->TXHUBPORT0 = bus_info.hub_port; USB0->TXFUNCADDR0 = dev_addr; USB0->CSRL0 = USB_CSRL0_TXRDY | USB_CSRL0_SETUP; return true; @@ -744,9 +744,9 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const pipe->remaining = 0; uint8_t pipe_type = 0; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); - switch (devtree.speed) { + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + switch (bus_info.speed) { default: return false; case TUSB_SPEED_LOW: pipe_type |= USB_TXTYPE1_SPEED_LOW; break; case TUSB_SPEED_FULL: pipe_type |= USB_TXTYPE1_SPEED_FULL; break; @@ -763,8 +763,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const hw_endpoint_t volatile *regs = edpt_regs(pipenum - 1); if (dir_tx) { fadr->TXFUNCADDR = dev_addr; - fadr->TXHUBADDR = devtree.hub_addr; - fadr->TXHUBPORT = devtree.hub_port; + fadr->TXHUBADDR = bus_info.hub_addr; + fadr->TXHUBPORT = bus_info.hub_port; regs->TXMAXP = mps; regs->TXTYPE = pipe_type | epn; regs->TXINTERVAL = ep_desc->bInterval; @@ -775,8 +775,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const USB0->TXIE |= TU_BIT(pipenum); } else { fadr->RXFUNCADDR = dev_addr; - fadr->RXHUBADDR = devtree.hub_addr; - fadr->RXHUBPORT = devtree.hub_port; + fadr->RXHUBADDR = bus_info.hub_addr; + fadr->RXHUBPORT = bus_info.hub_port; regs->RXMAXP = mps; regs->RXTYPE = pipe_type | epn; regs->RXINTERVAL = ep_desc->bInterval; diff --git a/src/portable/ohci/ohci.c b/src/portable/ohci/ohci.c index 672ad0443..465b6731c 100644 --- a/src/portable/ohci/ohci.c +++ b/src/portable/ohci/ohci.c @@ -328,13 +328,13 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t tu_memclr(p_ed, sizeof(ohci_ed_t)); } - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); p_ed->dev_addr = dev_addr; p_ed->ep_number = ep_addr & 0x0F; p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT); - p_ed->speed = devtree_info.speed; + p_ed->speed = bus_info.speed; p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0; p_ed->max_packet_size = ep_size; diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c index 225a44dcf..0e3d0d31a 100644 --- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c +++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c @@ -114,9 +114,9 @@ void hcd_int_disable(uint8_t rhport) { //--------------------------------------------------------------------+ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *desc_ep) { - hcd_devtree_info_t dev_tree; - hcd_devtree_get_info(dev_addr, &dev_tree); - bool const need_pre = (dev_tree.hub_addr && dev_tree.speed == TUSB_SPEED_LOW); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); + bool const need_pre = (bus_info.hub_addr && bus_info.speed == TUSB_SPEED_LOW); uint8_t const pio_rhport = RHPORT_PIO(rhport); return pio_usb_host_endpoint_open(pio_rhport, dev_addr, (uint8_t const *) desc_ep, need_pre); diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c index 3e4b36981..e6975287d 100644 --- a/src/portable/renesas/rusb2/hcd_rusb2.c +++ b/src/portable/renesas/rusb2/hcd_rusb2.c @@ -662,13 +662,13 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const if (0 == epn) { rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK; - hcd_devtree_info_t devtree; - hcd_devtree_get_info(dev_addr, &devtree); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); uint16_t volatile *devadd = (uint16_t volatile *)(uintptr_t) &rusb->DEVADD[0]; devadd += dev_addr; while (rusb->DCPCTR_b.PBUSY) {} rusb->DCPMAXP = (dev_addr << 12) | mps; - *devadd = (TUSB_SPEED_FULL == devtree.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS; + *devadd = (TUSB_SPEED_FULL == bus_info.speed) ? RUSB2_DEVADD_USBSPD_FS : RUSB2_DEVADD_USBSPD_LS; _hcd.ctl_mps[dev_addr] = mps; return true; } diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c index 53bc0b059..6fd343686 100644 --- a/src/portable/synopsys/dwc2/hcd_dwc2.c +++ b/src/portable/synopsys/dwc2/hcd_dwc2.c @@ -475,8 +475,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* dwc2_regs_t* dwc2 = DWC2_REG(rhport); const tusb_speed_t rh_speed = hprt_speed_get(dwc2); - hcd_devtree_info_t devtree_info; - hcd_devtree_get_info(dev_addr, &devtree_info); + tuh_bus_info_t bus_info; + hcd_bus_info_get(dev_addr, &bus_info); // find a free endpoint const uint8_t ep_id = edpt_alloc(); @@ -487,7 +487,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* hcchar_bm->ep_size = tu_edpt_packet_size(desc_ep); hcchar_bm->ep_num = tu_edpt_number(desc_ep->bEndpointAddress); hcchar_bm->ep_dir = tu_edpt_dir(desc_ep->bEndpointAddress); - hcchar_bm->low_speed_dev = (devtree_info.speed == TUSB_SPEED_LOW) ? 1 : 0; + hcchar_bm->low_speed_dev = (bus_info.speed == TUSB_SPEED_LOW) ? 1 : 0; hcchar_bm->ep_type = desc_ep->bmAttributes.xfer; // ep_type matches TUSB_XFER_* hcchar_bm->err_multi_count = 0; hcchar_bm->dev_addr = dev_addr; @@ -496,21 +496,21 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t* hcchar_bm->enable = 1; dwc2_channel_split_t* hcsplt_bm = &edpt->hcsplt_bm; - hcsplt_bm->hub_port = devtree_info.hub_port; - hcsplt_bm->hub_addr = devtree_info.hub_addr; + hcsplt_bm->hub_port = bus_info.hub_port; + hcsplt_bm->hub_addr = bus_info.hub_addr; hcsplt_bm->xact_pos = 0; hcsplt_bm->split_compl = 0; - hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && devtree_info.speed != TUSB_SPEED_HIGH) ? 1 : 0; + hcsplt_bm->split_en = (rh_speed == TUSB_SPEED_HIGH && bus_info.speed != TUSB_SPEED_HIGH) ? 1 : 0; - edpt->speed = devtree_info.speed; + edpt->speed = bus_info.speed; edpt->next_pid = HCTSIZ_PID_DATA0; if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) { edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); - if (devtree_info.speed == TUSB_SPEED_FULL) { + if (bus_info.speed == TUSB_SPEED_FULL) { edpt->uframe_interval <<= 3; } } else if (desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) { - if (devtree_info.speed == TUSB_SPEED_HIGH) { + if (bus_info.speed == TUSB_SPEED_HIGH) { edpt->uframe_interval = 1 << (desc_ep->bInterval - 1); } else { edpt->uframe_interval = desc_ep->bInterval << 3; -- cgit v1.3.1 From baf67539fc2d328a6274c35c18c90da27c37bc60 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 May 2025 10:28:42 +0700 Subject: fix warnings, minor clean up --- .github/actions/setup_toolchain/toolchain.json | 2 +- examples/host/cdc_msc_hid/src/hid_app.c | 100 ++++++++----------------- src/class/cdc/cdc_host.c | 2 +- src/class/hid/hid_host.c | 6 +- src/host/hub.c | 1 - src/host/usbh.c | 5 +- 6 files changed, 41 insertions(+), 75 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') diff --git a/.github/actions/setup_toolchain/toolchain.json b/.github/actions/setup_toolchain/toolchain.json index ea07ca344..f7123ef11 100644 --- a/.github/actions/setup_toolchain/toolchain.json +++ b/.github/actions/setup_toolchain/toolchain.json @@ -1,7 +1,7 @@ { "aarch64-gcc": "https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz", "arm-clang": "https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-19.1.1/LLVM-ET-Arm-19.1.1-Linux-x86_64.tar.xz", - "arm-gcc": "https://github.com/xpack-dev-tools/gcc-xpack/releases/download/v14.2.0-1/xpack-gcc-14.2.0-1-linux-x64.tar.gz", + "arm-gcc": "https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz", "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz", "rx-gcc": "https://github.com/hathach/rx_device/releases/download/0.0.1/gcc-8.3.0.202411-GNURX-ELF.run", diff --git a/examples/host/cdc_msc_hid/src/hid_app.c b/examples/host/cdc_msc_hid/src/hid_app.c index a751c9c80..6f01d6f45 100644 --- a/examples/host/cdc_msc_hid/src/hid_app.c +++ b/examples/host/cdc_msc_hid/src/hid_app.c @@ -29,14 +29,9 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ +#define MAX_REPORT 4 -// If your host terminal support ansi escape code such as TeraTerm -// it can be use to simulate mouse cursor movement within terminal -#define USE_ANSI_ESCAPE 0 - -#define MAX_REPORT 4 - -static uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; +static uint8_t const keycode2ascii[128][2] = {HID_KEYCODE_TO_ASCII}; // Each HID instance can has multiple reports static struct { @@ -45,8 +40,8 @@ static struct { } hid_info[CFG_TUH_HID]; static void process_kbd_report(hid_keyboard_report_t const *report); -static void process_mouse_report(hid_mouse_report_t const * report); -static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +static void process_mouse_report(hid_mouse_report_t const *report); +static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len); void hid_app_task(void) { // nothing to do @@ -70,7 +65,7 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_re printf("HID Interface Protocol = %s\r\n", protocol_str[itf_protocol]); - // By default host stack will use activate boot protocol on supported interface. + // By default, host stack will use boot protocol on supported interface. // Therefore for this simple example, we only need to parse generic report descriptor (with built-in parser) if (itf_protocol == HID_ITF_PROTOCOL_NONE) { hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len); @@ -121,7 +116,7 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons //--------------------------------------------------------------------+ // look up new key in previous keys -static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8_t keycode) { +static inline bool find_key_in_report(hid_keyboard_report_t const *report, uint8_t keycode) { for (uint8_t i = 0; i < 6; i++) { if (report->keycode[i] == keycode) { return true; @@ -130,28 +125,25 @@ static inline bool find_key_in_report(hid_keyboard_report_t const* report, uint8 return false; } -static void process_kbd_report(hid_keyboard_report_t const *report) -{ - static hid_keyboard_report_t prev_report = { 0, 0, {0} }; // previous report to check key released +static void process_kbd_report(hid_keyboard_report_t const *report) { + static hid_keyboard_report_t prev_report = {0, 0, {0}};// previous report to check key released //------------- example code ignore control (non-printable) key affects -------------// - for(uint8_t i=0; i<6; i++) - { - if ( report->keycode[i] ) - { - if ( find_key_in_report(&prev_report, report->keycode[i]) ) - { + for (uint8_t i = 0; i < 6; i++) { + if (report->keycode[i]) { + if (find_key_in_report(&prev_report, report->keycode[i])) { // exist in previous report means the current key is holding - }else - { + } else { // not existed in previous report means the current key is pressed bool const is_shift = report->modifier & (KEYBOARD_MODIFIER_LEFTSHIFT | KEYBOARD_MODIFIER_RIGHTSHIFT); uint8_t ch = keycode2ascii[report->keycode[i]][is_shift ? 1 : 0]; putchar(ch); - if ( ch == '\r' ) putchar('\n'); // added new line for enter key + if (ch == '\r') { + putchar('\n'); + } - #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? - fflush(stdout); // flush right away, else nanolib will wait for newline + #ifndef __ICCARM__ // TODO IAR doesn't support stream control ? + fflush(stdout);// flush right away, else nanolib will wait for newline #endif } } @@ -166,55 +158,22 @@ static void process_kbd_report(hid_keyboard_report_t const *report) //--------------------------------------------------------------------+ static void cursor_movement(int8_t x, int8_t y, int8_t wheel) { -#if USE_ANSI_ESCAPE - // Move X using ansi escape - if ( x < 0) - { - printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left - }else if ( x > 0) - { - printf(ANSI_CURSOR_FORWARD(%d), x); // move right - } - - // Move Y using ansi escape - if ( y < 0) - { - printf(ANSI_CURSOR_UP(%d), (-y)); // move up - }else if ( y > 0) - { - printf(ANSI_CURSOR_DOWN(%d), y); // move down - } - - // Scroll using ansi escape - if (wheel < 0) - { - printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up - }else if (wheel > 0) - { - printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down - } - - printf("\r\n"); -#else printf("(%d %d %d)\r\n", x, y, wheel); -#endif } -static void process_mouse_report(hid_mouse_report_t const * report) -{ - static hid_mouse_report_t prev_report = { 0 }; +static void process_mouse_report(hid_mouse_report_t const *report) { + static hid_mouse_report_t prev_report = {0}; - //------------- button state -------------// + // button state uint8_t button_changed_mask = report->buttons ^ prev_report.buttons; - if ( button_changed_mask & report->buttons) - { + if (button_changed_mask & report->buttons) { printf(" %c%c%c ", - report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', - report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', - report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); + report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', + report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', + report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); } - //------------- cursor movement -------------// + // cursor movement cursor_movement(report->x, report->y, report->wheel); } @@ -263,18 +222,23 @@ static void process_generic_report(uint8_t dev_addr, uint8_t instance, uint8_t c if (rpt_info->usage_page == HID_USAGE_PAGE_DESKTOP) { switch (rpt_info->usage) { case HID_USAGE_DESKTOP_KEYBOARD: - TU_LOG1("HID receive keyboard report\r\n"); + TU_LOG2("HID receive keyboard report\r\n"); // Assume keyboard follow boot report layout process_kbd_report((hid_keyboard_report_t const *) report); break; case HID_USAGE_DESKTOP_MOUSE: - TU_LOG1("HID receive mouse report\r\n"); + TU_LOG2("HID receive mouse report\r\n"); // Assume mouse follow boot report layout process_mouse_report((hid_mouse_report_t const *) report); break; default: + printf("report[%u] ", rpt_info->report_id); + for (uint8_t i = 0; i < len; i++) { + printf("%02X ", report[i]); + } + printf("\r\n"); break; } } diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 4058857c5..bf245db3f 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -672,7 +672,7 @@ void cdch_close(uint8_t daddr) { bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { // TODO handle stall response, retry failed transfer ... - TU_ASSERT(event == XFER_RESULT_SUCCESS); + 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); diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index a3cc7d6d7..57e437196 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -444,7 +444,7 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t hidh_epbuf_t* epbuf = get_hid_epbuf(idx); if (dir == TUSB_DIR_IN) { - TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx); + TU_LOG_DRV(" [idx=%u] Get Report callback\r\n", idx); TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2); tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes); } else { @@ -461,7 +461,9 @@ void hidh_close(uint8_t daddr) { hidh_interface_t* p_hid = &_hidh_itf[i]; if (p_hid->daddr == daddr) { TU_LOG_DRV(" HIDh close addr = %u index = %u\r\n", daddr, i); - if (tuh_hid_umount_cb) tuh_hid_umount_cb(daddr, i); + if (tuh_hid_umount_cb) { + tuh_hid_umount_cb(daddr, i); + } tu_memclr(p_hid, sizeof(hidh_interface_t)); } } diff --git a/src/host/hub.c b/src/host/hub.c index 0ed0e0c42..0b172a596 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -201,7 +201,6 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, bool hub_port_get_status_local(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) { (void) hub_port; - TU_VERIFY(hub_addr > CFG_TUH_DEVICE_MAX); hub_interface_t* p_hub = get_hub_itf(hub_addr); *resp = p_hub->port_status; return true; diff --git a/src/host/usbh.c b/src/host/usbh.c index a3d79a105..8ab1402dc 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -579,7 +579,8 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr); - TU_LOG_USBH("on EP %02X with %u bytes: %s\r\n", ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); + TU_LOG_USBH("[:%u] on EP %02X with %u bytes: %s\r\n", + event.dev_addr, ep_addr, (unsigned int) event.xfer_complete.len, tu_str_xfer_result[event.xfer_complete.result]); if (event.dev_addr == 0) { // device 0 only has control endpoint @@ -618,7 +619,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) { uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; usbh_class_driver_t const* driver = get_driver(drv_id); if (driver) { - TU_LOG_USBH("%s xfer callback\r\n", driver->name); + TU_LOG_USBH(" %s xfer callback\r\n", driver->name); driver->xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len); } else { -- cgit v1.3.1 From d4abf43f226b5594c935c60c38d05a90359763e1 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Jun 2025 22:16:13 +0700 Subject: 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(-) (limited to 'examples/host/cdc_msc_hid/src') 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; -- cgit v1.3.1 From fa3ec44533ff986688318c3f80e9f373f55318f0 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 19 Jun 2025 17:22:26 +0700 Subject: revert CFG_TUH_CDC_DTR/RTS_CONTROL_ON_ENUM --- examples/host/cdc_msc_hid/src/tusb_config.h | 5 +-- .../host/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(-) (limited to 'examples/host/cdc_msc_hid/src') 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 -- cgit v1.3.1 From adf6cbfe03523cd8f7e23cb7f2edbb4304a6cd89 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 20 Jun 2025 12:52:34 +0700 Subject: 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(-) (limited to 'examples/host/cdc_msc_hid/src') 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 { -- cgit v1.3.1 From d86362414e9c467d93f37672228e220a718de81d Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 27 Jun 2025 17:57:26 +0700 Subject: clean up --- examples/host/cdc_msc_hid/src/tusb_config.h | 3 +- .../host/cdc_msc_hid_freertos/src/tusb_config.h | 1 + src/class/cdc/cdc_host.c | 34 +++++++++++----------- 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'examples/host/cdc_msc_hid/src') 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)); - - 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; - } - } + } 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; } - } + } + } + } return false; } -- cgit v1.3.1 From a8b5e2bfc0a2d35ba775f7b2de81d531ed525e41 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 2 Jul 2025 15:38:14 +0700 Subject: 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(-) (limited to 'examples/host/cdc_msc_hid/src') 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 -- cgit v1.3.1