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*68159Scgd * @(#)dca.c 8.3 (Berkeley) 01/09/95
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
dcaprobe(hd)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__
dcaopen(dev_t dev,int flag,int mode,struct proc * p)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*/
dcaclose(dev,flag,mode,p)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
dcaread(dev,uio,flag)27241480Smckusick dcaread(dev, uio, flag)
27341480Smckusick dev_t dev;
27441480Smckusick struct uio *uio;
27565641Sbostic 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
dcawrite(dev,uio,flag)29241480Smckusick dcawrite(dev, uio, flag)
29341480Smckusick dev_t dev;
29441480Smckusick struct uio *uio;
29565641Sbostic 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
dcaintr(unit)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
dcaeint(unit,stat,dca)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
dcamint(unit,dca)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
dcaioctl(dev,cmd,data,flag,p)46652421Smckusick dcaioctl(dev, cmd, data, flag, p)
46741480Smckusick dev_t dev;
468*68159Scgd u_long 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
dcaparam(tp,t)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
dcastart(tp)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*/
dcastop(tp,flag)62341480Smckusick dcastop(tp, flag)
62441480Smckusick register struct tty *tp;
62565641Sbostic 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
dcamctl(dev,bits,how)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
dcainit(unit,rate)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
dcacngetc(dev)78841480Smckusick dcacngetc(dev)
78965641Sbostic 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 */
dcacnputc(dev,c)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