1 /* $NetBSD: kd.c,v 1.12 2000/05/19 05:26:17 eeh 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/openfirm.h> 58 #include <machine/eeprom.h> 59 #include <machine/psl.h> 60 #include <machine/cpu.h> 61 #include <machine/kbd.h> 62 #include <machine/autoconf.h> 63 #include <machine/conf.h> 64 65 #ifdef RASTERCONSOLE 66 #include <machine/fbio.h> 67 #include <machine/fbvar.h> 68 #endif 69 70 71 #include <dev/cons.h> 72 #include <dev/sun/event_var.h> 73 #include <dev/sun/kbd_xlate.h> 74 #include <dev/sun/kbdvar.h> 75 #include <sparc64/dev/cons.h> 76 77 struct tty *fbconstty = 0; /* tty structure for frame buffer console */ 78 79 #define KDMAJOR 1 80 #define PUT_WSIZE 64 81 82 struct kd_softc { 83 struct device kd_dev; /* required first: base device */ 84 struct tty *kd_tty; 85 int rows, cols; 86 87 /* Console input hook */ 88 struct cons_channel *kd_in; 89 }; 90 91 /* 92 * There is no point in pretending there might be 93 * more than one keyboard/display device. 94 */ 95 static struct kd_softc kd_softc; 96 static int kd_is_console; 97 98 static int kdparam(struct tty *, struct termios *); 99 static void kdstart(struct tty *); 100 static void kd_init __P((struct kd_softc *)); 101 static void kd_cons_input __P((int)); 102 static int kdcngetc __P((dev_t)); 103 104 int cons_ocount; /* output byte count */ 105 106 /* 107 * This is called by kbd_attach() 108 * XXX - Make this a proper child of kbd? 109 */ 110 void 111 kd_init(kd) 112 struct kd_softc *kd; 113 { 114 struct tty *tp; 115 int i; 116 char *prop; 117 118 kd = &kd_softc; /* XXX */ 119 120 tp = ttymalloc(); 121 tp->t_oproc = kdstart; 122 tp->t_param = kdparam; 123 tp->t_dev = makedev(KDMAJOR, 0); 124 125 tty_attach(tp); 126 kd->kd_tty = tp; 127 128 /* 129 * get the console struct winsize. 130 */ 131 if (kd_is_console) { 132 fbconstty = tp; 133 #ifdef RASTERCONSOLE 134 kd->rows = fbrcons_rows(); 135 kd->cols = fbrcons_cols(); 136 rcons_ttyinit(tp); 137 #endif 138 } 139 140 if (kd->rows == 0 && 141 (prop = getpropstring(optionsnode, "screen-#rows"))) { 142 i = 0; 143 while (*prop != '\0') 144 i = i * 10 + *prop++ - '0'; 145 kd->rows = (unsigned short)i; 146 } 147 if (kd->cols == 0 && 148 (prop = getpropstring(optionsnode, "screen-#columns"))) { 149 i = 0; 150 while (*prop != '\0') 151 i = i * 10 + *prop++ - '0'; 152 kd->cols = (unsigned short)i; 153 } 154 return; 155 } 156 157 struct tty * 158 kdtty(dev) 159 dev_t dev; 160 { 161 struct kd_softc *kd; 162 163 kd = &kd_softc; /* XXX */ 164 return (kd->kd_tty); 165 } 166 167 int 168 kdopen(dev, flag, mode, p) 169 dev_t dev; 170 int flag, mode; 171 struct proc *p; 172 { 173 struct kd_softc *kd; 174 int error, s, unit; 175 struct tty *tp; 176 static int firstopen = 1; 177 178 unit = minor(dev); 179 if (unit != 0) 180 return ENXIO; 181 kd = &kd_softc; /* XXX */ 182 183 if (firstopen) { 184 kd_init(kd); 185 firstopen = 0; 186 } 187 tp = kd->kd_tty; 188 189 /* It's simpler to do this up here. */ 190 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 191 == (TS_ISOPEN | TS_XCLUDE)) 192 && (p->p_ucred->cr_uid != 0) ) 193 { 194 return (EBUSY); 195 } 196 197 s = spltty(); 198 199 if ((tp->t_state & TS_ISOPEN) == 0) { 200 /* First open. */ 201 202 /* Notify the input device that serves us */ 203 struct cons_channel *cc = kd->kd_in; 204 if (cc != NULL && 205 (error = (*cc->cc_iopen)(cc)) != 0) { 206 return (error); 207 } 208 209 ttychars(tp); 210 tp->t_iflag = TTYDEF_IFLAG; 211 tp->t_oflag = TTYDEF_OFLAG; 212 tp->t_cflag = TTYDEF_CFLAG; 213 tp->t_lflag = TTYDEF_LFLAG; 214 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 215 (void) kdparam(tp, &tp->t_termios); 216 ttsetwater(tp); 217 tp->t_winsize.ws_row = kd->rows; 218 tp->t_winsize.ws_col = kd->cols; 219 /* Flush pending input? Clear translator? */ 220 /* This (pseudo)device always has SOFTCAR */ 221 tp->t_state |= TS_CARR_ON; 222 } 223 224 splx(s); 225 226 return ((*linesw[tp->t_line].l_open)(dev, tp)); 227 } 228 229 int 230 kdclose(dev, flag, mode, p) 231 dev_t dev; 232 int flag, mode; 233 struct proc *p; 234 { 235 struct kd_softc *kd; 236 struct tty *tp; 237 struct cons_channel *cc; 238 239 kd = &kd_softc; /* XXX */ 240 tp = kd->kd_tty; 241 242 /* XXX This is for cons.c. */ 243 if ((tp->t_state & TS_ISOPEN) == 0) 244 return 0; 245 246 (*linesw[tp->t_line].l_close)(tp, flag); 247 ttyclose(tp); 248 249 if ((cc = kd->kd_in) != NULL) 250 (void)(*cc->cc_iclose)(cc->cc_dev); 251 252 return (0); 253 } 254 255 int 256 kdread(dev, uio, flag) 257 dev_t dev; 258 struct uio *uio; 259 int flag; 260 { 261 struct kd_softc *kd; 262 struct tty *tp; 263 264 kd = &kd_softc; /* XXX */ 265 tp = kd->kd_tty; 266 267 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 268 } 269 270 int 271 kdwrite(dev, uio, flag) 272 dev_t dev; 273 struct uio *uio; 274 int flag; 275 { 276 struct kd_softc *kd; 277 struct tty *tp; 278 279 kd = &kd_softc; /* XXX */ 280 tp = kd->kd_tty; 281 282 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 283 } 284 285 int 286 kdioctl(dev, cmd, data, flag, p) 287 dev_t dev; 288 u_long cmd; 289 caddr_t data; 290 int flag; 291 struct proc *p; 292 { 293 struct kd_softc *kd; 294 struct tty *tp; 295 int error; 296 297 kd = &kd_softc; /* XXX */ 298 tp = kd->kd_tty; 299 300 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 301 if (error >= 0) 302 return error; 303 error = ttioctl(tp, cmd, data, flag, p); 304 if (error >= 0) 305 return error; 306 307 /* Handle any ioctl commands specific to kbd/display. */ 308 /* XXX - Send KB* ioctls to kbd module? */ 309 /* XXX - Send FB* ioctls to fb module? */ 310 311 return ENOTTY; 312 } 313 314 void 315 kdstop(tp, flag) 316 struct tty *tp; 317 int flag; 318 { 319 320 } 321 322 323 static int 324 kdparam(tp, t) 325 struct tty *tp; 326 struct termios *t; 327 { 328 /* XXX - These are ignored... */ 329 tp->t_ispeed = t->c_ispeed; 330 tp->t_ospeed = t->c_ospeed; 331 tp->t_cflag = t->c_cflag; 332 return 0; 333 } 334 335 336 static void kd_later(void*); 337 static void kd_putfb(struct tty *); 338 339 static void 340 kdstart(tp) 341 struct tty *tp; 342 { 343 struct clist *cl; 344 register int s; 345 346 s = spltty(); 347 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 348 goto out; 349 350 cl = &tp->t_outq; 351 if (cl->c_cc) { 352 if (kd_is_console) { 353 tp->t_state |= TS_BUSY; 354 if ((s & PSR_PIL) == 0) { 355 /* called at level zero - update screen now. */ 356 (void) spllowersoftclock(); 357 kd_putfb(tp); 358 (void) spltty(); 359 tp->t_state &= ~TS_BUSY; 360 } else { 361 /* called at interrupt level - do it later */ 362 callout_reset(&tp->t_rstrt_ch, 0, 363 kd_later, tp); 364 } 365 } else { 366 /* 367 * This driver uses the PROM for writing the screen, 368 * and that only works if this is the console device. 369 * If this is not the console, just flush the output. 370 * Sorry. (In that case, use xdm instead of getty.) 371 */ 372 ndflush(cl, cl->c_cc); 373 } 374 } 375 if (cl->c_cc <= tp->t_lowat) { 376 if (tp->t_state & TS_ASLEEP) { 377 tp->t_state &= ~TS_ASLEEP; 378 wakeup((caddr_t)cl); 379 } 380 selwakeup(&tp->t_wsel); 381 } 382 out: 383 splx(s); 384 } 385 386 /* 387 * Timeout function to do delayed writes to the screen. 388 * Called at splsoftclock when requested by kdstart. 389 */ 390 static void 391 kd_later(tpaddr) 392 void *tpaddr; 393 { 394 struct tty *tp = tpaddr; 395 register int s; 396 397 kd_putfb(tp); 398 399 s = spltty(); 400 tp->t_state &= ~TS_BUSY; 401 (*linesw[tp->t_line].l_start)(tp); 402 splx(s); 403 } 404 405 /* 406 * Put text on the screen using the PROM monitor. 407 * This can take a while, so to avoid missing 408 * interrupts, this is called at splsoftclock. 409 */ 410 static void 411 kd_putfb(tp) 412 struct tty *tp; 413 { 414 char buf[PUT_WSIZE]; 415 struct clist *cl = &tp->t_outq; 416 char *p, *end; 417 int len; 418 419 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 420 /* PROM will barf if high bits are set. */ 421 p = buf; 422 end = buf + len; 423 while (p < end) 424 *p++ &= 0x7f; 425 /* Now let the PROM print it. */ 426 OF_write(OF_stdout(), buf, len); 427 } 428 } 429 430 /* 431 * Default PROM-based console input stream 432 */ 433 static int kd_rom_iopen __P((struct cons_channel *)); 434 static int kd_rom_iclose __P((struct cons_channel *)); 435 436 static struct cons_channel prom_cons_channel; 437 438 int 439 kd_rom_iopen(cc) 440 struct cons_channel *cc; 441 { 442 return (0); 443 } 444 445 int 446 kd_rom_iclose(cc) 447 struct cons_channel *cc; 448 { 449 return (0); 450 } 451 452 /* 453 * Our "interrupt" routine for input. This is called by 454 * the keyboard driver (dev/sun/kbd.c) at spltty. 455 */ 456 void 457 kd_cons_input(c) 458 int c; 459 { 460 struct kd_softc *kd = &kd_softc; 461 struct tty *tp; 462 463 /* XXX: Make sure the device is open. */ 464 tp = kd->kd_tty; 465 if (tp == NULL) 466 return; 467 if ((tp->t_state & TS_ISOPEN) == 0) 468 return; 469 470 (*linesw[tp->t_line].l_rint)(c, tp); 471 } 472 473 474 /**************************************************************** 475 * kd console support 476 ****************************************************************/ 477 478 /* The debugger gets its own key translation state. */ 479 static struct kbd_state *kdcn_state; 480 481 static void kdcnprobe __P((struct consdev *)); 482 static void kdcninit __P((struct consdev *)); 483 static void kdcnputc __P((dev_t, int)); 484 static void kdcnpollc __P((dev_t, int)); 485 486 /* The keyboard driver uses cn_hw to access the real console driver */ 487 extern struct consdev consdev_prom; 488 struct consdev consdev_kd = { 489 kdcnprobe, 490 kdcninit, 491 kdcngetc, 492 kdcnputc, 493 kdcnpollc, 494 NULL, 495 }; 496 struct consdev *cn_hw = &consdev_kd; 497 498 void 499 cons_attach_input(cc, cn) 500 struct cons_channel *cc; 501 struct consdev *cn; 502 { 503 struct kd_softc *kd = &kd_softc; 504 struct kbd_softc *kds = cc->cc_dev; 505 struct kbd_state *ks; 506 507 /* Share the keyboard state */ 508 kdcn_state = ks = &kds->k_state; 509 510 kd->kd_in = cc; 511 cc->cc_upstream = kd_cons_input; 512 513 /* Attach lower level. */ 514 cn_hw->cn_pollc = cn->cn_pollc; 515 cn_hw->cn_getc = cn->cn_getc; 516 517 /* Attach us as console. */ 518 cn_tab->cn_dev = makedev(KDMAJOR, 0); 519 cn_tab->cn_probe = kdcnprobe; 520 cn_tab->cn_init = kdcninit; 521 cn_tab->cn_getc = kdcngetc; 522 cn_tab->cn_pollc = kdcnpollc; 523 cn_tab->cn_pri = CN_INTERNAL; 524 525 /* Set up initial PROM input channel for /dev/console */ 526 prom_cons_channel.cc_dev = NULL; 527 prom_cons_channel.cc_iopen = kd_rom_iopen; 528 prom_cons_channel.cc_iclose = kd_rom_iclose; 529 530 /* Indicate that it is OK to use the PROM fbwrite */ 531 kd_is_console = 1; 532 } 533 534 /* We never call this. */ 535 static void 536 kdcnprobe(cn) 537 struct consdev *cn; 538 { 539 } 540 541 static void 542 kdcninit(cn) 543 struct consdev *cn; 544 { 545 #if 0 546 struct kbd_state *ks = kdcn_state; 547 548 cn->cn_dev = makedev(KDMAJOR, 0); 549 cn->cn_pri = CN_INTERNAL; 550 551 /* This prepares kbd_translate() */ 552 ks->kbd_id = KBD_MIN_TYPE; 553 kbd_xlate_init(ks); 554 555 /* Set up initial PROM input channel for /dev/console */ 556 prom_cons_channel.cc_dev = NULL; 557 prom_cons_channel.cc_iopen = kd_rom_iopen; 558 prom_cons_channel.cc_iclose = kd_rom_iclose; 559 cons_attach_input(&prom_cons_channel); 560 561 /* Indicate that it is OK to use the PROM fbwrite */ 562 kd_is_console = 1; 563 #endif 564 } 565 566 static int 567 kdcngetc(dev) 568 dev_t dev; 569 { 570 struct kbd_state *ks = kdcn_state; 571 int code, class, data, keysym; 572 extern int prom_cngetc __P((dev_t)); 573 574 575 if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev); 576 for (;;) { 577 code = (*cn_hw->cn_getc)(dev); 578 keysym = kbd_code_to_keysym(ks, code); 579 class = KEYSYM_CLASS(keysym); 580 581 switch (class) { 582 case KEYSYM_ASCII: 583 goto out; 584 585 case KEYSYM_CLRMOD: 586 case KEYSYM_SETMOD: 587 data = (keysym & 0x1F); 588 /* Only allow ctrl or shift. */ 589 if (data > KBMOD_SHIFT_R) 590 break; 591 data = 1 << data; 592 if (class == KEYSYM_SETMOD) 593 ks->kbd_modbits |= data; 594 else 595 ks->kbd_modbits &= ~data; 596 break; 597 598 case KEYSYM_ALL_UP: 599 /* No toggle keys here. */ 600 ks->kbd_modbits = 0; 601 break; 602 603 default: /* ignore all other keysyms */ 604 break; 605 } 606 } 607 out: 608 return (keysym); 609 } 610 611 static void 612 kdcnputc(dev, c) 613 dev_t dev; 614 int c; 615 { 616 int s; 617 char c0 = (c & 0x7f); 618 619 s = splhigh(); 620 OF_write(OF_stdout(), &c0, 1); 621 splx(s); 622 } 623 624 static void 625 kdcnpollc(dev, on) 626 dev_t dev; 627 int on; 628 { 629 struct kbd_state *ks = kdcn_state; 630 631 if (on) { 632 /* Entering debugger. */ 633 #if NFB > 0 634 fb_unblank(); 635 #endif 636 /* Clear shift keys too. */ 637 ks->kbd_modbits = 0; 638 } else { 639 /* Resuming kernel. */ 640 } 641 (*cn_hw->cn_pollc)(dev, on); 642 } 643