diff --git a/hw/i2c.c b/hw/i2c.c index 838f40f88e..98aa7fcd24 100644 --- a/hw/i2c.c +++ b/hw/i2c.c @@ -17,6 +17,11 @@ struct i2c_bus int saved_address; }; +static struct BusInfo i2c_bus_info = { + .name = "I2C", + .size = sizeof(i2c_bus), +}; + static void i2c_bus_save(QEMUFile *f, void *opaque) { i2c_bus *bus = (i2c_bus *)opaque; @@ -44,8 +49,7 @@ i2c_bus *i2c_init_bus(DeviceState *parent, const char *name) { i2c_bus *bus; - bus = FROM_QBUS(i2c_bus, qbus_create(BUS_TYPE_I2C, sizeof(i2c_bus), - parent, name)); + bus = FROM_QBUS(i2c_bus, qbus_create(&i2c_bus_info, parent, name)); register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); return bus; } @@ -156,7 +160,7 @@ void i2c_register_slave(I2CSlaveInfo *info) { assert(info->qdev.size >= sizeof(i2c_slave)); info->qdev.init = i2c_slave_qdev_init; - info->qdev.bus_type = BUS_TYPE_I2C; + info->qdev.bus_info = &i2c_bus_info; qdev_register(&info->qdev); } diff --git a/hw/pci.c b/hw/pci.c index e82965ff12..f4c749483e 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -45,7 +45,15 @@ struct PCIBus { /* The bus IRQ state is the logical OR of the connected devices. Keep a count of the number of devices with raised IRQs. */ int nirq; - int irq_count[]; + int *irq_count; +}; + +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); + +static struct BusInfo pci_bus_info = { + .name = "PCI", + .size = sizeof(PCIBus), + .print_dev = pcibus_dev_print, }; static void pci_update_mappings(PCIDevice *d); @@ -109,14 +117,13 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, PCIBus *bus; static int nbus = 0; - bus = FROM_QBUS(PCIBus, qbus_create(BUS_TYPE_PCI, - sizeof(PCIBus) + (nirq * sizeof(int)), - parent, name)); + bus = FROM_QBUS(PCIBus, qbus_create(&pci_bus_info, parent, name)); bus->set_irq = set_irq; bus->map_irq = map_irq; bus->irq_opaque = pic; bus->devfn_min = devfn_min; bus->nirq = nirq; + bus->irq_count = qemu_malloc(nirq * sizeof(bus->irq_count[0])); bus->next = first_bus; first_bus = bus; register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus); @@ -892,7 +899,7 @@ static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base) void pci_qdev_register(PCIDeviceInfo *info) { info->qdev.init = pci_qdev_init; - info->qdev.bus_type = BUS_TYPE_PCI; + info->qdev.bus_info = &pci_bus_info; qdev_register(&info->qdev); } @@ -991,3 +998,39 @@ uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) { return pci_find_capability_list(pdev, cap_id, NULL); } + +static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent) +{ + PCIDevice *d = (PCIDevice *)dev; + const pci_class_desc *desc; + char ctxt[64]; + PCIIORegion *r; + int i, class; + + class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) + desc++; + if (desc->desc) { + snprintf(ctxt, sizeof(ctxt), "%s", desc->desc); + } else { + snprintf(ctxt, sizeof(ctxt), "Class %04x", class); + } + + monitor_printf(mon, "%*sclass %s, addr %02x:%02x.%x, " + "pci id %04x:%04x (sub %04x:%04x)\n", + indent, "", ctxt, + d->bus->bus_num, d->devfn >> 3, d->devfn & 7, + le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), + le16_to_cpu(*((uint16_t *)(d->config + PCI_DEVICE_ID))), + le16_to_cpu(*((uint16_t *)(d->config + PCI_SUBSYSTEM_VENDOR_ID))), + le16_to_cpu(*((uint16_t *)(d->config + PCI_SUBSYSTEM_ID)))); + for (i = 0; i < PCI_NUM_REGIONS; i++) { + r = &d->io_regions[i]; + if (!r->size) + continue; + monitor_printf(mon, "%*sbar %d: %s at 0x%x [0x%x]\n", indent, "", + i, r->type & PCI_ADDRESS_SPACE_IO ? "i/o" : "mem", + r->addr, r->addr + r->size - 1); + } +} diff --git a/hw/qdev.c b/hw/qdev.c index 385e7099b1..8506d85fac 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -48,6 +48,7 @@ struct DeviceType { /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ static BusState *main_system_bus; +extern struct BusInfo system_bus_info; static DeviceType *device_type_list; @@ -72,31 +73,26 @@ DeviceState *qdev_create(BusState *bus, const char *name) DeviceType *t; DeviceState *dev; - for (t = device_type_list; t; t = t->next) { - if (strcmp(t->info->name, name) == 0) { - break; + if (!bus) { + if (!main_system_bus) { + main_system_bus = qbus_create(&system_bus_info, NULL, "main-system-bus"); } + bus = main_system_bus; + } + + for (t = device_type_list; t; t = t->next) { + if (t->info->bus_info != bus->info) + continue; + if (strcmp(t->info->name, name) != 0) + continue; + break; } if (!t) { - hw_error("Unknown device '%s'\n", name); + hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name); } dev = qemu_mallocz(t->info->size); dev->type = t; - - 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; @@ -320,13 +316,12 @@ void scsi_bus_new(DeviceState *host, SCSIAttachFn attach) } } -BusState *qbus_create(BusType type, size_t size, - DeviceState *parent, const char *name) +BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name) { BusState *bus; - bus = qemu_mallocz(size); - bus->type = type; + bus = qemu_mallocz(info->size); + bus->info = info; bus->parent = parent; bus->name = qemu_strdup(name); LIST_INIT(&bus->children); @@ -336,14 +331,6 @@ BusState *qbus_create(BusType type, size_t size, return bus; } -static const char *bus_type_names[] = { - [ BUS_TYPE_SYSTEM ] = "System", - [ BUS_TYPE_PCI ] = "PCI", - [ BUS_TYPE_SCSI ] = "SCSI", - [ BUS_TYPE_I2C ] = "I2C", - [ BUS_TYPE_SSI ] = "SSI", -}; - #define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) static void qbus_print(Monitor *mon, BusState *bus, int indent); @@ -377,13 +364,8 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent) break; } } - switch (dev->parent_bus->type) { - case BUS_TYPE_SYSTEM: - sysbus_dev_print(mon, dev, indent); - break; - default: - break; - } + if (dev->parent_bus->info->print_dev) + dev->parent_bus->info->print_dev(mon, dev, indent); LIST_FOREACH(child, &dev->child_bus, sibling) { qbus_print(mon, child, indent); } @@ -395,7 +377,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent) qdev_printf("bus: %s\n", bus->name); indent += 2; - qdev_printf("type %s\n", bus_type_names[bus->type]); + qdev_printf("type %s\n", bus->info->name); LIST_FOREACH(dev, &bus->children, sibling) { qdev_print(mon, dev, indent); } diff --git a/hw/qdev.h b/hw/qdev.h index ad104992a6..36def1e6bf 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -10,6 +10,8 @@ typedef struct DeviceProperty DeviceProperty; typedef struct BusState BusState; +typedef struct BusInfo BusInfo; + /* This structure should not be accessed directly. We declare it here so that it can be embedded in individual device state structures. */ struct DeviceState { @@ -25,18 +27,17 @@ struct DeviceState { LIST_ENTRY(DeviceState) sibling; }; -typedef enum { - BUS_TYPE_SYSTEM, - BUS_TYPE_PCI, - BUS_TYPE_SCSI, - BUS_TYPE_I2C, - BUS_TYPE_SSI -} BusType; +typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent); +struct BusInfo { + const char *name; + size_t size; + bus_dev_printfn print_dev; +}; struct BusState { DeviceState *parent; + BusInfo *info; const char *name; - BusType type; LIST_HEAD(, DeviceState) children; LIST_ENTRY(BusState) sibling; }; @@ -84,7 +85,7 @@ struct DeviceInfo { /* Private to qdev / bus. */ qdev_initfn init; - BusType bus_type; + BusInfo *bus_info; }; void qdev_register(DeviceInfo *info); @@ -116,14 +117,12 @@ void *qdev_get_prop_ptr(DeviceState *dev, const char *name); /*** BUS API. ***/ -BusState *qbus_create(BusType type, size_t size, - DeviceState *parent, const char *name); +BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name); #define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev) /*** monitor commands ***/ void do_info_qtree(Monitor *mon); -void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); #endif diff --git a/hw/ssi.c b/hw/ssi.c index b0bcf97151..a5133be81b 100644 --- a/hw/ssi.c +++ b/hw/ssi.c @@ -13,6 +13,11 @@ struct SSIBus { BusState qbus; }; +static struct BusInfo ssi_bus_info = { + .name = "SSI", + .size = sizeof(SSIBus), +}; + static void ssi_slave_init(DeviceState *dev, DeviceInfo *base_info) { SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev); @@ -33,7 +38,7 @@ void ssi_register_slave(SSISlaveInfo *info) { assert(info->qdev.size >= sizeof(SSISlave)); info->qdev.init = ssi_slave_init; - info->qdev.bus_type = BUS_TYPE_SSI; + info->qdev.bus_info = &ssi_bus_info; qdev_register(&info->qdev); } @@ -48,7 +53,7 @@ DeviceState *ssi_create_slave(SSIBus *bus, const char *name) SSIBus *ssi_create_bus(DeviceState *parent, const char *name) { BusState *bus; - bus = qbus_create(BUS_TYPE_SSI, sizeof(SSIBus), parent, name); + bus = qbus_create(&ssi_bus_info, parent, name); return FROM_QBUS(SSIBus, bus); } diff --git a/hw/sysbus.c b/hw/sysbus.c index ef3a7011e9..08f15e42fa 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -22,6 +22,14 @@ #include "sysemu.h" #include "monitor.h" +static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); + +struct BusInfo system_bus_info = { + .name = "System", + .size = sizeof(BusState), + .print_dev = sysbus_dev_print, +}; + void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq) { assert(n >= 0 && n < dev->num_irq); @@ -108,7 +116,7 @@ static void sysbus_device_init(DeviceState *dev, DeviceInfo *base) void sysbus_register_withprop(SysBusDeviceInfo *info) { info->qdev.init = sysbus_device_init; - info->qdev.bus_type = BUS_TYPE_SYSTEM; + info->qdev.bus_info = &system_bus_info; assert(info->qdev.size >= sizeof(SysBusDevice)); qdev_register(&info->qdev); @@ -153,7 +161,7 @@ DeviceState *sysbus_create_varargs(const char *name, return dev; } -void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) +static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = sysbus_from_qdev(dev); int i;