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;
77228631Savgstatic cn_grab_t	ofw_cngrab;
78228631Savgstatic 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') {
91255424Snwhitehorn		tp = tty_alloc(&ofw_ttydevsw, NULL);
92255424Snwhitehorn		tty_makedev(tp, NULL, "%s", "ofwcons");
93255424Snwhitehorn
94255424Snwhitehorn		/*
95255424Snwhitehorn		 * XXX: This is a hack and it may result in two /dev/ttya
96255424Snwhitehorn		 * XXX: devices on platforms where the sab driver works.
97255424Snwhitehorn		 */
98107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
99107044Sjake		    OF_getprop(options, "output-device", output,
100107044Sjake		    sizeof(output)) == -1)
101107044Sjake			return;
102255424Snwhitehorn		if (strlen(output) > 0)
103255424Snwhitehorn			tty_makealias(tp, output);
104107044Sjake	}
10589115Sjake}
10689115Sjake
107177253SrwatsonSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
10889115Sjake
109265967Sianstatic pcell_t	stdin;
110265967Sianstatic pcell_t	stdout;
11178346Sbenno
11278346Sbennostatic int
113181905Sedofwtty_open(struct tty *tp)
11478346Sbenno{
115181905Sed	polltime = hz / OFWCONS_POLL_HZ;
116181905Sed	if (polltime < 1)
117181905Sed		polltime = 1;
11878346Sbenno
119181905Sed	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
12078346Sbenno
121181905Sed	return (0);
12278346Sbenno}
12378346Sbenno
124181905Sedstatic void
125181905Sedofwtty_close(struct tty *tp)
12678346Sbenno{
12778346Sbenno
128131016Sobrien	/* XXX Should be replaced with callout_stop(9) */
129131016Sobrien	untimeout(ofw_timeout, tp, ofw_timeouthandle);
13078346Sbenno}
13178346Sbenno
13278346Sbennostatic void
133181905Sedofwtty_outwakeup(struct tty *tp)
13478346Sbenno{
135131016Sobrien	int len;
136131016Sobrien	u_char buf[OFBURSTLEN];
13778346Sbenno
138181905Sed	for (;;) {
139181905Sed		len = ttydisc_getc(tp, buf, sizeof buf);
140181905Sed		if (len == 0)
141181905Sed			break;
142181905Sed		OF_write(stdout, buf, len);
14378346Sbenno	}
14478346Sbenno}
14578346Sbenno
14678346Sbennostatic void
14778346Sbennoofw_timeout(void *v)
14878346Sbenno{
14978346Sbenno	struct	tty *tp;
15078346Sbenno	int 	c;
15178346Sbenno
15278346Sbenno	tp = (struct tty *)v;
15378346Sbenno
154181905Sed	tty_lock(tp);
155181905Sed	while ((c = ofw_cngetc(NULL)) != -1)
156181905Sed		ttydisc_rint(tp, c, 0);
157181905Sed	ttydisc_rint_done(tp);
158181905Sed	tty_unlock(tp);
15978346Sbenno
16078346Sbenno	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
16178346Sbenno}
16278346Sbenno
16378346Sbennostatic void
164159065Sphkofw_cnprobe(struct consdev *cp)
16578346Sbenno{
16678346Sbenno	int chosen;
16778346Sbenno
16878346Sbenno	if ((chosen = OF_finddevice("/chosen")) == -1) {
16978346Sbenno		cp->cn_pri = CN_DEAD;
17078346Sbenno		return;
17178346Sbenno	}
17278346Sbenno
173265967Sian	if (OF_getencprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
17478346Sbenno		cp->cn_pri = CN_DEAD;
17578346Sbenno		return;
17678346Sbenno	}
17778346Sbenno
178265967Sian	if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
17978346Sbenno		cp->cn_pri = CN_DEAD;
18078346Sbenno		return;
18178346Sbenno	}
18278346Sbenno
183120542Sjake	cp->cn_pri = CN_LOW;
18478346Sbenno}
18578346Sbenno
18678346Sbennostatic void
187158964Sphkofw_cninit(struct consdev *cp)
18878346Sbenno{
18978346Sbenno
190120467Sphk	/* XXX: This is the alias, but that should be good enough */
191184329Sed	strcpy(cp->cn_name, "ofwcons");
19278346Sbenno}
19378346Sbenno
194158964Sphkstatic void
195159065Sphkofw_cnterm(struct consdev *cp)
19678346Sbenno{
19778346Sbenno}
19878346Sbenno
199228631Savgstatic void
200228631Savgofw_cngrab(struct consdev *cp)
201228631Savg{
202228631Savg}
203228631Savg
204228631Savgstatic void
205228631Savgofw_cnungrab(struct consdev *cp)
206228631Savg{
207228631Savg}
208228631Savg
20978346Sbennostatic int
210158964Sphkofw_cngetc(struct consdev *cp)
21178346Sbenno{
21278346Sbenno	unsigned char ch;
21378346Sbenno
21488792Sjake	if (OF_read(stdin, &ch, 1) > 0) {
215225203Srwatson#if defined(KDB)
216225203Srwatson		kdb_alt_break(ch, &alt_break_state);
217110509Sharti#endif
21878346Sbenno		return (ch);
21978346Sbenno	}
22078346Sbenno
22178346Sbenno	return (-1);
22278346Sbenno}
22378346Sbenno
22478346Sbennostatic void
225158964Sphkofw_cnputc(struct consdev *cp, int c)
22678346Sbenno{
22778346Sbenno	char cbuf;
22878346Sbenno
22978346Sbenno	if (c == '\n') {
23078346Sbenno		cbuf = '\r';
23178346Sbenno		OF_write(stdout, &cbuf, 1);
23278346Sbenno	}
23378346Sbenno
23478346Sbenno	cbuf = c;
23578346Sbenno	OF_write(stdout, &cbuf, 1);
23678346Sbenno}
237