2 * Copyright (C) 2006 Kip Macy
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY Kip Macy ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL Kip Macy BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/module.h>
35 #include <sys/kernel.h>
38 #include <sys/consio.h>
43 #include <machine/mdesc_bus.h>
44 #include <machine/cddl/mdesc.h>
46 #include "mdesc_bus_if.h"
48 #include "opt_simulator.h"
50 #include <machine/resource.h>
51 #include <machine/hypervisorvar.h>
52 #include <machine/hv_api.h>
54 #define HVCN_POLL_FREQ 10
56 static tsw_open_t hvcn_open;
57 static tsw_outwakeup_t hvcn_outwakeup;
58 static tsw_close_t hvcn_close;
60 static struct ttydevsw hvcn_class = {
61 .tsw_open = hvcn_open,
62 .tsw_outwakeup = hvcn_outwakeup,
63 .tsw_close = hvcn_close,
67 static struct tty *hvcn_tp = NULL;
68 static struct resource *hvcn_irq;
69 static void *hvcn_intrhand;
73 static u_char buf[PCBURST];
75 static struct callout_handle hvcn_timeouthandle
76 = CALLOUT_HANDLE_INITIALIZER(&hvcn_timeouthandle);
79 static int alt_break_state;
82 static void hvcn_timeout(void *);
84 static cn_probe_t hvcn_cnprobe;
85 static cn_init_t hvcn_cninit;
86 static cn_getc_t hvcn_cngetc;
87 static cn_putc_t hvcn_cnputc;
88 static cn_term_t hvcn_cnterm;
98 while ((c = *p++) != '\0') {
101 error = hv_cons_putchar('\r');
102 } while (error == H_EWOULDBLOCK);
105 error = hv_cons_putchar(c);
106 } while (error == H_EWOULDBLOCK);
111 hvcn_open(struct tty *tp)
115 * Set up timeout to trigger fake interrupts to transmit
118 polltime = hz / HVCN_POLL_FREQ;
121 hvcn_timeouthandle = timeout(hvcn_timeout, tp, polltime);
129 hvcn_close(struct tty *tp)
131 untimeout(hvcn_timeout, tp, hvcn_timeouthandle);
135 hvcn_cnprobe(struct consdev *cp)
143 panic("%s: OF_peer failed.", __func__);
145 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
146 OF_getprop(node, "name", name, sizeof(name));
147 if (!strcmp(name, "virtual-devices"))
154 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
155 OF_getprop(node, "name", name, sizeof(name));
156 if (!strcmp(name, "console"))
161 cp->cn_pri = CN_NORMAL;
166 hvcn_cninit(struct consdev *cp)
169 strcpy(cp->cn_name, "hvcn");
173 hvcn_cngetc(struct consdev *cp)
180 while ((l = hv_cons_getchar(&ch)) != H_EOK) {
184 if (l == H_BREAK || l == H_HUP)
185 kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
187 if ((kdb_brk = kdb_alt_break(ch, &alt_break_state)) != 0) {
189 case KDB_REQ_DEBUGGER:
190 kdb_enter(KDB_WHY_BREAK,
191 "Break sequence on console");
194 kdb_panic("Panic sequence on console");
202 if (l != -2 && l != 0) {
213 hvcn_cncheckc(struct consdev *cp)
218 if ((l = hv_cons_getchar(&ch)) == H_EOK) {
220 if (l == H_BREAK || l == H_HUP)
221 kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
222 if (kdb_alt_break(ch, &alt_break_state))
223 kdb_enter(KDB_WHY_BREAK, "Break sequence on console");
233 hvcn_cnterm(struct consdev *cp)
239 hvcn_cnputc(struct consdev *cp, int c)
247 error = hv_cons_putchar('\r');
248 } while (error == H_EWOULDBLOCK);
250 error = hv_cons_putchar(c);
251 } while (error == H_EWOULDBLOCK);
255 hvcn_outwakeup(struct tty *tp)
259 /* Refill the input buffer. */
261 buflen = ttydisc_getc(tp, buf, PCBURST);
265 /* Transmit the input buffer. */
267 if (hv_cons_putchar(buf[bufindex]) == H_EWOULDBLOCK)
284 while ((c = hvcn_cncheckc(NULL)) != -1)
285 ttydisc_rint(tp, c, 0);
286 ttydisc_rint_done(tp);
288 /* Transmit trailing data. */
294 hvcn_timeout(void *v)
298 hvcn_timeouthandle = timeout(hvcn_timeout, v, polltime);
303 hvcn_dev_probe(device_t dev)
306 if (strcmp(mdesc_bus_get_name(dev), "console"))
309 device_set_desc(dev, "sun4v virtual console");
316 hvcn_dev_attach(device_t dev)
322 /* belongs in attach - but attach is getting called multiple times
323 * for reasons I have not delved into
326 if (hvcn_consdev.cn_pri == CN_DEAD ||
327 hvcn_consdev.cn_name[0] == '\0')
330 tp = tty_alloc(&hvcn_class, NULL);
331 tty_makedev(tp, NULL, "v%r", 1);
332 tty_makealias(tp, "hvcn");
336 if ((hvcn_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
337 RF_SHAREABLE | RF_ACTIVE)) == NULL) {
338 device_printf(dev, "couldn't map interrupt\n");
343 error = bus_setup_intr(dev, hvcn_irq, INTR_TYPE_TTY, NULL, hvcn_intr, hvcn_tp,
347 device_printf(dev, "couldn't set up irq\n");
355 static device_method_t hvcn_methods[] = {
356 DEVMETHOD(device_probe, hvcn_dev_probe),
357 DEVMETHOD(device_attach, hvcn_dev_attach),
362 static driver_t hvcn_driver = {
369 static devclass_t hvcn_devclass;
371 DRIVER_MODULE(hvcn, vnex, hvcn_driver, hvcn_devclass, 0, 0);