fix OFLOW code, add hacks for less lossage on unbuffered port
[unix-history] / usr / src / sys / hp / dev / dca.c
CommitLineData
60f56dfc
KM
1/*
2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
9c4040a3 7 * @(#)dca.c 7.18 (Berkeley) %G%
60f56dfc
KM
8 */
9
10#include "dca.h"
11#if NDCA > 0
12/*
7b7da76f
MH
13 * Driver for National Semiconductor INS8250/NS16550AF/WD16C552 UARTs.
14 * Includes:
15 * 98626/98644/internal serial interface on hp300/hp400
16 * internal serial ports on hp700
17 *
18 * N.B. On the hp700, there is a "secret bit" with undocumented behavior.
19 * The third bit of the Modem Control Register (MCR_IEN == 0x08) must be
20 * set to enable interrupts.
60f56dfc 21 */
38a01dbe
KB
22#include <sys/param.h>
23#include <sys/systm.h>
24#include <sys/ioctl.h>
25#include <sys/proc.h>
26#include <sys/tty.h>
27#include <sys/conf.h>
28#include <sys/file.h>
29#include <sys/uio.h>
30#include <sys/kernel.h>
31#include <sys/syslog.h>
32
33#include <hp/dev/device.h>
34#include <hp/dev/dcareg.h>
35
36#include <machine/cpu.h>
7b7da76f 37#ifdef hp300
38a01dbe 38#include <hp300/hp300/isr.h>
7b7da76f
MH
39#endif
40#ifdef hp700
38a01dbe 41#include <machine/asp.h>
7b7da76f 42#endif
60f56dfc
KM
43
44int dcaprobe();
45struct driver dcadriver = {
46 dcaprobe, "dca",
47};
48
ed5ecb43
KM
49void dcastart();
50int dcaparam(), dcaintr();
60f56dfc
KM
51int dcasoftCAR;
52int dca_active;
9c7e9b26 53int dca_hasfifo;
60f56dfc 54int ndca = NDCA;
2723e1ed
MK
55#ifdef DCACONSOLE
56int dcaconsole = DCACONSOLE;
57#else
60f56dfc 58int dcaconsole = -1;
2723e1ed
MK
59#endif
60int dcaconsinit;
60f56dfc 61int dcadefaultrate = TTYDEF_SPEED;
2723e1ed 62int dcamajor;
60f56dfc
KM
63struct dcadevice *dca_addr[NDCA];
64struct tty dca_tty[NDCA];
7b7da76f 65#ifdef hp300
60f56dfc 66struct isr dcaisr[NDCA];
9c4040a3 67int dcafastservice;
7b7da76f 68#endif
9c4040a3 69int dcaoflows[NDCA];
60f56dfc
KM
70
71struct speedtab dcaspeedtab[] = {
72 0, 0,
73 50, DCABRD(50),
74 75, DCABRD(75),
75 110, DCABRD(110),
76 134, DCABRD(134),
77 150, DCABRD(150),
78 200, DCABRD(200),
79 300, DCABRD(300),
80 600, DCABRD(600),
81 1200, DCABRD(1200),
82 1800, DCABRD(1800),
83 2400, DCABRD(2400),
84 4800, DCABRD(4800),
85 9600, DCABRD(9600),
86 19200, DCABRD(19200),
87 38400, DCABRD(38400),
88 -1, -1
89};
90
60f56dfc 91#ifdef KGDB
38a01dbe 92#include <machine/remote-sl.h>
2723e1ed 93
05d25f26 94extern dev_t kgdb_dev;
60f56dfc
KM
95extern int kgdb_rate;
96extern int kgdb_debug_init;
97#endif
98
99#define UNIT(x) minor(x)
100
9c7e9b26
MH
101#ifdef DEBUG
102long fifoin[17];
103long fifoout[17];
104long dcaintrcount[16];
105long dcamintcount[16];
106#endif
107
60f56dfc
KM
108dcaprobe(hd)
109 register struct hp_device *hd;
110{
111 register struct dcadevice *dca;
112 register int unit;
113
114 dca = (struct dcadevice *)hd->hp_addr;
7b7da76f
MH
115#ifdef hp300
116 if (dca->dca_id != DCAID0 &&
117 dca->dca_id != DCAREMID0 &&
118 dca->dca_id != DCAID1 &&
119 dca->dca_id != DCAREMID1)
60f56dfc 120 return (0);
7b7da76f 121#endif
60f56dfc
KM
122 unit = hd->hp_unit;
123 if (unit == dcaconsole)
124 DELAY(100000);
7b7da76f
MH
125#ifdef hp300
126 dca->dca_reset = 0xFF;
60f56dfc 127 DELAY(100);
7b7da76f 128#endif
60f56dfc 129
9c7e9b26
MH
130 /* look for a NS 16550AF UART with FIFOs */
131 dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
132 DELAY(100);
133 if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
134 dca_hasfifo |= 1 << unit;
135
7b7da76f
MH
136 dca_addr[unit] = dca;
137#ifdef hp300
60f56dfc
KM
138 hd->hp_ipl = DCAIPL(dca->dca_ic);
139 dcaisr[unit].isr_ipl = hd->hp_ipl;
140 dcaisr[unit].isr_arg = unit;
141 dcaisr[unit].isr_intr = dcaintr;
60f56dfc 142 isrlink(&dcaisr[unit]);
7b7da76f
MH
143#endif
144 dca_active |= 1 << unit;
145 if (hd->hp_flags)
146 dcasoftCAR |= (1 << unit);
60f56dfc 147#ifdef KGDB
2723e1ed 148 if (kgdb_dev == makedev(dcamajor, unit)) {
60f56dfc 149 if (dcaconsole == unit)
05d25f26 150 kgdb_dev = NODEV; /* can't debug over console port */
60f56dfc 151 else {
2723e1ed 152 (void) dcainit(unit, kgdb_rate);
05d25f26 153 dcaconsinit = 1; /* don't re-init in dcaputc */
60f56dfc 154 if (kgdb_debug_init) {
2723e1ed
MK
155 /*
156 * Print prefix of device name,
157 * let kgdb_connect print the rest.
158 */
159 printf("dca%d: ", unit);
160 kgdb_connect(1);
60f56dfc
KM
161 } else
162 printf("dca%d: kgdb enabled\n", unit);
163 }
164 }
165#endif
7b7da76f 166#ifdef hp300
60f56dfc 167 dca->dca_ic = IC_IE;
7b7da76f 168#endif
60f56dfc 169 /*
2723e1ed
MK
170 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
171 * Also make sure console is always "hardwired."
60f56dfc
KM
172 */
173 if (unit == dcaconsole) {
2723e1ed 174 dcaconsinit = 0;
60f56dfc
KM
175 dcasoftCAR |= (1 << unit);
176 }
177 return (1);
178}
179
2723e1ed
MK
180/* ARGSUSED */
181#ifdef __STDC__
182dcaopen(dev_t dev, int flag, int mode, struct proc *p)
183#else
184dcaopen(dev, flag, mode, p)
60f56dfc 185 dev_t dev;
2723e1ed
MK
186 int flag, mode;
187 struct proc *p;
188#endif
60f56dfc
KM
189{
190 register struct tty *tp;
191 register int unit;
037e7e94 192 int error = 0;
60f56dfc
KM
193
194 unit = UNIT(dev);
195 if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
196 return (ENXIO);
197 tp = &dca_tty[unit];
198 tp->t_oproc = dcastart;
199 tp->t_param = dcaparam;
200 tp->t_dev = dev;
201 if ((tp->t_state & TS_ISOPEN) == 0) {
c98f3d99 202 tp->t_state |= TS_WOPEN;
60f56dfc 203 ttychars(tp);
2723e1ed
MK
204 if (tp->t_ispeed == 0) {
205 tp->t_iflag = TTYDEF_IFLAG;
206 tp->t_oflag = TTYDEF_OFLAG;
207 tp->t_cflag = TTYDEF_CFLAG;
208 tp->t_lflag = TTYDEF_LFLAG;
209 tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
210 }
60f56dfc
KM
211 dcaparam(tp, &tp->t_termios);
212 ttsetwater(tp);
2723e1ed 213 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
60f56dfc
KM
214 return (EBUSY);
215 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
216 if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
217 tp->t_state |= TS_CARR_ON;
218 (void) spltty();
23166e33 219 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
60f56dfc
KM
220 (tp->t_state & TS_CARR_ON) == 0) {
221 tp->t_state |= TS_WOPEN;
23166e33
MH
222 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
223 ttopen, 0))
224 break;
60f56dfc
KM
225 }
226 (void) spl0();
23166e33
MH
227 if (error == 0)
228 error = (*linesw[tp->t_line].l_open)(dev, tp);
9c4040a3
MH
229#ifdef hp300
230 /*
231 * XXX hack to speed up unbuffered builtin port.
232 * If dca_fastservice is set, a level 5 interrupt
233 * will be directed to dcaintr first.
234 */
235 if (error == 0 && unit == 0 && (dca_hasfifo & 1) == 0)
236 dcafastservice = 1;
237#endif
23166e33 238 return (error);
60f56dfc
KM
239}
240
241/*ARGSUSED*/
f5daa13d 242dcaclose(dev, flag, mode, p)
60f56dfc 243 dev_t dev;
f5daa13d
MT
244 int flag, mode;
245 struct proc *p;
60f56dfc
KM
246{
247 register struct tty *tp;
248 register struct dcadevice *dca;
249 register int unit;
250
251 unit = UNIT(dev);
9c4040a3
MH
252#ifdef hp300
253 if (unit == 0)
254 dcafastservice = 0;
255#endif
60f56dfc
KM
256 dca = dca_addr[unit];
257 tp = &dca_tty[unit];
f5daa13d 258 (*linesw[tp->t_line].l_close)(tp, flag);
60f56dfc
KM
259 dca->dca_cfcr &= ~CFCR_SBREAK;
260#ifdef KGDB
261 /* do not disable interrupts if debugging */
2723e1ed 262 if (dev != kgdb_dev)
60f56dfc
KM
263#endif
264 dca->dca_ier = 0;
05d25f26
MK
265 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
266 (tp->t_state&TS_ISOPEN) == 0)
267 (void) dcamctl(dev, 0, DMSET);
60f56dfc 268 ttyclose(tp);
05d25f26 269 return (0);
60f56dfc
KM
270}
271
272dcaread(dev, uio, flag)
273 dev_t dev;
274 struct uio *uio;
275{
9c4040a3
MH
276 int unit = UNIT(dev);
277 register struct tty *tp = &dca_tty[unit];
278 int error, of;
60f56dfc 279
9c4040a3
MH
280 of = dcaoflows[unit];
281 error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
282 /*
283 * XXX hardly a reasonable thing to do, but reporting overflows
284 * at interrupt time just exacerbates the problem.
285 */
286 if (dcaoflows[unit] != of)
287 log(LOG_WARNING, "dca%d: silo overflow\n", unit);
288 return (error);
60f56dfc
KM
289}
290
291dcawrite(dev, uio, flag)
292 dev_t dev;
293 struct uio *uio;
294{
295 int unit = UNIT(dev);
296 register struct tty *tp = &dca_tty[unit];
7b7da76f 297 extern struct tty *constty;
60f56dfc 298
fdf2ec5d
KM
299 /*
300 * (XXX) We disallow virtual consoles if the physical console is
301 * a serial port. This is in case there is a display attached that
302 * is not the console. In that situation we don't need/want the X
303 * server taking over the console.
304 */
305 if (constty && unit == dcaconsole)
306 constty = NULL;
60f56dfc
KM
307 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
308}
309
310dcaintr(unit)
311 register int unit;
312{
313 register struct dcadevice *dca;
05a2e58f
MH
314 register u_char code;
315 register struct tty *tp;
9c4040a3 316 int iflowdone = 0;
60f56dfc
KM
317
318 dca = dca_addr[unit];
7b7da76f
MH
319#ifdef hp300
320 if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
05d25f26 321 return (0);
7b7da76f 322#endif
9c4040a3 323 tp = &dca_tty[unit];
05a2e58f
MH
324 while (1) {
325 code = dca->dca_iir;
9c7e9b26
MH
326#ifdef DEBUG
327 dcaintrcount[code & IIR_IMASK]++;
328#endif
329 switch (code & IIR_IMASK) {
05a2e58f
MH
330 case IIR_NOPEND:
331 return (1);
9c7e9b26 332 case IIR_RXTOUT:
05a2e58f
MH
333 case IIR_RXRDY:
334 /* do time-critical read in-line */
9c7e9b26
MH
335/*
336 * Process a received byte. Inline for speed...
337 */
05a2e58f 338#ifdef KGDB
9c7e9b26
MH
339#define RCVBYTE() \
340 code = dca->dca_data; \
341 if ((tp->t_state & TS_ISOPEN) == 0) { \
05d25f26
MK
342 if (code == FRAME_END && \
343 kgdb_dev == makedev(dcamajor, unit)) \
9c7e9b26
MH
344 kgdb_connect(0); /* trap into kgdb */ \
345 } else \
346 (*linesw[tp->t_line].l_rint)(code, tp)
347#else
348#define RCVBYTE() \
349 code = dca->dca_data; \
350 if ((tp->t_state & TS_ISOPEN) != 0) \
351 (*linesw[tp->t_line].l_rint)(code, tp)
05a2e58f 352#endif
9c7e9b26
MH
353 RCVBYTE();
354 if (dca_hasfifo & (1 << unit)) {
355#ifdef DEBUG
356 register int fifocnt = 1;
357#endif
358 while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
359 if (code == LSR_RXRDY) {
360 RCVBYTE();
361 } else
362 dcaeint(unit, code, dca);
363#ifdef DEBUG
364 fifocnt++;
365#endif
366 }
367#ifdef DEBUG
368 if (fifocnt > 16)
369 fifoin[0]++;
370 else
371 fifoin[fifocnt]++;
372#endif
373 }
9c4040a3
MH
374 if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
375 tp->t_rawq.c_cc > TTYHOG/2) {
376 dca->dca_mcr &= ~MCR_RTS;
377 iflowdone = 1;
378 }
05a2e58f
MH
379 break;
380 case IIR_TXRDY:
05a2e58f
MH
381 tp->t_state &=~ (TS_BUSY|TS_FLUSH);
382 if (tp->t_line)
383 (*linesw[tp->t_line].l_start)(tp);
384 else
385 dcastart(tp);
386 break;
387 case IIR_RLS:
9c7e9b26 388 dcaeint(unit, dca->dca_lsr, dca);
05a2e58f
MH
389 break;
390 default:
391 if (code & IIR_NOPEND)
392 return (1);
393 log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
394 unit, code);
395 /* fall through */
396 case IIR_MLSC:
60f56dfc 397 dcamint(unit, dca);
05a2e58f
MH
398 break;
399 }
60f56dfc 400 }
60f56dfc
KM
401}
402
9c7e9b26
MH
403dcaeint(unit, stat, dca)
404 register int unit, stat;
60f56dfc
KM
405 register struct dcadevice *dca;
406{
407 register struct tty *tp;
9c7e9b26 408 register int c;
60f56dfc
KM
409
410 tp = &dca_tty[unit];
05a2e58f 411 c = dca->dca_data;
60f56dfc
KM
412 if ((tp->t_state & TS_ISOPEN) == 0) {
413#ifdef KGDB
414 /* we don't care about parity errors */
415 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
2723e1ed
MK
416 kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
417 kgdb_connect(0); /* trap into kgdb */
60f56dfc
KM
418#endif
419 return;
420 }
421 if (stat & (LSR_BI | LSR_FE))
422 c |= TTY_FE;
423 else if (stat & LSR_PE)
424 c |= TTY_PE;
425 else if (stat & LSR_OE)
9c4040a3 426 dcaoflows[unit]++;
60f56dfc
KM
427 (*linesw[tp->t_line].l_rint)(c, tp);
428}
429
60f56dfc
KM
430dcamint(unit, dca)
431 register int unit;
432 register struct dcadevice *dca;
433{
434 register struct tty *tp;
7b7da76f 435 register u_char stat;
60f56dfc
KM
436
437 tp = &dca_tty[unit];
438 stat = dca->dca_msr;
9c7e9b26
MH
439#ifdef DEBUG
440 dcamintcount[stat & 0xf]++;
441#endif
9c4040a3
MH
442 if ((stat & MSR_DDCD) &&
443 (dcasoftCAR & (1 << unit)) == 0) {
60f56dfc 444 if (stat & MSR_DCD)
05a2e58f 445 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
60f56dfc
KM
446 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
447 dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
9c4040a3
MH
448 }
449 /*
450 * CTS change.
451 * If doing HW output flow control start/stop output as appropriate.
452 */
453 if ((stat & MSR_DCTS) &&
454 (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
05a2e58f
MH
455 if (stat & MSR_CTS) {
456 tp->t_state &=~ TS_TTSTOP;
9c4040a3
MH
457 dcastart(tp);
458 } else {
05a2e58f 459 tp->t_state |= TS_TTSTOP;
9c4040a3 460 }
60f56dfc
KM
461 }
462}
463
9aceb128 464dcaioctl(dev, cmd, data, flag, p)
60f56dfc 465 dev_t dev;
9aceb128 466 int cmd;
60f56dfc 467 caddr_t data;
9aceb128
KM
468 int flag;
469 struct proc *p;
60f56dfc
KM
470{
471 register struct tty *tp;
472 register int unit = UNIT(dev);
473 register struct dcadevice *dca;
474 register int error;
475
476 tp = &dca_tty[unit];
9aceb128 477 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
60f56dfc
KM
478 if (error >= 0)
479 return (error);
480 error = ttioctl(tp, cmd, data, flag);
481 if (error >= 0)
482 return (error);
483
484 dca = dca_addr[unit];
485 switch (cmd) {
486
487 case TIOCSBRK:
488 dca->dca_cfcr |= CFCR_SBREAK;
489 break;
490
491 case TIOCCBRK:
492 dca->dca_cfcr &= ~CFCR_SBREAK;
493 break;
494
495 case TIOCSDTR:
496 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
497 break;
498
499 case TIOCCDTR:
500 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
501 break;
502
503 case TIOCMSET:
504 (void) dcamctl(dev, *(int *)data, DMSET);
505 break;
506
507 case TIOCMBIS:
508 (void) dcamctl(dev, *(int *)data, DMBIS);
509 break;
510
511 case TIOCMBIC:
512 (void) dcamctl(dev, *(int *)data, DMBIC);
513 break;
514
515 case TIOCMGET:
516 *(int *)data = dcamctl(dev, 0, DMGET);
517 break;
518
519 default:
520 return (ENOTTY);
521 }
522 return (0);
523}
524
525dcaparam(tp, t)
526 register struct tty *tp;
527 register struct termios *t;
528{
529 register struct dcadevice *dca;
530 register int cfcr, cflag = t->c_cflag;
531 int unit = UNIT(tp->t_dev);
532 int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
533
534 /* check requested parameters */
535 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
05d25f26 536 return (EINVAL);
60f56dfc
KM
537 /* and copy to tty */
538 tp->t_ispeed = t->c_ispeed;
539 tp->t_ospeed = t->c_ospeed;
540 tp->t_cflag = cflag;
541
542 dca = dca_addr[unit];
543 dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
7b7da76f
MH
544#ifdef hp700
545 dca->dca_mcr |= MCR_IEN;
546#endif
60f56dfc
KM
547 if (ospeed == 0) {
548 (void) dcamctl(unit, 0, DMSET); /* hang up line */
05d25f26 549 return (0);
60f56dfc
KM
550 }
551 dca->dca_cfcr |= CFCR_DLAB;
552 dca->dca_data = ospeed & 0xFF;
553 dca->dca_ier = ospeed >> 8;
554 switch (cflag&CSIZE) {
555 case CS5:
556 cfcr = CFCR_5BITS; break;
557 case CS6:
558 cfcr = CFCR_6BITS; break;
559 case CS7:
560 cfcr = CFCR_7BITS; break;
561 case CS8:
562 cfcr = CFCR_8BITS; break;
563 }
564 if (cflag&PARENB) {
565 cfcr |= CFCR_PENAB;
566 if ((cflag&PARODD) == 0)
567 cfcr |= CFCR_PEVEN;
568 }
569 if (cflag&CSTOPB)
570 cfcr |= CFCR_STOPB;
571 dca->dca_cfcr = cfcr;
9c7e9b26
MH
572 if (dca_hasfifo & (1 << unit))
573 dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
05d25f26 574 return (0);
60f56dfc
KM
575}
576
ed5ecb43 577void
60f56dfc
KM
578dcastart(tp)
579 register struct tty *tp;
580{
581 register struct dcadevice *dca;
582 int s, unit, c;
583
584 unit = UNIT(tp->t_dev);
585 dca = dca_addr[unit];
586 s = spltty();
05a2e58f 587 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
60f56dfc
KM
588 goto out;
589 if (tp->t_outq.c_cc <= tp->t_lowat) {
590 if (tp->t_state&TS_ASLEEP) {
591 tp->t_state &= ~TS_ASLEEP;
592 wakeup((caddr_t)&tp->t_outq);
593 }
2d32402a 594 selwakeup(&tp->t_wsel);
60f56dfc
KM
595 }
596 if (tp->t_outq.c_cc == 0)
597 goto out;
05a2e58f
MH
598 if (dca->dca_lsr & LSR_TXRDY) {
599 c = getc(&tp->t_outq);
600 tp->t_state |= TS_BUSY;
601 dca->dca_data = c;
9c7e9b26
MH
602 if (dca_hasfifo & (1 << unit)) {
603 for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
604 dca->dca_data = getc(&tp->t_outq);
605#ifdef DEBUG
606 if (c > 16)
607 fifoout[0]++;
608 else
609 fifoout[c]++;
610#endif
611 }
05a2e58f 612 }
60f56dfc
KM
613out:
614 splx(s);
615}
616
617/*
618 * Stop output on a line.
619 */
620/*ARGSUSED*/
621dcastop(tp, flag)
622 register struct tty *tp;
623{
624 register int s;
625
626 s = spltty();
627 if (tp->t_state & TS_BUSY) {
628 if ((tp->t_state&TS_TTSTOP)==0)
629 tp->t_state |= TS_FLUSH;
630 }
631 splx(s);
632}
633
634dcamctl(dev, bits, how)
635 dev_t dev;
636 int bits, how;
637{
638 register struct dcadevice *dca;
639 register int unit;
640 int s;
641
642 unit = UNIT(dev);
643 dca = dca_addr[unit];
7b7da76f
MH
644#ifdef hp700
645 /*
646 * Always make sure MCR_IEN is set (unless setting to 0)
647 */
648#ifdef KGDB
649 if (how == DMSET && kgdb_dev == makedev(dcamajor, unit))
650 bits |= MCR_IEN;
651 else
652#endif
653 if (how == DMBIS || (how == DMSET && bits))
654 bits |= MCR_IEN;
655 else if (how == DMBIC)
656 bits &= ~MCR_IEN;
657#endif
60f56dfc
KM
658 s = spltty();
659 switch (how) {
660
661 case DMSET:
662 dca->dca_mcr = bits;
663 break;
664
665 case DMBIS:
666 dca->dca_mcr |= bits;
667 break;
668
669 case DMBIC:
670 dca->dca_mcr &= ~bits;
671 break;
672
673 case DMGET:
674 bits = dca->dca_msr;
675 break;
676 }
677 (void) splx(s);
05d25f26 678 return (bits);
60f56dfc
KM
679}
680
681/*
682 * Following are all routines needed for DCA to act as console
683 */
38a01dbe 684#include <hp/dev/cons.h>
60f56dfc
KM
685
686dcacnprobe(cp)
687 struct consdev *cp;
688{
9c7e9b26 689 int unit;
2723e1ed
MK
690
691 /* locate the major number */
692 for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
693 if (cdevsw[dcamajor].d_open == dcaopen)
694 break;
60f56dfc
KM
695
696 /* XXX: ick */
697 unit = CONUNIT;
7b7da76f 698#ifdef hp300
9c7e9b26 699 dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
60f56dfc
KM
700
701 /* make sure hardware exists */
702 if (badaddr((short *)dca_addr[unit])) {
703 cp->cn_pri = CN_DEAD;
704 return;
705 }
7b7da76f
MH
706#endif
707#ifdef hp700
708 dca_addr[CONUNIT] = CONPORT;
709#endif
60f56dfc 710
60f56dfc 711 /* initialize required fields */
2723e1ed 712 cp->cn_dev = makedev(dcamajor, unit);
60f56dfc 713 cp->cn_tp = &dca_tty[unit];
7b7da76f
MH
714#ifdef hp300
715 switch (dca_addr[unit]->dca_id) {
60f56dfc
KM
716 case DCAID0:
717 case DCAID1:
718 cp->cn_pri = CN_NORMAL;
719 break;
720 case DCAREMID0:
721 case DCAREMID1:
722 cp->cn_pri = CN_REMOTE;
723 break;
724 default:
725 cp->cn_pri = CN_DEAD;
726 break;
727 }
7b7da76f
MH
728#endif
729#ifdef hp700
730 cp->cn_pri = CN_NORMAL;
731#endif
2723e1ed 732 /*
9c7e9b26 733 * If dcaconsole is initialized, raise our priority.
2723e1ed
MK
734 */
735 if (dcaconsole == unit)
736 cp->cn_pri = CN_REMOTE;
9c7e9b26 737#ifdef KGDB
2723e1ed
MK
738 if (major(kgdb_dev) == 1) /* XXX */
739 kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
9c7e9b26 740#endif
60f56dfc
KM
741}
742
743dcacninit(cp)
744 struct consdev *cp;
745{
746 int unit = UNIT(cp->cn_dev);
747
2723e1ed 748 dcainit(unit, dcadefaultrate);
60f56dfc 749 dcaconsole = unit;
2723e1ed 750 dcaconsinit = 1;
60f56dfc
KM
751}
752
2723e1ed
MK
753dcainit(unit, rate)
754 int unit, rate;
60f56dfc
KM
755{
756 register struct dcadevice *dca;
2723e1ed 757 int s;
60f56dfc
KM
758 short stat;
759
760#ifdef lint
761 stat = unit; if (stat) return;
762#endif
763 dca = dca_addr[unit];
764 s = splhigh();
7b7da76f
MH
765#ifdef hp300
766 dca->dca_reset = 0xFF;
60f56dfc
KM
767 DELAY(100);
768 dca->dca_ic = IC_IE;
7b7da76f 769#endif
60f56dfc 770 dca->dca_cfcr = CFCR_DLAB;
2723e1ed 771 rate = ttspeedtab(rate, dcaspeedtab);
60f56dfc
KM
772 dca->dca_data = rate & 0xFF;
773 dca->dca_ier = rate >> 8;
774 dca->dca_cfcr = CFCR_8BITS;
775 dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
7b7da76f
MH
776#ifdef hp700
777 dca->dca_mcr |= MCR_IEN;
778#endif
9c7e9b26 779 dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
7b7da76f 780 DELAY(100);
60f56dfc
KM
781 stat = dca->dca_iir;
782 splx(s);
783}
784
785dcacngetc(dev)
786{
787 register struct dcadevice *dca = dca_addr[UNIT(dev)];
7b7da76f 788 register u_char stat;
60f56dfc
KM
789 int c, s;
790
791#ifdef lint
05d25f26 792 stat = dev; if (stat) return (0);
60f56dfc
KM
793#endif
794 s = splhigh();
795 while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
796 ;
797 c = dca->dca_data;
798 stat = dca->dca_iir;
799 splx(s);
05d25f26 800 return (c);
60f56dfc
KM
801}
802
803/*
804 * Console kernel output character routine.
805 */
806dcacnputc(dev, c)
807 dev_t dev;
808 register int c;
809{
810 register struct dcadevice *dca = dca_addr[UNIT(dev)];
811 register int timo;
7b7da76f 812 register u_char stat;
60f56dfc
KM
813 int s = splhigh();
814
815#ifdef lint
816 stat = dev; if (stat) return;
2723e1ed
MK
817#endif
818 if (dcaconsinit == 0) {
819 (void) dcainit(UNIT(dev), dcadefaultrate);
820 dcaconsinit = 1;
60f56dfc
KM
821 }
822 /* wait for any pending transmission to finish */
823 timo = 50000;
824 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
825 ;
826 dca->dca_data = c;
827 /* wait for this transmission to complete */
828 timo = 1500000;
829 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
830 ;
7b7da76f
MH
831 /*
832 * If the "normal" interface was busy transfering a character
833 * we must let our interrupt through to keep things moving.
834 * Otherwise, we clear the interrupt that we have caused.
835 */
836 if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0)
837 stat = dca->dca_iir;
60f56dfc
KM
838 splx(s);
839}
840#endif