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