From: sasano Date: Fri, 16 May 2014 14:05:39 +0000 (+0000) Subject: It seems that there is new and old revision of CH340. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=5165e579a145cd62a9fbbbd8c33e30b50d88b5d1;p=openbsd 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@ --- 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;