Home | History | Annotate | Line # | Download | only in xen
      1 /*	$NetBSD: xencons.c,v 1.53 2023/02/25 00:35:40 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2006 Manuel Bouyer.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  *
     26  */
     27 
     28 /*
     29  *
     30  * Copyright (c) 2004 Christian Limpach.
     31  * All rights reserved.
     32  *
     33  * Redistribution and use in source and binary forms, with or without
     34  * modification, are permitted provided that the following conditions
     35  * are met:
     36  * 1. Redistributions of source code must retain the above copyright
     37  *    notice, this list of conditions and the following disclaimer.
     38  * 2. Redistributions in binary form must reproduce the above copyright
     39  *    notice, this list of conditions and the following disclaimer in the
     40  *    documentation and/or other materials provided with the distribution.
     41  *
     42  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     43  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     44  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     45  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     46  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     47  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     48  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     49  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     50  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     51  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     52  */
     53 
     54 
     55 #include <sys/cdefs.h>
     56 __KERNEL_RCSID(0, "$NetBSD: xencons.c,v 1.53 2023/02/25 00:35:40 riastradh Exp $");
     57 
     58 #include "opt_xen.h"
     59 
     60 #include <sys/param.h>
     61 #include <sys/ioctl.h>
     62 #include <sys/proc.h>
     63 #include <sys/tty.h>
     64 #include <sys/systm.h>
     65 #include <sys/device.h>
     66 #include <sys/conf.h>
     67 #include <sys/kauth.h>
     68 #include <sys/kernel.h>
     69 
     70 #include <xen/intr.h>
     71 #include <xen/xen.h>
     72 #include <xen/hypervisor.h>
     73 #include <xen/evtchn.h>
     74 #include <uvm/uvm.h>
     75 #include <machine/pmap.h>
     76 #include <xen/include/public/io/console.h>
     77 
     78 #include <dev/cons.h>
     79 
     80 #ifdef DDB
     81 #include <ddb/db_output.h>	/* XXX for db_max_line */
     82 #endif
     83 
     84 #undef XENDEBUG
     85 
     86 #ifdef XENDEBUG
     87 #define XENPRINTK(x) printk x
     88 #else
     89 #define XENPRINTK(x)
     90 #endif
     91 
     92 static int xencons_isconsole = 0;
     93 static struct xencons_softc *xencons_console_device = NULL;
     94 static struct intrhand *ih;
     95 
     96 #define	XENCONS_UNIT(x)	(minor(x))
     97 #define XENCONS_BURST 128
     98 
     99 static int xencons_match(device_t, cfdata_t, void *);
    100 static void xencons_attach(device_t, device_t, void *);
    101 static int xencons_intr(void *);
    102 static void xencons_tty_input(struct xencons_softc *, char*, int);
    103 
    104 struct xencons_softc {
    105 	device_t sc_dev;
    106 	struct	tty *sc_tty;
    107 	int polling;
    108 };
    109 volatile struct xencons_interface *xencons_interface;
    110 
    111 CFATTACH_DECL_NEW(xencons, sizeof(struct xencons_softc),
    112     xencons_match, xencons_attach, NULL, NULL);
    113 
    114 extern struct cfdriver xencons_cd;
    115 
    116 static dev_type_open(xencons_open);
    117 static dev_type_close(xencons_close);
    118 static dev_type_read(xencons_read);
    119 static dev_type_write(xencons_write);
    120 static dev_type_ioctl(xencons_ioctl);
    121 static dev_type_stop(xencons_stop);
    122 static dev_type_tty(xencons_tty);
    123 static dev_type_poll(xencons_poll);
    124 
    125 const struct cdevsw xencons_cdevsw = {
    126 	.d_open = xencons_open,
    127 	.d_close = xencons_close,
    128 	.d_read = xencons_read,
    129 	.d_write = xencons_write,
    130 	.d_ioctl = xencons_ioctl,
    131 	.d_stop = xencons_stop,
    132 	.d_tty = xencons_tty,
    133 	.d_poll = xencons_poll,
    134 	.d_mmap = NULL,	/* XXX: is this safe? - dholland 20140315 */
    135 	.d_kqfilter = ttykqfilter,
    136 	.d_discard = nodiscard,
    137 	.d_flag = D_TTY
    138 };
    139 
    140 static int xencons_handler(void *);
    141 static int xenconscn_getc(dev_t);
    142 static void xenconscn_putc(dev_t, int);
    143 static void xenconscn_pollc(dev_t, int);
    144 
    145 static bool xencons_suspend(device_t, const pmf_qual_t *);
    146 static bool xencons_resume(device_t, const pmf_qual_t *);
    147 
    148 static struct consdev xencons = {
    149 	NULL, NULL, xenconscn_getc, xenconscn_putc, xenconscn_pollc,
    150 	NULL, NULL, NULL, NODEV, CN_NORMAL
    151 };
    152 
    153 static struct cnm_state xencons_cnm_state;
    154 
    155 static void xencons_start(struct tty *);
    156 static int xencons_param(struct tty *, struct termios *);
    157 
    158 static int
    159 xencons_match(device_t parent, cfdata_t match, void *aux)
    160 {
    161 	struct xencons_attach_args *xa = (struct xencons_attach_args *)aux;
    162 
    163 	if (strcmp(xa->xa_device, "xencons") == 0)
    164 		return 1;
    165 	return 0;
    166 }
    167 
    168 static void
    169 xencons_attach(device_t parent, device_t self, void *aux)
    170 {
    171 	struct xencons_softc *sc = device_private(self);
    172 
    173 	aprint_normal(": Xen Virtual Console Driver\n");
    174 
    175 	sc->sc_dev = self;
    176 	sc->sc_tty = tty_alloc();
    177 	tty_attach(sc->sc_tty);
    178 	sc->sc_tty->t_oproc = xencons_start;
    179 	sc->sc_tty->t_param = xencons_param;
    180 
    181 	if (xencons_isconsole) {
    182 		int maj;
    183 
    184 		/* Locate the major number. */
    185 		maj = cdevsw_lookup_major(&xencons_cdevsw);
    186 
    187 		/* There can be only one, but it can have any unit number. */
    188 		cn_tab->cn_dev = makedev(maj, device_unit(self));
    189 
    190 		aprint_verbose_dev(self, "console major %d, unit %d\n",
    191 		    maj, device_unit(self));
    192 
    193 		sc->sc_tty->t_dev = cn_tab->cn_dev;
    194 
    195 #ifdef DDB
    196 		/* Set db_max_line to avoid paging. */
    197 		db_max_line = 0x7fffffff;
    198 #endif
    199 
    200 		xencons_console_device = sc;
    201 
    202 		xencons_resume(self, PMF_Q_NONE);
    203 	}
    204 	sc->polling = 0;
    205 
    206 	if (!pmf_device_register(self, xencons_suspend, xencons_resume))
    207 		aprint_error_dev(self, "couldn't establish power handler\n");
    208 }
    209 
    210 static bool
    211 xencons_suspend(device_t dev, const pmf_qual_t *qual) {
    212 
    213 	int evtch;
    214 
    215 	/* dom0 console should not be suspended */
    216 	if (!xendomain_is_dom0()) {
    217 		evtch = xen_start_info.console_evtchn;
    218 		hypervisor_mask_event(evtch);
    219 		xen_intr_disestablish(ih);
    220 		aprint_verbose_dev(dev, "removed event channel %d\n", ih->ih_pin);
    221 	}
    222 
    223 	return true;
    224 }
    225 
    226 static bool
    227 xencons_resume(device_t dev, const pmf_qual_t *qual) {
    228 
    229 	int evtch = -1;
    230 
    231 	if (xendomain_is_dom0()) {
    232 		/* dom0 console resume is required only during first start-up */
    233 		if (cold) {
    234 			evtch = bind_virq_to_evtch(VIRQ_CONSOLE);
    235 			ih = xen_intr_establish_xname(-1, &xen_pic, evtch,
    236 			    IST_LEVEL, IPL_TTY, xencons_intr,
    237 			    xencons_console_device, false,
    238 			    device_xname(dev));
    239 			KASSERT(ih != NULL);
    240 		}
    241 	} else {
    242 		evtch = xen_start_info.console_evtchn;
    243 		ih = xen_intr_establish_xname(-1, &xen_pic, evtch,
    244 		    IST_LEVEL, IPL_TTY, xencons_handler,
    245 		    xencons_console_device, false, device_xname(dev));
    246 		KASSERT(ih != NULL);
    247 	}
    248 
    249 	if (evtch != -1) {
    250 		aprint_verbose_dev(dev, "using event channel %d\n", evtch);
    251 		hypervisor_unmask_event(evtch);
    252 	}
    253 
    254 	return true;
    255 }
    256 
    257 static int
    258 xencons_open(dev_t dev, int flag, int mode, struct lwp *l)
    259 {
    260 	struct xencons_softc *sc;
    261 	struct tty *tp;
    262 
    263 	sc = device_lookup_private(&xencons_cd, XENCONS_UNIT(dev));
    264 	if (sc == NULL)
    265 		return (ENXIO);
    266 
    267 	tp = sc->sc_tty;
    268 
    269 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    270 		return (EBUSY);
    271 
    272 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
    273 		tp->t_dev = dev;
    274 		ttychars(tp);
    275 		tp->t_iflag = TTYDEF_IFLAG;
    276 		tp->t_oflag = TTYDEF_OFLAG;
    277 		tp->t_cflag = TTYDEF_CFLAG;
    278 		tp->t_lflag = TTYDEF_LFLAG;
    279 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
    280 		xencons_param(tp, &tp->t_termios);
    281 		ttsetwater(tp);
    282 	}
    283 	tp->t_state |= TS_CARR_ON;
    284 
    285 	return ((*tp->t_linesw->l_open)(dev, tp));
    286 }
    287 
    288 static int
    289 xencons_close(dev_t dev, int flag, int mode, struct lwp *l)
    290 {
    291 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    292 	    XENCONS_UNIT(dev));
    293 	struct tty *tp = sc->sc_tty;
    294 
    295 	if (tp == NULL)
    296 		return (0);
    297 	(*tp->t_linesw->l_close)(tp, flag);
    298 	ttyclose(tp);
    299 #ifdef notyet /* XXX */
    300 	tty_free(tp);
    301 #endif
    302 	return (0);
    303 }
    304 
    305 static int
    306 xencons_read(dev_t dev, struct uio *uio, int flag)
    307 {
    308 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    309 	    XENCONS_UNIT(dev));
    310 	struct tty *tp = sc->sc_tty;
    311 
    312 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
    313 }
    314 
    315 static int
    316 xencons_write(dev_t dev, struct uio *uio, int flag)
    317 {
    318 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    319 	    XENCONS_UNIT(dev));
    320 	struct tty *tp = sc->sc_tty;
    321 
    322 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
    323 }
    324 
    325 static int
    326 xencons_poll(dev_t dev, int events, struct lwp *l)
    327 {
    328 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    329 	    XENCONS_UNIT(dev));
    330 	struct tty *tp = sc->sc_tty;
    331 
    332 	return ((*tp->t_linesw->l_poll)(tp, events, l));
    333 }
    334 
    335 static struct tty *
    336 xencons_tty(dev_t dev)
    337 {
    338 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    339 	    XENCONS_UNIT(dev));
    340 	struct tty *tp = sc->sc_tty;
    341 
    342 	return (tp);
    343 }
    344 
    345 static int
    346 xencons_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    347 {
    348 	struct xencons_softc *sc = device_lookup_private(&xencons_cd,
    349 	    XENCONS_UNIT(dev));
    350 	struct tty *tp = sc->sc_tty;
    351 	int error;
    352 
    353 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    354 	if (error != EPASSTHROUGH)
    355 		return (error);
    356 
    357 	error = ttioctl(tp, cmd, data, flag, l);
    358 	if (error != EPASSTHROUGH)
    359 		return (error);
    360 
    361 	switch (cmd) {
    362 	default:
    363 		return (EPASSTHROUGH);
    364 	}
    365 
    366 #ifdef DIAGNOSTIC
    367 	panic("xencons_ioctl: impossible");
    368 #endif
    369 }
    370 
    371 static void
    372 xencons_start(struct tty *tp)
    373 {
    374 	struct clist *cl;
    375 	int s;
    376 
    377 	s = spltty();
    378 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
    379 		goto out;
    380 	tp->t_state |= TS_BUSY;
    381 	splx(s);
    382 
    383 	/*
    384 	 * We need to do this outside spl since it could be fairly
    385 	 * expensive and we don't want our serial ports to overflow.
    386 	 */
    387 	cl = &tp->t_outq;
    388 	if (xendomain_is_dom0()) {
    389 		int len, r;
    390 		u_char buf[XENCONS_BURST+1];
    391 
    392 		len = q_to_b(cl, buf, XENCONS_BURST);
    393 		while (len > 0) {
    394 			r = HYPERVISOR_console_io(CONSOLEIO_write, len, buf);
    395 			if (r <= 0)
    396 				break;
    397 			len -= r;
    398 		}
    399 	} else {
    400 		XENCONS_RING_IDX cons, prod, len;
    401 
    402 #define XNC_OUT (xencons_interface->out)
    403 		cons = xencons_interface->out_cons;
    404 		prod = xencons_interface->out_prod;
    405 		xen_rmb();
    406 		while (prod != cons + sizeof(xencons_interface->out)) {
    407 			if (MASK_XENCONS_IDX(prod, XNC_OUT) <
    408 			    MASK_XENCONS_IDX(cons, XNC_OUT)) {
    409 				len = MASK_XENCONS_IDX(cons, XNC_OUT) -
    410 				    MASK_XENCONS_IDX(prod, XNC_OUT);
    411 			} else {
    412 				len = sizeof(XNC_OUT) -
    413 				    MASK_XENCONS_IDX(prod, XNC_OUT);
    414 			}
    415 			len = q_to_b(cl, __UNVOLATILE(
    416 			    &XNC_OUT[MASK_XENCONS_IDX(prod, XNC_OUT)]), len);
    417 			if (len == 0)
    418 				break;
    419 			prod = prod + len;
    420 		}
    421 		xen_wmb();
    422 		xencons_interface->out_prod = prod;
    423 		xen_wmb();
    424 		hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
    425 #undef XNC_OUT
    426 	}
    427 
    428 	s = spltty();
    429 	tp->t_state &= ~TS_BUSY;
    430 	if (ttypull(tp)) {
    431 		tp->t_state |= TS_TIMEOUT;
    432 		callout_schedule(&tp->t_rstrt_ch, 1);
    433 	}
    434 out:
    435 	splx(s);
    436 }
    437 
    438 static void
    439 xencons_stop(struct tty *tp, int flag)
    440 {
    441 
    442 }
    443 
    444 /* Non-privileged console interrupt routine */
    445 static int
    446 xencons_handler(void *arg)
    447 {
    448 	struct xencons_softc *sc = arg;
    449 	XENCONS_RING_IDX cons, prod, len;
    450 	int s = spltty();
    451 
    452 	if (sc->polling) {
    453 		splx(s);
    454 		return 1;
    455 	}
    456 
    457 
    458 #define XNC_IN (xencons_interface->in)
    459 
    460 	cons = xencons_interface->in_cons;
    461 	prod = xencons_interface->in_prod;
    462 	xen_rmb();
    463 	while (cons != prod) {
    464 		if (MASK_XENCONS_IDX(cons, XNC_IN) <
    465 		    MASK_XENCONS_IDX(prod, XNC_IN))
    466 			len = MASK_XENCONS_IDX(prod, XNC_IN) -
    467 			    MASK_XENCONS_IDX(cons, XNC_IN);
    468 		else
    469 			len = sizeof(XNC_IN) - MASK_XENCONS_IDX(cons, XNC_IN);
    470 
    471 		xencons_tty_input(sc, __UNVOLATILE(
    472 		    &XNC_IN[MASK_XENCONS_IDX(cons, XNC_IN)]), len);
    473 		if (__predict_false(xencons_interface->in_cons != cons)) {
    474 			/* catch up with xenconscn_getc() */
    475 			cons = xencons_interface->in_cons;
    476 			prod = xencons_interface->in_prod;
    477 			xen_rmb();
    478 		} else {
    479 			cons += len;
    480 			xen_wmb();
    481 			xencons_interface->in_cons = cons;
    482 		}
    483 	}
    484 	xen_wmb();
    485 	hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
    486 	splx(s);
    487 	return 1;
    488 #undef XNC_IN
    489 }
    490 
    491 static void
    492 xencons_tty_input(struct xencons_softc *sc, char* buf, int len)
    493 {
    494 	struct tty *tp;
    495 	int i;
    496 
    497 	tp = sc->sc_tty;
    498 	if (tp == NULL)
    499 		return;
    500 
    501 	for (i = 0; i < len; i++) {
    502 		cn_check_magic(sc->sc_tty->t_dev, buf[i], xencons_cnm_state);
    503 		(*tp->t_linesw->l_rint)(buf[i], tp);
    504 	}
    505 }
    506 
    507 /* privileged receive callback */
    508 static int
    509 xencons_intr(void *p)
    510 {
    511 	static char rbuf[16];
    512 	int len;
    513 	struct xencons_softc *sc = p;
    514 
    515 	if (sc == NULL)
    516 		/* Interrupt may happen during resume */
    517 		return 1;
    518 
    519 	if (sc->polling)
    520 		return 1;
    521 
    522 	while ((len =
    523 	    HYPERVISOR_console_io(CONSOLEIO_read, sizeof(rbuf), rbuf)) > 0) {
    524 		xencons_tty_input(sc, rbuf, len);
    525 	}
    526 	return 1;
    527 }
    528 
    529 void
    530 xenconscn_attach(void)
    531 {
    532 
    533 	cn_tab = &xencons;
    534 
    535 	/* console ring mapped in locore.S */
    536 
    537 	cn_init_magic(&xencons_cnm_state);
    538 	cn_set_magic("+++++");
    539 
    540 	xencons_isconsole = 1;
    541 }
    542 
    543 static int
    544 xenconscn_getc(dev_t dev)
    545 {
    546 	char c;
    547 	int s = spltty();
    548 	XENCONS_RING_IDX cons, prod;
    549 
    550 	if (xencons_console_device && xencons_console_device->polling == 0) {
    551 		printf("xenconscn_getc() but not polling\n");
    552 		splx(s);
    553 		return 0;
    554 	}
    555 	if (xendomain_is_dom0()) {
    556 		while (HYPERVISOR_console_io(CONSOLEIO_read, 1, &c) == 0)
    557 			;
    558 		cn_check_magic(dev, c, xencons_cnm_state);
    559 		splx(s);
    560 		return c;
    561 	}
    562 	if (xencons_console_device == NULL) {
    563 		printf("xenconscn_getc(): not console\n");
    564 		while (1)
    565 			;  /* loop here instead of in ddb */
    566 		splx(s);
    567 		return 0;
    568 	}
    569 
    570 	if (xencons_console_device->polling == 0) {
    571 		printf("xenconscn_getc() but not polling\n");
    572 		splx(s);
    573 		return 0;
    574 	}
    575 
    576 	cons = xencons_interface->in_cons;
    577 	prod = xencons_interface->in_prod;
    578 	while (cons == prod) {
    579 		HYPERVISOR_yield();
    580 		prod = xencons_interface->in_prod;
    581 	}
    582 	xen_rmb();
    583 	c = xencons_interface->in[MASK_XENCONS_IDX(xencons_interface->in_cons,
    584 	    xencons_interface->in)];
    585 	xen_wmb();
    586 	xencons_interface->in_cons = cons + 1;
    587 	cn_check_magic(dev, c, xencons_cnm_state);
    588 	splx(s);
    589 	return c;
    590 }
    591 
    592 static void
    593 xenconscn_putc(dev_t dev, int c)
    594 {
    595 	int s = spltty();
    596 	XENCONS_RING_IDX cons, prod;
    597 
    598 	if (xendomain_is_dom0()) {
    599 		u_char buf[1];
    600 
    601 		buf[0] = c;
    602 		(void)HYPERVISOR_console_io(CONSOLEIO_write, 1, buf);
    603 	} else {
    604 		XENPRINTK(("xenconscn_putc(%c)\n", c));
    605 
    606 		cons = xencons_interface->out_cons;
    607 		prod = xencons_interface->out_prod;
    608 		xen_rmb();
    609 		while (prod == cons + sizeof(xencons_interface->out)) {
    610 			cons = xencons_interface->out_cons;
    611 			prod = xencons_interface->out_prod;
    612 			xen_rmb();
    613 		}
    614 		xencons_interface->out[MASK_XENCONS_IDX(xencons_interface->out_prod,
    615 		    xencons_interface->out)] = c;
    616 		xen_wmb();
    617 		xencons_interface->out_prod++;
    618 		xen_wmb();
    619 		hypervisor_notify_via_evtchn(xen_start_info.console.domU.evtchn);
    620 		splx(s);
    621 	}
    622 }
    623 
    624 static void
    625 xenconscn_pollc(dev_t dev, int on)
    626 {
    627 	if (xencons_console_device)
    628 		xencons_console_device->polling = on;
    629 }
    630 
    631 /*
    632  * Set line parameters.
    633  */
    634 static int
    635 xencons_param(struct tty *tp, struct termios *t)
    636 {
    637 
    638 	tp->t_ispeed = t->c_ispeed;
    639 	tp->t_ospeed = t->c_ospeed;
    640 	tp->t_cflag = t->c_cflag;
    641 	return (0);
    642 }
    643