diff options
Diffstat (limited to 'sys/arch/vax/qbus/dhu.c')
-rw-r--r-- | sys/arch/vax/qbus/dhu.c | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/sys/arch/vax/qbus/dhu.c b/sys/arch/vax/qbus/dhu.c new file mode 100644 index 00000000000..a28a8b77fc3 --- /dev/null +++ b/sys/arch/vax/qbus/dhu.c @@ -0,0 +1,843 @@ +/* $OpenBSD: dhu.c,v 1.1 2000/04/27 03:14:47 bjc Exp $ */ +/* $NetBSD: dhu.c,v 1.17 2000/01/24 02:40:28 matt Exp $ */ +/* + * Copyright (c) 1996 Ken C. Wellsch. All rights reserved. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ralph Campbell and Rick Macklem. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/map.h> +#include <sys/buf.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/scb.h> + +#include <arch/vax/qbus/ubavar.h> +#include <arch/vax/qbus/dhureg.h> + +/* A DHU-11 has 16 ports while a DHV-11 has only 8. We use 16 by default */ + +#define NDHULINE 16 + +#define DHU_M2U(c) ((c)>>4) /* convert minor(dev) to unit # */ +#define DHU_LINE(u) ((u)&0xF) /* extract line # from minor(dev) */ + +struct dhu_softc { + struct device sc_dev; /* Device struct used by config */ + int sc_type; /* controller type, DHU or DHV */ + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + struct { + struct tty *dhu_tty; /* what we work on */ + bus_dmamap_t dhu_dmah; + int dhu_state; /* to manage TX output status */ + short dhu_cc; /* character count on TX */ + short dhu_modem; /* modem bits state */ + } sc_dhu[NDHULINE]; +}; + +#define IS_DHU 16 /* Unibus DHU-11 board linecount */ +#define IS_DHV 8 /* Q-bus DHV-11 or DHQ-11 */ + +#define STATE_IDLE 000 /* no current output in progress */ +#define STATE_DMA_RUNNING 001 /* DMA TX in progress */ +#define STATE_DMA_STOPPED 002 /* DMA TX was aborted */ +#define STATE_TX_ONE_CHAR 004 /* did a single char directly */ + +/* Flags used to monitor modem bits, make them understood outside driver */ + +#define DML_DTR TIOCM_DTR +#define DML_RTS TIOCM_RTS +#define DML_CTS TIOCM_CTS +#define DML_DCD TIOCM_CD +#define DML_RI TIOCM_RI +#define DML_DSR TIOCM_DSR +#define DML_BRK 0100000 /* no equivalent, we will mask */ + +#define DHU_READ_WORD(reg) \ + bus_space_read_2(sc->sc_iot, sc->sc_ioh, reg) +#define DHU_WRITE_WORD(reg, val) \ + bus_space_write_2(sc->sc_iot, sc->sc_ioh, reg, val) +#define DHU_READ_BYTE(reg) \ + bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg) +#define DHU_WRITE_BYTE(reg, val) \ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val) + + +/* On a stock DHV, channel pairs (0/1, 2/3, etc.) must use */ +/* a baud rate from the same group. So limiting to B is likely */ +/* best, although clone boards like the ABLE QHV allow all settings. */ + +static struct speedtab dhuspeedtab[] = { + { 0, 0 }, /* Groups */ + { 50, DHU_LPR_B50 }, /* A */ + { 75, DHU_LPR_B75 }, /* B */ + { 110, DHU_LPR_B110 }, /* A and B */ + { 134, DHU_LPR_B134 }, /* A and B */ + { 150, DHU_LPR_B150 }, /* B */ + { 300, DHU_LPR_B300 }, /* A and B */ + { 600, DHU_LPR_B600 }, /* A and B */ + { 1200, DHU_LPR_B1200 }, /* A and B */ + { 1800, DHU_LPR_B1800 }, /* B */ + { 2000, DHU_LPR_B2000 }, /* B */ + { 2400, DHU_LPR_B2400 }, /* A and B */ + { 4800, DHU_LPR_B4800 }, /* A and B */ + { 7200, DHU_LPR_B7200 }, /* A */ + { 9600, DHU_LPR_B9600 }, /* A and B */ + { 19200, DHU_LPR_B19200 }, /* B */ + { 38400, DHU_LPR_B38400 }, /* A */ + { -1, -1 } +}; + +static int dhu_match __P((struct device *, struct cfdata *, void *)); +static void dhu_attach __P((struct device *, struct device *, void *)); +static void dhurint __P((void *)); +static void dhuxint __P((void *)); +static void dhustart __P((struct tty *)); +static int dhuparam __P((struct tty *, struct termios *)); +static int dhuiflow __P((struct tty *, int)); +static unsigned dhumctl __P((struct dhu_softc *,int, int, int)); + int dhuopen __P((dev_t, int, int, struct proc *)); + int dhuclose __P((dev_t, int, int, struct proc *)); + int dhuread __P((dev_t, struct uio *, int)); + int dhuwrite __P((dev_t, struct uio *, int)); + int dhuioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); + void dhustop __P((struct tty *, int)); +struct tty * dhutty __P((dev_t)); + +struct cfattach dhu_ca = { + sizeof(struct dhu_softc), (cfmatch_t)dhu_match, dhu_attach +}; + +struct cfdriver dhu_cd = { + NULL, "dhu", DV_TTY +}; + +/* Autoconfig handles: setup the controller to interrupt, */ +/* then complete the housecleaning for full operation */ + +static int +dhu_match(parent, cf, aux) + struct device *parent; + struct cfdata *cf; + void *aux; +{ + struct uba_attach_args *ua = aux; + register int n; + + /* Reset controller to initialize, enable TX/RX interrupts */ + /* to catch floating vector info elsewhere when completed */ + + bus_space_write_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR, + DHU_CSR_MASTER_RESET | DHU_CSR_RXIE | DHU_CSR_TXIE); + + /* Now wait up to 3 seconds for self-test to complete. */ + + for (n = 0; n < 300; n++) { + DELAY(10000); + if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) & + DHU_CSR_MASTER_RESET) == 0) + break; + } + + /* If the RESET did not clear after 3 seconds, */ + /* the controller must be broken. */ + + if (n >= 300) + return 0; + + /* Check whether diagnostic run has signalled a failure. */ + + if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) & + DHU_CSR_DIAG_FAIL) != 0) + return 0; + + return 1; +} + +static void +dhu_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + register struct dhu_softc *sc = (void *)self; + register struct uba_attach_args *ua = aux; + register unsigned c; + register int n, i; + + sc->sc_iot = ua->ua_iot; + sc->sc_ioh = ua->ua_ioh; + sc->sc_dmat = ua->ua_dmat; + /* Process the 8 bytes of diagnostic info put into */ + /* the FIFO following the master reset operation. */ + + printf("\n%s:", self->dv_xname); + for (n = 0; n < 8; n++) { + c = DHU_READ_WORD(DHU_UBA_RBUF); + + if ((c&DHU_DIAG_CODE) == DHU_DIAG_CODE) { + if ((c&0200) == 0000) + printf(" rom(%d) version %d", + ((c>>1)&01), ((c>>2)&037)); + else if (((c>>2)&07) != 0) + printf(" diag-error(proc%d)=%x", + ((c>>1)&01), ((c>>2)&07)); + } + } + + c = DHU_READ_WORD(DHU_UBA_STAT); + + sc->sc_type = (c & DHU_STAT_DHU)? IS_DHU: IS_DHV; + printf("\n%s: DH%s-11\n", self->dv_xname, (c & DHU_STAT_DHU)?"U":"V"); + + for (i = 0; i < sc->sc_type; i++) { + struct tty *tp; + tp = sc->sc_dhu[i].dhu_tty = ttymalloc(); + sc->sc_dhu[i].dhu_state = STATE_IDLE; + bus_dmamap_create(sc->sc_dmat, tp->t_outq.c_cn, 1, + tp->t_outq.c_cn, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT, + &sc->sc_dhu[i].dhu_dmah); + bus_dmamap_load(sc->sc_dmat, sc->sc_dhu[i].dhu_dmah, + tp->t_outq.c_cs, tp->t_outq.c_cn, 0, BUS_DMA_NOWAIT); + + } + + /* Now establish RX & TX interrupt handlers */ + + uba_intr_establish(ua->ua_icookie, ua->ua_cvec , dhurint, sc); + uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 4, dhuxint, sc); +} + +/* Receiver Interrupt */ + +static void +dhurint(arg) + void *arg; +{ + struct dhu_softc *sc = arg; + register struct tty *tp; + register int cc, line; + register unsigned c, delta; + int overrun = 0; + + while ((c = DHU_READ_WORD(DHU_UBA_RBUF)) & DHU_RBUF_DATA_VALID) { + + /* Ignore diagnostic FIFO entries. */ + + if ((c & DHU_DIAG_CODE) == DHU_DIAG_CODE) + continue; + + cc = c & 0xFF; + line = DHU_LINE(c>>8); + tp = sc->sc_dhu[line].dhu_tty; + + /* LINK.TYPE is set so we get modem control FIFO entries */ + + if ((c & DHU_DIAG_CODE) == DHU_MODEM_CODE) { + c = (c << 8); + /* Do MDMBUF flow control, wakeup sleeping opens */ + if (c & DHU_STAT_DCD) { + if (!(tp->t_state & TS_CARR_ON)) + (void)(*linesw[tp->t_line].l_modem)(tp, 1); + } + else if ((tp->t_state & TS_CARR_ON) && + (*linesw[tp->t_line].l_modem)(tp, 0) == 0) + (void) dhumctl(sc, line, 0, DMSET); + + /* Do CRTSCTS flow control */ + delta = c ^ sc->sc_dhu[line].dhu_modem; + sc->sc_dhu[line].dhu_modem = c; + if ((delta & DHU_STAT_CTS) && + (tp->t_state & TS_ISOPEN) && + (tp->t_cflag & CRTSCTS)) { + if (c & DHU_STAT_CTS) { + tp->t_state &= ~TS_TTSTOP; + ttstart(tp); + } else { + tp->t_state |= TS_TTSTOP; + dhustop(tp, 0); + } + } + continue; + } + + if (!(tp->t_state & TS_ISOPEN)) { + wakeup((caddr_t)&tp->t_rawq); + continue; + } + + if ((c & DHU_RBUF_OVERRUN_ERR) && overrun == 0) { + log(LOG_WARNING, "%s: silo overflow, line %d\n", + sc->sc_dev.dv_xname, line); + overrun = 1; + } + /* A BREAK key will appear as a NULL with a framing error */ + if (c & DHU_RBUF_FRAMING_ERR) + cc |= TTY_FE; + if (c & DHU_RBUF_PARITY_ERR) + cc |= TTY_PE; + + (*linesw[tp->t_line].l_rint)(cc, tp); + } +} + +/* Transmitter Interrupt */ + +static void +dhuxint(arg) + void *arg; +{ + register struct dhu_softc *sc = arg; + register struct tty *tp; + register int line; + + line = DHU_LINE(DHU_READ_BYTE(DHU_UBA_CSR_HI)); + + tp = sc->sc_dhu[line].dhu_tty; + + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + else { + if (sc->sc_dhu[line].dhu_state == STATE_DMA_STOPPED) + sc->sc_dhu[line].dhu_cc -= + DHU_READ_WORD(DHU_UBA_TBUFCNT); + ndflush(&tp->t_outq, sc->sc_dhu[line].dhu_cc); + sc->sc_dhu[line].dhu_cc = 0; + } + + sc->sc_dhu[line].dhu_state = STATE_IDLE; + + if (tp->t_line) + (*linesw[tp->t_line].l_start)(tp); + else + dhustart(tp); +} + +int +dhuopen(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + register struct tty *tp; + register int unit, line; + struct dhu_softc *sc; + int s, error = 0; + + unit = DHU_M2U(minor(dev)); + line = DHU_LINE(minor(dev)); + + if (unit >= dhu_cd.cd_ndevs || dhu_cd.cd_devs[unit] == NULL) + return (ENXIO); + + sc = dhu_cd.cd_devs[unit]; + + if (line >= sc->sc_type) + return ENXIO; + + s = spltty(); + DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line); + sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT); + (void) splx(s); + + tp = sc->sc_dhu[line].dhu_tty; + + tp->t_oproc = dhustart; + tp->t_param = dhuparam; + tp->t_hwiflow = dhuiflow; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + if (tp->t_ispeed == 0) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + } + (void) dhuparam(tp, &tp->t_termios); + ttsetwater(tp); + } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0) + return (EBUSY); + /* Use DMBIS and *not* DMSET or else we clobber incoming bits */ + if (dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS) & DML_DCD) + tp->t_state |= TS_CARR_ON; + s = spltty(); + while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) && + !(tp->t_state & TS_CARR_ON)) { + error = ttysleep(tp, (caddr_t)&tp->t_rawq, + TTIPRI | PCATCH, ttopen, 0); + if (error) + break; + } + (void) splx(s); + if (error) + return (error); + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +/*ARGSUSED*/ +int +dhuclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + register struct tty *tp; + register int unit, line; + struct dhu_softc *sc; + + unit = DHU_M2U(minor(dev)); + line = DHU_LINE(minor(dev)); + + sc = dhu_cd.cd_devs[unit]; + + tp = sc->sc_dhu[line].dhu_tty; + + (*linesw[tp->t_line].l_close)(tp, flag); + + /* Make sure a BREAK state is not left enabled. */ + + (void) dhumctl(sc, line, DML_BRK, DMBIC); + + /* Do a hangup if so required. */ + + if ((tp->t_cflag & HUPCL) || !(tp->t_state & TS_ISOPEN)) + (void) dhumctl(sc, line, 0, DMSET); + + return (ttyclose(tp)); +} + +int +dhuread(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + register struct dhu_softc *sc; + register struct tty *tp; + + sc = dhu_cd.cd_devs[DHU_M2U(minor(dev))]; + + tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty; + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +dhuwrite(dev, uio, flag) + dev_t dev; + struct uio *uio; +{ + register struct dhu_softc *sc; + register struct tty *tp; + + sc = dhu_cd.cd_devs[DHU_M2U(minor(dev))]; + + tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty; + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +/*ARGSUSED*/ +int +dhuioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + register struct dhu_softc *sc; + register struct tty *tp; + register int unit, line; + int error; + + unit = DHU_M2U(minor(dev)); + line = DHU_LINE(minor(dev)); + sc = dhu_cd.cd_devs[unit]; + tp = sc->sc_dhu[line].dhu_tty; + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + + switch (cmd) { + + case TIOCSBRK: + (void) dhumctl(sc, line, DML_BRK, DMBIS); + break; + + case TIOCCBRK: + (void) dhumctl(sc, line, DML_BRK, DMBIC); + break; + + case TIOCSDTR: + (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS); + break; + + case TIOCCDTR: + (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIC); + break; + + case TIOCMSET: + (void) dhumctl(sc, line, *(int *)data, DMSET); + break; + + case TIOCMBIS: + (void) dhumctl(sc, line, *(int *)data, DMBIS); + break; + + case TIOCMBIC: + (void) dhumctl(sc, line, *(int *)data, DMBIC); + break; + + case TIOCMGET: + *(int *)data = (dhumctl(sc, line, 0, DMGET) & ~DML_BRK); + break; + + default: + return (ENOTTY); + } + return (0); +} + +struct tty * +dhutty(dev) + dev_t dev; +{ + struct dhu_softc *sc = dhu_cd.cd_devs[DHU_M2U(minor(dev))]; + struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty; + return (tp); +} + +/*ARGSUSED*/ +void +dhustop(tp, flag) + register struct tty *tp; +{ + register struct dhu_softc *sc; + register int line; + int s; + + s = spltty(); + + if (tp->t_state & TS_BUSY) { + + sc = dhu_cd.cd_devs[DHU_M2U(minor(tp->t_dev))]; + line = DHU_LINE(minor(tp->t_dev)); + + if (sc->sc_dhu[line].dhu_state == STATE_DMA_RUNNING) { + + sc->sc_dhu[line].dhu_state = STATE_DMA_STOPPED; + + DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line); + DHU_WRITE_WORD(DHU_UBA_LNCTRL, + DHU_READ_WORD(DHU_UBA_LNCTRL) | + DHU_LNCTRL_DMA_ABORT); + } + + if (!(tp->t_state & TS_TTSTOP)) + tp->t_state |= TS_FLUSH; + } + (void) splx(s); +} + +static void +dhustart(tp) + register struct tty *tp; +{ + register struct dhu_softc *sc; + register int line, cc; + register int addr; + int s; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) + goto out; + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + if (tp->t_outq.c_cc == 0) + goto out; + cc = ndqb(&tp->t_outq, 0); + if (cc == 0) + goto out; + + tp->t_state |= TS_BUSY; + + sc = dhu_cd.cd_devs[DHU_M2U(minor(tp->t_dev))]; + + line = DHU_LINE(minor(tp->t_dev)); + + DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line); + + sc->sc_dhu[line].dhu_cc = cc; + + if (cc == 1) { + + sc->sc_dhu[line].dhu_state = STATE_TX_ONE_CHAR; + + DHU_WRITE_WORD(DHU_UBA_TXCHAR, + DHU_TXCHAR_DATA_VALID | *tp->t_outq.c_cf); + + } else { + + sc->sc_dhu[line].dhu_state = STATE_DMA_RUNNING; + + addr = sc->sc_dhu[line].dhu_dmah->dm_segs[0].ds_addr + + (tp->t_outq.c_cf - tp->t_outq.c_cs); + + DHU_WRITE_WORD(DHU_UBA_TBUFCNT, cc); + DHU_WRITE_WORD(DHU_UBA_TBUFAD1, addr & 0xFFFF); + DHU_WRITE_WORD(DHU_UBA_TBUFAD2, ((addr>>16) & 0x3F) | + DHU_TBUFAD2_TX_ENABLE); + DHU_WRITE_WORD(DHU_UBA_LNCTRL, + DHU_READ_WORD(DHU_UBA_LNCTRL) & ~DHU_LNCTRL_DMA_ABORT); + DHU_WRITE_WORD(DHU_UBA_TBUFAD2, + DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_DMA_START); + } +out: + (void) splx(s); + return; +} + +static int +dhuparam(tp, t) + register struct tty *tp; + register struct termios *t; +{ + struct dhu_softc *sc; + register int cflag = t->c_cflag; + int ispeed = ttspeedtab(t->c_ispeed, dhuspeedtab); + int ospeed = ttspeedtab(t->c_ospeed, dhuspeedtab); + register unsigned lpr, lnctrl; + int unit, line; + int s; + + unit = DHU_M2U(minor(tp->t_dev)); + line = DHU_LINE(minor(tp->t_dev)); + + sc = dhu_cd.cd_devs[unit]; + + /* check requested parameters */ + if (ospeed < 0 || ispeed < 0) + return (EINVAL); + + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = cflag; + + if (ospeed == 0) { + (void) dhumctl(sc, line, 0, DMSET); /* hang up line */ + return (0); + } + + s = spltty(); + DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line); + + lpr = ((ispeed&017)<<8) | ((ospeed&017)<<12) ; + + switch (cflag & CSIZE) { + + case CS5: + lpr |= DHU_LPR_5_BIT_CHAR; + break; + + case CS6: + lpr |= DHU_LPR_6_BIT_CHAR; + break; + + case CS7: + lpr |= DHU_LPR_7_BIT_CHAR; + break; + + default: + lpr |= DHU_LPR_8_BIT_CHAR; + break; + } + + if (cflag & PARENB) + lpr |= DHU_LPR_PARENB; + if (!(cflag & PARODD)) + lpr |= DHU_LPR_EPAR; + if (cflag & CSTOPB) + lpr |= DHU_LPR_2_STOP; + + DHU_WRITE_WORD(DHU_UBA_LPR, lpr); + + DHU_WRITE_WORD(DHU_UBA_TBUFAD2, + DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_TX_ENABLE); + + lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL); + + /* Setting LINK.TYPE enables modem signal change interrupts. */ + + lnctrl |= (DHU_LNCTRL_RX_ENABLE | DHU_LNCTRL_LINK_TYPE); + + /* Enable the auto XON/XOFF feature on the controller */ + + if (t->c_iflag & IXON) + lnctrl |= DHU_LNCTRL_OAUTO; + else + lnctrl &= ~DHU_LNCTRL_OAUTO; + + if (t->c_iflag & IXOFF) + lnctrl |= DHU_LNCTRL_IAUTO; + else + lnctrl &= ~DHU_LNCTRL_IAUTO; + + DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl); + + (void) splx(s); + return (0); +} + +static int +dhuiflow(tp, flag) + struct tty *tp; + int flag; +{ + register struct dhu_softc *sc; + register int line = DHU_LINE(minor(tp->t_dev)); + + if (tp->t_cflag & CRTSCTS) { + sc = dhu_cd.cd_devs[DHU_M2U(minor(tp->t_dev))]; + (void) dhumctl(sc, line, DML_RTS, ((flag)? DMBIC: DMBIS)); + return (1); + } + return (0); +} + +static unsigned +dhumctl(sc, line, bits, how) + struct dhu_softc *sc; + int line, bits, how; +{ + register unsigned status; + register unsigned lnctrl; + register unsigned mbits; + int s; + + s = spltty(); + + DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line); + + mbits = 0; + + /* external signals as seen from the port */ + + status = DHU_READ_WORD(DHU_UBA_STAT); + + if (status & DHU_STAT_CTS) + mbits |= DML_CTS; + + if (status & DHU_STAT_DCD) + mbits |= DML_DCD; + + if (status & DHU_STAT_DSR) + mbits |= DML_DSR; + + if (status & DHU_STAT_RI) + mbits |= DML_RI; + + /* internal signals/state delivered to port */ + + lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL); + + if (lnctrl & DHU_LNCTRL_RTS) + mbits |= DML_RTS; + + if (lnctrl & DHU_LNCTRL_DTR) + mbits |= DML_DTR; + + if (lnctrl & DHU_LNCTRL_BREAK) + mbits |= DML_BRK; + + switch (how) { + + case DMSET: + mbits = bits; + break; + + case DMBIS: + mbits |= bits; + break; + + case DMBIC: + mbits &= ~bits; + break; + + case DMGET: + (void) splx(s); + return (mbits); + } + + if (mbits & DML_RTS) + lnctrl |= DHU_LNCTRL_RTS; + else + lnctrl &= ~DHU_LNCTRL_RTS; + + if (mbits & DML_DTR) + lnctrl |= DHU_LNCTRL_DTR; + else + lnctrl &= ~DHU_LNCTRL_DTR; + + if (mbits & DML_BRK) + lnctrl |= DHU_LNCTRL_BREAK; + else + lnctrl &= ~DHU_LNCTRL_BREAK; + + DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl); + + (void) splx(s); + return (mbits); +} |