Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CHCh Upgrade: Improved FTDI and CP210x support, add PL2303 support, bugfixes #2488

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b9c44ee
improved tusb_config.h comment
heikokue Feb 10, 2024
ab6b9e3
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
heikokue Feb 22, 2024
069c68a
sorted driver functions into Control Request, Driver API, Enumeration…
heikokue Feb 23, 2024
47777a6
improved TU_LOGs
heikokue Feb 20, 2024
829ea52
splitted cdch_internal_control_complete() into driver's _internal_con…
heikokue Feb 22, 2024
2f50f5a
changed to use of p_cdc->requested_line_coding
heikokue Feb 22, 2024
7dd435c
changed to use of p_cdc->requested_line_state
heikokue Feb 20, 2024
dcadf8c
created set_function_call()
heikokue Feb 22, 2024
ea86bbe
added continue enum after config fail
heikokue Feb 21, 2024
22a12c7
improved ACM checks
heikokue Feb 22, 2024
138567a
fixed #2448 CH34x ch34x_set_line_coding() callback bug
heikokue Feb 18, 2024
db511fb
fixed CFG_TUH_CDC_LINE_CONTROL_ON_ENUM handling. only set if defined.…
heikokue Feb 19, 2024
0b5f85e
created set_line_coding_sequence() and void set_line_coding_stage1_co…
heikokue Feb 21, 2024
7fef594
improved FTDI support
heikokue Feb 24, 2024
4547737
improved CP210x support
heikokue Feb 22, 2024
aabee25
added PL2303 support
heikokue Feb 22, 2024
ea175a7
updated contribution, readme and some comments
heikokue Feb 24, 2024
2b507db
small changes & code style
heikokue Feb 24, 2024
da93fcf
improved TU_LOGs
heikokue Feb 22, 2024
46a861b
improved PL2303 TU_LOGs
heikokue Feb 23, 2024
af5e75c
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
heikokue Feb 24, 2024
7f7576f
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
heikokue Feb 29, 2024
f97e312
FTDI fixed itf_num and some improvement
heikokue Feb 28, 2024
d3d61da
improved & fixed compiler warnings device descriptor handling
heikokue Feb 25, 2024
edf1320
removed expendable ACM check
heikokue Feb 28, 2024
3cf9cb9
small PL2303 improvements
heikokue Feb 28, 2024
e7308e3
improved TU_LOGs
heikokue Feb 28, 2024
e6d27b6
fixed IAR compile error
heikokue Feb 29, 2024
dea27d2
added explicite (uint16_t) casts inside tu_htole16()
heikokue Feb 29, 2024
e055104
added use of cdc_line_control_state_t type in CDCh
heikokue Mar 3, 2024
a9cc07f
added line control function using cdc_line_control_state_t
heikokue Mar 10, 2024
ee92e58
added defines CFG_TUH_CDC_DTR_CONTROL_ON_ENUM & CFG_TUH_CDC_RTS_CONTR…
heikokue Mar 3, 2024
2786a61
fixed FTDI set control line
heikokue Mar 3, 2024
cb69ed0
code style and clean up CDC serial header files
heikokue Mar 21, 2024
1bbd658
Merge remote-tracking branch 'remotes/hathach/master' into work
heikokue Mar 21, 2024
e2a5630
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
heikokue Apr 4, 2024
5e67b92
fixed compile warnings
heikokue Apr 4, 2024
e07ee4a
CP210x removed baudrate check, fixed data bits check
heikokue Apr 4, 2024
a1b1c1f
foxed FTDI flow control config
heikokue Apr 4, 2024
e02a309
disable PL2303 flow control config
heikokue Apr 4, 2024
68602e4
small change process config complete
heikokue Apr 4, 2024
0c5e14c
updated doc
heikokue Apr 4, 2024
f00e698
Merge remote-tracking branch 'remotes/hathach/master' into cdch_upgrade
heikokue Apr 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
109 changes: 67 additions & 42 deletions src/class/cdc/cdc_host.c
Expand Up @@ -47,6 +47,16 @@
#define TU_LOG_P_CDC(TXT,...) TU_LOG_CDC(TXT, p_cdc->daddr, p_cdc->bInterfaceNumber, \
serial_drivers[p_cdc->serial_drid].name, ##__VA_ARGS__)

