xref: /freebsd/sys/dev/cfe/cfe_console.c (revision 8e8ee9aaba6bff7162e0797555eb0c6abb886861)
1ae36cccdSWarner Losh /*-
2ae36cccdSWarner Losh  * Copyright (c) 2007 Bruce M. Simpson.
3ae36cccdSWarner Losh  * All rights reserved.
4ae36cccdSWarner Losh  *
5ae36cccdSWarner Losh  * Redistribution and use in source and binary forms, with or without
6ae36cccdSWarner Losh  * modification, are permitted provided that the following conditions
7ae36cccdSWarner Losh  * are met:
8ae36cccdSWarner Losh  * 1. Redistributions of source code must retain the above copyright
9ae36cccdSWarner Losh  *    notice, this list of conditions and the following disclaimer.
10ae36cccdSWarner Losh  * 2. Redistributions in binary form must reproduce the above copyright
11ae36cccdSWarner Losh  *    notice, this list of conditions and the following disclaimer in the
12ae36cccdSWarner Losh  *    documentation and/or other materials provided with the distribution.
13ae36cccdSWarner Losh  *
14ae36cccdSWarner Losh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ae36cccdSWarner Losh  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ae36cccdSWarner Losh  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ae36cccdSWarner Losh  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ae36cccdSWarner Losh  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ae36cccdSWarner Losh  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ae36cccdSWarner Losh  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ae36cccdSWarner Losh  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ae36cccdSWarner Losh  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ae36cccdSWarner Losh  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ae36cccdSWarner Losh  * SUCH DAMAGE.
25ae36cccdSWarner Losh  */
26ae36cccdSWarner Losh 
27ae36cccdSWarner Losh #include <sys/cdefs.h>
28ae36cccdSWarner Losh __FBSDID("$FreeBSD$");
29ae36cccdSWarner Losh 
30ae36cccdSWarner Losh #include "opt_comconsole.h"
31ae36cccdSWarner Losh 
32ae36cccdSWarner Losh #include <sys/param.h>
33ae36cccdSWarner Losh #include <sys/kdb.h>
34ae36cccdSWarner Losh #include <sys/kernel.h>
35ae36cccdSWarner Losh #include <sys/priv.h>
36ae36cccdSWarner Losh #include <sys/systm.h>
37ae36cccdSWarner Losh #include <sys/types.h>
38ae36cccdSWarner Losh #include <sys/conf.h>
39ae36cccdSWarner Losh #include <sys/cons.h>
40ae36cccdSWarner Losh #include <sys/consio.h>
41ae36cccdSWarner Losh #include <sys/tty.h>
42ae36cccdSWarner Losh 
43ae36cccdSWarner Losh #include <dev/cfe/cfe_api.h>
44ae36cccdSWarner Losh #include <dev/cfe/cfe_error.h>
45ae36cccdSWarner Losh 
46ae36cccdSWarner Losh #include <ddb/ddb.h>
47ae36cccdSWarner Losh 
48ae36cccdSWarner Losh #ifndef	CFECONS_POLL_HZ
498e8ee9aaSWarner Losh #define	CFECONS_POLL_HZ	4
50ae36cccdSWarner Losh #endif
51ae36cccdSWarner Losh #define CFEBURSTLEN	128	/* max number of bytes to write in one chunk */
52ae36cccdSWarner Losh 
53ae36cccdSWarner Losh static d_open_t		cfe_dev_open;
54ae36cccdSWarner Losh static d_close_t	cfe_dev_close;
55ae36cccdSWarner Losh 
56ae36cccdSWarner Losh static struct cdevsw cfe_cdevsw = {
57ae36cccdSWarner Losh 	.d_version =	D_VERSION,
58ae36cccdSWarner Losh 	.d_open =	cfe_dev_open,
59ae36cccdSWarner Losh 	.d_close =	cfe_dev_close,
60ae36cccdSWarner Losh 	.d_name =	"cfe",
61ae36cccdSWarner Losh 	.d_flags =	D_TTY | D_NEEDGIANT,
62ae36cccdSWarner Losh };
63ae36cccdSWarner Losh 
64ae36cccdSWarner Losh static int			conhandle = -1;
65ae36cccdSWarner Losh static struct tty		*cfe_tp = NULL;
66ae36cccdSWarner Losh /* XXX does cfe have to poll? */
67ae36cccdSWarner Losh static int			polltime;
68ae36cccdSWarner Losh static struct callout_handle	cfe_timeouthandle
69ae36cccdSWarner Losh     = CALLOUT_HANDLE_INITIALIZER(&cfe_timeouthandle);
70ae36cccdSWarner Losh 
71ae36cccdSWarner Losh #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
72ae36cccdSWarner Losh static int			alt_break_state;
73ae36cccdSWarner Losh #endif
74ae36cccdSWarner Losh 
75ae36cccdSWarner Losh static void	cfe_tty_start(struct tty *);
76ae36cccdSWarner Losh static int	cfe_tty_param(struct tty *, struct termios *);
77ae36cccdSWarner Losh static void	cfe_tty_stop(struct tty *, int);
78ae36cccdSWarner Losh static void	cfe_timeout(void *);
79ae36cccdSWarner Losh 
80ae36cccdSWarner Losh static cn_probe_t	cfe_cnprobe;
81ae36cccdSWarner Losh static cn_init_t	cfe_cninit;
82ae36cccdSWarner Losh static cn_term_t	cfe_cnterm;
83ae36cccdSWarner Losh static cn_getc_t	cfe_cngetc;
84ae36cccdSWarner Losh static cn_putc_t	cfe_cnputc;
85ae36cccdSWarner Losh 
86ae36cccdSWarner Losh CONSOLE_DRIVER(cfe);
87ae36cccdSWarner Losh 
88ae36cccdSWarner Losh static void
89ae36cccdSWarner Losh cn_drvinit(void *unused)
90ae36cccdSWarner Losh {
91ae36cccdSWarner Losh 	char output[32];
92ae36cccdSWarner Losh 	struct cdev *dev;
93ae36cccdSWarner Losh 
94ae36cccdSWarner Losh 	if (cfe_consdev.cn_pri != CN_DEAD &&
95ae36cccdSWarner Losh 	    cfe_consdev.cn_name[0] != '\0') {
96ae36cccdSWarner Losh 		dev = make_dev(&cfe_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "%s",
97ae36cccdSWarner Losh 		    output);
98ae36cccdSWarner Losh 		make_dev_alias(dev, "cfecons");
99ae36cccdSWarner Losh 	}
100ae36cccdSWarner Losh }
101ae36cccdSWarner Losh 
102ae36cccdSWarner Losh static int
103ae36cccdSWarner Losh cfe_dev_open(struct cdev *dev, int flag, int mode, struct thread *td)
104ae36cccdSWarner Losh {
105ae36cccdSWarner Losh 	struct	tty *tp;
106ae36cccdSWarner Losh 	int	unit;
107ae36cccdSWarner Losh 	int	error, setuptimeout;
108ae36cccdSWarner Losh 
109ae36cccdSWarner Losh 	error = 0;
110ae36cccdSWarner Losh 	setuptimeout = 0;
111ae36cccdSWarner Losh 	unit = minor(dev);
112ae36cccdSWarner Losh 
113ae36cccdSWarner Losh 	/*
114ae36cccdSWarner Losh 	 * XXX: BAD, should happen at attach time
115ae36cccdSWarner Losh 	 */
116ae36cccdSWarner Losh 	if (dev->si_tty == NULL) {
117ae36cccdSWarner Losh 		cfe_tp = ttyalloc();
118ae36cccdSWarner Losh 		dev->si_tty = cfe_tp;
119ae36cccdSWarner Losh 		cfe_tp->t_dev = dev;
120ae36cccdSWarner Losh 	}
121ae36cccdSWarner Losh 	tp = dev->si_tty;
122ae36cccdSWarner Losh 
123ae36cccdSWarner Losh 	tp->t_oproc = cfe_tty_start;
124ae36cccdSWarner Losh 	tp->t_param = cfe_tty_param;
125ae36cccdSWarner Losh 	tp->t_stop = cfe_tty_stop;
126ae36cccdSWarner Losh 	tp->t_dev = dev;
127ae36cccdSWarner Losh 
128ae36cccdSWarner Losh 	if ((tp->t_state & TS_ISOPEN) == 0) {
129ae36cccdSWarner Losh 		tp->t_state |= TS_CARR_ON;
130ae36cccdSWarner Losh 		ttyconsolemode(tp, 0);
131ae36cccdSWarner Losh 
132ae36cccdSWarner Losh 		setuptimeout = 1;
133ae36cccdSWarner Losh 	} else if ((tp->t_state & TS_XCLUDE) &&
134ae36cccdSWarner Losh 	    priv_check(td, PRIV_TTY_EXCLUSIVE)) {
135ae36cccdSWarner Losh 		return (EBUSY);
136ae36cccdSWarner Losh 	}
137ae36cccdSWarner Losh 
138ae36cccdSWarner Losh 	error = ttyld_open(tp, dev);
139ae36cccdSWarner Losh 
140ae36cccdSWarner Losh 	if (error == 0 && setuptimeout) {
141ae36cccdSWarner Losh 		polltime = hz / CFECONS_POLL_HZ;
142ae36cccdSWarner Losh 		if (polltime < 1) {
143ae36cccdSWarner Losh 			polltime = 1;
144ae36cccdSWarner Losh 		}
145ae36cccdSWarner Losh 
146ae36cccdSWarner Losh 		cfe_timeouthandle = timeout(cfe_timeout, tp, polltime);
147ae36cccdSWarner Losh 	}
148ae36cccdSWarner Losh 
149ae36cccdSWarner Losh 	return (error);
150ae36cccdSWarner Losh }
151ae36cccdSWarner Losh 
152ae36cccdSWarner Losh static int
153ae36cccdSWarner Losh cfe_dev_close(struct cdev *dev, int flag, int mode, struct thread *td)
154ae36cccdSWarner Losh {
155ae36cccdSWarner Losh 	int	unit;
156ae36cccdSWarner Losh 	struct	tty *tp;
157ae36cccdSWarner Losh 
158ae36cccdSWarner Losh 	unit = minor(dev);
159ae36cccdSWarner Losh 	tp = dev->si_tty;
160ae36cccdSWarner Losh 
161ae36cccdSWarner Losh 	if (unit != 0) {
162ae36cccdSWarner Losh 		return (ENXIO);
163ae36cccdSWarner Losh 	}
164ae36cccdSWarner Losh 
165ae36cccdSWarner Losh 	/* XXX Should be replaced with callout_stop(9) */
166ae36cccdSWarner Losh 	untimeout(cfe_timeout, tp, cfe_timeouthandle);
167ae36cccdSWarner Losh 	ttyld_close(tp, flag);
168ae36cccdSWarner Losh 	tty_close(tp);
169ae36cccdSWarner Losh 
170ae36cccdSWarner Losh 	return (0);
171ae36cccdSWarner Losh }
172ae36cccdSWarner Losh 
173ae36cccdSWarner Losh 
174ae36cccdSWarner Losh static int
175ae36cccdSWarner Losh cfe_tty_param(struct tty *tp, struct termios *t)
176ae36cccdSWarner Losh {
177ae36cccdSWarner Losh 
178ae36cccdSWarner Losh 	return (0);
179ae36cccdSWarner Losh }
180ae36cccdSWarner Losh 
181ae36cccdSWarner Losh static void
182ae36cccdSWarner Losh cfe_tty_start(struct tty *tp)
183ae36cccdSWarner Losh {
184ae36cccdSWarner Losh 	struct clist *cl;
185ae36cccdSWarner Losh 	int len;
186ae36cccdSWarner Losh 	u_char buf[CFEBURSTLEN];
187ae36cccdSWarner Losh 
188ae36cccdSWarner Losh 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
189ae36cccdSWarner Losh 		return;
190ae36cccdSWarner Losh 
191ae36cccdSWarner Losh 	tp->t_state |= TS_BUSY;
192ae36cccdSWarner Losh 	cl = &tp->t_outq;
193ae36cccdSWarner Losh 	len = q_to_b(cl, buf, CFEBURSTLEN);
194ae36cccdSWarner Losh 	while (cfe_write(conhandle, buf, len) == 0)
195ae36cccdSWarner Losh 		;
196ae36cccdSWarner Losh 	tp->t_state &= ~TS_BUSY;
197ae36cccdSWarner Losh 
198ae36cccdSWarner Losh 	ttwwakeup(tp);
199ae36cccdSWarner Losh }
200ae36cccdSWarner Losh 
201ae36cccdSWarner Losh static void
202ae36cccdSWarner Losh cfe_tty_stop(struct tty *tp, int flag)
203ae36cccdSWarner Losh {
204ae36cccdSWarner Losh 
205ae36cccdSWarner Losh 	if (tp->t_state & TS_BUSY) {
206ae36cccdSWarner Losh 		if ((tp->t_state & TS_TTSTOP) == 0) {
207ae36cccdSWarner Losh 			tp->t_state |= TS_FLUSH;
208ae36cccdSWarner Losh 		}
209ae36cccdSWarner Losh 	}
210ae36cccdSWarner Losh }
211ae36cccdSWarner Losh 
212ae36cccdSWarner Losh static void
213ae36cccdSWarner Losh cfe_timeout(void *v)
214ae36cccdSWarner Losh {
215ae36cccdSWarner Losh 	struct	tty *tp;
216ae36cccdSWarner Losh 	int 	c;
217ae36cccdSWarner Losh 
218ae36cccdSWarner Losh 	tp = (struct tty *)v;
219ae36cccdSWarner Losh 
220ae36cccdSWarner Losh 	while ((c = cfe_cngetc(NULL)) != -1) {
221ae36cccdSWarner Losh 		if (tp->t_state & TS_ISOPEN) {
222ae36cccdSWarner Losh 			ttyld_rint(tp, c);
223ae36cccdSWarner Losh 		}
224ae36cccdSWarner Losh 	}
225ae36cccdSWarner Losh 
226ae36cccdSWarner Losh 	cfe_timeouthandle = timeout(cfe_timeout, tp, polltime);
227ae36cccdSWarner Losh }
228ae36cccdSWarner Losh 
229ae36cccdSWarner Losh static void
230ae36cccdSWarner Losh cfe_cnprobe(struct consdev *cp)
231ae36cccdSWarner Losh {
232ae36cccdSWarner Losh 
233ae36cccdSWarner Losh 	conhandle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
234ae36cccdSWarner Losh 	if (conhandle < 0) {
235ae36cccdSWarner Losh 		cp->cn_pri = CN_DEAD;
236ae36cccdSWarner Losh 		return;
237ae36cccdSWarner Losh 	}
238ae36cccdSWarner Losh 
239ae36cccdSWarner Losh 	/* XXX */
240ae36cccdSWarner Losh 	if (bootverbose) {
241ae36cccdSWarner Losh 		char *bootmsg = "Using CFE firmware console.\n";
242ae36cccdSWarner Losh 		int i;
243ae36cccdSWarner Losh 
244ae36cccdSWarner Losh 		for (i = 0; i < strlen(bootmsg); i++)
245ae36cccdSWarner Losh 			cfe_cnputc(cp, bootmsg[i]);
246ae36cccdSWarner Losh 	}
247ae36cccdSWarner Losh 
248ae36cccdSWarner Losh 	cp->cn_pri = CN_LOW;
249ae36cccdSWarner Losh }
250ae36cccdSWarner Losh 
251ae36cccdSWarner Losh static void
252ae36cccdSWarner Losh cfe_cninit(struct consdev *cp)
253ae36cccdSWarner Losh {
254ae36cccdSWarner Losh 
255ae36cccdSWarner Losh 	sprintf(cp->cn_name, "cfecons");
256ae36cccdSWarner Losh 	cp->cn_tp = cfe_tp;
257ae36cccdSWarner Losh }
258ae36cccdSWarner Losh 
259ae36cccdSWarner Losh static void
260ae36cccdSWarner Losh cfe_cnterm(struct consdev *cp)
261ae36cccdSWarner Losh {
262ae36cccdSWarner Losh 
263ae36cccdSWarner Losh }
264ae36cccdSWarner Losh 
265ae36cccdSWarner Losh static int
266ae36cccdSWarner Losh cfe_cngetc(struct consdev *cp)
267ae36cccdSWarner Losh {
268ae36cccdSWarner Losh 	int result;
269ae36cccdSWarner Losh 	unsigned char ch;
270ae36cccdSWarner Losh 
271ae36cccdSWarner Losh 	while ((result = cfe_read(conhandle, &ch, 1)) == 0)
272ae36cccdSWarner Losh 		;
273ae36cccdSWarner Losh 
274ae36cccdSWarner Losh 	if (result > 0) {
275ae36cccdSWarner Losh #if defined(KDB) && defined(ALT_BREAK_TO_DEBUGGER)
276ae36cccdSWarner Losh 		if (kdb_alt_break(ch, &alt_break_state))
277ae36cccdSWarner Losh 			kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
278ae36cccdSWarner Losh #endif
279ae36cccdSWarner Losh 		return (ch);
280ae36cccdSWarner Losh 	}
281ae36cccdSWarner Losh 
282ae36cccdSWarner Losh 	return (-1);
283ae36cccdSWarner Losh }
284ae36cccdSWarner Losh 
285ae36cccdSWarner Losh static void
286ae36cccdSWarner Losh cfe_cnputc(struct consdev *cp, int c)
287ae36cccdSWarner Losh {
288ae36cccdSWarner Losh 	char cbuf;
289ae36cccdSWarner Losh 
290ae36cccdSWarner Losh 	if (c == '\n')
291ae36cccdSWarner Losh 		cfe_cnputc(cp, '\r');
292ae36cccdSWarner Losh 
293ae36cccdSWarner Losh 	cbuf = c;
294ae36cccdSWarner Losh 	while (cfe_write(conhandle, &cbuf, 1) == 0)
295ae36cccdSWarner Losh 		;
296ae36cccdSWarner Losh }
297ae36cccdSWarner Losh 
298ae36cccdSWarner Losh SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL)
299