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