xref: /original-bsd/sys/tahoe/tahoe/cons.c (revision b9df2d9d)
1 /*	cons.c	7.9	91/05/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, flag, mode, p)
145 	dev_t dev;
146 	int flag, mode;
147 	struct proc *p;
148 {
149 	register struct tty *tp = cntty[minor(dev)];
150 
151 	(*linesw[tp->t_line].l_close)(tp, flag);
152 	ttyclose(tp);
153 }
154 
155 /*ARGSUSED*/
156 cnread(dev, uio, flag)
157 	dev_t dev;
158 	struct uio *uio;
159 {
160 	struct tty *tp = cntty[minor(dev)];
161 
162 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
163 }
164 
165 /*ARGSUSED*/
166 cnwrite(dev, uio, flag)
167 	dev_t dev;
168 	struct uio *uio;
169 {
170 	register struct tty *tp = cntty[minor(dev)];
171 
172 	if (tp == &cons && constty &&
173 	    (constty->t_state & (TS_CARR_ON | TS_ISOPEN)) ==
174 	    (TS_CARR_ON | TS_ISOPEN))
175 		tp = constty;
176 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
177 }
178 
179 /*
180  * Got a console receive interrupt -
181  * the console processor wants to give us a character.
182  * Catch the character, and see who it goes to.
183  */
184 cnrint(dev)
185 	dev_t dev;
186 {
187 	register int unit, timo;
188 	register struct tty *tp;
189 	int c;
190 
191 	unit = minor(dev);
192 	if (!intenable || consoftc[unit].cs_flags&CSF_POLLING)
193 		return;
194 	/* make sure we dont take it from cache */
195 	uncache(&consin[unit].cpi_buf[0]);
196 	c = consin[unit].cpi_buf[0];
197 	waitforlast(timo);
198 	/* This resets status bits */
199 	consin[unit].cp_hdr.cp_unit = unit;
200 	/* Ready for new character */
201 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)&consin[unit]));
202 	cnlast = &consin[unit].cp_hdr;
203 
204 	tp = cntty[unit];
205 	if ((tp->t_cflag&CSIZE) != CS8)
206 		c &= 0177;
207 #ifdef KADB
208 	if (unit == CPCONS && kdbrintr(c, tp))
209 		return;
210 #endif
211 	(*linesw[tp->t_line].l_rint)(c & 0377, tp);
212 }
213 
214 cnioctl(dev, cmd, addr, flag)
215 	dev_t dev;
216 	caddr_t addr;
217 {
218 	register struct tty *tp = cntty[minor(dev)];
219 	register error;
220 
221 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
222 	if (error >= 0)
223 		return error;
224 	if ((error = ttioctl(tp, cmd, addr, flag)) < 0)
225 		error = ENOTTY;
226 	return (error);
227 }
228 
229 extern	int consintr;
230 /*
231  * Got a console transmission interrupt -
232  * the console processor wants another character.
233  */
234 cnxint(dev)
235 	dev_t dev;
236 {
237 	register struct tty *tp;
238 	register int unit;
239 
240 	if (!intenable || !consintr)
241 		return;
242 	unit = minor(dev);
243 #ifdef CPPERF
244 	scope_in(unit == CPCONS ? 1 : 2);
245 #endif
246 	tp = cntty[unit];
247 	tp->t_state &= ~TS_BUSY;
248 	consoftc[unit].cs_timo = 0;
249 	if (tp->t_line)
250 		(*linesw[tp->t_line].l_start)(tp);
251 	else
252 		cnstart(tp);
253 }
254 
255 cnstart(tp)
256 	register struct tty *tp;
257 {
258 	register c, s;
259 
260 #ifdef	CPPERF
261 	scope_in(minor(tp->t_dev) == CPCONS ? 3 : 4);
262 #endif
263 	s = spl8();
264 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
265 		goto out;
266 	if (tp->t_outq.c_cc <= tp->t_lowat) {
267 		if (tp->t_state&TS_ASLEEP) {
268 			tp->t_state &= ~TS_ASLEEP;
269 			wakeup((caddr_t)&tp->t_outq);
270 		}
271 		if (tp->t_wsel) {
272 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
273 			tp->t_wsel = 0;
274 			tp->t_state &= ~TS_WCOLL;
275 		}
276 	}
277 	if (tp->t_outq.c_cc == 0)
278 		goto out;
279 	c = getc(&tp->t_outq) & 0xff;
280 	if (tp->t_cflag&PARENB && ((tp->t_cflag&CSIZE)==CS7)) {
281 		c &= 0177;
282 		c |= (tp->t_cflag&PARODD ? ~partab[c] : partab[c]) & 0200;
283 	}
284 	cnputchar(c, tp);
285 	tp->t_state |= TS_BUSY;
286 out:
287 	splx(s);
288 }
289 
290 cnputc(c)
291 	char c;
292 {
293 
294 	if (c == '\n')
295 		cnputchar('\r', (struct tty *)0);
296 	cnputchar(c, (struct tty *)0);
297 }
298 
299 /*
300  * Print a character on console.
301  */
302 cnputchar(c, tp)
303 	char c;
304 	register struct tty *tp;
305 {
306 	register timo;
307 	register struct cpdcb_o *current;
308 	register struct consoftc *cs;
309 	int unit;
310 
311 	/* tp == 0 only in system error messages */
312 	if (tp == 0) {
313 		tp = &cons;
314 		tp->t_dev = CPCONS;		/* may not be open */
315 		c |= partab[c&0177]&0200;
316 	}
317 	unit = minor(tp->t_dev);
318 	current = &consout[unit];
319 	timo = 30000;
320 	/*
321 	 * Try waiting for the console tty to finish previous command
322 	 * on this unit, otherwise give up after a reasonable time.
323 	 */
324 	do
325 		uncache(&current->cp_hdr.cp_unit);
326 	while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo);
327 
328 	current->cp_hdr.cp_comm = CPWRITE;
329 	current->cp_hdr.cp_count = 1;
330 	current->cp_buf[0] = c;
331 	/*
332 	 * Try waiting for the console tty
333 	 * to accept previous command.
334 	 */
335 	waitforlast(timo);
336 
337 	/* Reset done bit */
338 	current->cp_hdr.cp_unit = (char)unit;
339 #ifdef	CPPERF
340 	if (intenable != 0)
341 		scope_in(5);
342 #endif
343 	cs = &consoftc[unit];
344 	cs->cs_lastc = c;
345 	cs->cs_timo = CN_TIMO;
346 	if ((cs->cs_flags&CSF_ACTIVE) == 0 && clk_enable) {
347 		cs->cs_flags |= CSF_ACTIVE;
348 		timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL);
349 	}
350 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
351 	cnlast = &current->cp_hdr;
352 }
353 
354 #if defined(KADB) || defined(GENERIC)
355 cngetc()
356 {
357 	register int c, s;
358 
359 	s = spl8();		/* block cnrint while we poll */
360 	c = cngetchar(&cons);
361 	if (c == '\r')
362 		c = '\n';
363 	splx(s);
364 	return (c);
365 }
366 
367 cngetchar(tp)
368 	register struct tty *tp;
369 {
370 	register timo, unit;
371 	register struct cpdcb_i *current;
372 	char c;
373 
374 	unit = minor(tp->t_dev);
375 	current = &consin[unit];
376 	waitforlast(timo);
377 	current->cp_hdr.cp_unit = unit;		/* Resets done bit */
378 	current->cp_hdr.cp_comm = CPREAD;
379 	current->cp_hdr.cp_count = 1;
380 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
381 	while ((current->cp_hdr.cp_unit&CPDONE) == 0)
382 		uncache(&current->cp_hdr.cp_unit);
383 	uncache(&current->cpi_buf[0]);
384 	c = current->cpi_buf[0] & 0x7f;
385 	cnlast = &current->cp_hdr;
386 	return (c);
387 }
388 #endif
389 
390 /*
391  * Restart (if necessary) transfer to CP line.
392  * This way, lost transmit interrupts don't wedge output.
393  */
394 cnrestart(tp)
395 	struct tty *tp;
396 {
397 	register struct consoftc *cs;
398 
399 	cs = &consoftc[minor(tp->t_dev)];
400 	cs->cs_flags &= ~CSF_ACTIVE;
401 	if (cs->cs_timo) {
402 		if (--cs->cs_timo == 0) {
403 			cs->cs_wedgecnt++;
404 			cnreset(tp);
405 			cnputchar(cs->cs_lastc, tp);
406 		} else {
407 			cs->cs_flags |= CSF_ACTIVE;
408 			timeout(cnrestart, (caddr_t)tp, CN_TIMERVAL);
409 		}
410 	}
411 }
412 
413 /*
414  * Reset console.
415  */
416 cnreset(tp)
417 	register struct tty *tp;
418 {
419 	register timo;
420 	register struct cpdcb_o *current;
421 	register unit;
422 	static int failed;
423 
424 	unit = minor(tp->t_dev);
425 	current = &consout[unit];
426 	current->cp_hdr.cp_comm = CPRESET;
427 	current->cp_hdr.cp_count = 0;
428 	current->cp_hdr.cp_unit = unit;
429 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
430 	cnlast = &current->cp_hdr;
431 	timo = 10000;
432 	do
433 		uncache(&current->cp_hdr.cp_unit);
434 	while ((current->cp_hdr.cp_unit&CPTAKE) == 0 && --timo);
435 	if (current->cp_hdr.cp_unit & CPTAKE) {
436 		cnparams(tp, &tp->t_termios);
437 		failed = 0;
438 	} else {
439 		if (failed++ == 0)
440 			log(LOG_ERR, "Console wedged, reset failed.\n");
441 		ttyflush(tp, FWRITE);
442 	}
443 }
444 
445 /*
446  * Set line parameters
447  */
448 cnparams(tp, t)
449 	register struct tty *tp;
450 	register struct termios *t;
451 {
452 	register timo = 30000;
453 	int unit = minor(tp->t_dev);
454 	register struct cpdcb_o *current = &consout[unit];
455 	register cflag = t->c_cflag;
456 	int speedcode, csize;
457 
458 	if (((speedcode == ttspeedtab(t->c_ospeed, cnspeedtab)) < 0) ||
459 	   (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
460 	   ((csize = (cflag&CSIZE)) != CS7 && csize != CS8))
461 		return (EINVAL);
462 	/*XXX*/return (0);
463 	/*
464 	 * Try waiting for the console tty to finish any output,
465 	 * otherwise give up after a reasonable time.
466 	 */
467 	do
468 		uncache(&current->cp_hdr.cp_unit);
469 	while ((current->cp_hdr.cp_unit&CPDONE) == 0 && --timo);
470 	current->cp_hdr.cp_comm = CPSTTY;
471 	current->cp_hdr.cp_count = 4;
472 	current->cp_buf[0] = speedcode;
473 #ifdef notyet
474 	/* parity */
475 	current->cp_buf[1] = (cflag&PARENB) ? ((cflag&PARODD) ? 2 : 1) : 0;
476 	/* stop bits */
477 	current->cp_buf[2] = (cflag&CSTOPB) ? 2 : 0;
478 	/* data bits */
479 	current->cp_buf[3] = (csize==CS8) ? 8 : 7;
480 #else
481 	current->cp_buf[1] = 0;	/* no parity */
482 	current->cp_buf[2] = 0;	/* stop bits */
483 	current->cp_buf[3] = 8;	/* data bits */
484 #endif
485 
486 	/* Reset done bit */
487 	current->cp_hdr.cp_unit = unit;
488 
489 	waitforlast(timo);
490 	mtpr(CPMDCB, vtoph((struct proc *)0, (unsigned)current));
491 	cnlast = &current->cp_hdr;
492 	cnpostread(unit);
493 	return (0);
494 }
495 
496 #ifdef KADB
497 /*
498  * Turn input polling on/off (used by debugger).
499  */
500 cnpoll(onoff)
501 	int onoff;
502 {
503 
504 	if (!onoff) {
505 		consoftc[CPCONS].cs_flags &= ~CSF_POLLING;
506 		cnpostread(CPCONS);		/* restart input */
507 	} else
508 		consoftc[CPCONS].cs_flags |= CSF_POLLING;
509 }
510 #endif
511