xref: /csrg-svn/sys/hp300/dev/dcm.c (revision 41480)
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.1 (Berkeley) 05/08/90
15  */
16 
17 /*
18  *  Console support is not finished.
19  */
20 
21 #include "dcm.h"
22 #if NDCM > 0
23 /*
24  *  98642/MUX
25  */
26 #include "param.h"
27 #include "systm.h"
28 #include "ioctl.h"
29 #include "tty.h"
30 #include "user.h"
31 #include "conf.h"
32 #include "file.h"
33 #include "uio.h"
34 #include "kernel.h"
35 #include "syslog.h"
36 #include "time.h"
37 
38 #include "device.h"
39 #include "dcmreg.h"
40 #include "machine/cpu.h"
41 #include "machine/isr.h"
42 
43 int	dcmprobe();
44 struct	driver dcmdriver = {
45 	dcmprobe, "dcm",
46 };
47 
48 #define NDCMLINE (NDCM*4)
49 
50 int	dcmstart(), dcmparam(), dcmintr();
51 int	dcmsoftCAR[NDCM];
52 int     dcmintschm[NDCM];
53 int	dcm_active;
54 int	ndcm = NDCM;
55 int	dcmconsole = -1;
56 struct	dcmdevice *dcm_addr[NDCM];
57 struct	tty dcm_tty[NDCMLINE];
58 int	dcm_cnt = NDCMLINE;
59 struct	isr dcmisr[NDCM];
60 int     dcmintrval = 5; /* rate in secs that interschem is examined */
61 long    dcmbang[NDCM];
62 int	dcmchrrd[NDCM];	/* chars read during each sample time */
63 int     dcmintrocc[NDCM];	/* # of interrupts for each sample time */
64 
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 #ifdef DEBUG
86 int	dcmdebug = 0x00;
87 #define DDB_SIOERR	0x01
88 #define DDB_PARAM	0x02
89 #define DDB_INPUT	0x04
90 #define DDB_OUTPUT	0x08
91 #define DDB_INTR	0x10
92 #define DDB_IOCTL       0x20
93 #define DDB_INTSCHM     0x40
94 #define DDB_MOD         0x80
95 #define DDB_OPENCLOSE	0x100
96 
97 long unsigned int dcmrsize[33];	/* read sizes, 32 for over 31, 0 for 0 */
98 #endif
99 
100 extern	struct tty *constty;
101 
102 #define UNIT(x)		minor(x)
103 #define	BOARD(x)	((x) >> 2)
104 #define PORT(x)		((x) & 3)
105 #define MKUNIT(b,p)	(((b) << 2) | (p))
106 
107 dcmprobe(hd)
108 	register struct hp_device *hd;
109 {
110 	register struct dcmdevice *dcm;
111 	register int i;
112 	register int timo = 0;
113 	int s, brd;
114 
115 	dcm = (struct dcmdevice *)hd->hp_addr;
116 	if ((dcm->dcm_rsid & 0x1f) != DCMID)
117 		return (0);
118 	brd = hd->hp_unit;
119 	s = spltty();
120 	dcm->dcm_rsid = DCMRS;
121 	DELAY(50000);	/* 5000 is not long enough */
122 	dcm->dcm_rsid = 0;
123 	dcm->dcm_ic = IC_IE;
124 	dcm->dcm_cr = CR_SELFT;
125 	while ((dcm->dcm_ic & IC_IR) == 0) {
126 		if (++timo == 20000) {
127 			printf("dcm%d: timeout on selftest interrupt\n", brd);
128 			printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n",
129 			       brd, dcm->dcm_rsid, dcm->dcm_ic,
130 			       dcm->dcm_cr, dcm->dcm_iir);
131 			return(0);
132 		}
133 	}
134 	DELAY(50000)	/* XXX why is this needed ???? */
135 	while ((dcm->dcm_iir & IIR_SELFT) == 0) {
136 		if (++timo == 400000) {
137 			printf("dcm%d: timeout on selftest\n", brd);
138 			printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n",
139 			       brd, dcm->dcm_rsid, dcm->dcm_ic,
140 			       dcm->dcm_cr, dcm->dcm_iir);
141 			return(0);
142 		}
143 	}
144 	DELAY(50000)	/* XXX why is this needed ???? */
145 	if (dcm->dcm_stcon != ST_OK) {
146 		printf("dcm%d: self test failed: %x\n", brd, dcm->dcm_stcon);
147 		return(0);
148 	}
149 	dcm->dcm_ic = IC_ID;
150 	splx(s);
151 
152 	hd->hp_ipl = DCMIPL(dcm->dcm_ic);
153 	dcmisr[brd].isr_ipl = hd->hp_ipl;
154 	dcmisr[brd].isr_arg = brd;
155 	dcmisr[brd].isr_intr = dcmintr;
156 	dcm_addr[brd] = dcm;
157 	dcm_active |= 1 << brd;
158 	dcmsoftCAR[brd] = hd->hp_flags;
159 	dcmintschm[brd] = 1;	/* start with interrupt/char */
160 	for (i = 0; i < 256; i++)
161 		dcm->dcm_bmap[i].data_data = 0x0f;
162 	dcmintrocc[brd] = 0;
163 	dcmchrrd[brd] = 0;
164 	isrlink(&dcmisr[brd]);
165 	dcm->dcm_mdmmsk = MI_CD;	/* Enable carrier detect interrupts */
166 	dcm->dcm_ic = IC_IE;	/* turn interrupts on */
167 	/*
168 	 * Need to reset baud rate, etc. of next print so reset dcmconsole.
169 	 * Also make sure console is always "hardwired"
170 	 */
171 	if (brd == BOARD(dcmconsole)) {
172 		dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
173 		dcmconsole = -1;
174 	}
175 	return (1);
176 }
177 
178 dcmopen(dev, flag)
179 	dev_t dev;
180 {
181 	register struct tty *tp;
182 	register int unit, brd;
183 
184 	unit = UNIT(dev);
185 	brd = BOARD(unit);
186 	dcmbang[brd] = time.tv_sec;	/* for interrupt scheme */
187 	if (unit >= dcm_cnt || (dcm_active & (1 << brd)) == 0)
188 		return (ENXIO);
189 	tp = &dcm_tty[unit];
190 	tp->t_oproc = dcmstart;
191 	tp->t_param = dcaparam;
192 	tp->t_dev = dev;
193 	if ((tp->t_state & TS_ISOPEN) == 0) {
194 		ttychars(tp);
195 		tp->t_iflag = TTYDEF_IFLAG;
196 		tp->t_oflag = TTYDEF_OFLAG;
197 		tp->t_cflag = TTYDEF_CFLAG;
198 		tp->t_lflag = TTYDEF_LFLAG;
199 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
200 		dcmparam(tp, &tp->t_termios);
201 		ttsetwater(tp);
202 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
203 		return (EBUSY);
204 	if (PORT(unit) == 0)	/* enable port 0 */
205 		(void) dcmmctl(dev, MO_ON, DMSET);
206 	if (dcmsoftCAR[brd] & (1 << PORT(unit)))
207 		tp->t_state |= TS_CARR_ON;
208 	else if (PORT(unit))		/* Only port 0 has modem control */
209 		tp->t_state |= TS_CARR_ON;
210 	else if (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)
211 		tp->t_state |= TS_CARR_ON;
212 	(void) spltty();
213 	while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
214 	       (tp->t_state & TS_CARR_ON) == 0) {
215 		tp->t_state |= TS_WOPEN;
216 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
217 	}
218 	(void) spl0();
219 
220 #ifdef DEBUG
221 	if (dcmdebug & DDB_OPENCLOSE)
222 		printf("dcmopen: u %x st %x fl %x\n",
223 			unit, tp->t_state, tp->t_flags);
224 #endif
225 	return ((*linesw[tp->t_line].l_open)(dev, tp));
226 }
227 
228 /*ARGSUSED*/
229 dcmclose(dev, flag)
230 	dev_t dev;
231 {
232 	register struct tty *tp;
233 	int unit;
234 
235 	unit = UNIT(dev);
236 	tp = &dcm_tty[unit];
237 	(*linesw[tp->t_line].l_close)(tp);
238 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
239 	    (tp->t_state&TS_ISOPEN) == 0)
240 		(void) dcmmctl(dev, MO_OFF, DMSET);
241 #ifdef DEBUG
242 	if (dcmdebug & DDB_OPENCLOSE)
243 		printf("dcmclose: u %x st %x fl %x\n",
244 			unit, tp->t_state, tp->t_flags);
245 #endif
246 	ttyclose(tp);
247 	return(0);
248 }
249 
250 dcmread(dev, uio, flag)
251 	dev_t dev;
252 	struct uio *uio;
253 {
254 	register struct tty *tp;
255 
256 	tp = &dcm_tty[UNIT(dev)];
257 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
258 }
259 
260 dcmwrite(dev, uio, flag)
261 	dev_t dev;
262 	struct uio *uio;
263 {
264 	int unit = UNIT(dev);
265 	register struct tty *tp;
266 
267 	tp = &dcm_tty[unit];
268 	if (unit == dcmconsole && constty &&
269 	    (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN))
270 		tp = constty;
271 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
272 }
273 
274 dcmintr(brd)
275 	register int brd;
276 {
277 	register struct dcmdevice *dcm;
278 	int i, code, pcnd[4], mcnd, delta;
279 
280 	dcm = dcm_addr[brd];
281 	SEM_LOCK(dcm);
282 	if ((dcm->dcm_ic & IC_IR) == 0) {
283 		SEM_UNLOCK(dcm);
284 		return(0);
285 	}
286 	for (i = 0; i < 4; i++) {
287 		pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
288 		dcm->dcm_icrtab[i].dcm_data = 0;
289 	}
290 	mcnd = dcm->dcm_mdmin;
291 	code = dcm->dcm_iir & IIR_MASK;
292 	dcm->dcm_iir = 0;
293 	SEM_UNLOCK(dcm);
294 
295 #ifdef DEBUG
296 	if (dcmdebug & DDB_INTR)
297 		printf("dcmintr: iir %x p0 %x p1 %x p2 %x p3 %x m %x\n",
298 			code, pcnd[0], pcnd[1], pcnd[2],
299 			pcnd[3], mcnd);
300 #endif
301 	if (code & IIR_PORT0)
302 		dcmpint(MKUNIT(brd, 0), pcnd[0], dcm);
303 	if (code & IIR_PORT1)
304 		dcmpint(MKUNIT(brd, 1), pcnd[1],  dcm);
305 	if (code & IIR_PORT2)
306 		dcmpint(MKUNIT(brd, 2), pcnd[2], dcm);
307 	if (code & IIR_PORT3)
308 		dcmpint(MKUNIT(brd, 3), pcnd[3], dcm);
309 	if (code & IIR_MODM)
310 		dcmmint(MKUNIT(brd, 0), mcnd, dcm);	/* always port 0 */
311 	if (code & IIR_TIMEO)
312 		dcmrint(brd, dcm);
313 
314 	/*
315 	 * See if need to change interrupt rate.
316 	 * 16.7ms is the polling interrupt rate.
317 	 * Reference: 16.7ms is about 550 buad; 38.4k is 72 chars in 16.7ms
318 	 */
319 	if ((delta = time.tv_sec - dcmbang[brd]) >= dcmintrval) {
320 		dcmbang[brd] = time.tv_sec;
321 		/*
322 		 * 66 threshold of 600 buad, use 70
323 		 */
324 		if (dcmintschm[brd] && dcmintrocc[brd] > 70 * delta)
325 			dcm_setintrschm(dcm, 0, brd);
326 		else if (!dcmintschm[brd] && dcmintrocc[brd] > dcmchrrd[brd]) {
327 			dcm_setintrschm(dcm, 1, brd);
328 			/*
329 			 * Must check the receive queue after switch
330 			 * from polling mode to interrupt/char
331 			 */
332 			dcmrint(brd, dcm);
333 		}
334 		dcmintrocc[brd] = 0;
335 		dcmchrrd[brd] = 0;
336 	} else
337 		dcmintrocc[brd]++;
338 
339 	return(1);
340 }
341 
342 /*
343  *  Port interrupt.  Can be two things:
344  *	First, it might be a special character (exception interrupt);
345  *	Second, it may be a buffer empty (transmit interrupt);
346  */
347 dcmpint(unit, code, dcm)
348 	int unit, code;
349 	register struct dcmdevice *dcm;
350 {
351 	register struct tty *tp;
352 	register int port = PORT(unit);
353 
354 	if (code & IT_SPEC) {
355 		tp = &dcm_tty[unit];
356 		if ((tp->t_state & TS_ISOPEN) != 0)
357 			dcmreadbuf(unit, dcm, tp, port);
358 		else
359 			dcm->dcm_rhead[port].ptr = dcm->dcm_rtail[port].ptr & RX_MASK;
360 	}
361 	if (code & IT_TX)
362 		dcmxint(unit, dcm);
363 }
364 
365 dcmrint(brd, dcm)
366 	int brd;
367 	register struct dcmdevice *dcm;
368 {
369 	register struct tty *tp;
370 	register int i, unit;
371 
372 	unit = MKUNIT(brd, 0);
373 	tp = &dcm_tty[unit];
374 	for (i = 0; i < 4; i++, tp++, unit++) {
375 		/* TS_WOPEN catch race when switching to polling mode */
376 		if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) != 0)
377 			dcmreadbuf(unit, dcm, tp, i);
378 		else
379 			dcm->dcm_rhead[i].ptr = dcm->dcm_rtail[i].ptr & RX_MASK;
380 	}
381 }
382 
383 dcmreadbuf(unit, dcm, tp, port)
384 	int unit;
385 	register struct dcmdevice *dcm;
386 	register struct tty *tp;
387 	register int port;
388 {
389 	register int c, stat;
390 	register unsigned head;
391 	unsigned tail;
392 #ifdef DEBUG
393 	int silocnt;
394 	silocnt = 0;
395 #endif /* DEBUG */
396 
397 readrestart:
398 	head = dcm->dcm_rhead[port].ptr & RX_MASK;
399 	tail = dcm->dcm_rtail[port].ptr & RX_MASK;
400 
401 	while (head != tail) {
402 		c = dcm->dcm_rfifos[3 - port][head / 2].data_char;
403 		stat = dcm->dcm_rfifos[3 - port][head / 2].data_stat;
404 		dcmchrrd[BOARD(unit)]++;
405 #ifdef DEBUG
406 		silocnt++;
407 #endif
408 		head = (head + 2) & RX_MASK;
409 		dcm->dcm_rhead[port].ptr = head;
410 
411 #ifdef DEBUG
412 		if (dcmdebug & DDB_INPUT)
413 			printf("dcmreadbuf: u%d p%d c%x s%x f%x h%x t%x char %c\n",
414 			       BOARD(unit), PORT(unit), c&0xFF, stat&0xFF,
415 			       tp->t_flags, head, tail, c);
416 #endif
417 		if (stat & RD_MASK) {	/* Check for errors */
418 #ifdef DEBUG
419 			if (dcmdebug & DDB_INPUT || dcmdebug & DDB_SIOERR)
420 				printf("dcm%d port%d: data error: stat 0x%x data 0x%x chr %c\n",
421 				       BOARD(unit), PORT(unit), stat, c, c);
422 #endif
423 			if (stat & (RD_BD | RD_FE))
424 				c |= TTY_FE;
425 			else if (stat & RD_PE)
426 				c |= TTY_PE;
427 			else if (stat & RD_OVF)
428 				log(LOG_WARNING,
429 				    "dcm%d port%d: silo overflow\n",
430 				    BOARD(unit), PORT(unit));
431 			else if (stat & RD_OE)
432 				log(LOG_WARNING,
433 				    "dcm%d port%d: uart overflow\n",
434 				    BOARD(unit), PORT(unit));
435 		}
436 		(*linesw[tp->t_line].l_rint)(c, tp);
437 	}
438 	/* for higher speed need to processes everything that might
439 	 * have arrived since we started; see if tail changed */
440 	if (tail != dcm->dcm_rtail[port].ptr & RX_MASK)
441 		goto readrestart;
442 
443 #ifdef DEBUG
444 	if (silocnt < 33)
445 		dcmrsize[silocnt]++;
446 	else
447 		dcmrsize[32]++;
448 #endif
449 }
450 
451 dcmxint(unit, dcm)
452 	int unit;
453 	struct dcmdevice *dcm;
454 {
455 	register struct tty *tp;
456 
457 	tp = &dcm_tty[unit];
458 	tp->t_state &= ~TS_BUSY;
459 	if (tp->t_state & TS_FLUSH)
460 		tp->t_state &= ~TS_FLUSH;
461 	if (tp->t_line)
462 		(*linesw[tp->t_line].l_start)(tp);
463 	else
464 		dcmstart(tp);
465 }
466 
467 dcmmint(unit, mcnd, dcm)
468 	register int unit;
469 	register struct dcmdevice *dcm;
470         int mcnd;
471 {
472 	register struct tty *tp;
473 
474 #ifdef DEBUG
475 	if (dcmdebug & DDB_MOD)
476 		printf("dcmmint: unit %x mcnd %x\n", unit, mcnd);
477 #endif DEBUG
478 	tp = &dcm_tty[unit];
479 	if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) {
480 		if (mcnd & MI_CD)
481 			(void) (*linesw[tp->t_line].l_modem)(tp, 1);
482 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
483 			dcm->dcm_mdmout &= ~(MO_DTR | MO_RTS);
484 			SEM_LOCK(dcm);
485 			dcm->dcm_cr |= CR_MODM;
486 			SEM_UNLOCK(dcm);
487 		}
488 	}
489 }
490 
491 dcmioctl(dev, cmd, data, flag)
492 	dev_t dev;
493 	caddr_t data;
494 {
495 	register struct tty *tp;
496 	register int unit = UNIT(dev);
497 	register struct dcmdevice *dcm;
498 	register int port;
499 	int error;
500 
501 #ifdef DEBUG
502 	if (dcmdebug & DDB_IOCTL)
503 		printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
504 		       unit, cmd, *data, flag);
505 #endif
506 	tp = &dcm_tty[unit];
507 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
508 	if (error >= 0)
509 		return (error);
510 	error = ttioctl(tp, cmd, data, flag);
511 	if (error >= 0)
512 		return (error);
513 
514 	port = PORT(unit);
515 	dcm = dcm_addr[BOARD(unit)];
516 	switch (cmd) {
517 	case TIOCSBRK:
518 		dcm->dcm_cmdtab[port].dcm_data = CT_BRK;
519 		SEM_LOCK(dcm);
520 		dcm->dcm_cr = (1 << port);	/* start break */
521 		SEM_UNLOCK(dcm);
522 		break;
523 
524 	case TIOCCBRK:
525 		dcm->dcm_cmdtab[port].dcm_data = CT_BRK;
526 		SEM_LOCK(dcm);
527 		dcm->dcm_cr = (1 << port);	/* end break */
528 		SEM_UNLOCK(dcm);
529 		break;
530 
531 	case TIOCSDTR:
532 		(void) dcmmctl(dev, MO_ON, DMBIS);
533 		break;
534 
535 	case TIOCCDTR:
536 		(void) dcmmctl(dev, MO_ON, DMBIC);
537 		break;
538 
539 	case TIOCMSET:
540 		(void) dcmmctl(dev, *(int *)data, DMSET);
541 		break;
542 
543 	case TIOCMBIS:
544 		(void) dcmmctl(dev, *(int *)data, DMBIS);
545 		break;
546 
547 	case TIOCMBIC:
548 		(void) dcmmctl(dev, *(int *)data, DMBIC);
549 		break;
550 
551 	case TIOCMGET:
552 		*(int *)data = dcmmctl(dev, 0, DMGET);
553 		break;
554 
555 	default:
556 		return (ENOTTY);
557 	}
558 	return (0);
559 }
560 
561 dcmparam(tp, t)
562 	register struct tty *tp;
563 	register struct termios *t;
564 {
565 	register struct dcmdevice *dcm;
566 	register int mode, cflag = t->c_cflag;
567 	register int port;
568 	int unit = UNIT(tp->t_dev);
569 	int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
570 
571 	/* check requested parameters */
572         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
573                 return(EINVAL);
574         /* and copy to tty */
575         tp->t_ispeed = t->c_ispeed;
576         tp->t_ospeed = t->c_ospeed;
577         tp->t_cflag = cflag;
578 
579 	dcm = dcm_addr[BOARD(unit)];
580 	if (ospeed == 0) {
581 		(void) dcmmctl(unit, MO_OFF, DMSET);	/* hang up line */
582 		return;
583 	}
584 	port = PORT(unit);
585 	dcm->dcm_data[port].dcm_baud = ospeed;
586 	switch (cflag&CSIZE) {
587 	case CS5:
588 		mode = LC_5BITS; break;
589 	case CS6:
590 		mode = LC_6BITS; break;
591 	case CS7:
592 		mode = LC_7BITS; break;
593 	case CS8:
594 		mode = LC_8BITS; break;
595 	}
596 	if (cflag&PARENB) {
597 		if (cflag&PARODD)
598 			mode |= LC_PODD;
599 		else
600 			mode |= LC_PEVEN;
601 	}
602 	if (cflag&CSTOPB)
603 		mode |= LC_2STOP;
604 	else
605 		mode |= LC_1STOP;
606 #ifdef DEBUG
607 	if (dcmdebug & DDB_PARAM)
608 		printf("dcmparam: unit %d cflag %x mode %x speed %x\n",
609 		       unit, cflag, mode, ospeed);
610 #endif
611 	/* wait for transmitter buffer to empty */
612 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
613 		;
614 
615 	dcm->dcm_data[port].dcm_conf = mode;
616 	dcm->dcm_cmdtab[port].dcm_data = CT_CON;
617 	SEM_LOCK(dcm);
618 	dcm->dcm_cr = (1 << port);
619 	SEM_UNLOCK(dcm);
620 }
621 
622 dcmstart(tp)
623 	register struct tty *tp;
624 {
625 	register struct dcmdevice *dcm;
626 	int s, unit, c;
627 	register int tail, next, head, port;
628 	int restart = 0, nch = 0;
629 
630 	unit = UNIT(tp->t_dev);
631 	port = PORT(unit);
632 	dcm = dcm_addr[BOARD(unit)];
633 	s = spltty();
634 #ifdef DEBUG
635 	if (dcmdebug & DDB_OUTPUT)
636 		printf("dcmstart: unit %d state %x flags %x outcc %d\n",
637 		       unit, tp->t_state, tp->t_flags, tp->t_outq.c_cc);
638 #endif
639 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
640 		goto out;
641 	if (tp->t_outq.c_cc <= tp->t_lowat) {
642 		if (tp->t_state&TS_ASLEEP) {
643 			tp->t_state &= ~TS_ASLEEP;
644 			wakeup((caddr_t)&tp->t_outq);
645 		}
646 		if (tp->t_wsel) {
647 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
648 			tp->t_wsel = 0;
649 			tp->t_state &= ~TS_WCOLL;
650 		}
651 	}
652 	tail = dcm->dcm_ttail[port].ptr & TX_MASK;
653 	next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK;
654 	head = dcm->dcm_thead[port].ptr & TX_MASK;
655 #ifdef DEBUG
656       if (dcmdebug & DDB_OUTPUT)
657               printf("\thead %x tail %x next %x\n",
658                      head, tail, next);
659 #endif
660 	if (tail == head && tp->t_outq.c_cc)
661 		restart++;
662 	while (tp->t_outq.c_cc && next != head) {
663 		nch++;
664 		c = getc(&tp->t_outq);
665 		dcm->dcm_tfifos[3 - port][tail].data_char = c;
666 		dcm->dcm_ttail[port].ptr = next;
667 		tail = next;
668 		next = (tail + 1) & TX_MASK;
669 	}
670 	if (restart && nch) {
671 		tp->t_state |= TS_BUSY;
672 		SEM_LOCK(dcm);
673 #ifdef DEBUG
674 	if (dcmdebug & DDB_INTR)
675 		printf("TX on port %d head %x tail %x cc %d\n",
676 			port, tail, head, tp->t_outq.c_cc);
677 #endif
678 		dcm->dcm_cmdtab[port].dcm_data = CT_TX;
679 		dcm->dcm_cr = (1 << port);
680 		SEM_UNLOCK(dcm);
681 	}
682 out:
683 	splx(s);
684 }
685 
686 /*
687  * Stop output on a line.
688  */
689 dcmstop(tp, flag)
690 	register struct tty *tp;
691 {
692 	int s;
693 
694 	s = spltty();
695 	if (tp->t_state & TS_BUSY) {
696 		if ((tp->t_state&TS_TTSTOP)==0)
697 			tp->t_state |= TS_FLUSH;
698 	}
699 	splx(s);
700 }
701 
702 /* Modem control */
703 
704 dcmmctl(dev, bits, how)
705 	dev_t dev;
706 	int bits, how;
707 {
708 	register struct dcmdevice *dcm;
709 	int s, hit = 0;
710 
711 	/* Only port 0 has modem control lines. For right now the following */
712 	/* is ok, but needs to changed for the 8 port board. */
713 	if (PORT(UNIT(dev)) != 0)
714 		return(bits);
715 
716 	dcm = dcm_addr[BOARD(UNIT(dev))];
717 	s = spltty();
718 	switch (how) {
719 
720 	case DMSET:
721 		dcm->dcm_mdmout = bits;
722 		hit++;
723 		break;
724 
725 	case DMBIS:
726 		dcm->dcm_mdmout |= bits;
727 		hit++;
728 		break;
729 
730 	case DMBIC:
731 		dcm->dcm_mdmout &= ~bits;
732 		hit++;
733 		break;
734 
735 	case DMGET:
736 		bits = dcm->dcm_mdmin;
737 		break;
738 	}
739 	if (hit) {
740 		SEM_LOCK(dcm);
741 		dcm->dcm_cr |= CR_MODM;
742 		SEM_UNLOCK(dcm);
743 		(void) splx(s);
744 	}
745 	return(bits);
746 }
747 
748 dcm_setintrschm(dcm, request, brd)
749      register struct dcmdevice *dcm;
750      int request, brd;
751 {
752 	register int i;
753 
754 #ifdef DEBUG
755 	if (dcmdebug & DDB_INTSCHM) {
756 		printf("dcm%d set intr schm request %d int state %x silo hist \n\t",
757 		       brd, request, dcmintschm[brd]);
758 		for (i = 0; i < 33; i++)  {
759 			printf("  %u", dcmrsize[i]);
760 			dcmrsize[i] = 0;
761 		}
762 		printf("\n");
763 	}
764 #endif /* DEBUG */
765 
766 	/* if request true then we interrupt per char, else use card */
767 	/* polling interrupt hardware */
768 #ifdef DEBUG
769 	if (request == dcmintschm[brd]) {
770 		printf("dcm%d setintrschm redundent request %x current %x\n",
771 		       brd, request, dcmintschm[brd]);
772 		return;
773 	}
774 #endif /* DEBUG */
775 	if (request) {
776 		for (i = 0; i < 256; i++)
777 			dcm->dcm_bmap[i].data_data = 0x0f;
778 		dcmintschm[brd] = 1;
779 	}
780 	else {
781 		for (i = 0; i < 256; i++)
782 			dcm->dcm_bmap[i].data_data = 0x00;
783 		/*
784 		 * Don't slow down tandem mode, interrupt on these chars.
785 		 * XXX bad assumption, everyone uses ^Q, ^S for flow
786 		 */
787 		dcm->dcm_bmap[0x11].data_data = 0x0f;
788 		dcm->dcm_bmap[0x13].data_data = 0x0f;
789 		dcmintschm[brd] = 0;
790 	}
791 	while (dcm->dcm_cr & CR_TIMER) ;
792 	SEM_LOCK(dcm);
793 	dcm->dcm_cr |= CR_TIMER;	/* toggle card 16.7ms interrupts */
794 	SEM_UNLOCK(dcm);
795 }
796 
797 #ifdef notdef
798 /*
799  * Following are all routines needed for DCM to act as console
800  */
801 
802 struct tty *
803 dcmcninit(majordev)
804 	dev_t majordev;
805 {
806 	register struct dcmdevice *dcm;
807 	int unit, s;
808 	short stat;
809 
810 	unit = CONUNIT;				/* XXX */
811 	dcm_addr[BOARD(CONUNIT)] = CONADDR;	/* XXX */
812 
813 	dcm = dcm_addr[unit];
814 	s = splhigh();
815 	/* do something */
816 	splx(s);
817 	dcmconsole = unit;
818 	if (majordev)
819 		dcm_tty[unit].t_dev = makedev(majordev, unit);
820 	return(&dcm_tty[unit]);
821 }
822 
823 dcmcngetc(dev)
824 {
825 	return(0);
826 }
827 
828 /*
829  * Console kernel output character routine.
830  */
831 dcmcnputc(dev, c)
832 	dev_t dev;
833 	register int c;
834 {
835 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
836 	int port = PORT(dev);
837 	short stat;
838 	int head, tail, next;
839 	int s = splhigh();
840 
841 	if (dcmconsole == -1)
842 		(void) dcmcninit(0);
843 
844 	do {
845 		tail = dcm->dcm_ttail[port].ptr & TX_MASK;
846 		head = dcm->dcm_thead[port].ptr & TX_MASK;
847 	} while (tail != head);
848 	next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK;
849 
850 	dcm->dcm_tfifos[3 - port][tail].data_char = c;
851 	dcm->dcm_ttail[port].ptr = next;
852 
853 	dcm->dcm_cmdtab[port].dcm_data = CT_TX;
854 	SEM_LOCK(dcm);
855 	dcm->dcm_cr = (1 << port);
856 	SEM_UNLOCK(dcm);
857 
858 	splx(s);
859 }
860 #endif
861 #endif
862