qemu-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-commits] [COMMIT 02e2da4] Add common BusState


From: Anthony Liguori
Subject: [Qemu-commits] [COMMIT 02e2da4] Add common BusState
Date: Fri, 22 May 2009 23:17:41 -0000

From: Paul Brook <address@hidden>

Implement and use a common device bus state.  The main side-effect is
that creating a bus and attaching it to a parent device are no longer
separate operations.  For legacy code we allow a NULL parent, but that
should go away eventually.

Also tweak creation code to veriry theat a device in on the right bus.

Signed-off-by: Paul Brook <address@hidden>

diff --git a/hw/acpi.c b/hw/acpi.c
index 0bbb2d8..fccae69 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -548,7 +548,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t 
smb_io_base,
 
     register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
 
-    s->smbus = i2c_init_bus();
+    s->smbus = i2c_init_bus(NULL, "i2c");
     s->irq = sci_irq;
     qemu_register_reset(piix4_reset, 0, s);
 
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index d6ce9f4..dac5cd3 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -231,7 +231,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
 
     s = qemu_mallocz(sizeof(APBState));
     /* Ultrasparc PBM main bus */
-    s->bus = pci_register_bus(pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
+    s->bus = pci_register_bus(NULL, "pci",
+                              pci_apb_set_irq, pci_pbm_map_irq, pic, 0, 32);
 
     pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
                                             pci_apb_config_write, s);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 8b170d6..581d1c5 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -133,7 +133,8 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
     int pci_mem_config, pci_mem_data;
 
     s = qemu_mallocz(sizeof(GrackleState));
-    s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq,
+    s->bus = pci_register_bus(NULL, "pci",
+                              pci_grackle_set_irq, pci_grackle_map_irq,
                               pic, 0, 4);
 
     pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 7fc91dd..ce3ffe2 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1128,7 +1128,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
     s = qemu_mallocz(sizeof(GT64120State));
     s->pci = qemu_mallocz(sizeof(GT64120PCIState));
 
-    s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
+    s->pci->bus = pci_register_bus(NULL, "pci",
+                                   pci_gt64120_set_irq, pci_gt64120_map_irq,
                                    pic, 144, 4);
     s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s);
     d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
diff --git a/hw/i2c.c b/hw/i2c.c
index ce9de29..8a0c4d7 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -11,6 +11,7 @@
 
 struct i2c_bus
 {
+    BusState qbus;
     i2c_slave *current_dev;
     i2c_slave *dev;
     int saved_address;
@@ -39,11 +40,12 @@ static int i2c_bus_load(QEMUFile *f, void *opaque, int 
version_id)
 }
 
 /* Create a new I2C bus.  */
-i2c_bus *i2c_init_bus(void)
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
 {
     i2c_bus *bus;
 
-    bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus));
+    bus = FROM_QBUS(i2c_bus, qbus_create(BUS_TYPE_I2C, sizeof(i2c_bus),
+                                         parent, name));
     register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus);
     return bus;
 }
@@ -63,20 +65,22 @@ int i2c_bus_busy(i2c_bus *bus)
 /* TODO: Make this handle multiple masters.  */
 int i2c_start_transfer(i2c_bus *bus, int address, int recv)
 {
-    i2c_slave *dev;
+    DeviceState *qdev;
+    i2c_slave *slave = NULL;
 
-    for (dev = bus->dev; dev; dev = dev->next) {
-        if (dev->address == address)
+    LIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+        slave = I2C_SLAVE_FROM_QDEV(qdev);
+        if (slave->address == address)
             break;
     }
 
-    if (!dev)
+    if (!slave)
         return 1;
 
     /* If the bus is already busy, assume this is a repeated
        start condition.  */
-    bus->current_dev = dev;
-    dev->info->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
+    bus->current_dev = slave;
+    slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
     return 0;
 }
 
@@ -130,23 +134,20 @@ void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
 void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
 {
     i2c_bus *bus;
-    bus = qdev_get_bus(&dev->qdev);
+    bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
     dev->address = qemu_get_byte(f);
     if (bus->saved_address == dev->address) {
         bus->current_dev = dev;
     }
 }
 
