xref: /freebsd/sys/dev/ofw/ofw_console.c (revision 761f89f9d8f11f6ec8bafe85a7631ecddb402c51)
1707fed20SBenno Rice /*
2707fed20SBenno Rice  * Copyright (C) 2001 Benno Rice.
3707fed20SBenno Rice  * All rights reserved.
4707fed20SBenno Rice  *
5707fed20SBenno Rice  * Redistribution and use in source and binary forms, with or without
6707fed20SBenno Rice  * modification, are permitted provided that the following conditions
7707fed20SBenno Rice  * are met:
8707fed20SBenno Rice  * 1. Redistributions of source code must retain the above copyright
9707fed20SBenno Rice  *    notice, this list of conditions and the following disclaimer.
10707fed20SBenno Rice  * 2. Redistributions in binary form must reproduce the above copyright
11707fed20SBenno Rice  *    notice, this list of conditions and the following disclaimer in the
12707fed20SBenno Rice  *    documentation and/or other materials provided with the distribution.
13707fed20SBenno Rice  *
14707fed20SBenno Rice  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15707fed20SBenno Rice  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16707fed20SBenno Rice  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17707fed20SBenno Rice  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18707fed20SBenno Rice  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19707fed20SBenno Rice  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20707fed20SBenno Rice  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21707fed20SBenno Rice  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22707fed20SBenno Rice  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23707fed20SBenno Rice  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24707fed20SBenno Rice  */
25707fed20SBenno Rice 
26707fed20SBenno Rice #ifndef lint
27707fed20SBenno Rice static const char rcsid[] =
28707fed20SBenno Rice   "$FreeBSD$";
29707fed20SBenno Rice #endif /* not lint */
30707fed20SBenno Rice 
31761f89f9SHartmut Brandt #include "opt_ddb.h"
32761f89f9SHartmut Brandt #include "opt_comconsole.h"
33761f89f9SHartmut Brandt 
34707fed20SBenno Rice #include <sys/param.h>
35707fed20SBenno Rice #include <sys/kernel.h>
36707fed20SBenno Rice #include <sys/systm.h>
37707fed20SBenno Rice #include <sys/types.h>
38707fed20SBenno Rice #include <sys/conf.h>
39707fed20SBenno Rice #include <sys/cons.h>
40707fed20SBenno Rice #include <sys/consio.h>
41707fed20SBenno Rice #include <sys/tty.h>
42707fed20SBenno Rice 
43707fed20SBenno Rice #include <dev/ofw/openfirm.h>
44707fed20SBenno Rice 
45761f89f9SHartmut Brandt #include <ddb/ddb.h>
46761f89f9SHartmut Brandt 
47cbecdd57SJake Burkholder #define	OFW_POLL_HZ	4
48707fed20SBenno Rice 
49707fed20SBenno Rice static d_open_t		ofw_dev_open;
50707fed20SBenno Rice static d_close_t	ofw_dev_close;
51707fed20SBenno Rice static d_ioctl_t	ofw_dev_ioctl;
52707fed20SBenno Rice 
53707fed20SBenno Rice #define	CDEV_MAJOR	97
54707fed20SBenno Rice 
55707fed20SBenno Rice static struct cdevsw ofw_cdevsw = {
56707fed20SBenno Rice 	/* open */	ofw_dev_open,
57707fed20SBenno Rice 	/* close */	ofw_dev_close,
58707fed20SBenno Rice 	/* read */	ttyread,
59707fed20SBenno Rice 	/* write */	ttywrite,
60707fed20SBenno Rice 	/* ioctl */	ofw_dev_ioctl,
61707fed20SBenno Rice 	/* poll */	ttypoll,
62707fed20SBenno Rice 	/* mmap */	nommap,
63707fed20SBenno Rice 	/* strategy */	nostrategy,
64707fed20SBenno Rice 	/* name */	"ofw",
65707fed20SBenno Rice 	/* major */	CDEV_MAJOR,
66707fed20SBenno Rice 	/* dump */	nodump,
67707fed20SBenno Rice 	/* psize */	nopsize,
68707fed20SBenno Rice 	/* flags */	0,
69707fed20SBenno Rice };
70707fed20SBenno Rice 
71707fed20SBenno Rice static struct tty		*ofw_tp = NULL;
72707fed20SBenno Rice static int			polltime;
73707fed20SBenno Rice static struct callout_handle	ofw_timeouthandle
74707fed20SBenno Rice     = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
75707fed20SBenno Rice 
76761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
77761f89f9SHartmut Brandt static int			alt_break_state;
78761f89f9SHartmut Brandt #endif
79761f89f9SHartmut Brandt 
80707fed20SBenno Rice static void	ofw_tty_start(struct tty *);
81707fed20SBenno Rice static int	ofw_tty_param(struct tty *, struct termios *);
82707fed20SBenno Rice static void	ofw_tty_stop(struct tty *, int);
83707fed20SBenno Rice static void	ofw_timeout(void *);
84707fed20SBenno Rice 
85707fed20SBenno Rice static cn_probe_t	ofw_cons_probe;
86707fed20SBenno Rice static cn_init_t	ofw_cons_init;
87707fed20SBenno Rice static cn_getc_t	ofw_cons_getc;
88707fed20SBenno Rice static cn_checkc_t 	ofw_cons_checkc;
89707fed20SBenno Rice static cn_putc_t	ofw_cons_putc;
90707fed20SBenno Rice 
91707fed20SBenno Rice CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
92707fed20SBenno Rice     ofw_cons_checkc, ofw_cons_putc, NULL);
93707fed20SBenno Rice 
9447a1c915SJake Burkholder static void
9547a1c915SJake Burkholder cn_drvinit(void *unused)
9647a1c915SJake Burkholder {
97a121cb6aSJake Burkholder 	phandle_t options;
98a121cb6aSJake Burkholder 	char output[32];
9947a1c915SJake Burkholder 
100a121cb6aSJake Burkholder 	if (ofw_consdev.cn_dev != NULL) {
101a121cb6aSJake Burkholder 		if ((options = OF_finddevice("/options")) == -1 ||
102a121cb6aSJake Burkholder 		    OF_getprop(options, "output-device", output,
103a121cb6aSJake Burkholder 		    sizeof(output)) == -1)
104a121cb6aSJake Burkholder 			return;
105984e2655SJake Burkholder 		make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
106984e2655SJake Burkholder 		    output);
107984e2655SJake Burkholder 		make_dev_alias(ofw_consdev.cn_dev, "ofwcons");
108a121cb6aSJake Burkholder 	}
10947a1c915SJake Burkholder }
11047a1c915SJake Burkholder 
111a121cb6aSJake Burkholder SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE + CDEV_MAJOR, cn_drvinit, NULL)
11247a1c915SJake Burkholder 
113707fed20SBenno Rice static int	stdin;
114707fed20SBenno Rice static int	stdout;
115707fed20SBenno Rice 
116707fed20SBenno Rice static int
117b40ce416SJulian Elischer ofw_dev_open(dev_t dev, int flag, int mode, struct thread *td)
118707fed20SBenno Rice {
119707fed20SBenno Rice 	struct	tty *tp;
120707fed20SBenno Rice 	int	unit;
121707fed20SBenno Rice 	int	error, setuptimeout;
122707fed20SBenno Rice 
123707fed20SBenno Rice 	error = 0;
124707fed20SBenno Rice 	setuptimeout = 0;
125707fed20SBenno Rice 	unit = minor(dev);
126707fed20SBenno Rice 
127707fed20SBenno Rice 	tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
128707fed20SBenno Rice 
129707fed20SBenno Rice 	tp->t_oproc = ofw_tty_start;
130707fed20SBenno Rice 	tp->t_param = ofw_tty_param;
131707fed20SBenno Rice 	tp->t_stop = ofw_tty_stop;
132707fed20SBenno Rice 	tp->t_dev = dev;
133707fed20SBenno Rice 
134707fed20SBenno Rice 	if ((tp->t_state & TS_ISOPEN) == 0) {
135707fed20SBenno Rice 		tp->t_state |= TS_CARR_ON;
136707fed20SBenno Rice 		ttychars(tp);
137707fed20SBenno Rice 		tp->t_iflag = TTYDEF_IFLAG;
138707fed20SBenno Rice 		tp->t_oflag = TTYDEF_OFLAG;
139707fed20SBenno Rice 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
140707fed20SBenno Rice 		tp->t_lflag = TTYDEF_LFLAG;
141707fed20SBenno Rice 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
142707fed20SBenno Rice 		ttsetwater(tp);
143707fed20SBenno Rice 
144707fed20SBenno Rice 		setuptimeout = 1;
14544731cabSJohn Baldwin 	} else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
146707fed20SBenno Rice 		return (EBUSY);
147707fed20SBenno Rice 	}
148707fed20SBenno Rice 
149707fed20SBenno Rice 	error = (*linesw[tp->t_line].l_open)(dev, tp);
150707fed20SBenno Rice 
151707fed20SBenno Rice 	if (error == 0 && setuptimeout) {
152707fed20SBenno Rice 		polltime = hz / OFW_POLL_HZ;
153707fed20SBenno Rice 		if (polltime < 1) {
154707fed20SBenno Rice 			polltime = 1;
155707fed20SBenno Rice 		}
156707fed20SBenno Rice 
157707fed20SBenno Rice 		ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
158707fed20SBenno Rice 	}
159707fed20SBenno Rice 
160707fed20SBenno Rice 	return (error);
161707fed20SBenno Rice }
162707fed20SBenno Rice 
163707fed20SBenno Rice static int
164b40ce416SJulian Elischer ofw_dev_close(dev_t dev, int flag, int mode, struct thread *td)
165707fed20SBenno Rice {
166707fed20SBenno Rice 	int	unit;
167707fed20SBenno Rice 	struct	tty *tp;
168707fed20SBenno Rice 
169707fed20SBenno Rice 	unit = minor(dev);
170707fed20SBenno Rice 	tp = ofw_tp;
171707fed20SBenno Rice 
172707fed20SBenno Rice 	if (unit != 0) {
173707fed20SBenno Rice 		return (ENXIO);
174707fed20SBenno Rice 	}
175707fed20SBenno Rice 
176707fed20SBenno Rice 	(*linesw[tp->t_line].l_close)(tp, flag);
177707fed20SBenno Rice 	ttyclose(tp);
178707fed20SBenno Rice 
179707fed20SBenno Rice 	return (0);
180707fed20SBenno Rice }
181707fed20SBenno Rice 
182707fed20SBenno Rice static int
183b40ce416SJulian Elischer ofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
184707fed20SBenno Rice {
185707fed20SBenno Rice 	int	unit;
186707fed20SBenno Rice 	struct	tty *tp;
187707fed20SBenno Rice 	int	error;
188707fed20SBenno Rice 
189707fed20SBenno Rice 	unit = minor(dev);
190c22c65b1SJake Burkholder 	tp = ofw_tp;
191c22c65b1SJake Burkholder 
192707fed20SBenno Rice 	if (unit != 0) {
193707fed20SBenno Rice 		return (ENXIO);
194707fed20SBenno Rice 	}
195707fed20SBenno Rice 
196b40ce416SJulian Elischer 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
197707fed20SBenno Rice 	if (error != ENOIOCTL) {
198707fed20SBenno Rice 		return (error);
199707fed20SBenno Rice 	}
200707fed20SBenno Rice 
201707fed20SBenno Rice 	error = ttioctl(tp, cmd, data, flag);
202707fed20SBenno Rice 	if (error != ENOIOCTL) {
203707fed20SBenno Rice 		return (error);
204707fed20SBenno Rice 	}
205707fed20SBenno Rice 
206707fed20SBenno Rice 	return (ENOTTY);
207707fed20SBenno Rice }
208707fed20SBenno Rice 
209707fed20SBenno Rice static int
210707fed20SBenno Rice ofw_tty_param(struct tty *tp, struct termios *t)
211707fed20SBenno Rice {
212707fed20SBenno Rice 
213707fed20SBenno Rice 	return (0);
214707fed20SBenno Rice }
215707fed20SBenno Rice 
216707fed20SBenno Rice static void
217707fed20SBenno Rice ofw_tty_start(struct tty *tp)
218707fed20SBenno Rice {
219707fed20SBenno Rice 
220707fed20SBenno Rice 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
221707fed20SBenno Rice 		ttwwakeup(tp);
222707fed20SBenno Rice 		return;
223707fed20SBenno Rice 	}
224707fed20SBenno Rice 
225707fed20SBenno Rice 	tp->t_state |= TS_BUSY;
226707fed20SBenno Rice 	while (tp->t_outq.c_cc != 0) {
227707fed20SBenno Rice 		ofw_cons_putc(tp->t_dev, getc(&tp->t_outq));
228707fed20SBenno Rice 	}
229707fed20SBenno Rice 	tp->t_state &= ~TS_BUSY;
230707fed20SBenno Rice 
231707fed20SBenno Rice 	ttwwakeup(tp);
232707fed20SBenno Rice }
233707fed20SBenno Rice 
234707fed20SBenno Rice static void
235707fed20SBenno Rice ofw_tty_stop(struct tty *tp, int flag)
236707fed20SBenno Rice {
237707fed20SBenno Rice 
238707fed20SBenno Rice 	if (tp->t_state & TS_BUSY) {
239707fed20SBenno Rice 		if ((tp->t_state & TS_TTSTOP) == 0) {
240707fed20SBenno Rice 			tp->t_state |= TS_FLUSH;
241707fed20SBenno Rice 		}
242707fed20SBenno Rice 	}
243707fed20SBenno Rice }
244707fed20SBenno Rice 
245707fed20SBenno Rice static void
246707fed20SBenno Rice ofw_timeout(void *v)
247707fed20SBenno Rice {
248707fed20SBenno Rice 	struct	tty *tp;
249707fed20SBenno Rice 	int 	c;
250707fed20SBenno Rice 
251707fed20SBenno Rice 	tp = (struct tty *)v;
252707fed20SBenno Rice 
253707fed20SBenno Rice 	while ((c = ofw_cons_checkc(tp->t_dev)) != -1) {
254707fed20SBenno Rice 		if (tp->t_state & TS_ISOPEN) {
255707fed20SBenno Rice 			(*linesw[tp->t_line].l_rint)(c, tp);
256707fed20SBenno Rice 		}
257707fed20SBenno Rice 	}
258707fed20SBenno Rice 
259707fed20SBenno Rice 	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
260707fed20SBenno Rice }
261707fed20SBenno Rice 
262707fed20SBenno Rice static void
263707fed20SBenno Rice ofw_cons_probe(struct consdev *cp)
264707fed20SBenno Rice {
265707fed20SBenno Rice 	int chosen;
266707fed20SBenno Rice 
267707fed20SBenno Rice 	if ((chosen = OF_finddevice("/chosen")) == -1) {
268707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
269707fed20SBenno Rice 		return;
270707fed20SBenno Rice 	}
271707fed20SBenno Rice 
272707fed20SBenno Rice 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
273707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
274707fed20SBenno Rice 		return;
275707fed20SBenno Rice 	}
276707fed20SBenno Rice 
277707fed20SBenno Rice 	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
278707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
279707fed20SBenno Rice 		return;
280707fed20SBenno Rice 	}
281707fed20SBenno Rice 
282a121cb6aSJake Burkholder 	cp->cn_dev = NULL;
283707fed20SBenno Rice 	cp->cn_pri = CN_INTERNAL;
284707fed20SBenno Rice }
285707fed20SBenno Rice 
286707fed20SBenno Rice static void
287707fed20SBenno Rice ofw_cons_init(struct consdev *cp)
288707fed20SBenno Rice {
289707fed20SBenno Rice 
290a121cb6aSJake Burkholder 	cp->cn_dev = makedev(CDEV_MAJOR, 0);
291a121cb6aSJake Burkholder 	cp->cn_tp = ofw_tp;
292707fed20SBenno Rice }
293707fed20SBenno Rice 
294707fed20SBenno Rice static int
295707fed20SBenno Rice ofw_cons_getc(dev_t dev)
296707fed20SBenno Rice {
297707fed20SBenno Rice 	unsigned char ch;
298707fed20SBenno Rice 	int l;
299707fed20SBenno Rice 
300707fed20SBenno Rice 	ch = '\0';
301707fed20SBenno Rice 
302707fed20SBenno Rice 	while ((l = OF_read(stdin, &ch, 1)) != 1) {
303707fed20SBenno Rice 		if (l != -2 && l != 0) {
304707fed20SBenno Rice 			return (-1);
305707fed20SBenno Rice 		}
306707fed20SBenno Rice 	}
307707fed20SBenno Rice 
308761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
309761f89f9SHartmut Brandt 	if (db_alt_break(ch, &alt_break_state))
310761f89f9SHartmut Brandt 		breakpoint();
311761f89f9SHartmut Brandt #endif
312761f89f9SHartmut Brandt 
313707fed20SBenno Rice 	return (ch);
314707fed20SBenno Rice }
315707fed20SBenno Rice 
316707fed20SBenno Rice static int
317707fed20SBenno Rice ofw_cons_checkc(dev_t dev)
318707fed20SBenno Rice {
319707fed20SBenno Rice 	unsigned char ch;
320707fed20SBenno Rice 
321cbecdd57SJake Burkholder 	if (OF_read(stdin, &ch, 1) > 0) {
322761f89f9SHartmut Brandt #if defined(DDB) && defined(ALT_BREAK_TO_DEBUGGER)
323761f89f9SHartmut Brandt 		if (db_alt_break(ch, &alt_break_state))
324761f89f9SHartmut Brandt 			breakpoint();
325761f89f9SHartmut Brandt #endif
326707fed20SBenno Rice 		return (ch);
327707fed20SBenno Rice 	}
328707fed20SBenno Rice 
329707fed20SBenno Rice 	return (-1);
330707fed20SBenno Rice }
331707fed20SBenno Rice 
332707fed20SBenno Rice static void
333707fed20SBenno Rice ofw_cons_putc(dev_t dev, int c)
334707fed20SBenno Rice {
335707fed20SBenno Rice 	char cbuf;
336707fed20SBenno Rice 
337707fed20SBenno Rice 	if (c == '\n') {
338707fed20SBenno Rice 		cbuf = '\r';
339707fed20SBenno Rice 		OF_write(stdout, &cbuf, 1);
340707fed20SBenno Rice 	}
341707fed20SBenno Rice 
342707fed20SBenno Rice 	cbuf = c;
343707fed20SBenno Rice 	OF_write(stdout, &cbuf, 1);
344707fed20SBenno Rice }
345