Merge remote-tracking branch 'alon/libcacard_ccid.1' into staging

# By Alon Levy (15) and others
# Via Alon Levy
* alon/libcacard_ccid.1: (28 commits)
  libcacard/cac: change big switch functions to single return point
  dev-smartcard-reader: empty implementation for Mechanical (fail correctly)
  libcacard: move atr setting from macro to function
  libcacard/vreader: add debugging messages for apdu
  dev-smartcard-reader: copy atr protocol to ccid parameters
  dev-smartcard-reader: change default protocol to T=0
  dev-smartcard-reader: define structs for CCID_Parameter internals
  ccid-card-passthru, dev-smartcard-reader: add debug environment variables
  ccid-card-passthru: add atr check
  libcacard: change default ATR
  dev-smartcard-reader: reuse usb.h definitions
  dev-smartcard-reader: support windows guest
  dev-smartcard-reader: remove aborts (never triggered, but just in case)
  dev-smartcard-reader: nicer debug messages
  dev-smartcard-reader: white space fixes
  libcacard: remove default libcoolkey loading
  libcacard: remove sql: prefix
  libcacard: teach vscclient to use GMainLoop for portability
  libcacard: vscclient to use QemuThread for portability
  libcacard: split vscclient main() from socket reading
  ...

Message-id: 921423767.1475937.1366790789930.JavaMail.root@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
diff --git a/Makefile b/Makefile
index b6ad03a..efb1c44 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,12 @@
 endif
 endif
 
+CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
+CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
+CONFIG_ALL=y
+-include config-all-devices.mak
+-include config-all-disas.mak
+
 include $(SRC_PATH)/rules.mak
 config-host.mak: $(SRC_PATH)/configure
 	@echo $@ is out-of-date, running configure
@@ -107,12 +113,6 @@
 defconfig:
 	rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
 
--include config-all-devices.mak
--include config-all-disas.mak
-CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
-CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
-CONFIG_ALL=y
-
 ifneq ($(wildcard config-host.mak),)
 include $(SRC_PATH)/Makefile.objs
 include $(SRC_PATH)/tests/Makefile
diff --git a/Makefile.target b/Makefile.target
index 2636103..7e4c77a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -1,8 +1,8 @@
 # -*- Mode: makefile -*-
 
 include ../config-host.mak
-include config-devices.mak
 include config-target.mak
+include config-devices.mak
 include $(SRC_PATH)/rules.mak
 
 $(call set-vpath, $(SRC_PATH))
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 62a291b..dc6f4e4 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -92,9 +92,7 @@
     s->ctx.uid = -1;
 
     s->ops = fse->ops;
-    vdev->get_features = virtio_9p_get_features;
     s->config_size = sizeof(struct virtio_9p_config) + len;
-    vdev->get_config = virtio_9p_get_config;
     s->fid_list = NULL;
     qemu_co_rwlock_init(&s->rename_lock);
 
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index e663d29..4a17f32 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -203,7 +203,7 @@
 }
 
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq, qemu_irq cmos_s3)
+                  qemu_irq sci_irq)
 {
     memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE);
     memory_region_set_enabled(&pm->io, false);
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 5baef23..0356665 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -23,6 +23,7 @@
 #include "hw/virtio/virtio-blk.h"
 #include "virtio-blk.h"
 #include "block/aio.h"
+#include "hw/virtio/virtio-bus.h"
 
 enum {
     SEG_MAX = 126,                  /* maximum number of I/O segments */
@@ -455,6 +456,8 @@
 
 void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     VirtQueue *vq;
     int i;
 
@@ -470,8 +473,7 @@
     s->ctx = aio_context_new();
 
     /* Set up guest notifier (irq) */
-    if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1,
-                                              true) != 0) {
+    if (k->set_guest_notifiers(qbus->parent, 1, true) != 0) {
         fprintf(stderr, "virtio-blk failed to set guest notifier, "
                 "ensure -enable-kvm is set\n");
         exit(1);
@@ -479,8 +481,7 @@
     s->guest_notifier = virtio_queue_get_guest_notifier(vq);
 
     /* Set up virtqueue notify */
-    if (s->vdev->binding->set_host_notifier(s->vdev->binding_opaque,
-                                            0, true) != 0) {
+    if (k->set_host_notifier(qbus->parent, 0, true) != 0) {
         fprintf(stderr, "virtio-blk failed to set host notifier\n");
         exit(1);
     }
@@ -508,6 +509,8 @@
 
 void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     if (!s->started || s->stopping) {
         return;
     }
@@ -527,12 +530,12 @@
     ioq_cleanup(&s->ioqueue);
 
     aio_set_event_notifier(s->ctx, &s->host_notifier, NULL, NULL);
-    s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false);
+    k->set_host_notifier(qbus->parent, 0, false);
 
     aio_context_unref(s->ctx);
 
     /* Clean up guest notifier (irq) */
-    s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false);
+    k->set_guest_notifiers(qbus->parent, 1, false);
 
     vring_teardown(&s->vring);
     s->started = false;
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9fdf009..cf12469 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -652,11 +652,6 @@
     virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
                 sizeof(struct virtio_blk_config));
 
-    vdev->get_config = virtio_blk_update_config;
-    vdev->set_config = virtio_blk_set_config;
-    vdev->get_features = virtio_blk_get_features;
-    vdev->set_status = virtio_blk_set_status;
-    vdev->reset = virtio_blk_reset;
     s->bs = blk->conf.bs;
     s->conf = &blk->conf;
     memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
@@ -666,7 +661,7 @@
     s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
 #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
     if (!virtio_blk_data_plane_create(vdev, blk, &s->dataplane)) {
-        virtio_common_cleanup(vdev);
+        virtio_cleanup(vdev);
         return -1;
     }
 #endif
@@ -694,7 +689,7 @@
     qemu_del_vm_change_state_handler(s->change);
     unregister_savevm(dev, "virtio-blk", s);
     blockdev_mark_auto_del(s->bs);
-    virtio_common_cleanup(vdev);
+    virtio_cleanup(vdev);
     return 0;
 }
 
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 35c996d..3787ad2 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -954,12 +954,6 @@
      */
     mark_port_added(vser, 0);
 
-    vdev->get_features = get_features;
-    vdev->get_config = get_config;
-    vdev->set_config = set_config;
-    vdev->set_status = set_status;
-    vdev->reset = vser_reset;
-
     vser->post_load = NULL;
 
     /*
@@ -1007,7 +1001,7 @@
         qemu_free_timer(vser->post_load->timer);
         g_free(vser->post_load);
     }
-    virtio_common_cleanup(vdev);
+    virtio_cleanup(vdev);
     return 0;
 }
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 6ac1a89..e5f417e 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -45,17 +45,6 @@
 /* ICH9 AHCI has 6 ports */
 #define MAX_SATA_PORTS     6
 
-/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
- *    BIOS will read it and start S3 resume at POST Entry */
-static void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
-{
-    ISADevice *s = opaque;
-
-    if (level) {
-        rtc_set_memory(s, 0xF, 0xFE);
-    }
-}
-
 /* PC hardware initialisation */
 static void pc_q35_init(QEMUMachineInitArgs *args)
 {
@@ -84,7 +73,6 @@
     int i;
     ICH9LPCState *ich9_lpc;
     PCIDevice *ahci;
-    qemu_irq *cmos_s3;
 
     pc_cpus_init(cpu_model);
     pc_acpi_init("q35-acpi-dsdt.aml");
@@ -175,8 +163,7 @@
     pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
 
     /* connect pm stuff to lpc */
-    cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
-    ich9_lpc_pm_init(lpc, *cmos_s3);
+    ich9_lpc_pm_init(lpc);
 
     /* ahci and SATA device, for q35 1 ahci controller is built-in */
     ahci = pci_create_simple_multifunction(host_bus,
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 5fbde98..14b3125 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -415,7 +415,7 @@
 {
     switch (hs->kind) {
     case HID_KEYBOARD:
-        qemu_remove_kbd_event_handler();
+        qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
         break;
     case HID_MOUSE:
     case HID_TABLET:
@@ -431,7 +431,7 @@
     hs->event = event;
 
     if (hs->kind == HID_KEYBOARD) {
-        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+        hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs);
     } else if (hs->kind == HID_MOUSE) {
         hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
                                                         0, "QEMU HID Mouse");
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index d116075..667e882 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -356,13 +356,13 @@
     }
 }
 
-void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3)
+void ich9_lpc_pm_init(PCIDevice *lpc_pci)
 {
     ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
     qemu_irq *sci_irq;
 
     sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
-    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3);
+    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0]);
 
     ich9_lpc_reset(&lpc->d.qdev);
 }
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 8c5384c..006576d 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -37,6 +37,7 @@
 #include <stdio.h>
 
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/virtio-bus.h"
 
 struct vhost_net {
     struct vhost_dev dev;
@@ -211,9 +212,12 @@
 int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
                     int total_queues)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+    VirtioBusState *vbus = VIRTIO_BUS(qbus);
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
     int r, i = 0;
 