-static void i2c_slave_qdev_init(DeviceState *dev, void *opaque)
+static void i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
 {
-    I2CSlaveInfo *info = opaque;
+    I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
     i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
 
     s->info = info;
-    s->bus = qdev_get_bus(dev);
     s->address = qdev_get_prop_int(dev, "address", 0);
-    s->next = s->bus->dev;
-    s->bus->dev = s;
 
     info->init(s);
 }
@@ -154,14 +155,16 @@ static void i2c_slave_qdev_init(DeviceState *dev, void 
*opaque)
 void i2c_register_slave(const char *name, int size, I2CSlaveInfo *info)
 {
     assert(size >= sizeof(i2c_slave));
-    qdev_register(name, size, i2c_slave_qdev_init, info);
+    info->qdev.init = i2c_slave_qdev_init;
+    info->qdev.bus_type = BUS_TYPE_I2C;
+    qdev_register(name, size, &info->qdev);
 }
 
 DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, int addr)
 {
     DeviceState *dev;
 
-    dev = qdev_create(bus, name);
+    dev = qdev_create(&bus->qbus, name);
     qdev_set_prop_int(dev, "address", addr);
     qdev_init(dev);
     return dev;
diff --git a/hw/i2c.h b/hw/i2c.h
index 4e5a1ac..f15c70c 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -25,6 +25,8 @@ typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event 
event);
 typedef void (*i2c_slave_initfn)(i2c_slave *dev);
 
 typedef struct {
+    DeviceInfo qdev;
+
     /* Callbacks provided by the device.  */
     i2c_slave_initfn init;
     i2c_event_cb event;
@@ -39,11 +41,9 @@ struct i2c_slave
 
     /* Remaining fields for internal use by the I2C code.  */
     int address;
-    void *next;
-    i2c_bus *bus;
 };
 
