Home | History | Annotate | Line # | Download | only in virtio
viocon.c revision 1.4
      1 /*	$NetBSD: viocon.c,v 1.4 2022/08/13 17:31:21 riastradh Exp $	*/
      2 /*	$OpenBSD: viocon.c,v 1.8 2021/11/05 11:38:29 mpi Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2013-2015 Stefan Fritsch <sf (at) sfritsch.de>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __KERNEL_RCSID(0, "$NetBSD: viocon.c,v 1.4 2022/08/13 17:31:21 riastradh Exp $");
     22 
     23 #include <sys/param.h>
     24 #include <sys/types.h>
     25 
     26 #include <sys/bus.h>
     27 #include <sys/conf.h>
     28 #include <sys/device.h>
     29 #include <sys/kauth.h>
     30 #include <sys/kernel.h>
     31 #include <sys/kmem.h>
     32 #include <sys/lwp.h>
     33 #include <sys/systm.h>
     34 #include <sys/tty.h>
     35 
     36 #include <dev/pci/virtioreg.h>
     37 #include <dev/pci/virtiovar.h>
     38 
     39 #include "ioconf.h"
     40 
     41 /* OpenBSD compat shims */
     42 #define	ttymalloc(speed)	tty_alloc()
     43 #define	splassert(ipl)		__nothing
     44 #define	virtio_notify(vsc, vq)	virtio_enqueue_commit(vsc, vq, -1, true)
     45 #define	ttwakeupwr(tp)		__nothing
     46 
     47 /* features */
     48 #define	VIRTIO_CONSOLE_F_SIZE		(1ULL<<0)
     49 #define	VIRTIO_CONSOLE_F_MULTIPORT	(1ULL<<1)
     50 #define	VIRTIO_CONSOLE_F_EMERG_WRITE 	(1ULL<<2)
     51 
     52 /* config space */
     53 #define VIRTIO_CONSOLE_COLS		0	/* 16 bits */
     54 #define VIRTIO_CONSOLE_ROWS		2	/* 16 bits */
     55 #define VIRTIO_CONSOLE_MAX_NR_PORTS	4	/* 32 bits */
     56 #define VIRTIO_CONSOLE_EMERG_WR		8	/* 32 bits */
     57 
     58 #define VIOCON_DEBUG	0
     59 
     60 #if VIOCON_DEBUG
     61 #define DPRINTF(x...) printf(x)
     62 #else
     63 #define DPRINTF(x...)
     64 #endif
     65 
     66 #define	VIRTIO_CONSOLE_FLAG_BITS					      \
     67 	VIRTIO_COMMON_FLAG_BITS						      \
     68 	"b\x00" "SIZE\0"						      \
     69 	"b\x01" "MULTIPORT\0"						      \
     70 	"b\x02" "EMERG_WRITE\0"
     71 
     72 struct virtio_console_control {
     73 	uint32_t id;	/* Port number */
     74 
     75 #define	VIRTIO_CONSOLE_DEVICE_READY	0
     76 #define	VIRTIO_CONSOLE_PORT_ADD		1
     77 #define	VIRTIO_CONSOLE_PORT_REMOVE	2
     78 #define	VIRTIO_CONSOLE_PORT_READY	3
     79 #define	VIRTIO_CONSOLE_CONSOLE_PORT	4
     80 #define	VIRTIO_CONSOLE_RESIZE		5
     81 #define	VIRTIO_CONSOLE_PORT_OPEN	6
     82 #define	VIRTIO_CONSOLE_PORT_NAME	7
     83 	uint16_t event;
     84 
     85 	uint16_t value;
     86 };
     87 
     88 struct virtio_console_control_resize {
     89 	/* yes, the order is different than in config space */
     90 	uint16_t rows;
     91 	uint16_t cols;
     92 };
     93 
     94 #define	BUFSIZE		128
     95 
     96 #define	VIOCONDEV(u,p)	makedev(cdevsw_lookup_major(&viocon_cdevsw),	      \
     97 			    ((u) << 4) | (p))
     98 #define VIOCONUNIT(x)	(minor(x) >> 4)
     99 #define VIOCONPORT(x)	(minor(x) & 0x0f)
    100 
    101 struct viocon_port {
    102 	struct viocon_softc	*vp_sc;
    103 	struct virtqueue	*vp_rx;
    104 	struct virtqueue	*vp_tx;
    105 	void			*vp_si;
    106 	struct tty		*vp_tty;
    107 	const char 		*vp_name;
    108 	bus_dma_segment_t	 vp_dmaseg;
    109 	bus_dmamap_t		 vp_dmamap;
    110 #ifdef NOTYET
    111 	unsigned int		 vp_host_open:1;	/* XXX needs F_MULTIPORT */
    112 	unsigned int		 vp_guest_open:1;	/* XXX needs F_MULTIPORT */
    113 	unsigned int		 vp_is_console:1;	/* XXX needs F_MULTIPORT */
    114 #endif
    115 	unsigned int		 vp_iflow:1;		/* rx flow control */
    116 	uint16_t		 vp_rows;
    117 	uint16_t		 vp_cols;
    118 	u_char			*vp_rx_buf;
    119 	u_char			*vp_tx_buf;
    120 };
    121 
    122 struct viocon_softc {
    123 	struct device		*sc_dev;
    124 	struct virtio_softc	*sc_virtio;
    125 	struct virtqueue	*sc_vqs;
    126 
    127 	struct virtqueue        *sc_c_vq_rx;
    128 	struct virtqueue        *sc_c_vq_tx;
    129 
    130 	unsigned int		 sc_max_ports;
    131 	struct viocon_port	**sc_ports;
    132 
    133 	bus_dmamap_t		 sc_dmamap;
    134 };
    135 
    136 int	viocon_match(struct device *, struct cfdata *, void *);
    137 void	viocon_attach(struct device *, struct device *, void *);
    138 int	viocon_tx_intr(struct virtqueue *);
    139 int	viocon_tx_drain(struct viocon_port *, struct virtqueue *vq);
    140 int	viocon_rx_intr(struct virtqueue *);
    141 void	viocon_rx_soft(void *);
    142 void	viocon_rx_fill(struct viocon_port *);
    143 int	viocon_port_create(struct viocon_softc *, int);
    144 void	vioconstart(struct tty *);
    145 int	vioconhwiflow(struct tty *, int);
    146 int	vioconparam(struct tty *, struct termios *);
    147 int	vioconopen(dev_t, int, int, struct lwp *);
    148 int	vioconclose(dev_t, int, int, struct lwp *);
    149 int	vioconread(dev_t, struct uio *, int);
    150 int	vioconwrite(dev_t, struct uio *, int);
    151 void	vioconstop(struct tty *, int);
    152 int	vioconioctl(dev_t, u_long, void *, int, struct lwp *);
    153 struct tty	*viocontty(dev_t dev);
    154 
    155 CFATTACH_DECL_NEW(viocon, sizeof(struct viocon_softc),
    156     viocon_match, viocon_attach, /*detach*/NULL, /*activate*/NULL);
    157 
    158 const struct cdevsw viocon_cdevsw = {
    159 	.d_open = vioconopen,
    160 	.d_close = vioconclose,
    161 	.d_read = vioconread,
    162 	.d_write = vioconwrite,
    163 	.d_ioctl = vioconioctl,
    164 	.d_stop = vioconstop,
    165 	.d_tty = viocontty,
    166 	.d_poll = nopoll,	/* XXX */
    167 	.d_mmap = nommap,
    168 	.d_kqfilter = ttykqfilter,
    169 	.d_discard = nodiscard,
    170 	.d_flag = D_TTY,
    171 };
    172 
    173 static inline struct viocon_softc *
    174 dev2sc(dev_t dev)
    175 {
    176 	return device_lookup_private(&viocon_cd, VIOCONUNIT(dev));
    177 }
    178 
    179 static inline struct viocon_port *
    180 dev2port(dev_t dev)
    181 {
    182 	return dev2sc(dev)->sc_ports[VIOCONPORT(dev)];
    183 }
    184 
    185 int viocon_match(struct device *parent, struct cfdata *match, void *aux)
    186 {
    187 	struct virtio_attach_args *va = aux;
    188 	if (va->sc_childdevid == VIRTIO_DEVICE_ID_CONSOLE)
    189 		return 1;
    190 	return 0;
    191 }
    192 
    193 void
    194 viocon_attach(struct device *parent, struct device *self, void *aux)
    195 {
    196 	struct viocon_softc *sc = device_private(self);
    197 	struct virtio_softc *vsc = device_private(parent);
    198 	int maxports = 1;
    199 
    200 	sc->sc_dev = self;
    201 	if (virtio_child(vsc) != NULL) {
    202 		aprint_error(": parent %s already has a child\n",
    203 		    device_xname(parent));
    204 		return;
    205 	}
    206 	sc->sc_virtio = vsc;
    207 	sc->sc_max_ports = maxports;
    208 
    209 	sc->sc_vqs = kmem_zalloc(2 * (maxports + 1) * sizeof(sc->sc_vqs[0]),
    210 	    KM_SLEEP);
    211 	sc->sc_ports = kmem_zalloc(maxports * sizeof(sc->sc_ports[0]),
    212 	    KM_SLEEP);
    213 
    214 	virtio_child_attach_start(vsc, self, IPL_TTY, sc->sc_vqs,
    215 	    /*config_change*/NULL, virtio_vq_intr,
    216 	    /*req_flags*/0, /*req_features*/VIRTIO_CONSOLE_F_SIZE,
    217 	    VIRTIO_CONSOLE_FLAG_BITS);
    218 
    219 	DPRINTF("%s: softc: %p\n", __func__, sc);
    220 	if (viocon_port_create(sc, 0) != 0) {
    221 		printf("\n%s: viocon_port_create failed\n", __func__);
    222 		goto err;
    223 	}
    224 	viocon_rx_fill(sc->sc_ports[0]);
    225 
    226 	if (virtio_child_attach_finish(vsc) != 0)
    227 		goto err;
    228 
    229 	return;
    230 err:
    231 	kmem_free(sc->sc_vqs, 2 * (maxports + 1) * sizeof(sc->sc_vqs[0]));
    232 	kmem_free(sc->sc_ports, maxports * sizeof(sc->sc_ports[0]));
    233 	virtio_child_attach_failed(vsc);
    234 }
    235 
    236 int
    237 viocon_port_create(struct viocon_softc *sc, int portidx)
    238 {
    239 	struct virtio_softc *vsc = sc->sc_virtio;
    240 	int rxidx, txidx, allocsize, nsegs;
    241 	char name[6];
    242 	struct viocon_port *vp;
    243 	void *kva;
    244 	struct tty *tp;
    245 
    246 	vp = kmem_zalloc(sizeof(*vp), KM_SLEEP);
    247 	if (vp == NULL)
    248 		return ENOMEM;
    249 	sc->sc_ports[portidx] = vp;
    250 	vp->vp_sc = sc;
    251 	DPRINTF("%s: vp: %p\n", __func__, vp);
    252 
    253 	if (portidx == 0)
    254 		rxidx = 0;
    255 	else
    256 		rxidx = 2 * (portidx + 1);
    257 	txidx = rxidx + 1;
    258 
    259 	snprintf(name, sizeof(name), "p%drx", portidx);
    260 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[rxidx], rxidx, BUFSIZE, 1,
    261 	    name) != 0) {
    262 		printf("\nCan't alloc %s virtqueue\n", name);
    263 		goto err;
    264 	}
    265 	vp->vp_rx = &sc->sc_vqs[rxidx];
    266 	vp->vp_rx->vq_done = viocon_rx_intr;
    267 	vp->vp_si = softint_establish(SOFTINT_SERIAL, viocon_rx_soft, vp);
    268 	DPRINTF("%s: rx: %p\n", __func__, vp->vp_rx);
    269 
    270 	snprintf(name, sizeof(name), "p%dtx", portidx);
    271 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[txidx], txidx, BUFSIZE, 1,
    272 	    name) != 0) {
    273 		printf("\nCan't alloc %s virtqueue\n", name);
    274 		goto err;
    275 	}
    276 	vp->vp_tx = &sc->sc_vqs[txidx];
    277 	vp->vp_tx->vq_done = viocon_tx_intr;
    278 	DPRINTF("%s: tx: %p\n", __func__, vp->vp_tx);
    279 
    280 	allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE;
    281 
    282 	if (bus_dmamap_create(virtio_dmat(vsc), allocsize, 1, allocsize, 0,
    283 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0)
    284 		goto err;
    285 	if (bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 8, 0, &vp->vp_dmaseg,
    286 	    1, &nsegs, BUS_DMA_NOWAIT) != 0)
    287 		goto err;
    288 	if (bus_dmamem_map(virtio_dmat(vsc), &vp->vp_dmaseg, nsegs,
    289 	    allocsize, &kva, BUS_DMA_NOWAIT) != 0)
    290 		goto err;
    291 	memset(kva, 0, allocsize);
    292 	if (bus_dmamap_load(virtio_dmat(vsc), vp->vp_dmamap, kva,
    293 	    allocsize, NULL, BUS_DMA_NOWAIT) != 0)
    294 		goto err;
    295 	vp->vp_rx_buf = (unsigned char *)kva;
    296 	/*
    297 	 * XXX use only a small circular tx buffer instead of many BUFSIZE buffers?
    298 	 */
    299 	vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE;
    300 
    301 	if (virtio_features(vsc) & VIRTIO_CONSOLE_F_SIZE) {
    302 		vp->vp_cols = virtio_read_device_config_2(vsc,
    303 		    VIRTIO_CONSOLE_COLS);
    304 		vp->vp_rows = virtio_read_device_config_2(vsc,
    305 		    VIRTIO_CONSOLE_ROWS);
    306 	}
    307 
    308 	tp = ttymalloc(1000000);
    309 	tp->t_oproc = vioconstart;
    310 	tp->t_param = vioconparam;
    311 	tp->t_hwiflow = vioconhwiflow;
    312 	tp->t_dev = VIOCONDEV(device_unit(sc->sc_dev), portidx);
    313 	vp->vp_tty = tp;
    314 	DPRINTF("%s: tty: %p\n", __func__, tp);
    315 
    316 	virtio_start_vq_intr(vsc, vp->vp_rx);
    317 	virtio_start_vq_intr(vsc, vp->vp_tx);
    318 
    319 	return 0;
    320 err:
    321 	panic("%s failed", __func__);
    322 	return -1;
    323 }
    324 
    325 int
    326 viocon_tx_drain(struct viocon_port *vp, struct virtqueue *vq)
    327 {
    328 	struct virtio_softc *vsc = vq->vq_owner;
    329 	int ndone = 0, len, slot;
    330 
    331 	splassert(IPL_TTY);
    332 	while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    333 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    334 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, BUFSIZE,
    335 		    BUS_DMASYNC_POSTWRITE);
    336 		virtio_dequeue_commit(vsc, vq, slot);
    337 		ndone++;
    338 	}
    339 	return ndone;
    340 }
    341 
    342 int
    343 viocon_tx_intr(struct virtqueue *vq)
    344 {
    345 	struct virtio_softc *vsc = vq->vq_owner;
    346 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    347 	int ndone = 0;
    348 	int portidx = (vq->vq_index - 1) / 2;
    349 	struct viocon_port *vp = sc->sc_ports[portidx];
    350 	struct tty *tp = vp->vp_tty;
    351 
    352 	splassert(IPL_TTY);
    353 	ndone = viocon_tx_drain(vp, vq);
    354 	if (ndone && ISSET(tp->t_state, TS_BUSY)) {
    355 		CLR(tp->t_state, TS_BUSY);
    356 		(*tp->t_linesw->l_start)(tp);
    357 	}
    358 
    359 	return 1;
    360 }
    361 
    362 void
    363 viocon_rx_fill(struct viocon_port *vp)
    364 {
    365 	struct virtqueue *vq = vp->vp_rx;
    366 	struct virtio_softc *vsc = vp->vp_sc->sc_virtio;
    367 	int r, slot, ndone = 0;
    368 
    369 	while ((r = virtio_enqueue_prep(vsc, vq, &slot)) == 0) {
    370 		if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0)
    371 			break;
    372 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, slot * BUFSIZE,
    373 		    BUFSIZE, BUS_DMASYNC_PREREAD);
    374 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, slot * BUFSIZE,
    375 		    BUFSIZE, 0);
    376 		virtio_enqueue_commit(vsc, vq, slot, 0);
    377 		ndone++;
    378 	}
    379 	KASSERT(r == 0 || r == EAGAIN);
    380 	if (ndone > 0)
    381 		virtio_notify(vsc, vq);
    382 }
    383 
    384 int
    385 viocon_rx_intr(struct virtqueue *vq)
    386 {
    387 	struct virtio_softc *vsc = vq->vq_owner;
    388 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    389 	int portidx = (vq->vq_index - 1) / 2;
    390 	struct viocon_port *vp = sc->sc_ports[portidx];
    391 
    392 	softint_schedule(vp->vp_si);
    393 	return 1;
    394 }
    395 
    396 void
    397 viocon_rx_soft(void *arg)
    398 {
    399 	struct viocon_port *vp = arg;
    400 	struct virtqueue *vq = vp->vp_rx;
    401 	struct virtio_softc *vsc = vq->vq_owner;
    402 	struct tty *tp = vp->vp_tty;
    403 	int slot, len, i;
    404 	u_char *p;
    405 
    406 	while (!vp->vp_iflow && virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    407 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    408 		    slot * BUFSIZE, BUFSIZE, BUS_DMASYNC_POSTREAD);
    409 		p = vp->vp_rx_buf + slot * BUFSIZE;
    410 		for (i = 0; i < len; i++)
    411 			(*tp->t_linesw->l_rint)(*p++, tp);
    412 		virtio_dequeue_commit(vsc, vq, slot);
    413 	}
    414 
    415 	viocon_rx_fill(vp);
    416 
    417 	return;
    418 }
    419 
    420 void
    421 vioconstart(struct tty *tp)
    422 {
    423 	struct viocon_softc *sc = dev2sc(tp->t_dev);
    424 	struct virtio_softc *vsc;
    425 	struct viocon_port *vp = dev2port(tp->t_dev);
    426 	struct virtqueue *vq;
    427 	u_char *buf;
    428 	int s, cnt, slot, ret, ndone;
    429 
    430 	vsc = sc->sc_virtio;
    431 	vq = vp->vp_tx;
    432 
    433 	s = spltty();
    434 
    435 	ndone = viocon_tx_drain(vp, vq);
    436 	if (ISSET(tp->t_state, TS_BUSY)) {
    437 		if (ndone > 0)
    438 			CLR(tp->t_state, TS_BUSY);
    439 		else
    440 			goto out;
    441 	}
    442 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
    443 		goto out;
    444 
    445 	if (tp->t_outq.c_cc == 0)
    446 		goto out;
    447 	ndone = 0;
    448 
    449 	while (tp->t_outq.c_cc > 0) {
    450 		ret = virtio_enqueue_prep(vsc, vq, &slot);
    451 		if (ret == EAGAIN) {
    452 			SET(tp->t_state, TS_BUSY);
    453 			break;
    454 		}
    455 		KASSERT(ret == 0);
    456 		ret = virtio_enqueue_reserve(vsc, vq, slot, 1);
    457 		KASSERT(ret == 0);
    458 		buf = vp->vp_tx_buf + slot * BUFSIZE;
    459 		cnt = q_to_b(&tp->t_outq, buf, BUFSIZE);
    460 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    461 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt,
    462 		    BUS_DMASYNC_PREWRITE);
    463 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap,
    464 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 1);
    465 		virtio_enqueue_commit(vsc, vq, slot, 0);
    466 		ndone++;
    467 	}
    468 	if (ndone > 0)
    469 		virtio_notify(vsc, vq);
    470 	ttwakeupwr(tp);
    471 out:
    472 	splx(s);
    473 }
    474 
    475 int
    476 vioconhwiflow(struct tty *tp, int stop)
    477 {
    478 	struct viocon_port *vp = dev2port(tp->t_dev);
    479 	int s;
    480 
    481 	s = spltty();
    482 	vp->vp_iflow = stop;
    483 	if (stop) {
    484 		virtio_stop_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    485 	} else {
    486 		virtio_start_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    487 		softint_schedule(vp->vp_si);
    488 	}
    489 	splx(s);
    490 	return 1;
    491 }
    492 
    493 int
    494 vioconparam(struct tty *tp, struct termios *t)
    495 {
    496 	tp->t_ispeed = t->c_ispeed;
    497 	tp->t_ospeed = t->c_ospeed;
    498 	tp->t_cflag = t->c_cflag;
    499 
    500 	vioconstart(tp);
    501 	return 0;
    502 }
    503 
    504 int
    505 vioconopen(dev_t dev, int flag, int mode, struct lwp *l)
    506 {
    507 	int unit = VIOCONUNIT(dev);
    508 	int port = VIOCONPORT(dev);
    509 	struct viocon_softc *sc;
    510 	struct viocon_port *vp;
    511 	struct tty *tp;
    512 	int s, error;
    513 
    514 	sc = device_lookup_private(&viocon_cd, unit);
    515 	if (sc == NULL)
    516 		return (ENXIO);
    517 	if (!device_is_active(sc->sc_dev))
    518 		return (ENXIO);
    519 
    520 	s = spltty();
    521 	if (port >= sc->sc_max_ports) {
    522 		splx(s);
    523 		return (ENXIO);
    524 	}
    525 	vp = sc->sc_ports[port];
    526 	tp = vp->vp_tty;
    527 #ifdef NOTYET
    528 	vp->vp_guest_open = 1;
    529 #endif
    530 	splx(s);
    531 
    532 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    533 		return (EBUSY);
    534 
    535 	s = spltty();
    536 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    537 		ttychars(tp);
    538 		tp->t_ispeed = 1000000;
    539 		tp->t_ospeed = 1000000;
    540 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL|CRTSCTS;
    541 		tp->t_iflag = TTYDEF_IFLAG;
    542 		tp->t_oflag = TTYDEF_OFLAG;
    543 		tp->t_lflag = TTYDEF_LFLAG;
    544 		if (vp->vp_cols != 0) {
    545 			tp->t_winsize.ws_col = vp->vp_cols;
    546 			tp->t_winsize.ws_row = vp->vp_rows;
    547 		}
    548 
    549 		vioconparam(tp, &tp->t_termios);
    550 		ttsetwater(tp);
    551 	}
    552 	splx(s);
    553 
    554 	error = (*tp->t_linesw->l_open)(dev, tp);
    555 	return error;
    556 }
    557 
    558 int
    559 vioconclose(dev_t dev, int flag, int mode, struct lwp *l)
    560 {
    561 	struct viocon_port *vp = dev2port(dev);
    562 	struct tty *tp = vp->vp_tty;
    563 	int s;
    564 
    565 	if (!ISSET(tp->t_state, TS_ISOPEN))
    566 		return 0;
    567 
    568 	(*tp->t_linesw->l_close)(tp, flag);
    569 	s = spltty();
    570 #ifdef NOTYET
    571 	vp->vp_guest_open = 0;
    572 #endif
    573 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
    574 	ttyclose(tp);
    575 	splx(s);
    576 
    577 	return 0;
    578 }
    579 
    580 int
    581 vioconread(dev_t dev, struct uio *uio, int flag)
    582 {
    583 	struct viocon_port *vp = dev2port(dev);
    584 	struct tty *tp = vp->vp_tty;
    585 
    586 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    587 }
    588 
    589 int
    590 vioconwrite(dev_t dev, struct uio *uio, int flag)
    591 {
    592 	struct viocon_port *vp = dev2port(dev);
    593 	struct tty *tp = vp->vp_tty;
    594 
    595 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    596 }
    597 
    598 struct tty *
    599 viocontty(dev_t dev)
    600 {
    601 	struct viocon_port *vp = dev2port(dev);
    602 
    603 	return vp->vp_tty;
    604 }
    605 
    606 void
    607 vioconstop(struct tty *tp, int flag)
    608 {
    609 	int s;
    610 
    611 	s = spltty();
    612 	if (ISSET(tp->t_state, TS_BUSY))
    613 		if (!ISSET(tp->t_state, TS_TTSTOP))
    614 			SET(tp->t_state, TS_FLUSH);
    615 	splx(s);
    616 }
    617 
    618 int
    619 vioconioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    620 {
    621 	struct viocon_port *vp = dev2port(dev);
    622 	struct tty *tp;
    623 	int error1, error2;
    624 
    625 	tp = vp->vp_tty;
    626 
    627 	error1 = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    628 	if (error1 >= 0)
    629 		return error1;
    630 	error2 = ttioctl(tp, cmd, data, flag, l);
    631 	if (error2 >= 0)
    632 		return error2;
    633 	return ENOTTY;
    634 }
    635