141480Smckusick /* 241480Smckusick * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 341480Smckusick * All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*44762Skarels * @(#)dca.c 7.7 (Berkeley) 06/30/90 841480Smckusick */ 941480Smckusick 1041480Smckusick #include "dca.h" 1141480Smckusick #if NDCA > 0 1241480Smckusick /* 1341480Smckusick * 98626/98644/internal serial interface 1441480Smckusick */ 1541480Smckusick #include "param.h" 1641480Smckusick #include "systm.h" 1741480Smckusick #include "ioctl.h" 1841480Smckusick #include "tty.h" 1941480Smckusick #include "user.h" 2041480Smckusick #include "conf.h" 2141480Smckusick #include "file.h" 2241480Smckusick #include "uio.h" 2341480Smckusick #include "kernel.h" 2441480Smckusick #include "syslog.h" 2541480Smckusick 2641480Smckusick #include "device.h" 2741480Smckusick #include "dcareg.h" 2841480Smckusick #include "machine/cpu.h" 2941480Smckusick #include "machine/isr.h" 3041480Smckusick 3141480Smckusick int dcaprobe(); 3241480Smckusick struct driver dcadriver = { 3341480Smckusick dcaprobe, "dca", 3441480Smckusick }; 3541480Smckusick 3641480Smckusick int dcastart(), dcaparam(), dcaintr(); 3741480Smckusick int dcasoftCAR; 3841480Smckusick int dca_active; 3941480Smckusick int ndca = NDCA; 4041480Smckusick int dcaconsole = -1; 4141480Smckusick int dcadefaultrate = TTYDEF_SPEED; 4241480Smckusick struct dcadevice *dca_addr[NDCA]; 4341480Smckusick struct tty dca_tty[NDCA]; 4441480Smckusick struct isr dcaisr[NDCA]; 4541480Smckusick 4641480Smckusick struct speedtab dcaspeedtab[] = { 4741480Smckusick 0, 0, 4841480Smckusick 50, DCABRD(50), 4941480Smckusick 75, DCABRD(75), 5041480Smckusick 110, DCABRD(110), 5141480Smckusick 134, DCABRD(134), 5241480Smckusick 150, DCABRD(150), 5341480Smckusick 200, DCABRD(200), 5441480Smckusick 300, DCABRD(300), 5541480Smckusick 600, DCABRD(600), 5641480Smckusick 1200, DCABRD(1200), 5741480Smckusick 1800, DCABRD(1800), 5841480Smckusick 2400, DCABRD(2400), 5941480Smckusick 4800, DCABRD(4800), 6041480Smckusick 9600, DCABRD(9600), 6141480Smckusick 19200, DCABRD(19200), 6241480Smckusick 38400, DCABRD(38400), 6341480Smckusick -1, -1 6441480Smckusick }; 6541480Smckusick 6641480Smckusick extern struct tty *constty; 6741480Smckusick #ifdef KGDB 6841480Smckusick extern int kgdb_dev; 6941480Smckusick extern int kgdb_rate; 7041480Smckusick extern int kgdb_debug_init; 7141480Smckusick #endif 7241480Smckusick 7341480Smckusick #define UNIT(x) minor(x) 7441480Smckusick 7541480Smckusick dcaprobe(hd) 7641480Smckusick register struct hp_device *hd; 7741480Smckusick { 7841480Smckusick register struct dcadevice *dca; 7941480Smckusick register int unit; 8041480Smckusick 8141480Smckusick dca = (struct dcadevice *)hd->hp_addr; 8241480Smckusick if (dca->dca_irid != DCAID0 && 8341480Smckusick dca->dca_irid != DCAREMID0 && 8441480Smckusick dca->dca_irid != DCAID1 && 8541480Smckusick dca->dca_irid != DCAREMID1) 8641480Smckusick return (0); 8741480Smckusick unit = hd->hp_unit; 8841480Smckusick if (unit == dcaconsole) 8941480Smckusick DELAY(100000); 9041480Smckusick dca->dca_irid = 0xFF; 9141480Smckusick DELAY(100); 9241480Smckusick 9341480Smckusick hd->hp_ipl = DCAIPL(dca->dca_ic); 9441480Smckusick dcaisr[unit].isr_ipl = hd->hp_ipl; 9541480Smckusick dcaisr[unit].isr_arg = unit; 9641480Smckusick dcaisr[unit].isr_intr = dcaintr; 9741480Smckusick dca_addr[unit] = dca; 9841480Smckusick dca_active |= 1 << unit; 9941480Smckusick dcasoftCAR = hd->hp_flags; 10041480Smckusick isrlink(&dcaisr[unit]); 10141480Smckusick #ifdef KGDB 10241480Smckusick if (kgdb_dev == makedev(1, unit)) { 10341480Smckusick if (dcaconsole == unit) 10441480Smckusick kgdb_dev = -1; /* can't debug over console port */ 10541480Smckusick else { 10641480Smckusick (void) dcainit(unit); 10741480Smckusick dcaconsole = -2; /* XXX */ 10841480Smckusick if (kgdb_debug_init) { 10941480Smckusick printf("dca%d: kgdb waiting...", unit); 11041480Smckusick /* trap into kgdb */ 11141480Smckusick asm("trap #15;"); 11241480Smckusick printf("connected.\n"); 11341480Smckusick } else 11441480Smckusick printf("dca%d: kgdb enabled\n", unit); 11541480Smckusick } 11641480Smckusick } 11741480Smckusick #endif 11841480Smckusick dca->dca_ic = IC_IE; 11941480Smckusick /* 12041480Smckusick * Need to reset baud rate, etc. of next print so reset dcaconsole. 12141480Smckusick * Also make sure console is always "hardwired" 12241480Smckusick */ 12341480Smckusick if (unit == dcaconsole) { 12441480Smckusick dcaconsole = -1; 12541480Smckusick dcasoftCAR |= (1 << unit); 12641480Smckusick } 12741480Smckusick return (1); 12841480Smckusick } 12941480Smckusick 13041480Smckusick dcaopen(dev, flag) 13141480Smckusick dev_t dev; 13241480Smckusick { 13341480Smckusick register struct tty *tp; 13441480Smckusick register int unit; 135*44762Skarels int error = 0; 13641480Smckusick 13741480Smckusick unit = UNIT(dev); 13841480Smckusick if (unit >= NDCA || (dca_active & (1 << unit)) == 0) 13941480Smckusick return (ENXIO); 14041480Smckusick tp = &dca_tty[unit]; 14141480Smckusick tp->t_oproc = dcastart; 14241480Smckusick tp->t_param = dcaparam; 14341480Smckusick tp->t_dev = dev; 14441480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 14542950Smarc tp->t_state |= TS_WOPEN; 14641480Smckusick ttychars(tp); 14741480Smckusick tp->t_iflag = TTYDEF_IFLAG; 14841480Smckusick tp->t_oflag = TTYDEF_OFLAG; 14941480Smckusick tp->t_cflag = TTYDEF_CFLAG; 15041480Smckusick tp->t_lflag = TTYDEF_LFLAG; 15141480Smckusick tp->t_ispeed = tp->t_ospeed = dcadefaultrate; 15241480Smckusick dcaparam(tp, &tp->t_termios); 15341480Smckusick ttsetwater(tp); 15441480Smckusick } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 15541480Smckusick return (EBUSY); 15641480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET); 15741480Smckusick if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD)) 15841480Smckusick tp->t_state |= TS_CARR_ON; 15941480Smckusick (void) spltty(); 16044295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 16141480Smckusick (tp->t_state & TS_CARR_ON) == 0) { 16241480Smckusick tp->t_state |= TS_WOPEN; 16344295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 16444295Shibler ttopen, 0)) 16544295Shibler break; 16641480Smckusick } 16741480Smckusick (void) spl0(); 16844295Shibler if (error == 0) 16944295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp); 17044295Shibler return (error); 17141480Smckusick } 17241480Smckusick 17341480Smckusick /*ARGSUSED*/ 17441480Smckusick dcaclose(dev, flag) 17541480Smckusick dev_t dev; 17641480Smckusick { 17741480Smckusick register struct tty *tp; 17841480Smckusick register struct dcadevice *dca; 17941480Smckusick register int unit; 18041480Smckusick 18141480Smckusick unit = UNIT(dev); 18241480Smckusick dca = dca_addr[unit]; 18341480Smckusick tp = &dca_tty[unit]; 18441480Smckusick (*linesw[tp->t_line].l_close)(tp); 18541480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 18641480Smckusick #ifdef KGDB 18741480Smckusick /* do not disable interrupts if debugging */ 18841480Smckusick if (kgdb_dev != makedev(1, unit)) 18941480Smckusick #endif 19041480Smckusick dca->dca_ier = 0; 19141480Smckusick if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 19241480Smckusick (tp->t_state&TS_ISOPEN) == 0) 19341480Smckusick (void) dcamctl(dev, 0, DMSET); 19441480Smckusick ttyclose(tp); 19541480Smckusick return(0); 19641480Smckusick } 19741480Smckusick 19841480Smckusick dcaread(dev, uio, flag) 19941480Smckusick dev_t dev; 20041480Smckusick struct uio *uio; 20141480Smckusick { 20241480Smckusick register struct tty *tp = &dca_tty[UNIT(dev)]; 20341480Smckusick 20441480Smckusick return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 20541480Smckusick } 20641480Smckusick 20741480Smckusick dcawrite(dev, uio, flag) 20841480Smckusick dev_t dev; 20941480Smckusick struct uio *uio; 21041480Smckusick { 21141480Smckusick int unit = UNIT(dev); 21241480Smckusick register struct tty *tp = &dca_tty[unit]; 21341480Smckusick 21442353Smckusick /* 21542353Smckusick * (XXX) We disallow virtual consoles if the physical console is 21642353Smckusick * a serial port. This is in case there is a display attached that 21742353Smckusick * is not the console. In that situation we don't need/want the X 21842353Smckusick * server taking over the console. 21942353Smckusick */ 22042353Smckusick if (constty && unit == dcaconsole) 22142353Smckusick constty = NULL; 22241480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 22341480Smckusick } 22441480Smckusick 22541480Smckusick dcaintr(unit) 22641480Smckusick register int unit; 22741480Smckusick { 22841480Smckusick register struct dcadevice *dca; 22944318Shibler register u_char code; 23044318Shibler register struct tty *tp; 23141480Smckusick 23241480Smckusick dca = dca_addr[unit]; 23341480Smckusick if ((dca->dca_ic & IC_IR) == 0) 23441480Smckusick return(0); 23544318Shibler while (1) { 23644318Shibler code = dca->dca_iir; 23744318Shibler switch (code) { 23844318Shibler case IIR_NOPEND: 23944318Shibler return (1); 24044318Shibler case IIR_RXRDY: 24144318Shibler /* do time-critical read in-line */ 24244318Shibler tp = &dca_tty[unit]; 24344318Shibler code = dca->dca_data; 24444318Shibler if ((tp->t_state & TS_ISOPEN) == 0) { 24544318Shibler #ifdef KGDB 24644318Shibler if (kgdb_dev == makedev(1, unit) && 24744318Shibler code == '!') { 24844318Shibler printf("kgdb trap from dca%d\n", unit); 24944318Shibler /* trap into kgdb */ 25044318Shibler asm("trap #15;"); 25144318Shibler } 25244318Shibler #endif 25344318Shibler } else 25444318Shibler (*linesw[tp->t_line].l_rint)(code, tp); 25544318Shibler break; 25644318Shibler case IIR_TXRDY: 25744318Shibler tp = &dca_tty[unit]; 25844318Shibler tp->t_state &=~ (TS_BUSY|TS_FLUSH); 25944318Shibler if (tp->t_line) 26044318Shibler (*linesw[tp->t_line].l_start)(tp); 26144318Shibler else 26244318Shibler dcastart(tp); 26344318Shibler break; 26444318Shibler case IIR_RLS: 26541480Smckusick dcaeint(unit, dca); 26644318Shibler break; 26744318Shibler default: 26844318Shibler if (code & IIR_NOPEND) 26944318Shibler return (1); 27044318Shibler log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n", 27144318Shibler unit, code); 27244318Shibler /* fall through */ 27344318Shibler case IIR_MLSC: 27441480Smckusick dcamint(unit, dca); 27544318Shibler break; 27644318Shibler } 27741480Smckusick } 27841480Smckusick } 27941480Smckusick 28041480Smckusick dcaeint(unit, dca) 28141480Smckusick register int unit; 28241480Smckusick register struct dcadevice *dca; 28341480Smckusick { 28441480Smckusick register struct tty *tp; 28541480Smckusick register int stat, c; 28641480Smckusick 28741480Smckusick tp = &dca_tty[unit]; 28841480Smckusick stat = dca->dca_lsr; 28944318Shibler c = dca->dca_data; 29041480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 29141480Smckusick #ifdef KGDB 29241480Smckusick /* we don't care about parity errors */ 29341480Smckusick if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 29441480Smckusick kgdb_dev == makedev(1, unit) && c == '!') { 29541480Smckusick printf("kgdb trap from dca%d\n", unit); 29641480Smckusick /* trap into kgdb */ 29741480Smckusick asm("trap #15;"); 29841480Smckusick } 29941480Smckusick #endif 30041480Smckusick return; 30141480Smckusick } 30241480Smckusick if (stat & (LSR_BI | LSR_FE)) 30341480Smckusick c |= TTY_FE; 30441480Smckusick else if (stat & LSR_PE) 30541480Smckusick c |= TTY_PE; 30641480Smckusick else if (stat & LSR_OE) 30741480Smckusick log(LOG_WARNING, "dca%d: silo overflow\n", unit); 30841480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 30941480Smckusick } 31041480Smckusick 31141480Smckusick dcamint(unit, dca) 31241480Smckusick register int unit; 31341480Smckusick register struct dcadevice *dca; 31441480Smckusick { 31541480Smckusick register struct tty *tp; 31641480Smckusick register int stat; 31741480Smckusick 31841480Smckusick tp = &dca_tty[unit]; 31941480Smckusick stat = dca->dca_msr; 32044318Shibler if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) { 32141480Smckusick if (stat & MSR_DCD) 32244318Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 32341480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 32441480Smckusick dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 32544318Shibler } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 32644318Shibler (tp->t_flags & CRTSCTS)) { 32744318Shibler /* the line is up and we want to do rts/cts flow control */ 32844318Shibler if (stat & MSR_CTS) { 32944318Shibler tp->t_state &=~ TS_TTSTOP; 33044318Shibler ttstart(tp); 33144318Shibler } else 33244318Shibler tp->t_state |= TS_TTSTOP; 33341480Smckusick } 33441480Smckusick } 33541480Smckusick 33641480Smckusick dcaioctl(dev, cmd, data, flag) 33741480Smckusick dev_t dev; 33841480Smckusick caddr_t data; 33941480Smckusick { 34041480Smckusick register struct tty *tp; 34141480Smckusick register int unit = UNIT(dev); 34241480Smckusick register struct dcadevice *dca; 34341480Smckusick register int error; 34441480Smckusick 34541480Smckusick tp = &dca_tty[unit]; 34641480Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 34741480Smckusick if (error >= 0) 34841480Smckusick return (error); 34941480Smckusick error = ttioctl(tp, cmd, data, flag); 35041480Smckusick if (error >= 0) 35141480Smckusick return (error); 35241480Smckusick 35341480Smckusick dca = dca_addr[unit]; 35441480Smckusick switch (cmd) { 35541480Smckusick 35641480Smckusick case TIOCSBRK: 35741480Smckusick dca->dca_cfcr |= CFCR_SBREAK; 35841480Smckusick break; 35941480Smckusick 36041480Smckusick case TIOCCBRK: 36141480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 36241480Smckusick break; 36341480Smckusick 36441480Smckusick case TIOCSDTR: 36541480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 36641480Smckusick break; 36741480Smckusick 36841480Smckusick case TIOCCDTR: 36941480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 37041480Smckusick break; 37141480Smckusick 37241480Smckusick case TIOCMSET: 37341480Smckusick (void) dcamctl(dev, *(int *)data, DMSET); 37441480Smckusick break; 37541480Smckusick 37641480Smckusick case TIOCMBIS: 37741480Smckusick (void) dcamctl(dev, *(int *)data, DMBIS); 37841480Smckusick break; 37941480Smckusick 38041480Smckusick case TIOCMBIC: 38141480Smckusick (void) dcamctl(dev, *(int *)data, DMBIC); 38241480Smckusick break; 38341480Smckusick 38441480Smckusick case TIOCMGET: 38541480Smckusick *(int *)data = dcamctl(dev, 0, DMGET); 38641480Smckusick break; 38741480Smckusick 38841480Smckusick default: 38941480Smckusick return (ENOTTY); 39041480Smckusick } 39141480Smckusick return (0); 39241480Smckusick } 39341480Smckusick 39441480Smckusick dcaparam(tp, t) 39541480Smckusick register struct tty *tp; 39641480Smckusick register struct termios *t; 39741480Smckusick { 39841480Smckusick register struct dcadevice *dca; 39941480Smckusick register int cfcr, cflag = t->c_cflag; 40041480Smckusick int unit = UNIT(tp->t_dev); 40141480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 40241480Smckusick 40341480Smckusick /* check requested parameters */ 40441480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 40541480Smckusick return(EINVAL); 40641480Smckusick /* and copy to tty */ 40741480Smckusick tp->t_ispeed = t->c_ispeed; 40841480Smckusick tp->t_ospeed = t->c_ospeed; 40941480Smckusick tp->t_cflag = cflag; 41041480Smckusick 41141480Smckusick dca = dca_addr[unit]; 41241480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 41341480Smckusick if (ospeed == 0) { 41441480Smckusick (void) dcamctl(unit, 0, DMSET); /* hang up line */ 41541480Smckusick return(0); 41641480Smckusick } 41741480Smckusick dca->dca_cfcr |= CFCR_DLAB; 41841480Smckusick dca->dca_data = ospeed & 0xFF; 41941480Smckusick dca->dca_ier = ospeed >> 8; 42041480Smckusick switch (cflag&CSIZE) { 42141480Smckusick case CS5: 42241480Smckusick cfcr = CFCR_5BITS; break; 42341480Smckusick case CS6: 42441480Smckusick cfcr = CFCR_6BITS; break; 42541480Smckusick case CS7: 42641480Smckusick cfcr = CFCR_7BITS; break; 42741480Smckusick case CS8: 42841480Smckusick cfcr = CFCR_8BITS; break; 42941480Smckusick } 43041480Smckusick if (cflag&PARENB) { 43141480Smckusick cfcr |= CFCR_PENAB; 43241480Smckusick if ((cflag&PARODD) == 0) 43341480Smckusick cfcr |= CFCR_PEVEN; 43441480Smckusick } 43541480Smckusick if (cflag&CSTOPB) 43641480Smckusick cfcr |= CFCR_STOPB; 43741480Smckusick dca->dca_cfcr = cfcr; 43841480Smckusick return(0); 43941480Smckusick } 44041480Smckusick 44141480Smckusick dcastart(tp) 44241480Smckusick register struct tty *tp; 44341480Smckusick { 44441480Smckusick register struct dcadevice *dca; 44541480Smckusick int s, unit, c; 44641480Smckusick 44741480Smckusick unit = UNIT(tp->t_dev); 44841480Smckusick dca = dca_addr[unit]; 44941480Smckusick s = spltty(); 45044318Shibler if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 45141480Smckusick goto out; 45241480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 45341480Smckusick if (tp->t_state&TS_ASLEEP) { 45441480Smckusick tp->t_state &= ~TS_ASLEEP; 45541480Smckusick wakeup((caddr_t)&tp->t_outq); 45641480Smckusick } 45741480Smckusick if (tp->t_wsel) { 45841480Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 45941480Smckusick tp->t_wsel = 0; 46041480Smckusick tp->t_state &= ~TS_WCOLL; 46141480Smckusick } 46241480Smckusick } 46341480Smckusick if (tp->t_outq.c_cc == 0) 46441480Smckusick goto out; 46544318Shibler if (dca->dca_lsr & LSR_TXRDY) { 46644318Shibler c = getc(&tp->t_outq); 46744318Shibler tp->t_state |= TS_BUSY; 46844318Shibler dca->dca_data = c; 46944318Shibler } 47041480Smckusick out: 47141480Smckusick splx(s); 47241480Smckusick } 47341480Smckusick 47441480Smckusick /* 47541480Smckusick * Stop output on a line. 47641480Smckusick */ 47741480Smckusick /*ARGSUSED*/ 47841480Smckusick dcastop(tp, flag) 47941480Smckusick register struct tty *tp; 48041480Smckusick { 48141480Smckusick register int s; 48241480Smckusick 48341480Smckusick s = spltty(); 48441480Smckusick if (tp->t_state & TS_BUSY) { 48541480Smckusick if ((tp->t_state&TS_TTSTOP)==0) 48641480Smckusick tp->t_state |= TS_FLUSH; 48741480Smckusick } 48841480Smckusick splx(s); 48941480Smckusick } 49041480Smckusick 49141480Smckusick dcamctl(dev, bits, how) 49241480Smckusick dev_t dev; 49341480Smckusick int bits, how; 49441480Smckusick { 49541480Smckusick register struct dcadevice *dca; 49641480Smckusick register int unit; 49741480Smckusick int s; 49841480Smckusick 49941480Smckusick unit = UNIT(dev); 50041480Smckusick dca = dca_addr[unit]; 50141480Smckusick s = spltty(); 50241480Smckusick switch (how) { 50341480Smckusick 50441480Smckusick case DMSET: 50541480Smckusick dca->dca_mcr = bits; 50641480Smckusick break; 50741480Smckusick 50841480Smckusick case DMBIS: 50941480Smckusick dca->dca_mcr |= bits; 51041480Smckusick break; 51141480Smckusick 51241480Smckusick case DMBIC: 51341480Smckusick dca->dca_mcr &= ~bits; 51441480Smckusick break; 51541480Smckusick 51641480Smckusick case DMGET: 51741480Smckusick bits = dca->dca_msr; 51841480Smckusick break; 51941480Smckusick } 52041480Smckusick (void) splx(s); 52141480Smckusick return(bits); 52241480Smckusick } 52341480Smckusick 52441480Smckusick /* 52541480Smckusick * Following are all routines needed for DCA to act as console 52641480Smckusick */ 52741480Smckusick #include "machine/cons.h" 52841480Smckusick 52941480Smckusick dcacnprobe(cp) 53041480Smckusick struct consdev *cp; 53141480Smckusick { 53241480Smckusick int unit, i; 53341480Smckusick extern int dcaopen(); 53441480Smckusick 53541480Smckusick /* XXX: ick */ 53641480Smckusick unit = CONUNIT; 53741480Smckusick dca_addr[CONUNIT] = CONADDR; 53841480Smckusick 53941480Smckusick /* make sure hardware exists */ 54041480Smckusick if (badaddr((short *)dca_addr[unit])) { 54141480Smckusick cp->cn_pri = CN_DEAD; 54241480Smckusick return; 54341480Smckusick } 54441480Smckusick 54541480Smckusick /* locate the major number */ 54641480Smckusick for (i = 0; i < nchrdev; i++) 54741480Smckusick if (cdevsw[i].d_open == dcaopen) 54841480Smckusick break; 54941480Smckusick 55041480Smckusick /* initialize required fields */ 55141480Smckusick cp->cn_dev = makedev(i, unit); 55241480Smckusick cp->cn_tp = &dca_tty[unit]; 55341480Smckusick switch (dca_addr[unit]->dca_irid) { 55441480Smckusick case DCAID0: 55541480Smckusick case DCAID1: 55641480Smckusick cp->cn_pri = CN_NORMAL; 55741480Smckusick break; 55841480Smckusick case DCAREMID0: 55941480Smckusick case DCAREMID1: 56041480Smckusick cp->cn_pri = CN_REMOTE; 56141480Smckusick break; 56241480Smckusick default: 56341480Smckusick cp->cn_pri = CN_DEAD; 56441480Smckusick break; 56541480Smckusick } 56641480Smckusick } 56741480Smckusick 56841480Smckusick dcacninit(cp) 56941480Smckusick struct consdev *cp; 57041480Smckusick { 57141480Smckusick int unit = UNIT(cp->cn_dev); 57241480Smckusick 57341480Smckusick dcainit(unit); 57441480Smckusick dcaconsole = unit; 57541480Smckusick } 57641480Smckusick 57741480Smckusick dcainit(unit) 57841480Smckusick int unit; 57941480Smckusick { 58041480Smckusick register struct dcadevice *dca; 58141480Smckusick int s, rate; 58241480Smckusick short stat; 58341480Smckusick 58441480Smckusick #ifdef lint 58541480Smckusick stat = unit; if (stat) return; 58641480Smckusick #endif 58741480Smckusick dca = dca_addr[unit]; 58841480Smckusick s = splhigh(); 58941480Smckusick dca->dca_irid = 0xFF; 59041480Smckusick DELAY(100); 59141480Smckusick dca->dca_ic = IC_IE; 59241480Smckusick dca->dca_cfcr = CFCR_DLAB; 59341480Smckusick rate = ttspeedtab(dcadefaultrate, dcaspeedtab); 59441480Smckusick dca->dca_data = rate & 0xFF; 59541480Smckusick dca->dca_ier = rate >> 8; 59641480Smckusick dca->dca_cfcr = CFCR_8BITS; 59741480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 59841480Smckusick stat = dca->dca_iir; 59941480Smckusick splx(s); 60041480Smckusick } 60141480Smckusick 60241480Smckusick dcacngetc(dev) 60341480Smckusick { 60441480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 60541480Smckusick short stat; 60641480Smckusick int c, s; 60741480Smckusick 60841480Smckusick #ifdef lint 60941480Smckusick stat = dev; if (stat) return(0); 61041480Smckusick #endif 61141480Smckusick s = splhigh(); 61241480Smckusick while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 61341480Smckusick ; 61441480Smckusick c = dca->dca_data; 61541480Smckusick stat = dca->dca_iir; 61641480Smckusick splx(s); 61741480Smckusick return(c); 61841480Smckusick } 61941480Smckusick 62041480Smckusick /* 62141480Smckusick * Console kernel output character routine. 62241480Smckusick */ 62341480Smckusick dcacnputc(dev, c) 62441480Smckusick dev_t dev; 62541480Smckusick register int c; 62641480Smckusick { 62741480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 62841480Smckusick register int timo; 62941480Smckusick short stat; 63041480Smckusick int s = splhigh(); 63141480Smckusick 63241480Smckusick #ifdef lint 63341480Smckusick stat = dev; if (stat) return; 63441480Smckusick #endif 63541480Smckusick if (dcaconsole == -1) { 63641480Smckusick (void) dcainit(UNIT(dev)); 63741480Smckusick dcaconsole = UNIT(dev); 63841480Smckusick } 63941480Smckusick /* wait for any pending transmission to finish */ 64041480Smckusick timo = 50000; 64141480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 64241480Smckusick ; 64341480Smckusick dca->dca_data = c; 64441480Smckusick /* wait for this transmission to complete */ 64541480Smckusick timo = 1500000; 64641480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 64741480Smckusick ; 64841480Smckusick /* clear any interrupts generated by this transmission */ 64941480Smckusick stat = dca->dca_iir; 65041480Smckusick splx(s); 65141480Smckusick } 65241480Smckusick #endif 653