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