Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Fix uchcom(4) line parameter settings.



details:   https://anonhg.NetBSD.org/src/rev/21d98017c618
branches:  trunk
changeset: 446633:21d98017c618
user:      jakllsch <jakllsch%NetBSD.org@localhost>
date:      Thu Dec 13 00:36:30 2018 +0000

description:
Fix uchcom(4) line parameter settings.

Enables support for line modes other than 8-bit/no-parity/1-stop on
modern chips, and should also work on older chips.

diffstat:

 sys/dev/usb/uchcom.c |  137 ++++++++++++++++++++++++--------------------------
 1 files changed, 66 insertions(+), 71 deletions(-)

diffs (211 lines):

diff -r fdaa08012b78 -r 21d98017c618 sys/dev/usb/uchcom.c
--- a/sys/dev/usb/uchcom.c      Wed Dec 12 23:40:02 2018 +0000
+++ b/sys/dev/usb/uchcom.c      Thu Dec 13 00:36:30 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uchcom.c,v 1.25 2018/12/12 23:26:00 jakllsch Exp $     */
+/*     $NetBSD: uchcom.c,v 1.26 2018/12/13 00:36:30 jakllsch Exp $     */
 
 /*
  * Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.25 2018/12/12 23:26:00 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uchcom.c,v 1.26 2018/12/13 00:36:30 jakllsch Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -84,9 +84,8 @@
 #define UCHCOM_REG_STAT2       0x07
 #define UCHCOM_REG_BPS_PRE     0x12
 #define UCHCOM_REG_BPS_DIV     0x13
-#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
@@ -99,16 +98,20 @@
 #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_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_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
@@ -619,21 +622,21 @@
 set_break(struct uchcom_softc *sc, int onoff)
 {
        usbd_status err;
-       uint8_t brk1, brk2;
+       uint8_t brk, lcr;
 
-       err = read_reg(sc, UCHCOM_REG_BREAK1, &brk1, UCHCOM_REG_BREAK2, &brk2);
+       err = 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 = write_reg(sc, UCHCOM_REG_BREAK1, brk1, UCHCOM_REG_BREAK2, brk2);
+       err = write_reg(sc, UCHCOM_REG_BREAK, brk, UCHCOM_REG_LCR, lcr);
        if (err)
                return EIO;
 
@@ -698,52 +701,48 @@
 static int
 set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
 {
-       if (sc->sc_version < UCHCOM_VER_30) {
-               usbd_status err;
-               uint8_t lcr1val = 0, lcr2val = 0;
-
-               err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1val, UCHCOM_REG_LCR2, &lcr2val);
-               if (err) {
-                       device_printf(sc->sc_dev, "cannot get LCR: %s\n",
-                           usbd_errstr(err));
-                       return EIO;
-               }
+       usbd_status err;
+       uint8_t lcr = 0, lcr2 = 0;
 
-               lcr1val &= ~UCHCOM_LCR1_MASK;
-               lcr2val &= ~UCHCOM_LCR2_MASK;
+       err = read_reg(sc, UCHCOM_REG_LCR, &lcr, UCHCOM_REG_LCR2, &lcr2);
+       if (err) {
+               device_printf(sc->sc_dev, "cannot get LCR: %s\n",
+                   usbd_errstr(err));
+               return EIO;
+       }
 
-               /*
-                * 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.
-                */
+       lcr = UCHCOM_LCR_RXE | UCHCOM_LCR_TXE;
 
-               switch (ISSET(cflag, CSIZE)) {
-               case CS5:
-               case CS6:
-               case CS7:
-                       return EINVAL;
-               case CS8:
-                       break;
-               }
+       switch (ISSET(cflag, CSIZE)) {
+       case CS5:
+               lcr |= UCHCOM_LCR_CS5;
+               break;
+       case CS6:
+               lcr |= UCHCOM_LCR_CS6;
+               break;
+       case CS7:
+               lcr |= UCHCOM_LCR_CS7;
+               break;
+       case CS8:
+               lcr |= UCHCOM_LCR_CS8;
+               break;
+       }
 
-               if (ISSET(cflag, PARENB)) {
-                       lcr1val |= UCHCOM_LCR1_PARENB;
-                       if (ISSET(cflag, PARODD))
-                               lcr2val |= UCHCOM_LCR2_PARODD;
-                       else
-                               lcr2val |= UCHCOM_LCR2_PAREVEN;
-               }
+       if (ISSET(cflag, PARENB)) {
+               lcr |= UCHCOM_LCR_PARENB;
+               if (!ISSET(cflag, PARODD))
+                       lcr |= UCHCOM_LCR_PAREVEN;
+       }
 
-               err = write_reg(sc, UCHCOM_REG_LCR1, lcr1val, UCHCOM_REG_LCR2, lcr2val);
-               if (err) {
-                       device_printf(sc->sc_dev, "cannot set LCR: %s\n",
-                           usbd_errstr(err));
-                       return EIO;
-               }
+       if (ISSET(cflag, CSTOPB)) {
+               lcr |= UCHCOM_LCR_STOPB;
+       }
+
+       err = write_reg(sc, UCHCOM_REG_LCR, lcr, UCHCOM_REG_LCR2, lcr2);
+       if (err) {
+               device_printf(sc->sc_dev, "cannot set LCR: %s\n",
+                   usbd_errstr(err));
+               return EIO;
        }
 
        return 0;
@@ -769,10 +768,10 @@
 reset_chip(struct uchcom_softc *sc)
 {
        usbd_status err;
-       uint8_t lcr1val, lcr2val, pre, div;
+       uint8_t lcr, lcr2, pre, div;
        uint16_t val=0, idx=0;
 
-       err = read_reg(sc, UCHCOM_REG_LCR1, &lcr1val, UCHCOM_REG_LCR2, &lcr2val);
+       err = read_reg(sc, UCHCOM_REG_LCR, &lcr, UCHCOM_REG_LCR2, &lcr2);
        if (err)
                goto failed;
 
@@ -780,15 +779,11 @@
        if (err)
                goto failed;
 
-       val |= (uint16_t)(lcr1val&0xF0) << 8;
-       val |= 0x01;
-       val |= (uint16_t)(lcr2val&0x0F) << 8;
-       val |= 0x02;
+       val |= (uint16_t)lcr << 8;
+       val |= 0x9c;    /* magic from vendor Linux and Android drivers */
        idx |= pre & 0x07;
-       val |= 0x04;
        idx |= (uint16_t)div << 8;
-       val |= 0x08;
-       val |= 0x10;
+       idx |= UCHCOM_BPS_PRE_IMM;
 
        DPRINTF(("%s: reset v=0x%04X, i=0x%04X\n",
                 device_xname(sc->sc_dev), val, idx));



Home | Main Index | Thread Index | Old Index