xref: /original-bsd/sys/hp300/dev/dcm.c (revision c829ecf6)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: $Hdr: dcm.c 1.17 89/10/01$
13  *
14  *	@(#)dcm.c	7.4 (Berkeley) 06/06/90
15  */
16 
17 /*
18  * TODO:
19  *	Timeouts
20  *	Test console/kgdb support.
21  */
22 
23 #include "dcm.h"
24 #if NDCM > 0
25 /*
26  *  98642/MUX
27  */
28 #include "param.h"
29 #include "systm.h"
30 #include "ioctl.h"
31 #include "tty.h"
32 #include "user.h"
33 #include "conf.h"
34 #include "file.h"
35 #include "uio.h"
36 #include "kernel.h"
37 #include "syslog.h"
38 #include "time.h"
39 
40 #include "device.h"
41 #include "dcmreg.h"
42 #include "machine/cpu.h"
43 #include "machine/isr.h"
44 
45 #ifndef DEFAULT_BAUD_RATE
46 #define DEFAULT_BAUD_RATE 9600
47 #endif
48 
49 int	ttrstrt();
50 int	dcmprobe(), dcmstart(), dcmintr(), dcmparam();
51 
52 struct	driver dcmdriver = {
53 	dcmprobe, "dcm",
54 };
55 
56 #define NDCMLINE (NDCM*4)
57 
58 struct	tty dcm_tty[NDCMLINE];
59 int	ndcm = NDCMLINE;
60 
61 int	dcm_active;
62 int	dcmsoftCAR[NDCM];
63 struct	dcmdevice *dcm_addr[NDCM];
64 struct	isr dcmisr[NDCM];
65 
66 struct speedtab dcmspeedtab[] = {
67 	0,	BR_0,
68 	50,	BR_50,
69 	75,	BR_75,
70 	110,	BR_110,
71 	134,	BR_134,
72 	150,	BR_150,
73 	300,	BR_300,
74 	600,	BR_600,
75 	1200,	BR_1200,
76 	1800,	BR_1800,
77 	2400,	BR_2400,
78 	4800,	BR_4800,
79 	9600,	BR_9600,
80 	19200,	BR_19200,
81 	38400,	BR_38400,
82 	-1,	-1
83 };
84 
85 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
86 #define	DCM_USPERCH(s)	(10000000 / (s))
87 
88 /*
89  * Per board interrupt scheme.  16.7ms is the polling interrupt rate
90  * (16.7ms is about 550 buad, 38.4k is 72 chars in 16.7ms).
91  */
92 #define DIS_TIMER	0
93 #define DIS_PERCHAR	1
94 #define DIS_RESET	2
95 
96 int	dcmistype = -1;		/* -1 == dynamic, 0 == timer, 1 == perchar */
97 int     dcminterval = 5;	/* interval (secs) between checks */
98 struct	dcmischeme {
99 	int	dis_perchar;	/* non-zero if interrupting per char */
100 	long	dis_time;	/* last time examined */
101 	int	dis_intr;	/* recv interrupts during last interval */
102 	int	dis_char;	/* characters read during last interval */
103 } dcmischeme[NDCM];
104 
105 /*
106  * Console support
107  */
108 int	dcmconsole = -1;
109 int	dcmdefaultrate = DEFAULT_BAUD_RATE;
110 int	dcmconbrdbusy = 0;
111 extern	struct tty *constty;
112 
113 #ifdef KGDB
114 /*
115  * Kernel GDB support
116  */
117 extern int kgdb_dev;
118 extern int kgdb_rate;
119 extern int kgdb_debug_init;
120 #endif
121 
122 /* #define IOSTATS */
123 
124 #ifdef DEBUG
125 int	dcmdebug = 0x00;
126 #define DDB_SIOERR	0x01
127 #define DDB_PARAM	0x02
128 #define DDB_INPUT	0x04
129 #define DDB_OUTPUT	0x08
130 #define DDB_INTR	0x10
131 #define DDB_IOCTL	0x20
132 #define DDB_INTSCHM	0x40
133 #define DDB_MODEM	0x80
134 #define DDB_OPENCLOSE	0x100
135 #endif
136 
137 #ifdef IOSTATS
138 #define	DCMRBSIZE	94
139 #define DCMXBSIZE	24
140 
141 struct	dcmstats {
142 	long	xints;		    /* # of xmit ints */
143 	long	xchars;		    /* # of xmit chars */
144 	long	xempty;		    /* times outq is empty in dcmstart */
145 	long	xrestarts;	    /* times completed while xmitting */
146 	long	rints;		    /* # of recv ints */
147 	long	rchars;		    /* # of recv chars */
148 	long	xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
149 	long	rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
150 } dcmstats[NDCM];
151 #endif
152 
153 #define UNIT(x)		minor(x)
154 #define	BOARD(x)	(((x) >> 2) & 0x3f)
155 #define PORT(x)		((x) & 3)
156 #define MKUNIT(b,p)	(((b) << 2) | (p))
157 
158 dcmprobe(hd)
159 	register struct hp_device *hd;
160 {
161 	register struct dcmdevice *dcm;
162 	register int i;
163 	register int timo = 0;
164 	int s, brd, isconsole;
165 
166 	dcm = (struct dcmdevice *)hd->hp_addr;
167 	if ((dcm->dcm_rsid & 0x1f) != DCMID)
168 		return (0);
169 	brd = hd->hp_unit;
170 	isconsole = (brd == BOARD(dcmconsole));
171 	/*
172 	 * XXX selected console device (CONSUNIT) as determined by
173 	 * dcmcnprobe does not agree with logical numbering imposed
174 	 * by the config file (i.e. lowest address DCM is not unit
175 	 * CONSUNIT).  Don't recognize this card.
176 	 */
177 	if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)])
178 		return(0);
179 
180 	/*
181 	 * Empirically derived self-test magic
182 	 */
183 	s = spltty();
184 	dcm->dcm_rsid = DCMRS;
185 	DELAY(50000);	/* 5000 is not long enough */
186 	dcm->dcm_rsid = 0;
187 	dcm->dcm_ic = IC_IE;
188 	dcm->dcm_cr = CR_SELFT;
189 	while ((dcm->dcm_ic & IC_IR) == 0)
190 		if (++timo == 20000)
191 			return(0);
192 	DELAY(50000)	/* XXX why is this needed ???? */
193 	while ((dcm->dcm_iir & IIR_SELFT) == 0)
194 		if (++timo == 400000)
195 			return(0);
196 	DELAY(50000)	/* XXX why is this needed ???? */
197 	if (dcm->dcm_stcon != ST_OK) {
198 		if (!isconsole)
199 			printf("dcm%d: self test failed: %x\n",
200 			       brd, dcm->dcm_stcon);
201 		return(0);
202 	}
203 	dcm->dcm_ic = IC_ID;
204 	splx(s);
205 
206 	hd->hp_ipl = DCMIPL(dcm->dcm_ic);
207 	dcm_addr[brd] = dcm;
208 	dcm_active |= 1 << brd;
209 	dcmsoftCAR[brd] = hd->hp_flags;
210 	dcmisr[brd].isr_ipl = hd->hp_ipl;
211 	dcmisr[brd].isr_arg = brd;
212 	dcmisr[brd].isr_intr = dcmintr;
213 	isrlink(&dcmisr[brd]);
214 #ifdef KGDB
215 	if (major(kgdb_dev) == 2 && BOARD(kgdb_dev) == brd) {
216 		if (dcmconsole == UNIT(kgdb_dev))
217 			kgdb_dev = -1;	/* can't debug over console port */
218 		else {
219 			(void) dcminit(kgdb_dev, kgdb_rate);
220 			if (kgdb_debug_init) {
221 				printf("dcm%d: kgdb waiting...",
222 				       UNIT(kgdb_dev));
223 				/* trap into kgdb */
224 				asm("trap #15;");
225 				printf("connected.\n");
226 			} else
227 				printf("dcm%d: kgdb enabled\n",
228 				       UNIT(kgdb_dev));
229 		}
230 	}
231 #endif
232 	if (dcmistype == DIS_TIMER)
233 		dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
234 	else
235 		dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
236 	dcm->dcm_mdmmsk = MI_CD;	/* enable modem carrier detect intr */
237 	dcm->dcm_ic = IC_IE;		/* turn all interrupts on */
238 	/*
239 	 * Need to reset baud rate, etc. of next print so reset dcmconsole.
240 	 * Also make sure console is always "hardwired"
241 	 */
242 	if (isconsole) {
243 		dcmconsole = -1;
244 		dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
245 	}
246 	return (1);
247 }
248 
249 dcmopen(dev, flag)
250 	dev_t dev;
251 {
252 	register struct tty *tp;
253 	register int unit, brd;
254 	int error;
255 
256 	unit = UNIT(dev);
257 	brd = BOARD(unit);
258 	if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0)
259 		return (ENXIO);
260 #ifdef KGDB
261 	if (unit == UNIT(kgdb_dev))
262 		return (EBUSY);
263 #endif
264 	tp = &dcm_tty[unit];
265 	tp->t_oproc = dcmstart;
266 	tp->t_param = dcmparam;
267 	tp->t_dev = dev;
268 	if ((tp->t_state & TS_ISOPEN) == 0) {
269 		tp->t_state |= TS_WOPEN;
270 		ttychars(tp);
271 		tp->t_iflag = TTYDEF_IFLAG;
272 		tp->t_oflag = TTYDEF_OFLAG;
273 		tp->t_cflag = TTYDEF_CFLAG;
274 		tp->t_lflag = TTYDEF_LFLAG;
275 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
276 		(void) dcmparam(tp, &tp->t_termios);
277 		ttsetwater(tp);
278 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
279 		return (EBUSY);
280 	if (PORT(unit) == 0)	/* enable port 0 */
281 		(void) dcmmctl(dev, MO_ON, DMSET);
282 	if (dcmsoftCAR[brd] & (1 << PORT(unit)))
283 		tp->t_state |= TS_CARR_ON;
284 	else if (PORT(unit))		/* Only port 0 has modem control */
285 		tp->t_state |= TS_CARR_ON;
286 	else if (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)
287 		tp->t_state |= TS_CARR_ON;
288 	(void) spltty();
289 	while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
290 	       (tp->t_state & TS_CARR_ON) == 0) {
291 		tp->t_state |= TS_WOPEN;
292 		if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
293 				   ttopen, 0)) ||
294 		    (error = ttclosed(tp))) {
295 			tp->t_state &= ~TS_WOPEN;
296 			(void) spl0();
297 			return (error);
298 		}
299 	}
300 	(void) spl0();
301 
302 #ifdef DEBUG
303 	if (dcmdebug & DDB_OPENCLOSE)
304 		printf("dcmopen: u %x st %x fl %x\n",
305 			unit, tp->t_state, tp->t_flags);
306 #endif
307 	return ((*linesw[tp->t_line].l_open)(dev, tp));
308 }
309 
310 /*ARGSUSED*/
311 dcmclose(dev, flag)
312 	dev_t dev;
313 {
314 	register struct tty *tp;
315 	int unit;
316 
317 	unit = UNIT(dev);
318 	tp = &dcm_tty[unit];
319 	(*linesw[tp->t_line].l_close)(tp);
320 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
321 	    (tp->t_state&TS_ISOPEN) == 0)
322 		(void) dcmmctl(dev, MO_OFF, DMSET);
323 #ifdef DEBUG
324 	if (dcmdebug & DDB_OPENCLOSE)
325 		printf("dcmclose: u %x st %x fl %x\n",
326 			unit, tp->t_state, tp->t_flags);
327 #endif
328 	ttyclose(tp);
329 	return(0);
330 }
331 
332 dcmread(dev, uio, flag)
333 	dev_t dev;
334 	struct uio *uio;
335 {
336 	register struct tty *tp;
337 
338 	tp = &dcm_tty[UNIT(dev)];
339 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
340 }
341 
342 dcmwrite(dev, uio, flag)
343 	dev_t dev;
344 	struct uio *uio;
345 {
346 	int unit = UNIT(dev);
347 	register struct tty *tp;
348 
349 	tp = &dcm_tty[unit];
350 	/*
351 	 * XXX we disallow virtual consoles if the physical console is
352 	 * a serial port.  This is in case there is a display attached that
353 	 * is not the console.  In that situation we don't need/want the X
354 	 * server taking over the console.
355 	 */
356 	if (constty && unit == dcmconsole)
357 		constty = NULL;
358 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
359 }
360 
361 dcmintr(brd)
362 	register int brd;
363 {
364 	register struct dcmdevice *dcm = dcm_addr[brd];
365 	register struct dcmischeme *dis;
366 	int i, code, pcnd[4], mcnd, delta;
367 
368 	/*
369 	 * Do all guarded register accesses right off to minimize
370 	 * block out of hardware.
371 	 */
372 	SEM_LOCK(dcm);
373 	if ((dcm->dcm_ic & IC_IR) == 0) {
374 		SEM_UNLOCK(dcm);
375 		return(0);
376 	}
377 	for (i = 0; i < 4; i++) {
378 		pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
379 		dcm->dcm_icrtab[i].dcm_data = 0;
380 	}
381 	mcnd = dcm->dcm_mdmin;
382 	code = dcm->dcm_iir & IIR_MASK;
383 	dcm->dcm_iir = 0;	/* XXX doc claims read clears interrupt?! */
384 	SEM_UNLOCK(dcm);
385 
386 #ifdef DEBUG
387 	if (dcmdebug & DDB_INTR)
388 		printf("dcmintr(%d): iir %x p0 %x p1 %x p2 %x p3 %x m %x\n",
389 		       brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3], mcnd);
390 #endif
391 	if (code & IIR_TIMEO)
392 		dcmrint(brd, dcm);
393 	if (code & IIR_PORT0)
394 		dcmpint(MKUNIT(brd, 0), pcnd[0], dcm);
395 	if (code & IIR_PORT1)
396 		dcmpint(MKUNIT(brd, 1), pcnd[1],  dcm);
397 	if (code & IIR_PORT2)
398 		dcmpint(MKUNIT(brd, 2), pcnd[2], dcm);
399 	if (code & IIR_PORT3)
400 		dcmpint(MKUNIT(brd, 3), pcnd[3], dcm);
401 	if (code & IIR_MODM)
402 		dcmmint(MKUNIT(brd, 0), mcnd, dcm);	/* always port 0 */
403 
404 	dis = &dcmischeme[brd];
405 	/*
406 	 * Chalk up a receiver interrupt if the timer running or one of
407 	 * the ports reports a special character interrupt.
408 	 */
409 	if ((code & IIR_TIMEO) ||
410 	    ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
411 		dis->dis_intr++;
412 	/*
413 	 * See if it is time to check/change the interrupt rate.
414 	 */
415 	if (dcmistype < 0 &&
416 	    (delta = time.tv_sec - dis->dis_time) >= dcminterval) {
417 		/*
418 		 * If currently per-character and averaged over 70 interrupts
419 		 * per-second (66 is threshold of 600 baud) in last interval,
420 		 * switch to timer mode.
421 		 *
422 		 * XXX decay counts ala load average to avoid spikes?
423 		 */
424 		if (dis->dis_perchar && dis->dis_intr > 70 * delta)
425 			dcmsetischeme(brd, DIS_TIMER);
426 		/*
427 		 * If currently using timer and had more interrupts than
428 		 * received characters in the last interval, switch back
429 		 * to per-character.  Note that after changing to per-char
430 		 * we must process any characters already in the queue
431 		 * since they may have arrived before the bitmap was setup.
432 		 *
433 		 * XXX decay counts?
434 		 */
435 		else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
436 			dcmsetischeme(brd, DIS_PERCHAR);
437 			dcmrint(brd, dcm);
438 		}
439 		dis->dis_intr = dis->dis_char = 0;
440 		dis->dis_time = time.tv_sec;
441 	}
442 	return(1);
443 }
444 
445 /*
446  *  Port interrupt.  Can be two things:
447  *	First, it might be a special character (exception interrupt);
448  *	Second, it may be a buffer empty (transmit interrupt);
449  */
450 dcmpint(unit, code, dcm)
451 	int unit, code;
452 	struct dcmdevice *dcm;
453 {
454 	struct tty *tp = &dcm_tty[unit];
455 
456 	if (code & IT_SPEC)
457 		dcmreadbuf(unit, dcm, tp);
458 	if (code & IT_TX)
459 		dcmxint(unit, dcm, tp);
460 }
461 
462 dcmrint(brd, dcm)
463 	int brd;
464 	register struct dcmdevice *dcm;
465 {
466 	register int i, unit;
467 	register struct tty *tp;
468 
469 	unit = MKUNIT(brd, 0);
470 	tp = &dcm_tty[unit];
471 	for (i = 0; i < 4; i++, tp++, unit++)
472 		dcmreadbuf(unit, dcm, tp);
473 }
474 
475 dcmreadbuf(unit, dcm, tp)
476 	int unit;
477 	register struct dcmdevice *dcm;
478 	register struct tty *tp;
479 {
480 	int port = PORT(unit);
481 	register struct dcmpreg *pp = dcm_preg(dcm, port);
482 	register struct dcmrfifo *fifo;
483 	register int c, stat;
484 	register unsigned head;
485 	int nch = 0;
486 #ifdef IOSTATS
487 	struct dcmstats *dsp = &dcmstats[BOARD(unit)];
488 
489 	dsp->rints++;
490 #endif
491 	/*
492 	 * TS_WOPEN catches a race when switching to polling mode from dcmrint
493 	 */
494 	if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0) {
495 #ifdef KGDB
496 		if (unit == UNIT(kgdb_dev) &&
497 		    (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
498 		    dcm->dcm_rfifos[3-port][head>>1].data_char == '!') {
499 			pp->r_head = (head + 2) & RX_MASK;
500 			printf("kgdb trap from dcm%d\n", unit);
501 			/* trap into kgdb */
502 			asm("trap #15;");
503 			return;
504 		}
505 #endif
506 		pp->r_head = pp->r_tail & RX_MASK;
507 		return;
508 	}
509 
510 	head = pp->r_head & RX_MASK;
511 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
512 	/*
513 	 * XXX upper bound on how many chars we will take in one swallow?
514 	 */
515 	while (head != (pp->r_tail & RX_MASK)) {
516 		/*
517 		 * Get character/status and update head pointer as fast
518 		 * as possible to make room for more characters.
519 		 */
520 		c = fifo->data_char;
521 		stat = fifo->data_stat;
522 		head = (head + 2) & RX_MASK;
523 		pp->r_head = head;
524 		fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
525 		nch++;
526 
527 #ifdef DEBUG
528 		if (dcmdebug & DDB_INPUT)
529 			printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
530 			       unit, c&0xFF, c, stat&0xFF,
531 			       tp->t_flags, head, pp->r_tail);
532 #endif
533 		/*
534 		 * Check for and handle errors
535 		 */
536 		if (stat & RD_MASK) {
537 #ifdef DEBUG
538 			if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
539 				printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
540 				       unit, stat, c&0xFF, c);
541 #endif
542 			if (stat & (RD_BD | RD_FE))
543 				c |= TTY_FE;
544 			else if (stat & RD_PE)
545 				c |= TTY_PE;
546 			else if (stat & RD_OVF)
547 				log(LOG_WARNING,
548 				    "dcm%d: silo overflow\n", unit);
549 			else if (stat & RD_OE)
550 				log(LOG_WARNING,
551 				    "dcm%d: uart overflow\n", unit);
552 		}
553 		(*linesw[tp->t_line].l_rint)(c, tp);
554 	}
555 	dcmischeme[BOARD(unit)].dis_char += nch;
556 #ifdef IOSTATS
557 	dsp->rchars += nch;
558 	if (nch <= DCMRBSIZE)
559 		dsp->rsilo[nch]++;
560 	else
561 		dsp->rsilo[DCMRBSIZE+1]++;
562 #endif
563 }
564 
565 dcmxint(unit, dcm, tp)
566 	int unit;
567 	struct dcmdevice *dcm;
568 	register struct tty *tp;
569 {
570 	tp->t_state &= ~TS_BUSY;
571 	if (tp->t_state & TS_FLUSH)
572 		tp->t_state &= ~TS_FLUSH;
573 	if (tp->t_line)
574 		(*linesw[tp->t_line].l_start)(tp);
575 	else
576 		dcmstart(tp);
577 }
578 
579 dcmmint(unit, mcnd, dcm)
580 	register int unit;
581 	register struct dcmdevice *dcm;
582         int mcnd;
583 {
584 	register struct tty *tp;
585 
586 #ifdef DEBUG
587 	if (dcmdebug & DDB_MODEM)
588 		printf("dcmmint: unit %x mcnd %x\n", unit, mcnd);
589 #endif
590 	tp = &dcm_tty[unit];
591 	if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) {
592 		if (mcnd & MI_CD)
593 			(void) (*linesw[tp->t_line].l_modem)(tp, 1);
594 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
595 			dcm->dcm_mdmout &= ~(MO_DTR | MO_RTS);
596 			SEM_LOCK(dcm);
597 			dcm->dcm_cr |= CR_MODM;
598 			SEM_UNLOCK(dcm);
599 			DELAY(10); /* time to change lines */
600 		}
601 	}
602 }
603 
604 dcmioctl(dev, cmd, data, flag)
605 	dev_t dev;
606 	caddr_t data;
607 {
608 	register struct tty *tp;
609 	register int unit = UNIT(dev);
610 	register struct dcmdevice *dcm;
611 	register int port;
612 	int error, s;
613 
614 #ifdef DEBUG
615 	if (dcmdebug & DDB_IOCTL)
616 		printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
617 		       unit, cmd, *data, flag);
618 #endif
619 	tp = &dcm_tty[unit];
620 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
621 	if (error >= 0)
622 		return (error);
623 	error = ttioctl(tp, cmd, data, flag);
624 	if (error >= 0)
625 		return (error);
626 
627 	port = PORT(unit);
628 	dcm = dcm_addr[BOARD(unit)];
629 	switch (cmd) {
630 	case TIOCSBRK:
631 		/*
632 		 * Wait for transmitter buffer to empty
633 		 */
634 		s = spltty();
635 		while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
636 			DELAY(DCM_USPERCH(tp->t_ospeed));
637 		SEM_LOCK(dcm);
638 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
639 		dcm->dcm_cr |= (1 << port);	/* start break */
640 		SEM_UNLOCK(dcm);
641 		splx(s);
642 		break;
643 
644 	case TIOCCBRK:
645 		SEM_LOCK(dcm);
646 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
647 		dcm->dcm_cr |= (1 << port);	/* end break */
648 		SEM_UNLOCK(dcm);
649 		break;
650 
651 	case TIOCSDTR:
652 		(void) dcmmctl(dev, MO_ON, DMBIS);
653 		break;
654 
655 	case TIOCCDTR:
656 		(void) dcmmctl(dev, MO_ON, DMBIC);
657 		break;
658 
659 	case TIOCMSET:
660 		(void) dcmmctl(dev, *(int *)data, DMSET);
661 		break;
662 
663 	case TIOCMBIS:
664 		(void) dcmmctl(dev, *(int *)data, DMBIS);
665 		break;
666 
667 	case TIOCMBIC:
668 		(void) dcmmctl(dev, *(int *)data, DMBIC);
669 		break;
670 
671 	case TIOCMGET:
672 		*(int *)data = dcmmctl(dev, 0, DMGET);
673 		break;
674 
675 	default:
676 		return (ENOTTY);
677 	}
678 	return (0);
679 }
680 
681 dcmparam(tp, t)
682 	register struct tty *tp;
683 	register struct termios *t;
684 {
685 	register struct dcmdevice *dcm;
686 	register int port, mode, cflag = t->c_cflag;
687 	int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
688 
689 	/* check requested parameters */
690         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
691                 return(EINVAL);
692         /* and copy to tty */
693         tp->t_ispeed = t->c_ispeed;
694         tp->t_ospeed = t->c_ospeed;
695         tp->t_cflag = cflag;
696 	if (ospeed == 0) {
697 		(void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET);
698 		return(0);
699 	}
700 
701 	mode = 0;
702 	switch (cflag&CSIZE) {
703 	case CS5:
704 		mode = LC_5BITS; break;
705 	case CS6:
706 		mode = LC_6BITS; break;
707 	case CS7:
708 		mode = LC_7BITS; break;
709 	case CS8:
710 		mode = LC_8BITS; break;
711 	}
712 	if (cflag&PARENB) {
713 		if (cflag&PARODD)
714 			mode |= LC_PODD;
715 		else
716 			mode |= LC_PEVEN;
717 	}
718 	if (cflag&CSTOPB)
719 		mode |= LC_2STOP;
720 	else
721 		mode |= LC_1STOP;
722 #ifdef DEBUG
723 	if (dcmdebug & DDB_PARAM)
724 		printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
725 		       UNIT(tp->t_dev), cflag, mode, tp->t_ospeed,
726 		       DCM_USPERCH(tp->t_ospeed));
727 #endif
728 
729 	port = PORT(tp->t_dev);
730 	dcm = dcm_addr[BOARD(tp->t_dev)];
731 	/*
732 	 * Wait for transmitter buffer to empty.
733 	 */
734 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
735 		DELAY(DCM_USPERCH(tp->t_ospeed));
736 	/*
737 	 * Make changes known to hardware.
738 	 */
739 	dcm->dcm_data[port].dcm_baud = ospeed;
740 	dcm->dcm_data[port].dcm_conf = mode;
741 	SEM_LOCK(dcm);
742 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
743 	dcm->dcm_cr |= (1 << port);
744 	SEM_UNLOCK(dcm);
745 	/*
746 	 * Delay for config change to take place. Weighted by buad.
747 	 * XXX why do we do this?
748 	 */
749 	DELAY(16 * DCM_USPERCH(tp->t_ospeed));
750 	return(0);
751 }
752 
753 dcmstart(tp)
754 	register struct tty *tp;
755 {
756 	register struct dcmdevice *dcm;
757 	register struct dcmpreg *pp;
758 	register struct dcmtfifo *fifo;
759 	register char *bp;
760 	register unsigned tail, next;
761 	register int port, nch;
762 	unsigned head;
763 	char buf[16];
764 	int s;
765 #ifdef IOSTATS
766 	struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];
767 	int tch = 0;
768 #endif
769 
770 	s = spltty();
771 #ifdef IOSTATS
772 	dsp->xints++;
773 #endif
774 #ifdef DEBUG
775 	if (dcmdebug & DDB_OUTPUT)
776 		printf("dcmstart(%d): state %x flags %x outcc %d\n",
777 		       UNIT(tp->t_dev), tp->t_state, tp->t_flags,
778 		       tp->t_outq.c_cc);
779 #endif
780 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
781 		goto out;
782 	if (tp->t_outq.c_cc <= tp->t_lowat) {
783 		if (tp->t_state&TS_ASLEEP) {
784 			tp->t_state &= ~TS_ASLEEP;
785 			wakeup((caddr_t)&tp->t_outq);
786 		}
787 		if (tp->t_wsel) {
788 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
789 			tp->t_wsel = 0;
790 			tp->t_state &= ~TS_WCOLL;
791 		}
792 	}
793 	if (tp->t_outq.c_cc == 0) {
794 #ifdef IOSTATS
795 		dsp->xempty++;
796 #endif
797 		goto out;
798 	}
799 
800 	dcm = dcm_addr[BOARD(tp->t_dev)];
801 	port = PORT(tp->t_dev);
802 	pp = dcm_preg(dcm, port);
803 	tail = pp->t_tail & TX_MASK;
804 	next = (tail + 1) & TX_MASK;
805 	head = pp->t_head & TX_MASK;
806 	if (head == next)
807 		goto out;
808 	fifo = &dcm->dcm_tfifos[3-port][tail];
809 again:
810 	nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
811 #ifdef IOSTATS
812 	tch += nch;
813 #endif
814 #ifdef DEBUG
815 	if (dcmdebug & DDB_OUTPUT)
816 		printf("\thead %x tail %x nch %d\n", head, tail, nch);
817 #endif
818 	/*
819 	 * Loop transmitting all the characters we can.
820 	 */
821 	for (bp = buf; --nch >= 0; bp++) {
822 		fifo->data_char = *bp;
823 		pp->t_tail = next;
824 		/*
825 		 * If this is the first character,
826 		 * get the hardware moving right now.
827 		 */
828 		if (bp == buf) {
829 			tp->t_state |= TS_BUSY;
830 			SEM_LOCK(dcm);
831 			dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
832 			dcm->dcm_cr |= (1 << port);
833 			SEM_UNLOCK(dcm);
834 		}
835 		tail = next;
836 		fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
837 		next = (next + 1) & TX_MASK;
838 	}
839 	/*
840 	 * Head changed while we were loading the buffer,
841 	 * go back and load some more if we can.
842 	 */
843 	if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
844 #ifdef IOSTATS
845 		dsp->xrestarts++;
846 #endif
847 		head = pp->t_head & TX_MASK;
848 		goto again;
849 	}
850 	/*
851 	 * Kick it one last time in case it finished while we were
852 	 * loading the last time.
853 	 */
854 	if (bp > &buf[1]) {
855 		tp->t_state |= TS_BUSY;
856 		SEM_LOCK(dcm);
857 		dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
858 		dcm->dcm_cr |= (1 << port);
859 		SEM_UNLOCK(dcm);
860 	}
861 #ifdef DEBUG
862 	if (dcmdebug & DDB_INTR)
863 		printf("dcmstart(%d): head %x tail %x outqcc %d ch %d\n",
864 		       UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc, tch);
865 #endif
866 out:
867 #ifdef IOSTATS
868 	dsp->xchars += tch;
869 	if (tch <= DCMXBSIZE)
870 		dsp->xsilo[tch]++;
871 	else
872 		dsp->xsilo[DCMXBSIZE+1]++;
873 #endif
874 	splx(s);
875 }
876 
877 /*
878  * Stop output on a line.
879  */
880 dcmstop(tp, flag)
881 	register struct tty *tp;
882 {
883 	int s;
884 
885 	s = spltty();
886 	if (tp->t_state & TS_BUSY) {
887 		/* XXX is there some way to safely stop transmission? */
888 		if ((tp->t_state&TS_TTSTOP)==0)
889 			tp->t_state |= TS_FLUSH;
890 	}
891 	splx(s);
892 }
893 
894 /* Modem control */
895 
896 dcmmctl(dev, bits, how)
897 	dev_t dev;
898 	int bits, how;
899 {
900 	register struct dcmdevice *dcm;
901 	int s, hit = 0;
902 
903 	/*
904 	 * Only port 0 has modem control lines.
905 	 * XXX ok for now but needs to changed for the 8 port board.
906 	 */
907 	if (PORT(UNIT(dev)) != 0)
908 		return(bits);
909 
910 	dcm = dcm_addr[BOARD(UNIT(dev))];
911 	s = spltty();
912 	switch (how) {
913 
914 	case DMSET:
915 		dcm->dcm_mdmout = bits;
916 		hit++;
917 		break;
918 
919 	case DMBIS:
920 		dcm->dcm_mdmout |= bits;
921 		hit++;
922 		break;
923 
924 	case DMBIC:
925 		dcm->dcm_mdmout &= ~bits;
926 		hit++;
927 		break;
928 
929 	case DMGET:
930 		bits = dcm->dcm_mdmin;
931 		break;
932 	}
933 	if (hit) {
934 		SEM_LOCK(dcm);
935 		dcm->dcm_cr |= CR_MODM;
936 		SEM_UNLOCK(dcm);
937 		DELAY(10); /* delay until done */
938 		(void) splx(s);
939 	}
940 	return(bits);
941 }
942 
943 /*
944  * Set board to either interrupt per-character or at a fixed interval.
945  */
946 dcmsetischeme(brd, flags)
947 	int brd, flags;
948 {
949 	register struct dcmdevice *dcm = dcm_addr[brd];
950 	register struct dcmischeme *dis = &dcmischeme[brd];
951 	register int i;
952 	u_char mask;
953 	int perchar = flags & DIS_PERCHAR;
954 
955 #ifdef DEBUG
956 	if (dcmdebug & DDB_INTSCHM)
957 		printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
958 		       brd, perchar, dis->dis_perchar,
959 		       dis->dis_intr, dis->dis_char);
960 	if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
961 		printf("dcmsetischeme(%d):  redundent request %d\n",
962 		       brd, perchar);
963 		return;
964 	}
965 #endif
966 	/*
967 	 * If perchar is non-zero, we enable interrupts on all characters
968 	 * otherwise we disable perchar interrupts and use periodic
969 	 * polling interrupts.
970 	 */
971 	dis->dis_perchar = perchar;
972 	mask = perchar ? 0xf : 0x0;
973 	for (i = 0; i < 256; i++)
974 		dcm->dcm_bmap[i].data_data = mask;
975 	/*
976 	 * Don't slow down tandem mode, interrupt on flow control
977 	 * chars for any port on the board.
978 	 */
979 	if (!perchar) {
980 		register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];
981 		int c;
982 
983 		for (i = 0; i < 4; i++, tp++) {
984 			if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
985 				dcm->dcm_bmap[c].data_data |= (1 << i);
986 			if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
987 				dcm->dcm_bmap[c].data_data |= (1 << i);
988 		}
989 	}
990 	/*
991 	 * Board starts with timer disabled so if first call is to
992 	 * set perchar mode then we don't want to toggle the timer.
993 	 */
994 	if (flags == (DIS_RESET|DIS_PERCHAR))
995 		return;
996 	/*
997 	 * Toggle card 16.7ms interrupts (we first make sure that card
998 	 * has cleared the bit so it will see the toggle).
999 	 */
1000 	while (dcm->dcm_cr & CR_TIMER)
1001 		;
1002 	SEM_LOCK(dcm);
1003 	dcm->dcm_cr |= CR_TIMER;
1004 	SEM_UNLOCK(dcm);
1005 }
1006 
1007 /*
1008  * Following are all routines needed for DCM to act as console
1009  */
1010 #include "machine/cons.h"
1011 
1012 dcmcnprobe(cp)
1013 	struct consdev *cp;
1014 {
1015 	register struct hp_hw *hw;
1016 	int unit, i;
1017 	extern int dcmopen();
1018 
1019 	/*
1020 	 * Implicitly assigns the lowest select code DCM card found to be
1021 	 * logical unit 0 (actually CONUNIT).  If your config file does
1022 	 * anything different, you're screwed.
1023 	 */
1024 	for (hw = sc_table; hw->hw_type; hw++)
1025 	        if (hw->hw_type == COMMDCM && !badaddr((short *)hw->hw_addr))
1026 			break;
1027 	if (hw->hw_type != COMMDCM) {
1028 		cp->cn_pri = CN_DEAD;
1029 		return;
1030 	}
1031 	unit = CONUNIT;
1032 	dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_addr;
1033 
1034 	/* locate the major number */
1035 	for (i = 0; i < nchrdev; i++)
1036 		if (cdevsw[i].d_open == dcmopen)
1037 			break;
1038 
1039 	/* initialize required fields */
1040 	cp->cn_dev = makedev(i, unit);
1041 	cp->cn_tp = &dcm_tty[unit];
1042 	switch (dcm_addr[BOARD(unit)]->dcm_rsid) {
1043 	case DCMID:
1044 		cp->cn_pri = CN_NORMAL;
1045 		break;
1046 	case DCMID|DCMCON:
1047 		cp->cn_pri = CN_REMOTE;
1048 		break;
1049 	default:
1050 		cp->cn_pri = CN_DEAD;
1051 		break;
1052 	}
1053 }
1054 
1055 dcmcninit(cp)
1056 	struct consdev *cp;
1057 {
1058 	dcminit(cp->cn_dev, dcmdefaultrate);
1059 	dcmconsole = UNIT(cp->cn_dev);
1060 }
1061 
1062 dcminit(dev, rate)
1063 	dev_t dev;
1064 	int rate;
1065 {
1066 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1067 	int s, mode, port;
1068 
1069 	port = PORT(dev);
1070 	mode = LC_8BITS | LC_1STOP;
1071 	s = splhigh();
1072 	/*
1073 	 * Wait for transmitter buffer to empty.
1074 	 */
1075 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1076 		DELAY(DCM_USPERCH(rate));
1077 	/*
1078 	 * Make changes known to hardware.
1079 	 */
1080 	dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1081 	dcm->dcm_data[port].dcm_conf = mode;
1082 	SEM_LOCK(dcm);
1083 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1084 	dcm->dcm_cr |= (1 << port);
1085 	SEM_UNLOCK(dcm);
1086 	/*
1087 	 * Delay for config change to take place. Weighted by buad.
1088 	 * XXX why do we do this?
1089 	 */
1090 	DELAY(16 * DCM_USPERCH(rate));
1091 	splx(s);
1092 }
1093 
1094 dcmcngetc(dev)
1095 	dev_t dev;
1096 {
1097 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1098 	register struct dcmrfifo *fifo;
1099 	register struct dcmpreg *pp;
1100 	register unsigned head;
1101 	int s, c, stat, port;
1102 
1103 	port = PORT(dev);
1104 	pp = dcm_preg(dcm, port);
1105 	s = splhigh();
1106 	head = pp->r_head & RX_MASK;
1107 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
1108 	while (head == (pp->r_tail & RX_MASK))
1109 		;
1110 	/*
1111 	 * If board interrupts are enabled, just let our received char
1112 	 * interrupt through in case some other port on the board was
1113 	 * busy.  Otherwise we must clear the interrupt.
1114 	 */
1115 	SEM_LOCK(dcm);
1116 	if ((dcm->dcm_ic & IC_IE) == 0)
1117 		stat = dcm->dcm_iir;
1118 	SEM_UNLOCK(dcm);
1119 	c = fifo->data_char;
1120 	stat = fifo->data_stat;
1121 	pp->r_head = (head + 2) & RX_MASK;
1122 	splx(s);
1123 	return(c);
1124 }
1125 
1126 /*
1127  * Console kernel output character routine.
1128  */
1129 dcmcnputc(dev, c)
1130 	dev_t dev;
1131 	int c;
1132 {
1133 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1134 	register struct dcmpreg *pp;
1135 	unsigned tail;
1136 	int s, port, stat;
1137 
1138 	port = PORT(dev);
1139 	pp = dcm_preg(dcm, port);
1140 	s = splhigh();
1141 #ifdef KGDB
1142 	if (dev != kgdb_dev)
1143 #endif
1144 	if (dcmconsole == -1) {
1145 		(void) dcminit(dev, dcmdefaultrate);
1146 		dcmconsole = UNIT(dev);
1147 	}
1148 	tail = pp->t_tail & TX_MASK;
1149 	while (tail != (pp->t_head & TX_MASK))
1150 		;
1151 	dcm->dcm_tfifos[3-port][tail].data_char = c;
1152 	pp->t_tail = tail = (tail + 1) & TX_MASK;
1153 	SEM_LOCK(dcm);
1154 	dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1155 	dcm->dcm_cr |= (1 << port);
1156 	SEM_UNLOCK(dcm);
1157 	while (tail != (pp->t_head & TX_MASK))
1158 		;
1159 	/*
1160 	 * If board interrupts are enabled, just let our completion
1161 	 * interrupt through in case some other port on the board
1162 	 * was busy.  Otherwise we must clear the interrupt.
1163 	 */
1164 	if ((dcm->dcm_ic & IC_IE) == 0) {
1165 		SEM_LOCK(dcm);
1166 		stat = dcm->dcm_iir;
1167 		SEM_UNLOCK(dcm);
1168 	}
1169 	splx(s);
1170 }
1171 #endif
1172