On Wed, May 14, 2014 at 05:39:38AM +0900, SASANO Takayoshi wrote:
> 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;
>
What are these magic numbers?
> DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
> sc->sc_dev.dv_xname, val, idx));
>