Home | History | Annotate | Line # | Download | only in virtio
viocon.c revision 1.6
      1 /*	$NetBSD: viocon.c,v 1.6 2023/03/23 03:27:48 yamaguchi 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.6 2023/03/23 03:27:48 yamaguchi 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 
    134 int	viocon_match(struct device *, struct cfdata *, void *);
    135 void	viocon_attach(struct device *, struct device *, void *);
    136 int	viocon_tx_intr(struct virtqueue *);
    137 int	viocon_tx_drain(struct viocon_port *, struct virtqueue *vq);
    138 int	viocon_rx_intr(struct virtqueue *);
    139 void	viocon_rx_soft(void *);
    140 void	viocon_rx_fill(struct viocon_port *);
    141 int	viocon_port_create(struct viocon_softc *, int);
    142 void	vioconstart(struct tty *);
    143 int	vioconhwiflow(struct tty *, int);
    144 int	vioconparam(struct tty *, struct termios *);
    145 int	vioconopen(dev_t, int, int, struct lwp *);
    146 int	vioconclose(dev_t, int, int, struct lwp *);
    147 int	vioconread(dev_t, struct uio *, int);
    148 int	vioconwrite(dev_t, struct uio *, int);
    149 void	vioconstop(struct tty *, int);
    150 int	vioconioctl(dev_t, u_long, void *, int, struct lwp *);
    151 struct tty	*viocontty(dev_t dev);
    152 
    153 CFATTACH_DECL_NEW(viocon, sizeof(struct viocon_softc),
    154     viocon_match, viocon_attach, /*detach*/NULL, /*activate*/NULL);
    155 
    156 const struct cdevsw viocon_cdevsw = {
    157 	.d_open = vioconopen,
    158 	.d_close = vioconclose,
    159 	.d_read = vioconread,
    160 	.d_write = vioconwrite,
    161 	.d_ioctl = vioconioctl,
    162 	.d_stop = vioconstop,
    163 	.d_tty = viocontty,
    164 	.d_poll = nopoll,	/* XXX */
    165 	.d_mmap = nommap,
    166 	.d_kqfilter = ttykqfilter,
    167 	.d_discard = nodiscard,
    168 	.d_flag = D_TTY,
    169 };
    170 
    171 static inline struct viocon_softc *
    172 dev2sc(dev_t dev)
    173 {
    174 	return device_lookup_private(&viocon_cd, VIOCONUNIT(dev));
    175 }
    176 
    177 static inline struct viocon_port *
    178 dev2port(dev_t dev)
    179 {
    180 	return dev2sc(dev)->sc_ports[VIOCONPORT(dev)];
    181 }
    182 
    183 int viocon_match(struct device *parent, struct cfdata *match, void *aux)
    184 {
    185 	struct virtio_attach_args *va = aux;
    186 	if (va->sc_childdevid == VIRTIO_DEVICE_ID_CONSOLE)
    187 		return 1;
    188 	return 0;
    189 }
    190 
    191 void
    192 viocon_attach(struct device *parent, struct device *self, void *aux)
    193 {
    194 	struct viocon_softc *sc = device_private(self);
    195 	struct virtio_softc *vsc = device_private(parent);
    196 	int maxports = 1;
    197 
    198 	sc->sc_dev = self;
    199 	if (virtio_child(vsc) != NULL) {
    200 		aprint_error(": parent %s already has a child\n",
    201 		    device_xname(parent));
    202 		return;
    203 	}
    204 	sc->sc_virtio = vsc;
    205 	sc->sc_max_ports = maxports;
    206 
    207 	sc->sc_vqs = kmem_zalloc(2 * (maxports + 1) * sizeof(sc->sc_vqs[0]),
    208 	    KM_SLEEP);
    209 	sc->sc_ports = kmem_zalloc(maxports * sizeof(sc->sc_ports[0]),
    210 	    KM_SLEEP);
    211 
    212 	virtio_child_attach_start(vsc, self, IPL_TTY,
    213 	    /*req_features*/VIRTIO_CONSOLE_F_SIZE, VIRTIO_CONSOLE_FLAG_BITS);
    214 
    215 	DPRINTF("%s: softc: %p\n", __func__, sc);
    216 	if (viocon_port_create(sc, 0) != 0) {
    217 		printf("\n%s: viocon_port_create failed\n", __func__);
    218 		goto err;
    219 	}
    220 	viocon_rx_fill(sc->sc_ports[0]);
    221 
    222 	if (virtio_child_attach_finish(vsc, sc->sc_vqs, sc->sc_max_ports * 2,
    223 	    /*config_change*/NULL, virtio_vq_intr, /*req_flags*/0) != 0)
    224 		goto err;
    225 
    226 	return;
    227 err:
    228 	kmem_free(sc->sc_vqs, 2 * (maxports + 1) * sizeof(sc->sc_vqs[0]));
    229 	kmem_free(sc->sc_ports, maxports * sizeof(sc->sc_ports[0]));
    230 	virtio_child_attach_failed(vsc);
    231 }
    232 
    233 int
    234 viocon_port_create(struct viocon_softc *sc, int portidx)
    235 {
    236 	struct virtio_softc *vsc = sc->sc_virtio;
    237 	int rxidx, txidx, allocsize, nsegs;
    238 	char name[6];
    239 	struct viocon_port *vp;
    240 	void *kva;
    241 	struct tty *tp;
    242 
    243 	vp = kmem_zalloc(sizeof(*vp), KM_SLEEP);
    244 	if (vp == NULL)
    245 		return ENOMEM;
    246 	sc->sc_ports[portidx] = vp;
    247 	vp->vp_sc = sc;
    248 	DPRINTF("%s: vp: %p\n", __func__, vp);
    249 
    250 	if (portidx == 0)
    251 		rxidx = 0;
    252 	else
    253 		rxidx = 2 * (portidx + 1);
    254 	txidx = rxidx + 1;
    255 
    256 	snprintf(name, sizeof(name), "p%drx", portidx);
    257 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[rxidx], rxidx, BUFSIZE, 1,
    258 	    name) != 0) {
    259 		printf("\nCan't alloc %s virtqueue\n", name);
    260 		goto err;
    261 	}
    262 	vp->vp_rx = &sc->sc_vqs[rxidx];
    263 	vp->vp_rx->vq_done = viocon_rx_intr;
    264 	vp->vp_si = softint_establish(SOFTINT_SERIAL, viocon_rx_soft, vp);
    265 	DPRINTF("%s: rx: %p\n", __func__, vp->vp_rx);
    266 
    267 	snprintf(name, sizeof(name), "p%dtx", portidx);
    268 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[txidx], txidx, BUFSIZE, 1,
    269 	    name) != 0) {
    270 		printf("\nCan't alloc %s virtqueue\n", name);
    271 		goto err;
    272 	}
    273 	vp->vp_tx = &sc->sc_vqs[txidx];
    274 	vp->vp_tx->vq_done = viocon_tx_intr;
    275 	DPRINTF("%s: tx: %p\n", __func__, vp->vp_tx);
    276 
    277 	allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE;
    278 
    279 	if (bus_dmamap_create(virtio_dmat(vsc), allocsize, 1, allocsize, 0,
    280 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0)
    281 		goto err;
    282 	if (bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 8, 0, &vp->vp_dmaseg,
    283 	    1, &nsegs, BUS_DMA_NOWAIT) != 0)
    284 		goto err;
    285 	if (bus_dmamem_map(virtio_dmat(vsc), &vp->vp_dmaseg, nsegs,
    286 	    allocsize, &kva, BUS_DMA_NOWAIT) != 0)
    287 		goto err;
    288 	memset(kva, 0, allocsize);
    289 	if (bus_dmamap_load(virtio_dmat(vsc), vp->vp_dmamap, kva,
    290 	    allocsize, NULL, BUS_DMA_NOWAIT) != 0)
    291 		goto err;
    292 	vp->vp_rx_buf = (unsigned char *)kva;
    293 	/*
    294 	 * XXX use only a small circular tx buffer instead of many BUFSIZE buffers?
    295 	 */
    296 	vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE;
    297 
    298 	if (virtio_features(vsc) & VIRTIO_CONSOLE_F_SIZE) {
    299 		vp->vp_cols = virtio_read_device_config_2(vsc,
    300 		    VIRTIO_CONSOLE_COLS);
    301 		vp->vp_rows = virtio_read_device_config_2(vsc,
    302 		    VIRTIO_CONSOLE_ROWS);
    303 	}
    304 
    305 	tp = ttymalloc(1000000);
    306 	tp->t_oproc = vioconstart;
    307 	tp->t_param = vioconparam;
    308 	tp->t_hwiflow = vioconhwiflow;
    309 	tp->t_dev = VIOCONDEV(device_unit(sc->sc_dev), portidx);
    310 	vp->vp_tty = tp;
    311 	DPRINTF("%s: tty: %p\n", __func__, tp);
    312 
    313 	virtio_start_vq_intr(vsc, vp->vp_rx);
    314 	virtio_start_vq_intr(vsc, vp->vp_tx);
    315 
    316 	return 0;
    317 err:
    318 	panic("%s failed", __func__);
    319 	return -1;
    320 }
    321 
    322 int
    323 viocon_tx_drain(struct viocon_port *vp, struct virtqueue *vq)
    324 {
    325 	struct virtio_softc *vsc = vq->vq_owner;
    326 	int ndone = 0, len, slot;
    327 
    328 	splassert(IPL_TTY);
    329 	while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    330 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    331 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, BUFSIZE,
    332 		    BUS_DMASYNC_POSTWRITE);
    333 		virtio_dequeue_commit(vsc, vq, slot);
    334 		ndone++;
    335 	}
    336 	return ndone;
    337 }
    338 
    339 int
    340 viocon_tx_intr(struct virtqueue *vq)
    341 {
    342 	struct virtio_softc *vsc = vq->vq_owner;
    343 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    344 	int ndone = 0;
    345 	int portidx = (vq->vq_index - 1) / 2;
    346 	struct viocon_port *vp = sc->sc_ports[portidx];
    347 	struct tty *tp = vp->vp_tty;
    348 
    349 	splassert(IPL_TTY);
    350 	ndone = viocon_tx_drain(vp, vq);
    351 	if (ndone && ISSET(tp->t_state, TS_BUSY)) {
    352 		CLR(tp->t_state, TS_BUSY);
    353 		(*tp->t_linesw->l_start)(tp);
    354 	}
    355 
    356 	return 1;
    357 }
    358 
    359 void
    360 viocon_rx_fill(struct viocon_port *vp)
    361 {
    362 	struct virtqueue *vq = vp->vp_rx;
    363 	struct virtio_softc *vsc = vp->vp_sc->sc_virtio;
    364 	int r, slot, ndone = 0;
    365 
    366 	while ((r = virtio_enqueue_prep(vsc, vq, &slot)) == 0) {
    367 		if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0)
    368 			break;
    369 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, slot * BUFSIZE,
    370 		    BUFSIZE, BUS_DMASYNC_PREREAD);
    371 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, slot * BUFSIZE,
    372 		    BUFSIZE, 0);
    373 		virtio_enqueue_commit(vsc, vq, slot, 0);
    374 		ndone++;
    375 	}
    376 	KASSERT(r == 0 || r == EAGAIN);
    377 	if (ndone > 0)
    378 		virtio_notify(vsc, vq);
    379 }
    380 
    381 int
    382 viocon_rx_intr(struct virtqueue *vq)
    383 {
    384 	struct virtio_softc *vsc = vq->vq_owner;
    385 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    386 	int portidx = (vq->vq_index - 1) / 2;
    387 	struct viocon_port *vp = sc->sc_ports[portidx];
    388 
    389 	softint_schedule(vp->vp_si);
    390 	return 1;
    391 }
    392 
    393 void
    394 viocon_rx_soft(void *arg)
    395 {
    396 	struct viocon_port *vp = arg;
    397 	struct virtqueue *vq = vp->vp_rx;
    398 	struct virtio_softc *vsc = vq->vq_owner;
    399 	struct tty *tp = vp->vp_tty;
    400 	int slot, len, i;
    401 	u_char *p;
    402 
    403 	while (!vp->vp_iflow && virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    404 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    405 		    slot * BUFSIZE, BUFSIZE, BUS_DMASYNC_POSTREAD);
    406 		p = vp->vp_rx_buf + slot * BUFSIZE;
    407 		for (i = 0; i < len; i++)
    408 			(*tp->t_linesw->l_rint)(*p++, tp);
    409 		virtio_dequeue_commit(vsc, vq, slot);
    410 	}
    411 
    412 	viocon_rx_fill(vp);
    413 
    414 	return;
    415 }
    416 
    417 void
    418 vioconstart(struct tty *tp)
    419 {
    420 	struct viocon_softc *sc = dev2sc(tp->t_dev);
    421 	struct virtio_softc *vsc;
    422 	struct viocon_port *vp = dev2port(tp->t_dev);
    423 	struct virtqueue *vq;
    424 	u_char *buf;
    425 	int s, cnt, slot, ret, ndone;
    426 
    427 	vsc = sc->sc_virtio;
    428 	vq = vp->vp_tx;
    429 
    430 	s = spltty();
    431 
    432 	ndone = viocon_tx_drain(vp, vq);
    433 	if (ISSET(tp->t_state, TS_BUSY)) {
    434 		if (ndone > 0)
    435 			CLR(tp->t_state, TS_BUSY);
    436 		else
    437 			goto out;
    438 	}
    439 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
    440 		goto out;
    441 
    442 	if (tp->t_outq.c_cc == 0)
    443 		goto out;
    444 	ndone = 0;
    445 
    446 	while (tp->t_outq.c_cc > 0) {
    447 		ret = virtio_enqueue_prep(vsc, vq, &slot);
    448 		if (ret == EAGAIN) {
    449 			SET(tp->t_state, TS_BUSY);
    450 			break;
    451 		}
    452 		KASSERT(ret == 0);
    453 		ret = virtio_enqueue_reserve(vsc, vq, slot, 1);
    454 		KASSERT(ret == 0);
    455 		buf = vp->vp_tx_buf + slot * BUFSIZE;
    456 		cnt = q_to_b(&tp->t_outq, buf, BUFSIZE);
    457 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    458 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt,
    459 		    BUS_DMASYNC_PREWRITE);
    460 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap,
    461 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 1);
    462 		virtio_enqueue_commit(vsc, vq, slot, 0);
    463 		ndone++;
    464 	}
    465 	if (ndone > 0)
    466 		virtio_notify(vsc, vq);
    467 	ttwakeupwr(tp);
    468 out:
    469 	splx(s);
    470 }
    471 
    472 int
    473 vioconhwiflow(struct tty *tp, int stop)
    474 {
    475 	struct viocon_port *vp = dev2port(tp->t_dev);
    476 	int s;
    477 
    478 	s = spltty();
    479 	vp->vp_iflow = stop;
    480 	if (stop) {
    481 		virtio_stop_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    482 	} else {
    483 		virtio_start_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    484 		softint_schedule(vp->vp_si);
    485 	}
    486 	splx(s);
    487 	return 1;
    488 }
    489 
    490 int
    491 vioconparam(struct tty *tp, struct termios *t)
    492 {
    493 	tp->t_ispeed = t->c_ispeed;
    494 	tp->t_ospeed = t->c_ospeed;
    495 	tp->t_cflag = t->c_cflag;
    496 
    497 	vioconstart(tp);
    498 	return 0;
    499 }
    500 
    501 int
    502 vioconopen(dev_t dev, int flag, int mode, struct lwp *l)
    503 {
    504 	int unit = VIOCONUNIT(dev);
    505 	int port = VIOCONPORT(dev);
    506 	struct viocon_softc *sc;
    507 	struct viocon_port *vp;
    508 	struct tty *tp;
    509 	int s, error;
    510 
    511 	sc = device_lookup_private(&viocon_cd, unit);
    512 	if (sc == NULL)
    513 		return (ENXIO);
    514 	if (!device_is_active(sc->sc_dev))
    515 		return (ENXIO);
    516 
    517 	s = spltty();
    518 	if (port >= sc->sc_max_ports) {
    519 		splx(s);
    520 		return (ENXIO);
    521 	}
    522 	vp = sc->sc_ports[port];
    523 	tp = vp->vp_tty;
    524 #ifdef NOTYET
    525 	vp->vp_guest_open = 1;
    526 #endif
    527 	splx(s);
    528 
    529 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    530 		return (EBUSY);
    531 
    532 	s = spltty();
    533 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    534 		ttychars(tp);
    535 		tp->t_ispeed = 1000000;
    536 		tp->t_ospeed = 1000000;
    537 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL|CRTSCTS;
    538 		tp->t_iflag = TTYDEF_IFLAG;
    539 		tp->t_oflag = TTYDEF_OFLAG;
    540 		tp->t_lflag = TTYDEF_LFLAG;
    541 		if (vp->vp_cols != 0) {
    542 			tp->t_winsize.ws_col = vp->vp_cols;
    543 			tp->t_winsize.ws_row = vp->vp_rows;
    544 		}
    545 
    546 		vioconparam(tp, &tp->t_termios);
    547 		ttsetwater(tp);
    548 	}
    549 	splx(s);
    550 
    551 	error = (*tp->t_linesw->l_open)(dev, tp);
    552 	return error;
    553 }
    554 
    555 int
    556 vioconclose(dev_t dev, int flag, int mode, struct lwp *l)
    557 {
    558 	struct viocon_port *vp = dev2port(dev);
    559 	struct tty *tp = vp->vp_tty;
    560 	int s;
    561 
    562 	if (!ISSET(tp->t_state, TS_ISOPEN))
    563 		return 0;
    564 
    565 	(*tp->t_linesw->l_close)(tp, flag);
    566 	s = spltty();
    567 #ifdef NOTYET
    568 	vp->vp_guest_open = 0;
    569 #endif
    570 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
    571 	ttyclose(tp);
    572 	splx(s);
    573 
    574 	return 0;
    575 }
    576 
    577 int
    578 vioconread(dev_t dev, struct uio *uio, int flag)
    579 {
    580 	struct viocon_port *vp = dev2port(dev);
    581 	struct tty *tp = vp->vp_tty;
    582 
    583 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    584 }
    585 
    586 int
    587 vioconwrite(dev_t dev, struct uio *uio, int flag)
    588 {
    589 	struct viocon_port *vp = dev2port(dev);
    590 	struct tty *tp = vp->vp_tty;
    591 
    592 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    593 }
    594 
    595 struct tty *
    596 viocontty(dev_t dev)
    597 {
    598 	struct viocon_port *vp = dev2port(dev);
    599 
    600 	return vp->vp_tty;
    601 }
    602 
    603 void
    604 vioconstop(struct tty *tp, int flag)
    605 {
    606 	int s;
    607 
    608 	s = spltty();
    609 	if (ISSET(tp->t_state, TS_BUSY))
    610 		if (!ISSET(tp->t_state, TS_TTSTOP))
    611 			SET(tp->t_state, TS_FLUSH);
    612 	splx(s);
    613 }
    614 
    615 int
    616 vioconioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    617 {
    618 	struct viocon_port *vp = dev2port(dev);
    619 	struct tty *tp;
    620 	int error1, error2;
    621 
    622 	tp = vp->vp_tty;
    623 
    624 	error1 = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    625 	if (error1 >= 0)
    626 		return error1;
    627 	error2 = ttioctl(tp, cmd, data, flag, l);
    628 	if (error2 >= 0)
    629 		return error2;
    630 	return ENOTTY;
    631 }
    632