mirror of
https://github.com/qemu/qemu.git
synced 2024-11-24 19:33:39 +08:00
Add common BusState
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 <paul@codesourcery.com>
This commit is contained in:
parent
4856fcff8a
commit
02e2da45c4
@ -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);
|
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;
|
s->irq = sci_irq;
|
||||||
qemu_register_reset(piix4_reset, 0, s);
|
qemu_register_reset(piix4_reset, 0, s);
|
||||||
|
|
||||||
|
@ -231,7 +231,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
|
|||||||
|
|
||||||
s = qemu_mallocz(sizeof(APBState));
|
s = qemu_mallocz(sizeof(APBState));
|
||||||
/* Ultrasparc PBM main bus */
|
/* 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_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
|
||||||
pci_apb_config_write, s);
|
pci_apb_config_write, s);
|
||||||
|
@ -133,7 +133,8 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
|
|||||||
int pci_mem_config, pci_mem_data;
|
int pci_mem_config, pci_mem_data;
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(GrackleState));
|
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);
|
pic, 0, 4);
|
||||||
|
|
||||||
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
|
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
|
||||||
|
@ -1128,7 +1128,8 @@ PCIBus *pci_gt64120_init(qemu_irq *pic)
|
|||||||
s = qemu_mallocz(sizeof(GT64120State));
|
s = qemu_mallocz(sizeof(GT64120State));
|
||||||
s->pci = qemu_mallocz(sizeof(GT64120PCIState));
|
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);
|
pic, 144, 4);
|
||||||
s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s);
|
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),
|
d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
|
||||||
|
35
hw/i2c.c
35
hw/i2c.c
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
struct i2c_bus
|
struct i2c_bus
|
||||||
{
|
{
|
||||||
|
BusState qbus;
|
||||||
i2c_slave *current_dev;
|
i2c_slave *current_dev;
|
||||||
i2c_slave *dev;
|
i2c_slave *dev;
|
||||||
int saved_address;
|
int saved_address;
|
||||||
@ -39,11 +40,12 @@ static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new I2C bus. */
|
/* Create a new I2C bus. */
|
||||||
i2c_bus *i2c_init_bus(void)
|
i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
|
||||||
{
|
{
|
||||||
i2c_bus *bus;
|
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);
|
register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus);
|
||||||
return bus;
|
return bus;
|
||||||
}
|
}
|
||||||
@ -63,20 +65,22 @@ int i2c_bus_busy(i2c_bus *bus)
|
|||||||
/* TODO: Make this handle multiple masters. */
|
/* TODO: Make this handle multiple masters. */
|
||||||
int i2c_start_transfer(i2c_bus *bus, int address, int recv)
|
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) {
|
LIST_FOREACH(qdev, &bus->qbus.children, sibling) {
|
||||||
if (dev->address == address)
|
slave = I2C_SLAVE_FROM_QDEV(qdev);
|
||||||
|
if (slave->address == address)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dev)
|
if (!slave)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* If the bus is already busy, assume this is a repeated
|
/* If the bus is already busy, assume this is a repeated
|
||||||
start condition. */
|
start condition. */
|
||||||
bus->current_dev = dev;
|
bus->current_dev = slave;
|
||||||
dev->info->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
|
slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,23 +134,20 @@ void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
|
|||||||
void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
|
void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
|
||||||
{
|
{
|
||||||
i2c_bus *bus;
|
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);
|
dev->address = qemu_get_byte(f);
|
||||||
if (bus->saved_address == dev->address) {
|
if (bus->saved_address == dev->address) {
|
||||||
bus->current_dev = dev;
|
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);
|
i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
|
||||||
|
|
||||||
s->info = info;
|
s->info = info;
|
||||||
s->bus = qdev_get_bus(dev);
|
|
||||||
s->address = qdev_get_prop_int(dev, "address", 0);
|
s->address = qdev_get_prop_int(dev, "address", 0);
|
||||||
s->next = s->bus->dev;
|
|
||||||
s->bus->dev = s;
|
|
||||||
|
|
||||||
info->init(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)
|
void i2c_register_slave(const char *name, int size, I2CSlaveInfo *info)
|
||||||
{
|
{
|
||||||
assert(size >= sizeof(i2c_slave));
|
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 *i2c_create_slave(i2c_bus *bus, const char *name, int addr)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
|
||||||
dev = qdev_create(bus, name);
|
dev = qdev_create(&bus->qbus, name);
|
||||||
qdev_set_prop_int(dev, "address", addr);
|
qdev_set_prop_int(dev, "address", addr);
|
||||||
qdev_init(dev);
|
qdev_init(dev);
|
||||||
return dev;
|
return dev;
|
||||||
|
6
hw/i2c.h
6
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 void (*i2c_slave_initfn)(i2c_slave *dev);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
DeviceInfo qdev;
|
||||||
|
|
||||||
/* Callbacks provided by the device. */
|
/* Callbacks provided by the device. */
|
||||||
i2c_slave_initfn init;
|
i2c_slave_initfn init;
|
||||||
i2c_event_cb event;
|
i2c_event_cb event;
|
||||||
@ -39,11 +41,9 @@ struct i2c_slave
|
|||||||
|
|
||||||
/* Remaining fields for internal use by the I2C code. */
|
/* Remaining fields for internal use by the I2C code. */
|
||||||
int address;
|
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);
|
void i2c_set_slave_address(i2c_slave *dev, int address);
|
||||||
int i2c_bus_busy(i2c_bus *bus);
|
int i2c_bus_busy(i2c_bus *bus);
|
||||||
int i2c_start_transfer(i2c_bus *bus, int address, int recv);
|
int i2c_start_transfer(i2c_bus *bus, int address, int recv);
|
||||||
|
@ -907,7 +907,7 @@ void mips_malta_init (ram_addr_t ram_size,
|
|||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
/* TODO: Populate SPD eeprom data. */
|
/* TODO: Populate SPD eeprom data. */
|
||||||
DeviceState *eeprom;
|
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_int(eeprom, "address", 0x50 + i);
|
||||||
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
|
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
|
||||||
qdev_init(eeprom);
|
qdev_init(eeprom);
|
||||||
|
@ -431,7 +431,7 @@ static i2c_interface *musicpal_audio_init(qemu_irq irq)
|
|||||||
s->irq = irq;
|
s->irq = irq;
|
||||||
|
|
||||||
i2c = qemu_mallocz(sizeof(i2c_interface));
|
i2c = qemu_mallocz(sizeof(i2c_interface));
|
||||||
i2c->bus = i2c_init_bus();
|
i2c->bus = i2c_init_bus(NULL, "i2c");
|
||||||
i2c->current_addr = -1;
|
i2c->current_addr = -1;
|
||||||
|
|
||||||
s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR);
|
s->wm = i2c_create_slave(i2c->bus, "wm8750", MP_WM_ADDR);
|
||||||
|
@ -433,7 +433,7 @@ struct omap_i2c_s *omap_i2c_init(target_phys_addr_t base,
|
|||||||
s->irq = irq;
|
s->irq = irq;
|
||||||
s->drq[0] = dma[0];
|
s->drq[0] = dma[0];
|
||||||
s->drq[1] = dma[1];
|
s->drq[1] = dma[1];
|
||||||
s->bus = i2c_init_bus();
|
s->bus = i2c_init_bus(NULL, "i2c");
|
||||||
omap_i2c_reset(s);
|
omap_i2c_reset(s);
|
||||||
|
|
||||||
iomemtype = cpu_register_io_memory(0, omap_i2c_readfn,
|
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->irq = irq;
|
||||||
s->drq[0] = dma[0];
|
s->drq[0] = dma[0];
|
||||||
s->drq[1] = dma[1];
|
s->drq[1] = dma[1];
|
||||||
s->bus = i2c_init_bus();
|
s->bus = i2c_init_bus(NULL, "i2c");
|
||||||
omap_i2c_reset(s);
|
omap_i2c_reset(s);
|
||||||
|
|
||||||
iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
|
iomemtype = l4_register_io_memory(0, omap_i2c_readfn,
|
||||||
|
2
hw/pc.c
2
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]);
|
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
DeviceState *eeprom;
|
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_int(eeprom, "address", 0x50 + i);
|
||||||
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
|
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
|
||||||
qdev_init(eeprom);
|
qdev_init(eeprom);
|
||||||
|
37
hw/pci.c
37
hw/pci.c
@ -30,6 +30,7 @@
|
|||||||
//#define DEBUG_PCI
|
//#define DEBUG_PCI
|
||||||
|
|
||||||
struct PCIBus {
|
struct PCIBus {
|
||||||
|
BusState qbus;
|
||||||
int bus_num;
|
int bus_num;
|
||||||
int devfn_min;
|
int devfn_min;
|
||||||
pci_set_irq_fn set_irq;
|
pci_set_irq_fn set_irq;
|
||||||
@ -87,13 +88,16 @@ static int pcibus_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
return 0;
|
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)
|
qemu_irq *pic, int devfn_min, int nirq)
|
||||||
{
|
{
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
static int nbus = 0;
|
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->set_irq = set_irq;
|
||||||
bus->map_irq = map_irq;
|
bus->map_irq = map_irq;
|
||||||
bus->irq_opaque = pic;
|
bus->irq_opaque = pic;
|
||||||
@ -320,7 +324,7 @@ int pci_unregister_device(PCIDevice *pci_dev)
|
|||||||
qemu_free_irqs(pci_dev->irq);
|
qemu_free_irqs(pci_dev->irq);
|
||||||
pci_irq_index--;
|
pci_irq_index--;
|
||||||
pci_dev->bus->devices[pci_dev->devfn] = NULL;
|
pci_dev->bus->devices[pci_dev->devfn] = NULL;
|
||||||
qemu_free(pci_dev);
|
qdev_free(&pci_dev->qdev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,7 +825,7 @@ PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
|
|||||||
|
|
||||||
for (i = 0; pci_nic_models[i]; i++) {
|
for (i = 0; pci_nic_models[i]; i++) {
|
||||||
if (strcmp(nd->model, pci_nic_models[i]) == 0) {
|
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_prop_int(dev, "devfn", devfn);
|
||||||
qdev_set_netdev(dev, nd);
|
qdev_set_netdev(dev, nd);
|
||||||
qdev_init(dev);
|
qdev_init(dev);
|
||||||
@ -901,32 +905,43 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
|
|||||||
return s->bus;
|
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;
|
PCIDevice *pci_dev = (PCIDevice *)qdev;
|
||||||
pci_qdev_initfn init;
|
PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
int devfn;
|
int devfn;
|
||||||
|
|
||||||
init = opaque;
|
bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
|
||||||
bus = qdev_get_bus(qdev);
|
|
||||||
devfn = qdev_get_prop_int(qdev, "devfn", -1);
|
devfn = qdev_get_prop_int(qdev, "devfn", -1);
|
||||||
pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn,
|
pci_dev = do_pci_register_device(pci_dev, bus, "FIXME", devfn,
|
||||||
NULL, NULL);//FIXME:config_read, config_write);
|
NULL, NULL);//FIXME:config_read, config_write);
|
||||||
assert(pci_dev);
|
assert(pci_dev);
|
||||||
init(pci_dev);
|
info->init(pci_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pci_qdev_register(const char *name, int size, pci_qdev_initfn init)
|
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)
|
PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
|
||||||
dev = qdev_create(bus, name);
|
dev = qdev_create(&bus->qbus, name);
|
||||||
qdev_set_prop_int(dev, "devfn", devfn);
|
qdev_set_prop_int(dev, "devfn", devfn);
|
||||||
qdev_init(dev);
|
qdev_init(dev);
|
||||||
|
|
||||||
|
3
hw/pci.h
3
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 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);
|
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);
|
qemu_irq *pic, int devfn_min, int nirq);
|
||||||
|
|
||||||
PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
|
PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
|
||||||
|
@ -176,7 +176,8 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
|
|||||||
I440FXState *s;
|
I440FXState *s;
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(I440FXState));
|
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;
|
s->bus = b;
|
||||||
|
|
||||||
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
|
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
|
||||||
|
@ -297,8 +297,7 @@ static void pl022_init(SysBusDevice *dev)
|
|||||||
pl022_writefn, s);
|
pl022_writefn, s);
|
||||||
sysbus_init_mmio(dev, 0x1000, iomemtype);
|
sysbus_init_mmio(dev, 0x1000, iomemtype);
|
||||||
sysbus_init_irq(dev, &s->irq);
|
sysbus_init_irq(dev, &s->irq);
|
||||||
s->ssi = ssi_create_bus();
|
s->ssi = ssi_create_bus(&dev->qdev, "ssi");
|
||||||
qdev_attach_child_bus(&dev->qdev, "ssi", s->ssi);
|
|
||||||
pl022_reset(s);
|
pl022_reset(s);
|
||||||
register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s);
|
register_savevm("pl022_ssp", -1, 1, pl022_save, pl022_load, s);
|
||||||
}
|
}
|
||||||
|
@ -370,7 +370,8 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
|
|||||||
|
|
||||||
controller = qemu_mallocz(sizeof(PPC4xxPCIState));
|
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,
|
ppc4xx_pci_map_irq,
|
||||||
pci_irqs, 0, 4);
|
pci_irqs, 0, 4);
|
||||||
|
|
||||||
|
@ -317,7 +317,8 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
|
|||||||
|
|
||||||
controller = qemu_mallocz(sizeof(PPCE500PCIState));
|
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,
|
mpc85xx_pci_map_irq,
|
||||||
pci_irqs, 0x88, 4);
|
pci_irqs, 0x88, 4);
|
||||||
d = pci_register_device(controller->pci_state.bus,
|
d = pci_register_device(controller->pci_state.bus,
|
||||||
|
@ -136,7 +136,8 @@ PCIBus *pci_prep_init(qemu_irq *pic)
|
|||||||
int PPC_io_memory;
|
int PPC_io_memory;
|
||||||
|
|
||||||
s = qemu_mallocz(sizeof(PREPPCIState));
|
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_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
|
||||||
register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
|
register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
|
||||||
|
11
hw/pxa2xx.c
11
hw/pxa2xx.c
@ -863,8 +863,7 @@ static void pxa2xx_ssp_init(SysBusDevice *dev)
|
|||||||
register_savevm("pxa2xx_ssp", -1, 0,
|
register_savevm("pxa2xx_ssp", -1, 0,
|
||||||
pxa2xx_ssp_save, pxa2xx_ssp_load, s);
|
pxa2xx_ssp_save, pxa2xx_ssp_load, s);
|
||||||
|
|
||||||
s->bus = ssi_create_bus();
|
s->bus = ssi_create_bus(&dev->qdev, "ssi");
|
||||||
qdev_attach_child_bus(&dev->qdev, "ssi", s->bus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Real-Time Clock */
|
/* Real-Time Clock */
|
||||||
@ -1500,12 +1499,12 @@ PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
|
|||||||
PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState));
|
PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState));
|
||||||
|
|
||||||
/* FIXME: Should the slave device really be on a separate bus? */
|
/* 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 = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev));
|
||||||
s->slave->host = s;
|
s->slave->host = s;
|
||||||
|
|
||||||
s->irq = irq;
|
s->irq = irq;
|
||||||
s->bus = i2c_init_bus();
|
s->bus = i2c_init_bus(NULL, "i2c");
|
||||||
s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
|
s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK);
|
||||||
|
|
||||||
iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn,
|
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;
|
DeviceState *dev;
|
||||||
dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
|
dev = sysbus_create_simple("pxa2xx-ssp", pxa27x_ssp[i].io_base,
|
||||||
s->pic[pxa27x_ssp[i].irqn]);
|
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) {
|
if (usb_enabled) {
|
||||||
@ -2229,7 +2228,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
|
|||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
|
dev = sysbus_create_simple("pxa2xx-ssp", pxa255_ssp[i].io_base,
|
||||||
s->pic[pxa255_ssp[i].irqn]);
|
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) {
|
if (usb_enabled) {
|
||||||
|
89
hw/qdev.c
89
hw/qdev.c
@ -41,23 +41,18 @@ struct DeviceProperty {
|
|||||||
|
|
||||||
struct DeviceType {
|
struct DeviceType {
|
||||||
const char *name;
|
const char *name;
|
||||||
qdev_initfn init;
|
DeviceInfo *info;
|
||||||
void *opaque;
|
|
||||||
int size;
|
int size;
|
||||||
DeviceType *next;
|
DeviceType *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ChildBusList {
|
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
|
||||||
const char *name;
|
BusState *main_system_bus;
|
||||||
void *ptr;
|
|
||||||
ChildBusList *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
static DeviceType *device_type_list;
|
static DeviceType *device_type_list;
|
||||||
|
|
||||||
/* Register a new device type. */
|
/* Register a new device type. */
|
||||||
DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
|
void qdev_register(const char *name, int size, DeviceInfo *info)
|
||||||
void *opaque)
|
|
||||||
{
|
{
|
||||||
DeviceType *t;
|
DeviceType *t;
|
||||||
|
|
||||||
@ -68,16 +63,13 @@ DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
|
|||||||
device_type_list = t;
|
device_type_list = t;
|
||||||
t->name = qemu_strdup(name);
|
t->name = qemu_strdup(name);
|
||||||
t->size = size;
|
t->size = size;
|
||||||
t->init = init;
|
t->info = info;
|
||||||
t->opaque = opaque;
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new device. This only initializes the device state structure
|
/* Create a new device. This only initializes the device state structure
|
||||||
and allows properties to be set. qdev_init should be called to
|
and allows properties to be set. qdev_init should be called to
|
||||||
initialize the actual device emulation. */
|
initialize the actual device emulation. */
|
||||||
DeviceState *qdev_create(void *bus, const char *name)
|
DeviceState *qdev_create(BusState *bus, const char *name)
|
||||||
{
|
{
|
||||||
DeviceType *t;
|
DeviceType *t;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
@ -88,14 +80,28 @@ DeviceState *qdev_create(void *bus, const char *name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!t) {
|
if (!t) {
|
||||||
fprintf(stderr, "Unknown device '%s'\n", name);
|
hw_error("Unknown device '%s'\n", name);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = qemu_mallocz(t->size);
|
dev = qemu_mallocz(t->size);
|
||||||
dev->name = name;
|
dev->name = name;
|
||||||
dev->type = t;
|
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;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +110,14 @@ DeviceState *qdev_create(void *bus, const char *name)
|
|||||||
calling this function. */
|
calling this function. */
|
||||||
void qdev_init(DeviceState *dev)
|
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)
|
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)
|
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;
|
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) {
|
if (strcmp(name, bus->name) == 0) {
|
||||||
return bus->ptr;
|
return bus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
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;
|
static int next_scsi_bus;
|
||||||
|
|
||||||
/* Create a scsi bus, and attach devices to it. */
|
/* 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);
|
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;
|
||||||
|
}
|
||||||
|
54
hw/qdev.h
54
hw/qdev.h
@ -2,20 +2,20 @@
|
|||||||
#define QDEV_H
|
#define QDEV_H
|
||||||
|
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
|
#include "sys-queue.h"
|
||||||
|
|
||||||
typedef struct DeviceType DeviceType;
|
typedef struct DeviceType DeviceType;
|
||||||
|
|
||||||
typedef struct DeviceProperty DeviceProperty;
|
typedef struct DeviceProperty DeviceProperty;
|
||||||
|
|
||||||
typedef struct ChildBusList ChildBusList;
|
typedef struct BusState BusState;
|
||||||
|
|
||||||
/* This structure should not be accessed directly. We declare it here
|
/* This structure should not be accessed directly. We declare it here
|
||||||
so that it can be embedded in individual device state structures. */
|
so that it can be embedded in individual device state structures. */
|
||||||
struct DeviceState
|
struct DeviceState {
|
||||||
{
|
|
||||||
const char *name;
|
const char *name;
|
||||||
DeviceType *type;
|
DeviceType *type;
|
||||||
void *bus;
|
BusState *parent_bus;
|
||||||
DeviceProperty *props;
|
DeviceProperty *props;
|
||||||
int num_irq_sink;
|
int num_irq_sink;
|
||||||
qemu_irq *irq_sink;
|
qemu_irq *irq_sink;
|
||||||
@ -23,14 +23,32 @@ struct DeviceState
|
|||||||
qemu_irq *gpio_out;
|
qemu_irq *gpio_out;
|
||||||
int num_gpio_in;
|
int num_gpio_in;
|
||||||
qemu_irq *gpio_in;
|
qemu_irq *gpio_in;
|
||||||
ChildBusList *child_bus;
|
LIST_HEAD(, BusState) child_bus;
|
||||||
NICInfo *nd;
|
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. ***/
|
/*** 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_init(DeviceState *dev);
|
||||||
|
void qdev_free(DeviceState *dev);
|
||||||
|
|
||||||
/* Set properties between creation and init. */
|
/* Set properties between creation and init. */
|
||||||
void qdev_set_prop_int(DeviceState *dev, const char *name, uint64_t value);
|
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);
|
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
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. ***/
|
/*** 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,
|
typedef void (*SCSIAttachFn)(DeviceState *host, BlockDriverState *bdrv,
|
||||||
int unit);
|
int unit);
|
||||||
|
|
||||||
DeviceType *qdev_register(const char *name, int size, qdev_initfn init,
|
struct DeviceInfo {
|
||||||
void *opaque);
|
qdev_initfn init;
|
||||||
|
BusType bus_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
void qdev_register(const char *name, int size, DeviceInfo *info);
|
||||||
|
|
||||||
/* Register device properties. */
|
/* Register device properties. */
|
||||||
void qdev_init_irq_sink(DeviceState *dev, qemu_irq_handler handler, int nirq);
|
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_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
||||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, 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);
|
void scsi_bus_new(DeviceState *host, SCSIAttachFn attach);
|
||||||
|
|
||||||
CharDriverState *qdev_init_chardev(DeviceState *dev);
|
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);
|
uint64_t qdev_get_prop_int(DeviceState *dev, const char *name, uint64_t def);
|
||||||
void *qdev_get_prop_ptr(DeviceState *dev, const char *name);
|
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)
|
#define DO_UPCAST(type, field, dev) container_of(dev, type, field)
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
@ -109,7 +109,7 @@ static void realview_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
dev = sysbus_create_varargs("realview_pci", 0x60000000,
|
dev = sysbus_create_varargs("realview_pci", 0x60000000,
|
||||||
pic[48], pic[49], pic[50], pic[51], NULL);
|
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) {
|
if (usb_enabled) {
|
||||||
usb_ohci_init_pci(pci_bus, 3, -1);
|
usb_ohci_init_pci(pci_bus, 3, -1);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
int mem, reg, iop;
|
||||||
|
|
||||||
p = qemu_mallocz(sizeof(SHPCIC));
|
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),
|
p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
|
||||||
-1, NULL, NULL);
|
-1, NULL, NULL);
|
||||||
|
@ -706,12 +706,9 @@ static void corgi_ssp_init(SSISlave *dev)
|
|||||||
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
|
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
|
||||||
|
|
||||||
qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
|
qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
|
||||||
s->bus[0] = ssi_create_bus();
|
s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
|
||||||
qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]);
|
s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
|
||||||
s->bus[1] = ssi_create_bus();
|
s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
|
||||||
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]);
|
|
||||||
|
|
||||||
register_savevm("spitz_ssp", -1, 1, spitz_ssp_save, spitz_ssp_load, s);
|
register_savevm("spitz_ssp", -1, 1, spitz_ssp_save, spitz_ssp_load, s);
|
||||||
}
|
}
|
||||||
|
35
hw/ssi.c
35
hw/ssi.c
@ -10,16 +10,21 @@
|
|||||||
#include "ssi.h"
|
#include "ssi.h"
|
||||||
|
|
||||||
struct SSIBus {
|
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);
|
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;
|
s->info = info;
|
||||||
info->init(s);
|
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)
|
void ssi_register_slave(const char *name, int size, SSISlaveInfo *info)
|
||||||
{
|
{
|
||||||
assert(size >= sizeof(SSISlave));
|
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 *ssi_create_slave(SSIBus *bus, const char *name)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
dev = qdev_create(bus, name);
|
dev = qdev_create(&bus->qbus, name);
|
||||||
qdev_init(dev);
|
qdev_init(dev);
|
||||||
return 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)
|
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 0;
|
||||||
}
|
}
|
||||||
return bus->slave->info->transfer(bus->slave, val);
|
slave = SSI_SLAVE_FROM_QDEV(dev);
|
||||||
|
return slave->info->transfer(slave, val);
|
||||||
}
|
}
|
||||||
|
3
hw/ssi.h
3
hw/ssi.h
@ -17,6 +17,7 @@ typedef struct SSISlave SSISlave;
|
|||||||
|
|
||||||
/* Slave devices. */
|
/* Slave devices. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
DeviceInfo qdev;
|
||||||
void (*init)(SSISlave *dev);
|
void (*init)(SSISlave *dev);
|
||||||
uint32_t (*transfer)(SSISlave *dev, uint32_t val);
|
uint32_t (*transfer)(SSISlave *dev, uint32_t val);
|
||||||
} SSISlaveInfo;
|
} 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);
|
DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
|
||||||
|
|
||||||
/* Master interface. */
|
/* 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);
|
uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
|
||||||
|
|
||||||
|
@ -874,11 +874,11 @@ static int stellaris_i2c_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
static void stellaris_i2c_init(SysBusDevice * dev)
|
static void stellaris_i2c_init(SysBusDevice * dev)
|
||||||
{
|
{
|
||||||
stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
|
stellaris_i2c_state *s = FROM_SYSBUS(stellaris_i2c_state, dev);
|
||||||
i2c_bus *bus = i2c_init_bus();
|
i2c_bus *bus;
|
||||||
int iomemtype;
|
int iomemtype;
|
||||||
|
|
||||||
sysbus_init_irq(dev, &s->irq);
|
sysbus_init_irq(dev, &s->irq);
|
||||||
qdev_attach_child_bus(&dev->qdev, "i2c", bus);
|
bus = i2c_init_bus(&dev->qdev, "i2c");
|
||||||
s->bus = bus;
|
s->bus = bus;
|
||||||
|
|
||||||
iomemtype = cpu_register_io_memory(0, stellaris_i2c_readfn,
|
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);
|
stellaris_ssi_bus_state *s = FROM_SSI_SLAVE(stellaris_ssi_bus_state, dev);
|
||||||
|
|
||||||
s->bus[0] = ssi_create_bus();
|
s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
|
||||||
qdev_attach_child_bus(&dev->qdev, "ssi0", s->bus[0]);
|
s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
|
||||||
s->bus[1] = ssi_create_bus();
|
|
||||||
qdev_attach_child_bus(&dev->qdev, "ssi1", s->bus[1]);
|
|
||||||
qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
|
qdev_init_gpio_in(&dev->qdev, stellaris_ssi_bus_select, 1);
|
||||||
|
|
||||||
register_savevm("stellaris_ssi_bus", -1, 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)) {
|
if (board->dc2 & (1 << 12)) {
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
dev = sysbus_create_simple("stellaris-i2c", 0x40020000, pic[8]);
|
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) {
|
if (board->peripherals & BP_OLED_I2C) {
|
||||||
i2c_create_slave(i2c, "ssd0303", 0x3d);
|
i2c_create_slave(i2c, "ssd0303", 0x3d);
|
||||||
}
|
}
|
||||||
|
20
hw/sysbus.c
20
hw/sysbus.c
@ -21,6 +21,11 @@
|
|||||||
#include "sysbus.h"
|
#include "sysbus.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
DeviceInfo qdev;
|
||||||
|
sysbus_initfn init;
|
||||||
|
} SysBusDeviceInfo;
|
||||||
|
|
||||||
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
|
||||||
{
|
{
|
||||||
assert(n >= 0 && n < dev->num_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;
|
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)
|
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));
|
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,
|
DeviceState *sysbus_create_varargs(const char *name,
|
||||||
|
@ -175,7 +175,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
|
|||||||
/* Use values found on a real PowerMac */
|
/* Use values found on a real PowerMac */
|
||||||
/* Uninorth main bus */
|
/* Uninorth main bus */
|
||||||
s = qemu_mallocz(sizeof(UNINState));
|
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);
|
pic, 11 << 3, 4);
|
||||||
|
|
||||||
pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
|
pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
|
||||||
|
@ -118,9 +118,9 @@ static void pci_vpb_init(SysBusDevice *dev)
|
|||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
sysbus_init_irq(dev, &s->irq[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);
|
11 << 3, 4);
|
||||||
qdev_attach_child_bus(&dev->qdev, "pci", bus);
|
|
||||||
|
|
||||||
/* ??? Register memory space. */
|
/* ??? Register memory space. */
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ static void versatile_init(ram_addr_t ram_size,
|
|||||||
|
|
||||||
dev = sysbus_create_varargs("versatile_pci", 0x40000000,
|
dev = sysbus_create_varargs("versatile_pci", 0x40000000,
|
||||||
sic[27], sic[28], sic[29], sic[30], NULL);
|
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,
|
/* The Versatile PCI bridge does not provide access to PCI IO space,
|
||||||
so many of the qemu PCI devices are not useable. */
|
so many of the qemu PCI devices are not useable. */
|
||||||
|
Loading…
Reference in New Issue
Block a user