Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107060122
D46290.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D46290.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
@@ -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 @@
.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 @@
.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
--- 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,19 @@
&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
@@ -135,13 +136,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 +160,18 @@
#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,
};
@@ -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,39 +188,19 @@
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 */
@@ -226,8 +222,9 @@
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;
@@ -257,8 +254,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 +311,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 +331,49 @@
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;
}
@@ -450,7 +479,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,78 +587,69 @@
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);
-
- dp->dv_mod = (mod + 0xFF) / 0x100;
+ *factor = 256 - clk / rate;
- 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);
}
/* ----------------------------------------------------------------------
@@ -674,6 +696,14 @@
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);
}
@@ -681,53 +711,69 @@
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);
}
@@ -738,7 +784,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 +796,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 +826,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 +845,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
Fri, Jan 10, 11:47 AM (14 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15742301
Default Alt Text
D46290.diff (15 KB)
Attached To
Mode
D46290: uchcom(4): add support for CH9102 and CH343 uarts
Attached
Detach File
Event Timeline
Log In to Comment