1 /* $NetBSD: kd.c,v 1.44 2005/12/11 12:19:20 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.44 2005/12/11 12:19:20 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/autoconf.h> 61 #include <machine/mon.h> 62 #include <machine/psl.h> 63 64 #include <dev/cons.h> 65 #include <dev/sun/event_var.h> 66 #include <dev/sun/kbd_xlate.h> 67 #include <dev/sun/kbdvar.h> 68 #include <sun3/dev/zs_cons.h> 69 70 #include "fb.h" 71 72 extern void fb_unblank(void); /* XXX */ 73 74 #define PUT_WSIZE 64 75 76 struct kd_softc { 77 struct device kd_dev; /* required first: base device */ 78 struct tty *kd_tty; 79 80 /* Console input hook */ 81 struct cons_channel *kd_in; 82 }; 83 84 /* 85 * There is no point in pretending there might be 86 * more than one keyboard/display device. 87 */ 88 static struct kd_softc kd_softc; 89 static int kd_is_console; 90 91 static int kdparam(struct tty *, struct termios *); 92 static void kdstart(struct tty *); 93 static void kd_init(struct kd_softc *); 94 static void kd_cons_input(int); 95 96 dev_type_open(kdopen); 97 dev_type_close(kdclose); 98 dev_type_read(kdread); 99 dev_type_write(kdwrite); 100 dev_type_ioctl(kdioctl); 101 dev_type_tty(kdtty); 102 dev_type_poll(kdpoll); 103 104 const struct cdevsw kd_cdevsw = { 105 kdopen, kdclose, kdread, kdwrite, kdioctl, 106 nostop, kdtty, kdpoll, nommap, ttykqfilter, D_TTY 107 }; 108 109 /* 110 * Prepare the console tty; called on first open of /dev/console 111 */ 112 void 113 kd_init(struct kd_softc *kd) 114 { 115 struct tty *tp; 116 117 tp = ttymalloc(); 118 tp->t_oproc = kdstart; 119 tp->t_param = kdparam; 120 tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 121 122 tty_attach(tp); 123 kd->kd_tty = tp; 124 125 return; 126 } 127 128 struct tty * 129 kdtty(dev_t dev) 130 { 131 struct kd_softc *kd; 132 133 kd = &kd_softc; /* XXX */ 134 return (kd->kd_tty); 135 } 136 137 int 138 kdopen(dev_t dev, int flag, int mode, struct lwp *l) 139 { 140 struct kd_softc *kd; 141 int error, s, unit; 142 struct tty *tp; 143 static int firstopen = 1; 144 145 unit = minor(dev); 146 if (unit != 0) 147 return ENXIO; 148 kd = &kd_softc; /* XXX */ 149 if (firstopen) { 150 kd_init(kd); 151 firstopen = 0; 152 } 153 tp = kd->kd_tty; 154 155 /* It's simpler to do this up here. */ 156 if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) 157 == (TS_ISOPEN | TS_XCLUDE)) 158 && (suser(l->l_proc->p_ucred, &l->l_proc->p_acflag) != 0) ) 159 { 160 return (EBUSY); 161 } 162 163 s = spltty(); 164 165 if ((tp->t_state & TS_ISOPEN) == 0) { 166 /* First open. */ 167 168 /* Notify the input device that serves us */ 169 struct cons_channel *cc = kd->kd_in; 170 if (cc != NULL && 171 (error = (*cc->cc_iopen)(cc)) != 0) { 172 return (error); 173 } 174 175 ttychars(tp); 176 tp->t_iflag = TTYDEF_IFLAG; 177 tp->t_oflag = TTYDEF_OFLAG; 178 tp->t_cflag = TTYDEF_CFLAG; 179 tp->t_lflag = TTYDEF_LFLAG; 180 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 181 (void) kdparam(tp, &tp->t_termios); 182 ttsetwater(tp); 183 /* Flush pending input? Clear translator? */ 184 /* This (pseudo)device always has SOFTCAR */ 185 tp->t_state |= TS_CARR_ON; 186 } 187 188 splx(s); 189 190 return ((*tp->t_linesw->l_open)(dev, tp)); 191 } 192 193 int 194 kdclose(dev_t dev, int flag, int mode, struct lwp *l) 195 { 196 struct kd_softc *kd; 197 struct tty *tp; 198 struct cons_channel *cc; 199 200 kd = &kd_softc; /* XXX */ 201 tp = kd->kd_tty; 202 203 /* XXX This is for cons.c. */ 204 if ((tp->t_state & TS_ISOPEN) == 0) 205 return 0; 206 207 (*tp->t_linesw->l_close)(tp, flag); 208 ttyclose(tp); 209 if ((cc = kd->kd_in) != NULL) 210 (void)(*cc->cc_iclose)(cc); 211 return (0); 212 } 213 214 int 215 kdread(dev_t dev, struct uio *uio, int flag) 216 { 217 struct kd_softc *kd; 218 struct tty *tp; 219 220 kd = &kd_softc; /* XXX */ 221 tp = kd->kd_tty; 222 223 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 224 } 225 226 int 227 kdwrite(dev_t dev, struct uio *uio, int flag) 228 { 229 struct kd_softc *kd; 230 struct tty *tp; 231 232 kd = &kd_softc; /* XXX */ 233 tp = kd->kd_tty; 234 235 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 236 } 237 238 int 239 kdpoll(dev_t dev, int events, struct lwp *l) 240 { 241 struct kd_softc *kd; 242 struct tty *tp; 243 244 kd = &kd_softc; /* XXX */ 245 tp = kd->kd_tty; 246 247 return ((*tp->t_linesw->l_poll)(tp, events, l)); 248 } 249 250 int 251 kdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 252 { 253 struct kd_softc *kd; 254 struct tty *tp; 255 int error; 256 257 kd = &kd_softc; /* XXX */ 258 tp = kd->kd_tty; 259 260 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 261 if (error != EPASSTHROUGH) 262 return error; 263 264 error = ttioctl(tp, cmd, data, flag, l); 265 if (error != EPASSTHROUGH) 266 return error; 267 268 /* Handle any ioctl commands specific to kbd/display. */ 269 /* XXX - Send KB* ioctls to kbd module? */ 270 /* XXX - Send FB* ioctls to fb module? */ 271 272 return EPASSTHROUGH; 273 } 274 275 static int 276 kdparam(struct tty *tp, struct termios *t) 277 { 278 /* XXX - These are ignored... */ 279 tp->t_ispeed = t->c_ispeed; 280 tp->t_ospeed = t->c_ospeed; 281 tp->t_cflag = t->c_cflag; 282 return 0; 283 } 284 285 286 static void kd_later(void*); 287 static void kd_putfb(struct tty *); 288 289 static void 290 kdstart(struct tty *tp) 291 { 292 struct clist *cl; 293 int s; 294 295 s = spltty(); 296 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 297 goto out; 298 299 cl = &tp->t_outq; 300 if (cl->c_cc) { 301 if (kd_is_console) { 302 tp->t_state |= TS_BUSY; 303 if ((s & PSL_IPL) == 0) { 304 /* called at level zero - update screen now. */ 305 (void) spllowersoftclock(); 306 kd_putfb(tp); 307 (void) spltty(); 308 tp->t_state &= ~TS_BUSY; 309 } else { 310 /* called at interrupt level - do it later */ 311 callout_reset(&tp->t_rstrt_ch, 0, 312 kd_later, tp); 313 } 314 } else { 315 /* 316 * This driver uses the PROM for writing the screen, 317 * and that only works if this is the console device. 318 * If this is not the console, just flush the output. 319 * Sorry. (In that case, use xdm instead of getty.) 320 */ 321 ndflush(cl, cl->c_cc); 322 } 323 } 324 if (cl->c_cc <= tp->t_lowat) { 325 if (tp->t_state & TS_ASLEEP) { 326 tp->t_state &= ~TS_ASLEEP; 327 wakeup((caddr_t)cl); 328 } 329 selwakeup(&tp->t_wsel); 330 } 331 out: 332 splx(s); 333 } 334 335 /* 336 * Timeout function to do delayed writes to the screen. 337 * Called at splsoftclock when requested by kdstart. 338 */ 339 static void 340 kd_later(void *tpaddr) 341 { 342 struct tty *tp = tpaddr; 343 int s; 344 345 kd_putfb(tp); 346 347 s = spltty(); 348 tp->t_state &= ~TS_BUSY; 349 (*tp->t_linesw->l_start)(tp); 350 splx(s); 351 } 352 353 /* 354 * Put text on the screen using the PROM monitor. 355 * This can take a while, so to avoid missing 356 * interrupts, this is called at splsoftclock. 357 */ 358 static void 359 kd_putfb(struct tty *tp) 360 { 361 char buf[PUT_WSIZE]; 362 struct clist *cl = &tp->t_outq; 363 char *p, *end; 364 int len; 365 366 while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) { 367 /* PROM will barf if high bits are set. */ 368 p = buf; 369 end = buf + len; 370 while (p < end) 371 *p++ &= 0x7f; 372 (romVectorPtr->fbWriteStr)(buf, len); 373 } 374 } 375 376 void 377 cons_attach_input(struct cons_channel *cc, struct consdev *cn) 378 { 379 struct kd_softc *kd = &kd_softc; 380 381 kd->kd_in = cc; 382 cc->cc_upstream = kd_cons_input; 383 } 384 385 /* 386 * Default PROM-based console input stream 387 */ 388 static int kd_rom_iopen(struct cons_channel *); 389 static int kd_rom_iclose(struct cons_channel *); 390 391 static struct cons_channel prom_cons_channel; 392 393 int 394 kd_rom_iopen(struct cons_channel *cc) 395 { 396 /* No-op */ 397 return (0); 398 } 399 400 int 401 kd_rom_iclose(struct cons_channel *cc) 402 { 403 /* No-op */ 404 return (0); 405 } 406 407 /* 408 * Our "interrupt" routine for input. This is called by 409 * the keyboard driver (dev/sun/kbd.c) at spltty. 410 */ 411 void 412 kd_cons_input(int c) 413 { 414 struct kd_softc *kd = &kd_softc; 415 struct tty *tp; 416 417 /* XXX: Make sure the device is open. */ 418 tp = kd->kd_tty; 419 if (tp == NULL) 420 return; 421 if ((tp->t_state & TS_ISOPEN) == 0) 422 return; 423 424 (*tp->t_linesw->l_rint)(c, tp); 425 } 426 427 428 /**************************************************************** 429 * kd console support 430 ****************************************************************/ 431 432 /* The debugger gets its own key translation state. */ 433 static struct kbd_state kdcn_state; 434 435 static void kdcnprobe(struct consdev *); 436 static void kdcninit(struct consdev *); 437 static int kdcngetc(dev_t); 438 static void kdcnputc(dev_t, int); 439 static void kdcnpollc(dev_t, int); 440 441 struct consdev consdev_kd = { 442 kdcnprobe, 443 kdcninit, 444 kdcngetc, 445 kdcnputc, 446 kdcnpollc, 447 NULL, 448 }; 449 450 /* We never call this. */ 451 static void 452 kdcnprobe(struct consdev *cn) 453 { 454 } 455 456 static void 457 kdcninit(struct consdev *cn) 458 { 459 struct kbd_state *ks = &kdcn_state; 460 461 cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0); 462 cn->cn_pri = CN_INTERNAL; 463 464 /* This prepares kbd_translate() */ 465 ks->kbd_id = KBD_MIN_TYPE; 466 kbd_xlate_init(ks); 467 468 /* Set up initial PROM input channel for /dev/console */ 469 prom_cons_channel.cc_dev = NULL; 470 prom_cons_channel.cc_iopen = kd_rom_iopen; 471 prom_cons_channel.cc_iclose = kd_rom_iclose; 472 cons_attach_input(&prom_cons_channel, cn); 473 474 /* Indicate that it is OK to use the PROM fbwrite */ 475 kd_is_console = 1; 476 } 477 478 static int 479 kdcngetc(dev_t dev) 480 { 481 struct kbd_state *ks = &kdcn_state; 482 int code, class, data, keysym; 483 484 for (;;) { 485 code = zs_getc(zs_conschan); 486 keysym = kbd_code_to_keysym(ks, code); 487 class = KEYSYM_CLASS(keysym); 488 489 switch (class) { 490 case KEYSYM_ASCII: 491 goto out; 492 493 case KEYSYM_CLRMOD: 494 case KEYSYM_SETMOD: 495 data = (keysym & 0x1F); 496 /* Only allow ctrl or shift. */ 497 if (data > KBMOD_SHIFT_R) 498 break; 499 data = 1 << data; 500 if (class == KEYSYM_SETMOD) 501 ks->kbd_modbits |= data; 502 else 503 ks->kbd_modbits &= ~data; 504 break; 505 506 case KEYSYM_ALL_UP: 507 /* No toggle keys here. */ 508 ks->kbd_modbits = 0; 509 break; 510 511 default: /* ignore all other keysyms */ 512 break; 513 } 514 } 515 out: 516 return (keysym); 517 } 518 519 static void 520 kdcnputc(dev_t dev, int c) 521 { 522 (romVectorPtr->fbWriteChar)(c & 0x7f); 523 } 524 525 static void 526 kdcnpollc(dev_t dev, int on) 527 { 528 struct kbd_state *ks = &kdcn_state; 529 530 if (on) { 531 /* Entering debugger. */ 532 #if NFB > 0 533 fb_unblank(); 534 #endif 535 /* Clear shift keys too. */ 536 ks->kbd_modbits = 0; 537 } else { 538 /* Resuming kernel. */ 539 } 540 } 541 542