-    if (!dev->binding->set_guest_notifiers) {
+    if (!k->set_guest_notifiers) {
         error_report("binding does not support guest notifiers");
         r = -ENOSYS;
         goto err;
@@ -227,9 +231,7 @@
         }
     }
 
-    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
-                                          total_queues * 2,
-                                          true);
+    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
     if (r < 0) {
         error_report("Error binding guest notifier: %d", -r);
         goto err;
@@ -247,11 +249,12 @@
 void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
                     int total_queues)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
+    VirtioBusState *vbus = VIRTIO_BUS(qbus);
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
     int i, r;
 
-    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
-                                          total_queues * 2,
-                                          false);
+    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
     if (r < 0) {
         fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
         fflush(stderr);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 4d2cdd2..2aea5a1 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1283,15 +1283,6 @@
     virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET,
                                   n->config_size);
 
-    vdev->get_config = virtio_net_get_config;
-    vdev->set_config = virtio_net_set_config;
-    vdev->get_features = virtio_net_get_features;
-    vdev->set_features = virtio_net_set_features;
-    vdev->bad_features = virtio_net_bad_features;
-    vdev->reset = virtio_net_reset;
-    vdev->set_status = virtio_net_set_status;
-    vdev->guest_notifier_mask = virtio_net_guest_notifier_mask;
-    vdev->guest_notifier_pending = virtio_net_guest_notifier_pending;
     n->max_queues = MAX(n->nic_conf.queues, 1);
     n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
     n->vqs[0].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
@@ -1383,7 +1374,7 @@
 
     g_free(n->vqs);
     qemu_del_nic(n->nic);
-    virtio_common_cleanup(vdev);
+    virtio_cleanup(vdev);
 
     return 0;
 }
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index dabbc2e..cf51a85 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -47,14 +47,14 @@
 
 #define VIRTIO_EXT_CODE   0x2603
 
+static void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev);
+
 static const TypeInfo s390_virtio_bus_info = {
     .name = TYPE_S390_VIRTIO_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(VirtIOS390Bus),
 };
 
-static const VirtIOBindings virtio_s390_bindings;
-
 static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
 
 /* length of VirtIO device pages */
@@ -134,12 +134,12 @@
     dev_len = VIRTIO_DEV_OFFS_CONFIG;
     dev_len += s390_virtio_device_num_vq(dev) * VIRTIO_VQCONFIG_LEN;
     dev_len += dev->feat_len * 2;
-    dev_len += vdev->config_len;
+    dev_len += virtio_bus_get_vdev_config_len(&dev->bus);
 
     bus->dev_offs += dev_len;
 
-    virtio_bind_device(vdev, &virtio_s390_bindings, DEVICE(dev));
-    dev->host_features = vdev->get_features(vdev, dev->host_features);
+    dev->host_features = virtio_bus_get_vdev_features(&dev->bus,
+                                                      dev->host_features);
     s390_virtio_device_sync(dev);
     s390_virtio_reset_idx(dev);
     if (dev->qdev.hotplugged) {
@@ -262,16 +262,31 @@
 }
 #endif
 
-static int s390_virtio_rng_init(VirtIOS390Device *dev)
-{
-    VirtIODevice *vdev;
 
-    vdev = virtio_rng_init((DeviceState *)dev, &dev->rng);
-    if (!vdev) {
+static int s390_virtio_rng_init(VirtIOS390Device *s390_dev)
+{
+    VirtIORNGS390 *dev = VIRTIO_RNG_S390(s390_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
+    if (qdev_init(vdev) < 0) {
         return -1;
     }
 
-    return s390_virtio_device_init(dev, vdev);
+    object_property_set_link(OBJECT(dev),
+                             OBJECT(dev->vdev.conf.default_backend), "rng",
+                             NULL);
+
+    return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+}
+
+static void s390_virtio_rng_instance_init(Object *obj)
+{
+    VirtIORNGS390 *dev = VIRTIO_RNG_S390(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+                             (Object **)&dev->vdev.conf.rng, NULL);
 }
 
 static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq)
@@ -351,9 +366,7 @@
     cur_offs += dev->feat_len * 2;
 
     /* Sync config space */
-    if (dev->vdev->get_config) {
-        dev->vdev->get_config(dev->vdev, dev->vdev->config);
-    }
+    virtio_bus_get_vdev_config(&dev->bus, dev->vdev->config);
 
     cpu_physical_memory_write(cur_offs,
                               dev->vdev->config, dev->vdev->config_len);
@@ -450,11 +463,6 @@
 
 /**************** S390 Virtio Bus Device Descriptions *******************/
 
-static const VirtIOBindings virtio_s390_bindings = {
-    .notify = virtio_s390_notify,
-    .get_features = virtio_s390_get_features,
-};
-
 static Property s390_virtio_net_properties[] = {
     DEFINE_NIC_PROPERTIES(VirtIONetS390, vdev.nic_conf),
     DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
@@ -523,14 +531,6 @@
     .class_init    = s390_virtio_serial_class_init,
 };
 
-static void s390_virtio_rng_initfn(Object *obj)
-{
-    VirtIOS390Device *dev = VIRTIO_S390_DEVICE(obj);
-
-    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
-                             (Object **)&dev->rng.rng, NULL);
-}
-
 static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
 {
     VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
@@ -539,10 +539,10 @@
 }
 
 static const TypeInfo s390_virtio_rng = {
-    .name          = "virtio-rng-s390",
+    .name          = TYPE_VIRTIO_RNG_S390,
     .parent        = TYPE_VIRTIO_S390_DEVICE,
-    .instance_size = sizeof(VirtIOS390Device),
-    .instance_init = s390_virtio_rng_initfn,
+    .instance_size = sizeof(VirtIORNGS390),
+    .instance_init = s390_virtio_rng_instance_init,
     .class_init    = s390_virtio_rng_class_init,
 };
 
@@ -657,7 +657,7 @@
 
 /* virtio-s390-bus */
 
-void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev)
+static void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev)
 {
     DeviceState *qdev = DEVICE(dev);
     BusState *qbus;
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
index d7c47db..ac81bd8 100644
--- a/hw/s390x/s390-virtio-bus.h
+++ b/hw/s390x/s390-virtio-bus.h
@@ -79,8 +79,6 @@
 
 typedef struct VirtIOS390Device VirtIOS390Device;
 
-void virtio_s390_bus_new(VirtioBusState *bus, VirtIOS390Device *dev);
-
 typedef struct VirtIOS390DeviceClass {
     DeviceClass qdev;
     int (*init)(VirtIOS390Device *dev);
@@ -93,7 +91,6 @@
     uint8_t feat_len;
     VirtIODevice *vdev;
     uint32_t host_features;
-    VirtIORNGConf rng;
     VirtioBusState bus;
 };
 
@@ -176,4 +173,15 @@
 } VHostSCSIS390;
 #endif
 
+/* virtio-rng-s390 */
+
+#define TYPE_VIRTIO_RNG_S390 "virtio-rng-s390"
+#define VIRTIO_RNG_S390(obj) \
+        OBJECT_CHECK(VirtIORNGS390, (obj), TYPE_VIRTIO_RNG_S390)
+
+typedef struct VirtIORNGS390 {
+    VirtIOS390Device parent_obj;
+    VirtIORNG vdev;
+} VirtIORNGS390;
+
 #endif
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 56539d3..56e4872 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -27,6 +27,8 @@
 #include "virtio-ccw.h"
 #include "trace.h"
 
+static void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev);
+
 static int virtual_css_bus_reset(BusState *qbus)
 {
     /* This should actually be modelled via the generic css */
@@ -51,8 +53,6 @@
     .class_init = virtual_css_bus_class_init,
 };
 
