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: releng/10.2/sys/dev/bvm/bvm_console.c 245678 2013-01-20 03:42:49Z neel $
27221905Sgrehan */
28221905Sgrehan
29221905Sgrehan#include <sys/cdefs.h>
30221905Sgrehan__FBSDID("$FreeBSD: releng/10.2/sys/dev/bvm/bvm_console.c 245678 2013-01-20 03:42:49Z neel $");
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;
80229507Ssbrunostatic cn_grab_t 	bvm_cngrab;
81229507Ssbrunostatic cn_ungrab_t 	bvm_cnungrab;
82221905Sgrehan
83221905SgrehanCONSOLE_DRIVER(bvm);
84221905Sgrehan
85221905Sgrehanstatic int
86221905Sgrehanbvm_rcons(u_char *ch)
87221905Sgrehan{
88221905Sgrehan	int c;
89221905Sgrehan
90221905Sgrehan	c = inl(bvm_cons_port);
91221905Sgrehan	if (c != -1) {
92221905Sgrehan		*ch = (u_char)c;
93221905Sgrehan		return (0);
94221905Sgrehan	} else
95221905Sgrehan		return (-1);
96221905Sgrehan}
97221905Sgrehan
98221905Sgrehanstatic void
99221905Sgrehanbvm_wcons(u_char ch)
100221905Sgrehan{
101221905Sgrehan
102221905Sgrehan	outl(bvm_cons_port, ch);
103221905Sgrehan}
104221905Sgrehan
105221905Sgrehanstatic void
106221905Sgrehancn_drvinit(void *unused)
107221905Sgrehan{
108221905Sgrehan	struct tty *tp;
109221905Sgrehan
110221905Sgrehan	if (bvm_consdev.cn_pri != CN_DEAD &&
111221905Sgrehan	    bvm_consdev.cn_name[0] != '\0') {
112221905Sgrehan		tp = tty_alloc(&bvm_ttydevsw, NULL);
113221905Sgrehan		tty_makedev(tp, NULL, "bvmcons");
114221905Sgrehan	}
115221905Sgrehan}
116221905Sgrehan
117221905Sgrehanstatic int
118221905Sgrehanbvm_tty_open(struct tty *tp)
119221905Sgrehan{
120221905Sgrehan	polltime = hz / BVMCONS_POLL_HZ;
121221905Sgrehan	if (polltime < 1)
122221905Sgrehan		polltime = 1;
123221905Sgrehan	bvm_timeouthandle = timeout(bvm_timeout, tp, polltime);
124221905Sgrehan
125221905Sgrehan	return (0);
126221905Sgrehan}
127221905Sgrehan
128221905Sgrehanstatic void
129221905Sgrehanbvm_tty_close(struct tty *tp)
130221905Sgrehan{
131221905Sgrehan
132221905Sgrehan	/* XXX Should be replaced with callout_stop(9) */
133221905Sgrehan	untimeout(bvm_timeout, tp, bvm_timeouthandle);
134221905Sgrehan}
135221905Sgrehan
136221905Sgrehanstatic void
137221905Sgrehanbvm_tty_outwakeup(struct tty *tp)
138221905Sgrehan{
139221905Sgrehan	int len, written;
140221905Sgrehan	u_char buf[BVMBURSTLEN];
141221905Sgrehan
142221905Sgrehan	for (;;) {
143221905Sgrehan		len = ttydisc_getc(tp, buf, sizeof(buf));
144221905Sgrehan		if (len == 0)
145221905Sgrehan			break;
146221905Sgrehan
147221905Sgrehan		written = 0;
148221905Sgrehan		while (written < len)
149221905Sgrehan			bvm_wcons(buf[written++]);
150221905Sgrehan	}
151221905Sgrehan}
152221905Sgrehan
153221905Sgrehanstatic void
154221905Sgrehanbvm_timeout(void *v)
155221905Sgrehan{
156221905Sgrehan	struct	tty *tp;
157221905Sgrehan	int 	c;
158221905Sgrehan
159221905Sgrehan	tp = (struct tty *)v;
160221905Sgrehan
161221905Sgrehan	tty_lock(tp);
162221905Sgrehan	while ((c = bvm_cngetc(NULL)) != -1)
163221905Sgrehan		ttydisc_rint(tp, c, 0);
164221905Sgrehan	ttydisc_rint_done(tp);
165221905Sgrehan	tty_unlock(tp);
166221905Sgrehan
167221905Sgrehan	bvm_timeouthandle = timeout(bvm_timeout, tp, polltime);
168221905Sgrehan}
169221905Sgrehan
170221905Sgrehanstatic void
171221905Sgrehanbvm_cnprobe(struct consdev *cp)
172221905Sgrehan{
173221905Sgrehan	int disabled, port;
174221905Sgrehan
175221905Sgrehan	disabled = 0;
176222105Sgrehan	cp->cn_pri = CN_DEAD;
177222105Sgrehan
178221905Sgrehan	resource_int_value("bvmconsole", 0, "disabled", &disabled);
179222105Sgrehan	if (!disabled) {
180222105Sgrehan		if (resource_int_value("bvmconsole", 0, "port", &port) == 0)
181222105Sgrehan			bvm_cons_port = port;
182221905Sgrehan
183222105Sgrehan		if (inw(bvm_cons_port) == BVM_CONS_SIG)
184222105Sgrehan			cp->cn_pri = CN_REMOTE;
185222105Sgrehan	}
186221905Sgrehan}
187221905Sgrehan
188221905Sgrehanstatic void
189221905Sgrehanbvm_cninit(struct consdev *cp)
190221905Sgrehan{
191221905Sgrehan	int i;
192221905Sgrehan	const char *bootmsg = "Using bvm console.\n";
193221905Sgrehan
194221905Sgrehan	if (boothowto & RB_VERBOSE) {
195221905Sgrehan		for (i = 0; i < strlen(bootmsg); i++)
196221905Sgrehan			bvm_cnputc(cp, bootmsg[i]);
197221905Sgrehan	}
198221905Sgrehan
199221905Sgrehan	strcpy(cp->cn_name, "bvmcons");
200221905Sgrehan}
201221905Sgrehan
202221905Sgrehanstatic void
203221905Sgrehanbvm_cnterm(struct consdev *cp)
204221905Sgrehan{
205221905Sgrehan
206221905Sgrehan}
207221905Sgrehan
208221905Sgrehanstatic int
209221905Sgrehanbvm_cngetc(struct consdev *cp)
210221905Sgrehan{
211221905Sgrehan	unsigned char ch;
212221905Sgrehan
213221905Sgrehan	if (bvm_rcons(&ch) == 0) {
214225598Sgrehan#if defined(KDB)
215225598Sgrehan		kdb_alt_break(ch, &alt_break_state);
216221905Sgrehan#endif
217221905Sgrehan		return (ch);
218221905Sgrehan	}
219221905Sgrehan
220221905Sgrehan	return (-1);
221221905Sgrehan}
222221905Sgrehan
223221905Sgrehanstatic void
224221905Sgrehanbvm_cnputc(struct consdev *cp, int c)
225221905Sgrehan{
226221905Sgrehan
227221905Sgrehan	bvm_wcons(c);
228221905Sgrehan}
229221905Sgrehan
230229507Ssbrunostatic void
231229507Ssbrunobvm_cngrab(struct consdev *cp)
232229507Ssbruno{
233229507Ssbruno}
234229507Ssbruno
235229507Ssbrunostatic void
236229507Ssbrunobvm_cnungrab(struct consdev *cp)
237229507Ssbruno{
238229507Ssbruno}
239229507Ssbruno
240221905SgrehanSYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
241