/* $OpenBSD: mc68681.c,v 1.3 2013/10/07 17:53:56 miod Exp $ */ /* * Copyright (c) 2013 Miodrag Vallat. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Mach Operating System * Copyright (c) 1993-1991 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ #include #include #include #include #include #include #include #include #include #ifdef DDB #include #endif #define DART_UNIT(dev) (minor(dev) / N68681PORTS) #define DART_PORT(dev) (minor(dev) % N68681PORTS) struct cfdriver dart_cd = { NULL, "dart", DV_TTY }; #define MC68681_A_BASE 0x00 #define MC68681_B_BASE 0x08 cdev_decl(dart); void mc68681_set_acr(struct mc68681_softc *); const struct mc68681_s *mc68681_speed(int); void mc68681_start(struct tty *); int mc68681_mctl(struct mc68681_softc *, int, int, int); int mc68681_param(struct tty *, struct termios *); void mc68681_dcdint(struct mc68681_softc *); void mc68681_rxint(struct mc68681_softc *, int); void mc68681_txint(struct mc68681_softc *, int); void mc68681_common_attach(struct mc68681_softc *sc) { sc->sc_line[A_PORT].speed = sc->sc_line[B_PORT].speed = mc68681_speed(B9600); sc->sc_sw_reg->mr1[A_PORT] = sc->sc_sw_reg->mr1[B_PORT] = DART_MR1_RX_IRQ_RXRDY | DART_MR1_ERROR_CHAR | DART_MR1_PARITY_NONE | DART_MR1_RX_RTR | DART_MR1_BPC_8; sc->sc_sw_reg->mr2[A_PORT] = sc->sc_sw_reg->mr2[B_PORT] = DART_MR2_MODE_NORMAL | /* DART_MR2_TX_CTS | */ DART_MR2_STOP_1; sc->sc_sw_reg->cr[A_PORT] = sc->sc_sw_reg->cr[B_PORT] = DART_CR_TX_ENABLE | DART_CR_RX_ENABLE; sc->sc_sw_reg->acr &= ~DART_ACR_BRG_SET_MASK; sc->sc_sw_reg->acr |= DART_ACR_BRG_SET_2; /* Start out with Tx and RX interrupts disabled, but enable input port change interrupt */ sc->sc_sw_reg->imr |= DART_ISR_IP_CHANGE; if (sc->sc_consport >= 0) { printf(": console"); delay(10000); } mc68681_set_acr(sc); (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); printf("\n"); } /* * Update the ACR register. This requires both ports to be disabled. * Restart timer if necessary. */ void mc68681_set_acr(struct mc68681_softc *sc) { uint8_t acr; acr = sc->sc_sw_reg->acr; /* * If MD attachment configures a timer, ignore this until the timer * limit has been correctly set up. This allows this function to be * invoked at attach time, before cpu_initclocks() gets a chance to * run. */ if (ISSET(acr, DART_ACR_CT_TIMER_BIT) && *sc->sc_sw_reg->ct == 0) acr = (acr & ~DART_ACR_CT_MASK) | DART_ACR_CT_COUNTER_CLK_16; /* reset port a */ (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_RX | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE); (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_TX /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_ERROR /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_BREAK /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_MR1 /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); /* reset port b */ (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_RX | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE); (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_TX /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_ERROR /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_BREAK /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_MR1 /* | DART_CR_TX_DISABLE | DART_CR_RX_DISABLE */); (*sc->sc_write)(sc, DART_OPRS, sc->sc_sw_reg->oprs); (*sc->sc_write)(sc, DART_OPCR, sc->sc_sw_reg->opcr); (*sc->sc_write)(sc, DART_ACR, acr); /* * Restart timer if necessary. * XXX This loses the current timer cycle. */ if (ISSET(acr, DART_ACR_CT_TIMER_BIT)) { (*sc->sc_write)(sc, DART_CTUR, *sc->sc_sw_reg->ct >> 8); (*sc->sc_write)(sc, DART_CTLR, *sc->sc_sw_reg->ct & 0xff); (*sc->sc_read)(sc, DART_CTSTART); } /* reinitialize ports */ (*sc->sc_write)(sc, DART_MRA, sc->sc_sw_reg->mr1[A_PORT]); (*sc->sc_write)(sc, DART_MRA, sc->sc_sw_reg->mr2[A_PORT]); (*sc->sc_write)(sc, DART_CSRA, sc->sc_line[A_PORT].speed->csr); (*sc->sc_write)(sc, DART_CRA, sc->sc_sw_reg->cr[A_PORT]); (*sc->sc_write)(sc, DART_MRB, sc->sc_sw_reg->mr1[B_PORT]); (*sc->sc_write)(sc, DART_MRB, sc->sc_sw_reg->mr2[B_PORT]); (*sc->sc_write)(sc, DART_CSRB, sc->sc_line[B_PORT].speed->csr); (*sc->sc_write)(sc, DART_CRB, sc->sc_sw_reg->cr[B_PORT]); } /* speed table */ static const struct mc68681_s mc68681_speeds[] = { #define MC68681_SPEED(spd,sets) \ { .speed = spd, .brg_sets = sets, \ .csr = (DART_CSR_##spd << DART_CSR_RXCLOCK_SHIFT) | \ (DART_CSR_##spd << DART_CSR_TXCLOCK_SHIFT) } MC68681_SPEED(50, 1), MC68681_SPEED(75, 2), MC68681_SPEED(110, 1 | 2), MC68681_SPEED(134, 1 | 2), MC68681_SPEED(150, 2), MC68681_SPEED(200, 1), MC68681_SPEED(300, 1 | 2), MC68681_SPEED(600, 1 | 2), MC68681_SPEED(1050, 1), MC68681_SPEED(1200, 1 | 2), MC68681_SPEED(1800, 2), MC68681_SPEED(2000, 2), MC68681_SPEED(2400, 1 | 2), MC68681_SPEED(4800, 1 | 2), MC68681_SPEED(7200, 1), MC68681_SPEED(9600, 1 | 2), MC68681_SPEED(19200, 2), MC68681_SPEED(38400, 1) #undef MC68681_SPEED }; const struct mc68681_s * mc68681_speed(int speed) { const struct mc68681_s *mcs; uint n; for (n = nitems(mc68681_speeds), mcs = mc68681_speeds; n != 0; n--, mcs++) { if (mcs->speed == speed) return mcs; } return NULL; } void mc68681_start(struct tty *tp) { struct mc68681_softc *sc; dev_t dev; int s; int port, tries; int c; uint ptaddr; uint8_t imrbit; if ((tp->t_state & TS_ISOPEN) == 0) return; dev = tp->t_dev; sc = (struct mc68681_softc *)dart_cd.cd_devs[DART_UNIT(dev)]; port = DART_PORT(dev); ptaddr = port ? MC68681_B_BASE : MC68681_A_BASE; imrbit = port ? DART_ISR_TXB : DART_ISR_TXA; s = spltty(); if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) goto bail; ttwakeupwr(tp); if (tp->t_outq.c_cc == 0) goto bail; tp->t_state |= TS_BUSY; while (tp->t_outq.c_cc != 0) { /* load transmitter until it is full */ for (tries = 10000; tries != 0; tries --) if ((*sc->sc_read)(sc, ptaddr + DART_SRA) & DART_SR_TX_READY) break; if (tries == 0) { if (!ISSET(sc->sc_sw_reg->imr, imrbit)) { sc->sc_sw_reg->imr |= imrbit; (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); } goto bail; } c = getc(&tp->t_outq); (*sc->sc_write)(sc, ptaddr + DART_TBA, c & 0xff); } tp->t_state &= ~TS_BUSY; bail: splx(s); } int dartstop(struct tty *tp, int flag) { int s; s = spltty(); if (tp->t_state & TS_BUSY) { if ((tp->t_state & TS_TTSTOP) == 0) tp->t_state |= TS_FLUSH; } splx(s); return 0; } /* * To be called at spltty - tty already locked. * Returns status of carrier. */ int mc68681_mctl(struct mc68681_softc *sc, int port, int flags, int how) { int op, newflags = 0; struct mc68681_line *line; int s; line = &sc->sc_line[port]; s = spltty(); if (flags & TIOCM_DTR) { op = sc->sc_hw[port].dtr_op; if (op >= 0) { newflags |= 1 << op; flags &= ~TIOCM_DTR; } } if (flags & TIOCM_RTS) { op = sc->sc_hw[port].rts_op; if (op >= 0) { newflags |= 1 << op; flags &= ~TIOCM_RTS; } } switch (how) { case DMSET: (*sc->sc_write)(sc, DART_OPRS, newflags); (*sc->sc_write)(sc, DART_OPRR, ~newflags); break; case DMBIS: (*sc->sc_write)(sc, DART_OPRS, newflags); break; case DMBIC: (*sc->sc_write)(sc, DART_OPRR, newflags); break; case DMGET: flags = 0; /* XXX not supported */ break; } splx(s); return flags; } int dartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { int error; int unit, port; struct tty *tp; struct mc68681_line *line; struct mc68681_softc *sc; unit = DART_UNIT(dev); if (unit >= dart_cd.cd_ndevs) return ENXIO; sc = (struct mc68681_softc *)dart_cd.cd_devs[unit]; if (sc == NULL) return ENXIO; port = DART_PORT(dev); line = &sc->sc_line[port]; tp = line->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: case TIOCCBRK: break; case TIOCSDTR: (void)mc68681_mctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIS); break; case TIOCCDTR: (void)mc68681_mctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIC); break; case TIOCMSET: (void)mc68681_mctl(sc, port, *(int *)data, DMSET); break; case TIOCMBIS: (void)mc68681_mctl(sc, port, *(int *)data, DMBIS); break; case TIOCMBIC: (void)mc68681_mctl(sc, port, *(int *)data, DMBIC); break; case TIOCMGET: *(int *)data = mc68681_mctl(sc, port, 0, DMGET); break; case TIOCGFLAGS: if (sc->sc_consport == port) line->swflags |= TIOCFLAG_SOFTCAR; *(int *)data = line->swflags; break; case TIOCSFLAGS: error = suser(p, 0); if (error != 0) return EPERM; line->swflags = *(int *)data; if (sc->sc_consport == port) line->swflags |= TIOCFLAG_SOFTCAR; line->swflags &= /* only allow valid flags */ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); break; default: return ENOTTY; } return 0; } int mc68681_param(struct tty *tp, struct termios *t) { int unit, port, s, acrupdate; const struct mc68681_s *spd; uint8_t acr, mr1, mr2; struct mc68681_line *line; struct mc68681_softc *sc; dev_t dev; uint ptaddr; dev = tp->t_dev; unit = DART_UNIT(dev); sc = (struct mc68681_softc *)dart_cd.cd_devs[unit]; port = DART_PORT(dev); line = &sc->sc_line[port]; ptaddr = port ? MC68681_B_BASE : MC68681_A_BASE; tp->t_ispeed = t->c_ispeed; tp->t_ospeed = t->c_ospeed; tp->t_cflag = t->c_cflag; /* Reset to make global changes */ if (sc->sc_consport != port) { /* disable Tx and Rx */ if (port == A_PORT) sc->sc_sw_reg->imr &= ~(DART_ISR_TXA | DART_ISR_RXA); else sc->sc_sw_reg->imr &= ~(DART_ISR_TXB | DART_ISR_RXB); (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); acrupdate = 0; /* * Try to set baudrate. If the rate being asked for * uses a different BRG than the other port, bail * out with EAGAIN. * Note that, upon close, we will reset to 9600 * bps which is compatible with both BRG. */ spd = mc68681_speed(tp->t_ispeed); if (spd == NULL) return EINVAL; if ((spd->brg_sets & sc->sc_line[port ^ 1].speed->brg_sets) == 0) return EAGAIN; line->speed = spd; if (spd->brg_sets != (1 | 2)) { acr = sc->sc_sw_reg->acr; switch (acr & DART_ACR_BRG_SET_MASK) { case DART_ACR_BRG_SET_2: if (spd->brg_sets == 1) { acr &= ~DART_ACR_BRG_SET_MASK; acr |= DART_ACR_BRG_SET_1; } break; case DART_ACR_BRG_SET_1: if (spd->brg_sets == 2) { acr &= ~DART_ACR_BRG_SET_MASK; acr |= DART_ACR_BRG_SET_2; } break; } if (acr != sc->sc_sw_reg->acr) { sc->sc_sw_reg->acr = acr; acrupdate = 1; } } if (acrupdate == 0) (*sc->sc_write)(sc, ptaddr + DART_CSRA, spd->csr); /* get saved mode registers and clear set up parameters */ mr1 = sc->sc_sw_reg->mr1[port]; mr1 &= ~(DART_MR1_BPC_MASK | DART_MR1_PARITY_MASK); mr2 = sc->sc_sw_reg->mr2[port]; mr2 &= ~DART_MR2_STOP_MASK; /* set up character size */ switch (t->c_cflag & CSIZE) { case CS8: mr1 |= DART_MR1_BPC_8; break; case CS7: mr1 |= DART_MR1_BPC_7; break; case CS6: mr1 |= DART_MR1_BPC_6; break; case CS5: mr1 |= DART_MR1_BPC_5; break; } /* set up stop bits */ if (t->c_cflag & CSTOPB) mr2 |= DART_MR2_STOP_2; else { /* * When running in 5 bpc mode, low stop bit length * values are actually off .5 stop bits. */ if ((t->c_cflag & CSIZE) == CS5) mr2 |= DART_MR2_STOP_1_CL5; else mr2 |= DART_MR2_STOP_1; } /* set up parity */ if (t->c_cflag & PARENB) { mr1 |= DART_MR1_PARITY_ENABLE; if (t->c_cflag & PARODD) mr1 |= DART_MR1_PARITY_ENABLE_ODD; else mr1 |= DART_MR1_PARITY_ENABLE_EVEN; } else mr1 |= DART_MR1_PARITY_NONE; if (sc->sc_sw_reg->mr1[port] != mr1 || sc->sc_sw_reg->mr2[port] != mr2) { if (acrupdate == 0) { /* write mode registers to duart */ (*sc->sc_write)(sc, ptaddr + DART_CRA, DART_CR_RESET_MR1); (*sc->sc_write)(sc, ptaddr + DART_MRA, mr1); (*sc->sc_write)(sc, ptaddr + DART_MRA, mr2); } /* save changed mode registers */ sc->sc_sw_reg->mr1[port] = mr1; sc->sc_sw_reg->mr2[port] = mr2; } if (acrupdate != 0) { s = spltty(); mc68681_set_acr(sc); splx(s); } } /* enable transmitter? */ if (tp->t_state & TS_BUSY) { if (port == A_PORT) sc->sc_sw_reg->imr |= DART_ISR_TXA; else sc->sc_sw_reg->imr |= DART_ISR_TXB; /* will be done below (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); */ } /* re-enable the receiver */ if (port == A_PORT) sc->sc_sw_reg->imr |= DART_ISR_RXA; else sc->sc_sw_reg->imr |= DART_ISR_RXB; (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); return 0; } void mc68681_dcdint(struct mc68681_softc *sc) { unsigned int dcdstate; uint8_t ipcr, ip, ip_bit; struct tty *tp; int port; struct mc68681_line *line; ipcr = (*sc->sc_read)(sc, DART_IPCR); ip = (*sc->sc_read)(sc, DART_IP); for (port = A_PORT; port <= B_PORT; port++) { ip_bit = 0; switch (sc->sc_hw[port].dcd_ip) { case 3: if (ipcr & DART_IPCR_IP3_CHANGED) ip_bit = DART_IP_IP3; break; case 2: if (ipcr & DART_IPCR_IP2_CHANGED) ip_bit = DART_IP_IP2; break; case 1: if (ipcr & DART_IPCR_IP1_CHANGED) ip_bit = DART_IP_IP1; break; case 0: if (ipcr & DART_IPCR_IP0_CHANGED) ip_bit = DART_IP_IP0; break; } if (ip_bit != 0) { dcdstate = ip & ip_bit; if (sc->sc_hw[port].dcd_active_low) dcdstate = !dcdstate; line = &sc->sc_line[port]; tp = line->tty; if (tp != NULL) (*linesw[tp->t_line].l_modem)(tp, dcdstate); } } } struct tty * darttty(dev_t dev) { int unit, port; struct mc68681_softc *sc; unit = DART_UNIT(dev); sc = (struct mc68681_softc *)dart_cd.cd_devs[unit]; port = DART_PORT(dev); return sc->sc_line[port].tty; } int dartopen(dev_t dev, int flag, int mode, struct proc *p) { int s, unit, port; struct mc68681_line *line; struct mc68681_softc *sc; struct tty *tp; unit = DART_UNIT(dev); if (unit >= dart_cd.cd_ndevs) return ENXIO; sc = (struct mc68681_softc *)dart_cd.cd_devs[unit]; if (sc == NULL) return ENXIO; port = DART_PORT(dev); line = &sc->sc_line[port]; s = spltty(); if (line->tty != NULL) tp = line->tty; else tp = line->tty = ttymalloc(0); tp->t_oproc = mc68681_start; tp->t_param = mc68681_param; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = B9600; mc68681_param(tp, &tp->t_termios); if (sc->sc_consport == port) { /* console is 8N1 */ tp->t_cflag = CREAD | CS8 | HUPCL; } else { tp->t_cflag = TTYDEF_CFLAG; } ttsetwater(tp); (void)mc68681_mctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMSET); tp->t_state |= TS_CARR_ON; } else if (tp->t_state & TS_XCLUDE && suser(p, 0) != 0) { splx(s); return EBUSY; } splx(s); return (*linesw[tp->t_line].l_open)(dev, tp, p); } int dartclose(dev_t dev, int flag, int mode, struct proc *p) { struct tty *tp; struct mc68681_line *line; struct mc68681_softc *sc; sc = (struct mc68681_softc *)dart_cd.cd_devs[DART_UNIT(dev)]; line = &sc->sc_line[DART_PORT(dev)]; tp = line->tty; (*linesw[tp->t_line].l_close)(tp, flag, p); ttyclose(tp); return 0; } int dartread(dev_t dev, struct uio *uio, int flag) { struct tty *tp; struct mc68681_softc *sc; sc = (struct mc68681_softc *)dart_cd.cd_devs[DART_UNIT(dev)]; tp = sc->sc_line[DART_PORT(dev)].tty; return (*linesw[tp->t_line].l_read)(tp, uio, flag); } int dartwrite(dev_t dev, struct uio *uio, int flag) { struct tty *tp; struct mc68681_softc *sc; sc = (struct mc68681_softc *)dart_cd.cd_devs[DART_UNIT(dev)]; tp = sc->sc_line[DART_PORT(dev)].tty; return (*linesw[tp->t_line].l_write)(tp, uio, flag); } void mc68681_rxint(struct mc68681_softc *sc, int port) { struct tty *tp; uint8_t data, sr; uint ptaddr; tp = sc->sc_line[port].tty; ptaddr = port ? MC68681_B_BASE : MC68681_A_BASE; /* read status reg */ while ((sr = (*sc->sc_read)(sc, ptaddr + DART_SRA)) & DART_SR_RX_READY) { /* read data and reset receiver */ data = (*sc->sc_read)(sc, ptaddr + DART_RBA); if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0 && sc->sc_consport != port) { return; } if (sr & DART_SR_BREAK) { /* clear break state */ (*sc->sc_write)(sc, ptaddr + DART_CRA, DART_CR_RESET_BREAK); (*sc->sc_write)(sc, ptaddr + DART_CRA, DART_CR_RESET_ERROR); #if defined(DDB) if (db_console != 0 && sc->sc_consport == port) Debugger(); #endif } else if (sr & (DART_SR_FRAME | DART_SR_PARITY | DART_SR_OVERRUN)) { /* errors */ if (sr & DART_SR_OVERRUN) printf("%s: receiver overrun port %c\n", sc->sc_dev.dv_xname, 'A' + port); if (sr & DART_SR_FRAME) printf("%s: framing error port %c\n", sc->sc_dev.dv_xname, 'A' + port); if (sr & DART_SR_PARITY) printf("%s: parity error port %c\n", sc->sc_dev.dv_xname, 'A' + port); /* clear error state */ (*sc->sc_write)(sc, ptaddr + DART_CRA, DART_CR_RESET_ERROR); } else { /* no errors */ if (ISSET(tp->t_state, TS_ISOPEN)) (*linesw[tp->t_line].l_rint)(data,tp); } } } void mc68681_txint(struct mc68681_softc *sc, int port) { struct tty *tp; tp = sc->sc_line[port].tty; if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0) goto out; if (tp->t_state & TS_FLUSH) tp->t_state &= ~TS_FLUSH; if (tp->t_state & TS_BUSY) { tp->t_state &= ~TS_BUSY; (*linesw[tp->t_line].l_start)(tp); if (tp->t_state & TS_BUSY) { return; } } out: /* disable transmitter */ if (port == A_PORT) sc->sc_sw_reg->imr &= ~DART_ISR_TXA; else sc->sc_sw_reg->imr &= ~DART_ISR_TXB; (*sc->sc_write)(sc, DART_IMR, sc->sc_sw_reg->imr); } void mc68681_intr(struct mc68681_softc *sc, uint8_t isr) { if (isr & DART_ISR_IP_CHANGE) mc68681_dcdint(sc); if (isr & DART_ISR_RXA) mc68681_rxint(sc, A_PORT); if (isr & DART_ISR_RXB) mc68681_rxint(sc, B_PORT); if (isr & DART_ISR_TXA) mc68681_txint(sc, A_PORT); if (isr & DART_ISR_TXB) mc68681_txint(sc, B_PORT); #if 0 /* not enabled in imr */ if (isr & DART_ISR_DELTA_BREAK_A) (*sc->sc_write)(sc, DART_CRA, DART_CR_RESET_BREAK); if (isr & DART_ISR_DELTA_BREAK_B) (*sc->sc_write)(sc, DART_CRB, DART_CR_RESET_BREAK); #endif }