xref: /freebsd-11-stable/sys/dev/xen/console/xen_console.c (revision fe7e07e7f34c8d33a9fd3ecc0a95fb526fb51745)
1 /*
2  * Copyright (c) 2015 Julien Grall <julien.grall@citrix.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/module.h>
32 #include <sys/systm.h>
33 #include <sys/consio.h>
34 #include <sys/priv.h>
35 #include <sys/proc.h>
36 #include <sys/uio.h>
37 #include <sys/tty.h>
38 #include <sys/systm.h>
39 #include <sys/taskqueue.h>
40 #include <sys/conf.h>
41 #include <sys/kernel.h>
42 #include <sys/bus.h>
43 #include <sys/cons.h>
44 #include <sys/kdb.h>
45 #include <sys/proc.h>
46 #include <sys/reboot.h>
47 
48 #include <machine/stdarg.h>
49 
50 #include <xen/xen-os.h>
51 #include <xen/hypervisor.h>
52 #include <xen/xen_intr.h>
53 #include <xen/interface/io/console.h>
54 
55 #include "opt_ddb.h"
56 #include "opt_printf.h"
57 
58 #ifdef DDB
59 #include <ddb/ddb.h>
60 #endif
61 
62 static char driver_name[] = "xc";
63 
64 struct xencons_priv;
65 
66 typedef void xencons_early_init_t(struct xencons_priv *cons);
67 typedef int xencons_init_t(device_t dev, struct tty *tp,
68     driver_intr_t intr_handler);
69 typedef int xencons_read_t(struct xencons_priv *cons, char *buffer,
70     unsigned int size);
71 typedef int xencons_write_t(struct xencons_priv *cons, const char *buffer,
72     unsigned int size);
73 
74 struct xencons_ops {
75 	/*
76 	 * Called by the low-level driver during early boot.
77 	 * Only the minimal set up to get a console should be done here.
78 	 */
79 	xencons_early_init_t	*early_init;
80 	/* Prepare the console to be fully use */
81 	xencons_init_t		*init;
82 	/* Read/write helpers */
83 	xencons_read_t		*read;
84 	xencons_write_t		*write;
85 };
86 
87 struct xencons_priv {
88 	/* Mutex to protect the shared ring and the internal buffers */
89 	struct mtx			mtx;
90 	/* Interrupt handler used for notify the backend */
91 	xen_intr_handle_t		intr_handle;
92 	/* KDB internal state */
93 #ifdef KDB
94 	int				altbrk;
95 #endif
96 	/* Status of the tty */
97 	bool				opened;
98 	/* Callout used when the write buffer is full */
99 	struct callout			callout;
100 
101 	/* Internal buffers must be used with mtx locked */
102 #define WBUF_SIZE     4096
103 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
104 	char				wbuf[WBUF_SIZE];
105 	unsigned int			wc, wp; /* Consumer/producer wbuf */
106 
107 #define RBUF_SIZE     1024
108 #define RBUF_MASK(_i) ((_i)&(RBUF_SIZE-1))
109 	char				rbuf[RBUF_SIZE];
110 	unsigned int			rc, rp; /* Consumer/producer rbuf */
111 
112 	/* Pointer to the console operations */
113 	const struct xencons_ops	*ops;
114 
115 	/*
116 	 * Ring specific fields
117 	 * XXX: make an union?
118 	 */
119 	/* Event channel number for early notification (PV only) */
120 	uint32_t			evtchn;
121 	/* Console shared page */
122 	struct xencons_interface	*intf;
123 };
124 
125 /*
126  * Data for the main console
127  * Necessary to support low-level console driver
128  */
129 static struct xencons_priv main_cons;
130 
131 #define XC_POLLTIME 	(hz/10)
132 
133 /*
134  * Virtual address of the shared console page (only for PV guest)
135  * TODO: Introduce a function to set it
136  */
137 char *console_page;
138 
139 /*----------------------------- Debug function ------------------------------*/
140 struct putchar_arg {
141 	char	*buf;
142 	size_t	size;
143 	size_t	n_next;
144 };
145 
146 static void
putchar(int c,void * arg)147 putchar(int c, void *arg)
148 {
149 	struct putchar_arg *pca;
150 
151 	pca = (struct putchar_arg *)arg;
152 
153 	if (pca->buf == NULL) {
154 		/*
155 		 * We have no buffer, output directly to the
156 		 * console char by char.
157 		 */
158 		HYPERVISOR_console_write((char *)&c, 1);
159 	} else {
160 		pca->buf[pca->n_next++] = c;
161 		if ((pca->size == pca->n_next) || (c = '\0')) {
162 			/* Flush the buffer */
163 			HYPERVISOR_console_write(pca->buf, pca->n_next);
164 			pca->n_next = 0;
165 		}
166 	}
167 }
168 
169 void
xc_printf(const char * fmt,...)170 xc_printf(const char *fmt, ...)
171 {
172 	va_list ap;
173 	struct putchar_arg pca;
174 #ifdef PRINTF_BUFR_SIZE
175 	char buf[PRINTF_BUFR_SIZE];
176 
177 	pca.buf = buf;
178 	pca.size = sizeof(buf);
179 	pca.n_next = 0;
180 #else
181 	pca.buf = NULL;
182 	pca.size = 0;
183 #endif
184 
185 	KASSERT((xen_domain()), ("call to xc_printf from non Xen guest"));
186 
187 	va_start(ap, fmt);
188 	kvprintf(fmt, putchar, &pca, 10, ap);
189 	va_end(ap);
190 
191 #ifdef PRINTF_BUFR_SIZE
192 	if (pca.n_next != 0)
193 		HYPERVISOR_console_write(buf, pca.n_next);
194 #endif
195 }
196 
197 /*---------------------- Helpers for the console lock -----------------------*/
198 /*
199  * The lock is not used when the kernel is panicing as it will never recover
200  * and we want to output no matter what it costs.
201  */
xencons_lock(struct xencons_priv * cons)202 static inline void xencons_lock(struct xencons_priv *cons)
203 {
204 
205 	if (panicstr == NULL)
206 		mtx_lock_spin(&cons->mtx);
207 
208 }
209 
xencons_unlock(struct xencons_priv * cons)210 static inline void xencons_unlock(struct xencons_priv *cons)
211 {
212 
213 	if (panicstr == NULL)
214 		mtx_unlock_spin(&cons->mtx);
215 }
216 
217 #define xencons_lock_assert(cons)	mtx_assert(&(cons)->mtx, MA_OWNED)
218 
219 /*------------------ Helpers for the hypervisor console ---------------------*/
220 static void
xencons_early_init_hypervisor(struct xencons_priv * cons)221 xencons_early_init_hypervisor(struct xencons_priv *cons)
222 {
223 	/*
224 	 * Nothing to setup for the low-level console when using
225 	 * the hypervisor console.
226 	 */
227 }
228 
229 static int
xencons_init_hypervisor(device_t dev,struct tty * tp,driver_intr_t intr_handler)230 xencons_init_hypervisor(device_t dev, struct tty *tp,
231     driver_intr_t intr_handler)
232 {
233 	struct xencons_priv *cons;
234 	int err;
235 
236 	cons = tty_softc(tp);
237 
238 	err = xen_intr_bind_virq(dev, VIRQ_CONSOLE, 0, NULL,
239 	    intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
240 	if (err != 0)
241 		device_printf(dev, "Can't register console interrupt\n");
242 
243 	return (err);
244 }
245 
246 static int
xencons_write_hypervisor(struct xencons_priv * cons,const char * buffer,unsigned int size)247 xencons_write_hypervisor(struct xencons_priv *cons, const char *buffer,
248     unsigned int size)
249 {
250 
251 	HYPERVISOR_console_io(CONSOLEIO_write, size, buffer);
252 
253 	return (size);
254 }
255 
256 static int
xencons_read_hypervisor(struct xencons_priv * cons,char * buffer,unsigned int size)257 xencons_read_hypervisor(struct xencons_priv *cons, char *buffer,
258     unsigned int size)
259 {
260 
261 	xencons_lock_assert(cons);
262 
263 	return (HYPERVISOR_console_io(CONSOLEIO_read, size, buffer));
264 }
265 
266 static const struct xencons_ops xencons_hypervisor_ops = {
267 	.early_init	= xencons_early_init_hypervisor,
268 	.init		= xencons_init_hypervisor,
269 	.read		= xencons_read_hypervisor,
270 	.write		= xencons_write_hypervisor,
271 };
272 
273 /*------------------ Helpers for the ring console ---------------------------*/
274 static void
xencons_early_init_ring(struct xencons_priv * cons)275 xencons_early_init_ring(struct xencons_priv *cons)
276 {
277 	/* The shared page for PV is already mapped by the boot code */
278 	cons->intf = (struct xencons_interface *)console_page;
279 	cons->evtchn = HYPERVISOR_start_info->console.domU.evtchn;
280 }
281 
282 static int
xencons_init_ring(device_t dev,struct tty * tp,driver_intr_t intr_handler)283 xencons_init_ring(device_t dev, struct tty *tp, driver_intr_t intr_handler)
284 {
285 	struct xencons_priv *cons;
286 	int err;
287 
288 	cons = tty_softc(tp);
289 
290 	if (cons->evtchn == 0)
291 		return (ENODEV);
292 
293 	err = xen_intr_bind_local_port(dev, cons->evtchn, NULL,
294 	    intr_handler, tp, INTR_TYPE_TTY | INTR_MPSAFE, &cons->intr_handle);
295 	if (err != 0)
296 		return (err);
297 
298 	return (0);
299 }
300 
301 static void
xencons_notify_ring(struct xencons_priv * cons)302 xencons_notify_ring(struct xencons_priv *cons)
303 {
304 	/*
305 	 * The console may be used before the ring interrupt is properly
306 	 * initialized.
307 	 * If so, fallback to directly use the event channel hypercall.
308 	 */
309 	if (__predict_true(cons->intr_handle != NULL))
310 		xen_intr_signal(cons->intr_handle);
311 	else {
312 		struct evtchn_send send = {
313 			.port = cons->evtchn
314 		};
315 
316 		HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
317 	}
318 }
319 
320 static int
xencons_write_ring(struct xencons_priv * cons,const char * buffer,unsigned int size)321 xencons_write_ring(struct xencons_priv *cons, const char *buffer,
322     unsigned int size)
323 {
324 	struct xencons_interface *intf;
325 	XENCONS_RING_IDX wcons, wprod;
326 	int sent;
327 
328 	intf = cons->intf;
329 
330 	xencons_lock_assert(cons);
331 
332 	wcons = intf->out_cons;
333 	wprod = intf->out_prod;
334 
335 	mb();
336 	KASSERT((wprod - wcons) <= sizeof(intf->out),
337 		("console send ring inconsistent"));
338 
339 	for (sent = 0; sent < size; sent++, wprod++) {
340 		if ((wprod - wcons) >= sizeof(intf->out))
341 			break;
342 		intf->out[MASK_XENCONS_IDX(wprod, intf->out)] = buffer[sent];
343 	}
344 
345 	wmb();
346 	intf->out_prod = wprod;
347 
348 	xencons_notify_ring(cons);
349 
350 	return (sent);
351 }
352 
353 static int
xencons_read_ring(struct xencons_priv * cons,char * buffer,unsigned int size)354 xencons_read_ring(struct xencons_priv *cons, char *buffer, unsigned int size)
355 {
356 	struct xencons_interface *intf;
357 	XENCONS_RING_IDX rcons, rprod;
358 	unsigned int rsz;
359 
360 	intf = cons->intf;
361 
362 	xencons_lock_assert(cons);
363 
364 	rcons = intf->in_cons;
365 	rprod = intf->in_prod;
366 	rmb();
367 
368 	for (rsz = 0; rsz < size; rsz++, rcons++) {
369 		if (rprod == rcons)
370 			break;
371 		buffer[rsz] = intf->in[MASK_XENCONS_IDX(rcons, intf->in)];
372 	}
373 
374 	wmb();
375 	intf->in_cons = rcons;
376 
377 	/* No need to notify the backend if nothing has been read */
378 	if (rsz != 0)
379 		xencons_notify_ring(cons);
380 
381 	return (rsz);
382 }
383 
384 static const struct xencons_ops xencons_ring_ops = {
385 	.early_init	= xencons_early_init_ring,
386 	.init		= xencons_init_ring,
387 	.read		= xencons_read_ring,
388 	.write		= xencons_write_ring,
389 };
390 
391 /*------------------ Common implementation of the console -------------------*/
392 
393 /*
394  * Called by the low-level driver during early boot to initialize the
395  * main console driver.
396  * Only the minimal set up to get a console should be done here.
397  */
398 static void
xencons_early_init(void)399 xencons_early_init(void)
400 {
401 
402 	mtx_init(&main_cons.mtx, "XCONS LOCK", NULL, MTX_SPIN);
403 
404 	if (xen_initial_domain())
405 		main_cons.ops = &xencons_hypervisor_ops;
406 	else
407 		main_cons.ops = &xencons_ring_ops;
408 
409 	main_cons.ops->early_init(&main_cons);
410 }
411 
412 /*
413  * Receive character from the console and put them in the internal buffer
414  * XXX: Handle overflow of the internal buffer
415  */
416 static void
xencons_rx(struct xencons_priv * cons)417 xencons_rx(struct xencons_priv *cons)
418 {
419 	char buf[16];
420 	int sz;
421 
422 	xencons_lock(cons);
423 	while ((sz = cons->ops->read(cons, buf, sizeof(buf))) > 0) {
424 		int i;
425 
426 		for (i = 0; i < sz; i++)
427 			cons->rbuf[RBUF_MASK(cons->rp++)] = buf[i];
428 	}
429 	xencons_unlock(cons);
430 }
431 
432 /* Return true if the write buffer is full */
433 static bool
xencons_tx_full(struct xencons_priv * cons)434 xencons_tx_full(struct xencons_priv *cons)
435 {
436 	unsigned int used;
437 
438 	xencons_lock(cons);
439 	used = cons->wp - cons->wc;
440 	xencons_unlock(cons);
441 
442 	return (used >= WBUF_SIZE);
443 }
444 
445 static void
xencons_tx_flush(struct xencons_priv * cons,int force)446 xencons_tx_flush(struct xencons_priv *cons, int force)
447 {
448 	int        sz;
449 
450 	xencons_lock(cons);
451 	while (cons->wc != cons->wp) {
452 		int sent;
453 		sz = cons->wp - cons->wc;
454 		if (sz > (WBUF_SIZE - WBUF_MASK(cons->wc)))
455 			sz = WBUF_SIZE - WBUF_MASK(cons->wc);
456 		sent = cons->ops->write(cons, &cons->wbuf[WBUF_MASK(cons->wc)],
457 		    sz);
458 
459 		/*
460 		 * The other end may not have been initialized. Ignore
461 		 * the force.
462 		 */
463 		if (__predict_false(sent < 0))
464 			break;
465 
466 		/*
467 		 * If force is set, spin until the console data is
468 		 * flushed through the domain controller.
469 		 */
470 		if (sent == 0 && __predict_true(!force))
471 			break;
472 
473 		cons->wc += sent;
474 	}
475 	xencons_unlock(cons);
476 }
477 
478 static bool
xencons_putc(struct xencons_priv * cons,int c,bool force_flush)479 xencons_putc(struct xencons_priv *cons, int c, bool force_flush)
480 {
481 
482 	xencons_lock(cons);
483 	if ((cons->wp - cons->wc) < WBUF_SIZE)
484 		cons->wbuf[WBUF_MASK(cons->wp++)] = c;
485 	xencons_unlock(cons);
486 
487 	xencons_tx_flush(cons, force_flush);
488 
489 	return (xencons_tx_full(cons));
490 }
491 
492 static int
xencons_getc(struct xencons_priv * cons)493 xencons_getc(struct xencons_priv *cons)
494 {
495 	int ret;
496 
497 	xencons_lock(cons);
498 	if (cons->rp != cons->rc) {
499 		/* We need to return only one char */
500 		ret = (int)cons->rbuf[RBUF_MASK(cons->rc)];
501 		cons->rc++;
502 	} else {
503 		ret = -1;
504 	}
505 
506 	xencons_unlock(cons);
507 
508 	return (ret);
509 }
510 
511 static bool
xencons_tx(struct tty * tp)512 xencons_tx(struct tty *tp)
513 {
514 	bool cons_full;
515 	char c;
516 	struct xencons_priv *cons;
517 
518 	cons = tty_softc(tp);
519 
520 	tty_lock_assert(tp, MA_OWNED);
521 
522 	/*
523 	 * Don't transmit any character if the buffer is full. Otherwise,
524 	 * characters may be lost
525 	 */
526 	if (xencons_tx_full(cons))
527 		return (false);
528 
529 	cons_full = false;
530 	while (!cons_full && ttydisc_getc(tp, &c, 1) == 1)
531 		cons_full = xencons_putc(cons, c, false);
532 
533 	return (!cons_full);
534 }
535 
536 static void
xencons_intr(void * arg)537 xencons_intr(void *arg)
538 {
539 	struct tty *tp;
540 	struct xencons_priv *cons;
541 	int ret;
542 
543 	tp = arg;
544 	cons = tty_softc(tp);
545 
546 	/*
547 	 * The input will be used by the low-level console when KDB is active
548 	 */
549 	if (kdb_active)
550 		return;
551 
552 	/*
553 	 * It's not necessary to retrieve input when the tty is not opened
554 	 */
555 	if (!cons->opened)
556 		return;
557 
558 	xencons_rx(cons);
559 
560 	tty_lock(tp);
561 	while ((ret = xencons_getc(cons)) != -1) {
562 #ifdef KDB
563 		kdb_alt_break(ret, &cons->altbrk);
564 #endif
565 		ttydisc_rint(tp, ret, 0);
566 	}
567 	ttydisc_rint_done(tp);
568 	tty_unlock(tp);
569 
570 	/* Try to flush remaining characters if necessary */
571 	xencons_tx_flush(cons, 0);
572 }
573 
574 /*
575  * Helpers to call while shutting down:
576  *	- Force flush all output
577  */
578 static void
xencons_shutdown(void * arg,int howto)579 xencons_shutdown(void *arg, int howto)
580 {
581 	struct tty *tp;
582 
583 	tp = arg;
584 
585 	xencons_tx_flush(tty_softc(tp), 1);
586 }
587 
588 /*---------------------- Low-level console driver ---------------------------*/
589 static void
xencons_cnprobe(struct consdev * cp)590 xencons_cnprobe(struct consdev *cp)
591 {
592 
593 	if (!xen_pv_domain())
594 		return;
595 
596 	cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
597 	sprintf(cp->cn_name, "%s0", driver_name);
598 }
599 
600 static void
xencons_cninit(struct consdev * cp)601 xencons_cninit(struct consdev *cp)
602 {
603 
604 	xencons_early_init();
605 }
606 
607 static void
xencons_cnterm(struct consdev * cp)608 xencons_cnterm(struct consdev *cp)
609 {
610 }
611 
612 static void
xencons_cngrab(struct consdev * cp)613 xencons_cngrab(struct consdev *cp)
614 {
615 }
616 
617 static void
xencons_cnungrab(struct consdev * cp)618 xencons_cnungrab(struct consdev *cp)
619 {
620 }
621 
622 static int
xencons_cngetc(struct consdev * dev)623 xencons_cngetc(struct consdev *dev)
624 {
625 
626 	xencons_rx(&main_cons);
627 
628 	return (xencons_getc(&main_cons));
629 }
630 
631 static void
xencons_cnputc(struct consdev * dev,int c)632 xencons_cnputc(struct consdev *dev, int c)
633 {
634 	/*
635 	 * The low-level console is used by KDB and panic. We have to ensure
636 	 * that any character sent will be seen by the backend.
637 	 */
638 	xencons_putc(&main_cons, c, true);
639 }
640 
641 CONSOLE_DRIVER(xencons);
642 
643 /*----------------------------- TTY driver ---------------------------------*/
644 
645 static int
xencons_tty_open(struct tty * tp)646 xencons_tty_open(struct tty *tp)
647 {
648 	struct xencons_priv *cons;
649 
650 	cons = tty_softc(tp);
651 
652 	cons->opened = true;
653 
654 	return (0);
655 }
656 
657 static void
xencons_tty_close(struct tty * tp)658 xencons_tty_close(struct tty *tp)
659 {
660 	struct xencons_priv *cons;
661 
662 	cons = tty_softc(tp);
663 
664 	cons->opened = false;
665 }
666 
667 static void
xencons_timeout(void * v)668 xencons_timeout(void *v)
669 {
670 	struct tty *tp;
671 	struct xencons_priv *cons;
672 
673 	tp = v;
674 	cons = tty_softc(tp);
675 
676 	if (!xencons_tx(tp))
677 		callout_reset(&cons->callout, XC_POLLTIME,
678 		    xencons_timeout, tp);
679 }
680 
681 static void
xencons_tty_outwakeup(struct tty * tp)682 xencons_tty_outwakeup(struct tty *tp)
683 {
684 	struct xencons_priv *cons;
685 
686 	cons = tty_softc(tp);
687 
688 	callout_stop(&cons->callout);
689 
690 	if (!xencons_tx(tp))
691 		callout_reset(&cons->callout, XC_POLLTIME,
692 		    xencons_timeout, tp);
693 }
694 
695 static struct ttydevsw xencons_ttydevsw = {
696         .tsw_flags	= TF_NOPREFIX,
697         .tsw_open	= xencons_tty_open,
698         .tsw_close	= xencons_tty_close,
699         .tsw_outwakeup	= xencons_tty_outwakeup,
700 };
701 
702 /*------------------------ Main console driver ------------------------------*/
703 static void
xencons_identify(driver_t * driver,device_t parent)704 xencons_identify(driver_t *driver, device_t parent)
705 {
706 	device_t child;
707 
708 #if defined(__arm__) || defined(__aarch64__)
709 	if (!xen_domain())
710 		return;
711 #else
712 	if (!xen_pv_domain())
713 		return;
714 #endif
715 
716 	child = BUS_ADD_CHILD(parent, 0, driver_name, 0);
717 }
718 
719 static int
xencons_probe(device_t dev)720 xencons_probe(device_t dev)
721 {
722 
723 	device_set_desc(dev, "Xen Console");
724 	return (BUS_PROBE_NOWILDCARD);
725 }
726 
727 static int
xencons_attach(device_t dev)728 xencons_attach(device_t dev)
729 {
730 	struct tty *tp;
731 	/*
732 	 * The main console is already allocated statically in order to
733 	 * support low-level console
734 	 */
735 	struct xencons_priv *cons;
736 	int err;
737 
738 	cons = &main_cons;
739 
740 	tp = tty_alloc(&xencons_ttydevsw, cons);
741 	tty_makedev(tp, NULL, "%s%r", driver_name, 0);
742 	device_set_softc(dev, tp);
743 
744 	callout_init_mtx(&cons->callout, tty_getlock(tp), 0);
745 
746 	err = cons->ops->init(dev, tp, xencons_intr);
747 	if (err != 0) {
748 		device_printf(dev, "Unable to initialize the console (%d)\n",
749 		    err);
750 		return (err);
751 	}
752 
753 	/* register handler to flush console on shutdown */
754 	if ((EVENTHANDLER_REGISTER(shutdown_post_sync, xencons_shutdown,
755 	    tp, SHUTDOWN_PRI_DEFAULT)) == NULL)
756 		device_printf(dev, "shutdown event registration failed!\n");
757 
758 	return (0);
759 }
760 
761 static int
xencons_resume(device_t dev)762 xencons_resume(device_t dev)
763 {
764 	struct xencons_priv *cons;
765 	struct tty *tp;
766 	int err;
767 
768 	tp = device_get_softc(dev);
769 	cons = tty_softc(tp);
770 	xen_intr_unbind(&cons->intr_handle);
771 
772 	err = cons->ops->init(dev, tp, xencons_intr);
773 	if (err != 0) {
774 		device_printf(dev, "Unable to resume the console (%d)\n", err);
775 		return (err);
776 	}
777 
778 	return (0);
779 }
780 
781 static devclass_t xencons_devclass;
782 
783 static device_method_t xencons_methods[] = {
784 	DEVMETHOD(device_identify, xencons_identify),
785 	DEVMETHOD(device_probe, xencons_probe),
786 	DEVMETHOD(device_attach, xencons_attach),
787 	DEVMETHOD(device_resume, xencons_resume),
788 
789 	DEVMETHOD_END
790 };
791 
792 static driver_t xencons_driver = {
793 	driver_name,
794 	xencons_methods,
795 	0,
796 };
797 
798 DRIVER_MODULE(xc, xenpv, xencons_driver, xencons_devclass, 0, 0);
799