-static const VirtIOBindings virtio_ccw_bindings;
-
 VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
 {
     VirtIODevice *vdev = NULL;
@@ -233,9 +233,7 @@
             features.index = ldub_phys(ccw.cda + sizeof(features.features));
             features.features = ldl_le_phys(ccw.cda);
             if (features.index < ARRAY_SIZE(dev->host_features)) {
-                if (dev->vdev->set_features) {
-                    dev->vdev->set_features(dev->vdev, features.features);
-                }
+                virtio_bus_set_vdev_features(&dev->bus, features.features);
                 dev->vdev->guest_features = features.features;
             } else {
                 /*
@@ -263,7 +261,7 @@
         if (!ccw.cda) {
             ret = -EFAULT;
         } else {
-            dev->vdev->get_config(dev->vdev, dev->vdev->config);
+            virtio_bus_get_vdev_config(&dev->bus, dev->vdev->config);
             /* XXX config space endianness */
             cpu_physical_memory_write(ccw.cda, dev->vdev->config, len);
             sch->curr_status.scsw.count = ccw.count - len;
@@ -290,9 +288,7 @@
                 /* XXX config space endianness */
                 memcpy(dev->vdev->config, config, len);
                 cpu_physical_memory_unmap(config, hw_len, 0, hw_len);
-                if (dev->vdev->set_config) {
-                    dev->vdev->set_config(dev->vdev, dev->vdev->config);
-                }
+                virtio_bus_set_vdev_config(&dev->bus, dev->vdev->config);
                 sch->curr_status.scsw.count = ccw.count - len;
                 ret = 0;
             }
@@ -523,9 +519,10 @@
     sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
     sch->id.cu_model = dev->vdev->device_id;
 
-    virtio_bind_device(vdev, &virtio_ccw_bindings, DEVICE(dev));
     /* Only the first 32 feature bits are used. */
-    dev->host_features[0] = vdev->get_features(vdev, dev->host_features[0]);
+    dev->host_features[0] = virtio_bus_get_vdev_features(&dev->bus,
+                                                         dev->host_features[0]);
+
     dev->host_features[0] |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
     dev->host_features[0] |= 0x1 << VIRTIO_F_BAD_FEATURE;
 
@@ -709,28 +706,21 @@
 }
 #endif
 
-static int virtio_ccw_rng_init(VirtioCcwDevice *dev)
+static int virtio_ccw_rng_init(VirtioCcwDevice *ccw_dev)
 {
-    VirtIODevice *vdev;
+    VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
 
-    if (dev->rng.rng == NULL) {
-        dev->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
-        object_property_add_child(OBJECT(dev), "default-backend",
-                                  OBJECT(dev->rng.default_backend), NULL);
-        object_property_set_link(OBJECT(dev), OBJECT(dev->rng.default_backend),
-                                 "rng", NULL);
-    }
-    vdev = virtio_rng_init((DeviceState *)dev, &dev->rng);
-    if (!vdev) {
+    qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
+    if (qdev_init(vdev) < 0) {
         return -1;
     }
-    return virtio_ccw_device_init(dev, vdev);
-}
 
-static int virtio_ccw_rng_exit(VirtioCcwDevice *dev)
-{
-    virtio_rng_exit(dev->vdev);
-    return virtio_ccw_exit(dev);
+    object_property_set_link(OBJECT(dev),
+                             OBJECT(dev->vdev.conf.default_backend), "rng",
+                             NULL);
+
+    return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
 }
 
 /* DeviceState to VirtioCcwDevice. Note: used on datapath,
@@ -784,11 +774,6 @@
 
 /**************** Virtio-ccw Bus Device Descriptions *******************/
 
-static const VirtIOBindings virtio_ccw_bindings = {
-    .notify = virtio_ccw_notify,
-    .get_features = virtio_ccw_get_features,
-};
-
 static Property virtio_ccw_net_properties[] = {
     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
     DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
@@ -947,19 +932,19 @@
 };
 #endif
 
-static void virtio_ccw_rng_initfn(Object *obj)
+static void virtio_ccw_rng_instance_init(Object *obj)
 {
-    VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(obj);
-
+    VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
     object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
-                             (Object **)&dev->rng.rng, NULL);
+                             (Object **)&dev->vdev.conf.rng, NULL);
 }
 
 static Property virtio_ccw_rng_properties[] = {
     DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
     DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
-    DEFINE_PROP_UINT64("max-bytes", VirtioCcwDevice, rng.max_bytes, INT64_MAX),
-    DEFINE_PROP_UINT32("period", VirtioCcwDevice, rng.period_ms, 1 << 16),
+    DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -969,16 +954,16 @@
     VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
 
     k->init = virtio_ccw_rng_init;
-    k->exit = virtio_ccw_rng_exit;
+    k->exit = virtio_ccw_exit;
     dc->reset = virtio_ccw_reset;
     dc->props = virtio_ccw_rng_properties;
 }
 
 static const TypeInfo virtio_ccw_rng = {
-    .name          = "virtio-rng-ccw",
+    .name          = TYPE_VIRTIO_RNG_CCW,
     .parent        = TYPE_VIRTIO_CCW_DEVICE,
-    .instance_size = sizeof(VirtioCcwDevice),
-    .instance_init = virtio_ccw_rng_initfn,
+    .instance_size = sizeof(VirtIORNGCcw),
+    .instance_init = virtio_ccw_rng_instance_init,
     .class_init    = virtio_ccw_rng_class_init,
 };
 
@@ -1067,7 +1052,7 @@
 
 /* virtio-ccw-bus */
 
-void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev)
+static void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev)
 {
     DeviceState *qdev = DEVICE(dev);
     BusState *qbus;
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 84055e7..04ba1b9 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -60,8 +60,6 @@
 
 typedef struct VirtioCcwDevice VirtioCcwDevice;
 
-void virtio_ccw_bus_new(VirtioBusState *bus, VirtioCcwDevice *dev);
-
 typedef struct VirtIOCCWDeviceClass {
     DeviceClass parent_class;
     int (*init)(VirtioCcwDevice *dev);
@@ -77,7 +75,6 @@
     VirtIODevice *vdev;
     char *bus_id;
     uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
-    VirtIORNGConf rng;
     VirtioBusState bus;
     /* Guest provided values: */
     hwaddr indicators;
@@ -160,6 +157,17 @@
     VirtIONet vdev;
 } VirtIONetCcw;
 
+/* virtio-rng-ccw */
+
+#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw"
+#define VIRTIO_RNG_CCW(obj) \
+        OBJECT_CHECK(VirtIORNGCcw, (obj), TYPE_VIRTIO_RNG_CCW)
+
+typedef struct VirtIORNGCcw {
+    VirtioCcwDevice parent_obj;
+    VirtIORNG vdev;
+} VirtIORNGCcw;
+
 VirtualCssBus *virtual_css_bus_init(void);
 void virtio_ccw_device_update_status(SubchDev *sch);
 VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch);
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 3dd1a0f..d7a1c33 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -22,6 +22,7 @@
 #include "hw/virtio/vhost-scsi.h"
 #include "hw/virtio/vhost.h"
 #include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/virtio-bus.h"
 
 static int vhost_scsi_set_endpoint(VHostSCSI *s)
 {
@@ -52,8 +53,10 @@
 {
     int ret, abi_version, i;
     VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
-    if (!vdev->binding->set_guest_notifiers) {
+    if (!k->set_guest_notifiers) {
         error_report("binding does not support guest notifiers");
         return -ENOSYS;
     }
@@ -88,7 +91,7 @@
         goto err_vhost_stop;
     }
 
-    ret = vdev->binding->set_guest_notifiers(vdev->binding_opaque, s->dev.nvqs, true);
+    ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
     if (ret < 0) {
         error_report("Error binding guest notifier");
         goto err_endpoint;
@@ -116,11 +119,12 @@
 static void vhost_scsi_stop(VHostSCSI *s)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     int ret = 0;
 
-    if (!vdev->binding->set_guest_notifiers) {
-        ret = vdev->binding->set_guest_notifiers(vdev->binding_opaque,
-                                                 s->dev.nvqs, false);
+    if (!k->set_guest_notifiers) {
+        ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
         if (ret < 0) {
                 error_report("vhost guest notifier cleanup failed: %d\n", ret);
         }
@@ -217,10 +221,6 @@
         return ret;
     }
 
-    vdev->get_features = vhost_scsi_get_features;
-    vdev->set_config = vhost_scsi_set_config;
-    vdev->set_status = vhost_scsi_set_status;
-
     s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
     s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
     s->dev.vq_index = 0;
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 051daea..84b3ac7 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -599,8 +599,6 @@
     s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
     s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
 
-    vdev->get_config = virtio_scsi_get_config;
-
     s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
                                   virtio_scsi_handle_ctrl);
     s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
@@ -626,10 +624,6 @@
         return ret;
     }
 
-    vdev->get_features = virtio_scsi_get_features;
-    vdev->set_config = virtio_scsi_set_config;
-    vdev->reset = virtio_scsi_reset;
-
     scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info);
     if (!qdev->hotplugged) {
         scsi_bus_legacy_handle_cmdline(&s->bus);
@@ -646,7 +640,7 @@
     VirtIODevice *vdev = VIRTIO_DEVICE(vs);
 
     g_free(vs->cmd_vqs);
-    virtio_common_cleanup(vdev);
+    virtio_cleanup(vdev);
     return 0;
 }
 
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 40feab4..fbabf99 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -19,6 +19,7 @@
 #include "qemu/range.h"
 #include <linux/vhost.h>
 #include "exec/address-spaces.h"
+#include "hw/virtio/virtio-bus.h"
 
 static void vhost_dev_sync_region(struct vhost_dev *dev,
                                   MemoryRegionSection *section,
@@ -892,9 +893,13 @@
 
 bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
-    return !vdev->binding->query_guest_notifiers ||
-        vdev->binding->query_guest_notifiers(vdev->binding_opaque) ||
-        hdev->force;
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusState *vbus = VIRTIO_BUS(qbus);
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
+
+    return !k->query_guest_notifiers ||
+           k->query_guest_notifiers(qbus->parent) ||
+           hdev->force;
 }
 
 /* Stop processing guest IO notifications in qemu.
@@ -902,17 +907,18 @@
  */
 int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusState *vbus = VIRTIO_BUS(qbus);
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
     int i, r;
-    if (!vdev->binding->set_host_notifier) {
+    if (!k->set_host_notifier) {
         fprintf(stderr, "binding does not support host notifiers\n");
         r = -ENOSYS;
         goto fail;
     }
 
     for (i = 0; i < hdev->nvqs; ++i) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             true);
+        r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, true);
         if (r < 0) {
             fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
             goto fail_vq;
@@ -922,9 +928,7 @@
     return 0;
 fail_vq:
     while (--i >= 0) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             false);