-i2c_bus *i2c_init_bus(void);
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
 void i2c_set_slave_address(i2c_slave *dev, int address);
 int i2c_bus_busy(i2c_bus *bus);
 int i2c_start_transfer(i2c_bus *bus, int address, int recv);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index e71ecc1..a300808 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -907,7 +907,7 @@ void mips_malta_init (ram_addr_t ram_size,
     for (i = 0; i < 8; i++) {
         /* TODO: Populate SPD eeprom data.  */
         DeviceState *eeprom;
-        eeprom = qdev_create(smbus, "smbus-eeprom");
+        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
         qdev_set_prop_int(eeprom, "address", 0x50 + i);
         qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
         qdev_init(eeprom);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 16476f2..1e0aff5 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -431,7 +431,7 @@ static i2c_interface *musicpal_audio_init(qemu_irq irq)
     s->irq = irq;
 
     i2c = qemu_mallocz(sizeof(i2c_interface));
-    i2c->bus = i2c_init_bus();
+    i2c->bus = i2c_init_bus(NULL, "i2c");
     i2c->current_addr = -1;
 
     s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR);
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index f98ac8d..c0dd3a5 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -433,7 +433,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
     s->irq = irq;
     s->drq[0] = dma[0];
     s->drq[1] = dma[1];
-    s->bus = i2c_init_bus();
+    s->bus = i2c_init_bus(NULL, "i2c");
     omap_i2c_reset(s);
 
     iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
@@ -454,7 +454,7 @@ struct omap_i2c_s *omap2_i2c_init(struct 
omap_target_agent_s *ta,
     s->irq = irq;
     s->drq[0] = dma[0];
     s->drq[1] = dma[1];
-    s->bus = i2c_init_bus();
+    s->bus = i2c_init_bus(NULL, "i2c");
     omap_i2c_reset(s);
 
     iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
diff --git a/hw/pc.c b/hw/pc.c
index faaa60f..66cc780 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1105,7 +1105,7 @@ static void pc_init1(ram_addr_t ram_size,
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
         for (i = 0; i < 8; i++) {
             DeviceState *eeprom;
-            eeprom = qdev_create(smbus, "smbus-eeprom");
+            eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
             qdev_set_prop_int(eeprom, "address", 0x50 + i);
             qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
             qdev_init(eeprom);
diff --git a/hw/pci.c b/hw/pci.c
index bdf3941..0ab5b94 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -30,6 +30,7 @@
 //#define DEBUG_PCI
 
 struct PCIBus {
+    BusState qbus;
     int bus_num;
     int devfn_min;
     pci_set_irq_fn set_irq;
@@ -87,13 +88,16 @@ static int  pcibus_load(QEMUFile *f, void *opaque, int 
version_id)
     return 0;
 }
 
-PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq)
 {
     PCIBus *bus;
     static int nbus = 0;
 
-    bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
+    bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI,
+                                        sizeof(PCIBus) + (nirq * sizeof(int)),
+                                        parent, name));
     bus->set_irq = set_irq;
     bus->map_irq = map_irq;
     bus->irq_opaque = pic;
@@ -320,7 +324,7 @@ int pci_unregister_device(PCIDevice *pci_dev)
     qemu_free_irqs(pci_dev->irq);
     pci_irq_index--;
     pci_dev->bus->devices[pci_dev->devfn] = NULL;
-    qemu_free(pci_dev);
+    qdev_free(&pci_dev->qdev);
     return 0;
 }
 
@@ -821,7 +825,7 @@ PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
 
     for (i = 0; pci_nic_models[i]; i++) {
         if (strcmp(nd->model, pci_nic_models[i]) == 0) {
-            dev = qdev_create(bus, pci_nic_names[i]);
+            dev = qdev_create(&bus->qbus, pci_nic_names[i]);
             qdev_set_prop_int(dev, "devfn", devfn);
             qdev_set_netdev(dev, nd);
             qdev_init(dev);
@@ -901,32 +905,43 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t 
vid, uint16_t did,
     return s->bus;
 }
 
-static void pci_qdev_init(DeviceState *qdev, void *opaque)
+typedef struct {
+    DeviceInfo qdev;
+    pci_qdev_initfn init;
+} PCIDeviceInfo;
+
+static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     PCIDevice *pci_dev = (PCIDevice *)qdev;
-    pci_qdev_initfn init;
+    PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
     PCIBus *bus;
     int devfn;
 
-    init = opaque;
-    bus = qdev_get_bus(qdev);
+    bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
     devfn = qdev_get_prop_int(qdev, "devfn", -1);
     pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn,
                                      NULL, NULL);//FIXME:config_read, 
config_write);
     assert(pci_dev);
-    init(pci_dev);
+    info->init(pci_dev);
 }
 
 void pci_qdev_register(const char *name, int size, pci_qdev_initfn init)
 {
-    qdev_register(name, size, pci_qdev_init, init);
+    PCIDeviceInfo *info;
+
+    info = qemu_mallocz(sizeof(*info));
+    info->init = init;
+    info->qdev.init = pci_qdev_init;
+    info->qdev.bus_type = BUS_TYPE_PCI;
+
+    qdev_register(name, size, &info->qdev);
 }
 
 PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
 {
     DeviceState *dev;
 
-    dev = qdev_create(bus, name);
+    dev = qdev_create(&bus->qbus, name);
     qdev_set_prop_int(dev, "devfn", devfn);
     qdev_init(dev);
 
diff --git a/hw/pci.h b/hw/pci.h
index 09f9799..0405837 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -183,7 +183,8 @@ int pci_device_load(PCIDevice *s, QEMUFile *f);
 
 typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
-PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq);
 
 PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 2b19cc6..914a65a 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -176,7 +176,8 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq 
*pic)
     I440FXState *s;
 
     s = qemu_mallocz(sizeof(I440FXState));
-    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
+    b = pci_register_bus(NULL, "pci", 
+                         piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
     s->bus = b;
 
     register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
diff --git a/hw/pl022.c b/hw/pl022.c
index 20d317c..27cb7af 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -297,8 +297,7 @@ static void pl022_init(SysBusDevice *dev)
                                        pl022_writefn, s);
     sysbus_init_mmio(dev, 0x1000, iomemtype);
     sysbus_init_irq(dev, &s->irq);