#define TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset) \
do { \
if (!(_cond)) { _MESS_FAILED(); TU_BREAKPOINT(); set_config_complete(idx, _itf_offset, false); } \
} while(0)

#define TU_ASSERT_COMPLETE_1ARGS(_cond) TU_ASSERT_COMPLETE_DEFINE(_cond, 0)
#define TU_ASSERT_COMPLETE_2ARGS(_cond, _itf_offset) TU_ASSERT_COMPLETE_DEFINE(_cond, _itf_offset)

#define TU_ASSERT_COMPLETE(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_COMPLETE_2ARGS, TU_ASSERT_COMPLETE_1ARGS, _dummy)(__VA_ARGS__)

//--------------------------------------------------------------------+
// Host CDC Interface
//--------------------------------------------------------------------+
Expand Down Expand Up @@ -285,7 +295,6 @@ static cdch_interface_t* make_new_itf(uint8_t daddr, tusb_desc_interface_t const
}

static bool open_ep_stream_pair(cdch_interface_t* p_cdc , tusb_desc_endpoint_t const *desc_ep);
static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num);

//--------------------------------------------------------------------+
// APPLICATION API
Expand Down Expand Up @@ -657,16 +666,26 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
return false;
}

static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) {
TU_LOG_P_CDC("set config complete");
p_cdc->mounted = true;
if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
static void set_config_complete(uint8_t idx, uint8_t itf_offset, bool success) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now the enumeration will continue, even if a process config fails

cdch_interface_t * p_cdc = get_itf(idx);
TU_ASSERT(p_cdc,);
TU_LOG_P_CDC("set config complete success = %u", success);

// Prepare for incoming data
tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
if (success) {
p_cdc->mounted = true;
if (tuh_cdc_mount_cb) {
tuh_cdc_mount_cb(idx);
}
// Prepare for incoming data
tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
} else {
// clear the interface entry
p_cdc->daddr = 0;
p_cdc->bInterfaceNumber = 0;
}

// notify usbh that driver enumeration is complete
usbh_driver_set_config_complete(p_cdc->daddr, itf_num);
usbh_driver_set_config_complete(p_cdc->daddr, p_cdc->bInterfaceNumber + itf_offset);
}

bool cdch_set_config(uint8_t daddr, uint8_t itf_num) {
Expand Down Expand Up @@ -856,14 +875,14 @@ static void acm_process_config(tuh_xfer_t* xfer) {
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t* p_cdc = get_itf(idx);
TU_ASSERT(p_cdc,);
TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS, 1);

switch (state) {
case CONFIG_ACM_SET_CONTROL_LINE_STATE:
#if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
if (p_cdc->acm_capability.support_line_request) {
p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING),);
TU_ASSERT_COMPLETE(acm_set_control_line_state(p_cdc, acm_process_config, CONFIG_ACM_SET_LINE_CODING), 1);
break;
}
#endif
Expand All @@ -873,18 +892,19 @@ static void acm_process_config(tuh_xfer_t* xfer) {
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
if (p_cdc->acm_capability.support_line_request) {
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM;
TU_ASSERT(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE),);
TU_ASSERT_COMPLETE(acm_set_line_coding(p_cdc, acm_process_config, CONFIG_ACM_COMPLETE), 1);
break;
}
#endif
TU_ATTR_FALLTHROUGH;

case CONFIG_ACM_COMPLETE:
// itf_num+1 to account for data interface as well
set_config_complete(p_cdc, idx, itf_num + 1);
set_config_complete(idx, 1, true);
break;

default:
set_config_complete(idx, 1, false);
break;
}
}
Expand Down Expand Up @@ -1024,18 +1044,18 @@ static void ftdi_process_config(tuh_xfer_t* xfer) {
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t * p_cdc = get_itf(idx);
TU_ASSERT(p_cdc, );
TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS);

