xref: /netbsd/sys/arch/sun2/dev/kd.c (revision 1a918832)
1*1a918832Sdholland /*	$NetBSD: kd.c,v 1.25 2014/07/25 08:10:35 dholland Exp $	*/
2ae1f6b9eSfredette 
3ae1f6b9eSfredette /*-
4ae1f6b9eSfredette  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5ae1f6b9eSfredette  * All rights reserved.
6ae1f6b9eSfredette  *
7ae1f6b9eSfredette  * This code is derived from software contributed to The NetBSD Foundation
8ae1f6b9eSfredette  * by Gordon W. Ross.
9ae1f6b9eSfredette  *
10ae1f6b9eSfredette  * Redistribution and use in source and binary forms, with or without
11ae1f6b9eSfredette  * modification, are permitted provided that the following conditions
12ae1f6b9eSfredette  * are met:
13ae1f6b9eSfredette  * 1. Redistributions of source code must retain the above copyright
14ae1f6b9eSfredette  *    notice, this list of conditions and the following disclaimer.
15ae1f6b9eSfredette  * 2. Redistributions in binary form must reproduce the above copyright
16ae1f6b9eSfredette  *    notice, this list of conditions and the following disclaimer in the
17ae1f6b9eSfredette  *    documentation and/or other materials provided with the distribution.
18ae1f6b9eSfredette  *
19ae1f6b9eSfredette  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20ae1f6b9eSfredette  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21ae1f6b9eSfredette  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ae1f6b9eSfredette  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23ae1f6b9eSfredette  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ae1f6b9eSfredette  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ae1f6b9eSfredette  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ae1f6b9eSfredette  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ae1f6b9eSfredette  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ae1f6b9eSfredette  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ae1f6b9eSfredette  * POSSIBILITY OF SUCH DAMAGE.
30ae1f6b9eSfredette  */
31ae1f6b9eSfredette 
32ae1f6b9eSfredette /*
33ae1f6b9eSfredette  * Keyboard/Display device.
34ae1f6b9eSfredette  *
35ae1f6b9eSfredette  * This driver exists simply to provide a tty device that
36ae1f6b9eSfredette  * the indirect console driver can point to.
37ae1f6b9eSfredette  * The kbd driver sends its input here.
38ae1f6b9eSfredette  * Output goes to the screen via PROM printf.
39ae1f6b9eSfredette  */
40ae1f6b9eSfredette 
41ed517291Slukem #include <sys/cdefs.h>
42*1a918832Sdholland __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.25 2014/07/25 08:10:35 dholland Exp $");
43ed517291Slukem 
44ae1f6b9eSfredette #include <sys/param.h>
45ae1f6b9eSfredette #include <sys/proc.h>
46ae1f6b9eSfredette #include <sys/systm.h>
47ae1f6b9eSfredette #include <sys/ioctl.h>
48ae1f6b9eSfredette #include <sys/tty.h>
49ae1f6b9eSfredette #include <sys/file.h>
50ae1f6b9eSfredette #include <sys/conf.h>
51ae1f6b9eSfredette #include <sys/device.h>
528ccb6c93Selad #include <sys/kauth.h>
53ae1f6b9eSfredette 
54ae1f6b9eSfredette #include <machine/promlib.h>
55ae1f6b9eSfredette #include <machine/eeprom.h>
56ae1f6b9eSfredette #include <machine/psl.h>
57ae1f6b9eSfredette #include <machine/cpu.h>
58ae1f6b9eSfredette #include <machine/kbd.h>
59ae1f6b9eSfredette #include <machine/autoconf.h>
60ae1f6b9eSfredette 
61ae1f6b9eSfredette #ifdef RASTERCONSOLE
62ae1f6b9eSfredette #include <dev/sun/fbio.h>
63ae1f6b9eSfredette #include <machine/fbvar.h>
64ae1f6b9eSfredette #endif
65ae1f6b9eSfredette 
66ae1f6b9eSfredette 
67ae1f6b9eSfredette #include <dev/cons.h>
68ae1f6b9eSfredette #include <dev/sun/event_var.h>
69ae1f6b9eSfredette #include <dev/sun/kbd_xlate.h>
70ae1f6b9eSfredette #include <dev/sun/kbdvar.h>
71ae1f6b9eSfredette #include <sun2/dev/cons.h>
72ae1f6b9eSfredette 
73ae1f6b9eSfredette struct	tty *fbconstty = 0;	/* tty structure for frame buffer console */
74ae1f6b9eSfredette 
75ae1f6b9eSfredette #define PUT_WSIZE	64
76ae1f6b9eSfredette 
77ae1f6b9eSfredette struct kd_softc {
78ae1f6b9eSfredette 	struct  tty *kd_tty;
79ae1f6b9eSfredette 	int rows, cols;
80ae1f6b9eSfredette 
81ae1f6b9eSfredette 	/* Console input hook */
82ae1f6b9eSfredette 	struct cons_channel *kd_in;
83ae1f6b9eSfredette };
84ae1f6b9eSfredette 
85ae1f6b9eSfredette /*
86ae1f6b9eSfredette  * There is no point in pretending there might be
87ae1f6b9eSfredette  * more than one keyboard/display device.
88ae1f6b9eSfredette  */
89ae1f6b9eSfredette static struct kd_softc kd_softc;
90ae1f6b9eSfredette static int kd_is_console;
91ae1f6b9eSfredette 
92ae1f6b9eSfredette static int kdparam(struct tty *, struct termios *);
93ae1f6b9eSfredette static void kdstart(struct tty *);
9410b1a7beSchs static void kd_init(struct kd_softc *);
9510b1a7beSchs static void kd_cons_input(int);
9610b1a7beSchs static int  kdcngetc(dev_t);
97028d83d7She static void kd_later(void*);
98ae1f6b9eSfredette 
9977a6b82bSgehenna dev_type_open(kdopen);
10077a6b82bSgehenna dev_type_close(kdclose);
10177a6b82bSgehenna dev_type_read(kdread);
10277a6b82bSgehenna dev_type_write(kdwrite);
10377a6b82bSgehenna dev_type_ioctl(kdioctl);
10477a6b82bSgehenna dev_type_tty(kdtty);
10577a6b82bSgehenna dev_type_poll(kdpoll);
10677a6b82bSgehenna 
10777a6b82bSgehenna const struct cdevsw kd_cdevsw = {
10876258fa0Sdholland 	.d_open = kdopen,
10976258fa0Sdholland 	.d_close = kdclose,
11076258fa0Sdholland 	.d_read = kdread,
11176258fa0Sdholland 	.d_write = kdwrite,
11276258fa0Sdholland 	.d_ioctl = kdioctl,
11376258fa0Sdholland 	.d_stop = nostop,
11476258fa0Sdholland 	.d_tty = kdtty,
11576258fa0Sdholland 	.d_poll = kdpoll,
11676258fa0Sdholland 	.d_mmap = nommap,
11776258fa0Sdholland 	.d_kqfilter = ttykqfilter,
118*1a918832Sdholland 	.d_discard = nodiscard,
11976258fa0Sdholland 	.d_flag = D_TTY
12077a6b82bSgehenna };
12177a6b82bSgehenna 
122ae1f6b9eSfredette /*
123ae1f6b9eSfredette  * This is called by kbd_attach()
124ae1f6b9eSfredette  * XXX - Make this a proper child of kbd?
125ae1f6b9eSfredette  */
126ae1f6b9eSfredette void
kd_init(struct kd_softc * kd)12710b1a7beSchs kd_init(struct kd_softc *kd)
128ae1f6b9eSfredette {
129ae1f6b9eSfredette 	struct tty *tp;
130ae1f6b9eSfredette #ifdef	PROM_OLDMON
131ae1f6b9eSfredette 	struct eeprom *ep;
132ae1f6b9eSfredette #endif
133ae1f6b9eSfredette #ifdef	notyet /* PROM_OBP_V2 */
134ae1f6b9eSfredette 	int i;
135ae1f6b9eSfredette 	char *prop;
136ae1f6b9eSfredette #endif
137ae1f6b9eSfredette 
138ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
139ae1f6b9eSfredette 
14080f6fc52Srmind 	tp = tty_alloc();
141d238692cSjoerg 	callout_setfunc(&tp->t_rstrt_ch, kd_later, tp);
142ae1f6b9eSfredette 	tp->t_oproc = kdstart;
143ae1f6b9eSfredette 	tp->t_param = kdparam;
14477a6b82bSgehenna 	tp->t_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
145ae1f6b9eSfredette 
146ae1f6b9eSfredette 	tty_attach(tp);
147ae1f6b9eSfredette 	kd->kd_tty = tp;
148ae1f6b9eSfredette 
149ae1f6b9eSfredette 	/*
150ae1f6b9eSfredette 	 * get the console struct winsize.
151ae1f6b9eSfredette 	 */
152ae1f6b9eSfredette 	if (kd_is_console) {
153ae1f6b9eSfredette 		fbconstty = tp;
154ae1f6b9eSfredette #ifdef RASTERCONSOLE
155ae1f6b9eSfredette 		kd->rows = fbrcons_rows();
156ae1f6b9eSfredette 		kd->cols = fbrcons_cols();
157ae1f6b9eSfredette 		rcons_ttyinit(tp);
158ae1f6b9eSfredette #endif
159ae1f6b9eSfredette 	}
160ae1f6b9eSfredette 
161ae1f6b9eSfredette 	/* else, consult the PROM */
162ae1f6b9eSfredette 	switch (prom_version()) {
163ae1f6b9eSfredette #ifdef	PROM_OLDMON
164ae1f6b9eSfredette 	case PROM_OLDMON:
165ae1f6b9eSfredette 		if ((ep = (struct eeprom *)eeprom_va) == NULL)
166ae1f6b9eSfredette 			break;
167ae1f6b9eSfredette 		if (kd->rows == 0)
168ae1f6b9eSfredette 			kd->rows = (u_short)ep->eeTtyRows;
169ae1f6b9eSfredette 		if (kd->cols == 0)
170ae1f6b9eSfredette 			kd->cols = (u_short)ep->eeTtyCols;
171ae1f6b9eSfredette 		break;
172ae1f6b9eSfredette #endif	/* PROM_OLDMON */
173ae1f6b9eSfredette #ifdef	notyet /* PROM_OBP_V2 */
174ae1f6b9eSfredette 	case PROM_OBP_V0:
175ae1f6b9eSfredette 	case PROM_OBP_V2:
176ae1f6b9eSfredette 	case PROM_OBP_V3:
177ae1f6b9eSfredette 	case PROM_OPENFIRM:
178ae1f6b9eSfredette 
179ae1f6b9eSfredette 		if (kd->rows == 0 &&
180ae1f6b9eSfredette 		    (prop = PROM_getpropstring(optionsnode, "screen-#rows"))) {
181ae1f6b9eSfredette 			i = 0;
182ae1f6b9eSfredette 			while (*prop != '\0')
183ae1f6b9eSfredette 				i = i * 10 + *prop++ - '0';
184ae1f6b9eSfredette 			kd->rows = (unsigned short)i;
185ae1f6b9eSfredette 		}
186ae1f6b9eSfredette 		if (kd->cols == 0 &&
187ae1f6b9eSfredette 		    (prop = PROM_getpropstring(optionsnode, "screen-#columns"))) {
188ae1f6b9eSfredette 			i = 0;
189ae1f6b9eSfredette 			while (*prop != '\0')
190ae1f6b9eSfredette 				i = i * 10 + *prop++ - '0';
191ae1f6b9eSfredette 			kd->cols = (unsigned short)i;
192ae1f6b9eSfredette 		}
193ae1f6b9eSfredette 		break;
194ae1f6b9eSfredette #endif	/* PROM_OBP_V2 */
195ae1f6b9eSfredette 	}
196ae1f6b9eSfredette 	return;
197ae1f6b9eSfredette }
198ae1f6b9eSfredette 
199ae1f6b9eSfredette struct tty *
kdtty(dev_t dev)20010b1a7beSchs kdtty(dev_t dev)
201ae1f6b9eSfredette {
202ae1f6b9eSfredette 	struct kd_softc *kd;
203ae1f6b9eSfredette 
204ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
205ae1f6b9eSfredette 	return (kd->kd_tty);
206ae1f6b9eSfredette }
207ae1f6b9eSfredette 
208ae1f6b9eSfredette int
kdopen(dev_t dev,int flag,int mode,struct lwp * l)20995e1ffb1Schristos kdopen(dev_t dev, int flag, int mode, struct lwp *l)
210ae1f6b9eSfredette {
211ae1f6b9eSfredette 	struct kd_softc *kd;
212ae1f6b9eSfredette 	int error, s, unit;
213ae1f6b9eSfredette 	struct tty *tp;
214ae1f6b9eSfredette static	int firstopen = 1;
215ae1f6b9eSfredette 
216ae1f6b9eSfredette 	unit = minor(dev);
217ae1f6b9eSfredette 	if (unit != 0)
218ae1f6b9eSfredette 		return ENXIO;
219ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
220ae1f6b9eSfredette 
221ae1f6b9eSfredette 	if (firstopen) {
222ae1f6b9eSfredette 		kd_init(kd);
223ae1f6b9eSfredette 		firstopen = 0;
224ae1f6b9eSfredette 	}
225ae1f6b9eSfredette 	tp = kd->kd_tty;
226ae1f6b9eSfredette 
227ae1f6b9eSfredette 	/* It's simpler to do this up here. */
228e8373398Selad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
229ae1f6b9eSfredette 		return (EBUSY);
230ae1f6b9eSfredette 
231ae1f6b9eSfredette 	s = spltty();
232ae1f6b9eSfredette 
233ae1f6b9eSfredette 	if ((tp->t_state & TS_ISOPEN) == 0) {
234ae1f6b9eSfredette 		/* First open. */
235ae1f6b9eSfredette 
236ae1f6b9eSfredette 		/* Notify the input device that serves us */
237ae1f6b9eSfredette 		struct cons_channel *cc = kd->kd_in;
238ae1f6b9eSfredette 		if (cc != NULL &&
239ae1f6b9eSfredette 		    (error = (*cc->cc_iopen)(cc)) != 0) {
240ae1f6b9eSfredette 			splx(s);
241ae1f6b9eSfredette 			return (error);
242ae1f6b9eSfredette 		}
243ae1f6b9eSfredette 
244ae1f6b9eSfredette 		ttychars(tp);
245ae1f6b9eSfredette 		tp->t_iflag = TTYDEF_IFLAG;
246ae1f6b9eSfredette 		tp->t_oflag = TTYDEF_OFLAG;
247ae1f6b9eSfredette 		tp->t_cflag = TTYDEF_CFLAG;
248ae1f6b9eSfredette 		tp->t_lflag = TTYDEF_LFLAG;
249ae1f6b9eSfredette 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
250ae1f6b9eSfredette 		(void) kdparam(tp, &tp->t_termios);
251ae1f6b9eSfredette 		ttsetwater(tp);
252ae1f6b9eSfredette 		tp->t_winsize.ws_row = kd->rows;
253ae1f6b9eSfredette 		tp->t_winsize.ws_col = kd->cols;
254ae1f6b9eSfredette 		/* Flush pending input?  Clear translator? */
255ae1f6b9eSfredette 		/* This (pseudo)device always has SOFTCAR */
256ae1f6b9eSfredette 		tp->t_state |= TS_CARR_ON;
257ae1f6b9eSfredette 	}
258ae1f6b9eSfredette 
259ae1f6b9eSfredette 	splx(s);
260ae1f6b9eSfredette 
261ae1f6b9eSfredette 	return ((*tp->t_linesw->l_open)(dev, tp));
262ae1f6b9eSfredette }
263ae1f6b9eSfredette 
264ae1f6b9eSfredette int
kdclose(dev_t dev,int flag,int mode,struct lwp * l)26595e1ffb1Schristos kdclose(dev_t dev, int flag, int mode, struct lwp *l)
266ae1f6b9eSfredette {
267ae1f6b9eSfredette 	struct kd_softc *kd;
268ae1f6b9eSfredette 	struct tty *tp;
269ae1f6b9eSfredette 	struct cons_channel *cc;
270ae1f6b9eSfredette 
271ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
272ae1f6b9eSfredette 	tp = kd->kd_tty;
273ae1f6b9eSfredette 
274ae1f6b9eSfredette 	/* XXX This is for cons.c. */
275ae1f6b9eSfredette 	if ((tp->t_state & TS_ISOPEN) == 0)
276ae1f6b9eSfredette 		return 0;
277ae1f6b9eSfredette 
278ae1f6b9eSfredette 	(*tp->t_linesw->l_close)(tp, flag);
279ae1f6b9eSfredette 	ttyclose(tp);
280ae1f6b9eSfredette 
281ae1f6b9eSfredette 	if ((cc = kd->kd_in) != NULL)
28257801e8fSmartin 		(void)(*cc->cc_iclose)(cc);
283ae1f6b9eSfredette 
284ae1f6b9eSfredette 	return (0);
285ae1f6b9eSfredette }
286ae1f6b9eSfredette 
287ae1f6b9eSfredette int
kdread(dev_t dev,struct uio * uio,int flag)28810b1a7beSchs kdread(dev_t dev, struct uio *uio, int flag)
289ae1f6b9eSfredette {
290ae1f6b9eSfredette 	struct kd_softc *kd;
291ae1f6b9eSfredette 	struct tty *tp;
292ae1f6b9eSfredette 
293ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
294ae1f6b9eSfredette 	tp = kd->kd_tty;
295ae1f6b9eSfredette 
296ae1f6b9eSfredette 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
297ae1f6b9eSfredette }
298ae1f6b9eSfredette 
299ae1f6b9eSfredette int
kdwrite(dev_t dev,struct uio * uio,int flag)30010b1a7beSchs kdwrite(dev_t dev, struct uio *uio, int flag)
301ae1f6b9eSfredette {
302ae1f6b9eSfredette 	struct kd_softc *kd;
303ae1f6b9eSfredette 	struct tty *tp;
304ae1f6b9eSfredette 
305ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
306ae1f6b9eSfredette 	tp = kd->kd_tty;
307ae1f6b9eSfredette 
308ae1f6b9eSfredette 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
309ae1f6b9eSfredette }
310ae1f6b9eSfredette 
311ae1f6b9eSfredette int
kdpoll(dev_t dev,int events,struct lwp * l)31295e1ffb1Schristos kdpoll(dev_t dev, int events, struct lwp *l)
313ae1f6b9eSfredette {
314ae1f6b9eSfredette 	struct kd_softc *kd;
315ae1f6b9eSfredette 	struct tty *tp;
316ae1f6b9eSfredette 
317ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
318ae1f6b9eSfredette 	tp = kd->kd_tty;
319ae1f6b9eSfredette 
32095e1ffb1Schristos 	return ((*tp->t_linesw->l_poll)(tp, events, l));
321ae1f6b9eSfredette }
322ae1f6b9eSfredette 
323ae1f6b9eSfredette int
kdioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)32453524e44Schristos kdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
325ae1f6b9eSfredette {
326ae1f6b9eSfredette 	struct kd_softc *kd;
327ae1f6b9eSfredette 	struct tty *tp;
328ae1f6b9eSfredette 	int error;
329ae1f6b9eSfredette 
330ae1f6b9eSfredette 	kd = &kd_softc; 	/* XXX */
331ae1f6b9eSfredette 	tp = kd->kd_tty;
332ae1f6b9eSfredette 
33395e1ffb1Schristos 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
334ae1f6b9eSfredette 	if (error != EPASSTHROUGH)
335ae1f6b9eSfredette 		return error;
336ae1f6b9eSfredette 
33795e1ffb1Schristos 	error = ttioctl(tp, cmd, data, flag, l);
338ae1f6b9eSfredette 	if (error != EPASSTHROUGH)
339ae1f6b9eSfredette 		return error;
340ae1f6b9eSfredette 
341ae1f6b9eSfredette 	/* Handle any ioctl commands specific to kbd/display. */
342ae1f6b9eSfredette 	/* XXX - Send KB* ioctls to kbd module? */
343ae1f6b9eSfredette 	/* XXX - Send FB* ioctls to fb module?  */
344ae1f6b9eSfredette 
345ae1f6b9eSfredette 	return EPASSTHROUGH;
346ae1f6b9eSfredette }
347ae1f6b9eSfredette 
348ae1f6b9eSfredette static int
kdparam(struct tty * tp,struct termios * t)34910b1a7beSchs kdparam(struct tty *tp, struct termios *t)
350ae1f6b9eSfredette {
351ae1f6b9eSfredette 	/* XXX - These are ignored... */
352ae1f6b9eSfredette 	tp->t_ispeed = t->c_ispeed;
353ae1f6b9eSfredette 	tp->t_ospeed = t->c_ospeed;
354ae1f6b9eSfredette 	tp->t_cflag = t->c_cflag;
355ae1f6b9eSfredette 	return 0;
356ae1f6b9eSfredette }
357ae1f6b9eSfredette 
358ae1f6b9eSfredette 
359ae1f6b9eSfredette static void kd_putfb(struct tty *);
360ae1f6b9eSfredette 
361ae1f6b9eSfredette static void
kdstart(struct tty * tp)36210b1a7beSchs kdstart(struct tty *tp)
363ae1f6b9eSfredette {
364ae1f6b9eSfredette 	struct clist *cl;
36536bb413eSad 	int s1, s2;
366ae1f6b9eSfredette 
36736bb413eSad 	s1 = splsoftclock();
36836bb413eSad 	s2 = spltty();
369ae1f6b9eSfredette 	if (tp->t_state & (TS_BUSY|TS_TTSTOP|TS_TIMEOUT))
370ae1f6b9eSfredette 		goto out;
371ae1f6b9eSfredette 
372ae1f6b9eSfredette 	cl = &tp->t_outq;
373dc26833bSad 	if (ttypull(tp)) {
374ae1f6b9eSfredette 		if (kd_is_console) {
375ae1f6b9eSfredette 			tp->t_state |= TS_BUSY;
37636bb413eSad 			if (is_spl0(s1)) {
377ae1f6b9eSfredette 				/* called at level zero - update screen now. */
37836bb413eSad 				splx(s2);
379ae1f6b9eSfredette 				kd_putfb(tp);
38036bb413eSad 				s2 = spltty();
381ae1f6b9eSfredette 				tp->t_state &= ~TS_BUSY;
382ae1f6b9eSfredette 			} else {
383ae1f6b9eSfredette 				/* called at interrupt level - do it later */
384d238692cSjoerg 				callout_schedule(&tp->t_rstrt_ch, 0);
385ae1f6b9eSfredette 			}
386ae1f6b9eSfredette 		} else {
387ae1f6b9eSfredette 			/*
388ae1f6b9eSfredette 			 * This driver uses the PROM for writing the screen,
389ae1f6b9eSfredette 			 * and that only works if this is the console device.
390ae1f6b9eSfredette 			 * If this is not the console, just flush the output.
391ae1f6b9eSfredette 			 * Sorry.  (In that case, use xdm instead of getty.)
392ae1f6b9eSfredette 			 */
393ae1f6b9eSfredette 			ndflush(cl, cl->c_cc);
394ae1f6b9eSfredette 		}
395ae1f6b9eSfredette 	}
396ae1f6b9eSfredette out:
39736bb413eSad 	splx(s2);
39836bb413eSad 	splx(s1);
399ae1f6b9eSfredette }
400ae1f6b9eSfredette 
401ae1f6b9eSfredette /*
402ae1f6b9eSfredette  * Timeout function to do delayed writes to the screen.
403ae1f6b9eSfredette  * Called at splsoftclock when requested by kdstart.
404ae1f6b9eSfredette  */
405ae1f6b9eSfredette static void
kd_later(void * tpaddr)40610b1a7beSchs kd_later(void *tpaddr)
407ae1f6b9eSfredette {
408ae1f6b9eSfredette 	struct tty *tp = tpaddr;
40910b1a7beSchs 	int s;
410ae1f6b9eSfredette 
411ae1f6b9eSfredette 	kd_putfb(tp);
412ae1f6b9eSfredette 
413ae1f6b9eSfredette 	s = spltty();
414ae1f6b9eSfredette 	tp->t_state &= ~TS_BUSY;
415ae1f6b9eSfredette 	(*tp->t_linesw->l_start)(tp);
416ae1f6b9eSfredette 	splx(s);
417ae1f6b9eSfredette }
418ae1f6b9eSfredette 
419ae1f6b9eSfredette /*
420ae1f6b9eSfredette  * Put text on the screen using the PROM monitor.
421ae1f6b9eSfredette  * This can take a while, so to avoid missing
422ae1f6b9eSfredette  * interrupts, this is called at splsoftclock.
423ae1f6b9eSfredette  */
424ae1f6b9eSfredette static void
kd_putfb(struct tty * tp)42510b1a7beSchs kd_putfb(struct tty *tp)
426ae1f6b9eSfredette {
427ae1f6b9eSfredette 	char buf[PUT_WSIZE];
428ae1f6b9eSfredette 	struct clist *cl = &tp->t_outq;
429ae1f6b9eSfredette 	char *p, *end;
430ae1f6b9eSfredette 	int len;
431ae1f6b9eSfredette 
432ae1f6b9eSfredette 	while ((len = q_to_b(cl, buf, PUT_WSIZE-1)) > 0) {
433ae1f6b9eSfredette 		/* PROM will barf if high bits are set. */
434ae1f6b9eSfredette 		p = buf;
435ae1f6b9eSfredette 		end = buf + len;
436ae1f6b9eSfredette 		while (p < end)
437ae1f6b9eSfredette 			*p++ &= 0x7f;
438ae1f6b9eSfredette 		/* Now let the PROM print it. */
439ae1f6b9eSfredette 		prom_putstr(buf, len);
440ae1f6b9eSfredette 	}
441ae1f6b9eSfredette }
442ae1f6b9eSfredette 
443ae1f6b9eSfredette /*
444ae1f6b9eSfredette  * Default PROM-based console input stream
445ae1f6b9eSfredette  */
44610b1a7beSchs static int kd_rom_iopen(struct cons_channel *);
44710b1a7beSchs static int kd_rom_iclose(struct cons_channel *);
448ae1f6b9eSfredette 
449ae1f6b9eSfredette static struct cons_channel prom_cons_channel;
450ae1f6b9eSfredette 
451ae1f6b9eSfredette int
kd_rom_iopen(struct cons_channel * cc)45210b1a7beSchs kd_rom_iopen(struct cons_channel *cc)
453ae1f6b9eSfredette {
454ae1f6b9eSfredette 	return (0);
455ae1f6b9eSfredette }
456ae1f6b9eSfredette 
457ae1f6b9eSfredette int
kd_rom_iclose(struct cons_channel * cc)45810b1a7beSchs kd_rom_iclose(struct cons_channel *cc)
459ae1f6b9eSfredette {
460ae1f6b9eSfredette 	return (0);
461ae1f6b9eSfredette }
462ae1f6b9eSfredette 
463ae1f6b9eSfredette /*
464ae1f6b9eSfredette  * Our "interrupt" routine for input. This is called by
465ae1f6b9eSfredette  * the keyboard driver (dev/sun/kbd.c) at spltty.
466ae1f6b9eSfredette  */
467ae1f6b9eSfredette void
kd_cons_input(int c)46810b1a7beSchs kd_cons_input(int c)
469ae1f6b9eSfredette {
470ae1f6b9eSfredette 	struct kd_softc *kd = &kd_softc;
471ae1f6b9eSfredette 	struct tty *tp;
472ae1f6b9eSfredette 
473ae1f6b9eSfredette 	/* XXX: Make sure the device is open. */
474ae1f6b9eSfredette 	tp = kd->kd_tty;
475ae1f6b9eSfredette 	if (tp == NULL)
476ae1f6b9eSfredette 		return;
477ae1f6b9eSfredette 	if ((tp->t_state & TS_ISOPEN) == 0)
478ae1f6b9eSfredette 		return;
479ae1f6b9eSfredette 
480ae1f6b9eSfredette 	(*tp->t_linesw->l_rint)(c, tp);
481ae1f6b9eSfredette }
482ae1f6b9eSfredette 
483ae1f6b9eSfredette 
484ae1f6b9eSfredette /****************************************************************
485ae1f6b9eSfredette  * kd console support
486ae1f6b9eSfredette  ****************************************************************/
487ae1f6b9eSfredette 
488ae1f6b9eSfredette /* The debugger gets its own key translation state. */
489ae1f6b9eSfredette static struct kbd_state *kdcn_state;
490ae1f6b9eSfredette 
49110b1a7beSchs static void kdcnprobe(struct consdev *);
49210b1a7beSchs static void kdcninit(struct consdev *);
49310b1a7beSchs static void kdcnputc(dev_t, int);
49410b1a7beSchs static void kdcnpollc(dev_t, int);
495ae1f6b9eSfredette 
496ae1f6b9eSfredette /* The keyboard driver uses cn_hw to access the real console driver */
497ae1f6b9eSfredette extern struct consdev consdev_prom;
498ae1f6b9eSfredette struct consdev consdev_kd = {
499ae1f6b9eSfredette 	kdcnprobe,
500ae1f6b9eSfredette 	kdcninit,
501ae1f6b9eSfredette 	kdcngetc,
502ae1f6b9eSfredette 	kdcnputc,
503ae1f6b9eSfredette 	kdcnpollc,
504ae1f6b9eSfredette 	NULL,
505ae1f6b9eSfredette };
506ae1f6b9eSfredette struct consdev *cn_hw = &consdev_kd;
507ae1f6b9eSfredette 
508ae1f6b9eSfredette void
cons_attach_input(struct cons_channel * cc,struct consdev * cn)50910b1a7beSchs cons_attach_input(struct cons_channel *cc, struct consdev *cn)
510ae1f6b9eSfredette {
511ae1f6b9eSfredette 	struct kd_softc *kd = &kd_softc;
51202cb47caStsutsui 	struct kbd_softc *kds = cc->cc_private;
513ae1f6b9eSfredette 	struct kbd_state *ks;
514ae1f6b9eSfredette 
515ae1f6b9eSfredette 	/* Share the keyboard state */
516ae1f6b9eSfredette 	kdcn_state = ks = &kds->k_state;
517ae1f6b9eSfredette 
518ae1f6b9eSfredette 	kd->kd_in = cc;
519ae1f6b9eSfredette 	cc->cc_upstream = kd_cons_input;
520ae1f6b9eSfredette 
521ae1f6b9eSfredette 	/* Attach lower level. */
522ae1f6b9eSfredette 	cn_hw->cn_dev = cn->cn_dev;
523ae1f6b9eSfredette 	cn_hw->cn_pollc = cn->cn_pollc;
524ae1f6b9eSfredette 	cn_hw->cn_getc = cn->cn_getc;
525ae1f6b9eSfredette 
526ae1f6b9eSfredette 	/* Attach us as console. */
52777a6b82bSgehenna 	cn_tab->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
528ae1f6b9eSfredette 	cn_tab->cn_probe = kdcnprobe;
529ae1f6b9eSfredette 	cn_tab->cn_init = kdcninit;
530ae1f6b9eSfredette 	cn_tab->cn_getc = kdcngetc;
531ae1f6b9eSfredette 	cn_tab->cn_pollc = kdcnpollc;
532ae1f6b9eSfredette 	cn_tab->cn_pri = CN_INTERNAL;
533ae1f6b9eSfredette 
534ae1f6b9eSfredette 	/* Set up initial PROM input channel for /dev/console */
53502cb47caStsutsui 	prom_cons_channel.cc_private = NULL;
536ae1f6b9eSfredette 	prom_cons_channel.cc_iopen = kd_rom_iopen;
537ae1f6b9eSfredette 	prom_cons_channel.cc_iclose = kd_rom_iclose;
538ae1f6b9eSfredette 
539ae1f6b9eSfredette 	/* Indicate that it is OK to use the PROM fbwrite */
540ae1f6b9eSfredette 	kd_is_console = 1;
541ae1f6b9eSfredette }
542ae1f6b9eSfredette 
543ae1f6b9eSfredette 
544ae1f6b9eSfredette void kd_attach_input(struct cons_channel *);
545ae1f6b9eSfredette void
kd_attach_input(struct cons_channel * cc)54610b1a7beSchs kd_attach_input(struct cons_channel *cc)
547ae1f6b9eSfredette {
548ae1f6b9eSfredette 	struct kd_softc *kd = &kd_softc;
549ae1f6b9eSfredette 
550ae1f6b9eSfredette 	kd->kd_in = cc;
551ae1f6b9eSfredette 	cc->cc_upstream = kd_cons_input;
552ae1f6b9eSfredette }
553ae1f6b9eSfredette 
554ae1f6b9eSfredette 
555ae1f6b9eSfredette /* We never call this. */
556ae1f6b9eSfredette static void
kdcnprobe(struct consdev * cn)55710b1a7beSchs kdcnprobe(struct consdev *cn)
558ae1f6b9eSfredette {
559ae1f6b9eSfredette }
560ae1f6b9eSfredette 
561ae1f6b9eSfredette static void
kdcninit(struct consdev * cn)56210b1a7beSchs kdcninit(struct consdev *cn)
563ae1f6b9eSfredette {
564ae1f6b9eSfredette #if 0
565ae1f6b9eSfredette 	struct kbd_state *ks = kdcn_state;
566ae1f6b9eSfredette 
56777a6b82bSgehenna 	cn->cn_dev = makedev(cdevsw_lookup_major(&kd_cdevsw), 0);
568ae1f6b9eSfredette 	cn->cn_pri = CN_INTERNAL;
569ae1f6b9eSfredette 
570ae1f6b9eSfredette 	/* This prepares kbd_translate() */
571ae1f6b9eSfredette 	ks->kbd_id = KBD_MIN_TYPE;
572ae1f6b9eSfredette 	kbd_xlate_init(ks);
573ae1f6b9eSfredette 
574ae1f6b9eSfredette 	/* Set up initial PROM input channel for /dev/console */
57502cb47caStsutsui 	prom_cons_channel.cc_private = NULL;
576ae1f6b9eSfredette 	prom_cons_channel.cc_iopen = kd_rom_iopen;
577ae1f6b9eSfredette 	prom_cons_channel.cc_iclose = kd_rom_iclose;
578ae1f6b9eSfredette 	cons_attach_input(&prom_cons_channel);
579ae1f6b9eSfredette 
580ae1f6b9eSfredette 	/* Indicate that it is OK to use the PROM fbwrite */
581ae1f6b9eSfredette 	kd_is_console = 1;
582ae1f6b9eSfredette #endif
583ae1f6b9eSfredette }
584ae1f6b9eSfredette 
585ae1f6b9eSfredette static int
kdcngetc(dev_t dev)58610b1a7beSchs kdcngetc(dev_t dev)
587ae1f6b9eSfredette {
588ae1f6b9eSfredette 	struct kbd_state *ks = kdcn_state;
589ae1f6b9eSfredette 	int code, class, data, keysym;
59010b1a7beSchs 	extern int prom_cngetc(dev_t);
591ae1f6b9eSfredette 
592ae1f6b9eSfredette 
593ae1f6b9eSfredette 	if (cn_hw->cn_getc == prom_cngetc) return (*cn_hw->cn_getc)(dev);
594ae1f6b9eSfredette 	for (;;) {
595ae1f6b9eSfredette 		code = (*cn_hw->cn_getc)(dev);
596ae1f6b9eSfredette 		keysym = kbd_code_to_keysym(ks, code);
597ae1f6b9eSfredette 		class = KEYSYM_CLASS(keysym);
598ae1f6b9eSfredette 
599ae1f6b9eSfredette 		switch (class) {
600ae1f6b9eSfredette 		case KEYSYM_ASCII:
601ae1f6b9eSfredette 			goto out;
602ae1f6b9eSfredette 
603ae1f6b9eSfredette 		case KEYSYM_CLRMOD:
604ae1f6b9eSfredette 		case KEYSYM_SETMOD:
605ae1f6b9eSfredette 			data = (keysym & 0x1F);
606ae1f6b9eSfredette 			/* Only allow ctrl or shift. */
607ae1f6b9eSfredette 			if (data > KBMOD_SHIFT_R)
608ae1f6b9eSfredette 				break;
609ae1f6b9eSfredette 			data = 1 << data;
610ae1f6b9eSfredette 			if (class == KEYSYM_SETMOD)
611ae1f6b9eSfredette 				ks->kbd_modbits |= data;
612ae1f6b9eSfredette 			else
613ae1f6b9eSfredette 				ks->kbd_modbits &= ~data;
614ae1f6b9eSfredette 			break;
615ae1f6b9eSfredette 
616ae1f6b9eSfredette 		case KEYSYM_ALL_UP:
617ae1f6b9eSfredette 			/* No toggle keys here. */
618ae1f6b9eSfredette 			ks->kbd_modbits = 0;
619ae1f6b9eSfredette 			break;
620ae1f6b9eSfredette 
621ae1f6b9eSfredette 		default:	/* ignore all other keysyms */
622ae1f6b9eSfredette 			break;
623ae1f6b9eSfredette 		}
624ae1f6b9eSfredette 	}
625ae1f6b9eSfredette out:
626ae1f6b9eSfredette 	return (keysym);
627ae1f6b9eSfredette }
628ae1f6b9eSfredette 
629ae1f6b9eSfredette static void
kdcnputc(dev_t dev,int c)63010b1a7beSchs kdcnputc(dev_t dev, int c)
631ae1f6b9eSfredette {
632ae1f6b9eSfredette 	int s;
633ae1f6b9eSfredette 
634ae1f6b9eSfredette 	s = splhigh();
635ae1f6b9eSfredette 	prom_putchar(c);
636ae1f6b9eSfredette 	splx(s);
637ae1f6b9eSfredette }
638ae1f6b9eSfredette 
639ae1f6b9eSfredette static void
kdcnpollc(dev_t dev,int on)64010b1a7beSchs kdcnpollc(dev_t dev, int on)
641ae1f6b9eSfredette {
642ae1f6b9eSfredette 	struct kbd_state *ks = kdcn_state;
643ae1f6b9eSfredette 
644ae1f6b9eSfredette 	if (on) {
645ae1f6b9eSfredette 		/* Entering debugger. */
646ae1f6b9eSfredette #if NFB > 0
647ae1f6b9eSfredette 		fb_unblank();
648ae1f6b9eSfredette #endif
649ae1f6b9eSfredette 		/* Clear shift keys too. */
650ae1f6b9eSfredette 		ks->kbd_modbits = 0;
651ae1f6b9eSfredette 	} else {
652ae1f6b9eSfredette 		/* Resuming kernel. */
653ae1f6b9eSfredette 	}
654ae1f6b9eSfredette 	(*cn_hw->cn_pollc)(dev, on);
655ae1f6b9eSfredette }
656