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(¤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) 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(¤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 */ 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 */ 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 */ 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