diff options
Diffstat (limited to 'sys/arch/aviion/dev/dart.c')
-rw-r--r-- | sys/arch/aviion/dev/dart.c | 1039 |
1 files changed, 1039 insertions, 0 deletions
diff --git a/sys/arch/aviion/dev/dart.c b/sys/arch/aviion/dev/dart.c new file mode 100644 index 00000000000..ccbca07b568 --- /dev/null +++ b/sys/arch/aviion/dev/dart.c @@ -0,0 +1,1039 @@ +/* $OpenBSD: dart.c,v 1.1 2006/05/09 18:13:32 miod Exp $ */ + +/* + * 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 <sys/param.h> +#include <sys/ioctl.h> +#include <sys/proc.h> +#include <sys/tty.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/syslog.h> + +#include <machine/autoconf.h> +#include <machine/conf.h> +#include <machine/cpu.h> + +#include <dev/cons.h> + +#include <machine/av400.h> +#include <aviion/dev/sysconreg.h> +#include <aviion/dev/dartreg.h> +#include <aviion/dev/dartvar.h> + +#ifdef DDB +#include <ddb/db_var.h> +#endif + +struct cfdriver dart_cd = { + NULL, "dart", DV_TTY +}; + +/* console is on the first port */ +#define CONS_PORT A_PORT +#ifdef USE_PROM_CONSOLE +#define dartcn_sv sc->sc_sv_reg_storage +#else +struct dart_sv_reg dartcn_sv; +#endif + +/* prototypes */ +cons_decl(dart); +int dart_speed(int); +struct tty *darttty(dev_t); +void dartstart(struct tty *); +int dartmctl(struct dartsoftc *, int, int, int); +int dartparam(struct tty *, struct termios *); +void dartmodemtrans(struct dartsoftc *, unsigned int, unsigned int); +void dartrint(struct dartsoftc *, int); +void dartxint(struct dartsoftc *, int); + +/* + * DUART registers are mapped as the least-significant byte of 32-bit + * addresses. The following macros hide this. + */ + +#define dart_read(sc, reg) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, 3 + ((reg) << 2)) +#define dart_write(sc, reg, val) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, 3 + ((reg) << 2), (val)) + +#define DART_CHIP(dev) (minor(dev) >> 1) +#define DART_PORT(dev) (minor(dev) & 1) + +void +dart_common_attach(struct dartsoftc *sc) +{ + if (sc->sc_console) { + sc->sc_sv_reg = &dartcn_sv; + + if (A_PORT != CONS_PORT) { + sc->sc_sv_reg->sv_mr1[A_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[A_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[A_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[A_PORT] = TXEN | RXEN; + sc->sc_sv_reg->sv_opr |= OPDTRA | OPRTSA; + } else { + sc->sc_sv_reg->sv_mr1[B_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[B_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[B_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[B_PORT] = TXEN | RXEN; + sc->sc_sv_reg->sv_opr |= OPDTRB | OPRTSB; + } + } else { + sc->sc_sv_reg = &sc->sc_sv_reg_storage; + + sc->sc_sv_reg->sv_mr1[A_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[A_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[A_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[A_PORT] = TXEN | RXEN; + + sc->sc_sv_reg->sv_mr1[B_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[B_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[B_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[B_PORT] = TXEN | RXEN; + + sc->sc_sv_reg->sv_opr = OPDTRA | OPRTSA | OPDTRB | OPRTSB; + + /* Start out with Tx and RX interrupts disabled */ + /* Enable input port change interrupt */ + sc->sc_sv_reg->sv_imr = IIPCHG; + } + + /* reset port a */ + if (sc->sc_console == 0 || CONS_PORT != A_PORT) { + dart_write(sc, DART_CRA, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, MRRESET | TXDIS | RXDIS); +#if 0 + DELAY_CR; +#endif + + dart_write(sc, DART_MR1A, sc->sc_sv_reg->sv_mr1[A_PORT]); + dart_write(sc, DART_MR2A, sc->sc_sv_reg->sv_mr2[A_PORT]); + dart_write(sc, DART_CSRA, sc->sc_sv_reg->sv_csr[A_PORT]); + dart_write(sc, DART_CRA, sc->sc_sv_reg->sv_cr[A_PORT]); + } + + /* reset port b */ + if (sc->sc_console == 0 || CONS_PORT != B_PORT) { + dart_write(sc, DART_CRB, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, MRRESET | TXDIS | RXDIS); +#if 0 + DELAY_CR; +#endif + + dart_write(sc, DART_MR1B, sc->sc_sv_reg->sv_mr1[B_PORT]); + dart_write(sc, DART_MR2B, sc->sc_sv_reg->sv_mr2[B_PORT]); + dart_write(sc, DART_CSRB, sc->sc_sv_reg->sv_csr[B_PORT]); + dart_write(sc, DART_CRB, sc->sc_sv_reg->sv_cr[B_PORT]); + } + + /* initialize common register of a DUART */ + dart_write(sc, DART_OPRS, sc->sc_sv_reg->sv_opr); + +#if 0 + dart_write(sc, DART_CTUR, SLCTIM >> 8); + dart_write(sc, DART_CTLR, SLCTIM & 0xff); + dart_write(sc, DART_ACR, BDSET2 | CCLK16 | IPDCDIB | IPDCDIA); +#endif + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); +#if 0 + dart_write(sc, DART_OPCR, OPSET); +#endif +#if 0 + dart_write(sc, DART_IVR, SYSCON_VECT + SYSCV_SCC); +#endif + + sc->sc_dart[A_PORT].tty = sc->sc_dart[B_PORT].tty = NULL; + sc->sc_dart[A_PORT].dart_swflags = sc->sc_dart[B_PORT].dart_swflags = 0; + if (sc->sc_console) + sc->sc_dart[CONS_PORT].dart_swflags |= TIOCFLAG_SOFTCAR; + + printf("\n"); +} + +/* speed tables */ +const struct dart_s { + int kspeed; + int dspeed; +} dart_speeds[] = { + { B0, 0 }, /* 0 baud, special HUP condition */ + { B50, NOBAUD }, /* 50 baud, not implemented */ + { B75, BD75 }, /* 75 baud */ + { B110, BD110 }, /* 110 baud */ + { B134, BD134 }, /* 134.5 baud */ + { B150, BD150 }, /* 150 baud */ + { B200, NOBAUD }, /* 200 baud, not implemented */ + { B300, BD300 }, /* 300 baud */ + { B600, BD600 }, /* 600 baud */ + { B1200, BD1200 }, /* 1200 baud */ + { B1800, BD1800 }, /* 1800 baud */ + { B2400, BD2400 }, /* 2400 baud */ + { B4800, BD4800 }, /* 4800 baud */ + { B9600, BD9600 }, /* 9600 baud */ + { B19200, BD19200 }, /* 19200 baud */ + { -1, NOBAUD }, /* anything more is uncivilized */ +}; + +int +dart_speed(int speed) +{ + const struct dart_s *ds; + + for (ds = dart_speeds; ds->kspeed != -1; ds++) + if (ds->kspeed == speed) + return ds->dspeed; + + return NOBAUD; +} + +struct tty * +darttty(dev_t dev) +{ + u_int port, chip; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + if (dart_cd.cd_ndevs <= chip || port >= NDARTPORTS) + return (NULL); + + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + if (sc == NULL) + return (NULL); + + return sc->sc_dart[port].tty; +} + +void +dartstart(struct tty *tp) +{ + struct dartsoftc *sc; + dev_t dev; + int s; + u_int port, chip; + int c, tries; + bus_addr_t ptaddr; + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + dev = tp->t_dev; + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto bail; + + 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 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 (dart_read(sc, ptaddr + DART_SRA) & TXRDY) + break; + + if (tries == 0) { + timeout_add(&tp->t_rstrt_to, 1); + tp->t_state |= TS_TIMEOUT; + break; + } else { + c = getc(&tp->t_outq); + + dart_write(sc, ptaddr + DART_TBA, c & 0xff); + + sc->sc_sv_reg->sv_imr |= + port == A_PORT ? ITXRDYA : ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + } + } + 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 +dartmctl(struct dartsoftc *sc, int port, int flags, int how) +{ + int newflags, flagsmask; + struct dart_info *dart; + int s; + + dart = &sc->sc_dart[port]; + + s = spltty(); + + flagsmask = port == A_PORT ? (OPDTRA | OPRTSA) : (OPDTRB | OPRTSB); + newflags = (flags & TIOCM_DTR ? (OPDTRA | OPDTRB) : 0) | + (flags & TIOCM_RTS ? (OPRTSA | OPRTSB) : 0); + newflags &= flagsmask; /* restrict to the port we are acting on */ + + switch (how) { + case DMSET: + dart_write(sc, DART_OPRS, newflags); + dart_write(sc, DART_OPRR, ~newflags); + /* only replace the sv_opr bits for the port we are acting on */ + sc->sc_sv_reg->sv_opr &= ~flagsmask; + sc->sc_sv_reg->sv_opr |= newflags; + break; + case DMBIS: + dart_write(sc, DART_OPRS, newflags); + sc->sc_sv_reg->sv_opr |= newflags; + break; + case DMBIC: + dart_write(sc, DART_OPRR, newflags); + sc->sc_sv_reg->sv_opr &= ~newflags; + break; + case DMGET: + flags = 0; + if (port == A_PORT) { + if (sc->sc_sv_reg->sv_opr & OPDTRA) + flags |= TIOCM_DTR; + if (sc->sc_sv_reg->sv_opr & OPRTSA) + flags |= TIOCM_RTS; + } else { + if (sc->sc_sv_reg->sv_opr & OPDTRB) + flags |= TIOCM_DTR; + if (sc->sc_sv_reg->sv_opr & OPRTSB) + flags |= TIOCM_RTS; + } + break; + } + + splx(s); + return (flags); +} + +int +dartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + int error; + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + + 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)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIS); + break; + case TIOCCDTR: + (void)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIC); + break; + case TIOCMSET: + (void)dartmctl(sc, port, *(int *) data, DMSET); + break; + case TIOCMBIS: + (void)dartmctl(sc, port, *(int *) data, DMBIS); + break; + case TIOCMBIC: + (void)dartmctl(sc, port, *(int *) data, DMBIC); + break; + case TIOCMGET: + *(int *)data = dartmctl(sc, port, 0, DMGET); + break; + case TIOCGFLAGS: + *(int *)data = dart->dart_swflags; + break; + case TIOCSFLAGS: + error = suser(p, 0); + if (error != 0) + return (EPERM); + + dart->dart_swflags = *(int *)data; + dart->dart_swflags &= /* only allow valid flags */ + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); + break; + default: + return (ENOTTY); + } + + return (0); +} + +int +dartparam(struct tty *tp, struct termios *t) +{ + int flags; + u_int port, chip; + int speeds; + unsigned char mr1, mr2; + struct dart_info *dart; + struct dartsoftc *sc; + dev_t dev; + bus_addr_t ptaddr; + + dev = tp->t_dev; + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + + flags = tp->t_flags; + + /* Reset to make global changes*/ + /* disable Tx and Rx */ + + if (sc->sc_console == 0 || CONS_PORT != port) { + if (port == A_PORT) + sc->sc_sv_reg->sv_imr &= ~(ITXRDYA | IRXRDYA); + else + sc->sc_sv_reg->sv_imr &= ~(ITXRDYB | IRXRDYB); + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + + /* hang up on zero baud rate */ + if (tp->t_ispeed == 0) { + dartmctl(sc, port, HUPCL, DMSET); + return (0); + } else { + /* set baudrate */ + speeds = dart_speed(tp->t_ispeed); + if (speeds == NOBAUD) + speeds = sc->sc_sv_reg->sv_csr[port]; + dart_write(sc, ptaddr + DART_CSRA, speeds); + sc->sc_sv_reg->sv_csr[port] = speeds; + } + + /* get saved mode registers and clear set up parameters */ + mr1 = sc->sc_sv_reg->sv_mr1[port]; + mr1 &= ~(CLMASK | PARTYPEMASK | PARMODEMASK); + + mr2 = sc->sc_sv_reg->sv_mr2[port]; + mr2 &= ~SBMASK; + + /* set up character size */ + switch (t->c_cflag & CSIZE) { + case CL8: + mr1 |= CL8; + break; + case CL7: + mr1 |= CL7; + break; + case CL6: + mr1 |= CL6; + break; + case CL5: + mr1 |= CL5; + break; + } + + /* set up stop bits */ + if (tp->t_ospeed == B110) + mr2 |= SB2; + else + mr2 |= SB1; + + /* set up parity */ + if (t->c_cflag & PARENB) { + mr1 |= PAREN; + if (t->c_cflag & PARODD) + mr1 |= ODDPAR; + else + mr1 |= EVENPAR; + } else + mr1 |= PARDIS; + + if (sc->sc_sv_reg->sv_mr1[port] != mr1 || + sc->sc_sv_reg->sv_mr2[port] != mr2) { + /* write mode registers to duart */ + dart_write(sc, ptaddr + DART_CRA, MRRESET); + dart_write(sc, ptaddr + DART_MR1A, mr1); + dart_write(sc, ptaddr + DART_MR2A, mr2); + + /* save changed mode registers */ + sc->sc_sv_reg->sv_mr1[port] = mr1; + sc->sc_sv_reg->sv_mr2[port] = mr2; + } + } + + /* enable transmitter? */ + if (tp->t_state & TS_BUSY) { + sc->sc_sv_reg->sv_imr |= port == A_PORT ? ITXRDYA : ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + } + + /* re-enable the receiver */ +#if 0 + DELAY_CR; +#endif + sc->sc_sv_reg->sv_imr |= port == A_PORT ? IRXRDYA : IRXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + + return (0); +} + +void +dartmodemtrans(struct dartsoftc *sc, unsigned int ip, unsigned int ipcr) +{ + unsigned int dcdstate; + struct tty *tp; + int port; + struct dart_info *dart; + + /* input is inverted at port!!! */ + if (ipcr & IPCRDCDA) { + port = A_PORT; + dcdstate = !(ip & IPDCDA); + } else if (ipcr & IPCRDCDB) { + port = B_PORT; + dcdstate = !(ip & IPDCDB); + } else { +#ifdef DIAGNOSTIC + printf("dartmodemtrans: unknown transition ip=0x%x ipcr=0x%x\n", + ip, ipcr); +#endif + return; + } + + dart = &sc->sc_dart[port]; + tp = dart->tty; + if (tp != NULL) + ttymodem(tp, dcdstate); +} + +int +dartopen(dev_t dev, int flag, int mode, struct proc *p) +{ + int s; + u_int port, chip; + struct dart_info *dart; + struct dartsoftc *sc; + struct tty *tp; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + if (dart_cd.cd_ndevs <= chip || port >= NDARTPORTS) + return (ENODEV); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + if (sc == NULL) + return (ENODEV); + dart = &sc->sc_dart[port]; + + s = spltty(); + if (dart->tty != NULL) + tp = dart->tty; + else + tp = dart->tty = ttymalloc(); + + tp->t_oproc = dartstart; + tp->t_param = dartparam; + 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_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = B9600; + if (sc->sc_console && port == CONS_PORT) { + /* console is 8N1 */ + tp->t_cflag = (CREAD | CS8 | HUPCL); + } else { + tp->t_cflag = TTYDEF_CFLAG; + } + } + + if (dart->dart_swflags & TIOCFLAG_CLOCAL) + tp->t_cflag |= CLOCAL; + if (dart->dart_swflags & TIOCFLAG_CRTSCTS) + tp->t_cflag |= CRTSCTS; + if (dart->dart_swflags & TIOCFLAG_MDMBUF) + tp->t_cflag |= MDMBUF; + + dartparam(tp, &tp->t_termios); + ttsetwater(tp); + + (void)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMSET); + tp->t_state |= TS_CARR_ON; + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + + /* + * Reset the tty pointer, as there could have been a dialout + * use of the tty with a dialin open waiting. + */ + tp->t_dev = dev; + splx(s); + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int +dartclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + u_int port, chip; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + (*linesw[tp->t_line].l_close)(tp, flag); + ttyclose(tp); + + return (0); +} + +int +dartread(dev_t dev, struct uio *uio, int flag) +{ + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +dartwrite(dev_t dev, struct uio *uio, int flag) +{ + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +dartrint(struct dartsoftc *sc, int port) +{ + struct tty *tp; + unsigned char data, sr; + struct dart_info *dart; + bus_addr_t ptaddr; + + dart = &sc->sc_dart[port]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + tp = dart->tty; + + /* read status reg */ + while ((sr = dart_read(sc, ptaddr + DART_SRA)) & RXRDY) { + /* read data and reset receiver */ + data = dart_read(sc, ptaddr + DART_RBA); + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0 && + (sc->sc_console == 0 || CONS_PORT != port)) { + return; + } + + if (sr & RBRK) { + /* clear break state */ + dart_write(sc, ptaddr + DART_CRA, BRKINTRESET); + DELAY_CR; + dart_write(sc, ptaddr + DART_CRA, ERRRESET); + +#if defined(DDB) + if (db_console != 0 && + sc->sc_console && port == CONS_PORT) + Debugger(); +#endif + } else { + if (sr & (FRERR | PERR | ROVRN)) { /* errors */ + if (sr & ROVRN) + log(LOG_WARNING, "%s port %c: " + "receiver overrun\n", + sc->sc_dev.dv_xname, 'A' + port); + if (sr & FRERR) + log(LOG_WARNING, "%s port %c: " + "framing error\n", + sc->sc_dev.dv_xname, 'A' + port); + if (sr & PERR) + log(LOG_WARNING, "%s port %c: " + "parity error\n", + sc->sc_dev.dv_xname, 'A' + port); + /* clear error state */ + dart_write(sc, ptaddr + DART_CRA, ERRRESET); + } else { + /* no errors */ + (*linesw[tp->t_line].l_rint)(data,tp); + } + } + } +} + +void +dartxint(struct dartsoftc *sc, int port) +{ + struct tty *tp; + struct dart_info *dart; + + dart = &sc->sc_dart[port]; + tp = dart->tty; + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0) + goto out; + + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + dartstart(tp); + if (tp->t_state & TS_BUSY) { + /* do not disable transmitter, yet */ + return; + } + } +out: + + /* disable transmitter */ + sc->sc_sv_reg->sv_imr &= port == A_PORT ? ~ITXRDYA : ~ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); +} + +int +dartintr(void *arg) +{ + struct dartsoftc *sc = arg; + unsigned char isr, imr; + int port; + + /* read interrupt status register and mask with imr */ + isr = dart_read(sc, DART_ISR); + imr = sc->sc_sv_reg->sv_imr; + + if ((isr & imr) == 0) { + /* + * We got an interrupt on a disabled condition (such as TX + * ready change on a disabled port). This should not happen, + * but we have to claim the interrupt anyway. + */ +#ifdef DIAGNOSTIC + printf("%s: spurious interrupt, isr %x imr %x\n", + sc->sc_dev.dv_xname, isr, imr); +#endif + return (1); + } + isr &= imr; + + if (isr & IIPCHG) { + unsigned int ip, ipcr; + + ip = dart_read(sc, DART_IP); + ipcr = dart_read(sc, DART_IPCR); + dartmodemtrans(sc, ip, ipcr); + return (1); + } + + if (isr & (IRXRDYA | ITXRDYA)) + port = 0; +#ifdef DIAGNOSTIC + else if ((isr & (IRXRDYB | ITXRDYB)) == 0) { + printf("%s: spurious interrupt, isr %x\n", + sc->sc_dev.dv_xname, isr); + return (1); /* claim it anyway */ + } +#endif + else + port = 1; + + if (isr & (IRXRDYA | IRXRDYB)) + dartrint(sc, port); + if (isr & (ITXRDYA | ITXRDYB)) + dartxint(sc, port); + if (isr & (port == A_PORT ? IBRKA : IBRKB)) + dart_write(sc, port == A_PORT ? DART_CRA : DART_CRB, + BRKINTRESET); + + return (1); +} + +/* + * Console interface routines. +#ifdef USE_PROM_CONSOLE + * Since we select the actual console after all devices are attached, + * we can safely pick the appropriate softc and use its information. +#endif + */ + +#ifdef USE_PROM_CONSOLE +#define dart_cnread(reg) dart_read(sc, (reg)) +#define dart_cnwrite(reg, val) dart_write(sc, (reg), (val)) +#else +#define dart_cnread(reg) \ + *(volatile u_int8_t *)(DART_BASE + 3 + ((reg) << 2)) +#define dart_cnwrite(reg, val) \ + *(volatile u_int8_t *)(DART_BASE + 3 + ((reg) << 2)) = (val) +#endif + +void +dartcnprobe(struct consdev *cp) +{ + int maj; + + if (badaddr(DART_BASE, 4) != 0) + return; + +#ifdef USE_PROM_CONSOLE + /* do not attach as console if dart has been disabled */ + if (dart_cd.cd_ndevs == 0 || dart_cd.cd_devs[0] == NULL) + return; +#endif + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == dartopen) + break; + if (maj == nchrdev) + return; + + cp->cn_dev = makedev(maj, CONS_PORT); + cp->cn_pri = CN_NORMAL; +} + +void +dartcninit(cp) + struct consdev *cp; +{ +#ifndef USE_PROM_CONSOLE + dartcn_sv.sv_mr1[CONS_PORT] = PARDIS | RXRTS | CL8; + dartcn_sv.sv_mr2[CONS_PORT] = /* TXCTS | */ SB1; + dartcn_sv.sv_csr[CONS_PORT] = BD9600; + dartcn_sv.sv_cr[CONS_PORT] = TXEN | RXEN; + dartcn_sv.sv_opr = CONS_PORT == A_PORT ? (OPDTRA | OPRTSA) : + (OPDTRB | OPRTSB); + dartcn_sv.sv_imr = IIPCHG; + + dart_cnwrite(DART_CRA, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, MRRESET | TXDIS | RXDIS); + DELAY_CR; + + dart_cnwrite(DART_MR1A, dartcn_sv.sv_mr1[CONS_PORT]); + dart_cnwrite(DART_MR2A, dartcn_sv.sv_mr2[CONS_PORT]); + dart_cnwrite(DART_CSRA, dartcn_sv.sv_csr[CONS_PORT]); + dart_cnwrite(DART_CRA, dartcn_sv.sv_cr[CONS_PORT]); + + dart_cnwrite(DART_OPRS, dartcn_sv.sv_opr); + + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr); +#endif +} + +void +dartcnputc(dev_t dev, int c) +{ +#ifdef USE_PROM_CONSOLE + struct dartsoftc *sc; +#endif + int s; + u_int port; + bus_addr_t ptaddr; + +#ifdef USE_PROM_CONSOLE + sc = (struct dartsoftc *)dart_cd.cd_devs[0]; + port = DART_PORT(dev); +#else + port = CONS_PORT; +#endif + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + /* inhibit interrupts on the chip */ + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr & + (CONS_PORT == A_PORT ? ~ITXRDYA : ~ITXRDYB)); + /* make sure transmitter is enabled */ +#if 0 + DELAY_CR; +#endif + dart_cnwrite(ptaddr + DART_CRA, TXEN); + + while ((dart_cnread(ptaddr + DART_SRA) & TXRDY) == 0) + ; + dart_cnwrite(ptaddr + DART_TBA, c); + + /* wait for transmitter to empty */ + while ((dart_cnread(ptaddr + DART_SRA) & TXEMT) == 0) + ; + + /* restore the previous state */ + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr); +#if 0 + DELAY_CR; +#endif + dart_cnwrite(ptaddr + DART_CRA, dartcn_sv.sv_cr[0]); + + splx(s); +} + +int +dartcngetc(dev_t dev) +{ +#ifdef USE_PROM_CONSOLE + struct dartsoftc *sc; +#endif + unsigned char sr; /* status reg of port a/b */ + u_char c; /* received character */ + int s; + u_int port; + bus_addr_t ptaddr; + +#ifdef USE_PROM_CONSOLE + sc = (struct dartsoftc *)dart_cd.cd_devs[0]; + port = DART_PORT(dev); +#else + port = CONS_PORT; +#endif + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + /* enable receiver */ + dart_cnwrite(ptaddr + DART_CRA, RXEN); + + for (;;) { + /* read status reg */ + sr = dart_cnread(ptaddr + DART_SRA); + + /* receiver interrupt handler*/ + if (sr & RXRDY) { + /* read character from port */ + c = dart_cnread(ptaddr + DART_RBA); + + /* check break condition */ + if (sr & RBRK) { + /* clear break state */ + dart_cnwrite(ptaddr + DART_CRA, BRKINTRESET); + DELAY_CR; + dart_cnwrite(ptaddr + DART_CRA, ERRRESET); + break; + } + + if (sr & (FRERR | PERR | ROVRN)) { + /* clear error state */ + dart_cnwrite(ptaddr + DART_CRA, ERRRESET); + } else { + break; + } + } + } + splx(s); + + return ((int)c); +} |