kd.c revision 1.26 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