-    s->ssi = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi", s->ssi);
+    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
     pl022_reset(s);
     register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s);
 }
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 7ebfcc0..45ab3be 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -370,7 +370,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
 
     controller = qemu_mallocz(sizeof(PPC4xxPCIState));
 
-    controller->pci_state.bus = pci_register_bus(ppc4xx_pci_set_irq,
+    controller->pci_state.bus = pci_register_bus(NULL, "pci",
+                                                 ppc4xx_pci_set_irq,
                                                  ppc4xx_pci_map_irq,
                                                  pci_irqs, 0, 4);
 
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 9eed890..79703a3 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -317,7 +317,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], 
target_phys_addr_t registers)
 
     controller = qemu_mallocz(sizeof(PPCE500PCIState));
 
-    controller->pci_state.bus = pci_register_bus(mpc85xx_pci_set_irq,
+    controller->pci_state.bus = pci_register_bus(NULL, "pci",
+                                                 mpc85xx_pci_set_irq,
                                                  mpc85xx_pci_map_irq,
                                                  pci_irqs, 0x88, 4);
     d = pci_register_device(controller->pci_state.bus,
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index a97b845..e747e39 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -136,7 +136,8 @@ PCIBus *pci_prep_init(qemu_irq *pic)
     int PPC_io_memory;
 
     s = qemu_mallocz(sizeof(PREPPCIState));
-    s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 4);
+    s->bus = pci_register_bus(NULL, "pci",
+                              prep_set_irq, prep_map_irq, pic, 0, 4);
 
     register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
     register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index d54ad19..febe527 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -863,8 +863,7 @@ static void pxa2xx_ssp_init(SysBusDevice *dev)
     register_savevm("pxa2xx_ssp", -1, 0,
                     pxa2xx_ssp_save, pxa2xx_ssp_load, s);
 
-    s->bus = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi", s->bus);
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
 }
 
 /* Real-Time Clock */
@@ -1500,12 +1499,12 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
     PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState));
 
     /* FIXME: Should the slave device really be on a separate bus?  */
-    dev = i2c_create_slave(i2c_init_bus(), "pxa2xx-i2c-slave", 0);
+    dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0);
     s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev));
     s->slave->host = s;
 
     s->irq = irq;
-    s->bus = i2c_init_bus();
+    s->bus = i2c_init_bus(NULL, "i2c");
     s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
 
     iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn,
@@ -2117,7 +2116,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const 
char *revision)
         DeviceState *dev;
         dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
                                    s->pic[pxa27x_ssp[i].irqn]);
-        s->ssp[i] = qdev_get_child_bus(dev, "ssi");
+        s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
     }
 
     if (usb_enabled) {
@@ -2229,7 +2228,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
         DeviceState *dev;
         dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
                                    s->pic[pxa255_ssp[i].irqn]);
