xref: /netbsd/sys/arch/sparc64/dev/kd.c (revision 36bb413e)
1*36bb413eSad /*	$NetBSD: kd.c,v 1.43 2007/02/16 13:55:42 ad Exp $	*/
201e2e698Seeh 
301e2e698Seeh /*-
401e2e698Seeh  * Copyright (c) 1996 The NetBSD Foundation, Inc.
501e2e698Seeh  * All rights reserved.
601e2e698Seeh  *
701e2e698Seeh  * This code is derived from software contributed to The NetBSD Foundation
801e2e698Seeh  * by Gordon W. Ross.
901e2e698Seeh  *
1001e2e698Seeh  * Redistribution and use in source and binary forms, with or without
1101e2e698Seeh  * modification, are permitted provided that the following conditions
1201e2e698Seeh  * are met:
1301e2e698Seeh  * 1. Redistributions of source code must retain the above copyright
1401e2e698Seeh  *    notice, this list of conditions and the following disclaimer.
1501e2e698Seeh  * 2. Redistributions in binary form must reproduce the above copyright
1601e2e698Seeh  *    notice, this list of conditions and the following disclaimer in the
1701e2e698Seeh  *    documentation and/or other materials provided with the distribution.
1801e2e698Seeh  * 3. All advertising materials mentioning features or use of this software
1901e2e698Seeh  *    must display the following acknowledgement:
2001e2e698Seeh  *        This product includes software developed by the NetBSD
2101e2e698Seeh  *        Foundation, Inc. and its contributors.
2201e2e698Seeh  * 4. Neither the name of The NetBSD Foundation nor the names of its
2301e2e698Seeh  *    contributors may be used to endorse or promote products derived
2401e2e698Seeh  *    from this software without specific prior written permission.
2501e2e698Seeh  *
2601e2e698Seeh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2701e2e698Seeh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2801e2e698Seeh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2901e2e698Seeh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3001e2e698Seeh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3101e2e698Seeh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3201e2e698Seeh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3301e2e698Seeh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3401e2e698Seeh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3501e2e698Seeh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3601e2e698Seeh  * POSSIBILITY OF SUCH DAMAGE.
3701e2e698Seeh  */
3801e2e698Seeh 
3901e2e698Seeh /*
4001e2e698Seeh  * Keyboard/Display device.
4101e2e698Seeh  *
4201e2e698Seeh  * This driver exists simply to provide a tty device that
4301e2e698Seeh  * the indirect console driver can point to.
4401e2e698Seeh  * The kbd driver sends its input here.
4501e2e698Seeh  * Output goes to the screen via PROM printf.
4601e2e698Seeh  */
4701e2e698Seeh 
48ed517291Slukem #include <sys/cdefs.h>
49*36bb413eSad __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.43 2007/02/16 13:55:42 ad Exp $");
50ed517291Slukem 
5101e2e698Seeh #include <sys/param.h>
5201e2e698Seeh #include <sys/proc.h>
5301e2e698Seeh #include <sys/systm.h>
5401e2e698Seeh #include <sys/ioctl.h>
5501e2e698Seeh #include <sys/tty.h>
5601e2e698Seeh #include <sys/file.h>
5701e2e698Seeh #include <sys/conf.h>
5801e2e698Seeh #include <sys/device.h>
598ccb6c93Selad #include <sys/kauth.h>
6001e2e698Seeh 
6101e2e698Seeh #include <machine/openfirm.h>
6201e2e698Seeh #include <machine/eeprom.h>
6301e2e698Seeh #include <machine/psl.h>
6401e2e698Seeh #include <machine/cpu.h>
6501e2e698Seeh #include <machine/kbd.h>
6601e2e698Seeh #include <machine/autoconf.h>
6701e2e698Seeh 
6801e2e698Seeh #include <dev/cons.h>
69f5839cdaSpk #include <dev/sun/event_var.h>
7001e2e698Seeh #include <dev/sun/kbd_xlate.h>
71f5839cdaSpk #include <dev/sun/kbdvar.h>
7201e2e698Seeh #include <sparc64/dev/cons.h>
7301e2e698Seeh 
7477a6b82bSgehenna dev_type_open(kdopen);
7577a6b82bSgehenna dev_type_close(kdclose);
7677a6b82bSgehenna dev_type_read(kdread);
7777a6b82bSgehenna dev_type_write(kdwrite);
7877a6b82bSgehenna dev_type_ioctl(kdioctl);
7977a6b82bSgehenna dev_type_tty(kdtty);
8077a6b82bSgehenna dev_type_poll(kdpoll);
8177a6b82bSgehenna 
8277a6b82bSgehenna const struct cdevsw kd_cdevsw = {
8377a6b82bSgehenna 	kdopen, kdclose, kdread, kdwrite, kdioctl,
84e0cc03a0Sjdolecek 	nostop, kdtty, kdpoll, nommap, ttykqfilter, D_TTY
8577a6b82bSgehenna };
8677a6b82bSgehenna 
8701e2e698Seeh struct	tty *fbconstty = 0;	/* tty structure for frame buffer console */
8801e2e698Seeh 
8901e2e698Seeh #define PUT_WSIZE	64
9001e2e698Seeh 
9101e2e698Seeh struct kd_softc {
9201e2e698Seeh 	struct	device kd_dev;		/* required first: base device */
9301e2e698Seeh 	struct  tty *kd_tty;
9401e2e698Seeh 	int rows, cols;
95f5839cdaSpk 
96f5839cdaSpk 	/* Console input hook */
97f5839cdaSpk 	struct cons_channel *kd_in;
9801e2e698Seeh };
9901e2e698Seeh 
10001e2e698Seeh /*
10101e2e698Seeh  * There is no point in pretending there might be
10201e2e698Seeh  * more than one keyboard/display device.
10301e2e698Seeh  */
10401e2e698Seeh static struct kd_softc kd_softc;
10501e2e698Seeh static int kd_is_console;
10601e2e698Seeh 
10701e2e698Seeh static int kdparam(struct tty *, struct termios *);
10801e2e698Seeh static void kdstart(struct tty *);
109d50f0c62Scdi static void kd_init(struct kd_softc *);
110d50f0c62Scdi static void kd_cons_input(int);
111d50f0c62Scdi static int  kdcngetc(dev_t);
11201e2e698Seeh 
11301e2e698Seeh int	cons_ocount;		/* output byte count */
11401e2e698Seeh 
11501e2e698Seeh /*
11601e2e698Seeh  * This is called by kbd_attach()
11701e2e698Seeh  * XXX - Make this a proper child of kbd?
11801e2e698Seeh  */
11901e2e698Seeh void
120d50f0c62Scdi kd_init(struct kd_softc *kd)
121f5839cdaSpk {
12201e2e698Seeh 	struct tty *tp;
1238512c4b6Spk 	char prop[6+1];
12492ad9c40Seeh 
12501e2e698Seeh 	kd = &kd_softc; 	/* XXX */
12601e2e698Seeh 
12701e2e698Seeh 	tp = ttymalloc();
12801e2e698Seeh 	tp->t_oproc = kdstart;
12901e2e698Seeh 	tp->t_param = kdparam;
13077a6b82bSgehenna 	tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
13101e2e698Seeh 
13201e2e698Seeh 	tty_attach(tp);
13301e2e698Seeh 	kd->kd_tty = tp;
13401e2e698Seeh 
13501e2e698Seeh 	/*
13601e2e698Seeh 	 * get the console struct winsize.
13701e2e698Seeh 	 */
13801e2e698Seeh 	if (kd_is_console) {
13901e2e698Seeh 		fbconstty = tp;
14001e2e698Seeh 	}
14101e2e698Seeh 
14201e2e698Seeh 	if (kd->rows == 0 &&
1438512c4b6Spk 	    prom_getoption("screen-#rows", prop, sizeof prop) == 0)
1448512c4b6Spk 		kd->rows = strtoul(prop, NULL, 10);
1458512c4b6Spk 
14601e2e698Seeh 	if (kd->cols == 0 &&
1478512c4b6Spk 	    prom_getoption("screen-#columns", prop, sizeof prop) == 0)
1488512c4b6Spk 		kd->cols = strtoul(prop, NULL, 10);
14901e2e698Seeh }
15001e2e698Seeh 
15101e2e698Seeh struct tty *
1521a509d61Scdi kdtty(dev_t dev)
15301e2e698Seeh {
15401e2e698Seeh 	struct kd_softc *kd;
15501e2e698Seeh 
15601e2e698Seeh 	kd = &kd_softc; 	/* XXX */
15701e2e698Seeh 	return (kd->kd_tty);
15801e2e698Seeh }
15901e2e698Seeh 
16001e2e698Seeh int
1611a509d61Scdi kdopen(dev_t dev, int flag, int mode, struct lwp *l)
16201e2e698Seeh {
16301e2e698Seeh 	struct kd_softc *kd;
16401e2e698Seeh 	int error, s, unit;
16501e2e698Seeh 	struct tty *tp;
166f5839cdaSpk static	int firstopen = 1;
16701e2e698Seeh 
16801e2e698Seeh 	unit = minor(dev);
16901e2e698Seeh 	if (unit != 0)
17001e2e698Seeh 		return ENXIO;
17101e2e698Seeh 	kd = &kd_softc; 	/* XXX */
17201e2e698Seeh 
173f5839cdaSpk 	if (firstopen) {
174f5839cdaSpk 		kd_init(kd);
175f5839cdaSpk 		firstopen = 0;
17601e2e698Seeh 	}
177f5839cdaSpk 	tp = kd->kd_tty;
17801e2e698Seeh 
17901e2e698Seeh 	/* It's simpler to do this up here. */
180e8373398Selad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
18101e2e698Seeh 		return (EBUSY);
18201e2e698Seeh 
18301e2e698Seeh 	s = spltty();
18401e2e698Seeh 
18501e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0) {
18601e2e698Seeh 		/* First open. */
187f5839cdaSpk 
188f5839cdaSpk 		/* Notify the input device that serves us */
189f5839cdaSpk 		struct cons_channel *cc = kd->kd_in;
190f5839cdaSpk 		if (cc != NULL &&
191f5839cdaSpk 		    (error = (*cc->cc_iopen)(cc)) != 0) {
192805ffd07Seeh 			splx(s);
193f5839cdaSpk 			return (error);
194f5839cdaSpk 		}
195f5839cdaSpk 
19601e2e698Seeh 		ttychars(tp);
19701e2e698Seeh 		tp->t_iflag = TTYDEF_IFLAG;
19801e2e698Seeh 		tp->t_oflag = TTYDEF_OFLAG;
19901e2e698Seeh 		tp->t_cflag = TTYDEF_CFLAG;
20001e2e698Seeh 		tp->t_lflag = TTYDEF_LFLAG;
20101e2e698Seeh 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
20201e2e698Seeh 		(void) kdparam(tp, &tp->t_termios);
20301e2e698Seeh 		ttsetwater(tp);
20401e2e698Seeh 		tp->t_winsize.ws_row = kd->rows;
20501e2e698Seeh 		tp->t_winsize.ws_col = kd->cols;
20601e2e698Seeh 		/* Flush pending input?  Clear translator? */
20701e2e698Seeh 		/* This (pseudo)device always has SOFTCAR */
20801e2e698Seeh 		tp->t_state |= TS_CARR_ON;
20901e2e698Seeh 	}
21001e2e698Seeh 
21101e2e698Seeh 	splx(s);
21201e2e698Seeh 
21323a0c490Seeh 	return ((*tp->t_linesw->l_open)(dev, tp));
21401e2e698Seeh }
21501e2e698Seeh 
21601e2e698Seeh int
2171a509d61Scdi kdclose(dev_t dev, int flag, int mode, struct lwp *l)
21801e2e698Seeh {
21901e2e698Seeh 	struct kd_softc *kd;
22001e2e698Seeh 	struct tty *tp;
221f5839cdaSpk 	struct cons_channel *cc;
22201e2e698Seeh 
22301e2e698Seeh 	kd = &kd_softc; 	/* XXX */
22401e2e698Seeh 	tp = kd->kd_tty;
22501e2e698Seeh 
22601e2e698Seeh 	/* XXX This is for cons.c. */
22701e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0)
22801e2e698Seeh 		return 0;
22901e2e698Seeh 
23023a0c490Seeh 	(*tp->t_linesw->l_close)(tp, flag);
23101e2e698Seeh 	ttyclose(tp);
232f5839cdaSpk 
233f5839cdaSpk 	if ((cc = kd->kd_in) != NULL)
23457801e8fSmartin 		(void)(*cc->cc_iclose)(cc);
235f5839cdaSpk 
23601e2e698Seeh 	return (0);
23701e2e698Seeh }
23801e2e698Seeh 
23901e2e698Seeh int
2401a509d61Scdi kdread(dev_t dev, struct uio *uio, int flag)
24101e2e698Seeh {
24201e2e698Seeh 	struct kd_softc *kd;
24301e2e698Seeh 	struct tty *tp;
24401e2e698Seeh 
24501e2e698Seeh 	kd = &kd_softc; 	/* XXX */
24601e2e698Seeh 	tp = kd->kd_tty;
24701e2e698Seeh 
24823a0c490Seeh 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
24901e2e698Seeh }
25001e2e698Seeh 
25101e2e698Seeh int
2521a509d61Scdi kdwrite(dev_t dev, struct uio *uio, int flag)
25301e2e698Seeh {
25401e2e698Seeh 	struct kd_softc *kd;
25501e2e698Seeh 	struct tty *tp;
25601e2e698Seeh 
25701e2e698Seeh 	kd = &kd_softc; 	/* XXX */
25801e2e698Seeh 	tp = kd->kd_tty;
25901e2e698Seeh 
26023a0c490Seeh 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
26101e2e698Seeh }
26201e2e698Seeh 
26301e2e698Seeh int
2641a509d61Scdi kdpoll(dev_t dev, int events, struct lwp *l)
2652963ff5cSscw {
2662963ff5cSscw 	struct kd_softc *kd;
2672963ff5cSscw 	struct tty *tp;
2682963ff5cSscw 
2692963ff5cSscw 	kd = &kd_softc; 	/* XXX */
2702963ff5cSscw 	tp = kd->kd_tty;
2712963ff5cSscw 
27295e1ffb1Schristos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
2732963ff5cSscw }
2742963ff5cSscw 
2752963ff5cSscw int
2761a509d61Scdi kdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
27701e2e698Seeh {
27801e2e698Seeh 	struct kd_softc *kd;
27901e2e698Seeh 	struct tty *tp;
28001e2e698Seeh 	int error;
28101e2e698Seeh 
28201e2e698Seeh 	kd = &kd_softc; 	/* XXX */
28301e2e698Seeh 	tp = kd->kd_tty;
28401e2e698Seeh 
28595e1ffb1Schristos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
28631144d99Satatat 	if (error != EPASSTHROUGH)
28701e2e698Seeh 		return error;
28831144d99Satatat 
28995e1ffb1Schristos 	error = ttioctl(tp, cmd, data, flag, l);
29031144d99Satatat 	if (error != EPASSTHROUGH)
29101e2e698Seeh 		return error;
29201e2e698Seeh 
29301e2e698Seeh 	/* Handle any ioctl commands specific to kbd/display. */
29401e2e698Seeh 	/* XXX - Send KB* ioctls to kbd module? */
29501e2e698Seeh 	/* XXX - Send FB* ioctls to fb module?  */
29601e2e698Seeh 
29731144d99Satatat 	return EPASSTHROUGH;
29801e2e698Seeh }
29901e2e698Seeh 
30001e2e698Seeh static int
3011a509d61Scdi kdparam(struct tty *tp, struct termios *t)
30201e2e698Seeh {
30301e2e698Seeh 	/* XXX - These are ignored... */
30401e2e698Seeh 	tp->t_ispeed = t->c_ispeed;
30501e2e698Seeh 	tp->t_ospeed = t->c_ospeed;
30601e2e698Seeh 	tp->t_cflag = t->c_cflag;
30701e2e698Seeh 	return 0;
30801e2e698Seeh }
30901e2e698Seeh 
31001e2e698Seeh 
31101e2e698Seeh static void kd_later(void*);
31201e2e698Seeh static void kd_putfb(struct tty *);
31301e2e698Seeh 
31401e2e698Seeh static void
3151a509d61Scdi kdstart(struct tty *tp)
31601e2e698Seeh {
31701e2e698Seeh 	struct clist *cl;
318*36bb413eSad 	int s1, s2;
31901e2e698Seeh 
320*36bb413eSad 	s1 = splsoftclock();
321*36bb413eSad 	s2 = spltty();
32201e2e698Seeh 	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
32301e2e698Seeh 		goto out;
32401e2e698Seeh 
32501e2e698Seeh 	cl = &tp->t_outq;
32601e2e698Seeh 	if (cl->c_cc) {
32701e2e698Seeh 		if (kd_is_console) {
32801e2e698Seeh 			tp->t_state |= TS_BUSY;
329*36bb413eSad 			if (s1 == 0) {
33001e2e698Seeh 				/* called at level zero - update screen now. */
331*36bb413eSad 				splx(s2);
33201e2e698Seeh 				kd_putfb(tp);
333*36bb413eSad 				s2 = spltty();
33401e2e698Seeh 				tp->t_state &= ~TS_BUSY;
33501e2e698Seeh 			} else {
33601e2e698Seeh 				/* called at interrupt level - do it later */
3377b918b40Sthorpej 				callout_reset(&tp->t_rstrt_ch, 0,
3387b918b40Sthorpej 				    kd_later, tp);
33901e2e698Seeh 			}
34001e2e698Seeh 		} else {
34101e2e698Seeh 			/*
34201e2e698Seeh 			 * This driver uses the PROM for writing the screen,
34301e2e698Seeh 			 * and that only works if this is the console device.
34401e2e698Seeh 			 * If this is not the console, just flush the output.
34501e2e698Seeh 			 * Sorry.  (In that case, use xdm instead of getty.)
34601e2e698Seeh 			 */
34701e2e698Seeh 			ndflush(cl, cl->c_cc);
34801e2e698Seeh 		}
34901e2e698Seeh 	}
35001e2e698Seeh 	if (cl->c_cc <= tp->t_lowat) {
35101e2e698Seeh 		if (tp->t_state & TS_ASLEEP) {
35201e2e698Seeh 			tp->t_state &= ~TS_ASLEEP;
35301e2e698Seeh 			wakeup((caddr_t)cl);
35401e2e698Seeh 		}
35501e2e698Seeh 		selwakeup(&tp->t_wsel);
35601e2e698Seeh 	}
35701e2e698Seeh out:
358*36bb413eSad 	splx(s2);
359*36bb413eSad 	splx(s1);
36001e2e698Seeh }
36101e2e698Seeh 
36201e2e698Seeh /*
36301e2e698Seeh  * Timeout function to do delayed writes to the screen.
36401e2e698Seeh  * Called at splsoftclock when requested by kdstart.
36501e2e698Seeh  */
36601e2e698Seeh static void
3671a509d61Scdi kd_later(void *tpaddr)
36801e2e698Seeh {
36901e2e698Seeh 	struct tty *tp = tpaddr;
37001e2e698Seeh 	register int s;
37101e2e698Seeh 
37201e2e698Seeh 	kd_putfb(tp);
37301e2e698Seeh 
37401e2e698Seeh 	s = spltty();
37501e2e698Seeh 	tp->t_state &= ~TS_BUSY;
37623a0c490Seeh 	(*tp->t_linesw->l_start)(tp);
37701e2e698Seeh 	splx(s);
37801e2e698Seeh }
37901e2e698Seeh 
38001e2e698Seeh /*
38101e2e698Seeh  * Put text on the screen using the PROM monitor.
38201e2e698Seeh  * This can take a while, so to avoid missing
38301e2e698Seeh  * interrupts, this is called at splsoftclock.
38401e2e698Seeh  */
38501e2e698Seeh static void
3861a509d61Scdi kd_putfb(struct tty *tp)
38701e2e698Seeh {
38801e2e698Seeh 	char buf[PUT_WSIZE];
38901e2e698Seeh 	struct clist *cl = &tp->t_outq;
39001e2e698Seeh 	char *p, *end;
39101e2e698Seeh 	int len;
39201e2e698Seeh 
39301e2e698Seeh 	while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) {
39401e2e698Seeh 		/* PROM will barf if high bits are set. */
39501e2e698Seeh 		p = buf;
39601e2e698Seeh 		end = buf + len;
39701e2e698Seeh 		while (p < end)
39801e2e698Seeh 			*p++ &= 0x7f;
39901e2e698Seeh 		/* Now let the PROM print it. */
40005a2b230Spk 		prom_write(prom_stdout(), buf, len);
40101e2e698Seeh 	}
40201e2e698Seeh }
40301e2e698Seeh 
404f5839cdaSpk /*
405f5839cdaSpk  * Default PROM-based console input stream
406f5839cdaSpk  */
407d50f0c62Scdi static int kd_rom_iopen(struct cons_channel *);
408d50f0c62Scdi static int kd_rom_iclose(struct cons_channel *);
409f5839cdaSpk 
410f5839cdaSpk static struct cons_channel prom_cons_channel;
411f5839cdaSpk 
412f5839cdaSpk int
413d50f0c62Scdi kd_rom_iopen(struct cons_channel *cc)
414f5839cdaSpk {
415f5839cdaSpk 	return (0);
416f5839cdaSpk }
417f5839cdaSpk 
418f5839cdaSpk int
419d50f0c62Scdi kd_rom_iclose(struct cons_channel *cc)
420f5839cdaSpk {
421f5839cdaSpk 	return (0);
422f5839cdaSpk }
423f5839cdaSpk 
42401e2e698Seeh /*
42501e2e698Seeh  * Our "interrupt" routine for input. This is called by
42601e2e698Seeh  * the keyboard driver (dev/sun/kbd.c) at spltty.
42701e2e698Seeh  */
42801e2e698Seeh void
429d50f0c62Scdi kd_cons_input(int c)
43001e2e698Seeh {
43101e2e698Seeh 	struct kd_softc *kd = &kd_softc;
43201e2e698Seeh 	struct tty *tp;
43301e2e698Seeh 
43401e2e698Seeh 	/* XXX: Make sure the device is open. */
43501e2e698Seeh 	tp = kd->kd_tty;
43601e2e698Seeh 	if (tp == NULL)
43701e2e698Seeh 		return;
43801e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0)
43901e2e698Seeh 		return;
44001e2e698Seeh 
44123a0c490Seeh 	(*tp->t_linesw->l_rint)(c, tp);
44201e2e698Seeh }
44301e2e698Seeh 
44401e2e698Seeh 
44501e2e698Seeh /****************************************************************
44601e2e698Seeh  * kd console support
44701e2e698Seeh  ****************************************************************/
44801e2e698Seeh 
44901e2e698Seeh /* The debugger gets its own key translation state. */
450424619caSeeh static struct kbd_state *kdcn_state;
45101e2e698Seeh 
452d50f0c62Scdi static void kdcnprobe(struct consdev *);
453d50f0c62Scdi static void kdcninit(struct consdev *);
454d50f0c62Scdi static void kdcnputc(dev_t, int);
455d50f0c62Scdi static void kdcnpollc(dev_t, int);
45601e2e698Seeh 
45792ad9c40Seeh /* The keyboard driver uses cn_hw to access the real console driver */
45892ad9c40Seeh extern struct consdev consdev_prom;
45901e2e698Seeh struct consdev consdev_kd = {
4601f9d7be4Smartin 	.cn_probe = kdcnprobe,
4611f9d7be4Smartin 	.cn_init = kdcninit,
4621f9d7be4Smartin 	.cn_getc = kdcngetc,
4631f9d7be4Smartin 	.cn_putc = kdcnputc,
4641f9d7be4Smartin 	.cn_pollc = kdcnpollc,
46501e2e698Seeh };
466424619caSeeh struct consdev *cn_hw = &consdev_kd;
467424619caSeeh 
468424619caSeeh void
4691a509d61Scdi cons_attach_input(struct cons_channel *cc, struct consdev *cn)
470424619caSeeh {
471424619caSeeh 	struct kd_softc *kd = &kd_softc;
472424619caSeeh 	struct kbd_softc *kds = cc->cc_dev;
473424619caSeeh 	struct kbd_state *ks;
474424619caSeeh 
475424619caSeeh 	/* Share the keyboard state */
476424619caSeeh 	kdcn_state = ks = &kds->k_state;
477424619caSeeh 
478424619caSeeh 	kd->kd_in = cc;
479424619caSeeh 	cc->cc_upstream = kd_cons_input;
480424619caSeeh 
481424619caSeeh 	/* Attach lower level. */
48217b69d18Seeh 	cn_hw->cn_dev = cn->cn_dev;
483424619caSeeh 	cn_hw->cn_pollc = cn->cn_pollc;
484424619caSeeh 	cn_hw->cn_getc = cn->cn_getc;
485424619caSeeh 
486424619caSeeh 	/* Attach us as console. */
48777a6b82bSgehenna 	cn_tab->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
488424619caSeeh 	cn_tab->cn_probe = kdcnprobe;
489424619caSeeh 	cn_tab->cn_init = kdcninit;
490424619caSeeh 	cn_tab->cn_getc = kdcngetc;
491424619caSeeh 	cn_tab->cn_pollc = kdcnpollc;
492424619caSeeh 	cn_tab->cn_pri = CN_INTERNAL;
493424619caSeeh 
494424619caSeeh 	/* Set up initial PROM input channel for /dev/console */
495424619caSeeh 	prom_cons_channel.cc_dev = NULL;
496424619caSeeh 	prom_cons_channel.cc_iopen = kd_rom_iopen;
497424619caSeeh 	prom_cons_channel.cc_iclose = kd_rom_iclose;
498424619caSeeh 
499424619caSeeh 	/* Indicate that it is OK to use the PROM fbwrite */
500424619caSeeh 	kd_is_console = 1;
501424619caSeeh }
50201e2e698Seeh 
503805ffd07Seeh 
504805ffd07Seeh void kd_attach_input(struct cons_channel *);
505805ffd07Seeh void
5061a509d61Scdi kd_attach_input(struct cons_channel *cc)
507805ffd07Seeh {
508805ffd07Seeh 	struct kd_softc *kd = &kd_softc;
509805ffd07Seeh 
510805ffd07Seeh 	kd->kd_in = cc;
511805ffd07Seeh 	cc->cc_upstream = kd_cons_input;
512805ffd07Seeh }
513805ffd07Seeh 
514805ffd07Seeh 
51501e2e698Seeh /* We never call this. */
51601e2e698Seeh static void
517d50f0c62Scdi kdcnprobe(struct consdev *cn)
51801e2e698Seeh {
51901e2e698Seeh }
52001e2e698Seeh 
52101e2e698Seeh static void
522d50f0c62Scdi kdcninit(struct consdev *cn)
52301e2e698Seeh {
524424619caSeeh #if 0
525424619caSeeh 	struct kbd_state *ks = kdcn_state;
52601e2e698Seeh 
52777a6b82bSgehenna 	cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
52801e2e698Seeh 	cn->cn_pri = CN_INTERNAL;
52901e2e698Seeh 
53001e2e698Seeh 	/* This prepares kbd_translate() */
53101e2e698Seeh 	ks->kbd_id = KBD_MIN_TYPE;
53201e2e698Seeh 	kbd_xlate_init(ks);
53301e2e698Seeh 
534f5839cdaSpk 	/* Set up initial PROM input channel for /dev/console */
535f5839cdaSpk 	prom_cons_channel.cc_dev = NULL;
536f5839cdaSpk 	prom_cons_channel.cc_iopen = kd_rom_iopen;
537f5839cdaSpk 	prom_cons_channel.cc_iclose = kd_rom_iclose;
538f5839cdaSpk 	cons_attach_input(&prom_cons_channel);
539f5839cdaSpk 
54001e2e698Seeh 	/* Indicate that it is OK to use the PROM fbwrite */
54101e2e698Seeh 	kd_is_console = 1;
542424619caSeeh #endif
54301e2e698Seeh }
54401e2e698Seeh 
54501e2e698Seeh static int
546d50f0c62Scdi kdcngetc(dev_t dev)
54701e2e698Seeh {
548424619caSeeh 	struct kbd_state *ks = kdcn_state;
54901e2e698Seeh 	int code, class, data, keysym;
550d50f0c62Scdi 	extern int prom_cngetc(dev_t);
55101e2e698Seeh 
552424619caSeeh 
553424619caSeeh 	if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev);
55401e2e698Seeh 	for (;;) {
55592ad9c40Seeh 		code = (*cn_hw->cn_getc)(dev);
55601e2e698Seeh 		keysym = kbd_code_to_keysym(ks, code);
55701e2e698Seeh 		class = KEYSYM_CLASS(keysym);
55801e2e698Seeh 
55901e2e698Seeh 		switch (class) {
56001e2e698Seeh 		case KEYSYM_ASCII:
56101e2e698Seeh 			goto out;
56201e2e698Seeh 
56301e2e698Seeh 		case KEYSYM_CLRMOD:
56401e2e698Seeh 		case KEYSYM_SETMOD:
56501e2e698Seeh 			data = (keysym & 0x1F);
56601e2e698Seeh 			/* Only allow ctrl or shift. */
56701e2e698Seeh 			if (data > KBMOD_SHIFT_R)
56801e2e698Seeh 				break;
56901e2e698Seeh 			data = 1 << data;
57001e2e698Seeh 			if (class == KEYSYM_SETMOD)
57101e2e698Seeh 				ks->kbd_modbits |= data;
57201e2e698Seeh 			else
57301e2e698Seeh 				ks->kbd_modbits &= ~data;
57401e2e698Seeh 			break;
57501e2e698Seeh 
57601e2e698Seeh 		case KEYSYM_ALL_UP:
57701e2e698Seeh 			/* No toggle keys here. */
57801e2e698Seeh 			ks->kbd_modbits = 0;
57901e2e698Seeh 			break;
58001e2e698Seeh 
58101e2e698Seeh 		default:	/* ignore all other keysyms */
58201e2e698Seeh 			break;
58301e2e698Seeh 		}
58401e2e698Seeh 	}
58501e2e698Seeh out:
58601e2e698Seeh 	return (keysym);
58701e2e698Seeh }
58801e2e698Seeh 
58901e2e698Seeh static void
590d50f0c62Scdi kdcnputc(dev_t dev, int c)
59101e2e698Seeh {
59292ad9c40Seeh 	int s;
59301e2e698Seeh 	char c0 = (c & 0x7f);
59401e2e698Seeh 
59592ad9c40Seeh 	s = splhigh();
59605a2b230Spk 	prom_write(prom_stdout(), &c0, 1);
59792ad9c40Seeh 	splx(s);
59801e2e698Seeh }
59901e2e698Seeh 
60001e2e698Seeh static void
601d50f0c62Scdi kdcnpollc(dev_t dev, int on)
60201e2e698Seeh {
603424619caSeeh 	struct kbd_state *ks = kdcn_state;
60401e2e698Seeh 
60501e2e698Seeh 	if (on) {
60601e2e698Seeh 		/* Entering debugger. */
60701e2e698Seeh #if NFB > 0
60801e2e698Seeh 		fb_unblank();
60901e2e698Seeh #endif
61001e2e698Seeh 		/* Clear shift keys too. */
61101e2e698Seeh 		ks->kbd_modbits = 0;
61201e2e698Seeh 	} else {
61301e2e698Seeh 		/* Resuming kernel. */
61401e2e698Seeh 	}
61592ad9c40Seeh 	(*cn_hw->cn_pollc)(dev, on);
61601e2e698Seeh }
617