ofw_console.c revision 130585
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 130585 2004-06-16 09:47:26Z phk $");
2878346Sbenno
29110509Sharti#include "opt_ddb.h"
30110509Sharti#include "opt_comconsole.h"
31110509Sharti
3278346Sbenno#include <sys/param.h>
3378346Sbenno#include <sys/kernel.h>
3478346Sbenno#include <sys/systm.h>
3578346Sbenno#include <sys/types.h>
3678346Sbenno#include <sys/conf.h>
3778346Sbenno#include <sys/cons.h>
3878346Sbenno#include <sys/consio.h>
3978346Sbenno#include <sys/tty.h>
4078346Sbenno
4178346Sbenno#include <dev/ofw/openfirm.h>
4278346Sbenno
43110509Sharti#include <ddb/ddb.h>
44110509Sharti
4588792Sjake#define	OFW_POLL_HZ	4
4678346Sbenno
4778346Sbennostatic d_open_t		ofw_dev_open;
4878346Sbennostatic d_close_t	ofw_dev_close;
4978346Sbenno
5078346Sbennostatic struct cdevsw ofw_cdevsw = {
51126080Sphk	.d_version =	D_VERSION,
52111815Sphk	.d_open =	ofw_dev_open,
53111815Sphk	.d_close =	ofw_dev_close,
54111815Sphk	.d_name =	"ofw",
55126080Sphk	.d_flags =	D_TTY | D_NEEDGIANT,
5678346Sbenno};
5778346Sbenno
5878346Sbennostatic struct tty		*ofw_tp = NULL;
5978346Sbennostatic int			polltime;
6078346Sbennostatic struct callout_handle	ofw_timeouthandle
6178346Sbenno    = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
6278346Sbenno
63110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
64110509Shartistatic int			alt_break_state;
65110509Sharti#endif
66110509Sharti
6778346Sbennostatic void	ofw_tty_start(struct tty *);
6878346Sbennostatic int	ofw_tty_param(struct tty *, struct termios *);
6978346Sbennostatic void	ofw_tty_stop(struct tty *, int);
7078346Sbennostatic void	ofw_timeout(void *);
7178346Sbenno
7278346Sbennostatic cn_probe_t	ofw_cons_probe;
7378346Sbennostatic cn_init_t	ofw_cons_init;
7478346Sbennostatic cn_getc_t	ofw_cons_getc;
7578346Sbennostatic cn_checkc_t 	ofw_cons_checkc;
7678346Sbennostatic cn_putc_t	ofw_cons_putc;
7778346Sbenno
7878346SbennoCONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
7978346Sbenno    ofw_cons_checkc, ofw_cons_putc, NULL);
8078346Sbenno
8189115Sjakestatic void
8289115Sjakecn_drvinit(void *unused)
8389115Sjake{
84107044Sjake	phandle_t options;
85107044Sjake	char output[32];
86130585Sphk	struct cdev *dev;
8789115Sjake
88120544Sjake	if (ofw_consdev.cn_pri != CN_DEAD &&
89120544Sjake	    ofw_consdev.cn_name[0] != '\0') {
90107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
91107044Sjake		    OF_getprop(options, "output-device", output,
92107044Sjake		    sizeof(output)) == -1)
93107044Sjake			return;
94120491Sphk		dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
95109921Sjake		    output);
96120491Sphk		make_dev_alias(dev, "ofwcons");
97107044Sjake	}
9889115Sjake}
9989115Sjake
100126076SphkSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL)
10189115Sjake
10278346Sbennostatic int	stdin;
10378346Sbennostatic int	stdout;
10478346Sbenno
10578346Sbennostatic int
106130585Sphkofw_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
10778346Sbenno{
10878346Sbenno	struct	tty *tp;
10978346Sbenno	int	unit;
11078346Sbenno	int	error, setuptimeout;
11178346Sbenno
11278346Sbenno	error = 0;
11378346Sbenno	setuptimeout = 0;
11478346Sbenno	unit = minor(dev);
11578346Sbenno
11678346Sbenno	tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
11778346Sbenno
11878346Sbenno	tp->t_oproc = ofw_tty_start;
11978346Sbenno	tp->t_param = ofw_tty_param;
12078346Sbenno	tp->t_stop = ofw_tty_stop;
12178346Sbenno	tp->t_dev = dev;
12278346Sbenno
12378346Sbenno	if ((tp->t_state & TS_ISOPEN) == 0) {
12478346Sbenno		tp->t_state |= TS_CARR_ON;
12578346Sbenno		ttychars(tp);
12678346Sbenno		tp->t_iflag = TTYDEF_IFLAG;
12778346Sbenno		tp->t_oflag = TTYDEF_OFLAG;
12878346Sbenno		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
12978346Sbenno		tp->t_lflag = TTYDEF_LFLAG;
13078346Sbenno		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
13178346Sbenno		ttsetwater(tp);
13278346Sbenno
13378346Sbenno		setuptimeout = 1;
13493593Sjhb	} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
13578346Sbenno		return (EBUSY);
13678346Sbenno	}
13778346Sbenno
138130077Sphk	error = ttyld_open(tp, dev);
13978346Sbenno
14078346Sbenno	if (error == 0 && setuptimeout) {
14178346Sbenno		polltime = hz / OFW_POLL_HZ;
14278346Sbenno		if (polltime < 1) {
14378346Sbenno			polltime = 1;
14478346Sbenno		}
14578346Sbenno
14678346Sbenno		ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
14778346Sbenno	}
14878346Sbenno
14978346Sbenno	return (error);
15078346Sbenno}
15178346Sbenno
15278346Sbennostatic int
153130585Sphkofw_dev_close(struct cdev *dev, int flag, int mode, struct thread *td)
15478346Sbenno{
15578346Sbenno	int	unit;
15678346Sbenno	struct	tty *tp;
15778346Sbenno
15878346Sbenno	unit = minor(dev);
15978346Sbenno	tp = ofw_tp;
16078346Sbenno
16178346Sbenno	if (unit != 0) {
16278346Sbenno		return (ENXIO);
16378346Sbenno	}
16478346Sbenno
165130077Sphk	ttyld_close(tp, flag);
16678346Sbenno	ttyclose(tp);
16778346Sbenno
16878346Sbenno	return (0);
16978346Sbenno}
17078346Sbenno
17178346Sbenno
17278346Sbennostatic int
17378346Sbennoofw_tty_param(struct tty *tp, struct termios *t)
17478346Sbenno{
17578346Sbenno
17678346Sbenno	return (0);
17778346Sbenno}
17878346Sbenno
17978346Sbennostatic void
18078346Sbennoofw_tty_start(struct tty *tp)
18178346Sbenno{
18278346Sbenno
18378346Sbenno	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
18478346Sbenno		ttwwakeup(tp);
18578346Sbenno		return;
18678346Sbenno	}
18778346Sbenno
18878346Sbenno	tp->t_state |= TS_BUSY;
18978346Sbenno	while (tp->t_outq.c_cc != 0) {
190111194Sphk		ofw_cons_putc(NULL, getc(&tp->t_outq));
19178346Sbenno	}
19278346Sbenno	tp->t_state &= ~TS_BUSY;
19378346Sbenno
19478346Sbenno	ttwwakeup(tp);
19578346Sbenno}
19678346Sbenno
19778346Sbennostatic void
19878346Sbennoofw_tty_stop(struct tty *tp, int flag)
19978346Sbenno{
20078346Sbenno
20178346Sbenno	if (tp->t_state & TS_BUSY) {
20278346Sbenno		if ((tp->t_state & TS_TTSTOP) == 0) {
20378346Sbenno			tp->t_state |= TS_FLUSH;
20478346Sbenno		}
20578346Sbenno	}
20678346Sbenno}
20778346Sbenno
20878346Sbennostatic void
20978346Sbennoofw_timeout(void *v)
21078346Sbenno{
21178346Sbenno	struct	tty *tp;
21278346Sbenno	int 	c;
21378346Sbenno
21478346Sbenno	tp = (struct tty *)v;
21578346Sbenno
216111194Sphk	while ((c = ofw_cons_checkc(NULL)) != -1) {
21778346Sbenno		if (tp->t_state & TS_ISOPEN) {
218130077Sphk			ttyld_rint(tp, c);
21978346Sbenno		}
22078346Sbenno	}
22178346Sbenno
22278346Sbenno	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
22378346Sbenno}
22478346Sbenno
22578346Sbennostatic void
22678346Sbennoofw_cons_probe(struct consdev *cp)
22778346Sbenno{
22878346Sbenno	int chosen;
22978346Sbenno
23078346Sbenno	if ((chosen = OF_finddevice("/chosen")) == -1) {
23178346Sbenno		cp->cn_pri = CN_DEAD;
23278346Sbenno		return;
23378346Sbenno	}
23478346Sbenno
23578346Sbenno	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
23678346Sbenno		cp->cn_pri = CN_DEAD;
23778346Sbenno		return;
23878346Sbenno	}
23978346Sbenno
24078346Sbenno	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
24178346Sbenno		cp->cn_pri = CN_DEAD;
24278346Sbenno		return;
24378346Sbenno	}
24478346Sbenno
245120542Sjake	cp->cn_pri = CN_LOW;
24678346Sbenno}
24778346Sbenno
24878346Sbennostatic void
24978346Sbennoofw_cons_init(struct consdev *cp)
25078346Sbenno{
25178346Sbenno
252120467Sphk	/* XXX: This is the alias, but that should be good enough */
253120467Sphk	sprintf(cp->cn_name, "ofwcons");
254107044Sjake	cp->cn_tp = ofw_tp;
25578346Sbenno}
25678346Sbenno
25778346Sbennostatic int
258111194Sphkofw_cons_getc(struct consdev *cp)
25978346Sbenno{
26078346Sbenno	unsigned char ch;
26178346Sbenno	int l;
26278346Sbenno
26378346Sbenno	ch = '\0';
26478346Sbenno
26578346Sbenno	while ((l = OF_read(stdin, &ch, 1)) != 1) {
26678346Sbenno		if (l != -2 && l != 0) {
26778346Sbenno			return (-1);
26878346Sbenno		}
26978346Sbenno	}
27078346Sbenno
271110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
272110509Sharti	if (db_alt_break(ch, &alt_break_state))
273110509Sharti		breakpoint();
274110509Sharti#endif
275110509Sharti
27678346Sbenno	return (ch);
27778346Sbenno}
27878346Sbenno
27978346Sbennostatic int
280111194Sphkofw_cons_checkc(struct consdev *cp)
28178346Sbenno{
28278346Sbenno	unsigned char ch;
28378346Sbenno
28488792Sjake	if (OF_read(stdin, &ch, 1) > 0) {
285110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
286110509Sharti		if (db_alt_break(ch, &alt_break_state))
287110509Sharti			breakpoint();
288110509Sharti#endif
28978346Sbenno		return (ch);
29078346Sbenno	}
29178346Sbenno
29278346Sbenno	return (-1);
29378346Sbenno}
29478346Sbenno
29578346Sbennostatic void
296111194Sphkofw_cons_putc(struct consdev *cp, int c)
29778346Sbenno{
29878346Sbenno	char cbuf;
29978346Sbenno
30078346Sbenno	if (c == '\n') {
30178346Sbenno		cbuf = '\r';
30278346Sbenno		OF_write(stdout, &cbuf, 1);
30378346Sbenno	}
30478346Sbenno
30578346Sbenno	cbuf = c;
30678346Sbenno	OF_write(stdout, &cbuf, 1);
30778346Sbenno}
308