141480Smckusick /* 263146Sbostic * Copyright (c) 1982, 1986, 1990, 1993 363146Sbostic * The Regents of the University of California. All rights reserved. 441480Smckusick * 541480Smckusick * %sccs.include.redist.c% 641480Smckusick * 7*65641Sbostic * @(#)dca.c 8.2 (Berkeley) 01/12/94 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; 275*65641Sbostic int flag; 27641480Smckusick { 27757308Shibler int unit = UNIT(dev); 27857308Shibler register struct tty *tp = &dca_tty[unit]; 27957308Shibler int error, of; 28041480Smckusick 28157308Shibler of = dcaoflows[unit]; 28257308Shibler error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 28357308Shibler /* 28457308Shibler * XXX hardly a reasonable thing to do, but reporting overflows 28557308Shibler * at interrupt time just exacerbates the problem. 28657308Shibler */ 28757308Shibler if (dcaoflows[unit] != of) 28857308Shibler log(LOG_WARNING, "dca%d: silo overflow\n", unit); 28957308Shibler return (error); 29041480Smckusick } 29141480Smckusick 29241480Smckusick dcawrite(dev, uio, flag) 29341480Smckusick dev_t dev; 29441480Smckusick struct uio *uio; 295*65641Sbostic int flag; 29641480Smckusick { 29741480Smckusick int unit = UNIT(dev); 29841480Smckusick register struct tty *tp = &dca_tty[unit]; 29953923Shibler extern struct tty *constty; 30041480Smckusick 30142353Smckusick /* 30242353Smckusick * (XXX) We disallow virtual consoles if the physical console is 30342353Smckusick * a serial port. This is in case there is a display attached that 30442353Smckusick * is not the console. In that situation we don't need/want the X 30542353Smckusick * server taking over the console. 30642353Smckusick */ 30742353Smckusick if (constty && unit == dcaconsole) 30842353Smckusick constty = NULL; 30941480Smckusick return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 31041480Smckusick } 31141480Smckusick 31241480Smckusick dcaintr(unit) 31341480Smckusick register int unit; 31441480Smckusick { 31541480Smckusick register struct dcadevice *dca; 31644318Shibler register u_char code; 31744318Shibler register struct tty *tp; 31857308Shibler int iflowdone = 0; 31941480Smckusick 32041480Smckusick dca = dca_addr[unit]; 32153923Shibler #ifdef hp300 32253923Shibler if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE)) 32350219Skarels return (0); 32453923Shibler #endif 32557308Shibler tp = &dca_tty[unit]; 32644318Shibler while (1) { 32744318Shibler code = dca->dca_iir; 32849300Shibler #ifdef DEBUG 32949300Shibler dcaintrcount[code & IIR_IMASK]++; 33049300Shibler #endif 33149300Shibler switch (code & IIR_IMASK) { 33244318Shibler case IIR_NOPEND: 33344318Shibler return (1); 33449300Shibler case IIR_RXTOUT: 33544318Shibler case IIR_RXRDY: 33644318Shibler /* do time-critical read in-line */ 33749300Shibler /* 33849300Shibler * Process a received byte. Inline for speed... 33949300Shibler */ 34044318Shibler #ifdef KGDB 34149300Shibler #define RCVBYTE() \ 34249300Shibler code = dca->dca_data; \ 34349300Shibler if ((tp->t_state & TS_ISOPEN) == 0) { \ 34450219Skarels if (code == FRAME_END && \ 34550219Skarels kgdb_dev == makedev(dcamajor, unit)) \ 34649300Shibler kgdb_connect(0); /* trap into kgdb */ \ 34749300Shibler } else \ 34849300Shibler (*linesw[tp->t_line].l_rint)(code, tp) 34949300Shibler #else 35049300Shibler #define RCVBYTE() \ 35149300Shibler code = dca->dca_data; \ 35249300Shibler if ((tp->t_state & TS_ISOPEN) != 0) \ 35349300Shibler (*linesw[tp->t_line].l_rint)(code, tp) 35444318Shibler #endif 35549300Shibler RCVBYTE(); 35649300Shibler if (dca_hasfifo & (1 << unit)) { 35749300Shibler #ifdef DEBUG 35849300Shibler register int fifocnt = 1; 35949300Shibler #endif 36049300Shibler while ((code = dca->dca_lsr) & LSR_RCV_MASK) { 36149300Shibler if (code == LSR_RXRDY) { 36249300Shibler RCVBYTE(); 36349300Shibler } else 36449300Shibler dcaeint(unit, code, dca); 36549300Shibler #ifdef DEBUG 36649300Shibler fifocnt++; 36749300Shibler #endif 36849300Shibler } 36949300Shibler #ifdef DEBUG 37049300Shibler if (fifocnt > 16) 37149300Shibler fifoin[0]++; 37249300Shibler else 37349300Shibler fifoin[fifocnt]++; 37449300Shibler #endif 37549300Shibler } 37657308Shibler if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) && 37757308Shibler tp->t_rawq.c_cc > TTYHOG/2) { 37857308Shibler dca->dca_mcr &= ~MCR_RTS; 37957308Shibler iflowdone = 1; 38057308Shibler } 38144318Shibler break; 38244318Shibler case IIR_TXRDY: 38344318Shibler tp->t_state &=~ (TS_BUSY|TS_FLUSH); 38444318Shibler if (tp->t_line) 38544318Shibler (*linesw[tp->t_line].l_start)(tp); 38644318Shibler else 38744318Shibler dcastart(tp); 38844318Shibler break; 38944318Shibler case IIR_RLS: 39049300Shibler dcaeint(unit, dca->dca_lsr, dca); 39144318Shibler break; 39244318Shibler default: 39344318Shibler if (code & IIR_NOPEND) 39444318Shibler return (1); 39544318Shibler log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n", 39644318Shibler unit, code); 39744318Shibler /* fall through */ 39844318Shibler case IIR_MLSC: 39941480Smckusick dcamint(unit, dca); 40044318Shibler break; 40144318Shibler } 40241480Smckusick } 40341480Smckusick } 40441480Smckusick 40549300Shibler dcaeint(unit, stat, dca) 40649300Shibler register int unit, stat; 40741480Smckusick register struct dcadevice *dca; 40841480Smckusick { 40941480Smckusick register struct tty *tp; 41049300Shibler register int c; 41141480Smckusick 41241480Smckusick tp = &dca_tty[unit]; 41344318Shibler c = dca->dca_data; 41441480Smckusick if ((tp->t_state & TS_ISOPEN) == 0) { 41541480Smckusick #ifdef KGDB 41641480Smckusick /* we don't care about parity errors */ 41741480Smckusick if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 41849130Skarels kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END) 41949130Skarels kgdb_connect(0); /* trap into kgdb */ 42041480Smckusick #endif 42141480Smckusick return; 42241480Smckusick } 42341480Smckusick if (stat & (LSR_BI | LSR_FE)) 42441480Smckusick c |= TTY_FE; 42541480Smckusick else if (stat & LSR_PE) 42641480Smckusick c |= TTY_PE; 42741480Smckusick else if (stat & LSR_OE) 42857308Shibler dcaoflows[unit]++; 42941480Smckusick (*linesw[tp->t_line].l_rint)(c, tp); 43041480Smckusick } 43141480Smckusick 43241480Smckusick dcamint(unit, dca) 43341480Smckusick register int unit; 43441480Smckusick register struct dcadevice *dca; 43541480Smckusick { 43641480Smckusick register struct tty *tp; 43753923Shibler register u_char stat; 43841480Smckusick 43941480Smckusick tp = &dca_tty[unit]; 44041480Smckusick stat = dca->dca_msr; 44149300Shibler #ifdef DEBUG 44249300Shibler dcamintcount[stat & 0xf]++; 44349300Shibler #endif 44457308Shibler if ((stat & MSR_DDCD) && 44557308Shibler (dcasoftCAR & (1 << unit)) == 0) { 44641480Smckusick if (stat & MSR_DCD) 44744318Shibler (void)(*linesw[tp->t_line].l_modem)(tp, 1); 44841480Smckusick else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 44941480Smckusick dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 45057308Shibler } 45157308Shibler /* 45257308Shibler * CTS change. 45357308Shibler * If doing HW output flow control start/stop output as appropriate. 45457308Shibler */ 45557308Shibler if ((stat & MSR_DCTS) && 45657308Shibler (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) { 45744318Shibler if (stat & MSR_CTS) { 45844318Shibler tp->t_state &=~ TS_TTSTOP; 45957308Shibler dcastart(tp); 46057308Shibler } else { 46144318Shibler tp->t_state |= TS_TTSTOP; 46257308Shibler } 46341480Smckusick } 46441480Smckusick } 46541480Smckusick 46652421Smckusick dcaioctl(dev, cmd, data, flag, p) 46741480Smckusick dev_t dev; 46852421Smckusick int cmd; 46941480Smckusick caddr_t data; 47052421Smckusick int flag; 47152421Smckusick struct proc *p; 47241480Smckusick { 47341480Smckusick register struct tty *tp; 47441480Smckusick register int unit = UNIT(dev); 47541480Smckusick register struct dcadevice *dca; 47641480Smckusick register int error; 47741480Smckusick 47841480Smckusick tp = &dca_tty[unit]; 47952421Smckusick error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 48041480Smckusick if (error >= 0) 48141480Smckusick return (error); 48241480Smckusick error = ttioctl(tp, cmd, data, flag); 48341480Smckusick if (error >= 0) 48441480Smckusick return (error); 48541480Smckusick 48641480Smckusick dca = dca_addr[unit]; 48741480Smckusick switch (cmd) { 48841480Smckusick 48941480Smckusick case TIOCSBRK: 49041480Smckusick dca->dca_cfcr |= CFCR_SBREAK; 49141480Smckusick break; 49241480Smckusick 49341480Smckusick case TIOCCBRK: 49441480Smckusick dca->dca_cfcr &= ~CFCR_SBREAK; 49541480Smckusick break; 49641480Smckusick 49741480Smckusick case TIOCSDTR: 49841480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 49941480Smckusick break; 50041480Smckusick 50141480Smckusick case TIOCCDTR: 50241480Smckusick (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 50341480Smckusick break; 50441480Smckusick 50541480Smckusick case TIOCMSET: 50641480Smckusick (void) dcamctl(dev, *(int *)data, DMSET); 50741480Smckusick break; 50841480Smckusick 50941480Smckusick case TIOCMBIS: 51041480Smckusick (void) dcamctl(dev, *(int *)data, DMBIS); 51141480Smckusick break; 51241480Smckusick 51341480Smckusick case TIOCMBIC: 51441480Smckusick (void) dcamctl(dev, *(int *)data, DMBIC); 51541480Smckusick break; 51641480Smckusick 51741480Smckusick case TIOCMGET: 51841480Smckusick *(int *)data = dcamctl(dev, 0, DMGET); 51941480Smckusick break; 52041480Smckusick 52141480Smckusick default: 52241480Smckusick return (ENOTTY); 52341480Smckusick } 52441480Smckusick return (0); 52541480Smckusick } 52641480Smckusick 52741480Smckusick dcaparam(tp, t) 52841480Smckusick register struct tty *tp; 52941480Smckusick register struct termios *t; 53041480Smckusick { 53141480Smckusick register struct dcadevice *dca; 53241480Smckusick register int cfcr, cflag = t->c_cflag; 53341480Smckusick int unit = UNIT(tp->t_dev); 53441480Smckusick int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 53541480Smckusick 53641480Smckusick /* check requested parameters */ 53741480Smckusick if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 53850219Skarels return (EINVAL); 53941480Smckusick /* and copy to tty */ 54041480Smckusick tp->t_ispeed = t->c_ispeed; 54141480Smckusick tp->t_ospeed = t->c_ospeed; 54241480Smckusick tp->t_cflag = cflag; 54341480Smckusick 54441480Smckusick dca = dca_addr[unit]; 54541480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 54653923Shibler #ifdef hp700 54753923Shibler dca->dca_mcr |= MCR_IEN; 54853923Shibler #endif 54941480Smckusick if (ospeed == 0) { 55041480Smckusick (void) dcamctl(unit, 0, DMSET); /* hang up line */ 55150219Skarels return (0); 55241480Smckusick } 55341480Smckusick dca->dca_cfcr |= CFCR_DLAB; 55441480Smckusick dca->dca_data = ospeed & 0xFF; 55541480Smckusick dca->dca_ier = ospeed >> 8; 55641480Smckusick switch (cflag&CSIZE) { 55741480Smckusick case CS5: 55841480Smckusick cfcr = CFCR_5BITS; break; 55941480Smckusick case CS6: 56041480Smckusick cfcr = CFCR_6BITS; break; 56141480Smckusick case CS7: 56241480Smckusick cfcr = CFCR_7BITS; break; 56341480Smckusick case CS8: 56441480Smckusick cfcr = CFCR_8BITS; break; 56541480Smckusick } 56641480Smckusick if (cflag&PARENB) { 56741480Smckusick cfcr |= CFCR_PENAB; 56841480Smckusick if ((cflag&PARODD) == 0) 56941480Smckusick cfcr |= CFCR_PEVEN; 57041480Smckusick } 57141480Smckusick if (cflag&CSTOPB) 57241480Smckusick cfcr |= CFCR_STOPB; 57341480Smckusick dca->dca_cfcr = cfcr; 57449300Shibler if (dca_hasfifo & (1 << unit)) 57549300Shibler dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14; 57650219Skarels return (0); 57741480Smckusick } 57841480Smckusick 57952389Smckusick void 58041480Smckusick dcastart(tp) 58141480Smckusick register struct tty *tp; 58241480Smckusick { 58341480Smckusick register struct dcadevice *dca; 58441480Smckusick int s, unit, c; 58541480Smckusick 58641480Smckusick unit = UNIT(tp->t_dev); 58741480Smckusick dca = dca_addr[unit]; 58841480Smckusick s = spltty(); 58944318Shibler if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 59041480Smckusick goto out; 59141480Smckusick if (tp->t_outq.c_cc <= tp->t_lowat) { 59241480Smckusick if (tp->t_state&TS_ASLEEP) { 59341480Smckusick tp->t_state &= ~TS_ASLEEP; 59441480Smckusick wakeup((caddr_t)&tp->t_outq); 59541480Smckusick } 59652529Storek selwakeup(&tp->t_wsel); 59741480Smckusick } 59841480Smckusick if (tp->t_outq.c_cc == 0) 59941480Smckusick goto out; 60044318Shibler if (dca->dca_lsr & LSR_TXRDY) { 60144318Shibler c = getc(&tp->t_outq); 60244318Shibler tp->t_state |= TS_BUSY; 60344318Shibler dca->dca_data = c; 60449300Shibler if (dca_hasfifo & (1 << unit)) { 60549300Shibler for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 60649300Shibler dca->dca_data = getc(&tp->t_outq); 60749300Shibler #ifdef DEBUG 60849300Shibler if (c > 16) 60949300Shibler fifoout[0]++; 61049300Shibler else 61149300Shibler fifoout[c]++; 61249300Shibler #endif 61349300Shibler } 61444318Shibler } 61541480Smckusick out: 61641480Smckusick splx(s); 61741480Smckusick } 61841480Smckusick 61941480Smckusick /* 62041480Smckusick * Stop output on a line. 62141480Smckusick */ 62241480Smckusick /*ARGSUSED*/ 62341480Smckusick dcastop(tp, flag) 62441480Smckusick register struct tty *tp; 625*65641Sbostic int flag; 62641480Smckusick { 62741480Smckusick register int s; 62841480Smckusick 62941480Smckusick s = spltty(); 63041480Smckusick if (tp->t_state & TS_BUSY) { 63141480Smckusick if ((tp->t_state&TS_TTSTOP)==0) 63241480Smckusick tp->t_state |= TS_FLUSH; 63341480Smckusick } 63441480Smckusick splx(s); 63541480Smckusick } 63641480Smckusick 63741480Smckusick dcamctl(dev, bits, how) 63841480Smckusick dev_t dev; 63941480Smckusick int bits, how; 64041480Smckusick { 64141480Smckusick register struct dcadevice *dca; 64241480Smckusick register int unit; 64341480Smckusick int s; 64441480Smckusick 64541480Smckusick unit = UNIT(dev); 64641480Smckusick dca = dca_addr[unit]; 64753923Shibler #ifdef hp700 64853923Shibler /* 64953923Shibler * Always make sure MCR_IEN is set (unless setting to 0) 65053923Shibler */ 65153923Shibler #ifdef KGDB 65253923Shibler if (how == DMSET && kgdb_dev == makedev(dcamajor, unit)) 65353923Shibler bits |= MCR_IEN; 65453923Shibler else 65553923Shibler #endif 65653923Shibler if (how == DMBIS || (how == DMSET && bits)) 65753923Shibler bits |= MCR_IEN; 65853923Shibler else if (how == DMBIC) 65953923Shibler bits &= ~MCR_IEN; 66053923Shibler #endif 66141480Smckusick s = spltty(); 66241480Smckusick switch (how) { 66341480Smckusick 66441480Smckusick case DMSET: 66541480Smckusick dca->dca_mcr = bits; 66641480Smckusick break; 66741480Smckusick 66841480Smckusick case DMBIS: 66941480Smckusick dca->dca_mcr |= bits; 67041480Smckusick break; 67141480Smckusick 67241480Smckusick case DMBIC: 67341480Smckusick dca->dca_mcr &= ~bits; 67441480Smckusick break; 67541480Smckusick 67641480Smckusick case DMGET: 67741480Smckusick bits = dca->dca_msr; 67841480Smckusick break; 67941480Smckusick } 68041480Smckusick (void) splx(s); 68150219Skarels return (bits); 68241480Smckusick } 68341480Smckusick 68441480Smckusick /* 68541480Smckusick * Following are all routines needed for DCA to act as console 68641480Smckusick */ 68756504Sbostic #include <hp/dev/cons.h> 68841480Smckusick 68941480Smckusick dcacnprobe(cp) 69041480Smckusick struct consdev *cp; 69141480Smckusick { 69249300Shibler int unit; 69341480Smckusick 69449130Skarels /* locate the major number */ 69549130Skarels for (dcamajor = 0; dcamajor < nchrdev; dcamajor++) 69649130Skarels if (cdevsw[dcamajor].d_open == dcaopen) 69749130Skarels break; 69849130Skarels 69941480Smckusick /* XXX: ick */ 70041480Smckusick unit = CONUNIT; 70153923Shibler #ifdef hp300 70249300Shibler dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE); 70341480Smckusick 70441480Smckusick /* make sure hardware exists */ 70541480Smckusick if (badaddr((short *)dca_addr[unit])) { 70641480Smckusick cp->cn_pri = CN_DEAD; 70741480Smckusick return; 70841480Smckusick } 70953923Shibler #endif 71053923Shibler #ifdef hp700 71153923Shibler dca_addr[CONUNIT] = CONPORT; 71253923Shibler #endif 71341480Smckusick 71441480Smckusick /* initialize required fields */ 71549130Skarels cp->cn_dev = makedev(dcamajor, unit); 71641480Smckusick cp->cn_tp = &dca_tty[unit]; 71753923Shibler #ifdef hp300 71853923Shibler switch (dca_addr[unit]->dca_id) { 71941480Smckusick case DCAID0: 72041480Smckusick case DCAID1: 72141480Smckusick cp->cn_pri = CN_NORMAL; 72241480Smckusick break; 72341480Smckusick case DCAREMID0: 72441480Smckusick case DCAREMID1: 72541480Smckusick cp->cn_pri = CN_REMOTE; 72641480Smckusick break; 72741480Smckusick default: 72841480Smckusick cp->cn_pri = CN_DEAD; 72941480Smckusick break; 73041480Smckusick } 73153923Shibler #endif 73253923Shibler #ifdef hp700 73353923Shibler cp->cn_pri = CN_NORMAL; 73453923Shibler #endif 73549130Skarels /* 73649300Shibler * If dcaconsole is initialized, raise our priority. 73749130Skarels */ 73849130Skarels if (dcaconsole == unit) 73949130Skarels cp->cn_pri = CN_REMOTE; 74049300Shibler #ifdef KGDB 74149130Skarels if (major(kgdb_dev) == 1) /* XXX */ 74249130Skarels kgdb_dev = makedev(dcamajor, minor(kgdb_dev)); 74349300Shibler #endif 74441480Smckusick } 74541480Smckusick 74641480Smckusick dcacninit(cp) 74741480Smckusick struct consdev *cp; 74841480Smckusick { 74941480Smckusick int unit = UNIT(cp->cn_dev); 75041480Smckusick 75149130Skarels dcainit(unit, dcadefaultrate); 75241480Smckusick dcaconsole = unit; 75349130Skarels dcaconsinit = 1; 75441480Smckusick } 75541480Smckusick 75649130Skarels dcainit(unit, rate) 75749130Skarels int unit, rate; 75841480Smckusick { 75941480Smckusick register struct dcadevice *dca; 76049130Skarels int s; 76141480Smckusick short stat; 76241480Smckusick 76341480Smckusick #ifdef lint 76441480Smckusick stat = unit; if (stat) return; 76541480Smckusick #endif 76641480Smckusick dca = dca_addr[unit]; 76741480Smckusick s = splhigh(); 76853923Shibler #ifdef hp300 76953923Shibler dca->dca_reset = 0xFF; 77041480Smckusick DELAY(100); 77141480Smckusick dca->dca_ic = IC_IE; 77253923Shibler #endif 77341480Smckusick dca->dca_cfcr = CFCR_DLAB; 77449130Skarels rate = ttspeedtab(rate, dcaspeedtab); 77541480Smckusick dca->dca_data = rate & 0xFF; 77641480Smckusick dca->dca_ier = rate >> 8; 77741480Smckusick dca->dca_cfcr = CFCR_8BITS; 77841480Smckusick dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 77953923Shibler #ifdef hp700 78053923Shibler dca->dca_mcr |= MCR_IEN; 78153923Shibler #endif 78249300Shibler dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14; 78353923Shibler DELAY(100); 78441480Smckusick stat = dca->dca_iir; 78541480Smckusick splx(s); 78641480Smckusick } 78741480Smckusick 78841480Smckusick dcacngetc(dev) 789*65641Sbostic dev_t dev; 79041480Smckusick { 79141480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 79253923Shibler register u_char stat; 79341480Smckusick int c, s; 79441480Smckusick 79541480Smckusick #ifdef lint 79650219Skarels stat = dev; if (stat) return (0); 79741480Smckusick #endif 79841480Smckusick s = splhigh(); 79941480Smckusick while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 80041480Smckusick ; 80141480Smckusick c = dca->dca_data; 80241480Smckusick stat = dca->dca_iir; 80341480Smckusick splx(s); 80450219Skarels return (c); 80541480Smckusick } 80641480Smckusick 80741480Smckusick /* 80841480Smckusick * Console kernel output character routine. 80941480Smckusick */ 81041480Smckusick dcacnputc(dev, c) 81141480Smckusick dev_t dev; 81241480Smckusick register int c; 81341480Smckusick { 81441480Smckusick register struct dcadevice *dca = dca_addr[UNIT(dev)]; 81541480Smckusick register int timo; 81653923Shibler register u_char stat; 81741480Smckusick int s = splhigh(); 81841480Smckusick 81941480Smckusick #ifdef lint 82041480Smckusick stat = dev; if (stat) return; 82141480Smckusick #endif 82249130Skarels if (dcaconsinit == 0) { 82349130Skarels (void) dcainit(UNIT(dev), dcadefaultrate); 82449130Skarels dcaconsinit = 1; 82541480Smckusick } 82641480Smckusick /* wait for any pending transmission to finish */ 82741480Smckusick timo = 50000; 82841480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 82941480Smckusick ; 83041480Smckusick dca->dca_data = c; 83141480Smckusick /* wait for this transmission to complete */ 83241480Smckusick timo = 1500000; 83341480Smckusick while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 83441480Smckusick ; 83553923Shibler /* 83653923Shibler * If the "normal" interface was busy transfering a character 83753923Shibler * we must let our interrupt through to keep things moving. 83853923Shibler * Otherwise, we clear the interrupt that we have caused. 83953923Shibler */ 84053923Shibler if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0) 84153923Shibler stat = dca->dca_iir; 84241480Smckusick splx(s); 84341480Smckusick } 84441480Smckusick #endif 845