ofw_console.c revision 136680
178346Sbenno/*
278346Sbenno * Copyright (C) 2001 Benno Rice.
378346Sbenno * All rights reserved.
478346Sbenno *
578346Sbenno * Redistribution and use in source and binary forms, with or without
678346Sbenno * modification, are permitted provided that the following conditions
778346Sbenno * are met:
878346Sbenno * 1. Redistributions of source code must retain the above copyright
978346Sbenno *    notice, this list of conditions and the following disclaimer.
1078346Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1178346Sbenno *    notice, this list of conditions and the following disclaimer in the
1278346Sbenno *    documentation and/or other materials provided with the distribution.
1378346Sbenno *
1478346Sbenno * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
1578346Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1678346Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1778346Sbenno * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1878346Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1978346Sbenno * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2078346Sbenno * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2178346Sbenno * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2278346Sbenno * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2378346Sbenno * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2478346Sbenno */
2578346Sbenno
26113038Sobrien#include <sys/cdefs.h>
27113038Sobrien__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_console.c 136680 2004-10-18 21:51:27Z phk $");
2878346Sbenno
29110509Sharti#include "opt_comconsole.h"
30131016Sobrien#include "opt_ofw.h"
31110509Sharti
3278346Sbenno#include <sys/param.h>
33131916Smarcel#include <sys/kdb.h>
3478346Sbenno#include <sys/kernel.h>
3578346Sbenno#include <sys/systm.h>
3678346Sbenno#include <sys/types.h>
3778346Sbenno#include <sys/conf.h>
3878346Sbenno#include <sys/cons.h>
3978346Sbenno#include <sys/consio.h>
4078346Sbenno#include <sys/tty.h>
4178346Sbenno
4278346Sbenno#include <dev/ofw/openfirm.h>
4378346Sbenno
44110509Sharti#include <ddb/ddb.h>
45110509Sharti
46131016Sobrien#ifndef	OFWCONS_POLL_HZ
47131016Sobrien#define	OFWCONS_POLL_HZ	4	/* 50-100 works best on Ultra2 */
48131016Sobrien#endif
49131016Sobrien#define OFBURSTLEN	128	/* max number of bytes to write in one chunk */
5078346Sbenno
5178346Sbennostatic d_open_t		ofw_dev_open;
5278346Sbennostatic d_close_t	ofw_dev_close;
5378346Sbenno
5478346Sbennostatic struct cdevsw ofw_cdevsw = {
55126080Sphk	.d_version =	D_VERSION,
56111815Sphk	.d_open =	ofw_dev_open,
57111815Sphk	.d_close =	ofw_dev_close,
58111815Sphk	.d_name =	"ofw",
59126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
6078346Sbenno};
6178346Sbenno
6278346Sbennostatic struct tty		*ofw_tp = NULL;
6378346Sbennostatic int			polltime;
6478346Sbennostatic struct callout_handle	ofw_timeouthandle
6578346Sbenno    = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
6678346Sbenno
67131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
68110509Shartistatic int			alt_break_state;
69110509Sharti#endif
70110509Sharti
7178346Sbennostatic void	ofw_tty_start(struct tty *);
7278346Sbennostatic int	ofw_tty_param(struct tty *, struct termios *);
7378346Sbennostatic void	ofw_tty_stop(struct tty *, int);
7478346Sbennostatic void	ofw_timeout(void *);
7578346Sbenno
7678346Sbennostatic cn_probe_t	ofw_cons_probe;
7778346Sbennostatic cn_init_t	ofw_cons_init;
7878346Sbennostatic cn_getc_t	ofw_cons_getc;
7978346Sbennostatic cn_checkc_t 	ofw_cons_checkc;
8078346Sbennostatic cn_putc_t	ofw_cons_putc;
8178346Sbenno
8278346SbennoCONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
8378346Sbenno    ofw_cons_checkc, ofw_cons_putc, NULL);
8478346Sbenno
8589115Sjakestatic void
8689115Sjakecn_drvinit(void *unused)
8789115Sjake{
88107044Sjake	phandle_t options;
89107044Sjake	char output[32];
90130585Sphk	struct cdev *dev;
9189115Sjake
92120544Sjake	if (ofw_consdev.cn_pri != CN_DEAD &&
93120544Sjake	    ofw_consdev.cn_name[0] != '\0') {
94107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
95107044Sjake		    OF_getprop(options, "output-device", output,
96107044Sjake		    sizeof(output)) == -1)
97107044Sjake			return;
98136454Sphk		/*
99136454Sphk		 * XXX: This is a hack and it may result in two /dev/ttya
100136454Sphk		 * XXX: devices on platforms where the sab driver works.
101136454Sphk		 */
102120491Sphk		dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
103109921Sjake		    output);
104120491Sphk		make_dev_alias(dev, "ofwcons");
105107044Sjake	}
10689115Sjake}
10789115Sjake
108126076SphkSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL)
10989115Sjake
11078346Sbennostatic int	stdin;
11178346Sbennostatic int	stdout;
11278346Sbenno
11378346Sbennostatic int
114130585Sphkofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
11578346Sbenno{
11678346Sbenno	struct	tty *tp;
11778346Sbenno	int	unit;
11878346Sbenno	int	error, setuptimeout;
11978346Sbenno
12078346Sbenno	error = 0;
12178346Sbenno	setuptimeout = 0;
12278346Sbenno	unit = minor(dev);
12378346Sbenno
124136454Sphk	/*
125136454Sphk	 * XXX: BAD, should happen at attach time
126136454Sphk	 */
127136454Sphk	if (dev->si_tty == NULL) {
128136454Sphk		ofw_tp = ttyalloc();
129136454Sphk		dev->si_tty = ofw_tp;
130136454Sphk		ofw_tp->t_dev = dev;
131136454Sphk	}
132136454Sphk	tp = dev->si_tty;
13378346Sbenno
13478346Sbenno	tp->t_oproc = ofw_tty_start;
13578346Sbenno	tp->t_param = ofw_tty_param;
13678346Sbenno	tp->t_stop = ofw_tty_stop;
13778346Sbenno	tp->t_dev = dev;
13878346Sbenno
13978346Sbenno	if ((tp->t_state & TS_ISOPEN) == 0) {
14078346Sbenno		tp->t_state |= TS_CARR_ON;
141136680Sphk		ttyconsolemode(tp, 0);
14278346Sbenno		ttsetwater(tp);
14378346Sbenno
14478346Sbenno		setuptimeout = 1;
14593593Sjhb	} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
14678346Sbenno		return (EBUSY);
14778346Sbenno	}
14878346Sbenno
149130077Sphk	error = ttyld_open(tp, dev);
15078346Sbenno
15178346Sbenno	if (error == 0 && setuptimeout) {
152131016Sobrien		polltime = hz / OFWCONS_POLL_HZ;
15378346Sbenno		if (polltime < 1) {
15478346Sbenno			polltime = 1;
15578346Sbenno		}
15678346Sbenno
15778346Sbenno		ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
15878346Sbenno	}
15978346Sbenno
16078346Sbenno	return (error);
16178346Sbenno}
16278346Sbenno
16378346Sbennostatic int
164130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td)
16578346Sbenno{
16678346Sbenno	int	unit;
16778346Sbenno	struct	tty *tp;
16878346Sbenno
16978346Sbenno	unit = minor(dev);
170136454Sphk	tp = dev->si_tty;
17178346Sbenno
17278346Sbenno	if (unit != 0) {
17378346Sbenno		return (ENXIO);
17478346Sbenno	}
17578346Sbenno
176131016Sobrien	/* XXX Should be replaced with callout_stop(9) */
177131016Sobrien	untimeout(ofw_timeout, tp, ofw_timeouthandle);
178130077Sphk	ttyld_close(tp, flag);
179132226Sphk	tty_close(tp);
18078346Sbenno
18178346Sbenno	return (0);
18278346Sbenno}
18378346Sbenno
18478346Sbenno
18578346Sbennostatic int
18678346Sbennoofw_tty_param(struct tty *tp, struct termios *t)
18778346Sbenno{
18878346Sbenno
18978346Sbenno	return (0);
19078346Sbenno}
19178346Sbenno
19278346Sbennostatic void
19378346Sbennoofw_tty_start(struct tty *tp)
19478346Sbenno{
195131016Sobrien	struct clist *cl;
196131016Sobrien	int len;
197131016Sobrien	u_char buf[OFBURSTLEN];
19878346Sbenno
199131016Sobrien
200131016Sobrien	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
20178346Sbenno		return;
20278346Sbenno
20378346Sbenno	tp->t_state |= TS_BUSY;
204131016Sobrien	cl = &tp->t_outq;
205131016Sobrien	len = q_to_b(cl, buf, OFBURSTLEN);
206131016Sobrien	OF_write(stdout, buf, len);
20778346Sbenno	tp->t_state &= ~TS_BUSY;
20878346Sbenno
20978346Sbenno	ttwwakeup(tp);
21078346Sbenno}
21178346Sbenno
21278346Sbennostatic void
21378346Sbennoofw_tty_stop(struct tty *tp, int flag)
21478346Sbenno{
21578346Sbenno
21678346Sbenno	if (tp->t_state & TS_BUSY) {
21778346Sbenno		if ((tp->t_state & TS_TTSTOP) == 0) {
21878346Sbenno			tp->t_state |= TS_FLUSH;
21978346Sbenno		}
22078346Sbenno	}
22178346Sbenno}
22278346Sbenno
22378346Sbennostatic void
22478346Sbennoofw_timeout(void *v)
22578346Sbenno{
22678346Sbenno	struct	tty *tp;
22778346Sbenno	int 	c;
22878346Sbenno
22978346Sbenno	tp = (struct tty *)v;
23078346Sbenno
231111194Sphk	while ((c = ofw_cons_checkc(NULL)) != -1) {
23278346Sbenno		if (tp->t_state & TS_ISOPEN) {
233130077Sphk			ttyld_rint(tp, c);
23478346Sbenno		}
23578346Sbenno	}
23678346Sbenno
23778346Sbenno	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
23878346Sbenno}
23978346Sbenno
24078346Sbennostatic void
24178346Sbennoofw_cons_probe(struct consdev *cp)
24278346Sbenno{
24378346Sbenno	int chosen;
24478346Sbenno
24578346Sbenno	if ((chosen = OF_finddevice("/chosen")) == -1) {
24678346Sbenno		cp->cn_pri = CN_DEAD;
24778346Sbenno		return;
24878346Sbenno	}
24978346Sbenno
25078346Sbenno	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
25178346Sbenno		cp->cn_pri = CN_DEAD;
25278346Sbenno		return;
25378346Sbenno	}
25478346Sbenno
25578346Sbenno	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
25678346Sbenno		cp->cn_pri = CN_DEAD;
25778346Sbenno		return;
25878346Sbenno	}
25978346Sbenno
260120542Sjake	cp->cn_pri = CN_LOW;
26178346Sbenno}
26278346Sbenno
26378346Sbennostatic void
26478346Sbennoofw_cons_init(struct consdev *cp)
26578346Sbenno{
26678346Sbenno
267120467Sphk	/* XXX: This is the alias, but that should be good enough */
268120467Sphk	sprintf(cp->cn_name, "ofwcons");
269107044Sjake	cp->cn_tp = ofw_tp;
27078346Sbenno}
27178346Sbenno
27278346Sbennostatic int
273111194Sphkofw_cons_getc(struct consdev *cp)
27478346Sbenno{
27578346Sbenno	unsigned char ch;
27678346Sbenno	int l;
27778346Sbenno
27878346Sbenno	ch = '\0';
27978346Sbenno
28078346Sbenno	while ((l = OF_read(stdin, &ch, 1)) != 1) {
28178346Sbenno		if (l != -2 && l != 0) {
28278346Sbenno			return (-1);
28378346Sbenno		}
28478346Sbenno	}
28578346Sbenno
286131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
287131916Smarcel	if (kdb_alt_break(ch, &alt_break_state))
288131916Smarcel		kdb_enter("Break sequence on console");
289110509Sharti#endif
290110509Sharti
29178346Sbenno	return (ch);
29278346Sbenno}
29378346Sbenno
29478346Sbennostatic int
295111194Sphkofw_cons_checkc(struct consdev *cp)
29678346Sbenno{
29778346Sbenno	unsigned char ch;
29878346Sbenno
29988792Sjake	if (OF_read(stdin, &ch, 1) > 0) {
300131916Smarcel#if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
301131916Smarcel		if (kdb_alt_break(ch, &alt_break_state))
302131916Smarcel			kdb_enter("Break sequence on console");
303110509Sharti#endif
30478346Sbenno		return (ch);
30578346Sbenno	}
30678346Sbenno
30778346Sbenno	return (-1);
30878346Sbenno}
30978346Sbenno
31078346Sbennostatic void
311111194Sphkofw_cons_putc(struct consdev *cp, int c)
31278346Sbenno{
31378346Sbenno	char cbuf;
31478346Sbenno
31578346Sbenno	if (c == '\n') {
31678346Sbenno		cbuf = '\r';
31778346Sbenno		OF_write(stdout, &cbuf, 1);
31878346Sbenno	}
31978346Sbenno
32078346Sbenno	cbuf = c;
32178346Sbenno	OF_write(stdout, &cbuf, 1);
32278346Sbenno}
323