1 /* $NetBSD: kd.c,v 1.5 1999/08/05 18:08:13 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Gordon W. Ross. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Keyboard/Display device. 41 * 42 * This driver exists simply to provide a tty device that 43 * the indirect console driver can point to. 44 * The kbd driver sends its input here. 45 * Output goes to the screen via PROM printf. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/proc.h> 50 #include <sys/systm.h> 51 #include <sys/ioctl.h> 52 #include <sys/tty.h> 53 #include <sys/file.h> 54 #include <sys/conf.h> 55 #include <sys/device.h> 56 57 #include <machine/bsd_openprom.h> 58 #include <machine/promlib.h> 59 #include <machine/eeprom.h> 60 #include <machine/psl.h> 61 #include <machine/cpu.h> 62 #include <machine/kbd.h> 63 #include <machine/autoconf.h> 64 #include <machine/conf.h> 65 66 #ifdef RASTERCONSOLE 67 #include <machine/fbio.h> 68 #include <machine/fbvar.h> 69 #endif 70 71 72 #include <dev/cons.h> 73 #include <dev/sun/kbd_xlate.h> 74 #include <sparc/dev/cons.h> 75 76 struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 77 int cnrom __P((void)); 78 void cnrint __P((void)); 79 80 #define KDMAJOR 1 81 #define PUT_WSIZE 64 82 83 struct kd_softc { 84 struct device kd_dev; /* required first: base device */ 85 struct tty *kd_tty; 86 int rows, cols; 87 }; 88 89 /* 90 * There is no point in pretending there might be 91 * more than one keyboard/display device. 92 */ 93 static struct kd_softc kd_softc; 94 static int kd_is_console; 95 96 static int kdparam(struct tty *, struct termios *); 97 static void kdstart(struct tty *); 98 99 int rom_console_input; /* when set, hardclock calls cnrom() */ 100 int cons_ocount; /* output byte count */ 101 102 /* Now talking directly to the zs, so this is not needed. */ 103 int 104 cnrom() 105 { 106 return (0); 107 } 108 void 109 cnrint() 110 { 111 } 112 113 /* 114 * This is called by kbd_attach() 115 * XXX - Make this a proper child of kbd? 116 */ 117 void 118 kd_init(unit) 119 int unit; 120 { 121 struct kd_softc *kd; 122 struct tty *tp; 123 124 if (unit != 0) 125 return; 126 kd = &kd_softc; /* XXX */ 127 128 tp = ttymalloc(); 129 tp->t_oproc = kdstart; 130 tp->t_param = kdparam; 131 tp->t_dev = makedev(KDMAJOR, unit); 132 133 #if 1 /* XXX - Why? */ 134 clalloc(&tp->t_rawq, 1024, 1); 135 clalloc(&tp->t_canq, 1024, 1); 136 /* output queue doesn't need quoting */ 137 clalloc(&tp->t_outq, 1024, 0); 138 #endif 139 140 tty_attach(tp); 141 kd->kd_tty = tp; 142 143 /* 144 * get the console struct winsize. 145 */ 146 if (kd_is_console) { 147 fbconstty = tp; 148 #ifdef RASTERCONSOLE 149 kd->rows = fbrcons_rows(); 150 kd->cols = fbrcons_cols(); 151 #endif 152 } 153 154 if (CPU_ISSUN4COR4M) { 155 int i; 156 char *prop; 157 158 if (kd->rows == 0 && 159 (prop = getpropstring(optionsnode, "screen-#rows"))) { 160 i = 0; 161 while (*prop != '\0') 162 i = i * 10 + *prop++ - '0'; 163 kd->rows = (unsigned short)i; 164 } 165 if (kd->cols == 0 && 166 (prop = getpropstring(optionsnode, "screen-#columns"))) { 167 i = 0; 168 while (*prop != '\0') 169 i = i * 10 + *prop++ - '0'; 170 kd->cols = (unsigned short)i; 171 } 172 } 173 if (CPU_ISSUN4) { 174 struct eeprom *ep = (struct eeprom *)eeprom_va; 175 176 if (ep) { 177 if (kd->rows == 0) 178 kd->rows = (u_short)ep->eeTtyRows; 179 if (kd->cols == 0) 180 kd->cols = (u_short)ep->eeTtyCols; 181 } 182 } 183 184 return; 185 } 186 187 struct tty * 188 kdtty(dev) 189 dev_t dev; 190 { 191 struct kd_softc *kd; 192 193 kd = &kd_softc; /* XXX */ 194 return (kd->kd_tty); 195 } 196 197 int 198 kdopen(dev, flag, mode, p) 199 dev_t dev; 200 int flag, mode; 201 struct proc *p; 202 { 203 struct kd_softc *kd; 204 int error, s, unit; 205 struct tty *tp; 206 207 unit = minor(dev); 208 if (unit != 0) 209 return ENXIO; 210 kd = &kd_softc; /* XXX */ 211 tp = kd->kd_tty; 212 213 if ((error = kbd_iopen(unit)) != 0) { 214 #ifdef DIAGNOSTIC 215 printf("kd: kbd_iopen, error=%d\n", error); 216 #endif 217 return (error); 218 } 219 220 /* It's simpler to do this up here. */ 221 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 222 == (TS_ISOPEN | TS_XCLUDE)) 223 && (p->p_ucred->cr_uid != 0) ) 224 { 225 return (EBUSY); 226 } 227 228 s = spltty(); 229 230 if ((tp->t_state & TS_ISOPEN) == 0) { 231 /* First open. */ 232 ttychars(tp); 233 tp->t_iflag = TTYDEF_IFLAG; 234 tp->t_oflag = TTYDEF_OFLAG; 235 tp->t_cflag = TTYDEF_CFLAG; 236 tp->t_lflag = TTYDEF_LFLAG; 237 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 238 (void) kdparam(tp, &tp->t_termios); 239 ttsetwater(tp); 240 tp->t_winsize.ws_row = kd->rows; 241 tp->t_winsize.ws_col = kd->cols; 242 /* Flush pending input? Clear translator? */ 243 /* This (pseudo)device always has SOFTCAR */ 244 tp->t_state |= TS_CARR_ON; 245 } 246 247 splx(s); 248 249 return ((*linesw[tp->t_line].l_open)(dev, tp)); 250 } 251 252 int 253 kdclose(dev, flag, mode, p) 254 dev_t dev; 255 int flag, mode; 256 struct proc *p; 257 { 258 struct kd_softc *kd; 259 struct tty *tp; 260 261 kd = &kd_softc; /* XXX */ 262 tp = kd->kd_tty; 263 264 /* XXX This is for cons.c. */ 265 if ((tp->t_state & TS_ISOPEN) == 0) 266 return 0; 267 268 (*linesw[tp->t_line].l_close)(tp, flag); 269 ttyclose(tp); 270 return (0); 271 } 272 273 int 274 kdread(dev, uio, flag) 275 dev_t dev; 276 struct uio *uio; 277 int flag; 278 { 279 struct kd_softc *kd; 280 struct tty *tp; 281 282 kd = &kd_softc; /* XXX */ 283 tp = kd->kd_tty; 284 285 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 286 } 287 288 int 289 kdwrite(dev, uio, flag) 290 dev_t dev; 291 struct uio *uio; 292 int flag; 293 { 294 struct kd_softc *kd; 295 struct tty *tp; 296 297 kd = &kd_softc; /* XXX */ 298 tp = kd->kd_tty; 299 300 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 301 } 302 303 int 304 kdioctl(dev, cmd, data, flag, p) 305 dev_t dev; 306 u_long cmd; 307 caddr_t data; 308 int flag; 309 struct proc *p; 310 { 311 struct kd_softc *kd; 312 struct tty *tp; 313 int error; 314 315 kd = &kd_softc; /* XXX */ 316 tp = kd->kd_tty; 317 318 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 319 if (error >= 0) 320 return error; 321 error = ttioctl(tp, cmd, data, flag, p); 322 if (error >= 0) 323 return error; 324 325 /* Handle any ioctl commands specific to kbd/display. */ 326 /* XXX - Send KB* ioctls to kbd module? */ 327 /* XXX - Send FB* ioctls to fb module? */ 328 329 return ENOTTY; 330 } 331 332 void 333 kdstop(tp, flag) 334 struct tty *tp; 335 int flag; 336 { 337 338 } 339 340 341 static int 342 kdparam(tp, t) 343 struct tty *tp; 344 struct termios *t; 345 { 346 /* XXX - These are ignored... */ 347 tp->t_ispeed = t->c_ispeed; 348 tp->t_ospeed = t->c_ospeed; 349 tp->t_cflag = t->c_cflag; 350 return 0; 351 } 352 353 354 static void kd_later(void*); 355 static void kd_putfb(struct tty *); 356 357 static void 358 kdstart(tp) 359 struct tty *tp; 360 { 361 struct clist *cl; 362 register int s; 363 364 s = spltty(); 365 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 366 goto out; 367 368 cl = &tp->t_outq; 369 if (cl->c_cc) { 370 if (kd_is_console) { 371 tp->t_state |= TS_BUSY; 372 if ((s & PSR_PIL) == 0) { 373 /* called at level zero - update screen now. */ 374 (void) spllowersoftclock(); 375 kd_putfb(tp); 376 (void) spltty(); 377 tp->t_state &= ~TS_BUSY; 378 } else { 379 /* called at interrupt level - do it later */ 380 timeout(kd_later, (void*)tp, 0); 381 } 382 } else { 383 /* 384 * This driver uses the PROM for writing the screen, 385 * and that only works if this is the console device. 386 * If this is not the console, just flush the output. 387 * Sorry. (In that case, use xdm instead of getty.) 388 */ 389 ndflush(cl, cl->c_cc); 390 } 391 } 392 if (cl->c_cc <= tp->t_lowat) { 393 if (tp->t_state & TS_ASLEEP) { 394 tp->t_state &= ~TS_ASLEEP; 395 wakeup((caddr_t)cl); 396 } 397 selwakeup(&tp->t_wsel); 398 } 399 out: 400 splx(s); 401 } 402 403 /* 404 * Timeout function to do delayed writes to the screen. 405 * Called at splsoftclock when requested by kdstart. 406 */ 407 static void 408 kd_later(tpaddr) 409 void *tpaddr; 410 { 411 struct tty *tp = tpaddr; 412 register int s; 413 414 kd_putfb(tp); 415 416 s = spltty(); 417 tp->t_state &= ~TS_BUSY; 418 (*linesw[tp->t_line].l_start)(tp); 419 splx(s); 420 } 421 422 /* 423 * Put text on the screen using the PROM monitor. 424 * This can take a while, so to avoid missing 425 * interrupts, this is called at splsoftclock. 426 */ 427 static void 428 kd_putfb(tp) 429 struct tty *tp; 430 { 431 char buf[PUT_WSIZE]; 432 struct clist *cl = &tp->t_outq; 433 char *p, *end; 434 int len; 435 436 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 437 /* PROM will barf if high bits are set. */ 438 p = buf; 439 end = buf + len; 440 while (p < end) 441 *p++ &= 0x7f; 442 443 /* Now let the PROM print it. */ 444 prom_putstr(buf, len); 445 } 446 } 447 448 /* 449 * Our "interrupt" routine for input. This is called by 450 * the keyboard driver (dev/sun/kbd.c) at spltty. 451 */ 452 void 453 kd_input(c) 454 int c; 455 { 456 struct kd_softc *kd = &kd_softc; 457 struct tty *tp; 458 459 /* XXX: Make sure the device is open. */ 460 tp = kd->kd_tty; 461 if (tp == NULL) 462 return; 463 if ((tp->t_state & TS_ISOPEN) == 0) 464 return; 465 466 (*linesw[tp->t_line].l_rint)(c, tp); 467 } 468 469 470 /**************************************************************** 471 * kd console support 472 ****************************************************************/ 473 474 /* The debugger gets its own key translation state. */ 475 static struct kbd_state kdcn_state; 476 477 static void kdcnprobe __P((struct consdev *)); 478 static void kdcninit __P((struct consdev *)); 479 static int kdcngetc __P((dev_t)); 480 static void kdcnputc __P((dev_t, int)); 481 static void kdcnpollc __P((dev_t, int)); 482 483 struct consdev consdev_kd = { 484 kdcnprobe, 485 kdcninit, 486 kdcngetc, 487 kdcnputc, 488 kdcnpollc, 489 }; 490 491 /* We never call this. */ 492 static void 493 kdcnprobe(cn) 494 struct consdev *cn; 495 { 496 } 497 498 static void 499 kdcninit(cn) 500 struct consdev *cn; 501 { 502 struct kbd_state *ks = &kdcn_state; 503 504 cn->cn_dev = makedev(KDMAJOR, 0); 505 cn->cn_pri = CN_INTERNAL; 506 507 /* This prepares kbd_translate() */ 508 ks->kbd_id = KBD_MIN_TYPE; 509 kbd_xlate_init(ks); 510 511 /* Indicate that it is OK to use the PROM fbwrite */ 512 kd_is_console = 1; 513 } 514 515 static int 516 kdcngetc(dev) 517 dev_t dev; 518 { 519 struct kbd_state *ks = &kdcn_state; 520 int code, class, data, keysym; 521 522 for (;;) { 523 code = zs_getc(zs_conschan); 524 keysym = kbd_code_to_keysym(ks, code); 525 class = KEYSYM_CLASS(keysym); 526 527 switch (class) { 528 case KEYSYM_ASCII: 529 goto out; 530 531 case KEYSYM_CLRMOD: 532 case KEYSYM_SETMOD: 533 data = (keysym & 0x1F); 534 /* Only allow ctrl or shift. */ 535 if (data > KBMOD_SHIFT_R) 536 break; 537 data = 1 << data; 538 if (class == KEYSYM_SETMOD) 539 ks->kbd_modbits |= data; 540 else 541 ks->kbd_modbits &= ~data; 542 break; 543 544 case KEYSYM_ALL_UP: 545 /* No toggle keys here. */ 546 ks->kbd_modbits = 0; 547 break; 548 549 default: /* ignore all other keysyms */ 550 break; 551 } 552 } 553 out: 554 return (keysym); 555 } 556 557 static void 558 kdcnputc(dev, c) 559 dev_t dev; 560 int c; 561 { 562 563 prom_putchar(c); 564 } 565 566 static void 567 kdcnpollc(dev, on) 568 dev_t dev; 569 int on; 570 { 571 struct kbd_state *ks = &kdcn_state; 572 573 if (on) { 574 /* Entering debugger. */ 575 #if NFB > 0 576 fb_unblank(); 577 #endif 578 /* Clear shift keys too. */ 579 ks->kbd_modbits = 0; 580 } else { 581 /* Resuming kernel. */ 582 } 583 } 584 585