diff --git a/qemu-Move-virtio-serial-to-Makefile.objs.patch b/qemu-Move-virtio-serial-to-Makefile.objs.patch
new file mode 100644
index 0000000..fd62df4
--- /dev/null
+++ b/qemu-Move-virtio-serial-to-Makefile.objs.patch
@@ -0,0 +1,44 @@
+From 12a074387284fc530876ef709b3d344adea9b226 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:57 +0530
+Subject: [PATCH 7/9] Move virtio-serial to Makefile.objs
+
+There's nothing target-dependent in the virtio-serial code so allow it
+to be compiled just once for all the targets.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ Makefile.hw     |    2 +-
+ Makefile.target |    2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/Makefile.hw b/Makefile.hw
+index 6f4dbc4..de8a0c5 100644
+--- a/Makefile.hw
++++ b/Makefile.hw
+@@ -13,7 +13,7 @@ QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
+ 
+ obj-y =
+ obj-y += loader.o
+-obj-y += virtio.o
++obj-y += virtio.o virtio-serial.o
+ obj-y += fw_cfg.o
+ obj-y += watchdog.o
+ obj-$(CONFIG_ECC) += ecc.o
+diff --git a/Makefile.target b/Makefile.target
+index 234577c..0e4cfd1 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -166,7 +166,7 @@ ifdef CONFIG_SOFTMMU
+ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
+ # virtio has to be here due to weird dependency between PCI and virtio-net.
+ # need to fix this properly
+-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial.o virtio-serial-bus.o virtio-pci.o
++obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-pci.o virtio-serial-bus.o
+ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
+ # MSI-X depends on kvm for interrupt injection,
+ # so moved it from Makefile.hw to Makefile.target for now
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-Remove-duplicate-macro-definition-for-max.-v.patch b/qemu-virtio-Remove-duplicate-macro-definition-for-max.-v.patch
new file mode 100644
index 0000000..e5fa7e7
--- /dev/null
+++ b/qemu-virtio-Remove-duplicate-macro-definition-for-max.-v.patch
@@ -0,0 +1,47 @@
+From c11631e8bc91a1d1be2b89196e886a1385820dfb Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:51 +0530
+Subject: [PATCH 1/9] virtio: Remove duplicate macro definition for max. virtqueues, bump up the max
+
+VIRTIO_PCI_QUEUE_MAX is redefined in hw/virtio.c. Let's just keep it in
+hw/virtio.h.
+
+Also, bump up the value of the maximum allowed virtqueues to 64. This is
+in preparation to allow multiple ports per virtio-console device.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio.c |    2 --
+ hw/virtio.h |    2 +-
+ 2 files changed, 1 insertions(+), 3 deletions(-)
+
+diff --git a/hw/virtio.c b/hw/virtio.c
+index cecd0dc..88f4e78 100644
+--- a/hw/virtio.c
++++ b/hw/virtio.c
+@@ -75,8 +75,6 @@ struct VirtQueue
+     void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
+ };
+ 
+-#define VIRTIO_PCI_QUEUE_MAX        16
+-
+ /* virt queue functions */
+ static void virtqueue_init(VirtQueue *vq)
+ {
+diff --git a/hw/virtio.h b/hw/virtio.h
+index 35532a6..051910a 100644
+--- a/hw/virtio.h
++++ b/hw/virtio.h
+@@ -90,7 +90,7 @@ typedef struct {
+     unsigned (*get_features)(void * opaque);
+ } VirtIOBindings;
+ 
+-#define VIRTIO_PCI_QUEUE_MAX 16
++#define VIRTIO_PCI_QUEUE_MAX 64
+ 
+ #define VIRTIO_NO_VECTOR 0xffff
+ 
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-console-Rename-virtio-serial.c-back-to-virti.patch b/qemu-virtio-console-Rename-virtio-serial.c-back-to-virti.patch
new file mode 100644
index 0000000..a0a6af4
--- /dev/null
+++ b/qemu-virtio-console-Rename-virtio-serial.c-back-to-virti.patch
@@ -0,0 +1,341 @@
+From 9c7f6b094950f7772068b957c795d76463cdeba0 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Thu, 21 Jan 2010 15:43:26 +0530
+Subject: [PATCH 9/9] virtio-console: Rename virtio-serial.c back to virtio-console.c
+
+This file was renamed to ease the reviews of the recent changes
+that went in.
+
+Now that the changes are done, rename the file back to its original
+name.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ Makefile.hw         |    2 +-
+ hw/virtio-console.c |  146 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ hw/virtio-serial.c  |  146 ---------------------------------------------------
+ 3 files changed, 147 insertions(+), 147 deletions(-)
+ create mode 100644 hw/virtio-console.c
+ delete mode 100644 hw/virtio-serial.c
+
+diff --git a/Makefile.hw b/Makefile.hw
+index de8a0c5..43ca541 100644
+--- a/Makefile.hw
++++ b/Makefile.hw
+@@ -13,7 +13,7 @@ QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
+ 
+ obj-y =
+ obj-y += loader.o
+-obj-y += virtio.o virtio-serial.o
++obj-y += virtio.o virtio-console.o
+ obj-y += fw_cfg.o
+ obj-y += watchdog.o
+ obj-$(CONFIG_ECC) += ecc.o
+diff --git a/hw/virtio-console.c b/hw/virtio-console.c
+new file mode 100644
+index 0000000..bd44ec6
+--- /dev/null
++++ b/hw/virtio-console.c
+@@ -0,0 +1,146 @@
++/*
++ * Virtio Console and Generic Serial Port Devices
++ *
++ * Copyright Red Hat, Inc. 2009
++ *
++ * Authors:
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ */
++
++#include "qemu-char.h"
++#include "virtio-serial.h"
++
++typedef struct VirtConsole {
++    VirtIOSerialPort port;
++    CharDriverState *chr;
++} VirtConsole;
++
++
++/* Callback function that's called when the guest sends us data */
++static size_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
++{
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++    ssize_t ret;
++
++    ret = qemu_chr_write(vcon->chr, buf, len);
++
++    return ret < 0 ? 0 : ret;
++}
++
++/* Readiness of the guest to accept data on a port */
++static int chr_can_read(void *opaque)
++{
++    VirtConsole *vcon = opaque;
++
++    return virtio_serial_guest_ready(&vcon->port);
++}
++
++/* Send data from a char device over to the guest */
++static void chr_read(void *opaque, const uint8_t *buf, int size)
++{
++    VirtConsole *vcon = opaque;
++
++    virtio_serial_write(&vcon->port, buf, size);
++}
++
++static void chr_event(void *opaque, int event)
++{
++    VirtConsole *vcon = opaque;
++
++    switch (event) {
++    case CHR_EVENT_OPENED: {
++        virtio_serial_open(&vcon->port);
++        break;
++    }
++    case CHR_EVENT_CLOSED:
++        virtio_serial_close(&vcon->port);
++        break;
++    }
++}
++
++/* Virtio Console Ports */
++static int virtconsole_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    port->info = dev->info;
++
++    port->is_console = true;
++
++    if (vcon->chr) {
++        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
++                              vcon);
++        port->info->have_data = flush_buf;
++    }
++    return 0;
++}
++
++static int virtconsole_exitfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    if (vcon->chr) {
++        port->info->have_data = NULL;
++        qemu_chr_close(vcon->chr);
++    }
++
++    return 0;
++}
++
++static VirtIOSerialPortInfo virtconsole_info = {
++    .qdev.name     = "virtconsole",
++    .qdev.size     = sizeof(VirtConsole),
++    .init          = virtconsole_initfn,
++    .exit          = virtconsole_exitfn,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
++        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
++        DEFINE_PROP_STRING("name", VirtConsole, port.name),
++        DEFINE_PROP_END_OF_LIST(),
++    },
++};
++
++static void virtconsole_register(void)
++{
++    virtio_serial_port_qdev_register(&virtconsole_info);
++}
++device_init(virtconsole_register)
++
++/* Generic Virtio Serial Ports */
++static int virtserialport_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    port->info = dev->info;
++
++    if (vcon->chr) {
++        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
++                              vcon);
++        port->info->have_data = flush_buf;
++    }
++    return 0;
++}
++
++static VirtIOSerialPortInfo virtserialport_info = {
++    .qdev.name     = "virtserialport",
++    .qdev.size     = sizeof(VirtConsole),
++    .init          = virtserialport_initfn,
++    .exit          = virtconsole_exitfn,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
++        DEFINE_PROP_STRING("name", VirtConsole, port.name),
++        DEFINE_PROP_END_OF_LIST(),
++    },
++};
++
++static void virtserialport_register(void)
++{
++    virtio_serial_port_qdev_register(&virtserialport_info);
++}
++device_init(virtserialport_register)
+diff --git a/hw/virtio-serial.c b/hw/virtio-serial.c
+deleted file mode 100644
+index bd44ec6..0000000
+--- a/hw/virtio-serial.c
++++ /dev/null
+@@ -1,146 +0,0 @@
+-/*
+- * Virtio Console and Generic Serial Port Devices
+- *
+- * Copyright Red Hat, Inc. 2009
+- *
+- * Authors:
+- *  Amit Shah <amit.shah@redhat.com>
+- *
+- * This work is licensed under the terms of the GNU GPL, version 2.  See
+- * the COPYING file in the top-level directory.
+- */
+-
+-#include "qemu-char.h"
+-#include "virtio-serial.h"
+-
+-typedef struct VirtConsole {
+-    VirtIOSerialPort port;
+-    CharDriverState *chr;
+-} VirtConsole;
+-
+-
+-/* Callback function that's called when the guest sends us data */
+-static size_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+-{
+-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+-    ssize_t ret;
+-
+-    ret = qemu_chr_write(vcon->chr, buf, len);
+-
+-    return ret < 0 ? 0 : ret;
+-}
+-
+-/* Readiness of the guest to accept data on a port */
+-static int chr_can_read(void *opaque)
+-{
+-    VirtConsole *vcon = opaque;
+-
+-    return virtio_serial_guest_ready(&vcon->port);
+-}
+-
+-/* Send data from a char device over to the guest */
+-static void chr_read(void *opaque, const uint8_t *buf, int size)
+-{
+-    VirtConsole *vcon = opaque;
+-
+-    virtio_serial_write(&vcon->port, buf, size);
+-}
+-
+-static void chr_event(void *opaque, int event)
+-{
+-    VirtConsole *vcon = opaque;
+-
+-    switch (event) {
+-    case CHR_EVENT_OPENED: {
+-        virtio_serial_open(&vcon->port);
+-        break;
+-    }
+-    case CHR_EVENT_CLOSED:
+-        virtio_serial_close(&vcon->port);
+-        break;
+-    }
+-}
+-
+-/* Virtio Console Ports */
+-static int virtconsole_initfn(VirtIOSerialDevice *dev)
+-{
+-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+-
+-    port->info = dev->info;
+-
+-    port->is_console = true;
+-
+-    if (vcon->chr) {
+-        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
+-                              vcon);
+-        port->info->have_data = flush_buf;
+-    }
+-    return 0;
+-}
+-
+-static int virtconsole_exitfn(VirtIOSerialDevice *dev)
+-{
+-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+-
+-    if (vcon->chr) {
+-        port->info->have_data = NULL;
+-        qemu_chr_close(vcon->chr);
+-    }
+-
+-    return 0;
+-}
+-
+-static VirtIOSerialPortInfo virtconsole_info = {
+-    .qdev.name     = "virtconsole",
+-    .qdev.size     = sizeof(VirtConsole),
+-    .init          = virtconsole_initfn,
+-    .exit          = virtconsole_exitfn,
+-    .qdev.props = (Property[]) {
+-        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
+-        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+-        DEFINE_PROP_STRING("name", VirtConsole, port.name),
+-        DEFINE_PROP_END_OF_LIST(),
+-    },
+-};
+-
+-static void virtconsole_register(void)
+-{
+-    virtio_serial_port_qdev_register(&virtconsole_info);
+-}
+-device_init(virtconsole_register)
+-
+-/* Generic Virtio Serial Ports */
+-static int virtserialport_initfn(VirtIOSerialDevice *dev)
+-{
+-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+-
+-    port->info = dev->info;
+-
+-    if (vcon->chr) {
+-        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
+-                              vcon);
+-        port->info->have_data = flush_buf;
+-    }
+-    return 0;
+-}
+-
+-static VirtIOSerialPortInfo virtserialport_info = {
+-    .qdev.name     = "virtserialport",
+-    .qdev.size     = sizeof(VirtConsole),
+-    .init          = virtserialport_initfn,
+-    .exit          = virtconsole_exitfn,
+-    .qdev.props = (Property[]) {
+-        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+-        DEFINE_PROP_STRING("name", VirtConsole, port.name),
+-        DEFINE_PROP_END_OF_LIST(),
+-    },
+-};
+-
+-static void virtserialport_register(void)
+-{
+-    virtio_serial_port_qdev_register(&virtserialport_info);
+-}
+-device_init(virtserialport_register)
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-console-qdev-conversion-new-virtio-serial-b.patch b/qemu-virtio-console-qdev-conversion-new-virtio-serial-b.patch
new file mode 100644
index 0000000..950647b
--- /dev/null
+++ b/qemu-virtio-console-qdev-conversion-new-virtio-serial-b.patch
@@ -0,0 +1,1366 @@
+From 76c8fc3a48dcaf6161d7cb68976db99aaf97efdd Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:52 +0530
+Subject: [PATCH 2/9] virtio-console: qdev conversion, new virtio-serial-bus
+
+This commit converts the virtio-console device to create a new
+virtio-serial bus that can host console and generic serial ports. The
+file hosting this code is now called virtio-serial-bus.c.
+
+The virtio console is now a very simple qdev device that sits on the
+virtio-serial-bus and communicates between the bus and qemu's chardevs.
+
+This commit also includes a few changes to the virtio backing code for
+pci and s390 to spawn the virtio-serial bus.
+
+As a result of the qdev conversion, we get rid of a lot of legacy code.
+The old-style way of instantiating a virtio console using
+
+    -virtioconsole ...
+
+is maintained, but the new, preferred way is to use
+
+    -device virtio-serial -device virtconsole,chardev=...
+
+With this commit, multiple devices as well as multiple ports with a
+single device can be supported.
+
+For multiple ports support, each port gets an IO vq pair. Since the
+guest needs to know in advance how many vqs a particular device will
+need, we have to set this number as a property of the virtio-serial
+device and also as a config option.
+
+In addition, we also spawn a pair of control IO vqs. This is an internal
+channel meant for guest-host communication for things like port
+open/close, sending port properties over to the guest, etc.
+
+This commit is a part of a series of other commits to get the full
+implementation of multiport support. Future commits will add other
+support as well as ride on the savevm version that we bump up here.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ Makefile.target        |    2 +-
+ hw/pc.c                |   11 +-
+ hw/ppc440_bamboo.c     |    7 -
+ hw/qdev.c              |   10 +-
+ hw/s390-virtio-bus.c   |   17 +-
+ hw/s390-virtio-bus.h   |    2 +
+ hw/s390-virtio.c       |    8 -
+ hw/virtio-console.c    |  146 --------------
+ hw/virtio-console.h    |   19 --
+ hw/virtio-pci.c        |   13 +-
+ hw/virtio-serial-bus.c |  504 ++++++++++++++++++++++++++++++++++++++++++++++++
+ hw/virtio-serial.c     |  111 +++++++++++
+ hw/virtio-serial.h     |  158 +++++++++++++++
+ hw/virtio.h            |    2 +-
+ qemu-options.hx        |    4 +
+ sysemu.h               |    6 -
+ vl.c                   |   17 ++-
+ 17 files changed, 819 insertions(+), 218 deletions(-)
+ delete mode 100644 hw/virtio-console.c
+ delete mode 100644 hw/virtio-console.h
+ create mode 100644 hw/virtio-serial-bus.c
+ create mode 100644 hw/virtio-serial.c
+ create mode 100644 hw/virtio-serial.h
+
+diff --git a/Makefile.target b/Makefile.target
+index 6037fed..234577c 100644
+--- a/Makefile.target
++++ b/Makefile.target
+@@ -166,7 +166,7 @@ ifdef CONFIG_SOFTMMU
+ obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
+ # virtio has to be here due to weird dependency between PCI and virtio-net.
+ # need to fix this properly
+-obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
++obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial.o virtio-serial-bus.o virtio-pci.o
+ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
+ # MSI-X depends on kvm for interrupt injection,
+ # so moved it from Makefile.hw to Makefile.target for now
+diff --git a/hw/pc.c b/hw/pc.c
+index 78a07c2..acbfeba 100644
+--- a/hw/pc.c
++++ b/hw/pc.c
+@@ -1284,15 +1284,6 @@ static void pc_init1(ram_addr_t ram_size,
+ 	extboot_init(info->bdrv, 1);
+     }
+ 
+-    /* Add virtio console devices */
+-    if (pci_enabled) {
+-        for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+-            if (virtcon_hds[i]) {
+-                pci_create_simple(pci_bus, -1, "virtio-console-pci");
+-            }
+-        }
+-    }
+-
+ #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
+     if (kvm_enabled()) {
+         add_assigned_devices(pci_bus, assigned_devices, assigned_devices_index);
+@@ -1373,7 +1364,7 @@ static QEMUMachine pc_machine_v0_10 = {
+             .property = "class",
+             .value    = stringify(PCI_CLASS_STORAGE_OTHER),
+         },{
+-            .driver   = "virtio-console-pci",
++            .driver   = "virtio-serial-pci",
+             .property = "class",
+             .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
+         },{
+diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
+index 25417e3..c94c961 100644
+--- a/hw/ppc440_bamboo.c
++++ b/hw/ppc440_bamboo.c
+@@ -109,13 +109,6 @@ static void bamboo_init(ram_addr_t ram_size,
+     env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1, cpu_model);
+ 
+     if (pcibus) {
+-        /* Add virtio console devices */
+-        for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+-            if (virtcon_hds[i]) {
+-                pci_create_simple(pcibus, -1, "virtio-console-pci");
+-            }
+-        }
+-
+         /* Register network interfaces. */
+         for (i = 0; i < nb_nics; i++) {
+             /* There are no PCI NICs on the Bamboo board, but there are
+diff --git a/hw/qdev.c b/hw/qdev.c
+index b6bd4ae..c643576 100644
+--- a/hw/qdev.c
++++ b/hw/qdev.c
+@@ -321,13 +321,9 @@ void qdev_machine_creation_done(void)
+ CharDriverState *qdev_init_chardev(DeviceState *dev)
+ {
+     static int next_serial;
+-    static int next_virtconsole;
+-    /* FIXME: This is a nasty hack that needs to go away.  */
+-    if (strncmp(dev->info->name, "virtio", 6) == 0) {
+-        return virtcon_hds[next_virtconsole++];
+-    } else {
+-        return serial_hds[next_serial++];
+-    }
++
++    /* FIXME: This function needs to go away: use chardev properties!  */
++    return serial_hds[next_serial++];
+ }
+ 
+ BusState *qdev_get_parent_bus(DeviceState *dev)
+diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
+index dc154ed..95c516a 100644
+--- a/hw/s390-virtio-bus.c
++++ b/hw/s390-virtio-bus.c
+@@ -26,7 +26,7 @@
+ #include "loader.h"
+ #include "elf.h"
+ #include "hw/virtio.h"
+-#include "hw/virtio-console.h"
++#include "hw/virtio-serial.h"
+ #include "hw/sysbus.h"
+ #include "kvm.h"
+ 
+@@ -130,7 +130,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
+     return s390_virtio_device_init(dev, vdev);
+ }
+ 
+-static int s390_virtio_console_init(VirtIOS390Device *dev)
++static int s390_virtio_serial_init(VirtIOS390Device *dev)
+ {
+     VirtIOS390Bus *bus;
+     VirtIODevice *vdev;
+@@ -138,7 +138,7 @@ static int s390_virtio_console_init(VirtIOS390Device *dev)
+ 
+     bus = DO_UPCAST(VirtIOS390Bus, bus, dev->qdev.parent_bus);
+ 
+-    vdev = virtio_console_init((DeviceState *)dev);
++    vdev = virtio_serial_init((DeviceState *)dev, dev->max_virtserial_ports);
+     if (!vdev) {
+         return -1;
+     }
+@@ -336,11 +336,14 @@ static VirtIOS390DeviceInfo s390_virtio_blk = {
+     },
+ };
+ 
+-static VirtIOS390DeviceInfo s390_virtio_console = {
+-    .init = s390_virtio_console_init,
+-    .qdev.name = "virtio-console-s390",
++static VirtIOS390DeviceInfo s390_virtio_serial = {
++    .init = s390_virtio_serial_init,
++    .qdev.name = "virtio-serial-s390",
++    .qdev.alias = "virtio-serial",
+     .qdev.size = sizeof(VirtIOS390Device),
+     .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, max_virtserial_ports,
++                           31),
+         DEFINE_PROP_END_OF_LIST(),
+     },
+ };
+@@ -364,7 +367,7 @@ static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
+ 
+ static void s390_virtio_register(void)
+ {
+-    s390_virtio_bus_register_withprop(&s390_virtio_console);
++    s390_virtio_bus_register_withprop(&s390_virtio_serial);
+     s390_virtio_bus_register_withprop(&s390_virtio_blk);
+     s390_virtio_bus_register_withprop(&s390_virtio_net);
+ }
+diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
+index ef36714..ad85ed3 100644
+--- a/hw/s390-virtio-bus.h
++++ b/hw/s390-virtio-bus.h
+@@ -40,6 +40,8 @@ typedef struct VirtIOS390Device {
+     VirtIODevice *vdev;
+     DriveInfo *dinfo;
+     NICConf nic;
++    /* Max. number of ports we can have for a the virtio-serial device */
++    uint32_t max_virtserial_ports;
+ } VirtIOS390Device;
+ 
+ typedef struct VirtIOS390Bus {
+diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
+index 0fa6ba6..3582728 100644
+--- a/hw/s390-virtio.c
++++ b/hw/s390-virtio.c
+@@ -26,7 +26,6 @@
+ #include "loader.h"
+ #include "elf.h"
+ #include "hw/virtio.h"
+-#include "hw/virtio-console.h"
+ #include "hw/sysbus.h"
+ #include "kvm.h"
+ 
+@@ -207,13 +206,6 @@ static void s390_init(ram_addr_t ram_size,
+                                strlen(kernel_cmdline), 1);
+     }
+ 
+-    /* Create VirtIO console */
+-    for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+-        if (virtcon_hds[i]) {
+-            qdev_init_nofail(qdev_create((BusState *)s390_bus, "virtio-console-s390"));
+-        }
+-    }
+-
+     /* Create VirtIO network adapters */
+     for(i = 0; i < nb_nics; i++) {
+         NICInfo *nd = &nd_table[i];
+diff --git a/hw/virtio-console.c b/hw/virtio-console.c
+deleted file mode 100644
+index 92c953c..0000000
+--- a/hw/virtio-console.c
++++ /dev/null
+@@ -1,146 +0,0 @@
+-/*
+- * Virtio Console Device
+- *
+- * Copyright IBM, Corp. 2008
+- *
+- * Authors:
+- *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+- *
+- * This work is licensed under the terms of the GNU GPL, version 2.  See
+- * the COPYING file in the top-level directory.
+- *
+- */
+-
+-#include "hw.h"
+-#include "qemu-char.h"
+-#include "virtio.h"
+-#include "virtio-console.h"
+-
+-
+-typedef struct VirtIOConsole
+-{
+-    VirtIODevice vdev;
+-    VirtQueue *ivq, *ovq;
+-    CharDriverState *chr;
+-} VirtIOConsole;
+-
+-static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
+-{
+-    return (VirtIOConsole *)vdev;
+-}
+-
+-static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+-{
+-    VirtIOConsole *s = to_virtio_console(vdev);
+-    VirtQueueElement elem;
+-
+-    while (virtqueue_pop(vq, &elem)) {
+-        ssize_t len = 0;
+-        int d;
+-
+-        for (d = 0; d < elem.out_num; d++) {
+-            len += qemu_chr_write(s->chr, (uint8_t *)elem.out_sg[d].iov_base,
+-                                  elem.out_sg[d].iov_len);
+-        }
+-        virtqueue_push(vq, &elem, len);
+-        virtio_notify(vdev, vq);
+-    }
+-}
+-
+-static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
+-{
+-}
+-
+-static uint32_t virtio_console_get_features(VirtIODevice *vdev)
+-{
+-    return 0;
+-}
+-
+-static int vcon_can_read(void *opaque)
+-{
+-    VirtIOConsole *s = (VirtIOConsole *) opaque;
+-
+-    if (!virtio_queue_ready(s->ivq) ||
+-        !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
+-        virtio_queue_empty(s->ivq))
+-        return 0;
+-
+-    /* current implementations have a page sized buffer.
+-     * We fall back to a one byte per read if there is not enough room.
+-     * It would be cool to have a function that returns the available byte
+-     * instead of checking for a limit */
+-    if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
+-        return TARGET_PAGE_SIZE;
+-    if (virtqueue_avail_bytes(s->ivq, 1, 0))
+-        return 1;
+-    return 0;
+-}
+-
+-static void vcon_read(void *opaque, const uint8_t *buf, int size)
+-{
+-    VirtIOConsole *s = (VirtIOConsole *) opaque;
+-    VirtQueueElement elem;
+-    int offset = 0;
+-
+-    /* The current kernel implementation has only one outstanding input
+-     * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
+-     * handle multiple buffers with multiple sg element for input */
+-    while (offset < size) {
+-        int i = 0;
+-        if (!virtqueue_pop(s->ivq, &elem))
+-                break;
+-        while (offset < size && i < elem.in_num) {
+-            int len = MIN(elem.in_sg[i].iov_len, size - offset);
+-            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
+-            offset += len;
+-            i++;
+-        }
+-        virtqueue_push(s->ivq, &elem, size);
+-    }
+-    virtio_notify(&s->vdev, s->ivq);
+-}
+-
+-static void vcon_event(void *opaque, int event)
+-{
+-    /* we will ignore any event for the time being */
+-}
+-
+-static void virtio_console_save(QEMUFile *f, void *opaque)
+-{
+-    VirtIOConsole *s = opaque;
+-
+-    virtio_save(&s->vdev, f);
+-}
+-
+-static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
+-{
+-    VirtIOConsole *s = opaque;
+-
+-    if (version_id != 1)
+-        return -EINVAL;
+-
+-    virtio_load(&s->vdev, f);
+-    return 0;
+-}
+-
+-VirtIODevice *virtio_console_init(DeviceState *dev)
+-{
+-    VirtIOConsole *s;
+-    s = (VirtIOConsole *)virtio_common_init("virtio-console",
+-                                            VIRTIO_ID_CONSOLE,
+-                                            0, sizeof(VirtIOConsole));
+-    if (s == NULL)
+-        return NULL;
+-
+-    s->vdev.get_features = virtio_console_get_features;
+-
+-    s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
+-    s->ovq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
+-
+-    s->chr = qdev_init_chardev(dev);
+-    qemu_chr_add_handlers(s->chr, vcon_can_read, vcon_read, vcon_event, s);
+-
+-    register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
+-
+-    return &s->vdev;
+-}
+diff --git a/hw/virtio-console.h b/hw/virtio-console.h
+deleted file mode 100644
+index 84d0717..0000000
+--- a/hw/virtio-console.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/*
+- * Virtio Console Support
+- *
+- * Copyright IBM, Corp. 2008
+- *
+- * Authors:
+- *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+- *
+- * This work is licensed under the terms of the GNU GPL, version 2.  See
+- * the COPYING file in the top-level directory.
+- *
+- */
+-#ifndef _QEMU_VIRTIO_CONSOLE_H
+-#define _QEMU_VIRTIO_CONSOLE_H
+-
+-/* The ID for virtio console */
+-#define VIRTIO_ID_CONSOLE 3
+-
+-#endif
+diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
+index 3594152..c1a1e4c 100644
+--- a/hw/virtio-pci.c
++++ b/hw/virtio-pci.c
+@@ -92,6 +92,8 @@ typedef struct {
+     uint32_t nvectors;
+     DriveInfo *dinfo;
+     NICConf nic;
++    /* Max. number of ports we can have for a the virtio-serial device */
++    uint32_t max_virtserial_ports;
+ } VirtIOPCIProxy;
+ 
+ /* virtio device */
+@@ -481,7 +483,7 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
+     return virtio_exit_pci(pci_dev);
+ }
+ 
+-static int virtio_console_init_pci(PCIDevice *pci_dev)
++static int virtio_serial_init_pci(PCIDevice *pci_dev)
+ {
+     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+     VirtIODevice *vdev;
+@@ -491,7 +493,7 @@ static int virtio_console_init_pci(PCIDevice *pci_dev)
+         proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
+         proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
+ 
+-    vdev = virtio_console_init(&pci_dev->qdev);
++    vdev = virtio_serial_init(&pci_dev->qdev, proxy->max_virtserial_ports);
+     if (!vdev) {
+         return -1;
+     }
+@@ -569,12 +571,15 @@ static PCIDeviceInfo virtio_info[] = {
+         },
+         .qdev.reset = virtio_pci_reset,
+     },{
+-        .qdev.name = "virtio-console-pci",
++        .qdev.name = "virtio-serial-pci",
++        .qdev.alias = "virtio-serial",
+         .qdev.size = sizeof(VirtIOPCIProxy),
+-        .init      = virtio_console_init_pci,
++        .init      = virtio_serial_init_pci,
+         .exit      = virtio_exit_pci,
+         .qdev.props = (Property[]) {
+             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
++            DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
++                               31),
+             DEFINE_PROP_END_OF_LIST(),
+         },
+         .qdev.reset = virtio_pci_reset,
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+new file mode 100644
+index 0000000..5132c9c
+--- /dev/null
++++ b/hw/virtio-serial-bus.c
+@@ -0,0 +1,504 @@
++/*
++ * A bus for connecting virtio serial and console ports
++ *
++ * Copyright (C) 2009 Red Hat, Inc.
++ *
++ * Author(s):
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * Some earlier parts are:
++ *  Copyright IBM, Corp. 2008
++ * authored by
++ *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ */
++
++#include "monitor.h"
++#include "qemu-queue.h"
++#include "sysbus.h"
++#include "virtio-serial.h"
++
++/* The virtio-serial bus on top of which the ports will ride as devices */
++struct VirtIOSerialBus {
++    BusState qbus;
++
++    /* This is the parent device that provides the bus for ports. */
++    VirtIOSerial *vser;
++
++    /* The maximum number of ports that can ride on top of this bus */
++    uint32_t max_nr_ports;
++};
++
++struct VirtIOSerial {
++    VirtIODevice vdev;
++
++    VirtQueue *c_ivq, *c_ovq;
++    /* Arrays of ivqs and ovqs: one per port */
++    VirtQueue **ivqs, **ovqs;
++
++    VirtIOSerialBus *bus;
++
++    QTAILQ_HEAD(, VirtIOSerialPort) ports;
++    struct virtio_console_config config;
++};
++
++static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
++{
++    VirtIOSerialPort *port;
++
++    QTAILQ_FOREACH(port, &vser->ports, next) {
++        if (port->id == id)
++            return port;
++    }
++    return NULL;
++}
++
++static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
++{
++    VirtIOSerialPort *port;
++
++    QTAILQ_FOREACH(port, &vser->ports, next) {
++        if (port->ivq == vq || port->ovq == vq)
++            return port;
++    }
++    return NULL;
++}
++
++static size_t write_to_port(VirtIOSerialPort *port,
++                            const uint8_t *buf, size_t size)
++{
++    VirtQueueElement elem;
++    VirtQueue *vq;
++    size_t offset = 0;
++    size_t len = 0;
++
++    vq = port->ivq;
++    if (!virtio_queue_ready(vq)) {
++        return 0;
++    }
++    if (!size) {
++        return 0;
++    }
++
++    while (offset < size) {
++        int i;
++
++        if (!virtqueue_pop(vq, &elem)) {
++            break;
++        }
++
++        for (i = 0; offset < size && i < elem.in_num; i++) {
++            len = MIN(elem.in_sg[i].iov_len, size - offset);
++
++            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
++            offset += len;
++        }
++        virtqueue_push(vq, &elem, len);
++    }
++
++    virtio_notify(&port->vser->vdev, vq);
++    return offset;
++}
++
++static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
++{
++    VirtQueueElement elem;
++    VirtQueue *vq;
++    struct virtio_console_control *cpkt;
++
++    vq = port->vser->c_ivq;
++    if (!virtio_queue_ready(vq)) {
++        return 0;
++    }
++    if (!virtqueue_pop(vq, &elem)) {
++        return 0;
++    }
++
++    cpkt = (struct virtio_console_control *)buf;
++    stl_p(&cpkt->id, port->id);
++    memcpy(elem.in_sg[0].iov_base, buf, len);
++
++    virtqueue_push(vq, &elem, len);
++    virtio_notify(&port->vser->vdev, vq);
++    return len;
++}
++
++static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
++                                 uint16_t value)
++{
++    struct virtio_console_control cpkt;
++
++    stw_p(&cpkt.event, event);
++    stw_p(&cpkt.value, value);
++
++    return send_control_msg(port, &cpkt, sizeof(cpkt));
++}
++
++/* Functions for use inside qemu to open and read from/write to ports */
++int virtio_serial_open(VirtIOSerialPort *port)
++{
++    return 0;
++}
++
++int virtio_serial_close(VirtIOSerialPort *port)
++{
++    return 0;
++}
++
++/* Individual ports/apps call this function to write to the guest. */
++ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
++                            size_t size)
++{
++    return write_to_port(port, buf, size);
++}
++
++/*
++ * Readiness of the guest to accept data on a port.
++ * Returns max. data the guest can receive
++ */
++size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
++{
++    VirtQueue *vq = port->ivq;
++
++    if (!virtio_queue_ready(vq) ||
++        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
++        virtio_queue_empty(vq)) {
++        return 0;
++    }
++
++    if (virtqueue_avail_bytes(vq, 4096, 0)) {
++        return 4096;
++    }
++    if (virtqueue_avail_bytes(vq, 1, 0)) {
++        return 1;
++    }
++    return 0;
++}
++
++/* Guest wants to notify us of some event */
++static void handle_control_message(VirtIOSerial *vser, void *buf)
++{
++    struct VirtIOSerialPort *port;
++    struct virtio_console_control cpkt, *gcpkt;
++
++    gcpkt = buf;
++    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
++    if (!port)
++        return;
++
++    cpkt.event = lduw_p(&gcpkt->event);
++    cpkt.value = lduw_p(&gcpkt->value);
++
++    switch(cpkt.event) {
++    case VIRTIO_CONSOLE_PORT_READY:
++        /*
++         * Now that we know the guest asked for the port name, we're
++         * sure the guest has initialised whatever state is necessary
++         * for this port. Now's a good time to let the guest know if
++         * this port is a console port so that the guest can hook it
++         * up to hvc.
++         */
++        if (port->is_console) {
++            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
++        }
++        /*
++         * When the guest has asked us for this information it means
++         * the guest is all setup and has its virtqueues
++         * initialised. If some app is interested in knowing about
++         * this event, let it know.
++         */
++        if (port->info->guest_ready) {
++            port->info->guest_ready(port);
++        }
++        break;
++    }
++}
++
++static void control_in(VirtIODevice *vdev, VirtQueue *vq)
++{
++}
++
++static void control_out(VirtIODevice *vdev, VirtQueue *vq)
++{
++    VirtQueueElement elem;
++    VirtIOSerial *vser;
++
++    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++
++    while (virtqueue_pop(vq, &elem)) {
++        handle_control_message(vser, elem.out_sg[0].iov_base);
++        virtqueue_push(vq, &elem, elem.out_sg[0].iov_len);
++    }
++    virtio_notify(vdev, vq);
++}
++
++/* Guest wrote something to some port. */
++static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
++{
++    VirtIOSerial *vser;
++    VirtQueueElement elem;
++
++    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++
++    while (virtqueue_pop(vq, &elem)) {
++        VirtIOSerialPort *port;
++        size_t ret;
++
++        port = find_port_by_vq(vser, vq);
++        if (!port) {
++            ret = 0;
++            goto next_buf;
++        }
++
++        /*
++         * A port may not have any handler registered for consuming the
++         * data that the guest sends or it may not have a chardev associated
++         * with it. Just ignore the data in that case.
++         */
++        if (!port->info->have_data) {
++            ret = 0;
++            goto next_buf;
++        }
++
++        /* The guest always sends only one sg */
++        ret = port->info->have_data(port, elem.out_sg[0].iov_base,
++                                    elem.out_sg[0].iov_len);
++
++    next_buf:
++        virtqueue_push(vq, &elem, ret);
++    }
++    virtio_notify(vdev, vq);
++}
++
++static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
++{
++}
++
++static uint32_t get_features(VirtIODevice *vdev)
++{
++    return 1 << VIRTIO_CONSOLE_F_MULTIPORT;
++}
++
++/* Guest requested config info */
++static void get_config(VirtIODevice *vdev, uint8_t *config_data)
++{
++    VirtIOSerial *vser;
++
++    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
++}
++
++static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
++{
++    struct virtio_console_config config;
++
++    memcpy(&config, config_data, sizeof(config));
++}
++
++static void virtio_serial_save(QEMUFile *f, void *opaque)
++{
++    VirtIOSerial *s = opaque;
++
++    /* The virtio device */
++    virtio_save(&s->vdev, f);
++
++    /* The config space */
++    qemu_put_be16s(f, &s->config.cols);
++    qemu_put_be16s(f, &s->config.rows);
++    qemu_put_be32s(f, &s->config.nr_ports);
++}
++
++static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
++{
++    VirtIOSerial *s = opaque;
++
++    if (version_id > 2) {
++        return -EINVAL;
++    }
++    /* The virtio device */
++    virtio_load(&s->vdev, f);
++
++    if (version_id < 2) {
++        return 0;
++    }
++
++    /* The config space */
++    qemu_get_be16s(f, &s->config.cols);
++    qemu_get_be16s(f, &s->config.rows);
++    s->config.nr_ports = qemu_get_be32(f);
++
++    return 0;
++}
++
++static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
++
++static struct BusInfo virtser_bus_info = {
++    .name      = "virtio-serial-bus",
++    .size      = sizeof(VirtIOSerialBus),
++    .print_dev = virtser_bus_dev_print,
++};
++
++static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
++{
++    VirtIOSerialBus *bus;
++
++    bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
++    bus->qbus.allow_hotplug = 1;
++
++    return bus;
++}
++
++static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
++{
++    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++
++    monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
++                   indent, "", port->id);
++}
++
++static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
++{
++    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
++    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
++    int ret;
++    bool plugging_port0;
++
++    port->vser = bus->vser;
++
++    /*
++     * Is the first console port we're seeing? If so, put it up at
++     * location 0. This is done for backward compatibility (old
++     * kernel, new qemu).
++     */
++    plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
++
++    if (port->vser->config.nr_ports == bus->max_nr_ports && !plugging_port0) {
++        qemu_error("virtio-serial-bus: Maximum device limit reached\n");
++        return -1;
++    }
++    dev->info = info;
++
++    ret = info->init(dev);
++    if (ret) {
++        return ret;
++    }
++
++    port->id = plugging_port0 ? 0 : port->vser->config.nr_ports++;
++
++    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
++    port->ivq = port->vser->ivqs[port->id];
++    port->ovq = port->vser->ovqs[port->id];
++
++    /* Send an update to the guest about this new port added */
++    virtio_notify_config(&port->vser->vdev);
++
++    return ret;
++}
++
++static int virtser_port_qdev_exit(DeviceState *qdev)
++{
++    VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtIOSerial *vser = port->vser;
++
++    /*
++     * Don't decrement nr_ports here; thus we keep a linearly
++     * increasing port id. Not utilising an id again saves us a couple
++     * of complications:
++     *
++     * - Not having to bother about sending the port id to the guest
++     *   kernel on hotplug or on addition of new ports; the guest can
++     *   also linearly increment the port number. This is preferable
++     *   because the config space won't have the need to store a
++     *   ports_map.
++     *
++     * - Extra state to be stored for all the "holes" that got created
++     *   so that we keep filling in the ids from the least available
++     *   index.
++     *
++     * When such a functionality is desired, a control message to add
++     * a port can be introduced.
++     */
++    QTAILQ_REMOVE(&vser->ports, port, next);
++
++    if (port->info->exit)
++        port->info->exit(dev);
++
++    return 0;
++}
++
++void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
++{
++    info->qdev.init = virtser_port_qdev_init;
++    info->qdev.bus_info = &virtser_bus_info;
++    info->qdev.exit = virtser_port_qdev_exit;
++    info->qdev.unplug = qdev_simple_unplug_cb;
++    qdev_register(&info->qdev);
++}
++
++VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
++{
++    VirtIOSerial *vser;
++    VirtIODevice *vdev;
++    uint32_t i;
++
++    if (!max_nr_ports)
++        return NULL;
++
++    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
++                              sizeof(struct virtio_console_config),
++                              sizeof(VirtIOSerial));
++
++    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++
++    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
++    vser->bus = virtser_bus_new(dev);
++    vser->bus->vser = vser;
++    QTAILQ_INIT(&vser->ports);
++
++    vser->bus->max_nr_ports = max_nr_ports;
++    vser->ivqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
++    vser->ovqs = qemu_malloc(max_nr_ports * sizeof(VirtQueue *));
++
++    /* Add a queue for host to guest transfers for port 0 (backward compat) */
++    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
++    /* Add a queue for guest to host transfers for port 0 (backward compat) */
++    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
++
++    /* control queue: host to guest */
++    vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
++    /* control queue: guest to host */
++    vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
++
++    for (i = 1; i < vser->bus->max_nr_ports; i++) {
++        /* Add a per-port queue for host to guest transfers */
++        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
++        /* Add a per-per queue for guest to host transfers */
++        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
++    }
++
++    vser->config.max_nr_ports = max_nr_ports;
++    /*
++     * Reserve location 0 for a console port for backward compat
++     * (old kernel, new qemu)
++     */
++    vser->config.nr_ports = 1;
++
++    vser->vdev.get_features = get_features;
++    vser->vdev.get_config = get_config;
++    vser->vdev.set_config = set_config;
++
++    /*
++     * Register for the savevm section with the virtio-console name
++     * to preserve backward compat
++     */
++    register_savevm("virtio-console", -1, 2, virtio_serial_save,
++                    virtio_serial_load, vser);
++
++    return vdev;
++}
+diff --git a/hw/virtio-serial.c b/hw/virtio-serial.c
+new file mode 100644
+index 0000000..1dc031e
+--- /dev/null
++++ b/hw/virtio-serial.c
+@@ -0,0 +1,111 @@
++/*
++ * Virtio Console and Generic Serial Port Devices
++ *
++ * Copyright Red Hat, Inc. 2009
++ *
++ * Authors:
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ */
++
++#include "qemu-char.h"
++#include "virtio-serial.h"
++
++typedef struct VirtConsole {
++    VirtIOSerialPort port;
++    CharDriverState *chr;
++} VirtConsole;
++
++
++/* Callback function that's called when the guest sends us data */
++static size_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
++{
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++    ssize_t ret;
++
++    ret = qemu_chr_write(vcon->chr, buf, len);
++
++    return ret < 0 ? 0 : ret;
++}
++
++/* Readiness of the guest to accept data on a port */
++static int chr_can_read(void *opaque)
++{
++    VirtConsole *vcon = opaque;
++
++    return virtio_serial_guest_ready(&vcon->port);
++}
++
++/* Send data from a char device over to the guest */
++static void chr_read(void *opaque, const uint8_t *buf, int size)
++{
++    VirtConsole *vcon = opaque;
++
++    virtio_serial_write(&vcon->port, buf, size);
++}
++
++static void chr_event(void *opaque, int event)
++{
++    VirtConsole *vcon = opaque;
++
++    switch (event) {
++    case CHR_EVENT_OPENED: {
++        virtio_serial_open(&vcon->port);
++        break;
++    }
++    case CHR_EVENT_CLOSED:
++        virtio_serial_close(&vcon->port);
++        break;
++    }
++}
++
++/* Virtio Console Ports */
++static int virtconsole_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    port->info = dev->info;
++
++    port->is_console = true;
++
++    if (vcon->chr) {
++        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
++                              vcon);
++        port->info->have_data = flush_buf;
++    }
++    return 0;
++}
++
++static int virtconsole_exitfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    if (vcon->chr) {
++        port->info->have_data = NULL;
++        qemu_chr_close(vcon->chr);
++    }
++
++    return 0;
++}
++
++static VirtIOSerialPortInfo virtconsole_info = {
++    .qdev.name     = "virtconsole",
++    .qdev.size     = sizeof(VirtConsole),
++    .init          = virtconsole_initfn,
++    .exit          = virtconsole_exitfn,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
++        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
++        DEFINE_PROP_END_OF_LIST(),
++    },
++};
++
++static void virtconsole_register(void)
++{
++    virtio_serial_port_qdev_register(&virtconsole_info);
++}
++device_init(virtconsole_register)
+diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
+new file mode 100644
+index 0000000..fe8e357
+--- /dev/null
++++ b/hw/virtio-serial.h
+@@ -0,0 +1,158 @@
++/*
++ * Virtio Serial / Console Support
++ *
++ * Copyright IBM, Corp. 2008
++ * Copyright Red Hat, Inc. 2009
++ *
++ * Authors:
++ *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ *
++ */
++#ifndef _QEMU_VIRTIO_SERIAL_H
++#define _QEMU_VIRTIO_SERIAL_H
++
++#include <stdbool.h>
++#include "qdev.h"
++#include "virtio.h"
++
++/* == Interface shared between the guest kernel and qemu == */
++
++/* The Virtio ID for virtio console / serial ports */
++#define VIRTIO_ID_CONSOLE		3
++
++/* Features supported */
++#define VIRTIO_CONSOLE_F_MULTIPORT	1
++
++struct virtio_console_config {
++    /*
++     * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
++     * isn't implemented here yet
++     */
++    uint16_t cols;
++    uint16_t rows;
++
++    uint32_t max_nr_ports;
++    uint32_t nr_ports;
++} __attribute__((packed));
++
++struct virtio_console_control {
++    uint32_t id;		/* Port number */
++    uint16_t event;		/* The kind of control event (see below) */
++    uint16_t value;		/* Extra information for the key */
++};
++
++/* Some events for the internal messages (control packets) */
++#define VIRTIO_CONSOLE_PORT_READY	0
++#define VIRTIO_CONSOLE_CONSOLE_PORT	1
++#define VIRTIO_CONSOLE_RESIZE		2
++
++/* == In-qemu interface == */
++
++typedef struct VirtIOSerial VirtIOSerial;
++typedef struct VirtIOSerialBus VirtIOSerialBus;
++typedef struct VirtIOSerialPort VirtIOSerialPort;
++typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
++
++typedef struct VirtIOSerialDevice {
++    DeviceState qdev;
++    VirtIOSerialPortInfo *info;
++} VirtIOSerialDevice;
++
++/*
++ * This is the state that's shared between all the ports.  Some of the
++ * state is configurable via command-line options. Some of it can be
++ * set by individual devices in their initfn routines. Some of the
++ * state is set by the generic qdev device init routine.
++ */
++struct VirtIOSerialPort {
++    DeviceState dev;
++    VirtIOSerialPortInfo *info;
++
++    QTAILQ_ENTRY(VirtIOSerialPort) next;
++
++    /*
++     * This field gives us the virtio device as well as the qdev bus
++     * that we are associated with
++     */
++    VirtIOSerial *vser;
++
++    VirtQueue *ivq, *ovq;
++
++    /*
++     * This id helps identify ports between the guest and the host.
++     * The guest sends a "header" with this id with each data packet
++     * that it sends and the host can then find out which associated
++     * device to send out this data to
++     */
++    uint32_t id;
++
++    /* Identify if this is a port that binds with hvc in the guest */
++    uint8_t is_console;
++};
++
++struct VirtIOSerialPortInfo {
++    DeviceInfo qdev;
++    /*
++     * The per-port (or per-app) init function that's called when a
++     * new device is found on the bus.
++     */
++    int (*init)(VirtIOSerialDevice *dev);
++    /*
++     * Per-port exit function that's called when a port gets
++     * hot-unplugged or removed.
++     */
++    int (*exit)(VirtIOSerialDevice *dev);
++
++    /* Callbacks for guest events */
++        /* Guest opened device. */
++    void (*guest_open)(VirtIOSerialPort *port);
++        /* Guest closed device. */
++    void (*guest_close)(VirtIOSerialPort *port);
++
++        /* Guest is now ready to accept data (virtqueues set up). */
++    void (*guest_ready)(VirtIOSerialPort *port);
++
++    /*
++     * Guest wrote some data to the port. This data is handed over to
++     * the app via this callback. The app should return the number of
++     * bytes it successfully consumed.
++     */
++    size_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, size_t len);
++};
++
++/* Interface to the virtio-serial bus */
++
++/*
++ * Individual ports/apps should call this function to register the port
++ * with the virtio-serial bus
++ */
++void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
++
++/*
++ * Open a connection to the port
++ *   Returns 0 on success (always).
++ */
++int virtio_serial_open(VirtIOSerialPort *port);
++
++/*
++ * Close the connection to the port
++ *   Returns 0 on success (always).
++ */
++int virtio_serial_close(VirtIOSerialPort *port);
++
++/*
++ * Send data to Guest
++ */
++ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
++                            size_t size);
++
++/*
++ * Query whether a guest is ready to receive data.
++ */
++size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
++
++#endif
+diff --git a/hw/virtio.h b/hw/virtio.h
+index 051910a..a574928 100644
+--- a/hw/virtio.h
++++ b/hw/virtio.h
+@@ -171,7 +171,7 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
+ /* Base devices.  */
+ VirtIODevice *virtio_blk_init(DeviceState *dev, DriveInfo *dinfo);
+ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf);
+-VirtIODevice *virtio_console_init(DeviceState *dev);
++VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports);
+ VirtIODevice *virtio_balloon_init(DeviceState *dev);
+ 
+ void virtio_net_exit(VirtIODevice *vdev);
+diff --git a/qemu-options.hx b/qemu-options.hx
+index ca73ba5..173b1ec 100644
+--- a/qemu-options.hx
++++ b/qemu-options.hx
+@@ -1874,6 +1874,10 @@ DEF("virtioconsole", HAS_ARG, QEMU_OPTION_virtiocon, \
+ STEXI
+ @item -virtioconsole @var{c}
+ Set virtio console.
++
++This option is maintained for backward compatibility.
++
++Please use @code{-device virtconsole} for the new way of invocation.
+ ETEXI
+ 
+ DEF("show-cursor", 0, QEMU_OPTION_show_cursor, \
+diff --git a/sysemu.h b/sysemu.h
+index a545a2b..ff97786 100644
+--- a/sysemu.h
++++ b/sysemu.h
+@@ -237,12 +237,6 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
+ 
+ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+ 
+-/* virtio consoles */
+-
+-#define MAX_VIRTIO_CONSOLES 1
+-
+-extern CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+-
+ #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+ 
+ #ifdef HAS_AUDIO
+diff --git a/vl.c b/vl.c
+index c9d46de..a479ef3 100644
+--- a/vl.c
++++ b/vl.c
+@@ -175,6 +175,8 @@ int main(int argc, char **argv)
+ 
+ #define DEFAULT_RAM_SIZE 128
+ 
++#define MAX_VIRTIO_CONSOLES 1
++
+ static const char *data_dir;
+ const char *bios_name = NULL;
+ /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
+@@ -300,8 +302,9 @@ static struct {
+     { .driver = "isa-parallel",         .flag = &default_parallel  },
+     { .driver = "isa-fdc",              .flag = &default_floppy    },
+     { .driver = "ide-drive",            .flag = &default_cdrom     },
+-    { .driver = "virtio-console-pci",   .flag = &default_virtcon   },
+-    { .driver = "virtio-console-s390",  .flag = &default_virtcon   },
++    { .driver = "virtio-serial-pci",    .flag = &default_virtcon   },
++    { .driver = "virtio-serial-s390",   .flag = &default_virtcon   },
++    { .driver = "virtio-serial",        .flag = &default_virtcon   },
+     { .driver = "VGA",                  .flag = &default_vga       },
+     { .driver = "cirrus-vga",           .flag = &default_vga       },
+     { .driver = "vmware-svga",          .flag = &default_vga       },
+@@ -4885,6 +4888,7 @@ static int virtcon_parse(const char *devname)
+ {
+     static int index = 0;
+     char label[32];
++    QemuOpts *bus_opts, *dev_opts;
+ 
+     if (strcmp(devname, "none") == 0)
+         return 0;
+@@ -4892,6 +4896,13 @@ static int virtcon_parse(const char *devname)
+         fprintf(stderr, "qemu: too many virtio consoles\n");
+         exit(1);
+     }
++
++    bus_opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
++    qemu_opt_set(bus_opts, "driver", "virtio-serial");
++
++    dev_opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
++    qemu_opt_set(dev_opts, "driver", "virtconsole");
++
+     snprintf(label, sizeof(label), "virtcon%d", index);
+     virtcon_hds[index] = qemu_chr_open(label, devname, NULL);
+     if (!virtcon_hds[index]) {
+@@ -4899,6 +4910,8 @@ static int virtcon_parse(const char *devname)
+                 devname, strerror(errno));
+         return -1;
+     }
++    qemu_opt_set(dev_opts, "chardev", label);
++
+     index++;
+     return 0;
+ }
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-serial-Add-a-virtserialport-device-for-gen.patch b/qemu-virtio-serial-Add-a-virtserialport-device-for-gen.patch
new file mode 100644
index 0000000..d23e96e
--- /dev/null
+++ b/qemu-virtio-serial-Add-a-virtserialport-device-for-gen.patch
@@ -0,0 +1,63 @@
+From fcb66d7ac2271bcf0b46d6b1ae2d3db38e78bf2b Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:56 +0530
+Subject: [PATCH 6/9] virtio-serial: Add a 'virtserialport' device for generic serial port support
+
+This commit adds a simple chardev-based serial port. Any data the guest
+sends is forwarded to the chardev and vice-versa.
+
+Sample uses for such a device can be obtaining info from the guest like
+the file systems used, apps installed, etc. for offline usage and
+logged-in users, clipboard copy-paste, etc. for online usage.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio-serial.c |   34 ++++++++++++++++++++++++++++++++++
+ 1 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial.c b/hw/virtio-serial.c
+index 9c2c93c..bd44ec6 100644
+--- a/hw/virtio-serial.c
++++ b/hw/virtio-serial.c
+@@ -110,3 +110,37 @@ static void virtconsole_register(void)
+     virtio_serial_port_qdev_register(&virtconsole_info);
+ }
+ device_init(virtconsole_register)
++
++/* Generic Virtio Serial Ports */
++static int virtserialport_initfn(VirtIOSerialDevice *dev)
++{
++    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
++    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
++
++    port->info = dev->info;
++
++    if (vcon->chr) {
++        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
++                              vcon);
++        port->info->have_data = flush_buf;
++    }
++    return 0;
++}
++
++static VirtIOSerialPortInfo virtserialport_info = {
++    .qdev.name     = "virtserialport",
++    .qdev.size     = sizeof(VirtConsole),
++    .init          = virtserialport_initfn,
++    .exit          = virtconsole_exitfn,
++    .qdev.props = (Property[]) {
++        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
++        DEFINE_PROP_STRING("name", VirtConsole, port.name),
++        DEFINE_PROP_END_OF_LIST(),
++    },
++};
++
++static void virtserialport_register(void)
++{
++    virtio_serial_port_qdev_register(&virtserialport_info);
++}
++device_init(virtserialport_register)
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-serial-Use-MSI-vectors-for-port-virtqueues.patch b/qemu-virtio-serial-Use-MSI-vectors-for-port-virtqueues.patch
new file mode 100644
index 0000000..94fbd23
--- /dev/null
+++ b/qemu-virtio-serial-Use-MSI-vectors-for-port-virtqueues.patch
@@ -0,0 +1,45 @@
+From 43fa8533e10c478825952d489269d55e5c652c1a Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:58 +0530
+Subject: [PATCH 8/9] virtio-serial: Use MSI vectors for port virtqueues
+
+This commit enables the use of MSI interrupts for virtqueue
+notifications for ports. We use nr_ports + 1 (for control channel) msi
+entries for the ports, as only the in_vq operations need an interrupt on
+the guest.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio-pci.c |    4 ++++
+ 1 files changed, 4 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
+index c1a1e4c..4451a63 100644
+--- a/hw/virtio-pci.c
++++ b/hw/virtio-pci.c
+@@ -497,10 +497,13 @@ static int virtio_serial_init_pci(PCIDevice *pci_dev)
+     if (!vdev) {
+         return -1;
+     }
++    vdev->nvectors = proxy->nvectors ? proxy->nvectors
++                                     : proxy->max_virtserial_ports + 1;
+     virtio_init_pci(proxy, vdev,
+                     PCI_VENDOR_ID_REDHAT_QUMRANET,
+                     PCI_DEVICE_ID_VIRTIO_CONSOLE,
+                     proxy->class_code, 0x00);
++    proxy->nvectors = vdev->nvectors;
+     return 0;
+ }
+ 
+@@ -577,6 +580,7 @@ static PCIDeviceInfo virtio_info[] = {
+         .init      = virtio_serial_init_pci,
+         .exit      = virtio_exit_pci,
+         .qdev.props = (Property[]) {
++            DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 0),
+             DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+             DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, max_virtserial_ports,
+                                31),
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-serial-bus-Add-a-port-name-property-for-po.patch b/qemu-virtio-serial-bus-Add-a-port-name-property-for-po.patch
new file mode 100644
index 0000000..c3f3ec5
--- /dev/null
+++ b/qemu-virtio-serial-bus-Add-a-port-name-property-for-po.patch
@@ -0,0 +1,116 @@
+From ed4daf8c7722562ec05e83ec98a4d4d8adf20f7f Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:54 +0530
+Subject: [PATCH 4/9] virtio-serial-bus: Add a port 'name' property for port discovery in guests
+
+The port 'id' or number is internal state between the guest kernel and
+our bus implementation. This is invocation-dependent and isn't part of
+the guest-host ABI.
+
+To correcly enumerate and map ports between the host and the guest, the
+'name' property is used.
+
+Example:
+
+    -device virtserialport,name=org.qemu.port.0
+
+This invocation will get us a char device in the guest at:
+
+    /dev/virtio-ports/org.qemu.port.0
+
+which can be a symlink to
+
+    /dev/vport0p3
+
+This 'name' property is exposed by the guest kernel in a sysfs
+attribute:
+
+    /sys/kernel/virtio-ports/vport0p3/name
+
+A simple udev script can pick up this name and create the symlink
+mentioned above.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio-serial-bus.c |   17 +++++++++++++++++
+ hw/virtio-serial.c     |    1 +
+ hw/virtio-serial.h     |    8 ++++++++
+ 3 files changed, 26 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index 9af21df..6d69c56 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -204,6 +204,8 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
+ {
+     struct VirtIOSerialPort *port;
+     struct virtio_console_control cpkt, *gcpkt;
++    uint8_t *buffer;
++    size_t buffer_len;
+ 
+     gcpkt = buf;
+     port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+@@ -226,6 +228,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
+             send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
+         }
+ 
++        if (port->name) {
++            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
++            stw_p(&cpkt.value, 1);
++
++            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
++            buffer = qemu_malloc(buffer_len);
++
++            memcpy(buffer, &cpkt, sizeof(cpkt));
++            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
++            buffer[buffer_len - 1] = 0;
++
++            send_control_msg(port, buffer, buffer_len);
++            qemu_free(buffer);
++        }
++
+         if (port->host_connected) {
+             send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+         }
+diff --git a/hw/virtio-serial.c b/hw/virtio-serial.c
+index 1dc031e..9c2c93c 100644
+--- a/hw/virtio-serial.c
++++ b/hw/virtio-serial.c
+@@ -100,6 +100,7 @@ static VirtIOSerialPortInfo virtconsole_info = {
+     .qdev.props = (Property[]) {
+         DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
+         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
++        DEFINE_PROP_STRING("name", VirtConsole, port.name),
+         DEFINE_PROP_END_OF_LIST(),
+     },
+ };
+diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
+index d9c7acb..28ea7da 100644
+--- a/hw/virtio-serial.h
++++ b/hw/virtio-serial.h
+@@ -50,6 +50,7 @@ struct virtio_console_control {
+ #define VIRTIO_CONSOLE_CONSOLE_PORT	1
+ #define VIRTIO_CONSOLE_RESIZE		2
+ #define VIRTIO_CONSOLE_PORT_OPEN	3
++#define VIRTIO_CONSOLE_PORT_NAME	4
+ 
+ /* == In-qemu interface == */
+ 
+@@ -84,6 +85,13 @@ struct VirtIOSerialPort {
+     VirtQueue *ivq, *ovq;
+ 
+     /*
++     * This name is sent to the guest and exported via sysfs.
++     * The guest could create symlinks based on this information.
++     * The name is in the reverse fqdn format, like org.qemu.console.0
++     */
++    char *name;
++
++    /*
+      * This id helps identify ports between the guest and the host.
+      * The guest sends a "header" with this id with each data packet
+      * that it sends and the host can then find out which associated
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-serial-bus-Add-ability-to-hot-unplug-ports.patch b/qemu-virtio-serial-bus-Add-ability-to-hot-unplug-ports.patch
new file mode 100644
index 0000000..6a426b8
--- /dev/null
+++ b/qemu-virtio-serial-bus-Add-ability-to-hot-unplug-ports.patch
@@ -0,0 +1,40 @@
+From c101ff585d5b156a1f3461015a9acd73f15a45f6 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:55 +0530
+Subject: [PATCH 5/9] virtio-serial-bus: Add ability to hot-unplug ports
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio-serial-bus.c |    2 ++
+ hw/virtio-serial.h     |    1 +
+ 2 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index 6d69c56..037864f 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -517,6 +517,8 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
+     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+     VirtIOSerial *vser = port->vser;
+ 
++    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
++
+     /*
+      * Don't decrement nr_ports here; thus we keep a linearly
+      * increasing port id. Not utilising an id again saves us a couple
+diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
+index 28ea7da..f297b00 100644
+--- a/hw/virtio-serial.h
++++ b/hw/virtio-serial.h
+@@ -51,6 +51,7 @@ struct virtio_console_control {
+ #define VIRTIO_CONSOLE_RESIZE		2
+ #define VIRTIO_CONSOLE_PORT_OPEN	3
+ #define VIRTIO_CONSOLE_PORT_NAME	4
++#define VIRTIO_CONSOLE_PORT_REMOVE	5
+ 
+ /* == In-qemu interface == */
+ 
+-- 
+1.6.2.5
+
diff --git a/qemu-virtio-serial-bus-Maintain-guest-and-host-port-open.patch b/qemu-virtio-serial-bus-Maintain-guest-and-host-port-open.patch
new file mode 100644
index 0000000..56ee29f
--- /dev/null
+++ b/qemu-virtio-serial-bus-Maintain-guest-and-host-port-open.patch
@@ -0,0 +1,232 @@
+From 4945aee74f494cc8a17ce1634b5200eb9ee227d2 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Wed, 20 Jan 2010 00:36:53 +0530
+Subject: [PATCH 3/9] virtio-serial-bus: Maintain guest and host port open/close state
+
+Via control channel messages, the guest can tell us whether a port got
+opened or closed. Similarly, we can also indicate to the guest of host
+port open/close events.
+
+Signed-off-by: Amit Shah <amit.shah@redhat.com>
+Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
+---
+ hw/virtio-serial-bus.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++
+ hw/virtio-serial.h     |    6 +++
+ 2 files changed, 100 insertions(+), 0 deletions(-)
+
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index 5132c9c..9af21df 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -66,6 +66,11 @@ static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
+     return NULL;
+ }
+ 
++static bool use_multiport(VirtIOSerial *vser)
++{
++    return vser->vdev.features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
++}
++
+ static size_t write_to_port(VirtIOSerialPort *port,
+                             const uint8_t *buf, size_t size)
+ {
+@@ -139,11 +144,22 @@ static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
+ /* Functions for use inside qemu to open and read from/write to ports */
+ int virtio_serial_open(VirtIOSerialPort *port)
+ {
++    /* Don't allow opening an already-open port */
++    if (port->host_connected) {
++        return 0;
++    }
++    /* Send port open notification to the guest */
++    port->host_connected = true;
++    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
++
+     return 0;
+ }
+ 
+ int virtio_serial_close(VirtIOSerialPort *port)
+ {
++    port->host_connected = false;
++    send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
++
+     return 0;
+ }
+ 
+@@ -151,6 +167,9 @@ int virtio_serial_close(VirtIOSerialPort *port)
+ ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+                             size_t size)
+ {
++    if (!port || !port->host_connected || !port->guest_connected) {
++        return 0;
++    }
+     return write_to_port(port, buf, size);
+ }
+ 
+@@ -167,6 +186,9 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
+         virtio_queue_empty(vq)) {
+         return 0;
+     }
++    if (use_multiport(port->vser) && !port->guest_connected) {
++        return 0;
++    }
+ 
+     if (virtqueue_avail_bytes(vq, 4096, 0)) {
+         return 4096;
+@@ -203,6 +225,11 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
+         if (port->is_console) {
+             send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
+         }
++
++        if (port->host_connected) {
++            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
++        }
++
+         /*
+          * When the guest has asked us for this information it means
+          * the guest is all setup and has its virtqueues
+@@ -213,6 +240,19 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
+             port->info->guest_ready(port);
+         }
+         break;
++
++    case VIRTIO_CONSOLE_PORT_OPEN:
++        port->guest_connected = cpkt.value;
++        if (cpkt.value && port->info->guest_open) {
++            /* Send the guest opened notification if an app is interested */
++            port->info->guest_open(port);
++        }
++
++        if (!cpkt.value && port->info->guest_close) {
++            /* Send the guest closed notification if an app is interested */
++            port->info->guest_close(port);
++        }
++        break;
+     }
+ }
+ 
+@@ -300,6 +340,8 @@ static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
+ static void virtio_serial_save(QEMUFile *f, void *opaque)
+ {
+     VirtIOSerial *s = opaque;
++    VirtIOSerialPort *port;
++    uint32_t nr_active_ports;
+ 
+     /* The virtio device */
+     virtio_save(&s->vdev, f);
+@@ -308,15 +350,41 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
+     qemu_put_be16s(f, &s->config.cols);
+     qemu_put_be16s(f, &s->config.rows);
+     qemu_put_be32s(f, &s->config.nr_ports);
++
++    /* Items in struct VirtIOSerial */
++
++    /* Do this because we might have hot-unplugged some ports */
++    nr_active_ports = 0;
++    QTAILQ_FOREACH(port, &s->ports, next)
++        nr_active_ports++;
++
++    qemu_put_be32s(f, &nr_active_ports);
++
++    /*
++     * Items in struct VirtIOSerialPort.
++     */
++    QTAILQ_FOREACH(port, &s->ports, next) {
++        /*
++         * We put the port number because we may not have an active
++         * port at id 0 that's reserved for a console port, or in case
++         * of ports that might have gotten unplugged
++         */
++        qemu_put_be32s(f, &port->id);
++        qemu_put_byte(f, port->guest_connected);
++    }
+ }
+ 
+ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+ {
+     VirtIOSerial *s = opaque;
++    VirtIOSerialPort *port;
++    uint32_t nr_active_ports;
++    unsigned int i;
+ 
+     if (version_id > 2) {
+         return -EINVAL;
+     }
++
+     /* The virtio device */
+     virtio_load(&s->vdev, f);
+ 
+@@ -329,6 +397,20 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+     qemu_get_be16s(f, &s->config.rows);
+     s->config.nr_ports = qemu_get_be32(f);
+ 
++    /* Items in struct VirtIOSerial */
++
++    qemu_get_be32s(f, &nr_active_ports);
++
++    /* Items in struct VirtIOSerialPort */
++    for (i = 0; i < nr_active_ports; i++) {
++        uint32_t id;
++
++        id = qemu_get_be32(f);
++        port = find_port_by_id(s, id);
++
++        port->guest_connected = qemu_get_byte(f);
++    }
++
+     return 0;
+ }
+ 
+@@ -357,6 +439,10 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+ 
+     monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
+                    indent, "", port->id);
++    monitor_printf(mon, "%*s dev-prop-int: guest_connected: %d\n",
++                   indent, "", port->guest_connected);
++    monitor_printf(mon, "%*s dev-prop-int: host_connected: %d\n",
++                   indent, "", port->host_connected);
+ }
+ 
+ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+@@ -390,6 +476,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+ 
+     port->id = plugging_port0 ? 0 : port->vser->config.nr_ports++;
+ 
++    if (!use_multiport(port->vser)) {
++        /*
++         * Allow writes to guest in this case; we have no way of
++         * knowing if a guest port is connected.
++         */
++        port->guest_connected = true;
++    }
++
+     QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
+     port->ivq = port->vser->ivqs[port->id];
+     port->ovq = port->vser->ovqs[port->id];
+diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
+index fe8e357..d9c7acb 100644
+--- a/hw/virtio-serial.h
++++ b/hw/virtio-serial.h
+@@ -49,6 +49,7 @@ struct virtio_console_control {
+ #define VIRTIO_CONSOLE_PORT_READY	0
+ #define VIRTIO_CONSOLE_CONSOLE_PORT	1
+ #define VIRTIO_CONSOLE_RESIZE		2
++#define VIRTIO_CONSOLE_PORT_OPEN	3
+ 
+ /* == In-qemu interface == */
+ 
+@@ -92,6 +93,11 @@ struct VirtIOSerialPort {
+ 
+     /* Identify if this is a port that binds with hvc in the guest */
+     uint8_t is_console;
++
++    /* Is the corresponding guest device open? */
++    bool guest_connected;
++    /* Is this device open for IO on the host? */
++    bool host_connected;
+ };
+ 
+ struct VirtIOSerialPortInfo {
+-- 
+1.6.2.5
+
diff --git a/qemu.spec b/qemu.spec
index 2787af0..8aafdca 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,7 +1,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 0.12.2
-Release: 1%{?dist}
+Release: 2%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -24,6 +24,18 @@ Source6: ksmtuned.init
 Source7: ksmtuned
 Source8: ksmtuned.conf
 
+# virtio-console changes for the F13 VirtioSerial feature
+Patch01: qemu-virtio-Remove-duplicate-macro-definition-for-max.-v.patch
+Patch02: qemu-virtio-console-qdev-conversion-new-virtio-serial-b.patch
+Patch03: qemu-virtio-serial-bus-Maintain-guest-and-host-port-open.patch
+Patch04: qemu-virtio-serial-bus-Add-a-port-name-property-for-po.patch
+Patch05: qemu-virtio-serial-bus-Add-ability-to-hot-unplug-ports.patch
+Patch06: qemu-virtio-serial-Add-a-virtserialport-device-for-gen.patch
+Patch07: qemu-Move-virtio-serial-to-Makefile.objs.patch
+Patch08: qemu-virtio-serial-Use-MSI-vectors-for-port-virtqueues.patch
+Patch09: qemu-virtio-console-Rename-virtio-serial.c-back-to-virti.patch
+
+
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
 BuildRequires: rsync dev86 iasl
@@ -211,6 +223,16 @@ such as kvmtrace and kvm_stat.
 %prep
 %setup -q -n qemu-kvm-%{version}
 
+%patch01 -p1
+%patch02 -p1
+%patch03 -p1
+%patch04 -p1
+%patch05 -p1
+%patch06 -p1
+%patch07 -p1
+%patch08 -p1
+%patch09 -p1
+
 %build
 # --build-id option is used fedora 8 onwards for giving info to the debug packages.
 extraldflags="-Wl,--build-id";
@@ -493,6 +515,9 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Wed Jan 27 2010 Amit Shah <amit.shah@redhat.com> - 2:0.12.2-2
+- Add virtio-console patches from upstream for the F13 VirtioSerial feature
+
 * Mon Jan 25 2010 Justin M. Forbes <jforbes@redhat.com> - 2:0.12.2-1
 - Update to 0.12.2 upstream