]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/virtio/console/virtio_console.c
Import tzdata 2018a
[FreeBSD/FreeBSD.git] / sys / dev / virtio / console / virtio_console.c
1 /*-
2  * Copyright (c) 2014, Bryan Venteicher <bryanv@FreeBSD.org>
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 unmodified, this list of conditions, and the following
10  *    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 /* Driver for VirtIO console devices. */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/ctype.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/kdb.h>
39 #include <sys/lock.h>
40 #include <sys/mutex.h>
41 #include <sys/sglist.h>
42 #include <sys/sysctl.h>
43 #include <sys/taskqueue.h>
44 #include <sys/queue.h>
45
46 #include <sys/conf.h>
47 #include <sys/cons.h>
48 #include <sys/tty.h>
49
50 #include <machine/bus.h>
51 #include <machine/resource.h>
52 #include <sys/bus.h>
53
54 #include <dev/virtio/virtio.h>
55 #include <dev/virtio/virtqueue.h>
56 #include <dev/virtio/console/virtio_console.h>
57
58 #include "virtio_if.h"
59
60 #define VTCON_MAX_PORTS 32
61 #define VTCON_TTY_PREFIX "V"
62 #define VTCON_TTY_ALIAS_PREFIX "vtcon"
63 #define VTCON_BULK_BUFSZ 128
64 #define VTCON_CTRL_BUFSZ 128
65
66 /*
67  * The buffers cannot cross more than one page boundary due to the
68  * size of the sglist segment array used.
69  */
70 CTASSERT(VTCON_BULK_BUFSZ <= PAGE_SIZE);
71 CTASSERT(VTCON_CTRL_BUFSZ <= PAGE_SIZE);
72
73 CTASSERT(sizeof(struct virtio_console_config) <= VTCON_CTRL_BUFSZ);
74
75 struct vtcon_softc;
76 struct vtcon_softc_port;
77
78 struct vtcon_port {
79         struct mtx                       vtcport_mtx;
80         struct vtcon_softc              *vtcport_sc;
81         struct vtcon_softc_port         *vtcport_scport;
82         struct tty                      *vtcport_tty;
83         struct virtqueue                *vtcport_invq;
84         struct virtqueue                *vtcport_outvq;
85         int                              vtcport_id;
86         int                              vtcport_flags;
87 #define VTCON_PORT_FLAG_GONE    0x01
88 #define VTCON_PORT_FLAG_CONSOLE 0x02
89 #define VTCON_PORT_FLAG_ALIAS   0x04
90
91 #if defined(KDB)
92         int                              vtcport_alt_break_state;
93 #endif
94 };
95
96 #define VTCON_PORT_LOCK(_port)          mtx_lock(&(_port)->vtcport_mtx)
97 #define VTCON_PORT_UNLOCK(_port)        mtx_unlock(&(_port)->vtcport_mtx)
98
99 struct vtcon_softc_port {
100         struct vtcon_softc      *vcsp_sc;
101         struct vtcon_port       *vcsp_port;
102         struct virtqueue        *vcsp_invq;
103         struct virtqueue        *vcsp_outvq;
104 };
105
106 struct vtcon_softc {
107         device_t                 vtcon_dev;
108         struct mtx               vtcon_mtx;
109         uint64_t                 vtcon_features;
110         uint32_t                 vtcon_max_ports;
111         uint32_t                 vtcon_flags;
112 #define VTCON_FLAG_DETACHED     0x01
113 #define VTCON_FLAG_SIZE         0x02
114 #define VTCON_FLAG_MULTIPORT    0x04
115
116         /*
117          * Ports can be added and removed during runtime, but we have
118          * to allocate all the virtqueues during attach. This array is
119          * indexed by the port ID.
120          */
121         struct vtcon_softc_port *vtcon_ports;
122
123         struct task              vtcon_ctrl_task;
124         struct virtqueue        *vtcon_ctrl_rxvq;
125         struct virtqueue        *vtcon_ctrl_txvq;
126         struct mtx               vtcon_ctrl_tx_mtx;
127 };
128
129 #define VTCON_LOCK(_sc)                 mtx_lock(&(_sc)->vtcon_mtx)
130 #define VTCON_UNLOCK(_sc)               mtx_unlock(&(_sc)->vtcon_mtx)
131 #define VTCON_LOCK_ASSERT(_sc)          \
132     mtx_assert(&(_sc)->vtcon_mtx, MA_OWNED)
133 #define VTCON_LOCK_ASSERT_NOTOWNED(_sc) \
134     mtx_assert(&(_sc)->vtcon_mtx, MA_NOTOWNED)
135
136 #define VTCON_CTRL_TX_LOCK(_sc)         mtx_lock(&(_sc)->vtcon_ctrl_tx_mtx)
137 #define VTCON_CTRL_TX_UNLOCK(_sc)       mtx_unlock(&(_sc)->vtcon_ctrl_tx_mtx)
138
139 #define VTCON_ASSERT_VALID_PORTID(_sc, _id)                     \
140     KASSERT((_id) >= 0 && (_id) < (_sc)->vtcon_max_ports,       \
141         ("%s: port ID %d out of range", __func__, _id))
142
143 #define VTCON_FEATURES  VIRTIO_CONSOLE_F_MULTIPORT
144
145 static struct virtio_feature_desc vtcon_feature_desc[] = {
146         { VIRTIO_CONSOLE_F_SIZE,        "ConsoleSize"   },
147         { VIRTIO_CONSOLE_F_MULTIPORT,   "MultiplePorts" },
148         { VIRTIO_CONSOLE_F_EMERG_WRITE, "EmergencyWrite" },
149
150         { 0, NULL }
151 };
152
153 static int       vtcon_modevent(module_t, int, void *);
154 static void      vtcon_drain_all(void);
155
156 static int       vtcon_probe(device_t);
157 static int       vtcon_attach(device_t);
158 static int       vtcon_detach(device_t);
159 static int       vtcon_config_change(device_t);
160
161 static void      vtcon_setup_features(struct vtcon_softc *);
162 static void      vtcon_negotiate_features(struct vtcon_softc *);
163 static int       vtcon_alloc_scports(struct vtcon_softc *);
164 static int       vtcon_alloc_virtqueues(struct vtcon_softc *);
165 static void      vtcon_read_config(struct vtcon_softc *,
166                      struct virtio_console_config *);
167
168 static void      vtcon_determine_max_ports(struct vtcon_softc *,
169                      struct virtio_console_config *);
170 static void      vtcon_destroy_ports(struct vtcon_softc *);
171 static void      vtcon_stop(struct vtcon_softc *);
172
173 static int       vtcon_ctrl_event_enqueue(struct vtcon_softc *,
174                      struct virtio_console_control *);
175 static int       vtcon_ctrl_event_create(struct vtcon_softc *);
176 static void      vtcon_ctrl_event_requeue(struct vtcon_softc *,
177                      struct virtio_console_control *);
178 static int       vtcon_ctrl_event_populate(struct vtcon_softc *);
179 static void      vtcon_ctrl_event_drain(struct vtcon_softc *);
180 static int       vtcon_ctrl_init(struct vtcon_softc *);
181 static void      vtcon_ctrl_deinit(struct vtcon_softc *);
182 static void      vtcon_ctrl_port_add_event(struct vtcon_softc *, int);
183 static void      vtcon_ctrl_port_remove_event(struct vtcon_softc *, int);
184 static void      vtcon_ctrl_port_console_event(struct vtcon_softc *, int);
185 static void      vtcon_ctrl_port_open_event(struct vtcon_softc *, int);
186 static void      vtcon_ctrl_port_name_event(struct vtcon_softc *, int,
187                      const char *, size_t);
188 static void      vtcon_ctrl_process_event(struct vtcon_softc *,
189                      struct virtio_console_control *, void *, size_t);
190 static void      vtcon_ctrl_task_cb(void *, int);
191 static void      vtcon_ctrl_event_intr(void *);
192 static void      vtcon_ctrl_poll(struct vtcon_softc *,
193                      struct virtio_console_control *control);
194 static void      vtcon_ctrl_send_control(struct vtcon_softc *, uint32_t,
195                      uint16_t, uint16_t);
196
197 static int       vtcon_port_enqueue_buf(struct vtcon_port *, void *, size_t);
198 static int       vtcon_port_create_buf(struct vtcon_port *);
199 static void      vtcon_port_requeue_buf(struct vtcon_port *, void *);
200 static int       vtcon_port_populate(struct vtcon_port *);
201 static void      vtcon_port_destroy(struct vtcon_port *);
202 static int       vtcon_port_create(struct vtcon_softc *, int);
203 static void      vtcon_port_dev_alias(struct vtcon_port *, const char *,
204                      size_t);
205 static void      vtcon_port_drain_bufs(struct virtqueue *);
206 static void      vtcon_port_drain(struct vtcon_port *);
207 static void      vtcon_port_teardown(struct vtcon_port *);
208 static void      vtcon_port_change_size(struct vtcon_port *, uint16_t,
209                      uint16_t);
210 static void      vtcon_port_update_console_size(struct vtcon_softc *);
211 static void      vtcon_port_enable_intr(struct vtcon_port *);
212 static void      vtcon_port_disable_intr(struct vtcon_port *);
213 static void      vtcon_port_in(struct vtcon_port *);
214 static void      vtcon_port_intr(void *);
215 static void      vtcon_port_out(struct vtcon_port *, void *, int);
216 static void      vtcon_port_submit_event(struct vtcon_port *, uint16_t,
217                      uint16_t);
218
219 static int       vtcon_tty_open(struct tty *);
220 static void      vtcon_tty_close(struct tty *);
221 static void      vtcon_tty_outwakeup(struct tty *);
222 static void      vtcon_tty_free(void *);
223
224 static void      vtcon_get_console_size(struct vtcon_softc *, uint16_t *,
225                      uint16_t *);
226
227 static void      vtcon_enable_interrupts(struct vtcon_softc *);
228 static void      vtcon_disable_interrupts(struct vtcon_softc *);
229
230 static int       vtcon_pending_free;
231
232 static struct ttydevsw vtcon_tty_class = {
233         .tsw_flags      = 0,
234         .tsw_open       = vtcon_tty_open,
235         .tsw_close      = vtcon_tty_close,
236         .tsw_outwakeup  = vtcon_tty_outwakeup,
237         .tsw_free       = vtcon_tty_free,
238 };
239
240 static device_method_t vtcon_methods[] = {
241         /* Device methods. */
242         DEVMETHOD(device_probe,         vtcon_probe),
243         DEVMETHOD(device_attach,        vtcon_attach),
244         DEVMETHOD(device_detach,        vtcon_detach),
245
246         /* VirtIO methods. */
247         DEVMETHOD(virtio_config_change, vtcon_config_change),
248
249         DEVMETHOD_END
250 };
251
252 static driver_t vtcon_driver = {
253         "vtcon",
254         vtcon_methods,
255         sizeof(struct vtcon_softc)
256 };
257 static devclass_t vtcon_devclass;
258
259 DRIVER_MODULE(virtio_console, virtio_pci, vtcon_driver, vtcon_devclass,
260     vtcon_modevent, 0);
261 MODULE_VERSION(virtio_console, 1);
262 MODULE_DEPEND(virtio_console, virtio, 1, 1, 1);
263
264 static int
265 vtcon_modevent(module_t mod, int type, void *unused)
266 {
267         int error;
268
269         switch (type) {
270         case MOD_LOAD:
271                 error = 0;
272                 break;
273         case MOD_QUIESCE:
274                 error = 0;
275                 break;
276         case MOD_UNLOAD:
277                 vtcon_drain_all();
278                 error = 0;
279                 break;
280         case MOD_SHUTDOWN:
281                 error = 0;
282                 break;
283         default:
284                 error = EOPNOTSUPP;
285                 break;
286         }
287
288         return (error);
289 }
290
291 static void
292 vtcon_drain_all(void)
293 {
294         int first;
295
296         for (first = 1; vtcon_pending_free != 0; first = 0) {
297                 if (first != 0) {
298                         printf("virtio_console: Waiting for all detached TTY "
299                             "devices to have open fds closed.\n");
300                 }
301                 pause("vtcondra", hz);
302         }
303 }
304
305 static int
306 vtcon_probe(device_t dev)
307 {
308
309         if (virtio_get_device_type(dev) != VIRTIO_ID_CONSOLE)
310                 return (ENXIO);
311
312         device_set_desc(dev, "VirtIO Console Adapter");
313
314         return (BUS_PROBE_DEFAULT);
315 }
316
317 static int
318 vtcon_attach(device_t dev)
319 {
320         struct vtcon_softc *sc;
321         struct virtio_console_config concfg;
322         int error;
323
324         sc = device_get_softc(dev);
325         sc->vtcon_dev = dev;
326
327         mtx_init(&sc->vtcon_mtx, "vtconmtx", NULL, MTX_DEF);
328         mtx_init(&sc->vtcon_ctrl_tx_mtx, "vtconctrlmtx", NULL, MTX_DEF);
329
330         virtio_set_feature_desc(dev, vtcon_feature_desc);
331         vtcon_setup_features(sc);
332
333         vtcon_read_config(sc, &concfg);
334         vtcon_determine_max_ports(sc, &concfg);
335
336         error = vtcon_alloc_scports(sc);
337         if (error) {
338                 device_printf(dev, "cannot allocate softc port structures\n");
339                 goto fail;
340         }
341
342         error = vtcon_alloc_virtqueues(sc);
343         if (error) {
344                 device_printf(dev, "cannot allocate virtqueues\n");
345                 goto fail;
346         }
347
348         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
349                 TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc);
350                 error = vtcon_ctrl_init(sc);
351                 if (error)
352                         goto fail;
353         } else {
354                 error = vtcon_port_create(sc, 0);
355                 if (error)
356                         goto fail;
357                 if (sc->vtcon_flags & VTCON_FLAG_SIZE)
358                         vtcon_port_update_console_size(sc);
359         }
360
361         error = virtio_setup_intr(dev, INTR_TYPE_TTY);
362         if (error) {
363                 device_printf(dev, "cannot setup virtqueue interrupts\n");
364                 goto fail;
365         }
366
367         vtcon_enable_interrupts(sc);
368
369         vtcon_ctrl_send_control(sc, VIRTIO_CONSOLE_BAD_ID,
370             VIRTIO_CONSOLE_DEVICE_READY, 1);
371
372 fail:
373         if (error)
374                 vtcon_detach(dev);
375
376         return (error);
377 }
378
379 static int
380 vtcon_detach(device_t dev)
381 {
382         struct vtcon_softc *sc;
383
384         sc = device_get_softc(dev);
385
386         VTCON_LOCK(sc);
387         sc->vtcon_flags |= VTCON_FLAG_DETACHED;
388         if (device_is_attached(dev))
389                 vtcon_stop(sc);
390         VTCON_UNLOCK(sc);
391
392         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
393                 taskqueue_drain(taskqueue_thread, &sc->vtcon_ctrl_task);
394                 vtcon_ctrl_deinit(sc);
395         }
396
397         vtcon_destroy_ports(sc);
398         mtx_destroy(&sc->vtcon_mtx);
399         mtx_destroy(&sc->vtcon_ctrl_tx_mtx);
400
401         return (0);
402 }
403
404 static int
405 vtcon_config_change(device_t dev)
406 {
407         struct vtcon_softc *sc;
408
409         sc = device_get_softc(dev);
410
411         /*
412          * When the multiport feature is negotiated, all configuration
413          * changes are done through control virtqueue events.
414          */
415         if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0) {
416                 if (sc->vtcon_flags & VTCON_FLAG_SIZE)
417                         vtcon_port_update_console_size(sc);
418         }
419
420         return (0);
421 }
422
423 static void
424 vtcon_negotiate_features(struct vtcon_softc *sc)
425 {
426         device_t dev;
427         uint64_t features;
428
429         dev = sc->vtcon_dev;
430         features = VTCON_FEATURES;
431
432         sc->vtcon_features = virtio_negotiate_features(dev, features);
433 }
434
435 static void
436 vtcon_setup_features(struct vtcon_softc *sc)
437 {
438         device_t dev;
439
440         dev = sc->vtcon_dev;
441
442         vtcon_negotiate_features(sc);
443
444         if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_SIZE))
445                 sc->vtcon_flags |= VTCON_FLAG_SIZE;
446         if (virtio_with_feature(dev, VIRTIO_CONSOLE_F_MULTIPORT))
447                 sc->vtcon_flags |= VTCON_FLAG_MULTIPORT;
448 }
449
450 #define VTCON_GET_CONFIG(_dev, _feature, _field, _cfg)                  \
451         if (virtio_with_feature(_dev, _feature)) {                      \
452                 virtio_read_device_config(_dev,                         \
453                     offsetof(struct virtio_console_config, _field),     \
454                     &(_cfg)->_field, sizeof((_cfg)->_field));           \
455         }
456
457 static void
458 vtcon_read_config(struct vtcon_softc *sc, struct virtio_console_config *concfg)
459 {
460         device_t dev;
461
462         dev = sc->vtcon_dev;
463
464         bzero(concfg, sizeof(struct virtio_console_config));
465
466         VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, cols, concfg);
467         VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_SIZE, rows, concfg);
468         VTCON_GET_CONFIG(dev, VIRTIO_CONSOLE_F_MULTIPORT, max_nr_ports, concfg);
469 }
470
471 #undef VTCON_GET_CONFIG
472
473 static int
474 vtcon_alloc_scports(struct vtcon_softc *sc)
475 {
476         struct vtcon_softc_port *scport;
477         u_int max, i;
478
479         max = sc->vtcon_max_ports;
480
481         sc->vtcon_ports = mallocarray(max, sizeof(struct vtcon_softc_port),
482             M_DEVBUF, M_NOWAIT | M_ZERO);
483         if (sc->vtcon_ports == NULL)
484                 return (ENOMEM);
485
486         for (i = 0; i < max; i++) {
487                 scport = &sc->vtcon_ports[i];
488                 scport->vcsp_sc = sc;
489         }
490
491         return (0);
492 }
493
494 static int
495 vtcon_alloc_virtqueues(struct vtcon_softc *sc)
496 {
497         device_t dev;
498         struct vq_alloc_info *info;
499         struct vtcon_softc_port *scport;
500         u_int i, idx, portidx, nvqs;
501         int error;
502
503         dev = sc->vtcon_dev;
504
505         nvqs = sc->vtcon_max_ports * 2;
506         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
507                 nvqs += 2;
508
509         info = mallocarray(nvqs, sizeof(struct vq_alloc_info), M_TEMP,
510             M_NOWAIT);
511         if (info == NULL)
512                 return (ENOMEM);
513
514         for (i = 0, idx = 0, portidx = 0; i < nvqs / 2; i++, idx += 2) {
515
516                 if (i == 1) {
517                         /* The control virtqueues are after the first port. */
518                         VQ_ALLOC_INFO_INIT(&info[idx], 0,
519                             vtcon_ctrl_event_intr, sc, &sc->vtcon_ctrl_rxvq,
520                             "%s-control rx", device_get_nameunit(dev));
521                         VQ_ALLOC_INFO_INIT(&info[idx+1], 0,
522                             NULL, sc, &sc->vtcon_ctrl_txvq,
523                             "%s-control tx", device_get_nameunit(dev));
524                         continue;
525                 }
526
527                 scport = &sc->vtcon_ports[portidx];
528
529                 VQ_ALLOC_INFO_INIT(&info[idx], 0, vtcon_port_intr,
530                     scport, &scport->vcsp_invq, "%s-port%d in",
531                     device_get_nameunit(dev), i);
532                 VQ_ALLOC_INFO_INIT(&info[idx+1], 0, NULL,
533                     NULL, &scport->vcsp_outvq, "%s-port%d out",
534                     device_get_nameunit(dev), i);
535
536                 portidx++;
537         }
538
539         error = virtio_alloc_virtqueues(dev, 0, nvqs, info);
540         free(info, M_TEMP);
541
542         return (error);
543 }
544
545 static void
546 vtcon_determine_max_ports(struct vtcon_softc *sc,
547     struct virtio_console_config *concfg)
548 {
549
550         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
551                 sc->vtcon_max_ports =
552                     min(concfg->max_nr_ports, VTCON_MAX_PORTS);
553                 if (sc->vtcon_max_ports == 0)
554                         sc->vtcon_max_ports = 1;
555         } else
556                 sc->vtcon_max_ports = 1;
557 }
558
559 static void
560 vtcon_destroy_ports(struct vtcon_softc *sc)
561 {
562         struct vtcon_softc_port *scport;
563         struct vtcon_port *port;
564         struct virtqueue *vq;
565         int i;
566
567         if (sc->vtcon_ports == NULL)
568                 return;
569
570         VTCON_LOCK(sc);
571         for (i = 0; i < sc->vtcon_max_ports; i++) {
572                 scport = &sc->vtcon_ports[i];
573
574                 port = scport->vcsp_port;
575                 if (port != NULL) {
576                         scport->vcsp_port = NULL;
577                         VTCON_PORT_LOCK(port);
578                         VTCON_UNLOCK(sc);
579                         vtcon_port_teardown(port);
580                         VTCON_LOCK(sc);
581                 }
582
583                 vq = scport->vcsp_invq;
584                 if (vq != NULL)
585                         vtcon_port_drain_bufs(vq);
586         }
587         VTCON_UNLOCK(sc);
588
589         free(sc->vtcon_ports, M_DEVBUF);
590         sc->vtcon_ports = NULL;
591 }
592
593 static void
594 vtcon_stop(struct vtcon_softc *sc)
595 {
596
597         vtcon_disable_interrupts(sc);
598         virtio_stop(sc->vtcon_dev);
599 }
600
601 static int
602 vtcon_ctrl_event_enqueue(struct vtcon_softc *sc,
603     struct virtio_console_control *control)
604 {
605         struct sglist_seg segs[2];
606         struct sglist sg;
607         struct virtqueue *vq;
608         int error;
609
610         vq = sc->vtcon_ctrl_rxvq;
611
612         sglist_init(&sg, 2, segs);
613         error = sglist_append(&sg, control, VTCON_CTRL_BUFSZ);
614         KASSERT(error == 0, ("%s: error %d adding control to sglist",
615             __func__, error));
616
617         return (virtqueue_enqueue(vq, control, &sg, 0, sg.sg_nseg));
618 }
619
620 static int
621 vtcon_ctrl_event_create(struct vtcon_softc *sc)
622 {
623         struct virtio_console_control *control;
624         int error;
625
626         control = malloc(VTCON_CTRL_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT);
627         if (control == NULL)
628                 return (ENOMEM);
629
630         error = vtcon_ctrl_event_enqueue(sc, control);
631         if (error)
632                 free(control, M_DEVBUF);
633
634         return (error);
635 }
636
637 static void
638 vtcon_ctrl_event_requeue(struct vtcon_softc *sc,
639     struct virtio_console_control *control)
640 {
641         int error;
642
643         bzero(control, VTCON_CTRL_BUFSZ);
644
645         error = vtcon_ctrl_event_enqueue(sc, control);
646         KASSERT(error == 0,
647             ("%s: cannot requeue control buffer %d", __func__, error));
648 }
649
650 static int
651 vtcon_ctrl_event_populate(struct vtcon_softc *sc)
652 {
653         struct virtqueue *vq;
654         int nbufs, error;
655
656         vq = sc->vtcon_ctrl_rxvq;
657         error = ENOSPC;
658
659         for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
660                 error = vtcon_ctrl_event_create(sc);
661                 if (error)
662                         break;
663         }
664
665         if (nbufs > 0) {
666                 virtqueue_notify(vq);
667                 error = 0;
668         }
669
670         return (error);
671 }
672
673 static void
674 vtcon_ctrl_event_drain(struct vtcon_softc *sc)
675 {
676         struct virtio_console_control *control;
677         struct virtqueue *vq;
678         int last;
679
680         vq = sc->vtcon_ctrl_rxvq;
681         last = 0;
682
683         if (vq == NULL)
684                 return;
685
686         VTCON_LOCK(sc);
687         while ((control = virtqueue_drain(vq, &last)) != NULL)
688                 free(control, M_DEVBUF);
689         VTCON_UNLOCK(sc);
690 }
691
692 static int
693 vtcon_ctrl_init(struct vtcon_softc *sc)
694 {
695         int error;
696
697         error = vtcon_ctrl_event_populate(sc);
698
699         return (error);
700 }
701
702 static void
703 vtcon_ctrl_deinit(struct vtcon_softc *sc)
704 {
705
706         vtcon_ctrl_event_drain(sc);
707 }
708
709 static void
710 vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id)
711 {
712         device_t dev;
713         int error;
714
715         dev = sc->vtcon_dev;
716
717         /* This single thread only way for ports to be created. */
718         if (sc->vtcon_ports[id].vcsp_port != NULL) {
719                 device_printf(dev, "%s: adding port %d, but already exists\n",
720                     __func__, id);
721                 return;
722         }
723
724         error = vtcon_port_create(sc, id);
725         if (error) {
726                 device_printf(dev, "%s: cannot create port %d: %d\n",
727                     __func__, id, error);
728                 vtcon_ctrl_send_control(sc, id, VIRTIO_CONSOLE_PORT_READY, 0);
729                 return;
730         }
731 }
732
733 static void
734 vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id)
735 {
736         device_t dev;
737         struct vtcon_softc_port *scport;
738         struct vtcon_port *port;
739
740         dev = sc->vtcon_dev;
741         scport = &sc->vtcon_ports[id];
742
743         VTCON_LOCK(sc);
744         port = scport->vcsp_port;
745         if (port == NULL) {
746                 VTCON_UNLOCK(sc);
747                 device_printf(dev, "%s: remove port %d, but does not exist\n",
748                     __func__, id);
749                 return;
750         }
751
752         scport->vcsp_port = NULL;
753         VTCON_PORT_LOCK(port);
754         VTCON_UNLOCK(sc);
755         vtcon_port_teardown(port);
756 }
757
758 static void
759 vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id)
760 {
761         device_t dev;
762         struct vtcon_softc_port *scport;
763         struct vtcon_port *port;
764
765         dev = sc->vtcon_dev;
766         scport = &sc->vtcon_ports[id];
767
768         VTCON_LOCK(sc);
769         port = scport->vcsp_port;
770         if (port == NULL) {
771                 VTCON_UNLOCK(sc);
772                 device_printf(dev, "%s: console port %d, but does not exist\n",
773                     __func__, id);
774                 return;
775         }
776
777         VTCON_PORT_LOCK(port);
778         VTCON_UNLOCK(sc);
779         port->vtcport_flags |= VTCON_PORT_FLAG_CONSOLE;
780         vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
781         VTCON_PORT_UNLOCK(port);
782 }
783
784 static void
785 vtcon_ctrl_port_open_event(struct vtcon_softc *sc, int id)
786 {
787         device_t dev;
788         struct vtcon_softc_port *scport;
789         struct vtcon_port *port;
790
791         dev = sc->vtcon_dev;
792         scport = &sc->vtcon_ports[id];
793
794         VTCON_LOCK(sc);
795         port = scport->vcsp_port;
796         if (port == NULL) {
797                 VTCON_UNLOCK(sc);
798                 device_printf(dev, "%s: open port %d, but does not exist\n",
799                     __func__, id);
800                 return;
801         }
802
803         VTCON_PORT_LOCK(port);
804         VTCON_UNLOCK(sc);
805         vtcon_port_enable_intr(port);
806         VTCON_PORT_UNLOCK(port);
807 }
808
809 static void
810 vtcon_ctrl_port_name_event(struct vtcon_softc *sc, int id, const char *name,
811     size_t len)
812 {
813         device_t dev;
814         struct vtcon_softc_port *scport;
815         struct vtcon_port *port;
816
817         dev = sc->vtcon_dev;
818         scport = &sc->vtcon_ports[id];
819
820         /*
821          * The VirtIO specification says the NUL terminator is not included in
822          * the length, but QEMU includes it. Adjust the length if needed.
823          */
824         if (name == NULL || len == 0)
825                 return;
826         if (name[len - 1] == '\0') {
827                 len--;
828                 if (len == 0)
829                         return;
830         }
831
832         VTCON_LOCK(sc);
833         port = scport->vcsp_port;
834         if (port == NULL) {
835                 VTCON_UNLOCK(sc);
836                 device_printf(dev, "%s: name port %d, but does not exist\n",
837                     __func__, id);
838                 return;
839         }
840
841         VTCON_PORT_LOCK(port);
842         VTCON_UNLOCK(sc);
843         vtcon_port_dev_alias(port, name, len);
844         VTCON_PORT_UNLOCK(port);
845 }
846
847 static void
848 vtcon_ctrl_process_event(struct vtcon_softc *sc,
849     struct virtio_console_control *control, void *data, size_t data_len)
850 {
851         device_t dev;
852         int id;
853
854         dev = sc->vtcon_dev;
855         id = control->id;
856
857         if (id < 0 || id >= sc->vtcon_max_ports) {
858                 device_printf(dev, "%s: invalid port ID %d\n", __func__, id);
859                 return;
860         }
861
862         switch (control->event) {
863         case VIRTIO_CONSOLE_PORT_ADD:
864                 vtcon_ctrl_port_add_event(sc, id);
865                 break;
866
867         case VIRTIO_CONSOLE_PORT_REMOVE:
868                 vtcon_ctrl_port_remove_event(sc, id);
869                 break;
870
871         case VIRTIO_CONSOLE_CONSOLE_PORT:
872                 vtcon_ctrl_port_console_event(sc, id);
873                 break;
874
875         case VIRTIO_CONSOLE_RESIZE:
876                 break;
877
878         case VIRTIO_CONSOLE_PORT_OPEN:
879                 vtcon_ctrl_port_open_event(sc, id);
880                 break;
881
882         case VIRTIO_CONSOLE_PORT_NAME:
883                 vtcon_ctrl_port_name_event(sc, id, (const char *)data, data_len);
884                 break;
885         }
886 }
887
888 static void
889 vtcon_ctrl_task_cb(void *xsc, int pending)
890 {
891         struct vtcon_softc *sc;
892         struct virtqueue *vq;
893         struct virtio_console_control *control;
894         void *data;
895         size_t data_len;
896         int detached;
897         uint32_t len;
898
899         sc = xsc;
900         vq = sc->vtcon_ctrl_rxvq;
901
902         VTCON_LOCK(sc);
903
904         while ((detached = (sc->vtcon_flags & VTCON_FLAG_DETACHED)) == 0) {
905                 control = virtqueue_dequeue(vq, &len);
906                 if (control == NULL)
907                         break;
908
909                 if (len > sizeof(struct virtio_console_control)) {
910                         data = (void *) &control[1];
911                         data_len = len - sizeof(struct virtio_console_control);
912                 } else {
913                         data = NULL;
914                         data_len = 0;
915                 }
916
917                 VTCON_UNLOCK(sc);
918                 vtcon_ctrl_process_event(sc, control, data, data_len);
919                 VTCON_LOCK(sc);
920                 vtcon_ctrl_event_requeue(sc, control);
921         }
922
923         if (!detached) {
924                 virtqueue_notify(vq);
925                 if (virtqueue_enable_intr(vq) != 0)
926                         taskqueue_enqueue(taskqueue_thread,
927                             &sc->vtcon_ctrl_task);
928         }
929
930         VTCON_UNLOCK(sc);
931 }
932
933 static void
934 vtcon_ctrl_event_intr(void *xsc)
935 {
936         struct vtcon_softc *sc;
937
938         sc = xsc;
939
940         /*
941          * Only some events require us to potentially block, but it
942          * easier to just defer all event handling to the taskqueue.
943          */
944         taskqueue_enqueue(taskqueue_thread, &sc->vtcon_ctrl_task);
945 }
946
947 static void
948 vtcon_ctrl_poll(struct vtcon_softc *sc,
949     struct virtio_console_control *control)
950 {
951         struct sglist_seg segs[2];
952         struct sglist sg;
953         struct virtqueue *vq;
954         int error;
955
956         vq = sc->vtcon_ctrl_txvq;
957
958         sglist_init(&sg, 2, segs);
959         error = sglist_append(&sg, control,
960             sizeof(struct virtio_console_control));
961         KASSERT(error == 0, ("%s: error %d adding control to sglist",
962             __func__, error));
963
964         /*
965          * We cannot use the softc lock to serialize access to this
966          * virtqueue since this is called from the tty layer with the
967          * port lock held. Acquiring the softc would violate our lock
968          * ordering.
969          */
970         VTCON_CTRL_TX_LOCK(sc);
971         KASSERT(virtqueue_empty(vq),
972             ("%s: virtqueue is not emtpy", __func__));
973         error = virtqueue_enqueue(vq, control, &sg, sg.sg_nseg, 0);
974         if (error == 0) {
975                 virtqueue_notify(vq);
976                 virtqueue_poll(vq, NULL);
977         }
978         VTCON_CTRL_TX_UNLOCK(sc);
979 }
980
981 static void
982 vtcon_ctrl_send_control(struct vtcon_softc *sc, uint32_t portid,
983     uint16_t event, uint16_t value)
984 {
985         struct virtio_console_control control;
986
987         if ((sc->vtcon_flags & VTCON_FLAG_MULTIPORT) == 0)
988                 return;
989
990         control.id = portid;
991         control.event = event;
992         control.value = value;
993
994         vtcon_ctrl_poll(sc, &control);
995 }
996
997 static int
998 vtcon_port_enqueue_buf(struct vtcon_port *port, void *buf, size_t len)
999 {
1000         struct sglist_seg segs[2];
1001         struct sglist sg;
1002         struct virtqueue *vq;
1003         int error;
1004
1005         vq = port->vtcport_invq;
1006
1007         sglist_init(&sg, 2, segs);
1008         error = sglist_append(&sg, buf, len);
1009         KASSERT(error == 0,
1010             ("%s: error %d adding buffer to sglist", __func__, error));
1011
1012         error = virtqueue_enqueue(vq, buf, &sg, 0, sg.sg_nseg);
1013
1014         return (error);
1015 }
1016
1017 static int
1018 vtcon_port_create_buf(struct vtcon_port *port)
1019 {
1020         void *buf;
1021         int error;
1022
1023         buf = malloc(VTCON_BULK_BUFSZ, M_DEVBUF, M_ZERO | M_NOWAIT);
1024         if (buf == NULL)
1025                 return (ENOMEM);
1026
1027         error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ);
1028         if (error)
1029                 free(buf, M_DEVBUF);
1030
1031         return (error);
1032 }
1033
1034 static void
1035 vtcon_port_requeue_buf(struct vtcon_port *port, void *buf)
1036 {
1037         int error;
1038
1039         error = vtcon_port_enqueue_buf(port, buf, VTCON_BULK_BUFSZ);
1040         KASSERT(error == 0,
1041             ("%s: cannot requeue input buffer %d", __func__, error));
1042 }
1043
1044 static int
1045 vtcon_port_populate(struct vtcon_port *port)
1046 {
1047         struct virtqueue *vq;
1048         int nbufs, error;
1049
1050         vq = port->vtcport_invq;
1051         error = ENOSPC;
1052
1053         for (nbufs = 0; !virtqueue_full(vq); nbufs++) {
1054                 error = vtcon_port_create_buf(port);
1055                 if (error)
1056                         break;
1057         }
1058
1059         if (nbufs > 0) {
1060                 virtqueue_notify(vq);
1061                 error = 0;
1062         }
1063
1064         return (error);
1065 }
1066
1067 static void
1068 vtcon_port_destroy(struct vtcon_port *port)
1069 {
1070
1071         port->vtcport_sc = NULL;
1072         port->vtcport_scport = NULL;
1073         port->vtcport_invq = NULL;
1074         port->vtcport_outvq = NULL;
1075         port->vtcport_id = -1;
1076         mtx_destroy(&port->vtcport_mtx);
1077         free(port, M_DEVBUF);
1078 }
1079
1080 static int
1081 vtcon_port_init_vqs(struct vtcon_port *port)
1082 {
1083         struct vtcon_softc_port *scport;
1084         int error;
1085
1086         scport = port->vtcport_scport;
1087
1088         port->vtcport_invq = scport->vcsp_invq;
1089         port->vtcport_outvq = scport->vcsp_outvq;
1090
1091         /*
1092          * Free any data left over from when this virtqueue was in use by a
1093          * prior port. We have not yet notified the host that the port is
1094          * ready, so assume nothing in the virtqueue can be for us.
1095          */
1096         vtcon_port_drain(port);
1097
1098         KASSERT(virtqueue_empty(port->vtcport_invq),
1099             ("%s: in virtqueue is not empty", __func__));
1100         KASSERT(virtqueue_empty(port->vtcport_outvq),
1101             ("%s: out virtqueue is not empty", __func__));
1102
1103         error = vtcon_port_populate(port);
1104         if (error)
1105                 return (error);
1106
1107         return (0);
1108 }
1109
1110 static int
1111 vtcon_port_create(struct vtcon_softc *sc, int id)
1112 {
1113         device_t dev;
1114         struct vtcon_softc_port *scport;
1115         struct vtcon_port *port;
1116         int error;
1117
1118         dev = sc->vtcon_dev;
1119         scport = &sc->vtcon_ports[id];
1120
1121         VTCON_ASSERT_VALID_PORTID(sc, id);
1122         MPASS(scport->vcsp_port == NULL);
1123
1124         port = malloc(sizeof(struct vtcon_port), M_DEVBUF, M_NOWAIT | M_ZERO);
1125         if (port == NULL)
1126                 return (ENOMEM);
1127
1128         port->vtcport_sc = sc;
1129         port->vtcport_scport = scport;
1130         port->vtcport_id = id;
1131         mtx_init(&port->vtcport_mtx, "vtcpmtx", NULL, MTX_DEF);
1132         port->vtcport_tty = tty_alloc_mutex(&vtcon_tty_class, port,
1133             &port->vtcport_mtx);
1134
1135         error = vtcon_port_init_vqs(port);
1136         if (error) {
1137                 VTCON_PORT_LOCK(port);
1138                 vtcon_port_teardown(port);
1139                 return (error);
1140         }
1141
1142         VTCON_LOCK(sc);
1143         VTCON_PORT_LOCK(port);
1144         scport->vcsp_port = port;
1145         vtcon_port_enable_intr(port);
1146         vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_READY, 1);
1147         VTCON_PORT_UNLOCK(port);
1148         VTCON_UNLOCK(sc);
1149
1150         tty_makedev(port->vtcport_tty, NULL, "%s%r.%r", VTCON_TTY_PREFIX,
1151             device_get_unit(dev), id);
1152
1153         return (0);
1154 }
1155
1156 static void
1157 vtcon_port_dev_alias(struct vtcon_port *port, const char *name, size_t len)
1158 {
1159         struct vtcon_softc *sc;
1160         struct cdev *pdev;
1161         struct tty *tp;
1162         int i, error;
1163
1164         sc = port->vtcport_sc;
1165         tp = port->vtcport_tty;
1166
1167         if (port->vtcport_flags & VTCON_PORT_FLAG_ALIAS)
1168                 return;
1169
1170         /* Port name is UTF-8, but we can only handle ASCII. */
1171         for (i = 0; i < len; i++) {
1172                 if (!isascii(name[i]))
1173                         return;
1174         }
1175
1176         /*
1177          * Port name may not conform to the devfs requirements so we cannot use
1178          * tty_makealias() because the MAKEDEV_CHECKNAME flag must be specified.
1179          */
1180         error = make_dev_alias_p(MAKEDEV_NOWAIT | MAKEDEV_CHECKNAME, &pdev,
1181             tp->t_dev, "%s/%*s", VTCON_TTY_ALIAS_PREFIX, (int)len, name);
1182         if (error) {
1183                 device_printf(sc->vtcon_dev,
1184                     "%s: cannot make dev alias (%s/%*s) error %d\n", __func__,
1185                     VTCON_TTY_ALIAS_PREFIX, (int)len, name, error);
1186         } else
1187                 port->vtcport_flags |= VTCON_PORT_FLAG_ALIAS;
1188 }
1189
1190 static void
1191 vtcon_port_drain_bufs(struct virtqueue *vq)
1192 {
1193         void *buf;
1194         int last;
1195
1196         last = 0;
1197
1198         while ((buf = virtqueue_drain(vq, &last)) != NULL)
1199                 free(buf, M_DEVBUF);
1200 }
1201
1202 static void
1203 vtcon_port_drain(struct vtcon_port *port)
1204 {
1205
1206         vtcon_port_drain_bufs(port->vtcport_invq);
1207 }
1208
1209 static void
1210 vtcon_port_teardown(struct vtcon_port *port)
1211 {
1212         struct tty *tp;
1213
1214         tp = port->vtcport_tty;
1215
1216         port->vtcport_flags |= VTCON_PORT_FLAG_GONE;
1217
1218         if (tp != NULL) {
1219                 atomic_add_int(&vtcon_pending_free, 1);
1220                 tty_rel_gone(tp);
1221         } else
1222                 vtcon_port_destroy(port);
1223 }
1224
1225 static void
1226 vtcon_port_change_size(struct vtcon_port *port, uint16_t cols, uint16_t rows)
1227 {
1228         struct tty *tp;
1229         struct winsize sz;
1230
1231         tp = port->vtcport_tty;
1232
1233         if (tp == NULL)
1234                 return;
1235
1236         bzero(&sz, sizeof(struct winsize));
1237         sz.ws_col = cols;
1238         sz.ws_row = rows;
1239
1240         tty_set_winsize(tp, &sz);
1241 }
1242
1243 static void
1244 vtcon_port_update_console_size(struct vtcon_softc *sc)
1245 {
1246         struct vtcon_port *port;
1247         struct vtcon_softc_port *scport;
1248         uint16_t cols, rows;
1249
1250         vtcon_get_console_size(sc, &cols, &rows);
1251
1252         /*
1253          * For now, assume the first (only) port is the console. Note
1254          * QEMU does not implement this feature yet.
1255          */
1256         scport = &sc->vtcon_ports[0];
1257
1258         VTCON_LOCK(sc);
1259         port = scport->vcsp_port;
1260
1261         if (port != NULL) {
1262                 VTCON_PORT_LOCK(port);
1263                 VTCON_UNLOCK(sc);
1264                 vtcon_port_change_size(port, cols, rows);
1265                 VTCON_PORT_UNLOCK(port);
1266         } else
1267                 VTCON_UNLOCK(sc);
1268 }
1269
1270 static void
1271 vtcon_port_enable_intr(struct vtcon_port *port)
1272 {
1273
1274         /*
1275          * NOTE: The out virtqueue is always polled, so its interrupt
1276          * kept disabled.
1277          */
1278         virtqueue_enable_intr(port->vtcport_invq);
1279 }
1280
1281 static void
1282 vtcon_port_disable_intr(struct vtcon_port *port)
1283 {
1284
1285         if (port->vtcport_invq != NULL)
1286                 virtqueue_disable_intr(port->vtcport_invq);
1287         if (port->vtcport_outvq != NULL)
1288                 virtqueue_disable_intr(port->vtcport_outvq);
1289 }
1290
1291 static void
1292 vtcon_port_in(struct vtcon_port *port)
1293 {
1294         struct virtqueue *vq;
1295         struct tty *tp;
1296         char *buf;
1297         uint32_t len;
1298         int i, deq;
1299
1300         tp = port->vtcport_tty;
1301         vq = port->vtcport_invq;
1302
1303 again:
1304         deq = 0;
1305
1306         while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
1307                 for (i = 0; i < len; i++) {
1308 #if defined(KDB)
1309                         if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE)
1310                                 kdb_alt_break(buf[i],
1311                                     &port->vtcport_alt_break_state);
1312 #endif
1313                         ttydisc_rint(tp, buf[i], 0);
1314                 }
1315                 vtcon_port_requeue_buf(port, buf);
1316                 deq++;
1317         }
1318         ttydisc_rint_done(tp);
1319
1320         if (deq > 0)
1321                 virtqueue_notify(vq);
1322
1323         if (virtqueue_enable_intr(vq) != 0)
1324                 goto again;
1325 }
1326
1327 static void
1328 vtcon_port_intr(void *scportx)
1329 {
1330         struct vtcon_softc_port *scport;
1331         struct vtcon_softc *sc;
1332         struct vtcon_port *port;
1333
1334         scport = scportx;
1335         sc = scport->vcsp_sc;
1336
1337         VTCON_LOCK(sc);
1338         port = scport->vcsp_port;
1339         if (port == NULL) {
1340                 VTCON_UNLOCK(sc);
1341                 return;
1342         }
1343         VTCON_PORT_LOCK(port);
1344         VTCON_UNLOCK(sc);
1345         if ((port->vtcport_flags & VTCON_PORT_FLAG_GONE) == 0)
1346                 vtcon_port_in(port);
1347         VTCON_PORT_UNLOCK(port);
1348 }
1349
1350 static void
1351 vtcon_port_out(struct vtcon_port *port, void *buf, int bufsize)
1352 {
1353         struct sglist_seg segs[2];
1354         struct sglist sg;
1355         struct virtqueue *vq;
1356         int error;
1357
1358         vq = port->vtcport_outvq;
1359         KASSERT(virtqueue_empty(vq),
1360             ("%s: port %p out virtqueue not emtpy", __func__, port));
1361
1362         sglist_init(&sg, 2, segs);
1363         error = sglist_append(&sg, buf, bufsize);
1364         KASSERT(error == 0, ("%s: error %d adding buffer to sglist",
1365             __func__, error));
1366
1367         error = virtqueue_enqueue(vq, buf, &sg, sg.sg_nseg, 0);
1368         if (error == 0) {
1369                 virtqueue_notify(vq);
1370                 virtqueue_poll(vq, NULL);
1371         }
1372 }
1373
1374 static void
1375 vtcon_port_submit_event(struct vtcon_port *port, uint16_t event,
1376     uint16_t value)
1377 {
1378         struct vtcon_softc *sc;
1379
1380         sc = port->vtcport_sc;
1381
1382         vtcon_ctrl_send_control(sc, port->vtcport_id, event, value);
1383 }
1384
1385 static int
1386 vtcon_tty_open(struct tty *tp)
1387 {
1388         struct vtcon_port *port;
1389
1390         port = tty_softc(tp);
1391
1392         if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1393                 return (ENXIO);
1394
1395         vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
1396
1397         return (0);
1398 }
1399
1400 static void
1401 vtcon_tty_close(struct tty *tp)
1402 {
1403         struct vtcon_port *port;
1404
1405         port = tty_softc(tp);
1406
1407         if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1408                 return;
1409
1410         vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
1411 }
1412
1413 static void
1414 vtcon_tty_outwakeup(struct tty *tp)
1415 {
1416         struct vtcon_port *port;
1417         char buf[VTCON_BULK_BUFSZ];
1418         int len;
1419
1420         port = tty_softc(tp);
1421
1422         if (port->vtcport_flags & VTCON_PORT_FLAG_GONE)
1423                 return;
1424
1425         while ((len = ttydisc_getc(tp, buf, sizeof(buf))) != 0)
1426                 vtcon_port_out(port, buf, len);
1427 }
1428
1429 static void
1430 vtcon_tty_free(void *xport)
1431 {
1432         struct vtcon_port *port;
1433
1434         port = xport;
1435
1436         vtcon_port_destroy(port);
1437         atomic_subtract_int(&vtcon_pending_free, 1);
1438 }
1439
1440 static void
1441 vtcon_get_console_size(struct vtcon_softc *sc, uint16_t *cols, uint16_t *rows)
1442 {
1443         struct virtio_console_config concfg;
1444
1445         KASSERT(sc->vtcon_flags & VTCON_FLAG_SIZE,
1446             ("%s: size feature not negotiated", __func__));
1447
1448         vtcon_read_config(sc, &concfg);
1449
1450         *cols = concfg.cols;
1451         *rows = concfg.rows;
1452 }
1453
1454 static void
1455 vtcon_enable_interrupts(struct vtcon_softc *sc)
1456 {
1457         struct vtcon_softc_port *scport;
1458         struct vtcon_port *port;
1459         int i;
1460
1461         VTCON_LOCK(sc);
1462
1463         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1464                 virtqueue_enable_intr(sc->vtcon_ctrl_rxvq);
1465
1466         for (i = 0; i < sc->vtcon_max_ports; i++) {
1467                 scport = &sc->vtcon_ports[i];
1468
1469                 port = scport->vcsp_port;
1470                 if (port == NULL)
1471                         continue;
1472
1473                 VTCON_PORT_LOCK(port);
1474                 vtcon_port_enable_intr(port);
1475                 VTCON_PORT_UNLOCK(port);
1476         }
1477
1478         VTCON_UNLOCK(sc);
1479 }
1480
1481 static void
1482 vtcon_disable_interrupts(struct vtcon_softc *sc)
1483 {
1484         struct vtcon_softc_port *scport;
1485         struct vtcon_port *port;
1486         int i;
1487
1488         VTCON_LOCK_ASSERT(sc);
1489
1490         if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT)
1491                 virtqueue_disable_intr(sc->vtcon_ctrl_rxvq);
1492
1493         for (i = 0; i < sc->vtcon_max_ports; i++) {
1494                 scport = &sc->vtcon_ports[i];
1495
1496                 port = scport->vcsp_port;
1497                 if (port == NULL)
1498                         continue;
1499
1500                 VTCON_PORT_LOCK(port);
1501                 vtcon_port_disable_intr(port);
1502                 VTCON_PORT_UNLOCK(port);
1503         }
1504 }