diff mbox

[RFC,06/15] qdev: Add device_type field to BusClass

Message ID 1479777133-23567-7-git-send-email-ehabkost@redhat.com
State New
Headers show

Commit Message

Eduardo Habkost Nov. 22, 2016, 1:12 a.m. UTC
Each bus class will now be aware of the specific device type that
can be plugged on it.

Also add a read-only 'device-type' property to the class, that
will be useful for:

* Runtime check for which devices types can be plugged to the
  machine;
* Validation of query-machines output by automated tests.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/audio/intel-hda.c          |  7 +++++++
 hw/block/fdc.c                | 15 +++++++++++----
 hw/char/virtio-serial-bus.c   |  1 +
 hw/core/bus.c                 |  9 +++++++++
 hw/core/sysbus.c              |  1 +
 hw/i2c/core.c                 |  7 +++++++
 hw/ide/qdev.c                 |  1 +
 hw/input/adb.c                |  7 +++++++
 hw/ipack/ipack.c              |  7 +++++++
 hw/isa/isa-bus.c              |  1 +
 hw/misc/auxbus.c              |  1 +
 hw/pci/pci.c                  |  1 +
 hw/ppc/spapr_vio.c            |  1 +
 hw/s390x/css-bridge.c         |  2 ++
 hw/s390x/event-facility.c     |  1 +
 hw/s390x/s390-pci-bus.c       |  7 +++++++
 hw/scsi/scsi-bus.c            |  1 +
 hw/sd/core.c                  |  7 +++++++
 hw/ssi/ssi.c                  |  7 +++++++
 hw/usb/bus.c                  |  1 +
 hw/usb/dev-smartcard-reader.c |  7 +++++++
 hw/virtio/virtio-bus.c        |  1 +
 include/hw/qdev-core.h        |  2 ++
 23 files changed, 91 insertions(+), 4 deletions(-)

Comments

Cornelia Huck Nov. 24, 2016, 4:48 p.m. UTC | #1
On Mon, 21 Nov 2016 23:12:04 -0200
Eduardo Habkost <ehabkost@redhat.com> wrote:

<s390 glasses on>

> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 24fae16..74b8fef 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -152,6 +152,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
>      k->realize = pci_bus_realize;
>      k->unrealize = pci_bus_unrealize;
>      k->reset = pcibus_reset;
> +    k->device_type = TYPE_PCI_DEVICE;

This covers pci-per-se...

> 
>      pbc->is_root = pcibus_is_root;
>      pbc->bus_num = pcibus_num;

> diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
> index 9a7f7ee..8a6c1ae 100644
> --- a/hw/s390x/css-bridge.c
> +++ b/hw/s390x/css-bridge.c
> @@ -17,6 +17,7 @@
>  #include "hw/s390x/css.h"
>  #include "ccw-device.h"
>  #include "hw/s390x/css-bridge.h"
> +#include "hw/s390x/virtio-ccw.h"
> 
>  /*
>   * Invoke device-specific unplug handler, disable the subchannel
> @@ -81,6 +82,7 @@ static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
> 
>      k->reset = virtual_css_bus_reset;
>      k->get_dev_path = virtual_css_bus_get_dev_path;
> +    k->device_type = TYPE_VIRTIO_CCW_DEVICE;

...this covers virtio-ccw... (notably _not_ generic css)

>  }
> 
>  static const TypeInfo virtual_css_bus_info = {

> diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
> index 63f6248..7470fdd 100644
> --- a/hw/s390x/s390-pci-bus.c
> +++ b/hw/s390x/s390-pci-bus.c
> @@ -783,10 +783,17 @@ static const TypeInfo s390_pcihost_info = {
>      }
>  };
> 
> +static void s390_pcibus_class_init(ObjectClass *oc, void *opaque)
> +{
> +    BusClass *bc = BUS_CLASS(oc);
> +    bc->device_type = TYPE_S390_PCI_DEVICE;

...this covers zpci, which is needed _in addition to_ normal pci to make pci work on s390...

> +}
> +
>  static const TypeInfo s390_pcibus_info = {
>      .name = TYPE_S390_PCI_BUS,
>      .parent = TYPE_BUS,
>      .instance_size = sizeof(S390PCIBus),
> +    .class_init = s390_pcibus_class_init,
>  };
> 
>  static uint16_t s390_pci_generate_uid(void)

> diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
> index d6c0c72..815f3dd 100644
> --- a/hw/virtio/virtio-bus.c
> +++ b/hw/virtio/virtio-bus.c
> @@ -293,6 +293,7 @@ static void virtio_bus_class_init(ObjectClass *klass, void *data)
>      BusClass *bus_class = BUS_CLASS(klass);
>      bus_class->get_dev_path = virtio_bus_get_dev_path;
>      bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
> +    bus_class->device_type = TYPE_VIRTIO_DEVICE;
>  }
> 
>  static const TypeInfo virtio_bus_info = {

...and this covers virtio, which is kind of a glue bus.

So on s390, we have the following:

- to get virtio-ccw, we need virtio-ccw _and_ virtio
- to get virtio-pci, we need pci _and_ zpci _and_ virtio
- to get virtio-per-se, we need one of the combinations above

Please stop me if I'm babbling, but there seem to be some
interdependencies which are different on different architectures and
I'm not sure how these should be modelled.
Eduardo Habkost Nov. 24, 2016, 5:37 p.m. UTC | #2
On Thu, Nov 24, 2016 at 05:48:20PM +0100, Cornelia Huck wrote:
> On Mon, 21 Nov 2016 23:12:04 -0200
> Eduardo Habkost <ehabkost@redhat.com> wrote:
> 
> <s390 glasses on>
> 
> > diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> > index 24fae16..74b8fef 100644
> > --- a/hw/pci/pci.c
> > +++ b/hw/pci/pci.c
> > @@ -152,6 +152,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
> >      k->realize = pci_bus_realize;
> >      k->unrealize = pci_bus_unrealize;
> >      k->reset = pcibus_reset;
> > +    k->device_type = TYPE_PCI_DEVICE;
> 
> This covers pci-per-se...
> 
> > 
> >      pbc->is_root = pcibus_is_root;
> >      pbc->bus_num = pcibus_num;
> 
> > diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
> > index 9a7f7ee..8a6c1ae 100644
> > --- a/hw/s390x/css-bridge.c
> > +++ b/hw/s390x/css-bridge.c
> > @@ -17,6 +17,7 @@
> >  #include "hw/s390x/css.h"
> >  #include "ccw-device.h"
> >  #include "hw/s390x/css-bridge.h"
> > +#include "hw/s390x/virtio-ccw.h"
> > 
> >  /*
> >   * Invoke device-specific unplug handler, disable the subchannel
> > @@ -81,6 +82,7 @@ static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
> > 
> >      k->reset = virtual_css_bus_reset;
> >      k->get_dev_path = virtual_css_bus_get_dev_path;
> > +    k->device_type = TYPE_VIRTIO_CCW_DEVICE;
> 
> ...this covers virtio-ccw... (notably _not_ generic css)
> 
> >  }
> > 
> >  static const TypeInfo virtual_css_bus_info = {
> 
> > diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
> > index 63f6248..7470fdd 100644
> > --- a/hw/s390x/s390-pci-bus.c
> > +++ b/hw/s390x/s390-pci-bus.c
> > @@ -783,10 +783,17 @@ static const TypeInfo s390_pcihost_info = {
> >      }
> >  };
> > 
> > +static void s390_pcibus_class_init(ObjectClass *oc, void *opaque)
> > +{
> > +    BusClass *bc = BUS_CLASS(oc);
> > +    bc->device_type = TYPE_S390_PCI_DEVICE;
> 
> ...this covers zpci, which is needed _in addition to_ normal pci to make pci work on s390...
> 
> > +}
> > +
> >  static const TypeInfo s390_pcibus_info = {
> >      .name = TYPE_S390_PCI_BUS,
> >      .parent = TYPE_BUS,
> >      .instance_size = sizeof(S390PCIBus),
> > +    .class_init = s390_pcibus_class_init,
> >  };
> > 
> >  static uint16_t s390_pci_generate_uid(void)
> 
> > diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
> > index d6c0c72..815f3dd 100644
> > --- a/hw/virtio/virtio-bus.c
> > +++ b/hw/virtio/virtio-bus.c
> > @@ -293,6 +293,7 @@ static void virtio_bus_class_init(ObjectClass *klass, void *data)
> >      BusClass *bus_class = BUS_CLASS(klass);
> >      bus_class->get_dev_path = virtio_bus_get_dev_path;
> >      bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
> > +    bus_class->device_type = TYPE_VIRTIO_DEVICE;
> >  }
> > 
> >  static const TypeInfo virtio_bus_info = {
> 
> ...and this covers virtio, which is kind of a glue bus.
> 
> So on s390, we have the following:
> 
> - to get virtio-ccw, we need virtio-ccw _and_ virtio
> - to get virtio-pci, we need pci _and_ zpci _and_ virtio
> - to get virtio-per-se, we need one of the combinations above
> 
> Please stop me if I'm babbling, but there seem to be some
> interdependencies which are different on different architectures and
> I'm not sure how these should be modelled.

This series doesn't cover any of the interdependencies between
the multiple bus classes inside a machine. It just reports which
device types are available for usage with "-device" or
device_adde when running that machine-type.

If the user is not supposed to plug devices directly to some of
those buses, we can simply hide them on query-machines. (But we
should still set BusClass::device_type to allow internal
validation of the devices that are plugged on those bus objects).
diff mbox

Patch

diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 537face..a363993 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -36,9 +36,16 @@  static Property hda_props[] = {
     DEFINE_PROP_END_OF_LIST()
 };
 
+static void hda_codec_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_HDA_CODEC_DEVICE;
+}
+
 static const TypeInfo hda_codec_bus_info = {
     .name = TYPE_HDA_BUS,
     .parent = TYPE_BUS,
+    .class_init = hda_codec_bus_class_init,
     .instance_size = sizeof(HDACodecBus),
 };
 
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index 17d29e7..09bfdda 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -60,6 +60,10 @@ 
 #define TYPE_FLOPPY_BUS "floppy-bus"
 #define FLOPPY_BUS(obj) OBJECT_CHECK(FloppyBus, (obj), TYPE_FLOPPY_BUS)
 
+#define TYPE_FLOPPY_DRIVE "floppy"
+#define FLOPPY_DRIVE(obj) \
+     OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
+
 typedef struct FDCtrl FDCtrl;
 typedef struct FDrive FDrive;
 static FDrive *get_drv(FDCtrl *fdctrl, int unit);
@@ -69,9 +73,16 @@  typedef struct FloppyBus {
     FDCtrl *fdc;
 } FloppyBus;
 
+static void floppy_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_FLOPPY_DRIVE;
+}
+
 static const TypeInfo floppy_bus_info = {
     .name = TYPE_FLOPPY_BUS,
     .parent = TYPE_BUS,
+    .class_init = floppy_bus_class_init,
     .instance_size = sizeof(FloppyBus),
 };
 
@@ -483,10 +494,6 @@  static const BlockDevOps fd_block_ops = {
 };
 
 
-#define TYPE_FLOPPY_DRIVE "floppy"
-#define FLOPPY_DRIVE(obj) \
-     OBJECT_CHECK(FloppyDrive, (obj), TYPE_FLOPPY_DRIVE)
-
 typedef struct FloppyDrive {
     DeviceState     qdev;
     uint32_t        unit;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 7975c2c..215e180 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -832,6 +832,7 @@  static void virtser_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
     k->print_dev = virtser_bus_dev_print;
+    k->device_type = TYPE_VIRTIO_SERIAL_PORT;
 }
 
 static const TypeInfo virtser_bus_info = {
diff --git a/hw/core/bus.c b/hw/core/bus.c
index cf383fc..57bac8f 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -208,12 +208,21 @@  static char *default_bus_get_fw_dev_path(DeviceState *dev)
     return g_strdup(object_get_typename(OBJECT(dev)));
 }
 
+static char *bus_get_device_type(Object *obj, Error **errp)
+{
+    BusClass *bc = BUS_GET_CLASS(obj);
+    return g_strdup(bc->device_type);
+}
+
 static void bus_class_init(ObjectClass *class, void *data)
 {
     BusClass *bc = BUS_CLASS(class);
 
     class->unparent = bus_unparent;
     bc->get_fw_dev_path = default_bus_get_fw_dev_path;
+
+    object_class_property_add_str(class, "device-type",
+                                  bus_get_device_type, NULL, &error_abort);
 }
 
 static void qbus_finalize(Object *obj)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index c0f560b..c065eb8 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -76,6 +76,7 @@  static void system_bus_class_init(ObjectClass *klass, void *data)
 
     k->print_dev = sysbus_dev_print;
     k->get_fw_dev_path = sysbus_get_fw_dev_path;
+    k->device_type = TYPE_SYS_BUS_DEVICE;
 }
 
 static const TypeInfo system_bus_info = {
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index abd4c4c..81b6ae4 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -35,9 +35,16 @@  static Property i2c_props[] = {
 #define TYPE_I2C_BUS "i2c-bus"
 #define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS)
 
+static void i2c_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_I2C_SLAVE;
+}
+
 static const TypeInfo i2c_bus_info = {
     .name = TYPE_I2C_BUS,
     .parent = TYPE_BUS,
+    .class_init = i2c_bus_class_init,
     .instance_size = sizeof(I2CBus),
 };
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index dbaa75c..b526f85 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -43,6 +43,7 @@  static void ide_bus_class_init(ObjectClass *klass, void *data)
     BusClass *k = BUS_CLASS(klass);
 
     k->get_fw_dev_path = idebus_get_fw_dev_path;
+    k->device_type = TYPE_IDE_DEVICE;
 }
 
 static void idebus_unrealize(DeviceState *qdev, Error **errp)
diff --git a/hw/input/adb.c b/hw/input/adb.c
index 43d3205..c6a2b31 100644
--- a/hw/input/adb.c
+++ b/hw/input/adb.c
@@ -121,9 +121,16 @@  int adb_poll(ADBBusState *s, uint8_t *obuf, uint16_t poll_mask)
     return olen;
 }
 
+static void adb_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_ADB_DEVICE;
+}
+
 static const TypeInfo adb_bus_type_info = {
     .name = TYPE_ADB_BUS,
     .parent = TYPE_BUS,
+    .class_init = adb_bus_class_init,
     .instance_size = sizeof(ADBBusState),
 };
 
diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c
index 6021e6d..f22c504 100644
--- a/hw/ipack/ipack.c
+++ b/hw/ipack/ipack.c
@@ -106,9 +106,16 @@  static const TypeInfo ipack_device_info = {
     .abstract      = true,
 };
 
+static void ipack_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_IPACK_DEVICE;
+}
+
 static const TypeInfo ipack_bus_info = {
     .name = TYPE_IPACK_BUS,
     .parent = TYPE_BUS,
+    .class_init = ipack_bus_class_init,
     .instance_size = sizeof(IPackBus),
 };
 
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 9d07b11..aad7669 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -36,6 +36,7 @@  static void isa_bus_class_init(ObjectClass *klass, void *data)
 
     k->print_dev = isabus_dev_print;
     k->get_fw_dev_path = isabus_get_fw_dev_path;
+    k->device_type = TYPE_ISA_DEVICE;
 }
 
 static const TypeInfo isa_dma_info = {
diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c
index e4a7ba4..4b0d565 100644
--- a/hw/misc/auxbus.c
+++ b/hw/misc/auxbus.c
@@ -57,6 +57,7 @@  static void aux_bus_class_init(ObjectClass *klass, void *data)
      * in monitor.
      */
     k->print_dev = aux_slave_dev_print;
