mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-19 19:21:05 +00:00
implemented ch34x_set_line_coding() and some code cleanup
This commit is contained in:
parent
f221c0fb66
commit
3968a0fff8
@ -1179,7 +1179,7 @@ static void cp210x_process_config(tuh_xfer_t* xfer) {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
CONFIG_CH34X_READ_VERSION = 0,
|
CONFIG_CH34X_READ_VERSION = 0,
|
||||||
CONFIG_CH34X_SERIAL_INIT,
|
CONFIG_CH34X_SET_LINE_CODING,
|
||||||
CONFIG_CH34X_SPECIAL_REG_WRITE,
|
CONFIG_CH34X_SPECIAL_REG_WRITE,
|
||||||
CONFIG_CH34X_FLOW_CONTROL,
|
CONFIG_CH34X_FLOW_CONTROL,
|
||||||
CONFIG_CH34X_MODEM_CONTROL,
|
CONFIG_CH34X_MODEM_CONTROL,
|
||||||
@ -1292,11 +1292,10 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) {
|
|||||||
case CH34X_REQ_WRITE_REG:
|
case CH34X_REQ_WRITE_REG:
|
||||||
// register write request
|
// register write request
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case (0x1312):
|
case 0x1312:
|
||||||
// baudrate write
|
// baudrate write
|
||||||
p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested;
|
p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TU_ASSERT(false,); // unexpected register write
|
TU_ASSERT(false,); // unexpected register write
|
||||||
break;
|
break;
|
||||||
@ -1310,13 +1309,60 @@ static void ch34x_control_complete(tuh_xfer_t* xfer) {
|
|||||||
} else {
|
} else {
|
||||||
p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS;
|
p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_RTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (~value & CH34X_BIT_DTR) {
|
if (~value & CH34X_BIT_DTR) {
|
||||||
p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR;
|
p_cdc->line_state |= CDC_CONTROL_LINE_STATE_DTR;
|
||||||
} else {
|
} else {
|
||||||
p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR;
|
p_cdc->line_state &= (uint8_t ) ~CDC_CONTROL_LINE_STATE_DTR;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CH34X_REQ_SERIAL_INIT:
|
||||||
|
// serial init request (set line coding incl. baudrate)
|
||||||
|
p_cdc->line_coding.bit_rate = p_cdc->baudrate_requested;
|
||||||
|
uint8_t lcr = (uint8_t) (value >> 8);
|
||||||
|
TU_ASSERT (lcr & CH34X_LCR_ENABLE_RX && lcr & CH34X_LCR_ENABLE_TX,); // both have to be enabled
|
||||||
|
switch (lcr & CH34X_LCR_CS_MASK) {
|
||||||
|
case CH34X_LCR_CS5:
|
||||||
|
p_cdc->line_coding.data_bits = 5;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_CS6:
|
||||||
|
p_cdc->line_coding.data_bits = 6;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_CS7:
|
||||||
|
p_cdc->line_coding.data_bits = 7;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_CS8:
|
||||||
|
p_cdc->line_coding.data_bits = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TU_ASSERT (false,); // unexpected data_bits lcr
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lcr & CH34X_LCR_STOP_BITS_2) {
|
||||||
|
p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_2;
|
||||||
|
} else {
|
||||||
|
p_cdc->line_coding.stop_bits = CDC_LINE_CODING_STOP_BITS_1;
|
||||||
|
}
|
||||||
|
switch (lcr & CH34X_LCR_PAR_MASK) {
|
||||||
|
case 0:
|
||||||
|
p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_NONE;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_ENABLE_PAR:
|
||||||
|
p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_ODD;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_ENABLE_PAR | CH34X_LCR_PAR_EVEN:
|
||||||
|
p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_EVEN;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE:
|
||||||
|
p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_MARK;
|
||||||
|
break;
|
||||||
|
case CH34X_LCR_ENABLE_PAR | CH34X_LCR_MARK_SPACE | CH34X_LCR_PAR_EVEN:
|
||||||
|
p_cdc->line_coding.parity = CDC_LINE_CODING_PARITY_SPACE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TU_ASSERT (false,); // unexpected parity lcr
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1378,15 +1424,57 @@ static bool ch34x_get_factor_divisor(uint32_t baval, uint8_t* factor, uint8_t* d
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calc lcr register value (data bits, parity, stop bits)
|
||||||
|
static bool ch34x_get_lcr(cdc_line_coding_t const* line_coding, uint8_t *lcr) {
|
||||||
|
*lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX;
|
||||||
|
switch (line_coding->data_bits) {
|
||||||
|
case 5:
|
||||||
|
*lcr |= CH34X_LCR_CS5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*lcr |= CH34X_LCR_CS6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*lcr |= CH34X_LCR_CS7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*lcr |= CH34X_LCR_CS8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TU_ASSERT (false); // data_bits not supported
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TU_ASSERT (line_coding->parity == CDC_LINE_CODING_PARITY_NONE || // supported parities
|
||||||
|
line_coding->parity == CDC_LINE_CODING_PARITY_ODD || line_coding->parity == CDC_LINE_CODING_PARITY_EVEN ||
|
||||||
|
line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE);
|
||||||
|
if (line_coding->parity != CDC_LINE_CODING_PARITY_NONE) {
|
||||||
|
*lcr |= CH34X_LCR_ENABLE_PAR;
|
||||||
|
if (line_coding->parity == CDC_LINE_CODING_PARITY_EVEN || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) {
|
||||||
|
*lcr |= CH34X_LCR_PAR_EVEN;
|
||||||
|
}
|
||||||
|
if (line_coding->parity == CDC_LINE_CODING_PARITY_MARK || line_coding->parity == CDC_LINE_CODING_PARITY_SPACE) {
|
||||||
|
*lcr |= CH34X_LCR_MARK_SPACE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TU_ASSERT (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_1 ||
|
||||||
|
line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2); // not supported 1.5 stop bits
|
||||||
|
if (line_coding->stop_bits == CDC_LINE_CODING_STOP_BITS_2) {
|
||||||
|
*lcr |= CH34X_LCR_STOP_BITS_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding,
|
static bool ch34x_set_line_coding(cdch_interface_t* p_cdc, cdc_line_coding_t const* line_coding,
|
||||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||||
// TODO implement later
|
p_cdc->baudrate_requested = line_coding->bit_rate;
|
||||||
(void) p_cdc;
|
p_cdc->user_control_cb = complete_cb;
|
||||||
(void) line_coding;
|
uint8_t factor, divisor, lcr;
|
||||||
(void) complete_cb;
|
TU_ASSERT (ch34x_get_factor_divisor(line_coding->bit_rate, &factor, &divisor));
|
||||||
(void) user_data;
|
TU_ASSERT (ch34x_get_lcr(line_coding, &lcr));
|
||||||
|
TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor),
|
||||||
return false;
|
complete_cb ? ch34x_control_complete : NULL, user_data));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
|
static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
|
||||||
@ -1398,7 +1486,6 @@ static bool ch34x_set_baudrate(cdch_interface_t* p_cdc, uint32_t baudrate,
|
|||||||
uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor);
|
uint16_t const value = (uint16_t ) (factor << 8 | 0x80 | divisor);
|
||||||
TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value,
|
TU_ASSERT (ch34x_write_reg(p_cdc, 0x1312, value,
|
||||||
complete_cb ? ch34x_control_complete : NULL, user_data));
|
complete_cb ? ch34x_control_complete : NULL, user_data));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1427,82 +1514,36 @@ static void ch34x_process_config(tuh_xfer_t* xfer) {
|
|||||||
TU_ASSERT (p_cdc,);
|
TU_ASSERT (p_cdc,);
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case CONFIG_CH34X_READ_VERSION: // request version read
|
case CONFIG_CH34X_READ_VERSION:
|
||||||
TU_LOG_DRV("[%u] CDCh CH34x attempt to read version\r\n", p_cdc->daddr);
|
// version read request
|
||||||
TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SERIAL_INIT),);
|
TU_LOG_DRV("[%u] CDCh CH34x attempt to read Chip Version\r\n", p_cdc->daddr);
|
||||||
|
TU_ASSERT (ch34x_control_in(p_cdc, CH34X_REQ_READ_VERSION, 0, 0, buffer, 2, ch34x_process_config, CONFIG_CH34X_SET_LINE_CODING),);
|
||||||
break;
|
break;
|
||||||
|
case CONFIG_CH34X_SET_LINE_CODING:
|
||||||
case CONFIG_CH34X_SERIAL_INIT: { // handle version read data, request to init CH34x with line_coding and baudrate
|
// handle version read data, set CH34x line coding (incl. baudrate)
|
||||||
uint8_t version = xfer->buffer[0];
|
uint8_t version = xfer->buffer[0];
|
||||||
TU_LOG_DRV("[%u] CDCh CH34x Chip version = %02x\r\n", p_cdc->daddr, version);
|
TU_LOG_DRV("[%u] CDCh CH34x Chip Version = %02x\r\n", p_cdc->daddr, version);
|
||||||
// only versions >= 0x30 are tested, below 0x30 seems having other programming, see WCH vendor, linux kernel and FreeBSD drivers
|
// 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 (version >= 0x30,);
|
||||||
uint8_t factor, divisor;
|
TU_ASSERT (ch34x_set_line_coding(p_cdc, &line_coding, ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),);
|
||||||
TU_ASSERT (ch34x_get_factor_divisor(line_coding.bit_rate, &factor, &divisor),);
|
|
||||||
uint8_t lcr = CH34X_LCR_ENABLE_RX | CH34X_LCR_ENABLE_TX;
|
|
||||||
|
|
||||||
switch (line_coding.data_bits) {
|
|
||||||
case 5:
|
|
||||||
lcr |= CH34X_LCR_CS5;
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
lcr |= CH34X_LCR_CS6;
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
lcr |= CH34X_LCR_CS7;
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
lcr |= CH34X_LCR_CS8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
TU_ASSERT (false,); // not supported data_bits
|
|
||||||
lcr |= CH34X_LCR_CS8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_coding.parity != CDC_LINE_CODING_PARITY_NONE) {
|
|
||||||
lcr |= CH34X_LCR_ENABLE_PAR;
|
|
||||||
if (line_coding.parity == CDC_LINE_CODING_PARITY_EVEN ||
|
|
||||||
line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) {
|
|
||||||
lcr |= CH34X_LCR_PAR_EVEN;
|
|
||||||
}
|
|
||||||
if (line_coding.parity == CDC_LINE_CODING_PARITY_MARK ||
|
|
||||||
line_coding.parity == CDC_LINE_CODING_PARITY_SPACE) {
|
|
||||||
lcr |= CH34X_LCR_MARK_SPACE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TU_ASSERT (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_1 ||
|
|
||||||
line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2,); // 1.5 stop bits not supported
|
|
||||||
if (line_coding.stop_bits == CDC_LINE_CODING_STOP_BITS_2) {
|
|
||||||
lcr |= CH34X_LCR_STOP_BITS_2;
|
|
||||||
}
|
|
||||||
TU_ASSERT (ch34x_control_out(p_cdc, CH34X_REQ_SERIAL_INIT, (uint16_t) (lcr << 8 | 0x9c), (uint16_t) (factor << 8 | 0x80 | divisor),
|
|
||||||
ch34x_process_config, CONFIG_CH34X_SPECIAL_REG_WRITE),);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case CONFIG_CH34X_SPECIAL_REG_WRITE:
|
case CONFIG_CH34X_SPECIAL_REG_WRITE:
|
||||||
// do special reg write, purpose unknown, overtaken from WCH driver
|
// do special reg write, purpose unknown, overtaken from WCH driver
|
||||||
TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),);
|
TU_ASSERT (ch34x_write_reg(p_cdc, 0x0f2c, 0x0007, ch34x_process_config, CONFIG_CH34X_FLOW_CONTROL),);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_CH34X_FLOW_CONTROL:
|
case CONFIG_CH34X_FLOW_CONTROL:
|
||||||
// no hardware flow control
|
// no hardware flow control
|
||||||
TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),);
|
TU_ASSERT (ch34x_write_reg(p_cdc, 0x2727, 0x0000, ch34x_process_config, CONFIG_CH34X_MODEM_CONTROL),);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_CH34X_MODEM_CONTROL:
|
case CONFIG_CH34X_MODEM_CONTROL:
|
||||||
// !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT)
|
// !always! set modem controls RTS/DTR (CH34x has no reset state after CH34X_REQ_SERIAL_INIT)
|
||||||
TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),);
|
TU_ASSERT (ch34x_set_modem_ctrl(p_cdc, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, ch34x_process_config, CONFIG_CH34X_COMPLETE),);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CONFIG_CH34X_COMPLETE:
|
case CONFIG_CH34X_COMPLETE:
|
||||||
p_cdc->line_coding = line_coding; // CONFIG_CH34X_SERIAL_INIT not handled by ch34x_control_complete
|
|
||||||
set_config_complete(p_cdc, idx, itf_num);
|
set_config_complete(p_cdc, idx, itf_num);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TU_ASSERT (false,);
|
TU_ASSERT (false,); // something gone wrong, should never reached
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,13 @@
|
|||||||
#ifndef _CH34X_H_
|
#ifndef _CH34X_H_
|
||||||
#define _CH34X_H_
|
#define _CH34X_H_
|
||||||
|
|
||||||
|
// For simplicity, only the name CH34X is used here,
|
||||||
|
// but specifically only CH340 and CH341 are supported.
|
||||||
|
|
||||||
// There is no official documentation for the CH34x chips. Reference can be found
|
// There is no official documentation for the CH34x chips. Reference can be found
|
||||||
// - https://github.com/WCHSoftGroup/ch341ser_linux
|
// - https://github.com/WCHSoftGroup/ch341ser_linux
|
||||||
// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c
|
// - https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c
|
||||||
|
// - https://github.com/freebsd/freebsd-src/blob/main/sys/dev/usb/serial/uchcom.c
|
||||||
|
|
||||||
// set line_coding @ enumeration
|
// set line_coding @ enumeration
|
||||||
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
|
#ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
|
||||||
@ -45,6 +49,7 @@
|
|||||||
#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
|
#define CH34X_REQ_SERIAL_INIT 0xA1 // dec 161
|
||||||
#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
|
#define CH34X_REQ_MODEM_CTRL 0xA4 // dev 164
|
||||||
|
|
||||||
|
// registers
|
||||||
#define CH34X_REG_BREAK 0x05
|
#define CH34X_REG_BREAK 0x05
|
||||||
#define CH34X_REG_PRESCALER 0x12
|
#define CH34X_REG_PRESCALER 0x12
|
||||||
#define CH34X_REG_DIVISOR 0x13
|
#define CH34X_REG_DIVISOR 0x13
|
||||||
@ -64,10 +69,12 @@
|
|||||||
#define CH34X_LCR_MARK_SPACE 0x20
|
#define CH34X_LCR_MARK_SPACE 0x20
|
||||||
#define CH34X_LCR_PAR_EVEN 0x10
|
#define CH34X_LCR_PAR_EVEN 0x10
|
||||||
#define CH34X_LCR_ENABLE_PAR 0x08
|
#define CH34X_LCR_ENABLE_PAR 0x08
|
||||||
|
#define CH34X_LCR_PAR_MASK 0x38 // all parity bits
|
||||||
#define CH34X_LCR_STOP_BITS_2 0x04
|
#define CH34X_LCR_STOP_BITS_2 0x04
|
||||||
#define CH34X_LCR_CS8 0x03
|
#define CH34X_LCR_CS8 0x03
|
||||||
#define CH34X_LCR_CS7 0x02
|
#define CH34X_LCR_CS7 0x02
|
||||||
#define CH34X_LCR_CS6 0x01
|
#define CH34X_LCR_CS6 0x01
|
||||||
#define CH34X_LCR_CS5 0x00
|
#define CH34X_LCR_CS5 0x00
|
||||||
|
#define CH34X_LCR_CS_MASK 0x03 // all CSx bits
|
||||||
|
|
||||||
#endif /* _CH34X_H_ */
|
#endif /* _CH34X_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user