-        s->ssp[i] = qdev_get_child_bus(dev, "ssi");
+        s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
     }
 
     if (usb_enabled) {
diff --git a/hw/qdev.c b/hw/qdev.c
index 9ed6f85..b9278e9 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -41,23 +41,18 @@ struct DeviceProperty {
 
 struct DeviceType {
     const char *name;
-    qdev_initfn init;
-    void *opaque;
+    DeviceInfo *info;
     int size;
     DeviceType *next;
 };
 
-struct ChildBusList {
-    const char *name;
-    void *ptr;
-    ChildBusList *next;
-};
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+BusState *main_system_bus;
 
 static DeviceType *device_type_list;
 
 /* Register a new device type.  */
-DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
-                          void *opaque)
+void qdev_register(const char *name, int size, DeviceInfo *info)
 {
     DeviceType *t;
 
@@ -68,16 +63,13 @@ DeviceType *qdev_register(const char *name, int size, 
qdev_initfn init,
     device_type_list = t;
     t->name = qemu_strdup(name);
     t->size = size;
-    t->init = init;
-    t->opaque = opaque;
-
-    return t;
+    t->info = info;
 }
 
 /* Create a new device.  This only initializes the device state structure
    and allows properties to be set.  qdev_init should be called to
    initialize the actual device emulation.  */
-DeviceState *qdev_create(void *bus, const char *name)
+DeviceState *qdev_create(BusState *bus, const char *name)
 {
     DeviceType *t;
     DeviceState *dev;
@@ -88,14 +80,28 @@ DeviceState *qdev_create(void *bus, const char *name)
         }
     }
     if (!t) {
-        fprintf(stderr, "Unknown device '%s'\n", name);
-        exit(1);
+        hw_error("Unknown device '%s'\n", name);
     }
 
     dev = qemu_mallocz(t->size);
     dev->name = name;
     dev->type = t;
-    dev->bus = bus;
+
+    if (!bus) {
+        /* ???: This assumes system busses have no additional state.  */
+        if (!main_system_bus) {
+            main_system_bus = qbus_create(BUS_TYPE_SYSTEM, sizeof(BusState),
+                                          NULL, "main-system-bus");
+        }
+        bus = main_system_bus;
+    }
+    if (t->info->bus_type != bus->type) {
+        /* TODO: Print bus type names.  */
+        hw_error("Device '%s' on wrong bus type (%d/%d)", name,
+                 t->info->bus_type, bus->type);
+    }
+    dev->parent_bus = bus;
+    LIST_INSERT_HEAD(&bus->children, dev, sibling);
     return dev;
 }
 
@@ -104,7 +110,14 @@ DeviceState *qdev_create(void *bus, const char *name)
    calling this function.  */
 void qdev_init(DeviceState *dev)
 {
-    dev->type->init(dev, dev->type->opaque);
+    dev->type->info->init(dev, dev->type->info);
+}
+
+/* Unlink device from bus and free the structure.  */
+void qdev_free(DeviceState *dev)
+{
+    LIST_REMOVE(dev, sibling);
+    free(dev);
 }
 
 static DeviceProperty *create_prop(DeviceState *dev, const char *name)
@@ -169,9 +182,9 @@ CharDriverState *qdev_init_chardev(DeviceState *dev)
     }
 }
 
-void *qdev_get_bus(DeviceState *dev)
+BusState *qdev_get_parent_bus(DeviceState *dev)
 {
-    return dev->bus;
+    return dev->parent_bus;
 }
 
 static DeviceProperty *find_prop(DeviceState *dev, const char *name)
@@ -267,30 +280,18 @@ BlockDriverState *qdev_init_bdrv(DeviceState *dev, 
BlockInterfaceType type)
     return drives_table[index].bdrv;
 }
 
-void *qdev_get_child_bus(DeviceState *dev, const char *name)
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
 {
-    ChildBusList *bus;
+    BusState *bus;
 
-    for (bus = dev->child_bus; bus; bus = bus->next) {
+    LIST_FOREACH(bus, &dev->child_bus, sibling) {
         if (strcmp(name, bus->name) == 0) {
-            return bus->ptr;
+            return bus;
         }
     }
     return NULL;
 }
 
-void qdev_attach_child_bus(DeviceState *dev, const char *name, void *bus)
-{
-    ChildBusList *p;
-
-    assert(!qdev_get_child_bus(dev, name));
-    p = qemu_mallocz(sizeof(*p));
-    p->name = qemu_strdup(name);
-    p->ptr = bus;
-    p->next = dev->child_bus;
-    dev->child_bus = p;
-}
-
 static int next_scsi_bus;
 
 /* Create a scsi bus, and attach devices to it.  */
@@ -309,3 +310,19 @@ void scsi_bus_new(DeviceState *host, SCSIAttachFn attach)
        attach(host, drives_table[index].bdrv, unit);
    }
 }
