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