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