+    k->device_type = TYPE_AUX_SLAVE;
 }
 
 AUXBus *aux_init_bus(DeviceState *parent, const char *name)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 24fae16..74b8fef 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -152,6 +152,7 @@  static void pci_bus_class_init(ObjectClass *klass, void *data)
     k->realize = pci_bus_realize;
     k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
+    k->device_type = TYPE_PCI_DEVICE;
 
     pbc->is_root = pcibus_is_root;
     pbc->bus_num = pcibus_num;
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index cc1e09c..c70b9b9 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -61,6 +61,7 @@  static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
 
     k->get_dev_path = spapr_vio_get_dev_name;
     k->get_fw_dev_path = spapr_vio_get_dev_name;
+    k->device_type = TYPE_VIO_SPAPR_DEVICE;
 }
 
 static const TypeInfo spapr_vio_bus_info = {
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 9a7f7ee..8a6c1ae 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -17,6 +17,7 @@ 
 #include "hw/s390x/css.h"
 #include "ccw-device.h"
 #include "hw/s390x/css-bridge.h"
+#include "hw/s390x/virtio-ccw.h"
 
 /*
  * Invoke device-specific unplug handler, disable the subchannel
@@ -81,6 +82,7 @@  static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
 
     k->reset = virtual_css_bus_reset;
     k->get_dev_path = virtual_css_bus_get_dev_path;
+    k->device_type = TYPE_VIRTIO_CCW_DEVICE;
 }
 
 static const TypeInfo virtual_css_bus_info = {
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 34b2faf..f2562ce 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -307,6 +307,7 @@  static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
     BusClass *bc = BUS_CLASS(klass);
 
     bc->realize = sclp_events_bus_realize;
+    bc->device_type = TYPE_SCLP_EVENT;
 }
 
 static const TypeInfo sclp_events_bus_info = {
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 63f6248..7470fdd 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -783,10 +783,17 @@  static const TypeInfo s390_pcihost_info = {
     }
 };
 
+static void s390_pcibus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_S390_PCI_DEVICE;
+}
+
 static const TypeInfo s390_pcibus_info = {
     .name = TYPE_S390_PCI_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(S390PCIBus),
+    .class_init = s390_pcibus_class_init,
 };
 
 static uint16_t s390_pci_generate_uid(void)
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index 297216d..9faf45f 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -31,6 +31,7 @@  static void scsi_bus_class_init(ObjectClass *klass, void *data)
 
     k->get_dev_path = scsibus_get_dev_path;
     k->get_fw_dev_path = scsibus_get_fw_dev_path;
+    k->device_type = TYPE_SCSI_DEVICE;
     hc->unplug = qdev_simple_device_unplug_cb;
 }
 
diff --git a/hw/sd/core.c b/hw/sd/core.c
index 14c2bdf..49b9f59 100644
--- a/hw/sd/core.c
+++ b/hw/sd/core.c
@@ -131,11 +131,18 @@  void sdbus_set_readonly(SDBus *sdbus, bool readonly)
     }
 }
 
+static void sd_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_SD_CARD;
+}
+
 static const TypeInfo sd_bus_info = {
     .name = TYPE_SD_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(SDBus),
     .class_size = sizeof(SDBusClass),
+    .class_init = sd_bus_class_init,
 };
 
 static void sd_bus_register_types(void)
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 7eaaf56..c48920d 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -22,10 +22,17 @@  struct SSIBus {
 #define TYPE_SSI_BUS "SSI"
 #define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
 
+static void ssi_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_SSI_SLAVE;
+}
+
 static const TypeInfo ssi_bus_info = {
     .name = TYPE_SSI_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(SSIBus),
+    .class_init = ssi_bus_class_init,
 };
 
 static void ssi_cs_default(void *opaque, int n, int level)
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 25913ad..2cb7fa4 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -33,6 +33,7 @@  static void usb_bus_class_init(ObjectClass *klass, void *data)
     k->print_dev = usb_bus_dev_print;
     k->get_dev_path = usb_get_dev_path;
     k->get_fw_dev_path = usb_get_fw_dev_path;
+    k->device_type = TYPE_USB_DEVICE;
     hc->unplug = qdev_simple_device_unplug_cb;
 }
 
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 89e11b6..2721f0c 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -1180,10 +1180,17 @@  static Property ccid_props[] = {
 #define TYPE_CCID_BUS "ccid-bus"
 #define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
 
+static void ccid_bus_class_init(ObjectClass *oc, void *opaque)
+{
+    BusClass *bc = BUS_CLASS(oc);
+    bc->device_type = TYPE_CCID_CARD;
+}
+
 static const TypeInfo ccid_bus_info = {
     .name = TYPE_CCID_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(CCIDBus),
+    .class_init = ccid_bus_class_init,
 };
 
 void ccid_card_send_apdu_to_guest(CCIDCardState *card,
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index d6c0c72..815f3dd 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -293,6 +293,7 @@  static void virtio_bus_class_init(ObjectClass *klass, void *data)
     BusClass *bus_class = BUS_CLASS(klass);
     bus_class->get_dev_path = virtio_bus_get_dev_path;
     bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
+    bus_class->device_type = TYPE_VIRTIO_DEVICE;
 }
 
 static const TypeInfo virtio_bus_info = {
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 2c97347..7c34f14 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -207,6 +207,8 @@  struct BusClass {
     int max_dev;
     /* number of automatically allocated bus ids (e.g. ide.0) */
     int automatic_ids;
+    /* type or interface name devices should implement */
+    const char *device_type;
 };
 
 typedef struct BusChild {