peterdelevoryas / rpms / qemu

Forked from rpms/qemu 2 years ago
Clone

Blame qemu-virtio-console-qdev-conversion-new-virtio-serial-b.patch

amitshah 99a9ef
From 76c8fc3a48dcaf6161d7cb68976db99aaf97efdd Mon Sep 17 00:00:00 2001
amitshah 99a9ef
From: Amit Shah <amit.shah@redhat.com>
amitshah 99a9ef
Date: Wed, 20 Jan 2010 00:36:52 +0530
amitshah 99a9ef
Subject: [PATCH 2/9] virtio-console: qdev conversion, new virtio-serial-bus
amitshah 99a9ef
amitshah 99a9ef
This commit converts the virtio-console device to create a new
amitshah 99a9ef
virtio-serial bus that can host console and generic serial ports. The
amitshah 99a9ef
file hosting this code is now called virtio-serial-bus.c.
amitshah 99a9ef
amitshah 99a9ef
The virtio console is now a very simple qdev device that sits on the
amitshah 99a9ef
virtio-serial-bus and communicates between the bus and qemu's chardevs.
amitshah 99a9ef
amitshah 99a9ef
This commit also includes a few changes to the virtio backing code for
amitshah 99a9ef
pci and s390 to spawn the virtio-serial bus.
amitshah 99a9ef
amitshah 99a9ef
As a result of the qdev conversion, we get rid of a lot of legacy code.
amitshah 99a9ef
The old-style way of instantiating a virtio console using
amitshah 99a9ef
amitshah 99a9ef
    -virtioconsole ...
amitshah 99a9ef
amitshah 99a9ef
is maintained, but the new, preferred way is to use
amitshah 99a9ef
amitshah 99a9ef
    -device virtio-serial -device virtconsole,chardev=...
amitshah 99a9ef
amitshah 99a9ef
With this commit, multiple devices as well as multiple ports with a
amitshah 99a9ef
single device can be supported.
amitshah 99a9ef
amitshah 99a9ef
For multiple ports support, each port gets an IO vq pair. Since the
amitshah 99a9ef
guest needs to know in advance how many vqs a particular device will
amitshah 99a9ef
need, we have to set this number as a property of the virtio-serial
amitshah 99a9ef
device and also as a config option.
amitshah 99a9ef
amitshah 99a9ef
In addition, we also spawn a pair of control IO vqs. This is an internal
amitshah 99a9ef
channel meant for guest-host communication for things like port
amitshah 99a9ef
open/close, sending port properties over to the guest, etc.
amitshah 99a9ef
amitshah 99a9ef
This commit is a part of a series of other commits to get the full
amitshah 99a9ef
implementation of multiport support. Future commits will add other
amitshah 99a9ef
support as well as ride on the savevm version that we bump up here.
amitshah 99a9ef
amitshah 99a9ef
Signed-off-by: Amit Shah <amit.shah@redhat.com>
amitshah 99a9ef
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
amitshah 99a9ef
---
amitshah 99a9ef
 Makefile.target        |    2 +-
amitshah 99a9ef
 hw/pc.c                |   11 +-
amitshah 99a9ef
 hw/ppc440_bamboo.c     |    7 -
amitshah 99a9ef
 hw/qdev.c              |   10 +-
amitshah 99a9ef
 hw/s390-virtio-bus.c   |   17 +-
amitshah 99a9ef
 hw/s390-virtio-bus.h   |    2 +
amitshah 99a9ef
 hw/s390-virtio.c       |    8 -
amitshah 99a9ef
 hw/virtio-console.c    |  146 --------------
amitshah 99a9ef
 hw/virtio-console.h    |   19 --
amitshah 99a9ef
 hw/virtio-pci.c        |   13 +-
amitshah 99a9ef
 hw/virtio-serial-bus.c |  504 ++++++++++++++++++++++++++++++++++++++++++++++++
amitshah 99a9ef
 hw/virtio-serial.c     |  111 +++++++++++
amitshah 99a9ef
 hw/virtio-serial.h     |  158 +++++++++++++++
amitshah 99a9ef
 hw/virtio.h            |    2 +-
amitshah 99a9ef
 qemu-options.hx        |    4 +
amitshah 99a9ef
 sysemu.h               |    6 -
amitshah 99a9ef
 vl.c                   |   17 ++-
amitshah 99a9ef
 17 files changed, 819 insertions(+), 218 deletions(-)
amitshah 99a9ef
 delete mode 100644 hw/virtio-console.c
amitshah 99a9ef
 delete mode 100644 hw/virtio-console.h
amitshah 99a9ef
 create mode 100644 hw/virtio-serial-bus.c
amitshah 99a9ef
 create mode 100644 hw/virtio-serial.c
amitshah 99a9ef
 create mode 100644 hw/virtio-serial.h
amitshah 99a9ef
amitshah 99a9ef
diff --git a/Makefile.target b/Makefile.target
amitshah 99a9ef
index 6037fed..234577c 100644
amitshah 99a9ef
--- a/Makefile.target
amitshah 99a9ef
+++ b/Makefile.target
amitshah 99a9ef
@@ -166,7 +166,7 @@ ifdef CONFIG_SOFTMMU
amitshah 99a9ef
 obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
amitshah 99a9ef
 # virtio has to be here due to weird dependency between PCI and virtio-net.
amitshah 99a9ef
 # need to fix this properly
amitshah 99a9ef
-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
amitshah 99a9ef
+obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial.o virtio-serial-bus.o virtio-pci.o
amitshah 99a9ef
 obj-$(CONFIG_KVM) += kvm.o kvm-all.o
amitshah 99a9ef
 # MSI-X depends on kvm for interrupt injection,
amitshah 99a9ef
 # so moved it from Makefile.hw to Makefile.target for now
amitshah 99a9ef
diff --git a/hw/pc.c b/hw/pc.c
amitshah 99a9ef
index 78a07c2..acbfeba 100644
amitshah 99a9ef
--- a/hw/pc.c
amitshah 99a9ef
+++ b/hw/pc.c
amitshah 99a9ef
@@ -1284,15 +1284,6 @@ static void pc_init1(ram_addr_t ram_size,
amitshah 99a9ef
 	extboot_init(info->bdrv, 1);
amitshah 99a9ef
     }
amitshah 99a9ef
 
amitshah 99a9ef
-    /* Add virtio console devices */
amitshah 99a9ef
-    if (pci_enabled) {
amitshah 99a9ef
-        for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
amitshah 99a9ef
-            if (virtcon_hds[i]) {
amitshah 99a9ef
-                pci_create_simple(pci_bus, -1, "virtio-console-pci");
amitshah 99a9ef
-            }
amitshah 99a9ef
-        }
amitshah 99a9ef
-    }
amitshah 99a9ef
-
amitshah 99a9ef
 #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
