This allows future implementations of real pci-isa bridges or EISA bus emulation
Signed-off-by: Hervé Poussineau <hpous...@reactos.org> --- hw/isa-bus.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++----------- hw/isa.h | 15 ++++++++++++++ 2 files changed, 63 insertions(+), 12 deletions(-) diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 21b4b51..4757ff9 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -21,12 +21,9 @@ #include "sysbus.h" #include "isa.h" -struct ISABus { - BusState qbus; - qemu_irq *irqs; -}; static ISABus *isabus; target_phys_addr_t isa_mem_base = 0; +static qemu_irq *isa_bus_default_irqs; static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *isabus_get_fw_dev_path(DeviceState *dev); @@ -38,6 +35,24 @@ static struct BusInfo isa_bus_info = { .get_fw_dev_path = isabus_get_fw_dev_path, }; +static void isa_bus_default_set_irqs(ISABus *bus, qemu_irq *irqs) +{ + isa_bus_default_irqs = irqs; +} + +static qemu_irq isa_bus_default_get_irq(ISABus *bus, int isairq) +{ + if (isairq < 0 || isairq > 15) { + hw_error("isa irq %d invalid", isairq); + } + return isa_bus_default_irqs[isairq]; +} + +static ISABusOps isa_bus_default_ops = { + .set_irqs = isa_bus_default_set_irqs, + .get_irq = isa_bus_default_get_irq, +}; + ISABus *isa_bus_bridge_init(DeviceState *dev) { if (isabus) { @@ -48,14 +63,29 @@ ISABus *isa_bus_bridge_init(DeviceState *dev) dev = qdev_create(NULL, "isabus-bridge"); qdev_init_nofail(dev); } - - isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL)); + else { + isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL)); + isabus->ops = &isa_bus_default_ops; + } return isabus; } +void isa_bus_new(ISABus *bus, ISABusOps *ops, DeviceState *host) +{ + if (isabus) { + hw_error("Can't create a second ISA bus"); + } + qbus_create_inplace(&bus->qbus, &isa_bus_info, host, NULL); + bus->ops = ops; + isabus = bus; +} + void isa_bus_irqs(qemu_irq *irqs) { - isabus->irqs = irqs; + if (!isabus || !isabus->ops->set_irqs) { + hw_error("Tried to set isa irqs with no isa bus present."); + } + isabus->ops->set_irqs(isabus, irqs); } /* @@ -66,10 +96,10 @@ void isa_bus_irqs(qemu_irq *irqs) */ qemu_irq isa_get_irq(int isairq) { - if (isairq < 0 || isairq > 15) { - hw_error("isa irq %d invalid", isairq); + if (!isabus || !isabus->ops->get_irq) { + hw_error("ISA bus invalid"); } - return isabus->irqs[isairq]; + return isabus->ops->get_irq(isabus, isairq); } void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq) @@ -169,9 +199,15 @@ static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) } } +typedef struct { + SysBusDevice busdev; + ISABus bus; +} ISABridgeSysBusState; + static int isabus_bridge_init(SysBusDevice *dev) { - /* nothing */ + ISABridgeSysBusState *isa = FROM_SYSBUS(ISABridgeSysBusState, dev); + isa_bus_new(&isa->bus, &isa_bus_default_ops, &dev->qdev); return 0; } @@ -179,7 +215,7 @@ static SysBusDeviceInfo isabus_bridge_info = { .init = isabus_bridge_init, .qdev.name = "isabus-bridge", .qdev.fw_name = "isa", - .qdev.size = sizeof(SysBusDevice), + .qdev.size = sizeof(ISABridgeSysBusState), .qdev.no_user = 1, }; diff --git a/hw/isa.h b/hw/isa.h index d6938f1..8c1583f 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -8,6 +8,7 @@ #include "qdev.h" typedef struct ISABus ISABus; +typedef struct ISABusOps ISABusOps; typedef struct ISADevice ISADevice; typedef struct ISADeviceInfo ISADeviceInfo; @@ -25,7 +26,21 @@ struct ISADeviceInfo { isa_qdev_initfn init; }; +/* isa-bus.c */ + +struct ISABus { + BusState qbus; + ISABusOps *ops; +}; + +struct ISABusOps { + void (*set_irqs)(ISABus *bus, qemu_irq *irqs); + qemu_irq (*get_irq)(ISABus *bus, int isairq); +}; + ISABus *isa_bus_bridge_init(DeviceState *dev); + +void isa_bus_new(ISABus *bus, ISABusOps *ops, DeviceState *host); void isa_bus_irqs(qemu_irq *irqs); qemu_irq isa_get_irq(int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); -- 1.7.5.4