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(¤t->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 = ¤t->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(¤t->cp_hdr.cp_unit); 381 uncache(¤t->cpi_buf[0]); 382 c = current->cpi_buf[0] & 0x7f; 383 cnlast = ¤t->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 = ¤t->cp_hdr; 429 timo = 10000; 430 do 431 uncache(¤t->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(¤t->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 = ¤t->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