ofw_console.c revision 120491
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 120491 2003-09-26 19:35:50Z phk $");
2878346Sbenno
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/ofw/ofw_console.c 120491 2003-09-26 19:35:50Z phk $");
31119418Sobrien
32110509Sharti#include "opt_ddb.h"
33110509Sharti#include "opt_comconsole.h"
34110509Sharti
3578346Sbenno#include <sys/param.h>
3678346Sbenno#include <sys/kernel.h>
3778346Sbenno#include <sys/systm.h>
3878346Sbenno#include <sys/types.h>
3978346Sbenno#include <sys/conf.h>
4078346Sbenno#include <sys/cons.h>
4178346Sbenno#include <sys/consio.h>
4278346Sbenno#include <sys/tty.h>
4378346Sbenno
4478346Sbenno#include <dev/ofw/openfirm.h>
4578346Sbenno
46110509Sharti#include <ddb/ddb.h>
47110509Sharti
4888792Sjake#define	OFW_POLL_HZ	4
4978346Sbenno
5078346Sbennostatic d_open_t		ofw_dev_open;
5178346Sbennostatic d_close_t	ofw_dev_close;
5278346Sbennostatic d_ioctl_t	ofw_dev_ioctl;
5378346Sbenno
5478346Sbenno#define	CDEV_MAJOR	97
5578346Sbenno
5678346Sbennostatic struct cdevsw ofw_cdevsw = {
57111815Sphk	.d_open =	ofw_dev_open,
58111815Sphk	.d_close =	ofw_dev_close,
59111815Sphk	.d_read =	ttyread,
60111815Sphk	.d_write =	ttywrite,
61111815Sphk	.d_ioctl =	ofw_dev_ioctl,
62111815Sphk	.d_poll =	ttypoll,
63111815Sphk	.d_name =	"ofw",
64111815Sphk	.d_maj =	CDEV_MAJOR,
6578346Sbenno};
6678346Sbenno
6778346Sbennostatic struct tty		*ofw_tp = NULL;
6878346Sbennostatic int			polltime;
6978346Sbennostatic struct callout_handle	ofw_timeouthandle
7078346Sbenno    = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
7178346Sbenno
72110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
73110509Shartistatic int			alt_break_state;
74110509Sharti#endif
75110509Sharti
7678346Sbennostatic void	ofw_tty_start(struct tty *);
7778346Sbennostatic int	ofw_tty_param(struct tty *, struct termios *);
7878346Sbennostatic void	ofw_tty_stop(struct tty *, int);
7978346Sbennostatic void	ofw_timeout(void *);
8078346Sbenno
8178346Sbennostatic cn_probe_t	ofw_cons_probe;
8278346Sbennostatic cn_init_t	ofw_cons_init;
8378346Sbennostatic cn_getc_t	ofw_cons_getc;
8478346Sbennostatic cn_checkc_t 	ofw_cons_checkc;
8578346Sbennostatic cn_putc_t	ofw_cons_putc;
8678346Sbenno
8778346SbennoCONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
8878346Sbenno    ofw_cons_checkc, ofw_cons_putc, NULL);
8978346Sbenno
9089115Sjakestatic void
9189115Sjakecn_drvinit(void *unused)
9289115Sjake{
93107044Sjake	phandle_t options;
94107044Sjake	char output[32];
95120491Sphk	dev_t dev;
9689115Sjake
97120491Sphk	if (ofw_consdev.cn_pri != CN_DEAD) {
98107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
99107044Sjake		    OF_getprop(options, "output-device", output,
100107044Sjake		    sizeof(output)) == -1)
101107044Sjake			return;
102120491Sphk		dev = make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
103109921Sjake		    output);
104120491Sphk		make_dev_alias(dev, "ofwcons");
105107044Sjake	}
10689115Sjake}
10789115Sjake
108107044SjakeSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL)
10989115Sjake
11078346Sbennostatic int	stdin;
11178346Sbennostatic int	stdout;
11278346Sbenno
11378346Sbennostatic int
11483366Sjulianofw_dev_open(dev_t 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
12478346Sbenno	tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
12578346Sbenno
12678346Sbenno	tp->t_oproc = ofw_tty_start;
12778346Sbenno	tp->t_param = ofw_tty_param;
12878346Sbenno	tp->t_stop = ofw_tty_stop;
12978346Sbenno	tp->t_dev = dev;
13078346Sbenno
13178346Sbenno	if ((tp->t_state & TS_ISOPEN) == 0) {
13278346Sbenno		tp->t_state |= TS_CARR_ON;
13378346Sbenno		ttychars(tp);
13478346Sbenno		tp->t_iflag = TTYDEF_IFLAG;
13578346Sbenno		tp->t_oflag = TTYDEF_OFLAG;
13678346Sbenno		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
13778346Sbenno		tp->t_lflag = TTYDEF_LFLAG;
13878346Sbenno		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
13978346Sbenno		ttsetwater(tp);
14078346Sbenno
14178346Sbenno		setuptimeout = 1;
14293593Sjhb	} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
14378346Sbenno		return (EBUSY);
14478346Sbenno	}
14578346Sbenno
14678346Sbenno	error = (*linesw[tp->t_line].l_open)(dev, tp);
14778346Sbenno
14878346Sbenno	if (error == 0 && setuptimeout) {
14978346Sbenno		polltime = hz / OFW_POLL_HZ;
15078346Sbenno		if (polltime < 1) {
15178346Sbenno			polltime = 1;
15278346Sbenno		}
15378346Sbenno
15478346Sbenno		ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
15578346Sbenno	}
15678346Sbenno
15778346Sbenno	return (error);
15878346Sbenno}
15978346Sbenno
16078346Sbennostatic int
16183366Sjulianofw_dev_close(dev_t dev, int flag, int mode, struct thread *td)
16278346Sbenno{
16378346Sbenno	int	unit;
16478346Sbenno	struct	tty *tp;
16578346Sbenno
16678346Sbenno	unit = minor(dev);
16778346Sbenno	tp = ofw_tp;
16878346Sbenno
16978346Sbenno	if (unit != 0) {
17078346Sbenno		return (ENXIO);
17178346Sbenno	}
17278346Sbenno
17378346Sbenno	(*linesw[tp->t_line].l_close)(tp, flag);
17478346Sbenno	ttyclose(tp);
17578346Sbenno
17678346Sbenno	return (0);
17778346Sbenno}
17878346Sbenno
17978346Sbennostatic int
18083366Sjulianofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
18178346Sbenno{
18278346Sbenno	int	unit;
18378346Sbenno	struct	tty *tp;
18478346Sbenno	int	error;
18578346Sbenno
18678346Sbenno	unit = minor(dev);
18780696Sjake	tp = ofw_tp;
18880696Sjake
18978346Sbenno	if (unit != 0) {
19078346Sbenno		return (ENXIO);
19178346Sbenno	}
19278346Sbenno
19383366Sjulian	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
19478346Sbenno	if (error != ENOIOCTL) {
19578346Sbenno		return (error);
19678346Sbenno	}
19778346Sbenno
19878346Sbenno	error = ttioctl(tp, cmd, data, flag);
19978346Sbenno	if (error != ENOIOCTL) {
20078346Sbenno		return (error);
20178346Sbenno	}
20278346Sbenno
20378346Sbenno	return (ENOTTY);
20478346Sbenno}
20578346Sbenno
20678346Sbennostatic int
20778346Sbennoofw_tty_param(struct tty *tp, struct termios *t)
20878346Sbenno{
20978346Sbenno
21078346Sbenno	return (0);
21178346Sbenno}
21278346Sbenno
21378346Sbennostatic void
21478346Sbennoofw_tty_start(struct tty *tp)
21578346Sbenno{
21678346Sbenno
21778346Sbenno	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
21878346Sbenno		ttwwakeup(tp);
21978346Sbenno		return;
22078346Sbenno	}
22178346Sbenno
22278346Sbenno	tp->t_state |= TS_BUSY;
22378346Sbenno	while (tp->t_outq.c_cc != 0) {
224111194Sphk		ofw_cons_putc(NULL, getc(&tp->t_outq));
22578346Sbenno	}
22678346Sbenno	tp->t_state &= ~TS_BUSY;
22778346Sbenno
22878346Sbenno	ttwwakeup(tp);
22978346Sbenno}
23078346Sbenno
23178346Sbennostatic void
23278346Sbennoofw_tty_stop(struct tty *tp, int flag)
23378346Sbenno{
23478346Sbenno
23578346Sbenno	if (tp->t_state & TS_BUSY) {
23678346Sbenno		if ((tp->t_state & TS_TTSTOP) == 0) {
23778346Sbenno			tp->t_state |= TS_FLUSH;
23878346Sbenno		}
23978346Sbenno	}
24078346Sbenno}
24178346Sbenno
24278346Sbennostatic void
24378346Sbennoofw_timeout(void *v)
24478346Sbenno{
24578346Sbenno	struct	tty *tp;
24678346Sbenno	int 	c;
24778346Sbenno
24878346Sbenno	tp = (struct tty *)v;
24978346Sbenno
250111194Sphk	while ((c = ofw_cons_checkc(NULL)) != -1) {
25178346Sbenno		if (tp->t_state & TS_ISOPEN) {
25278346Sbenno			(*linesw[tp->t_line].l_rint)(c, tp);
25378346Sbenno		}
25478346Sbenno	}
25578346Sbenno
25678346Sbenno	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
25778346Sbenno}
25878346Sbenno
25978346Sbennostatic void
26078346Sbennoofw_cons_probe(struct consdev *cp)
26178346Sbenno{
26278346Sbenno	int chosen;
26378346Sbenno
26478346Sbenno	if ((chosen = OF_finddevice("/chosen")) == -1) {
26578346Sbenno		cp->cn_pri = CN_DEAD;
26678346Sbenno		return;
26778346Sbenno	}
26878346Sbenno
26978346Sbenno	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
27078346Sbenno		cp->cn_pri = CN_DEAD;
27178346Sbenno		return;
27278346Sbenno	}
27378346Sbenno
27478346Sbenno	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
27578346Sbenno		cp->cn_pri = CN_DEAD;
27678346Sbenno		return;
27778346Sbenno	}
27878346Sbenno
27978346Sbenno	cp->cn_pri = CN_INTERNAL;
28078346Sbenno}
28178346Sbenno
28278346Sbennostatic void
28378346Sbennoofw_cons_init(struct consdev *cp)
28478346Sbenno{
28578346Sbenno
286120467Sphk	/* XXX: This is the alias, but that should be good enough */
287120467Sphk	sprintf(cp->cn_name, "ofwcons");
288107044Sjake	cp->cn_tp = ofw_tp;
28978346Sbenno}
29078346Sbenno
29178346Sbennostatic int
292111194Sphkofw_cons_getc(struct consdev *cp)
29378346Sbenno{
29478346Sbenno	unsigned char ch;
29578346Sbenno	int l;
29678346Sbenno
29778346Sbenno	ch = '\0';
29878346Sbenno
29978346Sbenno	while ((l = OF_read(stdin, &ch, 1)) != 1) {
30078346Sbenno		if (l != -2 && l != 0) {
30178346Sbenno			return (-1);
30278346Sbenno		}
30378346Sbenno	}
30478346Sbenno
305110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
306110509Sharti	if (db_alt_break(ch, &alt_break_state))
307110509Sharti		breakpoint();
308110509Sharti#endif
309110509Sharti
31078346Sbenno	return (ch);
31178346Sbenno}
31278346Sbenno
31378346Sbennostatic int
314111194Sphkofw_cons_checkc(struct consdev *cp)
31578346Sbenno{
31678346Sbenno	unsigned char ch;
31778346Sbenno
31888792Sjake	if (OF_read(stdin, &ch, 1) > 0) {
319110509Sharti#if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
320110509Sharti		if (db_alt_break(ch, &alt_break_state))
321110509Sharti			breakpoint();
322110509Sharti#endif
32378346Sbenno		return (ch);
32478346Sbenno	}
32578346Sbenno
32678346Sbenno	return (-1);
32778346Sbenno}
32878346Sbenno
32978346Sbennostatic void
330111194Sphkofw_cons_putc(struct consdev *cp, int c)
33178346Sbenno{
33278346Sbenno	char cbuf;
33378346Sbenno
33478346Sbenno	if (c == '\n') {
33578346Sbenno		cbuf = '\r';
33678346Sbenno		OF_write(stdout, &cbuf, 1);
33778346Sbenno	}
33878346Sbenno
33978346Sbenno	cbuf = c;
34078346Sbenno	OF_write(stdout, &cbuf, 1);
34178346Sbenno}
342