+        r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
         if (r < 0) {
             fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
             fflush(stderr);
@@ -942,12 +946,13 @@
  */
 void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
 {
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusState *vbus = VIRTIO_BUS(qbus);
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
     int i, r;
 
     for (i = 0; i < hdev->nvqs; ++i) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             false);
+        r = k->set_host_notifier(qbus->parent, hdev->vq_index + i, false);
         if (r < 0) {
             fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
             fflush(stderr);
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 76e32ce..d669756 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -344,15 +344,11 @@
 
     virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
 
-    vdev->get_config = virtio_balloon_get_config;
-    vdev->set_config = virtio_balloon_set_config;
-    vdev->get_features = virtio_balloon_get_features;
-
     ret = qemu_add_balloon_handler(virtio_balloon_to_target,
                                    virtio_balloon_stat, s);
 
     if (ret < 0) {
-        virtio_common_cleanup(VIRTIO_DEVICE(s));
+        virtio_cleanup(VIRTIO_DEVICE(s));
         return -1;
     }
 
@@ -381,7 +377,7 @@
     balloon_stats_destroy_timer(s);
     qemu_remove_balloon_handler(s);
     unregister_savevm(qdev, "virtio-balloon", s);
-    virtio_common_cleanup(vdev);
+    virtio_cleanup(vdev);
     return 0;
 }
 
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index 1596a1c..aab72ff 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -48,23 +48,6 @@
 
     bus->vdev = vdev;
 
-    /*
-     * The lines below will disappear when we drop VirtIOBindings, at the end
-     * of the series.
-     */
-    bus->bindings.notify = klass->notify;
-    bus->bindings.save_config = klass->save_config;
-    bus->bindings.save_queue = klass->save_queue;
-    bus->bindings.load_config = klass->load_config;
-    bus->bindings.load_queue = klass->load_queue;
-    bus->bindings.load_done = klass->load_done;
-    bus->bindings.get_features = klass->get_features;
-    bus->bindings.query_guest_notifiers = klass->query_guest_notifiers;
-    bus->bindings.set_guest_notifiers = klass->set_guest_notifiers;
-    bus->bindings.set_host_notifier = klass->set_host_notifier;
-    bus->bindings.vmstate_change = klass->vmstate_change;
-    virtio_bind_device(bus->vdev, &bus->bindings, qbus->parent);
-
     if (klass->device_plugged != NULL) {
         klass->device_plugged(qbus->parent);
     }
@@ -124,6 +107,18 @@
     return k->get_features(bus->vdev, requested_features);
 }
 
+/* Set the features of the plugged device. */
+void virtio_bus_set_vdev_features(VirtioBusState *bus,
+                                      uint32_t requested_features)
+{
+    VirtioDeviceClass *k;
+    assert(bus->vdev != NULL);
+    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
+    if (k->set_features != NULL) {
+        k->set_features(bus->vdev, requested_features);
+    }
+}
+
 /* Get bad features of the plugged device. */
 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
 {
@@ -148,6 +143,17 @@
     }
 }
 
+/* Set config of the plugged device. */
+void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
+{
+    VirtioDeviceClass *k;
+    assert(bus->vdev != NULL);
+    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
+    if (k->set_config != NULL) {
+        k->set_config(bus->vdev, config);
+    }
+}
+
 static const TypeInfo virtio_bus_info = {
     .name = TYPE_VIRTIO_BUS,
     .parent = TYPE_BUS,
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index a1f15a8..41bb41e 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -98,6 +98,8 @@
 /* HACK for virtio to determine if it's running a big endian guest */
 bool virtio_is_big_endian(void);
 
+static void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev);
+
 /* virtio device */
 /* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
 static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
@@ -257,15 +259,6 @@
     proxy->ioeventfd_started = false;
 }
 
-static void virtio_pci_reset(DeviceState *d)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_reset(proxy->vdev);
-    msix_unuse_all_vectors(&proxy->pci_dev);
-    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-}
-
 static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     VirtIOPCIProxy *proxy = opaque;
@@ -274,10 +267,10 @@
 
     switch (addr) {
     case VIRTIO_PCI_GUEST_FEATURES:
-	/* Guest does not negotiate properly?  We have to assume nothing. */
-	if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
-            val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
-	}
+        /* Guest does not negotiate properly?  We have to assume nothing. */
+        if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
+            val = virtio_bus_get_vdev_bad_features(&proxy->bus);
+        }
         virtio_set_features(vdev, val);
         break;
     case VIRTIO_PCI_QUEUE_PFN:
@@ -542,6 +535,7 @@
 {
     PCIDevice *dev = &proxy->pci_dev;
     VirtIODevice *vdev = proxy->vdev;
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     unsigned int vector;
     int ret, queue_no;
     MSIMessage msg;
@@ -562,7 +556,7 @@
         /* If guest supports masking, set up irqfd now.
          * Otherwise, delay until unmasked in the frontend.
          */
-        if (proxy->vdev->guest_notifier_mask) {
+        if (k->guest_notifier_mask) {
             ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
             if (ret < 0) {
                 kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -578,7 +572,7 @@
         if (vector >= msix_nr_vectors_allocated(dev)) {
             continue;
         }
-        if (proxy->vdev->guest_notifier_mask) {
+        if (k->guest_notifier_mask) {
             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
         }
         kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -592,6 +586,7 @@
     VirtIODevice *vdev = proxy->vdev;
     unsigned int vector;
     int queue_no;
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
 
     for (queue_no = 0; queue_no < nvqs; queue_no++) {
         if (!virtio_queue_get_num(vdev, queue_no)) {
@@ -604,7 +599,7 @@
         /* If guest supports masking, clean up irqfd now.
          * Otherwise, it was cleaned when masked in the frontend.
          */
-        if (proxy->vdev->guest_notifier_mask) {
+        if (k->guest_notifier_mask) {
             kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
         }
         kvm_virtio_pci_vq_vector_release(proxy, vector);
@@ -616,6 +611,7 @@
                                        unsigned int vector,
                                        MSIMessage msg)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
     VirtIOIRQFD *irqfd;
@@ -634,11 +630,11 @@
     /* If guest supports masking, irqfd is already setup, unmask it.
      * Otherwise, set it up now.
      */
-    if (proxy->vdev->guest_notifier_mask) {
-        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false);
+    if (k->guest_notifier_mask) {
+        k->guest_notifier_mask(proxy->vdev, queue_no, false);
         /* Test after unmasking to avoid losing events. */
-        if (proxy->vdev->guest_notifier_pending &&
-            proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) {
+        if (k->guest_notifier_pending &&
+            k->guest_notifier_pending(proxy->vdev, queue_no)) {
             event_notifier_set(n);
         }
     } else {
@@ -651,11 +647,13 @@
                                              unsigned int queue_no,
                                              unsigned int vector)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev);
+
     /* If guest supports masking, keep irqfd but mask it.
      * Otherwise, clean it up now.
      */ 
-    if (proxy->vdev->guest_notifier_mask) {
-        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
+    if (k->guest_notifier_mask) {
+        k->guest_notifier_mask(proxy->vdev, queue_no, true);
     } else {
         kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
     }
@@ -715,6 +713,7 @@
 {
     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
     VirtIODevice *vdev = proxy->vdev;
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     int queue_no;
     unsigned int vector;
     EventNotifier *notifier;
@@ -731,8 +730,8 @@
         }
         vq = virtio_get_queue(vdev, queue_no);
         notifier = virtio_queue_get_guest_notifier(vq);
-        if (vdev->guest_notifier_pending) {
-            if (vdev->guest_notifier_pending(vdev, queue_no)) {
+        if (k->guest_notifier_pending) {
+            if (k->guest_notifier_pending(vdev, queue_no)) {
                 msix_set_pending(dev, vector);
             }
         } else if (event_notifier_test_and_clear(notifier)) {
@@ -772,6 +771,7 @@
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
     VirtIODevice *vdev = proxy->vdev;
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     int r, n;
     bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
         kvm_msi_via_irqfd_enabled();
@@ -786,7 +786,7 @@
     proxy->nvqs_with_notifiers = nvqs;
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
+    if ((proxy->vector_irqfd || k->guest_notifier_mask) && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
         if (proxy->vector_irqfd) {
             kvm_virtio_pci_vector_release(proxy, nvqs);
@@ -808,7 +808,7 @@
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
+    if ((with_irqfd || k->guest_notifier_mask) && assign) {
         if (with_irqfd) {
             proxy->vector_irqfd =
                 g_malloc0(sizeof(*proxy->vector_irqfd) *
@@ -879,149 +879,6 @@
     }
 }
 
-static const VirtIOBindings virtio_pci_bindings = {
-    .notify = virtio_pci_notify,
-    .save_config = virtio_pci_save_config,
-    .load_config = virtio_pci_load_config,
-    .save_queue = virtio_pci_save_queue,
-    .load_queue = virtio_pci_load_queue,
-    .get_features = virtio_pci_get_features,
-    .query_guest_notifiers = virtio_pci_query_guest_notifiers,
-    .set_host_notifier = virtio_pci_set_host_notifier,
-    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
-    .vmstate_change = virtio_pci_vmstate_change,
-};
-
-void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
-{
-    uint8_t *config;
-    uint32_t size;
-
-    proxy->vdev = vdev;
-
-    config = proxy->pci_dev.config;
-
-    if (proxy->class_code) {
-        pci_config_set_class(config, proxy->class_code);
-    }
-    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
-                 pci_get_word(config + PCI_VENDOR_ID));
-    pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id);
-    config[PCI_INTERRUPT_PIN] = 1;
-
-    if (vdev->nvectors &&
-        msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) {
-        vdev->nvectors = 0;
-    }
-
-    proxy->pci_dev.config_write = virtio_write_config;
-
-    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
-    if (size & (size-1))
-        size = 1 << qemu_fls(size);
-
-    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
-                          "virtio-pci", size);
-    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                     &proxy->bar);
-
-    if (!kvm_has_many_ioeventfds()) {
-        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
-    }
-
-    virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy));
-    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
-    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
-    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
-}
-
-static void virtio_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    memory_region_destroy(&proxy->bar);
-    msix_uninit_exclusive_bar(pci_dev);
-}
-
-static int virtio_rng_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    if (proxy->rng.rng == NULL) {
-        proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
-
-        object_property_add_child(OBJECT(pci_dev),
-                                  "default-backend",
-                                  OBJECT(proxy->rng.default_backend),
-                                  NULL);
-
-        object_property_set_link(OBJECT(pci_dev),
-                                 OBJECT(proxy->rng.default_backend),
-                                 "rng", NULL);
-    }
-
-    vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
-    if (!vdev) {
-        return -1;
-    }
-    virtio_init_pci(proxy, vdev);
-    return 0;
-}
-
-static void virtio_rng_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_rng_exit(proxy->vdev);
-    virtio_exit_pci(pci_dev);
-}
-
-static void virtio_rng_initfn(Object *obj)
-{
-    PCIDevice *pci_dev = PCI_DEVICE(obj);
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
-                             (Object **)&proxy->rng.rng, NULL);
-}
-
-static Property virtio_rng_properties[] = {
-    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-    /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
-       you have an entropy source capable of generating more entropy than this
-       and you can pass it through via virtio-rng, then hats off to you.  Until
-       then, this is unlimited for all practical purposes.
-    */
-    DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
-    DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_rng_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_rng_init_pci;
-    k->exit = virtio_rng_exit_pci;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_OTHERS;
-    dc->reset = virtio_pci_reset;
-    dc->props = virtio_rng_properties;
-}
-
-static const TypeInfo virtio_rng_info = {
-    .name          = "virtio-rng-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .instance_init = virtio_rng_initfn,
-    .class_init    = virtio_rng_class_init,
-};
-
 #ifdef CONFIG_VIRTFS
 static int virtio_9p_init_pci(VirtIOPCIProxy *vpci_dev)
 {
@@ -1140,14 +997,11 @@
 {
     VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
     virtio_pci_stop_ioeventfd(proxy);
-    virtio_exit_pci(pci_dev);
+    memory_region_destroy(&proxy->bar);
+    msix_uninit_exclusive_bar(pci_dev);
 }
 
-/*
- * This will be renamed virtio_pci_reset at the end of the series.
- * virtio_pci_reset is still in use at this moment.
- */
-static void virtio_pci_rst(DeviceState *qdev)
+static void virtio_pci_reset(DeviceState *qdev)
 {
     VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
     VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
@@ -1167,7 +1021,7 @@
     k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
     k->revision = VIRTIO_PCI_ABI_VERSION;
     k->class_id = PCI_CLASS_OTHERS;
-    dc->reset = virtio_pci_rst;
+    dc->reset = virtio_pci_reset;
 }
 
 static const TypeInfo virtio_pci_info = {
@@ -1556,9 +1410,67 @@
     .class_init    = virtio_net_pci_class_init,
 };
 
+/* virtio-rng-pci */
+
+static Property virtio_rng_pci_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORngPCI, vdev.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_rng_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIORngPCI *vrng = VIRTIO_RNG_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&vrng->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+
+    object_property_set_link(OBJECT(vrng),
+                             OBJECT(vrng->vdev.conf.default_backend), "rng",
+                             NULL);
+
+    return 0;
+}
+
+static void virtio_rng_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_rng_pci_init;
+    dc->props = virtio_rng_pci_properties;
+
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_rng_initfn(Object *obj)
+{
+    VirtIORngPCI *dev = VIRTIO_RNG_PCI(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_RNG);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+                             (Object **)&dev->vdev.conf.rng, NULL);
+
+}
+
+static const TypeInfo virtio_rng_pci_info = {
+    .name          = TYPE_VIRTIO_RNG_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIORngPCI),
+    .instance_init = virtio_rng_initfn,
+    .class_init    = virtio_rng_pci_class_init,
+};
+
 /* virtio-pci-bus */
 
-void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
+static void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
 {
     DeviceState *qdev = DEVICE(dev);
     BusState *qbus;
@@ -1594,7 +1506,7 @@
 
 static void virtio_pci_register_types(void)
 {
-    type_register_static(&virtio_rng_info);
+    type_register_static(&virtio_rng_pci_info);
     type_register_static(&virtio_pci_bus_info);
     type_register_static(&virtio_pci_info);
 #ifdef CONFIG_VIRTFS
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index db0185c..917bcc5 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -38,6 +38,7 @@
 typedef struct VirtIOSerialPCI VirtIOSerialPCI;
 typedef struct VirtIONetPCI VirtIONetPCI;
 typedef struct VHostSCSIPCI VHostSCSIPCI;
+typedef struct VirtIORngPCI VirtIORngPCI;
 
 /* virtio-pci-bus */
 
@@ -87,7 +88,6 @@
     uint32_t class_code;
     uint32_t nvectors;
     uint32_t host_features;
-    VirtIORNGConf rng;
     bool ioeventfd_disabled;
     bool ioeventfd_started;
     VirtIOIRQFD *vector_irqfd;
@@ -188,8 +188,17 @@
 
 #endif
 
-void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
-void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev);
+/*
+ * virtio-rng-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_RNG_PCI "virtio-rng-pci"
+#define VIRTIO_RNG_PCI(obj) \
+        OBJECT_CHECK(VirtIORngPCI, (obj), TYPE_VIRTIO_RNG_PCI)
+
+struct VirtIORngPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIORNG vdev;
+};
 
 /* Virtio ABI version, if we increment this, we break the guest driver. */
 #define VIRTIO_PCI_ABI_VERSION          0
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index fcc223a..cb787c7 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -18,8 +18,9 @@
 
 static bool is_guest_ready(VirtIORNG *vrng)
 {
+    VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
     if (virtio_queue_ready(vrng->vq)
-        && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
         return true;
     }
     return false;
@@ -39,6 +40,7 @@
 static void chr_read(void *opaque, const void *buf, size_t size)
 {
     VirtIORNG *vrng = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
     VirtQueueElement elem;
     size_t len;
     int offset;
@@ -60,7 +62,7 @@
 
         virtqueue_push(vrng->vq, &elem, len);
     }
-    virtio_notify(&vrng->vdev, vrng->vq);
+    virtio_notify(vdev, vrng->vq);
 }
 
 static void virtio_rng_process(VirtIORNG *vrng)
@@ -86,7 +88,7 @@
 
 static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
 {
-    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+    VirtIORNG *vrng = VIRTIO_RNG(vdev);
     virtio_rng_process(vrng);
 }
 
@@ -97,19 +99,20 @@
 
 static void virtio_rng_save(QEMUFile *f, void *opaque)
 {
-    VirtIORNG *vrng = opaque;
+    VirtIODevice *vdev = opaque;
 
-    virtio_save(&vrng->vdev, f);
+    virtio_save(vdev, f);
 }
 
 static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
 {
     VirtIORNG *vrng = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(vrng);
 
     if (version_id != 1) {
         return -EINVAL;
     }
-    virtio_load(&vrng->vdev, f);
+    virtio_load(vdev, f);
 
     /* We may have an element ready but couldn't process it due to a quota
      * limit.  Make sure to try again after live migration when the quota may
@@ -122,66 +125,111 @@
 
 static void check_rate_limit(void *opaque)
 {
-    VirtIORNG *s = opaque;
+    VirtIORNG *vrng = opaque;
 
-    s->quota_remaining = s->conf->max_bytes;
-    virtio_rng_process(s);
-    qemu_mod_timer(s->rate_limit_timer,
-                   qemu_get_clock_ms(vm_clock) + s->conf->period_ms);
+    vrng->quota_remaining = vrng->conf.max_bytes;
+    virtio_rng_process(vrng);
+    qemu_mod_timer(vrng->rate_limit_timer,
+                   qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
 }
 
-
-VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
+static int virtio_rng_device_init(VirtIODevice *vdev)
 {
-    VirtIORNG *vrng;
-    VirtIODevice *vdev;
+    DeviceState *qdev = DEVICE(vdev);
+    VirtIORNG *vrng = VIRTIO_RNG(vdev);
     Error *local_err = NULL;
 
-    vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
-                              sizeof(VirtIORNG));
+    if (vrng->conf.rng == NULL) {
+        vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
 
-    vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+        object_property_add_child(OBJECT(qdev),
+                                  "default-backend",
+                                  OBJECT(vrng->conf.default_backend),
+                                  NULL);
 
-    vrng->rng = conf->rng;
+        object_property_set_link(OBJECT(qdev),
+                                 OBJECT(vrng->conf.default_backend),
+                                 "rng", NULL);
+    }
+
+    virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
+
+    vrng->rng = vrng->conf.rng;
     if (vrng->rng == NULL) {
         qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
-        return NULL;
+        return -1;
     }
 
     rng_backend_open(vrng->rng, &local_err);
     if (local_err) {
         qerror_report_err(local_err);
         error_free(local_err);
-        return NULL;
+        return -1;
     }
 
     vrng->vq = virtio_add_queue(vdev, 8, handle_input);
-    vrng->vdev.get_features = get_features;
 
-    vrng->qdev = dev;
-    vrng->conf = conf;
-
-    assert(vrng->conf->max_bytes <= INT64_MAX);
-    vrng->quota_remaining = vrng->conf->max_bytes;
+    assert(vrng->conf.max_bytes <= INT64_MAX);
+    vrng->quota_remaining = vrng->conf.max_bytes;
 
     vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
                                                check_rate_limit, vrng);
 
     qemu_mod_timer(vrng->rate_limit_timer,
-                   qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms);
+                   qemu_get_clock_ms(vm_clock) + vrng->conf.period_ms);
 
-    register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
+    register_savevm(qdev, "virtio-rng", -1, 1, virtio_rng_save,
                     virtio_rng_load, vrng);
 
-    return vdev;
+    return 0;
 }
 
-void virtio_rng_exit(VirtIODevice *vdev)
+static int virtio_rng_device_exit(DeviceState *qdev)
 {
-    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+    VirtIORNG *vrng = VIRTIO_RNG(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
 
     qemu_del_timer(vrng->rate_limit_timer);
     qemu_free_timer(vrng->rate_limit_timer);
-    unregister_savevm(vrng->qdev, "virtio-rng", vrng);
+    unregister_savevm(qdev, "virtio-rng", vrng);
     virtio_cleanup(vdev);
+    return 0;
 }
+
+static Property virtio_rng_properties[] = {
+    DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNG, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_rng_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    dc->exit = virtio_rng_device_exit;
+    dc->props = virtio_rng_properties;
+    vdc->init = virtio_rng_device_init;
+    vdc->get_features = get_features;
+}
+
+static void virtio_rng_initfn(Object *obj)
+{
+    VirtIORNG *vrng = VIRTIO_RNG(obj);
+
+    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+                             (Object **)&vrng->conf.rng, NULL);
+}
+
+static const TypeInfo virtio_rng_info = {
+    .name = TYPE_VIRTIO_RNG,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIORNG),
+    .instance_init = virtio_rng_initfn,
+    .class_init = virtio_rng_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_rng_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 1c2282c..0f88c25 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -507,8 +507,11 @@
 /* virtio device */
 static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
 {
-    if (vdev->binding->notify) {
-        vdev->binding->notify(vdev->binding_opaque, vector);
+    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+
+    if (k->notify) {
+        k->notify(qbus->parent, vector);
     }
 }
 
@@ -519,10 +522,11 @@
 
 void virtio_set_status(VirtIODevice *vdev, uint8_t val)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     trace_virtio_set_status(vdev, val);
 
-    if (vdev->set_status) {
-        vdev->set_status(vdev, val);
+    if (k->set_status) {
+        k->set_status(vdev, val);
     }
     vdev->status = val;
 }
@@ -530,12 +534,14 @@
 void virtio_reset(void *opaque)
 {
     VirtIODevice *vdev = opaque;
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     int i;
 
     virtio_set_status(vdev, 0);
 
-    if (vdev->reset)
-        vdev->reset(vdev);
+    if (k->reset) {
+        k->reset(vdev);
+    }
 
     vdev->guest_features = 0;
     vdev->queue_sel = 0;
@@ -559,9 +565,10 @@
 
 uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint8_t val;
 
-    vdev->get_config(vdev, vdev->config);
+    k->get_config(vdev, vdev->config);
 
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
@@ -572,9 +579,10 @@
 
 uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint16_t val;
 
-    vdev->get_config(vdev, vdev->config);
+    k->get_config(vdev, vdev->config);
 
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
@@ -585,9 +593,10 @@
 
 uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint32_t val;
 
-    vdev->get_config(vdev, vdev->config);
+    k->get_config(vdev, vdev->config);
 
     if (addr > (vdev->config_len - sizeof(val)))
         return (uint32_t)-1;
@@ -598,6 +607,7 @@
 
 void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint8_t val = data;
 
     if (addr > (vdev->config_len - sizeof(val)))
@@ -605,12 +615,14 @@
 
     stb_p(vdev->config + addr, val);
 
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
+    if (k->set_config) {
+        k->set_config(vdev, vdev->config);
+    }
 }
 
 void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint16_t val = data;
 
     if (addr > (vdev->config_len - sizeof(val)))
@@ -618,12 +630,14 @@
 
     stw_p(vdev->config + addr, val);
 
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
+    if (k->set_config) {
+        k->set_config(vdev, vdev->config);
+    }
 }
 
 void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
 {
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint32_t val = data;
 
     if (addr > (vdev->config_len - sizeof(val)))
@@ -631,8 +645,9 @@
 
     stl_p(vdev->config + addr, val);
 
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
+    if (k->set_config) {
+        k->set_config(vdev, vdev->config);
+    }
 }
 
 void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
@@ -777,10 +792,13 @@
 
 void virtio_save(VirtIODevice *vdev, QEMUFile *f)
 {
+    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     int i;
 
-    if (vdev->binding->save_config)
-        vdev->binding->save_config(vdev->binding_opaque, f);
+    if (k->save_config) {
+        k->save_config(qbus->parent, f);
+    }
 
     qemu_put_8s(f, &vdev->status);
     qemu_put_8s(f, &vdev->isr);
@@ -803,20 +821,23 @@
         qemu_put_be32(f, vdev->vq[i].vring.num);
         qemu_put_be64(f, vdev->vq[i].pa);
         qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
-        if (vdev->binding->save_queue)
-            vdev->binding->save_queue(vdev->binding_opaque, i, f);
+        if (k->save_queue) {
+            k->save_queue(qbus->parent, i, f);
+        }
     }
 }
 
 int virtio_set_features(VirtIODevice *vdev, uint32_t val)
 {
-    uint32_t supported_features =
-        vdev->binding->get_features(vdev->binding_opaque);
+    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+    VirtioBusClass *vbusk = VIRTIO_BUS_GET_CLASS(qbus);
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+    uint32_t supported_features = vbusk->get_features(qbus->parent);
     bool bad = (val & ~supported_features) != 0;
 
     val &= supported_features;
-    if (vdev->set_features) {
-        vdev->set_features(vdev, val);
+    if (k->set_features) {
+        k->set_features(vdev, val);
     }
     vdev->guest_features = val;
     return bad ? -1 : 0;
@@ -827,9 +848,11 @@
     int num, i, ret;
     uint32_t features;
     uint32_t supported_features;
+    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
-    if (vdev->binding->load_config) {
-        ret = vdev->binding->load_config(vdev->binding_opaque, f);
+    if (k->load_config) {
+        ret = k->load_config(qbus->parent, f);
         if (ret)
             return ret;
     }
@@ -840,7 +863,7 @@
     qemu_get_be32s(f, &features);
 
     if (virtio_set_features(vdev, features) < 0) {
-        supported_features = vdev->binding->get_features(vdev->binding_opaque);
+        supported_features = k->get_features(qbus->parent);
         error_report("Features 0x%x unsupported. Allowed features: 0x%x",
                      features, supported_features);
         return -1;
@@ -876,8 +899,8 @@
                          i, vdev->vq[i].last_avail_idx);
                 return -1;
 	}
-        if (vdev->binding->load_queue) {
-            ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
+        if (k->load_queue) {
+            ret = k->load_queue(qbus->parent, i, f);
             if (ret)
                 return ret;
         }
@@ -887,22 +910,18 @@
     return 0;
 }
 
-void virtio_common_cleanup(VirtIODevice *vdev)
+void virtio_cleanup(VirtIODevice *vdev)
 {
     qemu_del_vm_change_state_handler(vdev->vmstate);
     g_free(vdev->config);
     g_free(vdev->vq);
 }
 
-void virtio_cleanup(VirtIODevice *vdev)
-{
-    virtio_common_cleanup(vdev);
-    g_free(vdev);
-}
-
 static void virtio_vmstate_change(void *opaque, int running, RunState state)
 {
     VirtIODevice *vdev = opaque;
+    BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
     vdev->vm_running = running;
 
@@ -910,8 +929,8 @@
         virtio_set_status(vdev, vdev->status);
     }
 
-    if (vdev->binding->vmstate_change) {
-        vdev->binding->vmstate_change(vdev->binding_opaque, backend_run);
+    if (k->vmstate_change) {
+        k->vmstate_change(qbus->parent, backend_run);
     }
 
     if (!backend_run) {
@@ -947,22 +966,6 @@
                                                      vdev);
 }
 
-VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size)
-{
-    VirtIODevice *vdev;
-    vdev = g_malloc0(struct_size);
-    virtio_init(vdev, name, device_id, config_size);
-    return vdev;
-}
-
-void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
-                        DeviceState *opaque)
-{
-    vdev->binding = binding;
-    vdev->binding_opaque = opaque;
-}
-
 hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
 {
     return vdev->vq[n].vring.desc;
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 85b82ee..b1fe71f 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -45,7 +45,7 @@
 } ICH9LPCPMRegs;
 
 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq, qemu_irq cmos_s3_resume);
+                  qemu_irq sci_irq);
 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
 extern const VMStateDescription vmstate_ich9_pm;
 
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 51d5981..c5f637b 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -18,7 +18,7 @@
 void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
 int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
 PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
-void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
+void ich9_lpc_pm_init(PCIDevice *pci_lpc);
 PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
 i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
 
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 56c71ed..2567879 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -31,6 +31,7 @@
     uint8_t leds;
     uint8_t key[16];
     int32_t keys;
+    QEMUPutKbdEntry *eh_entry;
 } HIDKeyboardState;
 
 struct HIDState {
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index 311e8c7..9ed60f9 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -70,10 +70,6 @@
      * Only one VirtIODevice can be plugged on the bus.
      */
     VirtIODevice *vdev;
-    /*
-     * This will be removed at the end of the series.
-     */
-    VirtIOBindings bindings;
 };
 
 int virtio_bus_plug_device(VirtIODevice *vdev);
