bvm_console.c revision 225598
1221905Sgrehan/*-
2221905Sgrehan * Copyright (c) 2011 NetApp, Inc.
3221905Sgrehan * All rights reserved.
4221905Sgrehan *
5221905Sgrehan * Redistribution and use in source and binary forms, with or without
6221905Sgrehan * modification, are permitted provided that the following conditions
7221905Sgrehan * are met:
8221905Sgrehan * 1. Redistributions of source code must retain the above copyright
9221905Sgrehan *    notice, this list of conditions and the following disclaimer.
10221905Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11221905Sgrehan *    notice, this list of conditions and the following disclaimer in the
12221905Sgrehan *    documentation and/or other materials provided with the distribution.
13221905Sgrehan *
14221905Sgrehan * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15221905Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16221905Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17221905Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18221905Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19221905Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20221905Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21221905Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22221905Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23221905Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24221905Sgrehan * SUCH DAMAGE.
25221905Sgrehan *
26221905Sgrehan * $FreeBSD$
27221905Sgrehan */
28221905Sgrehan
29221905Sgrehan#include <sys/cdefs.h>
30221905Sgrehan__FBSDID("$FreeBSD$");
31221905Sgrehan
32221905Sgrehan#include <sys/param.h>
33221905Sgrehan#include <sys/kernel.h>
34221905Sgrehan#include <sys/systm.h>
35221905Sgrehan#include <sys/types.h>
36221905Sgrehan#include <sys/cons.h>
37221905Sgrehan#include <sys/tty.h>
38221905Sgrehan#include <sys/reboot.h>
39221905Sgrehan#include <sys/bus.h>
40221905Sgrehan
41221905Sgrehan#include <sys/kdb.h>
42221905Sgrehan#include <ddb/ddb.h>
43221905Sgrehan
44221905Sgrehan#ifndef	BVMCONS_POLL_HZ
45221905Sgrehan#define	BVMCONS_POLL_HZ	4
46221905Sgrehan#endif
47221905Sgrehan#define BVMBURSTLEN	16	/* max number of bytes to write in one chunk */
48221905Sgrehan
49221905Sgrehanstatic tsw_open_t bvm_tty_open;
50221905Sgrehanstatic tsw_close_t bvm_tty_close;
51221905Sgrehanstatic tsw_outwakeup_t bvm_tty_outwakeup;
52221905Sgrehan
53221905Sgrehanstatic struct ttydevsw bvm_ttydevsw = {
54221905Sgrehan	.tsw_flags	= TF_NOPREFIX,
55221905Sgrehan	.tsw_open	= bvm_tty_open,
56221905Sgrehan	.tsw_close	= bvm_tty_close,
57221905Sgrehan	.tsw_outwakeup	= bvm_tty_outwakeup,
58221905Sgrehan};
59221905Sgrehan
60221905Sgrehanstatic int			polltime;
61221905Sgrehanstatic struct callout_handle	bvm_timeouthandle
62221905Sgrehan    = CALLOUT_HANDLE_INITIALIZER(&bvm_timeouthandle);
63221905Sgrehan
64225598Sgrehan#if defined(KDB)
65221905Sgrehanstatic int			alt_break_state;
66221905Sgrehan#endif
67221905Sgrehan
68221905Sgrehan#define	BVM_CONS_PORT	0x220
69221905Sgrehanstatic int bvm_cons_port = BVM_CONS_PORT;
70221905Sgrehan
71222105Sgrehan#define BVM_CONS_SIG	('b' << 8 | 'v')
72222105Sgrehan
73221905Sgrehanstatic void	bvm_timeout(void *);
74221905Sgrehan
75221905Sgrehanstatic cn_probe_t	bvm_cnprobe;
76221905Sgrehanstatic cn_init_t	bvm_cninit;
77221905Sgrehanstatic cn_term_t	bvm_cnterm;
78221905Sgrehanstatic cn_getc_t	bvm_cngetc;
79221905Sgrehanstatic cn_putc_t	bvm_cnputc;
80221905Sgrehan
81221905SgrehanCONSOLE_DRIVER(bvm);
82221905Sgrehan
83221905Sgrehanstatic int
84221905Sgrehanbvm_rcons(u_char *ch)
85221905Sgrehan{
86221905Sgrehan	int c;
87221905Sgrehan
88221905Sgrehan	c = inl(bvm_cons_port);
89221905Sgrehan	if (c != -1) {
90221905Sgrehan		*ch = (u_char)c;
91221905Sgrehan		return (0);
92221905Sgrehan	} else
93221905Sgrehan		return (-1);
94221905Sgrehan}
95221905Sgrehan
96221905Sgrehanstatic void
97221905Sgrehanbvm_wcons(u_char ch)
98221905Sgrehan{
99221905Sgrehan
100221905Sgrehan	outl(bvm_cons_port, ch);
101221905Sgrehan}
102221905Sgrehan
103221905Sgrehanstatic void
104221905Sgrehancn_drvinit(void *unused)
105221905Sgrehan{
106221905Sgrehan	struct tty *tp;
107221905Sgrehan
108221905Sgrehan	if (bvm_consdev.cn_pri != CN_DEAD &&
109221905Sgrehan	    bvm_consdev.cn_name[0] != '\0') {
110221905Sgrehan		tp = tty_alloc(&bvm_ttydevsw, NULL);
111221905Sgrehan		tty_makedev(tp, NULL, "bvmcons");
112221905Sgrehan	}
113221905Sgrehan}
114221905Sgrehan
115221905Sgrehanstatic int
116221905Sgrehanbvm_tty_open(struct tty *tp)
117221905Sgrehan{
118221905Sgrehan	polltime = hz / BVMCONS_POLL_HZ;
119221905Sgrehan	if (polltime < 1)
120221905Sgrehan		polltime = 1;
121221905Sgrehan	bvm_timeouthandle = timeout(bvm_timeout, tp, polltime);
122221905Sgrehan
123221905Sgrehan	return (0);
124221905Sgrehan}
125221905Sgrehan
126221905Sgrehanstatic void
127221905Sgrehanbvm_tty_close(struct tty *tp)
128221905Sgrehan{
129221905Sgrehan
130221905Sgrehan	/* XXX Should be replaced with callout_stop(9) */
131221905Sgrehan	untimeout(bvm_timeout, tp, bvm_timeouthandle);
132221905Sgrehan}
133221905Sgrehan
134221905Sgrehanstatic void
135221905Sgrehanbvm_tty_outwakeup(struct tty *tp)
136221905Sgrehan{
137221905Sgrehan	int len, written;
138221905Sgrehan	u_char buf[BVMBURSTLEN];
139221905Sgrehan
140221905Sgrehan	for (;;) {
141221905Sgrehan		len = ttydisc_getc(tp, buf, sizeof(buf));
142221905Sgrehan		if (len == 0)
143221905Sgrehan			break;
144221905Sgrehan
145221905Sgrehan		written = 0;
146221905Sgrehan		while (written < len)
147221905Sgrehan			bvm_wcons(buf[written++]);
148221905Sgrehan	}
149221905Sgrehan}
150221905Sgrehan
151221905Sgrehanstatic void
152221905Sgrehanbvm_timeout(void *v)
153221905Sgrehan{
154221905Sgrehan	struct	tty *tp;
155221905Sgrehan	int 	c;
156221905Sgrehan
157221905Sgrehan	tp = (struct tty *)v;
158221905Sgrehan
159221905Sgrehan	tty_lock(tp);
160221905Sgrehan	while ((c = bvm_cngetc(NULL)) != -1)
161221905Sgrehan		ttydisc_rint(tp, c, 0);
162221905Sgrehan	ttydisc_rint_done(tp);
163221905Sgrehan	tty_unlock(tp);
164221905Sgrehan
165221905Sgrehan	bvm_timeouthandle = timeout(bvm_timeout, tp, polltime);
166221905Sgrehan}
167221905Sgrehan
168221905Sgrehanstatic void
169221905Sgrehanbvm_cnprobe(struct consdev *cp)
170221905Sgrehan{
171221905Sgrehan	int disabled, port;
172221905Sgrehan
173221905Sgrehan	disabled = 0;
174222105Sgrehan	cp->cn_pri = CN_DEAD;
175222105Sgrehan
176221905Sgrehan	resource_int_value("bvmconsole", 0, "disabled", &disabled);
177222105Sgrehan	if (!disabled) {
178222105Sgrehan		if (resource_int_value("bvmconsole", 0, "port", &port) == 0)
179222105Sgrehan			bvm_cons_port = port;
180221905Sgrehan
181222105Sgrehan		if (inw(bvm_cons_port) == BVM_CONS_SIG)
182222105Sgrehan			cp->cn_pri = CN_REMOTE;
183222105Sgrehan	}
184221905Sgrehan}
185221905Sgrehan
186221905Sgrehanstatic void
187221905Sgrehanbvm_cninit(struct consdev *cp)
188221905Sgrehan{
189221905Sgrehan	int i;
190221905Sgrehan	const char *bootmsg = "Using bvm console.\n";
191221905Sgrehan
192221905Sgrehan	if (boothowto & RB_VERBOSE) {
193221905Sgrehan		for (i = 0; i < strlen(bootmsg); i++)
194221905Sgrehan			bvm_cnputc(cp, bootmsg[i]);
195221905Sgrehan	}
196221905Sgrehan
197221905Sgrehan	strcpy(cp->cn_name, "bvmcons");
198221905Sgrehan}
199221905Sgrehan
200221905Sgrehanstatic void
201221905Sgrehanbvm_cnterm(struct consdev *cp)
202221905Sgrehan{
203221905Sgrehan
204221905Sgrehan}
205221905Sgrehan
206221905Sgrehanstatic int
207221905Sgrehanbvm_cngetc(struct consdev *cp)
208221905Sgrehan{
209221905Sgrehan	unsigned char ch;
210221905Sgrehan
211221905Sgrehan	if (bvm_rcons(&ch) == 0) {
212225598Sgrehan#if defined(KDB)
213225598Sgrehan		kdb_alt_break(ch, &alt_break_state);
214221905Sgrehan#endif
215221905Sgrehan		return (ch);
216221905Sgrehan	}
217221905Sgrehan
218221905Sgrehan	return (-1);
219221905Sgrehan}
220221905Sgrehan
221221905Sgrehanstatic void
222221905Sgrehanbvm_cnputc(struct consdev *cp, int c)
223221905Sgrehan{
224221905Sgrehan
225221905Sgrehan	bvm_wcons(c);
226221905Sgrehan}
227221905Sgrehan
228221905SgrehanSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
229