5 #include <sys/module.h>
7 #include <sys/consio.h>
11 #include <sys/systm.h>
12 #include <sys/taskqueue.h>
14 #include <sys/kernel.h>
16 #include <machine/stdarg.h>
17 #include <machine/xen/xen-os.h>
18 #include <machine/xen/hypervisor.h>
19 #include <machine/xen/xen_intr.h>
24 #include <dev/xen/console/xencons_ring.h>
25 #include <xen/interface/io/console.h>
33 static char driver_name[] = "xc";
34 devclass_t xc_devclass; /* do not make static */
35 static void xcoutwakeup(struct tty *);
36 static void xc_timeout(void *);
37 static void __xencons_tx_flush(void);
38 static boolean_t xcons_putc(int c);
40 /* switch console so that shutdown can occur gracefully */
41 static void xc_shutdown(void *arg, int howto);
44 static void xcons_force_flush(void);
45 static void xencons_priv_interrupt(void *);
47 static cn_probe_t xccnprobe;
48 static cn_init_t xccninit;
49 static cn_getc_t xccngetc;
50 static cn_putc_t xccnputc;
51 static cn_putc_t xccnputc_dom0;
52 static cn_checkc_t xccncheckc;
54 #define XC_POLLTIME (hz/10)
56 CONS_DRIVER(xc, xccnprobe, xccninit, NULL, xccngetc,
57 xccncheckc, xccnputc, NULL);
59 static int xen_console_up;
60 static boolean_t xc_start_needed;
61 static struct callout xc_callout;
64 #define RBUF_SIZE 1024
65 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
66 #define WBUF_SIZE 4096
67 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
68 static char wbuf[WBUF_SIZE];
69 static char rbuf[RBUF_SIZE];
71 static unsigned int cnsl_evt_reg;
72 static unsigned int wc, wp; /* write_cons, write_prod */
75 #define XCUNIT(x) (dev2unit(x))
76 #define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
77 #define CN_LOCK_INIT(x, _name) \
78 mtx_init(&x, _name, NULL, MTX_SPIN|MTX_RECURSE)
82 if (panicstr == NULL) \
83 mtx_lock_spin(&(l)); \
85 #define CN_UNLOCK(l) \
87 if (panicstr == NULL) \
88 mtx_unlock_spin(&(l)); \
90 #define CN_LOCK_ASSERT(x) mtx_assert(&x, MA_OWNED)
91 #define CN_LOCK_DESTROY(x) mtx_destroy(&x)
94 static struct tty *xccons;
96 static tsw_open_t xcopen;
97 static tsw_close_t xcclose;
99 static struct ttydevsw xc_ttydevsw = {
100 .tsw_flags = TF_NOPREFIX,
102 .tsw_close = xcclose,
103 .tsw_outwakeup = xcoutwakeup,
107 xccnprobe(struct consdev *cp)
109 cp->cn_pri = CN_REMOTE;
111 sprintf(cp->cn_name, "%s0", driver_name);
116 xccninit(struct consdev *cp)
118 CN_LOCK_INIT(cn_mtx,"XCONS LOCK");
122 xccngetc(struct consdev *dev)
128 if ((c = xccncheckc(dev)) == -1) {
129 /* polling without sleeping in Xen doesn't work well.
130 * Sleeping gives other things like clock a chance to
133 tsleep(&cn_mtx, PWAIT | PCATCH, "console sleep",
141 xccncheckc(struct consdev *dev)
143 int ret = (xc_mute ? 0 : -1);
144 if (xencons_has_input())
145 xencons_handle_input(NULL);
149 /* we need to return only one char */
150 ret = (int)rbuf[RBUF_MASK(rc)];
158 xccnputc(struct consdev *dev, int c)
164 xccnputc_dom0(struct consdev *dev, int c)
166 HYPERVISOR_console_io(CONSOLEIO_write, 1, (char *)&c);
169 extern int db_active;
173 int force_flush = xc_mute ||
177 panicstr; /* we're not gonna recover, so force
181 if ((wp-wc) < (WBUF_SIZE-1)) {
182 if ((wbuf[WBUF_MASK(wp++)] = c) == '\n') {
183 wbuf[WBUF_MASK(wp++)] = '\r';
189 } else if (force_flush) {
195 __xencons_tx_flush();
197 /* inform start path that we're pretty full */
198 return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE;
202 xc_identify(driver_t *driver, device_t parent)
205 child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
206 device_set_driver(child, driver);
207 device_set_desc(child, "Xen Console");
211 xc_probe(device_t dev)
218 xc_attach(device_t dev)
221 if (xen_start_info->flags & SIF_INITDOMAIN) {
222 xc_consdev.cn_putc = xccnputc_dom0;
225 xccons = tty_alloc(&xc_ttydevsw, NULL, NULL);
226 tty_makedev(xccons, NULL, "xc%r", 0);
228 callout_init(&xc_callout, 0);
233 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons);
235 if (xen_start_info->flags & SIF_INITDOMAIN) {
236 PANIC_IF(bind_virq_to_irqhandler(
241 xencons_priv_interrupt,
247 /* register handler to flush console on shutdown */
248 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown,
249 NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
250 printf("xencons: shutdown event registration failed!\n");
256 * return 0 for all console input, force flush all output.
259 xc_shutdown(void *arg, int howto)
266 xencons_rx(char *buf, unsigned len)
269 struct tty *tp = xccons;
271 if (xen_console_up) {
273 for (i = 0; i < len; i++)
274 ttydisc_rint(tp, buf[i], 0);
275 ttydisc_rint_done(tp);
278 for (i = 0; i < len; i++)
279 rbuf[RBUF_MASK(rp++)] = buf[i];
284 __xencons_tx_flush(void)
292 if (sz > (WBUF_SIZE - WBUF_MASK(wc)))
293 sz = WBUF_SIZE - WBUF_MASK(wc);
294 if (xen_start_info->flags & SIF_INITDOMAIN) {
295 HYPERVISOR_console_io(CONSOLEIO_write, sz, &wbuf[WBUF_MASK(wc)]);
298 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
310 __xencons_tx_flush();
314 xencons_priv_interrupt(void *arg)
317 static char rbuf[16];
320 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
327 xcopen(struct tty *tp)
335 xcclose(struct tty *tp)
342 __xencons_put_char(int ch)
345 if ((wp - wc) == WBUF_SIZE)
347 wbuf[WBUF_MASK(wp++)] = _ch;
353 xcoutwakeup(struct tty *tp)
355 boolean_t cons_full = FALSE;
358 while (ttydisc_getc(tp, &c, 1) == 1 && !cons_full)
359 cons_full = xcons_putc(c);
362 /* let the timeout kick us in a bit */
363 xc_start_needed = TRUE;
374 tp = (struct tty *)v;
377 while ((c = xccncheckc(NULL)) != -1)
378 ttydisc_rint(tp, c, 0);
380 if (xc_start_needed) {
381 xc_start_needed = FALSE;
386 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp);
389 static device_method_t xc_methods[] = {
390 DEVMETHOD(device_identify, xc_identify),
391 DEVMETHOD(device_probe, xc_probe),
392 DEVMETHOD(device_attach, xc_attach),
396 static driver_t xc_driver = {
402 /*** Forcibly flush console data before dying. ***/
404 xcons_force_flush(void)
408 if (xen_start_info->flags & SIF_INITDOMAIN)
411 /* Spin until console data is flushed through to the domain controller. */
414 if ((sz = wp - wc) == 0)
417 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
423 DRIVER_MODULE(xc, nexus, xc_driver, xc_devclass, 0, 0);
430 * indent-tabs-mode: t