@@ -86,9 +82,14 @@
 /* Get the features of the plugged device. */
 uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
                                     uint32_t requested_features);
+/* Set the features of the plugged device. */
+void virtio_bus_set_vdev_features(VirtioBusState *bus,
+                                  uint32_t requested_features);
 /* Get bad features of the plugged device. */
 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus);
 /* Get config of the plugged device. */
 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config);
+/* Set config of the plugged device. */
+void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config);
 
 #endif /* VIRTIO_BUS_H */
diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
index c9cadc2..debaa15 100644
--- a/include/hw/virtio/virtio-rng.h
+++ b/include/hw/virtio/virtio-rng.h
@@ -15,6 +15,10 @@
 #include "sysemu/rng.h"
 #include "sysemu/rng-random.h"
 
+#define TYPE_VIRTIO_RNG "virtio-rng-device"
+#define VIRTIO_RNG(obj) \
+        OBJECT_CHECK(VirtIORNG, (obj), TYPE_VIRTIO_RNG)
+
 /* The Virtio ID for the virtio rng device */
 #define VIRTIO_ID_RNG    4
 
@@ -26,14 +30,12 @@
 };
 
 typedef struct VirtIORNG {
-    VirtIODevice vdev;
-
-    DeviceState *qdev;
+    VirtIODevice parent_obj;
 
     /* Only one vq - guest puts buffer(s) on it when it needs entropy */
     VirtQueue *vq;
 
-    VirtIORNGConf *conf;
+    VirtIORNGConf conf;
 
     RngBackend *rng;
 
@@ -44,4 +46,14 @@
     int64_t quota_remaining;
 } VirtIORNG;
 
