summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsasano <sasano@cvs.openbsd.org>2014-05-16 14:05:40 +0000
committersasano <sasano@cvs.openbsd.org>2014-05-16 14:05:40 +0000
commit28b155d8eb0ab2ad321858434438a3d3d9a2bf6c (patch)
tree4e6e5323e5ce04d66e1ef6ab4b7f1e1295ff7180
parent1266f11a4fbb0f3bc17e3c639e1f80ad16fddf35 (diff)
It seems that there is new and old revision of CH340.
Previous uchcom(4) driver targeted old one, and new one could not work because of uchcom_set_line_control() broke the value of UCHCOM_REG_LCR1(0x18). To support new CH340, uchcom_set_line_control() and uchcom_reset_chip() have been overhauled. Current uchcom(4) does not change the value of UCHCOM_REG_LCR1 register, it means even/odd parity mode is no longer supported with old CH340. ok by mpi@
-rw-r--r--sys/dev/usb/uchcom.c89
1 files changed, 16 insertions, 73 deletions
diff --git a/sys/dev/usb/uchcom.c b/sys/dev/usb/uchcom.c
index 8f92ebe0b5b..502b920b3c5 100644
--- a/sys/dev/usb/uchcom.c
+++ b/sys/dev/usb/uchcom.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uchcom.c,v 1.19 2013/11/15 10:17:39 pirofti Exp $ */
+/* $OpenBSD: uchcom.c,v 1.20 2014/05/16 14:05:39 sasano Exp $ */
/* $NetBSD: uchcom.c,v 1.1 2007/09/03 17:57:37 tshiozak Exp $ */
/*
@@ -91,18 +91,17 @@ int uchcomdebug = 0;
#define UCHCOM_BRK1_MASK 0x01
#define UCHCOM_BRK2_MASK 0x40
-#define UCHCOM_LCR1_MASK 0xAF
-#define UCHCOM_LCR2_MASK 0x07
-#define UCHCOM_LCR1_PARENB 0x80
-#define UCHCOM_LCR2_PAREVEN 0x07
-#define UCHCOM_LCR2_PARODD 0x06
-#define UCHCOM_LCR2_PARMARK 0x05
-#define UCHCOM_LCR2_PARSPACE 0x04
-
#define UCHCOM_INTR_STAT1 0x02
#define UCHCOM_INTR_STAT2 0x03
#define UCHCOM_INTR_LEAST 4
+/*
+ * XXX - these magic numbers come from Linux (drivers/usb/serial/ch341.c).
+ * The manufacturer was unresponsive when asked for documentation.
+ */
+#define UCHCOM_RESET_VALUE 0x501F /* line mode? */
+#define UCHCOM_RESET_INDEX 0xD90A /* baud rate? */
+
#define UCHCOMIBUFSIZE 256
#define UCHCOMOBUFSIZE 256
@@ -707,27 +706,10 @@ uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate)
int
uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
{
- usbd_status err;
- uint8_t lcr1 = 0, lcr2 = 0;
-
- err = uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2,
- &lcr2);
- if (err) {
- printf("%s: cannot get LCR: %s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err));
- return EIO;
- }
-
- lcr1 &= ~UCHCOM_LCR1_MASK;
- lcr2 &= ~UCHCOM_LCR2_MASK;
-
/*
* XXX: it is difficult to handle the line control appropriately:
- * - CS8, !CSTOPB and any parity mode seems ok, but
- * - the chip doesn't have the function to calculate parity
- * in !CS8 mode.
- * - it is unclear that the chip supports CS5,6 mode.
- * - it is unclear how to handle stop bits.
+ * work as chip default - CS8, no parity, !CSTOPB
+ * other modes are not supported.
*/
switch (ISSET(cflag, CSIZE)) {
@@ -739,21 +721,8 @@ uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
break;
}
- if (ISSET(cflag, PARENB)) {
- lcr1 |= UCHCOM_LCR1_PARENB;
- if (ISSET(cflag, PARODD))
- lcr2 |= UCHCOM_LCR2_PARODD;
- else
- lcr2 |= UCHCOM_LCR2_PAREVEN;
- }
-
- err = uchcom_write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2,
- lcr2);
- if (err) {
- printf("%s: cannot set LCR: %s\n",
- sc->sc_dev.dv_xname, usbd_errstr(err));
- return EIO;
- }
+ if (ISSET(cflag, PARENB) || ISSET(cflag, CSTOPB))
+ return EINVAL;
return 0;
}
@@ -778,38 +747,12 @@ int
uchcom_reset_chip(struct uchcom_softc *sc)
{
usbd_status err;
- uint8_t lcr1, lcr2, pre, div, mod;
- uint16_t val=0, idx=0;
-
- err = uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2);
- if (err)
- goto failed;
-
- err = uchcom_read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV,
- &div);
- if (err)
- goto failed;
- err = uchcom_read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD,
- NULL);
- if (err)
- goto failed;
+ DPRINTF(("%s: reset\n", sc->sc_dev.dv_xname));
- val |= (uint16_t)(lcr1&0xF0) << 8;
- val |= 0x01;
- val |= (uint16_t)(lcr2&0x0F) << 8;
- val |= 0x02;
- idx |= pre & 0x07;
- val |= 0x04;
- idx |= (uint16_t)div << 8;
- val |= 0x08;
- idx |= mod & 0xF8;
- val |= 0x10;
-
- DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
- sc->sc_dev.dv_xname, val, idx));
-
- err = uchcom_generic_control_out(sc, UCHCOM_REQ_RESET, val, idx);
+ err = uchcom_generic_control_out(sc, UCHCOM_REQ_RESET,
+ UCHCOM_RESET_VALUE,
+ UCHCOM_RESET_INDEX);
if (err)
goto failed;