5 #include <sys/module.h>
7 #include <sys/consio.h>
12 #include <sys/systm.h>
13 #include <sys/taskqueue.h>
15 #include <sys/kernel.h>
17 #include <machine/stdarg.h>
18 #include <xen/xen-os.h>
19 #include <xen/hypervisor.h>
20 #include <xen/xen_intr.h>
25 #include <dev/xen/console/xencons_ring.h>
26 #include <xen/interface/io/console.h>
34 static char driver_name[] = "xc";
35 devclass_t xc_devclass; /* do not make static */
36 static void xcoutwakeup(struct tty *);
37 static void xc_timeout(void *);
38 static void __xencons_tx_flush(void);
39 static boolean_t xcons_putc(int c);
41 /* switch console so that shutdown can occur gracefully */
42 static void xc_shutdown(void *arg, int howto);
45 static void xcons_force_flush(void);
46 static void xencons_priv_interrupt(void *);
48 static cn_probe_t xc_cnprobe;
49 static cn_init_t xc_cninit;
50 static cn_term_t xc_cnterm;
51 static cn_getc_t xc_cngetc;
52 static cn_putc_t xc_cnputc;
53 static cn_grab_t xc_cngrab;
54 static cn_ungrab_t xc_cnungrab;
56 #define XC_POLLTIME (hz/10)
60 static int xen_console_up;
61 static boolean_t xc_start_needed;
62 static struct callout xc_callout;
65 #define RBUF_SIZE 1024
66 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
67 #define WBUF_SIZE 4096
68 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
69 static char wbuf[WBUF_SIZE];
70 static char rbuf[RBUF_SIZE];
72 static unsigned int cnsl_evt_reg;
73 static unsigned int wc, wp; /* write_cons, write_prod */
74 xen_intr_handle_t xen_intr_handle;
82 #define XCUNIT(x) (dev2unit(x))
83 #define ISTTYOPEN(tp) ((tp) && ((tp)->t_state & TS_ISOPEN))
84 #define CN_LOCK_INIT(x, _name) \
85 mtx_init(&x, _name, NULL, MTX_SPIN|MTX_RECURSE)
89 if (panicstr == NULL) \
90 mtx_lock_spin(&(l)); \
92 #define CN_UNLOCK(l) \
94 if (panicstr == NULL) \
95 mtx_unlock_spin(&(l)); \
97 #define CN_LOCK_ASSERT(x) mtx_assert(&x, MA_OWNED)
98 #define CN_LOCK_DESTROY(x) mtx_destroy(&x)
101 static struct tty *xccons;
103 static tsw_open_t xcopen;
104 static tsw_close_t xcclose;
106 static struct ttydevsw xc_ttydevsw = {
107 .tsw_flags = TF_NOPREFIX,
109 .tsw_close = xcclose,
110 .tsw_outwakeup = xcoutwakeup,
114 xc_cnprobe(struct consdev *cp)
116 cp->cn_pri = CN_REMOTE;
117 sprintf(cp->cn_name, "%s0", driver_name);
122 xc_cninit(struct consdev *cp)
124 CN_LOCK_INIT(cn_mtx,"XCONS LOCK");
129 xc_cnterm(struct consdev *cp)
134 xc_cngrab(struct consdev *cp)
139 xc_cnungrab(struct consdev *cp)
144 xc_cngetc(struct consdev *dev)
148 if (xencons_has_input())
149 xencons_handle_input(NULL);
152 if ((rp - rc) && !xc_mute) {
153 /* we need to return only one char */
154 ret = (int)rbuf[RBUF_MASK(rc)];
163 xc_cnputc_domu(struct consdev *dev, int c)
169 xc_cnputc_dom0(struct consdev *dev, int c)
171 HYPERVISOR_console_io(CONSOLEIO_write, 1, (char *)&c);
175 xc_cnputc(struct consdev *dev, int c)
178 if (xen_start_info->flags & SIF_INITDOMAIN)
179 xc_cnputc_dom0(dev, c);
181 xc_cnputc_domu(dev, c);
184 extern int db_active;
188 int force_flush = xc_mute ||
192 panicstr; /* we're not gonna recover, so force
196 if ((wp-wc) < (WBUF_SIZE-1)) {
197 if ((wbuf[WBUF_MASK(wp++)] = c) == '\n') {
198 wbuf[WBUF_MASK(wp++)] = '\r';
204 } else if (force_flush) {
210 __xencons_tx_flush();
212 /* inform start path that we're pretty full */
213 return ((wp - wc) >= WBUF_SIZE - 100) ? TRUE : FALSE;
217 xc_identify(driver_t *driver, device_t parent)
220 child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
221 device_set_driver(child, driver);
222 device_set_desc(child, "Xen Console");
226 xc_probe(device_t dev)
229 return (BUS_PROBE_NOWILDCARD);
233 xc_attach(device_t dev)
238 xccons = tty_alloc(&xc_ttydevsw, NULL);
239 tty_makedev(xccons, NULL, "xc%r", 0);
241 callout_init(&xc_callout, 0);
246 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, xccons);
248 if (xen_start_info->flags & SIF_INITDOMAIN) {
249 error = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
250 xencons_priv_interrupt, NULL,
251 INTR_TYPE_TTY, &xen_intr_handle);
252 KASSERT(error >= 0, ("can't register console interrupt"));
255 /* register handler to flush console on shutdown */
256 if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xc_shutdown,
257 NULL, SHUTDOWN_PRI_DEFAULT)) == NULL)
258 printf("xencons: shutdown event registration failed!\n");
264 * return 0 for all console input, force flush all output.
267 xc_shutdown(void *arg, int howto)
274 xencons_rx(char *buf, unsigned len)
277 struct tty *tp = xccons;
285 for (i = 0; i < len; i++) {
287 kdb_alt_break(buf[i], &xc_altbrk);
289 ttydisc_rint(tp, buf[i], 0);
291 ttydisc_rint_done(tp);
295 for (i = 0; i < len; i++)
296 rbuf[RBUF_MASK(rp++)] = buf[i];
302 __xencons_tx_flush(void)
310 if (sz > (WBUF_SIZE - WBUF_MASK(wc)))
311 sz = WBUF_SIZE - WBUF_MASK(wc);
312 if (xen_start_info->flags & SIF_INITDOMAIN) {
313 HYPERVISOR_console_io(CONSOLEIO_write, sz, &wbuf[WBUF_MASK(wc)]);
316 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
328 __xencons_tx_flush();
332 xencons_priv_interrupt(void *arg)
335 static char rbuf[16];
338 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
345 xcopen(struct tty *tp)
353 xcclose(struct tty *tp)
361 __xencons_put_char(int ch)
364 if ((wp - wc) == WBUF_SIZE)
366 wbuf[WBUF_MASK(wp++)] = _ch;
373 xcoutwakeup(struct tty *tp)
375 boolean_t cons_full = FALSE;
378 while (ttydisc_getc(tp, &c, 1) == 1 && !cons_full)
379 cons_full = xcons_putc(c);
382 /* let the timeout kick us in a bit */
383 xc_start_needed = TRUE;
394 tp = (struct tty *)v;
397 while ((c = xc_cngetc(NULL)) != -1)
398 ttydisc_rint(tp, c, 0);
400 if (xc_start_needed) {
401 xc_start_needed = FALSE;
406 callout_reset(&xc_callout, XC_POLLTIME, xc_timeout, tp);
409 static device_method_t xc_methods[] = {
410 DEVMETHOD(device_identify, xc_identify),
411 DEVMETHOD(device_probe, xc_probe),
412 DEVMETHOD(device_attach, xc_attach),
417 static driver_t xc_driver = {
423 /*** Forcibly flush console data before dying. ***/
425 xcons_force_flush(void)
429 if (xen_start_info->flags & SIF_INITDOMAIN)
432 /* Spin until console data is flushed through to the domain controller. */
435 if ((sz = wp - wc) == 0)
438 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
444 DRIVER_MODULE(xc, nexus, xc_driver, xc_devclass, 0, 0);