diff mbox series

[RFC,1/1] hw/audio: Make 'soundhw' command line option a QOM interface

Message ID 20200429173352.29442-2-philmd@redhat.com
State New
Headers show
Series [RFC,1/1] hw/audio: Make 'soundhw' command line option a QOM interface | expand

Commit Message

Philippe Mathieu-Daudé April 29, 2020, 5:33 p.m. UTC
From: Philippe Mathieu-Daudé <f4bug@amsat.org>

Introduce the SOUNDHW_CMDLINE_INTERFACE QOM type to replace the
deprecated register_soundhw() API.

The conversion of devices calling isa_register_soundhw() /
pci_register_soundhw() is easy:
- Add SOUNDHW_CMDLINE_INTERFACE to InterfaceInfo[],
- Set cmdline_name to the soundhw name, the first argument
  of register_soundhw()to cmdline_name,
- Remove register_soundhw() call.

soundhw.c is rewritten:
- Register the new interface type,
- Use GLib APIs
- Remove register_soundhw() functions.

As the conversion is hardly splitable, it is unfortunately
written as a single patch.

Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
pcspk and hda-intel are problematic, so the conversion is not
finished there, code is marked /* XXX */.
---
 include/hw/audio/soundhw.h |  20 +++-
 hw/audio/ac97.c            |  10 +-
 hw/audio/adlib.c           |  13 ++-
 hw/audio/cs4231a.c         |  13 ++-
 hw/audio/es1370.c          |  10 +-
 hw/audio/gus.c             |  13 ++-
 hw/audio/intel-hda.c       |  13 ++-
 hw/audio/pcspk.c           |  14 ++-
 hw/audio/sb16.c            |  13 ++-
 hw/audio/soundhw.c         | 203 ++++++++++++++++++++-----------------
 10 files changed, 178 insertions(+), 144 deletions(-)
diff mbox series

Patch

diff --git a/include/hw/audio/soundhw.h b/include/hw/audio/soundhw.h
index c8eef82418..4d65412493 100644
--- a/include/hw/audio/soundhw.h
+++ b/include/hw/audio/soundhw.h
@@ -1,13 +1,23 @@ 
 #ifndef HW_SOUNDHW_H
 #define HW_SOUNDHW_H
 
-void isa_register_soundhw(const char *name, const char *descr,
-                          int (*init_isa)(ISABus *bus));
-
-void pci_register_soundhw(const char *name, const char *descr,
-                          int (*init_pci)(PCIBus *bus));
+#include "qom/object.h"
 
 void soundhw_init(void);
 void select_soundhw(const char *optarg);
 
+#define SOUNDHW_CMDLINE_INTERFACE "soundhw-deprecated"
+
+#define SOUNDHW_CMDLINE_CLASS(class) \
+    OBJECT_CLASS_CHECK(SoundHwCmdlineClass, (class), SOUNDHW_CMDLINE_INTERFACE)
+
+typedef struct SoundHwCmdlineClass {
+    /*< private >*/
+    InterfaceClass parent_class;
+    /*< public >*/
+
+    const char *cmdline_name;
+    bool option_used;
+} SoundHwCmdlineClass;
+
 #endif
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 1ec87feec0..5599f97f39 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -1395,12 +1395,6 @@  static void ac97_exit(PCIDevice *dev)
     AUD_remove_card(&s->card);
 }
 