+
+BusState *qbus_create(BusType type, size_t size,
+                      DeviceState *parent, const char *name)
+{
+    BusState *bus;
+
+    bus = qemu_mallocz(size);
+    bus->type = type;
+    bus->parent = parent;
+    bus->name = qemu_strdup(name);
+    LIST_INIT(&bus->children);
+    if (parent) {
+        LIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
+    }
+    return bus;
+}
diff --git a/hw/qdev.h b/hw/qdev.h
index 5a34f51..0931bc1 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -2,20 +2,20 @@
 #define QDEV_H
 
 #include "hw.h"
+#include "sys-queue.h"
 
 typedef struct DeviceType DeviceType;
 
 typedef struct DeviceProperty DeviceProperty;
 
-typedef struct ChildBusList ChildBusList;
+typedef struct BusState BusState;
 
 /* This structure should not be accessed directly.  We declare it here
    so that it can be embedded in individual device state structures.  */
-struct DeviceState
-{
+struct DeviceState {
     const char *name;
     DeviceType *type;
-    void *bus;
+    BusState *parent_bus;
     DeviceProperty *props;
     int num_irq_sink;
     qemu_irq *irq_sink;
@@ -23,14 +23,32 @@ struct DeviceState
     qemu_irq *gpio_out;
     int num_gpio_in;
     qemu_irq *gpio_in;
-    ChildBusList *child_bus;
+    LIST_HEAD(, BusState) child_bus;
     NICInfo *nd;
+    LIST_ENTRY(DeviceState) sibling;
+};
+
+typedef enum {
+    BUS_TYPE_SYSTEM,
+    BUS_TYPE_PCI,
+    BUS_TYPE_SCSI,
+    BUS_TYPE_I2C,
+    BUS_TYPE_SSI
+} BusType;
+
+struct BusState {
+    DeviceState *parent;
+    const char *name;
+    BusType type;
+    LIST_HEAD(, DeviceState) children;
+    LIST_ENTRY(BusState) sibling;
 };
 
 /*** Board API.  This should go away once we have a machine config file.  ***/
 
-DeviceState *qdev_create(void *bus, const char *name);
+DeviceState *qdev_create(BusState *bus, const char *name);
 void qdev_init(DeviceState *dev);
+void qdev_free(DeviceState *dev);
 
 /* Set properties between creation and init.  */
 void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value);
@@ -41,28 +59,33 @@ qemu_irq qdev_get_irq_sink(DeviceState *dev, int n);
 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
 void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
 
-void *qdev_get_child_bus(DeviceState *dev, const char *name);
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
 /*** Device API.  ***/
 
-typedef void (*qdev_initfn)(DeviceState *dev, void *opaque);
+typedef struct DeviceInfo DeviceInfo;
+
+typedef void (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
 typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
               int unit);
 
-DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
-                          void *opaque);
+struct DeviceInfo {
+    qdev_initfn init;
+    BusType bus_type;
+};
+
+void qdev_register(const char *name, int size, DeviceInfo *info);
 
 /* Register device properties.  */
 void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq);
 void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
 void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
-void qdev_attach_child_bus(DeviceState *dev, const char *name, void *bus);
 
 void scsi_bus_new(DeviceState *host, SCSIAttachFn attach);
 
 CharDriverState *qdev_init_chardev(DeviceState *dev);
 
-void *qdev_get_bus(DeviceState *dev);
+BusState *qdev_get_parent_bus(DeviceState *dev);
 uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def);
 void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
 
@@ -76,4 +99,11 @@ void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
 #define DO_UPCAST(type, field, dev) container_of(dev, type, field)
 #endif
 
+/*** BUS API. ***/
+
+BusState *qbus_create(BusType type, size_t size,
+                      DeviceState *parent, const char *name);
+
+#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
+
 #endif
diff --git a/hw/realview.c b/hw/realview.c
index 49e07fd..535f907 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -109,7 +109,7 @@ static void realview_init(ram_addr_t ram_size,
 
     dev = sysbus_create_varargs("realview_pci", 0x60000000,
                                 pic[48], pic[49], pic[50], pic[51], NULL);
-    pci_bus = qdev_get_child_bus(dev, "pci");
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, 3, -1);
     }
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 3f79b10..2ec4b43 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -174,7 +174,8 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, 
pci_map_irq_fn map_irq,
     int mem, reg, iop;
 
     p = qemu_mallocz(sizeof(SHPCIC));
