xref: /freebsd/sys/dev/ofw/ofw_console.c (revision 47a1c9151495c236f571a8c99ca848ec848e90f4)
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 
31707fed20SBenno Rice #include <sys/param.h>
32707fed20SBenno Rice #include <sys/kernel.h>
33707fed20SBenno Rice #include <sys/systm.h>
34707fed20SBenno Rice #include <sys/types.h>
35707fed20SBenno Rice #include <sys/conf.h>
36707fed20SBenno Rice #include <sys/cons.h>
37707fed20SBenno Rice #include <sys/consio.h>
38707fed20SBenno Rice #include <sys/tty.h>
39707fed20SBenno Rice 
40707fed20SBenno Rice #include <dev/ofw/openfirm.h>
41707fed20SBenno Rice 
42cbecdd57SJake Burkholder #define	OFW_POLL_HZ	4
43707fed20SBenno Rice 
44707fed20SBenno Rice static d_open_t		ofw_dev_open;
45707fed20SBenno Rice static d_close_t	ofw_dev_close;
46707fed20SBenno Rice static d_ioctl_t	ofw_dev_ioctl;
47707fed20SBenno Rice 
48707fed20SBenno Rice #define	CDEV_MAJOR	97
49707fed20SBenno Rice 
50707fed20SBenno Rice static struct cdevsw ofw_cdevsw = {
51707fed20SBenno Rice 	/* open */	ofw_dev_open,
52707fed20SBenno Rice 	/* close */	ofw_dev_close,
53707fed20SBenno Rice 	/* read */	ttyread,
54707fed20SBenno Rice 	/* write */	ttywrite,
55707fed20SBenno Rice 	/* ioctl */	ofw_dev_ioctl,
56707fed20SBenno Rice 	/* poll */	ttypoll,
57707fed20SBenno Rice 	/* mmap */	nommap,
58707fed20SBenno Rice 	/* strategy */	nostrategy,
59707fed20SBenno Rice 	/* name */	"ofw",
60707fed20SBenno Rice 	/* major */	CDEV_MAJOR,
61707fed20SBenno Rice 	/* dump */	nodump,
62707fed20SBenno Rice 	/* psize */	nopsize,
63707fed20SBenno Rice 	/* flags */	0,
64707fed20SBenno Rice };
65707fed20SBenno Rice 
66707fed20SBenno Rice static struct tty		*ofw_tp = NULL;
67707fed20SBenno Rice static int			polltime;
68707fed20SBenno Rice static struct callout_handle	ofw_timeouthandle
69707fed20SBenno Rice     = CALLOUT_HANDLE_INITIALIZER(&ofw_timeouthandle);
70707fed20SBenno Rice 
71707fed20SBenno Rice static void	ofw_tty_start(struct tty *);
72707fed20SBenno Rice static int	ofw_tty_param(struct tty *, struct termios *);
73707fed20SBenno Rice static void	ofw_tty_stop(struct tty *, int);
74707fed20SBenno Rice static void	ofw_timeout(void *);
75707fed20SBenno Rice 
76707fed20SBenno Rice static cn_probe_t	ofw_cons_probe;
77707fed20SBenno Rice static cn_init_t	ofw_cons_init;
78707fed20SBenno Rice static cn_getc_t	ofw_cons_getc;
79707fed20SBenno Rice static cn_checkc_t 	ofw_cons_checkc;
80707fed20SBenno Rice static cn_putc_t	ofw_cons_putc;
81707fed20SBenno Rice 
82707fed20SBenno Rice CONS_DRIVER(ofw, ofw_cons_probe, ofw_cons_init, NULL, ofw_cons_getc,
83707fed20SBenno Rice     ofw_cons_checkc, ofw_cons_putc, NULL);
84707fed20SBenno Rice 
8547a1c915SJake Burkholder static void
8647a1c915SJake Burkholder cn_drvinit(void *unused)
8747a1c915SJake Burkholder {
8847a1c915SJake Burkholder 
8947a1c915SJake Burkholder 	make_dev(&ofw_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "ofwcons");
9047a1c915SJake Burkholder }
9147a1c915SJake Burkholder 
9247a1c915SJake Burkholder SYSINIT(cndev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,cn_drvinit,NULL)
9347a1c915SJake Burkholder 
94707fed20SBenno Rice static int	stdin;
95707fed20SBenno Rice static int	stdout;
96707fed20SBenno Rice 
97707fed20SBenno Rice static int
98b40ce416SJulian Elischer ofw_dev_open(dev_t dev, int flag, int mode, struct thread *td)
99707fed20SBenno Rice {
100707fed20SBenno Rice 	struct	tty *tp;
101707fed20SBenno Rice 	int	unit;
102707fed20SBenno Rice 	int	error, setuptimeout;
103707fed20SBenno Rice 
104707fed20SBenno Rice 	error = 0;
105707fed20SBenno Rice 	setuptimeout = 0;
106707fed20SBenno Rice 	unit = minor(dev);
107707fed20SBenno Rice 
108707fed20SBenno Rice 	tp = ofw_tp = dev->si_tty = ttymalloc(ofw_tp);
109707fed20SBenno Rice 
110707fed20SBenno Rice 	tp->t_oproc = ofw_tty_start;
111707fed20SBenno Rice 	tp->t_param = ofw_tty_param;
112707fed20SBenno Rice 	tp->t_stop = ofw_tty_stop;
113707fed20SBenno Rice 	tp->t_dev = dev;
114707fed20SBenno Rice 
115707fed20SBenno Rice 	if ((tp->t_state & TS_ISOPEN) == 0) {
116707fed20SBenno Rice 		tp->t_state |= TS_CARR_ON;
117707fed20SBenno Rice 		ttychars(tp);
118707fed20SBenno Rice 		tp->t_iflag = TTYDEF_IFLAG;
119707fed20SBenno Rice 		tp->t_oflag = TTYDEF_OFLAG;
120707fed20SBenno Rice 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
121707fed20SBenno Rice 		tp->t_lflag = TTYDEF_LFLAG;
122707fed20SBenno Rice 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
123707fed20SBenno Rice 		ttsetwater(tp);
124707fed20SBenno Rice 
125707fed20SBenno Rice 		setuptimeout = 1;
126b40ce416SJulian Elischer 	} else if ((tp->t_state & TS_XCLUDE) && suser_td(td)) {
127707fed20SBenno Rice 		return (EBUSY);
128707fed20SBenno Rice 	}
129707fed20SBenno Rice 
130707fed20SBenno Rice 	error = (*linesw[tp->t_line].l_open)(dev, tp);
131707fed20SBenno Rice 
132707fed20SBenno Rice 	if (error == 0 && setuptimeout) {
133707fed20SBenno Rice 		polltime = hz / OFW_POLL_HZ;
134707fed20SBenno Rice 		if (polltime < 1) {
135707fed20SBenno Rice 			polltime = 1;
136707fed20SBenno Rice 		}
137707fed20SBenno Rice 
138707fed20SBenno Rice 		ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
139707fed20SBenno Rice 	}
140707fed20SBenno Rice 
141707fed20SBenno Rice 	return (error);
142707fed20SBenno Rice }
143707fed20SBenno Rice 
144707fed20SBenno Rice static int
145b40ce416SJulian Elischer ofw_dev_close(dev_t dev, int flag, int mode, struct thread *td)
146707fed20SBenno Rice {
147707fed20SBenno Rice 	int	unit;
148707fed20SBenno Rice 	struct	tty *tp;
149707fed20SBenno Rice 
150707fed20SBenno Rice 	unit = minor(dev);
151707fed20SBenno Rice 	tp = ofw_tp;
152707fed20SBenno Rice 
153707fed20SBenno Rice 	if (unit != 0) {
154707fed20SBenno Rice 		return (ENXIO);
155707fed20SBenno Rice 	}
156707fed20SBenno Rice 
157707fed20SBenno Rice 	(*linesw[tp->t_line].l_close)(tp, flag);
158707fed20SBenno Rice 	ttyclose(tp);
159707fed20SBenno Rice 
160707fed20SBenno Rice 	return (0);
161707fed20SBenno Rice }
162707fed20SBenno Rice 
163707fed20SBenno Rice static int
164b40ce416SJulian Elischer ofw_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
165707fed20SBenno Rice {
166707fed20SBenno Rice 	int	unit;
167707fed20SBenno Rice 	struct	tty *tp;
168707fed20SBenno Rice 	int	error;
169707fed20SBenno Rice 
170707fed20SBenno Rice 	unit = minor(dev);
171c22c65b1SJake Burkholder 	tp = ofw_tp;
172c22c65b1SJake Burkholder 
173707fed20SBenno Rice 	if (unit != 0) {
174707fed20SBenno Rice 		return (ENXIO);
175707fed20SBenno Rice 	}
176707fed20SBenno Rice 
177b40ce416SJulian Elischer 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
178707fed20SBenno Rice 	if (error != ENOIOCTL) {
179707fed20SBenno Rice 		return (error);
180707fed20SBenno Rice 	}
181707fed20SBenno Rice 
182707fed20SBenno Rice 	error = ttioctl(tp, cmd, data, flag);
183707fed20SBenno Rice 	if (error != ENOIOCTL) {
184707fed20SBenno Rice 		return (error);
185707fed20SBenno Rice 	}
186707fed20SBenno Rice 
187707fed20SBenno Rice 	return (ENOTTY);
188707fed20SBenno Rice }
189707fed20SBenno Rice 
190707fed20SBenno Rice static int
191707fed20SBenno Rice ofw_tty_param(struct tty *tp, struct termios *t)
192707fed20SBenno Rice {
193707fed20SBenno Rice 
194707fed20SBenno Rice 	return (0);
195707fed20SBenno Rice }
196707fed20SBenno Rice 
197707fed20SBenno Rice static void
198707fed20SBenno Rice ofw_tty_start(struct tty *tp)
199707fed20SBenno Rice {
200707fed20SBenno Rice 
201707fed20SBenno Rice 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
202707fed20SBenno Rice 		ttwwakeup(tp);
203707fed20SBenno Rice 		return;
204707fed20SBenno Rice 	}
205707fed20SBenno Rice 
206707fed20SBenno Rice 	tp->t_state |= TS_BUSY;
207707fed20SBenno Rice 	while (tp->t_outq.c_cc != 0) {
208707fed20SBenno Rice 		ofw_cons_putc(tp->t_dev, getc(&tp->t_outq));
209707fed20SBenno Rice 	}
210707fed20SBenno Rice 	tp->t_state &= ~TS_BUSY;
211707fed20SBenno Rice 
212707fed20SBenno Rice 	ttwwakeup(tp);
213707fed20SBenno Rice }
214707fed20SBenno Rice 
215707fed20SBenno Rice static void
216707fed20SBenno Rice ofw_tty_stop(struct tty *tp, int flag)
217707fed20SBenno Rice {
218707fed20SBenno Rice 
219707fed20SBenno Rice 	if (tp->t_state & TS_BUSY) {
220707fed20SBenno Rice 		if ((tp->t_state & TS_TTSTOP) == 0) {
221707fed20SBenno Rice 			tp->t_state |= TS_FLUSH;
222707fed20SBenno Rice 		}
223707fed20SBenno Rice 	}
224707fed20SBenno Rice }
225707fed20SBenno Rice 
226707fed20SBenno Rice static void
227707fed20SBenno Rice ofw_timeout(void *v)
228707fed20SBenno Rice {
229707fed20SBenno Rice 	struct	tty *tp;
230707fed20SBenno Rice 	int 	c;
231707fed20SBenno Rice 
232707fed20SBenno Rice 	tp = (struct tty *)v;
233707fed20SBenno Rice 
234707fed20SBenno Rice 	while ((c = ofw_cons_checkc(tp->t_dev)) != -1) {
235707fed20SBenno Rice 		if (tp->t_state & TS_ISOPEN) {
236707fed20SBenno Rice 			(*linesw[tp->t_line].l_rint)(c, tp);
237707fed20SBenno Rice 		}
238707fed20SBenno Rice 	}
239707fed20SBenno Rice 
240707fed20SBenno Rice 	ofw_timeouthandle = timeout(ofw_timeout, tp, polltime);
241707fed20SBenno Rice }
242707fed20SBenno Rice 
243707fed20SBenno Rice static void
244707fed20SBenno Rice ofw_cons_probe(struct consdev *cp)
245707fed20SBenno Rice {
246707fed20SBenno Rice 	int chosen;
247707fed20SBenno Rice 
248707fed20SBenno Rice 	if ((chosen = OF_finddevice("/chosen")) == -1) {
249707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
250707fed20SBenno Rice 		return;
251707fed20SBenno Rice 	}
252707fed20SBenno Rice 
253707fed20SBenno Rice 	if (OF_getprop(chosen, "stdin", &stdin, sizeof(stdin)) == -1) {
254707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
255707fed20SBenno Rice 		return;
256707fed20SBenno Rice 	}
257707fed20SBenno Rice 
258707fed20SBenno Rice 	if (OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)) == -1) {
259707fed20SBenno Rice 		cp->cn_pri = CN_DEAD;
260707fed20SBenno Rice 		return;
261707fed20SBenno Rice 	}
262707fed20SBenno Rice 
263707fed20SBenno Rice 	cp->cn_dev = makedev(CDEV_MAJOR, 0);
264707fed20SBenno Rice 	cp->cn_pri = CN_INTERNAL;
265707fed20SBenno Rice 	cp->cn_tp = ofw_tp;
266707fed20SBenno Rice }
267707fed20SBenno Rice 
268707fed20SBenno Rice static void
269707fed20SBenno Rice ofw_cons_init(struct consdev *cp)
270707fed20SBenno Rice {
271707fed20SBenno Rice 
272707fed20SBenno Rice 	return;
273707fed20SBenno Rice }
274707fed20SBenno Rice 
275707fed20SBenno Rice static int
276707fed20SBenno Rice ofw_cons_getc(dev_t dev)
277707fed20SBenno Rice {
278707fed20SBenno Rice 	unsigned char ch;
279707fed20SBenno Rice 	int l;
280707fed20SBenno Rice 
281707fed20SBenno Rice 	ch = '\0';
282707fed20SBenno Rice 
283707fed20SBenno Rice 	while ((l = OF_read(stdin, &ch, 1)) != 1) {
284707fed20SBenno Rice 		if (l != -2 && l != 0) {
285707fed20SBenno Rice 			return (-1);
286707fed20SBenno Rice 		}
287707fed20SBenno Rice 	}
288707fed20SBenno Rice 
289707fed20SBenno Rice 	return (ch);
290707fed20SBenno Rice }
291707fed20SBenno Rice 
292707fed20SBenno Rice static int
293707fed20SBenno Rice ofw_cons_checkc(dev_t dev)
294707fed20SBenno Rice {
295707fed20SBenno Rice 	unsigned char ch;
296707fed20SBenno Rice 
297cbecdd57SJake Burkholder 	if (OF_read(stdin, &ch, 1) > 0) {
298707fed20SBenno Rice 		return (ch);
299707fed20SBenno Rice 	}
300707fed20SBenno Rice 
301707fed20SBenno Rice 	return (-1);
302707fed20SBenno Rice }
303707fed20SBenno Rice 
304707fed20SBenno Rice static void
305707fed20SBenno Rice ofw_cons_putc(dev_t dev, int c)
306707fed20SBenno Rice {
307707fed20SBenno Rice 	char cbuf;
308707fed20SBenno Rice 
309707fed20SBenno Rice 	if (c == '\n') {
310707fed20SBenno Rice 		cbuf = '\r';
311707fed20SBenno Rice 		OF_write(stdout, &cbuf, 1);
312707fed20SBenno Rice 	}
313707fed20SBenno Rice 
314707fed20SBenno Rice 	cbuf = c;
315707fed20SBenno Rice 	OF_write(stdout, &cbuf, 1);
316707fed20SBenno Rice }
317