switch(state) {
// Note may need to read FTDI eeprom
case CONFIG_FTDI_RESET:
TU_ASSERT(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL),);
TU_ASSERT_COMPLETE(ftdi_sio_reset(p_cdc, ftdi_process_config, CONFIG_FTDI_MODEM_CTRL));
break;

case CONFIG_FTDI_MODEM_CTRL:
#if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE),);
TU_ASSERT_COMPLETE(ftdi_sio_set_modem_ctrl(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_BAUDRATE));
break;
#else
TU_ATTR_FALLTHROUGH;
Expand All @@ -1044,7 +1064,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) {
case CONFIG_FTDI_SET_BAUDRATE: {
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate;
TU_ASSERT(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA),);
TU_ASSERT_COMPLETE(ftdi_sio_set_baudrate(p_cdc, ftdi_process_config, CONFIG_FTDI_SET_DATA));
break;
#else
TU_ATTR_FALLTHROUGH;
Expand All @@ -1055,7 +1075,7 @@ static void ftdi_process_config(tuh_xfer_t* xfer) {
#if 0 // TODO set data format
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
TU_ASSERT(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE),);
TU_ASSERT_COMPLETE(ftdi_sio_set_data(p_cdc, process_ftdi_config, CONFIG_FTDI_COMPLETE));
break;
#endif
#endif
Expand All @@ -1064,10 +1084,11 @@ static void ftdi_process_config(tuh_xfer_t* xfer) {
}

case CONFIG_FTDI_COMPLETE:
set_config_complete(p_cdc, idx, itf_num);
set_config_complete(idx, 0, true);
break;

default:
set_config_complete(idx, 0, false);
break;
}
}
Expand Down Expand Up @@ -1150,8 +1171,8 @@ static bool cp210x_ifc_enable(cdch_interface_t* p_cdc, uint16_t enabled, tuh_xfe
static void cp210x_internal_control_complete(tuh_xfer_t * xfer) {
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t * p_cdc = get_itf(idx);
TU_ASSERT(p_cdc,);
cdch_interface_t* p_cdc = get_itf(idx);
TU_ASSERT(p_cdc, );
bool const success = (xfer->result == XFER_RESULT_SUCCESS);
TU_LOG_P_CDC("control complete success = %u", success);

Expand Down Expand Up @@ -1236,17 +1257,17 @@ static void cp210x_process_config(tuh_xfer_t* xfer) {
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t *p_cdc = get_itf(idx);
TU_ASSERT(p_cdc,);
TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS);

switch (state) {
case CONFIG_CP210X_IFC_ENABLE:
TU_ASSERT(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE),);
TU_ASSERT_COMPLETE(cp210x_ifc_enable(p_cdc, 1, cp210x_process_config, CONFIG_CP210X_SET_BAUDRATE));
break;

case CONFIG_CP210X_SET_BAUDRATE: {
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
p_cdc->requested_line_coding.bit_rate = ((cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM).bit_rate;
TU_ASSERT(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL),);
TU_ASSERT_COMPLETE(cp210x_set_baudrate(p_cdc, cp210x_process_config, CONFIG_CP210X_SET_LINE_CTL));
break;
#else
TU_ATTR_FALLTHROUGH;
Expand All @@ -1265,17 +1286,19 @@ static void cp210x_process_config(tuh_xfer_t* xfer) {
case CONFIG_CP210X_SET_DTR_RTS:
#if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE),);
TU_ASSERT_COMPLETE(cp210x_set_modem_ctrl(p_cdc, cp210x_process_config, CONFIG_CP210X_COMPLETE));
break;
#else
TU_ATTR_FALLTHROUGH;
#endif

case CONFIG_CP210X_COMPLETE:
set_config_complete(p_cdc, idx, itf_num);
set_config_complete(idx, 0, true);
break;

default: break;
default:
set_config_complete(idx, 0, false);
break;
}
}

Expand Down Expand Up @@ -1361,11 +1384,11 @@ static bool ch34x_write_reg_baudrate(cdch_interface_t* p_cdc, tuh_xfer_cb_t comp

// internal control complete to update state such as line state, encoding
static void ch34x_internal_control_complete(tuh_xfer_t * xfer) {
// CH34x has only interface 0, because wIndex is used as payload and not for bInterfaceNumber
// CH34x only has 1 interface and wIndex used as payload and not for bInterfaceNumber
uint8_t const itf_num = 0;
uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t * p_cdc = get_itf(idx);
TU_ASSERT(p_cdc,);
cdch_interface_t* p_cdc = get_itf(idx);
TU_ASSERT(p_cdc, );
bool const success = (xfer->result == XFER_RESULT_SUCCESS);
TU_LOG_P_CDC("control complete success = %u", success);

Expand Down Expand Up @@ -1526,56 +1549,58 @@ static void ch34x_process_config(tuh_xfer_t* xfer) {
uint8_t const itf_num = 0;
uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
cdch_interface_t* p_cdc = get_itf(idx);
TU_ASSERT_COMPLETE(p_cdc && xfer->result == XFER_RESULT_SUCCESS);
uintptr_t const state = xfer->user_data;
uint8_t buffer[2]; // TODO remove
TU_ASSERT (p_cdc,);
TU_ASSERT (xfer->result == XFER_RESULT_SUCCESS,);

switch (state) {
case CONFIG_CH34X_READ_VERSION:
TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),);
TU_ASSERT_COMPLETE(ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2,
ch34x_process_config, CONFIG_CH34X_SERIAL_INIT));
break;

case CONFIG_CH34X_SERIAL_INIT: {
// handle version read data, set CH34x line coding (incl. baudrate)
uint8_t const version = xfer->buffer[0];
TU_LOG_P_CDC("Chip Version = %02x", version);
// only versions >= 0x30 are tested, below 0x30 seems having other programming, see drivers from WCH vendor, Linux kernel and FreeBSD
TU_ASSERT (version >= 0x30,);
TU_ASSERT_COMPLETE(version >= 0x30);
// init CH34x with line coding
p_cdc->requested_line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
uint16_t const div_ps = ch34x_get_divisor_prescaler(p_cdc);
TU_ASSERT(div_ps, );
TU_ASSERT_COMPLETE(div_ps);
uint8_t const lcr = ch34x_get_lcr(p_cdc);
TU_ASSERT(lcr, );
TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps,
ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),);
TU_ASSERT_COMPLETE(lcr);
TU_ASSERT_COMPLETE(ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, tu_u16(lcr, 0x9c), div_ps,
ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE));
break;
}

