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: releng/11.0/sys/dev/ofw/ofw_console.c 270975 2014-09-02 18:57:19Z jhb $");
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;
63270975Sjhbstatic struct callout		ofw_timer;
6478346Sbenno
65225203Srwatson#if defined(KDB)
66110509Shartistatic int			alt_break_state;
67110509Sharti#endif
68110509Sharti
6978346Sbennostatic void	ofw_timeout(void *);
7078346Sbenno
71158964Sphkstatic cn_probe_t	ofw_cnprobe;
72158964Sphkstatic cn_init_t	ofw_cninit;
73158964Sphkstatic cn_term_t	ofw_cnterm;
74158964Sphkstatic cn_getc_t	ofw_cngetc;
75158964Sphkstatic cn_putc_t	ofw_cnputc;
76228631Savgstatic cn_grab_t	ofw_cngrab;
77228631Savgstatic cn_ungrab_t	ofw_cnungrab;
7878346Sbenno
79159065SphkCONSOLE_DRIVER(ofw);
8078346Sbenno
8189115Sjakestatic void
8289115Sjakecn_drvinit(void *unused)
8389115Sjake{
84107044Sjake	phandle_t options;
85107044Sjake	char output[32];
86181905Sed	struct tty *tp;
8789115Sjake
88120544Sjake	if (ofw_consdev.cn_pri != CN_DEAD &&
89120544Sjake	    ofw_consdev.cn_name[0] != '\0') {
90255424Snwhitehorn		tp = tty_alloc(&ofw_ttydevsw, NULL);
91255424Snwhitehorn		tty_makedev(tp, NULL, "%s", "ofwcons");
92255424Snwhitehorn
93255424Snwhitehorn		/*
94255424Snwhitehorn		 * XXX: This is a hack and it may result in two /dev/ttya
95255424Snwhitehorn		 * XXX: devices on platforms where the sab driver works.
96255424Snwhitehorn		 */
97107044Sjake		if ((options = OF_finddevice("/options")) == -1 ||
98107044Sjake		    OF_getprop(options, "output-device", output,
99107044Sjake		    sizeof(output)) == -1)
100107044Sjake			return;
101255424Snwhitehorn		if (strlen(output) > 0)
102259398Snwhitehorn			tty_makealias(tp, "%s", output);
103270975Sjhb		callout_init_mtx(&ofw_timer, tty_getlock(tp), 0);
104107044Sjake	}
10589115Sjake}
10689115Sjake
107177253SrwatsonSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
10889115Sjake
109256966Snwhitehornstatic pcell_t	stdin;
110256966Snwhitehornstatic 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
119270975Sjhb	callout_reset(&ofw_timer, polltime, ofw_timeout, tp);
12078346Sbenno
121181905Sed	return (0);
12278346Sbenno}
12378346Sbenno
124181905Sedstatic void
125181905Sedofwtty_close(struct tty *tp)
12678346Sbenno{
12778346Sbenno
128270975Sjhb	callout_stop(&ofw_timer);
12978346Sbenno}
13078346Sbenno
13178346Sbennostatic void
132181905Sedofwtty_outwakeup(struct tty *tp)
13378346Sbenno{
134131016Sobrien	int len;
135131016Sobrien	u_char buf[OFBURSTLEN];
13678346Sbenno
137181905Sed	for (;;) {
138181905Sed		len = ttydisc_getc(tp, buf, sizeof buf);
139181905Sed		if (len == 0)
140181905Sed			break;
141181905Sed		OF_write(stdout, buf, len);
14278346Sbenno	}
14378346Sbenno}
14478346Sbenno
14578346Sbennostatic void
14678346Sbennoofw_timeout(void *v)
14778346Sbenno{
14878346Sbenno	struct	tty *tp;
14978346Sbenno	int 	c;
15078346Sbenno
15178346Sbenno	tp = (struct tty *)v;
15278346Sbenno
153270975Sjhb	tty_lock_assert(tp, MA_OWNED);
154181905Sed	while ((c = ofw_cngetc(NULL)) != -1)
155181905Sed		ttydisc_rint(tp, c, 0);
156181905Sed	ttydisc_rint_done(tp);
15778346Sbenno
158270975Sjhb	callout_schedule(&ofw_timer, 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
171256966Snwhitehorn	if (OF_getencprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
17278346Sbenno		cp->cn_pri = CN_DEAD;
17378346Sbenno		return;
17478346Sbenno	}
17578346Sbenno
176256966Snwhitehorn	if (OF_getencprop(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
197228631Savgstatic void
198228631Savgofw_cngrab(struct consdev *cp)
199228631Savg{
200228631Savg}
201228631Savg
202228631Savgstatic void
203228631Savgofw_cnungrab(struct consdev *cp)
204228631Savg{
205228631Savg}
206228631Savg
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