1139749Simp/*-
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$");
2878346Sbenno
29131016Sobrien#include "opt_ofw.h"
30110509Sharti
3178346Sbenno#include <sys/param.h>
32131916Smarcel#include <sys/kdb.h>
3378346Sbenno#include <sys/kernel.h>
34164049Srwatson#include <sys/priv.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
51181905Sedstatic tsw_open_t ofwtty_open;
52181905Sedstatic tsw_close_t ofwtty_close;
53181905Sedstatic tsw_outwakeup_t ofwtty_outwakeup;
5478346Sbenno
55181905Sedstatic struct ttydevsw ofw_ttydevsw = {
56181905Sed	.tsw_flags	= TF_NOPREFIX,
57181905Sed	.tsw_open	= ofwtty_open,
58181905Sed	.tsw_close	= ofwtty_close,
59181905Sed	.tsw_outwakeup	= ofwtty_outwakeup,
6078346Sbenno};
6178346Sbenno
6278346Sbennostatic int			polltime;
6378346Sbennostatic struct callout_handle	ofw_timeouthandle
6478346Sbenno    = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
6578346Sbenno
66225203Srwatson#if defined(KDB)
67110509Shartistatic int			alt_break_state;
68110509Sharti#endif
69110509Sharti
7078346Sbennostatic void	ofw_timeout(void *);
7178346Sbenno
72158964Sphkstatic cn_probe_t	ofw_cnprobe;
73158964Sphkstatic cn_init_t	ofw_cninit;
74158964Sphkstatic cn_term_t	ofw_cnterm;
75158964Sphkstatic cn_getc_t	ofw_cngetc;
76158964Sphkstatic cn_putc_t	ofw_cnputc;
77235405Savgstatic cn_grab_t	ofw_cngrab;
78235405Savgstatic cn_ungrab_t	ofw_cnungrab;
7978346Sbenno
80159065SphkCONSOLE_DRIVER(ofw);
8178346Sbenno
8289115Sjakestatic void
8389115Sjakecn_drvinit(void *unused)
8489115Sjake{
85107044Sjake	phandle_t options;
86107044Sjake	char output[32];
87181905Sed	struct tty *tp;
8889115Sjake
89120544Sjake	if (ofw_consdev.cn_pri != CN_DEAD &&
90120544Sjake	    ofw_consdev.cn_name[0] != '\0') {
91107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
92107044Sjake		    OF_getprop(options, "output-device", output,
93107044Sjake		    sizeof(output)) == -1)
94107044Sjake			return;
95136454Sphk		/*
96136454Sphk		 * XXX: This is a hack and it may result in two /dev/ttya
97136454Sphk		 * XXX: devices on platforms where the sab driver works.
98136454Sphk		 */
99193018Sed		tp = tty_alloc(&ofw_ttydevsw, NULL);
100181905Sed		tty_makedev(tp, NULL, "%s", output);
101181905Sed		tty_makealias(tp, "ofwcons");
102107044Sjake	}
10389115Sjake}
10489115Sjake
105177253SrwatsonSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
10689115Sjake
10778346Sbennostatic int	stdin;
10878346Sbennostatic int	stdout;
10978346Sbenno
11078346Sbennostatic int
111181905Sedofwtty_open(struct tty *tp)
11278346Sbenno{
113181905Sed	polltime = hz / OFWCONS_POLL_HZ;
114181905Sed	if (polltime < 1)
115181905Sed		polltime = 1;
11678346Sbenno
117181905Sed	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
11878346Sbenno
119181905Sed	return (0);
12078346Sbenno}
12178346Sbenno
122181905Sedstatic void
123181905Sedofwtty_close(struct tty *tp)
12478346Sbenno{
12578346Sbenno
126131016Sobrien	/* XXX Should be replaced with callout_stop(9) */
127131016Sobrien	untimeout(ofw_timeout, tp, ofw_timeouthandle);
12878346Sbenno}
12978346Sbenno
13078346Sbennostatic void
131181905Sedofwtty_outwakeup(struct tty *tp)
13278346Sbenno{
133131016Sobrien	int len;
134131016Sobrien	u_char buf[OFBURSTLEN];
13578346Sbenno
136181905Sed	for (;;) {
137181905Sed		len = ttydisc_getc(tp, buf, sizeof buf);
138181905Sed		if (len == 0)
139181905Sed			break;
140181905Sed		OF_write(stdout, buf, len);
14178346Sbenno	}
14278346Sbenno}
14378346Sbenno
14478346Sbennostatic void
14578346Sbennoofw_timeout(void *v)
14678346Sbenno{
14778346Sbenno	struct	tty *tp;
14878346Sbenno	int 	c;
14978346Sbenno
15078346Sbenno	tp = (struct tty *)v;
15178346Sbenno
152181905Sed	tty_lock(tp);
153181905Sed	while ((c = ofw_cngetc(NULL)) != -1)
154181905Sed		ttydisc_rint(tp, c, 0);
155181905Sed	ttydisc_rint_done(tp);
156181905Sed	tty_unlock(tp);
15778346Sbenno
15878346Sbenno	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
15978346Sbenno}
16078346Sbenno
16178346Sbennostatic void
162159065Sphkofw_cnprobe(struct consdev *cp)
16378346Sbenno{
16478346Sbenno	int chosen;
16578346Sbenno
16678346Sbenno	if ((chosen = OF_finddevice("/chosen")) == -1) {
16778346Sbenno		cp->cn_pri = CN_DEAD;
16878346Sbenno		return;
16978346Sbenno	}
17078346Sbenno
17178346Sbenno	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
17278346Sbenno		cp->cn_pri = CN_DEAD;
17378346Sbenno		return;
17478346Sbenno	}
17578346Sbenno
17678346Sbenno	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
17778346Sbenno		cp->cn_pri = CN_DEAD;
17878346Sbenno		return;
17978346Sbenno	}
18078346Sbenno
181120542Sjake	cp->cn_pri = CN_LOW;
18278346Sbenno}
18378346Sbenno
18478346Sbennostatic void
185158964Sphkofw_cninit(struct consdev *cp)
18678346Sbenno{
18778346Sbenno
188120467Sphk	/* XXX: This is the alias, but that should be good enough */
189184329Sed	strcpy(cp->cn_name, "ofwcons");
19078346Sbenno}
19178346Sbenno
192158964Sphkstatic void
193159065Sphkofw_cnterm(struct consdev *cp)
19478346Sbenno{
19578346Sbenno}
19678346Sbenno
197235405Savgstatic void
198235405Savgofw_cngrab(struct consdev *cp)
199235405Savg{
200235405Savg}
201235405Savg
202235405Savgstatic void
203235405Savgofw_cnungrab(struct consdev *cp)
204235405Savg{
205235405Savg}
206235405Savg
20778346Sbennostatic int
208158964Sphkofw_cngetc(struct consdev *cp)
20978346Sbenno{
21078346Sbenno	unsigned char ch;
21178346Sbenno
21288792Sjake	if (OF_read(stdin, &ch, 1) > 0) {
213225203Srwatson#if defined(KDB)
214225203Srwatson		kdb_alt_break(ch, &alt_break_state);
215110509Sharti#endif
21678346Sbenno		return (ch);
21778346Sbenno	}
21878346Sbenno
21978346Sbenno	return (-1);
22078346Sbenno}
22178346Sbenno
22278346Sbennostatic void
223158964Sphkofw_cnputc(struct consdev *cp, int c)
22478346Sbenno{
22578346Sbenno	char cbuf;
22678346Sbenno
22778346Sbenno	if (c == '\n') {
22878346Sbenno		cbuf = '\r';
22978346Sbenno		OF_write(stdout, &cbuf, 1);
23078346Sbenno	}
23178346Sbenno
23278346Sbenno	cbuf = c;
23378346Sbenno	OF_write(stdout, &cbuf, 1);
23478346Sbenno}
235