amitshah 99a9ef
     if (kvm_enabled()) {
amitshah 99a9ef
         add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
amitshah 99a9ef
@@ -1373,7 +1364,7 @@ static QEMUMachine pc_machine_v0_10 = {
amitshah 99a9ef
             .property = "class",
amitshah 99a9ef
             .value    = stringify(PCI_CLASS_STORAGE_OTHER),
amitshah 99a9ef
         },{
amitshah 99a9ef
-            .driver   = "virtio-console-pci",
amitshah 99a9ef
+            .driver   = "virtio-serial-pci",
amitshah 99a9ef
             .property = "class",
amitshah 99a9ef
             .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
amitshah 99a9ef
         },{
amitshah 99a9ef
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
amitshah 99a9ef
index 25417e3..c94c961 100644
amitshah 99a9ef
--- a/hw/ppc440_bamboo.c
amitshah 99a9ef
+++ b/hw/ppc440_bamboo.c
amitshah 99a9ef
@@ -109,13 +109,6 @@ static void bamboo_init(ram_addr_t ram_size,
amitshah 99a9ef
     env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1, cpu_model);
amitshah 99a9ef
 
amitshah 99a9ef
     if (pcibus) {
amitshah 99a9ef
-        /* Add virtio console devices */
amitshah 99a9ef
-        for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
amitshah 99a9ef
-            if (virtcon_hds[i]) {
amitshah 99a9ef
-                pci_create_simple(pcibus, -1, "virtio-console-pci");
amitshah 99a9ef
-            }
amitshah 99a9ef
-        }
amitshah 99a9ef
-
amitshah 99a9ef
         /* Register network interfaces. */
amitshah 99a9ef
         for (i = 0; i < nb_nics; i++) {
amitshah 99a9ef
             /* There are no PCI NICs on the Bamboo board, but there are
amitshah 99a9ef
diff --git a/hw/qdev.c b/hw/qdev.c
amitshah 99a9ef
index b6bd4ae..c643576 100644
amitshah 99a9ef
--- a/hw/qdev.c
amitshah 99a9ef
+++ b/hw/qdev.c
amitshah 99a9ef
@@ -321,13 +321,9 @@ void qdev_machine_creation_done(void)
amitshah 99a9ef
 CharDriverState *qdev_init_chardev(DeviceState *dev)
amitshah 99a9ef
 {
amitshah 99a9ef
     static int next_serial;
amitshah 99a9ef
-    static int next_virtconsole;
amitshah 99a9ef
-    /* FIXME: This is a nasty hack that needs to go away.  */
amitshah 99a9ef
-    if (strncmp(dev->info->name, "virtio", 6) == 0) {
amitshah 99a9ef
-        return virtcon_hds[next_virtconsole++];
amitshah 99a9ef
-    } else {
amitshah 99a9ef
-        return serial_hds[next_serial++];
amitshah 99a9ef
-    }
amitshah 99a9ef
+
amitshah 99a9ef
+    /* FIXME: This function needs to go away: use chardev properties!  */
amitshah 99a9ef
+    return serial_hds[next_serial++];
amitshah 99a9ef
 }
amitshah 99a9ef
 
amitshah 99a9ef
 BusState *qdev_get_parent_bus(DeviceState *dev)
amitshah 99a9ef
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
amitshah 99a9ef
index dc154ed..95c516a 100644
amitshah 99a9ef
--- a/hw/s390-virtio-bus.c
amitshah 99a9ef
+++ b/hw/s390-virtio-bus.c
amitshah 99a9ef
@@ -26,7 +26,7 @@
amitshah 99a9ef
 #include "loader.h"
amitshah 99a9ef
 #include "elf.h"
amitshah 99a9ef
 #include "hw/virtio.h"
amitshah 99a9ef
-#include "hw/virtio-console.h"
amitshah 99a9ef
+#include "hw/virtio-serial.h"
amitshah 99a9ef
 #include "hw/sysbus.h"
amitshah 99a9ef
 #include "kvm.h"
amitshah 99a9ef
 
amitshah 99a9ef
@@ -130,7 +130,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
amitshah 99a9ef
     return s390_virtio_device_init(dev, vdev);
amitshah 99a9ef
 }
amitshah 99a9ef
 
amitshah 99a9ef
-static int s390_virtio_console_init(VirtIOS390Device *dev)
amitshah 99a9ef
+static int s390_virtio_serial_init(VirtIOS390Device *dev)
amitshah 99a9ef
 {
amitshah 99a9ef
     VirtIOS390Bus *bus;
amitshah 99a9ef
     VirtIODevice *vdev;
amitshah 99a9ef
@@ -138,7 +138,7 @@ static int s390_virtio_console_init(VirtIOS390Device *dev)
amitshah 99a9ef
 
amitshah 99a9ef
     bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
amitshah 99a9ef
 
amitshah 99a9ef
-    vdev = virtio_console_init((DeviceState *)dev);
amitshah 99a9ef
+    vdev = virtio_serial_init((DeviceState *)dev, dev->max_virtserial_ports);
amitshah 99a9ef
     if (!vdev) {
amitshah 99a9ef
         return -1;
amitshah 99a9ef
     }
amitshah 99a9ef
@@ -336,11 +336,14 @@ static VirtIOS390DeviceInfo s390_virtio_blk = {
amitshah 99a9ef
     },
amitshah 99a9ef
 };
amitshah 99a9ef
 
amitshah 99a9ef
-static VirtIOS390DeviceInfo s390_virtio_console = {
amitshah 99a9ef
-    .init = s390_virtio_console_init,
amitshah 99a9ef
-    .qdev.name = "virtio-console-s390",
amitshah 99a9ef
+static VirtIOS390DeviceInfo s390_virtio_serial = {
amitshah 99a9ef
+    .init = s390_virtio_serial_init,
amitshah 99a9ef
+    .qdev.name = "virtio-serial-s390",
amitshah 99a9ef
+    .qdev.alias = "virtio-serial",
amitshah 99a9ef
     .qdev.size = sizeof(VirtIOS390Device),
amitshah 99a9ef
     .qdev.props = (Property[]) {
amitshah 99a9ef
+        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, max_virtserial_ports,
amitshah 99a9ef
+                           31),
amitshah 99a9ef
         DEFINE_PROP_END_OF_LIST(),
amitshah 99a9ef
     },
amitshah 99a9ef
 };
amitshah 99a9ef
@@ -364,7 +367,7 @@ static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
amitshah 99a9ef
 
amitshah 99a9ef
 static void s390_virtio_register(void)
amitshah 99a9ef
 {
amitshah 99a9ef
-    s390_virtio_bus_register_withprop(&s390_virtio_console);
amitshah 99a9ef
+    s390_virtio_bus_register_withprop(&s390_virtio_serial);
amitshah 99a9ef
     s390_virtio_bus_register_withprop(&s390_virtio_blk);
amitshah 99a9ef
     s390_virtio_bus_register_withprop(&s390_virtio_net);
amitshah 99a9ef
 }
amitshah 99a9ef
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
amitshah 99a9ef
index ef36714..ad85ed3 100644
amitshah 99a9ef
--- a/hw/s390-virtio-bus.h
amitshah 99a9ef
+++ b/hw/s390-virtio-bus.h
amitshah 99a9ef
@@ -40,6 +40,8 @@ typedef struct VirtIOS390Device {
amitshah 99a9ef
     VirtIODevice *vdev;
amitshah 99a9ef
     DriveInfo *dinfo;
amitshah 99a9ef
     NICConf nic;
amitshah 99a9ef
+    /* Max. number of ports we can have for a the virtio-serial device */
amitshah 99a9ef
+    uint32_t max_virtserial_ports;
amitshah 99a9ef
 } VirtIOS390Device;
amitshah 99a9ef
 
amitshah 99a9ef
 typedef struct VirtIOS390Bus {
amitshah 99a9ef
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
amitshah 99a9ef
index 0fa6ba6..3582728 100644
amitshah 99a9ef
--- a/hw/s390-virtio.c
amitshah 99a9ef
+++ b/hw/s390-virtio.c
amitshah 99a9ef
@@ -26,7 +26,6 @@
amitshah 99a9ef
 #include "loader.h"
amitshah 99a9ef
 #include "elf.h"
amitshah 99a9ef
 #include "hw/virtio.h"
amitshah 99a9ef
-#include "hw/virtio-console.h"
amitshah 99a9ef
 #include "hw/sysbus.h"
amitshah 99a9ef
 #include "kvm.h"
amitshah 99a9ef
 
amitshah 99a9ef
@@ -207,13 +206,6 @@ static void s390_init(ram_addr_t ram_size,
amitshah 99a9ef
                                strlen(kernel_cmdline), 1);
amitshah 99a9ef
     }
amitshah 99a9ef
 
amitshah 99a9ef
-    /* Create VirtIO console */
amitshah 99a9ef
-    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
amitshah 99a9ef
-        if (virtcon_hds[i]) {
amitshah 99a9ef
-            qdev_init_nofail(qdev_create((BusState *)s390_bus, "virtio-console-s390"));
amitshah 99a9ef
-        }
amitshah 99a9ef
-    }
amitshah 99a9ef
-
amitshah 99a9ef
     /* Create VirtIO network adapters */
