1 /* $NetBSD: kd.c,v 1.13 1995/04/26 23:20:15 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Gordon W. Ross 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 4. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Gordon Ross 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Keyboard/Display device. 35 * 36 * This driver exists simply to provide a tty device that 37 * the indirect console driver can point to. 38 * The kbd driver sends its input here. 39 * Output goes to the screen via PROM printf. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/proc.h> 44 #include <sys/systm.h> 45 #include <sys/ioctl.h> 46 #include <sys/tty.h> 47 #include <sys/file.h> 48 #include <sys/conf.h> 49 #include <sys/device.h> 50 51 #include <machine/autoconf.h> 52 #include <machine/mon.h> 53 #include <machine/psl.h> 54 55 #include <dev/cons.h> 56 57 #define BURST 64 58 59 /* 60 * There is no point in pretending there might be 61 * more than one keyboard/display device. 62 */ 63 struct tty *kd_tty[1]; 64 65 int kdopen(dev_t, int, int, struct proc *); 66 int kdclose(dev_t, int, int, struct proc *); 67 int kdread(dev_t, struct uio *, int); 68 int kdwrite(dev_t, struct uio *, int); 69 int kdioctl(dev_t, int, caddr_t, int, struct proc *); 70 71 static int kdparam(struct tty *, struct termios *); 72 static void kdstart(struct tty *); 73 74 int kd_is_console; 75 76 /* This is called by kbd_serial() like a pseudo-device. */ 77 void 78 kd_attach(n) 79 int n; 80 { 81 kd_tty[0] = ttymalloc(); 82 83 /* Tell keyboard module where to send read data. */ 84 kbd_ascii(kd_tty[0]); 85 } 86 87 struct tty * 88 kdtty(dev) 89 dev_t dev; 90 { 91 return kd_tty[0]; 92 } 93 94 int 95 kdopen(dev, flag, mode, p) 96 dev_t dev; 97 int flag, mode; 98 struct proc *p; 99 { 100 int error, unit; 101 struct tty *tp; 102 103 unit = minor(dev); 104 if (unit) return ENXIO; 105 106 tp = kd_tty[unit]; 107 if (tp == NULL) 108 return ENXIO; 109 110 if ((error = kbd_iopen()) != 0) { 111 #ifdef DIAGNOSTIC 112 printf("kd: kbd_iopen, error=%d\n", error); 113 #endif 114 return (error); 115 } 116 117 tp->t_oproc = kdstart; 118 tp->t_param = kdparam; 119 tp->t_dev = dev; 120 if ((tp->t_state & TS_ISOPEN) == 0) { 121 tp->t_state |= TS_WOPEN; 122 ttychars(tp); 123 tp->t_iflag = TTYDEF_IFLAG; 124 tp->t_oflag = TTYDEF_OFLAG; 125 tp->t_cflag = TTYDEF_CFLAG; 126 tp->t_lflag = TTYDEF_LFLAG; 127 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 128 kdparam(tp, &tp->t_termios); 129 ttsetwater(tp); 130 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 131 return EBUSY; 132 tp->t_state |= TS_CARR_ON; 133 134 return ((*linesw[tp->t_line].l_open)(dev, tp)); 135 } 136 137 int 138 kdclose(dev, flag, mode, p) 139 dev_t dev; 140 int flag, mode; 141 struct proc *p; 142 { 143 int unit = minor(dev); 144 struct tty *tp = kd_tty[unit]; 145 146 (*linesw[tp->t_line].l_close)(tp, flag); 147 ttyclose(tp); 148 return (0); 149 } 150 151 int 152 kdread(dev, uio, flag) 153 dev_t dev; 154 struct uio *uio; 155 int flag; 156 { 157 int unit = minor(dev); 158 struct tty *tp = kd_tty[unit]; 159 160 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 161 } 162 163 int 164 kdwrite(dev, uio, flag) 165 dev_t dev; 166 struct uio *uio; 167 int flag; 168 { 169 int unit = minor(dev); 170 struct tty *tp = kd_tty[unit]; 171 172 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 173 } 174 175 int 176 kdstop(tp, flag) 177 struct tty *tp; 178 int flag; 179 { 180 181 } 182 183 int 184 kdioctl(dev, cmd, data, flag, p) 185 dev_t dev; 186 int cmd; 187 caddr_t data; 188 int flag; 189 struct proc *p; 190 { 191 int error; 192 int unit = minor(dev); 193 struct tty *tp = kd_tty[unit]; 194 195 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 196 if (error >= 0) 197 return error; 198 error = ttioctl(tp, cmd, data, flag, p); 199 if (error >= 0) 200 return error; 201 202 /* Handle any ioctl commands specific to kbd/display. */ 203 /* XXX - Send KB* ioctls to kbd module? */ 204 /* XXX - Send FB* ioctls to fb module? */ 205 206 return ENOTTY; 207 } 208 209 static void kd_later(void*); 210 static void kd_putfb(struct tty *); 211 212 void 213 kdstart(tp) 214 struct tty *tp; 215 { 216 struct clist *cl; 217 register int s; 218 219 s = spltty(); 220 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 221 goto out; 222 223 cl = &tp->t_outq; 224 if (cl->c_cc) { 225 if (kd_is_console) { 226 tp->t_state |= TS_BUSY; 227 if ((s & PSL_IPL) == 0) { 228 /* called at level zero - update screen now. */ 229 (void) splsoftclock(); 230 kd_putfb(tp); 231 (void) spltty(); 232 tp->t_state &= ~TS_BUSY; 233 } else { 234 /* called at interrupt level - do it later */ 235 timeout(kd_later, (void*)tp, 0); 236 } 237 } else { 238 /* 239 * This driver uses the PROM for writing the screen, 240 * and that only works if this is the console device. 241 * If this is not the console, just flush the output. 242 * Sorry. (In that case, use xdm instead of getty.) 243 */ 244 ndflush(cl, cl->c_cc); 245 } 246 } 247 if (cl->c_cc <= tp->t_lowat) { 248 if (tp->t_state & TS_ASLEEP) { 249 tp->t_state &= ~TS_ASLEEP; 250 wakeup((caddr_t)cl); 251 } 252 selwakeup(&tp->t_wsel); 253 } 254 out: 255 splx(s); 256 } 257 258 /* 259 * Timeout function to do delayed writes to the screen. 260 * Called at splsoftclock when requested by kdstart. 261 */ 262 static void 263 kd_later(tpaddr) 264 void *tpaddr; 265 { 266 struct tty *tp = tpaddr; 267 register int s; 268 269 kd_putfb(tp); 270 271 s = spltty(); 272 tp->t_state &= ~TS_BUSY; 273 if (tp->t_line) 274 (*linesw[tp->t_line].l_start)(tp); 275 else 276 kdstart(tp); 277 splx(s); 278 } 279 280 /* 281 * Put text on the screen using the PROM monitor. 282 * This can take a while, so to avoid missing 283 * interrupts, this is called at splsoftclock. 284 */ 285 static void kd_putfb(tp) 286 struct tty *tp; 287 { 288 char buf[BURST]; 289 struct clist *cl = &tp->t_outq; 290 char *p, *end; 291 int len; 292 293 while ((len = q_to_b(cl, buf, BURST-1)) > 0) { 294 /* PROM will barf if high bits are set. */ 295 p = buf; 296 end = buf + len; 297 while (p < end) 298 *p++ &= 0x7f; 299 (romVectorPtr->fbWriteStr)(buf, len); 300 } 301 } 302 303 304 static int 305 kdparam(tp, t) 306 struct tty *tp; 307 struct termios *t; 308 { 309 /* XXX - These are ignored... */ 310 tp->t_ispeed = t->c_ispeed; 311 tp->t_ospeed = t->c_ospeed; 312 tp->t_cflag = t->c_cflag; 313 return 0; 314 } 315 316 317 /* 318 * kd console support 319 */ 320 321 extern int zscnprobe_kbd(), zscngetc(), kbd_translate(); 322 323 kdcnprobe(cp) 324 struct consdev *cp; 325 { 326 int maj; 327 328 /* locate the major number */ 329 for (maj = 0; maj < nchrdev; maj++) 330 if (cdevsw[maj].d_open == (void*)kdopen) 331 break; 332 333 /* initialize required fields */ 334 cp->cn_dev = makedev(maj, 0); 335 cp->cn_pri = zscnprobe_kbd(); 336 } 337 338 kdcninit(cp) 339 struct consdev *cp; 340 { 341 342 /* This prepares zscngetc() */ 343 zs_set_conschan(1, 0); 344 345 /* This prepares kbd_translate() */ 346 kbd_init_tables(); 347 348 /* Indicate that it is OK to use the PROM fbwrite */ 349 kd_is_console = 1; 350 351 mon_printf("console on kd0 (keyboard/display)\n"); 352 } 353 354 kdcngetc(dev) 355 dev_t dev; 356 { 357 int c; 358 359 do { 360 c = zscngetc(0); 361 c = kbd_translate(c); 362 } while (c == -1); 363 364 return (c); 365 } 366 367 kdcnputc(dev, c) 368 dev_t dev; 369 int c; 370 { 371 (romVectorPtr->fbWriteChar)(c & 0x7f); 372 } 373 374 extern void fb_unblank(); 375 void kdcnpollc(dev, on) 376 dev_t dev; 377 int on; 378 { 379 if (on) 380 fb_unblank(); 381 } 382