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