+/* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
+   you have an entropy source capable of generating more entropy than this
+   and you can pass it through via virtio-rng, then hats off to you.  Until
+   then, this is unlimited for all practical purposes.
+*/
+#define DEFINE_VIRTIO_RNG_PROPERTIES(_state, _conf_field)                    \
+        DEFINE_PROP_UINT64("max-bytes", _state, _conf_field.max_bytes,       \
+                           INT64_MAX),                                       \
+        DEFINE_PROP_UINT32("period", _state, _conf_field.period_ms, 1 << 16)
+
 #endif
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index d3f1436..ae7a4c4 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -90,20 +90,6 @@
     struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
 } VirtQueueElement;
 
-typedef struct {
-    void (*notify)(DeviceState *d, uint16_t vector);
-    void (*save_config)(DeviceState *d, QEMUFile *f);
-    void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_config)(DeviceState *d, QEMUFile *f);
-    int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_done)(DeviceState *d, QEMUFile *f);
-    unsigned (*get_features)(DeviceState *d);
-    bool (*query_guest_notifiers)(DeviceState *d);
-    int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assigned);
-    int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
-    void (*vmstate_change)(DeviceState *d, bool running);
-} VirtIOBindings;
-
 #define VIRTIO_PCI_QUEUE_MAX 64
 
 #define VIRTIO_NO_VECTOR 0xffff
