141480Smckusick /* 2*63146Sbostic * Copyright (c) 1982, 1986, 1990, 1993 3*63146Sbostic * The Regents of the University of California. All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*63146Sbostic * @(#)dca.c 8.1 (Berkeley) 06/10/93 841480Smckusick */ 941480Smckusick 1041480Smckusick #include "dca.h" 1141480Smckusick #if NDCA > 0 1241480Smckusick /* 1353923Shibler * Driver for National Semiconductor INS8250/NS16550AF/WD16C552 UARTs. 1453923Shibler * Includes: 1553923Shibler * 98626/98644/internal serial interface on hp300/hp400 1653923Shibler * internal serial ports on hp700 1753923Shibler * 1853923Shibler * N.B. On the hp700, there is a "secret bit" with undocumented behavior. 1953923Shibler * The third bit of the Modem Control Register (MCR_IEN == 0x08) must be 2053923Shibler * set to enable interrupts. 2141480Smckusick */ 2256504Sbostic #include <sys/param.h> 2356504Sbostic #include <sys/systm.h> 2456504Sbostic #include <sys/ioctl.h> 2556504Sbostic #include <sys/proc.h> 2656504Sbostic #include <sys/tty.h> 2756504Sbostic #include <sys/conf.h> 2856504Sbostic #include <sys/file.h> 2956504Sbostic #include <sys/uio.h> 3056504Sbostic #include <sys/kernel.h> 3156504Sbostic #include <sys/syslog.h> 3241480Smckusick 3356504Sbostic #include <hp/dev/device.h> 3456504Sbostic #include <hp/dev/dcareg.h> 3553923Shibler 3656504Sbostic #include <machine/cpu.h> 3753923Shibler #ifdef hp300 3856504Sbostic #include <hp300/hp300/isr.h> 3953923Shibler #endif 4053923Shibler #ifdef hp700 4156504Sbostic #include <machine/asp.h> 4253923Shibler #endif 4341480Smckusick 4441480Smckusick int dcaprobe(); 4541480Smckusick struct driver dcadriver = { 4641480Smckusick dcaprobe, "dca", 4741480Smckusick }; 4841480Smckusick 4952389Smckusick void dcastart(); 5052389Smckusick int dcaparam(), dcaintr(); 5141480Smckusick int dcasoftCAR; 5241480Smckusick int dca_active; 5349300Shibler int dca_hasfifo; 5441480Smckusick int ndca = NDCA; 5549130Skarels #ifdef DCACONSOLE 5649130Skarels int dcaconsole = DCACONSOLE; 5749130Skarels #else 5841480Smckusick int dcaconsole = -1; 5949130Skarels #endif 6049130Skarels int dcaconsinit; 6141480Smckusick int dcadefaultrate = TTYDEF_SPEED; 6249130Skarels int dcamajor; 6341480Smckusick struct dcadevice *dca_addr[NDCA]; 6441480Smckusick struct tty dca_tty[NDCA]; 6553923Shibler #ifdef hp300 6641480Smckusick struct isr dcaisr[NDCA]; 6757308Shibler int dcafastservice; 6853923Shibler #endif 6957308Shibler int dcaoflows[NDCA]; 7041480Smckusick 7141480Smckusick struct speedtab dcaspeedtab[] = { 7241480Smckusick 0, 0, 7341480Smckusick 50, DCABRD(50), 7441480Smckusick 75, DCABRD(75), 7541480Smckusick 110, DCABRD(110), 7641480Smckusick 134, DCABRD(134), 7741480Smckusick 150, DCABRD(150), 7841480Smckusick 200, DCABRD(200), 7941480Smckusick 300, DCABRD(300), 8041480Smckusick 600, DCABRD(600), 8141480Smckusick 1200, DCABRD(1200), 8241480Smckusick 1800, DCABRD(1800), 8341480Smckusick 2400, DCABRD(2400), 8441480Smckusick 4800, DCABRD(4800), 8541480Smckusick 9600, DCABRD(9600), 8641480Smckusick 19200, DCABRD(19200), 8741480Smckusick 38400, DCABRD(38400), 8841480Smckusick -1, -1 8941480Smckusick }; 9041480Smckusick 9141480Smckusick #ifdef KGDB 9256504Sbostic #include <machine/remote-sl.h> 9349130Skarels 9450219Skarels extern dev_t kgdb_dev; 9541480Smckusick extern int kgdb_rate; 9641480Smckusick extern int kgdb_debug_init; 9741480Smckusick #endif 9841480Smckusick 9941480Smckusick #define UNIT(x) minor(x) 10041480Smckusick 10149300Shibler #ifdef DEBUG 10249300Shibler long fifoin[17]; 10349300Shibler long fifoout[17]; 10449300Shibler long dcaintrcount[16]; 10549300Shibler long dcamintcount[16]; 10649300Shibler #endif 10749300Shibler 10841480Smckusick dcaprobe(hd) 10941480Smckusick register struct hp_device *hd; 11041480Smckusick { 11141480Smckusick register struct dcadevice *dca; 11241480Smckusick register int unit; 11341480Smckusick 11441480Smckusick dca = (struct dcadevice *)hd->hp_addr; 11553923Shibler #ifdef hp300 11653923Shibler if (dca->dca_id != DCAID0 && 11753923Shibler dca->dca_id != DCAREMID0 && 11853923Shibler dca->dca_id != DCAID1 && 11953923Shibler dca->dca_id != DCAREMID1) 12041480Smckusick return (0); 12153923Shibler #endif 12241480Smckusick unit = hd->hp_unit; 12341480Smckusick if (unit == dcaconsole) 12441480Smckusick DELAY(100000); 12553923Shibler #ifdef hp300 12653923Shibler dca->dca_reset = 0xFF; 12741480Smckusick DELAY(100); 12853923Shibler #endif 12941480Smckusick 13049300Shibler /* look for a NS 16550AF UART with FIFOs */ 13149300Shibler dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14; 13249300Shibler DELAY(100); 13349300Shibler if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK) 13449300Shibler dca_hasfifo |= 1 << unit; 13549300Shibler 13653923Shibler dca_addr[unit] = dca; 13753923Shibler #ifdef hp300 13841480Smckusick hd->hp_ipl = DCAIPL(dca->dca_ic); 13941480Smckusick dcaisr[unit].isr_ipl = hd->hp_ipl; 14041480Smckusick dcaisr[unit].isr_arg = unit; 14141480Smckusick dcaisr[unit].isr_intr = dcaintr; 14253923Shibler isrlink(&dcaisr[unit]); 14353923Shibler #endif 14441480Smckusick dca_active |= 1 << unit; 14553923Shibler if (hd->hp_flags) 14653923Shibler dcasoftCAR |= (1 << unit); 14741480Smckusick #ifdef KGDB 14849130Skarels if (kgdb_dev == makedev(dcamajor, unit)) { 14941480Smckusick if (dcaconsole == unit) 15050219Skarels kgdb_dev = NODEV; /* can't debug over console port */ 15141480Smckusick else { 15249130Skarels (void) dcainit(unit, kgdb_rate); 15350219Skarels dcaconsinit = 1; /* don't re-init in dcaputc */ 15441480Smckusick if (kgdb_debug_init) { 15549130Skarels /* 15649130Skarels * Print prefix of device name, 15749130Skarels * let kgdb_connect print the rest. 15849130Skarels */ 15949130Skarels printf("dca%d: ", unit); 16049130Skarels kgdb_connect(1); 16141480Smckusick } else 16241480Smckusick printf("dca%d: kgdb enabled\n", unit); 16341480Smckusick } 16441480Smckusick } 16541480Smckusick #endif 16653923Shibler #ifdef hp300 16741480Smckusick dca->dca_ic = IC_IE; 16853923Shibler #endif 16941480Smckusick /* 17049130Skarels * Need to reset baud rate, etc. of next print so reset dcaconsinit. 17149130Skarels * Also make sure console is always "hardwired." 17241480Smckusick */ 17341480Smckusick if (unit == dcaconsole) { 17449130Skarels dcaconsinit = 0; 17541480Smckusick dcasoftCAR |= (1 << unit); 17641480Smckusick } 17741480Smckusick return (1); 17841480Smckusick } 17941480Smckusick 18049130Skarels /* ARGSUSED */ 18149130Skarels #ifdef __STDC__ 18249130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p) 18349130Skarels #else 18449130Skarels dcaopen(dev, flag, mode, p) 18541480Smckusick dev_t dev; 18649130Skarels int flag, mode; 18749130Skarels struct proc *p; 18849130Skarels #endif 18941480Smckusick { 19041480Smckusick register struct tty *tp; 19141480Smckusick register int unit; 19244762Skarels int error = 0; 19341480Smckusick 19441480Smckusick unit = UNIT(dev); 19541480Smckusick if (unit >= NDCA || (dca_active & (1 << unit)) == 0) 19641480Smckusick return (ENXIO); 19741480Smckusick tp = &dca_tty[unit]; 19841480Smckusick tp->t_oproc = dcastart; 19941480Smckusick tp->t_param = dcaparam; 20041480Smckusick tp->t_dev = dev; 20141480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 20242950Smarc tp->t_state |= TS_WOPEN; 20341480Smckusick ttychars(tp); 20449130Skarels if (tp->t_ispeed == 0) { 20549130Skarels tp->t_iflag = TTYDEF_IFLAG; 20649130Skarels tp->t_oflag = TTYDEF_OFLAG; 20749130Skarels tp->t_cflag = TTYDEF_CFLAG; 20849130Skarels tp->t_lflag = TTYDEF_LFLAG; 20949130Skarels tp->t_ispeed = tp->t_ospeed = dcadefaultrate; 21049130Skarels } 21141480Smckusick dcaparam(tp, &tp->t_termios); 21241480Smckusick ttsetwater(tp); 21349130Skarels } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 21441480Smckusick return (EBUSY); 21541480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET); 21641480Smckusick if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD)) 21741480Smckusick tp->t_state |= TS_CARR_ON; 21841480Smckusick (void) spltty(); 21944295Shibler while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 22041480Smckusick (tp->t_state & TS_CARR_ON) == 0) { 22141480Smckusick tp->t_state |= TS_WOPEN; 22244295Shibler if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 22344295Shibler ttopen, 0)) 22444295Shibler break; 22541480Smckusick } 22641480Smckusick (void) spl0(); 22744295Shibler if (error == 0) 22844295Shibler error = (*linesw[tp->t_line].l_open)(dev, tp); 22957308Shibler #ifdef hp300 23057308Shibler /* 23157308Shibler * XXX hack to speed up unbuffered builtin port. 23257308Shibler * If dca_fastservice is set, a level 5 interrupt 23357308Shibler * will be directed to dcaintr first. 23457308Shibler */ 23557308Shibler if (error == 0 && unit == 0 && (dca_hasfifo & 1) == 0) 23657308Shibler dcafastservice = 1; 23757308Shibler #endif 23844295Shibler return (error); 23941480Smckusick } 24041480Smckusick 24141480Smckusick /*ARGSUSED*/ 24249750Smarc dcaclose(dev, flag, mode, p) 24341480Smckusick dev_t dev; 24449750Smarc int flag, mode; 24549750Smarc struct proc *p; 24641480Smckusick { 24741480Smckusick register struct tty *tp; 24841480Smckusick register struct dcadevice *dca; 24941480Smckusick register int unit; 25041480Smckusick 25141480Smckusick unit = UNIT(dev); 25257308Shibler #ifdef hp300 25357308Shibler if (unit == 0) 25457308Shibler dcafastservice = 0; 25557308Shibler #endif 25641480Smckusick dca = dca_addr[unit]; 25741480Smckusick tp = &dca_tty[unit]; 25849750Smarc (*linesw[tp->t_line].l_close)(tp, flag); 25941480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 26041480Smckusick #ifdef KGDB 26141480Smckusick /* do not disable interrupts if debugging */ 26249130Skarels if (dev != kgdb_dev) 26341480Smckusick #endif 26441480Smckusick dca->dca_ier = 0; 26550219Skarels if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 26650219Skarels (tp->t_state&TS_ISOPEN) == 0) 26750219Skarels (void) dcamctl(dev, 0, DMSET); 26841480Smckusick ttyclose(tp); 26950219Skarels return (0); 27041480Smckusick } 27141480Smckusick 27241480Smckusick dcaread(dev, uio, flag) 27341480Smckusick dev_t dev; 27441480Smckusick struct uio *uio; 27541480Smckusick { 27657308Shibler int unit = UNIT(dev); 27757308Shibler register struct tty *tp = &dca_tty[unit]; 27857308Shibler int error, of; 27941480Smckusick 28057308Shibler of = dcaoflows[unit]; 28157308Shibler error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 28257308Shibler /* 28357308Shibler * XXX hardly a reasonable thing to do, but reporting overflows 28457308Shibler * at interrupt time just exacerbates the problem. 28557308Shibler */ 28657308Shibler if (dcaoflows[unit] != of) 28757308Shibler log(LOG_WARNING, "dca%d: silo overflow\n", unit); 28857308Shibler return (error); 28941480Smckusick } 29041480Smckusick 29141480Smckusick dcawrite(dev, uio, flag) 29241480Smckusick dev_t dev; 29341480Smckusick struct uio *uio; 29441480Smckusick { 29541480Smckusick int unit = UNIT(dev); 29641480Smckusick register struct tty *tp = &dca_tty[unit]; 29753923Shibler extern struct tty *constty; 29841480Smckusick 29942353Smckusick /* 30042353Smckusick * (XXX) We disallow virtual consoles if the physical console is 30142353Smckusick * a serial port. This is in case there is a display attached that 30242353Smckusick * is not the console. In that situation we don't need/want the X 30342353Smckusick * server taking over the console. 30442353Smckusick */ 30542353Smckusick if (constty && unit == dcaconsole) 30642353Smckusick constty = NULL; 30741480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 30841480Smckusick } 30941480Smckusick 31041480Smckusick dcaintr(unit) 31141480Smckusick register int unit; 31241480Smckusick { 31341480Smckusick register struct dcadevice *dca; 31444318Shibler register u_char code; 31544318Shibler register struct tty *tp; 31657308Shibler int iflowdone = 0; 31741480Smckusick 31841480Smckusick dca = dca_addr[unit]; 31953923Shibler #ifdef hp300 32053923Shibler if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE)) 32150219Skarels return (0); 32253923Shibler #endif 32357308Shibler tp = &dca_tty[unit]; 32444318Shibler while (1) { 32544318Shibler code = dca->dca_iir; 32649300Shibler #ifdef DEBUG 32749300Shibler dcaintrcount[code & IIR_IMASK]++; 32849300Shibler #endif 32949300Shibler switch (code & IIR_IMASK) { 33044318Shibler case IIR_NOPEND: 33144318Shibler return (1); 33249300Shibler case IIR_RXTOUT: 33344318Shibler case IIR_RXRDY: 33444318Shibler /* do time-critical read in-line */ 33549300Shibler /* 33649300Shibler * Process a received byte. Inline for speed... 33749300Shibler */ 33844318Shibler #ifdef KGDB 33949300Shibler #define RCVBYTE() \ 34049300Shibler code = dca->dca_data; \ 34149300Shibler if ((tp->t_state & TS_ISOPEN) == 0) { \ 34250219Skarels if (code == FRAME_END && \ 34350219Skarels kgdb_dev == makedev(dcamajor, unit)) \ 34449300Shibler kgdb_connect(0); /* trap into kgdb */ \ 34549300Shibler } else \ 34649300Shibler (*linesw[tp->t_line].l_rint)(code, tp) 34749300Shibler #else 34849300Shibler #define RCVBYTE() \ 34949300Shibler code = dca->dca_data; \ 35049300Shibler if ((tp->t_state & TS_ISOPEN) != 0) \ 35149300Shibler (*linesw[tp->t_line].l_rint)(code, tp) 35244318Shibler #endif 35349300Shibler RCVBYTE(); 35449300Shibler if (dca_hasfifo & (1 << unit)) { 35549300Shibler #ifdef DEBUG 35649300Shibler register int fifocnt = 1; 35749300Shibler #endif 35849300Shibler while ((code = dca->dca_lsr) & LSR_RCV_MASK) { 35949300Shibler if (code == LSR_RXRDY) { 36049300Shibler RCVBYTE(); 36149300Shibler } else 36249300Shibler dcaeint(unit, code, dca); 36349300Shibler #ifdef DEBUG 36449300Shibler fifocnt++; 36549300Shibler #endif 36649300Shibler } 36749300Shibler #ifdef DEBUG 36849300Shibler if (fifocnt > 16) 36949300Shibler fifoin[0]++; 37049300Shibler else 37149300Shibler fifoin[fifocnt]++; 37249300Shibler #endif 37349300Shibler } 37457308Shibler if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) && 37557308Shibler tp->t_rawq.c_cc > TTYHOG/2) { 37657308Shibler dca->dca_mcr &= ~MCR_RTS; 37757308Shibler iflowdone = 1; 37857308Shibler } 37944318Shibler break; 38044318Shibler case IIR_TXRDY: 38144318Shibler tp->t_state &=~ (TS_BUSY|TS_FLUSH); 38244318Shibler if (tp->t_line) 38344318Shibler (*linesw[tp->t_line].l_start)(tp); 38444318Shibler else 38544318Shibler dcastart(tp); 38644318Shibler break; 38744318Shibler case IIR_RLS: 38849300Shibler dcaeint(unit, dca->dca_lsr, dca); 38944318Shibler break; 39044318Shibler default: 39144318Shibler if (code & IIR_NOPEND) 39244318Shibler return (1); 39344318Shibler log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n", 39444318Shibler unit, code); 39544318Shibler /* fall through */ 39644318Shibler case IIR_MLSC: 39741480Smckusick dcamint(unit, dca); 39844318Shibler break; 39944318Shibler } 40041480Smckusick } 40141480Smckusick } 40241480Smckusick 40349300Shibler dcaeint(unit, stat, dca) 40449300Shibler register int unit, stat; 40541480Smckusick register struct dcadevice *dca; 40641480Smckusick { 40741480Smckusick register struct tty *tp; 40849300Shibler register int c; 40941480Smckusick 41041480Smckusick tp = &dca_tty[unit]; 41144318Shibler c = dca->dca_data; 41241480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 41341480Smckusick #ifdef KGDB 41441480Smckusick /* we don't care about parity errors */ 41541480Smckusick if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 41649130Skarels kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END) 41749130Skarels kgdb_connect(0); /* trap into kgdb */ 41841480Smckusick #endif 41941480Smckusick return; 42041480Smckusick } 42141480Smckusick if (stat & (LSR_BI | LSR_FE)) 42241480Smckusick c |= TTY_FE; 42341480Smckusick else if (stat & LSR_PE) 42441480Smckusick c |= TTY_PE; 42541480Smckusick else if (stat & LSR_OE) 42657308Shibler dcaoflows[unit]++; 42741480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 42841480Smckusick } 42941480Smckusick 43041480Smckusick dcamint(unit, dca) 43141480Smckusick register int unit; 43241480Smckusick register struct dcadevice *dca; 43341480Smckusick { 43441480Smckusick register struct tty *tp; 43553923Shibler register u_char stat; 43641480Smckusick 43741480Smckusick tp = &dca_tty[unit]; 43841480Smckusick stat = dca->dca_msr; 43949300Shibler #ifdef DEBUG 44049300Shibler dcamintcount[stat & 0xf]++; 44149300Shibler #endif 44257308Shibler if ((stat & MSR_DDCD) && 44357308Shibler (dcasoftCAR & (1 << unit)) == 0) { 44441480Smckusick if (stat & MSR_DCD) 44544318Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 44641480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 44741480Smckusick dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 44857308Shibler } 44957308Shibler /* 45057308Shibler * CTS change. 45157308Shibler * If doing HW output flow control start/stop output as appropriate. 45257308Shibler */ 45357308Shibler if ((stat & MSR_DCTS) && 45457308Shibler (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) { 45544318Shibler if (stat & MSR_CTS) { 45644318Shibler tp->t_state &=~ TS_TTSTOP; 45757308Shibler dcastart(tp); 45857308Shibler } else { 45944318Shibler tp->t_state |= TS_TTSTOP; 46057308Shibler } 46141480Smckusick } 46241480Smckusick } 46341480Smckusick 46452421Smckusick dcaioctl(dev, cmd, data, flag, p) 46541480Smckusick dev_t dev; 46652421Smckusick int cmd; 46741480Smckusick caddr_t data; 46852421Smckusick int flag; 46952421Smckusick struct proc *p; 47041480Smckusick { 47141480Smckusick register struct tty *tp; 47241480Smckusick register int unit = UNIT(dev); 47341480Smckusick register struct dcadevice *dca; 47441480Smckusick register int error; 47541480Smckusick 47641480Smckusick tp = &dca_tty[unit]; 47752421Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 47841480Smckusick if (error >= 0) 47941480Smckusick return (error); 48041480Smckusick error = ttioctl(tp, cmd, data, flag); 48141480Smckusick if (error >= 0) 48241480Smckusick return (error); 48341480Smckusick 48441480Smckusick dca = dca_addr[unit]; 48541480Smckusick switch (cmd) { 48641480Smckusick 48741480Smckusick case TIOCSBRK: 48841480Smckusick dca->dca_cfcr |= CFCR_SBREAK; 48941480Smckusick break; 49041480Smckusick 49141480Smckusick case TIOCCBRK: 49241480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 49341480Smckusick break; 49441480Smckusick 49541480Smckusick case TIOCSDTR: 49641480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 49741480Smckusick break; 49841480Smckusick 49941480Smckusick case TIOCCDTR: 50041480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 50141480Smckusick break; 50241480Smckusick 50341480Smckusick case TIOCMSET: 50441480Smckusick (void) dcamctl(dev, *(int *)data, DMSET); 50541480Smckusick break; 50641480Smckusick 50741480Smckusick case TIOCMBIS: 50841480Smckusick (void) dcamctl(dev, *(int *)data, DMBIS); 50941480Smckusick break; 51041480Smckusick 51141480Smckusick case TIOCMBIC: 51241480Smckusick (void) dcamctl(dev, *(int *)data, DMBIC); 51341480Smckusick break; 51441480Smckusick 51541480Smckusick case TIOCMGET: 51641480Smckusick *(int *)data = dcamctl(dev, 0, DMGET); 51741480Smckusick break; 51841480Smckusick 51941480Smckusick default: 52041480Smckusick return (ENOTTY); 52141480Smckusick } 52241480Smckusick return (0); 52341480Smckusick } 52441480Smckusick 52541480Smckusick dcaparam(tp, t) 52641480Smckusick register struct tty *tp; 52741480Smckusick register struct termios *t; 52841480Smckusick { 52941480Smckusick register struct dcadevice *dca; 53041480Smckusick register int cfcr, cflag = t->c_cflag; 53141480Smckusick int unit = UNIT(tp->t_dev); 53241480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 53341480Smckusick 53441480Smckusick /* check requested parameters */ 53541480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 53650219Skarels return (EINVAL); 53741480Smckusick /* and copy to tty */ 53841480Smckusick tp->t_ispeed = t->c_ispeed; 53941480Smckusick tp->t_ospeed = t->c_ospeed; 54041480Smckusick tp->t_cflag = cflag; 54141480Smckusick 54241480Smckusick dca = dca_addr[unit]; 54341480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 54453923Shibler #ifdef hp700 54553923Shibler dca->dca_mcr |= MCR_IEN; 54653923Shibler #endif 54741480Smckusick if (ospeed == 0) { 54841480Smckusick (void) dcamctl(unit, 0, DMSET); /* hang up line */ 54950219Skarels return (0); 55041480Smckusick } 55141480Smckusick dca->dca_cfcr |= CFCR_DLAB; 55241480Smckusick dca->dca_data = ospeed & 0xFF; 55341480Smckusick dca->dca_ier = ospeed >> 8; 55441480Smckusick switch (cflag&CSIZE) { 55541480Smckusick case CS5: 55641480Smckusick cfcr = CFCR_5BITS; break; 55741480Smckusick case CS6: 55841480Smckusick cfcr = CFCR_6BITS; break; 55941480Smckusick case CS7: 56041480Smckusick cfcr = CFCR_7BITS; break; 56141480Smckusick case CS8: 56241480Smckusick cfcr = CFCR_8BITS; break; 56341480Smckusick } 56441480Smckusick if (cflag&PARENB) { 56541480Smckusick cfcr |= CFCR_PENAB; 56641480Smckusick if ((cflag&PARODD) == 0) 56741480Smckusick cfcr |= CFCR_PEVEN; 56841480Smckusick } 56941480Smckusick if (cflag&CSTOPB) 57041480Smckusick cfcr |= CFCR_STOPB; 57141480Smckusick dca->dca_cfcr = cfcr; 57249300Shibler if (dca_hasfifo & (1 << unit)) 57349300Shibler dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14; 57450219Skarels return (0); 57541480Smckusick } 57641480Smckusick 57752389Smckusick void 57841480Smckusick dcastart(tp) 57941480Smckusick register struct tty *tp; 58041480Smckusick { 58141480Smckusick register struct dcadevice *dca; 58241480Smckusick int s, unit, c; 58341480Smckusick 58441480Smckusick unit = UNIT(tp->t_dev); 58541480Smckusick dca = dca_addr[unit]; 58641480Smckusick s = spltty(); 58744318Shibler if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 58841480Smckusick goto out; 58941480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 59041480Smckusick if (tp->t_state&TS_ASLEEP) { 59141480Smckusick tp->t_state &= ~TS_ASLEEP; 59241480Smckusick wakeup((caddr_t)&tp->t_outq); 59341480Smckusick } 59452529Storek selwakeup(&tp->t_wsel); 59541480Smckusick } 59641480Smckusick if (tp->t_outq.c_cc == 0) 59741480Smckusick goto out; 59844318Shibler if (dca->dca_lsr & LSR_TXRDY) { 59944318Shibler c = getc(&tp->t_outq); 60044318Shibler tp->t_state |= TS_BUSY; 60144318Shibler dca->dca_data = c; 60249300Shibler if (dca_hasfifo & (1 << unit)) { 60349300Shibler for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 60449300Shibler dca->dca_data = getc(&tp->t_outq); 60549300Shibler #ifdef DEBUG 60649300Shibler if (c > 16) 60749300Shibler fifoout[0]++; 60849300Shibler else 60949300Shibler fifoout[c]++; 61049300Shibler #endif 61149300Shibler } 61244318Shibler } 61341480Smckusick out: 61441480Smckusick splx(s); 61541480Smckusick } 61641480Smckusick 61741480Smckusick /* 61841480Smckusick * Stop output on a line. 61941480Smckusick */ 62041480Smckusick /*ARGSUSED*/ 62141480Smckusick dcastop(tp, flag) 62241480Smckusick register struct tty *tp; 62341480Smckusick { 62441480Smckusick register int s; 62541480Smckusick 62641480Smckusick s = spltty(); 62741480Smckusick if (tp->t_state & TS_BUSY) { 62841480Smckusick if ((tp->t_state&TS_TTSTOP)==0) 62941480Smckusick tp->t_state |= TS_FLUSH; 63041480Smckusick } 63141480Smckusick splx(s); 63241480Smckusick } 63341480Smckusick 63441480Smckusick dcamctl(dev, bits, how) 63541480Smckusick dev_t dev; 63641480Smckusick int bits, how; 63741480Smckusick { 63841480Smckusick register struct dcadevice *dca; 63941480Smckusick register int unit; 64041480Smckusick int s; 64141480Smckusick 64241480Smckusick unit = UNIT(dev); 64341480Smckusick dca = dca_addr[unit]; 64453923Shibler #ifdef hp700 64553923Shibler /* 64653923Shibler * Always make sure MCR_IEN is set (unless setting to 0) 64753923Shibler */ 64853923Shibler #ifdef KGDB 64953923Shibler if (how == DMSET && kgdb_dev == makedev(dcamajor, unit)) 65053923Shibler bits |= MCR_IEN; 65153923Shibler else 65253923Shibler #endif 65353923Shibler if (how == DMBIS || (how == DMSET && bits)) 65453923Shibler bits |= MCR_IEN; 65553923Shibler else if (how == DMBIC) 65653923Shibler bits &= ~MCR_IEN; 65753923Shibler #endif 65841480Smckusick s = spltty(); 65941480Smckusick switch (how) { 66041480Smckusick 66141480Smckusick case DMSET: 66241480Smckusick dca->dca_mcr = bits; 66341480Smckusick break; 66441480Smckusick 66541480Smckusick case DMBIS: 66641480Smckusick dca->dca_mcr |= bits; 66741480Smckusick break; 66841480Smckusick 66941480Smckusick case DMBIC: 67041480Smckusick dca->dca_mcr &= ~bits; 67141480Smckusick break; 67241480Smckusick 67341480Smckusick case DMGET: 67441480Smckusick bits = dca->dca_msr; 67541480Smckusick break; 67641480Smckusick } 67741480Smckusick (void) splx(s); 67850219Skarels return (bits); 67941480Smckusick } 68041480Smckusick 68141480Smckusick /* 68241480Smckusick * Following are all routines needed for DCA to act as console 68341480Smckusick */ 68456504Sbostic #include <hp/dev/cons.h> 68541480Smckusick 68641480Smckusick dcacnprobe(cp) 68741480Smckusick struct consdev *cp; 68841480Smckusick { 68949300Shibler int unit; 69041480Smckusick 69149130Skarels /* locate the major number */ 69249130Skarels for (dcamajor = 0; dcamajor < nchrdev; dcamajor++) 69349130Skarels if (cdevsw[dcamajor].d_open == dcaopen) 69449130Skarels break; 69549130Skarels 69641480Smckusick /* XXX: ick */ 69741480Smckusick unit = CONUNIT; 69853923Shibler #ifdef hp300 69949300Shibler dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE); 70041480Smckusick 70141480Smckusick /* make sure hardware exists */ 70241480Smckusick if (badaddr((short *)dca_addr[unit])) { 70341480Smckusick cp->cn_pri = CN_DEAD; 70441480Smckusick return; 70541480Smckusick } 70653923Shibler #endif 70753923Shibler #ifdef hp700 70853923Shibler dca_addr[CONUNIT] = CONPORT; 70953923Shibler #endif 71041480Smckusick 71141480Smckusick /* initialize required fields */ 71249130Skarels cp->cn_dev = makedev(dcamajor, unit); 71341480Smckusick cp->cn_tp = &dca_tty[unit]; 71453923Shibler #ifdef hp300 71553923Shibler switch (dca_addr[unit]->dca_id) { 71641480Smckusick case DCAID0: 71741480Smckusick case DCAID1: 71841480Smckusick cp->cn_pri = CN_NORMAL; 71941480Smckusick break; 72041480Smckusick case DCAREMID0: 72141480Smckusick case DCAREMID1: 72241480Smckusick cp->cn_pri = CN_REMOTE; 72341480Smckusick break; 72441480Smckusick default: 72541480Smckusick cp->cn_pri = CN_DEAD; 72641480Smckusick break; 72741480Smckusick } 72853923Shibler #endif 72953923Shibler #ifdef hp700 73053923Shibler cp->cn_pri = CN_NORMAL; 73153923Shibler #endif 73249130Skarels /* 73349300Shibler * If dcaconsole is initialized, raise our priority. 73449130Skarels */ 73549130Skarels if (dcaconsole == unit) 73649130Skarels cp->cn_pri = CN_REMOTE; 73749300Shibler #ifdef KGDB 73849130Skarels if (major(kgdb_dev) == 1) /* XXX */ 73949130Skarels kgdb_dev = makedev(dcamajor, minor(kgdb_dev)); 74049300Shibler #endif 74141480Smckusick } 74241480Smckusick 74341480Smckusick dcacninit(cp) 74441480Smckusick struct consdev *cp; 74541480Smckusick { 74641480Smckusick int unit = UNIT(cp->cn_dev); 74741480Smckusick 74849130Skarels dcainit(unit, dcadefaultrate); 74941480Smckusick dcaconsole = unit; 75049130Skarels dcaconsinit = 1; 75141480Smckusick } 75241480Smckusick 75349130Skarels dcainit(unit, rate) 75449130Skarels int unit, rate; 75541480Smckusick { 75641480Smckusick register struct dcadevice *dca; 75749130Skarels int s; 75841480Smckusick short stat; 75941480Smckusick 76041480Smckusick #ifdef lint 76141480Smckusick stat = unit; if (stat) return; 76241480Smckusick #endif 76341480Smckusick dca = dca_addr[unit]; 76441480Smckusick s = splhigh(); 76553923Shibler #ifdef hp300 76653923Shibler dca->dca_reset = 0xFF; 76741480Smckusick DELAY(100); 76841480Smckusick dca->dca_ic = IC_IE; 76953923Shibler #endif 77041480Smckusick dca->dca_cfcr = CFCR_DLAB; 77149130Skarels rate = ttspeedtab(rate, dcaspeedtab); 77241480Smckusick dca->dca_data = rate & 0xFF; 77341480Smckusick dca->dca_ier = rate >> 8; 77441480Smckusick dca->dca_cfcr = CFCR_8BITS; 77541480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 77653923Shibler #ifdef hp700 77753923Shibler dca->dca_mcr |= MCR_IEN; 77853923Shibler #endif 77949300Shibler dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14; 78053923Shibler DELAY(100); 78141480Smckusick stat = dca->dca_iir; 78241480Smckusick splx(s); 78341480Smckusick } 78441480Smckusick 78541480Smckusick dcacngetc(dev) 78641480Smckusick { 78741480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 78853923Shibler register u_char stat; 78941480Smckusick int c, s; 79041480Smckusick 79141480Smckusick #ifdef lint 79250219Skarels stat = dev; if (stat) return (0); 79341480Smckusick #endif 79441480Smckusick s = splhigh(); 79541480Smckusick while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 79641480Smckusick ; 79741480Smckusick c = dca->dca_data; 79841480Smckusick stat = dca->dca_iir; 79941480Smckusick splx(s); 80050219Skarels return (c); 80141480Smckusick } 80241480Smckusick 80341480Smckusick /* 80441480Smckusick * Console kernel output character routine. 80541480Smckusick */ 80641480Smckusick dcacnputc(dev, c) 80741480Smckusick dev_t dev; 80841480Smckusick register int c; 80941480Smckusick { 81041480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 81141480Smckusick register int timo; 81253923Shibler register u_char stat; 81341480Smckusick int s = splhigh(); 81441480Smckusick 81541480Smckusick #ifdef lint 81641480Smckusick stat = dev; if (stat) return; 81741480Smckusick #endif 81849130Skarels if (dcaconsinit == 0) { 81949130Skarels (void) dcainit(UNIT(dev), dcadefaultrate); 82049130Skarels dcaconsinit = 1; 82141480Smckusick } 82241480Smckusick /* wait for any pending transmission to finish */ 82341480Smckusick timo = 50000; 82441480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 82541480Smckusick ; 82641480Smckusick dca->dca_data = c; 82741480Smckusick /* wait for this transmission to complete */ 82841480Smckusick timo = 1500000; 82941480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 83041480Smckusick ; 83153923Shibler /* 83253923Shibler * If the "normal" interface was busy transfering a character 83353923Shibler * we must let our interrupt through to keep things moving. 83453923Shibler * Otherwise, we clear the interrupt that we have caused. 83553923Shibler */ 83653923Shibler if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0) 83753923Shibler stat = dca->dca_iir; 83841480Smckusick splx(s); 83941480Smckusick } 84041480Smckusick #endif 841