1 /* $NetBSD: kd.c,v 1.12 1995/04/10 07:33:53 mycroft 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 struct tty *kd_tty[1]; 60 61 int kdopen(dev_t, int, int, struct proc *); 62 int kdclose(dev_t, int, int, struct proc *); 63 int kdread(dev_t, struct uio *, int); 64 int kdwrite(dev_t, struct uio *, int); 65 int kdioctl(dev_t, int, caddr_t, int, struct proc *); 66 67 static int kdparam(struct tty *, struct termios *); 68 static void kdstart(struct tty *); 69 70 int kd_is_console; 71 72 /* This is called by kbd_serial() like a pseudo-device. */ 73 void 74 kd_attach(n) 75 int n; 76 { 77 kd_tty[0] = ttymalloc(); 78 79 /* Tell keyboard module where to send read data. */ 80 kbd_ascii(kd_tty[0]); 81 } 82 83 int 84 kdopen(dev, flag, mode, p) 85 dev_t dev; 86 int flag, mode; 87 struct proc *p; 88 { 89 int error, unit; 90 struct tty *tp; 91 92 unit = minor(dev); 93 if (unit) return ENXIO; 94 95 tp = kd_tty[unit]; 96 if (tp == NULL) 97 return ENXIO; 98 99 if ((error = kbd_iopen()) != 0) { 100 #ifdef DIAGNOSTIC 101 printf("kd: kbd_iopen, error=%d\n", error); 102 #endif 103 return (error); 104 } 105 106 tp->t_oproc = kdstart; 107 tp->t_param = kdparam; 108 tp->t_dev = dev; 109 if ((tp->t_state & TS_ISOPEN) == 0) { 110 tp->t_state |= TS_WOPEN; 111 ttychars(tp); 112 tp->t_iflag = TTYDEF_IFLAG; 113 tp->t_oflag = TTYDEF_OFLAG; 114 tp->t_cflag = TTYDEF_CFLAG; 115 tp->t_lflag = TTYDEF_LFLAG; 116 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 117 kdparam(tp, &tp->t_termios); 118 ttsetwater(tp); 119 } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) 120 return EBUSY; 121 tp->t_state |= TS_CARR_ON; 122 123 return ((*linesw[tp->t_line].l_open)(dev, tp)); 124 } 125 126 int 127 kdclose(dev, flag, mode, p) 128 dev_t dev; 129 int flag, mode; 130 struct proc *p; 131 { 132 int unit = minor(dev); 133 struct tty *tp = kd_tty[unit]; 134 135 (*linesw[tp->t_line].l_close)(tp, flag); 136 ttyclose(tp); 137 return (0); 138 } 139 140 int 141 kdread(dev, uio, flag) 142 dev_t dev; 143 struct uio *uio; 144 int flag; 145 { 146 int unit = minor(dev); 147 struct tty *tp = kd_tty[unit]; 148 149 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 150 } 151 152 int 153 kdwrite(dev, uio, flag) 154 dev_t dev; 155 struct uio *uio; 156 int flag; 157 { 158 int unit = minor(dev); 159 struct tty *tp = kd_tty[unit]; 160 161 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 162 } 163 164 int 165 kdstop(tp, flag) 166 struct tty *tp; 167 int flag; 168 { 169 170 } 171 172 int 173 kdioctl(dev, cmd, data, flag, p) 174 dev_t dev; 175 int cmd; 176 caddr_t data; 177 int flag; 178 struct proc *p; 179 { 180 int error; 181 int unit = minor(dev); 182 struct tty *tp = kd_tty[unit]; 183 184 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 185 if (error >= 0) 186 return error; 187 error = ttioctl(tp, cmd, data, flag, p); 188 if (error >= 0) 189 return error; 190 191 /* Handle any ioctl commands specific to kbd/display. */ 192 /* XXX - Send KB* ioctls to kbd module? */ 193 /* XXX - Send FB* ioctls to fb module? */ 194 195 return ENOTTY; 196 } 197 198 static void kd_later(void*); 199 static void kd_putfb(struct tty *); 200 201 void 202 kdstart(tp) 203 struct tty *tp; 204 { 205 struct clist *cl; 206 register int s; 207 208 s = spltty(); 209 if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT)) 210 goto out; 211 212 cl = &tp->t_outq; 213 if (cl->c_cc) { 214 if (kd_is_console) { 215 tp->t_state |= TS_BUSY; 216 if ((s & PSL_IPL) == 0) { 217 /* called at level zero - update screen now. */ 218 (void) splsoftclock(); 219 kd_putfb(tp); 220 (void) spltty(); 221 tp->t_state &= ~TS_BUSY; 222 } else { 223 /* called at interrupt level - do it later */ 224 timeout(kd_later, (void*)tp, 0); 225 } 226 } else { 227 /* 228 * This driver uses the PROM for writing the screen, 229 * and that only works if this is the console device. 230 * If this is not the console, just flush the output. 231 * Sorry. (In that case, use xdm instead of getty.) 232 */ 233 ndflush(cl, cl->c_cc); 234 } 235 } 236 if (cl->c_cc <= tp->t_lowat) { 237 if (tp->t_state & TS_ASLEEP) { 238 tp->t_state &= ~TS_ASLEEP; 239 wakeup((caddr_t)cl); 240 } 241 selwakeup(&tp->t_wsel); 242 } 243 out: 244 splx(s); 245 } 246 247 /* 248 * Timeout function to do delayed writes to the screen. 249 * Called at splsoftclock when requested by kdstart. 250 */ 251 static void 252 kd_later(tpaddr) 253 void *tpaddr; 254 { 255 struct tty *tp = tpaddr; 256 register int s; 257 258 kd_putfb(tp); 259 260 s = spltty(); 261 tp->t_state &= ~TS_BUSY; 262 if (tp->t_line) 263 (*linesw[tp->t_line].l_start)(tp); 264 else 265 kdstart(tp); 266 splx(s); 267 } 268 269 /* 270 * Put text on the screen using the PROM monitor. 271 * This can take a while, so to avoid missing 272 * interrupts, this is called at splsoftclock. 273 */ 274 static void kd_putfb(tp) 275 struct tty *tp; 276 { 277 char buf[BURST]; 278 struct clist *cl = &tp->t_outq; 279 char *p, *end; 280 int len; 281 282 while ((len = q_to_b(cl, buf, BURST-1)) > 0) { 283 /* PROM will barf if high bits are set. */ 284 p = buf; 285 end = buf + len; 286 while (p < end) 287 *p++ &= 0x7f; 288 (romVectorPtr->fbWriteStr)(buf, len); 289 } 290 } 291 292 293 static int 294 kdparam(tp, t) 295 struct tty *tp; 296 struct termios *t; 297 { 298 /* XXX - These are ignored... */ 299 tp->t_ispeed = t->c_ispeed; 300 tp->t_ospeed = t->c_ospeed; 301 tp->t_cflag = t->c_cflag; 302 return 0; 303 } 304 305 306 /* 307 * kd console support 308 */ 309 310 extern int zscnprobe_kbd(), zscngetc(), kbd_translate(); 311 312 kdcnprobe(cp) 313 struct consdev *cp; 314 { 315 int maj; 316 317 /* locate the major number */ 318 for (maj = 0; maj < nchrdev; maj++) 319 if (cdevsw[maj].d_open == (void*)kdopen) 320 break; 321 322 /* initialize required fields */ 323 cp->cn_dev = makedev(maj, 0); 324 cp->cn_pri = zscnprobe_kbd(); 325 } 326 327 kdcninit(cp) 328 struct consdev *cp; 329 { 330 331 /* This prepares zscngetc() */ 332 zs_set_conschan(1, 0); 333 334 /* This prepares kbd_translate() */ 335 kbd_init_tables(); 336 337 /* Indicate that it is OK to use the PROM fbwrite */ 338 kd_is_console = 1; 339 340 mon_printf("console on kd0 (keyboard/display)\n"); 341 } 342 343 kdcngetc(dev) 344 dev_t dev; 345 { 346 int c; 347 348 do { 349 c = zscngetc(0); 350 c = kbd_translate(c); 351 } while (c == -1); 352 353 return (c); 354 } 355 356 kdcnputc(dev, c) 357 dev_t dev; 358 int c; 359 { 360 (romVectorPtr->fbWriteChar)(c & 0x7f); 361 } 362 363 extern void fb_unblank(); 364 void kdcnpollc(dev, on) 365 dev_t dev; 366 int on; 367 { 368 if (on) 369 fb_unblank(); 370 } 371