@@ -128,33 +114,7 @@
     void *config;
     uint16_t config_vector;
     int nvectors;
-    /*
-     * Function pointers will be removed at the end of the series as they are in
-     * VirtioDeviceClass.
-     */
-    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
-    uint32_t (*bad_features)(VirtIODevice *vdev);
-    void (*set_features)(VirtIODevice *vdev, uint32_t val);
-    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
-    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
-    void (*reset)(VirtIODevice *vdev);
-    void (*set_status)(VirtIODevice *vdev, uint8_t val);
-    /* Test and clear event pending status.
-     * Should be called after unmask to avoid losing events.
-     * If backend does not support masking,
-     * must check in frontend instead.
-     */
-    bool (*guest_notifier_pending)(VirtIODevice *vdev, int n);
-    /* Mask/unmask events from this vq. Any events reported
-     * while masked will become pending.
-     * If backend does not support masking,
-     * must mask in frontend instead.
-     */
-    void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
-
     VirtQueue *vq;
-    const VirtIOBindings *binding;
-    DeviceState *binding_opaque;
     uint16_t device_id;
     bool vm_running;
     VMChangeStateEntry *vmstate;
@@ -187,7 +147,7 @@
 
 void virtio_init(VirtIODevice *vdev, const char *name,
                          uint16_t device_id, size_t config_size);
-void virtio_common_cleanup(VirtIODevice *vdev);
+void virtio_cleanup(VirtIODevice *vdev);
 
 VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
                             void (*handle_output)(VirtIODevice *,
@@ -216,8 +176,6 @@
 
 int virtio_load(VirtIODevice *vdev, QEMUFile *f);
 
-void virtio_cleanup(VirtIODevice *vdev);
-
 void virtio_notify_config(VirtIODevice *vdev);
 
 void virtio_queue_set_notification(VirtQueue *vq, int enable);
@@ -228,8 +186,6 @@
 
 /* Host binding interface.  */
 
-VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size);
 uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
 uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr);
 uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr);
@@ -247,9 +203,6 @@
 void virtio_update_irq(VirtIODevice *vdev);
 int virtio_set_features(VirtIODevice *vdev, uint32_t val);
 
-void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
-                        DeviceState *opaque);
-
 /* Base devices.  */
 typedef struct VirtIOBlkConf VirtIOBlkConf;
 struct virtio_net_conf;
@@ -257,20 +210,8 @@
                               struct virtio_net_conf *net,
                               uint32_t host_features);
 typedef struct virtio_serial_conf virtio_serial_conf;
-VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
 typedef struct VirtIOSCSIConf VirtIOSCSIConf;
-VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
 typedef struct VirtIORNGConf VirtIORNGConf;
-VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf);
-#ifdef CONFIG_VIRTFS
-VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
-#endif
-
-
-void virtio_net_exit(VirtIODevice *vdev);
-void virtio_serial_exit(VirtIODevice *vdev);
-void virtio_scsi_exit(VirtIODevice *vdev);
-void virtio_rng_exit(VirtIODevice *vdev);
 
 #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \
diff --git a/include/ui/console.h b/include/ui/console.h
index e591d74..1c82f51 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -28,26 +28,13 @@
 typedef void QEMUPutLEDEvent(void *opaque, int ledstate);
 typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
 
-typedef struct QEMUPutMouseEntry {
-    QEMUPutMouseEvent *qemu_put_mouse_event;
-    void *qemu_put_mouse_event_opaque;
-    int qemu_put_mouse_event_absolute;
-    char *qemu_put_mouse_event_name;
+typedef struct QEMUPutMouseEntry QEMUPutMouseEntry;
+typedef struct QEMUPutKbdEntry QEMUPutKbdEntry;
+typedef struct QEMUPutLEDEntry QEMUPutLEDEntry;
 
-    int index;
-
-    /* used internally by qemu for handling mice */
-    QTAILQ_ENTRY(QEMUPutMouseEntry) node;
-} QEMUPutMouseEntry;
-
-typedef struct QEMUPutLEDEntry {
-    QEMUPutLEDEvent *put_led;
-    void *opaque;
-    QTAILQ_ENTRY(QEMUPutLEDEntry) next;
-} QEMUPutLEDEntry;
-
-void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
-void qemu_remove_kbd_event_handler(void);
+QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func,
+                                            void *opaque);
+void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry);
 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
                                                 void *opaque, int absolute,
                                                 const char *name);
diff --git a/ui/input.c b/ui/input.c
index ecfeb43..8ca1a03 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -29,12 +29,37 @@
 #include "qmp-commands.h"
 #include "qapi-types.h"
 
-static QEMUPutKBDEvent *qemu_put_kbd_event;
-static void *qemu_put_kbd_event_opaque;
-static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
+struct QEMUPutMouseEntry {
+    QEMUPutMouseEvent *qemu_put_mouse_event;
+    void *qemu_put_mouse_event_opaque;
+    int qemu_put_mouse_event_absolute;
+    char *qemu_put_mouse_event_name;
+
+    int index;
+
+    /* used internally by qemu for handling mice */
+    QTAILQ_ENTRY(QEMUPutMouseEntry) node;
+};
+
+struct QEMUPutKbdEntry {
+    QEMUPutKBDEvent *put_kbd;
+    void *opaque;
+    QTAILQ_ENTRY(QEMUPutKbdEntry) next;
+};
+
+struct QEMUPutLEDEntry {
+    QEMUPutLEDEvent *put_led;
+    void *opaque;
+    QTAILQ_ENTRY(QEMUPutLEDEntry) next;
+};
+
+static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
+    QTAILQ_HEAD_INITIALIZER(led_handlers);
+static QTAILQ_HEAD(, QEMUPutKbdEntry) kbd_handlers =
+    QTAILQ_HEAD_INITIALIZER(kbd_handlers);
 static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
     QTAILQ_HEAD_INITIALIZER(mouse_handlers);
-static NotifierList mouse_mode_notifiers = 
+static NotifierList mouse_mode_notifiers =
     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
 
 static const int key_defs[] = {
@@ -286,16 +311,20 @@
                    muldiv64(get_ticks_per_sec(), hold_time, 1000));
 }
 
-void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
 {
-    qemu_put_kbd_event_opaque = opaque;
-    qemu_put_kbd_event = func;
+    QEMUPutKbdEntry *entry;
+
+    entry = g_malloc0(sizeof(QEMUPutKbdEntry));
+    entry->put_kbd = func;
+    entry->opaque = opaque;
+    QTAILQ_INSERT_HEAD(&kbd_handlers, entry, next);
+    return entry;
 }
 
-void qemu_remove_kbd_event_handler(void)
+void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry)
 {
-    qemu_put_kbd_event_opaque = NULL;
-    qemu_put_kbd_event = NULL;
+    QTAILQ_REMOVE(&kbd_handlers, entry, next);
 }
 
 static void check_mode_change(void)
@@ -379,11 +408,13 @@
 
 void kbd_put_keycode(int keycode)
 {
+    QEMUPutKbdEntry *entry = QTAILQ_FIRST(&kbd_handlers);
+
     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
         return;
     }
-    if (qemu_put_kbd_event) {
-        qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode);
+    if (entry) {
+        entry->put_kbd(entry->opaque, keycode);
     }
 }