-    p->bus = pci_register_bus(set_irq, map_irq, pic, devfn_min, nirq);
+    p->bus = pci_register_bus(NULL, "pci",
+                              set_irq, map_irq, pic, devfn_min, nirq);
 
     p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
                                  -1, NULL, NULL);
diff --git a/hw/spitz.c b/hw/spitz.c
index dd16780..aa1487b 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -706,12 +706,9 @@ static void corgi_ssp_init(SSISlave *dev)
     CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
 
     qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
-    s->bus[0] = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]);
-    s->bus[1] = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi1", s->bus[1]);
-    s->bus[2] = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi2", s->bus[2]);
+    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
+    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
+    s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
 
     register_savevm("spitz_ssp", -1, 1, spitz_ssp_save, spitz_ssp_load, s);
 }
diff --git a/hw/ssi.c b/hw/ssi.c
index 9dfdbe9..52b7b7c 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -10,16 +10,21 @@
 #include "ssi.h"
 
 struct SSIBus {
-    SSISlave *slave;
+    BusState qbus;
 };
 
-static void ssi_slave_init(DeviceState *dev, void *opaque)
+static void ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
 {
-    SSISlaveInfo *info = opaque;
+    SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev);
     SSISlave *s = SSI_SLAVE_FROM_QDEV(dev);
-    SSIBus *bus = qdev_get_bus(dev);
+    SSIBus *bus;
+
+    bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
+    if (LIST_FIRST(&bus->qbus.children) != dev
+        || LIST_NEXT(dev, sibling) != NULL) {
+        hw_error("Too many devices on SSI bus");
+    }
 
-    bus->slave = s;
     s->info = info;
     info->init(s);
 }
@@ -27,26 +32,34 @@ static void ssi_slave_init(DeviceState *dev, void *opaque)
 void ssi_register_slave(const char *name, int size, SSISlaveInfo *info)
 {
     assert(size >= sizeof(SSISlave));
-    qdev_register(name, size, ssi_slave_init, info);
+    info->qdev.init = ssi_slave_init;
+    info->qdev.bus_type = BUS_TYPE_SSI;
+    qdev_register(name, size, &info->qdev);
 }
 
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
 {
     DeviceState *dev;
-    dev = qdev_create(bus, name);
+    dev = qdev_create(&bus->qbus, name);
     qdev_init(dev);
     return dev;
 }
 
-SSIBus *ssi_create_bus(void)
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
 {
-    return qemu_mallocz(sizeof(SSIBus));
+    BusState *bus;
+    bus = qbus_create(BUS_TYPE_SSI, sizeof(SSIBus), parent, name);
+    return FROM_QBUS(SSIBus, bus);
 }
 
 uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
-    if (!bus->slave) {
+    DeviceState *dev;
+    SSISlave *slave;
+    dev = LIST_FIRST(&bus->qbus.children);
+    if (!dev) {
         return 0;
     }
-    return bus->slave->info->transfer(bus->slave, val);
+    slave = SSI_SLAVE_FROM_QDEV(dev);
+    return slave->info->transfer(slave, val);
 }
diff --git a/hw/ssi.h b/hw/ssi.h
index aab740f..861c484 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -17,6 +17,7 @@ typedef struct SSISlave SSISlave;
 
 /* Slave devices.  */
 typedef struct {
+    DeviceInfo qdev;
     void (*init)(SSISlave *dev);
     uint32_t (*transfer)(SSISlave *dev, uint32_t val);
 } SSISlaveInfo;
@@ -34,7 +35,7 @@ void ssi_register_slave(const char *name, int size, 
SSISlaveInfo *info);
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
 
 /* Master interface.  */
-SSIBus *ssi_create_bus(void);
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
 
 uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
 
