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