diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 7926aa9fc..81337cde4 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -117,8 +117,6 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, uint static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void acm_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool acm_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool acm_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool acm_set_control_line_state(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); @@ -169,8 +167,6 @@ static bool pl2303_open(uint8_t daddr, tusb_desc_interface_t const * itf_desc, u static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer); -static bool pl2303_set_baudrate(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); -static bool pl2303_set_data_format(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); static bool pl2303_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data); #endif @@ -228,10 +224,9 @@ static const cdch_serial_driver_t serial_drivers[] = { .open = acm_open, .process_set_config = acm_process_set_config, .request_complete = acm_internal_control_complete, - .set_control_line_state = acm_set_control_line_state, - .set_baudrate = acm_set_baudrate, - .set_data_format = acm_set_data_format, + .set_baudrate = acm_set_line_coding, + .set_data_format = acm_set_line_coding, .set_line_coding = acm_set_line_coding, DRIVER_NAME_DECLARE("ACM") }, @@ -290,8 +285,8 @@ static const cdch_serial_driver_t serial_drivers[] = { .process_set_config = pl2303_process_set_config, .request_complete = pl2303_internal_control_complete, .set_control_line_state = pl2303_set_modem_ctrl, - .set_baudrate = pl2303_set_baudrate, - .set_data_format = pl2303_set_data_format, + .set_baudrate = pl2303_set_line_coding, + .set_data_format = pl2303_set_line_coding, .set_line_coding = pl2303_set_line_coding, DRIVER_NAME_DECLARE("PL2303") } @@ -586,10 +581,11 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits)); cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid]; p_cdc->requested_line.coding = *line_coding; + p_cdc->user_complete_cb = complete_cb; if (driver->set_line_coding) { // driver support set_line_coding request - TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb, user_data)); + TU_VERIFY(driver->set_line_coding(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); if (!complete_cb) { p_cdc->line.coding = *line_coding; @@ -598,7 +594,6 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding, // driver does not support set_line_coding and need 2 stage to set baudrate and data format separately if (complete_cb) { // non-blocking - p_cdc->user_complete_cb = complete_cb; TU_VERIFY(driver->set_baudrate(p_cdc, cdch_set_line_coding_stage1_baudrate_complete, user_data)); } else { // blocking @@ -795,7 +790,7 @@ bool cdch_set_config(uint8_t daddr, uint8_t itf_num) { return true; } -static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, bool success) { +static void set_config_complete(cdch_interface_t *p_cdc, bool success) { if (success) { const uint8_t idx = get_idx_by_ptr(p_cdc); p_cdc->mounted = true; @@ -811,6 +806,7 @@ static void set_config_complete(cdch_interface_t *p_cdc, uint8_t itf_offset, boo } // notify usbh that driver enumeration is complete + const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset); } @@ -821,8 +817,7 @@ static void cdch_process_set_config(tuh_xfer_t *xfer) { const cdch_serial_driver_t *driver = &serial_drivers[p_cdc->serial_drid]; if (!driver->process_set_config(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -858,11 +853,9 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ATTR_FALLTHROUGH; #endif - case ENUM_SET_LINE_COMPLETE: { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, true); + case ENUM_SET_LINE_COMPLETE: + set_config_complete(p_cdc, true); break; - } default: return false; @@ -874,11 +867,8 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { static void cdch_process_line_state_on_enum(tuh_xfer_t *xfer) { cdch_interface_t *p_cdc = get_itf_by_xfer(xfer); TU_ASSERT(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT,); - TU_LOG_DRV(" xfer result = %u\r\n", xfer->result); - if (xfer->result != XFER_RESULT_SUCCESS || !set_line_state_on_enum(p_cdc, xfer)) { - const uint8_t itf_offset = (p_cdc->serial_drid == SERIAL_DRIVER_ACM) ? 1 : 0; - set_config_complete(p_cdc, itf_offset, false); + set_config_complete(p_cdc, false); } } @@ -967,20 +957,16 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co .wLength = 0 }; - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = NULL, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; + return tuh_control_xfer(&xfer); } static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { @@ -1004,35 +990,21 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_ uint8_t *enum_buf = usbh_get_enum_buf(); memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t)); - p_cdc->user_complete_cb = complete_cb; - tuh_xfer_t xfer = { .daddr = p_cdc->daddr, .ep_addr = 0, .setup = &request, .buffer = enum_buf, - .complete_cb = complete_cb ? cdch_internal_control_complete : NULL, + .complete_cb = complete_cb, .user_data = user_data }; - TU_ASSERT(tuh_control_xfer(&xfer)); - - return true; -} - -static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); -} - -static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - return acm_set_line_coding(p_cdc, complete_cb, user_data); + return tuh_control_xfer(&xfer); } //------------- Enumeration -------------// enum { - CONFIG_ACM_SET_CONTROL_LINE_STATE = 0, - CONFIG_ACM_SET_LINE_CODING, - CONFIG_ACM_COMPLETE + CONFIG_ACM_COMPLETE = 0 }; static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) { @@ -1084,30 +1056,11 @@ static bool acm_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS); const uintptr_t state = xfer->user_data; switch (state) { - case CONFIG_ACM_SET_CONTROL_LINE_STATE: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - if (p_cdc->acm.capability.support_line_request) { - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING)); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_SET_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - if (p_cdc->acm.capability.support_line_request) { - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE)); - break; - } - #endif - TU_ATTR_FALLTHROUGH; - - case CONFIG_ACM_COMPLETE: - // itf_num+1 to account for data interface as well - set_config_complete(p_cdc, 1, true); + case CONFIG_ACM_COMPLETE: { + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; + } default: return false; // invalid state @@ -2023,18 +1976,40 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c &buf, 1, complete_cb, user_data); } -static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - // PL2303 has the same bit coding - return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, - p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); -} - -//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) -//{ +//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE]) { // return pl2303_set_request(p_cdc, PL2303_GET_LINE_REQUEST, PL2303_GET_LINE_REQUEST_TYPE, 0, 0, buf, PL2303_LINE_CODING_BUFSIZE); //} -static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { +//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) { +// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; +// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); +//} + +static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { + /* we don't care if it wasn't halted first. in fact some devices + * (like some ibmcam model 1 units) seem to expect hosts to make + * this request for iso endpoints, which can't halt! + */ + return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, + NULL, 0, complete_cb, user_data); +} + +//------------- Driver API -------------// + +// internal control complete to update state such as line state, encoding +static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { + TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); + if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { + p_cdc->line.coding = p_cdc->requested_line.coding; + } + if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && + xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { + p_cdc->line.control_state = p_cdc->requested_line.control_state; + } +} + +static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // the caller has to precheck, that the new line coding different than the current, else false returned uint8_t buf[PL2303_LINE_CODING_BUFSIZE]; /* @@ -2070,63 +2045,10 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data); } -//static bool pl2303_set_break(cdch_interface_t * p_cdc, bool enable) -//{ -// uint16_t state = enable ? PL2303_BREAK_ON : PL2303_BREAK_OFF; -// return pl2303_set_request(p_cdc, PL2303_BREAK_REQUEST, PL2303_BREAK_REQUEST_TYPE, state, 0, NULL, 0); -//} - -static inline int pl2303_clear_halt(cdch_interface_t *p_cdc, uint8_t endp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - /* we don't care if it wasn't halted first. in fact some devices - * (like some ibmcam model 1 units) seem to expect hosts to make - * this request for iso endpoints, which can't halt! - */ - return pl2303_set_request(p_cdc, TUSB_REQ_CLEAR_FEATURE, PL2303_CLEAR_HALT_REQUEST_TYPE, TUSB_REQ_FEATURE_EDPT_HALT, endp, - NULL, 0, complete_cb, user_data); -} - -//------------- Driver API -------------// - -// internal control complete to update state such as line state, encoding -static void pl2303_internal_control_complete(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) { - TU_VERIFY(xfer->result == XFER_RESULT_SUCCESS,); - if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) { - p_cdc->line.coding = p_cdc->requested_line.coding; - } - if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST && - xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) { - p_cdc->line.control_state = p_cdc->requested_line.control_state; - } -} - -static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - -static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { - p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits; - p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity; - p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits; - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; -} - static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) { // PL2303 has the same bit coding - p_cdc->user_complete_cb = complete_cb; - TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? cdch_internal_control_complete : NULL, user_data)); - return true; + return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE, + p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data); } //------------- Enumeration -------------// @@ -2146,8 +2068,6 @@ enum { CONFIG_PL2303_WRITE5, CONFIG_PL2303_RESET_ENDP1, CONFIG_PL2303_RESET_ENDP2, - CONFIG_PL2303_LINE_CODING, - CONFIG_PL2303_MODEM_CONTROL, // CONFIG_PL2303_FLOW_CTRL_READ, // CONFIG_PL2303_FLOW_CTRL_WRITE, CONFIG_PL2303_COMPLETE @@ -2190,7 +2110,6 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) switch (state) { // from here sequence overtaken from Linux Kernel function pl2303_startup() case CONFIG_PL2303_DETECT_TYPE: - p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config // get type and quirks (step 1) type = pl2303_detect_type(p_cdc, 1); TU_ASSERT(type != PL2303_TYPE_UNKNOWN); @@ -2313,7 +2232,7 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { TU_ASSERT(pl2303_vendor_write(p_cdc, PL2303_HXN_RESET_REG,// skip CONFIG_PL2303_RESET_ENDP2, no 2nd step PL2303_HXN_RESET_UPSTREAM_PIPE | PL2303_HXN_RESET_DOWNSTREAM_PIPE, - cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { pl2303_vendor_write(p_cdc, 8, 0, cdch_process_set_config, CONFIG_PL2303_RESET_ENDP2); } @@ -2323,37 +2242,17 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) case CONFIG_PL2303_RESET_ENDP2: // step 2 if (p_cdc->pl2303.quirks & PL2303_QUIRK_LEGACY) { - TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_clear_halt(p_cdc, PL2303_IN_EP, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } else { /* reset upstream data pipes */ if (p_cdc->pl2303.type == PL2303_TYPE_HXN) { // here nothing to do, only structure of previous step overtaken for better reading and comparison } else { - TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_LINE_CODING)); + TU_ASSERT(pl2303_vendor_write(p_cdc, 9, 0, cdch_process_set_config, CONFIG_PL2303_COMPLETE)); } } break; - // from here sequence overtaken from Linux Kernel function pl2303_set_termios() - // unnecessary pl2303_get_line_request() is skipped due to a stall - case CONFIG_PL2303_LINE_CODING: - #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM - p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM; - TU_ASSERT(pl2303_set_line_request(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - - case CONFIG_PL2303_MODEM_CONTROL: - #ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM - p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM; - TU_ASSERT(pl2303_set_control_lines(p_cdc, cdch_internal_control_complete, CONFIG_PL2303_COMPLETE)); - break; - #else - TU_ATTR_FALLTHROUGH; - #endif - // skipped, because it's not working with each PL230x. flow control can be also set by PL2303 EEPROM Writer Program // case CONFIG_PL2303_FLOW_CTRL_READ: // // read flow control register for modify & write back in next step @@ -2383,7 +2282,8 @@ static bool pl2303_process_set_config(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) // break; case CONFIG_PL2303_COMPLETE: - set_config_complete(p_cdc, 0, true); + xfer->user_data = 0; // kick-off set line state on enum + cdch_process_line_state_on_enum(xfer); break; default: