Date: Wed, 25 Jun 2025 07:45:51 +0200 (CEST) From: Ronald Klop <ronald-lists@klop.ws> To: Kevin Lo <kevlo@FreeBSD.org> Cc: dev-commits-src-all@FreeBSD.org, src-committers@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: Re: git: 1395712cab8e - main - uchcom: add support for CH9102 and CH343 uarts Message-ID: <727722724.560.1750830351345@localhost> In-Reply-To: <202506250136.55P1aag8094334@gitrepo.freebsd.org> References: <202506250136.55P1aag8094334@gitrepo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
------=_Part_559_1619721974.1750830351251 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Hi, nice work! Isn't the HARDWARE section in the man page used to generate a supported hardware list in the release notes of a new FreeBSD version? Regards, Ronald. Van: Kevin Lo <kevlo@FreeBSD.org> Datum:woensdag, 25 juni 2025 03:36 Aan:src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Onderwerp:git: 1395712cab8e - main - uchcom: add support for CH9102 and CH343 uarts > > The branch main has been updated by kevlo: > > URL: https://cgit.FreeBSD.org/src/commit/?id=1395712cab8e95808064ba68c5a792b7cd0fe35f > > commit 1395712cab8e95808064ba68c5a792b7cd0fe35f > Author: Kevin Lo <kevlo@FreeBSD.org> > AuthorDate: 2025-06-25 01:33:35 +0000 > Commit: Kevin Lo <kevlo@FreeBSD.org> > CommitDate: 2025-06-25 01:33:35 +0000 > > uchcom: add support for CH9102 and CH343 uarts > > The CH343 devices support any baud rate up to 6 Mbps. > PR: 272803 > Reviewed by: imp > Tested by: joerg, Tomasz "CeDeROM" CEDRO <tomek_AT_cedro_DOT_info> > Differential Revision: https://reviews.freebsd.org/D46290 > --- > share/man/man4/uchcom.4 | 27 +--- > sys/dev/usb/serial/uchcom.c | 353 +++++++++++++++++++++++++------------------- > sys/dev/usb/usbdevs | 4 +- > 3 files changed, 208 insertions(+), 176 deletions(-) > > diff --git a/share/man/man4/uchcom.4 b/share/man/man4/uchcom.4 > index d5efe83286ba..4d395573589f 100644 > --- a/share/man/man4/uchcom.4 > +++ b/share/man/man4/uchcom.4 > @@ -27,12 +27,12 @@ > .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > .\" POSSIBILITY OF SUCH DAMAGE. > .\" > -.Dd April 26, 2017 > +.Dd August 19, 2024 > .Dt UCHCOM 4 > .Os > .Sh NAME > .Nm uchcom > -.Nd WinChipHead CH341/CH340 serial adapter driver > +.Nd WinChipHead CH9102/CH343/CH341/CH340 serial adapter driver > .Sh SYNOPSIS > To compile this driver into the kernel, > place the following lines in your > @@ -52,22 +52,12 @@ uchcom_load="YES" > .Sh DESCRIPTION > The > .Nm > -driver provides support for the WinChipHead CH341/CH340 USB-to-RS-232 > -Bridge chip. > +driver provides support for the WinChipHead CH9102/CH343/CH341/CH340 > +USB-to-RS-232 Bridge chip. > .Pp > -The device is accessed through the > -.Xr ucom 4 > -driver which makes it behave like a > -.Xr tty 4 . > -.Sh HARDWARE > -The > -.Nm > -driver supports the following adapters: > -.Pp > -.Bl -bullet -compact > -.It > -HL USB-RS232 > -.El > +The datasheets for the CH340/CH341 list the maximum > +supported baud rate as 2,000,000. > +CH9102/CH343 devices support any baud rate up to 6 Mbps. > .Sh FILES > .Bl -tag -width "/dev/ttyU*.init" -compact > .It Pa /dev/ttyU* > @@ -95,6 +85,3 @@ The first > .Fx > release to include it was > .Fx 8.0 . > -.Sh BUGS > -Actually, this chip seems unable to drive other than 8 data bits and > -1 stop bit line. > diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c > index a886b25c89d7..fdc5515fa722 100644 > --- a/sys/dev/usb/serial/uchcom.c > +++ b/sys/dev/usb/serial/uchcom.c > @@ -58,8 +58,7 @@ > */ > > /* > - * Driver for WinChipHead CH341/340, the worst USB-serial chip in the > - * world. > + * Driver for WinChipHead CH9102/343/341/340. > */ > > #include <sys/stdint.h> > @@ -101,17 +100,19 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN, > &uchcom_debug, 0, "uchcom debug level"); > #endif > > -#define UCHCOM_IFACE_INDEX 0 > -#define UCHCOM_CONFIG_INDEX 0 > +#define UCHCOM_IFACE_INDEX 0 > +#define UCHCOM_CONFIG_INDEX 0 > +#define UCHCOM_SECOND_IFACE_INDEX 1 > > #define UCHCOM_REV_CH340 0x0250 > #define UCHCOM_INPUT_BUF_SIZE 8 > > -#define UCHCOM_REQ_GET_VERSION 0x5F > -#define UCHCOM_REQ_READ_REG 0x95 > -#define UCHCOM_REQ_WRITE_REG 0x9A > -#define UCHCOM_REQ_RESET 0xA1 > -#define UCHCOM_REQ_SET_DTRRTS 0xA4 > +#define UCHCOM_REQ_GET_VERSION 0x5F > +#define UCHCOM_REQ_READ_REG 0x95 > +#define UCHCOM_REQ_WRITE_REG 0x9A > +#define UCHCOM_REQ_RESET 0xA1 > +#define UCHCOM_REQ_SET_DTRRTS 0xA4 > +#define UCHCOM_REQ_CH343_WRITE_REG 0xA8 > > #define UCHCOM_REG_STAT1 0x06 > #define UCHCOM_REG_STAT2 0x07 > @@ -134,13 +135,21 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN, > #define UCHCOM_RTS_MASK 0x40 > > #define UCHCOM_BRK_MASK 0x01 > +#define UCHCOM_ABRK_MASK 0x10 > +#define UCHCOM_CH343_BRK_MASK 0x80 > > #define UCHCOM_LCR1_MASK 0xAF > #define UCHCOM_LCR2_MASK 0x07 > #define UCHCOM_LCR1_RX 0x80 > #define UCHCOM_LCR1_TX 0x40 > #define UCHCOM_LCR1_PARENB 0x08 > +#define UCHCOM_LCR1_CS5 0x00 > +#define UCHCOM_LCR1_CS6 0x01 > +#define UCHCOM_LCR1_CS7 0x02 > #define UCHCOM_LCR1_CS8 0x03 > +#define UCHCOM_LCR1_STOPB 0x04 > +#define UCHCOM_LCR1_PARODD 0x00 > +#define UCHCOM_LCR1_PAREVEN 0x10 > #define UCHCOM_LCR2_PAREVEN 0x07 > #define UCHCOM_LCR2_PARODD 0x06 > #define UCHCOM_LCR2_PARMARK 0x05 > @@ -150,12 +159,18 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN, > #define UCHCOM_INTR_STAT2 0x03 > #define UCHCOM_INTR_LEAST 4 > > -#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */ > +#define UCHCOM_T 0x08 > +#define UCHCOM_CL 0x04 > +#define UCHCOM_CH343_CT 0x80 > +#define UCHCOM_CT 0x90 > + > +#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */ > + > +#define TYPE_CH343 1 > > enum { > UCHCOM_BULK_DT_WR, > UCHCOM_BULK_DT_RD, > - UCHCOM_INTR_DT_RD, > UCHCOM_N_TRANSFER, > }; > > @@ -164,6 +179,7 @@ struct uchcom_softc { > struct ucom_softc sc_ucom; > > struct usb_xfer *sc_xfer[UCHCOM_N_TRANSFER]; > + struct usb_xfer *sc_intr_xfer; /* Interrupt endpoint */ > struct usb_device *sc_udev; > struct mtx sc_mtx; > > @@ -171,39 +187,19 @@ struct uchcom_softc { > uint8_t sc_rts; /* local copy */ > uint8_t sc_version; > uint8_t sc_msr; > - uint8_t sc_lsr; /* local status register */ > -}; > - > -struct uchcom_divider { > - uint8_t dv_prescaler; > - uint8_t dv_div; > - uint8_t dv_mod; > -}; > - > -struct uchcom_divider_record { > - uint32_t dvr_high; > - uint32_t dvr_low; > - uint32_t dvr_base_clock; > - struct uchcom_divider dvr_divider; > -}; > - > -static const struct uchcom_divider_record dividers[] = > -{ > - {307200, 307200, UCHCOM_BASE_UNKNOWN, {7, 0xD9, 0}}, > - {921600, 921600, UCHCOM_BASE_UNKNOWN, {7, 0xF3, 0}}, > - {2999999, 23530, 6000000, {3, 0, 0}}, > - {23529, 2942, 750000, {2, 0, 0}}, > - {2941, 368, 93750, {1, 0, 0}}, > - {367, 1, 11719, {0, 0, 0}}, > + uint8_t sc_lsr; /* local status register */ > + uint8_t sc_chiptype; /* type of chip */ > + uint8_t sc_ctrl_iface_no; > + uint8_t sc_iface_index; > }; > > -#define NUM_DIVIDERS nitems(dividers) > - > static const STRUCT_USB_HOST_ID uchcom_devs[] = { > {USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)}, > {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)}, > {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_2, 0)}, > {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_3, 0)}, > + {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH343SER, 0)}, > + {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH9102SER, 0)}, > }; > > /* protypes */ > @@ -225,8 +221,9 @@ static void uchcom_update_version(struct uchcom_softc *); > static void uchcom_convert_status(struct uchcom_softc *, uint8_t); > static void uchcom_update_status(struct uchcom_softc *); > static void uchcom_set_dtr_rts(struct uchcom_softc *); > -static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t); > -static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t); > +static void uchcom_calc_baudrate(struct uchcom_softc *, uint32_t, uint8_t *, > + uint8_t *); > +static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t, uint16_t); > static void uchcom_poll(struct ucom_softc *ucom); > > static device_probe_t uchcom_probe; > @@ -244,7 +241,7 @@ static const struct usb_config uchcom_config_data[UCHCOM_N_TRANSFER] = { > .endpoint = UE_ADDR_ANY, > .direction = UE_DIR_OUT, > .bufsize = UCHCOM_BULK_BUF_SIZE, > - .flags = {.pipe_bof = 1,.force_short_xfer = 1,}, > + .flags = {.pipe_bof = 1,}, > .callback = &uchcom_write_callback, > }, > > @@ -256,8 +253,10 @@ static const struct usb_config uchcom_config_data[UCHCOM_N_TRANSFER] = { > .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, > .callback = &uchcom_read_callback, > }, > +}; > > - [UCHCOM_INTR_DT_RD] = { > +static const struct usb_config uchcom_intr_config_data[1] = { > + [0] = { > .type = UE_INTERRUPT, > .endpoint = UE_ADDR_ANY, > .direction = UE_DIR_IN, > @@ -311,8 +310,9 @@ uchcom_attach(device_t dev) > { > struct uchcom_softc *sc = device_get_softc(dev); > struct usb_attach_arg *uaa = device_get_ivars(dev); > + struct usb_interface *iface; > + struct usb_interface_descriptor *id; > int error; > - uint8_t iface_index; > > DPRINTFN(11, "\n"); > > @@ -330,20 +330,49 @@ uchcom_attach(device_t dev) > case USB_PRODUCT_WCH2_CH341SER_3: > device_printf(dev, "CH341 detected\n"); > break; > + case USB_PRODUCT_WCH2_CH343SER: > + device_printf(dev, "CH343 detected\n"); > + break; > + case USB_PRODUCT_WCH2_CH9102SER: > + device_printf(dev, "CH9102 detected\n"); > + break; > default: > - device_printf(dev, "New CH340/CH341 product 0x%04x detected\n", > - uaa->info.idProduct); > + device_printf(dev, "New CH340/CH341/CH343/CH9102 product " > + "0x%04x detected\n", uaa->info.idProduct); > break; > } > > - iface_index = UCHCOM_IFACE_INDEX; > - error = usbd_transfer_setup(uaa->device, > - &iface_index, sc->sc_xfer, uchcom_config_data, > - UCHCOM_N_TRANSFER, sc, &sc->sc_mtx); > + /* CH343/CH9102 has two interfaces. */ > + sc->sc_ctrl_iface_no = uaa->info.bIfaceNum; > > + iface = usbd_get_iface(uaa->device, UCHCOM_SECOND_IFACE_INDEX); > + if (iface) { > + id = usbd_get_interface_descriptor(iface); > + if (id == NULL) { > + device_printf(dev, "no interface descriptor\n"); > + goto detach; > + } > + sc->sc_iface_index = UCHCOM_SECOND_IFACE_INDEX; > + usbd_set_parent_iface(uaa->device, UCHCOM_SECOND_IFACE_INDEX, > + uaa->info.bIfaceIndex); > + sc->sc_chiptype = TYPE_CH343; > + } else { > + sc->sc_iface_index = UCHCOM_IFACE_INDEX; > + } > + > + /* Setup all transfers. */ > + error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, > + sc->sc_xfer, uchcom_config_data, UCHCOM_N_TRANSFER, sc, > + &sc->sc_mtx); > + if (error) { > + device_printf(dev, "could not allocate all pipes\n"); > + goto detach; > + } > + error = usbd_transfer_setup(uaa->device, &sc->sc_ctrl_iface_no, > + &sc->sc_intr_xfer, uchcom_intr_config_data, 1, sc, &sc->sc_mtx); > if (error) { > - DPRINTF("one or more missing USB endpoints, " > - "error=%s\n", usbd_errstr(error)); > + device_printf(dev, "allocating USB transfers failed for " > + "interrupt\n"); > goto detach; > } > > @@ -449,7 +478,9 @@ uchcom_write_reg(struct uchcom_softc *sc, > (unsigned)reg1, (unsigned)val1, > (unsigned)reg2, (unsigned)val2); > uchcom_ctrl_write( > - sc, UCHCOM_REQ_WRITE_REG, > + sc, > + (sc->sc_chiptype != TYPE_CH343) ? > + UCHCOM_REQ_WRITE_REG : UCHCOM_REQ_CH343_WRITE_REG, > reg1 | ((uint16_t)reg2 << 8), val1 | ((uint16_t)val2 << 8)); > } > > @@ -516,9 +547,6 @@ uchcom_update_version(struct uchcom_softc *sc) > static void > uchcom_convert_status(struct uchcom_softc *sc, uint8_t cur) > { > - sc->sc_dtr = !(cur & UCHCOM_DTR_MASK); > - sc->sc_rts = !(cur & UCHCOM_RTS_MASK); > - > cur = ~cur & 0x0F; > sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur); > } > @@ -555,78 +583,69 @@ uchcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff) > uint8_t brk1; > uint8_t brk2; > > - uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1, &brk2); > - if (onoff) { > - /* on - clear bits */ > - brk1 &= ~UCHCOM_BRK_MASK; > - brk2 &= ~UCHCOM_LCR1_TX; > + if (sc->sc_chiptype == TYPE_CH343) { > + brk1 = UCHCOM_CH343_BRK_MASK; > + if (!onoff) > + brk1 |= UCHCOM_ABRK_MASK; > + uchcom_write_reg(sc, brk1, 0, 0, 0); > } else { > - /* off - set bits */ > - brk1 |= UCHCOM_BRK_MASK; > - brk2 |= UCHCOM_LCR1_TX; > + uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1, > + &brk2); > + if (onoff) { > + /* on - clear bits */ > + brk1 &= ~UCHCOM_BRK_MASK; > + brk2 &= ~UCHCOM_LCR1_TX; > + } else { > + /* off - set bits */ > + brk1 |= UCHCOM_BRK_MASK; > + brk2 |= UCHCOM_LCR1_TX; > + } > + uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1, > + brk2); > } > - uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1, brk2); > } > > -static int > -uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) > -{ > - const struct uchcom_divider_record *rp; > - uint32_t div; > - uint32_t rem; > - uint32_t mod; > - uint8_t i; > - > - /* find record */ > - for (i = 0; i != NUM_DIVIDERS; i++) { > - if (dividers[i].dvr_high >= rate && > - dividers[i].dvr_low <= rate) { > - rp = ÷rs[i]; > - goto found; > - } > - } > - return (-1); > - > -found: > - dp->dv_prescaler = rp->dvr_divider.dv_prescaler; > - if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN) > - dp->dv_div = rp->dvr_divider.dv_div; > - else { > - div = rp->dvr_base_clock / rate; > - rem = rp->dvr_base_clock % rate; > - if (div == 0 || div >= 0xFF) > - return (-1); > - if ((rem << 1) >= rate) > - div += 1; > - dp->dv_div = (uint8_t)-div; > +static void > +uchcom_calc_baudrate(struct uchcom_softc *sc, uint32_t rate, uint8_t *divisor, > + uint8_t *factor) > +{ > + uint32_t clk = 12000000; > + > + if (rate >= 256000 && sc->sc_chiptype == TYPE_CH343) > + *divisor = 7; > + else if (rate > 23529) { > + clk /= 2; > + *divisor = 3; > + } else if (rate > 2941) { > + clk /= 16; > + *divisor = 2; > + } else if (rate > 367) { > + clk /= 128; > + *divisor = 1; > + } else { > + clk = 11719; > + *divisor = 0; > } > > - mod = (UCHCOM_BPS_MOD_BASE / rate) + UCHCOM_BPS_MOD_BASE_OFS; > - mod = mod + (mod / 2); > + *factor = 256 - clk / rate; > > - dp->dv_mod = (mod + 0xFF) / 0x100; > - > - return (0); > + if (rate == 921600 && sc->sc_chiptype != TYPE_CH343) { > + *divisor = 7; > + *factor = 243; > + } > } > > static void > -uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate) > +uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate, uint16_t lcr) > { > - struct uchcom_divider dv; > + uint16_t idx; > + uint8_t factor, div; > > - if (uchcom_calc_divider_settings(&dv, rate)) > - return; > + uchcom_calc_baudrate(sc, rate, &div, &factor); > + div |= (sc->sc_chiptype != TYPE_CH343) ? 0x80 : 0x00; > + idx = (factor << 8) | div; > > - /* > - * According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE, > - * otherwise the chip will buffer data. > - */ > - uchcom_write_reg(sc, > - UCHCOM_REG_BPS_PRE, dv.dv_prescaler | 0x80, > - UCHCOM_REG_BPS_DIV, dv.dv_div); > - uchcom_write_reg(sc, > - UCHCOM_REG_BPS_MOD, dv.dv_mod, > - UCHCOM_REG_BPS_PAD, 0); > + uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, lcr, idx); > } > > /* ---------------------------------------------------------------------- > @@ -673,6 +692,14 @@ uchcom_cfg_open(struct ucom_softc *ucom) > > DPRINTF("\n"); > > + if (sc->sc_chiptype != TYPE_CH343) { > + /* Set default configuration. */ > + uchcom_get_version(sc, NULL); > + uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0); > + uchcom_write_reg(sc, UCHCOM_REG_BPS_PRE, 0x82, > + UCHCOM_REG_BPS_DIV, 0xd9); > + uchcom_write_reg(sc, 0x2c, 0x07, UCHCOM_REG_BPS_PAD, 0); > + } > uchcom_update_version(sc); > uchcom_update_status(sc); > } > @@ -680,53 +707,69 @@ uchcom_cfg_open(struct ucom_softc *ucom) > static int > uchcom_pre_param(struct ucom_softc *ucom, struct termios *t) > { > - struct uchcom_divider dv; > + struct uchcom_softc *sc = ucom->sc_parent; > > - switch (t->c_cflag & CSIZE) { > - case CS8: > + /* > + * Check requested baud rate. > + * The CH340/CH341 can set any baud rate up to 2Mb. > + * The CH9102/CH343 can set any baud rate up to 6Mb. > + */ > + switch (sc->sc_chiptype) { > + case TYPE_CH343: > + if (t->c_ospeed <= 6000000) > + return (0); > break; > default: > - return (EIO); > + if (t->c_ospeed <= 2000000) > + return (0); > + break; > } > - if ((t->c_cflag & CSTOPB) != 0) > - return (EIO); > - if ((t->c_cflag & PARENB) != 0) > - return (EIO); > > - if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) { > - return (EIO); > - } > - return (0); /* success */ > + return (EIO); > } > > static void > uchcom_cfg_param(struct ucom_softc *ucom, struct termios *t) > { > struct uchcom_softc *sc = ucom->sc_parent; > + uint8_t lcr; > > - uchcom_get_version(sc, NULL); > - uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0); > - uchcom_set_baudrate(sc, t->c_ospeed); > - if (sc->sc_version < UCHCOM_VER_30) { > - uchcom_read_reg(sc, UCHCOM_REG_LCR1, NULL, > - UCHCOM_REG_LCR2, NULL); > - uchcom_write_reg(sc, UCHCOM_REG_LCR1, 0x50, > - UCHCOM_REG_LCR2, 0x00); > - } else { > - /* > - * Set up line control: > - * - enable transmit and receive > - * - set 8n1 mode > - * To do: support other sizes, parity, stop bits. > - */ > - uchcom_write_reg(sc, > - UCHCOM_REG_LCR1, > - UCHCOM_LCR1_RX | UCHCOM_LCR1_TX | UCHCOM_LCR1_CS8, > - UCHCOM_REG_LCR2, 0x00); > + lcr = UCHCOM_LCR1_RX | UCHCOM_LCR1_TX; > + > + if (t->c_cflag & CSTOPB) > + lcr |= UCHCOM_LCR1_STOPB; > + > + if (t->c_cflag & PARENB) { > + lcr |= UCHCOM_LCR1_PARENB; > + if (t->c_cflag & PARODD) > + lcr |= UCHCOM_LCR1_PARODD; > + else > + lcr |= UCHCOM_LCR1_PAREVEN; > } > - uchcom_update_status(sc); > - uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0x501f, 0xd90a); > - uchcom_set_baudrate(sc, t->c_ospeed); > + > + switch (t->c_cflag & CSIZE) { > + case CS5: > + lcr |= UCHCOM_LCR1_CS5; > + break; > + case CS6: > + lcr |= UCHCOM_LCR1_CS6; > + break; > + case CS7: > + lcr |= UCHCOM_LCR1_CS7; > + break; > + case CS8: > + default: > + lcr |= UCHCOM_LCR1_CS8; > + break; > + } > + > + if (sc->sc_chiptype == TYPE_CH343) > + uchcom_set_baudrate(sc, t->c_ospeed, > + UCHCOM_T | UCHCOM_CL | UCHCOM_CH343_CT | lcr << 8); > + else > + uchcom_set_baudrate(sc, t->c_ospeed, > + UCHCOM_T | UCHCOM_CL | UCHCOM_CT | lcr << 8); > + > uchcom_set_dtr_rts(sc); > uchcom_update_status(sc); > } > @@ -737,7 +780,7 @@ uchcom_start_read(struct ucom_softc *ucom) > struct uchcom_softc *sc = ucom->sc_parent; > > /* start interrupt endpoint */ > - usbd_transfer_start(sc->sc_xfer[UCHCOM_INTR_DT_RD]); > + usbd_transfer_start(sc->sc_intr_xfer); > > /* start read endpoint */ > usbd_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_RD]); > @@ -749,7 +792,7 @@ uchcom_stop_read(struct ucom_softc *ucom) > struct uchcom_softc *sc = ucom->sc_parent; > > /* stop interrupt endpoint */ > - usbd_transfer_stop(sc->sc_xfer[UCHCOM_INTR_DT_RD]); > + usbd_transfer_stop(sc->sc_intr_xfer); > > /* stop read endpoint */ > usbd_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_RD]); > @@ -779,7 +822,8 @@ uchcom_intr_callback(struct usb_xfer *xfer, usb_error_t error) > { > struct uchcom_softc *sc = usbd_xfer_softc(xfer); > struct usb_page_cache *pc; > - uint8_t buf[UCHCOM_INTR_LEAST]; > + uint32_t intrstat; > + uint8_t buf[16]; > int actlen; > > usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); > @@ -791,13 +835,12 @@ uchcom_intr_callback(struct usb_xfer *xfer, usb_error_t error) > > if (actlen >= UCHCOM_INTR_LEAST) { > pc = usbd_xfer_get_frame(xfer, 0); > - usbd_copy_out(pc, 0, buf, UCHCOM_INTR_LEAST); > + usbd_copy_out(pc, 0, buf, sizeof(buf)); > > - DPRINTF("data = 0x%02X 0x%02X 0x%02X 0x%02X\n", > - (unsigned)buf[0], (unsigned)buf[1], > - (unsigned)buf[2], (unsigned)buf[3]); > + intrstat = (sc->sc_chiptype == TYPE_CH343) ? > + actlen - 1 : UCHCOM_INTR_STAT1; > > - uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]); > + uchcom_convert_status(sc, buf[intrstat]); > ucom_status_change(&sc->sc_ucom); > } > case USB_ST_SETUP: > diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs > index f26edcebcb9c..2318e6bd0017 100644 > --- a/sys/dev/usb/usbdevs > +++ b/sys/dev/usb/usbdevs > @@ -4972,9 +4972,11 @@ product WAVESENSE JAZZ 0xaaaa Jazz blood glucose meter > /* WCH products */ > product WCH CH341SER 0x5523 CH341/CH340 USB-Serial Bridge > product WCH2 CH341SER_2 0x5523 CH341/CH340 USB-Serial Bridge > +product WCH2 CH343SER 0x55d3 CH343 USB Serial > +product WCH2 CH9102SER 0x55d4 CH9102 USB Serial > product WCH2 CH341SER_3 0x7522 CH341/CH340 USB-Serial Bridge > product WCH2 CH341SER 0x7523 CH341/CH340 USB-Serial Bridge > -product WCH2 U2M 0X752d CH345 USB2.0-MIDI > +product WCH2 U2M 0x752d CH345 USB2.0-MIDI > > /* West Mountain Radio products */ > product WESTMOUNTAIN RIGBLASTER_ADVANTAGE 0x0003 RIGblaster Advantage > > > > ------=_Part_559_1619721974.1750830351251 Content-Type: text/html; charset=us-ascii Content-Transfer-Encoding: 7bit <html><head></head><body>Hi,<br> <br> nice work!<br> <br> Isn't the HARDWARE section in the man page used to generate a supported hardware list in the release notes of a new FreeBSD version?<br> <br> Regards,<br> Ronald.<br> <br> <p><strong>Van:</strong> Kevin Lo <kevlo@FreeBSD.org><br> <strong>Datum:</strong>woensdag, 25 juni 2025 03:36<br> <strong>Aan:</strong>src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org<br> <strong>Onderwerp:</strong>git: 1395712cab8e - main - uchcom: add support for CH9102 and CH343 uarts</p> <blockquote style="padding-right: 0px; padding-left: 5px; margin-left: 5px; border-left: #000000 2px solid; margin-right: 0px"> <div class="MessageRFC822Viewer" id="P"> <div class="TextPlainViewer" id="P.P">The branch main has been updated by kevlo:<br> <br> URL: <a href="https://cgit.FreeBSD.org/src/commit/?id=1395712cab8e95808064ba68c5a792b7cd0fe35f">https://cgit.FreeBSD.org/src/commit/?id=1395712cab8e95808064ba68c5a792b7cd0fe35f</a><br> <br> commit 1395712cab8e95808064ba68c5a792b7cd0fe35f<br> Author: Kevin Lo <kevlo@FreeBSD.org><br> AuthorDate: 2025-06-25 01:33:35 +0000<br> Commit: Kevin Lo <kevlo@FreeBSD.org><br> CommitDate: 2025-06-25 01:33:35 +0000<br> <br> uchcom: add support for CH9102 and CH343 uarts<br> <br> The CH343 devices support any baud rate up to 6 Mbps.<br> PR: 272803<br> Reviewed by: imp<br> Tested by: joerg, Tomasz "CeDeROM" CEDRO <tomek_AT_cedro_DOT_info><br> Differential Revision: <a href="https://reviews.freebsd.org/D46290">https://reviews.freebsd.org/D46290</a><br> ---<br> share/man/man4/uchcom.4 | 27 +---<br> sys/dev/usb/serial/uchcom.c | 353 +++++++++++++++++++++++++-------------------<br> sys/dev/usb/usbdevs | 4 +-<br> 3 files changed, 208 insertions(+), 176 deletions(-)<br> <br> diff --git a/share/man/man4/uchcom.4 b/share/man/man4/uchcom.4<br> index d5efe83286ba..4d395573589f 100644<br> --- a/share/man/man4/uchcom.4<br> +++ b/share/man/man4/uchcom.4<br> @@ -27,12 +27,12 @@<br> .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br> .\" POSSIBILITY OF SUCH DAMAGE.<br> .\"<br> -.Dd April 26, 2017<br> +.Dd August 19, 2024<br> .Dt UCHCOM 4<br> .Os<br> .Sh NAME<br> .Nm uchcom<br> -.Nd WinChipHead CH341/CH340 serial adapter driver<br> +.Nd WinChipHead CH9102/CH343/CH341/CH340 serial adapter driver<br> .Sh SYNOPSIS<br> To compile this driver into the kernel,<br> place the following lines in your<br> @@ -52,22 +52,12 @@ uchcom_load="YES"<br> .Sh DESCRIPTION<br> The<br> .Nm<br> -driver provides support for the WinChipHead CH341/CH340 USB-to-RS-232<br> -Bridge chip.<br> +driver provides support for the WinChipHead CH9102/CH343/CH341/CH340<br> +USB-to-RS-232 Bridge chip.<br> .Pp<br> -The device is accessed through the<br> -.Xr ucom 4<br> -driver which makes it behave like a<br> -.Xr tty 4 .<br> -.Sh HARDWARE<br> -The<br> -.Nm<br> -driver supports the following adapters:<br> -.Pp<br> -.Bl -bullet -compact<br> -.It<br> -HL USB-RS232<br> -.El<br> +The datasheets for the CH340/CH341 list the maximum<br> +supported baud rate as 2,000,000.<br> +CH9102/CH343 devices support any baud rate up to 6 Mbps.<br> .Sh FILES<br> .Bl -tag -width "/dev/ttyU*.init" -compact<br> .It Pa /dev/ttyU*<br> @@ -95,6 +85,3 @@ The first<br> .Fx<br> release to include it was<br> .Fx 8.0 .<br> -.Sh BUGS<br> -Actually, this chip seems unable to drive other than 8 data bits and<br> -1 stop bit line.<br> diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c<br> index a886b25c89d7..fdc5515fa722 100644<br> --- a/sys/dev/usb/serial/uchcom.c<br> +++ b/sys/dev/usb/serial/uchcom.c<br> @@ -58,8 +58,7 @@<br> */<br> <br> /*<br> - * Driver for WinChipHead CH341/340, the worst USB-serial chip in the<br> - * world.<br> + * Driver for WinChipHead CH9102/343/341/340.<br> */<br> <br> #include <sys/stdint.h><br> @@ -101,17 +100,19 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN,<br> &uchcom_debug, 0, "uchcom debug level");<br> #endif<br> <br> -#define UCHCOM_IFACE_INDEX 0<br> -#define UCHCOM_CONFIG_INDEX 0<br> +#define UCHCOM_IFACE_INDEX 0<br> +#define UCHCOM_CONFIG_INDEX 0<br> +#define UCHCOM_SECOND_IFACE_INDEX 1<br> <br> #define UCHCOM_REV_CH340 0x0250<br> #define UCHCOM_INPUT_BUF_SIZE 8<br> <br> -#define UCHCOM_REQ_GET_VERSION 0x5F<br> -#define UCHCOM_REQ_READ_REG 0x95<br> -#define UCHCOM_REQ_WRITE_REG 0x9A<br> -#define UCHCOM_REQ_RESET 0xA1<br> -#define UCHCOM_REQ_SET_DTRRTS 0xA4<br> +#define UCHCOM_REQ_GET_VERSION 0x5F<br> +#define UCHCOM_REQ_READ_REG 0x95<br> +#define UCHCOM_REQ_WRITE_REG 0x9A<br> +#define UCHCOM_REQ_RESET 0xA1<br> +#define UCHCOM_REQ_SET_DTRRTS 0xA4<br> +#define UCHCOM_REQ_CH343_WRITE_REG 0xA8<br> <br> #define UCHCOM_REG_STAT1 0x06<br> #define UCHCOM_REG_STAT2 0x07<br> @@ -134,13 +135,21 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN,<br> #define UCHCOM_RTS_MASK 0x40<br> <br> #define UCHCOM_BRK_MASK 0x01<br> +#define UCHCOM_ABRK_MASK 0x10<br> +#define UCHCOM_CH343_BRK_MASK 0x80<br> <br> #define UCHCOM_LCR1_MASK 0xAF<br> #define UCHCOM_LCR2_MASK 0x07<br> #define UCHCOM_LCR1_RX 0x80<br> #define UCHCOM_LCR1_TX 0x40<br> #define UCHCOM_LCR1_PARENB 0x08<br> +#define UCHCOM_LCR1_CS5 0x00<br> +#define UCHCOM_LCR1_CS6 0x01<br> +#define UCHCOM_LCR1_CS7 0x02<br> #define UCHCOM_LCR1_CS8 0x03<br> +#define UCHCOM_LCR1_STOPB 0x04<br> +#define UCHCOM_LCR1_PARODD 0x00<br> +#define UCHCOM_LCR1_PAREVEN 0x10<br> #define UCHCOM_LCR2_PAREVEN 0x07<br> #define UCHCOM_LCR2_PARODD 0x06<br> #define UCHCOM_LCR2_PARMARK 0x05<br> @@ -150,12 +159,18 @@ SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RWTUN,<br> #define UCHCOM_INTR_STAT2 0x03<br> #define UCHCOM_INTR_LEAST 4<br> <br> -#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */<br> +#define UCHCOM_T 0x08<br> +#define UCHCOM_CL 0x04<br> +#define UCHCOM_CH343_CT 0x80<br> +#define UCHCOM_CT 0x90<br> +<br> +#define UCHCOM_BULK_BUF_SIZE 1024 /* bytes */<br> +<br> +#define TYPE_CH343 1<br> <br> enum {<br> UCHCOM_BULK_DT_WR,<br> UCHCOM_BULK_DT_RD,<br> - UCHCOM_INTR_DT_RD,<br> UCHCOM_N_TRANSFER,<br> };<br> <br> @@ -164,6 +179,7 @@ struct uchcom_softc {<br> struct ucom_softc sc_ucom;<br> <br> struct usb_xfer *sc_xfer[UCHCOM_N_TRANSFER];<br> + struct usb_xfer *sc_intr_xfer; /* Interrupt endpoint */<br> struct usb_device *sc_udev;<br> struct mtx sc_mtx;<br> <br> @@ -171,39 +187,19 @@ struct uchcom_softc {<br> uint8_t sc_rts; /* local copy */<br> uint8_t sc_version;<br> uint8_t sc_msr;<br> - uint8_t sc_lsr; /* local status register */<br> -};<br> -<br> -struct uchcom_divider {<br> - uint8_t dv_prescaler;<br> - uint8_t dv_div;<br> - uint8_t dv_mod;<br> -};<br> -<br> -struct uchcom_divider_record {<br> - uint32_t dvr_high;<br> - uint32_t dvr_low;<br> - uint32_t dvr_base_clock;<br> - struct uchcom_divider dvr_divider;<br> -};<br> -<br> -static const struct uchcom_divider_record dividers[] =<br> -{<br> - {307200, 307200, UCHCOM_BASE_UNKNOWN, {7, 0xD9, 0}},<br> - {921600, 921600, UCHCOM_BASE_UNKNOWN, {7, 0xF3, 0}},<br> - {2999999, 23530, 6000000, {3, 0, 0}},<br> - {23529, 2942, 750000, {2, 0, 0}},<br> - {2941, 368, 93750, {1, 0, 0}},<br> - {367, 1, 11719, {0, 0, 0}},<br> + uint8_t sc_lsr; /* local status register */<br> + uint8_t sc_chiptype; /* type of chip */<br> + uint8_t sc_ctrl_iface_no;<br> + uint8_t sc_iface_index;<br> };<br> <br> -#define NUM_DIVIDERS nitems(dividers)<br> -<br> static const STRUCT_USB_HOST_ID uchcom_devs[] = {<br> {USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)},<br> {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)},<br> {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_2, 0)},<br> {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_3, 0)},<br> + {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH343SER, 0)},<br> + {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH9102SER, 0)},<br> };<br> <br> /* protypes */<br> @@ -225,8 +221,9 @@ static void uchcom_update_version(struct uchcom_softc *);<br> static void uchcom_convert_status(struct uchcom_softc *, uint8_t);<br> static void uchcom_update_status(struct uchcom_softc *);<br> static void uchcom_set_dtr_rts(struct uchcom_softc *);<br> -static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t);<br> -static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t);<br> +static void uchcom_calc_baudrate(struct uchcom_softc *, uint32_t, uint8_t *,<br> + uint8_t *);<br> +static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t, uint16_t);<br> static void uchcom_poll(struct ucom_softc *ucom);<br> <br> static device_probe_t uchcom_probe;<br> @@ -244,7 +241,7 @@ static const struct usb_config uchcom_config_data[UCHCOM_N_TRANSFER] = {<br> .endpoint = UE_ADDR_ANY,<br> .direction = UE_DIR_OUT,<br> .bufsize = UCHCOM_BULK_BUF_SIZE,<br> - .flags = {.pipe_bof = 1,.force_short_xfer = 1,},<br> + .flags = {.pipe_bof = 1,},<br> .callback = &uchcom_write_callback,<br> },<br> <br> @@ -256,8 +253,10 @@ static const struct usb_config uchcom_config_data[UCHCOM_N_TRANSFER] = {<br> .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},<br> .callback = &uchcom_read_callback,<br> },<br> +};<br> <br> - [UCHCOM_INTR_DT_RD] = {<br> +static const struct usb_config uchcom_intr_config_data[1] = {<br> + [0] = {<br> .type = UE_INTERRUPT,<br> .endpoint = UE_ADDR_ANY,<br> .direction = UE_DIR_IN,<br> @@ -311,8 +310,9 @@ uchcom_attach(device_t dev)<br> {<br> struct uchcom_softc *sc = device_get_softc(dev);<br> struct usb_attach_arg *uaa = device_get_ivars(dev);<br> + struct usb_interface *iface;<br> + struct usb_interface_descriptor *id;<br> int error;<br> - uint8_t iface_index;<br> <br> DPRINTFN(11, "\n");<br> <br> @@ -330,20 +330,49 @@ uchcom_attach(device_t dev)<br> case USB_PRODUCT_WCH2_CH341SER_3:<br> device_printf(dev, "CH341 detected\n");<br> break;<br> + case USB_PRODUCT_WCH2_CH343SER:<br> + device_printf(dev, "CH343 detected\n");<br> + break;<br> + case USB_PRODUCT_WCH2_CH9102SER:<br> + device_printf(dev, "CH9102 detected\n");<br> + break;<br> default:<br> - device_printf(dev, "New CH340/CH341 product 0x%04x detected\n",<br> - uaa->info.idProduct);<br> + device_printf(dev, "New CH340/CH341/CH343/CH9102 product "<br> + "0x%04x detected\n", uaa->info.idProduct);<br> break;<br> }<br> <br> - iface_index = UCHCOM_IFACE_INDEX;<br> - error = usbd_transfer_setup(uaa->device,<br> - &iface_index, sc->sc_xfer, uchcom_config_data,<br> - UCHCOM_N_TRANSFER, sc, &sc->sc_mtx);<br> + /* CH343/CH9102 has two interfaces. */<br> + sc->sc_ctrl_iface_no = uaa->info.bIfaceNum;<br> <br> + iface = usbd_get_iface(uaa->device, UCHCOM_SECOND_IFACE_INDEX);<br> + if (iface) {<br> + id = usbd_get_interface_descriptor(iface);<br> + if (id == NULL) {<br> + device_printf(dev, "no interface descriptor\n");<br> + goto detach;<br> + }<br> + sc->sc_iface_index = UCHCOM_SECOND_IFACE_INDEX;<br> + usbd_set_parent_iface(uaa->device, UCHCOM_SECOND_IFACE_INDEX,<br> + uaa->info.bIfaceIndex);<br> + sc->sc_chiptype = TYPE_CH343;<br> + } else {<br> + sc->sc_iface_index = UCHCOM_IFACE_INDEX;<br> + }<br> +<br> + /* Setup all transfers. */<br> + error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index,<br> + sc->sc_xfer, uchcom_config_data, UCHCOM_N_TRANSFER, sc,<br> + &sc->sc_mtx);<br> + if (error) {<br> + device_printf(dev, "could not allocate all pipes\n");<br> + goto detach;<br> + }<br> + error = usbd_transfer_setup(uaa->device, &sc->sc_ctrl_iface_no,<br> + &sc->sc_intr_xfer, uchcom_intr_config_data, 1, sc, &sc->sc_mtx);<br> if (error) {<br> - DPRINTF("one or more missing USB endpoints, "<br> - "error=%s\n", usbd_errstr(error));<br> + device_printf(dev, "allocating USB transfers failed for "<br> + "interrupt\n");<br> goto detach;<br> }<br> <br> @@ -449,7 +478,9 @@ uchcom_write_reg(struct uchcom_softc *sc,<br> (unsigned)reg1, (unsigned)val1,<br> (unsigned)reg2, (unsigned)val2);<br> uchcom_ctrl_write(<br> - sc, UCHCOM_REQ_WRITE_REG,<br> + sc,<br> + (sc->sc_chiptype != TYPE_CH343) ?<br> + UCHCOM_REQ_WRITE_REG : UCHCOM_REQ_CH343_WRITE_REG,<br> reg1 | ((uint16_t)reg2 << 8), val1 | ((uint16_t)val2 << 8));<br> }<br> <br> @@ -516,9 +547,6 @@ uchcom_update_version(struct uchcom_softc *sc)<br> static void<br> uchcom_convert_status(struct uchcom_softc *sc, uint8_t cur)<br> {<br> - sc->sc_dtr = !(cur & UCHCOM_DTR_MASK);<br> - sc->sc_rts = !(cur & UCHCOM_RTS_MASK);<br> -<br> cur = ~cur & 0x0F;<br> sc->sc_msr = (cur << 4) | ((sc->sc_msr >> 4) ^ cur);<br> }<br> @@ -555,78 +583,69 @@ uchcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)<br> uint8_t brk1;<br> uint8_t brk2;<br> <br> - uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1, &brk2);<br> - if (onoff) {<br> - /* on - clear bits */<br> - brk1 &= ~UCHCOM_BRK_MASK;<br> - brk2 &= ~UCHCOM_LCR1_TX;<br> + if (sc->sc_chiptype == TYPE_CH343) {<br> + brk1 = UCHCOM_CH343_BRK_MASK;<br> + if (!onoff)<br> + brk1 |= UCHCOM_ABRK_MASK;<br> + uchcom_write_reg(sc, brk1, 0, 0, 0);<br> } else {<br> - /* off - set bits */<br> - brk1 |= UCHCOM_BRK_MASK;<br> - brk2 |= UCHCOM_LCR1_TX;<br> + uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1,<br> + &brk2);<br> + if (onoff) {<br> + /* on - clear bits */<br> + brk1 &= ~UCHCOM_BRK_MASK;<br> + brk2 &= ~UCHCOM_LCR1_TX;<br> + } else {<br> + /* off - set bits */<br> + brk1 |= UCHCOM_BRK_MASK;<br> + brk2 |= UCHCOM_LCR1_TX;<br> + }<br> + uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1,<br> + brk2);<br> }<br> - uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1, brk2);<br> }<br> <br> -static int<br> -uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate)<br> -{<br> - const struct uchcom_divider_record *rp;<br> - uint32_t div;<br> - uint32_t rem;<br> - uint32_t mod;<br> - uint8_t i;<br> -<br> - /* find record */<br> - for (i = 0; i != NUM_DIVIDERS; i++) {<br> - if (dividers[i].dvr_high >= rate &&<br> - dividers[i].dvr_low <= rate) {<br> - rp = &dividers[i];<br> - goto found;<br> - }<br> - }<br> - return (-1);<br> -<br> -found:<br> - dp->dv_prescaler = rp->dvr_divider.dv_prescaler;<br> - if (rp->dvr_base_clock == UCHCOM_BASE_UNKNOWN)<br> - dp->dv_div = rp->dvr_divider.dv_div;<br> - else {<br> - div = rp->dvr_base_clock / rate;<br> - rem = rp->dvr_base_clock % rate;<br> - if (div == 0 || div >= 0xFF)<br> - return (-1);<br> - if ((rem << 1) >= rate)<br> - div += 1;<br> - dp->dv_div = (uint8_t)-div;<br> +static void<br> +uchcom_calc_baudrate(struct uchcom_softc *sc, uint32_t rate, uint8_t *divisor,<br> + uint8_t *factor)<br> +{<br> + uint32_t clk = 12000000;<br> +<br> + if (rate >= 256000 && sc->sc_chiptype == TYPE_CH343)<br> + *divisor = 7;<br> + else if (rate > 23529) {<br> + clk /= 2;<br> + *divisor = 3;<br> + } else if (rate > 2941) {<br> + clk /= 16;<br> + *divisor = 2;<br> + } else if (rate > 367) {<br> + clk /= 128;<br> + *divisor = 1;<br> + } else {<br> + clk = 11719;<br> + *divisor = 0;<br> }<br> <br> - mod = (UCHCOM_BPS_MOD_BASE / rate) + UCHCOM_BPS_MOD_BASE_OFS;<br> - mod = mod + (mod / 2);<br> + *factor = 256 - clk / rate;<br> <br> - dp->dv_mod = (mod + 0xFF) / 0x100;<br> -<br> - return (0);<br> + if (rate == 921600 && sc->sc_chiptype != TYPE_CH343) {<br> + *divisor = 7;<br> + *factor = 243;<br> + }<br> }<br> <br> static void<br> -uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate)<br> +uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate, uint16_t lcr)<br> {<br> - struct uchcom_divider dv;<br> + uint16_t idx;<br> + uint8_t factor, div;<br> <br> - if (uchcom_calc_divider_settings(&dv, rate))<br> - return;<br> + uchcom_calc_baudrate(sc, rate, &div, &factor);<br> + div |= (sc->sc_chiptype != TYPE_CH343) ? 0x80 : 0x00;<br> + idx = (factor << 8) | div;<br> <br> - /*<br> - * According to linux code we need to set bit 7 of UCHCOM_REG_BPS_PRE,<br> - * otherwise the chip will buffer data.<br> - */<br> - uchcom_write_reg(sc,<br> - UCHCOM_REG_BPS_PRE, dv.dv_prescaler | 0x80,<br> - UCHCOM_REG_BPS_DIV, dv.dv_div);<br> - uchcom_write_reg(sc,<br> - UCHCOM_REG_BPS_MOD, dv.dv_mod,<br> - UCHCOM_REG_BPS_PAD, 0);<br> + uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, lcr, idx);<br> }<br> <br> /* ----------------------------------------------------------------------<br> @@ -673,6 +692,14 @@ uchcom_cfg_open(struct ucom_softc *ucom)<br> <br> DPRINTF("\n");<br> <br> + if (sc->sc_chiptype != TYPE_CH343) {<br> + /* Set default configuration. */<br> + uchcom_get_version(sc, NULL);<br> + uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);<br> + uchcom_write_reg(sc, UCHCOM_REG_BPS_PRE, 0x82,<br> + UCHCOM_REG_BPS_DIV, 0xd9);<br> + uchcom_write_reg(sc, 0x2c, 0x07, UCHCOM_REG_BPS_PAD, 0);<br> + }<br> uchcom_update_version(sc);<br> uchcom_update_status(sc);<br> }<br> @@ -680,53 +707,69 @@ uchcom_cfg_open(struct ucom_softc *ucom)<br> static int<br> uchcom_pre_param(struct ucom_softc *ucom, struct termios *t)<br> {<br> - struct uchcom_divider dv;<br> + struct uchcom_softc *sc = ucom->sc_parent;<br> <br> - switch (t->c_cflag & CSIZE) {<br> - case CS8:<br> + /*<br> + * Check requested baud rate.<br> + * The CH340/CH341 can set any baud rate up to 2Mb.<br> + * The CH9102/CH343 can set any baud rate up to 6Mb.<br> + */<br> + switch (sc->sc_chiptype) {<br> + case TYPE_CH343:<br> + if (t->c_ospeed <= 6000000)<br> + return (0);<br> break;<br> default:<br> - return (EIO);<br> + if (t->c_ospeed <= 2000000)<br> + return (0);<br> + break;<br> }<br> - if ((t->c_cflag & CSTOPB) != 0)<br> - return (EIO);<br> - if ((t->c_cflag & PARENB) != 0)<br> - return (EIO);<br> <br> - if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) {<br> - return (EIO);<br> - }<br> - return (0); /* success */<br> + return (EIO);<br> }<br> <br> static void<br> uchcom_cfg_param(struct ucom_softc *ucom, struct termios *t)<br> {<br> struct uchcom_softc *sc = ucom->sc_parent;<br> + uint8_t lcr;<br> <br> - uchcom_get_version(sc, NULL);<br> - uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);<br> - uchcom_set_baudrate(sc, t->c_ospeed);<br> - if (sc->sc_version < UCHCOM_VER_30) {<br> - uchcom_read_reg(sc, UCHCOM_REG_LCR1, NULL,<br> - UCHCOM_REG_LCR2, NULL);<br> - uchcom_write_reg(sc, UCHCOM_REG_LCR1, 0x50,<br> - UCHCOM_REG_LCR2, 0x00);<br> - } else {<br> - /*<br> - * Set up line control:<br> - * - enable transmit and receive<br> - * - set 8n1 mode<br> - * To do: support other sizes, parity, stop bits.<br> - */<br> - uchcom_write_reg(sc,<br> - UCHCOM_REG_LCR1,<br> - UCHCOM_LCR1_RX | UCHCOM_LCR1_TX | UCHCOM_LCR1_CS8,<br> - UCHCOM_REG_LCR2, 0x00);<br> + lcr = UCHCOM_LCR1_RX | UCHCOM_LCR1_TX;<br> +<br> + if (t->c_cflag & CSTOPB)<br> + lcr |= UCHCOM_LCR1_STOPB;<br> +<br> + if (t->c_cflag & PARENB) {<br> + lcr |= UCHCOM_LCR1_PARENB;<br> + if (t->c_cflag & PARODD)<br> + lcr |= UCHCOM_LCR1_PARODD;<br> + else<br> + lcr |= UCHCOM_LCR1_PAREVEN;<br> }<br> - uchcom_update_status(sc);<br> - uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0x501f, 0xd90a);<br> - uchcom_set_baudrate(sc, t->c_ospeed);<br> +<br> + switch (t->c_cflag & CSIZE) {<br> + case CS5:<br> + lcr |= UCHCOM_LCR1_CS5;<br> + break;<br> + case CS6:<br> + lcr |= UCHCOM_LCR1_CS6;<br> + break;<br> + case CS7:<br> + lcr |= UCHCOM_LCR1_CS7;<br> + break;<br> + case CS8:<br> + default:<br> + lcr |= UCHCOM_LCR1_CS8;<br> + break;<br> + }<br> +<br> + if (sc->sc_chiptype == TYPE_CH343)<br> + uchcom_set_baudrate(sc, t->c_ospeed,<br> + UCHCOM_T | UCHCOM_CL | UCHCOM_CH343_CT | lcr << 8);<br> + else<br> + uchcom_set_baudrate(sc, t->c_ospeed,<br> + UCHCOM_T | UCHCOM_CL | UCHCOM_CT | lcr << 8);<br> +<br> uchcom_set_dtr_rts(sc);<br> uchcom_update_status(sc);<br> }<br> @@ -737,7 +780,7 @@ uchcom_start_read(struct ucom_softc *ucom)<br> struct uchcom_softc *sc = ucom->sc_parent;<br> <br> /* start interrupt endpoint */<br> - usbd_transfer_start(sc->sc_xfer[UCHCOM_INTR_DT_RD]);<br> + usbd_transfer_start(sc->sc_intr_xfer);<br> <br> /* start read endpoint */<br> usbd_transfer_start(sc->sc_xfer[UCHCOM_BULK_DT_RD]);<br> @@ -749,7 +792,7 @@ uchcom_stop_read(struct ucom_softc *ucom)<br> struct uchcom_softc *sc = ucom->sc_parent;<br> <br> /* stop interrupt endpoint */<br> - usbd_transfer_stop(sc->sc_xfer[UCHCOM_INTR_DT_RD]);<br> + usbd_transfer_stop(sc->sc_intr_xfer);<br> <br> /* stop read endpoint */<br> usbd_transfer_stop(sc->sc_xfer[UCHCOM_BULK_DT_RD]);<br> @@ -779,7 +822,8 @@ uchcom_intr_callback(struct usb_xfer *xfer, usb_error_t error)<br> {<br> struct uchcom_softc *sc = usbd_xfer_softc(xfer);<br> struct usb_page_cache *pc;<br> - uint8_t buf[UCHCOM_INTR_LEAST];<br> + uint32_t intrstat;<br> + uint8_t buf[16];<br> int actlen;<br> <br> usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);<br> @@ -791,13 +835,12 @@ uchcom_intr_callback(struct usb_xfer *xfer, usb_error_t error)<br> <br> if (actlen >= UCHCOM_INTR_LEAST) {<br> pc = usbd_xfer_get_frame(xfer, 0);<br> - usbd_copy_out(pc, 0, buf, UCHCOM_INTR_LEAST);<br> + usbd_copy_out(pc, 0, buf, sizeof(buf));<br> <br> - DPRINTF("data = 0x%02X 0x%02X 0x%02X 0x%02X\n",<br> - (unsigned)buf[0], (unsigned)buf[1],<br> - (unsigned)buf[2], (unsigned)buf[3]);<br> + intrstat = (sc->sc_chiptype == TYPE_CH343) ?<br> + actlen - 1 : UCHCOM_INTR_STAT1;<br> <br> - uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]);<br> + uchcom_convert_status(sc, buf[intrstat]);<br> ucom_status_change(&sc->sc_ucom);<br> }<br> case USB_ST_SETUP:<br> diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs<br> index f26edcebcb9c..2318e6bd0017 100644<br> --- a/sys/dev/usb/usbdevs<br> +++ b/sys/dev/usb/usbdevs<br> @@ -4972,9 +4972,11 @@ product WAVESENSE JAZZ 0xaaaa Jazz blood glucose meter<br> /* WCH products */<br> product WCH CH341SER 0x5523 CH341/CH340 USB-Serial Bridge<br> product WCH2 CH341SER_2 0x5523 CH341/CH340 USB-Serial Bridge<br> +product WCH2 CH343SER 0x55d3 CH343 USB Serial<br> +product WCH2 CH9102SER 0x55d4 CH9102 USB Serial<br> product WCH2 CH341SER_3 0x7522 CH341/CH340 USB-Serial Bridge<br> product WCH2 CH341SER 0x7523 CH341/CH340 USB-Serial Bridge<br> -product WCH2 U2M 0X752d CH345 USB2.0-MIDI<br> +product WCH2 U2M 0x752d CH345 USB2.0-MIDI<br> <br> /* West Mountain Radio products */<br> product WESTMOUNTAIN RIGBLASTER_ADVANTAGE 0x0003 RIGblaster Advantage<br> </div> <hr></div> </blockquote> <br> </body></html> ------=_Part_559_1619721974.1750830351251--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?727722724.560.1750830351345>