case CONFIG_CH34X_SPECIAL_REG_WRITE:
// overtake line coding and do special reg write, purpose unknown, overtaken from WCH driver
p_cdc->line_coding = (cdc_line_coding_t) CFG_TUH_CDC_LINE_CODING_ON_ENUM_CH34X;
TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),);
TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x0F, CH341_REG_0x2C), 0x0007,
ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL));
break;

case CONFIG_CH34X_FLOW_CONTROL:
// no hardware flow control
TU_ASSERT (ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),);
TU_ASSERT_COMPLETE(ch34x_write_reg(p_cdc, TU_U16(CH341_REG_0x27, CH341_REG_0x27), 0x0000,
ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL));
break;

case CONFIG_CH34X_MODEM_CONTROL:
// !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT)
p_cdc->requested_line_state = CFG_TUH_CDC_LINE_CONTROL_ON_ENUM;
TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE),);
TU_ASSERT_COMPLETE(ch34x_set_modem_ctrl(p_cdc, ch34x_process_config, CONFIG_CH34X_COMPLETE));
break;

case CONFIG_CH34X_COMPLETE:
set_config_complete(p_cdc, idx, itf_num);
set_config_complete(idx, 0, true);
break;

default:
TU_ASSERT (false,);
set_config_complete(idx, 0, false);
break;
}
}
Expand Down