union ftdi/pl2303/acm data to save memory.

This commit is contained in:
hathach
2025-06-19 18:14:24 +07:00
parent ce9140a150
commit 221b5288e4

View File

@@ -65,27 +65,30 @@ typedef struct {
uint8_t ep_notif;
uint8_t serial_drid; // Serial Driver ID
bool mounted; // Enumeration is complete
cdc_acm_capability_t acm_capability;
TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
TU_ATTR_ALIGNED(4) cdc_line_coding_t requested_line_coding;
// 1 byte padding
struct {
TU_ATTR_ALIGNED(4) cdc_line_coding_t coding; // Baudrate, stop bits, parity, data width
cdc_line_control_state_t control_state; // DTR, RTS
} line, requested_line;
cdc_line_control_state_t line_state;
cdc_line_control_state_t requested_line_state;
tuh_xfer_cb_t user_control_cb;
tuh_xfer_cb_t user_complete_cb; // required since we handle request internally first
#if CFG_TUH_CDC_FTDI || CFG_TUH_CDC_CP210X || CFG_TUH_CDC_CH34X
tuh_xfer_cb_t requested_complete_cb;
#endif
#if CFG_TUH_CDC_FTDI
ftdi_private_t ftdi;
#endif
union {
struct {
cdc_acm_capability_t capability;
} acm;
#if CFG_TUH_CDC_PL2303
#if CFG_TUH_CDC_FTDI
ftdi_private_t ftdi;
#endif
#if CFG_TUH_CDC_PL2303
pl2303_private_t pl2303;
#endif
#endif
};
struct {
tu_edpt_stream_t tx;
@@ -376,8 +379,8 @@ static cdch_interface_t * make_new_itf(uint8_t daddr, tusb_desc_interface_t cons
p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
p_cdc->line_coding = (cdc_line_coding_t) { 0, 0, 0, 0 };
p_cdc->line_state.value = 0;
p_cdc->line.coding = (cdc_line_coding_t) { 0, 0, 0, 0 };
p_cdc->line.control_state.value = 0;
return p_cdc;
}
}
@@ -430,7 +433,7 @@ bool tuh_cdc_mounted(uint8_t idx) {
bool tuh_cdc_get_control_line_state_local(uint8_t idx, uint16_t* line_state) {
cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
*line_state = p_cdc->line_state.value;
*line_state = p_cdc->line.control_state.value;
return true;
}
@@ -438,10 +441,10 @@ bool tuh_cdc_get_line_coding_local(uint8_t idx, cdc_line_coding_t * line_coding)
cdch_interface_t * p_cdc = get_itf(idx);
TU_VERIFY(p_cdc);
*line_coding = p_cdc->line_coding;
*line_coding = p_cdc->line.coding;
TU_LOG_P_CDC("get line coding %lu %u%c%s",
p_cdc->line_coding.bit_rate, p_cdc->line_coding.data_bits,
CDC_LINE_CODING_PARITY_CHAR(p_cdc->line_coding.parity),
p_cdc->line.coding.bit_rate, p_cdc->line.coding.data_bits,
CDC_LINE_CODING_PARITY_CHAR(p_cdc->line.coding.parity),
CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits));
return true;
@@ -533,7 +536,7 @@ static bool set_line_coding_sequence(
// non-blocking
// stage 1 set baudrate
p_cdc->requested_complete_cb = complete_cb; // store complete_cb to be used in set_line_coding_stage1_complete()
p_cdc->user_control_cb = set_line_coding_stage1_complete;
p_cdc->user_complete_cb = set_line_coding_stage1_complete;
return set_baudrate_request(p_cdc, internal_control_complete, user_data);
} else {
// blocking sequence
@@ -549,7 +552,7 @@ static bool set_line_coding_sequence(
TU_VERIFY(result == XFER_RESULT_SUCCESS);
// overtake baudrate after successful request
p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
// stage 2 set data format
result = XFER_RESULT_INVALID;
@@ -577,7 +580,7 @@ static void set_line_coding_stage1_complete(
if (xfer->result == XFER_RESULT_SUCCESS) {
// stage 1 success, continue with stage 2
p_cdc->user_control_cb = p_cdc->requested_complete_cb;
p_cdc->user_complete_cb = p_cdc->requested_complete_cb;
set_data_format_request(p_cdc, internal_control_complete, xfer->user_data);
} else {
// stage 1 failed, notify user
@@ -614,13 +617,13 @@ bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_c
TU_VERIFY(p_cdc && p_cdc->serial_drid < SERIAL_DRIVER_COUNT);
cdch_serial_driver_t const * driver = &serial_drivers[p_cdc->serial_drid];
p_cdc->requested_line_state.value = (uint8_t) line_state;
TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line_state.dtr, p_cdc->requested_line_state.rts);
p_cdc->requested_line.control_state.value = (uint8_t) line_state;
TU_LOG_P_CDC("set control line state dtr = %u rts = %u", p_cdc->requested_line.control_state.dtr, p_cdc->requested_line.control_state.rts);
const bool ret = set_function_call(p_cdc, driver->set_control_line_state, complete_cb, user_data);
if (ret && !complete_cb) {
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
}
return ret;
}
@@ -631,12 +634,12 @@ bool tuh_cdc_set_baudrate(uint8_t idx, uint32_t baudrate, tuh_xfer_cb_t complete
TU_LOG_P_CDC("set baudrate %lu", baudrate);
cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid];
p_cdc->requested_line_coding.bit_rate = baudrate;
p_cdc->requested_line.coding.bit_rate = baudrate;
bool ret = set_function_call(p_cdc, driver->set_baudrate, complete_cb, user_data);
if (ret && !complete_cb) {
p_cdc->line_coding.bit_rate = baudrate;
p_cdc->line.coding.bit_rate = baudrate;
}
// TU_LOG_P_CDC_BOOL("set baudrate", ret);
@@ -652,16 +655,16 @@ bool tuh_cdc_set_data_format(uint8_t idx, uint8_t stop_bits, uint8_t parity, uin
CDC_LINE_CODING_STOP_BITS_TEXT(stop_bits));
cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid];
p_cdc->requested_line_coding.stop_bits = stop_bits;
p_cdc->requested_line_coding.parity = parity;
p_cdc->requested_line_coding.data_bits = data_bits;
p_cdc->requested_line.coding.stop_bits = stop_bits;
p_cdc->requested_line.coding.parity = parity;
p_cdc->requested_line.coding.data_bits = data_bits;
bool ret = set_function_call(p_cdc, driver->set_data_format, complete_cb, user_data);
if (ret && !complete_cb) {
p_cdc->line_coding.stop_bits = stop_bits;
p_cdc->line_coding.parity = parity;
p_cdc->line_coding.data_bits = data_bits;
p_cdc->line.coding.stop_bits = stop_bits;
p_cdc->line.coding.parity = parity;
p_cdc->line.coding.data_bits = data_bits;
}
// TU_LOG_P_CDC_BOOL("set data format", ret);
@@ -678,12 +681,12 @@ bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const *line_coding,
CDC_LINE_CODING_STOP_BITS_TEXT(line_coding->stop_bits));
cdch_serial_driver_t const *driver = &serial_drivers[p_cdc->serial_drid];
p_cdc->requested_line_coding = *line_coding;
p_cdc->requested_line.coding = *line_coding;
bool ret = set_function_call(p_cdc, driver->set_line_coding, complete_cb, user_data);
if (ret && !complete_cb) {
p_cdc->line_coding = *line_coding;
p_cdc->line.coding = *line_coding;
}
// TU_LOG_P_CDC_BOOL("set line coding", ret);
@@ -921,25 +924,25 @@ static void acm_internal_control_complete(tuh_xfer_t *xfer) {
if (success) {
switch (xfer->setup->bRequest) {
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
break;
case CDC_REQUEST_SET_LINE_CODING:
p_cdc->line_coding = p_cdc->requested_line_coding;
p_cdc->line.coding = p_cdc->requested_line.coding;
break;
default: break;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
xfer->complete_cb = p_cdc->user_complete_cb;
if (xfer->complete_cb) {
xfer->complete_cb(xfer);
}
}
static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_VERIFY(p_cdc->acm_capability.support_line_request);
TU_VERIFY(p_cdc->acm.capability.support_line_request);
tusb_control_request_t const request = {
.bmRequestType_bit = {
@@ -948,12 +951,12 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co
.direction = TUSB_DIR_OUT
},
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
.wValue = tu_htole16((uint16_t) p_cdc->requested_line_state.value),
.wValue = tu_htole16((uint16_t) p_cdc->requested_line.control_state.value),
.wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
.wLength = 0
};
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
tuh_xfer_t xfer = {
.daddr = p_cdc->daddr,
@@ -970,9 +973,9 @@ static bool acm_set_control_line_state(cdch_interface_t *p_cdc, tuh_xfer_cb_t co
}
static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_VERIFY(p_cdc->acm_capability.support_line_request);
TU_VERIFY((p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8) ||
p_cdc->requested_line_coding.data_bits == 16);
TU_VERIFY(p_cdc->acm.capability.support_line_request);
TU_VERIFY((p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8) ||
p_cdc->requested_line.coding.data_bits == 16);
tusb_control_request_t const request = {
.bmRequestType_bit = {
@@ -988,9 +991,9 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_
// use usbh enum buf to hold line coding since user line_coding variable does not live long enough
uint8_t *enum_buf = usbh_get_enum_buf();
memcpy(enum_buf, &p_cdc->requested_line_coding, sizeof(cdc_line_coding_t));
memcpy(enum_buf, &p_cdc->requested_line.coding, sizeof(cdc_line_coding_t));
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
tuh_xfer_t xfer = {
.daddr = p_cdc->daddr,
@@ -1007,15 +1010,15 @@ static bool acm_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_
}
static bool acm_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate;
p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate;
return acm_set_line_coding(p_cdc, complete_cb, user_data);
}
static bool acm_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits;
p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity;
p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits;
p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits;
p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity;
p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits;
return acm_set_line_coding(p_cdc, complete_cb, user_data);
}
@@ -1042,7 +1045,7 @@ static bool acm_open(uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint1
while ((p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc))) {
if (CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc)) {
// save ACM bmCapabilities
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
p_cdc->acm.capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
}
p_desc = tu_desc_next(p_desc);
@@ -1082,8 +1085,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) {
switch (state) {
case CONFIG_ACM_SET_CONTROL_LINE_STATE:
#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
if (p_cdc->acm_capability.support_line_request) {
p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
if (p_cdc->acm.capability.support_line_request) {
p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT(acm_set_control_line_state(p_cdc, cdch_process_set_config, CONFIG_ACM_SET_LINE_CODING));
break;
}
@@ -1092,8 +1095,8 @@ static bool acm_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_ACM_SET_LINE_CODING:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
if (p_cdc->acm_capability.support_line_request) {
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
if (p_cdc->acm.capability.support_line_request) {
p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
TU_ASSERT(acm_set_line_coding(p_cdc, cdch_process_set_config, CONFIG_ACM_COMPLETE));
break;
}
@@ -1175,10 +1178,10 @@ static bool ftdi_change_speed(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb
}
static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 7 && p_cdc->requested_line_coding.data_bits <= 8, 0);
uint16_t value = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3
(p_cdc->requested_line_coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding
(p_cdc->requested_line_coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding
TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 7 && p_cdc->requested_line.coding.data_bits <= 8, 0);
uint16_t value = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) | // data bit quantity is stored in bits 0-3
(p_cdc->requested_line.coding.parity & 0x7UL) << 8 | // parity is stored in bits 8-10, same coding
(p_cdc->requested_line.coding.stop_bits & 0x3UL) << 11); // stop bits quantity is stored in bits 11-12, same coding
// not each FTDI supports 1.5 stop bits
return ftdi_set_request(p_cdc, FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE,
@@ -1186,8 +1189,8 @@ static bool ftdi_set_data_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet
}
static inline bool ftdi_update_mctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
uint16_t value = (uint16_t) ((p_cdc->requested_line_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) |
(p_cdc->requested_line_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
uint16_t value = (uint16_t) ((p_cdc->requested_line.control_state.dtr ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW) |
(p_cdc->requested_line.control_state.rts ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW));
return ftdi_set_request(p_cdc, FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
value, p_cdc->ftdi.channel, complete_cb, user_data);
@@ -1206,35 +1209,35 @@ static void ftdi_internal_control_complete(tuh_xfer_t *xfer) {
if (success) {
if (xfer->setup->bRequest == FTDI_SIO_SET_MODEM_CTRL_REQUEST &&
xfer->setup->bmRequestType == FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE ) {
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
}
if (xfer->setup->bRequest == FTDI_SIO_SET_DATA_REQUEST &&
xfer->setup->bmRequestType == FTDI_SIO_SET_DATA_REQUEST_TYPE ) {
p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits;
p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity;
p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits;
p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
}
if (xfer->setup->bRequest == FTDI_SIO_SET_BAUDRATE_REQUEST &&
xfer->setup->bmRequestType == FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE ) {
p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
xfer->complete_cb = p_cdc->user_complete_cb;
if (xfer->complete_cb) {
xfer->complete_cb(xfer);
}
}
static bool ftdi_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ftdi_set_data_request(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data));
return true;
}
static bool ftdi_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ftdi_change_speed(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data));
return true;
@@ -1261,7 +1264,7 @@ static bool ftdi_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t complet
}
static bool ftdi_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ftdi_update_mctrl(p_cdc, complete_cb ? ftdi_internal_control_complete : NULL, user_data));
return true;
@@ -1339,15 +1342,15 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) {
// from here sequence overtaken from Linux Kernel function ftdi_open()
case CONFIG_FTDI_SIO_RESET:
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(ftdi_sio_reset(p_cdc, cdch_process_set_config, CONFIG_FTDI_SET_DATA));
break;
// from here sequence overtaken from Linux Kernel function ftdi_set_termios()
case CONFIG_FTDI_SET_DATA:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(ftdi_set_data_request(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_SET_BAUDRATE));
break;
#else
@@ -1356,7 +1359,7 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) {
case CONFIG_FTDI_SET_BAUDRATE:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(ftdi_change_speed(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_FLOW_CONTROL));
break;
#else
@@ -1371,8 +1374,8 @@ static bool ftdi_proccess_set_config(tuh_xfer_t *xfer) {
case CONFIG_FTDI_MODEM_CTRL:
#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(ftdi_update_mctrl(p_cdc, ftdi_internal_control_complete, CONFIG_FTDI_COMPLETE));
break;
#else
@@ -1529,7 +1532,7 @@ static inline uint32_t ftdi_2232h_baud_to_divisor(uint32_t baud) {
}
static inline uint32_t ftdi_get_divisor(cdch_interface_t *p_cdc) {
uint32_t baud = p_cdc->requested_line_coding.bit_rate;
uint32_t baud = p_cdc->requested_line.coding.bit_rate;
uint32_t div_value = 0;
TU_VERIFY(baud);
@@ -1661,16 +1664,16 @@ static inline bool cp210x_ifc_enable(cdch_interface_t *p_cdc, uint16_t enabled,
static bool cp210x_set_baudrate_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
// Not every baud rate is supported. See datasheets and AN205 "CP210x Baud Rate Support"
uint32_t baud_le = tu_htole32(p_cdc->requested_line_coding.bit_rate);
uint32_t baud_le = tu_htole32(p_cdc->requested_line.coding.bit_rate);
return cp210x_set_request(p_cdc, CP210X_SET_BAUDRATE, 0, (uint8_t *) &baud_le, 4, complete_cb, user_data);
}
static bool cp210x_set_line_ctl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0);
uint16_t lcr = (uint16_t) ((p_cdc->requested_line_coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11
(p_cdc->requested_line_coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding
(p_cdc->requested_line_coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding
TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0);
uint16_t lcr = (uint16_t) ((p_cdc->requested_line.coding.data_bits & 0xfUL) << 8 | // data bit quantity is stored in bits 8-11
(p_cdc->requested_line.coding.parity & 0xfUL) << 4 | // parity is stored in bits 4-7, same coding
(p_cdc->requested_line.coding.stop_bits & 0xfUL)); // parity is stored in bits 0-3, same coding
return cp210x_set_request(p_cdc, CP210X_SET_LINE_CTL, lcr, NULL, 0, complete_cb, user_data);
}
@@ -1679,7 +1682,7 @@ static inline bool cp210x_set_mhs(cdch_interface_t *p_cdc, tuh_xfer_cb_t complet
// CP210x has the same bit coding
return cp210x_set_request(p_cdc, CP210X_SET_MHS,
(uint16_t) (CP210X_CONTROL_WRITE_DTR | CP210X_CONTROL_WRITE_RTS |
p_cdc->requested_line_state.value),
p_cdc->requested_line.control_state.value),
NULL, 0, complete_cb, user_data);
}
@@ -1697,38 +1700,38 @@ static void cp210x_internal_control_complete(tuh_xfer_t *xfer) {
if (success) {
switch (xfer->setup->bRequest) {
case CP210X_SET_MHS:
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
break;
case CP210X_SET_LINE_CTL:
p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits;
p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity;
p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits;
p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
break;
case CP210X_SET_BAUDRATE:
p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
break;
default: break;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
xfer->complete_cb = p_cdc->user_complete_cb;
if (xfer->complete_cb) {
xfer->complete_cb(xfer);
}
}
static bool cp210x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(cp210x_set_baudrate_request(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data));
return true;
}
static bool cp210x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(cp210x_set_line_ctl(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data));
return true;
@@ -1752,7 +1755,7 @@ static bool cp210x_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t comple
}
static bool cp210x_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(cp210x_set_mhs(p_cdc, complete_cb ? cp210x_internal_control_complete : NULL, user_data));
return true;
@@ -1799,8 +1802,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_CP210X_SET_BAUDRATE_REQUEST:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(cp210x_set_baudrate_request(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_LINE_CTL));
break;
#else
@@ -1809,7 +1812,7 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_CP210X_SET_LINE_CTL:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(cp210x_set_line_ctl(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_SET_DTR_RTS));
break;
#else
@@ -1818,8 +1821,8 @@ static bool cp210x_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_CP210X_SET_DTR_RTS:
#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(cp210x_set_mhs(p_cdc, cp210x_internal_control_complete, CONFIG_CP210X_COMPLETE));
break;
#else
@@ -1923,8 +1926,8 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t comp
static bool ch34x_modem_ctrl_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
// CH34x signals are inverted
uint8_t control = ~((p_cdc->requested_line_state.rts ? CH34X_BIT_RTS : 0) |
(p_cdc->requested_line_state.dtr ? CH34X_BIT_DTR : 0));
uint8_t control = ~((p_cdc->requested_line.control_state.rts ? CH34X_BIT_RTS : 0) |
(p_cdc->requested_line.control_state.dtr ? CH34X_BIT_DTR : 0));
return ch34x_control_out(p_cdc, CH34X_REQ_MODEM_CTRL, control, 0, complete_cb, user_data);
}
@@ -1947,14 +1950,14 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) {
switch (tu_le16toh(xfer->setup->wValue)) {
case CH34X_REG16_DIVISOR_PRESCALER:
// baudrate
p_cdc->line_coding.bit_rate = p_cdc->requested_line_coding.bit_rate;
p_cdc->line.coding.bit_rate = p_cdc->requested_line.coding.bit_rate;
break;
case CH32X_REG16_LCR2_LCR:
// data format
p_cdc->line_coding.stop_bits = p_cdc->requested_line_coding.stop_bits;
p_cdc->line_coding.parity = p_cdc->requested_line_coding.parity;
p_cdc->line_coding.data_bits = p_cdc->requested_line_coding.data_bits;
p_cdc->line.coding.stop_bits = p_cdc->requested_line.coding.stop_bits;
p_cdc->line.coding.parity = p_cdc->requested_line.coding.parity;
p_cdc->line.coding.data_bits = p_cdc->requested_line.coding.data_bits;
break;
default: break;
@@ -1962,28 +1965,28 @@ static void ch34x_internal_control_complete(tuh_xfer_t *xfer) {
break;
case CH34X_REQ_MODEM_CTRL:
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
break;
default: break;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
xfer->complete_cb = p_cdc->user_complete_cb;
if (xfer->complete_cb) {
xfer->complete_cb(xfer);
}
}
static bool ch34x_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ch34x_write_reg_data_format(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data));
return true;
}
static bool ch34x_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ch34x_write_reg_baudrate(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data));
return true;
@@ -2008,7 +2011,7 @@ static bool ch34x_set_line_coding(cdch_interface_t * p_cdc, tuh_xfer_cb_t comple
}
static bool ch34x_set_modem_ctrl(cdch_interface_t * p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, complete_cb ? ch34x_internal_control_complete : NULL, user_data));
return true;
@@ -2073,7 +2076,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) {
// see drivers from WCH vendor, Linux kernel and FreeBSD
if (version >= 0x30) {
// init CH34x with line coding
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc);
uint8_t const lcr = ch34x_get_lcr(p_cdc);
TU_ASSERT(div_ps != 0 && lcr != 0);
@@ -2085,7 +2088,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_CH34X_SPECIAL_REG_WRITE:
// overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver
p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
p_cdc->line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
TU_ASSERT(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007,
cdch_process_set_config, CONFIG_CH34X_FLOW_CONTROL));
break;
@@ -2098,8 +2101,8 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_CH34X_MODEM_CONTROL:
#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_control_cb = cdch_process_set_config;
p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->user_complete_cb = cdch_process_set_config;
TU_ASSERT(ch34x_modem_ctrl_request(p_cdc, ch34x_internal_control_complete, CONFIG_CH34X_COMPLETE));
break;
#else
@@ -2121,7 +2124,7 @@ static bool ch34x_process_set_config(tuh_xfer_t *xfer) {
// calculate divisor and prescaler for baudrate, return it as 16-bit combined value
static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) {
uint32_t const baval = p_cdc->requested_line_coding.bit_rate;
uint32_t const baval = p_cdc->requested_line.coding.bit_rate;
uint8_t a;
uint8_t b;
uint32_t c;
@@ -2171,9 +2174,9 @@ static uint16_t ch34x_get_divisor_prescaler(cdch_interface_t *p_cdc) {
// calculate lcr value from data coding
static uint8_t ch34x_get_lcr(cdch_interface_t *p_cdc) {
uint8_t const stop_bits = p_cdc->requested_line_coding.stop_bits;
uint8_t const parity = p_cdc->requested_line_coding.parity;
uint8_t const data_bits = p_cdc->requested_line_coding.data_bits;
uint8_t const stop_bits = p_cdc->requested_line.coding.stop_bits;
uint8_t const parity = p_cdc->requested_line.coding.parity;
uint8_t const data_bits = p_cdc->requested_line.coding.data_bits;
uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX;
TU_VERIFY(data_bits >= 5 && data_bits <= 8);
@@ -2276,7 +2279,7 @@ static inline bool pl2303_supports_hx_status(cdch_interface_t *p_cdc, tuh_xfer_c
static inline bool pl2303_set_control_lines(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
// PL2303 has the same bit coding
return pl2303_set_request(p_cdc, PL2303_SET_CONTROL_REQUEST, PL2303_SET_CONTROL_REQUEST_TYPE,
p_cdc->requested_line_state.value, 0, NULL, 0, complete_cb, user_data);
p_cdc->requested_line.control_state.value, 0, NULL, 0, complete_cb, user_data);
}
//static bool pl2303_get_line_request(cdch_interface_t * p_cdc, uint8_t buf[PL2303_LINE_CODING_BUFSIZE])
@@ -2292,14 +2295,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl
* even to the same values as before. Thus we actually need to filter
* in this specific case.
*/
TU_VERIFY(p_cdc->requested_line_coding.data_bits != p_cdc->line_coding.data_bits ||
p_cdc->requested_line_coding.stop_bits != p_cdc->line_coding.stop_bits ||
p_cdc->requested_line_coding.parity != p_cdc->line_coding.parity ||
p_cdc->requested_line_coding.bit_rate != p_cdc->line_coding.bit_rate );
TU_VERIFY(p_cdc->requested_line.coding.data_bits != p_cdc->line.coding.data_bits ||
p_cdc->requested_line.coding.stop_bits != p_cdc->line.coding.stop_bits ||
p_cdc->requested_line.coding.parity != p_cdc->line.coding.parity ||
p_cdc->requested_line.coding.bit_rate != p_cdc->line.coding.bit_rate );
/* For reference buf[6] data bits value */
TU_VERIFY(p_cdc->requested_line_coding.data_bits >= 5 && p_cdc->requested_line_coding.data_bits <= 8, 0);
buf[6] = p_cdc->requested_line_coding.data_bits;
TU_VERIFY(p_cdc->requested_line.coding.data_bits >= 5 && p_cdc->requested_line.coding.data_bits <= 8, 0);
buf[6] = p_cdc->requested_line.coding.data_bits;
/* For reference buf[0]:buf[3] baud rate value */
TU_VERIFY(pl2303_encode_baud_rate(p_cdc, &buf[0]));
@@ -2307,14 +2310,14 @@ static bool pl2303_set_line_request(cdch_interface_t *p_cdc, tuh_xfer_cb_t compl
/* For reference buf[4]=0 is 1 stop bits */
/* For reference buf[4]=1 is 1.5 stop bits */
/* For reference buf[4]=2 is 2 stop bits */
buf[4] = p_cdc->requested_line_coding.stop_bits; // PL2303 has the same coding
buf[4] = p_cdc->requested_line.coding.stop_bits; // PL2303 has the same coding
/* For reference buf[5]=0 is none parity */
/* For reference buf[5]=1 is odd parity */
/* For reference buf[5]=2 is even parity */
/* For reference buf[5]=3 is mark parity */
/* For reference buf[5]=4 is space parity */
buf[5] = p_cdc->requested_line_coding.parity; // PL2303 has the same coding
buf[5] = p_cdc->requested_line.coding.parity; // PL2303 has the same coding
return pl2303_set_request(p_cdc, PL2303_SET_LINE_REQUEST, PL2303_SET_LINE_REQUEST_TYPE, 0, 0,
buf, PL2303_LINE_CODING_BUFSIZE, complete_cb, user_data);
@@ -2350,45 +2353,45 @@ static void pl2303_internal_control_complete(tuh_xfer_t *xfer) {
if (success) {
if (xfer->setup->bRequest == PL2303_SET_LINE_REQUEST &&
xfer->setup->bmRequestType == PL2303_SET_LINE_REQUEST_TYPE) {
p_cdc->line_coding = p_cdc->requested_line_coding;
p_cdc->line.coding = p_cdc->requested_line.coding;
}
if (xfer->setup->bRequest == PL2303_SET_CONTROL_REQUEST &&
xfer->setup->bmRequestType == PL2303_SET_CONTROL_REQUEST_TYPE) {
p_cdc->line_state = p_cdc->requested_line_state;
p_cdc->line.control_state = p_cdc->requested_line.control_state;
}
}
xfer->complete_cb = p_cdc->user_control_cb;
xfer->complete_cb = p_cdc->user_complete_cb;
if (xfer->complete_cb) {
xfer->complete_cb(xfer);
}
}
static bool pl2303_set_line_coding(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data));
return true;
}
static bool pl2303_set_data_format(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->requested_line_coding.bit_rate = p_cdc->line_coding.bit_rate;
p_cdc->user_control_cb = complete_cb;
p_cdc->requested_line.coding.bit_rate = p_cdc->line.coding.bit_rate;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data));
return true;
}
static bool pl2303_set_baudrate(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
p_cdc->requested_line_coding.stop_bits = p_cdc->line_coding.stop_bits;
p_cdc->requested_line_coding.parity = p_cdc->line_coding.parity;
p_cdc->requested_line_coding.data_bits = p_cdc->line_coding.data_bits;
p_cdc->user_control_cb = complete_cb;
p_cdc->requested_line.coding.stop_bits = p_cdc->line.coding.stop_bits;
p_cdc->requested_line.coding.parity = p_cdc->line.coding.parity;
p_cdc->requested_line.coding.data_bits = p_cdc->line.coding.data_bits;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(pl2303_set_line_request(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data));
return true;
}
static bool pl2303_set_modem_ctrl(cdch_interface_t *p_cdc, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
// PL2303 has the same bit coding
p_cdc->user_control_cb = complete_cb;
p_cdc->user_complete_cb = complete_cb;
TU_ASSERT(pl2303_set_control_lines(p_cdc, complete_cb ? pl2303_internal_control_complete : NULL, user_data));
return true;
}
@@ -2458,7 +2461,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) {
switch (state) {
// from here sequence overtaken from Linux Kernel function pl2303_startup()
case CONFIG_PL2303_DETECT_TYPE:
p_cdc->user_control_cb = cdch_process_set_config;// set once for whole process config
p_cdc->user_complete_cb = cdch_process_set_config;// set once for whole process config
// get type and quirks (step 1)
type = pl2303_detect_type(p_cdc, 1);
TU_ASSERT(type != PL2303_TYPE_UNKNOWN);
@@ -2606,7 +2609,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) {
// unnecessary pl2303_get_line_request() is skipped due to a stall
case CONFIG_PL2303_LINE_CODING:
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
p_cdc->requested_line.coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
TU_ASSERT(pl2303_set_line_request(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_MODEM_CONTROL));
break;
#else
@@ -2615,7 +2618,7 @@ static bool pl2303_process_set_config(tuh_xfer_t *xfer) {
case CONFIG_PL2303_MODEM_CONTROL:
#ifdef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
p_cdc->requested_line.control_state.value = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT(pl2303_set_control_lines(p_cdc, pl2303_internal_control_complete, CONFIG_PL2303_COMPLETE));
break;
#else
@@ -2861,7 +2864,7 @@ static uint32_t pl2303_encode_baud_rate_divisor_alt(uint8_t buf[PL2303_LINE_CODI
}
static bool pl2303_encode_baud_rate(cdch_interface_t *p_cdc, uint8_t buf[PL2303_LINE_CODING_BAUDRATE_BUFSIZE]) {
uint32_t baud = p_cdc->requested_line_coding.bit_rate;
uint32_t baud = p_cdc->requested_line.coding.bit_rate;
uint32_t baud_sup;
const pl2303_type_data_t* type_data = &pl2303_type_data[p_cdc->pl2303.type];