amitshah 99a9ef
     for(i = 0; i < nb_nics; i++) {
amitshah 99a9ef
         NICInfo *nd = &nd_table[i];
amitshah 99a9ef
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
amitshah 99a9ef
deleted file mode 100644
amitshah 99a9ef
index 92c953c..0000000
amitshah 99a9ef
--- a/hw/virtio-console.c
amitshah 99a9ef
+++ /dev/null
amitshah 99a9ef
@@ -1,146 +0,0 @@
amitshah 99a9ef
-/*
amitshah 99a9ef
- * Virtio Console Device
amitshah 99a9ef
- *
amitshah 99a9ef
- * Copyright IBM, Corp. 2008
amitshah 99a9ef
- *
amitshah 99a9ef
- * Authors:
amitshah 99a9ef
- *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
amitshah 99a9ef
- *
amitshah 99a9ef
- * This work is licensed under the terms of the GNU GPL, version 2.  See
amitshah 99a9ef
- * the COPYING file in the top-level directory.
amitshah 99a9ef
- *
amitshah 99a9ef
- */
amitshah 99a9ef
-
amitshah 99a9ef
-#include "hw.h"
amitshah 99a9ef
-#include "qemu-char.h"
amitshah 99a9ef
-#include "virtio.h"
amitshah 99a9ef
-#include "virtio-console.h"
amitshah 99a9ef
-
amitshah 99a9ef
-
amitshah 99a9ef
-typedef struct VirtIOConsole
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIODevice vdev;
amitshah 99a9ef
-    VirtQueue *ivq, *ovq;
amitshah 99a9ef
-    CharDriverState *chr;
amitshah 99a9ef
-} VirtIOConsole;
amitshah 99a9ef
-
amitshah 99a9ef
-static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
amitshah 99a9ef
-{
amitshah 99a9ef
-    return (VirtIOConsole *)vdev;
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s = to_virtio_console(vdev);
amitshah 99a9ef
-    VirtQueueElement elem;
amitshah 99a9ef
-
amitshah 99a9ef
-    while (virtqueue_pop(vq, &elem)) {
amitshah 99a9ef
-        ssize_t len = 0;
amitshah 99a9ef
-        int d;
amitshah 99a9ef
-
amitshah 99a9ef
-        for (d = 0; d < elem.out_num; d++) {
amitshah 99a9ef
-            len += qemu_chr_write(s->chr, (uint8_t *)elem.out_sg[d].iov_base,
amitshah 99a9ef
-                                  elem.out_sg[d].iov_len);
amitshah 99a9ef
-        }
amitshah 99a9ef
-        virtqueue_push(vq, &elem, len);
amitshah 99a9ef
-        virtio_notify(vdev, vq);
amitshah 99a9ef
-    }
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
-{
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static uint32_t virtio_console_get_features(VirtIODevice *vdev)
amitshah 99a9ef
-{
amitshah 99a9ef
-    return 0;
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static int vcon_can_read(void *opaque)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s = (VirtIOConsole *) opaque;
amitshah 99a9ef
-
amitshah 99a9ef
-    if (!virtio_queue_ready(s->ivq) ||
amitshah 99a9ef
-        !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
amitshah 99a9ef
-        virtio_queue_empty(s->ivq))
amitshah 99a9ef
-        return 0;
amitshah 99a9ef
-
amitshah 99a9ef
-    /* current implementations have a page sized buffer.
amitshah 99a9ef
-     * We fall back to a one byte per read if there is not enough room.
amitshah 99a9ef
-     * It would be cool to have a function that returns the available byte
amitshah 99a9ef
-     * instead of checking for a limit */
amitshah 99a9ef
-    if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
amitshah 99a9ef
-        return TARGET_PAGE_SIZE;
amitshah 99a9ef
-    if (virtqueue_avail_bytes(s->ivq, 1, 0))
amitshah 99a9ef
-        return 1;
amitshah 99a9ef
-    return 0;
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static void vcon_read(void *opaque, const uint8_t *buf, int size)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s = (VirtIOConsole *) opaque;
amitshah 99a9ef
-    VirtQueueElement elem;
amitshah 99a9ef
-    int offset = 0;
amitshah 99a9ef
-
amitshah 99a9ef
-    /* The current kernel implementation has only one outstanding input
amitshah 99a9ef
-     * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
amitshah 99a9ef
-     * handle multiple buffers with multiple sg element for input */
amitshah 99a9ef
-    while (offset < size) {
amitshah 99a9ef
-        int i = 0;
amitshah 99a9ef
-        if (!virtqueue_pop(s->ivq, &elem))
amitshah 99a9ef
-                break;
amitshah 99a9ef
-        while (offset < size && i < elem.in_num) {
amitshah 99a9ef
-            int len = MIN(elem.in_sg[i].iov_len, size - offset);
amitshah 99a9ef
-            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
amitshah 99a9ef
-            offset += len;
amitshah 99a9ef
-            i++;
amitshah 99a9ef
-        }
amitshah 99a9ef
-        virtqueue_push(s->ivq, &elem, size);
amitshah 99a9ef
-    }
amitshah 99a9ef
-    virtio_notify(&s->vdev, s->ivq);
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static void vcon_event(void *opaque, int event)
amitshah 99a9ef
-{
amitshah 99a9ef
-    /* we will ignore any event for the time being */
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static void virtio_console_save(QEMUFile *f, void *opaque)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s = opaque;
amitshah 99a9ef
-
amitshah 99a9ef
-    virtio_save(&s->vdev, f);
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s = opaque;
amitshah 99a9ef
-
amitshah 99a9ef
-    if (version_id != 1)
amitshah 99a9ef
-        return -EINVAL;
amitshah 99a9ef
-
amitshah 99a9ef
-    virtio_load(&s->vdev, f);
amitshah 99a9ef
-    return 0;
amitshah 99a9ef
-}
amitshah 99a9ef
-
amitshah 99a9ef
-VirtIODevice *virtio_console_init(DeviceState *dev)
amitshah 99a9ef
-{
amitshah 99a9ef
-    VirtIOConsole *s;
amitshah 99a9ef
-    s = (VirtIOConsole *)virtio_common_init("virtio-console",
amitshah 99a9ef
-                                            VIRTIO_ID_CONSOLE,
amitshah 99a9ef
-                                            0, sizeof(VirtIOConsole));
amitshah 99a9ef
-    if (s == NULL)
amitshah 99a9ef
-        return NULL;
amitshah 99a9ef
-
amitshah 99a9ef
-    s->vdev.get_features = virtio_console_get_features;
amitshah 99a9ef
-
amitshah 99a9ef
-    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
amitshah 99a9ef
-    s->ovq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
amitshah 99a9ef
-
amitshah 99a9ef
-    s->chr = qdev_init_chardev(dev);
amitshah 99a9ef
-    qemu_chr_add_handlers(s->chr, vcon_can_read, vcon_read, vcon_event, s);
amitshah 99a9ef
-
amitshah 99a9ef
-    register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
amitshah 99a9ef
-
amitshah 99a9ef
-    return &s->vdev;
amitshah 99a9ef
-}
amitshah 99a9ef
diff --git a/hw/virtio-console.h b/hw/virtio-console.h
amitshah 99a9ef
deleted file mode 100644
amitshah 99a9ef
index 84d0717..0000000
amitshah 99a9ef
--- a/hw/virtio-console.h
amitshah 99a9ef
+++ /dev/null
amitshah 99a9ef
@@ -1,19 +0,0 @@
amitshah 99a9ef
-/*
amitshah 99a9ef
- * Virtio Console Support
amitshah 99a9ef
- *
amitshah 99a9ef
- * Copyright IBM, Corp. 2008
amitshah 99a9ef
- *
amitshah 99a9ef
- * Authors:
amitshah 99a9ef
- *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
amitshah 99a9ef
- *
amitshah 99a9ef
- * This work is licensed under the terms of the GNU GPL, version 2.  See
amitshah 99a9ef
- * the COPYING file in the top-level directory.
amitshah 99a9ef
- *
amitshah 99a9ef
- */
amitshah 99a9ef
-#ifndef _QEMU_VIRTIO_CONSOLE_H
amitshah 99a9ef
-#define _QEMU_VIRTIO_CONSOLE_H
amitshah 99a9ef
-
amitshah 99a9ef
-/* The ID for virtio console */
amitshah 99a9ef
-#define VIRTIO_ID_CONSOLE 3
amitshah 99a9ef
-
amitshah 99a9ef
-#endif
amitshah 99a9ef
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
amitshah 99a9ef
index 3594152..c1a1e4c 100644
amitshah 99a9ef
--- a/hw/virtio-pci.c
amitshah 99a9ef
+++ b/hw/virtio-pci.c
amitshah 99a9ef
@@ -92,6 +92,8 @@ typedef struct {
amitshah 99a9ef
     uint32_t nvectors;
amitshah 99a9ef
     DriveInfo *dinfo;
amitshah 99a9ef
     NICConf nic;
amitshah 99a9ef
+    /* Max. number of ports we can have for a the virtio-serial device */
amitshah 99a9ef
+    uint32_t max_virtserial_ports;
amitshah 99a9ef
 } VirtIOPCIProxy;
amitshah 99a9ef
 
amitshah 99a9ef
 /* virtio device */
amitshah 99a9ef
@@ -481,7 +483,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
amitshah 99a9ef
     return virtio_exit_pci(pci_dev);
amitshah 99a9ef
 }
amitshah 99a9ef
 
amitshah 99a9ef
-static int virtio_console_init_pci(PCIDevice *pci_dev)
amitshah 99a9ef
+static int virtio_serial_init_pci(PCIDevice *pci_dev)
amitshah 99a9ef
 {
amitshah 99a9ef
     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
amitshah 99a9ef
     VirtIODevice *vdev;
amitshah 99a9ef
@@ -491,7 +493,7 @@ static int virtio_console_init_pci(PCIDevice *pci_dev)
amitshah 99a9ef
         proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
amitshah 99a9ef
         proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
amitshah 99a9ef
 
amitshah 99a9ef
-    vdev = virtio_console_init(&pci_dev->qdev);
amitshah 99a9ef
+    vdev = virtio_serial_init(&pci_dev->qdev, proxy->max_virtserial_ports);
amitshah 99a9ef
     if (!vdev) {
amitshah 99a9ef
         return -1;
amitshah 99a9ef
     }
amitshah 99a9ef
@@ -569,12 +571,15 @@ static PCIDeviceInfo virtio_info[] = {
amitshah 99a9ef
         },
amitshah 99a9ef
         .qdev.reset = virtio_pci_reset,
amitshah 99a9ef
     },{
amitshah 99a9ef
-        .qdev.name = "virtio-console-pci",
amitshah 99a9ef
+        .qdev.name = "virtio-serial-pci",
amitshah 99a9ef
+        .qdev.alias = "virtio-serial",
amitshah 99a9ef
         .qdev.size = sizeof(VirtIOPCIProxy),
amitshah 99a9ef
-        .init      = virtio_console_init_pci,
amitshah 99a9ef
+        .init      = virtio_serial_init_pci,
amitshah 99a9ef
         .exit      = virtio_exit_pci,
amitshah 99a9ef
         .qdev.props = (Property[]) {
amitshah 99a9ef
             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
amitshah 99a9ef
+            DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
amitshah 99a9ef
+                               31),
amitshah 99a9ef
             DEFINE_PROP_END_OF_LIST(),
amitshah 99a9ef
         },
amitshah 99a9ef
         .qdev.reset = virtio_pci_reset,
amitshah 99a9ef
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
amitshah 99a9ef
new file mode 100644
amitshah 99a9ef
index 0000000..5132c9c
amitshah 99a9ef
--- /dev/null
amitshah 99a9ef
+++ b/hw/virtio-serial-bus.c
amitshah 99a9ef
@@ -0,0 +1,504 @@
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * A bus for connecting virtio serial and console ports
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Copyright (C) 2009 Red Hat, Inc.
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Author(s):
amitshah 99a9ef
+ *  Amit Shah <amit.shah@redhat.com>
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Some earlier parts are:
amitshah 99a9ef
+ *  Copyright IBM, Corp. 2008
amitshah 99a9ef
+ * authored by
amitshah 99a9ef
+ *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
amitshah 99a9ef
+ * the COPYING file in the top-level directory.
amitshah 99a9ef
+ */
amitshah 99a9ef
+
amitshah 99a9ef
+#include "monitor.h"
amitshah 99a9ef
+#include "qemu-queue.h"
amitshah 99a9ef
+#include "sysbus.h"
amitshah 99a9ef
+#include "virtio-serial.h"
amitshah 99a9ef
+
amitshah 99a9ef
+/* The virtio-serial bus on top of which the ports will ride as devices */
amitshah 99a9ef
+struct VirtIOSerialBus {
amitshah 99a9ef
+    BusState qbus;
amitshah 99a9ef
+
amitshah 99a9ef
+    /* This is the parent device that provides the bus for ports. */
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    /* The maximum number of ports that can ride on top of this bus */
amitshah 99a9ef
+    uint32_t max_nr_ports;
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+struct VirtIOSerial {
amitshah 99a9ef
+    VirtIODevice vdev;
amitshah 99a9ef
+
amitshah 99a9ef
+    VirtQueue *c_ivq, *c_ovq;
amitshah 99a9ef
+    /* Arrays of ivqs and ovqs: one per port */
amitshah 99a9ef
+    VirtQueue **ivqs, **ovqs;
amitshah 99a9ef
+
amitshah 99a9ef
+    VirtIOSerialBus *bus;
amitshah 99a9ef
+
amitshah 99a9ef
+    QTAILQ_HEAD(, VirtIOSerialPort) ports;
amitshah 99a9ef
+    struct virtio_console_config config;
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialPort *port;
amitshah 99a9ef
+
amitshah 99a9ef
+    QTAILQ_FOREACH(port, &vser->ports, next) {
amitshah 99a9ef
+        if (port->id == id)
amitshah 99a9ef
+            return port;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    return NULL;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialPort *port;
amitshah 99a9ef
+
amitshah 99a9ef
+    QTAILQ_FOREACH(port, &vser->ports, next) {
amitshah 99a9ef
+        if (port->ivq == vq || port->ovq == vq)
amitshah 99a9ef
+            return port;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    return NULL;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static size_t write_to_port(VirtIOSerialPort *port,
amitshah 99a9ef
+                            const uint8_t *buf, size_t size)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtQueueElement elem;
amitshah 99a9ef
+    VirtQueue *vq;
amitshah 99a9ef
+    size_t offset = 0;
amitshah 99a9ef
+    size_t len = 0;
amitshah 99a9ef
+
amitshah 99a9ef
+    vq = port->ivq;
amitshah 99a9ef
+    if (!virtio_queue_ready(vq)) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    if (!size) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    while (offset < size) {
amitshah 99a9ef
+        int i;
amitshah 99a9ef
+
amitshah 99a9ef
+        if (!virtqueue_pop(vq, &elem)) {
amitshah 99a9ef
+            break;
amitshah 99a9ef
+        }
amitshah 99a9ef
+
amitshah 99a9ef
+        for (i = 0; offset < size && i < elem.in_num; i++) {
amitshah 99a9ef
+            len = MIN(elem.in_sg[i].iov_len, size - offset);
amitshah 99a9ef
+
amitshah 99a9ef
+            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
amitshah 99a9ef
+            offset += len;
amitshah 99a9ef
+        }
amitshah 99a9ef
+        virtqueue_push(vq, &elem, len);
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    virtio_notify(&port->vser->vdev, vq);
amitshah 99a9ef
+    return offset;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtQueueElement elem;
amitshah 99a9ef
+    VirtQueue *vq;
amitshah 99a9ef
+    struct virtio_console_control *cpkt;
amitshah 99a9ef
+
amitshah 99a9ef
+    vq = port->vser->c_ivq;
amitshah 99a9ef
+    if (!virtio_queue_ready(vq)) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    if (!virtqueue_pop(vq, &elem)) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    cpkt = (struct virtio_console_control *)buf;
amitshah 99a9ef
+    stl_p(&cpkt->id, port->id);
amitshah 99a9ef
+    memcpy(elem.in_sg[0].iov_base, buf, len);
amitshah 99a9ef
+
amitshah 99a9ef
+    virtqueue_push(vq, &elem, len);
amitshah 99a9ef
+    virtio_notify(&port->vser->vdev, vq);
amitshah 99a9ef
+    return len;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
amitshah 99a9ef
+                                 uint16_t value)
amitshah 99a9ef
+{
amitshah 99a9ef
+    struct virtio_console_control cpkt;
amitshah 99a9ef
+
amitshah 99a9ef
+    stw_p(&cpkt.event, event);
amitshah 99a9ef
+    stw_p(&cpkt.value, value);
amitshah 99a9ef
+
amitshah 99a9ef
+    return send_control_msg(port, &cpkt, sizeof(cpkt));
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Functions for use inside qemu to open and read from/write to ports */
amitshah 99a9ef
+int virtio_serial_open(VirtIOSerialPort *port)
amitshah 99a9ef
+{
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+int virtio_serial_close(VirtIOSerialPort *port)
amitshah 99a9ef
+{
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Individual ports/apps call this function to write to the guest. */
amitshah 99a9ef
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
amitshah 99a9ef
+                            size_t size)
amitshah 99a9ef
+{
amitshah 99a9ef
+    return write_to_port(port, buf, size);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Readiness of the guest to accept data on a port.
amitshah 99a9ef
+ * Returns max. data the guest can receive
amitshah 99a9ef
+ */
amitshah 99a9ef
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtQueue *vq = port->ivq;
amitshah 99a9ef
+
amitshah 99a9ef
+    if (!virtio_queue_ready(vq) ||
amitshah 99a9ef
+        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
amitshah 99a9ef
+        virtio_queue_empty(vq)) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    if (virtqueue_avail_bytes(vq, 4096, 0)) {
amitshah 99a9ef
+        return 4096;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    if (virtqueue_avail_bytes(vq, 1, 0)) {
amitshah 99a9ef
+        return 1;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Guest wants to notify us of some event */
amitshah 99a9ef
+static void handle_control_message(VirtIOSerial *vser, void *buf)
amitshah 99a9ef
+{
amitshah 99a9ef
+    struct VirtIOSerialPort *port;
amitshah 99a9ef
+    struct virtio_console_control cpkt, *gcpkt;
amitshah 99a9ef
+
amitshah 99a9ef
+    gcpkt = buf;
amitshah 99a9ef
+    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
amitshah 99a9ef
+    if (!port)
amitshah 99a9ef
+        return;
amitshah 99a9ef
+
amitshah 99a9ef
+    cpkt.event = lduw_p(&gcpkt->event);
amitshah 99a9ef
+    cpkt.value = lduw_p(&gcpkt->value);
amitshah 99a9ef
+
amitshah 99a9ef
+    switch(cpkt.event) {
amitshah 99a9ef
+    case VIRTIO_CONSOLE_PORT_READY:
amitshah 99a9ef
+        /*
amitshah 99a9ef
+         * Now that we know the guest asked for the port name, we're
amitshah 99a9ef
+         * sure the guest has initialised whatever state is necessary
amitshah 99a9ef
+         * for this port. Now's a good time to let the guest know if
amitshah 99a9ef
+         * this port is a console port so that the guest can hook it
amitshah 99a9ef
+         * up to hvc.
amitshah 99a9ef
+         */
amitshah 99a9ef
+        if (port->is_console) {
amitshah 99a9ef
+            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
amitshah 99a9ef
+        }
amitshah 99a9ef
+        /*
amitshah 99a9ef
+         * When the guest has asked us for this information it means
amitshah 99a9ef
+         * the guest is all setup and has its virtqueues
amitshah 99a9ef
+         * initialised. If some app is interested in knowing about
amitshah 99a9ef
+         * this event, let it know.
amitshah 99a9ef
+         */
amitshah 99a9ef
+        if (port->info->guest_ready) {
amitshah 99a9ef
+            port->info->guest_ready(port);
amitshah 99a9ef
+        }
amitshah 99a9ef
+        break;
amitshah 99a9ef
+    }
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void control_in(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
+{
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void control_out(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtQueueElement elem;
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
amitshah 99a9ef
+
amitshah 99a9ef
+    while (virtqueue_pop(vq, &elem)) {
amitshah 99a9ef
+        handle_control_message(vser, elem.out_sg[0].iov_base);
amitshah 99a9ef
+        virtqueue_push(vq, &elem, elem.out_sg[0].iov_len);
amitshah 99a9ef
+    }
amitshah 99a9ef
+    virtio_notify(vdev, vq);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Guest wrote something to some port. */
amitshah 99a9ef
+static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+    VirtQueueElement elem;
amitshah 99a9ef
+
amitshah 99a9ef
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
amitshah 99a9ef
+
amitshah 99a9ef
+    while (virtqueue_pop(vq, &elem)) {
amitshah 99a9ef
+        VirtIOSerialPort *port;
amitshah 99a9ef
+        size_t ret;
amitshah 99a9ef
+
amitshah 99a9ef
+        port = find_port_by_vq(vser, vq);
amitshah 99a9ef
+        if (!port) {
amitshah 99a9ef
+            ret = 0;
amitshah 99a9ef
+            goto next_buf;
amitshah 99a9ef
+        }
amitshah 99a9ef
+
amitshah 99a9ef
+        /*
amitshah 99a9ef
+         * A port may not have any handler registered for consuming the
amitshah 99a9ef
+         * data that the guest sends or it may not have a chardev associated
amitshah 99a9ef
+         * with it. Just ignore the data in that case.
amitshah 99a9ef
+         */
amitshah 99a9ef
+        if (!port->info->have_data) {
amitshah 99a9ef
+            ret = 0;
amitshah 99a9ef
+            goto next_buf;
amitshah 99a9ef
+        }
amitshah 99a9ef
+
amitshah 99a9ef
+        /* The guest always sends only one sg */
amitshah 99a9ef
+        ret = port->info->have_data(port, elem.out_sg[0].iov_base,
amitshah 99a9ef
+                                    elem.out_sg[0].iov_len);
amitshah 99a9ef
+
amitshah 99a9ef
+    next_buf:
amitshah 99a9ef
+        virtqueue_push(vq, &elem, ret);
amitshah 99a9ef
+    }
amitshah 99a9ef
+    virtio_notify(vdev, vq);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
amitshah 99a9ef
+{
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static uint32_t get_features(VirtIODevice *vdev)
amitshah 99a9ef
+{
amitshah 99a9ef
+    return 1 << VIRTIO_CONSOLE_F_MULTIPORT;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Guest requested config info */
amitshah 99a9ef
+static void get_config(VirtIODevice *vdev, uint8_t *config_data)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
amitshah 99a9ef
+    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
amitshah 99a9ef
+{
amitshah 99a9ef
+    struct virtio_console_config config;
amitshah 99a9ef
+
amitshah 99a9ef
+    memcpy(&config, config_data, sizeof(config));
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void virtio_serial_save(QEMUFile *f, void *opaque)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerial *s = opaque;
amitshah 99a9ef
+
amitshah 99a9ef
+    /* The virtio device */
amitshah 99a9ef
+    virtio_save(&s->vdev, f);
amitshah 99a9ef
+
amitshah 99a9ef
+    /* The config space */
amitshah 99a9ef
+    qemu_put_be16s(f, &s->config.cols);
amitshah 99a9ef
+    qemu_put_be16s(f, &s->config.rows);
amitshah 99a9ef
+    qemu_put_be32s(f, &s->config.nr_ports);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerial *s = opaque;
amitshah 99a9ef
+
amitshah 99a9ef
+    if (version_id > 2) {
amitshah 99a9ef
+        return -EINVAL;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    /* The virtio device */
amitshah 99a9ef
+    virtio_load(&s->vdev, f);
amitshah 99a9ef
+
amitshah 99a9ef
+    if (version_id < 2) {
amitshah 99a9ef
+        return 0;
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    /* The config space */
amitshah 99a9ef
+    qemu_get_be16s(f, &s->config.cols);
amitshah 99a9ef
+    qemu_get_be16s(f, &s->config.rows);
amitshah 99a9ef
+    s->config.nr_ports = qemu_get_be32(f);
amitshah 99a9ef
+
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
amitshah 99a9ef
+
amitshah 99a9ef
+static struct BusInfo virtser_bus_info = {
amitshah 99a9ef
+    .name      = "virtio-serial-bus",
amitshah 99a9ef
+    .size      = sizeof(VirtIOSerialBus),
amitshah 99a9ef
+    .print_dev = virtser_bus_dev_print,
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialBus *bus;
amitshah 99a9ef
+
amitshah 99a9ef
+    bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
amitshah 99a9ef
+    bus->qbus.allow_hotplug = 1;
amitshah 99a9ef
+
amitshah 99a9ef
+    return bus;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
amitshah 99a9ef
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
amitshah 99a9ef
+
amitshah 99a9ef
+    monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
amitshah 99a9ef
+                   indent, "", port->id);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
amitshah 99a9ef
+    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
amitshah 99a9ef
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
amitshah 99a9ef
+    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
amitshah 99a9ef
+    int ret;
amitshah 99a9ef
+    bool plugging_port0;
amitshah 99a9ef
+
amitshah 99a9ef
+    port->vser = bus->vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Is the first console port we're seeing? If so, put it up at
amitshah 99a9ef
+     * location 0. This is done for backward compatibility (old
amitshah 99a9ef
+     * kernel, new qemu).
amitshah 99a9ef
+     */
amitshah 99a9ef
+    plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
amitshah 99a9ef
+
amitshah 99a9ef
+    if (port->vser->config.nr_ports == bus->max_nr_ports && !plugging_port0) {
amitshah 99a9ef
+        qemu_error("virtio-serial-bus: Maximum device limit reached\n");
amitshah 99a9ef
+        return -1;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    dev->info = info;
amitshah 99a9ef
+
amitshah 99a9ef
+    ret = info->init(dev);
amitshah 99a9ef
+    if (ret) {
amitshah 99a9ef
+        return ret;
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    port->id = plugging_port0 ? 0 : port->vser->config.nr_ports++;
amitshah 99a9ef
+
amitshah 99a9ef
+    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
amitshah 99a9ef
+    port->ivq = port->vser->ivqs[port->id];
amitshah 99a9ef
+    port->ovq = port->vser->ovqs[port->id];
amitshah 99a9ef
+
amitshah 99a9ef
+    /* Send an update to the guest about this new port added */
amitshah 99a9ef
+    virtio_notify_config(&port->vser->vdev);
amitshah 99a9ef
+
amitshah 99a9ef
+    return ret;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static int virtser_port_qdev_exit(DeviceState *qdev)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
amitshah 99a9ef
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
amitshah 99a9ef
+    VirtIOSerial *vser = port->vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Don't decrement nr_ports here; thus we keep a linearly
amitshah 99a9ef
+     * increasing port id. Not utilising an id again saves us a couple
amitshah 99a9ef
+     * of complications:
amitshah 99a9ef
+     *
amitshah 99a9ef
+     * - Not having to bother about sending the port id to the guest
amitshah 99a9ef
+     *   kernel on hotplug or on addition of new ports; the guest can
amitshah 99a9ef
+     *   also linearly increment the port number. This is preferable
amitshah 99a9ef
+     *   because the config space won't have the need to store a
amitshah 99a9ef
+     *   ports_map.
amitshah 99a9ef
+     *
amitshah 99a9ef
+     * - Extra state to be stored for all the "holes" that got created
amitshah 99a9ef
+     *   so that we keep filling in the ids from the least available
amitshah 99a9ef
+     *   index.
amitshah 99a9ef
+     *
amitshah 99a9ef
+     * When such a functionality is desired, a control message to add
amitshah 99a9ef
+     * a port can be introduced.
amitshah 99a9ef
+     */
amitshah 99a9ef
+    QTAILQ_REMOVE(&vser->ports, port, next);
amitshah 99a9ef
+
amitshah 99a9ef
+    if (port->info->exit)
amitshah 99a9ef
+        port->info->exit(dev);
amitshah 99a9ef
+
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
amitshah 99a9ef
+{
amitshah 99a9ef
+    info->qdev.init = virtser_port_qdev_init;
amitshah 99a9ef
+    info->qdev.bus_info = &virtser_bus_info;
amitshah 99a9ef
+    info->qdev.exit = virtser_port_qdev_exit;
amitshah 99a9ef
+    info->qdev.unplug = qdev_simple_unplug_cb;
amitshah 99a9ef
+    qdev_register(&info->qdev);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+    VirtIODevice *vdev;
amitshah 99a9ef
+    uint32_t i;
amitshah 99a9ef
+
amitshah 99a9ef
+    if (!max_nr_ports)
amitshah 99a9ef
+        return NULL;
amitshah 99a9ef
+
amitshah 99a9ef
+    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
amitshah 99a9ef
+                              sizeof(struct virtio_console_config),
amitshah 99a9ef
+                              sizeof(VirtIOSerial));
amitshah 99a9ef
+
amitshah 99a9ef
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
amitshah 99a9ef
+
amitshah 99a9ef
+    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
amitshah 99a9ef
+    vser->bus = virtser_bus_new(dev);
amitshah 99a9ef
+    vser->bus->vser = vser;
amitshah 99a9ef
+    QTAILQ_INIT(&vser->ports);
amitshah 99a9ef
+
amitshah 99a9ef
+    vser->bus->max_nr_ports = max_nr_ports;
amitshah 99a9ef
+    vser->ivqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
amitshah 99a9ef
+    vser->ovqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
amitshah 99a9ef
+
amitshah 99a9ef
+    /* Add a queue for host to guest transfers for port 0 (backward compat) */
amitshah 99a9ef
+    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
amitshah 99a9ef
+    /* Add a queue for guest to host transfers for port 0 (backward compat) */
amitshah 99a9ef
+    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
amitshah 99a9ef
+
amitshah 99a9ef
+    /* control queue: host to guest */
amitshah 99a9ef
+    vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
amitshah 99a9ef
+    /* control queue: guest to host */
amitshah 99a9ef
+    vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
amitshah 99a9ef
+
amitshah 99a9ef
+    for (i = 1; i < vser->bus->max_nr_ports; i++) {
amitshah 99a9ef
+        /* Add a per-port queue for host to guest transfers */
amitshah 99a9ef
+        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
amitshah 99a9ef
+        /* Add a per-per queue for guest to host transfers */
amitshah 99a9ef
+        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    vser->config.max_nr_ports = max_nr_ports;
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Reserve location 0 for a console port for backward compat
amitshah 99a9ef
+     * (old kernel, new qemu)
amitshah 99a9ef
+     */
amitshah 99a9ef
+    vser->config.nr_ports = 1;
amitshah 99a9ef
+
amitshah 99a9ef
+    vser->vdev.get_features = get_features;
amitshah 99a9ef
+    vser->vdev.get_config = get_config;
amitshah 99a9ef
+    vser->vdev.set_config = set_config;
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Register for the savevm section with the virtio-console name
amitshah 99a9ef
+     * to preserve backward compat
amitshah 99a9ef
+     */
amitshah 99a9ef
+    register_savevm("virtio-console", -1, 2, virtio_serial_save,
amitshah 99a9ef
+                    virtio_serial_load, vser);
amitshah 99a9ef
+
amitshah 99a9ef
+    return vdev;
amitshah 99a9ef
+}
amitshah 99a9ef
diff --git a/hw/virtio-serial.c b/hw/virtio-serial.c
amitshah 99a9ef
new file mode 100644
amitshah 99a9ef
index 0000000..1dc031e
amitshah 99a9ef
--- /dev/null
amitshah 99a9ef
+++ b/hw/virtio-serial.c
amitshah 99a9ef
@@ -0,0 +1,111 @@
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Virtio Console and Generic Serial Port Devices
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Copyright Red Hat, Inc. 2009
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Authors:
amitshah 99a9ef
+ *  Amit Shah <amit.shah@redhat.com>
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
amitshah 99a9ef
+ * the COPYING file in the top-level directory.
amitshah 99a9ef
+ */
amitshah 99a9ef
+
amitshah 99a9ef
+#include "qemu-char.h"
amitshah 99a9ef
+#include "virtio-serial.h"
amitshah 99a9ef
+
amitshah 99a9ef
+typedef struct VirtConsole {
amitshah 99a9ef
+    VirtIOSerialPort port;
amitshah 99a9ef
+    CharDriverState *chr;
amitshah 99a9ef
+} VirtConsole;
amitshah 99a9ef
+
amitshah 99a9ef
+
amitshah 99a9ef
+/* Callback function that's called when the guest sends us data */
amitshah 99a9ef
+static size_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
amitshah 99a9ef
+    ssize_t ret;
amitshah 99a9ef
+
amitshah 99a9ef
+    ret = qemu_chr_write(vcon->chr, buf, len);
amitshah 99a9ef
+
amitshah 99a9ef
+    return ret < 0 ? 0 : ret;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Readiness of the guest to accept data on a port */
amitshah 99a9ef
+static int chr_can_read(void *opaque)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtConsole *vcon = opaque;
amitshah 99a9ef
+
amitshah 99a9ef
+    return virtio_serial_guest_ready(&vcon->port);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Send data from a char device over to the guest */
amitshah 99a9ef
+static void chr_read(void *opaque, const uint8_t *buf, int size)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtConsole *vcon = opaque;
amitshah 99a9ef
+
amitshah 99a9ef
+    virtio_serial_write(&vcon->port, buf, size);
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static void chr_event(void *opaque, int event)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtConsole *vcon = opaque;
amitshah 99a9ef
+
amitshah 99a9ef
+    switch (event) {
amitshah 99a9ef
+    case CHR_EVENT_OPENED: {
amitshah 99a9ef
+        virtio_serial_open(&vcon->port);
amitshah 99a9ef
+        break;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    case CHR_EVENT_CLOSED:
amitshah 99a9ef
+        virtio_serial_close(&vcon->port);
amitshah 99a9ef
+        break;
amitshah 99a9ef
+    }
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+/* Virtio Console Ports */
amitshah 99a9ef
+static int virtconsole_initfn(VirtIOSerialDevice *dev)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
amitshah 99a9ef
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
amitshah 99a9ef
+
amitshah 99a9ef
+    port->info = dev->info;
amitshah 99a9ef
+
amitshah 99a9ef
+    port->is_console = true;
amitshah 99a9ef
+
amitshah 99a9ef
+    if (vcon->chr) {
amitshah 99a9ef
+        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
amitshah 99a9ef
+                              vcon);
amitshah 99a9ef
+        port->info->have_data = flush_buf;
amitshah 99a9ef
+    }
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static int virtconsole_exitfn(VirtIOSerialDevice *dev)
amitshah 99a9ef
+{
amitshah 99a9ef
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
amitshah 99a9ef
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
amitshah 99a9ef
+
amitshah 99a9ef
+    if (vcon->chr) {
amitshah 99a9ef
+        port->info->have_data = NULL;
amitshah 99a9ef
+        qemu_chr_close(vcon->chr);
amitshah 99a9ef
+    }
amitshah 99a9ef
+
amitshah 99a9ef
+    return 0;
amitshah 99a9ef
+}
amitshah 99a9ef
+
amitshah 99a9ef
+static VirtIOSerialPortInfo virtconsole_info = {
amitshah 99a9ef
+    .qdev.name     = "virtconsole",
amitshah 99a9ef
+    .qdev.size     = sizeof(VirtConsole),
amitshah 99a9ef
+    .init          = virtconsole_initfn,
amitshah 99a9ef
+    .exit          = virtconsole_exitfn,
amitshah 99a9ef
+    .qdev.props = (Property[]) {
amitshah 99a9ef
+        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
amitshah 99a9ef
+        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
amitshah 99a9ef
+        DEFINE_PROP_END_OF_LIST(),
amitshah 99a9ef
+    },
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+static void virtconsole_register(void)
amitshah 99a9ef
+{
amitshah 99a9ef
+    virtio_serial_port_qdev_register(&virtconsole_info);
amitshah 99a9ef
+}
amitshah 99a9ef
+device_init(virtconsole_register)
amitshah 99a9ef
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
amitshah 99a9ef
new file mode 100644
amitshah 99a9ef
index 0000000..fe8e357
amitshah 99a9ef
--- /dev/null
amitshah 99a9ef
+++ b/hw/virtio-serial.h
amitshah 99a9ef
@@ -0,0 +1,158 @@
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Virtio Serial / Console Support
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Copyright IBM, Corp. 2008
amitshah 99a9ef
+ * Copyright Red Hat, Inc. 2009
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * Authors:
amitshah 99a9ef
+ *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
amitshah 99a9ef
+ *  Amit Shah <amit.shah@redhat.com>
amitshah 99a9ef
+ *
amitshah 99a9ef
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
amitshah 99a9ef
+ * the COPYING file in the top-level directory.
amitshah 99a9ef
+ *
amitshah 99a9ef
+ */
amitshah 99a9ef
+#ifndef _QEMU_VIRTIO_SERIAL_H
amitshah 99a9ef
+#define _QEMU_VIRTIO_SERIAL_H
amitshah 99a9ef
+
amitshah 99a9ef
+#include <stdbool.h>
amitshah 99a9ef
+#include "qdev.h"
amitshah 99a9ef
+#include "virtio.h"
amitshah 99a9ef
+
amitshah 99a9ef
+/* == Interface shared between the guest kernel and qemu == */
amitshah 99a9ef
+
amitshah 99a9ef
+/* The Virtio ID for virtio console / serial ports */
amitshah 99a9ef
+#define VIRTIO_ID_CONSOLE		3
amitshah 99a9ef
+
amitshah 99a9ef
+/* Features supported */
amitshah 99a9ef
+#define VIRTIO_CONSOLE_F_MULTIPORT	1
amitshah 99a9ef
+
amitshah 99a9ef
+struct virtio_console_config {
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
amitshah 99a9ef
+     * isn't implemented here yet
amitshah 99a9ef
+     */
amitshah 99a9ef
+    uint16_t cols;
amitshah 99a9ef
+    uint16_t rows;
amitshah 99a9ef
+
amitshah 99a9ef
+    uint32_t max_nr_ports;
amitshah 99a9ef
+    uint32_t nr_ports;
amitshah 99a9ef
+} __attribute__((packed));
amitshah 99a9ef
+
amitshah 99a9ef
+struct virtio_console_control {
amitshah 99a9ef
+    uint32_t id;		/* Port number */
amitshah 99a9ef
+    uint16_t event;		/* The kind of control event (see below) */
amitshah 99a9ef
+    uint16_t value;		/* Extra information for the key */
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+/* Some events for the internal messages (control packets) */
amitshah 99a9ef
+#define VIRTIO_CONSOLE_PORT_READY	0
amitshah 99a9ef
+#define VIRTIO_CONSOLE_CONSOLE_PORT	1
amitshah 99a9ef
+#define VIRTIO_CONSOLE_RESIZE		2
amitshah 99a9ef
+
amitshah 99a9ef
+/* == In-qemu interface == */
amitshah 99a9ef
+
amitshah 99a9ef
+typedef struct VirtIOSerial VirtIOSerial;
amitshah 99a9ef
+typedef struct VirtIOSerialBus VirtIOSerialBus;
amitshah 99a9ef
+typedef struct VirtIOSerialPort VirtIOSerialPort;
amitshah 99a9ef
+typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
amitshah 99a9ef
+
amitshah 99a9ef
+typedef struct VirtIOSerialDevice {
amitshah 99a9ef
+    DeviceState qdev;
amitshah 99a9ef
+    VirtIOSerialPortInfo *info;
amitshah 99a9ef
+} VirtIOSerialDevice;
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * This is the state that's shared between all the ports.  Some of the
amitshah 99a9ef
+ * state is configurable via command-line options. Some of it can be
amitshah 99a9ef
+ * set by individual devices in their initfn routines. Some of the
amitshah 99a9ef
+ * state is set by the generic qdev device init routine.
amitshah 99a9ef
+ */
amitshah 99a9ef
+struct VirtIOSerialPort {
amitshah 99a9ef
+    DeviceState dev;
amitshah 99a9ef
+    VirtIOSerialPortInfo *info;
amitshah 99a9ef
+
amitshah 99a9ef
+    QTAILQ_ENTRY(VirtIOSerialPort) next;
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * This field gives us the virtio device as well as the qdev bus
amitshah 99a9ef
+     * that we are associated with
amitshah 99a9ef
+     */
amitshah 99a9ef
+    VirtIOSerial *vser;
amitshah 99a9ef
+
amitshah 99a9ef
+    VirtQueue *ivq, *ovq;
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * This id helps identify ports between the guest and the host.
amitshah 99a9ef
+     * The guest sends a "header" with this id with each data packet
amitshah 99a9ef
+     * that it sends and the host can then find out which associated
amitshah 99a9ef
+     * device to send out this data to
amitshah 99a9ef
+     */
amitshah 99a9ef
+    uint32_t id;
amitshah 99a9ef
+
amitshah 99a9ef
+    /* Identify if this is a port that binds with hvc in the guest */
amitshah 99a9ef
+    uint8_t is_console;
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+struct VirtIOSerialPortInfo {
amitshah 99a9ef
+    DeviceInfo qdev;
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * The per-port (or per-app) init function that's called when a
amitshah 99a9ef
+     * new device is found on the bus.
amitshah 99a9ef
+     */
amitshah 99a9ef
+    int (*init)(VirtIOSerialDevice *dev);
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Per-port exit function that's called when a port gets
amitshah 99a9ef
+     * hot-unplugged or removed.
amitshah 99a9ef
+     */
amitshah 99a9ef
+    int (*exit)(VirtIOSerialDevice *dev);
amitshah 99a9ef
+
amitshah 99a9ef
+    /* Callbacks for guest events */
amitshah 99a9ef
+        /* Guest opened device. */
amitshah 99a9ef
+    void (*guest_open)(VirtIOSerialPort *port);
amitshah 99a9ef
+        /* Guest closed device. */
amitshah 99a9ef
+    void (*guest_close)(VirtIOSerialPort *port);
amitshah 99a9ef
+
amitshah 99a9ef
+        /* Guest is now ready to accept data (virtqueues set up). */
amitshah 99a9ef
+    void (*guest_ready)(VirtIOSerialPort *port);
amitshah 99a9ef
+
amitshah 99a9ef
+    /*
amitshah 99a9ef
+     * Guest wrote some data to the port. This data is handed over to
amitshah 99a9ef
+     * the app via this callback. The app should return the number of
amitshah 99a9ef
+     * bytes it successfully consumed.
amitshah 99a9ef
+     */
amitshah 99a9ef
+    size_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, size_t len);
amitshah 99a9ef
+};
amitshah 99a9ef
+
amitshah 99a9ef
+/* Interface to the virtio-serial bus */
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Individual ports/apps should call this function to register the port
amitshah 99a9ef
+ * with the virtio-serial bus
amitshah 99a9ef
+ */
amitshah 99a9ef
+void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Open a connection to the port
amitshah 99a9ef
+ *   Returns 0 on success (always).
amitshah 99a9ef
+ */
amitshah 99a9ef
+int virtio_serial_open(VirtIOSerialPort *port);
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Close the connection to the port
amitshah 99a9ef
+ *   Returns 0 on success (always).
amitshah 99a9ef
+ */
amitshah 99a9ef
+int virtio_serial_close(VirtIOSerialPort *port);
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Send data to Guest
amitshah 99a9ef
+ */
amitshah 99a9ef
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
amitshah 99a9ef
+                            size_t size);
amitshah 99a9ef
+
amitshah 99a9ef
+/*
amitshah 99a9ef
+ * Query whether a guest is ready to receive data.
amitshah 99a9ef
+ */
amitshah 99a9ef
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
amitshah 99a9ef
+
amitshah 99a9ef
+#endif
amitshah 99a9ef
diff --git a/hw/virtio.h b/hw/virtio.h
amitshah 99a9ef
index 051910a..a574928 100644
amitshah 99a9ef
--- a/hw/virtio.h
amitshah 99a9ef
+++ b/hw/virtio.h
amitshah 99a9ef
@@ -171,7 +171,7 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
amitshah 99a9ef
 /* Base devices.  */
amitshah 99a9ef
 VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo);
amitshah 99a9ef
 VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
amitshah 99a9ef
-VirtIODevice *virtio_console_init(DeviceState *dev);
amitshah 99a9ef
+VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
amitshah 99a9ef
 VirtIODevice *virtio_balloon_init(DeviceState *dev);
amitshah 99a9ef
 
amitshah 99a9ef
 void virtio_net_exit(VirtIODevice *vdev);
amitshah 99a9ef
diff --git a/qemu-options.hx b/qemu-options.hx
amitshah 99a9ef
index ca73ba5..173b1ec 100644
amitshah 99a9ef
--- a/qemu-options.hx
amitshah 99a9ef
+++ b/qemu-options.hx
amitshah 99a9ef
@@ -1874,6 +1874,10 @@ DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \
amitshah 99a9ef
 STEXI
amitshah 99a9ef
 @item -virtioconsole @var{c}
amitshah 99a9ef
 Set virtio console.
amitshah 99a9ef
+
amitshah 99a9ef
+This option is maintained for backward compatibility.
amitshah 99a9ef
+
amitshah 99a9ef
+Please use @code{-device virtconsole} for the new way of invocation.
amitshah 99a9ef
 ETEXI
amitshah 99a9ef
 
amitshah 99a9ef
 DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \
amitshah 99a9ef
diff --git a/sysemu.h b/sysemu.h
amitshah 99a9ef
index a545a2b..ff97786 100644
amitshah 99a9ef
--- a/sysemu.h
amitshah 99a9ef
+++ b/sysemu.h
amitshah 99a9ef
@@ -237,12 +237,6 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
amitshah 99a9ef
 
amitshah 99a9ef
 extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
amitshah 99a9ef
 
amitshah 99a9ef
-/* virtio consoles */
amitshah 99a9ef
-
amitshah 99a9ef
-#define MAX_VIRTIO_CONSOLES 1
amitshah 99a9ef
-
amitshah 99a9ef
-extern CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
amitshah 99a9ef
-
amitshah 99a9ef
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
amitshah 99a9ef
 
amitshah 99a9ef
 #ifdef HAS_AUDIO
amitshah 99a9ef
diff --git a/vl.c b/vl.c
amitshah 99a9ef
index c9d46de..a479ef3 100644
amitshah 99a9ef
--- a/vl.c
amitshah 99a9ef
+++ b/vl.c
amitshah 99a9ef
@@ -175,6 +175,8 @@ int main(int argc, char **argv)
amitshah 99a9ef
 
amitshah 99a9ef
 #define DEFAULT_RAM_SIZE 128
amitshah 99a9ef
 
amitshah 99a9ef
+#define MAX_VIRTIO_CONSOLES 1
amitshah 99a9ef
+
amitshah 99a9ef
 static const char *data_dir;
amitshah 99a9ef
 const char *bios_name = NULL;
amitshah 99a9ef
 /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
amitshah 99a9ef
@@ -300,8 +302,9 @@ static struct {
amitshah 99a9ef
     { .driver = "isa-parallel",         .flag = &default_parallel  },
amitshah 99a9ef
     { .driver = "isa-fdc",              .flag = &default_floppy    },
amitshah 99a9ef
     { .driver = "ide-drive",            .flag = &default_cdrom     },
amitshah 99a9ef
-    { .driver = "virtio-console-pci",   .flag = &default_virtcon   },
amitshah 99a9ef
-    { .driver = "virtio-console-s390",  .flag = &default_virtcon   },
amitshah 99a9ef
+    { .driver = "virtio-serial-pci",    .flag = &default_virtcon   },
amitshah 99a9ef
+    { .driver = "virtio-serial-s390",   .flag = &default_virtcon   },
amitshah 99a9ef
+    { .driver = "virtio-serial",        .flag = &default_virtcon   },
amitshah 99a9ef
     { .driver = "VGA",                  .flag = &default_vga       },
amitshah 99a9ef
     { .driver = "cirrus-vga",           .flag = &default_vga       },
amitshah 99a9ef
     { .driver = "vmware-svga",          .flag = &default_vga       },
amitshah 99a9ef
@@ -4885,6 +4888,7 @@ static int virtcon_parse(const char *devname)
amitshah 99a9ef
 {
amitshah 99a9ef
     static int index = 0;
amitshah 99a9ef
     char label[32];
amitshah 99a9ef
+    QemuOpts *bus_opts, *dev_opts;
amitshah 99a9ef
 
amitshah 99a9ef
     if (strcmp(devname, "none") == 0)
amitshah 99a9ef
         return 0;
amitshah 99a9ef
@@ -4892,6 +4896,13 @@ static int virtcon_parse(const char *devname)
amitshah 99a9ef
         fprintf(stderr, "qemu: too many virtio consoles\n");
amitshah 99a9ef
         exit(1);
amitshah 99a9ef
     }
amitshah 99a9ef
+
amitshah 99a9ef
+    bus_opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
amitshah 99a9ef
+    qemu_opt_set(bus_opts, "driver", "virtio-serial");
amitshah 99a9ef
+
amitshah 99a9ef
+    dev_opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
amitshah 99a9ef
+    qemu_opt_set(dev_opts, "driver", "virtconsole");
amitshah 99a9ef
+
amitshah 99a9ef
     snprintf(label, sizeof(label), "virtcon%d", index);
amitshah 99a9ef
     virtcon_hds[index] = qemu_chr_open(label, devname, NULL);
amitshah 99a9ef
     if (!virtcon_hds[index]) {
amitshah 99a9ef
@@ -4899,6 +4910,8 @@ static int virtcon_parse(const char *devname)
amitshah 99a9ef
                 devname, strerror(errno));
amitshah 99a9ef
         return -1;
amitshah 99a9ef
     }
amitshah 99a9ef
+    qemu_opt_set(dev_opts, "chardev", label);
amitshah 99a9ef
+
amitshah 99a9ef
     index++;
amitshah 99a9ef
     return 0;
amitshah 99a9ef
 }
amitshah 99a9ef
-- 
amitshah 99a9ef
1.6.2.5
amitshah 99a9ef