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*/
cnopen(dev,flag)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
cnpostread(unit)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
cnclose(dev,flag,mode,p)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*/
cnread(dev,uio,flag)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*/
cnwrite(dev,uio,flag)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 */
cnrint(dev)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
cnioctl(dev,cmd,addr,flag)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 */
cnxint(dev)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
cnstart(tp)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
cnputc(c)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 */
cnputchar(c,tp)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(¤t->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 = ¤t->cp_hdr;
352 }
353
354 #if defined(KADB) || defined(GENERIC)
cngetc()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
cngetchar(tp)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(¤t->cp_hdr.cp_unit);
383 uncache(¤t->cpi_buf[0]);
384 c = current->cpi_buf[0] & 0x7f;
385 cnlast = ¤t->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 */
cnreset(tp)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 = ¤t->cp_hdr;
431 timo = 10000;
432 do
433 uncache(¤t->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 */
cnparams(tp,t)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(¤t->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 = ¤t->cp_hdr;
492 cnpostread(unit);
493 return (0);
494 }
495
496 #ifdef KADB
497 /*
498 * Turn input polling on/off (used by debugger).
499 */
cnpoll(onoff)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