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*44295Shibler * @(#)dca.c 7.5 (Berkeley) 06/26/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; 13542353Smckusick int error; 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(); 160*44295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 16141480Smckusick (tp->t_state & TS_CARR_ON) == 0) { 16241480Smckusick tp->t_state |= TS_WOPEN; 163*44295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 164*44295Shibler ttopen, 0)) 165*44295Shibler break; 16641480Smckusick } 16741480Smckusick (void) spl0(); 168*44295Shibler if (error == 0) 169*44295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp); 170*44295Shibler 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; 22941480Smckusick register int code; 23041480Smckusick 23141480Smckusick dca = dca_addr[unit]; 23241480Smckusick if ((dca->dca_ic & IC_IR) == 0) 23341480Smckusick return(0); 23441480Smckusick while (((code = dca->dca_iir) & IIR_NOPEND) == 0) { 23541480Smckusick code &= IIR_IMASK; 23641480Smckusick if (code == IIR_RLS) 23741480Smckusick dcaeint(unit, dca); 23841480Smckusick else if (code == IIR_RXRDY) 23941480Smckusick dcarint(unit, dca); 24041480Smckusick else if (code == IIR_TXRDY) 24141480Smckusick dcaxint(unit, dca); 24241480Smckusick else 24341480Smckusick dcamint(unit, dca); 24441480Smckusick } 24541480Smckusick return(1); 24641480Smckusick } 24741480Smckusick 24841480Smckusick dcaeint(unit, dca) 24941480Smckusick register int unit; 25041480Smckusick register struct dcadevice *dca; 25141480Smckusick { 25241480Smckusick register struct tty *tp; 25341480Smckusick register int stat, c; 25441480Smckusick 25541480Smckusick tp = &dca_tty[unit]; 25641480Smckusick stat = dca->dca_lsr; 25741480Smckusick c = dca->dca_data & 0xff; 25841480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 25941480Smckusick #ifdef KGDB 26041480Smckusick /* we don't care about parity errors */ 26141480Smckusick if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 26241480Smckusick kgdb_dev == makedev(1, unit) && c == '!') { 26341480Smckusick printf("kgdb trap from dca%d\n", unit); 26441480Smckusick /* trap into kgdb */ 26541480Smckusick asm("trap #15;"); 26641480Smckusick } 26741480Smckusick #endif 26841480Smckusick return; 26941480Smckusick } 27041480Smckusick if (stat & (LSR_BI | LSR_FE)) 27141480Smckusick c |= TTY_FE; 27241480Smckusick else if (stat & LSR_PE) 27341480Smckusick c |= TTY_PE; 27441480Smckusick else if (stat & LSR_OE) 27541480Smckusick log(LOG_WARNING, "dca%d: silo overflow\n", unit); 27641480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 27741480Smckusick } 27841480Smckusick 27941480Smckusick dcarint(unit, dca) 28041480Smckusick int unit; 28141480Smckusick register struct dcadevice *dca; 28241480Smckusick { 28341480Smckusick register struct tty *tp; 28441480Smckusick register int c; 28541480Smckusick 28641480Smckusick tp = &dca_tty[unit]; 28741480Smckusick c = dca->dca_data; 28841480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 28941480Smckusick #ifdef KGDB 29041480Smckusick if (kgdb_dev == makedev(1, unit) && c == '!') { 29141480Smckusick printf("kgdb trap from dca%d\n", unit); 29241480Smckusick /* trap into kgdb */ 29341480Smckusick asm("trap #15;"); 29441480Smckusick } 29541480Smckusick #endif 29641480Smckusick return; 29741480Smckusick } 29841480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 29941480Smckusick } 30041480Smckusick 30141480Smckusick /*ARGSUSED*/ 30241480Smckusick dcaxint(unit, dca) 30341480Smckusick int unit; 30441480Smckusick struct dcadevice *dca; 30541480Smckusick { 30641480Smckusick register struct tty *tp; 30741480Smckusick 30841480Smckusick tp = &dca_tty[unit]; 30941480Smckusick tp->t_state &= ~TS_BUSY; 31041480Smckusick if (tp->t_state & TS_FLUSH) 31141480Smckusick tp->t_state &= ~TS_FLUSH; 31241480Smckusick if (tp->t_line) 31341480Smckusick (*linesw[tp->t_line].l_start)(tp); 31441480Smckusick else 31541480Smckusick dcastart(tp); 31641480Smckusick } 31741480Smckusick 31841480Smckusick dcamint(unit, dca) 31941480Smckusick register int unit; 32041480Smckusick register struct dcadevice *dca; 32141480Smckusick { 32241480Smckusick register struct tty *tp; 32341480Smckusick register int stat; 32441480Smckusick 32541480Smckusick tp = &dca_tty[unit]; 32641480Smckusick stat = dca->dca_msr; 32741480Smckusick if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) { 32841480Smckusick if (stat & MSR_DCD) 32941480Smckusick (void) (*linesw[tp->t_line].l_modem)(tp, 1); 33041480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 33141480Smckusick dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 33241480Smckusick } 33341480Smckusick } 33441480Smckusick 33541480Smckusick dcaioctl(dev, cmd, data, flag) 33641480Smckusick dev_t dev; 33741480Smckusick caddr_t data; 33841480Smckusick { 33941480Smckusick register struct tty *tp; 34041480Smckusick register int unit = UNIT(dev); 34141480Smckusick register struct dcadevice *dca; 34241480Smckusick register int error; 34341480Smckusick 34441480Smckusick tp = &dca_tty[unit]; 34541480Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 34641480Smckusick if (error >= 0) 34741480Smckusick return (error); 34841480Smckusick error = ttioctl(tp, cmd, data, flag); 34941480Smckusick if (error >= 0) 35041480Smckusick return (error); 35141480Smckusick 35241480Smckusick dca = dca_addr[unit]; 35341480Smckusick switch (cmd) { 35441480Smckusick 35541480Smckusick case TIOCSBRK: 35641480Smckusick dca->dca_cfcr |= CFCR_SBREAK; 35741480Smckusick break; 35841480Smckusick 35941480Smckusick case TIOCCBRK: 36041480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 36141480Smckusick break; 36241480Smckusick 36341480Smckusick case TIOCSDTR: 36441480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 36541480Smckusick break; 36641480Smckusick 36741480Smckusick case TIOCCDTR: 36841480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 36941480Smckusick break; 37041480Smckusick 37141480Smckusick case TIOCMSET: 37241480Smckusick (void) dcamctl(dev, *(int *)data, DMSET); 37341480Smckusick break; 37441480Smckusick 37541480Smckusick case TIOCMBIS: 37641480Smckusick (void) dcamctl(dev, *(int *)data, DMBIS); 37741480Smckusick break; 37841480Smckusick 37941480Smckusick case TIOCMBIC: 38041480Smckusick (void) dcamctl(dev, *(int *)data, DMBIC); 38141480Smckusick break; 38241480Smckusick 38341480Smckusick case TIOCMGET: 38441480Smckusick *(int *)data = dcamctl(dev, 0, DMGET); 38541480Smckusick break; 38641480Smckusick 38741480Smckusick default: 38841480Smckusick return (ENOTTY); 38941480Smckusick } 39041480Smckusick return (0); 39141480Smckusick } 39241480Smckusick 39341480Smckusick dcaparam(tp, t) 39441480Smckusick register struct tty *tp; 39541480Smckusick register struct termios *t; 39641480Smckusick { 39741480Smckusick register struct dcadevice *dca; 39841480Smckusick register int cfcr, cflag = t->c_cflag; 39941480Smckusick int unit = UNIT(tp->t_dev); 40041480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 40141480Smckusick 40241480Smckusick /* check requested parameters */ 40341480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 40441480Smckusick return(EINVAL); 40541480Smckusick /* and copy to tty */ 40641480Smckusick tp->t_ispeed = t->c_ispeed; 40741480Smckusick tp->t_ospeed = t->c_ospeed; 40841480Smckusick tp->t_cflag = cflag; 40941480Smckusick 41041480Smckusick dca = dca_addr[unit]; 41141480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 41241480Smckusick if (ospeed == 0) { 41341480Smckusick (void) dcamctl(unit, 0, DMSET); /* hang up line */ 41441480Smckusick return(0); 41541480Smckusick } 41641480Smckusick dca->dca_cfcr |= CFCR_DLAB; 41741480Smckusick dca->dca_data = ospeed & 0xFF; 41841480Smckusick dca->dca_ier = ospeed >> 8; 41941480Smckusick switch (cflag&CSIZE) { 42041480Smckusick case CS5: 42141480Smckusick cfcr = CFCR_5BITS; break; 42241480Smckusick case CS6: 42341480Smckusick cfcr = CFCR_6BITS; break; 42441480Smckusick case CS7: 42541480Smckusick cfcr = CFCR_7BITS; break; 42641480Smckusick case CS8: 42741480Smckusick cfcr = CFCR_8BITS; break; 42841480Smckusick } 42941480Smckusick if (cflag&PARENB) { 43041480Smckusick cfcr |= CFCR_PENAB; 43141480Smckusick if ((cflag&PARODD) == 0) 43241480Smckusick cfcr |= CFCR_PEVEN; 43341480Smckusick } 43441480Smckusick if (cflag&CSTOPB) 43541480Smckusick cfcr |= CFCR_STOPB; 43641480Smckusick dca->dca_cfcr = cfcr; 43741480Smckusick return(0); 43841480Smckusick } 43941480Smckusick 44041480Smckusick dcastart(tp) 44141480Smckusick register struct tty *tp; 44241480Smckusick { 44341480Smckusick register struct dcadevice *dca; 44441480Smckusick int s, unit, c; 44541480Smckusick 44641480Smckusick unit = UNIT(tp->t_dev); 44741480Smckusick dca = dca_addr[unit]; 44841480Smckusick s = spltty(); 44941480Smckusick if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 45041480Smckusick goto out; 45141480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 45241480Smckusick if (tp->t_state&TS_ASLEEP) { 45341480Smckusick tp->t_state &= ~TS_ASLEEP; 45441480Smckusick wakeup((caddr_t)&tp->t_outq); 45541480Smckusick } 45641480Smckusick if (tp->t_wsel) { 45741480Smckusick selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 45841480Smckusick tp->t_wsel = 0; 45941480Smckusick tp->t_state &= ~TS_WCOLL; 46041480Smckusick } 46141480Smckusick } 46241480Smckusick if (tp->t_outq.c_cc == 0) 46341480Smckusick goto out; 46441480Smckusick c = getc(&tp->t_outq); 46541480Smckusick tp->t_state |= TS_BUSY; 46641480Smckusick dca->dca_data = c; 46741480Smckusick out: 46841480Smckusick splx(s); 46941480Smckusick } 47041480Smckusick 47141480Smckusick /* 47241480Smckusick * Stop output on a line. 47341480Smckusick */ 47441480Smckusick /*ARGSUSED*/ 47541480Smckusick dcastop(tp, flag) 47641480Smckusick register struct tty *tp; 47741480Smckusick { 47841480Smckusick register int s; 47941480Smckusick 48041480Smckusick s = spltty(); 48141480Smckusick if (tp->t_state & TS_BUSY) { 48241480Smckusick if ((tp->t_state&TS_TTSTOP)==0) 48341480Smckusick tp->t_state |= TS_FLUSH; 48441480Smckusick } 48541480Smckusick splx(s); 48641480Smckusick } 48741480Smckusick 48841480Smckusick dcamctl(dev, bits, how) 48941480Smckusick dev_t dev; 49041480Smckusick int bits, how; 49141480Smckusick { 49241480Smckusick register struct dcadevice *dca; 49341480Smckusick register int unit; 49441480Smckusick int s; 49541480Smckusick 49641480Smckusick unit = UNIT(dev); 49741480Smckusick dca = dca_addr[unit]; 49841480Smckusick s = spltty(); 49941480Smckusick switch (how) { 50041480Smckusick 50141480Smckusick case DMSET: 50241480Smckusick dca->dca_mcr = bits; 50341480Smckusick break; 50441480Smckusick 50541480Smckusick case DMBIS: 50641480Smckusick dca->dca_mcr |= bits; 50741480Smckusick break; 50841480Smckusick 50941480Smckusick case DMBIC: 51041480Smckusick dca->dca_mcr &= ~bits; 51141480Smckusick break; 51241480Smckusick 51341480Smckusick case DMGET: 51441480Smckusick bits = dca->dca_msr; 51541480Smckusick break; 51641480Smckusick } 51741480Smckusick (void) splx(s); 51841480Smckusick return(bits); 51941480Smckusick } 52041480Smckusick 52141480Smckusick /* 52241480Smckusick * Following are all routines needed for DCA to act as console 52341480Smckusick */ 52441480Smckusick #include "machine/cons.h" 52541480Smckusick 52641480Smckusick dcacnprobe(cp) 52741480Smckusick struct consdev *cp; 52841480Smckusick { 52941480Smckusick int unit, i; 53041480Smckusick extern int dcaopen(); 53141480Smckusick 53241480Smckusick /* XXX: ick */ 53341480Smckusick unit = CONUNIT; 53441480Smckusick dca_addr[CONUNIT] = CONADDR; 53541480Smckusick 53641480Smckusick /* make sure hardware exists */ 53741480Smckusick if (badaddr((short *)dca_addr[unit])) { 53841480Smckusick cp->cn_pri = CN_DEAD; 53941480Smckusick return; 54041480Smckusick } 54141480Smckusick 54241480Smckusick /* locate the major number */ 54341480Smckusick for (i = 0; i < nchrdev; i++) 54441480Smckusick if (cdevsw[i].d_open == dcaopen) 54541480Smckusick break; 54641480Smckusick 54741480Smckusick /* initialize required fields */ 54841480Smckusick cp->cn_dev = makedev(i, unit); 54941480Smckusick cp->cn_tp = &dca_tty[unit]; 55041480Smckusick switch (dca_addr[unit]->dca_irid) { 55141480Smckusick case DCAID0: 55241480Smckusick case DCAID1: 55341480Smckusick cp->cn_pri = CN_NORMAL; 55441480Smckusick break; 55541480Smckusick case DCAREMID0: 55641480Smckusick case DCAREMID1: 55741480Smckusick cp->cn_pri = CN_REMOTE; 55841480Smckusick break; 55941480Smckusick default: 56041480Smckusick cp->cn_pri = CN_DEAD; 56141480Smckusick break; 56241480Smckusick } 56341480Smckusick } 56441480Smckusick 56541480Smckusick dcacninit(cp) 56641480Smckusick struct consdev *cp; 56741480Smckusick { 56841480Smckusick int unit = UNIT(cp->cn_dev); 56941480Smckusick 57041480Smckusick dcainit(unit); 57141480Smckusick dcaconsole = unit; 57241480Smckusick } 57341480Smckusick 57441480Smckusick dcainit(unit) 57541480Smckusick int unit; 57641480Smckusick { 57741480Smckusick register struct dcadevice *dca; 57841480Smckusick int s, rate; 57941480Smckusick short stat; 58041480Smckusick 58141480Smckusick #ifdef lint 58241480Smckusick stat = unit; if (stat) return; 58341480Smckusick #endif 58441480Smckusick dca = dca_addr[unit]; 58541480Smckusick s = splhigh(); 58641480Smckusick dca->dca_irid = 0xFF; 58741480Smckusick DELAY(100); 58841480Smckusick dca->dca_ic = IC_IE; 58941480Smckusick dca->dca_cfcr = CFCR_DLAB; 59041480Smckusick rate = ttspeedtab(dcadefaultrate, dcaspeedtab); 59141480Smckusick dca->dca_data = rate & 0xFF; 59241480Smckusick dca->dca_ier = rate >> 8; 59341480Smckusick dca->dca_cfcr = CFCR_8BITS; 59441480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 59541480Smckusick stat = dca->dca_iir; 59641480Smckusick splx(s); 59741480Smckusick } 59841480Smckusick 59941480Smckusick dcacngetc(dev) 60041480Smckusick { 60141480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 60241480Smckusick short stat; 60341480Smckusick int c, s; 60441480Smckusick 60541480Smckusick #ifdef lint 60641480Smckusick stat = dev; if (stat) return(0); 60741480Smckusick #endif 60841480Smckusick s = splhigh(); 60941480Smckusick while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 61041480Smckusick ; 61141480Smckusick c = dca->dca_data; 61241480Smckusick stat = dca->dca_iir; 61341480Smckusick splx(s); 61441480Smckusick return(c); 61541480Smckusick } 61641480Smckusick 61741480Smckusick /* 61841480Smckusick * Console kernel output character routine. 61941480Smckusick */ 62041480Smckusick dcacnputc(dev, c) 62141480Smckusick dev_t dev; 62241480Smckusick register int c; 62341480Smckusick { 62441480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 62541480Smckusick register int timo; 62641480Smckusick short stat; 62741480Smckusick int s = splhigh(); 62841480Smckusick 62941480Smckusick #ifdef lint 63041480Smckusick stat = dev; if (stat) return; 63141480Smckusick #endif 63241480Smckusick if (dcaconsole == -1) { 63341480Smckusick (void) dcainit(UNIT(dev)); 63441480Smckusick dcaconsole = UNIT(dev); 63541480Smckusick } 63641480Smckusick /* wait for any pending transmission to finish */ 63741480Smckusick timo = 50000; 63841480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 63941480Smckusick ; 64041480Smckusick dca->dca_data = c; 64141480Smckusick /* wait for this transmission to complete */ 64241480Smckusick timo = 1500000; 64341480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 64441480Smckusick ; 64541480Smckusick /* clear any interrupts generated by this transmission */ 64641480Smckusick stat = dca->dca_iir; 64741480Smckusick splx(s); 64841480Smckusick } 64941480Smckusick #endif 650