xref: /netbsd/sys/arch/sparc64/dev/kd.c (revision 1a918832)
1*1a918832Sdholland /*	$NetBSD: kd.c,v 1.53 2014/07/25 08:10:35 dholland 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  *
1901e2e698Seeh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2001e2e698Seeh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2101e2e698Seeh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2201e2e698Seeh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2301e2e698Seeh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2401e2e698Seeh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2501e2e698Seeh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2601e2e698Seeh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2701e2e698Seeh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2801e2e698Seeh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2901e2e698Seeh  * POSSIBILITY OF SUCH DAMAGE.
3001e2e698Seeh  */
3101e2e698Seeh 
3201e2e698Seeh /*
3301e2e698Seeh  * Keyboard/Display device.
3401e2e698Seeh  *
3501e2e698Seeh  * This driver exists simply to provide a tty device that
3601e2e698Seeh  * the indirect console driver can point to.
3701e2e698Seeh  * The kbd driver sends its input here.
3801e2e698Seeh  * Output goes to the screen via PROM printf.
3901e2e698Seeh  */
4001e2e698Seeh 
41ed517291Slukem #include <sys/cdefs.h>
42*1a918832Sdholland __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.53 2014/07/25 08:10:35 dholland Exp $");
43ed517291Slukem 
4401e2e698Seeh #include <sys/param.h>
4501e2e698Seeh #include <sys/proc.h>
4601e2e698Seeh #include <sys/systm.h>
4701e2e698Seeh #include <sys/ioctl.h>
4801e2e698Seeh #include <sys/tty.h>
4901e2e698Seeh #include <sys/file.h>
5001e2e698Seeh #include <sys/conf.h>
5101e2e698Seeh #include <sys/device.h>
528ccb6c93Selad #include <sys/kauth.h>
5301e2e698Seeh 
5401e2e698Seeh #include <machine/openfirm.h>
5501e2e698Seeh #include <machine/eeprom.h>
5601e2e698Seeh #include <machine/psl.h>
5701e2e698Seeh #include <machine/cpu.h>
5801e2e698Seeh #include <machine/kbd.h>
5901e2e698Seeh #include <machine/autoconf.h>
6001e2e698Seeh 
6101e2e698Seeh #include <dev/cons.h>
62f5839cdaSpk #include <dev/sun/event_var.h>
6301e2e698Seeh #include <dev/sun/kbd_xlate.h>
64f5839cdaSpk #include <dev/sun/kbdvar.h>
6501e2e698Seeh #include <sparc64/dev/cons.h>
6601e2e698Seeh 
6777a6b82bSgehenna dev_type_open(kdopen);
6877a6b82bSgehenna dev_type_close(kdclose);
6977a6b82bSgehenna dev_type_read(kdread);
7077a6b82bSgehenna dev_type_write(kdwrite);
7177a6b82bSgehenna dev_type_ioctl(kdioctl);
7277a6b82bSgehenna dev_type_tty(kdtty);
7377a6b82bSgehenna dev_type_poll(kdpoll);
7477a6b82bSgehenna 
7577a6b82bSgehenna const struct cdevsw kd_cdevsw = {
7676258fa0Sdholland 	.d_open = kdopen,
7776258fa0Sdholland 	.d_close = kdclose,
7876258fa0Sdholland 	.d_read = kdread,
7976258fa0Sdholland 	.d_write = kdwrite,
8076258fa0Sdholland 	.d_ioctl = kdioctl,
8176258fa0Sdholland 	.d_stop = nostop,
8276258fa0Sdholland 	.d_tty = kdtty,
8376258fa0Sdholland 	.d_poll = kdpoll,
8476258fa0Sdholland 	.d_mmap = nommap,
8576258fa0Sdholland 	.d_kqfilter = ttykqfilter,
86*1a918832Sdholland 	.d_discard = nodiscard,
8776258fa0Sdholland 	.d_flag = D_TTY
8877a6b82bSgehenna };
8977a6b82bSgehenna 
9001e2e698Seeh struct	tty *fbconstty = 0;	/* tty structure for frame buffer console */
9101e2e698Seeh 
9201e2e698Seeh #define PUT_WSIZE	64
9301e2e698Seeh 
9401e2e698Seeh struct kd_softc {
9501e2e698Seeh 	struct  tty *kd_tty;
9601e2e698Seeh 	int rows, cols;
97f5839cdaSpk 
98f5839cdaSpk 	/* Console input hook */
99f5839cdaSpk 	struct cons_channel *kd_in;
10001e2e698Seeh };
10101e2e698Seeh 
10201e2e698Seeh /*
10301e2e698Seeh  * There is no point in pretending there might be
10401e2e698Seeh  * more than one keyboard/display device.
10501e2e698Seeh  */
10601e2e698Seeh static struct kd_softc kd_softc;
10701e2e698Seeh static int kd_is_console;
10801e2e698Seeh 
10901e2e698Seeh static int kdparam(struct tty *, struct termios *);
11001e2e698Seeh static void kdstart(struct tty *);
111d50f0c62Scdi static void kd_init(struct kd_softc *);
112d50f0c62Scdi static void kd_cons_input(int);
113d50f0c62Scdi static int  kdcngetc(dev_t);
1144f239666Sdogcow static void kd_later(void*);
1154f239666Sdogcow static void kd_putfb(struct tty *);
11601e2e698Seeh 
11701e2e698Seeh int	cons_ocount;		/* output byte count */
11801e2e698Seeh 
11901e2e698Seeh /*
12001e2e698Seeh  * This is called by kbd_attach()
12101e2e698Seeh  * XXX - Make this a proper child of kbd?
12201e2e698Seeh  */
12301e2e698Seeh void
kd_init(struct kd_softc * kd)124d50f0c62Scdi kd_init(struct kd_softc *kd)
125f5839cdaSpk {
12601e2e698Seeh 	struct tty *tp;
1278512c4b6Spk 	char prop[6+1];
12892ad9c40Seeh 
12901e2e698Seeh 	kd = &kd_softc; 	/* XXX */
13001e2e698Seeh 
13180f6fc52Srmind 	tp = tty_alloc();
132d238692cSjoerg 	callout_setfunc(&tp->t_rstrt_ch, kd_later, tp);
13301e2e698Seeh 	tp->t_oproc = kdstart;
13401e2e698Seeh 	tp->t_param = kdparam;
13577a6b82bSgehenna 	tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
13601e2e698Seeh 
13701e2e698Seeh 	tty_attach(tp);
13801e2e698Seeh 	kd->kd_tty = tp;
13901e2e698Seeh 
14001e2e698Seeh 	/*
14101e2e698Seeh 	 * get the console struct winsize.
14201e2e698Seeh 	 */
14301e2e698Seeh 	if (kd_is_console) {
14401e2e698Seeh 		fbconstty = tp;
14501e2e698Seeh 	}
14601e2e698Seeh 
14701e2e698Seeh 	if (kd->rows == 0 &&
1488512c4b6Spk 	    prom_getoption("screen-#rows", prop, sizeof prop) == 0)
1498512c4b6Spk 		kd->rows = strtoul(prop, NULL, 10);
1508512c4b6Spk 
15101e2e698Seeh 	if (kd->cols == 0 &&
1528512c4b6Spk 	    prom_getoption("screen-#columns", prop, sizeof prop) == 0)
1538512c4b6Spk 		kd->cols = strtoul(prop, NULL, 10);
15401e2e698Seeh }
15501e2e698Seeh 
15601e2e698Seeh struct tty *
kdtty(dev_t dev)1571a509d61Scdi kdtty(dev_t dev)
15801e2e698Seeh {
15901e2e698Seeh 	struct kd_softc *kd;
16001e2e698Seeh 
16101e2e698Seeh 	kd = &kd_softc; 	/* XXX */
16201e2e698Seeh 	return (kd->kd_tty);
16301e2e698Seeh }
16401e2e698Seeh 
16501e2e698Seeh int
kdopen(dev_t dev,int flag,int mode,struct lwp * l)1661a509d61Scdi kdopen(dev_t dev, int flag, int mode, struct lwp *l)
16701e2e698Seeh {
16801e2e698Seeh 	struct kd_softc *kd;
16901e2e698Seeh 	int error, s, unit;
17001e2e698Seeh 	struct tty *tp;
171f5839cdaSpk static	int firstopen = 1;
17201e2e698Seeh 
17301e2e698Seeh 	unit = minor(dev);
17401e2e698Seeh 	if (unit != 0)
17501e2e698Seeh 		return ENXIO;
17601e2e698Seeh 	kd = &kd_softc; 	/* XXX */
17701e2e698Seeh 
178f5839cdaSpk 	if (firstopen) {
179f5839cdaSpk 		kd_init(kd);
180f5839cdaSpk 		firstopen = 0;
18101e2e698Seeh 	}
182f5839cdaSpk 	tp = kd->kd_tty;
18301e2e698Seeh 
18401e2e698Seeh 	/* It's simpler to do this up here. */
185e8373398Selad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
18601e2e698Seeh 		return (EBUSY);
18701e2e698Seeh 
18801e2e698Seeh 	s = spltty();
18901e2e698Seeh 
19001e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0) {
19101e2e698Seeh 		/* First open. */
192f5839cdaSpk 
193f5839cdaSpk 		/* Notify the input device that serves us */
194f5839cdaSpk 		struct cons_channel *cc = kd->kd_in;
195f5839cdaSpk 		if (cc != NULL &&
196f5839cdaSpk 		    (error = (*cc->cc_iopen)(cc)) != 0) {
197805ffd07Seeh 			splx(s);
198f5839cdaSpk 			return (error);
199f5839cdaSpk 		}
200f5839cdaSpk 
20101e2e698Seeh 		ttychars(tp);
20201e2e698Seeh 		tp->t_iflag = TTYDEF_IFLAG;
20301e2e698Seeh 		tp->t_oflag = TTYDEF_OFLAG;
20401e2e698Seeh 		tp->t_cflag = TTYDEF_CFLAG;
20501e2e698Seeh 		tp->t_lflag = TTYDEF_LFLAG;
20601e2e698Seeh 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
20701e2e698Seeh 		(void) kdparam(tp, &tp->t_termios);
20801e2e698Seeh 		ttsetwater(tp);
20901e2e698Seeh 		tp->t_winsize.ws_row = kd->rows;
21001e2e698Seeh 		tp->t_winsize.ws_col = kd->cols;
21101e2e698Seeh 		/* Flush pending input?  Clear translator? */
21201e2e698Seeh 		/* This (pseudo)device always has SOFTCAR */
21301e2e698Seeh 		tp->t_state |= TS_CARR_ON;
21401e2e698Seeh 	}
21501e2e698Seeh 
21601e2e698Seeh 	splx(s);
21701e2e698Seeh 
21823a0c490Seeh 	return ((*tp->t_linesw->l_open)(dev, tp));
21901e2e698Seeh }
22001e2e698Seeh 
22101e2e698Seeh int
kdclose(dev_t dev,int flag,int mode,struct lwp * l)2221a509d61Scdi kdclose(dev_t dev, int flag, int mode, struct lwp *l)
22301e2e698Seeh {
22401e2e698Seeh 	struct kd_softc *kd;
22501e2e698Seeh 	struct tty *tp;
226f5839cdaSpk 	struct cons_channel *cc;
22701e2e698Seeh 
22801e2e698Seeh 	kd = &kd_softc; 	/* XXX */
22901e2e698Seeh 	tp = kd->kd_tty;
23001e2e698Seeh 
23101e2e698Seeh 	/* XXX This is for cons.c. */
23201e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0)
23301e2e698Seeh 		return 0;
23401e2e698Seeh 
23523a0c490Seeh 	(*tp->t_linesw->l_close)(tp, flag);
23601e2e698Seeh 	ttyclose(tp);
237f5839cdaSpk 
238f5839cdaSpk 	if ((cc = kd->kd_in) != NULL)
23957801e8fSmartin 		(void)(*cc->cc_iclose)(cc);
240f5839cdaSpk 
24101e2e698Seeh 	return (0);
24201e2e698Seeh }
24301e2e698Seeh 
24401e2e698Seeh int
kdread(dev_t dev,struct uio * uio,int flag)2451a509d61Scdi kdread(dev_t dev, struct uio *uio, int flag)
24601e2e698Seeh {
24701e2e698Seeh 	struct kd_softc *kd;
24801e2e698Seeh 	struct tty *tp;
24901e2e698Seeh 
25001e2e698Seeh 	kd = &kd_softc; 	/* XXX */
25101e2e698Seeh 	tp = kd->kd_tty;
25201e2e698Seeh 
25323a0c490Seeh 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
25401e2e698Seeh }
25501e2e698Seeh 
25601e2e698Seeh int
kdwrite(dev_t dev,struct uio * uio,int flag)2571a509d61Scdi kdwrite(dev_t dev, struct uio *uio, int flag)
25801e2e698Seeh {
25901e2e698Seeh 	struct kd_softc *kd;
26001e2e698Seeh 	struct tty *tp;
26101e2e698Seeh 
26201e2e698Seeh 	kd = &kd_softc; 	/* XXX */
26301e2e698Seeh 	tp = kd->kd_tty;
26401e2e698Seeh 
26523a0c490Seeh 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
26601e2e698Seeh }
26701e2e698Seeh 
26801e2e698Seeh int
kdpoll(dev_t dev,int events,struct lwp * l)2691a509d61Scdi kdpoll(dev_t dev, int events, struct lwp *l)
2702963ff5cSscw {
2712963ff5cSscw 	struct kd_softc *kd;
2722963ff5cSscw 	struct tty *tp;
2732963ff5cSscw 
2742963ff5cSscw 	kd = &kd_softc; 	/* XXX */
2752963ff5cSscw 	tp = kd->kd_tty;
2762963ff5cSscw 
27795e1ffb1Schristos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
2782963ff5cSscw }
2792963ff5cSscw 
2802963ff5cSscw int
kdioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)28153524e44Schristos kdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
28201e2e698Seeh {
28301e2e698Seeh 	struct kd_softc *kd;
28401e2e698Seeh 	struct tty *tp;
28501e2e698Seeh 	int error;
28601e2e698Seeh 
28701e2e698Seeh 	kd = &kd_softc; 	/* XXX */
28801e2e698Seeh 	tp = kd->kd_tty;
28901e2e698Seeh 
29095e1ffb1Schristos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
29131144d99Satatat 	if (error != EPASSTHROUGH)
29201e2e698Seeh 		return error;
29331144d99Satatat 
29495e1ffb1Schristos 	error = ttioctl(tp, cmd, data, flag, l);
29531144d99Satatat 	if (error != EPASSTHROUGH)
29601e2e698Seeh 		return error;
29701e2e698Seeh 
29801e2e698Seeh 	/* Handle any ioctl commands specific to kbd/display. */
29901e2e698Seeh 	/* XXX - Send KB* ioctls to kbd module? */
30001e2e698Seeh 	/* XXX - Send FB* ioctls to fb module?  */
30101e2e698Seeh 
30231144d99Satatat 	return EPASSTHROUGH;
30301e2e698Seeh }
30401e2e698Seeh 
30501e2e698Seeh static int
kdparam(struct tty * tp,struct termios * t)3061a509d61Scdi kdparam(struct tty *tp, struct termios *t)
30701e2e698Seeh {
30801e2e698Seeh 	/* XXX - These are ignored... */
30901e2e698Seeh 	tp->t_ispeed = t->c_ispeed;
31001e2e698Seeh 	tp->t_ospeed = t->c_ospeed;
31101e2e698Seeh 	tp->t_cflag = t->c_cflag;
31201e2e698Seeh 	return 0;
31301e2e698Seeh }
31401e2e698Seeh 
31501e2e698Seeh static void
kdstart(struct tty * tp)3161a509d61Scdi kdstart(struct tty *tp)
31701e2e698Seeh {
31801e2e698Seeh 	struct clist *cl;
31936bb413eSad 	int s1, s2;
32001e2e698Seeh 
32136bb413eSad 	s1 = splsoftclock();
32236bb413eSad 	s2 = spltty();
32301e2e698Seeh 	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
32401e2e698Seeh 		goto out;
32501e2e698Seeh 
32601e2e698Seeh 	cl = &tp->t_outq;
32701e2e698Seeh 	if (cl->c_cc) {
32801e2e698Seeh 		if (kd_is_console) {
32901e2e698Seeh 			tp->t_state |= TS_BUSY;
33036bb413eSad 			if (s1 == 0) {
33101e2e698Seeh 				/* called at level zero - update screen now. */
33236bb413eSad 				splx(s2);
33301e2e698Seeh 				kd_putfb(tp);
33436bb413eSad 				s2 = spltty();
33501e2e698Seeh 				tp->t_state &= ~TS_BUSY;
33601e2e698Seeh 			} else {
33701e2e698Seeh 				/* called at interrupt level - do it later */
338d238692cSjoerg 				callout_schedule(&tp->t_rstrt_ch, 0);
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 	}
350dc26833bSad 	ttypull(tp);
35101e2e698Seeh out:
35236bb413eSad 	splx(s2);
35336bb413eSad 	splx(s1);
35401e2e698Seeh }
35501e2e698Seeh 
35601e2e698Seeh /*
35701e2e698Seeh  * Timeout function to do delayed writes to the screen.
35801e2e698Seeh  * Called at splsoftclock when requested by kdstart.
35901e2e698Seeh  */
36001e2e698Seeh static void
kd_later(void * tpaddr)3611a509d61Scdi kd_later(void *tpaddr)
36201e2e698Seeh {
36301e2e698Seeh 	struct tty *tp = tpaddr;
36401e2e698Seeh 	register int s;
36501e2e698Seeh 
36601e2e698Seeh 	kd_putfb(tp);
36701e2e698Seeh 
36801e2e698Seeh 	s = spltty();
36901e2e698Seeh 	tp->t_state &= ~TS_BUSY;
37023a0c490Seeh 	(*tp->t_linesw->l_start)(tp);
37101e2e698Seeh 	splx(s);
37201e2e698Seeh }
37301e2e698Seeh 
37401e2e698Seeh /*
37501e2e698Seeh  * Put text on the screen using the PROM monitor.
37601e2e698Seeh  * This can take a while, so to avoid missing
37701e2e698Seeh  * interrupts, this is called at splsoftclock.
37801e2e698Seeh  */
37901e2e698Seeh static void
kd_putfb(struct tty * tp)3801a509d61Scdi kd_putfb(struct tty *tp)
38101e2e698Seeh {
38201e2e698Seeh 	char buf[PUT_WSIZE];
38301e2e698Seeh 	struct clist *cl = &tp->t_outq;
38401e2e698Seeh 	char *p, *end;
38501e2e698Seeh 	int len;
38601e2e698Seeh 
38701e2e698Seeh 	while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) {
38801e2e698Seeh 		/* PROM will barf if high bits are set. */
38901e2e698Seeh 		p = buf;
39001e2e698Seeh 		end = buf + len;
39101e2e698Seeh 		while (p < end)
39201e2e698Seeh 			*p++ &= 0x7f;
39301e2e698Seeh 		/* Now let the PROM print it. */
39405a2b230Spk 		prom_write(prom_stdout(), buf, len);
39501e2e698Seeh 	}
39601e2e698Seeh }
39701e2e698Seeh 
398f5839cdaSpk /*
399f5839cdaSpk  * Default PROM-based console input stream
400f5839cdaSpk  */
401d50f0c62Scdi static int kd_rom_iopen(struct cons_channel *);
402d50f0c62Scdi static int kd_rom_iclose(struct cons_channel *);
403f5839cdaSpk 
404f5839cdaSpk static struct cons_channel prom_cons_channel;
405f5839cdaSpk 
406f5839cdaSpk int
kd_rom_iopen(struct cons_channel * cc)407d50f0c62Scdi kd_rom_iopen(struct cons_channel *cc)
408f5839cdaSpk {
409f5839cdaSpk 	return (0);
410f5839cdaSpk }
411f5839cdaSpk 
412f5839cdaSpk int
kd_rom_iclose(struct cons_channel * cc)413d50f0c62Scdi kd_rom_iclose(struct cons_channel *cc)
414f5839cdaSpk {
415f5839cdaSpk 	return (0);
416f5839cdaSpk }
417f5839cdaSpk 
41801e2e698Seeh /*
41901e2e698Seeh  * Our "interrupt" routine for input. This is called by
42001e2e698Seeh  * the keyboard driver (dev/sun/kbd.c) at spltty.
42101e2e698Seeh  */
42201e2e698Seeh void
kd_cons_input(int c)423d50f0c62Scdi kd_cons_input(int c)
42401e2e698Seeh {
42501e2e698Seeh 	struct kd_softc *kd = &kd_softc;
42601e2e698Seeh 	struct tty *tp;
42701e2e698Seeh 
42801e2e698Seeh 	/* XXX: Make sure the device is open. */
42901e2e698Seeh 	tp = kd->kd_tty;
43001e2e698Seeh 	if (tp == NULL)
43101e2e698Seeh 		return;
43201e2e698Seeh 	if ((tp->t_state & TS_ISOPEN) == 0)
43301e2e698Seeh 		return;
43401e2e698Seeh 
43523a0c490Seeh 	(*tp->t_linesw->l_rint)(c, tp);
43601e2e698Seeh }
43701e2e698Seeh 
43801e2e698Seeh 
43901e2e698Seeh /****************************************************************
44001e2e698Seeh  * kd console support
44101e2e698Seeh  ****************************************************************/
44201e2e698Seeh 
44301e2e698Seeh /* The debugger gets its own key translation state. */
444424619caSeeh static struct kbd_state *kdcn_state;
44501e2e698Seeh 
446d50f0c62Scdi static void kdcnprobe(struct consdev *);
447d50f0c62Scdi static void kdcninit(struct consdev *);
448d50f0c62Scdi static void kdcnputc(dev_t, int);
449d50f0c62Scdi static void kdcnpollc(dev_t, int);
45001e2e698Seeh 
45192ad9c40Seeh /* The keyboard driver uses cn_hw to access the real console driver */
45292ad9c40Seeh extern struct consdev consdev_prom;
45301e2e698Seeh struct consdev consdev_kd = {
4541f9d7be4Smartin 	.cn_probe = kdcnprobe,
4551f9d7be4Smartin 	.cn_init = kdcninit,
4561f9d7be4Smartin 	.cn_getc = kdcngetc,
4571f9d7be4Smartin 	.cn_putc = kdcnputc,
4581f9d7be4Smartin 	.cn_pollc = kdcnpollc,
45901e2e698Seeh };
460424619caSeeh struct consdev *cn_hw = &consdev_kd;
461424619caSeeh 
462424619caSeeh void
cons_attach_input(struct cons_channel * cc,struct consdev * cn)4631a509d61Scdi cons_attach_input(struct cons_channel *cc, struct consdev *cn)
464424619caSeeh {
465424619caSeeh 	struct kd_softc *kd = &kd_softc;
4668a19236fStsutsui 	struct kbd_softc *kds = cc->cc_private;
467424619caSeeh 	struct kbd_state *ks;
468424619caSeeh 
469424619caSeeh 	/* Share the keyboard state */
470424619caSeeh 	kdcn_state = ks = &kds->k_state;
471424619caSeeh 
472424619caSeeh 	kd->kd_in = cc;
473424619caSeeh 	cc->cc_upstream = kd_cons_input;
474424619caSeeh 
475424619caSeeh 	/* Attach lower level. */
47617b69d18Seeh 	cn_hw->cn_dev = cn->cn_dev;
477424619caSeeh 	cn_hw->cn_pollc = cn->cn_pollc;
478424619caSeeh 	cn_hw->cn_getc = cn->cn_getc;
479424619caSeeh 
480424619caSeeh 	/* Attach us as console. */
48177a6b82bSgehenna 	cn_tab->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
482424619caSeeh 	cn_tab->cn_probe = kdcnprobe;
483424619caSeeh 	cn_tab->cn_init = kdcninit;
484424619caSeeh 	cn_tab->cn_getc = kdcngetc;
485424619caSeeh 	cn_tab->cn_pollc = kdcnpollc;
486424619caSeeh 	cn_tab->cn_pri = CN_INTERNAL;
487424619caSeeh 
488424619caSeeh 	/* Set up initial PROM input channel for /dev/console */
4898a19236fStsutsui 	prom_cons_channel.cc_private = NULL;
490424619caSeeh 	prom_cons_channel.cc_iopen = kd_rom_iopen;
491424619caSeeh 	prom_cons_channel.cc_iclose = kd_rom_iclose;
492424619caSeeh 
493424619caSeeh 	/* Indicate that it is OK to use the PROM fbwrite */
494424619caSeeh 	kd_is_console = 1;
495424619caSeeh }
49601e2e698Seeh 
497805ffd07Seeh 
498805ffd07Seeh void kd_attach_input(struct cons_channel *);
499805ffd07Seeh void
kd_attach_input(struct cons_channel * cc)5001a509d61Scdi kd_attach_input(struct cons_channel *cc)
501805ffd07Seeh {
502805ffd07Seeh 	struct kd_softc *kd = &kd_softc;
503805ffd07Seeh 
504805ffd07Seeh 	kd->kd_in = cc;
505805ffd07Seeh 	cc->cc_upstream = kd_cons_input;
506805ffd07Seeh }
507805ffd07Seeh 
508805ffd07Seeh 
50901e2e698Seeh /* We never call this. */
51001e2e698Seeh static void
kdcnprobe(struct consdev * cn)511d50f0c62Scdi kdcnprobe(struct consdev *cn)
51201e2e698Seeh {
51301e2e698Seeh }
51401e2e698Seeh 
51501e2e698Seeh static void
kdcninit(struct consdev * cn)516d50f0c62Scdi kdcninit(struct consdev *cn)
51701e2e698Seeh {
518424619caSeeh #if 0
519424619caSeeh 	struct kbd_state *ks = kdcn_state;
52001e2e698Seeh 
52177a6b82bSgehenna 	cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
52201e2e698Seeh 	cn->cn_pri = CN_INTERNAL;
52301e2e698Seeh 
52401e2e698Seeh 	/* This prepares kbd_translate() */
52501e2e698Seeh 	ks->kbd_id = KBD_MIN_TYPE;
52601e2e698Seeh 	kbd_xlate_init(ks);
52701e2e698Seeh 
528f5839cdaSpk 	/* Set up initial PROM input channel for /dev/console */
5298a19236fStsutsui 	prom_cons_channel.cc_private = NULL;
530f5839cdaSpk 	prom_cons_channel.cc_iopen = kd_rom_iopen;
531f5839cdaSpk 	prom_cons_channel.cc_iclose = kd_rom_iclose;
532f5839cdaSpk 	cons_attach_input(&prom_cons_channel);
533f5839cdaSpk 
53401e2e698Seeh 	/* Indicate that it is OK to use the PROM fbwrite */
53501e2e698Seeh 	kd_is_console = 1;
536424619caSeeh #endif
53701e2e698Seeh }
53801e2e698Seeh 
53901e2e698Seeh static int
kdcngetc(dev_t dev)540d50f0c62Scdi kdcngetc(dev_t dev)
54101e2e698Seeh {
542424619caSeeh 	struct kbd_state *ks = kdcn_state;
54301e2e698Seeh 	int code, class, data, keysym;
544d50f0c62Scdi 	extern int prom_cngetc(dev_t);
54501e2e698Seeh 
546424619caSeeh 
547424619caSeeh 	if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev);
54801e2e698Seeh 	for (;;) {
54992ad9c40Seeh 		code = (*cn_hw->cn_getc)(dev);
55001e2e698Seeh 		keysym = kbd_code_to_keysym(ks, code);
55101e2e698Seeh 		class = KEYSYM_CLASS(keysym);
55201e2e698Seeh 
55301e2e698Seeh 		switch (class) {
55401e2e698Seeh 		case KEYSYM_ASCII:
55501e2e698Seeh 			goto out;
55601e2e698Seeh 
55701e2e698Seeh 		case KEYSYM_CLRMOD:
55801e2e698Seeh 		case KEYSYM_SETMOD:
55901e2e698Seeh 			data = (keysym & 0x1F);
56001e2e698Seeh 			/* Only allow ctrl or shift. */
56101e2e698Seeh 			if (data > KBMOD_SHIFT_R)
56201e2e698Seeh 				break;
56301e2e698Seeh 			data = 1 << data;
56401e2e698Seeh 			if (class == KEYSYM_SETMOD)
56501e2e698Seeh 				ks->kbd_modbits |= data;
56601e2e698Seeh 			else
56701e2e698Seeh 				ks->kbd_modbits &= ~data;
56801e2e698Seeh 			break;
56901e2e698Seeh 
57001e2e698Seeh 		case KEYSYM_ALL_UP:
57101e2e698Seeh 			/* No toggle keys here. */
57201e2e698Seeh 			ks->kbd_modbits = 0;
57301e2e698Seeh 			break;
57401e2e698Seeh 
57501e2e698Seeh 		default:	/* ignore all other keysyms */
57601e2e698Seeh 			break;
57701e2e698Seeh 		}
57801e2e698Seeh 	}
57901e2e698Seeh out:
58001e2e698Seeh 	return (keysym);
58101e2e698Seeh }
58201e2e698Seeh 
58301e2e698Seeh static void
kdcnputc(dev_t dev,int c)584d50f0c62Scdi kdcnputc(dev_t dev, int c)
58501e2e698Seeh {
58692ad9c40Seeh 	int s;
58701e2e698Seeh 	char c0 = (c & 0x7f);
58801e2e698Seeh 
58992ad9c40Seeh 	s = splhigh();
59005a2b230Spk 	prom_write(prom_stdout(), &c0, 1);
59192ad9c40Seeh 	splx(s);
59201e2e698Seeh }
59301e2e698Seeh 
59401e2e698Seeh static void
kdcnpollc(dev_t dev,int on)595d50f0c62Scdi kdcnpollc(dev_t dev, int on)
59601e2e698Seeh {
597424619caSeeh 	struct kbd_state *ks = kdcn_state;
59801e2e698Seeh 
59901e2e698Seeh 	if (on) {
60001e2e698Seeh 		/* Entering debugger. */
60101e2e698Seeh #if NFB > 0
60201e2e698Seeh 		fb_unblank();
60301e2e698Seeh #endif
60401e2e698Seeh 		/* Clear shift keys too. */
60501e2e698Seeh 		ks->kbd_modbits = 0;
60601e2e698Seeh 	} else {
60701e2e698Seeh 		/* Resuming kernel. */
60801e2e698Seeh 	}
60992ad9c40Seeh 	(*cn_hw->cn_pollc)(dev, on);
61001e2e698Seeh }
611