[Midnightbsd-cvs] src [12297] trunk/sys/dev/usb/serial: add additional device.
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sun Feb 2 16:21:14 EST 2020
Revision: 12297
http://svnweb.midnightbsd.org/src/?rev=12297
Author: laffer1
Date: 2020-02-02 16:21:13 -0500 (Sun, 02 Feb 2020)
Log Message:
-----------
add additional device.
Modified Paths:
--------------
trunk/sys/dev/usb/serial/u3g.c
trunk/sys/dev/usb/serial/uchcom.c
trunk/sys/dev/usb/serial/uplcom.c
Modified: trunk/sys/dev/usb/serial/u3g.c
===================================================================
--- trunk/sys/dev/usb/serial/u3g.c 2020-02-02 21:19:40 UTC (rev 12296)
+++ trunk/sys/dev/usb/serial/u3g.c 2020-02-02 21:21:13 UTC (rev 12297)
@@ -17,7 +17,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $FreeBSD: stable/10/sys/dev/usb/serial/u3g.c 329304 2018-02-15 08:57:14Z hselasky $
+ * $FreeBSD: stable/10/sys/dev/usb/serial/u3g.c 342037 2018-12-13 10:34:26Z hselasky $
*/
/*
@@ -214,6 +214,7 @@
U3G_DEV(ALINK, 3G, 0),
U3G_DEV(ALINK, 3GU, 0),
U3G_DEV(ALINK, DWM652U5, 0),
+ U3G_DEV(ALINK, SIM7600E, 0),
U3G_DEV(AMOI, H01, 0),
U3G_DEV(AMOI, H01A, 0),
U3G_DEV(AMOI, H02, 0),
Modified: trunk/sys/dev/usb/serial/uchcom.c
===================================================================
--- trunk/sys/dev/usb/serial/uchcom.c 2020-02-02 21:19:40 UTC (rev 12296)
+++ trunk/sys/dev/usb/serial/uchcom.c 2020-02-02 21:21:13 UTC (rev 12297)
@@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/dev/usb/serial/uchcom.c 263687 2014-03-24 13:48:04Z emaste $");
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/serial/uchcom.c 335627 2018-06-25 08:57:03Z avg $");
/*
* Driver for WinChipHead CH341/340, the worst USB-serial chip in the
@@ -121,11 +121,11 @@
#define UCHCOM_REG_BPS_MOD 0x14
#define UCHCOM_REG_BPS_PAD 0x0F
#define UCHCOM_REG_BREAK1 0x05
-#define UCHCOM_REG_BREAK2 0x18
#define UCHCOM_REG_LCR1 0x18
#define UCHCOM_REG_LCR2 0x25
#define UCHCOM_VER_20 0x20
+#define UCHCOM_VER_30 0x30
#define UCHCOM_BASE_UNKNOWN 0
#define UCHCOM_BPS_MOD_BASE 20000000
@@ -134,12 +134,14 @@
#define UCHCOM_DTR_MASK 0x20
#define UCHCOM_RTS_MASK 0x40
-#define UCHCOM_BRK1_MASK 0x01
-#define UCHCOM_BRK2_MASK 0x40
+#define UCHCOM_BRK_MASK 0x01
#define UCHCOM_LCR1_MASK 0xAF
#define UCHCOM_LCR2_MASK 0x07
-#define UCHCOM_LCR1_PARENB 0x80
+#define UCHCOM_LCR1_RX 0x80
+#define UCHCOM_LCR1_TX 0x40
+#define UCHCOM_LCR1_PARENB 0x08
+#define UCHCOM_LCR1_CS8 0x03
#define UCHCOM_LCR2_PAREVEN 0x07
#define UCHCOM_LCR2_PARODD 0x06
#define UCHCOM_LCR2_PARMARK 0x05
@@ -321,13 +323,17 @@
sc->sc_udev = uaa->device;
- switch (uaa->info.bcdDevice) {
- case UCHCOM_REV_CH340:
+ switch (uaa->info.idProduct) {
+ case USB_PRODUCT_WCH2_CH341SER:
device_printf(dev, "CH340 detected\n");
break;
- default:
+ case USB_PRODUCT_WCH2_CH341SER_2:
device_printf(dev, "CH341 detected\n");
break;
+ default:
+ device_printf(dev, "New CH340/CH341 product 0x%04x detected\n",
+ uaa->info.idProduct);
+ break;
}
iface_index = UCHCOM_IFACE_INDEX;
@@ -411,6 +417,8 @@
USETW(req.wIndex, index);
USETW(req.wLength, 0);
+ DPRINTF("WR REQ 0x%02X VAL 0x%04X IDX 0x%04X\n",
+ reqno, value, index);
ucom_cfg_do_request(sc->sc_udev,
&sc->sc_ucom, &req, NULL, 0, 1000);
}
@@ -427,6 +435,8 @@
USETW(req.wIndex, index);
USETW(req.wLength, buflen);
+ DPRINTF("RD REQ 0x%02X VAL 0x%04X IDX 0x%04X LEN %d\n",
+ reqno, value, index, buflen);
ucom_cfg_do_request(sc->sc_udev,
&sc->sc_ucom, &req, buf, USB_SHORT_XFER_OK, 1000);
}
@@ -501,6 +511,7 @@
uchcom_update_version(struct uchcom_softc *sc)
{
uchcom_get_version(sc, &sc->sc_version);
+ DPRINTF("Chip version: 0x%02x\n", sc->sc_version);
}
static void
@@ -546,17 +557,17 @@
uint8_t brk1;
uint8_t brk2;
- uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2);
+ uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_LCR1, &brk2);
if (onoff) {
/* on - clear bits */
- brk1 &= ~UCHCOM_BRK1_MASK;
- brk2 &= ~UCHCOM_BRK2_MASK;
+ brk1 &= ~UCHCOM_BRK_MASK;
+ brk2 &= ~UCHCOM_LCR1_TX;
} else {
/* off - set bits */
- brk1 |= UCHCOM_BRK1_MASK;
- brk2 |= UCHCOM_BRK2_MASK;
+ brk1 |= UCHCOM_BRK_MASK;
+ brk2 |= UCHCOM_LCR1_TX;
}
- uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2);
+ uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_LCR1, brk2);
}
static int
@@ -608,8 +619,12 @@
if (uchcom_calc_divider_settings(&dv, rate))
return;
+ /*
+ * 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,
+ 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,
@@ -674,6 +689,10 @@
default:
return (EIO);
}
+ 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);
@@ -686,11 +705,26 @@
{
struct uchcom_softc *sc = ucom->sc_parent;
- uchcom_get_version(sc, 0);
+ uchcom_get_version(sc, NULL);
uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);
uchcom_set_baudrate(sc, t->c_ospeed);
- uchcom_read_reg(sc, 0x18, 0, 0x25, 0);
- uchcom_write_reg(sc, 0x18, 0x50, 0x25, 0x00);
+ 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);
+ }
uchcom_update_status(sc);
uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0x501f, 0xd90a);
uchcom_set_baudrate(sc, t->c_ospeed);
Modified: trunk/sys/dev/usb/serial/uplcom.c
===================================================================
--- trunk/sys/dev/usb/serial/uplcom.c 2020-02-02 21:19:40 UTC (rev 12296)
+++ trunk/sys/dev/usb/serial/uplcom.c 2020-02-02 21:21:13 UTC (rev 12297)
@@ -2,7 +2,7 @@
/* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: stable/10/sys/dev/usb/serial/uplcom.c 305557 2016-09-07 19:21:52Z dim $");
+__FBSDID("$FreeBSD: stable/10/sys/dev/usb/serial/uplcom.c 339853 2018-10-29 12:11:27Z hselasky $");
/*-
* Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama at jp.FreeBSD.org>.
@@ -133,12 +133,20 @@
#define UPLCOM_SET_CRTSCTS 0x41
#define UPLCOM_SET_CRTSCTS_PL2303X 0x61
#define RSAQ_STATUS_CTS 0x80
+#define RSAQ_STATUS_OVERRUN_ERROR 0x40
+#define RSAQ_STATUS_PARITY_ERROR 0x20
+#define RSAQ_STATUS_FRAME_ERROR 0x10
+#define RSAQ_STATUS_RING 0x08
+#define RSAQ_STATUS_BREAK_ERROR 0x04
#define RSAQ_STATUS_DSR 0x02
#define RSAQ_STATUS_DCD 0x01
#define TYPE_PL2303 0
#define TYPE_PL2303HX 1
+#define TYPE_PL2303HXD 2
+#define UPLCOM_STATE_INDEX 8
+
enum {
UPLCOM_BULK_DT_WR,
UPLCOM_BULK_DT_RD,
@@ -367,18 +375,49 @@
sc->sc_udev = uaa->device;
- /* Determine the chip type. This algorithm is taken from Linux. */
dd = usbd_get_device_descriptor(sc->sc_udev);
- if (dd->bDeviceClass == 0x02)
- sc->sc_chiptype = TYPE_PL2303;
- else if (dd->bMaxPacketSize == 0x40)
+
+ switch (UGETW(dd->bcdDevice)) {
+ case 0x0300:
sc->sc_chiptype = TYPE_PL2303HX;
- else
- sc->sc_chiptype = TYPE_PL2303;
+ /* or TA, that is HX with external crystal */
+ break;
+ case 0x0400:
+ sc->sc_chiptype = TYPE_PL2303HXD;
+ /* or EA, that is HXD with ESD protection */
+ /* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
+ break;
+ case 0x0500:
+ sc->sc_chiptype = TYPE_PL2303HXD;
+ /* in fact it's TB, that is HXD with external crystal */
+ break;
+ default:
+ /* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
+ only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
+ /* Determine the chip type. This algorithm is taken from Linux. */
+ if (dd->bDeviceClass == 0x02)
+ sc->sc_chiptype = TYPE_PL2303;
+ else if (dd->bMaxPacketSize == 0x40)
+ sc->sc_chiptype = TYPE_PL2303HX;
+ else
+ sc->sc_chiptype = TYPE_PL2303;
+ break;
+ }
- DPRINTF("chiptype: %s\n",
- (sc->sc_chiptype == TYPE_PL2303HX) ?
- "2303X" : "2303");
+ switch (sc->sc_chiptype) {
+ case TYPE_PL2303:
+ DPRINTF("chiptype: 2303\n");
+ break;
+ case TYPE_PL2303HX:
+ DPRINTF("chiptype: 2303HX/TA\n");
+ break;
+ case TYPE_PL2303HXD:
+ DPRINTF("chiptype: 2303HXD/TB/RA/EA\n");
+ break;
+ default:
+ DPRINTF("chiptype: unknown %d\n", sc->sc_chiptype);
+ break;
+ }
/*
* USB-RSAQ1 has two interface
@@ -427,7 +466,7 @@
goto detach;
}
- if (sc->sc_chiptype != TYPE_PL2303HX) {
+ if (sc->sc_chiptype == TYPE_PL2303) {
/* HX variants seem to lock up after a clear stall request. */
mtx_lock(&sc->sc_mtx);
usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
@@ -434,6 +473,7 @@
usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
mtx_unlock(&sc->sc_mtx);
} else {
+ /* reset upstream data pipes */
if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
UPLCOM_SET_REQUEST, 8, 0, 0) ||
uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
@@ -552,7 +592,7 @@
|| uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0))
return (EIO);
- if (chiptype == TYPE_PL2303HX)
+ if (chiptype != TYPE_PL2303)
err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0);
else
err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0);
@@ -632,23 +672,52 @@
&req, NULL, 0, 1000);
}
+/*
+ * NOTE: These baud rates are officially supported, they can be written
+ * directly into dwDTERate register.
+ *
+ * Free baudrate setting is not supported by the base PL2303, and on
+ * other models it requires writing a divisor value to dwDTERate instead
+ * of the raw baudrate. The formula for divisor calculation is not published
+ * by the vendor, so it is speculative, though the official product homepage
+ * refers to the Linux module source as a reference implementation.
+ */
static const uint32_t uplcom_rates[] = {
- 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
- 19200, 28800, 38400, 57600, 115200,
/*
- * Higher speeds are probably possible. PL2303X supports up to
- * 6Mb and can set any rate
+ * Basic 'standard' speed rates, supported by all models
+ * NOTE: 900 and 56000 actually works as well
*/
- 230400, 460800, 614400, 921600, 1228800
+ 75, 150, 300, 600, 900, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
+ 19200, 28800, 38400, 56000, 57600, 115200,
+ /*
+ * Advanced speed rates up to 6Mbs, supported by HX/TA and HXD/TB/EA/RA
+ * NOTE: regardless of the spec, 256000 does not work
+ */
+ 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400,
+ 806400, 921600, 1228800, 2457600, 3000000, 6000000,
+ /*
+ * Advanced speed rates up to 12, supported by HXD/TB/EA/RA
+ */
+ 12000000
};
#define N_UPLCOM_RATES (sizeof(uplcom_rates)/sizeof(uplcom_rates[0]))
static int
+uplcom_baud_supported(unsigned int speed)
+{
+ int i;
+ for (i = 0; i < N_UPLCOM_RATES; i++) {
+ if (uplcom_rates[i] == speed)
+ return 1;
+ }
+ return 0;
+}
+
+static int
uplcom_pre_param(struct ucom_softc *ucom, struct termios *t)
{
struct uplcom_softc *sc = ucom->sc_parent;
- uint8_t i;
DPRINTF("\n");
@@ -656,20 +725,27 @@
* Check requested baud rate.
*
* The PL2303 can only set specific baud rates, up to 1228800 baud.
- * The PL2303X can set any baud rate up to 6Mb.
+ * The PL2303HX can set any baud rate up to 6Mb.
* The PL2303HX rev. D can set any baud rate up to 12Mb.
*
- * XXX: We currently cannot identify the PL2303HX rev. D, so treat
- * it the same as the PL2303X.
*/
- if (sc->sc_chiptype != TYPE_PL2303HX) {
- for (i = 0; i < N_UPLCOM_RATES; i++) {
- if (uplcom_rates[i] == t->c_ospeed)
+
+ /* accept raw divisor data, if someone wants to do the math in user domain */
+ if (t->c_ospeed & 0x80000000)
+ return 0;
+ switch (sc->sc_chiptype) {
+ case TYPE_PL2303HXD:
+ if (t->c_ospeed <= 12000000)
return (0);
- }
- } else {
- if (t->c_ospeed <= 6000000)
- return (0);
+ break;
+ case TYPE_PL2303HX:
+ if (t->c_ospeed <= 6000000)
+ return (0);
+ break;
+ default:
+ if (uplcom_baud_supported(t->c_ospeed))
+ return (0);
+ break;
}
DPRINTF("uplcom_param: bad baud rate (%d)\n", t->c_ospeed);
@@ -676,6 +752,48 @@
return (EIO);
}
+static unsigned int
+uplcom_encode_baud_rate_divisor(uint8_t *buf, unsigned int baud)
+{
+ unsigned int baseline, mantissa, exponent;
+
+ /* Determine the baud rate divisor. This algorithm is taken from Linux. */
+ /*
+ * Apparently the formula is:
+ * baudrate = baseline / (mantissa * 4^exponent)
+ * where
+ * mantissa = buf[8:0]
+ * exponent = buf[11:9]
+ */
+ if (baud == 0)
+ baud = 1;
+ baseline = 383385600;
+ mantissa = baseline / baud;
+ if (mantissa == 0)
+ mantissa = 1;
+ exponent = 0;
+ while (mantissa >= 512) {
+ if (exponent < 7) {
+ mantissa >>= 2; /* divide by 4 */
+ exponent++;
+ } else {
+ /* Exponent is maxed. Trim mantissa and leave. This gives approx. 45.8 baud */
+ mantissa = 511;
+ break;
+ }
+ }
+
+ buf[3] = 0x80;
+ buf[2] = 0;
+ buf[1] = exponent << 1 | mantissa >> 8;
+ buf[0] = mantissa & 0xff;
+
+ /* Calculate and return the exact baud rate. */
+ baud = (baseline / mantissa) >> (exponent << 1);
+ DPRINTF("real baud rate will be %u\n", baud);
+
+ return baud;
+}
static void
uplcom_cfg_param(struct ucom_softc *ucom, struct termios *t)
{
@@ -687,10 +805,24 @@
memset(&ls, 0, sizeof(ls));
- USETDW(ls.dwDTERate, t->c_ospeed);
+ /*
+ * NOTE: If unsupported baud rates are set directly, the PL2303* uses 9600 baud.
+ */
+ if ((t->c_ospeed & 0x80000000) || uplcom_baud_supported(t->c_ospeed))
+ USETDW(ls.dwDTERate, t->c_ospeed);
+ else
+ t->c_ospeed = uplcom_encode_baud_rate_divisor((uint8_t*)&ls.dwDTERate, t->c_ospeed);
if (t->c_cflag & CSTOPB) {
- ls.bCharFormat = UCDC_STOP_BIT_2;
+ if ((t->c_cflag & CSIZE) == CS5) {
+ /*
+ * NOTE: Comply with "real" UARTs / RS232:
+ * use 1.5 instead of 2 stop bits with 5 data bits
+ */
+ ls.bCharFormat = UCDC_STOP_BIT_1_5;
+ } else {
+ ls.bCharFormat = UCDC_STOP_BIT_2;
+ }
} else {
ls.bCharFormat = UCDC_STOP_BIT_1;
}
@@ -720,7 +852,7 @@
break;
}
- DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n",
+ DPRINTF("rate=0x%08x fmt=%d parity=%d bits=%d\n",
UGETDW(ls.dwDTERate), ls.bCharFormat,
ls.bParityType, ls.bDataBits);
@@ -741,7 +873,7 @@
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = UPLCOM_SET_REQUEST;
USETW(req.wValue, 0);
- if (sc->sc_chiptype == TYPE_PL2303HX)
+ if (sc->sc_chiptype != TYPE_PL2303)
USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X);
else
USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
@@ -831,18 +963,33 @@
pc = usbd_xfer_get_frame(xfer, 0);
usbd_copy_out(pc, 0, buf, sizeof(buf));
- DPRINTF("status = 0x%02x\n", buf[8]);
+ DPRINTF("status = 0x%02x\n", buf[UPLCOM_STATE_INDEX]);
sc->sc_lsr = 0;
sc->sc_msr = 0;
- if (buf[8] & RSAQ_STATUS_CTS) {
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_CTS) {
sc->sc_msr |= SER_CTS;
}
- if (buf[8] & RSAQ_STATUS_DSR) {
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_OVERRUN_ERROR) {
+ sc->sc_lsr |= ULSR_OE;
+ }
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_PARITY_ERROR) {
+ sc->sc_lsr |= ULSR_PE;
+ }
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_FRAME_ERROR) {
+ sc->sc_lsr |= ULSR_FE;
+ }
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_RING) {
+ sc->sc_msr |= SER_RI;
+ }
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_BREAK_ERROR) {
+ sc->sc_lsr |= ULSR_BI;
+ }
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DSR) {
sc->sc_msr |= SER_DSR;
}
- if (buf[8] & RSAQ_STATUS_DCD) {
+ if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DCD) {
sc->sc_msr |= SER_DCD;
}
ucom_status_change(&sc->sc_ucom);
More information about the Midnightbsd-cvs
mailing list