Am Wed, Oct 27, 2021 at 06:46:38AM +1000 schrieb David Gwynne:
> i bought some random usb to rs485 serial adapters so i can talk
> modbus to a thing, but then discovered i can't talk to the modbus
> thing because uchcom doesn't support configuring parity.
> 
> this ports the functionality to support configuring parity and char size
> masks from netbsd src/sys/dev/usb/uchcom.c r1.26. part of that change
> including tweaks to uchcom_reset_chip, which was then changed in r1.28
> back to what we already have, so i left that chunk out.
> 
> ive tested this talking to a device at 19200 with cs8 and even
> parity. more tests would be appreciated to make sure i haven't
> broken existing use functionality.

ok patrick@

> Index: uchcom.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/uchcom.c,v
> retrieving revision 1.28
> diff -u -p -r1.28 uchcom.c
> --- uchcom.c  31 Jul 2020 10:49:33 -0000      1.28
> +++ uchcom.c  26 Oct 2021 20:33:36 -0000
> @@ -72,9 +72,8 @@ int uchcomdebug = 0;
>  #define UCHCOM_REG_BPS_DIV   0x13
>  #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_BREAK     0x05
> +#define UCHCOM_REG_LCR               0x18
>  #define UCHCOM_REG_LCR2              0x25
>  
>  #define UCHCOM_VER_20                0x20
> @@ -83,11 +82,25 @@ int       uchcomdebug = 0;
>  #define UCHCOM_BPS_MOD_BASE  20000000
>  #define UCHCOM_BPS_MOD_BASE_OFS      1100
>  
> +#define UCHCOM_BPS_PRE_IMM   0x80    /* CH341: immediate RX forwarding */
> +
>  #define UCHCOM_DTR_MASK              0x20
>  #define UCHCOM_RTS_MASK              0x40
>  
> -#define UCHCOM_BRK1_MASK     0x01
> -#define UCHCOM_BRK2_MASK     0x40
> +#define UCHCOM_BREAK_MASK    0x01
> +
> +#define UCHCOM_LCR_CS5               0x00
> +#define UCHCOM_LCR_CS6               0x01
> +#define UCHCOM_LCR_CS7               0x02
> +#define UCHCOM_LCR_CS8               0x03
> +#define UCHCOM_LCR_STOPB     0x04
> +#define UCHCOM_LCR_PARENB    0x08
> +#define UCHCOM_LCR_PARODD    0x00
> +#define UCHCOM_LCR_PAREVEN   0x10
> +#define UCHCOM_LCR_PARMARK   0x20
> +#define UCHCOM_LCR_PARSPACE  0x30
> +#define UCHCOM_LCR_TXE               0x40
> +#define UCHCOM_LCR_RXE               0x80
>  
>  #define UCHCOM_INTR_STAT1    0x02
>  #define UCHCOM_INTR_STAT2    0x03
> @@ -577,23 +590,21 @@ int
>  uchcom_set_break(struct uchcom_softc *sc, int onoff)
>  {
>       usbd_status err;
> -     uint8_t brk1, brk2;
> +     uint8_t brk, lcr;
>  
> -     err = uchcom_read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2,
> -         &brk2);
> +     err = uchcom_read_reg(sc, UCHCOM_REG_BREAK, &brk, UCHCOM_REG_LCR, &lcr);
>       if (err)
>               return EIO;
>       if (onoff) {
>               /* on - clear bits */
> -             brk1 &= ~UCHCOM_BRK1_MASK;
> -             brk2 &= ~UCHCOM_BRK2_MASK;
> +             brk &= ~UCHCOM_BREAK_MASK;
> +             lcr &= ~UCHCOM_LCR_TXE;
>       } else {
>               /* off - set bits */
> -             brk1 |= UCHCOM_BRK1_MASK;
> -             brk2 |= UCHCOM_BRK2_MASK;
> +             brk |= UCHCOM_BREAK_MASK;
> +             lcr |= UCHCOM_LCR_TXE;
>       }
> -     err = uchcom_write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2,
> -         brk2);
> +     err = uchcom_write_reg(sc, UCHCOM_REG_BREAK, brk, UCHCOM_REG_LCR, lcr);
>       if (err)
>               return EIO;
>  
> @@ -665,23 +676,50 @@ uchcom_set_dte_rate(struct uchcom_softc 
>  int
>  uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
>  {
> -     /*
> -      * XXX: it is difficult to handle the line control appropriately:
> -      *   work as chip default - CS8, no parity, !CSTOPB
> -      *   other modes are not supported.
> -      */
> +     usbd_status err;
> +     uint8_t lcr = 0, lcr2 = 0;
> +
> +     err = uchcom_read_reg(sc, UCHCOM_REG_LCR, &lcr,
> +         UCHCOM_REG_LCR2, &lcr2);
> +     if (err) {
> +             printf("%s: cannot get LCR: %s\n",
> +                 sc->sc_dev.dv_xname, usbd_errstr(err));
> +             return EIO;
> +     }
> +
> +     lcr = UCHCOM_LCR_RXE | UCHCOM_LCR_TXE;
>  
>       switch (ISSET(cflag, CSIZE)) {
>       case CS5:
> +             lcr |= UCHCOM_LCR_CS5;
> +             break;
>       case CS6:
> +             lcr |= UCHCOM_LCR_CS6;
> +             break;
>       case CS7:
> -             return EINVAL;
> +             lcr |= UCHCOM_LCR_CS7;
> +             break;
>       case CS8:
> +             lcr |= UCHCOM_LCR_CS8;
>               break;
>       }
>  
> -     if (ISSET(cflag, PARENB) || ISSET(cflag, CSTOPB))
> -             return EINVAL;
> +     if (ISSET(cflag, PARENB)) {
> +             lcr |= UCHCOM_LCR_PARENB;
> +             if (!ISSET(cflag, PARODD))
> +                     lcr |= UCHCOM_LCR_PAREVEN;
> +     }
> +
> +     if (ISSET(cflag, CSTOPB)) {
> +             lcr |= UCHCOM_LCR_STOPB;
> +     }
> +
> +     err = uchcom_write_reg(sc, UCHCOM_REG_LCR, lcr, UCHCOM_REG_LCR2, lcr2);
> +     if (err) {
> +             printf("%s: cannot set LCR: %s\n",
> +                 sc->sc_dev.dv_xname, usbd_errstr(err));
> +             return EIO;
> +     }
>  
>       return 0;
>  }
> 

Reply via email to