Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135261375
D46290.id142069.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D46290.id142069.diff
View Options
diff --git a/share/man/man4/uchcom.4 b/share/man/man4/uchcom.4
--- a/share/man/man4/uchcom.4
+++ b/share/man/man4/uchcom.4
@@ -32,7 +32,7 @@
.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,8 +52,9 @@
.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.
+CH9102/CH343 devices support any baud rate up to 6 Mbps.
.Pp
The device is accessed through the
.Xr ucom 4
@@ -96,5 +97,5 @@
release to include it was
.Fx 8.0 .
.Sh BUGS
-Actually, this chip seems unable to drive other than 8 data bits and
+CH341/CH340 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
--- a/sys/dev/usb/serial/uchcom.c
+++ b/sys/dev/usb/serial/uchcom.c
@@ -59,8 +59,7 @@
#include <sys/cdefs.h>
/*
- * Driver for WinChipHead CH341/340, the worst USB-serial chip in the
- * world.
+ * Driver for WinChipHead CH9102/343/341/340.
*/
#include <sys/stdint.h>
@@ -102,17 +101,20 @@
&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_REQ_SET_BAUDRATE UCHCOM_REQ_RESET
#define UCHCOM_REG_STAT1 0x06
#define UCHCOM_REG_STAT2 0x07
@@ -135,13 +137,21 @@
#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
@@ -151,12 +161,17 @@
#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_CT 0x80
+
+#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,
};
@@ -165,6 +180,7 @@
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;
@@ -172,7 +188,11 @@
uint8_t sc_rts; /* local copy */
uint8_t sc_version;
uint8_t sc_msr;
- uint8_t sc_lsr; /* local status register */
+ uint8_t sc_lsr; /* local status register */
+ uint8_t sc_chiptype; /* type of chip */
+ uint8_t sc_ctrl_iface_no;
+ uint8_t sc_data_iface_no;
+ uint8_t sc_iface_index;
};
struct uchcom_divider {
@@ -205,6 +225,8 @@
{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 */
@@ -226,8 +248,11 @@
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 void uchcom_calc_baudrate_ch343(uint32_t, uint8_t *, uint8_t *);
static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t);
static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t);
+static void uchcom_set_baudrate_ch343(struct uchcom_softc *, uint32_t,
+ uint16_t);
static void uchcom_poll(struct ucom_softc *ucom);
static device_probe_t uchcom_probe;
@@ -257,8 +282,10 @@
.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,
@@ -312,8 +339,9 @@
{
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");
@@ -331,20 +359,51 @@
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_data_iface_no = id->bInterfaceNumber;
+ 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_data_iface_no = sc->sc_ctrl_iface_no;
+ 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) {
- DPRINTF("one or more missing USB endpoints, "
- "error=%s\n", usbd_errstr(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) {
+ device_printf(dev, "allocating USB transfers failed for "
+ "interrupt\n");
goto detach;
}
@@ -450,7 +509,9 @@
(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));
}
@@ -556,17 +617,50 @@
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 void
+uchcom_calc_baudrate_ch343(uint32_t rate, uint8_t *divisor, uint8_t *factor)
+{
+ uint32_t clk = 12000000;
+
+ if (rate >= 256000)
+ *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;
+ }
+
+ *factor = 256 - clk / rate;
}
static int
@@ -630,6 +724,18 @@
UCHCOM_REG_BPS_PAD, 0);
}
+static void
+uchcom_set_baudrate_ch343(struct uchcom_softc *sc, uint32_t rate, uint16_t lcr)
+{
+ uint16_t idx;
+ uint8_t factor, div;
+
+ uchcom_calc_baudrate_ch343(rate, &div, &factor);
+ idx = (factor << 8) | div;
+
+ uchcom_ctrl_write(sc, UCHCOM_REQ_SET_BAUDRATE, lcr, idx);
+}
+
/* ----------------------------------------------------------------------
* methods for ucom
*/
@@ -704,6 +810,45 @@
uchcom_cfg_param(struct ucom_softc *ucom, struct termios *t)
{
struct uchcom_softc *sc = ucom->sc_parent;
+ uint8_t lcr = 0;
+
+ if (sc->sc_chiptype == TYPE_CH343) {
+ 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;
+ }
+
+ 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;
+ }
+
+ uchcom_set_baudrate_ch343(sc, t->c_ospeed,
+ UCHCOM_T | UCHCOM_CL | UCHCOM_CT | lcr << 8);
+
+ uchcom_set_dtr_rts(sc);
+ uchcom_update_status(sc);
+ return;
+ }
uchcom_get_version(sc, NULL);
uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);
@@ -738,7 +883,7 @@
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]);
@@ -750,7 +895,7 @@
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]);
@@ -780,6 +925,7 @@
{
struct uchcom_softc *sc = usbd_xfer_softc(xfer);
struct usb_page_cache *pc;
+ uint32_t intrstat;
uint8_t buf[UCHCOM_INTR_LEAST];
int actlen;
@@ -798,7 +944,10 @@
(unsigned)buf[0], (unsigned)buf[1],
(unsigned)buf[2], (unsigned)buf[3]);
- uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]);
+ intrstat = (sc->sc_chiptype != TYPE_CH343) ?
+ actlen - 1 : 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
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -4903,9 +4903,11 @@
/* 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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 9, 2:08 AM (15 h, 24 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25057301
Default Alt Text
D46290.id142069.diff (11 KB)
Attached To
Mode
D46290: uchcom(4): add support for CH9102 and CH343 uarts
Attached
Detach File
Event Timeline
Log In to Comment