-static int ac97_init (PCIBus *bus)
-{
-    pci_create_simple(bus, -1, TYPE_AC97);
-    return 0;
-}
-
 static Property ac97_properties[] = {
     DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
     DEFINE_PROP_END_OF_LIST (),
@@ -1410,6 +1404,7 @@  static void ac97_class_init (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     k->realize = ac97_realize;
     k->exit = ac97_exit;
@@ -1422,6 +1417,7 @@  static void ac97_class_init (ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_ac97;
     device_class_set_props(dc, ac97_properties);
     dc->reset = ac97_on_reset;
+    sk->cmdline_name = "ac97";
 }
 
 static const TypeInfo ac97_info = {
@@ -1431,6 +1427,7 @@  static const TypeInfo ac97_info = {
     .class_init    = ac97_class_init,
     .interfaces = (InterfaceInfo[]) {
         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { SOUNDHW_CMDLINE_INTERFACE },
         { },
     },
 };
@@ -1438,7 +1435,6 @@  static const TypeInfo ac97_info = {
 static void ac97_register_types (void)
 {
     type_register_static (&ac97_info);
-    pci_register_soundhw("ac97", "Intel 82801AA AC97 Audio", ac97_init);
 }
 
 type_init (ac97_register_types)
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index d6c1fb0586..a2b298c264 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -308,11 +308,13 @@  static Property adlib_properties[] = {
 static void adlib_class_initfn (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     dc->realize = adlib_realizefn;
     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
     dc->desc = ADLIB_DESC;
     device_class_set_props(dc, adlib_properties);
+    sk->cmdline_name = "adlib";
 }
 
 static const TypeInfo adlib_info = {
@@ -320,18 +322,15 @@  static const TypeInfo adlib_info = {
     .parent        = TYPE_ISA_DEVICE,
     .instance_size = sizeof (AdlibState),
     .class_init    = adlib_class_initfn,
+    .interfaces    = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
-static int Adlib_init (ISABus *bus)
-{
-    isa_create_simple (bus, TYPE_ADLIB);
-    return 0;
-}
-
 static void adlib_register_types (void)
 {
     type_register_static (&adlib_info);
-    isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init);
 }
 
 type_init (adlib_register_types)
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index ffdbb58d6a..bdbb792777 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -683,12 +683,6 @@  static void cs4231a_realizefn (DeviceState *dev, Error **errp)
     AUD_register_card ("cs4231a", &s->card);
 }
 
-static int cs4231a_init (ISABus *bus)
-{
-    isa_create_simple (bus, TYPE_CS4231A);
-    return 0;
-}
-
 static Property cs4231a_properties[] = {
     DEFINE_AUDIO_PROPERTIES(CSState, card),
     DEFINE_PROP_UINT32 ("iobase",  CSState, port, 0x534),
@@ -700,6 +694,7 @@  static Property cs4231a_properties[] = {
 static void cs4231a_class_initfn (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     dc->realize = cs4231a_realizefn;
     dc->reset = cs4231a_reset;
@@ -707,6 +702,7 @@  static void cs4231a_class_initfn (ObjectClass *klass, void *data)
     dc->desc = "Crystal Semiconductor CS4231A";
     dc->vmsd = &vmstate_cs4231a;
     device_class_set_props(dc, cs4231a_properties);
+    sk->cmdline_name = "cs4231a";
 }
 
 static const TypeInfo cs4231a_info = {
@@ -715,12 +711,15 @@  static const TypeInfo cs4231a_info = {
     .instance_size = sizeof (CSState),
     .instance_init = cs4231a_initfn,
     .class_init    = cs4231a_class_initfn,
+    .interfaces    = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
 static void cs4231a_register_types (void)
 {
     type_register_static (&cs4231a_info);
-    isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
 }
 
 type_init (cs4231a_register_types)
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 89c4dabcd4..e162fe6e95 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -881,12 +881,6 @@  static void es1370_exit(PCIDevice *dev)
     AUD_remove_card(&s->card);
 }
 
-static int es1370_init (PCIBus *bus)
-{
-    pci_create_simple (bus, -1, TYPE_ES1370);
-    return 0;
-}
-
 static Property es1370_properties[] = {
     DEFINE_AUDIO_PROPERTIES(ES1370State, card),
     DEFINE_PROP_END_OF_LIST(),
@@ -896,6 +890,7 @@  static void es1370_class_init (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     k->realize = es1370_realize;
     k->exit = es1370_exit;
@@ -909,6 +904,7 @@  static void es1370_class_init (ObjectClass *klass, void *data)
     dc->vmsd = &vmstate_es1370;
     dc->reset = es1370_on_reset;
     device_class_set_props(dc, es1370_properties);
+    sk->cmdline_name = "es1370";
 }
 
 static const TypeInfo es1370_info = {
@@ -918,6 +914,7 @@  static const TypeInfo es1370_info = {
     .class_init    = es1370_class_init,
     .interfaces = (InterfaceInfo[]) {
         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { SOUNDHW_CMDLINE_INTERFACE },
         { },
     },
 };
@@ -925,7 +922,6 @@  static const TypeInfo es1370_info = {
 static void es1370_register_types (void)
 {
     type_register_static (&es1370_info);
-    pci_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370", es1370_init);
 }
 
 type_init (es1370_register_types)
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index eb4a803fb5..6ecf7f9a0a 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -292,12 +292,6 @@  static void gus_realizefn (DeviceState *dev, Error **errp)
     AUD_set_active_out (s->voice, 1);
 }
 
-static int GUS_init (ISABus *bus)
-{
-    isa_create_simple (bus, TYPE_GUS);
-    return 0;
-}
-
 static Property gus_properties[] = {
     DEFINE_AUDIO_PROPERTIES(GUSState, card),
     DEFINE_PROP_UINT32 ("freq",    GUSState, freq,        44100),
@@ -310,12 +304,14 @@  static Property gus_properties[] = {
 static void gus_class_initfn (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     dc->realize = gus_realizefn;
     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
     dc->desc = "Gravis Ultrasound GF1";
     dc->vmsd = &vmstate_gus;
     device_class_set_props(dc, gus_properties);
+    sk->cmdline_name = "gus";
 }
 
 static const TypeInfo gus_info = {
@@ -323,12 +319,15 @@  static const TypeInfo gus_info = {
     .parent        = TYPE_ISA_DEVICE,
     .instance_size = sizeof (GUSState),
     .class_init    = gus_class_initfn,
+    .interfaces    = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
 static void gus_register_types (void)
 {
     type_register_static (&gus_info);
-    isa_register_soundhw("gus", "Gravis Ultrasound GF1", GUS_init);
 }
 
 type_init (gus_register_types)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index e8d18b7c58..77b4091433 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -1281,11 +1281,15 @@  static const TypeInfo intel_hda_info_ich9 = {
 static void hda_codec_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
+    SoundHwCmdlineClass *shc = SOUNDHW_CMDLINE_CLASS(klass);
+
     k->realize = hda_codec_dev_realize;
     k->unrealize = hda_codec_dev_unrealize;
     set_bit(DEVICE_CATEGORY_SOUND, k->categories);
     k->bus_type = TYPE_HDA_BUS;
     device_class_set_props(k, hda_props);
+    k->desc = "Intel HD Audio";
+    shc->cmdline_name = "hda";
 }
 
 static const TypeInfo hda_codec_device_type_info = {
@@ -1295,6 +1299,10 @@  static const TypeInfo hda_codec_device_type_info = {
     .abstract = true,
     .class_size = sizeof(HDACodecDeviceClass),
     .class_init = hda_codec_device_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
 /*
@@ -1321,7 +1329,10 @@  static void intel_hda_register_types(void)
     type_register_static(&intel_hda_info_ich6);
     type_register_static(&intel_hda_info_ich9);
     type_register_static(&hda_codec_device_type_info);
-    pci_register_soundhw("hda", "Intel HD Audio", intel_hda_and_codec_init);
+
+    if (0) {
+        intel_hda_and_codec_init(NULL); /* XXX */
+    }
 }
 
 type_init(intel_hda_register_types)
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index 29dc00bf8d..f9aafea115 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -112,7 +112,7 @@  static void pcspk_callback(void *opaque, int free)
     }
 }
 
-static int pcspk_audio_init(ISABus *bus)
+static int pcspk_audio_init(BusState *bus)
 {
     PCSpkState *s = pcspk_state;
     struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUDIO_FORMAT_U8, 0};
@@ -218,14 +218,21 @@  static Property pcspk_properties[] = {
 static void pcspk_class_initfn(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     dc->realize = pcspk_realizefn;
     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
+    dc->desc = "PC speaker";
     dc->vmsd = &vmstate_spk;
     device_class_set_props(dc, pcspk_properties);
     /* Reason: realize sets global pcspk_state */
     /* Reason: pit object link */
     dc->user_creatable = false;
+    sk->cmdline_name = "pcspk";
+
+    if (0) {
+        pcspk_audio_init(NULL); /* XXX */
+    }
 }
 
 static const TypeInfo pcspk_info = {
@@ -234,11 +241,14 @@  static const TypeInfo pcspk_info = {
     .instance_size  = sizeof(PCSpkState),
     .instance_init  = pcspk_initfn,
     .class_init     = pcspk_class_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
 static void pcspk_register(void)
 {
     type_register_static(&pcspk_info);
-    isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init);
 }
 type_init(pcspk_register)
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index df6f755a37..e562338ad7 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -1415,12 +1415,6 @@  static void sb16_realizefn (DeviceState *dev, Error **errp)
     AUD_register_card ("sb16", &s->card);
 }
 
-static int SB16_init (ISABus *bus)
-{
-    isa_create_simple (bus, TYPE_SB16);
-    return 0;
-}
-
 static Property sb16_properties[] = {
     DEFINE_AUDIO_PROPERTIES(SB16State, card),
     DEFINE_PROP_UINT32 ("version", SB16State, ver,  0x0405), /* 4.5 */
@@ -1434,12 +1428,14 @@  static Property sb16_properties[] = {
 static void sb16_class_initfn (ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS (klass);
+    SoundHwCmdlineClass *sk = SOUNDHW_CMDLINE_CLASS(klass);
 
     dc->realize = sb16_realizefn;
     set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
     dc->desc = "Creative Sound Blaster 16";
     dc->vmsd = &vmstate_sb16;
     device_class_set_props(dc, sb16_properties);
+    sk->cmdline_name = "sb16";
 }
 
 static const TypeInfo sb16_info = {
@@ -1448,12 +1444,15 @@  static const TypeInfo sb16_info = {
     .instance_size = sizeof (SB16State),
     .instance_init = sb16_initfn,
     .class_init    = sb16_class_initfn,
+    .interfaces    = (InterfaceInfo[]) {
+        { SOUNDHW_CMDLINE_INTERFACE },
+        { },
+    },
 };
 
 static void sb16_register_types (void)
 {
     type_register_static (&sb16_info);
-    isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init);
 }
 
 type_init (sb16_register_types)
diff --git a/hw/audio/soundhw.c b/hw/audio/soundhw.c
index c750473c8f..1b495fddfb 100644
--- a/hw/audio/soundhw.c
+++ b/hw/audio/soundhw.c
@@ -31,125 +31,140 @@ 
 
 struct soundhw {
     const char *name;
-    const char *descr;
-    int enabled;
-    int isa;
-    union {
-        int (*init_isa) (ISABus *bus);
-        int (*init_pci) (PCIBus *bus);
-    } init;
+    bool is_found;
 };
 
-static struct soundhw soundhw[9];
-static int soundhw_count;
-
-void isa_register_soundhw(const char *name, const char *descr,
-                          int (*init_isa)(ISABus *bus))
+static gint soundhw_list_compare(gconstpointer a, gconstpointer b)
 {
-    assert(soundhw_count < ARRAY_SIZE(soundhw) - 1);
-    soundhw[soundhw_count].name = name;
-    soundhw[soundhw_count].descr = descr;
-    soundhw[soundhw_count].isa = 1;
-    soundhw[soundhw_count].init.init_isa = init_isa;
-    soundhw_count++;
+    SoundHwCmdlineClass *sc_a = SOUNDHW_CMDLINE_CLASS(a);
+    SoundHwCmdlineClass *sc_b = SOUNDHW_CMDLINE_CLASS(b);
+
+    return strcmp(sc_a->cmdline_name, sc_b->cmdline_name);
 }
 
-void pci_register_soundhw(const char *name, const char *descr,
-                          int (*init_pci)(PCIBus *bus))
+static void soundhw_list_entry(gpointer data, gpointer user_data)
 {
-    assert(soundhw_count < ARRAY_SIZE(soundhw) - 1);
-    soundhw[soundhw_count].name = name;
-    soundhw[soundhw_count].descr = descr;
-    soundhw[soundhw_count].isa = 0;
-    soundhw[soundhw_count].init.init_pci = init_pci;
-    soundhw_count++;
+    SoundHwCmdlineClass *sc = SOUNDHW_CMDLINE_CLASS(data);
+    DeviceClass *dc = DEVICE_CLASS(data);
+
+    printf("%-11s %s\n", sc->cmdline_name, dc->desc);
+}
+
+static void soundhw_check_enable_entry(gpointer data, gpointer user_data)
+{
+    SoundHwCmdlineClass *sc = SOUNDHW_CMDLINE_CLASS(data);
+    struct soundhw *d = user_data;
+
+    if (g_str_equal(d->name, "all") || g_str_equal(d->name, sc->cmdline_name)) {
+        sc->option_used = d->is_found = true;
+    }
+}
+
+static void soundhw_list(GSList *list)
+{
+    if (!list) {
+        printf("Machine has no user-selectable audio hardware "
+                "(it may or may not have always-present audio hardware).\n");
+        return;
+    }
+    list = g_slist_sort(list, soundhw_list_compare);
+    printf("Valid sound card names (comma separated):\n");
+    g_slist_foreach(list, soundhw_list_entry, NULL);
+    printf("\n-soundhw all will enable all of the above\n");
 }
 
 void select_soundhw(const char *optarg)
 {
-    struct soundhw *c;
+    struct soundhw data;
+    GSList *list;
+
+    list = object_class_get_list(SOUNDHW_CMDLINE_INTERFACE, false);
 
     if (is_help_option(optarg)) {
-    show_valid_cards:
-
-        if (soundhw_count) {
-             printf("Valid sound card names (comma separated):\n");
-             for (c = soundhw; c->name; ++c) {
-                 printf ("%-11s %s\n", c->name, c->descr);
-             }
-             printf("\n-soundhw all will enable all of the above\n");
-        } else {
-             printf("Machine has no user-selectable audio hardware "
-                    "(it may or may not have always-present audio hardware).\n");
-        }
-        exit(!is_help_option(optarg));
+        soundhw_list(list);
+        exit(0);
     }
-    else {
-        size_t l;
-        const char *p;
-        char *e;
-        int bad_card = 0;
 
-        if (!strcmp(optarg, "all")) {
-            for (c = soundhw; c->name; ++c) {
-                c->enabled = 1;
+    if (strchr(optarg, ',')) {
+        char **parts = g_strsplit(optarg, ",", 0);
+        char **tmp;
+
+        for (tmp = parts; tmp && *tmp; tmp++) {
+            data = (struct soundhw){ .name = *tmp };
+            g_slist_foreach(list, soundhw_check_enable_entry, &data);
+            if (!data.is_found) {
+                goto invalid_name;
             }
-            return;
         }
-
-        p = optarg;
-        while (*p) {
-            e = strchr(p, ',');
-            l = !e ? strlen(p) : (size_t) (e - p);
-
-            for (c = soundhw; c->name; ++c) {
-                if (!strncmp(c->name, p, l) && !c->name[l]) {
-                    c->enabled = 1;
-                    break;
-                }
-            }
-
-            if (!c->name) {
-                if (l > 80) {
-                    error_report("Unknown sound card name (too big to show)");
-                }
-                else {
-                    error_report("Unknown sound card name `%.*s'",
-                                 (int) l, p);
-                }
-                bad_card = 1;
-            }
-            p += l + (e != NULL);
+        g_strfreev(parts);
+    } else {
+        data = (struct soundhw){ .name = optarg };
+        g_slist_foreach(list, soundhw_check_enable_entry, &data);
+        if (!data.is_found) {
+            goto invalid_name;
         }
+    }
+    g_slist_free(list);
+    return;
 
-        if (bad_card) {
-            goto show_valid_cards;
+invalid_name:
+    error_report("Unknown sound card name `%s'", data.name);
+    soundhw_list(list);
+    exit(1);
+}
+
+static void soundhw_create_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    SoundHwCmdlineClass *sc = SOUNDHW_CMDLINE_CLASS(oc);
+    const char *typename = object_class_get_name(oc);
+    BusState *bus;
+
+    if (!sc->option_used) {
+        return;
+    }
+
+    warn_report("'-soundhw %s' is deprecated, please use '-device %s' instead",
+                sc->cmdline_name, typename);
+
+    if (object_class_dynamic_cast(oc, TYPE_ISA_DEVICE)) {
+        bus = (BusState *)object_resolve_path_type("", TYPE_ISA_BUS, NULL);
+        if (!bus) {
+            error_report("ISA bus not available for %s", sc->cmdline_name);
+            exit(1);
         }
+        isa_create_simple(ISA_BUS(bus), typename);
+    }
+    if (object_class_dynamic_cast(oc, TYPE_PCI_DEVICE)) {
+        bus = (BusState *)object_resolve_path_type("", TYPE_PCI_BUS, NULL);
+        if (!bus) {
+            error_report("PCI bus not available for %s", sc->cmdline_name);
+            exit(1);
+        }
+        pci_create_simple(PCI_BUS(bus), -1, typename);
     }
 }
 
 void soundhw_init(void)
 {
-    struct soundhw *c;
-    ISABus *isa_bus = (ISABus *) object_resolve_path_type("", TYPE_ISA_BUS, NULL);
-    PCIBus *pci_bus = (PCIBus *) object_resolve_path_type("", TYPE_PCI_BUS, NULL);
+    GSList *list;
 
-    for (c = soundhw; c->name; ++c) {
-        if (c->enabled) {
-            if (c->isa) {
-                if (!isa_bus) {
-                    error_report("ISA bus not available for %s", c->name);
-                    exit(1);
-                }
-                c->init.init_isa(isa_bus);
-            } else {
-                if (!pci_bus) {
-                    error_report("PCI bus not available for %s", c->name);
-                    exit(1);
-                }
-                c->init.init_pci(pci_bus);
-            }
-        }
+    list = object_class_get_list(SOUNDHW_CMDLINE_INTERFACE, false);
+    if (list) {
+        g_slist_foreach(list, soundhw_create_entry, NULL);
+        g_slist_free(list);
     }
 }
 
+static const TypeInfo soundhw_interface_info = {
+    .name       = SOUNDHW_CMDLINE_INTERFACE,
+    .parent     = TYPE_INTERFACE,
+    .class_size = sizeof(SoundHwCmdlineClass),
+};
+
+static void soundhw_register_types(void)
+{
+    type_register_static(&soundhw_interface_info);
+}
+
+type_init(soundhw_register_types)