Hello, Recently I bought Arduino board which uses Nanjing QinHeng (WinChipHead) CH340T USB-UART bridge via eBay, and I found uchcom(4) did not work. At misc@, other user reported similar problem. [1]
The uchcom(4) comes from NetBSD and it seems to be worked at that time. I found that uchcom_set_line_control() breaks the value of UCHCOM_REG_LCR1(0x18) makes the problem. The UCHCOM_REG_LCR1 register seems to control parity bit (none/odd/even) but I doubt the role of that register has changed between old/new CH340T chip. At least following changes are required to work my CH340T but parity bit control is no longer supported. If there is no problem, I want to commit. [1] http://openbsd.7691.n7.nabble.com/issue-with-WinChipHead-CH340-usb-serial-td99678.html Index: uchcom.c =================================================================== RCS file: /cvs/src/sys/dev/usb/uchcom.c,v retrieving revision 1.19 diff -u -p -r1.19 uchcom.c --- uchcom.c 15 Nov 2013 10:17:39 -0000 1.19 +++ uchcom.c 13 May 2014 19:43:37 -0000 @@ -91,14 +91,6 @@ 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 @@ -707,27 +699,10 @@ uchcom_set_dte_rate(struct uchcom_softc 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 +714,8 @@ uchcom_set_line_control(struct uchcom_so 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,33 +740,10 @@ 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; + uint16_t val, idx; - 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; + val = 0x501f; + idx = 0xd90a; DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n", sc->sc_dev.dv_xname, val, idx));