diff --git a/hw/stellaris.c b/hw/stellaris.c
index e7f3604..a107db7 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -874,11 +874,11 @@ static int stellaris_i2c_load(QEMUFile *f, void *opaque, 
int version_id)
 static void stellaris_i2c_init(SysBusDevice * dev)
 {
     stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
-    i2c_bus *bus = i2c_init_bus();
+    i2c_bus *bus;
     int iomemtype;
 
     sysbus_init_irq(dev, &s->irq);
-    qdev_attach_child_bus(&dev->qdev, "i2c", bus);
+    bus = i2c_init_bus(&dev->qdev, "i2c");
     s->bus = bus;
 
     iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn,
@@ -1239,10 +1239,8 @@ static void stellaris_ssi_bus_init(SSISlave *dev)
 {
     stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
 
-    s->bus[0] = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]);
-    s->bus[1] = ssi_create_bus();
-    qdev_attach_child_bus(&dev->qdev, "ssi1", s->bus[1]);
+    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
+    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
     qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
 
     register_savevm("stellaris_ssi_bus", -1, 1,
@@ -1320,7 +1318,7 @@ static void stellaris_init(const char *kernel_filename, 
const char *cpu_model,
     if (board->dc2 & (1 << 12)) {
         DeviceState *dev;
         dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
-        i2c = qdev_get_child_bus(dev, "i2c");
+        i2c = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
         if (board->peripherals & BP_OLED_I2C) {
             i2c_create_slave(i2c, "ssd0303", 0x3d);
         }
diff --git a/hw/sysbus.c b/hw/sysbus.c
index e6cb7dd..13d81f5 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -21,6 +21,11 @@
 #include "sysbus.h"
 #include "sysemu.h"
 
+typedef struct {
+    DeviceInfo qdev;
+    sysbus_initfn init;
+} SysBusDeviceInfo;
+
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
 {
     assert(n >= 0 && n < dev->num_irq);
@@ -97,17 +102,24 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, 
target_phys_addr_t size,
     dev->mmio[n].cb = cb;
 }
 
-static void sysbus_device_init(DeviceState *dev, void *opaque)
+static void sysbus_device_init(DeviceState *dev, DeviceInfo *base)
 {
-    sysbus_initfn init = (sysbus_initfn)opaque;
+    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
 
-    init(sysbus_from_qdev(dev));
+    info->init(sysbus_from_qdev(dev));
 }
 
 void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
 {
+    SysBusDeviceInfo *info;
+
+    info = qemu_mallocz(sizeof(*info));
+    info->init = init;
+    info->qdev.init = sysbus_device_init;
+    info->qdev.bus_type = BUS_TYPE_SYSTEM;
+
     assert(size >= sizeof(SysBusDevice));
-    qdev_register(name, size, sysbus_device_init, init);
+    qdev_register(name, size, &info->qdev);
 }
 
 DeviceState *sysbus_create_varargs(const char *name,
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index b9c1821..a9ef217 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -175,7 +175,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
     /* Use values found on a real PowerMac */
     /* Uninorth main bus */
     s = qemu_mallocz(sizeof(UNINState));
-    s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq,
+    s->bus = pci_register_bus(NULL, "pci",
+                              pci_unin_set_irq, pci_unin_map_irq,
                               pic, 11 << 3, 4);
 
     pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 720742c..e454d49 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -118,9 +118,9 @@ static void pci_vpb_init(SysBusDevice *dev)
     for (i = 0; i < 4; i++) {
         sysbus_init_irq(dev, &s->irq[i]);
     }
-    bus = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
+    bus = pci_register_bus(&dev->qdev, "pci",
+                           pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
                            11 << 3, 4);
-    qdev_attach_child_bus(&dev->qdev, "pci", bus);
 
     /* ??? Register memory space.  */
 
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 5ae57e3..eed97d6 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -201,7 +201,7 @@ static void versatile_init(ram_addr_t ram_size,
 
     dev = sysbus_create_varargs("versatile_pci", 0x40000000,
                                 sic[27], sic[28], sic[29], sic[30], NULL);
-    pci_bus = qdev_get_child_bus(dev, "pci");
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
 
     /* The Versatile PCI bridge does not provide access to PCI IO space,
        so many of the qemu PCI devices are not useable.  */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]