xref: /original-bsd/sys/tahoe/tahoe/cons.c (revision 0dce6c9d)
1 /*	cons.c	7.7	90/12/16	*/
2 
3 /*
4  * Tahoe console processor driver
5  *
6  * Minor device 0 is the CP itself.
7  *	  No real read/writes can be done to him.
8  * Minor 1 is the console terminal.
9  * Minor 2 is the remote line trminal.
10  */
11 #include "sys/param.h"
12 #include "sys/conf.h"
13 #include "sys/file.h"
14 #include "sys/ioctl.h"
15 #include "sys/user.h"
16 #include "sys/proc.h"
17 #include "sys/tty.h"
18 #include "sys/callout.h"
19 #include "sys/systm.h"
20 #include "sys/kernel.h"
21 #include "sys/syslog.h"
22 
23 #include "cp.h"
24 #include "../include/cpu.h"
25 #include "../include/mtpr.h"
26 
27 int	cnrestart();
28 int	timeout();
29 
30 struct	tty CPtty;
31 struct	tty cons;
32 struct	tty RLtty;
33 struct	tty *cntty[3] = { &CPtty, &cons, &RLtty };
34 
35 struct	tty *constty = 0;	/* virtual console */
36 
37 struct	consoftc {
38 	char	cs_flags;
39 #define	CSF_ACTIVE	0x1	/* timeout active */
40 #define	CSF_POLLING	0x2	/* polling for input */
41 	char	cs_lastc;	/* last char sent */
42 	int	cs_timo;	/* timeouts since interrupt */
43 	u_long	cs_wedgecnt;	/* times restarted */
44 } consoftc[3];
45 
46 struct speedtab cnspeedtab[] = {
47 	9600,	13,
48 	4800,	12,
49 	2400,	11,
50 	1800,	10,
51 	1200,	9,
52 	600,	8,
53 	300,	7,
54 	200,	6,
55 	150,	5,
56 	134,	4,
57 	110,	3,
58 	75,	2,
59 	50,	1,
60 	0,	13,
61 	-1,	-1,
62 };
63 
64 /*
65  * We check the console periodically to make sure
66  * that it hasn't wedged.  Unfortunately, if an XOFF
67  * is typed on the console, that can't be distinguished
68  * from more catastrophic failure.
69  */
70 #define	CN_TIMERVAL	(hz)		/* frequency at which to check cons */
71 #define	CN_TIMO		(2*60)		/* intervals to allow for output char */
72 
73 struct	cpdcb_o consout[3] = {
74 	{ CPTAKE|CPDONE }, { CPTAKE|CPDONE }, { CPTAKE|CPDONE }
75 };
76 struct	cpdcb_i consin[3] = {
77 	{ CPTAKE|CPDONE }, { CPTAKE|CPDONE }, { CPTAKE|CPDONE }
78 };
79 struct	cphdr *cnlast;
80 
81 int	cnstart();
82 int	ttrstrt();
83 char	partab[];
84 
85 /*
86  * Wait for CP to accept last CP command sent
87  * before setting up next command.
88  */
89 #define	waitforlast(timo) { \
90 	if (cnlast) { \
91 		(timo) = 10000; \
92 		do \
93 			uncache((char *)&cnlast->cp_unit); \
94 		while ((cnlast->cp_unit&CPTAKE) == 0 && --(timo)); \
95 	} \
96 }
97 
98 /*ARGSUSED*/
99 cnopen(dev, flag)
100 	dev_t dev;
101 {
102 	register struct tty *tp;
103 	int unit = minor(dev);
104 	int cnparams();
105 
106 	if (unit > CPREMOT)
107 		return (ENXIO);
108 	tp = cntty[unit];
109 	if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
110 		return (EBUSY);
111 	cnpostread(unit);		/* post request for input */
112 	tp->t_oproc = cnstart;
113 	tp->t_param = cnparams;
114 	tp->t_dev = dev;
115 	if ((tp->t_state&TS_ISOPEN) == 0) {
116 		ttychars(tp);
117 		tp->t_iflag = TTYDEF_IFLAG|ICRNL;
118 		tp->t_oflag = TTYDEF_OFLAG|OPOST|ONLCR;
119 		tp->t_lflag = TTYDEF_LFLAG;
120 		tp->t_cflag = CS8|CREAD;
121 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
122 		tp->t_state = TS_ISOPEN|TS_CARR_ON;
123 		cnparams(tp, &tp->t_termios);
124 		ttsetwater(tp);
125 	}
126 	return ((*linesw[tp->t_line].l_open)(dev, tp));
127 }
128 
129 cnpostread(unit)
130 	int unit;
131 {
132 	register struct cpdcb_i *cin;
133 	register int timo;
134 
135 	waitforlast(timo);
136 	cin = &consin[unit];
137 	cin->cp_hdr.cp_unit = unit;
138 	cin->cp_hdr.cp_comm = CPREAD;
139 	cin->cp_hdr.cp_count = 1;	/* Get ready for input */
140 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)cin));
141 	cnlast = &cin->cp_hdr;
142 }
143 
144 cnclose(dev)
145 	dev_t dev;
146 {
147 	register struct tty *tp = cntty[minor(dev)];
148 
149 	(*linesw[tp->t_line].l_close)(tp);
150 	ttyclose(tp);
151 }
152 
153 /*ARGSUSED*/
154 cnread(dev, uio, flag)
155 	dev_t dev;
156 	struct uio *uio;
157 {
158 	struct tty *tp = cntty[minor(dev)];
159 
160 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
161 }
162 
163 /*ARGSUSED*/
164 cnwrite(dev, uio, flag)
165 	dev_t dev;
166 	struct uio *uio;
167 {
168 	register struct tty *tp = cntty[minor(dev)];
169 
170 	if (tp == &cons && constty &&
171 	    (constty->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
172 	    (TS_CARR_ON | TS_ISOPEN))
173 		tp = constty;
174 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
175 }
176 
177 /*
178  * Got a console receive interrupt -
179  * the console processor wants to give us a character.
180  * Catch the character, and see who it goes to.
181  */
182 cnrint(dev)
183 	dev_t dev;
184 {
185 	register int unit, timo;
186 	register struct tty *tp;
187 	int c;
188 
189 	unit = minor(dev);
190 	if (!intenable || consoftc[unit].cs_flags&CSF_POLLING)
191 		return;
192 	/* make sure we dont take it from cache */
193 	uncache(&consin[unit].cpi_buf[0]);
194 	c = consin[unit].cpi_buf[0];
195 	waitforlast(timo);
196 	/* This resets status bits */
197 	consin[unit].cp_hdr.cp_unit = unit;
198 	/* Ready for new character */
199 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)&consin[unit]));
200 	cnlast = &consin[unit].cp_hdr;
201 
202 	tp = cntty[unit];
203 	if ((tp->t_cflag&CSIZE) != CS8)
204 		c &= 0177;
205 #ifdef KADB
206 	if (unit == CPCONS && kdbrintr(c, tp))
207 		return;
208 #endif
209 	(*linesw[tp->t_line].l_rint)(c & 0377, tp);
210 }
211 
212 cnioctl(dev, cmd, addr, flag)
213 	dev_t dev;
214 	caddr_t addr;
215 {
216 	register struct tty *tp = cntty[minor(dev)];
217 	register error;
218 
219 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
220 	if (error >= 0)
221 		return error;
222 	if ((error = ttioctl(tp, cmd, addr, flag)) < 0)
223 		error = ENOTTY;
224 	return (error);
225 }
226 
227 int	consintr = 1;
228 /*
229  * Got a console transmission interrupt -
230  * the console processor wants another character.
231  */
232 cnxint(dev)
233 	dev_t dev;
234 {
235 	register struct tty *tp;
236 	register int unit;
237 
238 	if (!intenable || !consintr)
239 		return;
240 	unit = minor(dev);
241 #ifdef CPPERF
242 	scope_in(unit == CPCONS ? 1 : 2);
243 #endif
244 	tp = cntty[unit];
245 	tp->t_state &= ~TS_BUSY;
246 	consoftc[unit].cs_timo = 0;
247 	if (tp->t_line)
248 		(*linesw[tp->t_line].l_start)(tp);
249 	else
250 		cnstart(tp);
251 }
252 
253 cnstart(tp)
254 	register struct tty *tp;
255 {
256 	register c, s;
257 
258 #ifdef	CPPERF
259 	scope_in(minor(tp->t_dev) == CPCONS ? 3 : 4);
260 #endif
261 	s = spl8();
262 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
263 		goto out;
264 	if (tp->t_outq.c_cc <= tp->t_lowat) {
265 		if (tp->t_state&TS_ASLEEP) {
266 			tp->t_state &= ~TS_ASLEEP;
267 			wakeup((caddr_t)&tp->t_outq);
268 		}
269 		if (tp->t_wsel) {
270 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
271 			tp->t_wsel = 0;
272 			tp->t_state &= ~TS_WCOLL;
273 		}
274 	}
275 	if (tp->t_outq.c_cc == 0)
276 		goto out;
277 	c = getc(&tp->t_outq) & 0xff;
278 	if (tp->t_cflag&PARENB && ((tp->t_cflag&CSIZE)==CS7)) {
279 		c &= 0177;
280 		c |= (tp->t_cflag&PARODD ? ~partab[c] : partab[c]) & 0200;
281 	}
282 	cnputchar(c, tp);
283 	tp->t_state |= TS_BUSY;
284 out:
285 	splx(s);
286 }
287 
288 cnputc(c)
289 	char c;
290 {
291 
292 	if (c == '\n')
293 		cnputchar('\r', (struct tty *)0);
294 	cnputchar(c, (struct tty *)0);
295 }
296 
297 /*
298  * Print a character on console.
299  */
300 cnputchar(c, tp)
301 	char c;
302 	register struct tty *tp;
303 {
304 	register timo;
305 	register struct cpdcb_o *current;
306 	register struct consoftc *cs;
307 	int unit;
308 
309 	/* tp == 0 only in system error messages */
310 	if (tp == 0) {
311 		tp = &cons;
312 		tp->t_dev = CPCONS;		/* may not be open */
313 		c |= partab[c&0177]&0200;
314 	}
315 	unit = minor(tp->t_dev);
316 	current = &consout[unit];
317 	timo = 30000;
318 	/*
319 	 * Try waiting for the console tty to finish previous command
320 	 * on this unit, otherwise give up after a reasonable time.
321 	 */
322 	do
323 		uncache(&current->cp_hdr.cp_unit);
324 	while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo);
325 
326 	current->cp_hdr.cp_comm = CPWRITE;
327 	current->cp_hdr.cp_count = 1;
328 	current->cp_buf[0] = c;
329 	/*
330 	 * Try waiting for the console tty
331 	 * to accept previous command.
332 	 */
333 	waitforlast(timo);
334 
335 	/* Reset done bit */
336 	current->cp_hdr.cp_unit = (char)unit;
337 #ifdef	CPPERF
338 	if (intenable != 0)
339 		scope_in(5);
340 #endif
341 	cs = &consoftc[unit];
342 	cs->cs_lastc = c;
343 	cs->cs_timo = CN_TIMO;
344 	if ((cs->cs_flags&CSF_ACTIVE) == 0 && clk_enable) {
345 		cs->cs_flags |= CSF_ACTIVE;
346 		timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL);
347 	}
348 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
349 	cnlast = &current->cp_hdr;
350 }
351 
352 #if defined(KADB) || defined(GENERIC)
353 cngetc()
354 {
355 	register int c, s;
356 
357 	s = spl8();		/* block cnrint while we poll */
358 	c = cngetchar(&cons);
359 	if (c == '\r')
360 		c = '\n';
361 	splx(s);
362 	return (c);
363 }
364 
365 cngetchar(tp)
366 	register struct tty *tp;
367 {
368 	register timo, unit;
369 	register struct cpdcb_i *current;
370 	char c;
371 
372 	unit = minor(tp->t_dev);
373 	current = &consin[unit];
374 	waitforlast(timo);
375 	current->cp_hdr.cp_unit = unit;		/* Resets done bit */
376 	current->cp_hdr.cp_comm = CPREAD;
377 	current->cp_hdr.cp_count = 1;
378 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
379 	while ((current->cp_hdr.cp_unit&CPDONE) == 0)
380 		uncache(&current->cp_hdr.cp_unit);
381 	uncache(&current->cpi_buf[0]);
382 	c = current->cpi_buf[0] & 0x7f;
383 	cnlast = &current->cp_hdr;
384 	return (c);
385 }
386 #endif
387 
388 /*
389  * Restart (if necessary) transfer to CP line.
390  * This way, lost transmit interrupts don't wedge output.
391  */
392 cnrestart(tp)
393 	struct tty *tp;
394 {
395 	register struct consoftc *cs;
396 
397 	cs = &consoftc[minor(tp->t_dev)];
398 	cs->cs_flags &= ~CSF_ACTIVE;
399 	if (cs->cs_timo) {
400 		if (--cs->cs_timo == 0) {
401 			cs->cs_wedgecnt++;
402 			cnreset(tp);
403 			cnputchar(cs->cs_lastc, tp);
404 		} else {
405 			cs->cs_flags |= CSF_ACTIVE;
406 			timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL);
407 		}
408 	}
409 }
410 
411 /*
412  * Reset console.
413  */
414 cnreset(tp)
415 	register struct tty *tp;
416 {
417 	register timo;
418 	register struct cpdcb_o *current;
419 	register unit;
420 	static int failed;
421 
422 	unit = minor(tp->t_dev);
423 	current = &consout[unit];
424 	current->cp_hdr.cp_comm = CPRESET;
425 	current->cp_hdr.cp_count = 0;
426 	current->cp_hdr.cp_unit = unit;
427 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
428 	cnlast = &current->cp_hdr;
429 	timo = 10000;
430 	do
431 		uncache(&current->cp_hdr.cp_unit);
432 	while ((current->cp_hdr.cp_unit&CPTAKE) == 0 && --timo);
433 	if (current->cp_hdr.cp_unit & CPTAKE) {
434 		cnparams(tp, &tp->t_termios);
435 		failed = 0;
436 	} else {
437 		if (failed++ == 0)
438 			log(LOG_ERR, "Console wedged, reset failed.\n");
439 		ttyflush(tp, FWRITE);
440 	}
441 }
442 
443 /*
444  * Set line parameters
445  */
446 cnparams(tp, t)
447 	register struct tty *tp;
448 	register struct termios *t;
449 {
450 	register timo = 30000;
451 	int unit = minor(tp->t_dev);
452 	register struct cpdcb_o *current = &consout[unit];
453 	register cflag = t->c_cflag;
454 	int speedcode, csize;
455 
456 	if (((speedcode == ttspeedtab(t->c_ospeed, cnspeedtab)) < 0) ||
457 	   (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
458 	   ((csize = (cflag&CSIZE)) != CS7 && csize != CS8))
459 		return (EINVAL);
460 	/*XXX*/return (0);
461 	/*
462 	 * Try waiting for the console tty to finish any output,
463 	 * otherwise give up after a reasonable time.
464 	 */
465 	do
466 		uncache(&current->cp_hdr.cp_unit);
467 	while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo);
468 	current->cp_hdr.cp_comm = CPSTTY;
469 	current->cp_hdr.cp_count = 4;
470 	current->cp_buf[0] = speedcode;
471 #ifdef notyet
472 	/* parity */
473 	current->cp_buf[1] = (cflag&PARENB) ? ((cflag&PARODD) ? 2 : 1) : 0;
474 	/* stop bits */
475 	current->cp_buf[2] = (cflag&CSTOPB) ? 2 : 0;
476 	/* data bits */
477 	current->cp_buf[3] = (csize==CS8) ? 8 : 7;
478 #else
479 	current->cp_buf[1] = 0;	/* no parity */
480 	current->cp_buf[2] = 0;	/* stop bits */
481 	current->cp_buf[3] = 8;	/* data bits */
482 #endif
483 
484 	/* Reset done bit */
485 	current->cp_hdr.cp_unit = unit;
486 
487 	waitforlast(timo);
488 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
489 	cnlast = &current->cp_hdr;
490 	cnpostread(unit);
491 	return (0);
492 }
493 
494 #ifdef KADB
495 /*
496  * Turn input polling on/off (used by debugger).
497  */
498 cnpoll(onoff)
499 	int onoff;
500 {
501 
502 	if (!onoff) {
503 		consoftc[CPCONS].cs_flags &= ~CSF_POLLING;
504 		cnpostread(CPCONS);		/* restart input */
505 	} else
506 		consoftc[CPCONS].cs_flags |= CSF_POLLING;
507 }
508 #endif
509