diff options
Diffstat (limited to 'hw')
294 files changed, 16283 insertions, 7096 deletions
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 41a1a820e0..791a5572bb 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -154,29 +154,39 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev) return 0; } -static PCIDeviceInfo virtio_9p_info = { - .qdev.name = "virtio-9p-pci", - .qdev.size = sizeof(VirtIOPCIProxy), - .init = virtio_9p_init_pci, - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = 0x1009, - .revision = VIRTIO_PCI_ABI_VERSION, - .class_id = 0x2, - .qdev.props = (Property[]) { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), - DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = virtio_pci_reset, +static Property virtio_9p_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), + DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_9p_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_9p_init_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = 0x1009; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = 0x2; + dc->props = virtio_9p_properties; + dc->reset = virtio_pci_reset; +} + +static TypeInfo virtio_9p_info = { + .name = "virtio-9p-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_9p_class_init, }; static void virtio_9p_register_devices(void) { - pci_qdev_register(&virtio_9p_info); + type_register_static(&virtio_9p_info); virtio_9p_set_fd_limit(); } diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c index 3ef0e138c4..19de12b4b4 100644 --- a/hw/a9mpcore.c +++ b/hw/a9mpcore.c @@ -11,9 +11,8 @@ #include "sysbus.h" /* Configuration for arm_gic.c: - * number of external IRQ lines, max number of CPUs, how to ID current CPU + * max number of CPUs, how to ID current CPU */ -#define GIC_NIRQ 96 #define NCPU 4 static inline int @@ -37,6 +36,7 @@ typedef struct a9mp_priv_state { MemoryRegion ptimer_iomem; MemoryRegion container; DeviceState *mptimer; + uint32_t num_irq; } a9mp_priv_state; static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset, @@ -153,7 +153,7 @@ static int a9mp_priv_init(SysBusDevice *dev) hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU); } - gic_init(&s->gic, s->num_cpu); + gic_init(&s->gic, s->num_cpu, s->num_irq); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); @@ -208,21 +208,39 @@ static const VMStateDescription vmstate_a9mp_priv = { } }; -static SysBusDeviceInfo a9mp_priv_info = { - .init = a9mp_priv_init, - .qdev.name = "a9mpcore_priv", - .qdev.size = sizeof(a9mp_priv_state), - .qdev.vmsd = &vmstate_a9mp_priv, - .qdev.reset = a9mp_priv_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1), - DEFINE_PROP_END_OF_LIST(), - } +static Property a9mp_priv_properties[] = { + DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1), + /* The Cortex-A9MP may have anything from 0 to 224 external interrupt + * IRQ lines (with another 32 internal). We default to 64+32, which + * is the number provided by the Cortex-A9MP test chip in the + * Realview PBX-A9 and Versatile Express A9 development boards. + * Other boards may differ and should set this property appropriately. + */ + DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96), + DEFINE_PROP_END_OF_LIST(), +}; + +static void a9mp_priv_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = a9mp_priv_init; + dc->props = a9mp_priv_properties; + dc->vmsd = &vmstate_a9mp_priv; + dc->reset = a9mp_priv_reset; +} + +static TypeInfo a9mp_priv_info = { + .name = "a9mpcore_priv", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(a9mp_priv_state), + .class_init = a9mp_priv_class_init, }; static void a9mp_register_devices(void) { - sysbus_register_withprop(&a9mp_priv_info); + type_register_static(&a9mp_priv_info); } device_init(a9mp_register_devices) @@ -1175,17 +1175,17 @@ static const VMStateDescription vmstate_ac97_bm_regs = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField []) { - VMSTATE_UINT32(bdbar, AC97BusMasterRegs), - VMSTATE_UINT8(civ, AC97BusMasterRegs), - VMSTATE_UINT8(lvi, AC97BusMasterRegs), - VMSTATE_UINT16(sr, AC97BusMasterRegs), - VMSTATE_UINT16(picb, AC97BusMasterRegs), - VMSTATE_UINT8(piv, AC97BusMasterRegs), - VMSTATE_UINT8(cr, AC97BusMasterRegs), - VMSTATE_UINT32(bd_valid, AC97BusMasterRegs), - VMSTATE_UINT32(bd.addr, AC97BusMasterRegs), - VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs), - VMSTATE_END_OF_LIST() + VMSTATE_UINT32 (bdbar, AC97BusMasterRegs), + VMSTATE_UINT8 (civ, AC97BusMasterRegs), + VMSTATE_UINT8 (lvi, AC97BusMasterRegs), + VMSTATE_UINT16 (sr, AC97BusMasterRegs), + VMSTATE_UINT16 (picb, AC97BusMasterRegs), + VMSTATE_UINT8 (piv, AC97BusMasterRegs), + VMSTATE_UINT8 (cr, AC97BusMasterRegs), + VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs), + VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs), + VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs), + VMSTATE_END_OF_LIST () } }; @@ -1224,15 +1224,15 @@ static const VMStateDescription vmstate_ac97 = { .minimum_version_id_old = 2, .post_load = ac97_post_load, .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, AC97LinkState), - VMSTATE_UINT32(glob_cnt, AC97LinkState), - VMSTATE_UINT32(glob_sta, AC97LinkState), - VMSTATE_UINT32(cas, AC97LinkState), - VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1, - vmstate_ac97_bm_regs, AC97BusMasterRegs), - VMSTATE_BUFFER(mixer_data, AC97LinkState), - VMSTATE_UNUSED_TEST(is_version_2, 3), - VMSTATE_END_OF_LIST() + VMSTATE_PCI_DEVICE (dev, AC97LinkState), + VMSTATE_UINT32 (glob_cnt, AC97LinkState), + VMSTATE_UINT32 (glob_sta, AC97LinkState), + VMSTATE_UINT32 (cas, AC97LinkState), + VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1, + vmstate_ac97_bm_regs, AC97BusMasterRegs), + VMSTATE_BUFFER (mixer_data, AC97LinkState), + VMSTATE_UNUSED_TEST (is_version_2, 3), + VMSTATE_END_OF_LIST () } }; @@ -1243,7 +1243,7 @@ static const MemoryRegionPortio nam_portio[] = { { 0, 256 * 1, 1, .write = nam_writeb, }, { 0, 256 * 2, 2, .write = nam_writew, }, { 0, 256 * 4, 4, .write = nam_writel, }, - PORTIO_END_OF_LIST(), + PORTIO_END_OF_LIST (), }; static const MemoryRegionOps ac97_io_nam_ops = { @@ -1257,7 +1257,7 @@ static const MemoryRegionPortio nabm_portio[] = { { 0, 64 * 1, 1, .write = nabm_writeb, }, { 0, 64 * 2, 2, .write = nabm_writew, }, { 0, 64 * 4, 4, .write = nabm_writel, }, - PORTIO_END_OF_LIST() + PORTIO_END_OF_LIST () }; static const MemoryRegionOps ac97_io_nabm_ops = { @@ -1344,26 +1344,37 @@ int ac97_init (PCIBus *bus) return 0; } -static PCIDeviceInfo ac97_info = { - .qdev.name = "AC97", - .qdev.desc = "Intel 82801AA AC97 Audio", - .qdev.size = sizeof (AC97LinkState), - .qdev.vmsd = &vmstate_ac97, - .init = ac97_initfn, - .exit = ac97_exitfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801AA_5, - .revision = 0x01, - .class_id = PCI_CLASS_MULTIMEDIA_AUDIO, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property ac97_properties[] = { + DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0), + DEFINE_PROP_END_OF_LIST (), +}; + +static void ac97_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); + + k->init = ac97_initfn; + k->exit = ac97_exitfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5; + k->revision = 0x01; + k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + dc->desc = "Intel 82801AA AC97 Audio"; + dc->vmsd = &vmstate_ac97; + dc->props = ac97_properties; +} + +static TypeInfo ac97_info = { + .name = "AC97", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof (AC97LinkState), + .class_init = ac97_class_init, }; static void ac97_register (void) { - pci_qdev_register (&ac97_info); + type_register_static (&ac97_info); } device_init (ac97_register); diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index bdc55a1eaa..21484aec42 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -280,11 +280,11 @@ static void piix4_update_hotplug(PIIX4PMState *s) s->pci0_hotplug_enable = ~0; QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { - PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev); - PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *pdev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev); int slot = PCI_SLOT(pdev->devfn); - if (info->no_hotplug) { + if (pc->no_hotplug) { s->pci0_hotplug_enable &= ~(1 << slot); } } @@ -396,28 +396,39 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, return s->smb.smbus; } -static PCIDeviceInfo piix4_pm_info = { - .qdev.name = "PIIX4_PM", - .qdev.desc = "PM", - .qdev.size = sizeof(PIIX4PMState), - .qdev.vmsd = &vmstate_acpi, - .qdev.no_user = 1, - .no_hotplug = 1, - .init = piix4_pm_initfn, - .config_write = pm_write_config, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371AB_3, - .revision = 0x03, - .class_id = PCI_CLASS_BRIDGE_OTHER, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property piix4_pm_properties[] = { + DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void piix4_pm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = piix4_pm_initfn; + k->config_write = pm_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3; + k->revision = 0x03; + k->class_id = PCI_CLASS_BRIDGE_OTHER; + dc->desc = "PM"; + dc->no_user = 1; + dc->vmsd = &vmstate_acpi; + dc->props = piix4_pm_properties; +} + +static TypeInfo piix4_pm_info = { + .name = "PIIX4_PM", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX4PMState), + .class_init = piix4_pm_class_init, }; static void piix4_pm_register(void) { - pci_qdev_register(&piix4_pm_info); + type_register_static(&piix4_pm_info); } device_init(piix4_pm_register); @@ -485,14 +496,12 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val) { BusState *bus = opaque; DeviceState *qdev, *next; - PCIDevice *dev; - PCIDeviceInfo *info; int slot = ffs(val) - 1; QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { - dev = DO_UPCAST(PCIDevice, qdev, qdev); - info = container_of(qdev->info, PCIDeviceInfo, qdev); - if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) { + PCIDevice *dev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) { qdev_free(qdev); } } @@ -553,7 +562,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, { int slot = PCI_SLOT(dev->devfn); PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, - DO_UPCAST(PCIDevice, qdev, qdev)); + PCI_DEVICE(qdev)); /* Don't send event when device is enabled during qemu machine creation: * it is present on boot, no hotplug event is necessary. We do send an diff --git a/hw/adlib.c b/hw/adlib.c index dd8b1888cf..d39cd97384 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -164,7 +164,7 @@ static void timer_handler (int c, double interval_Sec) s->ticking[n] = 1; #ifdef DEBUG - interval = get_ticks_per_sec() * interval_Sec; + interval = get_ticks_per_sec () * interval_Sec; exp = qemu_get_clock_ns (vm_clock) + interval; s->exp[n] = exp; #endif diff --git a/hw/ads7846.c b/hw/ads7846.c index de3f7af127..3cfdecbe5c 100644 --- a/hw/ads7846.c +++ b/hw/ads7846.c @@ -153,16 +153,24 @@ static int ads7846_init(SSISlave *dev) return 0; } -static SSISlaveInfo ads7846_info = { - .qdev.name ="ads7846", - .qdev.size = sizeof(ADS7846State), - .init = ads7846_init, - .transfer = ads7846_transfer +static void ads7846_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = ads7846_init; + k->transfer = ads7846_transfer; +} + +static TypeInfo ads7846_info = { + .name = "ads7846", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(ADS7846State), + .class_init = ads7846_class_init, }; static void ads7846_register_devices(void) { - ssi_register_slave(&ads7846_info); + type_register_static(&ads7846_info); } device_init(ads7846_register_devices) diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index e9757028af..673557781e 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -121,10 +121,8 @@ void alpha_pci_vga_setup(PCIBus *pci_bus) pci_cirrus_vga_init(pci_bus); return; case VGA_VMWARE: - if (pci_vmsvga_init(pci_bus)) { - return; - } - break; + pci_vmsvga_init(pci_bus); + return; } /* If VGA is enabled at all, and one of the above didn't work, then fallback to Standard VGA. */ diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 7d924a3f08..736c28a3a9 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -808,15 +808,24 @@ static int typhoon_pcihost_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo typhoon_pcihost_info = { - .init = typhoon_pcihost_init, - .qdev.name = "typhoon-pcihost", - .qdev.size = sizeof(TyphoonState), - .qdev.no_user = 1 +static void typhoon_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = typhoon_pcihost_init; + dc->no_user = 1; +} + +static TypeInfo typhoon_pcihost_info = { + .name = "typhoon-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TyphoonState), + .class_init = typhoon_pcihost_class_init, }; static void typhoon_register(void) { - sysbus_register_withprop(&typhoon_pcihost_info); + type_register_static(&typhoon_pcihost_info); } device_init(typhoon_register); diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 3a1b111455..c7aaa72d07 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -350,7 +350,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, sysbus_connect_irq(s, i, pic[i]); } - pci_create_simple(d->bus, 0, "pbm"); + pci_create_simple(d->bus, 0, "pbm-pci"); /* APB secondary busses */ pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true, @@ -436,42 +436,68 @@ static int pbm_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo pbm_pci_host_info = { - .qdev.name = "pbm", - .qdev.size = sizeof(PCIDevice), - .init = pbm_pci_host_init, - .vendor_id = PCI_VENDOR_ID_SUN, - .device_id = PCI_DEVICE_ID_SUN_SABRE, - .class_id = PCI_CLASS_BRIDGE_HOST, - .is_bridge = 1, +static void pbm_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pbm_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_SUN; + k->device_id = PCI_DEVICE_ID_SUN_SABRE; + k->class_id = PCI_CLASS_BRIDGE_HOST; + k->is_bridge = 1; +} + +static TypeInfo pbm_pci_host_info = { + .name = "pbm-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = pbm_pci_host_class_init, }; -static SysBusDeviceInfo pbm_host_info = { - .qdev.name = "pbm", - .qdev.size = sizeof(APBState), - .qdev.reset = pci_pbm_reset, - .init = pci_pbm_init_device, +static void pbm_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pci_pbm_init_device; + dc->reset = pci_pbm_reset; +} + +static TypeInfo pbm_host_info = { + .name = "pbm", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(APBState), + .class_init = pbm_host_class_init, }; -static PCIDeviceInfo pbm_pci_bridge_info = { - .qdev.name = "pbm-bridge", - .qdev.size = sizeof(PCIBridge), - .qdev.vmsd = &vmstate_pci_device, - .qdev.reset = pci_bridge_reset, - .init = apb_pci_bridge_initfn, - .exit = pci_bridge_exitfn, - .vendor_id = PCI_VENDOR_ID_SUN, - .device_id = PCI_DEVICE_ID_SUN_SIMBA, - .revision = 0x11, - .config_write = pci_bridge_write_config, - .is_bridge = 1, +static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = apb_pci_bridge_initfn; + k->exit = pci_bridge_exitfn; + k->vendor_id = PCI_VENDOR_ID_SUN; + k->device_id = PCI_DEVICE_ID_SUN_SIMBA; + k->revision = 0x11; + k->config_write = pci_bridge_write_config; + k->is_bridge = 1; + dc->reset = pci_bridge_reset; + dc->vmsd = &vmstate_pci_device; +} + +static TypeInfo pbm_pci_bridge_info = { + .name = "pbm-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIBridge), + .class_init = pbm_pci_bridge_class_init, }; static void pbm_register_devices(void) { - sysbus_register_withprop(&pbm_host_info); - pci_qdev_register(&pbm_pci_host_info); - pci_qdev_register(&pbm_pci_bridge_info); + type_register_static(&pbm_host_info); + type_register_static(&pbm_pci_host_info); + type_register_static(&pbm_pci_bridge_info); } device_init(pbm_register_devices) @@ -16,53 +16,13 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/> */ -#include "hw.h" +#include "apic_internal.h" #include "apic.h" #include "ioapic.h" -#include "qemu-timer.h" #include "host-utils.h" -#include "sysbus.h" #include "trace.h" #include "pc.h" -/* APIC Local Vector Table */ -#define APIC_LVT_TIMER 0 -#define APIC_LVT_THERMAL 1 -#define APIC_LVT_PERFORM 2 -#define APIC_LVT_LINT0 3 -#define APIC_LVT_LINT1 4 -#define APIC_LVT_ERROR 5 -#define APIC_LVT_NB 6 - -/* APIC delivery modes */ -#define APIC_DM_FIXED 0 -#define APIC_DM_LOWPRI 1 -#define APIC_DM_SMI 2 -#define APIC_DM_NMI 4 -#define APIC_DM_INIT 5 -#define APIC_DM_SIPI 6 -#define APIC_DM_EXTINT 7 - -/* APIC destination mode */ -#define APIC_DESTMODE_FLAT 0xf -#define APIC_DESTMODE_CLUSTER 1 - -#define APIC_TRIGGER_EDGE 0 -#define APIC_TRIGGER_LEVEL 1 - -#define APIC_LVT_TIMER_PERIODIC (1<<17) -#define APIC_LVT_MASKED (1<<16) -#define APIC_LVT_LEVEL_TRIGGER (1<<15) -#define APIC_LVT_REMOTE_IRR (1<<14) -#define APIC_INPUT_POLARITY (1<<13) -#define APIC_SEND_PENDING (1<<12) - -#define ESR_ILLEGAL_ADDRESS (1 << 7) - -#define APIC_SV_DIRECTED_IO (1<<12) -#define APIC_SV_ENABLE (1<<8) - -#define MAX_APICS 255 #define MAX_APIC_WORDS 8 /* Intel APIC constants: from include/asm/msidef.h */ @@ -75,43 +35,10 @@ #define MSI_ADDR_DEST_ID_SHIFT 12 #define MSI_ADDR_DEST_ID_MASK 0x00ffff0 -#define MSI_ADDR_SIZE 0x100000 - -typedef struct APICState APICState; - -struct APICState { - SysBusDevice busdev; - MemoryRegion io_memory; - void *cpu_env; - uint32_t apicbase; - uint8_t id; - uint8_t arb_id; - uint8_t tpr; - uint32_t spurious_vec; - uint8_t log_dest; - uint8_t dest_mode; - uint32_t isr[8]; /* in service register */ - uint32_t tmr[8]; /* trigger mode register */ - uint32_t irr[8]; /* interrupt request register */ - uint32_t lvt[APIC_LVT_NB]; - uint32_t esr; /* error register */ - uint32_t icr[2]; - - uint32_t divide_conf; - int count_shift; - uint32_t initial_count; - int64_t initial_count_load_time, next_time; - uint32_t idx; - QEMUTimer *timer; - int sipi_vector; - int wait_for_sipi; -}; - -static APICState *local_apics[MAX_APICS + 1]; -static int apic_irq_delivered; +static APICCommonState *local_apics[MAX_APICS + 1]; -static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); -static void apic_update_irq(APICState *s); +static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); +static void apic_update_irq(APICCommonState *s); static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, uint8_t dest, uint8_t dest_mode); @@ -151,7 +78,7 @@ static inline int get_bit(uint32_t *tab, int index) return !!(tab[i] & mask); } -static void apic_local_deliver(APICState *s, int vector) +static void apic_local_deliver(APICCommonState *s, int vector) { uint32_t lvt = s->lvt[vector]; int trigger_mode; @@ -185,7 +112,7 @@ static void apic_local_deliver(APICState *s, int vector) void apic_deliver_pic_intr(DeviceState *d, int level) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); if (level) { apic_local_deliver(s, APIC_LVT_LINT0); @@ -205,6 +132,11 @@ void apic_deliver_pic_intr(DeviceState *d, int level) } } +static void apic_external_nmi(APICCommonState *s) +{ + apic_local_deliver(s, APIC_LVT_LINT1); +} + #define foreach_apic(apic, deliver_bitmask, code) \ {\ int __i, __j, __mask;\ @@ -227,7 +159,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) { - APICState *apic_iter; + APICCommonState *apic_iter; switch (delivery_mode) { case APIC_DM_LOWPRI: @@ -293,14 +225,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); } -void cpu_set_apic_base(DeviceState *d, uint64_t val) +static void apic_set_base(APICCommonState *s, uint64_t val) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - - trace_cpu_set_apic_base(val); - - if (!s) - return; s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); /* if disabled, cannot be enabled again */ @@ -311,32 +237,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val) } } -uint64_t cpu_get_apic_base(DeviceState *d) -{ - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - - trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0); - - return s ? s->apicbase : 0; -} - -void cpu_set_apic_tpr(DeviceState *d, uint8_t val) +static void apic_set_tpr(APICCommonState *s, uint8_t val) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - - if (!s) - return; s->tpr = (val & 0x0f) << 4; apic_update_irq(s); } -uint8_t cpu_get_apic_tpr(DeviceState *d) -{ - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - - return s ? s->tpr >> 4 : 0; -} - /* return -1 if no bit is set */ static int get_highest_priority_int(uint32_t *tab) { @@ -349,7 +255,7 @@ static int get_highest_priority_int(uint32_t *tab) return -1; } -static int apic_get_ppr(APICState *s) +static int apic_get_ppr(APICCommonState *s) { int tpr, isrv, ppr; @@ -365,7 +271,7 @@ static int apic_get_ppr(APICState *s) return ppr; } -static int apic_get_arb_pri(APICState *s) +static int apic_get_arb_pri(APICCommonState *s) { /* XXX: arbitration */ return 0; @@ -377,7 +283,7 @@ static int apic_get_arb_pri(APICState *s) * 0 - no interrupt, * >0 - interrupt number */ -static int apic_irq_pending(APICState *s) +static int apic_irq_pending(APICCommonState *s) { int irrv, ppr; irrv = get_highest_priority_int(s->irr); @@ -393,7 +299,7 @@ static int apic_irq_pending(APICState *s) } /* signal the CPU if an irq is pending */ -static void apic_update_irq(APICState *s) +static void apic_update_irq(APICCommonState *s) { if (!(s->spurious_vec & APIC_SV_ENABLE)) { return; @@ -406,25 +312,9 @@ static void apic_update_irq(APICState *s) } } -void apic_reset_irq_delivered(void) +static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) { - trace_apic_reset_irq_delivered(apic_irq_delivered); - - apic_irq_delivered = 0; -} - -int apic_get_irq_delivered(void) -{ - trace_apic_get_irq_delivered(apic_irq_delivered); - - return apic_irq_delivered; -} - -static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) -{ - apic_irq_delivered += !get_bit(s->irr, vector_num); - - trace_apic_set_irq(apic_irq_delivered); + apic_report_irq_delivered(!get_bit(s->irr, vector_num)); set_bit(s->irr, vector_num); if (trigger_mode) @@ -434,7 +324,7 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) apic_update_irq(s); } -static void apic_eoi(APICState *s) +static void apic_eoi(APICCommonState *s) { int isrv; isrv = get_highest_priority_int(s->isr); @@ -449,7 +339,7 @@ static void apic_eoi(APICState *s) static int apic_find_dest(uint8_t dest) { - APICState *apic = local_apics[dest]; + APICCommonState *apic = local_apics[dest]; int i; if (apic && apic->id == dest) @@ -469,7 +359,7 @@ static int apic_find_dest(uint8_t dest) static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, uint8_t dest, uint8_t dest_mode) { - APICState *apic_iter; + APICCommonState *apic_iter; int i; if (dest_mode == 0) { @@ -503,34 +393,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, } } -void apic_init_reset(DeviceState *d) -{ - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - int i; - - if (!s) - return; - - s->tpr = 0; - s->spurious_vec = 0xff; - s->log_dest = 0; - s->dest_mode = 0xf; - memset(s->isr, 0, sizeof(s->isr)); - memset(s->tmr, 0, sizeof(s->tmr)); - memset(s->irr, 0, sizeof(s->irr)); - for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ - s->esr = 0; - memset(s->icr, 0, sizeof(s->icr)); - s->divide_conf = 0; - s->count_shift = 0; - s->initial_count = 0; - s->initial_count_load_time = 0; - s->next_time = 0; - s->wait_for_sipi = 1; -} - -static void apic_startup(APICState *s, int vector_num) +static void apic_startup(APICCommonState *s, int vector_num) { s->sipi_vector = vector_num; cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI); @@ -538,7 +401,7 @@ static void apic_startup(APICState *s, int vector_num) void apic_sipi(DeviceState *d) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI); @@ -552,10 +415,10 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); uint32_t deliver_bitmask[MAX_APIC_WORDS]; int dest_shorthand = (s->icr[0] >> 18) & 3; - APICState *apic_iter; + APICCommonState *apic_iter; switch (dest_shorthand) { case 0: @@ -598,7 +461,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode, int apic_get_interrupt(DeviceState *d) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); int intno; /* if the APIC is installed or enabled, we let the 8259 handle the @@ -623,7 +486,7 @@ int apic_get_interrupt(DeviceState *d) int apic_accept_pic_intr(DeviceState *d) { - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); uint32_t lvt0; if (!s) @@ -638,7 +501,7 @@ int apic_accept_pic_intr(DeviceState *d) return 0; } -static uint32_t apic_get_current_count(APICState *s) +static uint32_t apic_get_current_count(APICCommonState *s) { int64_t d; uint32_t val; @@ -656,34 +519,18 @@ static uint32_t apic_get_current_count(APICState *s) return val; } -static void apic_timer_update(APICState *s, int64_t current_time) +static void apic_timer_update(APICCommonState *s, int64_t current_time) { - int64_t next_time, d; - - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - d = (current_time - s->initial_count_load_time) >> - s->count_shift; - if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - if (!s->initial_count) - goto no_timer; - d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); - } else { - if (d >= s->initial_count) - goto no_timer; - d = (uint64_t)s->initial_count + 1; - } - next_time = s->initial_count_load_time + (d << s->count_shift); - qemu_mod_timer(s->timer, next_time); - s->next_time = next_time; + if (apic_next_timer(s, current_time)) { + qemu_mod_timer(s->timer, s->next_time); } else { - no_timer: qemu_del_timer(s->timer); } } static void apic_timer(void *opaque) { - APICState *s = opaque; + APICCommonState *s = opaque; apic_local_deliver(s, APIC_LVT_TIMER); apic_timer_update(s, s->next_time); @@ -710,7 +557,7 @@ static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) { DeviceState *d; - APICState *s; + APICCommonState *s; uint32_t val; int index; @@ -718,7 +565,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) if (!d) { return 0; } - s = DO_UPCAST(APICState, busdev.qdev, d); + s = DO_UPCAST(APICCommonState, busdev.qdev, d); index = (addr >> 4) & 0xff; switch(index) { @@ -801,7 +648,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data) static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { DeviceState *d; - APICState *s; + APICCommonState *s; int index = (addr >> 4) & 0xff; if (addr > 0xfff || !index) { /* MSI and MMIO APIC are at the same memory location, @@ -817,7 +664,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) if (!d) { return; } - s = DO_UPCAST(APICState, busdev.qdev, d); + s = DO_UPCAST(APICCommonState, busdev.qdev, d); trace_apic_mem_writel(addr, val); @@ -890,93 +737,12 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) } } -/* This function is only used for old state version 1 and 2 */ -static int apic_load_old(QEMUFile *f, void *opaque, int version_id) +static void apic_post_load(APICCommonState *s) { - APICState *s = opaque; - int i; - - if (version_id > 2) - return -EINVAL; - - /* XXX: what if the base changes? (registered memory regions) */ - qemu_get_be32s(f, &s->apicbase); - qemu_get_8s(f, &s->id); - qemu_get_8s(f, &s->arb_id); - qemu_get_8s(f, &s->tpr); - qemu_get_be32s(f, &s->spurious_vec); - qemu_get_8s(f, &s->log_dest); - qemu_get_8s(f, &s->dest_mode); - for (i = 0; i < 8; i++) { - qemu_get_be32s(f, &s->isr[i]); - qemu_get_be32s(f, &s->tmr[i]); - qemu_get_be32s(f, &s->irr[i]); - } - for (i = 0; i < APIC_LVT_NB; i++) { - qemu_get_be32s(f, &s->lvt[i]); - } - qemu_get_be32s(f, &s->esr); - qemu_get_be32s(f, &s->icr[0]); - qemu_get_be32s(f, &s->icr[1]); - qemu_get_be32s(f, &s->divide_conf); - s->count_shift=qemu_get_be32(f); - qemu_get_be32s(f, &s->initial_count); - s->initial_count_load_time=qemu_get_be64(f); - s->next_time=qemu_get_be64(f); - - if (version_id >= 2) - qemu_get_timer(f, s->timer); - return 0; -} - -static const VMStateDescription vmstate_apic = { - .name = "apic", - .version_id = 3, - .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = apic_load_old, - .fields = (VMStateField []) { - VMSTATE_UINT32(apicbase, APICState), - VMSTATE_UINT8(id, APICState), - VMSTATE_UINT8(arb_id, APICState), - VMSTATE_UINT8(tpr, APICState), - VMSTATE_UINT32(spurious_vec, APICState), - VMSTATE_UINT8(log_dest, APICState), - VMSTATE_UINT8(dest_mode, APICState), - VMSTATE_UINT32_ARRAY(isr, APICState, 8), - VMSTATE_UINT32_ARRAY(tmr, APICState, 8), - VMSTATE_UINT32_ARRAY(irr, APICState, 8), - VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB), - VMSTATE_UINT32(esr, APICState), - VMSTATE_UINT32_ARRAY(icr, APICState, 2), - VMSTATE_UINT32(divide_conf, APICState), - VMSTATE_INT32(count_shift, APICState), - VMSTATE_UINT32(initial_count, APICState), - VMSTATE_INT64(initial_count_load_time, APICState), - VMSTATE_INT64(next_time, APICState), - VMSTATE_TIMER(timer, APICState), - VMSTATE_END_OF_LIST() - } -}; - -static void apic_reset(DeviceState *d) -{ - APICState *s = DO_UPCAST(APICState, busdev.qdev, d); - int bsp; - - bsp = cpu_is_bsp(s->cpu_env); - s->apicbase = 0xfee00000 | - (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE; - - apic_init_reset(d); - - if (bsp) { - /* - * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization - * time typically by BIOS, so PIC interrupt can be delivered to the - * processor when local APIC is enabled. - */ - s->lvt[APIC_LVT_LINT0] = 0x700; + if (s->timer_expiry != -1) { + qemu_mod_timer(s->timer, s->timer_expiry); + } else { + qemu_del_timer(s->timer); } } @@ -988,41 +754,36 @@ static const MemoryRegionOps apic_io_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static int apic_init1(SysBusDevice *dev) +static void apic_init(APICCommonState *s) { - APICState *s = FROM_SYSBUS(APICState, dev); - static int last_apic_idx; - - if (last_apic_idx >= MAX_APICS) { - return -1; - } - memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic", - MSI_ADDR_SIZE); - sysbus_init_mmio(dev, &s->io_memory); + memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi", + MSI_SPACE_SIZE); s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s); - s->idx = last_apic_idx++; local_apics[s->idx] = s; - return 0; } -static SysBusDeviceInfo apic_info = { - .init = apic_init1, - .qdev.name = "apic", - .qdev.size = sizeof(APICState), - .qdev.vmsd = &vmstate_apic, - .qdev.reset = apic_reset, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("id", APICState, id, -1), - DEFINE_PROP_PTR("cpu_env", APICState, cpu_env), - DEFINE_PROP_END_OF_LIST(), - } +static void apic_class_init(ObjectClass *klass, void *data) +{ + APICCommonClass *k = APIC_COMMON_CLASS(klass); + + k->init = apic_init; + k->set_base = apic_set_base; + k->set_tpr = apic_set_tpr; + k->external_nmi = apic_external_nmi; + k->post_load = apic_post_load; +} + +static TypeInfo apic_info = { + .name = "apic", + .instance_size = sizeof(APICCommonState), + .parent = TYPE_APIC_COMMON, + .class_init = apic_class_init, }; static void apic_register_devices(void) { - sysbus_register_withprop(&apic_info); + type_register_static(&apic_info); } device_init(apic_register_devices) @@ -8,6 +8,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, uint8_t vector_num, uint8_t trigger_mode); int apic_accept_pic_intr(DeviceState *s); void apic_deliver_pic_intr(DeviceState *s, int level); +void apic_deliver_nmi(DeviceState *d); int apic_get_interrupt(DeviceState *s); void apic_reset_irq_delivered(void); int apic_get_irq_delivered(void); diff --git a/hw/apic_common.c b/hw/apic_common.c new file mode 100644 index 0000000000..26991b4516 --- /dev/null +++ b/hw/apic_common.c @@ -0,0 +1,321 @@ +/* + * APIC support - common bits of emulated and KVM kernel model + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ +#include "apic.h" +#include "apic_internal.h" +#include "trace.h" + +static int apic_irq_delivered; + +void cpu_set_apic_base(DeviceState *d, uint64_t val) +{ + trace_cpu_set_apic_base(val); + + if (d) { + APICCommonState *s = APIC_COMMON(d); + APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + info->set_base(s, val); + } +} + +uint64_t cpu_get_apic_base(DeviceState *d) +{ + if (d) { + APICCommonState *s = APIC_COMMON(d); + trace_cpu_get_apic_base((uint64_t)s->apicbase); + return s->apicbase; + } else { + trace_cpu_get_apic_base(0); + return 0; + } +} + +void cpu_set_apic_tpr(DeviceState *d, uint8_t val) +{ + APICCommonState *s; + APICCommonClass *info; + + if (!d) { + return; + } + + s = APIC_COMMON(d); + info = APIC_COMMON_GET_CLASS(s); + + info->set_tpr(s, val); +} + +uint8_t cpu_get_apic_tpr(DeviceState *d) +{ + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); + + return s ? s->tpr >> 4 : 0; +} + +void apic_report_irq_delivered(int delivered) +{ + apic_irq_delivered += delivered; + + trace_apic_report_irq_delivered(apic_irq_delivered); +} + +void apic_reset_irq_delivered(void) +{ + trace_apic_reset_irq_delivered(apic_irq_delivered); + + apic_irq_delivered = 0; +} + +int apic_get_irq_delivered(void) +{ + trace_apic_get_irq_delivered(apic_irq_delivered); + + return apic_irq_delivered; +} + +void apic_deliver_nmi(DeviceState *d) +{ + APICCommonState *s = APIC_COMMON(d); + APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + + info->external_nmi(s); +} + +bool apic_next_timer(APICCommonState *s, int64_t current_time) +{ + int64_t d; + + /* We need to store the timer state separately to support APIC + * implementations that maintain a non-QEMU timer, e.g. inside the + * host kernel. This open-coded state allows us to migrate between + * both models. */ + s->timer_expiry = -1; + + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) { + return false; + } + + d = (current_time - s->initial_count_load_time) >> s->count_shift; + + if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { + if (!s->initial_count) { + return false; + } + d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * + ((uint64_t)s->initial_count + 1); + } else { + if (d >= s->initial_count) { + return false; + } + d = (uint64_t)s->initial_count + 1; + } + s->next_time = s->initial_count_load_time + (d << s->count_shift); + s->timer_expiry = s->next_time; + return true; +} + +void apic_init_reset(DeviceState *d) +{ + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); + int i; + + if (!s) { + return; + } + s->tpr = 0; + s->spurious_vec = 0xff; + s->log_dest = 0; + s->dest_mode = 0xf; + memset(s->isr, 0, sizeof(s->isr)); + memset(s->tmr, 0, sizeof(s->tmr)); + memset(s->irr, 0, sizeof(s->irr)); + for (i = 0; i < APIC_LVT_NB; i++) { + s->lvt[i] = APIC_LVT_MASKED; + } + s->esr = 0; + memset(s->icr, 0, sizeof(s->icr)); + s->divide_conf = 0; + s->count_shift = 0; + s->initial_count = 0; + s->initial_count_load_time = 0; + s->next_time = 0; + s->wait_for_sipi = 1; + + if (s->timer) { + qemu_del_timer(s->timer); + } + s->timer_expiry = -1; +} + +static void apic_reset_common(DeviceState *d) +{ + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); + bool bsp; + + bsp = cpu_is_bsp(s->cpu_env); + s->apicbase = 0xfee00000 | + (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE; + + apic_init_reset(d); + + if (bsp) { + /* + * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization + * time typically by BIOS, so PIC interrupt can be delivered to the + * processor when local APIC is enabled. + */ + s->lvt[APIC_LVT_LINT0] = 0x700; + } +} + +/* This function is only used for old state version 1 and 2 */ +static int apic_load_old(QEMUFile *f, void *opaque, int version_id) +{ + APICCommonState *s = opaque; + int i; + + if (version_id > 2) { + return -EINVAL; + } + + /* XXX: what if the base changes? (registered memory regions) */ + qemu_get_be32s(f, &s->apicbase); + qemu_get_8s(f, &s->id); + qemu_get_8s(f, &s->arb_id); + qemu_get_8s(f, &s->tpr); + qemu_get_be32s(f, &s->spurious_vec); + qemu_get_8s(f, &s->log_dest); + qemu_get_8s(f, &s->dest_mode); + for (i = 0; i < 8; i++) { + qemu_get_be32s(f, &s->isr[i]); + qemu_get_be32s(f, &s->tmr[i]); + qemu_get_be32s(f, &s->irr[i]); + } + for (i = 0; i < APIC_LVT_NB; i++) { + qemu_get_be32s(f, &s->lvt[i]); + } + qemu_get_be32s(f, &s->esr); + qemu_get_be32s(f, &s->icr[0]); + qemu_get_be32s(f, &s->icr[1]); + qemu_get_be32s(f, &s->divide_conf); + s->count_shift = qemu_get_be32(f); + qemu_get_be32s(f, &s->initial_count); + s->initial_count_load_time = qemu_get_be64(f); + s->next_time = qemu_get_be64(f); + + if (version_id >= 2) { + qemu_get_timer(f, s->timer); + } + return 0; +} + +static int apic_init_common(SysBusDevice *dev) +{ + APICCommonState *s = APIC_COMMON(dev); + APICCommonClass *info; + static int apic_no; + + if (apic_no >= MAX_APICS) { + return -1; + } + s->idx = apic_no++; + + info = APIC_COMMON_GET_CLASS(s); + info->init(s); + + sysbus_init_mmio(&s->busdev, &s->io_memory); + return 0; +} + +static int apic_dispatch_post_load(void *opaque, int version_id) +{ + APICCommonState *s = APIC_COMMON(opaque); + APICCommonClass *info = APIC_COMMON_GET_CLASS(s); + + if (info->post_load) { + info->post_load(s); + } + return 0; +} + +static const VMStateDescription vmstate_apic_common = { + .name = "apic", + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 1, + .load_state_old = apic_load_old, + .post_load = apic_dispatch_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(apicbase, APICCommonState), + VMSTATE_UINT8(id, APICCommonState), + VMSTATE_UINT8(arb_id, APICCommonState), + VMSTATE_UINT8(tpr, APICCommonState), + VMSTATE_UINT32(spurious_vec, APICCommonState), + VMSTATE_UINT8(log_dest, APICCommonState), + VMSTATE_UINT8(dest_mode, APICCommonState), + VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8), + VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8), + VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8), + VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB), + VMSTATE_UINT32(esr, APICCommonState), + VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2), + VMSTATE_UINT32(divide_conf, APICCommonState), + VMSTATE_INT32(count_shift, APICCommonState), + VMSTATE_UINT32(initial_count, APICCommonState), + VMSTATE_INT64(initial_count_load_time, APICCommonState), + VMSTATE_INT64(next_time, APICCommonState), + VMSTATE_INT64(timer_expiry, + APICCommonState), /* open-coded timer state */ + VMSTATE_END_OF_LIST() + } +}; + +static Property apic_properties_common[] = { + DEFINE_PROP_UINT8("id", APICCommonState, id, -1), + DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env), + DEFINE_PROP_END_OF_LIST(), +}; + +static void apic_common_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_apic_common; + dc->reset = apic_reset_common; + dc->no_user = 1; + dc->props = apic_properties_common; + sc->init = apic_init_common; +} + +static TypeInfo apic_common_type = { + .name = TYPE_APIC_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(APICCommonState), + .class_size = sizeof(APICCommonClass), + .class_init = apic_common_class_init, + .abstract = true, +}; + +static void register_devices(void) +{ + type_register_static(&apic_common_type); +} + +device_init(register_devices); diff --git a/hw/apic_internal.h b/hw/apic_internal.h new file mode 100644 index 0000000000..0cab010717 --- /dev/null +++ b/hw/apic_internal.h @@ -0,0 +1,122 @@ +/* + * APIC support - internal interfaces + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ +#ifndef QEMU_APIC_INTERNAL_H +#define QEMU_APIC_INTERNAL_H + +#include "memory.h" +#include "sysbus.h" +#include "qemu-timer.h" + +/* APIC Local Vector Table */ +#define APIC_LVT_TIMER 0 +#define APIC_LVT_THERMAL 1 +#define APIC_LVT_PERFORM 2 +#define APIC_LVT_LINT0 3 +#define APIC_LVT_LINT1 4 +#define APIC_LVT_ERROR 5 +#define APIC_LVT_NB 6 + +/* APIC delivery modes */ +#define APIC_DM_FIXED 0 +#define APIC_DM_LOWPRI 1 +#define APIC_DM_SMI 2 +#define APIC_DM_NMI 4 +#define APIC_DM_INIT 5 +#define APIC_DM_SIPI 6 +#define APIC_DM_EXTINT 7 + +/* APIC destination mode */ +#define APIC_DESTMODE_FLAT 0xf +#define APIC_DESTMODE_CLUSTER 1 + +#define APIC_TRIGGER_EDGE 0 +#define APIC_TRIGGER_LEVEL 1 + +#define APIC_LVT_TIMER_PERIODIC (1<<17) +#define APIC_LVT_MASKED (1<<16) +#define APIC_LVT_LEVEL_TRIGGER (1<<15) +#define APIC_LVT_REMOTE_IRR (1<<14) +#define APIC_INPUT_POLARITY (1<<13) +#define APIC_SEND_PENDING (1<<12) + +#define ESR_ILLEGAL_ADDRESS (1 << 7) + +#define APIC_SV_DIRECTED_IO (1<<12) +#define APIC_SV_ENABLE (1<<8) + +#define MAX_APICS 255 + +#define MSI_SPACE_SIZE 0x100000 + +typedef struct APICCommonState APICCommonState; + +#define TYPE_APIC_COMMON "apic-common" +#define APIC_COMMON(obj) \ + OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON) +#define APIC_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON) +#define APIC_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON) + +typedef struct APICCommonClass +{ + SysBusDeviceClass parent_class; + + void (*init)(APICCommonState *s); + void (*set_base)(APICCommonState *s, uint64_t val); + void (*set_tpr)(APICCommonState *s, uint8_t val); + void (*external_nmi)(APICCommonState *s); + void (*post_load)(APICCommonState *s); +} APICCommonClass; + +struct APICCommonState { + SysBusDevice busdev; + MemoryRegion io_memory; + void *cpu_env; + uint32_t apicbase; + uint8_t id; + uint8_t arb_id; + uint8_t tpr; + uint32_t spurious_vec; + uint8_t log_dest; + uint8_t dest_mode; + uint32_t isr[8]; /* in service register */ + uint32_t tmr[8]; /* trigger mode register */ + uint32_t irr[8]; /* interrupt request register */ + uint32_t lvt[APIC_LVT_NB]; + uint32_t esr; /* error register */ + uint32_t icr[2]; + + uint32_t divide_conf; + int count_shift; + uint32_t initial_count; + int64_t initial_count_load_time; + int64_t next_time; + int idx; + QEMUTimer *timer; + int64_t timer_expiry; + int sipi_vector; + int wait_for_sipi; +}; + +void apic_report_irq_delivered(int delivered); +bool apic_next_timer(APICCommonState *s, int64_t current_time); + +#endif /* !QEMU_APIC_INTERNAL_H */ diff --git a/hw/applesmc.c b/hw/applesmc.c index c47b592747..b06487f70d 100644 --- a/hw/applesmc.c +++ b/hw/applesmc.c @@ -220,22 +220,32 @@ static int applesmc_isa_init(ISADevice *dev) return 0; } -static ISADeviceInfo applesmc_isa_info = { - .qdev.name = "isa-applesmc", - .qdev.size = sizeof(struct AppleSMCStatus), - .qdev.reset = qdev_applesmc_isa_reset, - .init = applesmc_isa_init, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase, - APPLESMC_DEFAULT_IOBASE), - DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk), - DEFINE_PROP_END_OF_LIST(), - }, +static Property applesmc_isa_properties[] = { + DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase, + APPLESMC_DEFAULT_IOBASE), + DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void qdev_applesmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = applesmc_isa_init; + dc->reset = qdev_applesmc_isa_reset; + dc->props = applesmc_isa_properties; +} + +static TypeInfo applesmc_isa_info = { + .name = "isa-applesmc", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(struct AppleSMCStatus), + .class_init = qdev_applesmc_class_init, }; static void applesmc_register_devices(void) { - isa_qdev_register(&applesmc_isa_info); + type_register_static(&applesmc_isa_info); } device_init(applesmc_register_devices) diff --git a/hw/arm-misc.h b/hw/arm-misc.h index 6e8ae6b02e..5e5204bbf5 100644 --- a/hw/arm-misc.h +++ b/hw/arm-misc.h @@ -30,12 +30,29 @@ struct arm_boot_info { const char *kernel_cmdline; const char *initrd_filename; target_phys_addr_t loader_start; + /* multicore boards that use the default secondary core boot functions + * need to put the address of the secondary boot code, the boot reg, + * and the GIC address in the next 3 values, respectively. boards that + * have their own boot functions can use these values as they want. + */ target_phys_addr_t smp_loader_start; target_phys_addr_t smp_bootreg_addr; target_phys_addr_t smp_priv_base; int nb_cpus; int board_id; int (*atag_board)(const struct arm_boot_info *info, void *p); + /* multicore boards that use the default secondary core boot functions + * can ignore these two function calls. If the default functions won't + * work, then write_secondary_boot() should write a suitable blob of + * code mimicing the secondary CPU startup process used by the board's + * boot loader/boot ROM code, and secondary_cpu_reset_hook() should + * perform any necessary CPU reset handling and set the PC for thei + * secondary CPUs to point at this boot blob. + */ + void (*write_secondary_boot)(CPUState *env, + const struct arm_boot_info *info); + void (*secondary_cpu_reset_hook)(CPUState *env, + const struct arm_boot_info *info); /* Used internally by arm_boot.c */ int is_linux; target_phys_addr_t initrd_size; diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c index bc0457e58b..3c0839c4b4 100644 --- a/hw/arm11mpcore.c +++ b/hw/arm11mpcore.c @@ -10,11 +10,6 @@ #include "sysbus.h" #include "qemu-timer.h" -/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines - (+ 32 internal). However my test chip only exposes/reports 32. - More importantly Linux falls over if more than 32 are present! */ -#define GIC_NIRQ 64 - #define NCPU 4 static inline int @@ -37,6 +32,7 @@ typedef struct mpcore_priv_state { MemoryRegion iomem; MemoryRegion container; DeviceState *mptimer; + uint32_t num_irq; } mpcore_priv_state; /* Per-CPU private memory mapped IO. */ @@ -132,7 +128,7 @@ static int mpcore_priv_init(SysBusDevice *dev) { mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); - gic_init(&s->gic, s->num_cpu); + gic_init(&s->gic, s->num_cpu, s->num_irq); s->mptimer = qdev_create(NULL, "arm_mptimer"); qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu); qdev_init_nofail(s->mptimer); @@ -205,30 +201,61 @@ static int realview_mpcore_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo mpcore_rirq_info = { - .init = realview_mpcore_init, - .qdev.name = "realview_mpcore", - .qdev.size = sizeof(mpcore_rirq_state), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), - DEFINE_PROP_END_OF_LIST(), - } +static Property mpcore_rirq_properties[] = { + DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), + /* The ARM11 MPCORE TRM says the on-chip controller may have + * anything from 0 to 224 external interrupt IRQ lines (with another + * 32 internal). We default to 32+32, which is the number provided by + * the ARM11 MPCore test chip in the Realview Versatile Express + * coretile. Other boards may differ and should set this property + * appropriately. Some Linux kernels may not boot if the hardware + * has more IRQ lines than the kernel expects. + */ + DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo mpcore_priv_info = { - .init = mpcore_priv_init, - .qdev.name = "arm11mpcore_priv", - .qdev.size = sizeof(mpcore_priv_state), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), - DEFINE_PROP_END_OF_LIST(), - } +static void mpcore_rirq_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = realview_mpcore_init; + dc->props = mpcore_rirq_properties; +} + +static TypeInfo mpcore_rirq_info = { + .name = "realview_mpcore", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mpcore_rirq_state), + .class_init = mpcore_rirq_class_init, +}; + +static Property mpcore_priv_properties[] = { + DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mpcore_priv_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mpcore_priv_init; + dc->props = mpcore_priv_properties; +} + +static TypeInfo mpcore_priv_info = { + .name = "arm11mpcore_priv", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mpcore_priv_state), + .class_init = mpcore_priv_class_init, }; static void arm11mpcore_register_devices(void) { - sysbus_register_withprop(&mpcore_rirq_info); - sysbus_register_withprop(&mpcore_priv_info); + type_register_static(&mpcore_rirq_info); + type_register_static(&mpcore_priv_info); } device_init(arm11mpcore_register_devices) diff --git a/hw/arm_boot.c b/hw/arm_boot.c index bf509a8eb9..5f163fda02 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -20,16 +20,28 @@ /* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */ static uint32_t bootloader[] = { 0xe3a00000, /* mov r0, #0 */ - 0xe3a01000, /* mov r1, #0x?? */ - 0xe3811c00, /* orr r1, r1, #0x??00 */ - 0xe59f2000, /* ldr r2, [pc, #0] */ - 0xe59ff000, /* ldr pc, [pc, #0] */ + 0xe59f1004, /* ldr r1, [pc, #4] */ + 0xe59f2004, /* ldr r2, [pc, #4] */ + 0xe59ff004, /* ldr pc, [pc, #4] */ + 0, /* Board ID */ 0, /* Address of kernel args. Set by integratorcp_init. */ 0 /* Kernel entry point. Set by integratorcp_init. */ }; -/* Entry point for secondary CPUs. Enable interrupt controller and - Issue WFI until start address is written to system controller. */ +/* Handling for secondary CPU boot in a multicore system. + * Unlike the uniprocessor/primary CPU boot, this is platform + * dependent. The default code here is based on the secondary + * CPU boot protocol used on realview/vexpress boards, with + * some parameterisation to increase its flexibility. + * QEMU platform models for which this code is not appropriate + * should override write_secondary_boot and secondary_cpu_reset_hook + * instead. + * + * This code enables the interrupt controllers for the secondary + * CPUs and then puts all the secondary CPUs into a loop waiting + * for an interprocessor interrupt and polling a configurable + * location for the kernel secondary CPU entry point. + */ static uint32_t smpboot[] = { 0xe59f201c, /* ldr r2, privbase */ 0xe59f001c, /* ldr r0, startaddr */ @@ -44,6 +56,26 @@ static uint32_t smpboot[] = { 0 /* bootreg: Boot register address is held here */ }; +static void default_write_secondary(CPUState *env, + const struct arm_boot_info *info) +{ + int n; + smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; + smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), + info->smp_loader_start); +} + +static void default_reset_secondary(CPUState *env, + const struct arm_boot_info *info) +{ + stl_phys_notdirty(info->smp_bootreg_addr, 0); + env->regs[15] = info->smp_loader_start; +} + #define WRITE_WORD(p, value) do { \ stl_phys_notdirty(p, value); \ p += 4; \ @@ -197,8 +229,7 @@ static void do_cpu_reset(void *opaque) info->loader_start); } } else { - stl_phys_notdirty(info->smp_bootreg_addr, 0); - env->regs[15] = info->smp_loader_start; + info->secondary_cpu_reset_hook(env, info); } } } @@ -220,6 +251,13 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) exit(1); } + if (!info->secondary_cpu_reset_hook) { + info->secondary_cpu_reset_hook = default_reset_secondary; + } + if (!info->write_secondary_boot) { + info->write_secondary_boot = default_write_secondary; + } + if (info->nb_cpus == 0) info->nb_cpus = 1; @@ -263,8 +301,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) } else { initrd_size = 0; } - bootloader[1] |= info->board_id & 0xff; - bootloader[2] |= (info->board_id >> 8) & 0xff; + bootloader[4] = info->board_id; bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR; bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) { @@ -273,13 +310,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info) rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader), info->loader_start); if (info->nb_cpus > 1) { - smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr; - smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base; - for (n = 0; n < ARRAY_SIZE(smpboot); n++) { - smpboot[n] = tswap32(smpboot[n]); - } - rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), - info->smp_loader_start); + info->write_secondary_boot(env, info); } info->initrd_size = initrd_size; } diff --git a/hw/arm_gic.c b/hw/arm_gic.c index 0339cf59fb..cf582a5a14 100644 --- a/hw/arm_gic.c +++ b/hw/arm_gic.c @@ -11,6 +11,8 @@ controller, MPCore distributed interrupt controller and ARMv7-M Nested Vectored Interrupt Controller. */ +/* Maximum number of possible interrupts, determined by the GIC architecture */ +#define GIC_MAXIRQ 1020 //#define DEBUG_GIC #ifdef DEBUG_GIC @@ -86,13 +88,13 @@ typedef struct gic_state int enabled; int cpu_enabled[NCPU]; - gic_irq_state irq_state[GIC_NIRQ]; + gic_irq_state irq_state[GIC_MAXIRQ]; #ifndef NVIC - int irq_target[GIC_NIRQ]; + int irq_target[GIC_MAXIRQ]; #endif int priority1[32][NCPU]; - int priority2[GIC_NIRQ - 32]; - int last_active[GIC_NIRQ][NCPU]; + int priority2[GIC_MAXIRQ - 32]; + int last_active[GIC_MAXIRQ][NCPU]; int priority_mask[NCPU]; int running_irq[NCPU]; @@ -111,6 +113,7 @@ typedef struct gic_state struct gic_state *backref[NCPU]; MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */ #endif + uint32_t num_irq; } gic_state; /* TODO: Many places that call this routine could be optimized. */ @@ -133,7 +136,7 @@ static void gic_update(gic_state *s) } best_prio = 0x100; best_irq = 1023; - for (irq = 0; irq < GIC_NIRQ; irq++) { + for (irq = 0; irq < s->num_irq; irq++) { if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) { if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { best_prio = GIC_GET_PRIORITY(irq, cpu); @@ -222,7 +225,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq) int update = 0; int cm = 1 << cpu; DPRINTF("EOI %d\n", irq); - if (irq >= GIC_NIRQ) { + if (irq >= s->num_irq) { /* This handles two cases: * 1. If software writes the ID of a spurious interrupt [ie 1023] * to the GICC_EOIR, the GIC ignores that write. @@ -279,7 +282,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) if (offset == 0) return s->enabled; if (offset == 4) - return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5); + return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5); if (offset < 0x08) return 0; if (offset >= 0x80) { @@ -295,7 +298,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) else irq = (offset - 0x180) * 8; irq += GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; for (i = 0; i < 8; i++) { @@ -310,7 +313,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) else irq = (offset - 0x280) * 8; irq += GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; mask = (irq < 32) ? cm : ALL_CPU_MASK; @@ -322,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0x400) { /* Interrupt Active. */ irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; mask = (irq < 32) ? cm : ALL_CPU_MASK; @@ -334,14 +337,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0x800) { /* Interrupt Priority. */ irq = (offset - 0x400) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = GIC_GET_PRIORITY(irq, cpu); #ifndef NVIC } else if (offset < 0xc00) { /* Interrupt CPU Target. */ irq = (offset - 0x800) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq >= 29 && irq <= 31) { res = cm; @@ -351,7 +354,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset) } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; res = 0; for (i = 0; i < 4; i++) { @@ -426,7 +429,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x180) { /* Interrupt Set Enable. */ irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) value = 0xff; @@ -451,7 +454,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x200) { /* Interrupt Clear Enable. */ irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) value = 0; @@ -468,7 +471,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x280) { /* Interrupt Set Pending. */ irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 16) irq = 0; @@ -481,7 +484,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x300) { /* Interrupt Clear Pending. */ irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; for (i = 0; i < 8; i++) { /* ??? This currently clears the pending bit for all CPUs, even @@ -497,7 +500,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0x800) { /* Interrupt Priority. */ irq = (offset - 0x400) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 32) { s->priority1[irq][cpu] = value; @@ -508,7 +511,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0xc00) { /* Interrupt CPU Target. */ irq = (offset - 0x800) + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 29) value = 0; @@ -518,7 +521,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset, } else if (offset < 0xf00) { /* Interrupt Configuration. */ irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; - if (irq >= GIC_NIRQ) + if (irq >= s->num_irq) goto bad_reg; if (irq < 32) value |= 0xaa; @@ -699,7 +702,7 @@ static const MemoryRegionOps gic_cpu_ops = { static void gic_reset(gic_state *s) { int i; - memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); + memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state)); for (i = 0 ; i < NUM_CPU(s); i++) { s->priority_mask[i] = 0xf0; s->current_pending[i] = 1023; @@ -735,17 +738,17 @@ static void gic_save(QEMUFile *f, void *opaque) qemu_put_be32(f, s->cpu_enabled[i]); for (j = 0; j < 32; j++) qemu_put_be32(f, s->priority1[j][i]); - for (j = 0; j < GIC_NIRQ; j++) + for (j = 0; j < s->num_irq; j++) qemu_put_be32(f, s->last_active[j][i]); qemu_put_be32(f, s->priority_mask[i]); qemu_put_be32(f, s->running_irq[i]); qemu_put_be32(f, s->running_priority[i]); qemu_put_be32(f, s->current_pending[i]); } - for (i = 0; i < GIC_NIRQ - 32; i++) { + for (i = 0; i < s->num_irq - 32; i++) { qemu_put_be32(f, s->priority2[i]); } - for (i = 0; i < GIC_NIRQ; i++) { + for (i = 0; i < s->num_irq; i++) { #ifndef NVIC qemu_put_be32(f, s->irq_target[i]); #endif @@ -772,17 +775,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) s->cpu_enabled[i] = qemu_get_be32(f); for (j = 0; j < 32; j++) s->priority1[j][i] = qemu_get_be32(f); - for (j = 0; j < GIC_NIRQ; j++) + for (j = 0; j < s->num_irq; j++) s->last_active[j][i] = qemu_get_be32(f); s->priority_mask[i] = qemu_get_be32(f); s->running_irq[i] = qemu_get_be32(f); s->running_priority[i] = qemu_get_be32(f); s->current_pending[i] = qemu_get_be32(f); } - for (i = 0; i < GIC_NIRQ - 32; i++) { + for (i = 0; i < s->num_irq - 32; i++) { s->priority2[i] = qemu_get_be32(f); } - for (i = 0; i < GIC_NIRQ; i++) { + for (i = 0; i < s->num_irq; i++) { #ifndef NVIC s->irq_target[i] = qemu_get_be32(f); #endif @@ -798,9 +801,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) } #if NCPU > 1 -static void gic_init(gic_state *s, int num_cpu) +static void gic_init(gic_state *s, int num_cpu, int num_irq) #else -static void gic_init(gic_state *s) +static void gic_init(gic_state *s, int num_irq) #endif { int i; @@ -808,7 +811,12 @@ static void gic_init(gic_state *s) #if NCPU > 1 s->num_cpu = num_cpu; #endif - qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32); + s->num_irq = num_irq + GIC_BASE_IRQ; + if (s->num_irq > GIC_MAXIRQ) { + hw_error("requested %u interrupt lines exceeds GIC maximum %d\n", + num_irq, GIC_MAXIRQ); + } + qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32); for (i = 0; i < NUM_CPU(s); i++) { sysbus_init_irq(&s->busdev, &s->parent_irq[i]); } diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c index 2faed39f0f..ba26abc6f4 100644 --- a/hw/arm_l2x0.c +++ b/hw/arm_l2x0.c @@ -160,22 +160,33 @@ static int l2x0_priv_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo l2x0_info = { - .init = l2x0_priv_init, - .qdev.name = "l2x0", - .qdev.size = sizeof(l2x0_state), - .qdev.vmsd = &vmstate_l2x0, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = l2x0_priv_reset, +static Property l2x0_properties[] = { + DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100), + DEFINE_PROP_END_OF_LIST(), +}; + +static void l2x0_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = l2x0_priv_init; + dc->vmsd = &vmstate_l2x0; + dc->no_user = 1; + dc->props = l2x0_properties; + dc->reset = l2x0_priv_reset; +} + +static TypeInfo l2x0_info = { + .name = "l2x0", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(l2x0_state), + .class_init = l2x0_class_init, }; static void l2x0_register_device(void) { - sysbus_register_withprop(&l2x0_info); + type_register_static(&l2x0_info); } device_init(l2x0_register_device) diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c index 455a0aa55a..5a02365b6f 100644 --- a/hw/arm_mptimer.c +++ b/hw/arm_mptimer.c @@ -311,22 +311,33 @@ static const VMStateDescription vmstate_arm_mptimer = { } }; -static SysBusDeviceInfo arm_mptimer_info = { - .init = arm_mptimer_init, - .qdev.name = "arm_mptimer", - .qdev.size = sizeof(arm_mptimer_state), - .qdev.vmsd = &vmstate_arm_mptimer, - .qdev.reset = arm_mptimer_reset, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0), - DEFINE_PROP_END_OF_LIST() - } +static Property arm_mptimer_properties[] = { + DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void arm_mptimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = arm_mptimer_init; + dc->vmsd = &vmstate_arm_mptimer; + dc->reset = arm_mptimer_reset; + dc->no_user = 1; + dc->props = arm_mptimer_properties; +} + +static TypeInfo arm_mptimer_info = { + .name = "arm_mptimer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(arm_mptimer_state), + .class_init = arm_mptimer_class_init, }; static void arm_mptimer_register_devices(void) { - sysbus_register_withprop(&arm_mptimer_info); + type_register_static(&arm_mptimer_info); } device_init(arm_mptimer_register_devices) diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 4b88648780..9d257994c0 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -401,22 +401,33 @@ void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id) sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); } -static SysBusDeviceInfo arm_sysctl_info = { - .init = arm_sysctl_init1, - .qdev.name = "realview_sysctl", - .qdev.size = sizeof(arm_sysctl_state), - .qdev.vmsd = &vmstate_arm_sysctl, - .qdev.reset = arm_sysctl_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), - DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property arm_sysctl_properties[] = { + DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0), + DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void arm_sysctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = arm_sysctl_init1; + dc->reset = arm_sysctl_reset; + dc->vmsd = &vmstate_arm_sysctl; + dc->props = arm_sysctl_properties; +} + +static TypeInfo arm_sysctl_info = { + .name = "realview_sysctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(arm_sysctl_state), + .class_init = arm_sysctl_class_init, }; static void arm_sysctl_register_devices(void) { - sysbus_register_withprop(&arm_sysctl_info); + type_register_static(&arm_sysctl_info); } device_init(arm_sysctl_register_devices) diff --git a/hw/arm_timer.c b/hw/arm_timer.c index 1902f1a7b9..1019d41b3e 100644 --- a/hw/arm_timer.c +++ b/hw/arm_timer.c @@ -273,11 +273,8 @@ static int sp804_init(SysBusDevice *dev) qi = qemu_allocate_irqs(sp804_set_irq, s, 2); sysbus_init_irq(dev, &s->irq); - /* The timers are configurable between 32kHz and 1MHz - * defaulting to 1MHz but overrideable as individual properties */ s->timer[0] = arm_timer_init(s->freq0); s->timer[1] = arm_timer_init(s->freq1); - s->timer[0]->irq = qi[0]; s->timer[1]->irq = qi[1]; memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000); @@ -286,17 +283,6 @@ static int sp804_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo sp804_info = { - .init = sp804_init, - .qdev.name = "sp804", - .qdev.size = sizeof(sp804_state), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000), - DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000), - DEFINE_PROP_END_OF_LIST(), - } -}; - /* Integrator/CP timer module. */ typedef struct { @@ -361,10 +347,46 @@ static int icp_pit_init(SysBusDevice *dev) return 0; } +static void icp_pit_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = icp_pit_init; +} + +static TypeInfo icp_pit_info = { + .name = "integrator_pit", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(icp_pit_state), + .class_init = icp_pit_class_init, +}; + +static Property sp804_properties[] = { + DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000), + DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sp804_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + + sdc->init = sp804_init; + k->props = sp804_properties; +} + +static TypeInfo sp804_info = { + .name = "sp804", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(sp804_state), + .class_init = sp804_class_init, +}; + static void arm_timer_register_devices(void) { - sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init); - sysbus_register_withprop(&sp804_info); + type_register_static(&icp_pit_info); + type_register_static(&sp804_info); } device_init(arm_timer_register_devices) diff --git a/hw/armv7m.c b/hw/armv7m.c index 5c7a9502c6..de3d7e0828 100644 --- a/hw/armv7m.c +++ b/hw/armv7m.c @@ -245,19 +245,30 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, return pic; } -static SysBusDeviceInfo bitband_info = { - .init = bitband_init, - .qdev.name = "ARM,bitband-memory", - .qdev.size = sizeof(BitBandState), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("base", BitBandState, base, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property bitband_properties[] = { + DEFINE_PROP_UINT32("base", BitBandState, base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void bitband_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = bitband_init; + dc->props = bitband_properties; +} + +static TypeInfo bitband_info = { + .name = "ARM,bitband-memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BitBandState), + .class_init = bitband_class_init, }; static void armv7m_register_devices(void) { - sysbus_register_withprop(&bitband_info); + type_register_static(&bitband_info); } device_init(armv7m_register_devices) diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c index bf8c3c50dc..1ed0abc3e7 100644 --- a/hw/armv7m_nvic.c +++ b/hw/armv7m_nvic.c @@ -15,9 +15,6 @@ #include "arm-misc.h" #include "exec-memory.h" -/* 32 internal lines (16 used for system exceptions) plus 64 external - interrupt lines. */ -#define GIC_NIRQ 96 #define NCPU 1 #define NVIC 1 @@ -41,6 +38,7 @@ typedef struct { int64_t tick; QEMUTimer *timer; } systick; + uint32_t num_irq; } nvic_state; /* qemu timers run at 1GHz. We want something closer to 1MHz. */ @@ -125,7 +123,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) switch (offset) { case 4: /* Interrupt Control Type. */ - return (GIC_NIRQ / 32) - 1; + return (s->num_irq / 32) - 1; case 0x10: /* SysTick Control and Status. */ val = s->systick.control; s->systick.control &= ~SYSTICK_COUNTFLAG; @@ -169,7 +167,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) if (s->gic.current_pending[0] != 1023) val |= (s->gic.current_pending[0] << 12); /* ISRPENDING */ - for (irq = 32; irq < GIC_NIRQ; irq++) { + for (irq = 32; irq < s->num_irq; irq++) { if (s->gic.irq_state[irq].pending) { val |= (1 << 22); break; @@ -384,16 +382,44 @@ static int armv7m_nvic_init(SysBusDevice *dev) { nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); - gic_init(&s->gic); + /* note that for the M profile gic_init() takes the number of external + * interrupt lines only. + */ + gic_init(&s->gic, s->num_irq); memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem); s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); - vmstate_register(&dev->qdev, -1, &vmstate_nvic, s); return 0; } +static Property armv7m_nvic_properties[] = { + /* The ARM v7m may have anything from 0 to 496 external interrupt + * IRQ lines. We default to 64. Other boards may differ and should + * set this property appropriately. + */ + DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64), + DEFINE_PROP_END_OF_LIST(), +}; + +static void armv7m_nvic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = armv7m_nvic_init; + dc->vmsd = &vmstate_nvic; + dc->props = armv7m_nvic_properties; +} + +static TypeInfo armv7m_nvic_info = { + .name = "armv7m_nvic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(nvic_state), + .class_init = armv7m_nvic_class_init, +}; + static void armv7m_nvic_register_devices(void) { - sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init); + type_register_static(&armv7m_nvic_info); } device_init(armv7m_nvic_register_devices) diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c index 93fb2ed2c8..c9c11823af 100644 --- a/hw/bitbang_i2c.c +++ b/hw/bitbang_i2c.c @@ -221,16 +221,25 @@ static int gpio_i2c_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo gpio_i2c_info = { - .init = gpio_i2c_init, - .qdev.name = "gpio_i2c", - .qdev.desc = "Virtual GPIO to I2C bridge", - .qdev.size = sizeof(GPIOI2CState), +static void gpio_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = gpio_i2c_init; + dc->desc = "Virtual GPIO to I2C bridge"; +} + +static TypeInfo gpio_i2c_info = { + .name = "gpio_i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GPIOI2CState), + .class_init = gpio_i2c_class_init, }; static void bitbang_i2c_register(void) { - sysbus_register_withprop(&gpio_i2c_info); + type_register_static(&gpio_i2c_info); } device_init(bitbang_i2c_register) diff --git a/hw/boards.h b/hw/boards.h index 716fd7b1a6..f6d3784cf1 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -22,7 +22,6 @@ typedef struct QEMUMachine { unsigned int no_serial:1, no_parallel:1, use_virtcon:1, - no_vga:1, no_floppy:1, no_cdrom:1, no_sdcard:1; diff --git a/hw/bonito.c b/hw/bonito.c index f2c78377bb..7350a4f9ec 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -766,30 +766,47 @@ PCIBus *bonito_init(qemu_irq *pic) return b; } -static PCIDeviceInfo bonito_info = { - .qdev.name = "Bonito", - .qdev.desc = "Host bridge", - .qdev.size = sizeof(PCIBonitoState), - .qdev.vmsd = &vmstate_bonito, - .qdev.no_user = 1, - .init = bonito_initfn, - /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/ - .vendor_id = 0xdf53, - .device_id = 0x00d5, - .revision = 0x01, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void bonito_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = bonito_initfn; + k->vendor_id = 0xdf53; + k->device_id = 0x00d5; + k->revision = 0x01; + k->class_id = PCI_CLASS_BRIDGE_HOST; + dc->desc = "Host bridge"; + dc->no_user = 1; + dc->vmsd = &vmstate_bonito; +} + +static TypeInfo bonito_info = { + .name = "Bonito", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIBonitoState), + .class_init = bonito_class_init, }; -static SysBusDeviceInfo bonito_pcihost_info = { - .init = bonito_pcihost_initfn, - .qdev.name = "Bonito-pcihost", - .qdev.size = sizeof(BonitoState), - .qdev.no_user = 1, +static void bonito_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = bonito_pcihost_initfn; + dc->no_user = 1; +} + +static TypeInfo bonito_pcihost_info = { + .name = "Bonito-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(BonitoState), + .class_init = bonito_pcihost_class_init, }; static void bonito_register(void) { - sysbus_register_withprop(&bonito_pcihost_info); - pci_qdev_register(&bonito_info); + type_register_static(&bonito_pcihost_info); + type_register_static(&bonito_info); } device_init(bonito_register); diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c index 2d2ebce852..9510ed4d94 100644 --- a/hw/ccid-card-emulated.c +++ b/hw/ccid-card-emulated.c @@ -564,29 +564,39 @@ static int emulated_exitfn(CCIDCardState *base) return 0; } -static CCIDCardInfo emulated_card_info = { - .qdev.name = EMULATED_DEV_NAME, - .qdev.desc = "emulated smartcard", - .qdev.size = sizeof(EmulatedState), - .initfn = emulated_initfn, - .exitfn = emulated_exitfn, - .get_atr = emulated_get_atr, - .apdu_from_guest = emulated_apdu_from_guest, - .qdev.unplug = qdev_simple_unplug_cb, - .qdev.props = (Property[]) { - DEFINE_PROP_STRING("backend", EmulatedState, backend_str), - DEFINE_PROP_STRING("cert1", EmulatedState, cert1), - DEFINE_PROP_STRING("cert2", EmulatedState, cert2), - DEFINE_PROP_STRING("cert3", EmulatedState, cert3), - DEFINE_PROP_STRING("db", EmulatedState, db), - DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0), - DEFINE_PROP_END_OF_LIST(), - }, +static Property emulated_card_properties[] = { + DEFINE_PROP_STRING("backend", EmulatedState, backend_str), + DEFINE_PROP_STRING("cert1", EmulatedState, cert1), + DEFINE_PROP_STRING("cert2", EmulatedState, cert2), + DEFINE_PROP_STRING("cert3", EmulatedState, cert3), + DEFINE_PROP_STRING("db", EmulatedState, db), + DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void emulated_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + CCIDCardClass *cc = CCID_CARD_CLASS(klass); + + cc->initfn = emulated_initfn; + cc->exitfn = emulated_exitfn; + cc->get_atr = emulated_get_atr; + cc->apdu_from_guest = emulated_apdu_from_guest; + dc->desc = "emulated smartcard"; + dc->props = emulated_card_properties; +} + +static TypeInfo emulated_card_info = { + .name = EMULATED_DEV_NAME, + .parent = TYPE_CCID_CARD, + .instance_size = sizeof(EmulatedState), + .class_init = emulated_class_initfn, }; static void ccid_card_emulated_register_devices(void) { - ccid_card_qdev_register(&emulated_card_info); + type_register_static(&emulated_card_info); } device_init(ccid_card_emulated_register_devices) diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c index 9f51c6cb05..a7006ca035 100644 --- a/hw/ccid-card-passthru.c +++ b/hw/ccid-card-passthru.c @@ -316,25 +316,36 @@ static VMStateDescription passthru_vmstate = { } }; -static CCIDCardInfo passthru_card_info = { - .qdev.name = PASSTHRU_DEV_NAME, - .qdev.desc = "passthrough smartcard", - .qdev.size = sizeof(PassthruState), - .qdev.vmsd = &passthru_vmstate, - .initfn = passthru_initfn, - .exitfn = passthru_exitfn, - .get_atr = passthru_get_atr, - .apdu_from_guest = passthru_apdu_from_guest, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", PassthruState, cs), - DEFINE_PROP_UINT8("debug", PassthruState, debug, 0), - DEFINE_PROP_END_OF_LIST(), - }, +static Property passthru_card_properties[] = { + DEFINE_PROP_CHR("chardev", PassthruState, cs), + DEFINE_PROP_UINT8("debug", PassthruState, debug, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void passthru_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + CCIDCardClass *cc = CCID_CARD_CLASS(klass); + + cc->initfn = passthru_initfn; + cc->exitfn = passthru_exitfn; + cc->get_atr = passthru_get_atr; + cc->apdu_from_guest = passthru_apdu_from_guest; + dc->desc = "passthrough smartcard"; + dc->vmsd = &passthru_vmstate; + dc->props = passthru_card_properties; +} + +static TypeInfo passthru_card_info = { + .name = PASSTHRU_DEV_NAME, + .parent = TYPE_CCID_CARD, + .instance_size = sizeof(PassthruState), + .class_init = passthru_class_initfn, }; static void ccid_card_passthru_register_devices(void) { - ccid_card_qdev_register(&passthru_card_info); + type_register_static(&passthru_card_info); } device_init(ccid_card_passthru_register_devices) @@ -15,26 +15,34 @@ typedef struct CCIDCardState CCIDCardState; typedef struct CCIDCardInfo CCIDCardInfo; -/* - * state of the CCID Card device (i.e. hw/ccid-card-*.c) - */ -struct CCIDCardState { - DeviceState qdev; - uint32_t slot; /* For future use with multiple slot reader. */ -}; +#define TYPE_CCID_CARD "ccid-card" +#define CCID_CARD(obj) \ + OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD) +#define CCID_CARD_CLASS(klass) \ + OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD) +#define CCID_CARD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD) /* * callbacks to be used by the CCID device (hw/usb-ccid.c) to call * into the smartcard device (hw/ccid-card-*.c) */ -struct CCIDCardInfo { - DeviceInfo qdev; +typedef struct CCIDCardClass { + DeviceClass parent_class; const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len); void (*apdu_from_guest)(CCIDCardState *card, const uint8_t *apdu, uint32_t len); int (*exitfn)(CCIDCardState *card); int (*initfn)(CCIDCardState *card); +} CCIDCardClass; + +/* + * state of the CCID Card device (i.e. hw/ccid-card-*.c) + */ +struct CCIDCardState { + DeviceState qdev; + uint32_t slot; /* For future use with multiple slot reader. */ }; /* @@ -46,7 +54,6 @@ void ccid_card_send_apdu_to_guest(CCIDCardState *card, void ccid_card_card_removed(CCIDCardState *card); void ccid_card_card_inserted(CCIDCardState *card); void ccid_card_card_error(CCIDCardState *card, uint64_t error); -void ccid_card_qdev_register(CCIDCardInfo *card); /* * support guest visible insertion/removal of ccid devices based on actual diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index f7b1d3d785..a8e8ab7660 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -250,6 +250,11 @@ typedef struct PCICirrusVGAState { CirrusVGAState cirrus_vga; } PCICirrusVGAState; +typedef struct ISACirrusVGAState { + ISADevice dev; + CirrusVGAState cirrus_vga; +} ISACirrusVGAState; + static uint8_t rop_to_index[256]; /*************************************** @@ -613,11 +618,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, for (y = 0; y < lines; y++) { off_cur = off_begin; off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask; - off_cur &= TARGET_PAGE_MASK; - while (off_cur < off_cur_end) { - memory_region_set_dirty(&s->vga.vram, off_cur); - off_cur += TARGET_PAGE_SIZE; - } + memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur); off_begin += off_pitch; } } @@ -1895,8 +1896,6 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, * * write mode 4/5 * - * assume TARGET_PAGE_SIZE >= 16 - * ***************************************/ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, @@ -1918,8 +1917,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, val <<= 1; dst++; } - memory_region_set_dirty(&s->vga.vram, offset); - memory_region_set_dirty(&s->vga.vram, offset + 7); + memory_region_set_dirty(&s->vga.vram, offset, 8); } static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, @@ -1943,8 +1941,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, val <<= 1; dst += 2; } - memory_region_set_dirty(&s->vga.vram, offset); - memory_region_set_dirty(&s->vga.vram, offset + 15); + memory_region_set_dirty(&s->vga.vram, offset, 16); } /*************************************** @@ -2034,7 +2031,8 @@ static void cirrus_vga_mem_write(void *opaque, mode = s->vga.gr[0x05] & 0x7; if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { *(s->vga.vram_ptr + bank_offset) = mem_value; - memory_region_set_dirty(&s->vga.vram, bank_offset); + memory_region_set_dirty(&s->vga.vram, bank_offset, + sizeof(mem_value)); } else { if ((s->vga.gr[0x0B] & 0x14) != 0x14) { cirrus_mem_writeb_mode4and5_8bpp(s, mode, @@ -2166,6 +2164,15 @@ static void cirrus_cursor_invalidate(VGACommonState *s1) } } +#define DEPTH 8 +#include "cirrus_vga_template.h" + +#define DEPTH 16 +#include "cirrus_vga_template.h" + +#define DEPTH 32 +#include "cirrus_vga_template.h" + static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y) { CirrusVGAState *s = container_of(s1, CirrusVGAState, vga); @@ -2306,7 +2313,7 @@ static void cirrus_linear_write(void *opaque, target_phys_addr_t addr, mode = s->vga.gr[0x05] & 0x7; if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) { *(s->vga.vram_ptr + addr) = (uint8_t) val; - memory_region_set_dirty(&s->vga.vram, addr); + memory_region_set_dirty(&s->vga.vram, addr, 1); } else { if ((s->vga.gr[0x0B] & 0x14) != 0x14) { cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val); @@ -2883,24 +2890,45 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, * ***************************************/ -DeviceState *isa_cirrus_vga_init(MemoryRegion *system_memory) +static int vga_initfn(ISADevice *dev) { - CirrusVGAState *s; - - s = g_malloc0(sizeof(CirrusVGAState)); - - vga_common_init(&s->vga, VGA_RAM_SIZE); - cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - &s->vga); - vmstate_register(NULL, 0, &vmstate_cirrus_vga, s); + ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev); + VGACommonState *s = &d->cirrus_vga.vga; + + vga_common_init(s, VGA_RAM_SIZE); + cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, + isa_address_space(dev)); + s->ds = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, + s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ - return NULL; + return 0; +} + +static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_cirrus_vga; + k->init = vga_initfn; } +static TypeInfo isa_cirrus_vga_info = { + .name = "isa-cirrus-vga", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISACirrusVGAState), + .class_init = isa_cirrus_vga_class_init, +}; + +static void isa_cirrus_vga_register(void) +{ + type_register_static(&isa_cirrus_vga_info); +} +device_init(isa_cirrus_vga_register) + /*************************************** * * PCI bus support @@ -2911,8 +2939,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) { PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev); CirrusVGAState *s = &d->cirrus_vga; - PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info); - int16_t device_id = info->device_id; + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); + int16_t device_id = pc->device_id; /* setup VGA */ vga_common_init(&s->vga, VGA_RAM_SIZE); @@ -2946,21 +2974,30 @@ DeviceState *pci_cirrus_vga_init(PCIBus *bus) return &pci_create_simple(bus, -1, "cirrus-vga")->qdev; } -static PCIDeviceInfo cirrus_vga_info = { - .qdev.name = "cirrus-vga", - .qdev.desc = "Cirrus CLGD 54xx VGA", - .qdev.size = sizeof(PCICirrusVGAState), - .qdev.vmsd = &vmstate_pci_cirrus_vga, - .no_hotplug = 1, - .init = pci_cirrus_vga_initfn, - .romfile = VGABIOS_CIRRUS_FILENAME, - .vendor_id = PCI_VENDOR_ID_CIRRUS, - .device_id = CIRRUS_ID_CLGD5446, - .class_id = PCI_CLASS_DISPLAY_VGA, +static void cirrus_vga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = pci_cirrus_vga_initfn; + k->romfile = VGABIOS_CIRRUS_FILENAME; + k->vendor_id = PCI_VENDOR_ID_CIRRUS; + k->device_id = CIRRUS_ID_CLGD5446; + k->class_id = PCI_CLASS_DISPLAY_VGA; + dc->desc = "Cirrus CLGD 54xx VGA"; + dc->vmsd = &vmstate_pci_cirrus_vga; +} + +static TypeInfo cirrus_vga_info = { + .name = "cirrus-vga", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCICirrusVGAState), + .class_init = cirrus_vga_class_init, }; static void cirrus_vga_register(void) { - pci_qdev_register(&cirrus_vga_info); + type_register_static(&cirrus_vga_info); } device_init(cirrus_vga_register); diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h new file mode 100644 index 0000000000..3b28280588 --- /dev/null +++ b/hw/cirrus_vga_template.h @@ -0,0 +1,102 @@ +/* + * QEMU Cirrus VGA Emulator templates + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#if DEPTH == 8 +#define BPP 1 +#elif DEPTH == 15 || DEPTH == 16 +#define BPP 2 +#elif DEPTH == 32 +#define BPP 4 +#else +#error unsupported depth +#endif + +static void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, + const uint8_t *src1, + int poffset, int w, + unsigned int color0, + unsigned int color1, + unsigned int color_xor) +{ + const uint8_t *plane0, *plane1; + int x, b0, b1; + uint8_t *d; + + d = d1; + plane0 = src1; + plane1 = src1 + poffset; + for (x = 0; x < w; x++) { + b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; + b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; +#if DEPTH == 8 + switch (b0 | (b1 << 1)) { + case 0: + break; + case 1: + d[0] ^= color_xor; + break; + case 2: + d[0] = color0; + break; + case 3: + d[0] = color1; + break; + } +#elif DEPTH == 16 + switch (b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint16_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint16_t *)d)[0] = color0; + break; + case 3: + ((uint16_t *)d)[0] = color1; + break; + } +#elif DEPTH == 32 + switch (b0 | (b1 << 1)) { + case 0: + break; + case 1: + ((uint32_t *)d)[0] ^= color_xor; + break; + case 2: + ((uint32_t *)d)[0] = color0; + break; + case 3: + ((uint32_t *)d)[0] = color1; + break; + } +#else +#error unsupported depth +#endif + d += BPP; + } +} + +#undef DEPTH +#undef BPP diff --git a/hw/container.c b/hw/container.c deleted file mode 100644 index 9cbf3992c4..0000000000 --- a/hw/container.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "sysbus.h" - -static int container_initfn(SysBusDevice *dev) -{ - return 0; -} - -static SysBusDeviceInfo container_info = { - .init = container_initfn, - .qdev.name = "container", - .qdev.size = sizeof(SysBusDevice), - .qdev.no_user = 1, -}; - -static void container_init(void) -{ - sysbus_register_withprop(&container_info); -} - -device_init(container_init); diff --git a/hw/cs4231.c b/hw/cs4231.c index 2dfb708fe7..c0badbff5c 100644 --- a/hw/cs4231.c +++ b/hw/cs4231.c @@ -151,20 +151,31 @@ static int cs4231_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo cs4231_info = { - .init = cs4231_init1, - .qdev.name = "SUNW,CS4231", - .qdev.size = sizeof(CSState), - .qdev.vmsd = &vmstate_cs4231, - .qdev.reset = cs_reset, - .qdev.props = (Property[]) { - {.name = NULL} - } +static Property cs4231_properties[] = { + {.name = NULL}, +}; + +static void cs4231_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = cs4231_init1; + dc->reset = cs_reset; + dc->vmsd = &vmstate_cs4231; + dc->props = cs4231_properties; +} + +static TypeInfo cs4231_info = { + .name = "SUNW,CS4231", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(CSState), + .class_init = cs4231_class_init, }; static void cs4231_register_devices(void) { - sysbus_register_withprop(&cs4231_info); + type_register_static(&cs4231_info); } device_init(cs4231_register_devices) diff --git a/hw/cs4231a.c b/hw/cs4231a.c index dc77a3aa15..ad04ad667c 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -622,13 +622,13 @@ static const VMStateDescription vmstate_cs4231a = { .pre_load = cs4231a_pre_load, .post_load = cs4231a_post_load, .fields = (VMStateField []) { - VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS), - VMSTATE_BUFFER(dregs, CSState), - VMSTATE_INT32(dma_running, CSState), - VMSTATE_INT32(audio_free, CSState), - VMSTATE_INT32(transferred, CSState), - VMSTATE_INT32(aci_counter, CSState), - VMSTATE_END_OF_LIST() + VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS), + VMSTATE_BUFFER (dregs, CSState), + VMSTATE_INT32 (dma_running, CSState), + VMSTATE_INT32 (audio_free, CSState), + VMSTATE_INT32 (transferred, CSState), + VMSTATE_INT32 (aci_counter, CSState), + VMSTATE_END_OF_LIST () } }; @@ -665,22 +665,32 @@ int cs4231a_init (ISABus *bus) return 0; } -static ISADeviceInfo cs4231a_info = { - .qdev.name = "cs4231a", - .qdev.desc = "Crystal Semiconductor CS4231A", - .qdev.size = sizeof (CSState), - .qdev.vmsd = &vmstate_cs4231a, - .init = cs4231a_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534), - DEFINE_PROP_UINT32 ("irq", CSState, irq, 9), - DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), - DEFINE_PROP_END_OF_LIST (), - }, +static Property cs4231a_properties[] = { + DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534), + DEFINE_PROP_UINT32 ("irq", CSState, irq, 9), + DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), + DEFINE_PROP_END_OF_LIST (), +}; + +static void cs4231a_class_initfn (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS (klass); + ic->init = cs4231a_initfn; + dc->desc = "Crystal Semiconductor CS4231A"; + dc->vmsd = &vmstate_cs4231a; + dc->props = cs4231a_properties; +} + +static TypeInfo cs4231a_info = { + .name = "cs4231a", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof (CSState), + .class_init = cs4231a_class_initfn, }; static void cs4231a_register (void) { - isa_qdev_register (&cs4231a_info); + type_register_static (&cs4231a_info); } device_init (cs4231a_register) diff --git a/hw/debugcon.c b/hw/debugcon.c index c9ee6d90b0..3903b2605d 100644 --- a/hw/debugcon.c +++ b/hw/debugcon.c @@ -87,21 +87,31 @@ static int debugcon_isa_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo debugcon_isa_info = { - .qdev.name = "isa-debugcon", - .qdev.size = sizeof(ISADebugconState), - .init = debugcon_isa_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9), - DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr), - DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9), - DEFINE_PROP_END_OF_LIST(), - }, +static Property debugcon_isa_properties[] = { + DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9), + DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr), + DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9), + DEFINE_PROP_END_OF_LIST(), +}; + +static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = debugcon_isa_initfn; + dc->props = debugcon_isa_properties; +} + +static TypeInfo debugcon_isa_info = { + .name = "isa-debugcon", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISADebugconState), + .class_init = debugcon_isa_class_initfn, }; static void debugcon_register_devices(void) { - isa_qdev_register(&debugcon_isa_info); + type_register_static(&debugcon_isa_info); } device_init(debugcon_register_devices) diff --git a/hw/dec_pci.c b/hw/dec_pci.c index 08d4e06697..a40fbcf3e5 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -50,18 +50,27 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num) return irq_num; } -static PCIDeviceInfo dec_21154_pci_bridge_info = { - .qdev.name = "dec-21154-p2p-bridge", - .qdev.desc = "DEC 21154 PCI-PCI bridge", - .qdev.size = sizeof(PCIBridge), - .qdev.vmsd = &vmstate_pci_device, - .qdev.reset = pci_bridge_reset, - .init = pci_bridge_initfn, - .exit = pci_bridge_exitfn, - .vendor_id = PCI_VENDOR_ID_DEC, - .device_id = PCI_DEVICE_ID_DEC_21154, - .config_write = pci_bridge_write_config, - .is_bridge = 1, +static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_bridge_initfn; + k->exit = pci_bridge_exitfn; + k->vendor_id = PCI_VENDOR_ID_DEC; + k->device_id = PCI_DEVICE_ID_DEC_21154; + k->config_write = pci_bridge_write_config; + k->is_bridge = 1; + dc->desc = "DEC 21154 PCI-PCI bridge"; + dc->reset = pci_bridge_reset; + dc->vmsd = &vmstate_pci_device; +} + +static TypeInfo dec_21154_pci_bridge_info = { + .name = "dec-21154-p2p-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIBridge), + .class_init = dec_21154_pci_bridge_class_init, }; PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) @@ -77,7 +86,7 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn) return pci_bridge_get_sec_bus(br); } -static int pci_dec_21154_init_device(SysBusDevice *dev) +static int pci_dec_21154_device_init(SysBusDevice *dev) { DECState *s; @@ -98,23 +107,44 @@ static int dec_21154_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo dec_21154_pci_host_info = { - .qdev.name = "dec-21154", - .qdev.size = sizeof(PCIDevice), - .init = dec_21154_pci_host_init, - .vendor_id = PCI_VENDOR_ID_DEC, - .device_id = PCI_DEVICE_ID_DEC_21154, - .revision = 0x02, - .class_id = PCI_CLASS_BRIDGE_PCI, - .is_bridge = 1, +static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = dec_21154_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_DEC; + k->device_id = PCI_DEVICE_ID_DEC_21154; + k->revision = 0x02; + k->class_id = PCI_CLASS_BRIDGE_PCI; + k->is_bridge = 1; +} + +static TypeInfo dec_21154_pci_host_info = { + .name = "dec-21154", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = dec_21154_pci_host_class_init, +}; + +static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pci_dec_21154_device_init; +} + +static TypeInfo pci_dec_21154_device_info = { + .name = "dec-21154-sysbus", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DECState), + .class_init = pci_dec_21154_device_class_init, }; static void dec_register_devices(void) { - sysbus_register_dev("dec-21154", sizeof(DECState), - pci_dec_21154_init_device); - pci_qdev_register(&dec_21154_pci_host_info); - pci_qdev_register(&dec_21154_pci_bridge_info); + type_register_static(&pci_dec_21154_device_info); + type_register_static(&dec_21154_pci_host_info); + type_register_static(&dec_21154_pci_bridge_info); } device_init(dec_register_devices) diff --git a/hw/ds1225y.c b/hw/ds1225y.c index 7aa0832266..539bcebae0 100644 --- a/hw/ds1225y.c +++ b/hw/ds1225y.c @@ -134,21 +134,32 @@ static int nvram_sysbus_initfn(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo nvram_sysbus_info = { - .qdev.name = "ds1225y", - .qdev.size = sizeof(SysBusNvRamState), - .qdev.vmsd = &vmstate_nvram, - .init = nvram_sysbus_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000), - DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename), - DEFINE_PROP_END_OF_LIST(), - }, +static Property nvram_sysbus_properties[] = { + DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000), + DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename), + DEFINE_PROP_END_OF_LIST(), +}; + +static void nvram_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = nvram_sysbus_initfn; + dc->vmsd = &vmstate_nvram; + dc->props = nvram_sysbus_properties; +} + +static TypeInfo nvram_sysbus_info = { + .name = "ds1225y", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusNvRamState), + .class_init = nvram_sysbus_class_init, }; static void nvram_register(void) { - sysbus_register_withprop(&nvram_sysbus_info); + type_register_static(&nvram_sysbus_info); } device_init(nvram_register) diff --git a/hw/ds1338.c b/hw/ds1338.c index f754cb7cea..b137e13379 100644 --- a/hw/ds1338.c +++ b/hw/ds1338.c @@ -13,7 +13,7 @@ #include "i2c.h" typedef struct { - i2c_slave i2c; + I2CSlave i2c; time_t offset; struct tm now; uint8_t nvram[56]; @@ -21,7 +21,7 @@ typedef struct { int addr_byte; } DS1338State; -static void ds1338_event(i2c_slave *i2c, enum i2c_event event) +static void ds1338_event(I2CSlave *i2c, enum i2c_event event) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); @@ -51,7 +51,7 @@ static void ds1338_event(i2c_slave *i2c, enum i2c_event event) } } -static int ds1338_recv(i2c_slave *i2c) +static int ds1338_recv(I2CSlave *i2c) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); uint8_t res; @@ -61,7 +61,7 @@ static int ds1338_recv(i2c_slave *i2c) return res; } -static int ds1338_send(i2c_slave *i2c, uint8_t data) +static int ds1338_send(I2CSlave *i2c, uint8_t data) { DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); if (s->addr_byte) { @@ -113,23 +113,31 @@ static int ds1338_send(i2c_slave *i2c, uint8_t data) return 0; } -static int ds1338_init(i2c_slave *i2c) +static int ds1338_init(I2CSlave *i2c) { return 0; } -static I2CSlaveInfo ds1338_info = { - .qdev.name = "ds1338", - .qdev.size = sizeof(DS1338State), - .init = ds1338_init, - .event = ds1338_event, - .recv = ds1338_recv, - .send = ds1338_send, +static void ds1338_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = ds1338_init; + k->event = ds1338_event; + k->recv = ds1338_recv; + k->send = ds1338_send; +} + +static TypeInfo ds1338_info = { + .name = "ds1338", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(DS1338State), + .class_init = ds1338_class_init, }; static void ds1338_register_devices(void) { - i2c_register_slave(&ds1338_info); + type_register_static(&ds1338_info); } device_init(ds1338_register_devices) diff --git a/hw/e1000.c b/hw/e1000.c index a29c944df4..751f79d5ff 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = split_size; if (tp->size + bytes > msh) bytes = msh - tp->size; + + bytes = MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes); if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) memmove(tp->header, tp->data, hdr); @@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentaion Error\n"); } else { + split_size = MIN(sizeof(tp->data) - tp->size, split_size); pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size); tp->size += split_size; } @@ -1130,6 +1133,11 @@ static void e1000_reset(void *opaque) memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init); d->rxbuf_min_shift = 1; memset(&d->tx, 0, sizeof d->tx); + + if (d->nic->nc.link_down) { + d->mac_reg[STATUS] &= ~E1000_STATUS_LU; + d->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS; + } } static NetClientInfo net_e1000_info = { @@ -1174,7 +1182,7 @@ static int pci_e1000_init(PCIDevice *pci_dev) d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; d->nic = qemu_new_nic(&net_e1000_info, &d->conf, - d->dev.qdev.info->name, d->dev.qdev.id, d); + object_get_typename(OBJECT(d)), d->dev.qdev.id, d); qemu_format_nic_info_str(&d->nic->nc, macaddr); @@ -1189,28 +1197,39 @@ static void qdev_e1000_reset(DeviceState *dev) e1000_reset(d); } -static PCIDeviceInfo e1000_info = { - .qdev.name = "e1000", - .qdev.desc = "Intel Gigabit Ethernet", - .qdev.size = sizeof(E1000State), - .qdev.reset = qdev_e1000_reset, - .qdev.vmsd = &vmstate_e1000, - .init = pci_e1000_init, - .exit = pci_e1000_uninit, - .romfile = "pxe-e1000.rom", - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = E1000_DEVID, - .revision = 0x03, - .class_id = PCI_CLASS_NETWORK_ETHERNET, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(E1000State, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property e1000_properties[] = { + DEFINE_NIC_PROPERTIES(E1000State, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void e1000_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_e1000_init; + k->exit = pci_e1000_uninit; + k->romfile = "pxe-e1000.rom"; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = E1000_DEVID; + k->revision = 0x03; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + dc->desc = "Intel Gigabit Ethernet"; + dc->reset = qdev_e1000_reset; + dc->vmsd = &vmstate_e1000; + dc->props = e1000_properties; +} + +static TypeInfo e1000_info = { + .name = "e1000", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(E1000State), + .class_init = e1000_class_init, }; static void e1000_register_devices(void) { - pci_qdev_register(&e1000_info); + type_register_static(&e1000_info); } device_init(e1000_register_devices) diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c index 774346543a..1cf2090c1f 100644 --- a/hw/eccmemctl.c +++ b/hw/eccmemctl.c @@ -308,22 +308,33 @@ static int ecc_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo ecc_info = { - .init = ecc_init1, - .qdev.name = "eccmemctl", - .qdev.size = sizeof(ECCState), - .qdev.vmsd = &vmstate_ecc, - .qdev.reset = ecc_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("version", ECCState, version, -1), - DEFINE_PROP_END_OF_LIST(), - } +static Property ecc_properties[] = { + DEFINE_PROP_HEX32("version", ECCState, version, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ecc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ecc_init1; + dc->reset = ecc_reset; + dc->vmsd = &vmstate_ecc; + dc->props = ecc_properties; +} + +static TypeInfo ecc_info = { + .name = "eccmemctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ECCState), + .class_init = ecc_class_init, }; static void ecc_register_devices(void) { - sysbus_register_withprop(&ecc_info); + type_register_static(&ecc_info); } device_init(ecc_register_devices) diff --git a/hw/eepro100.c b/hw/eepro100.c index 6a162f607f..843610c933 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -128,7 +128,13 @@ #define DRVR_INT 0x0200 /* Driver generated interrupt. */ typedef struct { - PCIDeviceInfo pci; + const char *name; + const char *desc; + uint16_t device_id; + uint8_t revision; + uint16_t subsystem_vendor_id; + uint16_t subsystem_id; + uint32_t device; uint8_t stats_size; bool has_extended_tcb_support; @@ -318,6 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = { #define POLYNOMIAL 0x04c11db6 +static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); + /* From FreeBSD */ /* XXX: optimize */ static unsigned compute_mcast_idx(const uint8_t * ep) @@ -487,8 +495,9 @@ static void eepro100_fcp_interrupt(EEPRO100State * s) } #endif -static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) +static void e100_pci_reset(EEPRO100State * s) { + E100PCIDeviceInfo *info = eepro100_get_class(s); uint32_t device = s->device; uint8_t *pci_conf = s->dev.config; @@ -508,8 +517,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) /* Maximum Latency */ pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18); - s->stats_size = e100_device->stats_size; - s->has_extended_tcb_support = e100_device->has_extended_tcb_support; + s->stats_size = info->stats_size; + s->has_extended_tcb_support = info->has_extended_tcb_support; switch (device) { case i82550: @@ -558,7 +567,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device) } assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics)); - if (e100_device->power_management) { + if (info->power_management) { /* Power Management Capabilities */ int cfg_offset = 0xdc; int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM, @@ -1847,14 +1856,13 @@ static NetClientInfo net_eepro100_info = { static int e100_nic_init(PCIDevice *pci_dev) { EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev); - E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev, - pci_dev->qdev.info); + E100PCIDeviceInfo *info = eepro100_get_class(s); TRACE(OTHER, logout("\n")); - s->device = e100_device->device; + s->device = info->device; - e100_pci_reset(s, e100_device); + e100_pci_reset(s); /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM, * i82559 and later support 64 or 256 word EEPROM. */ @@ -1878,7 +1886,7 @@ static int e100_nic_init(PCIDevice *pci_dev) nic_reset(s); s->nic = qemu_new_nic(&net_eepro100_info, &s->conf, - pci_dev->qdev.info->name, pci_dev->qdev.id, s); + object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); TRACE(OTHER, logout("%s\n", s->nic->nc.info_str)); @@ -1897,156 +1905,203 @@ static int e100_nic_init(PCIDevice *pci_dev) static E100PCIDeviceInfo e100_devices[] = { { - .pci.qdev.name = "i82550", - .pci.qdev.desc = "Intel i82550 Ethernet", + .name = "i82550", + .desc = "Intel i82550 Ethernet", .device = i82550, /* TODO: check device id. */ - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* Revision ID: 0x0c, 0x0d, 0x0e. */ - .pci.revision = 0x0e, + .revision = 0x0e, /* TODO: check size of statistical counters. */ .stats_size = 80, /* TODO: check extended tcb support. */ .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82551", - .pci.qdev.desc = "Intel i82551 Ethernet", + .name = "i82551", + .desc = "Intel i82551 Ethernet", .device = i82551, - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* Revision ID: 0x0f, 0x10. */ - .pci.revision = 0x0f, + .revision = 0x0f, /* TODO: check size of statistical counters. */ .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82557a", - .pci.qdev.desc = "Intel i82557A Ethernet", + .name = "i82557a", + .desc = "Intel i82557A Ethernet", .device = i82557A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x01, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x01, .power_management = false, },{ - .pci.qdev.name = "i82557b", - .pci.qdev.desc = "Intel i82557B Ethernet", + .name = "i82557b", + .desc = "Intel i82557B Ethernet", .device = i82557B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x02, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x02, .power_management = false, },{ - .pci.qdev.name = "i82557c", - .pci.qdev.desc = "Intel i82557C Ethernet", + .name = "i82557c", + .desc = "Intel i82557C Ethernet", .device = i82557C, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x03, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x03, .power_management = false, },{ - .pci.qdev.name = "i82558a", - .pci.qdev.desc = "Intel i82558A Ethernet", + .name = "i82558a", + .desc = "Intel i82558A Ethernet", .device = i82558A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x04, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x04, .stats_size = 76, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82558b", - .pci.qdev.desc = "Intel i82558B Ethernet", + .name = "i82558b", + .desc = "Intel i82558B Ethernet", .device = i82558B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x05, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x05, .stats_size = 76, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559a", - .pci.qdev.desc = "Intel i82559A Ethernet", + .name = "i82559a", + .desc = "Intel i82559A Ethernet", .device = i82559A, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x06, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x06, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559b", - .pci.qdev.desc = "Intel i82559B Ethernet", + .name = "i82559b", + .desc = "Intel i82559B Ethernet", .device = i82559B, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, - .pci.revision = 0x07, + .device_id = PCI_DEVICE_ID_INTEL_82557, + .revision = 0x07, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559c", - .pci.qdev.desc = "Intel i82559C Ethernet", + .name = "i82559c", + .desc = "Intel i82559C Ethernet", .device = i82559C, - .pci.device_id = PCI_DEVICE_ID_INTEL_82557, + .device_id = PCI_DEVICE_ID_INTEL_82557, #if 0 - .pci.revision = 0x08, + .revision = 0x08, #endif /* TODO: Windows wants revision id 0x0c. */ - .pci.revision = 0x0c, + .revision = 0x0c, #if EEPROM_SIZE > 0 - .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL, - .pci.subsystem_id = 0x0040, + .subsystem_vendor_id = PCI_VENDOR_ID_INTEL, + .subsystem_id = 0x0040, #endif .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82559er", - .pci.qdev.desc = "Intel i82559ER Ethernet", + .name = "i82559er", + .desc = "Intel i82559ER Ethernet", .device = i82559ER, - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, - .pci.revision = 0x09, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, + .revision = 0x09, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ - .pci.qdev.name = "i82562", - .pci.qdev.desc = "Intel i82562 Ethernet", + .name = "i82562", + .desc = "Intel i82562 Ethernet", .device = i82562, /* TODO: check device id. */ - .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT, + .device_id = PCI_DEVICE_ID_INTEL_82551IT, /* TODO: wrong revision id. */ - .pci.revision = 0x0e, + .revision = 0x0e, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, },{ /* Toshiba Tecra 8200. */ - .pci.qdev.name = "i82801", - .pci.qdev.desc = "Intel i82801 Ethernet", + .name = "i82801", + .desc = "Intel i82801 Ethernet", .device = i82801, - .pci.device_id = 0x2449, - .pci.revision = 0x03, + .device_id = 0x2449, + .revision = 0x03, .stats_size = 80, .has_extended_tcb_support = true, .power_management = true, } }; +static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename) +{ + E100PCIDeviceInfo *info = NULL; + int i; + + /* This is admittedly awkward but also temporary. QOM allows for + * parameterized typing and for subclassing both of which would suitable + * handle what's going on here. But class_data is already being used as + * a stop-gap hack to allow incremental qdev conversion so we cannot use it + * right now. Once we merge the final QOM series, we can come back here and + * do this in a much more elegant fashion. + */ + for (i = 0; i < ARRAY_SIZE(e100_devices); i++) { + if (strcmp(e100_devices[i].name, typename) == 0) { + info = &e100_devices[i]; + break; + } + } + assert(info != NULL); + + return info; +} + +static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s) +{ + return eepro100_get_class_by_name(object_get_typename(OBJECT(s))); +} + static Property e100_properties[] = { DEFINE_NIC_PROPERTIES(EEPRO100State, conf), DEFINE_PROP_END_OF_LIST(), }; +static void eepro100_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + E100PCIDeviceInfo *info; + + info = eepro100_get_class_by_name(object_class_get_name(klass)); + + dc->props = e100_properties; + dc->desc = info->desc; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + k->romfile = "pxe-eepro100.rom"; + k->init = e100_nic_init; + k->exit = pci_nic_uninit; + k->device_id = info->device_id; + k->revision = info->revision; + k->subsystem_vendor_id = info->subsystem_vendor_id; + k->subsystem_id = info->subsystem_id; +} + static void eepro100_register_devices(void) { size_t i; for (i = 0; i < ARRAY_SIZE(e100_devices); i++) { - PCIDeviceInfo *pci_dev = &e100_devices[i].pci; - /* We use the same rom file for all device ids. - QEMU fixes the device id during rom load. */ - pci_dev->vendor_id = PCI_VENDOR_ID_INTEL; - pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET; - pci_dev->romfile = "pxe-eepro100.rom"; - pci_dev->init = e100_nic_init; - pci_dev->exit = pci_nic_uninit; - pci_dev->qdev.props = e100_properties; - pci_dev->qdev.size = sizeof(EEPRO100State); - pci_qdev_register(pci_dev); + TypeInfo type_info = {}; + E100PCIDeviceInfo *info = &e100_devices[i]; + + type_info.name = info->name; + type_info.parent = TYPE_PCI_DEVICE; + type_info.class_init = eepro100_class_init; + type_info.instance_size = sizeof(EEPRO100State); + + type_register(&type_info); } } diff --git a/hw/empty_slot.c b/hw/empty_slot.c index 8b734f2c9f..1bc181555f 100644 --- a/hw/empty_slot.c +++ b/hw/empty_slot.c @@ -76,15 +76,23 @@ static int empty_slot_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo empty_slot_info = { - .init = empty_slot_init1, - .qdev.name = "empty_slot", - .qdev.size = sizeof(EmptySlot), +static void empty_slot_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = empty_slot_init1; +} + +static TypeInfo empty_slot_info = { + .name = "empty_slot", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(EmptySlot), + .class_init = empty_slot_class_init, }; static void empty_slot_register_devices(void) { - sysbus_register_withprop(&empty_slot_info); + type_register_static(&empty_slot_info); } device_init(empty_slot_register_devices); diff --git a/hw/es1370.c b/hw/es1370.c index 6a3ba55f6f..e377c48e49 100644 --- a/hw/es1370.c +++ b/hw/es1370.c @@ -914,7 +914,7 @@ static const MemoryRegionPortio es1370_portio[] = { { 0, 0x40 * 4, 1, .read = es1370_readb, }, { 0, 0x40 * 2, 2, .read = es1370_readw, }, { 0, 0x40, 4, .read = es1370_readl, }, - PORTIO_END_OF_LIST() + PORTIO_END_OF_LIST () }; static const MemoryRegionOps es1370_io_ops = { @@ -928,12 +928,12 @@ static const VMStateDescription vmstate_es1370_channel = { .minimum_version_id = 2, .minimum_version_id_old = 2, .fields = (VMStateField []) { - VMSTATE_UINT32(shift, struct chan), - VMSTATE_UINT32(leftover, struct chan), - VMSTATE_UINT32(scount, struct chan), - VMSTATE_UINT32(frame_addr, struct chan), - VMSTATE_UINT32(frame_cnt, struct chan), - VMSTATE_END_OF_LIST() + VMSTATE_UINT32 (shift, struct chan), + VMSTATE_UINT32 (leftover, struct chan), + VMSTATE_UINT32 (scount, struct chan), + VMSTATE_UINT32 (frame_addr, struct chan), + VMSTATE_UINT32 (frame_cnt, struct chan), + VMSTATE_END_OF_LIST () } }; @@ -973,15 +973,15 @@ static const VMStateDescription vmstate_es1370 = { .minimum_version_id_old = 2, .post_load = es1370_post_load, .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, ES1370State), - VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2, - vmstate_es1370_channel, struct chan), - VMSTATE_UINT32(ctl, ES1370State), - VMSTATE_UINT32(status, ES1370State), - VMSTATE_UINT32(mempage, ES1370State), - VMSTATE_UINT32(codec, ES1370State), - VMSTATE_UINT32(sctl, ES1370State), - VMSTATE_END_OF_LIST() + VMSTATE_PCI_DEVICE (dev, ES1370State), + VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2, + vmstate_es1370_channel, struct chan), + VMSTATE_UINT32 (ctl, ES1370State), + VMSTATE_UINT32 (status, ES1370State), + VMSTATE_UINT32 (mempage, ES1370State), + VMSTATE_UINT32 (codec, ES1370State), + VMSTATE_UINT32 (sctl, ES1370State), + VMSTATE_END_OF_LIST () } }; @@ -1017,7 +1017,7 @@ static int es1370_initfn (PCIDevice *dev) return 0; } -static int es1370_exitfn(PCIDevice *dev) +static int es1370_exitfn (PCIDevice *dev) { ES1370State *s = DO_UPCAST (ES1370State, dev, dev); @@ -1031,28 +1031,32 @@ int es1370_init (PCIBus *bus) return 0; } -static PCIDeviceInfo es1370_info = { - .qdev.name = "ES1370", - .qdev.desc = "ENSONIQ AudioPCI ES1370", - .qdev.size = sizeof (ES1370State), - .qdev.vmsd = &vmstate_es1370, - .init = es1370_initfn, - .exit = es1370_exitfn, - .vendor_id = PCI_VENDOR_ID_ENSONIQ, - .device_id = PCI_DEVICE_ID_ENSONIQ_ES1370, - .class_id = PCI_CLASS_MULTIMEDIA_AUDIO, -#if 1 - .subsystem_vendor_id = 0x4942, - .subsystem_id = 0x4c4c, -#else - .subsystem_vendor_id = 0x1274, - .subsystem_id = 0x1371, -#endif +static void es1370_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); + + k->init = es1370_initfn; + k->exit = es1370_exitfn; + k->vendor_id = PCI_VENDOR_ID_ENSONIQ; + k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370; + k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + k->subsystem_vendor_id = 0x4942; + k->subsystem_id = 0x4c4c; + dc->desc = "ENSONIQ AudioPCI ES1370"; + dc->vmsd = &vmstate_es1370; +} + +static TypeInfo es1370_info = { + .name = "ES1370", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof (ES1370State), + .class_init = es1370_class_init, }; static void es1370_register (void) { - pci_qdev_register (&es1370_info); + type_register_static (&es1370_info); } device_init (es1370_register); @@ -901,28 +901,39 @@ static int escc_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo escc_info = { - .init = escc_init1, - .qdev.name = "escc", - .qdev.size = sizeof(SerialState), - .qdev.vmsd = &vmstate_escc, - .qdev.reset = escc_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0), - DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0), - DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), - DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), - DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0), - DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0), - DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr), - DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr), - DEFINE_PROP_END_OF_LIST(), - } +static Property escc_properties[] = { + DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0), + DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0), + DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), + DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0), + DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0), + DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0), + DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr), + DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void escc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = escc_init1; + dc->reset = escc_reset; + dc->vmsd = &vmstate_escc; + dc->props = escc_properties; +} + +static TypeInfo escc_info = { + .name = "escc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SerialState), + .class_init = escc_class_init, }; static void escc_register_devices(void) { - sysbus_register_withprop(&escc_info); + type_register_static(&escc_info); } device_init(escc_register_devices) @@ -753,20 +753,31 @@ static int esp_init1(SysBusDevice *dev) return scsi_bus_legacy_handle_cmdline(&s->bus); } -static SysBusDeviceInfo esp_info = { - .init = esp_init1, - .qdev.name = "esp", - .qdev.size = sizeof(ESPState), - .qdev.vmsd = &vmstate_esp, - .qdev.reset = esp_hard_reset, - .qdev.props = (Property[]) { - {.name = NULL} - } +static Property esp_properties[] = { + {.name = NULL}, +}; + +static void esp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = esp_init1; + dc->reset = esp_hard_reset; + dc->vmsd = &vmstate_esp; + dc->props = esp_properties; +} + +static TypeInfo esp_info = { + .name = "esp", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ESPState), + .class_init = esp_class_init, }; static void esp_register_devices(void) { - sysbus_register_withprop(&esp_info); + type_register_static(&esp_info); } device_init(esp_register_devices) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 5afa55fb29..aefd5778ab 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -605,7 +605,7 @@ static int fs_eth_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(s)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); tdk_init(&s->phy); @@ -613,22 +613,33 @@ static int fs_eth_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo etraxfs_eth_info = { - .init = fs_eth_init, - .qdev.name = "etraxfs-eth", - .qdev.size = sizeof(struct fs_eth), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1), - DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out), - DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in), - DEFINE_NIC_PROPERTIES(struct fs_eth, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property etraxfs_eth_properties[] = { + DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1), + DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out), + DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in), + DEFINE_NIC_PROPERTIES(struct fs_eth, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void etraxfs_eth_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = fs_eth_init; + dc->props = etraxfs_eth_properties; +} + +static TypeInfo etraxfs_eth_info = { + .name = "etraxfs-eth", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct fs_eth), + .class_init = etraxfs_eth_class_init, }; static void etraxfs_eth_register(void) { - sysbus_register_withprop(&etraxfs_eth_info); + type_register_static(&etraxfs_eth_info); } device_init(etraxfs_eth_register) diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c index 993d6a8885..33541fcc61 100644 --- a/hw/etraxfs_pic.c +++ b/hw/etraxfs_pic.c @@ -151,19 +151,30 @@ static int etraxfs_pic_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo etraxfs_pic_info = { - .init = etraxfs_pic_init, - .qdev.name = "etraxfs,pic", - .qdev.size = sizeof(struct etrax_pic), - .qdev.props = (Property[]) { - DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector), - DEFINE_PROP_END_OF_LIST(), - } +static Property etraxfs_pic_properties[] = { + DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector), + DEFINE_PROP_END_OF_LIST(), +}; + +static void etraxfs_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = etraxfs_pic_init; + dc->props = etraxfs_pic_properties; +} + +static TypeInfo etraxfs_pic_info = { + .name = "etraxfs,pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct etrax_pic), + .class_init = etraxfs_pic_class_init, }; static void etraxfs_pic_register(void) { - sysbus_register_withprop(&etraxfs_pic_info); + type_register_static(&etraxfs_pic_info); } device_init(etraxfs_pic_register) diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c index 2623dab9d4..567cb8cc2d 100644 --- a/hw/etraxfs_ser.c +++ b/hw/etraxfs_ser.c @@ -216,7 +216,7 @@ static int etraxfs_ser_init(SysBusDevice *dev) memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); if (s->chr) qemu_chr_add_handlers(s->chr, serial_can_receive, serial_receive, @@ -224,16 +224,25 @@ static int etraxfs_ser_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo etraxfs_ser_info = { - .init = etraxfs_ser_init, - .qdev.name = "etraxfs,serial", - .qdev.size = sizeof(struct etrax_serial), - .qdev.reset = etraxfs_ser_reset, +static void etraxfs_ser_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = etraxfs_ser_init; + dc->reset = etraxfs_ser_reset; +} + +static TypeInfo etraxfs_ser_info = { + .name = "etraxfs,serial", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct etrax_serial), + .class_init = etraxfs_ser_class_init, }; static void etraxfs_serial_register(void) { - sysbus_register_withprop(&etraxfs_ser_info); + type_register_static(&etraxfs_ser_info); } device_init(etraxfs_serial_register) diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c index 2dfdb3063e..b71c5ee9d5 100644 --- a/hw/etraxfs_timer.c +++ b/hw/etraxfs_timer.c @@ -329,10 +329,23 @@ static int etraxfs_timer_init(SysBusDevice *dev) return 0; } +static void etraxfs_timer_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = etraxfs_timer_init; +} + +static TypeInfo etraxfs_timer_info = { + .name = "etraxfs,timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (struct etrax_timer), + .class_init = etraxfs_timer_class_init, +}; + static void etraxfs_timer_register(void) { - sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer), - etraxfs_timer_init); + type_register_static(&etraxfs_timer_info); } device_init(etraxfs_timer_register) @@ -1959,21 +1959,31 @@ static const VMStateDescription vmstate_isa_fdc ={ } }; -static ISADeviceInfo isa_fdc_info = { - .init = isabus_fdc_init1, - .qdev.name = "isa-fdc", - .qdev.fw_name = "fdc", - .qdev.size = sizeof(FDCtrlISABus), - .qdev.no_user = 1, - .qdev.vmsd = &vmstate_isa_fdc, - .qdev.reset = fdctrl_external_reset_isa, - .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs), - DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs), - DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1), - DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1), - DEFINE_PROP_END_OF_LIST(), - }, +static Property isa_fdc_properties[] = { + DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs), + DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs), + DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1), + DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void isabus_fdc_class_init1(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = isabus_fdc_init1; + dc->fw_name = "fdc"; + dc->no_user = 1; + dc->reset = fdctrl_external_reset_isa; + dc->vmsd = &vmstate_isa_fdc; + dc->props = isa_fdc_properties; +} + +static TypeInfo isa_fdc_info = { + .name = "isa-fdc", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(FDCtrlISABus), + .class_init = isabus_fdc_class_init1, }; static const VMStateDescription vmstate_sysbus_fdc ={ @@ -1986,36 +1996,58 @@ static const VMStateDescription vmstate_sysbus_fdc ={ } }; -static SysBusDeviceInfo sysbus_fdc_info = { - .init = sysbus_fdc_init1, - .qdev.name = "sysbus-fdc", - .qdev.size = sizeof(FDCtrlSysBus), - .qdev.vmsd = &vmstate_sysbus_fdc, - .qdev.reset = fdctrl_external_reset_sysbus, - .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs), - DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs), - DEFINE_PROP_END_OF_LIST(), - }, +static Property sysbus_fdc_properties[] = { + DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs), + DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo sun4m_fdc_info = { - .init = sun4m_fdc_init1, - .qdev.name = "SUNW,fdtwo", - .qdev.size = sizeof(FDCtrlSysBus), - .qdev.vmsd = &vmstate_sysbus_fdc, - .qdev.reset = fdctrl_external_reset_sysbus, - .qdev.props = (Property[]) { - DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs), - DEFINE_PROP_END_OF_LIST(), - }, +static void sysbus_fdc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sysbus_fdc_init1; + dc->reset = fdctrl_external_reset_sysbus; + dc->vmsd = &vmstate_sysbus_fdc; + dc->props = sysbus_fdc_properties; +} + +static TypeInfo sysbus_fdc_info = { + .name = "sysbus-fdc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FDCtrlSysBus), + .class_init = sysbus_fdc_class_init, +}; + +static Property sun4m_fdc_properties[] = { + DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sun4m_fdc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sun4m_fdc_init1; + dc->reset = fdctrl_external_reset_sysbus; + dc->vmsd = &vmstate_sysbus_fdc; + dc->props = sun4m_fdc_properties; +} + +static TypeInfo sun4m_fdc_info = { + .name = "SUNW,fdtwo", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FDCtrlSysBus), + .class_init = sun4m_fdc_class_init, }; static void fdc_register_devices(void) { - isa_qdev_register(&isa_fdc_info); - sysbus_register_withprop(&sysbus_fdc_info); - sysbus_register_withprop(&sun4m_fdc_info); + type_register_static(&isa_fdc_info); + type_register_static(&sysbus_fdc_info); + type_register_static(&sun4m_fdc_info); } device_init(fdc_register_devices) diff --git a/hw/framebuffer.c b/hw/framebuffer.c index 6bf48dc046..ea122fb266 100644 --- a/hw/framebuffer.c +++ b/hw/framebuffer.c @@ -87,15 +87,8 @@ void framebuffer_update_display( dest += i * dest_row_pitch; for (; i < rows; i++) { - target_phys_addr_t dirty_offset; - dirty = 0; - dirty_offset = 0; - while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) { - dirty |= memory_region_get_dirty(mem, addr + dirty_offset, + dirty = memory_region_get_dirty(mem, addr, addr + src_width, DIRTY_MEMORY_VGA); - dirty_offset += TARGET_PAGE_SIZE; - } - if (dirty || invalidate) { fn(opaque, dest, src, cols, dest_col_pitch); if (first == -1) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index f9535328f0..6b2f7d1986 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -531,23 +531,34 @@ static int fw_cfg_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo fw_cfg_info = { - .init = fw_cfg_init1, - .qdev.name = "fw_cfg", - .qdev.size = sizeof(FWCfgState), - .qdev.vmsd = &vmstate_fw_cfg, - .qdev.reset = fw_cfg_reset, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1), - DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1), - DEFINE_PROP_END_OF_LIST(), - }, +static Property fw_cfg_properties[] = { + DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1), + DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void fw_cfg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = fw_cfg_init1; + dc->no_user = 1; + dc->reset = fw_cfg_reset; + dc->vmsd = &vmstate_fw_cfg; + dc->props = fw_cfg_properties; +} + +static TypeInfo fw_cfg_info = { + .name = "fw_cfg", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(FWCfgState), + .class_init = fw_cfg_class_init, }; static void fw_cfg_register_devices(void) { - sysbus_register_withprop(&fw_cfg_info); + type_register_static(&fw_cfg_info); } device_init(fw_cfg_register_devices) diff --git a/hw/g364fb.c b/hw/g364fb.c index 33ec149e0f..66d0044c06 100644 --- a/hw/g364fb.c +++ b/hw/g364fb.c @@ -62,7 +62,8 @@ typedef struct G364State { static inline int check_dirty(G364State *s, ram_addr_t page) { - return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA); + return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE, + DIRTY_MEMORY_VGA); } static inline void reset_dirty(G364State *s, @@ -268,12 +269,9 @@ static void g364fb_update_display(void *opaque) static inline void g364fb_invalidate_display(void *opaque) { G364State *s = opaque; - int i; s->blanked = 0; - for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) { - memory_region_set_dirty(&s->mem_vram, i); - } + memory_region_set_dirty(&s->mem_vram, 0, s->vram_size); } static void g364fb_reset(G364State *s) @@ -385,7 +383,7 @@ static void g364fb_update_depth(G364State *s) static void g364_invalidate_cursor_position(G364State *s) { - int ymin, ymax, start, end, i; + int ymin, ymax, start, end; /* invalidate only near the cursor */ ymin = s->cursor_position & 0xfff; @@ -393,9 +391,7 @@ static void g364_invalidate_cursor_position(G364State *s) start = ymin * ds_get_linesize(s->ds); end = (ymax + 1) * ds_get_linesize(s->ds); - for (i = start; i < end; i += G364_PAGE_SIZE) { - memory_region_set_dirty(&s->mem_vram, i); - } + memory_region_set_dirty(&s->mem_vram, start, end - start); } static void g364fb_ctrl_write(void *opaque, @@ -553,23 +549,34 @@ static void g364fb_sysbus_reset(DeviceState *d) g364fb_reset(&s->g364); } -static SysBusDeviceInfo g364fb_sysbus_info = { - .init = g364fb_sysbus_init, - .qdev.name = "sysbus-g364", - .qdev.desc = "G364 framebuffer", - .qdev.size = sizeof(G364SysBusState), - .qdev.vmsd = &vmstate_g364fb, - .qdev.reset = g364fb_sysbus_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size, - 8 * 1024 * 1024), - DEFINE_PROP_END_OF_LIST(), - } +static Property g364fb_sysbus_properties[] = { + DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size, + 8 * 1024 * 1024), + DEFINE_PROP_END_OF_LIST(), +}; + +static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = g364fb_sysbus_init; + dc->desc = "G364 framebuffer"; + dc->reset = g364fb_sysbus_reset; + dc->vmsd = &vmstate_g364fb; + dc->props = g364fb_sysbus_properties; +} + +static TypeInfo g364fb_sysbus_info = { + .name = "sysbus-g364", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(G364SysBusState), + .class_init = g364fb_sysbus_class_init, }; static void g364fb_register(void) { - sysbus_register_withprop(&g364fb_sysbus_info); + type_register_static(&g364fb_sysbus_info); } device_init(g364fb_register); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 1e529fb5d0..8122baf482 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -71,7 +71,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, SysBusDevice *s; GrackleState *d; - dev = qdev_create(NULL, "grackle"); + dev = qdev_create(NULL, "grackle-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); d = FROM_SYSBUS(GrackleState, s); @@ -121,21 +121,46 @@ static int grackle_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo grackle_pci_host_info = { - .qdev.name = "grackle", - .qdev.size = sizeof(PCIDevice), - .init = grackle_pci_host_init, - .vendor_id = PCI_VENDOR_ID_MOTOROLA, - .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106, - .revision = 0x00, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void grackle_pci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = grackle_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_MOTOROLA; + k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; + dc->no_user = 1; +} + +static TypeInfo grackle_pci_info = { + .name = "grackle", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = grackle_pci_class_init, +}; + +static void pci_grackle_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = pci_grackle_init_device; + dc->no_user = 1; +} + +static TypeInfo grackle_pci_host_info = { + .name = "grackle-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GrackleState), + .class_init = pci_grackle_class_init, }; static void grackle_register_devices(void) { - sysbus_register_dev("grackle", sizeof(GrackleState), - pci_grackle_init_device); - pci_qdev_register(&grackle_pci_host_info); + type_register_static(&grackle_pci_info); + type_register_static(&grackle_pci_host_info); } device_init(grackle_register_devices) diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c index f8a64e1644..89de2d85ae 100644 --- a/hw/grlib_apbuart.c +++ b/hw/grlib_apbuart.c @@ -24,7 +24,6 @@ #include "sysbus.h" #include "qemu-char.h" -#include "ptimer.h" #include "trace.h" @@ -66,6 +65,8 @@ #define SCALER_OFFSET 0x0C /* not supported */ #define FIFO_DEBUG_OFFSET 0x10 /* not supported */ +#define FIFO_LENGTH 1024 + typedef struct UART { SysBusDevice busdev; MemoryRegion iomem; @@ -77,21 +78,67 @@ typedef struct UART { uint32_t receive; uint32_t status; uint32_t control; + + /* FIFO */ + char buffer[FIFO_LENGTH]; + int len; + int current; } UART; +static int uart_data_to_read(UART *uart) +{ + return uart->current < uart->len; +} + +static char uart_pop(UART *uart) +{ + char ret; + + if (uart->len == 0) { + uart->status &= ~UART_DATA_READY; + return 0; + } + + ret = uart->buffer[uart->current++]; + + if (uart->current >= uart->len) { + /* Flush */ + uart->len = 0; + uart->current = 0; + } + + if (!uart_data_to_read(uart)) { + uart->status &= ~UART_DATA_READY; + } + + return ret; +} + +static void uart_add_to_fifo(UART *uart, + const uint8_t *buffer, + int length) +{ + if (uart->len + length > FIFO_LENGTH) { + abort(); + } + memcpy(uart->buffer + uart->len, buffer, length); + uart->len += length; +} + static int grlib_apbuart_can_receive(void *opaque) { UART *uart = opaque; - return !!(uart->status & UART_DATA_READY); + return FIFO_LENGTH - uart->len; } static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) { UART *uart = opaque; - uart->receive = *buf; - uart->status |= UART_DATA_READY; + uart_add_to_fifo(uart, buf, size); + + uart->status |= UART_DATA_READY; if (uart->control & UART_RECEIVE_INTERRUPT) { qemu_irq_pulse(uart->irq); @@ -103,9 +150,39 @@ static void grlib_apbuart_event(void *opaque, int event) trace_grlib_apbuart_event(event); } -static void -grlib_apbuart_write(void *opaque, target_phys_addr_t addr, - uint64_t value, unsigned size) + +static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr, + unsigned size) +{ + UART *uart = opaque; + + addr &= 0xff; + + /* Unit registers */ + switch (addr) { + case DATA_OFFSET: + case DATA_OFFSET + 3: /* when only one byte read */ + return uart_pop(uart); + + case STATUS_OFFSET: + /* Read Only */ + return uart->status; + + case CONTROL_OFFSET: + return uart->control; + + case SCALER_OFFSET: + /* Not supported */ + return 0; + + default: + trace_grlib_apbuart_readl_unknown(addr); + return 0; + } +} + +static void grlib_apbuart_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) { UART *uart = opaque; unsigned char c = 0; @@ -115,6 +192,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr, /* Unit registers */ switch (addr) { case DATA_OFFSET: + case DATA_OFFSET + 3: /* When only one byte write */ c = value & 0xFF; qemu_chr_fe_write(uart->chr, &c, 1); return; @@ -124,7 +202,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr, return; case CONTROL_OFFSET: - /* Not supported */ + uart->control = value; return; case SCALER_OFFSET: @@ -138,21 +216,15 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr, trace_grlib_apbuart_writel_unknown(addr, value); } -static bool grlib_apbuart_accepts(void *opaque, target_phys_addr_t addr, - unsigned size, bool is_write) -{ - return is_write && size == 4; -} - static const MemoryRegionOps grlib_apbuart_ops = { - .write = grlib_apbuart_write, - .valid.accepts = grlib_apbuart_accepts, + .write = grlib_apbuart_write, + .read = grlib_apbuart_read, .endianness = DEVICE_NATIVE_ENDIAN, }; static int grlib_apbuart_init(SysBusDevice *dev) { - UART *uart = FROM_SYSBUS(typeof(*uart), dev); + UART *uart = FROM_SYSBUS(typeof(*uart), dev); qemu_chr_add_handlers(uart->chr, grlib_apbuart_can_receive, @@ -170,19 +242,30 @@ static int grlib_apbuart_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo grlib_gptimer_info = { - .init = grlib_apbuart_init, - .qdev.name = "grlib,apbuart", - .qdev.size = sizeof(UART), - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chrdev", UART, chr), - DEFINE_PROP_END_OF_LIST() - } +static Property grlib_gptimer_properties[] = { + DEFINE_PROP_CHR("chrdev", UART, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void grlib_gptimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = grlib_apbuart_init; + dc->props = grlib_gptimer_properties; +} + +static TypeInfo grlib_gptimer_info = { + .name = "grlib,apbuart", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UART), + .class_init = grlib_gptimer_class_init, }; static void grlib_gptimer_register(void) { - sysbus_register_withprop(&grlib_gptimer_info); + type_register_static(&grlib_gptimer_info); } device_init(grlib_gptimer_register) diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c index 9c98a830d7..fb0b236746 100644 --- a/hw/grlib_gptimer.c +++ b/hw/grlib_gptimer.c @@ -372,22 +372,33 @@ static int grlib_gptimer_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo grlib_gptimer_info = { - .init = grlib_gptimer_init, - .qdev.name = "grlib,gptimer", - .qdev.reset = grlib_gptimer_reset, - .qdev.size = sizeof(GPTimerUnit), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000), - DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8), - DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2), - DEFINE_PROP_END_OF_LIST() - } +static Property grlib_gptimer_properties[] = { + DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000), + DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8), + DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2), + DEFINE_PROP_END_OF_LIST(), +}; + +static void grlib_gptimer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = grlib_gptimer_init; + dc->reset = grlib_gptimer_reset; + dc->props = grlib_gptimer_properties; +} + +static TypeInfo grlib_gptimer_info = { + .name = "grlib,gptimer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GPTimerUnit), + .class_init = grlib_gptimer_class_init, }; static void grlib_gptimer_register(void) { - sysbus_register_withprop(&grlib_gptimer_info); + type_register_static(&grlib_gptimer_info); } device_init(grlib_gptimer_register) diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c index 28725563c0..1e5ad826f5 100644 --- a/hw/grlib_irqmp.c +++ b/hw/grlib_irqmp.c @@ -354,21 +354,32 @@ static int grlib_irqmp_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo grlib_irqmp_info = { - .init = grlib_irqmp_init, - .qdev.name = "grlib,irqmp", - .qdev.reset = grlib_irqmp_reset, - .qdev.size = sizeof(IRQMP), - .qdev.props = (Property[]) { - DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in), - DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque), - DEFINE_PROP_END_OF_LIST(), - } +static Property grlib_irqmp_properties[] = { + DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in), + DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque), + DEFINE_PROP_END_OF_LIST(), +}; + +static void grlib_irqmp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = grlib_irqmp_init; + dc->reset = grlib_irqmp_reset; + dc->props = grlib_irqmp_properties; +} + +static TypeInfo grlib_irqmp_info = { + .name = "grlib,irqmp", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IRQMP), + .class_init = grlib_irqmp_class_init, }; static void grlib_irqmp_register(void) { - sysbus_register_withprop(&grlib_irqmp_info); + type_register_static(&grlib_irqmp_info); } device_init(grlib_irqmp_register) diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index 432683acea..e8cd59c3a4 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -1136,21 +1136,42 @@ static int gt64120_pci_init(PCIDevice *d) return 0; } -static PCIDeviceInfo gt64120_pci_info = { - .qdev.name = "gt64120_pci", - .qdev.size = sizeof(PCIDevice), - .init = gt64120_pci_init, - .vendor_id = PCI_VENDOR_ID_MARVELL, - .device_id = PCI_DEVICE_ID_MARVELL_GT6412X, - .revision = 0x10, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void gt64120_pci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = gt64120_pci_init; + k->vendor_id = PCI_VENDOR_ID_MARVELL; + k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X; + k->revision = 0x10; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static TypeInfo gt64120_pci_info = { + .name = "gt64120_pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = gt64120_pci_class_init, +}; + +static void gt64120_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = gt64120_init; +} + +static TypeInfo gt64120_info = { + .name = "gt64120", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GT64120State), + .class_init = gt64120_class_init, }; static void gt64120_pci_register_devices(void) { - sysbus_register_dev("gt64120", sizeof(GT64120State), - gt64120_init); - pci_qdev_register(>64120_pci_info); + type_register_static(>64120_info); + type_register_static(>64120_pci_info); } device_init(gt64120_pci_register_devices) @@ -221,14 +221,14 @@ static const VMStateDescription vmstate_gus = { .minimum_version_id = 2, .minimum_version_id_old = 2, .fields = (VMStateField []) { - VMSTATE_INT32(pos, GUSState), - VMSTATE_INT32(left, GUSState), - VMSTATE_INT32(shift, GUSState), - VMSTATE_INT32(irqs, GUSState), - VMSTATE_INT32(samples, GUSState), - VMSTATE_INT64(last_ticks, GUSState), - VMSTATE_BUFFER(himem, GUSState), - VMSTATE_END_OF_LIST() + VMSTATE_INT32 (pos, GUSState), + VMSTATE_INT32 (left, GUSState), + VMSTATE_INT32 (shift, GUSState), + VMSTATE_INT32 (irqs, GUSState), + VMSTATE_INT32 (samples, GUSState), + VMSTATE_INT64 (last_ticks, GUSState), + VMSTATE_BUFFER (himem, GUSState), + VMSTATE_END_OF_LIST () } }; @@ -239,13 +239,13 @@ static const MemoryRegionPortio gus_portio_list1[] = { {0x006, 10, 2, .read = gus_readw, .write = gus_writew }, {0x100, 8, 1, .read = gus_readb, .write = gus_writeb }, {0x100, 8, 2, .read = gus_readw, .write = gus_writew }, - PORTIO_END_OF_LIST(), + PORTIO_END_OF_LIST (), }; static const MemoryRegionPortio gus_portio_list2[] = { {0, 1, 1, .read = gus_readb }, {0, 1, 2, .read = gus_readw }, - PORTIO_END_OF_LIST(), + PORTIO_END_OF_LIST (), }; static int gus_initfn (ISADevice *dev) @@ -299,23 +299,33 @@ int GUS_init (ISABus *bus) return 0; } -static ISADeviceInfo gus_info = { - .qdev.name = "gus", - .qdev.desc = "Gravis Ultrasound GF1", - .qdev.size = sizeof (GUSState), - .qdev.vmsd = &vmstate_gus, - .init = gus_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100), - DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240), - DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7), - DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3), - DEFINE_PROP_END_OF_LIST (), - }, +static Property gus_properties[] = { + DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100), + DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240), + DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7), + DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3), + DEFINE_PROP_END_OF_LIST (), +}; + +static void gus_class_initfn (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS (klass); + ic->init = gus_initfn; + dc->desc = "Gravis Ultrasound GF1"; + dc->vmsd = &vmstate_gus; + dc->props = gus_properties; +} + +static TypeInfo gus_info = { + .name = "gus", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof (GUSState), + .class_init = gus_class_initfn, }; static void gus_register (void) { - isa_qdev_register (&gus_info); + type_register_static (&gus_info); } device_init (gus_register) diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 9b089e65b4..152f8e6f13 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -777,7 +777,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) uint32_t i, type; a->desc = desc; - a->name = a->hda.qdev.info->name; + a->name = object_get_typename(OBJECT(a)); dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad); AUD_register_card("hda", &a->card); @@ -906,33 +906,51 @@ static int hda_audio_init_duplex(HDACodecDevice *hda) return hda_audio_init(hda, &duplex); } -static HDACodecDeviceInfo hda_audio_info_output = { - .qdev.name = "hda-output", - .qdev.desc = "HDA Audio Codec, output-only", - .qdev.size = sizeof(HDAAudioState), - .qdev.vmsd = &vmstate_hda_audio, - .qdev.props = hda_audio_properties, - .init = hda_audio_init_output, - .exit = hda_audio_exit, - .command = hda_audio_command, - .stream = hda_audio_stream, +static void hda_audio_output_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); + + k->init = hda_audio_init_output; + k->exit = hda_audio_exit; + k->command = hda_audio_command; + k->stream = hda_audio_stream; + dc->desc = "HDA Audio Codec, output-only"; + dc->vmsd = &vmstate_hda_audio; + dc->props = hda_audio_properties; +} + +static TypeInfo hda_audio_output_info = { + .name = "hda-output", + .parent = TYPE_HDA_CODEC_DEVICE, + .instance_size = sizeof(HDAAudioState), + .class_init = hda_audio_output_class_init, }; -static HDACodecDeviceInfo hda_audio_info_duplex = { - .qdev.name = "hda-duplex", - .qdev.desc = "HDA Audio Codec, duplex", - .qdev.size = sizeof(HDAAudioState), - .qdev.vmsd = &vmstate_hda_audio, - .qdev.props = hda_audio_properties, - .init = hda_audio_init_duplex, - .exit = hda_audio_exit, - .command = hda_audio_command, - .stream = hda_audio_stream, +static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); + + k->init = hda_audio_init_duplex; + k->exit = hda_audio_exit; + k->command = hda_audio_command; + k->stream = hda_audio_stream; + dc->desc = "HDA Audio Codec, duplex"; + dc->vmsd = &vmstate_hda_audio; + dc->props = hda_audio_properties; +} + +static TypeInfo hda_audio_duplex_info = { + .name = "hda-duplex", + .parent = TYPE_HDA_CODEC_DEVICE, + .instance_size = sizeof(HDAAudioState), + .class_init = hda_audio_duplex_class_init, }; static void hda_audio_register(void) { - hda_codec_register(&hda_audio_info_output); - hda_codec_register(&hda_audio_info_duplex); + type_register_static(&hda_audio_output_info); + type_register_static(&hda_audio_duplex_info); } device_init(hda_audio_register); diff --git a/hw/highbank.c b/hw/highbank.c new file mode 100644 index 0000000000..684178ee3e --- /dev/null +++ b/hw/highbank.c @@ -0,0 +1,339 @@ +/* + * Calxeda Highbank SoC emulation + * + * Copyright (c) 2010-2012 Calxeda + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "sysbus.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "loader.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" +#include "sysbus.h" +#include "blockdev.h" +#include "exec-memory.h" + +#define SMP_BOOT_ADDR 0x100 +#define SMP_BOOT_REG 0x40 +#define GIC_BASE_ADDR 0xfff10000 + +#define NIRQ_GIC 160 + +/* Board init. */ +static void highbank_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + env->cp15.c15_config_base_address = GIC_BASE_ADDR; +} + +static void hb_write_secondary(CPUState *env, const struct arm_boot_info *info) +{ + int n; + uint32_t smpboot[] = { + 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */ + 0xe210000f, /* ands r0, r0, #0x0f */ + 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */ + 0xe0830200, /* add r0, r3, r0, lsl #4 */ + 0xe59f2018, /* ldr r2, privbase */ + 0xe3a01001, /* mov r1, #1 */ + 0xe5821100, /* str r1, [r2, #256] */ + 0xe320f003, /* wfi */ + 0xe5901000, /* ldr r1, [r0] */ + 0xe1110001, /* tst r1, r1 */ + 0x0afffffb, /* beq <wfi> */ + 0xe12fff11, /* bx r1 */ + GIC_BASE_ADDR /* privbase: gic address. */ + }; + for (n = 0; n < ARRAY_SIZE(smpboot); n++) { + smpboot[n] = tswap32(smpboot[n]); + } + rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR); +} + +static void hb_reset_secondary(CPUState *env, const struct arm_boot_info *info) +{ + switch (info->nb_cpus) { + case 4: + stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0); + case 3: + stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0); + case 2: + stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0); + env->regs[15] = SMP_BOOT_ADDR; + break; + default: + break; + } +} + +#define NUM_REGS 0x200 +static void hb_regs_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ + uint32_t *regs = opaque; + + if (offset == 0xf00) { + if (value == 1 || value == 2) { + qemu_system_reset_request(); + } else if (value == 3) { + qemu_system_shutdown_request(); + } + } + + regs[offset/4] = value; +} + +static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ + uint32_t *regs = opaque; + uint32_t value = regs[offset/4]; + + if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { + value |= 0x30000000; + } + + return value; +} + +static const MemoryRegionOps hb_mem_ops = { + .read = hb_regs_read, + .write = hb_regs_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +typedef struct { + SysBusDevice busdev; + MemoryRegion *iomem; + uint32_t regs[NUM_REGS]; +} HighbankRegsState; + +static VMStateDescription vmstate_highbank_regs = { + .name = "highbank-regs", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static void highbank_regs_reset(DeviceState *dev) +{ + SysBusDevice *sys_dev = sysbus_from_qdev(dev); + HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev); + + s->regs[0x40] = 0x05F20121; + s->regs[0x41] = 0x2; + s->regs[0x42] = 0x05F30121; + s->regs[0x43] = 0x05F40121; +} + +static int highbank_regs_init(SysBusDevice *dev) +{ + HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev); + + s->iomem = g_new(MemoryRegion, 1); + memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs", + 0x1000); + sysbus_init_mmio(dev, s->iomem); + + return 0; +} + +static void highbank_regs_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sbc->init = highbank_regs_init; + dc->desc = "Calxeda Highbank registers"; + dc->vmsd = &vmstate_highbank_regs; + dc->reset = highbank_regs_reset; +} + +static TypeInfo highbank_regs_info = { + .name = "highbank-regs", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(HighbankRegsState), + .class_init = highbank_regs_class_init, +}; + +static void highbank_regs_register_device(void) +{ + type_register_static(&highbank_regs_info); +} + +device_init(highbank_regs_register_device) + +static struct arm_boot_info highbank_binfo; + +/* ram_size must be set to match the upper bound of memory in the + * device tree (linux/arch/arm/boot/dts/highbank.dts), which is + * normally 0xff900000 or -m 4089. When running this board on a + * 32-bit host, set the reg value of memory to 0xf7ff00000 in the + * device tree and pass -m 2047 to QEMU. + */ +static void highbank_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env = NULL; + DeviceState *dev; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[128]; + int n; + qemu_irq cpu_irq[4]; + MemoryRegion *sysram; + MemoryRegion *dram; + MemoryRegion *sysmem; + char *sysboot_filename; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + for (n = 0; n < smp_cpus; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(env); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + qemu_register_reset(highbank_cpu_reset, env); + } + + sysmem = get_system_memory(); + dram = g_new(MemoryRegion, 1); + memory_region_init_ram(dram, "highbank.dram", ram_size); + /* SDRAM at address zero. */ + memory_region_add_subregion(sysmem, 0, dram); + + sysram = g_new(MemoryRegion, 1); + memory_region_init_ram(sysram, "highbank.sysram", 0x8000); + memory_region_add_subregion(sysmem, 0xfff88000, sysram); + if (bios_name != NULL) { + sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (sysboot_filename != NULL) { + uint32_t filesize = get_image_size(sysboot_filename); + if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) { + hw_error("Unable to load %s\n", bios_name); + } + } else { + hw_error("Unable to find %s\n", bios_name); + } + } + + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + + for (n = 0; n < 128; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + dev = qdev_create(NULL, "l2x0"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff12000); + + dev = qdev_create(NULL, "sp804"); + qdev_prop_set_uint32(dev, "freq0", 150000000); + qdev_prop_set_uint32(dev, "freq1", 150000000); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff34000); + sysbus_connect_irq(busdev, 0, pic[18]); + sysbus_create_simple("pl011", 0xfff36000, pic[20]); + + dev = qdev_create(NULL, "highbank-regs"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff3c000); + + sysbus_create_simple("pl061", 0xfff30000, pic[14]); + sysbus_create_simple("pl061", 0xfff31000, pic[15]); + sysbus_create_simple("pl061", 0xfff32000, pic[16]); + sysbus_create_simple("pl061", 0xfff33000, pic[17]); + sysbus_create_simple("pl031", 0xfff35000, pic[19]); + sysbus_create_simple("pl022", 0xfff39000, pic[23]); + + sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); + + if (nd_table[0].vlan) { + qemu_check_nic_model(&nd_table[0], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]); + + qemu_check_nic_model(&nd_table[1], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[1]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]); + } + + highbank_binfo.ram_size = ram_size; + highbank_binfo.kernel_filename = kernel_filename; + highbank_binfo.kernel_cmdline = kernel_cmdline; + highbank_binfo.initrd_filename = initrd_filename; + /* highbank requires a dtb in order to boot, and the dtb will override + * the board ID. The following value is ignored, so set it to -1 to be + * clear that the value is meaningless. + */ + highbank_binfo.board_id = -1; + highbank_binfo.nb_cpus = smp_cpus; + highbank_binfo.loader_start = 0; + highbank_binfo.write_secondary_boot = hb_write_secondary; + highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary; + arm_load_kernel(first_cpu, &highbank_binfo); +} + +static QEMUMachine highbank_machine = { + .name = "highbank", + .desc = "Calxeda Highbank (ECX-1000)", + .init = highbank_init, + .use_scsi = 1, + .max_cpus = 4, +}; + +static void highbank_machine_init(void) +{ + qemu_register_machine(&highbank_machine); +} + +machine_init(highbank_machine_init); @@ -695,23 +695,34 @@ static int hpet_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo hpet_device_info = { - .qdev.name = "hpet", - .qdev.size = sizeof(HPETState), - .qdev.no_user = 1, - .qdev.vmsd = &vmstate_hpet, - .qdev.reset = hpet_reset, - .init = hpet_init, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), - DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), - DEFINE_PROP_END_OF_LIST(), - }, +static Property hpet_device_properties[] = { + DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), + DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void hpet_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = hpet_init; + dc->no_user = 1; + dc->reset = hpet_reset; + dc->vmsd = &vmstate_hpet; + dc->props = hpet_device_properties; +} + +static TypeInfo hpet_device_info = { + .name = "hpet", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(HPETState), + .class_init = hpet_device_class_init, }; static void hpet_register_device(void) { - sysbus_register_withprop(&hpet_device_info); + type_register_static(&hpet_device_info); } device_init(hpet_register_device) @@ -12,8 +12,8 @@ struct i2c_bus { BusState qbus; - i2c_slave *current_dev; - i2c_slave *dev; + I2CSlave *current_dev; + I2CSlave *dev; uint8_t saved_address; }; @@ -21,7 +21,7 @@ static struct BusInfo i2c_bus_info = { .name = "I2C", .size = sizeof(i2c_bus), .props = (Property[]) { - DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0), + DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0), DEFINE_PROP_END_OF_LIST(), } }; @@ -66,7 +66,7 @@ i2c_bus *i2c_init_bus(DeviceState *parent, const char *name) return bus; } -void i2c_set_slave_address(i2c_slave *dev, uint8_t address) +void i2c_set_slave_address(I2CSlave *dev, uint8_t address) { dev->address = address; } @@ -82,71 +82,100 @@ int i2c_bus_busy(i2c_bus *bus) int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv) { DeviceState *qdev; - i2c_slave *slave = NULL; + I2CSlave *slave = NULL; + I2CSlaveClass *sc; QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) { - i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev); + I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev); if (candidate->address == address) { slave = candidate; break; } } - if (!slave) + if (!slave) { return 1; + } + sc = I2C_SLAVE_GET_CLASS(slave); /* If the bus is already busy, assume this is a repeated start condition. */ bus->current_dev = slave; - slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND); + if (sc->event) { + sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND); + } return 0; } void i2c_end_transfer(i2c_bus *bus) { - i2c_slave *dev = bus->current_dev; + I2CSlave *dev = bus->current_dev; + I2CSlaveClass *sc; - if (!dev) + if (!dev) { return; + } - dev->info->event(dev, I2C_FINISH); + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->event) { + sc->event(dev, I2C_FINISH); + } bus->current_dev = NULL; } int i2c_send(i2c_bus *bus, uint8_t data) { - i2c_slave *dev = bus->current_dev; + I2CSlave *dev = bus->current_dev; + I2CSlaveClass *sc; - if (!dev) + if (!dev) { return -1; + } + + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->send) { + return sc->send(dev, data); + } - return dev->info->send(dev, data); + return -1; } int i2c_recv(i2c_bus *bus) { - i2c_slave *dev = bus->current_dev; + I2CSlave *dev = bus->current_dev; + I2CSlaveClass *sc; - if (!dev) + if (!dev) { return -1; + } + + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->recv) { + return sc->recv(dev); + } - return dev->info->recv(dev); + return -1; } void i2c_nack(i2c_bus *bus) { - i2c_slave *dev = bus->current_dev; + I2CSlave *dev = bus->current_dev; + I2CSlaveClass *sc; - if (!dev) + if (!dev) { return; + } - dev->info->event(dev, I2C_NACK); + sc = I2C_SLAVE_GET_CLASS(dev); + if (sc->event) { + sc->event(dev, I2C_NACK); + } } static int i2c_slave_post_load(void *opaque, int version_id) { - i2c_slave *dev = opaque; + I2CSlave *dev = opaque; i2c_bus *bus; bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev)); if (bus->saved_address == dev->address) { @@ -156,33 +185,23 @@ static int i2c_slave_post_load(void *opaque, int version_id) } const VMStateDescription vmstate_i2c_slave = { - .name = "i2c_slave", + .name = "I2CSlave", .version_id = 1, .minimum_version_id = 1, .minimum_version_id_old = 1, .post_load = i2c_slave_post_load, .fields = (VMStateField []) { - VMSTATE_UINT8(address, i2c_slave), + VMSTATE_UINT8(address, I2CSlave), VMSTATE_END_OF_LIST() } }; -static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base) +static int i2c_slave_qdev_init(DeviceState *dev) { - I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev); - i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev); - - s->info = info; + I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev); + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s); - return info->init(s); -} - -void i2c_register_slave(I2CSlaveInfo *info) -{ - assert(info->qdev.size >= sizeof(i2c_slave)); - info->qdev.init = i2c_slave_qdev_init; - info->qdev.bus_info = &i2c_bus_info; - qdev_register(&info->qdev); + return sc->init(s); } DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr) @@ -194,3 +213,26 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr) qdev_init_nofail(dev); return dev; } + +static void i2c_slave_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = i2c_slave_qdev_init; + k->bus_info = &i2c_bus_info; +} + +static TypeInfo i2c_slave_type_info = { + .name = TYPE_I2C_SLAVE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(I2CSlave), + .abstract = true, + .class_size = sizeof(I2CSlaveClass), + .class_init = i2c_slave_class_init, +}; + +static void i2c_slave_register_devices(void) +{ + type_register_static(&i2c_slave_type_info); +} + +device_init(i2c_slave_register_devices); @@ -15,36 +15,43 @@ enum i2c_event { I2C_NACK /* Masker NACKed a receive byte. */ }; -/* Master to slave. */ -typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data); -/* Slave to master. */ -typedef int (*i2c_recv_cb)(i2c_slave *s); -/* Notify the slave of a bus state change. */ -typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event); +typedef struct I2CSlave I2CSlave; -typedef int (*i2c_slave_initfn)(i2c_slave *dev); +#define TYPE_I2C_SLAVE "i2c-slave" +#define I2C_SLAVE(obj) \ + OBJECT_CHECK(I2CSlave, (obj), TYPE_I2C_SLAVE) +#define I2C_SLAVE_CLASS(klass) \ + OBJECT_CLASS_CHECK(I2CSlaveClass, (klass), TYPE_I2C_SLAVE) +#define I2C_SLAVE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(I2CSlaveClass, (obj), TYPE_I2C_SLAVE) -typedef struct { - DeviceInfo qdev; +typedef struct I2CSlaveClass +{ + DeviceClass parent_class; /* Callbacks provided by the device. */ - i2c_slave_initfn init; - i2c_event_cb event; - i2c_recv_cb recv; - i2c_send_cb send; -} I2CSlaveInfo; + int (*init)(I2CSlave *dev); + + /* Master to slave. */ + int (*send)(I2CSlave *s, uint8_t data); + + /* Slave to master. */ + int (*recv)(I2CSlave *s); -struct i2c_slave + /* Notify the slave of a bus state change. */ + void (*event)(I2CSlave *s, enum i2c_event event); +} I2CSlaveClass; + +struct I2CSlave { DeviceState qdev; - I2CSlaveInfo *info; /* Remaining fields for internal use by the I2C code. */ uint8_t address; }; i2c_bus *i2c_init_bus(DeviceState *parent, const char *name); -void i2c_set_slave_address(i2c_slave *dev, uint8_t address); +void i2c_set_slave_address(I2CSlave *dev, uint8_t address); int i2c_bus_busy(i2c_bus *bus); int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv); void i2c_end_transfer(i2c_bus *bus); @@ -52,11 +59,9 @@ void i2c_nack(i2c_bus *bus); int i2c_send(i2c_bus *bus, uint8_t data); int i2c_recv(i2c_bus *bus); -#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(i2c_slave, qdev, dev) +#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(I2CSlave, qdev, dev) #define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev) -void i2c_register_slave(I2CSlaveInfo *type); - DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr); /* wm8750.c */ @@ -69,7 +74,7 @@ void wm8750_dac_commit(void *opaque); void wm8750_set_bclk_in(void *opaque, int new_hz); /* tmp105.c */ -void tmp105_set(i2c_slave *i2c, int temp); +void tmp105_set(I2CSlave *i2c, int temp); /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); @@ -78,10 +83,10 @@ extern const VMStateDescription vmstate_i2c_slave; #define VMSTATE_I2C_SLAVE(_field, _state) { \ .name = (stringify(_field)), \ - .size = sizeof(i2c_slave), \ + .size = sizeof(I2CSlave), \ .vmsd = &vmstate_i2c_slave, \ .flags = VMS_STRUCT, \ - .offset = vmstate_offset_value(_state, _field, i2c_slave), \ + .offset = vmstate_offset_value(_state, _field, I2CSlave), \ } #endif diff --git a/hw/i82374.c b/hw/i82374.c new file mode 100644 index 0000000000..220e8cccb6 --- /dev/null +++ b/hw/i82374.c @@ -0,0 +1,165 @@ +/* + * QEMU Intel 82374 emulation (Enhanced DMA controller) + * + * Copyright (c) 2010 Hervé Poussineau + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "isa.h" + +//#define DEBUG_I82374 + +#ifdef DEBUG_I82374 +#define DPRINTF(fmt, ...) \ +do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ +do {} while (0) +#endif +#define BADF(fmt, ...) \ +do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0) + +typedef struct I82374State { + uint8_t commands[8]; +} I82374State; + +static const VMStateDescription vmstate_i82374 = { + .name = "i82374", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(commands, I82374State, 8), + VMSTATE_END_OF_LIST() + }, +}; + +static uint32_t i82374_read_isr(void *opaque, uint32_t nport) +{ + uint32_t val = 0; + + BADF("%s: %08x\n", __func__, nport); + + DPRINTF("%s: %08x=%08x\n", __func__, nport, val); + return val; +} + +static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data) +{ + DPRINTF("%s: %08x=%08x\n", __func__, nport, data); + + if (data != 0x42) { + /* Not Stop S/G command */ + BADF("%s: %08x=%08x\n", __func__, nport, data); + } +} + +static uint32_t i82374_read_status(void *opaque, uint32_t nport) +{ + uint32_t val = 0; + + BADF("%s: %08x\n", __func__, nport); + + DPRINTF("%s: %08x=%08x\n", __func__, nport, val); + return val; +} + +static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data) +{ + DPRINTF("%s: %08x=%08x\n", __func__, nport, data); + + BADF("%s: %08x=%08x\n", __func__, nport, data); +} + +static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport) +{ + uint32_t val = 0; + + BADF("%s: %08x\n", __func__, nport); + + DPRINTF("%s: %08x=%08x\n", __func__, nport, val); + return val; +} + +static void i82374_init(I82374State *s) +{ + DMA_init(1, NULL); + memset(s->commands, 0, sizeof(s->commands)); +} + +typedef struct ISAi82374State { + ISADevice dev; + uint32_t iobase; + I82374State state; +} ISAi82374State; + +static const VMStateDescription vmstate_isa_i82374 = { + .name = "isa-i82374", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(state, ISAi82374State, 0, vmstate_i82374, I82374State), + VMSTATE_END_OF_LIST() + }, +}; + +static int i82374_isa_init(ISADevice *dev) +{ + ISAi82374State *isa = DO_UPCAST(ISAi82374State, dev, dev); + I82374State *s = &isa->state; + + register_ioport_read(isa->iobase + 0x0A, 1, 1, i82374_read_isr, s); + register_ioport_write(isa->iobase + 0x10, 8, 1, i82374_write_command, s); + register_ioport_read(isa->iobase + 0x18, 8, 1, i82374_read_status, s); + register_ioport_write(isa->iobase + 0x20, 0x20, 1, i82374_write_descriptor, s); + register_ioport_read(isa->iobase + 0x20, 0x20, 1, i82374_read_descriptor, s); + + i82374_init(s); + + return 0; +} + +static Property i82374_properties[] = { + DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400), + DEFINE_PROP_END_OF_LIST() +}; + +static void i82374_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *k = ISA_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = i82374_isa_init; + dc->vmsd = &vmstate_isa_i82374; + dc->props = i82374_properties; +} + +static TypeInfo i82374_isa_info = { + .name = "i82374", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISAi82374State), + .class_init = i82374_class_init, +}; + +static void i82374_register_devices(void) +{ + type_register_static(&i82374_isa_info); +} + +device_init(i82374_register_devices) diff --git a/hw/i82378.c b/hw/i82378.c new file mode 100644 index 0000000000..9c3efe8b95 --- /dev/null +++ b/hw/i82378.c @@ -0,0 +1,275 @@ +/* + * QEMU Intel i82378 emulation (PCI to ISA bridge) + * + * Copyright (c) 2010-2011 Hervé Poussineau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "pci.h" +#include "pc.h" + +//#define DEBUG_I82378 + +#ifdef DEBUG_I82378 +#define DPRINTF(fmt, ...) \ +do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ +do {} while (0) +#endif + +#define BADF(fmt, ...) \ +do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0) + +typedef struct I82378State { + qemu_irq out[2]; + qemu_irq *i8259; + MemoryRegion io; + MemoryRegion mem; +} I82378State; + +typedef struct PCIi82378State { + PCIDevice pci_dev; + uint32_t isa_io_base; + uint32_t isa_mem_base; + I82378State state; +} PCIi82378State; + +static const VMStateDescription vmstate_pci_i82378 = { + .name = "pci-i82378", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(pci_dev, PCIi82378State), + VMSTATE_END_OF_LIST() + }, +}; + +static void i82378_io_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned int size) +{ + switch (size) { + case 1: + DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__, + addr, value); + cpu_outb(addr, value); + break; + case 2: + DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__, + addr, value); + cpu_outw(addr, value); + break; + case 4: + DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__, + addr, value); + cpu_outl(addr, value); + break; + default: + abort(); + } +} + +static uint64_t i82378_io_read(void *opaque, target_phys_addr_t addr, + unsigned int size) +{ + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + switch (size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + default: + abort(); + } +} + +static const MemoryRegionOps i82378_io_ops = { + .read = i82378_io_read, + .write = i82378_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void i82378_mem_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned int size) +{ + switch (size) { + case 1: + DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__, + addr, value); + cpu_outb(addr, value); + break; + case 2: + DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__, + addr, value); + cpu_outw(addr, value); + break; + case 4: + DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__, + addr, value); + cpu_outl(addr, value); + break; + default: + abort(); + } +} + +static uint64_t i82378_mem_read(void *opaque, target_phys_addr_t addr, + unsigned int size) +{ + DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr); + switch (size) { + case 1: + return cpu_inb(addr); + case 2: + return cpu_inw(addr); + case 4: + return cpu_inl(addr); + default: + abort(); + } +} + +static const MemoryRegionOps i82378_mem_ops = { + .read = i82378_mem_read, + .write = i82378_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void i82378_request_out0_irq(void *opaque, int irq, int level) +{ + I82378State *s = opaque; + qemu_set_irq(s->out[0], level); +} + +static void i82378_request_pic_irq(void *opaque, int irq, int level) +{ + DeviceState *dev = opaque; + PCIDevice *pci = DO_UPCAST(PCIDevice, qdev, dev); + PCIi82378State *s = DO_UPCAST(PCIi82378State, pci_dev, pci); + + qemu_set_irq(s->state.i8259[irq], level); +} + +static void i82378_init(DeviceState *dev, I82378State *s) +{ + ISABus *isabus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(dev, "isa.0")); + ISADevice *pit; + qemu_irq *out0_irq; + + /* This device has: + 2 82C59 (irq) + 1 82C54 (pit) + 2 82C37 (dma) + NMI + Utility Bus Support Registers + + All devices accept byte access only, except timer + */ + + qdev_init_gpio_out(dev, s->out, 2); + qdev_init_gpio_in(dev, i82378_request_pic_irq, 16); + + /* Workaround the fact that i8259 is not qdev'ified... */ + out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1); + + /* 2 82C59 (irq) */ + s->i8259 = i8259_init(isabus, *out0_irq); + isa_bus_irqs(isabus, s->i8259); + + /* 1 82C54 (pit) */ + pit = pit_init(isabus, 0x40, 0); + + /* speaker */ + pcspk_init(pit); + + /* 2 82C37 (dma) */ + DMA_init(1, &s->out[1]); + isa_create_simple(isabus, "i82374"); + + /* timer */ + isa_create_simple(isabus, "mc146818rtc"); +} + +static int pci_i82378_init(PCIDevice *dev) +{ + PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, dev); + I82378State *s = &pci->state; + uint8_t *pci_conf; + + pci_conf = dev->config; + pci_set_word(pci_conf + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_set_word(pci_conf + PCI_STATUS, + PCI_STATUS_DEVSEL_MEDIUM); + + pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */ + + memory_region_init_io(&s->io, &i82378_io_ops, s, "i82378-io", 0x00010000); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io); + + memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000); + memory_region_set_coalescing(&s->mem); + pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); + + /* Make I/O address read only */ + pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL); + pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0); + pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base); + + isa_mem_base = pci->isa_mem_base; + isa_bus_new(&dev->qdev, pci_address_space_io(dev)); + + i82378_init(&dev->qdev, s); + + return 0; +} + +static Property i82378_properties[] = { + DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000), + DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000), + DEFINE_PROP_END_OF_LIST() +}; + +static void pci_i82378_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = pci_i82378_init; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82378; + k->revision = 0x03; + k->class_id = PCI_CLASS_BRIDGE_ISA; + k->subsystem_vendor_id = 0x0; + k->subsystem_id = 0x0; + dc->vmsd = &vmstate_pci_i82378; + dc->props = i82378_properties; +} + +static TypeInfo pci_i82378_info = { + .name = "i82378", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIi82378State), + .class_init = pci_i82378_class_init, +}; + +static void i82378_register_devices(void) +{ + type_register_static(&pci_i82378_info); +} + +device_init(i82378_register_devices) diff --git a/hw/i8254.c b/hw/i8254.c index cf9ed2ff25..522fed8809 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -535,22 +535,32 @@ static int pit_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo pit_info = { - .qdev.name = "isa-pit", - .qdev.size = sizeof(PITState), - .qdev.vmsd = &vmstate_pit, - .qdev.reset = pit_reset, - .qdev.no_user = 1, - .init = pit_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("irq", PITState, irq, -1), - DEFINE_PROP_HEX32("iobase", PITState, iobase, -1), - DEFINE_PROP_END_OF_LIST(), - }, +static Property pit_properties[] = { + DEFINE_PROP_UINT32("irq", PITState, irq, -1), + DEFINE_PROP_HEX32("iobase", PITState, iobase, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pit_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = pit_initfn; + dc->no_user = 1; + dc->reset = pit_reset; + dc->vmsd = &vmstate_pit; + dc->props = pit_properties; +} + +static TypeInfo pit_info = { + .name = "isa-pit", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PITState), + .class_init = pit_class_initfn, }; static void pit_register(void) { - isa_qdev_register(&pit_info); + type_register_static(&pit_info); } device_init(pit_register) diff --git a/hw/i8259.c b/hw/i8259.c index 7331e0e61c..7ae53805d7 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -26,6 +26,7 @@ #include "isa.h" #include "monitor.h" #include "qemu-timer.h" +#include "i8259_internal.h" /* debug PIC */ //#define DEBUG_PIC @@ -40,33 +41,6 @@ //#define DEBUG_IRQ_LATENCY //#define DEBUG_IRQ_COUNT -struct PicState { - ISADevice dev; - uint8_t last_irr; /* edge detection */ - uint8_t irr; /* interrupt request register */ - uint8_t imr; /* interrupt mask register */ - uint8_t isr; /* interrupt service register */ - uint8_t priority_add; /* highest irq priority */ - uint8_t irq_base; - uint8_t read_reg_select; - uint8_t poll; - uint8_t special_mask; - uint8_t init_state; - uint8_t auto_eoi; - uint8_t rotate_on_auto_eoi; - uint8_t special_fully_nested_mode; - uint8_t init4; /* true if 4 byte init */ - uint8_t single_mode; /* true if slave pic is not initialized */ - uint8_t elcr; /* PIIX edge/trigger selection*/ - uint8_t elcr_mask; - qemu_irq int_out[1]; - uint32_t master; /* reflects /SP input pin */ - uint32_t iobase; - uint32_t elcr_addr; - MemoryRegion base_io; - MemoryRegion elcr_io; -}; - #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) static int irq_level[16]; #endif @@ -76,12 +50,12 @@ static uint64_t irq_count[16]; #ifdef DEBUG_IRQ_LATENCY static int64_t irq_time[16]; #endif -PicState *isa_pic; -static PicState *slave_pic; +DeviceState *isa_pic; +static PICCommonState *slave_pic; /* return the highest priority found in mask (highest = smallest number). Return 8 if no irq */ -static int get_priority(PicState *s, int mask) +static int get_priority(PICCommonState *s, int mask) { int priority; @@ -96,7 +70,7 @@ static int get_priority(PicState *s, int mask) } /* return the pic wanted interrupt. return -1 if none */ -static int pic_get_irq(PicState *s) +static int pic_get_irq(PICCommonState *s) { int mask, cur_priority, priority; @@ -125,7 +99,7 @@ static int pic_get_irq(PicState *s) } /* Update INT output. Must be called every time the output may have changed. */ -static void pic_update_irq(PicState *s) +static void pic_update_irq(PICCommonState *s) { int irq; @@ -142,7 +116,7 @@ static void pic_update_irq(PicState *s) /* set irq level. If an edge is detected, then the IRR is set to 1 */ static void pic_set_irq(void *opaque, int irq, int level) { - PicState *s = opaque; + PICCommonState *s = opaque; int mask = 1 << irq; #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \ @@ -190,7 +164,7 @@ static void pic_set_irq(void *opaque, int irq, int level) } /* acknowledge interrupt 'irq' */ -static void pic_intack(PicState *s, int irq) +static void pic_intack(PICCommonState *s, int irq) { if (s->auto_eoi) { if (s->rotate_on_auto_eoi) { @@ -206,8 +180,9 @@ static void pic_intack(PicState *s, int irq) pic_update_irq(s); } -int pic_read_irq(PicState *s) +int pic_read_irq(DeviceState *d) { + PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d); int irq, irq2, intno; irq = pic_get_irq(s); @@ -246,30 +221,15 @@ int pic_read_irq(PicState *s) return intno; } -static void pic_init_reset(PicState *s) +static void pic_init_reset(PICCommonState *s) { - s->last_irr = 0; - s->irr = 0; - s->imr = 0; - s->isr = 0; - s->priority_add = 0; - s->irq_base = 0; - s->read_reg_select = 0; - s->poll = 0; - s->special_mask = 0; - s->init_state = 0; - s->auto_eoi = 0; - s->rotate_on_auto_eoi = 0; - s->special_fully_nested_mode = 0; - s->init4 = 0; - s->single_mode = 0; - /* Note: ELCR is not reset */ + pic_reset_common(s); pic_update_irq(s); } static void pic_reset(DeviceState *dev) { - PicState *s = container_of(dev, PicState, dev.qdev); + PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev); pic_init_reset(s); s->elcr = 0; @@ -278,7 +238,7 @@ static void pic_reset(DeviceState *dev) static void pic_ioport_write(void *opaque, target_phys_addr_t addr64, uint64_t val64, unsigned size) { - PicState *s = opaque; + PICCommonState *s = opaque; uint32_t addr = addr64; uint32_t val = val64; int priority, cmd, irq; @@ -372,7 +332,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64, static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr, unsigned size) { - PicState *s = opaque; + PICCommonState *s = opaque; int ret; if (s->poll) { @@ -399,51 +359,27 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr, return ret; } -int pic_get_output(PicState *s) +int pic_get_output(DeviceState *d) { + PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d); + return (pic_get_irq(s) >= 0); } static void elcr_ioport_write(void *opaque, target_phys_addr_t addr, uint64_t val, unsigned size) { - PicState *s = opaque; + PICCommonState *s = opaque; s->elcr = val & s->elcr_mask; } static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr, unsigned size) { - PicState *s = opaque; + PICCommonState *s = opaque; return s->elcr; } -static const VMStateDescription vmstate_pic = { - .name = "i8259", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(last_irr, PicState), - VMSTATE_UINT8(irr, PicState), - VMSTATE_UINT8(imr, PicState), - VMSTATE_UINT8(isr, PicState), - VMSTATE_UINT8(priority_add, PicState), - VMSTATE_UINT8(irq_base, PicState), - VMSTATE_UINT8(read_reg_select, PicState), - VMSTATE_UINT8(poll, PicState), - VMSTATE_UINT8(special_mask, PicState), - VMSTATE_UINT8(init_state, PicState), - VMSTATE_UINT8(auto_eoi, PicState), - VMSTATE_UINT8(rotate_on_auto_eoi, PicState), - VMSTATE_UINT8(special_fully_nested_mode, PicState), - VMSTATE_UINT8(init4, PicState), - VMSTATE_UINT8(single_mode, PicState), - VMSTATE_UINT8(elcr, PicState), - VMSTATE_END_OF_LIST() - } -}; - static const MemoryRegionOps pic_base_ioport_ops = { .read = pic_ioport_read, .write = pic_ioport_write, @@ -462,36 +398,25 @@ static const MemoryRegionOps pic_elcr_ioport_ops = { }, }; -static int pic_initfn(ISADevice *dev) +static void pic_init(PICCommonState *s) { - PicState *s = DO_UPCAST(PicState, dev, dev); - memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2); memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1); - isa_register_ioport(dev, &s->base_io, s->iobase); - if (s->elcr_addr != -1) { - isa_register_ioport(dev, &s->elcr_io, s->elcr_addr); - } - - qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out)); - qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8); - - qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1); - - return 0; + qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out)); + qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8); } void pic_info(Monitor *mon) { int i; - PicState *s; + PICCommonState *s; if (!isa_pic) { return; } for (i = 0; i < 2; i++) { - s = i == 0 ? isa_pic : slave_pic; + s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic; monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", i, s->irr, s->imr, s->isr, s->priority_add, @@ -526,54 +451,46 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq)); - dev = isa_create(bus, "isa-i8259"); - qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20); - qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0); - qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8); - qdev_prop_set_bit(&dev->qdev, "master", true); - qdev_init_nofail(&dev->qdev); + dev = i8259_init_chip("isa-i8259", bus, true); qdev_connect_gpio_out(&dev->qdev, 0, parent_irq); for (i = 0 ; i < 8; i++) { irq_set[i] = qdev_get_gpio_in(&dev->qdev, i); } - isa_pic = DO_UPCAST(PicState, dev, dev); + isa_pic = &dev->qdev; - dev = isa_create(bus, "isa-i8259"); - qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0); - qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1); - qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde); - qdev_init_nofail(&dev->qdev); + dev = i8259_init_chip("isa-i8259", bus, false); qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]); for (i = 0 ; i < 8; i++) { irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i); } - slave_pic = DO_UPCAST(PicState, dev, dev); + slave_pic = DO_UPCAST(PICCommonState, dev, dev); return irq_set; } -static ISADeviceInfo i8259_info = { - .qdev.name = "isa-i8259", - .qdev.size = sizeof(PicState), - .qdev.vmsd = &vmstate_pic, - .qdev.reset = pic_reset, - .qdev.no_user = 1, - .init = pic_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("iobase", PicState, iobase, -1), - DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr, -1), - DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask, -1), - DEFINE_PROP_BIT("master", PicState, master, 0, false), - DEFINE_PROP_END_OF_LIST(), - }, +static void i8259_class_init(ObjectClass *klass, void *data) +{ + PICCommonClass *k = PIC_COMMON_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = pic_init; + dc->reset = pic_reset; +} + +static TypeInfo i8259_info = { + .name = "isa-i8259", + .instance_size = sizeof(PICCommonState), + .parent = TYPE_PIC_COMMON, + .class_init = i8259_class_init, }; static void pic_register(void) { - isa_qdev_register(&i8259_info); + type_register_static(&i8259_info); } + device_init(pic_register) diff --git a/hw/i8259_common.c b/hw/i8259_common.c new file mode 100644 index 0000000000..9f150bc6d0 --- /dev/null +++ b/hw/i8259_common.c @@ -0,0 +1,161 @@ +/* + * QEMU 8259 - common bits of emulated and KVM kernel model + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "pc.h" +#include "i8259_internal.h" + +void pic_reset_common(PICCommonState *s) +{ + s->last_irr = 0; + s->irr = 0; + s->imr = 0; + s->isr = 0; + s->priority_add = 0; + s->irq_base = 0; + s->read_reg_select = 0; + s->poll = 0; + s->special_mask = 0; + s->init_state = 0; + s->auto_eoi = 0; + s->rotate_on_auto_eoi = 0; + s->special_fully_nested_mode = 0; + s->init4 = 0; + s->single_mode = 0; + /* Note: ELCR is not reset */ +} + +static void pic_dispatch_pre_save(void *opaque) +{ + PICCommonState *s = opaque; + PICCommonClass *info = PIC_COMMON_GET_CLASS(s); + + if (info->pre_save) { + info->pre_save(s); + } +} + +static int pic_dispatch_post_load(void *opaque, int version_id) +{ + PICCommonState *s = opaque; + PICCommonClass *info = PIC_COMMON_GET_CLASS(s); + + if (info->post_load) { + info->post_load(s); + } + return 0; +} + +static int pic_init_common(ISADevice *dev) +{ + PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev); + PICCommonClass *info = PIC_COMMON_GET_CLASS(s); + + info->init(s); + + isa_register_ioport(NULL, &s->base_io, s->iobase); + if (s->elcr_addr != -1) { + isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr); + } + + qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1); + + return 0; +} + +ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master) +{ + ISADevice *dev; + + dev = isa_create(bus, name); + qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0); + qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1); + qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde); + qdev_prop_set_bit(&dev->qdev, "master", master); + qdev_init_nofail(&dev->qdev); + + return dev; +} + +static const VMStateDescription vmstate_pic_common = { + .name = "i8259", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = pic_dispatch_pre_save, + .post_load = pic_dispatch_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(last_irr, PICCommonState), + VMSTATE_UINT8(irr, PICCommonState), + VMSTATE_UINT8(imr, PICCommonState), + VMSTATE_UINT8(isr, PICCommonState), + VMSTATE_UINT8(priority_add, PICCommonState), + VMSTATE_UINT8(irq_base, PICCommonState), + VMSTATE_UINT8(read_reg_select, PICCommonState), + VMSTATE_UINT8(poll, PICCommonState), + VMSTATE_UINT8(special_mask, PICCommonState), + VMSTATE_UINT8(init_state, PICCommonState), + VMSTATE_UINT8(auto_eoi, PICCommonState), + VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState), + VMSTATE_UINT8(special_fully_nested_mode, PICCommonState), + VMSTATE_UINT8(init4, PICCommonState), + VMSTATE_UINT8(single_mode, PICCommonState), + VMSTATE_UINT8(elcr, PICCommonState), + VMSTATE_END_OF_LIST() + } +}; + +static Property pic_properties_common[] = { + DEFINE_PROP_HEX32("iobase", PICCommonState, iobase, -1), + DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr, -1), + DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask, -1), + DEFINE_PROP_BIT("master", PICCommonState, master, 0, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pic_common_class_init(ObjectClass *klass, void *data) +{ + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_pic_common; + dc->no_user = 1; + dc->props = pic_properties_common; + ic->init = pic_init_common; +} + +static TypeInfo pic_common_type = { + .name = TYPE_PIC_COMMON, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(PICCommonState), + .class_size = sizeof(PICCommonClass), + .class_init = pic_common_class_init, + .abstract = true, +}; + +static void register_devices(void) +{ + type_register_static(&pic_common_type); +} + +device_init(register_devices); diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h new file mode 100644 index 0000000000..4137b61703 --- /dev/null +++ b/hw/i8259_internal.h @@ -0,0 +1,82 @@ +/* + * QEMU 8259 - internal interfaces + * + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_I8259_INTERNAL_H +#define QEMU_I8259_INTERNAL_H + +#include "hw.h" +#include "pc.h" +#include "isa.h" + +typedef struct PICCommonState PICCommonState; + +#define TYPE_PIC_COMMON "pic-common" +#define PIC_COMMON(obj) \ + OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON) +#define PIC_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON) +#define PIC_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON) + +typedef struct PICCommonClass +{ + ISADeviceClass parent_class; + void (*init)(PICCommonState *s); + void (*pre_save)(PICCommonState *s); + void (*post_load)(PICCommonState *s); +} PICCommonClass; + +struct PICCommonState { + ISADevice dev; + uint8_t last_irr; /* edge detection */ + uint8_t irr; /* interrupt request register */ + uint8_t imr; /* interrupt mask register */ + uint8_t isr; /* interrupt service register */ + uint8_t priority_add; /* highest irq priority */ + uint8_t irq_base; + uint8_t read_reg_select; + uint8_t poll; + uint8_t special_mask; + uint8_t init_state; + uint8_t auto_eoi; + uint8_t rotate_on_auto_eoi; + uint8_t special_fully_nested_mode; + uint8_t init4; /* true if 4 byte init */ + uint8_t single_mode; /* true if slave pic is not initialized */ + uint8_t elcr; /* PIIX edge/trigger selection*/ + uint8_t elcr_mask; + qemu_irq int_out[1]; + uint32_t master; /* reflects /SP input pin */ + uint32_t iobase; + uint32_t elcr_addr; + MemoryRegion base_io; + MemoryRegion elcr_io; +}; + +void pic_reset_common(PICCommonState *s); + +ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master); + + +#endif /* !QEMU_I8259_INTERNAL_H */ diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 0af201de2f..c87a6ca515 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -25,6 +25,7 @@ #include <hw/msi.h> #include <hw/pc.h> #include <hw/pci.h> +#include <hw/sysbus.h> #include "monitor.h" #include "dma.h" @@ -1214,3 +1215,55 @@ void ahci_reset(void *opaque) ahci_reset_port(&d->ahci, i); } } + +typedef struct SysbusAHCIState { + SysBusDevice busdev; + AHCIState ahci; + uint32_t num_ports; +} SysbusAHCIState; + +static const VMStateDescription vmstate_sysbus_ahci = { + .name = "sysbus-ahci", + .unmigratable = 1, +}; + +static int sysbus_ahci_init(SysBusDevice *dev) +{ + SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev); + ahci_init(&s->ahci, &dev->qdev, s->num_ports); + + sysbus_init_mmio(dev, &s->ahci.mem); + sysbus_init_irq(dev, &s->ahci.irq); + + qemu_register_reset(ahci_reset, &s->ahci); + return 0; +} + +static Property sysbus_ahci_properties[] = { + DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sysbus_ahci_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sbc->init = sysbus_ahci_init; + dc->vmsd = &vmstate_sysbus_ahci; + dc->props = sysbus_ahci_properties; +} + +static TypeInfo sysbus_ahci_info = { + .name = "sysbus-ahci", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysbusAHCIState), + .class_init = sysbus_ahci_class_init, +}; + +static void sysbus_ahci_register(void) +{ + type_register_static(&sysbus_ahci_info); +} + +device_init(sysbus_ahci_register); diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 5fe98b1bb3..a119500f40 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -325,27 +325,34 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, pci_ide_create_devs(dev, hd_table); } -static PCIDeviceInfo cmd646_ide_info[] = { - { - .qdev.name = "cmd646-ide", - .qdev.size = sizeof(PCIIDEState), - .init = pci_cmd646_ide_initfn, - .exit = pci_cmd646_ide_exitfn, - .vendor_id = PCI_VENDOR_ID_CMD, - .device_id = PCI_DEVICE_ID_CMD_646, - .revision = 0x07, // IDE controller revision - .class_id = PCI_CLASS_STORAGE_IDE, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), - DEFINE_PROP_END_OF_LIST(), - }, - },{ - /* end of list */ - } +static Property cmd646_ide_properties[] = { + DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void cmd646_ide_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_cmd646_ide_initfn; + k->exit = pci_cmd646_ide_exitfn; + k->vendor_id = PCI_VENDOR_ID_CMD; + k->device_id = PCI_DEVICE_ID_CMD_646; + k->revision = 0x07; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->props = cmd646_ide_properties; +} + +static TypeInfo cmd646_ide_info = { + .name = "cmd646-ide", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = cmd646_ide_class_init, }; static void cmd646_ide_register(void) { - pci_qdev_register_many(cmd646_ide_info); + type_register_static(&cmd646_ide_info); } device_init(cmd646_ide_register); diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 3f7510f52e..5cdaa990ea 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -146,26 +146,30 @@ static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr, msi_write_config(pci, addr, val, len); } -static PCIDeviceInfo ich_ahci_info[] = { - { - .qdev.name = "ich9-ahci", - .qdev.alias = "ahci", - .qdev.size = sizeof(AHCIPCIState), - .qdev.vmsd = &vmstate_ahci, - .init = pci_ich9_ahci_init, - .exit = pci_ich9_uninit, - .config_write = pci_ich9_write_config, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801IR, - .revision = 0x02, - .class_id = PCI_CLASS_STORAGE_SATA, - },{ - /* end of list */ - } +static void ich_ahci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_ich9_ahci_init; + k->exit = pci_ich9_uninit; + k->config_write = pci_ich9_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801IR; + k->revision = 0x02; + k->class_id = PCI_CLASS_STORAGE_SATA; + dc->vmsd = &vmstate_ahci; +} + +static TypeInfo ich_ahci_info = { + .name = "ich9-ahci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(AHCIPCIState), + .class_init = ich_ahci_class_init, }; static void ich_ahci_register(void) { - pci_qdev_register_many(ich_ahci_info); + type_register_static(&ich_ahci_info); } device_init(ich_ahci_register); diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 00b28dfdbc..c808a0ddf8 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -21,7 +21,6 @@ typedef struct IDEBus IDEBus; typedef struct IDEDevice IDEDevice; -typedef struct IDEDeviceInfo IDEDeviceInfo; typedef struct IDEState IDEState; typedef struct IDEDMA IDEDMA; typedef struct IDEDMAOps IDEDMAOps; @@ -450,6 +449,19 @@ struct IDEBus { int error_status; }; +#define TYPE_IDE_DEVICE "ide-device" +#define IDE_DEVICE(obj) \ + OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE) +#define IDE_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE) +#define IDE_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE) + +typedef struct IDEDeviceClass { + DeviceClass parent_class; + int (*init)(IDEDevice *dev); +} IDEDeviceClass; + struct IDEDevice { DeviceState qdev; uint32_t unit; @@ -458,12 +470,6 @@ struct IDEDevice { char *serial; }; -typedef int (*ide_qdev_initfn)(IDEDevice *dev); -struct IDEDeviceInfo { - DeviceInfo qdev; - ide_qdev_initfn init; -}; - #define BM_STATUS_DMAING 0x01 #define BM_STATUS_ERROR 0x02 #define BM_STATUS_INT 0x04 diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 219f3a4c6b..a0bcb43eba 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -94,23 +94,33 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, return dev; } -static ISADeviceInfo isa_ide_info = { - .qdev.name = "isa-ide", - .qdev.fw_name = "ide", - .qdev.size = sizeof(ISAIDEState), - .init = isa_ide_initfn, - .qdev.reset = isa_ide_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0), - DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6), - DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14), - DEFINE_PROP_END_OF_LIST(), - }, +static Property isa_ide_properties[] = { + DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0), + DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6), + DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14), + DEFINE_PROP_END_OF_LIST(), +}; + +static void isa_ide_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = isa_ide_initfn; + dc->fw_name = "ide"; + dc->reset = isa_ide_reset; + dc->props = isa_ide_properties; +} + +static TypeInfo isa_ide_info = { + .name = "isa-ide", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISAIDEState), + .class_init = isa_ide_class_initfn, }; static void isa_ide_register_devices(void) { - isa_qdev_register(&isa_ide_info); + type_register_static(&isa_ide_info); } device_init(isa_ide_register_devices) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index cb3de6537b..246dd5704b 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -327,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) bm->cmd = val & 0x09; } -static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr, +static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, unsigned width) { BMDMAState *bm = opaque; @@ -341,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr, return data; } -static void bmdma_addr_write(void *opaque, dma_addr_t addr, +static void bmdma_addr_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned width) { BMDMAState *bm = opaque; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 34733454ea..bf4465bb49 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -195,7 +195,6 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) PCIDevice *dev; dev = pci_create_simple(bus, devfn, "piix3-ide-xen"); - dev->qdev.info->unplug = pci_piix3_xen_ide_unplug; pci_ide_create_devs(dev, hd_table); return dev; } @@ -238,42 +237,72 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) return dev; } -static PCIDeviceInfo piix_ide_info[] = { - { - .qdev.name = "piix3-ide", - .qdev.size = sizeof(PCIIDEState), - .qdev.no_user = 1, - .no_hotplug = 1, - .init = pci_piix_ide_initfn, - .exit = pci_piix_ide_exitfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371SB_1, - .class_id = PCI_CLASS_STORAGE_IDE, - },{ - .qdev.name = "piix3-ide-xen", - .qdev.size = sizeof(PCIIDEState), - .qdev.no_user = 1, - .init = pci_piix_ide_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371SB_1, - .class_id = PCI_CLASS_STORAGE_IDE, - },{ - .qdev.name = "piix4-ide", - .qdev.size = sizeof(PCIIDEState), - .qdev.no_user = 1, - .no_hotplug = 1, - .init = pci_piix_ide_initfn, - .exit = pci_piix_ide_exitfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371AB, - .class_id = PCI_CLASS_STORAGE_IDE, - },{ - /* end of list */ - } +static void piix3_ide_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = pci_piix_ide_initfn; + k->exit = pci_piix_ide_exitfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->no_user = 1; +} + +static TypeInfo piix3_ide_info = { + .name = "piix3-ide", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = piix3_ide_class_init, +}; + +static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_piix_ide_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->no_user = 1; + dc->unplug = pci_piix3_xen_ide_unplug; +} + +static TypeInfo piix3_ide_xen_info = { + .name = "piix3-ide-xen", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = piix3_ide_xen_class_init, +}; + +static void piix4_ide_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = pci_piix_ide_initfn; + k->exit = pci_piix_ide_exitfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->no_user = 1; +} + +static TypeInfo piix4_ide_info = { + .name = "piix4-ide", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = piix4_ide_class_init, }; static void piix_ide_register(void) { - pci_qdev_register_many(piix_ide_info); + type_register_static(&piix3_ide_info); + type_register_static(&piix3_ide_xen_info); + type_register_static(&piix4_ide_info); } device_init(piix_ide_register); diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 42071277bb..1640616906 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -53,10 +53,10 @@ static char *idebus_get_fw_dev_path(DeviceState *dev) return strdup(path); } -static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int ide_qdev_init(DeviceState *qdev) { - IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev); - IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base); + IDEDevice *dev = IDE_DEVICE(qdev); + IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev); IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus); if (!dev->conf.bs) { @@ -85,19 +85,12 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base) error_report("Invalid IDE unit %d", dev->unit); goto err; } - return info->init(dev); + return dc->init(dev); err: return -1; } -static void ide_qdev_register(IDEDeviceInfo *info) -{ - info->qdev.init = ide_qdev_init; - info->qdev.bus_info = &ide_bus_info; - qdev_register(&info->qdev); -} - IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive) { DeviceState *dev; @@ -182,46 +175,93 @@ static int ide_drive_initfn(IDEDevice *dev) DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \ DEFINE_PROP_STRING("serial", IDEDrive, dev.serial) -static IDEDeviceInfo ide_dev_info[] = { - { - .qdev.name = "ide-hd", - .qdev.fw_name = "drive", - .qdev.desc = "virtual IDE disk", - .qdev.size = sizeof(IDEDrive), - .init = ide_hd_initfn, - .qdev.props = (Property[]) { - DEFINE_IDE_DEV_PROPERTIES(), - DEFINE_PROP_END_OF_LIST(), - } - },{ - .qdev.name = "ide-cd", - .qdev.fw_name = "drive", - .qdev.desc = "virtual IDE CD-ROM", - .qdev.size = sizeof(IDEDrive), - .init = ide_cd_initfn, - .qdev.props = (Property[]) { - DEFINE_IDE_DEV_PROPERTIES(), - DEFINE_PROP_END_OF_LIST(), - } - },{ - .qdev.name = "ide-drive", /* legacy -device ide-drive */ - .qdev.fw_name = "drive", - .qdev.desc = "virtual IDE disk or CD-ROM (legacy)", - .qdev.size = sizeof(IDEDrive), - .init = ide_drive_initfn, - .qdev.props = (Property[]) { - DEFINE_IDE_DEV_PROPERTIES(), - DEFINE_PROP_END_OF_LIST(), - } - } +static Property ide_hd_properties[] = { + DEFINE_IDE_DEV_PROPERTIES(), + DEFINE_PROP_END_OF_LIST(), }; -static void ide_dev_register(void) +static void ide_hd_class_init(ObjectClass *klass, void *data) { - int i; + DeviceClass *dc = DEVICE_CLASS(klass); + IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); + k->init = ide_hd_initfn; + dc->fw_name = "drive"; + dc->desc = "virtual IDE disk"; + dc->props = ide_hd_properties; +} - for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) { - ide_qdev_register(&ide_dev_info[i]); - } +static TypeInfo ide_hd_info = { + .name = "ide-hd", + .parent = TYPE_IDE_DEVICE, + .instance_size = sizeof(IDEDrive), + .class_init = ide_hd_class_init, +}; + +static Property ide_cd_properties[] = { + DEFINE_IDE_DEV_PROPERTIES(), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ide_cd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); + k->init = ide_cd_initfn; + dc->fw_name = "drive"; + dc->desc = "virtual IDE CD-ROM"; + dc->props = ide_cd_properties; +} + +static TypeInfo ide_cd_info = { + .name = "ide-cd", + .parent = TYPE_IDE_DEVICE, + .instance_size = sizeof(IDEDrive), + .class_init = ide_cd_class_init, +}; + +static Property ide_drive_properties[] = { + DEFINE_IDE_DEV_PROPERTIES(), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ide_drive_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); + k->init = ide_drive_initfn; + dc->fw_name = "drive"; + dc->desc = "virtual IDE disk or CD-ROM (legacy)"; + dc->props = ide_drive_properties; +} + +static TypeInfo ide_drive_info = { + .name = "ide-drive", + .parent = TYPE_IDE_DEVICE, + .instance_size = sizeof(IDEDrive), + .class_init = ide_drive_class_init, +}; + +static void ide_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = ide_qdev_init; + k->bus_info = &ide_bus_info; +} + +static TypeInfo ide_device_type_info = { + .name = TYPE_IDE_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(IDEDevice), + .abstract = true, + .class_size = sizeof(IDEDeviceClass), + .class_init = ide_device_class_init, +}; + +static void ide_dev_register(void) +{ + type_register_static(&ide_hd_info); + type_register_static(&ide_cd_info); + type_register_static(&ide_drive_info); + type_register_static(&ide_device_type_info); } device_init(ide_dev_register); diff --git a/hw/ide/via.c b/hw/ide/via.c index 4ea2064498..b4ca6f27b3 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -213,20 +213,29 @@ void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) pci_ide_create_devs(dev, hd_table); } -static PCIDeviceInfo via_ide_info = { - .qdev.name = "via-ide", - .qdev.size = sizeof(PCIIDEState), - .qdev.no_user = 1, - .init = vt82c686b_ide_initfn, - .exit = vt82c686b_ide_exitfn, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_IDE, - .revision = 0x06, - .class_id = PCI_CLASS_STORAGE_IDE, +static void via_ide_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = vt82c686b_ide_initfn; + k->exit = vt82c686b_ide_exitfn; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_IDE; + k->revision = 0x06; + k->class_id = PCI_CLASS_STORAGE_IDE; + dc->no_user = 1; +} + +static TypeInfo via_ide_info = { + .name = "via-ide", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIIDEState), + .class_init = via_ide_class_init, }; static void via_ide_register(void) { - pci_qdev_register(&via_ide_info); + type_register_static(&via_ide_info); } device_init(via_ide_register); diff --git a/hw/integratorcp.c b/hw/integratorcp.c index e5712fc3e7..6dbd649908 100644 --- a/hw/integratorcp.c +++ b/hw/integratorcp.c @@ -518,20 +518,45 @@ static void integratorcp_machine_init(void) machine_init(integratorcp_machine_init); -static SysBusDeviceInfo core_info = { - .init = integratorcm_init, - .qdev.name = "integrator_core", - .qdev.size = sizeof(integratorcm_state), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property core_properties[] = { + DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void core_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = integratorcm_init; + dc->props = core_properties; +} + +static TypeInfo core_info = { + .name = "integrator_core", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(integratorcm_state), + .class_init = core_class_init, +}; + +static void icp_pic_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = icp_pic_init; +} + +static TypeInfo icp_pic_info = { + .name = "integrator_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(icp_pic_state), + .class_init = icp_pic_class_init, }; static void integratorcp_register_devices(void) { - sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init); - sysbus_register_withprop(&core_info); + type_register_static(&icp_pic_info); + type_register_static(&core_info); } device_init(integratorcp_register_devices) diff --git a/hw/intel-hda.c b/hw/intel-hda.c index 10769e0f49..83c42d58b6 100644 --- a/hw/intel-hda.c +++ b/hw/intel-hda.c @@ -47,13 +47,12 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, bus->xfer = xfer; } -static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) +static int hda_codec_dev_init(DeviceState *qdev) { HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus); HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); - HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base); + HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); - dev->info = info; if (dev->cad == -1) { dev->cad = bus->next_cad; } @@ -61,27 +60,20 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base) return -1; } bus->next_cad = dev->cad + 1; - return info->init(dev); + return cdc->init(dev); } static int hda_codec_dev_exit(DeviceState *qdev) { HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); + HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); - if (dev->info->exit) { - dev->info->exit(dev); + if (cdc->exit) { + cdc->exit(dev); } return 0; } -void hda_codec_register(HDACodecDeviceInfo *info) -{ - info->qdev.init = hda_codec_dev_init; - info->qdev.exit = hda_codec_dev_exit; - info->qdev.bus_info = &hda_codec_bus_info; - qdev_register(&info->qdev); -} - HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) { DeviceState *qdev; @@ -283,6 +275,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) { uint32_t cad, nid, data; HDACodecDevice *codec; + HDACodecDeviceClass *cdc; cad = (verb >> 28) & 0x0f; if (verb & (1 << 27)) { @@ -298,7 +291,8 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__); return -1; } - codec->info->command(codec, nid, data); + cdc = HDA_CODEC_DEVICE_GET_CLASS(codec); + cdc->command(codec, nid, data); return 0; } @@ -491,9 +485,12 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn HDACodecDevice *cdev; QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) { + HDACodecDeviceClass *cdc; + cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); - if (cdev->info->stream) { - cdev->info->stream(cdev, stream, running, output); + cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev); + if (cdc->stream) { + cdc->stream(cdev, stream, running, output); } } } @@ -1116,9 +1113,7 @@ static void intel_hda_reset(DeviceState *dev) /* reset codecs */ QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) { cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); - if (qdev->info->reset) { - qdev->info->reset(qdev); - } + device_reset(DEVICE(cdev)); d->state_sts |= (1 << cdev->cad); } intel_hda_update_irq(d); @@ -1129,7 +1124,7 @@ static int intel_hda_init(PCIDevice *pci) IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci); uint8_t *conf = d->pci.config; - d->name = d->pci.qdev.info->name; + d->name = object_get_typename(OBJECT(d)); pci_config_set_interrupt_pin(conf, 1); @@ -1244,29 +1239,58 @@ static const VMStateDescription vmstate_intel_hda = { } }; -static PCIDeviceInfo intel_hda_info = { - .qdev.name = "intel-hda", - .qdev.desc = "Intel HD Audio Controller", - .qdev.size = sizeof(IntelHDAState), - .qdev.vmsd = &vmstate_intel_hda, - .qdev.reset = intel_hda_reset, - .init = intel_hda_init, - .exit = intel_hda_exit, - .config_write = intel_hda_write_config, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = 0x2668, - .revision = 1, - .class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), - DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), - DEFINE_PROP_END_OF_LIST(), - } +static Property intel_hda_properties[] = { + DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), + DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void intel_hda_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = intel_hda_init; + k->exit = intel_hda_exit; + k->config_write = intel_hda_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = 0x2668; + k->revision = 1; + k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO; + dc->desc = "Intel HD Audio Controller"; + dc->reset = intel_hda_reset; + dc->vmsd = &vmstate_intel_hda; + dc->props = intel_hda_properties; +} + +static TypeInfo intel_hda_info = { + .name = "intel-hda", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(IntelHDAState), + .class_init = intel_hda_class_init, +}; + +static void hda_codec_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = hda_codec_dev_init; + k->exit = hda_codec_dev_exit; + k->bus_info = &hda_codec_bus_info; +} + +static TypeInfo hda_codec_device_type_info = { + .name = TYPE_HDA_CODEC_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(HDACodecDevice), + .abstract = true, + .class_size = sizeof(HDACodecDeviceClass), + .class_init = hda_codec_device_class_init, }; static void intel_hda_register(void) { - pci_qdev_register(&intel_hda_info); + type_register_static(&intel_hda_info); + type_register_static(&hda_codec_device_type_info); } device_init(intel_hda_register); diff --git a/hw/intel-hda.h b/hw/intel-hda.h index 65fd2a85bb..a1cca5b1bb 100644 --- a/hw/intel-hda.h +++ b/hw/intel-hda.h @@ -6,9 +6,16 @@ /* --------------------------------------------------------------------- */ /* hda bus */ +#define TYPE_HDA_CODEC_DEVICE "hda-codec" +#define HDA_CODEC_DEVICE(obj) \ + OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE) +#define HDA_CODEC_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE) +#define HDA_CODEC_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE) + typedef struct HDACodecBus HDACodecBus; typedef struct HDACodecDevice HDACodecDevice; -typedef struct HDACodecDeviceInfo HDACodecDeviceInfo; typedef void (*hda_codec_response_func)(HDACodecDevice *dev, bool solicited, uint32_t response); @@ -23,24 +30,24 @@ struct HDACodecBus { hda_codec_xfer_func xfer; }; -struct HDACodecDevice { - DeviceState qdev; - HDACodecDeviceInfo *info; - uint32_t cad; /* codec address */ -}; +typedef struct HDACodecDeviceClass +{ + DeviceClass parent_class; -struct HDACodecDeviceInfo { - DeviceInfo qdev; int (*init)(HDACodecDevice *dev); int (*exit)(HDACodecDevice *dev); void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output); +} HDACodecDeviceClass; + +struct HDACodecDevice { + DeviceState qdev; + uint32_t cad; /* codec address */ }; void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, hda_codec_response_func response, hda_codec_xfer_func xfer); -void hda_codec_register(HDACodecDeviceInfo *info); HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad); void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response); diff --git a/hw/ioapic.c b/hw/ioapic.c index 27b07c6317..79549f8ed1 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -24,9 +24,7 @@ #include "pc.h" #include "apic.h" #include "ioapic.h" -#include "qemu-timer.h" -#include "host-utils.h" -#include "sysbus.h" +#include "ioapic_internal.h" //#define DEBUG_IOAPIC @@ -37,65 +35,9 @@ #define DPRINTF(fmt, ...) #endif -#define MAX_IOAPICS 1 +static IOAPICCommonState *ioapics[MAX_IOAPICS]; -#define IOAPIC_VERSION 0x11 - -#define IOAPIC_LVT_DEST_SHIFT 56 -#define IOAPIC_LVT_MASKED_SHIFT 16 -#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 -#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 -#define IOAPIC_LVT_POLARITY_SHIFT 13 -#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 -#define IOAPIC_LVT_DEST_MODE_SHIFT 11 -#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 - -#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) -#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) - -#define IOAPIC_TRIGGER_EDGE 0 -#define IOAPIC_TRIGGER_LEVEL 1 - -/*io{apic,sapic} delivery mode*/ -#define IOAPIC_DM_FIXED 0x0 -#define IOAPIC_DM_LOWEST_PRIORITY 0x1 -#define IOAPIC_DM_PMI 0x2 -#define IOAPIC_DM_NMI 0x4 -#define IOAPIC_DM_INIT 0x5 -#define IOAPIC_DM_SIPI 0x6 -#define IOAPIC_DM_EXTINT 0x7 -#define IOAPIC_DM_MASK 0x7 - -#define IOAPIC_VECTOR_MASK 0xff - -#define IOAPIC_IOREGSEL 0x00 -#define IOAPIC_IOWIN 0x10 - -#define IOAPIC_REG_ID 0x00 -#define IOAPIC_REG_VER 0x01 -#define IOAPIC_REG_ARB 0x02 -#define IOAPIC_REG_REDTBL_BASE 0x10 -#define IOAPIC_ID 0x00 - -#define IOAPIC_ID_SHIFT 24 -#define IOAPIC_ID_MASK 0xf - -#define IOAPIC_VER_ENTRIES_SHIFT 16 - -typedef struct IOAPICState IOAPICState; - -struct IOAPICState { - SysBusDevice busdev; - MemoryRegion io_memory; - uint8_t id; - uint8_t ioregsel; - uint32_t irr; - uint64_t ioredtbl[IOAPIC_NUM_PINS]; -}; - -static IOAPICState *ioapics[MAX_IOAPICS]; - -static void ioapic_service(IOAPICState *s) +static void ioapic_service(IOAPICCommonState *s) { uint8_t i; uint8_t trig_mode; @@ -135,7 +77,7 @@ static void ioapic_service(IOAPICState *s) static void ioapic_set_irq(void *opaque, int vector, int level) { - IOAPICState *s = opaque; + IOAPICCommonState *s = opaque; /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps * to GSI 2. GSI maps to ioapic 1-1. This is not @@ -174,7 +116,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level) void ioapic_eoi_broadcast(int vector) { - IOAPICState *s; + IOAPICCommonState *s; uint64_t entry; int i, n; @@ -199,7 +141,7 @@ void ioapic_eoi_broadcast(int vector) static uint64_t ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size) { - IOAPICState *s = opaque; + IOAPICCommonState *s = opaque; int index; uint32_t val = 0; @@ -242,7 +184,7 @@ static void ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, unsigned int size) { - IOAPICState *s = opaque; + IOAPICCommonState *s = opaque; int index; switch (addr & 0xff) { @@ -278,83 +220,40 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, } } -static int ioapic_post_load(void *opaque, int version_id) -{ - IOAPICState *s = opaque; - - if (version_id == 1) { - /* set sane value */ - s->irr = 0; - } - return 0; -} - -static const VMStateDescription vmstate_ioapic = { - .name = "ioapic", - .version_id = 3, - .post_load = ioapic_post_load, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(id, IOAPICState), - VMSTATE_UINT8(ioregsel, IOAPICState), - VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */ - VMSTATE_UINT32_V(irr, IOAPICState, 2), - VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS), - VMSTATE_END_OF_LIST() - } -}; - -static void ioapic_reset(DeviceState *d) -{ - IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d); - int i; - - s->id = 0; - s->ioregsel = 0; - s->irr = 0; - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; - } -} - static const MemoryRegionOps ioapic_io_ops = { .read = ioapic_mem_read, .write = ioapic_mem_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -static int ioapic_init1(SysBusDevice *dev) +static void ioapic_init(IOAPICCommonState *s, int instance_no) { - IOAPICState *s = FROM_SYSBUS(IOAPICState, dev); - static int ioapic_no; - - if (ioapic_no >= MAX_IOAPICS) { - return -1; - } - memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000); - sysbus_init_mmio(dev, &s->io_memory); - qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS); + qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS); + + ioapics[instance_no] = s; +} - ioapics[ioapic_no++] = s; +static void ioapic_class_init(ObjectClass *klass, void *data) +{ + IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); - return 0; + k->init = ioapic_init; + dc->reset = ioapic_reset_common; } -static SysBusDeviceInfo ioapic_info = { - .init = ioapic_init1, - .qdev.name = "ioapic", - .qdev.size = sizeof(IOAPICState), - .qdev.vmsd = &vmstate_ioapic, - .qdev.reset = ioapic_reset, - .qdev.no_user = 1, +static TypeInfo ioapic_info = { + .name = "ioapic", + .parent = TYPE_IOAPIC_COMMON, + .instance_size = sizeof(IOAPICCommonState), + .class_init = ioapic_class_init, }; static void ioapic_register_devices(void) { - sysbus_register_withprop(&ioapic_info); + type_register_static(&ioapic_info); } device_init(ioapic_register_devices) diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c new file mode 100644 index 0000000000..f932700d12 --- /dev/null +++ b/hw/ioapic_common.c @@ -0,0 +1,121 @@ +/* + * IOAPIC emulation logic - common bits of emulated and KVM kernel model + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2009 Xiantao Zhang, Intel + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "ioapic.h" +#include "ioapic_internal.h" +#include "sysbus.h" + +void ioapic_reset_common(DeviceState *dev) +{ + IOAPICCommonState *s = IOAPIC_COMMON(dev); + int i; + + s->id = 0; + s->ioregsel = 0; + s->irr = 0; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; + } +} + +static void ioapic_dispatch_pre_save(void *opaque) +{ + IOAPICCommonState *s = IOAPIC_COMMON(opaque); + IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s); + + if (info->pre_save) { + info->pre_save(s); + } +} + +static int ioapic_dispatch_post_load(void *opaque, int version_id) +{ + IOAPICCommonState *s = IOAPIC_COMMON(opaque); + IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s); + + if (info->post_load) { + info->post_load(s); + } + return 0; +} + +static int ioapic_init_common(SysBusDevice *dev) +{ + IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev); + IOAPICCommonClass *info; + static int ioapic_no; + + if (ioapic_no >= MAX_IOAPICS) { + return -1; + } + + info = IOAPIC_COMMON_GET_CLASS(s); + info->init(s, ioapic_no); + + sysbus_init_mmio(&s->busdev, &s->io_memory); + ioapic_no++; + + return 0; +} + +static const VMStateDescription vmstate_ioapic_common = { + .name = "ioapic", + .version_id = 3, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = ioapic_dispatch_pre_save, + .post_load = ioapic_dispatch_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(id, IOAPICCommonState), + VMSTATE_UINT8(ioregsel, IOAPICCommonState), + VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */ + VMSTATE_UINT32_V(irr, IOAPICCommonState, 2), + VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS), + VMSTATE_END_OF_LIST() + } +}; + +static void ioapic_common_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sc->init = ioapic_init_common; + dc->vmsd = &vmstate_ioapic_common; + dc->no_user = 1; +} + +static TypeInfo ioapic_common_type = { + .name = TYPE_IOAPIC_COMMON, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOAPICCommonState), + .class_size = sizeof(IOAPICCommonClass), + .class_init = ioapic_common_class_init, + .abstract = true, +}; + +static void register_devices(void) +{ + type_register_static(&ioapic_common_type); +} + +device_init(register_devices); + diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h new file mode 100644 index 0000000000..e04c9f3c12 --- /dev/null +++ b/hw/ioapic_internal.h @@ -0,0 +1,102 @@ +/* + * IOAPIC emulation logic - internal interfaces + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2009 Xiantao Zhang, Intel + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_IOAPIC_INTERNAL_H +#define QEMU_IOAPIC_INTERNAL_H + +#include "hw.h" +#include "memory.h" +#include "sysbus.h" + +#define MAX_IOAPICS 1 + +#define IOAPIC_VERSION 0x11 + +#define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_MASKED_SHIFT 16 +#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 +#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 +#define IOAPIC_LVT_POLARITY_SHIFT 13 +#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 +#define IOAPIC_LVT_DEST_MODE_SHIFT 11 +#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 + +#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) +#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) + +#define IOAPIC_TRIGGER_EDGE 0 +#define IOAPIC_TRIGGER_LEVEL 1 + +/*io{apic,sapic} delivery mode*/ +#define IOAPIC_DM_FIXED 0x0 +#define IOAPIC_DM_LOWEST_PRIORITY 0x1 +#define IOAPIC_DM_PMI 0x2 +#define IOAPIC_DM_NMI 0x4 +#define IOAPIC_DM_INIT 0x5 +#define IOAPIC_DM_SIPI 0x6 +#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_MASK 0x7 + +#define IOAPIC_VECTOR_MASK 0xff + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 +#define IOAPIC_REG_REDTBL_BASE 0x10 +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0xf + +#define IOAPIC_VER_ENTRIES_SHIFT 16 + +typedef struct IOAPICCommonState IOAPICCommonState; + +#define TYPE_IOAPIC_COMMON "ioapic-common" +#define IOAPIC_COMMON(obj) \ + OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON) +#define IOAPIC_COMMON_CLASS(klass) \ + OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON) +#define IOAPIC_COMMON_GET_CLASS(obj) \ + OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON) + +typedef struct IOAPICCommonClass { + SysBusDeviceClass parent_class; + void (*init)(IOAPICCommonState *s, int instance_no); + void (*pre_save)(IOAPICCommonState *s); + void (*post_load)(IOAPICCommonState *s); +} IOAPICCommonClass; + +struct IOAPICCommonState { + SysBusDevice busdev; + MemoryRegion io_memory; + uint8_t id; + uint8_t ioregsel; + uint32_t irr; + uint64_t ioredtbl[IOAPIC_NUM_PINS]; +}; + +void ioapic_reset_common(DeviceState *dev); + +#endif /* !QEMU_IOAPIC_INTERNAL_H */ diff --git a/hw/ioh3420.c b/hw/ioh3420.c index a6bfbb9173..1c60123d43 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -80,7 +80,7 @@ static void ioh3420_write_config(PCIDevice *d, static void ioh3420_reset(DeviceState *qdev) { - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *d = PCI_DEVICE(qdev); msi_reset(d); ioh3420_aer_vector_update(d); pcie_cap_root_reset(d); @@ -201,36 +201,45 @@ static const VMStateDescription vmstate_ioh3420 = { } }; -static PCIDeviceInfo ioh3420_info = { - .qdev.name = "ioh3420", - .qdev.desc = "Intel IOH device id 3420 PCIE Root Port", - .qdev.size = sizeof(PCIESlot), - .qdev.reset = ioh3420_reset, - .qdev.vmsd = &vmstate_ioh3420, - - .is_express = 1, - .is_bridge = 1, - .config_write = ioh3420_write_config, - .init = ioh3420_initfn, - .exit = ioh3420_exitfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_IOH_EPORT, - .revision = PCI_DEVICE_ID_IOH_REV, - - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), - DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), - DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIESlot, - port.br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), - } +static Property ioh3420_properties[] = { + DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), + DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), + DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), + DEFINE_PROP_UINT16("aer_log_max", PCIESlot, + port.br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ioh3420_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->is_express = 1; + k->is_bridge = 1; + k->config_write = ioh3420_write_config; + k->init = ioh3420_initfn; + k->exit = ioh3420_exitfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_IOH_EPORT; + k->revision = PCI_DEVICE_ID_IOH_REV; + dc->desc = "Intel IOH device id 3420 PCIE Root Port"; + dc->reset = ioh3420_reset; + dc->vmsd = &vmstate_ioh3420; + dc->props = ioh3420_properties; +} + +static TypeInfo ioh3420_info = { + .name = "ioh3420", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIESlot), + .class_init = ioh3420_class_init, }; static void ioh3420_register(void) { - pci_qdev_register(&ioh3420_info); + type_register_static(&ioh3420_info); } device_init(ioh3420_register); diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 5af790bf81..d03f82824c 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -110,22 +110,19 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start, portio_list_add(piolist, isabus->address_space_io, start); } -static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int isa_qdev_init(DeviceState *qdev) { - ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev); - ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base); + ISADevice *dev = ISA_DEVICE(qdev); + ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev); dev->isairq[0] = -1; dev->isairq[1] = -1; - return info->init(dev); -} + if (klass->init) { + return klass->init(dev); + } -void isa_qdev_register(ISADeviceInfo *info) -{ - info->qdev.init = isa_qdev_init; - info->qdev.bus_info = &isa_bus_info; - qdev_register(&info->qdev); + return 0; } ISADevice *isa_create(ISABus *bus, const char *name) @@ -137,7 +134,7 @@ ISADevice *isa_create(ISABus *bus, const char *name) name); } dev = qdev_create(&bus->qbus, name); - return DO_UPCAST(ISADevice, qdev, dev); + return ISA_DEVICE(dev); } ISADevice *isa_try_create(ISABus *bus, const char *name) @@ -149,7 +146,7 @@ ISADevice *isa_try_create(ISABus *bus, const char *name) name); } dev = qdev_try_create(&bus->qbus, name); - return DO_UPCAST(ISADevice, qdev, dev); + return ISA_DEVICE(dev); } ISADevice *isa_create_simple(ISABus *bus, const char *name) @@ -163,7 +160,7 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name) static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent) { - ISADevice *d = DO_UPCAST(ISADevice, qdev, dev); + ISADevice *d = ISA_DEVICE(dev); if (d->isairq[1] != -1) { monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "", @@ -180,17 +177,43 @@ static int isabus_bridge_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo isabus_bridge_info = { - .init = isabus_bridge_init, - .qdev.name = "isabus-bridge", - .qdev.fw_name = "isa", - .qdev.size = sizeof(SysBusDevice), - .qdev.no_user = 1, +static void isabus_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = isabus_bridge_init; + dc->fw_name = "isa"; + dc->no_user = 1; +} + +static TypeInfo isabus_bridge_info = { + .name = "isabus-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = isabus_bridge_class_init, +}; + +static void isa_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = isa_qdev_init; + k->bus_info = &isa_bus_info; +} + +static TypeInfo isa_device_type_info = { + .name = TYPE_ISA_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ISADevice), + .abstract = true, + .class_size = sizeof(ISADeviceClass), + .class_init = isa_device_class_init, }; static void isabus_register_devices(void) { - sysbus_register_withprop(&isabus_bridge_info); + type_register_static(&isabus_bridge_info); + type_register_static(&isa_device_type_info); } static char *isabus_get_fw_dev_path(DeviceState *dev) @@ -10,7 +10,19 @@ #define ISA_NUM_IRQS 16 typedef struct ISADevice ISADevice; -typedef struct ISADeviceInfo ISADeviceInfo; + +#define TYPE_ISA_DEVICE "isa-device" +#define ISA_DEVICE(obj) \ + OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE) +#define ISA_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(ISADeviceClass, (klass), TYPE_ISA_DEVICE) +#define ISA_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE) + +typedef struct ISADeviceClass { + DeviceClass parent_class; + int (*init)(ISADevice *dev); +} ISADeviceClass; struct ISABus { BusState qbus; @@ -25,17 +37,10 @@ struct ISADevice { int ioport_id; }; -typedef int (*isa_qdev_initfn)(ISADevice *dev); -struct ISADeviceInfo { - DeviceInfo qdev; - isa_qdev_initfn init; -}; - ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io); void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); -void isa_qdev_register(ISADeviceInfo *info); MemoryRegion *isa_address_space(ISADevice *dev); ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); diff --git a/hw/ivshmem.c b/hw/ivshmem.c index bec2e0b8fe..6f017d474c 100644 --- a/hw/ivshmem.c +++ b/hw/ivshmem.c @@ -766,30 +766,41 @@ static int pci_ivshmem_uninit(PCIDevice *dev) return 0; } -static PCIDeviceInfo ivshmem_info = { - .qdev.name = "ivshmem", - .qdev.size = sizeof(IVShmemState), - .qdev.reset = ivshmem_reset, - .init = pci_ivshmem_init, - .exit = pci_ivshmem_uninit, - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = 0x1110, - .class_id = PCI_CLASS_MEMORY_RAM, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", IVShmemState, server_chr), - DEFINE_PROP_STRING("size", IVShmemState, sizearg), - DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1), - DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false), - DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true), - DEFINE_PROP_STRING("shm", IVShmemState, shmobj), - DEFINE_PROP_STRING("role", IVShmemState, role), - DEFINE_PROP_END_OF_LIST(), - } +static Property ivshmem_properties[] = { + DEFINE_PROP_CHR("chardev", IVShmemState, server_chr), + DEFINE_PROP_STRING("size", IVShmemState, sizearg), + DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1), + DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false), + DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true), + DEFINE_PROP_STRING("shm", IVShmemState, shmobj), + DEFINE_PROP_STRING("role", IVShmemState, role), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ivshmem_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_ivshmem_init; + k->exit = pci_ivshmem_uninit; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = 0x1110; + k->class_id = PCI_CLASS_MEMORY_RAM; + dc->reset = ivshmem_reset; + dc->props = ivshmem_properties; +} + +static TypeInfo ivshmem_info = { + .name = "ivshmem", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(IVShmemState), + .class_init = ivshmem_class_init, }; static void ivshmem_register_devices(void) { - pci_qdev_register(&ivshmem_info); + type_register_static(&ivshmem_info); } device_init(ivshmem_register_devices) diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c new file mode 100644 index 0000000000..dfc2ab3b03 --- /dev/null +++ b/hw/kvm/apic.c @@ -0,0 +1,147 @@ +/* + * KVM in-kernel APIC support + * + * Copyright (c) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + */ +#include "hw/apic_internal.h" +#include "kvm.h" + +static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, + int reg_id, uint32_t val) +{ + *((uint32_t *)(kapic->regs + (reg_id << 4))) = val; +} + +static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic, + int reg_id) +{ + return *((uint32_t *)(kapic->regs + (reg_id << 4))); +} + +void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) +{ + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); + int i; + + memset(kapic, 0, sizeof(kapic)); + kvm_apic_set_reg(kapic, 0x2, s->id << 24); + kvm_apic_set_reg(kapic, 0x8, s->tpr); + kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24); + kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff); + kvm_apic_set_reg(kapic, 0xf, s->spurious_vec); + for (i = 0; i < 8; i++) { + kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]); + kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]); + kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]); + } + kvm_apic_set_reg(kapic, 0x28, s->esr); + kvm_apic_set_reg(kapic, 0x30, s->icr[0]); + kvm_apic_set_reg(kapic, 0x31, s->icr[1]); + for (i = 0; i < APIC_LVT_NB; i++) { + kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]); + } + kvm_apic_set_reg(kapic, 0x38, s->initial_count); + kvm_apic_set_reg(kapic, 0x3e, s->divide_conf); +} + +void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic) +{ + APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d); + int i, v; + + s->id = kvm_apic_get_reg(kapic, 0x2) >> 24; + s->tpr = kvm_apic_get_reg(kapic, 0x8); + s->arb_id = kvm_apic_get_reg(kapic, 0x9); + s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24; + s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28; + s->spurious_vec = kvm_apic_get_reg(kapic, 0xf); + for (i = 0; i < 8; i++) { + s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i); + s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i); + s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i); + } + s->esr = kvm_apic_get_reg(kapic, 0x28); + s->icr[0] = kvm_apic_get_reg(kapic, 0x30); + s->icr[1] = kvm_apic_get_reg(kapic, 0x31); + for (i = 0; i < APIC_LVT_NB; i++) { + s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i); + } + s->initial_count = kvm_apic_get_reg(kapic, 0x38); + s->divide_conf = kvm_apic_get_reg(kapic, 0x3e); + + v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); + s->count_shift = (v + 1) & 7; + + s->initial_count_load_time = qemu_get_clock_ns(vm_clock); + apic_next_timer(s, s->initial_count_load_time); +} + +static void kvm_apic_set_base(APICCommonState *s, uint64_t val) +{ + s->apicbase = val; +} + +static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val) +{ + s->tpr = (val & 0x0f) << 4; +} + +static void do_inject_external_nmi(void *data) +{ + APICCommonState *s = data; + CPUState *env = s->cpu_env; + uint32_t lvt; + int ret; + + cpu_synchronize_state(env); + + lvt = s->lvt[APIC_LVT_LINT1]; + if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) { + ret = kvm_vcpu_ioctl(env, KVM_NMI); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", + strerror(-ret)); + } + } +} + +static void kvm_apic_external_nmi(APICCommonState *s) +{ + run_on_cpu(s->cpu_env, do_inject_external_nmi, s); +} + +static void kvm_apic_init(APICCommonState *s) +{ + memory_region_init_reservation(&s->io_memory, "kvm-apic-msi", + MSI_SPACE_SIZE); +} + +static void kvm_apic_class_init(ObjectClass *klass, void *data) +{ + APICCommonClass *k = APIC_COMMON_CLASS(klass); + + k->init = kvm_apic_init; + k->set_base = kvm_apic_set_base; + k->set_tpr = kvm_apic_set_tpr; + k->external_nmi = kvm_apic_external_nmi; +} + +static TypeInfo kvm_apic_info = { + .name = "kvm-apic", + .parent = TYPE_APIC_COMMON, + .instance_size = sizeof(APICCommonState), + .class_init = kvm_apic_class_init, +}; + +static void kvm_apic_register_device(void) +{ + type_register_static(&kvm_apic_info); +} + +device_init(kvm_apic_register_device) diff --git a/hw/kvmclock.c b/hw/kvm/clock.c index 3b9fb20495..d5a53869b3 100644 --- a/hw/kvmclock.c +++ b/hw/kvm/clock.c @@ -15,9 +15,9 @@ #include "qemu-common.h" #include "sysemu.h" -#include "sysbus.h" #include "kvm.h" -#include "kvmclock.h" +#include "hw/sysbus.h" +#include "hw/kvm/clock.h" #include <linux/kvm.h> #include <linux/kvm_para.h> @@ -92,12 +92,21 @@ static const VMStateDescription kvmclock_vmsd = { } }; -static SysBusDeviceInfo kvmclock_info = { - .qdev.name = "kvmclock", - .qdev.size = sizeof(KVMClockState), - .qdev.vmsd = &kvmclock_vmsd, - .qdev.no_user = 1, - .init = kvmclock_init, +static void kvmclock_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = kvmclock_init; + dc->no_user = 1; + dc->vmsd = &kvmclock_vmsd; +} + +static TypeInfo kvmclock_info = { + .name = "kvmclock", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(KVMClockState), + .class_init = kvmclock_class_init, }; /* Note: Must be called after VCPU initialization. */ @@ -113,7 +122,7 @@ void kvmclock_create(void) static void kvmclock_register_device(void) { if (kvm_enabled()) { - sysbus_register_withprop(&kvmclock_info); + type_register_static(&kvmclock_info); } } diff --git a/hw/kvmclock.h b/hw/kvm/clock.h index 252ea13461..252ea13461 100644 --- a/hw/kvmclock.h +++ b/hw/kvm/clock.h diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c new file mode 100644 index 0000000000..14bd427518 --- /dev/null +++ b/hw/kvm/i8259.c @@ -0,0 +1,138 @@ +/* + * KVM in-kernel PIC (i8259) support + * + * Copyright (c) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + */ +#include "hw/i8259_internal.h" +#include "hw/apic_internal.h" +#include "kvm.h" + +static void kvm_pic_get(PICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_pic_state *kpic; + int ret; + + chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE; + ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } + + kpic = &chip.chip.pic; + + s->last_irr = kpic->last_irr; + s->irr = kpic->irr; + s->imr = kpic->imr; + s->isr = kpic->isr; + s->priority_add = kpic->priority_add; + s->irq_base = kpic->irq_base; + s->read_reg_select = kpic->read_reg_select; + s->poll = kpic->poll; + s->special_mask = kpic->special_mask; + s->init_state = kpic->init_state; + s->auto_eoi = kpic->auto_eoi; + s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi; + s->special_fully_nested_mode = kpic->special_fully_nested_mode; + s->init4 = kpic->init4; + s->elcr = kpic->elcr; + s->elcr_mask = kpic->elcr_mask; +} + +static void kvm_pic_put(PICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_pic_state *kpic; + int ret; + + chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE; + + kpic = &chip.chip.pic; + + kpic->last_irr = s->last_irr; + kpic->irr = s->irr; + kpic->imr = s->imr; + kpic->isr = s->isr; + kpic->priority_add = s->priority_add; + kpic->irq_base = s->irq_base; + kpic->read_reg_select = s->read_reg_select; + kpic->poll = s->poll; + kpic->special_mask = s->special_mask; + kpic->init_state = s->init_state; + kpic->auto_eoi = s->auto_eoi; + kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi; + kpic->special_fully_nested_mode = s->special_fully_nested_mode; + kpic->init4 = s->init4; + kpic->elcr = s->elcr; + kpic->elcr_mask = s->elcr_mask; + + ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } +} + +static void kvm_pic_reset(DeviceState *dev) +{ + PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev); + + pic_reset_common(s); + s->elcr = 0; + + kvm_pic_put(s); +} + +static void kvm_pic_set_irq(void *opaque, int irq, int level) +{ + int delivered; + + delivered = kvm_irqchip_set_irq(kvm_state, irq, level); + apic_report_irq_delivered(delivered); +} + +static void kvm_pic_init(PICCommonState *s) +{ + memory_region_init_reservation(&s->base_io, "kvm-pic", 2); + memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1); +} + +qemu_irq *kvm_i8259_init(ISABus *bus) +{ + i8259_init_chip("kvm-i8259", bus, true); + i8259_init_chip("kvm-i8259", bus, false); + + return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS); +} + +static void kvm_i8259_class_init(ObjectClass *klass, void *data) +{ + PICCommonClass *k = PIC_COMMON_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = kvm_pic_reset; + k->init = kvm_pic_init; + k->pre_save = kvm_pic_get; + k->post_load = kvm_pic_put; +} + +static TypeInfo kvm_i8259_info = { + .name = "kvm-i8259", + .parent = TYPE_PIC_COMMON, + .instance_size = sizeof(PICCommonState), + .class_init = kvm_i8259_class_init, +}; + +static void kvm_pic_register(void) +{ + type_register_static(&kvm_i8259_info); +} + +device_init(kvm_pic_register) diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c new file mode 100644 index 0000000000..b316933a96 --- /dev/null +++ b/hw/kvm/ioapic.c @@ -0,0 +1,125 @@ +/* + * KVM in-kernel IOPIC support + * + * Copyright (c) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + */ + +#include "hw/pc.h" +#include "hw/ioapic_internal.h" +#include "hw/apic_internal.h" +#include "kvm.h" + +typedef struct KVMIOAPICState KVMIOAPICState; + +struct KVMIOAPICState { + IOAPICCommonState ioapic; + uint32_t kvm_gsi_base; +}; + +static void kvm_ioapic_get(IOAPICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_ioapic_state *kioapic; + int ret, i; + + chip.chip_id = KVM_IRQCHIP_IOAPIC; + ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } + + kioapic = &chip.chip.ioapic; + + s->id = kioapic->id; + s->ioregsel = kioapic->ioregsel; + s->irr = kioapic->irr; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = kioapic->redirtbl[i].bits; + } +} + +static void kvm_ioapic_put(IOAPICCommonState *s) +{ + struct kvm_irqchip chip; + struct kvm_ioapic_state *kioapic; + int ret, i; + + chip.chip_id = KVM_IRQCHIP_IOAPIC; + kioapic = &chip.chip.ioapic; + + kioapic->id = s->id; + kioapic->ioregsel = s->ioregsel; + kioapic->base_address = s->busdev.mmio[0].addr; + kioapic->irr = s->irr; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + kioapic->redirtbl[i].bits = s->ioredtbl[i]; + } + + ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); + if (ret < 0) { + fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); + abort(); + } +} + +static void kvm_ioapic_reset(DeviceState *dev) +{ + IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev); + + ioapic_reset_common(dev); + kvm_ioapic_put(s); +} + +static void kvm_ioapic_set_irq(void *opaque, int irq, int level) +{ + KVMIOAPICState *s = opaque; + int delivered; + + delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level); + apic_report_irq_delivered(delivered); +} + +static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no) +{ + memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000); + + qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); +} + +static Property kvm_ioapic_properties[] = { + DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void kvm_ioapic_class_init(ObjectClass *klass, void *data) +{ + IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = kvm_ioapic_init; + k->pre_save = kvm_ioapic_get; + k->post_load = kvm_ioapic_put; + dc->reset = kvm_ioapic_reset; + dc->props = kvm_ioapic_properties; +} + +static TypeInfo kvm_ioapic_info = { + .name = "kvm-ioapic", + .parent = TYPE_IOAPIC_COMMON, + .instance_size = sizeof(KVMIOAPICState), + .class_init = kvm_ioapic_class_init, +}; + +static void kvm_ioapic_register_device(void) +{ + type_register_static(&kvm_ioapic_info); +} + +device_init(kvm_ioapic_register_device) diff --git a/hw/lan9118.c b/hw/lan9118.c index 8b83fe2198..78777c7336 100644 --- a/hw/lan9118.c +++ b/hw/lan9118.c @@ -140,17 +140,36 @@ enum tx_state { }; typedef struct { - enum tx_state state; + /* state is a tx_state but we can't put enums in VMStateDescriptions. */ + uint32_t state; uint32_t cmd_a; uint32_t cmd_b; - int buffer_size; - int offset; - int pad; - int fifo_used; - int len; + int32_t buffer_size; + int32_t offset; + int32_t pad; + int32_t fifo_used; + int32_t len; uint8_t data[2048]; } LAN9118Packet; +static const VMStateDescription vmstate_lan9118_packet = { + .name = "lan9118_packet", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(state, LAN9118Packet), + VMSTATE_UINT32(cmd_a, LAN9118Packet), + VMSTATE_UINT32(cmd_b, LAN9118Packet), + VMSTATE_INT32(buffer_size, LAN9118Packet), + VMSTATE_INT32(offset, LAN9118Packet), + VMSTATE_INT32(pad, LAN9118Packet), + VMSTATE_INT32(fifo_used, LAN9118Packet), + VMSTATE_INT32(len, LAN9118Packet), + VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048), + VMSTATE_END_OF_LIST() + } +}; + typedef struct { SysBusDevice busdev; NICState *nic; @@ -190,34 +209,95 @@ typedef struct { uint32_t phy_int; uint32_t phy_int_mask; - int eeprom_writable; + int32_t eeprom_writable; uint8_t eeprom[128]; - int tx_fifo_size; + int32_t tx_fifo_size; LAN9118Packet *txp; LAN9118Packet tx_packet; - int tx_status_fifo_used; - int tx_status_fifo_head; + int32_t tx_status_fifo_used; + int32_t tx_status_fifo_head; uint32_t tx_status_fifo[512]; - int rx_status_fifo_size; - int rx_status_fifo_used; - int rx_status_fifo_head; + int32_t rx_status_fifo_size; + int32_t rx_status_fifo_used; + int32_t rx_status_fifo_head; uint32_t rx_status_fifo[896]; - int rx_fifo_size; - int rx_fifo_used; - int rx_fifo_head; + int32_t rx_fifo_size; + int32_t rx_fifo_used; + int32_t rx_fifo_head; uint32_t rx_fifo[3360]; - int rx_packet_size_head; - int rx_packet_size_tail; - int rx_packet_size[1024]; + int32_t rx_packet_size_head; + int32_t rx_packet_size_tail; + int32_t rx_packet_size[1024]; - int rxp_offset; - int rxp_size; - int rxp_pad; + int32_t rxp_offset; + int32_t rxp_size; + int32_t rxp_pad; } lan9118_state; +static const VMStateDescription vmstate_lan9118 = { + .name = "lan9118", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_PTIMER(timer, lan9118_state), + VMSTATE_UINT32(irq_cfg, lan9118_state), + VMSTATE_UINT32(int_sts, lan9118_state), + VMSTATE_UINT32(int_en, lan9118_state), + VMSTATE_UINT32(fifo_int, lan9118_state), + VMSTATE_UINT32(rx_cfg, lan9118_state), + VMSTATE_UINT32(tx_cfg, lan9118_state), + VMSTATE_UINT32(hw_cfg, lan9118_state), + VMSTATE_UINT32(pmt_ctrl, lan9118_state), + VMSTATE_UINT32(gpio_cfg, lan9118_state), + VMSTATE_UINT32(gpt_cfg, lan9118_state), + VMSTATE_UINT32(word_swap, lan9118_state), + VMSTATE_UINT32(free_timer_start, lan9118_state), + VMSTATE_UINT32(mac_cmd, lan9118_state), + VMSTATE_UINT32(mac_data, lan9118_state), + VMSTATE_UINT32(afc_cfg, lan9118_state), + VMSTATE_UINT32(e2p_cmd, lan9118_state), + VMSTATE_UINT32(e2p_data, lan9118_state), + VMSTATE_UINT32(mac_cr, lan9118_state), + VMSTATE_UINT32(mac_hashh, lan9118_state), + VMSTATE_UINT32(mac_hashl, lan9118_state), + VMSTATE_UINT32(mac_mii_acc, lan9118_state), + VMSTATE_UINT32(mac_mii_data, lan9118_state), + VMSTATE_UINT32(mac_flow, lan9118_state), + VMSTATE_UINT32(phy_status, lan9118_state), + VMSTATE_UINT32(phy_control, lan9118_state), + VMSTATE_UINT32(phy_advertise, lan9118_state), + VMSTATE_UINT32(phy_int, lan9118_state), + VMSTATE_UINT32(phy_int_mask, lan9118_state), + VMSTATE_INT32(eeprom_writable, lan9118_state), + VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128), + VMSTATE_INT32(tx_fifo_size, lan9118_state), + /* txp always points at tx_packet so need not be saved */ + VMSTATE_STRUCT(tx_packet, lan9118_state, 0, + vmstate_lan9118_packet, LAN9118Packet), + VMSTATE_INT32(tx_status_fifo_used, lan9118_state), + VMSTATE_INT32(tx_status_fifo_head, lan9118_state), + VMSTATE_UINT32_ARRAY(tx_status_fifo, lan9118_state, 512), + VMSTATE_INT32(rx_status_fifo_size, lan9118_state), + VMSTATE_INT32(rx_status_fifo_used, lan9118_state), + VMSTATE_INT32(rx_status_fifo_head, lan9118_state), + VMSTATE_UINT32_ARRAY(rx_status_fifo, lan9118_state, 896), + VMSTATE_INT32(rx_fifo_size, lan9118_state), + VMSTATE_INT32(rx_fifo_used, lan9118_state), + VMSTATE_INT32(rx_fifo_head, lan9118_state), + VMSTATE_UINT32_ARRAY(rx_fifo, lan9118_state, 3360), + VMSTATE_INT32(rx_packet_size_head, lan9118_state), + VMSTATE_INT32(rx_packet_size_tail, lan9118_state), + VMSTATE_INT32_ARRAY(rx_packet_size, lan9118_state, 1024), + VMSTATE_INT32(rxp_offset, lan9118_state), + VMSTATE_INT32(rxp_size, lan9118_state), + VMSTATE_INT32(rxp_pad, lan9118_state), + VMSTATE_END_OF_LIST() + } +}; + static void lan9118_update(lan9118_state *s) { int level; @@ -1141,7 +1221,7 @@ static int lan9118_init1(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_lan9118_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); s->eeprom[0] = 0xa5; for (i = 0; i < 6; i++) { @@ -1155,24 +1235,35 @@ static int lan9118_init1(SysBusDevice *dev) ptimer_set_freq(s->timer, 10000); ptimer_set_limit(s->timer, 0xffff, 1); - /* ??? Save/restore. */ return 0; } -static SysBusDeviceInfo lan9118_info = { - .init = lan9118_init1, - .qdev.name = "lan9118", - .qdev.size = sizeof(lan9118_state), - .qdev.reset = lan9118_reset, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(lan9118_state, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property lan9118_properties[] = { + DEFINE_NIC_PROPERTIES(lan9118_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lan9118_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lan9118_init1; + dc->reset = lan9118_reset; + dc->props = lan9118_properties; + dc->vmsd = &vmstate_lan9118; +} + +static TypeInfo lan9118_info = { + .name = "lan9118", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(lan9118_state), + .class_init = lan9118_class_init, }; static void lan9118_register_devices(void) { - sysbus_register_withprop(&lan9118_info); + type_register_static(&lan9118_info); } /* Legacy helper function. Should go away when machine config files are diff --git a/hw/lance.c b/hw/lance.c index 716470061c..519720bd9c 100644 --- a/hw/lance.c +++ b/hw/lance.c @@ -137,22 +137,33 @@ static void lance_reset(DeviceState *dev) pcnet_h_reset(&d->state); } -static SysBusDeviceInfo lance_info = { - .init = lance_init, - .qdev.name = "lance", - .qdev.fw_name = "ethernet", - .qdev.size = sizeof(SysBusPCNetState), - .qdev.reset = lance_reset, - .qdev.vmsd = &vmstate_lance, - .qdev.props = (Property[]) { - DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque), - DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property lance_properties[] = { + DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque), + DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lance_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lance_init; + dc->fw_name = "ethernet"; + dc->reset = lance_reset; + dc->vmsd = &vmstate_lance; + dc->props = lance_properties; +} + +static TypeInfo lance_info = { + .name = "lance", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusPCNetState), + .class_init = lance_class_init, }; static void lance_register_devices(void) { - sysbus_register_withprop(&lance_info); + type_register_static(&lance_info); } device_init(lance_register_devices) diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c index 5454aa4e4d..38dd28230d 100644 --- a/hw/lm32_juart.c +++ b/hw/lm32_juart.c @@ -114,7 +114,7 @@ static int lm32_juart_init(SysBusDevice *dev) { LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); } @@ -134,17 +134,26 @@ static const VMStateDescription vmstate_lm32_juart = { } }; -static SysBusDeviceInfo lm32_juart_info = { - .init = lm32_juart_init, - .qdev.name = "lm32-juart", - .qdev.size = sizeof(LM32JuartState), - .qdev.vmsd = &vmstate_lm32_juart, - .qdev.reset = juart_reset, +static void lm32_juart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_juart_init; + dc->reset = juart_reset; + dc->vmsd = &vmstate_lm32_juart; +} + +static TypeInfo lm32_juart_info = { + .name = "lm32-juart", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32JuartState), + .class_init = lm32_juart_class_init, }; static void lm32_juart_register(void) { - sysbus_register_withprop(&lm32_juart_info); + type_register_static(&lm32_juart_info); } device_init(lm32_juart_register) diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c index 8dd005077c..7be6d0d68e 100644 --- a/hw/lm32_pic.c +++ b/hw/lm32_pic.c @@ -174,17 +174,26 @@ static const VMStateDescription vmstate_lm32_pic = { } }; -static SysBusDeviceInfo lm32_pic_info = { - .init = lm32_pic_init, - .qdev.name = "lm32-pic", - .qdev.size = sizeof(LM32PicState), - .qdev.vmsd = &vmstate_lm32_pic, - .qdev.reset = pic_reset, +static void lm32_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_pic_init; + dc->reset = pic_reset; + dc->vmsd = &vmstate_lm32_pic; +} + +static TypeInfo lm32_pic_info = { + .name = "lm32-pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32PicState), + .class_init = lm32_pic_class_init, }; static void lm32_pic_register(void) { - sysbus_register_withprop(&lm32_pic_info); + type_register_static(&lm32_pic_info); } device_init(lm32_pic_register) diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c index 83974ee4fb..ba6f4acbaa 100644 --- a/hw/lm32_sys.c +++ b/hw/lm32_sys.c @@ -141,21 +141,32 @@ static const VMStateDescription vmstate_lm32_sys = { } }; -static SysBusDeviceInfo lm32_sys_info = { - .init = lm32_sys_init, - .qdev.name = "lm32-sys", - .qdev.size = sizeof(LM32SysState), - .qdev.vmsd = &vmstate_lm32_sys, - .qdev.reset = sys_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000), - DEFINE_PROP_END_OF_LIST(), - } +static Property lm32_sys_properties[] = { + DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lm32_sys_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_sys_init; + dc->reset = sys_reset; + dc->vmsd = &vmstate_lm32_sys; + dc->props = lm32_sys_properties; +} + +static TypeInfo lm32_sys_info = { + .name = "lm32-sys", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32SysState), + .class_init = lm32_sys_class_init, }; static void lm32_sys_register(void) { - sysbus_register_withprop(&lm32_sys_info); + type_register_static(&lm32_sys_info); } device_init(lm32_sys_register) diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c index 115e1e968f..3cb4e0a4f3 100644 --- a/hw/lm32_timer.c +++ b/hw/lm32_timer.c @@ -199,23 +199,32 @@ static const VMStateDescription vmstate_lm32_timer = { } }; -static SysBusDeviceInfo lm32_timer_info = { - .init = lm32_timer_init, - .qdev.name = "lm32-timer", - .qdev.size = sizeof(LM32TimerState), - .qdev.vmsd = &vmstate_lm32_timer, - .qdev.reset = timer_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32( - "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY - ), - DEFINE_PROP_END_OF_LIST(), - } +static Property lm32_timer_properties[] = { + DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY), + DEFINE_PROP_END_OF_LIST(), +}; + +static void lm32_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_timer_init; + dc->reset = timer_reset; + dc->vmsd = &vmstate_lm32_timer; + dc->props = lm32_timer_properties; +} + +static TypeInfo lm32_timer_info = { + .name = "lm32-timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32TimerState), + .class_init = lm32_timer_class_init, }; static void lm32_timer_register(void) { - sysbus_register_withprop(&lm32_timer_info); + type_register_static(&lm32_timer_info); } device_init(lm32_timer_register) diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c index d013abd1c6..630ccb7131 100644 --- a/hw/lm32_uart.c +++ b/hw/lm32_uart.c @@ -252,7 +252,7 @@ static int lm32_uart_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4); sysbus_init_mmio(dev, &s->iomem); - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -271,17 +271,26 @@ static const VMStateDescription vmstate_lm32_uart = { } }; -static SysBusDeviceInfo lm32_uart_info = { - .init = lm32_uart_init, - .qdev.name = "lm32-uart", - .qdev.size = sizeof(LM32UartState), - .qdev.vmsd = &vmstate_lm32_uart, - .qdev.reset = uart_reset, +static void lm32_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = lm32_uart_init; + dc->reset = uart_reset; + dc->vmsd = &vmstate_lm32_uart; +} + +static TypeInfo lm32_uart_info = { + .name = "lm32-uart", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LM32UartState), + .class_init = lm32_uart_class_init, }; static void lm32_uart_register(void) { - sysbus_register_withprop(&lm32_uart_info); + type_register_static(&lm32_uart_info); } device_init(lm32_uart_register) diff --git a/hw/lm832x.c b/hw/lm832x.c index 992ce49729..895d306635 100644 --- a/hw/lm832x.c +++ b/hw/lm832x.c @@ -24,7 +24,7 @@ #include "console.h" typedef struct { - i2c_slave i2c; + I2CSlave i2c; uint8_t i2c_dir; uint8_t i2c_cycle; uint8_t reg; @@ -378,7 +378,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value) } } -static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event) +static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event) { LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c); @@ -394,14 +394,14 @@ static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event) } } -static int lm_i2c_rx(i2c_slave *i2c) +static int lm_i2c_rx(I2CSlave *i2c) { LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c); return lm_kbd_read(s, s->reg, s->i2c_cycle ++); } -static int lm_i2c_tx(i2c_slave *i2c, uint8_t data) +static int lm_i2c_tx(I2CSlave *i2c, uint8_t data) { LM823KbdState *s = (LM823KbdState *) i2c; @@ -458,7 +458,7 @@ static const VMStateDescription vmstate_lm_kbd = { }; -static int lm8323_init(i2c_slave *i2c) +static int lm8323_init(I2CSlave *i2c) { LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c); @@ -494,19 +494,28 @@ void lm832x_key_event(DeviceState *dev, int key, int state) lm_kbd_irq_update(s); } -static I2CSlaveInfo lm8323_info = { - .qdev.name = "lm8323", - .qdev.size = sizeof(LM823KbdState), - .qdev.vmsd = &vmstate_lm_kbd, - .init = lm8323_init, - .event = lm_i2c_event, - .recv = lm_i2c_rx, - .send = lm_i2c_tx +static void lm8323_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = lm8323_init; + k->event = lm_i2c_event; + k->recv = lm_i2c_rx; + k->send = lm_i2c_tx; + dc->vmsd = &vmstate_lm_kbd; +} + +static TypeInfo lm8323_info = { + .name = "lm8323", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(LM823KbdState), + .class_init = lm8323_class_init, }; static void lm832x_register_devices(void) { - i2c_register_slave(&lm8323_info); + type_register_static(&lm8323_info); } device_init(lm832x_register_devices) diff --git a/hw/loader.c b/hw/loader.c index 446b62874e..415cdce534 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -108,8 +108,12 @@ int load_image_targphys(const char *filename, int size; size = get_image_size(filename); - if (size > 0) + if (size > max_sz) { + return -1; + } + if (size > 0) { rom_add_file_fixed(filename, addr, -1); + } return size; } diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 0d3a1016df..9a7ffe3f42 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1681,7 +1681,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) DeviceState *dev; QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) { - dev->info->reset(dev); + device_reset(dev); } s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); @@ -2120,23 +2120,31 @@ static int lsi_scsi_init(PCIDevice *dev) return 0; } -static PCIDeviceInfo lsi_info = { - .qdev.name = "lsi53c895a", - .qdev.alias = "lsi", - .qdev.size = sizeof(LSIState), - .qdev.reset = lsi_scsi_reset, - .qdev.vmsd = &vmstate_lsi_scsi, - .init = lsi_scsi_init, - .exit = lsi_scsi_uninit, - .vendor_id = PCI_VENDOR_ID_LSI_LOGIC, - .device_id = PCI_DEVICE_ID_LSI_53C895A, - .class_id = PCI_CLASS_STORAGE_SCSI, - .subsystem_id = 0x1000, +static void lsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = lsi_scsi_init; + k->exit = lsi_scsi_uninit; + k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC; + k->device_id = PCI_DEVICE_ID_LSI_53C895A; + k->class_id = PCI_CLASS_STORAGE_SCSI; + k->subsystem_id = 0x1000; + dc->reset = lsi_scsi_reset; + dc->vmsd = &vmstate_lsi_scsi; +} + +static TypeInfo lsi_info = { + .name = "lsi53c895a", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(LSIState), + .class_init = lsi_class_init, }; static void lsi53c895a_register_devices(void) { - pci_qdev_register(&lsi_info); + type_register_static(&lsi_info); } device_init(lsi53c895a_register_devices); diff --git a/hw/m48t59.c b/hw/m48t59.c index c0439966cf..c35867d0a1 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -126,7 +126,7 @@ static void alarm_cb (void *opaque) /* Repeat once a second */ next_time = 1; } - qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) + + qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) + next_time * 1000); qemu_set_irq(NVRAM->IRQ, 0); } @@ -687,7 +687,7 @@ static void m48t59_init_common(M48t59State *s) { s->buffer = g_malloc0(s->size); if (s->type == 59) { - s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s); + s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s); s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s); } qemu_get_timedate(&s->alarm, 0); @@ -720,37 +720,58 @@ static int m48t59_init1(SysBusDevice *dev) return 0; } -static ISADeviceInfo m48t59_isa_info = { - .init = m48t59_init_isa1, - .qdev.name = "m48t59_isa", - .qdev.size = sizeof(M48t59ISAState), - .qdev.reset = m48t59_reset_isa, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1), - DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1), - DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property m48t59_isa_properties[] = { + DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1), + DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1), + DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo m48t59_info = { - .init = m48t59_init1, - .qdev.name = "m48t59", - .qdev.size = sizeof(M48t59SysBusState), - .qdev.reset = m48t59_reset_sysbus, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1), - DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1), - DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0), - DEFINE_PROP_END_OF_LIST(), - } +static void m48t59_init_class_isa1(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = m48t59_init_isa1; + dc->no_user = 1; + dc->reset = m48t59_reset_isa; + dc->props = m48t59_isa_properties; +} + +static TypeInfo m48t59_isa_info = { + .name = "m48t59_isa", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(M48t59ISAState), + .class_init = m48t59_init_class_isa1, +}; + +static Property m48t59_properties[] = { + DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1), + DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1), + DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void m48t59_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = m48t59_init1; + dc->reset = m48t59_reset_sysbus; + dc->props = m48t59_properties; +} + +static TypeInfo m48t59_info = { + .name = "m48t59", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(M48t59SysBusState), + .class_init = m48t59_class_init, }; static void m48t59_register_devices(void) { - sysbus_register_withprop(&m48t59_info); - isa_qdev_register(&m48t59_isa_info); + type_register_static(&m48t59_info); + type_register_static(&m48t59_isa_info); } device_init(m48t59_register_devices) diff --git a/hw/macio.c b/hw/macio.c index cc6ae40050..3d648e934b 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -27,8 +27,9 @@ #include "pci.h" #include "escc.h" -typedef struct macio_state_t macio_state_t; -struct macio_state_t { +typedef struct MacIOState +{ + PCIDevice parent; int is_oldworld; MemoryRegion bar; MemoryRegion *pic_mem; @@ -38,9 +39,9 @@ struct macio_state_t { void *nvram; int nb_ide; MemoryRegion *ide_mem[4]; -}; +} MacIOState; -static void macio_bar_setup(macio_state_t *macio_state) +static void macio_bar_setup(MacIOState *macio_state) { int i; MemoryRegion *bar = &macio_state->bar; @@ -74,6 +75,35 @@ static void macio_bar_setup(macio_state_t *macio_state) macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000); } +static int macio_initfn(PCIDevice *d) +{ + d->config[0x3d] = 0x01; // interrupt on pin 1 + return 0; +} + +static void macio_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = macio_initfn; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->class_id = PCI_CLASS_OTHERS << 8; +} + +static TypeInfo macio_info = { + .name = "macio", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(MacIOState), + .class_init = macio_class_init, +}; + +static void macio_register(void) +{ + type_register_static(&macio_info); +} + +device_init(macio_register); + void macio_init (PCIBus *bus, int device_id, int is_oldworld, MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, MemoryRegion *cuda_mem, void *nvram, @@ -81,13 +111,12 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, MemoryRegion *escc_mem) { PCIDevice *d; - macio_state_t *macio_state; + MacIOState *macio_state; int i; - d = pci_register_device(bus, "macio", - sizeof(PCIDevice) + sizeof(macio_state_t), - -1, NULL, NULL); - macio_state = (macio_state_t *)(d + 1); + d = pci_create_simple(bus, -1, "macio"); + + macio_state = DO_UPCAST(MacIOState, parent, d); macio_state->is_oldworld = is_oldworld; macio_state->pic_mem = pic_mem; macio_state->dbdma_mem = dbdma_mem; @@ -104,11 +133,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld, /* Note: this code is strongly inspirated from the corresponding code in PearPC */ - pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); pci_config_set_device_id(d->config, device_id); - pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8); - - d->config[0x3d] = 0x01; // interrupt on pin 1 macio_bar_setup(macio_state); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar); diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c index 0cd8410622..b628f1718d 100644 --- a/hw/marvell_88w8618_audio.c +++ b/hw/marvell_88w8618_audio.c @@ -50,7 +50,7 @@ typedef struct mv88w8618_audio_state { uint32_t play_pos; uint32_t last_free; uint32_t clock_div; - DeviceState *wm; + void *wm; } mv88w8618_audio_state; static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in) @@ -272,25 +272,32 @@ static const VMStateDescription mv88w8618_audio_vmsd = { } }; -static SysBusDeviceInfo mv88w8618_audio_info = { - .init = mv88w8618_audio_init, - .qdev.name = "mv88w8618_audio", - .qdev.size = sizeof(mv88w8618_audio_state), - .qdev.reset = mv88w8618_audio_reset, - .qdev.vmsd = &mv88w8618_audio_vmsd, - .qdev.props = (Property[]) { - { - .name = "wm8750", - .info = &qdev_prop_ptr, - .offset = offsetof(mv88w8618_audio_state, wm), - }, - {/* end of list */} - } +static Property mv88w8618_audio_properties[] = { + DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm), + {/* end of list */}, +}; + +static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_audio_init; + dc->reset = mv88w8618_audio_reset; + dc->vmsd = &mv88w8618_audio_vmsd; + dc->props = mv88w8618_audio_properties; +} + +static TypeInfo mv88w8618_audio_info = { + .name = "mv88w8618_audio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_audio_state), + .class_init = mv88w8618_audio_class_init, }; static void mv88w8618_register_devices(void) { - sysbus_register_withprop(&mv88w8618_audio_info); + type_register_static(&mv88w8618_audio_info); } device_init(mv88w8618_register_devices) diff --git a/hw/max111x.c b/hw/max111x.c index fc79814bf8..9d61aa98db 100644 --- a/hw/max111x.c +++ b/hw/max111x.c @@ -153,24 +153,40 @@ void max111x_set_input(DeviceState *dev, int line, uint8_t value) s->input[line] = value; } -static SSISlaveInfo max1110_info = { - .qdev.name = "max1110", - .qdev.size = sizeof(MAX111xState), - .init = max1110_init, - .transfer = max111x_transfer +static void max1110_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = max1110_init; + k->transfer = max111x_transfer; +} + +static TypeInfo max1110_info = { + .name = "max1110", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(MAX111xState), + .class_init = max1110_class_init, }; -static SSISlaveInfo max1111_info = { - .qdev.name = "max1111", - .qdev.size = sizeof(MAX111xState), - .init = max1111_init, - .transfer = max111x_transfer +static void max1111_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = max1111_init; + k->transfer = max111x_transfer; +} + +static TypeInfo max1111_info = { + .name = "max1111", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(MAX111xState), + .class_init = max1111_class_init, }; static void max111x_register_devices(void) { - ssi_register_slave(&max1110_info); - ssi_register_slave(&max1111_info); + type_register_static(&max1110_info); + type_register_static(&max1111_info); } device_init(max111x_register_devices) diff --git a/hw/max7310.c b/hw/max7310.c index c1bdb2ee0c..3a6bb961ef 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -10,7 +10,7 @@ #include "i2c.h" typedef struct { - i2c_slave i2c; + I2CSlave i2c; int i2c_command_byte; int len; @@ -33,7 +33,7 @@ static void max7310_reset(DeviceState *dev) s->command = 0x00; } -static int max7310_rx(i2c_slave *i2c) +static int max7310_rx(I2CSlave *i2c) { MAX7310State *s = (MAX7310State *) i2c; @@ -68,7 +68,7 @@ static int max7310_rx(i2c_slave *i2c) return 0xff; } -static int max7310_tx(i2c_slave *i2c, uint8_t data) +static int max7310_tx(I2CSlave *i2c, uint8_t data) { MAX7310State *s = (MAX7310State *) i2c; uint8_t diff; @@ -123,7 +123,7 @@ static int max7310_tx(i2c_slave *i2c, uint8_t data) return 0; } -static void max7310_event(i2c_slave *i2c, enum i2c_event event) +static void max7310_event(I2CSlave *i2c, enum i2c_event event) { MAX7310State *s = (MAX7310State *) i2c; s->len = 0; @@ -175,7 +175,7 @@ static void max7310_gpio_set(void *opaque, int line, int level) /* MAX7310 is SMBus-compatible (can be used with only SMBus protocols), * but also accepts sequences that are not SMBus so return an I2C device. */ -static int max7310_init(i2c_slave *i2c) +static int max7310_init(I2CSlave *i2c) { MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c); @@ -185,20 +185,29 @@ static int max7310_init(i2c_slave *i2c) return 0; } -static I2CSlaveInfo max7310_info = { - .qdev.name = "max7310", - .qdev.size = sizeof(MAX7310State), - .qdev.vmsd = &vmstate_max7310, - .qdev.reset = max7310_reset, - .init = max7310_init, - .event = max7310_event, - .recv = max7310_rx, - .send = max7310_tx +static void max7310_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = max7310_init; + k->event = max7310_event; + k->recv = max7310_rx; + k->send = max7310_tx; + dc->reset = max7310_reset; + dc->vmsd = &vmstate_max7310; +} + +static TypeInfo max7310_info = { + .name = "max7310", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(MAX7310State), + .class_init = max7310_class_init, }; static void max7310_register_devices(void) { - i2c_register_slave(&max7310_info); + type_register_static(&max7310_info); } device_init(max7310_register_devices) diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 657fa10d6d..4a43225707 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -101,6 +101,7 @@ typedef struct RTCState { QEMUTimer *second_timer; QEMUTimer *second_timer2; Notifier clock_reset_notifier; + LostTickPolicy lost_tick_policy; } RTCState; static void rtc_set_time(RTCState *s); @@ -183,7 +184,7 @@ static void rtc_periodic_timer(void *opaque) if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= REG_C_IRQF; #ifdef TARGET_I386 - if(rtc_td_hack) { + if (s->lost_tick_policy == LOST_TICK_SLEW) { if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); @@ -544,7 +545,7 @@ static int rtc_post_load(void *opaque, int version_id) RTCState *s = opaque; if (version_id >= 2) { - if (rtc_td_hack) { + if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); } } @@ -589,7 +590,7 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data) qemu_mod_timer(s->second_timer2, s->next_second_time); rtc_timer_update(s, now); #ifdef TARGET_I386 - if (rtc_td_hack) { + if (s->lost_tick_policy == LOST_TICK_SLEW) { rtc_coalesced_timer_update(s); } #endif @@ -605,8 +606,9 @@ static void rtc_reset(void *opaque) qemu_irq_lower(s->irq); #ifdef TARGET_I386 - if (rtc_td_hack) - s->irq_coalesced = 0; + if (s->lost_tick_policy == LOST_TICK_SLEW) { + s->irq_coalesced = 0; + } #endif } @@ -626,10 +628,10 @@ static void visit_type_int32(Visitor *v, int *value, const char *name, Error **e visit_type_int(v, &val, name, errp); } -static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque, +static void rtc_get_date(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { - ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev); + ISADevice *isa = ISA_DEVICE(obj); RTCState *s = DO_UPCAST(RTCState, dev, isa); visit_start_struct(v, NULL, "struct tm", name, 0, errp); @@ -654,12 +656,20 @@ static int rtc_initfn(ISADevice *dev) rtc_set_date_from_host(dev); - s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); #ifdef TARGET_I386 - if (rtc_td_hack) + switch (s->lost_tick_policy) { + case LOST_TICK_SLEW: s->coalesced_timer = qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s); + break; + case LOST_TICK_DISCARD: + break; + default: + return -EINVAL; + } #endif + + s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s); s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s); s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s); @@ -676,8 +686,8 @@ static int rtc_initfn(ISADevice *dev) qdev_set_legacy_instance_id(&dev->qdev, base, 2); qemu_register_reset(rtc_reset, s); - qdev_property_add(&s->dev.qdev, "date", "struct tm", - rtc_get_date, NULL, NULL, s, NULL); + object_property_add(OBJECT(s), "date", "struct tm", + rtc_get_date, NULL, NULL, s, NULL); return 0; } @@ -699,20 +709,32 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) return dev; } -static ISADeviceInfo mc146818rtc_info = { - .qdev.name = "mc146818rtc", - .qdev.size = sizeof(RTCState), - .qdev.no_user = 1, - .qdev.vmsd = &vmstate_rtc, - .init = rtc_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), - DEFINE_PROP_END_OF_LIST(), - } +static Property mc146818rtc_properties[] = { + DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980), + DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState, + lost_tick_policy, LOST_TICK_DISCARD), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rtc_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = rtc_initfn; + dc->no_user = 1; + dc->vmsd = &vmstate_rtc; + dc->props = mc146818rtc_properties; +} + +static TypeInfo mc146818rtc_info = { + .name = "mc146818rtc", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(RTCState), + .class_init = rtc_class_initfn, }; static void mc146818rtc_register(void) { - isa_qdev_register(&mc146818rtc_info); + type_register_static(&mc146818rtc_info); } device_init(mc146818rtc_register) diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c index e824a49e9a..0881643a4c 100644 --- a/hw/milkymist-ac97.c +++ b/hw/milkymist-ac97.c @@ -319,17 +319,26 @@ static const VMStateDescription vmstate_milkymist_ac97 = { } }; -static SysBusDeviceInfo milkymist_ac97_info = { - .init = milkymist_ac97_init, - .qdev.name = "milkymist-ac97", - .qdev.size = sizeof(MilkymistAC97State), - .qdev.vmsd = &vmstate_milkymist_ac97, - .qdev.reset = milkymist_ac97_reset, +static void milkymist_ac97_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_ac97_init; + dc->reset = milkymist_ac97_reset; + dc->vmsd = &vmstate_milkymist_ac97; +} + +static TypeInfo milkymist_ac97_info = { + .name = "milkymist-ac97", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistAC97State), + .class_init = milkymist_ac97_class_init, }; static void milkymist_ac97_register(void) { - sysbus_register_withprop(&milkymist_ac97_info); + type_register_static(&milkymist_ac97_info); } device_init(milkymist_ac97_register) diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c index be575c98a0..b5122afd57 100644 --- a/hw/milkymist-hpdmc.c +++ b/hw/milkymist-hpdmc.c @@ -145,17 +145,26 @@ static const VMStateDescription vmstate_milkymist_hpdmc = { } }; -static SysBusDeviceInfo milkymist_hpdmc_info = { - .init = milkymist_hpdmc_init, - .qdev.name = "milkymist-hpdmc", - .qdev.size = sizeof(MilkymistHpdmcState), - .qdev.vmsd = &vmstate_milkymist_hpdmc, - .qdev.reset = milkymist_hpdmc_reset, +static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_hpdmc_init; + dc->reset = milkymist_hpdmc_reset; + dc->vmsd = &vmstate_milkymist_hpdmc; +} + +static TypeInfo milkymist_hpdmc_info = { + .name = "milkymist-hpdmc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistHpdmcState), + .class_init = milkymist_hpdmc_class_init, }; static void milkymist_hpdmc_register(void) { - sysbus_register_withprop(&milkymist_hpdmc_info); + type_register_static(&milkymist_hpdmc_info); } device_init(milkymist_hpdmc_register) diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c index 865a46c127..3c1c68a2e7 100644 --- a/hw/milkymist-memcard.c +++ b/hw/milkymist-memcard.c @@ -278,17 +278,26 @@ static const VMStateDescription vmstate_milkymist_memcard = { } }; -static SysBusDeviceInfo milkymist_memcard_info = { - .init = milkymist_memcard_init, - .qdev.name = "milkymist-memcard", - .qdev.size = sizeof(MilkymistMemcardState), - .qdev.vmsd = &vmstate_milkymist_memcard, - .qdev.reset = milkymist_memcard_reset, +static void milkymist_memcard_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_memcard_init; + dc->reset = milkymist_memcard_reset; + dc->vmsd = &vmstate_milkymist_memcard; +} + +static TypeInfo milkymist_memcard_info = { + .name = "milkymist-memcard", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistMemcardState), + .class_init = milkymist_memcard_class_init, }; static void milkymist_memcard_register(void) { - sysbus_register_withprop(&milkymist_memcard_info); + type_register_static(&milkymist_memcard_info); } device_init(milkymist_memcard_register) diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c index 7006d29788..b9b553fc95 100644 --- a/hw/milkymist-minimac2.c +++ b/hw/milkymist-minimac2.c @@ -479,7 +479,7 @@ static int milkymist_minimac2_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; @@ -516,24 +516,35 @@ static const VMStateDescription vmstate_milkymist_minimac2 = { } }; -static SysBusDeviceInfo milkymist_minimac2_info = { - .init = milkymist_minimac2_init, - .qdev.name = "milkymist-minimac2", - .qdev.size = sizeof(MilkymistMinimac2State), - .qdev.vmsd = &vmstate_milkymist_minimac2, - .qdev.reset = milkymist_minimac2_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State, - buffers_base, 0), - DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf), - DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model), - DEFINE_PROP_END_OF_LIST(), - } +static Property milkymist_minimac2_properties[] = { + DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State, + buffers_base, 0), + DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf), + DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model), + DEFINE_PROP_END_OF_LIST(), +}; + +static void milkymist_minimac2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_minimac2_init; + dc->reset = milkymist_minimac2_reset; + dc->vmsd = &vmstate_milkymist_minimac2; + dc->props = milkymist_minimac2_properties; +} + +static TypeInfo milkymist_minimac2_info = { + .name = "milkymist-minimac2", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistMinimac2State), + .class_init = milkymist_minimac2_class_init, }; static void milkymist_minimac2_register(void) { - sysbus_register_withprop(&milkymist_minimac2_info); + type_register_static(&milkymist_minimac2_info); } device_init(milkymist_minimac2_register) diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c index dc92eb68e3..1b73a4686b 100644 --- a/hw/milkymist-pfpu.c +++ b/hw/milkymist-pfpu.c @@ -519,17 +519,26 @@ static const VMStateDescription vmstate_milkymist_pfpu = { } }; -static SysBusDeviceInfo milkymist_pfpu_info = { - .init = milkymist_pfpu_init, - .qdev.name = "milkymist-pfpu", - .qdev.size = sizeof(MilkymistPFPUState), - .qdev.vmsd = &vmstate_milkymist_pfpu, - .qdev.reset = milkymist_pfpu_reset, +static void milkymist_pfpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_pfpu_init; + dc->reset = milkymist_pfpu_reset; + dc->vmsd = &vmstate_milkymist_pfpu; +} + +static TypeInfo milkymist_pfpu_info = { + .name = "milkymist-pfpu", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistPFPUState), + .class_init = milkymist_pfpu_class_init, }; static void milkymist_pfpu_register(void) { - sysbus_register_withprop(&milkymist_pfpu_info); + type_register_static(&milkymist_pfpu_info); } device_init(milkymist_pfpu_register) diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c index 83bd1c4c6b..5d496cbdb0 100644 --- a/hw/milkymist-softusb.c +++ b/hw/milkymist-softusb.c @@ -297,32 +297,35 @@ static const VMStateDescription vmstate_milkymist_softusb = { } }; -static SysBusDeviceInfo milkymist_softusb_info = { - .init = milkymist_softusb_init, - .qdev.name = "milkymist-softusb", - .qdev.size = sizeof(MilkymistSoftUsbState), - .qdev.vmsd = &vmstate_milkymist_softusb, - .qdev.reset = milkymist_softusb_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32( - "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000 - ), - DEFINE_PROP_UINT32( - "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000 - ), - DEFINE_PROP_UINT32( - "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000 - ), - DEFINE_PROP_UINT32( - "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000 - ), - DEFINE_PROP_END_OF_LIST(), - } +static Property milkymist_softusb_properties[] = { + DEFINE_PROP_UINT32("pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000), + DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000), + DEFINE_PROP_UINT32("dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000), + DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void milkymist_softusb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_softusb_init; + dc->reset = milkymist_softusb_reset; + dc->vmsd = &vmstate_milkymist_softusb; + dc->props = milkymist_softusb_properties; +} + +static TypeInfo milkymist_softusb_info = { + .name = "milkymist-softusb", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistSoftUsbState), + .class_init = milkymist_softusb_class_init, }; static void milkymist_softusb_register(void) { - sysbus_register_withprop(&milkymist_softusb_info); + type_register_static(&milkymist_softusb_info); } device_init(milkymist_softusb_register) diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c index bd2a298d2e..18171f6165 100644 --- a/hw/milkymist-sysctl.c +++ b/hw/milkymist-sysctl.c @@ -292,28 +292,39 @@ static const VMStateDescription vmstate_milkymist_sysctl = { } }; -static SysBusDeviceInfo milkymist_sysctl_info = { - .init = milkymist_sysctl_init, - .qdev.name = "milkymist-sysctl", - .qdev.size = sizeof(MilkymistSysctlState), - .qdev.vmsd = &vmstate_milkymist_sysctl, - .qdev.reset = milkymist_sysctl_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, - freq_hz, 80000000), - DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, - capabilities, 0x00000000), - DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, - systemid, 0x10014d31), - DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, - strappings, 0x00000001), - DEFINE_PROP_END_OF_LIST(), - } +static Property milkymist_sysctl_properties[] = { + DEFINE_PROP_UINT32("frequency", MilkymistSysctlState, + freq_hz, 80000000), + DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState, + capabilities, 0x00000000), + DEFINE_PROP_UINT32("systemid", MilkymistSysctlState, + systemid, 0x10014d31), + DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState, + strappings, 0x00000001), + DEFINE_PROP_END_OF_LIST(), +}; + +static void milkymist_sysctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_sysctl_init; + dc->reset = milkymist_sysctl_reset; + dc->vmsd = &vmstate_milkymist_sysctl; + dc->props = milkymist_sysctl_properties; +} + +static TypeInfo milkymist_sysctl_info = { + .name = "milkymist-sysctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistSysctlState), + .class_init = milkymist_sysctl_class_init, }; static void milkymist_sysctl_register(void) { - sysbus_register_withprop(&milkymist_sysctl_info); + type_register_static(&milkymist_sysctl_info); } device_init(milkymist_sysctl_register) diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c index 20110e5a83..474eae0a4a 100644 --- a/hw/milkymist-tmu2.c +++ b/hw/milkymist-tmu2.c @@ -465,17 +465,26 @@ static const VMStateDescription vmstate_milkymist_tmu2 = { } }; -static SysBusDeviceInfo milkymist_tmu2_info = { - .init = milkymist_tmu2_init, - .qdev.name = "milkymist-tmu2", - .qdev.size = sizeof(MilkymistTMU2State), - .qdev.vmsd = &vmstate_milkymist_tmu2, - .qdev.reset = milkymist_tmu2_reset, +static void milkymist_tmu2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_tmu2_init; + dc->reset = milkymist_tmu2_reset; + dc->vmsd = &vmstate_milkymist_tmu2; +} + +static TypeInfo milkymist_tmu2_info = { + .name = "milkymist-tmu2", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistTMU2State), + .class_init = milkymist_tmu2_class_init, }; static void milkymist_tmu2_register(void) { - sysbus_register_withprop(&milkymist_tmu2_info); + type_register_static(&milkymist_tmu2_info); } device_init(milkymist_tmu2_register) diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c index eaf1c0dce1..f9a229cf68 100644 --- a/hw/milkymist-uart.c +++ b/hw/milkymist-uart.c @@ -199,7 +199,7 @@ static int milkymist_uart_init(SysBusDevice *dev) "milkymist-uart", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); if (s->chr) { qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); } @@ -218,17 +218,26 @@ static const VMStateDescription vmstate_milkymist_uart = { } }; -static SysBusDeviceInfo milkymist_uart_info = { - .init = milkymist_uart_init, - .qdev.name = "milkymist-uart", - .qdev.size = sizeof(MilkymistUartState), - .qdev.vmsd = &vmstate_milkymist_uart, - .qdev.reset = milkymist_uart_reset, +static void milkymist_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_uart_init; + dc->reset = milkymist_uart_reset; + dc->vmsd = &vmstate_milkymist_uart; +} + +static TypeInfo milkymist_uart_info = { + .name = "milkymist-uart", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistUartState), + .class_init = milkymist_uart_class_init, }; static void milkymist_uart_register(void) { - sysbus_register_withprop(&milkymist_uart_info); + type_register_static(&milkymist_uart_info); } device_init(milkymist_uart_register) diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c index 108115e300..92ad02f9e2 100644 --- a/hw/milkymist-vgafb.c +++ b/hw/milkymist-vgafb.c @@ -299,22 +299,33 @@ static const VMStateDescription vmstate_milkymist_vgafb = { } }; -static SysBusDeviceInfo milkymist_vgafb_info = { - .init = milkymist_vgafb_init, - .qdev.name = "milkymist-vgafb", - .qdev.size = sizeof(MilkymistVgafbState), - .qdev.vmsd = &vmstate_milkymist_vgafb, - .qdev.reset = milkymist_vgafb_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0), - DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff), - DEFINE_PROP_END_OF_LIST(), - } +static Property milkymist_vgafb_properties[] = { + DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0), + DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff), + DEFINE_PROP_END_OF_LIST(), +}; + +static void milkymist_vgafb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = milkymist_vgafb_init; + dc->reset = milkymist_vgafb_reset; + dc->vmsd = &vmstate_milkymist_vgafb; + dc->props = milkymist_vgafb_properties; +} + +static TypeInfo milkymist_vgafb_info = { + .name = "milkymist-vgafb", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MilkymistVgafbState), + .class_init = milkymist_vgafb_class_init, }; static void milkymist_vgafb_register(void) { - sysbus_register_withprop(&milkymist_vgafb_info); + type_register_static(&milkymist_vgafb_info); } device_init(milkymist_vgafb_register) diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h index 69af9ef3f6..1d33ee8b50 100644 --- a/hw/milkymist-vgafb_template.h +++ b/hw/milkymist-vgafb_template.h @@ -39,7 +39,7 @@ #elif BITS == 24 #define COPY_PIXEL(to, r, g, b) \ do { \ - uint32 tmp = rgb_to_pixel24(r, g, b); \ + uint32_t tmp = rgb_to_pixel24(r, g, b); \ *(to++) = tmp & 0xff; \ *(to++) = (tmp >> 8) & 0xff; \ *(to++) = (tmp >> 16) & 0xff; \ diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e625ec398f..d232630e66 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -996,11 +996,7 @@ void mips_malta_init (ram_addr_t ram_size, if (cirrus_vga_enabled) { pci_cirrus_vga_init(pci_bus); } else if (vmsvga_enabled) { - if (!pci_vmsvga_init(pci_bus)) { - fprintf(stderr, "Warning: vmware_vga not available," - " using standard VGA instead\n"); - pci_vga_init(pci_bus); - } + pci_vmsvga_init(pci_bus); } else if (std_vga_enabled) { pci_vga_init(pci_bus); } @@ -1011,13 +1007,18 @@ static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev) return 0; } -static SysBusDeviceInfo mips_malta_device = { - .init = mips_malta_sysbus_device_init, - .qdev.name = "mips-malta", - .qdev.size = sizeof(MaltaState), - .qdev.props = (Property[]) { - DEFINE_PROP_END_OF_LIST(), - } +static void mips_malta_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mips_malta_sysbus_device_init; +} + +static TypeInfo mips_malta_device = { + .name = "mips-malta", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MaltaState), + .class_init = mips_malta_class_init, }; static QEMUMachine mips_malta_machine = { @@ -1030,7 +1031,7 @@ static QEMUMachine mips_malta_machine = { static void mips_malta_device_init(void) { - sysbus_register_withprop(&mips_malta_device); + type_register_static(&mips_malta_device); } static void mips_malta_machine_init(void) diff --git a/hw/mipsnet.c b/hw/mipsnet.c index b1234b8282..a0e6c9fa1e 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -240,7 +240,7 @@ static int mipsnet_sysbus_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; @@ -252,22 +252,33 @@ static void mipsnet_sysbus_reset(DeviceState *dev) mipsnet_reset(s); } -static SysBusDeviceInfo mipsnet_info = { - .init = mipsnet_sysbus_init, - .qdev.name = "mipsnet", - .qdev.desc = "MIPS Simulator network device", - .qdev.size = sizeof(MIPSnetState), - .qdev.vmsd = &vmstate_mipsnet, - .qdev.reset = mipsnet_sysbus_reset, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(MIPSnetState, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property mipsnet_properties[] = { + DEFINE_NIC_PROPERTIES(MIPSnetState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mipsnet_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mipsnet_sysbus_init; + dc->desc = "MIPS Simulator network device"; + dc->reset = mipsnet_sysbus_reset; + dc->vmsd = &vmstate_mipsnet; + dc->props = mipsnet_properties; +} + +static TypeInfo mipsnet_info = { + .name = "mipsnet", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MIPSnetState), + .class_init = mipsnet_class_init, }; static void mipsnet_register_devices(void) { - sysbus_register_withprop(&mipsnet_info); + type_register_static(&mipsnet_info); } device_init(mipsnet_register_devices) diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c index f01b38cfc2..28cd60d89c 100644 --- a/hw/mpc8544_guts.c +++ b/hw/mpc8544_guts.c @@ -121,14 +121,22 @@ static int mpc8544_guts_initfn(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo mpc8544_guts_info = { - .init = mpc8544_guts_initfn, - .qdev.name = "mpc8544-guts", - .qdev.size = sizeof(GutsState), +static void mpc8544_guts_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mpc8544_guts_initfn; +} + +static TypeInfo mpc8544_guts_info = { + .name = "mpc8544-guts", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GutsState), + .class_init = mpc8544_guts_class_init, }; static void mpc8544_guts_register(void) { - sysbus_register_withprop(&mpc8544_guts_info); + type_register_static(&mpc8544_guts_info); } device_init(mpc8544_guts_register); @@ -36,6 +36,9 @@ #define PCI_MSI_VECTORS_MAX 32 +/* Flag for interrupt controller to declare MSI/MSI-X support */ +bool msi_supported; + /* If we get rid of cap allocator, we won't need this. */ static inline uint8_t msi_cap_sizeof(uint16_t flags) { @@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset, uint16_t flags; uint8_t cap_size; int config_offset; + + if (!msi_supported) { + return -ENOTSUP; + } + MSI_DEV_PRINTF(dev, "init offset: 0x%"PRIx8" vector: %"PRId8 " 64bit %d mask %d\n", @@ -24,6 +24,8 @@ #include "qemu-common.h" #include "pci.h" +extern bool msi_supported; + bool msi_enabled(const PCIDevice *dev); int msi_init(struct PCIDevice *dev, uint8_t offset, unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask); @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "msi.h" #include "msix.h" #include "pci.h" #include "range.h" @@ -35,9 +36,6 @@ #define MSIX_MAX_ENTRIES 32 -/* Flag for interrupt controller to declare MSI-X support */ -int msix_supported; - /* Add MSI-X capability to the config space for the device. */ /* Given a bar and its size, add MSI-X table on top of it * and fill MSI-X capability in the config space. @@ -238,10 +236,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, unsigned bar_nr, unsigned bar_size) { int ret; + /* Nothing to do if MSI is not supported by interrupt controller */ - if (!msix_supported) + if (!msi_supported) { return -ENOTSUP; - + } if (nentries > MSIX_MAX_ENTRIES) return -EINVAL; @@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector); void msix_reset(PCIDevice *dev); -extern int msix_supported; - #endif diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 8bfa5dda37..1729db01a4 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -238,16 +238,25 @@ static VMStateDescription vmstate_mst_fpga_regs = { }, }; -static SysBusDeviceInfo mst_fpga_info = { - .init = mst_fpga_init, - .qdev.name = "mainstone-fpga", - .qdev.desc = "Mainstone II FPGA", - .qdev.size = sizeof(mst_irq_state), - .qdev.vmsd = &vmstate_mst_fpga_regs, +static void mst_fpga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mst_fpga_init; + dc->desc = "Mainstone II FPGA"; + dc->vmsd = &vmstate_mst_fpga_regs; +} + +static TypeInfo mst_fpga_info = { + .name = "mainstone-fpga", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mst_irq_state), + .class_init = mst_fpga_class_init, }; static void mst_fpga_register(void) { - sysbus_register_withprop(&mst_fpga_info); + type_register_static(&mst_fpga_info); } device_init(mst_fpga_register); diff --git a/hw/musicpal.c b/hw/musicpal.c index 977ffb6e50..ac909248d4 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -387,7 +387,7 @@ static int mv88w8618_eth_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth", MP_ETH_SIZE); sysbus_init_mmio(dev, &s->iomem); @@ -412,15 +412,26 @@ static const VMStateDescription mv88w8618_eth_vmsd = { } }; -static SysBusDeviceInfo mv88w8618_eth_info = { - .init = mv88w8618_eth_init, - .qdev.name = "mv88w8618_eth", - .qdev.size = sizeof(mv88w8618_eth_state), - .qdev.vmsd = &mv88w8618_eth_vmsd, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), - DEFINE_PROP_END_OF_LIST(), - }, +static Property mv88w8618_eth_properties[] = { + DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_eth_init; + dc->vmsd = &mv88w8618_eth_vmsd; + dc->props = mv88w8618_eth_properties; +} + +static TypeInfo mv88w8618_eth_info = { + .name = "mv88w8618_eth", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_eth_state), + .class_init = mv88w8618_eth_class_init, }; /* LCD register offsets */ @@ -624,11 +635,20 @@ static const VMStateDescription musicpal_lcd_vmsd = { } }; -static SysBusDeviceInfo musicpal_lcd_info = { - .init = musicpal_lcd_init, - .qdev.name = "musicpal_lcd", - .qdev.size = sizeof(musicpal_lcd_state), - .qdev.vmsd = &musicpal_lcd_vmsd, +static void musicpal_lcd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_lcd_init; + dc->vmsd = &musicpal_lcd_vmsd; +} + +static TypeInfo musicpal_lcd_info = { + .name = "musicpal_lcd", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_lcd_state), + .class_init = musicpal_lcd_class_init, }; /* PIC register offsets */ @@ -733,12 +753,21 @@ static const VMStateDescription mv88w8618_pic_vmsd = { } }; -static SysBusDeviceInfo mv88w8618_pic_info = { - .init = mv88w8618_pic_init, - .qdev.name = "mv88w8618_pic", - .qdev.size = sizeof(mv88w8618_pic_state), - .qdev.reset = mv88w8618_pic_reset, - .qdev.vmsd = &mv88w8618_pic_vmsd, +static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_pic_init; + dc->reset = mv88w8618_pic_reset; + dc->vmsd = &mv88w8618_pic_vmsd; +} + +static TypeInfo mv88w8618_pic_info = { + .name = "mv88w8618_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_pic_state), + .class_init = mv88w8618_pic_class_init, }; /* PIT register offsets */ @@ -901,12 +930,21 @@ static const VMStateDescription mv88w8618_pit_vmsd = { } }; -static SysBusDeviceInfo mv88w8618_pit_info = { - .init = mv88w8618_pit_init, - .qdev.name = "mv88w8618_pit", - .qdev.size = sizeof(mv88w8618_pit_state), - .qdev.reset = mv88w8618_pit_reset, - .qdev.vmsd = &mv88w8618_pit_vmsd, +static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_pit_init; + dc->reset = mv88w8618_pit_reset; + dc->vmsd = &mv88w8618_pit_vmsd; +} + +static TypeInfo mv88w8618_pit_info = { + .name = "mv88w8618_pit", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_pit_state), + .class_init = mv88w8618_pit_class_init, }; /* Flash config register offsets */ @@ -973,11 +1011,20 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = { } }; -static SysBusDeviceInfo mv88w8618_flashcfg_info = { - .init = mv88w8618_flashcfg_init, - .qdev.name = "mv88w8618_flashcfg", - .qdev.size = sizeof(mv88w8618_flashcfg_state), - .qdev.vmsd = &mv88w8618_flashcfg_vmsd, +static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = mv88w8618_flashcfg_init; + dc->vmsd = &mv88w8618_flashcfg_vmsd; +} + +static TypeInfo mv88w8618_flashcfg_info = { + .name = "mv88w8618_flashcfg", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(mv88w8618_flashcfg_state), + .class_init = mv88w8618_flashcfg_class_init, }; /* Misc register offsets */ @@ -1285,12 +1332,21 @@ static const VMStateDescription musicpal_gpio_vmsd = { } }; -static SysBusDeviceInfo musicpal_gpio_info = { - .init = musicpal_gpio_init, - .qdev.name = "musicpal_gpio", - .qdev.size = sizeof(musicpal_gpio_state), - .qdev.reset = musicpal_gpio_reset, - .qdev.vmsd = &musicpal_gpio_vmsd, +static void musicpal_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_gpio_init; + dc->reset = musicpal_gpio_reset; + dc->vmsd = &musicpal_gpio_vmsd; +} + +static TypeInfo musicpal_gpio_info = { + .name = "musicpal_gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_gpio_state), + .class_init = musicpal_gpio_class_init, }; /* Keyboard codes & masks */ @@ -1431,11 +1487,20 @@ static const VMStateDescription musicpal_key_vmsd = { } }; -static SysBusDeviceInfo musicpal_key_info = { - .init = musicpal_key_init, - .qdev.name = "musicpal_key", - .qdev.size = sizeof(musicpal_key_state), - .qdev.vmsd = &musicpal_key_vmsd, +static void musicpal_key_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = musicpal_key_init; + dc->vmsd = &musicpal_key_vmsd; +} + +static TypeInfo musicpal_key_info = { + .name = "musicpal_key", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(musicpal_key_state), + .class_init = musicpal_key_class_init, }; static struct arm_boot_info musicpal_binfo = { @@ -1602,17 +1667,30 @@ static void musicpal_machine_init(void) machine_init(musicpal_machine_init); +static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = mv88w8618_wlan_init; +} + +static TypeInfo mv88w8618_wlan_info = { + .name = "mv88w8618_wlan", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = mv88w8618_wlan_class_init, +}; + static void musicpal_register_devices(void) { - sysbus_register_withprop(&mv88w8618_pic_info); - sysbus_register_withprop(&mv88w8618_pit_info); - sysbus_register_withprop(&mv88w8618_flashcfg_info); - sysbus_register_withprop(&mv88w8618_eth_info); - sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice), - mv88w8618_wlan_init); - sysbus_register_withprop(&musicpal_lcd_info); - sysbus_register_withprop(&musicpal_gpio_info); - sysbus_register_withprop(&musicpal_key_info); + type_register_static(&mv88w8618_pic_info); + type_register_static(&mv88w8618_pit_info); + type_register_static(&mv88w8618_flashcfg_info); + type_register_static(&mv88w8618_eth_info); + type_register_static(&mv88w8618_wlan_info); + type_register_static(&musicpal_lcd_info); + type_register_static(&musicpal_gpio_info); + type_register_static(&musicpal_key_info); } device_init(musicpal_register_devices) @@ -417,23 +417,34 @@ static int nand_device_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo nand_info = { - .init = nand_device_init, - .qdev.name = "nand", - .qdev.size = sizeof(NANDFlashState), - .qdev.reset = nand_reset, - .qdev.vmsd = &vmstate_nand, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0), - DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0), - DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv), - DEFINE_PROP_END_OF_LIST() - } +static Property nand_properties[] = { + DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0), + DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0), + DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv), + DEFINE_PROP_END_OF_LIST(), +}; + +static void nand_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = nand_device_init; + dc->reset = nand_reset; + dc->vmsd = &vmstate_nand; + dc->props = nand_properties; +} + +static TypeInfo nand_info = { + .name = "nand", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(NANDFlashState), + .class_init = nand_class_init, }; static void nand_create_device(void) { - sysbus_register_withprop(&nand_info); + type_register_static(&nand_info); } /* diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c index 11ffee7d7c..1352282152 100644 --- a/hw/ne2000-isa.c +++ b/hw/ne2000-isa.c @@ -76,27 +76,37 @@ static int isa_ne2000_initfn(ISADevice *dev) ne2000_reset(s); s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); return 0; } -static ISADeviceInfo ne2000_isa_info = { - .qdev.name = "ne2k_isa", - .qdev.size = sizeof(ISANE2000State), - .init = isa_ne2000_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300), - DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9), - DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c), - DEFINE_PROP_END_OF_LIST(), - }, +static Property ne2000_isa_properties[] = { + DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300), + DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9), + DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c), + DEFINE_PROP_END_OF_LIST(), +}; + +static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = isa_ne2000_initfn; + dc->props = ne2000_isa_properties; +} + +static TypeInfo ne2000_isa_info = { + .name = "ne2k_isa", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISANE2000State), + .class_init = isa_ne2000_class_initfn, }; static void ne2000_isa_register_devices(void) { - isa_qdev_register(&ne2000_isa_info); + type_register_static(&ne2000_isa_info); } device_init(ne2000_isa_register_devices) diff --git a/hw/ne2000.c b/hw/ne2000.c index 62e082f8a9..080811ec4d 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -760,7 +760,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev) ne2000_reset(s); s->nic = qemu_new_nic(&net_ne2000_info, &s->c, - pci_dev->qdev.info->name, pci_dev->qdev.id, s); + object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a); if (!pci_dev->qdev.hotplugged) { @@ -786,24 +786,35 @@ static int pci_ne2000_exit(PCIDevice *pci_dev) return 0; } -static PCIDeviceInfo ne2000_info = { - .qdev.name = "ne2k_pci", - .qdev.size = sizeof(PCINE2000State), - .qdev.vmsd = &vmstate_pci_ne2000, - .init = pci_ne2000_init, - .exit = pci_ne2000_exit, - .vendor_id = PCI_VENDOR_ID_REALTEK, - .device_id = PCI_DEVICE_ID_REALTEK_8029, - .class_id = PCI_CLASS_NETWORK_ETHERNET, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c), - DEFINE_PROP_END_OF_LIST(), - } +static Property ne2000_properties[] = { + DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ne2000_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_ne2000_init; + k->exit = pci_ne2000_exit; + k->vendor_id = PCI_VENDOR_ID_REALTEK; + k->device_id = PCI_DEVICE_ID_REALTEK_8029; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + dc->vmsd = &vmstate_pci_ne2000; + dc->props = ne2000_properties; +} + +static TypeInfo ne2000_info = { + .name = "ne2k_pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCINE2000State), + .class_init = ne2000_class_init, }; static void ne2000_register_devices(void) { - pci_qdev_register(&ne2000_info); + type_register_static(&ne2000_info); } device_init(ne2000_register_devices) diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c index 29147be8b8..9a9a8e183f 100644 --- a/hw/omap_gpio.c +++ b/hw/omap_gpio.c @@ -731,40 +731,62 @@ static int omap2_gpio_init(SysBusDevice *dev) * translation.) */ -static SysBusDeviceInfo omap_gpio_info = { - .init = omap_gpio_init, - .qdev.name = "omap-gpio", - .qdev.size = sizeof(struct omap_gpif_s), - .qdev.reset = omap_gpif_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0), - DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk), - DEFINE_PROP_END_OF_LIST() - } +static Property omap_gpio_properties[] = { + DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0), + DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo omap2_gpio_info = { - .init = omap2_gpio_init, - .qdev.name = "omap2-gpio", - .qdev.size = sizeof(struct omap2_gpif_s), - .qdev.reset = omap2_gpif_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0), - DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk), - DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]), - DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]), - DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]), - DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]), - DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]), - DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]), - DEFINE_PROP_END_OF_LIST() - } +static void omap_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = omap_gpio_init; + dc->reset = omap_gpif_reset; + dc->props = omap_gpio_properties; +} + +static TypeInfo omap_gpio_info = { + .name = "omap-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct omap_gpif_s), + .class_init = omap_gpio_class_init, +}; + +static Property omap2_gpio_properties[] = { + DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0), + DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk), + DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]), + DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]), + DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]), + DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]), + DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]), + DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]), + DEFINE_PROP_END_OF_LIST(), +}; + +static void omap2_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = omap2_gpio_init; + dc->reset = omap2_gpif_reset; + dc->props = omap2_gpio_properties; +} + +static TypeInfo omap2_gpio_info = { + .name = "omap2-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct omap2_gpif_s), + .class_init = omap2_gpio_class_init, }; static void omap_gpio_register_device(void) { - sysbus_register_withprop(&omap_gpio_info); - sysbus_register_withprop(&omap2_gpio_info); + type_register_static(&omap_gpio_info); + type_register_static(&omap2_gpio_info); } device_init(omap_gpio_register_device) diff --git a/hw/omap_intc.c b/hw/omap_intc.c index fc53ec71fb..5aa98a8fdb 100644 --- a/hw/omap_intc.c +++ b/hw/omap_intc.c @@ -373,16 +373,27 @@ static int omap_intc_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo omap_intc_info = { - .init = omap_intc_init, - .qdev.name = "omap-intc", - .qdev.size = sizeof(struct omap_intr_handler_s), - .qdev.reset = omap_inth_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100), - DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk), - DEFINE_PROP_END_OF_LIST() - } +static Property omap_intc_properties[] = { + DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100), + DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void omap_intc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = omap_intc_init; + dc->reset = omap_inth_reset; + dc->props = omap_intc_properties; +} + +static TypeInfo omap_intc_info = { + .name = "omap-intc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct omap_intr_handler_s), + .class_init = omap_intc_class_init, }; static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr, @@ -604,24 +615,35 @@ static int omap2_intc_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo omap2_intc_info = { - .init = omap2_intc_init, - .qdev.name = "omap2-intc", - .qdev.size = sizeof(struct omap_intr_handler_s), - .qdev.reset = omap_inth_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s, - revision, 0x21), - DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk), - DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk), - DEFINE_PROP_END_OF_LIST() - } +static Property omap2_intc_properties[] = { + DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s, + revision, 0x21), + DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk), + DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk), + DEFINE_PROP_END_OF_LIST(), +}; + +static void omap2_intc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = omap2_intc_init; + dc->reset = omap_inth_reset; + dc->props = omap2_intc_properties; +} + +static TypeInfo omap2_intc_info = { + .name = "omap2-intc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct omap_intr_handler_s), + .class_init = omap2_intc_class_init, }; static void omap_intc_register_device(void) { - sysbus_register_withprop(&omap_intc_info); - sysbus_register_withprop(&omap2_intc_info); + type_register_static(&omap_intc_info); + type_register_static(&omap2_intc_info); } device_init(omap_intc_register_device) diff --git a/hw/onenand.c b/hw/onenand.c index 33c9718629..8744b04db3 100644 --- a/hw/onenand.c +++ b/hw/onenand.c @@ -802,24 +802,35 @@ static int onenand_initfn(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo onenand_info = { - .init = onenand_initfn, - .qdev.name = "onenand", - .qdev.size = sizeof(OneNANDState), - .qdev.reset = onenand_system_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0), - DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0), - DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0), - DEFINE_PROP_INT32("shift", OneNANDState, shift, 0), - DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv), - DEFINE_PROP_END_OF_LIST() - } +static Property onenand_properties[] = { + DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0), + DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0), + DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0), + DEFINE_PROP_INT32("shift", OneNANDState, shift, 0), + DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv), + DEFINE_PROP_END_OF_LIST(), +}; + +static void onenand_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = onenand_initfn; + dc->reset = onenand_system_reset; + dc->props = onenand_properties; +} + +static TypeInfo onenand_info = { + .name = "onenand", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OneNANDState), + .class_init = onenand_class_init, }; static void onenand_register_device(void) { - sysbus_register_withprop(&onenand_info); + type_register_static(&onenand_info); } void *onenand_raw_otp(DeviceState *onenand_device) diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c index f7cc1b403b..09f2757df3 100644 --- a/hw/opencores_eth.c +++ b/hw/opencores_eth.c @@ -717,7 +717,7 @@ static int sysbus_open_eth_init(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); s->nic = qemu_new_nic(&net_open_eth_info, &s->conf, - s->dev.qdev.info->name, s->dev.qdev.id, s); + object_get_typename(OBJECT(s)), s->dev.qdev.id, s); return 0; } @@ -727,21 +727,32 @@ static void qdev_open_eth_reset(DeviceState *dev) open_eth_reset(d); } -static SysBusDeviceInfo open_eth_info = { - .qdev.name = "open_eth", - .qdev.desc = "Opencores 10/100 Mbit Ethernet", - .qdev.size = sizeof(OpenEthState), - .qdev.reset = qdev_open_eth_reset, - .init = sysbus_open_eth_init, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(OpenEthState, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property open_eth_properties[] = { + DEFINE_NIC_PROPERTIES(OpenEthState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void open_eth_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sysbus_open_eth_init; + dc->desc = "Opencores 10/100 Mbit Ethernet"; + dc->reset = qdev_open_eth_reset; + dc->props = open_eth_properties; +} + +static TypeInfo open_eth_info = { + .name = "open_eth", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OpenEthState), + .class_init = open_eth_class_init, }; static void open_eth_register_devices(void) { - sysbus_register_withprop(&open_eth_info); + type_register_static(&open_eth_info); } device_init(open_eth_register_devices) diff --git a/hw/openpic.c b/hw/openpic.c index 22fc275b62..280b7a9bbb 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -1181,41 +1181,17 @@ static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src) qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } -qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus, +qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) { openpic_t *opp; - uint8_t *pci_conf; int i, m; /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; - if (bus) { - opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), - -1, NULL, NULL); - pci_conf = opp->pci_dev.config; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2); - pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME? - pci_conf[0x3d] = 0x00; // no interrupt pin - - memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); -#if 0 // Don't implement ISU for now - opp_io_memory = cpu_register_io_memory(openpic_src_read, - openpic_src_write, NULL - DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), - opp_io_memory); -#endif - - /* Register I/O spaces */ - pci_register_bar(&opp->pci_dev, 0, - PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem); - } else { - opp = g_malloc0(sizeof(openpic_t)); - memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); - } + opp = g_malloc0(sizeof(openpic_t)); + memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); // isu_base &= 0xFFFC0000; opp->nb_cpus = nb_cpus; diff --git a/hw/openpic.h b/hw/openpic.h index 715f0847bf..855603026b 100644 --- a/hw/openpic.h +++ b/hw/openpic.h @@ -11,7 +11,7 @@ enum { OPENPIC_OUTPUT_NB, }; -qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus, +qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out); qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out); diff --git a/hw/parallel.c b/hw/parallel.c index c4c5dbee5b..484d727927 100644 --- a/hw/parallel.c +++ b/hw/parallel.c @@ -583,22 +583,32 @@ bool parallel_mm_init(MemoryRegion *address_space, return true; } -static ISADeviceInfo parallel_isa_info = { - .qdev.name = "isa-parallel", - .qdev.size = sizeof(ISAParallelState), - .init = parallel_isa_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("index", ISAParallelState, index, -1), - DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7), - DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr), - DEFINE_PROP_END_OF_LIST(), - }, +static Property parallel_isa_properties[] = { + DEFINE_PROP_UINT32("index", ISAParallelState, index, -1), + DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1), + DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7), + DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void parallel_isa_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = parallel_isa_initfn; + dc->props = parallel_isa_properties; +} + +static TypeInfo parallel_isa_info = { + .name = "isa-parallel", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISAParallelState), + .class_init = parallel_isa_class_initfn, }; static void parallel_register_devices(void) { - isa_qdev_register(¶llel_isa_info); + type_register_static(¶llel_isa_info); } device_init(parallel_register_devices) @@ -36,9 +36,10 @@ #include "elf.h" #include "multiboot.h" #include "mc146818rtc.h" -#include "msix.h" +#include "msi.h" #include "sysbus.h" #include "sysemu.h" +#include "kvm.h" #include "blockdev.h" #include "ui/qemu-spice.h" #include "memory.h" @@ -496,18 +497,26 @@ static int port92_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo port92_info = { - .qdev.name = "port92", - .qdev.size = sizeof(Port92State), - .qdev.vmsd = &vmstate_port92_isa, - .qdev.no_user = 1, - .qdev.reset = port92_reset, - .init = port92_initfn, +static void port92_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = port92_initfn; + dc->no_user = 1; + dc->reset = port92_reset; + dc->vmsd = &vmstate_port92_isa; +} + +static TypeInfo port92_info = { + .name = "port92", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(Port92State), + .class_init = port92_class_initfn, }; static void port92_register(void) { - isa_qdev_register(&port92_info); + type_register_static(&port92_info); } device_init(port92_register) @@ -609,7 +618,7 @@ static void *bochs_bios_init(void) fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables, acpi_tables_len); - fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1); + fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); smbios_table = smbios_get_table(&smbios_len); if (smbios_table) @@ -878,25 +887,30 @@ DeviceState *cpu_get_current_apic(void) static DeviceState *apic_init(void *env, uint8_t apic_id) { DeviceState *dev; - SysBusDevice *d; static int apic_mapped; - dev = qdev_create(NULL, "apic"); + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-apic"); + } else { + dev = qdev_create(NULL, "apic"); + } qdev_prop_set_uint8(dev, "id", apic_id); qdev_prop_set_ptr(dev, "cpu_env", env); qdev_init_nofail(dev); - d = sysbus_from_qdev(dev); /* XXX: mapping more APICs at the same memory location */ if (apic_mapped == 0) { /* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ /* XXX: what if the base changes? */ - sysbus_mmio_map(d, 0, MSI_ADDR_BASE); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE); apic_mapped = 1; } - msix_supported = 1; + /* KVM does not support MSI yet. */ + if (!kvm_enabled() || !kvm_irqchip_in_kernel()) { + msi_supported = true; + } return dev; } @@ -1080,16 +1094,11 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) if (pci_bus) { dev = pci_cirrus_vga_init(pci_bus); } else { - dev = isa_cirrus_vga_init(get_system_memory()); + dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev; } } else if (vmsvga_enabled) { if (pci_bus) { dev = pci_vmsvga_init(pci_bus); - if (!dev) { - fprintf(stderr, "Warning: vmware_vga not available," - " using standard VGA instead\n"); - dev = pci_vga_init(pci_bus); - } } else { fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } @@ -62,11 +62,11 @@ bool parallel_mm_init(MemoryRegion *address_space, /* i8259.c */ -typedef struct PicState PicState; -extern PicState *isa_pic; +extern DeviceState *isa_pic; qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); -int pic_read_irq(PicState *s); -int pic_get_output(PicState *s); +qemu_irq *kvm_i8259_init(ISABus *bus); +int pic_read_irq(DeviceState *d); +int pic_get_output(DeviceState *d); void pic_info(Monitor *mon); void irq_info(Monitor *mon); @@ -226,7 +226,6 @@ int isa_vga_mm_init(target_phys_addr_t vram_base, /* cirrus_vga.c */ DeviceState *pci_cirrus_vga_init(PCIBus *bus); -DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space); /* ne2000.c */ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 3aea3cc9de..c06f1b544e 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -34,7 +34,7 @@ #include "boards.h" #include "ide.h" #include "kvm.h" -#include "kvmclock.h" +#include "kvm/clock.h" #include "sysemu.h" #include "sysbus.h" #include "arch_init.h" @@ -53,13 +53,62 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; +static void kvm_piix3_setup_irq_routing(bool pci_enabled) +{ +#ifdef CONFIG_KVM + KVMState *s = kvm_state; + int ret, i; + + if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { + for (i = 0; i < 8; ++i) { + if (i == 2) { + continue; + } + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); + } + for (i = 8; i < 16; ++i) { + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); + } + if (pci_enabled) { + for (i = 0; i < 24; ++i) { + if (i == 0) { + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2); + } else if (i != 2) { + kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i); + } + } + } + ret = kvm_irqchip_commit_routes(s); + if (ret < 0) { + hw_error("KVM IRQ routing setup failed"); + } + } +#endif /* CONFIG_KVM */ +} + +static void kvm_piix3_gsi_handler(void *opaque, int n, int level) +{ + GSIState *s = opaque; + + if (n < ISA_NUM_IRQS) { + /* Kernel will forward to both PIC and IOAPIC */ + qemu_set_irq(s->i8259_irq[n], level); + } else { + qemu_set_irq(s->ioapic_irq[n], level); + } +} + static void ioapic_init(GSIState *gsi_state) { DeviceState *dev; SysBusDevice *d; unsigned int i; - dev = qdev_create(NULL, "ioapic"); + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + dev = qdev_create(NULL, "kvm-ioapic"); + } else { + dev = qdev_create(NULL, "ioapic"); + } qdev_init_nofail(dev); d = sysbus_from_qdev(dev); sysbus_mmio_map(d, 0, 0xfec00000); @@ -134,7 +183,13 @@ static void pc_init1(MemoryRegion *system_memory, } gsi_state = g_malloc0(sizeof(*gsi_state)); - gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_piix3_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, @@ -154,11 +209,13 @@ static void pc_init1(MemoryRegion *system_memory, } isa_bus_irqs(isa_bus, gsi); - if (!xen_enabled()) { + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { cpu_irq = pc_allocate_cpu_irq(); i8259 = i8259_init(isa_bus, cpu_irq[0]); - } else { - i8259 = xen_interrupt_controller_init(); } for (i = 0; i < ISA_NUM_IRQS; i++) { @@ -172,7 +229,7 @@ static void pc_init1(MemoryRegion *system_memory, dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); if (dev) { - qdev_property_add_child(qdev_get_root(), "vga", dev, NULL); + object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL); } if (xen_enabled()) { @@ -210,8 +267,8 @@ static void pc_init1(MemoryRegion *system_memory, * For now, let's "fix" this by making judicious use of paths. This * is not generally the right way to do this. */ - qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL), - "rtc", (DeviceState *)rtc_state, NULL); + object_property_add_child(object_resolve_path("/i440fx/piix3", NULL), + "rtc", (Object *)rtc_state, NULL); } else { for(i = 0; i < MAX_IDE_BUS; i++) { ISADevice *dev; @@ -89,7 +89,6 @@ static const VMStateDescription vmstate_pcibus = { VMSTATE_END_OF_LIST() } }; - static int pci_bar(PCIDevice *d, int reg) { uint8_t type; @@ -159,11 +158,8 @@ void pci_device_deassert_intx(PCIDevice *dev) void pci_device_reset(PCIDevice *dev) { int r; - /* TODO: call the below unconditionally once all pci devices - * are qdevified */ - if (dev->qdev.info) { - qdev_reset_all(&dev->qdev); - } + + qdev_reset_all(&dev->qdev); dev->irq_state = 0; pci_update_irq_status(dev); @@ -733,11 +729,11 @@ static void pci_config_free(PCIDevice *pci_dev) /* -1 for devfn means auto assign */ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, - const char *name, int devfn, - const PCIDeviceInfo *info) + const char *name, int devfn) { - PCIConfigReadFunc *config_read = info->config_read; - PCIConfigWriteFunc *config_write = info->config_write; + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); + PCIConfigReadFunc *config_read = pc->config_read; + PCIConfigWriteFunc *config_write = pc->config_write; if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices); @@ -759,29 +755,29 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, pci_dev->irq_state = 0; pci_config_alloc(pci_dev); - pci_config_set_vendor_id(pci_dev->config, info->vendor_id); - pci_config_set_device_id(pci_dev->config, info->device_id); - pci_config_set_revision(pci_dev->config, info->revision); - pci_config_set_class(pci_dev->config, info->class_id); + pci_config_set_vendor_id(pci_dev->config, pc->vendor_id); + pci_config_set_device_id(pci_dev->config, pc->device_id); + pci_config_set_revision(pci_dev->config, pc->revision); + pci_config_set_class(pci_dev->config, pc->class_id); - if (!info->is_bridge) { - if (info->subsystem_vendor_id || info->subsystem_id) { + if (!pc->is_bridge) { + if (pc->subsystem_vendor_id || pc->subsystem_id) { pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, - info->subsystem_vendor_id); + pc->subsystem_vendor_id); pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, - info->subsystem_id); + pc->subsystem_id); } else { pci_set_default_subsystem_id(pci_dev); } } else { /* subsystem_vendor_id/subsystem_id are only for header type 0 */ - assert(!info->subsystem_vendor_id); - assert(!info->subsystem_id); + assert(!pc->subsystem_vendor_id); + assert(!pc->subsystem_id); } pci_init_cmask(pci_dev); pci_init_wmask(pci_dev); pci_init_w1cmask(pci_dev); - if (info->is_bridge) { + if (pc->is_bridge) { pci_init_wmask_bridge(pci_dev); } if (pci_init_multifunction(bus, pci_dev)) { @@ -808,26 +804,6 @@ static void do_pci_unregister_device(PCIDevice *pci_dev) pci_config_free(pci_dev); } -/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */ -PCIDevice *pci_register_device(PCIBus *bus, const char *name, - int instance_size, int devfn, - PCIConfigReadFunc *config_read, - PCIConfigWriteFunc *config_write) -{ - PCIDevice *pci_dev; - PCIDeviceInfo info = { - .config_read = config_read, - .config_write = config_write, - }; - - pci_dev = g_malloc0(instance_size); - pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info); - if (pci_dev == NULL) { - hw_error("PCI: can't register device\n"); - } - return pci_dev; -} - static void pci_unregister_io_regions(PCIDevice *pci_dev) { PCIIORegion *r; @@ -843,12 +819,12 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev) static int pci_unregister_device(DeviceState *dev) { - PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev); - PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info); + PCIDevice *pci_dev = PCI_DEVICE(dev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); int ret = 0; - if (info->exit) - ret = info->exit(pci_dev); + if (pc->exit) + ret = pc->exit(pci_dev); if (ret) return ret; @@ -1477,31 +1453,32 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn) return bus->devices[devfn]; } -static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int pci_qdev_init(DeviceState *qdev) { PCIDevice *pci_dev = (PCIDevice *)qdev; - PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev); PCIBus *bus; int rc; bool is_default_rom; /* initialize cap_present for pci_is_express() and pci_config_size() */ - if (info->is_express) { + if (pc->is_express) { pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev)); - pci_dev = do_pci_register_device(pci_dev, bus, base->name, - pci_dev->devfn, info); + pci_dev = do_pci_register_device(pci_dev, bus, + object_get_typename(OBJECT(qdev)), + pci_dev->devfn); if (pci_dev == NULL) return -1; - if (qdev->hotplugged && info->no_hotplug) { - qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name); + if (qdev->hotplugged && pc->no_hotplug) { + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev))); do_pci_unregister_device(pci_dev); return -1; } - if (info->init) { - rc = info->init(pci_dev); + if (pc->init) { + rc = pc->init(pci_dev); if (rc != 0) { do_pci_unregister_device(pci_dev); return rc; @@ -1510,8 +1487,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) /* rom loading */ is_default_rom = false; - if (pci_dev->romfile == NULL && info->romfile != NULL) { - pci_dev->romfile = g_strdup(info->romfile); + if (pci_dev->romfile == NULL && pc->romfile != NULL) { + pci_dev->romfile = g_strdup(pc->romfile); is_default_rom = true; } pci_add_option_rom(pci_dev, is_default_rom); @@ -1533,34 +1510,18 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base) static int pci_unplug_device(DeviceState *qdev) { - PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev); + PCIDevice *dev = PCI_DEVICE(qdev); + PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); - if (info->no_hotplug) { - qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name); + if (pc->no_hotplug) { + qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev))); return -1; } + object_unparent(OBJECT(dev)); return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, PCI_HOTPLUG_DISABLED); } -void pci_qdev_register(PCIDeviceInfo *info) -{ - info->qdev.init = pci_qdev_init; - info->qdev.unplug = pci_unplug_device; - info->qdev.exit = pci_unregister_device; - info->qdev.bus_info = &pci_bus_info; - qdev_register(&info->qdev); -} - -void pci_qdev_register_many(PCIDeviceInfo *info) -{ - while (info->qdev.name) { - pci_qdev_register(info); - info++; - } -} - PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) { @@ -1569,22 +1530,7 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, dev = qdev_create(&bus->qbus, name); qdev_prop_set_uint32(dev, "addr", devfn); qdev_prop_set_bit(dev, "multifunction", multifunction); - return DO_UPCAST(PCIDevice, qdev, dev); -} - -PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name) -{ - DeviceState *dev; - - dev = qdev_try_create(&bus->qbus, name); - if (!dev) { - return NULL; - } - qdev_prop_set_uint32(dev, "addr", devfn); - qdev_prop_set_bit(dev, "multifunction", multifunction); - return DO_UPCAST(PCIDevice, qdev, dev); + return PCI_DEVICE(dev); } PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, @@ -1606,11 +1552,6 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) return pci_create_simple_multifunction(bus, devfn, false, name); } -PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name) -{ - return pci_try_create_multifunction(bus, devfn, false, name); -} - static int pci_find_space(PCIDevice *pdev, uint8_t size) { int config_size = pci_config_size(pdev); @@ -1724,6 +1665,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) char *path; void *ptr; char name[32]; + const VMStateDescription *vmsd; if (!pdev->romfile) return 0; @@ -1760,10 +1702,13 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) size = 1 << qemu_fls(size); } - if (pdev->qdev.info->vmsd) - snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name); - else - snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name); + vmsd = qdev_get_vmsd(DEVICE(pdev)); + + if (vmsd) { + snprintf(name, sizeof(name), "%s.rom", vmsd->name); + } else { + snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev))); + } pdev->has_rom = true; memory_region_init_ram(&pdev->rom, name, size); vmstate_register_ram(&pdev->rom, &pdev->qdev); @@ -2004,9 +1949,8 @@ static int pci_qdev_find_recursive(PCIBus *bus, } /* roughly check if given qdev is pci device */ - if (qdev->info->init == &pci_qdev_init && - qdev->parent_bus->info == &pci_bus_info) { - *pdev = DO_UPCAST(PCIDevice, qdev, qdev); + if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) { + *pdev = PCI_DEVICE(qdev); return 0; } return -EINVAL; @@ -2040,3 +1984,28 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev) { return dev->bus->address_space_io; } + +static void pci_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = pci_qdev_init; + k->unplug = pci_unplug_device; + k->exit = pci_unregister_device; + k->bus_info = &pci_bus_info; +} + +static TypeInfo pci_device_type_info = { + .name = TYPE_PCI_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(PCIDevice), + .abstract = true, + .class_size = sizeof(PCIDeviceClass), + .class_init = pci_device_class_init, +}; + +static void pci_register_devices(void) +{ + type_register_static(&pci_device_type_info); +} + +device_init(pci_register_devices); @@ -127,6 +127,46 @@ enum { QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), }; +#define TYPE_PCI_DEVICE "pci-device" +#define PCI_DEVICE(obj) \ + OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE) +#define PCI_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE) +#define PCI_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE) + +typedef struct PCIDeviceClass { + DeviceClass parent_class; + + int (*init)(PCIDevice *dev); + PCIUnregisterFunc *exit; + PCIConfigReadFunc *config_read; + PCIConfigWriteFunc *config_write; + + uint16_t vendor_id; + uint16_t device_id; + uint8_t revision; + uint16_t class_id; + uint16_t subsystem_vendor_id; /* only for header type = 0 */ + uint16_t subsystem_id; /* only for header type = 0 */ + + /* + * pci-to-pci bridge or normal device. + * This doesn't mean pci host switch. + * When card bus bridge is supported, this would be enhanced. + */ + int is_bridge; + + /* pcie stuff */ + int is_express; /* is this device pci express? */ + + /* device isn't hot-pluggable */ + int no_hotplug; + + /* rom bar */ + const char *romfile; +} PCIDeviceClass; + struct PCIDevice { DeviceState qdev; /* PCI config space */ @@ -196,11 +236,6 @@ struct PCIDevice { uint32_t rom_bar; }; -PCIDevice *pci_register_device(PCIBus *bus, const char *name, - int instance_size, int devfn, - PCIConfigReadFunc *config_read, - PCIConfigWriteFunc *config_write); - void pci_register_bar(PCIDevice *pci_dev, int region_num, uint8_t attr, MemoryRegion *memory); pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num); @@ -429,52 +464,13 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask) return val & mask; } -typedef int (*pci_qdev_initfn)(PCIDevice *dev); -typedef struct { - DeviceInfo qdev; - pci_qdev_initfn init; - PCIUnregisterFunc *exit; - PCIConfigReadFunc *config_read; - PCIConfigWriteFunc *config_write; - - uint16_t vendor_id; - uint16_t device_id; - uint8_t revision; - uint16_t class_id; - uint16_t subsystem_vendor_id; /* only for header type = 0 */ - uint16_t subsystem_id; /* only for header type = 0 */ - - /* - * pci-to-pci bridge or normal device. - * This doesn't mean pci host switch. - * When card bus bridge is supported, this would be enhanced. - */ - int is_bridge; - - /* pcie stuff */ - int is_express; /* is this device pci express? */ - - /* device isn't hot-pluggable */ - int no_hotplug; - - /* rom bar */ - const char *romfile; -} PCIDeviceInfo; - -void pci_qdev_register(PCIDeviceInfo *info); -void pci_qdev_register_many(PCIDeviceInfo *info); - PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); -PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name); PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); -PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name); static inline int pci_is_express(const PCIDevice *d) { diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c index 650d1650c5..1ed43394de 100644 --- a/hw/pci_bridge.c +++ b/hw/pci_bridge.c @@ -294,7 +294,7 @@ void pci_bridge_reset_reg(PCIDevice *dev) /* default reset function for PCI-to-PCI bridge */ void pci_bridge_reset(DeviceState *qdev) { - PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *dev = PCI_DEVICE(qdev); pci_bridge_reset_reg(dev); } diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 83f38934ec..e8235a7d05 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -98,6 +98,7 @@ #define PCI_DEVICE_ID_MPC8533E 0x0030 #define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82378 0x0484 #define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 #define PCI_DEVICE_ID_INTEL_82801D 0x24CD @@ -120,3 +121,6 @@ #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 + +#define PCI_VENDOR_ID_NEC 0x1033 +#define PCI_DEVICE_ID_NEC_UPD720200 0x0194 @@ -203,7 +203,7 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event) static int pcie_cap_slot_hotplug(DeviceState *qdev, PCIDevice *pci_dev, PCIHotplugState state) { - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *d = PCI_DEVICE(qdev); uint8_t *exp_cap = d->config + d->exp.exp_cap; uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA); diff --git a/hw/pckbd.c b/hw/pckbd.c index 06b40c540c..b4c53bed6c 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -497,16 +497,24 @@ static int i8042_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo i8042_info = { - .qdev.name = "i8042", - .qdev.size = sizeof(ISAKBDState), - .qdev.vmsd = &vmstate_kbd_isa, - .qdev.no_user = 1, - .init = i8042_initfn, +static void i8042_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = i8042_initfn; + dc->no_user = 1; + dc->vmsd = &vmstate_kbd_isa; +} + +static TypeInfo i8042_info = { + .name = "i8042", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISAKBDState), + .class_init = i8042_class_initfn, }; static void i8042_register(void) { - isa_qdev_register(&i8042_info); + type_register_static(&i8042_info); } device_init(i8042_register) diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c index 4e164da3ac..439f32caae 100644 --- a/hw/pcnet-pci.c +++ b/hw/pcnet-pci.c @@ -348,26 +348,37 @@ static void pci_reset(DeviceState *dev) pcnet_h_reset(&d->state); } -static PCIDeviceInfo pcnet_info = { - .qdev.name = "pcnet", - .qdev.size = sizeof(PCIPCNetState), - .qdev.reset = pci_reset, - .qdev.vmsd = &vmstate_pci_pcnet, - .init = pci_pcnet_init, - .exit = pci_pcnet_uninit, - .vendor_id = PCI_VENDOR_ID_AMD, - .device_id = PCI_DEVICE_ID_AMD_LANCE, - .revision = 0x10, - .class_id = PCI_CLASS_NETWORK_ETHERNET, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property pcnet_properties[] = { + DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pcnet_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_pcnet_init; + k->exit = pci_pcnet_uninit; + k->vendor_id = PCI_VENDOR_ID_AMD; + k->device_id = PCI_DEVICE_ID_AMD_LANCE; + k->revision = 0x10; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + dc->reset = pci_reset; + dc->vmsd = &vmstate_pci_pcnet; + dc->props = pcnet_properties; +} + +static TypeInfo pcnet_info = { + .name = "pcnet", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIPCNetState), + .class_init = pcnet_class_init, }; static void pci_pcnet_register_devices(void) { - pci_qdev_register(&pcnet_info); + type_register_static(&pcnet_info); } device_init(pci_pcnet_register_devices) diff --git a/hw/pcnet.c b/hw/pcnet.c index 306dc6ed7e..c53f06ef3b 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -688,7 +688,6 @@ static void pcnet_s_reset(PCNetState *s) printf("pcnet_s_reset\n"); #endif - s->lnkst = 0x40; s->rdra = 0; s->tdra = 0; s->rap = 0; @@ -1719,7 +1718,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s); qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s); + s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0"); @@ -1751,5 +1750,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) } *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); + s->lnkst = 0x40; /* initial link state: up */ + return 0; } diff --git a/hw/piix4.c b/hw/piix4.c index 51af459073..4e7a2370cd 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -102,25 +102,30 @@ int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn) return d->devfn; } -static PCIDeviceInfo piix4_info[] = { - { - .qdev.name = "PIIX4", - .qdev.desc = "ISA bridge", - .qdev.size = sizeof(PIIX4State), - .qdev.vmsd = &vmstate_piix4, - .qdev.no_user = 1, - .no_hotplug = 1, - .init = piix4_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge - .class_id = PCI_CLASS_BRIDGE_ISA, - },{ - /* end of list */ - } +static void piix4_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = piix4_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0; + k->class_id = PCI_CLASS_BRIDGE_ISA; + dc->desc = "ISA bridge"; + dc->no_user = 1; + dc->vmsd = &vmstate_piix4; +} + +static TypeInfo piix4_info = { + .name = "PIIX4", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX4State), + .class_init = piix4_class_init, }; static void piix4_register(void) { - pci_qdev_register_many(piix4_info); + type_register_static(&piix4_info); } device_init(piix4_register); diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 3652522e58..190642733f 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -277,7 +277,7 @@ static PCIBus *i440fx_common_init(const char *device_name, address_space_io, 0); s->bus = b; qdev_init_nofail(dev); - qdev_property_add_child(qdev_get_root(), "i440fx", dev, NULL); + object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL); d = pci_create_simple(b, 0, device_name); *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d); @@ -316,7 +316,7 @@ static PCIBus *i440fx_common_init(const char *device_name, pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, PIIX_NUM_PIRQS); } - qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL); + object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL); piix3->pic = pic; *isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&piix3->dev.qdev, "isa.0")); @@ -502,60 +502,98 @@ static int piix3_initfn(PCIDevice *dev) return 0; } -static PCIDeviceInfo i440fx_info[] = { - { - .qdev.name = "i440FX", - .qdev.desc = "Host bridge", - .qdev.size = sizeof(PCII440FXState), - .qdev.vmsd = &vmstate_i440fx, - .qdev.no_user = 1, - .no_hotplug = 1, - .init = i440fx_initfn, - .config_write = i440fx_write_config, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82441, - .revision = 0x02, - .class_id = PCI_CLASS_BRIDGE_HOST, - },{ - .qdev.name = "PIIX3", - .qdev.desc = "ISA bridge", - .qdev.size = sizeof(PIIX3State), - .qdev.vmsd = &vmstate_piix3, - .qdev.no_user = 1, - .no_hotplug = 1, - .init = piix3_initfn, - .config_write = piix3_write_config, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - .class_id = PCI_CLASS_BRIDGE_ISA, - },{ - .qdev.name = "PIIX3-xen", - .qdev.desc = "ISA bridge", - .qdev.size = sizeof(PIIX3State), - .qdev.vmsd = &vmstate_piix3, - .qdev.no_user = 1, - .no_hotplug = 1, - .init = piix3_initfn, - .config_write = piix3_write_config_xen, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - .class_id = PCI_CLASS_BRIDGE_ISA, - },{ - /* end of list */ - } +static void piix3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_piix3; + dc->no_user = 1, + k->no_hotplug = 1; + k->init = piix3_initfn; + k->config_write = piix3_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + k->class_id = PCI_CLASS_BRIDGE_ISA; +} + +static TypeInfo piix3_info = { + .name = "PIIX3", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX3State), + .class_init = piix3_class_init, +}; + +static void piix3_xen_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_piix3; + dc->no_user = 1; + k->no_hotplug = 1; + k->init = piix3_initfn; + k->config_write = piix3_write_config_xen; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) + k->class_id = PCI_CLASS_BRIDGE_ISA; +}; + +static TypeInfo piix3_xen_info = { + .name = "PIIX3-xen", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX3State), + .class_init = piix3_xen_class_init, }; -static SysBusDeviceInfo i440fx_pcihost_info = { - .init = i440fx_pcihost_initfn, - .qdev.name = "i440FX-pcihost", - .qdev.fw_name = "pci", - .qdev.size = sizeof(I440FXState), - .qdev.no_user = 1, +static void i440fx_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = i440fx_initfn; + k->config_write = i440fx_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82441; + k->revision = 0x02; + k->class_id = PCI_CLASS_BRIDGE_HOST; + dc->desc = "Host bridge"; + dc->no_user = 1; + dc->vmsd = &vmstate_i440fx; +} + +static TypeInfo i440fx_info = { + .name = "i440FX", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCII440FXState), + .class_init = i440fx_class_init, +}; + +static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = i440fx_pcihost_initfn; + dc->fw_name = "pci"; + dc->no_user = 1; +} + +static TypeInfo i440fx_pcihost_info = { + .name = "i440FX-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(I440FXState), + .class_init = i440fx_pcihost_class_init, }; static void i440fx_register(void) { - sysbus_register_withprop(&i440fx_pcihost_info); - pci_qdev_register_many(i440fx_info); + type_register_static(&i440fx_info); + type_register_static(&piix3_info); + type_register_static(&piix3_xen_info); + type_register_static(&i440fx_pcihost_info); } device_init(i440fx_register); diff --git a/hw/pl011.c b/hw/pl011.c index 1b05d76a78..752cbf9725 100644 --- a/hw/pl011.c +++ b/hw/pl011.c @@ -264,7 +264,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) sysbus_init_mmio(dev, &s->iomem); sysbus_init_irq(dev, &s->irq); s->id = id; - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); s->read_trigger = 1; s->ifl = 0x12; @@ -278,22 +278,48 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) return 0; } -static int pl011_init_arm(SysBusDevice *dev) +static int pl011_arm_init(SysBusDevice *dev) { return pl011_init(dev, pl011_id_arm); } -static int pl011_init_luminary(SysBusDevice *dev) +static int pl011_luminary_init(SysBusDevice *dev) { return pl011_init(dev, pl011_id_luminary); } +static void pl011_arm_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pl011_arm_init; +} + +static TypeInfo pl011_arm_info = { + .name = "pl011", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl011_state), + .class_init = pl011_arm_class_init, +}; + +static void pl011_luminary_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pl011_luminary_init; +} + +static TypeInfo pl011_luminary_info = { + .name = "pl011_luminary", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl011_state), + .class_init = pl011_luminary_class_init, +}; + static void pl011_register_devices(void) { - sysbus_register_dev("pl011", sizeof(pl011_state), - pl011_init_arm); - sysbus_register_dev("pl011_luminary", sizeof(pl011_state), - pl011_init_luminary); + type_register_static(&pl011_arm_info); + type_register_static(&pl011_luminary_info); } device_init(pl011_register_devices) diff --git a/hw/pl022.c b/hw/pl022.c index d43e4a29da..30bd3442bb 100644 --- a/hw/pl022.c +++ b/hw/pl022.c @@ -285,9 +285,23 @@ static int pl022_init(SysBusDevice *dev) return 0; } +static void pl022_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pl022_init; +} + +static TypeInfo pl022_info = { + .name = "pl022", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl022_state), + .class_init = pl022_class_init, +}; + static void pl022_register_devices(void) { - sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init); + type_register_static(&pl022_info); } device_init(pl022_register_devices) diff --git a/hw/pl031.c b/hw/pl031.c index 2fb0c8ef24..8416a609ef 100644 --- a/hw/pl031.c +++ b/hw/pl031.c @@ -213,17 +213,26 @@ static int pl031_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo pl031_info = { - .init = pl031_init, - .qdev.name = "pl031", - .qdev.size = sizeof(pl031_state), - .qdev.vmsd = &vmstate_pl031, - .qdev.no_user = 1, +static void pl031_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl031_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl031; +} + +static TypeInfo pl031_info = { + .name = "pl031", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl031_state), + .class_init = pl031_class_init, }; static void pl031_register_devices(void) { - sysbus_register_withprop(&pl031_info); + type_register_static(&pl031_info); } device_init(pl031_register_devices) diff --git a/hw/pl041.c b/hw/pl041.c index 4585ccf9c0..6d99c9cbbc 100644 --- a/hw/pl041.c +++ b/hw/pl041.c @@ -613,24 +613,34 @@ static const VMStateDescription vmstate_pl041 = { } }; -static SysBusDeviceInfo pl041_device_info = { - .init = pl041_init, - .qdev.name = "pl041", - .qdev.size = sizeof(pl041_state), - .qdev.vmsd = &vmstate_pl041, - .qdev.reset = pl041_device_reset, - .qdev.no_user = 1, - .qdev.props = (Property[]) { - /* Non-compact FIFO depth property */ - DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, - fifo_depth, DEFAULT_FIFO_DEPTH), - DEFINE_PROP_END_OF_LIST(), - }, +static Property pl041_device_properties[] = { + /* Non-compact FIFO depth property */ + DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pl041_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl041_init; + dc->no_user = 1; + dc->reset = pl041_device_reset; + dc->vmsd = &vmstate_pl041; + dc->props = pl041_device_properties; +} + +static TypeInfo pl041_device_info = { + .name = "pl041", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl041_state), + .class_init = pl041_device_class_init, }; static void pl041_register_device(void) { - sysbus_register_withprop(&pl041_device_info); + type_register_static(&pl041_device_info); } device_init(pl041_register_device) diff --git a/hw/pl050.c b/hw/pl050.c index 8182a1c82d..b0094ac9b3 100644 --- a/hw/pl050.c +++ b/hw/pl050.c @@ -157,24 +157,42 @@ static int pl050_init_mouse(SysBusDevice *dev) return pl050_init(dev, 1); } -static SysBusDeviceInfo pl050_kbd_info = { - .init = pl050_init_keyboard, - .qdev.name = "pl050_keyboard", - .qdev.size = sizeof(pl050_state), - .qdev.vmsd = &vmstate_pl050, +static void pl050_kbd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl050_init_keyboard; + dc->vmsd = &vmstate_pl050; +} + +static TypeInfo pl050_kbd_info = { + .name = "pl050_keyboard", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl050_state), + .class_init = pl050_kbd_class_init, }; -static SysBusDeviceInfo pl050_mouse_info = { - .init = pl050_init_mouse, - .qdev.name = "pl050_mouse", - .qdev.size = sizeof(pl050_state), - .qdev.vmsd = &vmstate_pl050, +static void pl050_mouse_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl050_init_mouse; + dc->vmsd = &vmstate_pl050; +} + +static TypeInfo pl050_mouse_info = { + .name = "pl050_mouse", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl050_state), + .class_init = pl050_mouse_class_init, }; static void pl050_register_devices(void) { - sysbus_register_withprop(&pl050_kbd_info); - sysbus_register_withprop(&pl050_mouse_info); + type_register_static(&pl050_kbd_info); + type_register_static(&pl050_mouse_info); } device_init(pl050_register_devices) diff --git a/hw/pl061.c b/hw/pl061.c index f33ae84408..3136c99423 100644 --- a/hw/pl061.c +++ b/hw/pl061.c @@ -293,24 +293,42 @@ static int pl061_init_arm(SysBusDevice *dev) return pl061_init(dev, pl061_id); } -static SysBusDeviceInfo pl061_info = { - .init = pl061_init_arm, - .qdev.name = "pl061", - .qdev.size = sizeof(pl061_state), - .qdev.vmsd = &vmstate_pl061, +static void pl061_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl061_init_arm; + dc->vmsd = &vmstate_pl061; +} + +static TypeInfo pl061_info = { + .name = "pl061", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl061_state), + .class_init = pl061_class_init, }; -static SysBusDeviceInfo pl061_luminary_info = { - .init = pl061_init_luminary, - .qdev.name = "pl061_luminary", - .qdev.size = sizeof(pl061_state), - .qdev.vmsd = &vmstate_pl061, +static void pl061_luminary_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl061_init_luminary; + dc->vmsd = &vmstate_pl061; +} + +static TypeInfo pl061_luminary_info = { + .name = "pl061_luminary", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl061_state), + .class_init = pl061_luminary_class_init, }; static void pl061_register_devices(void) { - sysbus_register_withprop(&pl061_info); - sysbus_register_withprop(&pl061_luminary_info); + type_register_static(&pl061_info); + type_register_static(&pl061_luminary_info); } device_init(pl061_register_devices) diff --git a/hw/pl080.c b/hw/pl080.c index e001df92e0..4405d1823b 100644 --- a/hw/pl080.c +++ b/hw/pl080.c @@ -373,28 +373,46 @@ static int pl081_init(SysBusDevice *dev) return pl08x_init(dev, 2); } -static SysBusDeviceInfo pl080_info = { - .init = pl080_init, - .qdev.name = "pl080", - .qdev.size = sizeof(pl080_state), - .qdev.vmsd = &vmstate_pl080, - .qdev.no_user = 1, +static void pl080_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl080_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl080; +} + +static TypeInfo pl080_info = { + .name = "pl080", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl080_state), + .class_init = pl080_class_init, }; -static SysBusDeviceInfo pl081_info = { - .init = pl081_init, - .qdev.name = "pl081", - .qdev.size = sizeof(pl080_state), - .qdev.vmsd = &vmstate_pl080, - .qdev.no_user = 1, +static void pl081_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl081_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl080; +} + +static TypeInfo pl081_info = { + .name = "pl081", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl080_state), + .class_init = pl081_class_init, }; /* The PL080 and PL081 are the same except for the number of channels they implement (8 and 2 respectively). */ static void pl080_register_devices(void) { - sysbus_register_withprop(&pl080_info); - sysbus_register_withprop(&pl081_info); + type_register_static(&pl080_info); + type_register_static(&pl081_info); } device_init(pl080_register_devices) diff --git a/hw/pl110.c b/hw/pl110.c index 0e1f415aeb..86e95a3ffd 100644 --- a/hw/pl110.c +++ b/hw/pl110.c @@ -469,35 +469,62 @@ static int pl111_init(SysBusDevice *dev) return pl110_init(dev); } -static SysBusDeviceInfo pl110_info = { - .init = pl110_init, - .qdev.name = "pl110", - .qdev.size = sizeof(pl110_state), - .qdev.vmsd = &vmstate_pl110, - .qdev.no_user = 1, +static void pl110_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl110_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl110; +} + +static TypeInfo pl110_info = { + .name = "pl110", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl110_state), + .class_init = pl110_class_init, }; -static SysBusDeviceInfo pl110_versatile_info = { - .init = pl110_versatile_init, - .qdev.name = "pl110_versatile", - .qdev.size = sizeof(pl110_state), - .qdev.vmsd = &vmstate_pl110, - .qdev.no_user = 1, +static void pl110_versatile_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl110_versatile_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl110; +} + +static TypeInfo pl110_versatile_info = { + .name = "pl110_versatile", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl110_state), + .class_init = pl110_versatile_class_init, }; -static SysBusDeviceInfo pl111_info = { - .init = pl111_init, - .qdev.name = "pl111", - .qdev.size = sizeof(pl110_state), - .qdev.vmsd = &vmstate_pl110, - .qdev.no_user = 1, +static void pl111_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl111_init; + dc->no_user = 1; + dc->vmsd = &vmstate_pl110; +} + +static TypeInfo pl111_info = { + .name = "pl111", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl110_state), + .class_init = pl111_class_init, }; static void pl110_register_devices(void) { - sysbus_register_withprop(&pl110_info); - sysbus_register_withprop(&pl110_versatile_info); - sysbus_register_withprop(&pl111_info); + type_register_static(&pl110_info); + type_register_static(&pl110_versatile_info); + type_register_static(&pl111_info); } device_init(pl110_register_devices) diff --git a/hw/pl181.c b/hw/pl181.c index b79aa418fa..ae636e220e 100644 --- a/hw/pl181.c +++ b/hw/pl181.c @@ -487,18 +487,27 @@ static int pl181_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo pl181_info = { - .init = pl181_init, - .qdev.name = "pl181", - .qdev.size = sizeof(pl181_state), - .qdev.vmsd = &vmstate_pl181, - .qdev.reset = pl181_reset, - .qdev.no_user = 1, +static void pl181_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + + sdc->init = pl181_init; + k->vmsd = &vmstate_pl181; + k->reset = pl181_reset; + k->no_user = 1; +} + +static TypeInfo pl181_info = { + .name = "pl181", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl181_state), + .class_init = pl181_class_init, }; static void pl181_register_devices(void) { - sysbus_register_withprop(&pl181_info); + type_register_static(&pl181_info); } device_init(pl181_register_devices) diff --git a/hw/pl190.c b/hw/pl190.c index 6fc2656f69..956ab21c6a 100644 --- a/hw/pl190.c +++ b/hw/pl190.c @@ -255,18 +255,27 @@ static const VMStateDescription vmstate_pl190 = { } }; -static SysBusDeviceInfo pl190_info = { - .init = pl190_init, - .qdev.name = "pl190", - .qdev.size = sizeof(pl190_state), - .qdev.vmsd = &vmstate_pl190, - .qdev.reset = pl190_reset, - .qdev.no_user = 1, +static void pl190_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pl190_init; + dc->no_user = 1; + dc->reset = pl190_reset; + dc->vmsd = &vmstate_pl190; +} + +static TypeInfo pl190_info = { + .name = "pl190", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(pl190_state), + .class_init = pl190_class_init, }; static void pl190_register_devices(void) { - sysbus_register_withprop(&pl190_info); + type_register_static(&pl190_info); } device_init(pl190_register_devices) diff --git a/hw/ppc440.c b/hw/ppc440.c deleted file mode 100644 index cd8a95d52b..0000000000 --- a/hw/ppc440.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Qemu PowerPC 440 chip emulation - * - * Copyright 2007 IBM Corporation. - * Authors: - * Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * Hollis Blanchard <hollisb@us.ibm.com> - * - * This work is licensed under the GNU GPL license version 2 or later. - * - */ - -#include "hw.h" -#include "pc.h" -#include "isa.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "ppc440.h" -#include "ppc405.h" -#include "sysemu.h" -#include "kvm.h" - -#define PPC440EP_PCI_CONFIG 0xeec00000 -#define PPC440EP_PCI_INTACK 0xeed00000 -#define PPC440EP_PCI_SPECIAL 0xeed00000 -#define PPC440EP_PCI_REGS 0xef400000 -#define PPC440EP_PCI_IO 0xe8000000 -#define PPC440EP_PCI_IOLEN 0x00010000 - -#define PPC440EP_SDRAM_NR_BANKS 4 - -static const unsigned int ppc440ep_sdram_bank_sizes[] = { - 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 -}; - -CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size, - PCIBus **pcip, const unsigned int pci_irq_nrs[4], - int do_init, const char *cpu_model) -{ - MemoryRegion *ram_memories - = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); - target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS]; - target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS]; - CPUState *env; - qemu_irq *pic; - qemu_irq *irqs; - qemu_irq *pci_irqs; - - if (cpu_model == NULL) { - cpu_model = "440-Xilinx"; // XXX: should be 440EP - } - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "Unable to initialize CPU!\n"); - exit(1); - } - - ppc_dcr_init(env, NULL, NULL); - - /* interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); - - /* SDRAM controller */ - memset(ram_bases, 0, sizeof(ram_bases)); - memset(ram_sizes, 0, sizeof(ram_sizes)); - *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS, - ram_memories, - ram_bases, ram_sizes, - ppc440ep_sdram_bank_sizes); - /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ - ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, do_init); - - /* PCI */ - pci_irqs = g_malloc(sizeof(qemu_irq) * 4); - pci_irqs[0] = pic[pci_irq_nrs[0]]; - pci_irqs[1] = pic[pci_irq_nrs[1]]; - pci_irqs[2] = pic[pci_irq_nrs[2]]; - pci_irqs[3] = pic[pci_irq_nrs[3]]; - *pcip = ppc4xx_pci_init(env, pci_irqs, - PPC440EP_PCI_CONFIG, - PPC440EP_PCI_INTACK, - PPC440EP_PCI_SPECIAL, - PPC440EP_PCI_REGS); - if (!*pcip) - printf("couldn't create PCI controller!\n"); - - isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); - - if (serial_hds[0] != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], - PPC_SERIAL_MM_BAUDBASE, serial_hds[0], - DEVICE_BIG_ENDIAN); - } - if (serial_hds[1] != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], - PPC_SERIAL_MM_BAUDBASE, serial_hds[1], - DEVICE_BIG_ENDIAN); - } - - return env; -} diff --git a/hw/ppc440.h b/hw/ppc440.h deleted file mode 100644 index 9c27c36fd0..0000000000 --- a/hw/ppc440.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Qemu PowerPC 440 board emualtion - * - * Copyright 2007 IBM Corporation. - * Authors: Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * - * This work is licensed under the GNU GPL licence version 2 or later - * - */ - -#ifndef QEMU_PPC440_H -#define QEMU_PPC440_H - -#include "hw.h" - -CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size, - PCIBus **pcip, const unsigned int pci_irq_nrs[4], - int do_init, const char *cpu_model); - -#endif diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index b734e3a56c..f86b16838a 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -3,9 +3,9 @@ * * Copyright 2007 IBM Corporation. * Authors: - * Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * Hollis Blanchard <hollisb@us.ibm.com> + * Jerone Young <jyoung5@us.ibm.com> + * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> + * Hollis Blanchard <hollisb@us.ibm.com> * * This work is licensed under the GNU GPL license version 2 or later. * @@ -17,13 +17,17 @@ #include "hw.h" #include "pci.h" #include "boards.h" -#include "ppc440.h" #include "kvm.h" #include "kvm_ppc.h" #include "device_tree.h" #include "loader.h" #include "elf.h" #include "exec-memory.h" +#include "pc.h" +#include "ppc.h" +#include "ppc405.h" +#include "sysemu.h" +#include "sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" @@ -32,6 +36,21 @@ #define FDT_ADDR 0x1800000 #define RAMDISK_ADDR 0x1900000 +#define PPC440EP_PCI_CONFIG 0xeec00000 +#define PPC440EP_PCI_INTACK 0xeed00000 +#define PPC440EP_PCI_SPECIAL 0xeed00000 +#define PPC440EP_PCI_REGS 0xef400000 +#define PPC440EP_PCI_IO 0xe8000000 +#define PPC440EP_PCI_IOLEN 0x00010000 + +#define PPC440EP_SDRAM_NR_BANKS 4 + +static const unsigned int ppc440ep_sdram_bank_sizes[] = { + 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 +}; + +static target_phys_addr_t entry; + static int bamboo_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, @@ -101,6 +120,42 @@ out: return ret; } +/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ +static void mmubooke_create_initial_mapping(CPUState *env, + target_ulong va, + target_phys_addr_t pa) +{ + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0x80000000 */ + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; + + tlb = &env->tlb.tlbe[1]; + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0xffffffff */ + tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + cpu_reset(env); + env->gpr[1] = (16<<20) - 8; + env->gpr[3] = FDT_ADDR; + env->nip = entry; + + /* Create a mapping for the kernel. */ + mmubooke_create_initial_mapping(env, 0, 0); +} + static void bamboo_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -110,19 +165,76 @@ static void bamboo_init(ram_addr_t ram_size, { unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram_memories + = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); + target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS]; + target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS]; + qemu_irq *pic; + qemu_irq *irqs; PCIBus *pcibus; CPUState *env; uint64_t elf_entry; uint64_t elf_lowaddr; - target_phys_addr_t entry = 0; target_phys_addr_t loadaddr = 0; target_long initrd_size = 0; + DeviceState *dev; int success; int i; /* Setup CPU. */ - env = ppc440ep_init(address_space_mem, &ram_size, &pcibus, - pci_irq_nrs, 1, cpu_model); + if (cpu_model == NULL) { + cpu_model = "440EP"; + } + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to initialize CPU!\n"); + exit(1); + } + + qemu_register_reset(main_cpu_reset, env); + ppc_booke_timers_init(env, 400000000, 0); + ppc_dcr_init(env, NULL, NULL); + + /* interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + + /* SDRAM controller */ + memset(ram_bases, 0, sizeof(ram_bases)); + memset(ram_sizes, 0, sizeof(ram_sizes)); + ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS, + ram_memories, + ram_bases, ram_sizes, + ppc440ep_sdram_bank_sizes); + /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ + ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, + ram_bases, ram_sizes, 1); + + /* PCI */ + dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG, + pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]], + pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]], + NULL); + pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); + if (!pcibus) { + fprintf(stderr, "couldn't create PCI controller!\n"); + exit(1); + } + + isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); + + if (serial_hds[0] != NULL) { + serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], + PPC_SERIAL_MM_BAUDBASE, serial_hds[0], + DEVICE_BIG_ENDIAN); + } + if (serial_hds[1] != NULL) { + serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], + PPC_SERIAL_MM_BAUDBASE, serial_hds[1], + DEVICE_BIG_ENDIAN); + } if (pcibus) { /* Register network interfaces. */ @@ -169,12 +281,6 @@ static void bamboo_init(ram_addr_t ram_size, fprintf(stderr, "couldn't load device tree\n"); exit(1); } - - /* Set initial guest state. */ - env->gpr[1] = (16<<20) - 8; - env->gpr[3] = FDT_ADDR; - env->nip = entry; - /* XXX we currently depend on KVM to create some initial TLB entries. */ } if (kvm_enabled()) @@ -182,34 +288,14 @@ static void bamboo_init(ram_addr_t ram_size, } static QEMUMachine bamboo_machine = { - .name = "bamboo-0.13", - .alias = "bamboo", - .desc = "bamboo", - .init = bamboo_init, -}; - -static QEMUMachine bamboo_machine_v0_12 = { - .name = "bamboo-0.12", + .name = "bamboo", .desc = "bamboo", .init = bamboo_init, - .compat_props = (GlobalProperty[]) { - { - .driver = "virtio-serial-pci", - .property = "max_ports", - .value = stringify(1), - },{ - .driver = "virtio-serial-pci", - .property = "vectors", - .value = stringify(0), - }, - { /* end of list */ } - }, }; static void bamboo_machine_init(void) { qemu_register_machine(&bamboo_machine); - qemu_register_machine(&bamboo_machine_v0_12); } machine_init(bamboo_machine_init); diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 2c69210225..d11f120d32 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -49,13 +49,14 @@ struct PCITargetMap { #define PPC4xx_PCI_NR_PTMS 2 struct PPC4xxPCIState { + PCIHostState pci_state; + struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS]; struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS]; + qemu_irq irq[4]; - PCIHostState pci_state; - PCIDevice *pci_dev; - MemoryRegion iomem_addr; - MemoryRegion iomem_regs; + MemoryRegion container; + MemoryRegion iomem; }; typedef struct PPC4xxPCIState PPC4xxPCIState; @@ -83,8 +84,10 @@ typedef struct PPC4xxPCIState PPC4xxPCIState; #define PCIL0_PTM1LA 0x34 #define PCIL0_PTM2MS 0x38 #define PCIL0_PTM2LA 0x3c +#define PCI_REG_BASE 0x800000 #define PCI_REG_SIZE 0x40 +#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE) static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr, unsigned size) @@ -275,6 +278,10 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_irq *pci_irqs = opaque; DPRINTF("%s: PCI irq %d\n", __func__, irq_num); + if (irq_num < 0) { + fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); + return; + } qemu_set_irq(pci_irqs[irq_num], level); } @@ -310,7 +317,6 @@ static const VMStateDescription vmstate_ppc4xx_pci = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState), VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1, vmstate_pci_master_map, struct PCIMasterMap), @@ -322,60 +328,81 @@ static const VMStateDescription vmstate_ppc4xx_pci = { }; /* XXX Interrupt acknowledge cycles not supported. */ -PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], - target_phys_addr_t config_space, - target_phys_addr_t int_ack, - target_phys_addr_t special_cycle, - target_phys_addr_t registers) +static int ppc4xx_pcihost_initfn(SysBusDevice *dev) +{ + PPC4xxPCIState *s; + PCIHostState *h; + PCIBus *b; + int i; + + h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); + s = DO_UPCAST(PPC4xxPCIState, pci_state, h); + + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { + sysbus_init_irq(dev, &s->irq[i]); + } + + b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq, + ppc4xx_pci_map_irq, s->irq, get_system_memory(), + get_system_io(), 0, 4); + s->pci_state.bus = b; + + pci_create_simple(b, 0, "ppc4xx-host-bridge"); + + /* XXX split into 2 memory regions, one for config space, one for regs */ + memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE); + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h, + "pci-conf-idx", 4); + memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h, + "pci-conf-data", 4); + memory_region_init_io(&s->iomem, &pci_reg_ops, s, + "pci.reg", PCI_REG_SIZE); + memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); + memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); + memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem); + sysbus_init_mmio(dev, &s->container); + qemu_register_reset(ppc4xx_pci_reset, s); + + return 0; +} + +static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "Host bridge"; + k->vendor_id = PCI_VENDOR_ID_IBM; + k->device_id = PCI_DEVICE_ID_IBM_440GX; + k->class_id = PCI_CLASS_BRIDGE_OTHER; +} + +static TypeInfo ppc4xx_host_bridge_info = { + .name = "ppc4xx-host-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = ppc4xx_host_bridge_class_init, +}; + +static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = ppc4xx_pcihost_initfn; + dc->vmsd = &vmstate_ppc4xx_pci; +} + +static TypeInfo ppc4xx_pcihost_info = { + .name = "ppc4xx-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PPC4xxPCIState), + .class_init = ppc4xx_pcihost_class_init, +}; + +static void ppc4xx_pci_register(void) { - PPC4xxPCIState *controller; - static int ppc4xx_pci_id; - uint8_t *pci_conf; - - controller = g_malloc0(sizeof(PPC4xxPCIState)); - - controller->pci_state.bus = pci_register_bus(NULL, "pci", - ppc4xx_pci_set_irq, - ppc4xx_pci_map_irq, - pci_irqs, - get_system_memory(), - get_system_io(), - 0, 4); - - controller->pci_dev = pci_register_device(controller->pci_state.bus, - "host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - pci_conf = controller->pci_dev->config; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX); - pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); - - /* CFGADDR */ - memory_region_init_io(&controller->iomem_addr, &pci4xx_cfgaddr_ops, - controller, "pci.cfgaddr", 4); - memory_region_add_subregion(get_system_memory(), - config_space + PCIC0_CFGADDR, - &controller->iomem_addr); - - /* CFGDATA */ - memory_region_init_io(&controller->pci_state.data_mem, - &pci_host_data_be_ops, - &controller->pci_state, "pci-conf-data", 4); - memory_region_add_subregion(get_system_memory(), - config_space + PCIC0_CFGDATA, - &controller->pci_state.data_mem); - - /* Internal registers */ - memory_region_init_io(&controller->iomem_regs, &pci_reg_ops, controller, - "pci.regs", PCI_REG_SIZE); - memory_region_add_subregion(get_system_memory(), registers, - &controller->iomem_regs); - - qemu_register_reset(ppc4xx_pci_reset, controller); - - /* XXX load/save code not tested. */ - vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++, - &vmstate_ppc4xx_pci, controller); - - return controller->pci_state.bus; + type_register_static(&ppc4xx_pcihost_info); + type_register_static(&ppc4xx_host_bridge_info); } +device_init(ppc4xx_pci_register); diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index a746c9c3c6..506187b182 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -311,7 +311,7 @@ static void ppc_core99_init (ram_addr_t ram_size, exit(1); } } - pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL); + pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL); if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { /* 970 gets a U3 bus */ pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io()); diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index 47dab3f184..eb43fb5849 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -29,7 +29,7 @@ #include "sysemu.h" #include "isa.h" #include "pci.h" -#include "prep_pci.h" +#include "pci_host.h" #include "usb-ohci.h" #include "ppc.h" #include "boards.h" @@ -83,37 +83,9 @@ static const int ide_irq[2] = { 13, 13 }; static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; -//static ISADevice *pit; - /* ISA IO ports bridge */ #define PPC_IO_BASE 0x80000000 -#if 0 -/* Speaker port 0x61 */ -static int speaker_data_on; -static int dummy_refresh_clock; -#endif - -static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val) -{ -#if 0 - speaker_data_on = (val >> 1) & 1; - pit_set_gate(pit, 2, val & 1); -#endif -} - -static uint32_t speaker_ioport_read (void *opaque, uint32_t addr) -{ -#if 0 - int out; - out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock)); - dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | - (dummy_refresh_clock << 4); -#endif - return 0; -} - /* PCI intack register */ /* Read-only register (?) */ static void PPC_intack_write (void *opaque, target_phys_addr_t addr, @@ -522,9 +494,12 @@ static void ppc_prep_init (ram_addr_t ram_size, MemoryRegion *bios = g_new(MemoryRegion, 1); uint32_t kernel_base, initrd_base; long kernel_size, initrd_size; + DeviceState *dev; + SysBusDevice *sys; + PCIHostState *pcihost; PCIBus *pci_bus; + PCIDevice *pci; ISABus *isa_bus; - qemu_irq *i8259; qemu_irq *cpu_exit_irq; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; @@ -560,6 +535,8 @@ static void ppc_prep_init (ram_addr_t ram_size, /* allocate and load BIOS */ memory_region_init_ram(bios, "ppc_prep.bios", BIOS_SIZE); + memory_region_set_readonly(bios, true); + memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios); vmstate_register_ram_global(bios); if (bios_name == NULL) bios_name = BIOS_FILENAME; @@ -573,8 +550,6 @@ static void ppc_prep_init (ram_addr_t ram_size, target_phys_addr_t bios_addr; bios_size = (bios_size + 0xfff) & ~0xfff; bios_addr = (uint32_t)(-bios_size); - memory_region_set_readonly(bios, true); - memory_region_add_subregion(sysmem, bios_addr, bios); bios_size = load_image_targphys(filename, bios_addr, bios_size); } if (bios_size < 0 || bios_size > BIOS_SIZE) { @@ -626,16 +601,34 @@ static void ppc_prep_init (ram_addr_t ram_size, } } - isa_mem_base = 0xc0000000; if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) { hw_error("Only 6xx bus is supported on PREP machine\n"); } - /* Hmm, prep has no pci-isa bridge ??? */ - isa_bus = isa_bus_new(NULL, get_system_io()); - i8259 = i8259_init(isa_bus, first_cpu->irq_inputs[PPC6xx_INPUT_INT]); - pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io()); - isa_bus_irqs(isa_bus, i8259); - // pci_bus = i440fx_init(); + + dev = qdev_create(NULL, "raven-pcihost"); + sys = sysbus_from_qdev(dev); + pcihost = DO_UPCAST(PCIHostState, busdev, sys); + pcihost->address_space = get_system_memory(); + qdev_init_nofail(dev); + object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL); + pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); + if (pci_bus == NULL) { + fprintf(stderr, "Couldn't create PCI host controller.\n"); + exit(1); + } + + /* PCI -> ISA bridge */ + pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378"); + cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); + qdev_connect_gpio_out(&pci->qdev, 0, + first_cpu->irq_inputs[PPC6xx_INPUT_INT]); + qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq); + sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9)); + sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11)); + sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9)); + sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11)); + isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0")); + /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl, "ppc-io", 0x00800000); @@ -643,9 +636,6 @@ static void ppc_prep_init (ram_addr_t ram_size, /* init basic PC hardware */ pci_vga_init(pci_bus); - // openpic = openpic_init(0x00000000, 0xF0000000, 1); - // pit = pit_init(0x40, 0); - rtc_init(isa_bus, 2000, NULL); if (serial_hds[0]) serial_isa_init(isa_bus, 0, serial_hds[0]); @@ -672,9 +662,6 @@ static void ppc_prep_init (ram_addr_t ram_size, } isa_create_simple(isa_bus, "i8042"); - cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); - DMA_init(1, cpu_exit_irq); - // SB16_init(); for(i = 0; i < MAX_FD; i++) { @@ -682,9 +669,6 @@ static void ppc_prep_init (ram_addr_t ram_size, } fdctrl_init_isa(isa_bus, fd); - /* Register speaker port */ - register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); - register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); /* Register fake IO ports for PREP */ sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET]; register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); @@ -707,7 +691,7 @@ static void ppc_prep_init (ram_addr_t ram_size, usb_ohci_init_pci(pci_bus, -1); } - m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59); + m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); if (m48t59 == NULL) return; sysctrl->nvram = m48t59; diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index b606206e00..d5bce71429 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -339,25 +339,43 @@ static int e500_pcihost_initfn(SysBusDevice *dev) return 0; } -static PCIDeviceInfo e500_host_bridge_info = { - .qdev.name = "e500-host-bridge", - .qdev.desc = "Host bridge", - .qdev.size = sizeof(PCIDevice), - .vendor_id = PCI_VENDOR_ID_FREESCALE, - .device_id = PCI_DEVICE_ID_MPC8533E, - .class_id = PCI_CLASS_PROCESSOR_POWERPC, +static void e500_host_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_FREESCALE; + k->device_id = PCI_DEVICE_ID_MPC8533E; + k->class_id = PCI_CLASS_PROCESSOR_POWERPC; + dc->desc = "Host bridge"; +} + +static TypeInfo e500_host_bridge_info = { + .name = "e500-host-bridge", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = e500_host_bridge_class_init, }; -static SysBusDeviceInfo e500_pcihost_info = { - .init = e500_pcihost_initfn, - .qdev.name = "e500-pcihost", - .qdev.size = sizeof(PPCE500PCIState), - .qdev.vmsd = &vmstate_ppce500_pci, +static void e500_pcihost_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = e500_pcihost_initfn; + dc->vmsd = &vmstate_ppce500_pci; +} + +static TypeInfo e500_pcihost_info = { + .name = "e500-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PPCE500PCIState), + .class_init = e500_pcihost_class_init, }; static void e500_pci_register(void) { - sysbus_register_withprop(&e500_pcihost_info); - pci_qdev_register(&e500_host_bridge_info); + type_register_static(&e500_pcihost_info); + type_register_static(&e500_host_bridge_info); } device_init(e500_pci_register); diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c index e7b1453855..9d648ec90a 100644 --- a/hw/ppce500_spin.c +++ b/hw/ppce500_spin.c @@ -203,14 +203,22 @@ static int ppce500_spin_initfn(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo ppce500_spin_info = { - .init = ppce500_spin_initfn, - .qdev.name = "e500-spin", - .qdev.size = sizeof(SpinState), +static void ppce500_spin_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ppce500_spin_initfn; +} + +static TypeInfo ppce500_spin_info = { + .name = "e500-spin", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SpinState), + .class_init = ppce500_spin_class_init, }; static void ppce500_spin_register(void) { - sysbus_register_withprop(&ppce500_spin_info); + type_register_static(&ppce500_spin_info); } device_init(ppce500_spin_register); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index ea9fb6902c..40b8bb0edd 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -25,9 +25,16 @@ #include "hw.h" #include "pci.h" #include "pci_host.h" -#include "prep_pci.h" +#include "exec-memory.h" -typedef PCIHostState PREPPCIState; +typedef struct PRePPCIState { + PCIHostState host_state; + qemu_irq irq[4]; +} PREPPCIState; + +typedef struct RavenPCIState { + PCIDevice dev; +} RavenPCIState; static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) { @@ -40,58 +47,24 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) return (addr & 0x7ff) | (i << 11); } -static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1); -} - -static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; - val = bswap16(val); - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2); -} - -static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) +static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr, + uint64_t val, unsigned int size) { PREPPCIState *s = opaque; - val = bswap32(val); - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4); + pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size); } -static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) +static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr, + unsigned int size) { PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1); - return val; -} - -static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) -{ - PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2); - val = bswap16(val); - return val; -} - -static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) -{ - PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4); - val = bswap32(val); - return val; + return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size); } static const MemoryRegionOps PPC_PCIIO_ops = { - .old_mmio = { - .read = { PPC_PCIIO_readb, PPC_PCIIO_readw, PPC_PCIIO_readl, }, - .write = { PPC_PCIIO_writeb, PPC_PCIIO_writew, PPC_PCIIO_writel, }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = ppc_pci_io_read, + .write = ppc_pci_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, }; static int prep_map_irq(PCIDevice *pci_dev, int irq_num) @@ -103,46 +76,107 @@ static void prep_set_irq(void *opaque, int irq_num, int level) { qemu_irq *pic = opaque; - qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level); + qemu_set_irq(pic[irq_num] , level); } -PCIBus *pci_prep_init(qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io) +static int raven_pcihost_init(SysBusDevice *dev) { - PREPPCIState *s; - PCIDevice *d; + PCIHostState *h = FROM_SYSBUS(PCIHostState, dev); + PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h); + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *address_space_io = get_system_io(); + PCIBus *bus; + int i; + + for (i = 0; i < 4; i++) { + sysbus_init_irq(dev, &s->irq[i]); + } - s = g_malloc0(sizeof(PREPPCIState)); - s->bus = pci_register_bus(NULL, "pci", - prep_set_irq, prep_map_irq, pic, - address_space_mem, - address_space_io, - 0, 4); + bus = pci_register_bus(&h->busdev.qdev, NULL, + prep_set_irq, prep_map_irq, s->irq, + address_space_mem, address_space_io, 0, 4); + h->bus = bus; - memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s, + memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s, "pci-conf-idx", 1); - memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem); - sysbus_init_ioports(&s->busdev, 0xcf8, 1); + sysbus_add_io(dev, 0xcf8, &h->conf_mem); + sysbus_init_ioports(&h->busdev, 0xcf8, 1); - memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s, + memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s, "pci-conf-data", 1); - memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem); - sysbus_init_ioports(&s->busdev, 0xcfc, 1); - - memory_region_init_io(&s->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000); - memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg); - - /* PCI host bridge */ - d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", - sizeof(PCIDevice), 0, NULL, NULL); - pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA); - pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN); - d->config[0x08] = 0x00; // revision - pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST); + sysbus_add_io(dev, 0xcfc, &h->data_mem); + sysbus_init_ioports(&h->busdev, 0xcfc, 1); + + memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000); + memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg); + + pci_create_simple(bus, 0, "raven"); + + return 0; +} + +static int raven_init(PCIDevice *d) +{ d->config[0x0C] = 0x08; // cache_line_size d->config[0x0D] = 0x10; // latency_timer d->config[0x34] = 0x00; // capabilities_pointer - return s->bus; + return 0; +} + +static const VMStateDescription vmstate_raven = { + .name = "raven", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, RavenPCIState), + VMSTATE_END_OF_LIST() + }, +}; + +static void raven_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = raven_init; + k->vendor_id = PCI_VENDOR_ID_MOTOROLA; + k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; + dc->desc = "PReP Host Bridge - Motorola Raven"; + dc->vmsd = &vmstate_raven; + dc->no_user = 1; +} + +static TypeInfo raven_info = { + .name = "raven", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(RavenPCIState), + .class_init = raven_class_init, +}; + +static void raven_pcihost_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = raven_pcihost_init; + dc->fw_name = "pci"; + dc->no_user = 1; } + +static TypeInfo raven_pcihost_info = { + .name = "raven-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PREPPCIState), + .class_init = raven_pcihost_class_init, +}; + +static void raven_register_devices(void) +{ + type_register_static(&raven_pcihost_info); + type_register_static(&raven_info); +} + +device_init(raven_register_devices) diff --git a/hw/prep_pci.h b/hw/prep_pci.h deleted file mode 100644 index b6b481a517..0000000000 --- a/hw/prep_pci.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef QEMU_PREP_PCI_H -#define QEMU_PREP_PCI_H - -#include "qemu-common.h" -#include "memory.h" - -PCIBus *pci_prep_init(qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io); - -#endif diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index 6ddd5005de..244c614510 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1233,17 +1233,26 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = { }, }; -static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = { - .init = pxa2xx_rtc_init, - .qdev.name = "pxa2xx_rtc", - .qdev.desc = "PXA2xx RTC Controller", - .qdev.size = sizeof(PXA2xxRTCState), - .qdev.vmsd = &vmstate_pxa2xx_rtc_regs, +static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_rtc_init; + dc->desc = "PXA2xx RTC Controller"; + dc->vmsd = &vmstate_pxa2xx_rtc_regs; +} + +static TypeInfo pxa2xx_rtc_sysbus_info = { + .name = "pxa2xx_rtc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxRTCState), + .class_init = pxa2xx_rtc_sysbus_class_init, }; /* I2C Interface */ typedef struct { - i2c_slave i2c; + I2CSlave i2c; PXA2xxI2CState *host; } PXA2xxI2CSlaveState; @@ -1279,7 +1288,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s) } /* These are only stubs now. */ -static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event) +static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event) { PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); PXA2xxI2CState *s = slave->host; @@ -1303,7 +1312,7 @@ static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event) pxa2xx_i2c_update(s); } -static int pxa2xx_i2c_rx(i2c_slave *i2c) +static int pxa2xx_i2c_rx(I2CSlave *i2c) { PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); PXA2xxI2CState *s = slave->host; @@ -1318,7 +1327,7 @@ static int pxa2xx_i2c_rx(i2c_slave *i2c) return s->data; } -static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data) +static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data) { PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c); PXA2xxI2CState *s = slave->host; @@ -1466,19 +1475,27 @@ static const VMStateDescription vmstate_pxa2xx_i2c = { } }; -static int pxa2xx_i2c_slave_init(i2c_slave *i2c) +static int pxa2xx_i2c_slave_init(I2CSlave *i2c) { /* Nothing to do. */ return 0; } -static I2CSlaveInfo pxa2xx_i2c_slave_info = { - .qdev.name = "pxa2xx-i2c-slave", - .qdev.size = sizeof(PXA2xxI2CSlaveState), - .init = pxa2xx_i2c_slave_init, - .event = pxa2xx_i2c_event, - .recv = pxa2xx_i2c_rx, - .send = pxa2xx_i2c_tx +static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = pxa2xx_i2c_slave_init; + k->event = pxa2xx_i2c_event; + k->recv = pxa2xx_i2c_rx; + k->send = pxa2xx_i2c_tx; +} + +static TypeInfo pxa2xx_i2c_slave_info = { + .name = "pxa2xx-i2c-slave", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(PXA2xxI2CSlaveState), + .class_init = pxa2xx_i2c_slave_class_init, }; PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, @@ -1526,17 +1543,28 @@ i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s) return s->bus; } -static SysBusDeviceInfo pxa2xx_i2c_info = { - .init = pxa2xx_i2c_initfn, - .qdev.name = "pxa2xx_i2c", - .qdev.desc = "PXA2xx I2C Bus Controller", - .qdev.size = sizeof(PXA2xxI2CState), - .qdev.vmsd = &vmstate_pxa2xx_i2c, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), - DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), - DEFINE_PROP_END_OF_LIST(), - }, +static Property pxa2xx_i2c_properties[] = { + DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), + DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_i2c_initfn; + dc->desc = "PXA2xx I2C Bus Controller"; + dc->vmsd = &vmstate_pxa2xx_i2c; + dc->props = pxa2xx_i2c_properties; +} + +static TypeInfo pxa2xx_i2c_info = { + .name = "pxa2xx_i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxI2CState), + .class_init = pxa2xx_i2c_class_init, }; /* PXA Inter-IC Sound Controller */ @@ -2288,12 +2316,26 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) return s; } +static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pxa2xx_ssp_init; +} + +static TypeInfo pxa2xx_ssp_info = { + .name = "pxa2xx-ssp", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxSSPState), + .class_init = pxa2xx_ssp_class_init, +}; + static void pxa2xx_register_devices(void) { - i2c_register_slave(&pxa2xx_i2c_slave_info); - sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init); - sysbus_register_withprop(&pxa2xx_i2c_info); - sysbus_register_withprop(&pxa2xx_rtc_sysbus_info); + type_register_static(&pxa2xx_i2c_slave_info); + type_register_static(&pxa2xx_ssp_info); + type_register_static(&pxa2xx_i2c_info); + type_register_static(&pxa2xx_rtc_sysbus_info); } device_init(pxa2xx_register_devices) diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c index cb281071f0..2d61565f1d 100644 --- a/hw/pxa2xx_dma.c +++ b/hw/pxa2xx_dma.c @@ -543,20 +543,31 @@ static VMStateDescription vmstate_pxa2xx_dma = { }, }; -static SysBusDeviceInfo pxa2xx_dma_info = { - .init = pxa2xx_dma_init, - .qdev.name = "pxa2xx-dma", - .qdev.desc = "PXA2xx DMA controller", - .qdev.size = sizeof(PXA2xxDMAState), - .qdev.vmsd = &vmstate_pxa2xx_dma, - .qdev.props = (Property[]) { - DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1), - DEFINE_PROP_END_OF_LIST(), - }, +static Property pxa2xx_dma_properties[] = { + DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_dma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_dma_init; + dc->desc = "PXA2xx DMA controller"; + dc->vmsd = &vmstate_pxa2xx_dma; + dc->props = pxa2xx_dma_properties; +} + +static TypeInfo pxa2xx_dma_info = { + .name = "pxa2xx-dma", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxDMAState), + .class_init = pxa2xx_dma_class_init, }; static void pxa2xx_dma_register(void) { - sysbus_register_withprop(&pxa2xx_dma_info); + type_register_static(&pxa2xx_dma_info); } device_init(pxa2xx_dma_register); diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c index cc58c40914..67fd17c4ca 100644 --- a/hw/pxa2xx_gpio.c +++ b/hw/pxa2xx_gpio.c @@ -317,20 +317,31 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = { }, }; -static SysBusDeviceInfo pxa2xx_gpio_info = { - .init = pxa2xx_gpio_initfn, - .qdev.name = "pxa2xx-gpio", - .qdev.desc = "PXA2xx GPIO controller", - .qdev.size = sizeof(PXA2xxGPIOInfo), - .qdev.props = (Property []) { - DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0), - DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property pxa2xx_gpio_properties[] = { + DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0), + DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_gpio_initfn; + dc->desc = "PXA2xx GPIO controller"; + dc->props = pxa2xx_gpio_properties; +} + +static TypeInfo pxa2xx_gpio_info = { + .name = "pxa2xx-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxGPIOInfo), + .class_init = pxa2xx_gpio_class_init, }; static void pxa2xx_gpio_register(void) { - sysbus_register_withprop(&pxa2xx_gpio_info); + type_register_static(&pxa2xx_gpio_info); } device_init(pxa2xx_gpio_register); diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c index 92effbc806..ca85743aea 100644 --- a/hw/pxa2xx_pic.c +++ b/hw/pxa2xx_pic.c @@ -296,16 +296,25 @@ static int pxa2xx_pic_initfn(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo pxa2xx_pic_info = { - .init = pxa2xx_pic_initfn, - .qdev.name = "pxa2xx_pic", - .qdev.desc = "PXA2xx PIC", - .qdev.size = sizeof(PXA2xxPICState), - .qdev.vmsd = &vmstate_pxa2xx_pic_regs, +static void pxa2xx_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_pic_initfn; + dc->desc = "PXA2xx PIC"; + dc->vmsd = &vmstate_pxa2xx_pic_regs; +} + +static TypeInfo pxa2xx_pic_info = { + .name = "pxa2xx_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxPICState), + .class_init = pxa2xx_pic_class_init, }; static void pxa2xx_pic_register(void) { - sysbus_register_withprop(&pxa2xx_pic_info); + type_register_static(&pxa2xx_pic_info); } device_init(pxa2xx_pic_register); diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 50e26789d2..90800751b1 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -477,37 +477,59 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = { } }; -static SysBusDeviceInfo pxa25x_timer_dev_info = { - .init = pxa2xx_timer_init, - .qdev.name = "pxa25x-timer", - .qdev.desc = "PXA25x timer", - .qdev.size = sizeof(PXA2xxTimerInfo), - .qdev.vmsd = &vmstate_pxa2xx_timer_regs, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), - DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, false), - DEFINE_PROP_END_OF_LIST(), - }, +static Property pxa25x_timer_dev_properties[] = { + DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), + DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, + PXA2XX_TIMER_HAVE_TM4, false), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo pxa27x_timer_dev_info = { - .init = pxa2xx_timer_init, - .qdev.name = "pxa27x-timer", - .qdev.desc = "PXA27x timer", - .qdev.size = sizeof(PXA2xxTimerInfo), - .qdev.vmsd = &vmstate_pxa2xx_timer_regs, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), - DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, - PXA2XX_TIMER_HAVE_TM4, true), - DEFINE_PROP_END_OF_LIST(), - }, +static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_timer_init; + dc->desc = "PXA25x timer"; + dc->vmsd = &vmstate_pxa2xx_timer_regs; + dc->props = pxa25x_timer_dev_properties; +} + +static TypeInfo pxa25x_timer_dev_info = { + .name = "pxa25x-timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxTimerInfo), + .class_init = pxa25x_timer_dev_class_init, +}; + +static Property pxa27x_timer_dev_properties[] = { + DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), + DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, + PXA2XX_TIMER_HAVE_TM4, true), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = pxa2xx_timer_init; + dc->desc = "PXA27x timer"; + dc->vmsd = &vmstate_pxa2xx_timer_regs; + dc->props = pxa27x_timer_dev_properties; +} + +static TypeInfo pxa27x_timer_dev_info = { + .name = "pxa27x-timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxTimerInfo), + .class_init = pxa27x_timer_dev_class_init, }; static void pxa2xx_timer_register(void) { - sysbus_register_withprop(&pxa25x_timer_dev_info); - sysbus_register_withprop(&pxa27x_timer_dev_info); + type_register_static(&pxa25x_timer_dev_info); + type_register_static(&pxa27x_timer_dev_info); }; device_init(pxa2xx_timer_register); diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c index 5ddda2d0f4..5976dcdf47 100644 --- a/hw/qdev-addr.c +++ b/hw/qdev-addr.c @@ -18,9 +18,10 @@ static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len) return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr); } -static void get_taddr(DeviceState *dev, Visitor *v, void *opaque, +static void get_taddr(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); int64_t value; @@ -29,9 +30,10 @@ static void get_taddr(DeviceState *dev, Visitor *v, void *opaque, visit_type_int(v, &value, name, errp); } -static void set_taddr(DeviceState *dev, Visitor *v, void *opaque, +static void set_taddr(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c new file mode 100644 index 0000000000..135c2bf237 --- /dev/null +++ b/hw/qdev-monitor.c @@ -0,0 +1,588 @@ +/* + * Dynamic device configuration and creation. + * + * Copyright (c) 2009 CodeSourcery + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qdev.h" +#include "monitor.h" + +/* + * Aliases were a bad idea from the start. Let's keep them + * from spreading further. + */ +typedef struct QDevAlias +{ + const char *typename; + const char *alias; +} QDevAlias; + +static const QDevAlias qdev_alias_table[] = { + { "virtio-blk-pci", "virtio-blk" }, + { "virtio-net-pci", "virtio-net" }, + { "virtio-serial-pci", "virtio-serial" }, + { "virtio-balloon-pci", "virtio-balloon" }, + { "virtio-blk-s390", "virtio-blk" }, + { "virtio-net-s390", "virtio-net" }, + { "virtio-serial-s390", "virtio-serial" }, + { "lsi53c895a", "lsi" }, + { "ich9-ahci", "ahci" }, + { } +}; + +static const char *qdev_class_get_alias(DeviceClass *dc) +{ + const char *typename = object_class_get_name(OBJECT_CLASS(dc)); + int i; + + for (i = 0; qdev_alias_table[i].typename; i++) { + if (strcmp(qdev_alias_table[i].typename, typename) == 0) { + return qdev_alias_table[i].alias; + } + } + + return NULL; +} + +static bool qdev_class_has_alias(DeviceClass *dc) +{ + return (qdev_class_get_alias(dc) != NULL); +} + +static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +{ + DeviceClass *dc; + bool *show_no_user = opaque; + + dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + + if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { + return; + } + + error_printf("name \"%s\"", object_class_get_name(klass)); + if (dc->bus_info) { + error_printf(", bus %s", dc->bus_info->name); + } + if (qdev_class_has_alias(dc)) { + error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); + } + if (dc->desc) { + error_printf(", desc \"%s\"", dc->desc); + } + if (dc->no_user) { + error_printf(", no-user"); + } + error_printf("\n"); +} + +static int set_property(const char *name, const char *value, void *opaque) +{ + DeviceState *dev = opaque; + + if (strcmp(name, "driver") == 0) + return 0; + if (strcmp(name, "bus") == 0) + return 0; + + if (qdev_prop_parse(dev, name, value) == -1) { + return -1; + } + return 0; +} + +static const char *find_typename_by_alias(const char *alias) +{ + int i; + + for (i = 0; qdev_alias_table[i].alias; i++) { + if (strcmp(qdev_alias_table[i].alias, alias) == 0) { + return qdev_alias_table[i].typename; + } + } + + return NULL; +} + +int qdev_device_help(QemuOpts *opts) +{ + const char *driver; + Property *prop; + ObjectClass *klass; + DeviceClass *info; + + driver = qemu_opt_get(opts, "driver"); + if (driver && !strcmp(driver, "?")) { + bool show_no_user = false; + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); + return 1; + } + + if (!driver || !qemu_opt_get(opts, "?")) { + return 0; + } + + klass = object_class_by_name(driver); + if (!klass) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + klass = object_class_by_name(driver); + } + } + + if (!klass) { + return 0; + } + info = DEVICE_CLASS(klass); + + for (prop = info->props; prop && prop->name; prop++) { + /* + * TODO Properties without a parser are just for dirty hacks. + * qdev_prop_ptr is the only such PropertyInfo. It's marked + * for removal. This conditional should be removed along with + * it. + */ + if (!prop->info->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", driver, prop->name, + prop->info->legacy_name ?: prop->info->name); + } + if (info->bus_info) { + for (prop = info->bus_info->props; prop && prop->name; prop++) { + if (!prop->info->parse) { + continue; /* no way to set it, don't show */ + } + error_printf("%s.%s=%s\n", driver, prop->name, + prop->info->legacy_name ?: prop->info->name); + } + } + return 1; +} + +static Object *qdev_get_peripheral(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = object_new("container"); + object_property_add_child(object_get_root(), "peripheral", + OBJECT(dev), NULL); + } + + return dev; +} + +static Object *qdev_get_peripheral_anon(void) +{ + static Object *dev; + + if (dev == NULL) { + dev = object_new("container"); + object_property_add_child(object_get_root(), "peripheral-anon", + OBJECT(dev), NULL); + } + + return dev; +} + +static void qbus_list_bus(DeviceState *dev) +{ + BusState *child; + const char *sep = " "; + + error_printf("child busses at \"%s\":", + dev->id ? dev->id : object_get_typename(OBJECT(dev))); + QLIST_FOREACH(child, &dev->child_bus, sibling) { + error_printf("%s\"%s\"", sep, child->name); + sep = ", "; + } + error_printf("\n"); +} + +static void qbus_list_dev(BusState *bus) +{ + DeviceState *dev; + const char *sep = " "; + + error_printf("devices at \"%s\":", bus->name); + QTAILQ_FOREACH(dev, &bus->children, sibling) { + error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); + if (dev->id) + error_printf("/\"%s\"", dev->id); + sep = ", "; + } + error_printf("\n"); +} + +static BusState *qbus_find_bus(DeviceState *dev, char *elem) +{ + BusState *child; + + QLIST_FOREACH(child, &dev->child_bus, sibling) { + if (strcmp(child->name, elem) == 0) { + return child; + } + } + return NULL; +} + +static DeviceState *qbus_find_dev(BusState *bus, char *elem) +{ + DeviceState *dev; + + /* + * try to match in order: + * (1) instance id, if present + * (2) driver name + * (3) driver alias, if present + */ + QTAILQ_FOREACH(dev, &bus->children, sibling) { + if (dev->id && strcmp(dev->id, elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(dev, &bus->children, sibling) { + if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { + return dev; + } + } + QTAILQ_FOREACH(dev, &bus->children, sibling) { + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (qdev_class_has_alias(dc) && + strcmp(qdev_class_get_alias(dc), elem) == 0) { + return dev; + } + } + return NULL; +} + +static BusState *qbus_find_recursive(BusState *bus, const char *name, + const BusInfo *info) +{ + DeviceState *dev; + BusState *child, *ret; + int match = 1; + + if (name && (strcmp(bus->name, name) != 0)) { + match = 0; + } + if (info && (bus->info != info)) { + match = 0; + } + if (match) { + return bus; + } + + QTAILQ_FOREACH(dev, &bus->children, sibling) { + QLIST_FOREACH(child, &dev->child_bus, sibling) { + ret = qbus_find_recursive(child, name, info); + if (ret) { + return ret; + } + } + } + return NULL; +} + +static BusState *qbus_find(const char *path) +{ + DeviceState *dev; + BusState *bus; + char elem[128]; + int pos, len; + + /* find start element */ + if (path[0] == '/') { + bus = sysbus_get_default(); + pos = 0; + } else { + if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { + assert(!path[0]); + elem[0] = len = 0; + } + bus = qbus_find_recursive(sysbus_get_default(), elem, NULL); + if (!bus) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + return NULL; + } + pos = len; + } + + for (;;) { + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } + if (path[pos] == '\0') { + return bus; + } + + /* find device */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + dev = qbus_find_dev(bus, elem); + if (!dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_dev(bus); + } + return NULL; + } + + assert(path[pos] == '/' || !path[pos]); + while (path[pos] == '/') { + pos++; + } + if (path[pos] == '\0') { + /* last specified element is a device. If it has exactly + * one child bus accept it nevertheless */ + switch (dev->num_child_bus) { + case 0: + qerror_report(QERR_DEVICE_NO_BUS, elem); + return NULL; + case 1: + return QLIST_FIRST(&dev->child_bus); + default: + qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } + + /* find bus */ + if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { + assert(0); + elem[0] = len = 0; + } + pos += len; + bus = qbus_find_bus(dev, elem); + if (!bus) { + qerror_report(QERR_BUS_NOT_FOUND, elem); + if (!monitor_cur_is_qmp()) { + qbus_list_bus(dev); + } + return NULL; + } + } +} + +DeviceState *qdev_device_add(QemuOpts *opts) +{ + ObjectClass *obj; + DeviceClass *k; + const char *driver, *path, *id; + DeviceState *qdev; + BusState *bus; + + driver = qemu_opt_get(opts, "driver"); + if (!driver) { + qerror_report(QERR_MISSING_PARAMETER, "driver"); + return NULL; + } + + /* find driver */ + obj = object_class_by_name(driver); + if (!obj) { + const char *typename = find_typename_by_alias(driver); + + if (typename) { + driver = typename; + obj = object_class_by_name(driver); + } + } + + if (!obj) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type"); + return NULL; + } + + k = DEVICE_CLASS(obj); + + /* find bus */ + path = qemu_opt_get(opts, "bus"); + if (path != NULL) { + bus = qbus_find(path); + if (!bus) { + return NULL; + } + if (bus->info != k->bus_info) { + qerror_report(QERR_BAD_BUS_FOR_DEVICE, + driver, bus->info->name); + return NULL; + } + } else { + bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info); + if (!bus) { + qerror_report(QERR_NO_BUS_FOR_DEVICE, + driver, k->bus_info->name); + return NULL; + } + } + if (qdev_hotplug && !bus->allow_hotplug) { + qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); + return NULL; + } + + if (!bus) { + bus = sysbus_get_default(); + } + + /* create device, set properties */ + qdev = DEVICE(object_new(driver)); + qdev_set_parent_bus(qdev, bus); + qdev_prop_set_globals(qdev); + + id = qemu_opts_id(opts); + if (id) { + qdev->id = id; + object_property_add_child(qdev_get_peripheral(), qdev->id, + OBJECT(qdev), NULL); + } else { + static int anon_count; + gchar *name = g_strdup_printf("device[%d]", anon_count++); + object_property_add_child(qdev_get_peripheral_anon(), name, + OBJECT(qdev), NULL); + g_free(name); + } + if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { + qdev_free(qdev); + return NULL; + } + if (qdev_init(qdev) < 0) { + qerror_report(QERR_DEVICE_INIT_FAILED, driver); + return NULL; + } + qdev->opts = opts; + return qdev; +} + + +#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) +static void qbus_print(Monitor *mon, BusState *bus, int indent); + +static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, + const char *prefix, int indent) +{ + char buf[64]; + + if (!props) + return; + while (props->name) { + /* + * TODO Properties without a print method are just for dirty + * hacks. qdev_prop_ptr is the only such PropertyInfo. It's + * marked for removal. The test props->info->print should be + * removed along with it. + */ + if (props->info->print) { + props->info->print(dev, props, buf, sizeof(buf)); + qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); + } + props++; + } +} + +static void qdev_print(Monitor *mon, DeviceState *dev, int indent) +{ + BusState *child; + qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)), + dev->id ? dev->id : ""); + indent += 2; + if (dev->num_gpio_in) { + qdev_printf("gpio-in %d\n", dev->num_gpio_in); + } + if (dev->num_gpio_out) { + qdev_printf("gpio-out %d\n", dev->num_gpio_out); + } + qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent); + qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent); + if (dev->parent_bus->info->print_dev) + dev->parent_bus->info->print_dev(mon, dev, indent); + QLIST_FOREACH(child, &dev->child_bus, sibling) { + qbus_print(mon, child, indent); + } +} + +static void qbus_print(Monitor *mon, BusState *bus, int indent) +{ + struct DeviceState *dev; + + qdev_printf("bus: %s\n", bus->name); + indent += 2; + qdev_printf("type %s\n", bus->info->name); + QTAILQ_FOREACH(dev, &bus->children, sibling) { + qdev_print(mon, dev, indent); + } +} +#undef qdev_printf + +void do_info_qtree(Monitor *mon) +{ + if (sysbus_get_default()) + qbus_print(mon, sysbus_get_default(), 0); +} + +void do_info_qdm(Monitor *mon) +{ + object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL); +} + +int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + QemuOpts *opts; + + opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict); + if (!opts) { + return -1; + } + if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { + qemu_opts_del(opts); + return 0; + } + if (!qdev_device_add(opts)) { + qemu_opts_del(opts); + return -1; + } + return 0; +} + +int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) +{ + const char *id = qdict_get_str(qdict, "id"); + DeviceState *dev; + + dev = qdev_find_recursive(sysbus_get_default(), id); + if (NULL == dev) { + qerror_report(QERR_DEVICE_NOT_FOUND, id); + return -1; + } + return qdev_unplug(dev); +} + +void qdev_machine_init(void) +{ + qdev_get_peripheral_anon(); + qdev_get_peripheral(); +} diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index 02f0dae0bc..c4583a14d7 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -40,9 +40,9 @@ static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src) /* Bit */ static int parse_bit(DeviceState *dev, Property *prop, const char *str) { - if (!strncasecmp(str, "on", 2)) + if (!strcasecmp(str, "on")) bit_prop_set(dev, prop, true); - else if (!strncasecmp(str, "off", 3)) + else if (!strcasecmp(str, "off")) bit_prop_set(dev, prop, false); else return -EINVAL; @@ -55,9 +55,10 @@ static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); } -static void get_bit(DeviceState *dev, Visitor *v, void *opaque, +static void get_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; uint32_t *p = qdev_get_prop_ptr(dev, prop); bool value = (*p & qdev_get_prop_mask(prop)) != 0; @@ -65,9 +66,10 @@ static void get_bit(DeviceState *dev, Visitor *v, void *opaque, visit_type_bool(v, &value, name, errp); } -static void set_bit(DeviceState *dev, Visitor *v, void *opaque, +static void set_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; Error *local_err = NULL; bool value; @@ -118,9 +120,10 @@ static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) return snprintf(dest, len, "%" PRIu8, *ptr); } -static void get_int8(DeviceState *dev, Visitor *v, void *opaque, +static void get_int8(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int8_t *ptr = qdev_get_prop_ptr(dev, prop); int64_t value; @@ -129,9 +132,10 @@ static void get_int8(DeviceState *dev, Visitor *v, void *opaque, visit_type_int(v, &value, name, errp); } -static void set_int8(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) +static void set_int8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int8_t *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; @@ -224,9 +228,10 @@ static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len return snprintf(dest, len, "%" PRIu16, *ptr); } -static void get_int16(DeviceState *dev, Visitor *v, void *opaque, +static void get_int16(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int16_t *ptr = qdev_get_prop_ptr(dev, prop); int64_t value; @@ -235,9 +240,10 @@ static void get_int16(DeviceState *dev, Visitor *v, void *opaque, visit_type_int(v, &value, name, errp); } -static void set_int16(DeviceState *dev, Visitor *v, void *opaque, +static void set_int16(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int16_t *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; @@ -296,9 +302,10 @@ static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len return snprintf(dest, len, "%" PRIu32, *ptr); } -static void get_int32(DeviceState *dev, Visitor *v, void *opaque, +static void get_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); int64_t value; @@ -307,9 +314,10 @@ static void get_int32(DeviceState *dev, Visitor *v, void *opaque, visit_type_int(v, &value, name, errp); } -static void set_int32(DeviceState *dev, Visitor *v, void *opaque, +static void set_int32(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; @@ -433,18 +441,20 @@ static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len return snprintf(dest, len, "%" PRIu64, *ptr); } -static void get_int64(DeviceState *dev, Visitor *v, void *opaque, +static void get_int64(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int64_t *ptr = qdev_get_prop_ptr(dev, prop); visit_type_int(v, ptr, name, errp); } -static void set_int64(DeviceState *dev, Visitor *v, void *opaque, +static void set_int64(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; int64_t *ptr = qdev_get_prop_ptr(dev, prop); @@ -523,9 +533,10 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len return snprintf(dest, len, "\"%s\"", *ptr); } -static void get_string(DeviceState *dev, Visitor *v, void *opaque, +static void get_string(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; char **ptr = qdev_get_prop_ptr(dev, prop); @@ -537,9 +548,10 @@ static void get_string(DeviceState *dev, Visitor *v, void *opaque, } } -static void set_string(DeviceState *dev, Visitor *v, void *opaque, +static void set_string(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; char **ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; @@ -609,9 +621,10 @@ static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) *ptr ? bdrv_get_device_name(*ptr) : "<null>"); } -static void get_generic(DeviceState *dev, Visitor *v, void *opaque, +static void get_generic(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; void **ptr = qdev_get_prop_ptr(dev, prop); char buffer[1024]; @@ -624,9 +637,10 @@ static void get_generic(DeviceState *dev, Visitor *v, void *opaque, visit_type_str(v, &p, name, errp); } -static void set_generic(DeviceState *dev, Visitor *v, void *opaque, +static void set_generic(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; Error *local_err = NULL; char *str; @@ -774,9 +788,10 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) } } -static void get_vlan(DeviceState *dev, Visitor *v, void *opaque, +static void get_vlan(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; VLANState **ptr = qdev_get_prop_ptr(dev, prop); int64_t id; @@ -785,9 +800,10 @@ static void get_vlan(DeviceState *dev, Visitor *v, void *opaque, visit_type_int(v, &id, name, errp); } -static void set_vlan(DeviceState *dev, Visitor *v, void *opaque, +static void set_vlan(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; VLANState **ptr = qdev_get_prop_ptr(dev, prop); Error *local_err = NULL; @@ -885,6 +901,55 @@ PropertyInfo qdev_prop_macaddr = { .set = set_generic, }; + +/* --- lost tick policy --- */ + +static const struct { + const char *name; + LostTickPolicy code; +} lost_tick_policy_table[] = { + { .name = "discard", .code = LOST_TICK_DISCARD }, + { .name = "delay", .code = LOST_TICK_DELAY }, + { .name = "merge", .code = LOST_TICK_MERGE }, + { .name = "slew", .code = LOST_TICK_SLEW }, +}; + +static int parse_lost_tick_policy(DeviceState *dev, Property *prop, + const char *str) +{ + LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop); + int i; + + for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) { + if (!strcasecmp(str, lost_tick_policy_table[i].name)) { + *ptr = lost_tick_policy_table[i].code; + break; + } + } + if (i == ARRAY_SIZE(lost_tick_policy_table)) { + return -EINVAL; + } + return 0; +} + +static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest, + size_t len) +{ + LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop); + + return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name); +} + +PropertyInfo qdev_prop_losttickpolicy = { + .name = "lost_tick_policy", + .type = PROP_TYPE_LOSTTICKPOLICY, + .size = sizeof(LostTickPolicy), + .parse = parse_lost_tick_policy, + .print = print_lost_tick_policy, + .get = get_generic, + .set = set_generic, +}; + /* --- pci address --- */ /* @@ -922,9 +987,10 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t } } -static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque, +static void get_pci_devfn(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); char buffer[32]; @@ -966,7 +1032,7 @@ static Property *qdev_prop_find(DeviceState *dev, const char *name) Property *prop; /* device properties */ - prop = qdev_prop_walk(dev->info->props, name); + prop = qdev_prop_walk(qdev_get_props(dev), name); if (prop) return prop; @@ -989,16 +1055,16 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, switch (ret) { case -EEXIST: error_set(errp, QERR_PROPERTY_VALUE_IN_USE, - dev->info->name, prop->name, value); + object_get_typename(OBJECT(dev)), prop->name, value); break; default: case -EINVAL: error_set(errp, QERR_PROPERTY_VALUE_BAD, - dev->info->name, prop->name, value); + object_get_typename(OBJECT(dev)), prop->name, value); break; case -ENOENT: error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, - dev->info->name, prop->name, value); + object_get_typename(OBJECT(dev)), prop->name, value); break; case 0: break; @@ -1018,7 +1084,7 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) * removed along with it. */ if (!prop || !prop->info->parse) { - qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); + qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name); return -1; } ret = prop->info->parse(dev, prop, value); @@ -1039,12 +1105,12 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT prop = qdev_prop_find(dev, name); if (!prop) { fprintf(stderr, "%s: property \"%s.%s\" not found\n", - __FUNCTION__, dev->info->name, name); + __FUNCTION__, object_get_typename(OBJECT(dev)), name); abort(); } if (prop->info->type != type) { fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", - __FUNCTION__, dev->info->name, name); + __FUNCTION__, object_get_typename(OBJECT(dev)), name); abort(); } qdev_prop_cpy(dev, prop, src); @@ -1093,7 +1159,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va if (res < 0) { error_report("Can't attach drive %s to %s.%s: %s", bdrv_get_device_name(value), - dev->id ? dev->id : dev->info->name, + dev->id ? dev->id : object_get_typename(OBJECT(dev)), name, strerror(-res)); return -1; } @@ -1127,6 +1193,12 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); } +void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name, + LostTickPolicy *value) +{ + qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY); +} + void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) { qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); @@ -1165,8 +1237,8 @@ void qdev_prop_set_globals(DeviceState *dev) GlobalProperty *prop; QTAILQ_FOREACH(prop, &global_props, next) { - if (strcmp(dev->info->name, prop->driver) != 0 && - strcmp(dev->info->bus_info->name, prop->driver) != 0) { + if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 && + strcmp(qdev_get_bus_info(dev)->name, prop->driver) != 0) { continue; } if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { @@ -28,9 +28,8 @@ #include "net.h" #include "qdev.h" #include "sysemu.h" -#include "monitor.h" -static int qdev_hotplug = 0; +int qdev_hotplug = 0; static bool qdev_hot_added = false; static bool qdev_hot_removed = false; @@ -38,86 +37,60 @@ static bool qdev_hot_removed = false; static BusState *main_system_bus; static void main_system_bus_create(void); -DeviceInfo *device_info_list; - -static BusState *qbus_find_recursive(BusState *bus, const char *name, - const BusInfo *info); -static BusState *qbus_find(const char *path); - /* Register a new device type. */ -void qdev_register(DeviceInfo *info) +const VMStateDescription *qdev_get_vmsd(DeviceState *dev) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + return dc->vmsd; +} + +BusInfo *qdev_get_bus_info(DeviceState *dev) { - assert(info->size >= sizeof(DeviceState)); - assert(!info->next); + DeviceClass *dc = DEVICE_GET_CLASS(dev); + return dc->bus_info; +} - info->next = device_info_list; - device_info_list = info; +Property *qdev_get_props(DeviceState *dev) +{ + DeviceClass *dc = DEVICE_GET_CLASS(dev); + return dc->props; } -static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name) +const char *qdev_fw_name(DeviceState *dev) { - DeviceInfo *info; - - /* first check device names */ - for (info = device_info_list; info != NULL; info = info->next) { - if (bus_info && info->bus_info != bus_info) - continue; - if (strcmp(info->name, name) != 0) - continue; - return info; - } + DeviceClass *dc = DEVICE_GET_CLASS(dev); - /* failing that check the aliases */ - for (info = device_info_list; info != NULL; info = info->next) { - if (bus_info && info->bus_info != bus_info) - continue; - if (!info->alias) - continue; - if (strcmp(info->alias, name) != 0) - continue; - return info; + if (dc->fw_name) { + return dc->fw_name; } - return NULL; + + return object_get_typename(OBJECT(dev)); +} + +bool qdev_exists(const char *name) +{ + return !!object_class_by_name(name); } static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp); -static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info) +void qdev_set_parent_bus(DeviceState *dev, BusState *bus) { - DeviceState *dev; Property *prop; - assert(bus->info == info->bus_info); - dev = g_malloc0(info->size); - dev->info = info; - dev->parent_bus = bus; - qdev_prop_set_defaults(dev, dev->info->props); - qdev_prop_set_defaults(dev, dev->parent_bus->info->props); - qdev_prop_set_globals(dev); - QTAILQ_INSERT_HEAD(&bus->children, dev, sibling); if (qdev_hotplug) { assert(bus->allow_hotplug); - dev->hotplugged = 1; - qdev_hot_added = true; } - dev->instance_id_alias = -1; - QTAILQ_INIT(&dev->properties); - dev->state = DEV_STATE_CREATED; - for (prop = dev->info->props; prop && prop->name; prop++) { - qdev_property_add_legacy(dev, prop, NULL); - qdev_property_add_static(dev, prop, NULL); - } + dev->parent_bus = bus; + QTAILQ_INSERT_HEAD(&bus->children, dev, sibling); - for (prop = dev->info->bus_info->props; prop && prop->name; prop++) { + qdev_prop_set_defaults(dev, dev->parent_bus->info->props); + for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) { qdev_property_add_legacy(dev, prop, NULL); qdev_property_add_static(dev, prop, NULL); } - - qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL); - - return dev; } /* Create a new device. This only initializes the device state structure @@ -142,197 +115,23 @@ DeviceState *qdev_create(BusState *bus, const char *name) DeviceState *qdev_try_create(BusState *bus, const char *name) { - DeviceInfo *info; - - if (!bus) { - bus = sysbus_get_default(); - } + DeviceState *dev; - info = qdev_find_info(bus->info, name); - if (!info) { + dev = DEVICE(object_new(name)); + if (!dev) { return NULL; } - return qdev_create_from_info(bus, info); -} - -static void qdev_print_devinfo(DeviceInfo *info) -{ - error_printf("name \"%s\", bus %s", - info->name, info->bus_info->name); - if (info->alias) { - error_printf(", alias \"%s\"", info->alias); - } - if (info->desc) { - error_printf(", desc \"%s\"", info->desc); - } - if (info->no_user) { - error_printf(", no-user"); - } - error_printf("\n"); -} - -static int set_property(const char *name, const char *value, void *opaque) -{ - DeviceState *dev = opaque; - - if (strcmp(name, "driver") == 0) - return 0; - if (strcmp(name, "bus") == 0) - return 0; - - if (qdev_prop_parse(dev, name, value) == -1) { - return -1; - } - return 0; -} - -int qdev_device_help(QemuOpts *opts) -{ - const char *driver; - DeviceInfo *info; - Property *prop; - - driver = qemu_opt_get(opts, "driver"); - if (driver && !strcmp(driver, "?")) { - for (info = device_info_list; info != NULL; info = info->next) { - if (info->no_user) { - continue; /* not available, don't show */ - } - qdev_print_devinfo(info); - } - return 1; - } - - if (!driver || !qemu_opt_get(opts, "?")) { - return 0; - } - - info = qdev_find_info(NULL, driver); - if (!info) { - return 0; - } - - for (prop = info->props; prop && prop->name; prop++) { - /* - * TODO Properties without a parser are just for dirty hacks. - * qdev_prop_ptr is the only such PropertyInfo. It's marked - * for removal. This conditional should be removed along with - * it. - */ - if (!prop->info->parse) { - continue; /* no way to set it, don't show */ - } - error_printf("%s.%s=%s\n", info->name, prop->name, - prop->info->legacy_name ?: prop->info->name); - } - for (prop = info->bus_info->props; prop && prop->name; prop++) { - if (!prop->info->parse) { - continue; /* no way to set it, don't show */ - } - error_printf("%s.%s=%s\n", info->name, prop->name, - prop->info->legacy_name ?: prop->info->name); - } - return 1; -} - -static DeviceState *qdev_get_peripheral(void) -{ - static DeviceState *dev; - - if (dev == NULL) { - dev = qdev_create(NULL, "container"); - qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL); - qdev_init_nofail(dev); + if (!bus) { + bus = sysbus_get_default(); } - return dev; -} - -static DeviceState *qdev_get_peripheral_anon(void) -{ - static DeviceState *dev; - - if (dev == NULL) { - dev = qdev_create(NULL, "container"); - qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL); - qdev_init_nofail(dev); - } + qdev_set_parent_bus(dev, bus); + qdev_prop_set_globals(dev); return dev; } -DeviceState *qdev_device_add(QemuOpts *opts) -{ - const char *driver, *path, *id; - DeviceInfo *info; - DeviceState *qdev; - BusState *bus; - - driver = qemu_opt_get(opts, "driver"); - if (!driver) { - qerror_report(QERR_MISSING_PARAMETER, "driver"); - return NULL; - } - - /* find driver */ - info = qdev_find_info(NULL, driver); - if (!info || info->no_user) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name"); - error_printf_unless_qmp("Try with argument '?' for a list.\n"); - return NULL; - } - - /* find bus */ - path = qemu_opt_get(opts, "bus"); - if (path != NULL) { - bus = qbus_find(path); - if (!bus) { - return NULL; - } - if (bus->info != info->bus_info) { - qerror_report(QERR_BAD_BUS_FOR_DEVICE, - driver, bus->info->name); - return NULL; - } - } else { - bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info); - if (!bus) { - qerror_report(QERR_NO_BUS_FOR_DEVICE, - info->name, info->bus_info->name); - return NULL; - } - } - if (qdev_hotplug && !bus->allow_hotplug) { - qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); - return NULL; - } - - /* create device, set properties */ - qdev = qdev_create_from_info(bus, info); - id = qemu_opts_id(opts); - if (id) { - qdev->id = id; - qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL); - } else { - static int anon_count; - gchar *name = g_strdup_printf("device[%d]", anon_count++); - qdev_property_add_child(qdev_get_peripheral_anon(), name, - qdev, NULL); - g_free(name); - } - if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) { - qdev_free(qdev); - return NULL; - } - if (qdev_init(qdev) < 0) { - qerror_report(QERR_DEVICE_INIT_FAILED, driver); - return NULL; - } - qdev->opts = opts; - return qdev; -} - /* Initialize a device. Device properties should be set before calling this function. IRQs and MMIO regions should be connected/mapped after calling this function. @@ -340,22 +139,24 @@ DeviceState *qdev_device_add(QemuOpts *opts) Return 0 on success. */ int qdev_init(DeviceState *dev) { + DeviceClass *dc = DEVICE_GET_CLASS(dev); int rc; assert(dev->state == DEV_STATE_CREATED); - rc = dev->info->init(dev, dev->info); + + rc = dc->init(dev); if (rc < 0) { qdev_free(dev); return rc; } - if (dev->info->vmsd) { - vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev, + if (qdev_get_vmsd(dev)) { + vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, dev->instance_id_alias, dev->alias_required_for_version); } dev->state = DEV_STATE_INITIALIZED; - if (dev->hotplugged && dev->info->reset) { - dev->info->reset(dev); + if (dev->hotplugged) { + device_reset(dev); } return 0; } @@ -370,22 +171,22 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, int qdev_unplug(DeviceState *dev) { + DeviceClass *dc = DEVICE_GET_CLASS(dev); + if (!dev->parent_bus->allow_hotplug) { qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); return -1; } - assert(dev->info->unplug != NULL); + assert(dc->unplug != NULL); qdev_hot_removed = true; - return dev->info->unplug(dev); + return dc->unplug(dev); } static int qdev_reset_one(DeviceState *dev, void *opaque) { - if (dev->info->reset) { - dev->info->reset(dev); - } + device_reset(dev); return 0; } @@ -421,6 +222,7 @@ void qbus_reset_all_fn(void *opaque) int qdev_simple_unplug_cb(DeviceState *dev) { /* just zap it */ + object_unparent(OBJECT(dev)); qdev_free(dev); return 0; } @@ -435,87 +237,17 @@ int qdev_simple_unplug_cb(DeviceState *dev) way is somewhat unclean, and best avoided. */ void qdev_init_nofail(DeviceState *dev) { - DeviceInfo *info = dev->info; - if (qdev_init(dev) < 0) { - error_report("Initialization of device %s failed", info->name); + error_report("Initialization of device %s failed", + object_get_typename(OBJECT(dev))); exit(1); } } -static void qdev_property_del_all(DeviceState *dev) -{ - while (!QTAILQ_EMPTY(&dev->properties)) { - DeviceProperty *prop = QTAILQ_FIRST(&dev->properties); - - QTAILQ_REMOVE(&dev->properties, prop, node); - - if (prop->release) { - prop->release(dev, prop->name, prop->opaque); - } - - g_free(prop->name); - g_free(prop->type); - g_free(prop); - } -} - -static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp) -{ - DeviceProperty *prop; - - QTAILQ_FOREACH(prop, &dev->properties, node) { - if (strstart(prop->type, "child<", NULL) && prop->opaque == child) { - break; - } - } - - g_assert(prop != NULL); - - QTAILQ_REMOVE(&dev->properties, prop, node); - - if (prop->release) { - prop->release(dev, prop->name, prop->opaque); - } - - g_free(prop->name); - g_free(prop->type); - g_free(prop); -} - /* Unlink device from bus and free the structure. */ void qdev_free(DeviceState *dev) { - BusState *bus; - Property *prop; - - qdev_property_del_all(dev); - - if (dev->state == DEV_STATE_INITIALIZED) { - while (dev->num_child_bus) { - bus = QLIST_FIRST(&dev->child_bus); - qbus_free(bus); - } - if (dev->info->vmsd) - vmstate_unregister(dev, dev->info->vmsd, dev); - if (dev->info->exit) - dev->info->exit(dev); - if (dev->opts) - qemu_opts_del(dev->opts); - } - QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling); - for (prop = dev->info->props; prop && prop->name; prop++) { - if (prop->info->free) { - prop->info->free(dev, prop); - } - } - if (dev->parent) { - qdev_property_del_child(dev->parent, dev, NULL); - } - if (dev->ref != 0) { - qerror_report(QERR_DEVICE_IN_USE, dev->id?:""); - } - g_free(dev); + object_delete(OBJECT(dev)); } void qdev_machine_creation_done(void) @@ -532,15 +264,6 @@ bool qdev_machine_modified(void) return qdev_hot_added || qdev_hot_removed; } -/* Get a character (serial) device interface. */ -CharDriverState *qdev_init_chardev(DeviceState *dev) -{ - static int next_serial; - - /* FIXME: This function needs to go away: use chardev properties! */ - return serial_hds[next_serial++]; -} - BusState *qdev_get_parent_bus(DeviceState *dev) { return dev->parent_bus; @@ -644,34 +367,6 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn, return 0; } -static BusState *qbus_find_recursive(BusState *bus, const char *name, - const BusInfo *info) -{ - DeviceState *dev; - BusState *child, *ret; - int match = 1; - - if (name && (strcmp(bus->name, name) != 0)) { - match = 0; - } - if (info && (bus->info != info)) { - match = 0; - } - if (match) { - return bus; - } - - QTAILQ_FOREACH(dev, &bus->children, sibling) { - QLIST_FOREACH(child, &dev->child_bus, sibling) { - ret = qbus_find_recursive(child, name, info); - if (ret) { - return ret; - } - } - } - return NULL; -} - DeviceState *qdev_find_recursive(BusState *bus, const char *id) { DeviceState *dev, *ret; @@ -690,162 +385,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id) return NULL; } -static void qbus_list_bus(DeviceState *dev) -{ - BusState *child; - const char *sep = " "; - - error_printf("child busses at \"%s\":", - dev->id ? dev->id : dev->info->name); - QLIST_FOREACH(child, &dev->child_bus, sibling) { - error_printf("%s\"%s\"", sep, child->name); - sep = ", "; - } - error_printf("\n"); -} - -static void qbus_list_dev(BusState *bus) -{ - DeviceState *dev; - const char *sep = " "; - - error_printf("devices at \"%s\":", bus->name); - QTAILQ_FOREACH(dev, &bus->children, sibling) { - error_printf("%s\"%s\"", sep, dev->info->name); - if (dev->id) - error_printf("/\"%s\"", dev->id); - sep = ", "; - } - error_printf("\n"); -} - -static BusState *qbus_find_bus(DeviceState *dev, char *elem) -{ - BusState *child; - - QLIST_FOREACH(child, &dev->child_bus, sibling) { - if (strcmp(child->name, elem) == 0) { - return child; - } - } - return NULL; -} - -static DeviceState *qbus_find_dev(BusState *bus, char *elem) -{ - DeviceState *dev; - - /* - * try to match in order: - * (1) instance id, if present - * (2) driver name - * (3) driver alias, if present - */ - QTAILQ_FOREACH(dev, &bus->children, sibling) { - if (dev->id && strcmp(dev->id, elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(dev, &bus->children, sibling) { - if (strcmp(dev->info->name, elem) == 0) { - return dev; - } - } - QTAILQ_FOREACH(dev, &bus->children, sibling) { - if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) { - return dev; - } - } - return NULL; -} - -static BusState *qbus_find(const char *path) -{ - DeviceState *dev; - BusState *bus; - char elem[128]; - int pos, len; - - /* find start element */ - if (path[0] == '/') { - bus = main_system_bus; - pos = 0; - } else { - if (sscanf(path, "%127[^/]%n", elem, &len) != 1) { - assert(!path[0]); - elem[0] = len = 0; - } - bus = qbus_find_recursive(main_system_bus, elem, NULL); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - return NULL; - } - pos = len; - } - - for (;;) { - assert(path[pos] == '/' || !path[pos]); - while (path[pos] == '/') { - pos++; - } - if (path[pos] == '\0') { - return bus; - } - - /* find device */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - dev = qbus_find_dev(bus, elem); - if (!dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_dev(bus); - } - return NULL; - } - - assert(path[pos] == '/' || !path[pos]); - while (path[pos] == '/') { - pos++; - } - if (path[pos] == '\0') { - /* last specified element is a device. If it has exactly - * one child bus accept it nevertheless */ - switch (dev->num_child_bus) { - case 0: - qerror_report(QERR_DEVICE_NO_BUS, elem); - return NULL; - case 1: - return QLIST_FIRST(&dev->child_bus); - default: - qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } - - /* find bus */ - if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) { - assert(0); - elem[0] = len = 0; - } - pos += len; - bus = qbus_find_bus(dev, elem); - if (!bus) { - qerror_report(QERR_BUS_NOT_FOUND, elem); - if (!monitor_cur_is_qmp()) { - qbus_list_bus(dev); - } - return NULL; - } - } -} - void qbus_create_inplace(BusState *bus, BusInfo *info, DeviceState *parent, const char *name) { @@ -926,112 +465,6 @@ void qbus_free(BusState *bus) } } -#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__) -static void qbus_print(Monitor *mon, BusState *bus, int indent); - -static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props, - const char *prefix, int indent) -{ - char buf[64]; - - if (!props) - return; - while (props->name) { - /* - * TODO Properties without a print method are just for dirty - * hacks. qdev_prop_ptr is the only such PropertyInfo. It's - * marked for removal. The test props->info->print should be - * removed along with it. - */ - if (props->info->print) { - props->info->print(dev, props, buf, sizeof(buf)); - qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf); - } - props++; - } -} - -static void qdev_print(Monitor *mon, DeviceState *dev, int indent) -{ - BusState *child; - qdev_printf("dev: %s, id \"%s\"\n", dev->info->name, - dev->id ? dev->id : ""); - indent += 2; - if (dev->num_gpio_in) { - qdev_printf("gpio-in %d\n", dev->num_gpio_in); - } - if (dev->num_gpio_out) { - qdev_printf("gpio-out %d\n", dev->num_gpio_out); - } - qdev_print_props(mon, dev, dev->info->props, "dev", indent); - qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent); - if (dev->parent_bus->info->print_dev) - dev->parent_bus->info->print_dev(mon, dev, indent); - QLIST_FOREACH(child, &dev->child_bus, sibling) { - qbus_print(mon, child, indent); - } -} - -static void qbus_print(Monitor *mon, BusState *bus, int indent) -{ - struct DeviceState *dev; - - qdev_printf("bus: %s\n", bus->name); - indent += 2; - qdev_printf("type %s\n", bus->info->name); - QTAILQ_FOREACH(dev, &bus->children, sibling) { - qdev_print(mon, dev, indent); - } -} -#undef qdev_printf - -void do_info_qtree(Monitor *mon) -{ - if (main_system_bus) - qbus_print(mon, main_system_bus, 0); -} - -void do_info_qdm(Monitor *mon) -{ - DeviceInfo *info; - - for (info = device_info_list; info != NULL; info = info->next) { - qdev_print_devinfo(info); - } -} - -int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - QemuOpts *opts; - - opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict); - if (!opts) { - return -1; - } - if (!monitor_cur_is_qmp() && qdev_device_help(opts)) { - qemu_opts_del(opts); - return 0; - } - if (!qdev_device_add(opts)) { - qemu_opts_del(opts); - return -1; - } - return 0; -} - -int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data) -{ - const char *id = qdict_get_str(qdict, "id"); - DeviceState *dev; - - dev = qdev_find_recursive(main_system_bus, id); - if (NULL == dev) { - qerror_report(QERR_DEVICE_NOT_FOUND, id); - return -1; - } - return qdev_unplug(dev); -} - static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) { int l = 0; @@ -1044,7 +477,7 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size) l += snprintf(p + l, size - l, "%s", d); g_free(d); } else { - l += snprintf(p + l, size - l, "%s", dev->info->name); + l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev))); } } l += snprintf(p + l , size - l, "/"); @@ -1064,106 +497,19 @@ char* qdev_get_fw_dev_path(DeviceState *dev) return strdup(path); } -char *qdev_get_type(DeviceState *dev, Error **errp) +static char *qdev_get_type(Object *obj, Error **errp) { - return g_strdup(dev->info->name); -} - -void qdev_ref(DeviceState *dev) -{ - dev->ref++; -} - -void qdev_unref(DeviceState *dev) -{ - g_assert(dev->ref > 0); - dev->ref--; -} - -void qdev_property_add(DeviceState *dev, const char *name, const char *type, - DevicePropertyAccessor *get, DevicePropertyAccessor *set, - DevicePropertyRelease *release, - void *opaque, Error **errp) -{ - DeviceProperty *prop = g_malloc0(sizeof(*prop)); - - prop->name = g_strdup(name); - prop->type = g_strdup(type); - - prop->get = get; - prop->set = set; - prop->release = release; - prop->opaque = opaque; - - QTAILQ_INSERT_TAIL(&dev->properties, prop, node); -} - -static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name) -{ - DeviceProperty *prop; - - QTAILQ_FOREACH(prop, &dev->properties, node) { - if (strcmp(prop->name, name) == 0) { - return prop; - } - } - - return NULL; -} - -void qdev_property_get(DeviceState *dev, Visitor *v, const char *name, - Error **errp) -{ - DeviceProperty *prop = qdev_property_find(dev, name); - - if (prop == NULL) { - error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); - return; - } - - if (!prop->get) { - error_set(errp, QERR_PERMISSION_DENIED); - } else { - prop->get(dev, v, prop->opaque, name, errp); - } -} - -void qdev_property_set(DeviceState *dev, Visitor *v, const char *name, - Error **errp) -{ - DeviceProperty *prop = qdev_property_find(dev, name); - - if (prop == NULL) { - error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); - return; - } - - if (!prop->set) { - error_set(errp, QERR_PERMISSION_DENIED); - } else { - prop->set(dev, v, prop->opaque, name, errp); - } -} - -const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp) -{ - DeviceProperty *prop = qdev_property_find(dev, name); - - if (prop == NULL) { - error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name); - return NULL; - } - - return prop->type; + return g_strdup(object_get_typename(obj)); } /** * Legacy property handling */ -static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque, +static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; char buffer[1024]; @@ -1173,9 +519,10 @@ static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque, visit_type_str(v, &ptr, name, errp); } -static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque, +static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); Property *prop = opaque; Error *local_err = NULL; char *ptr = NULL; @@ -1215,11 +562,11 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop, type = g_strdup_printf("legacy<%s>", prop->info->legacy_name ?: prop->info->name); - qdev_property_add(dev, name, type, - prop->info->print ? qdev_get_legacy_property : NULL, - prop->info->parse ? qdev_set_legacy_property : NULL, - NULL, - prop, errp); + object_property_add(OBJECT(dev), name, type, + prop->info->print ? qdev_get_legacy_property : NULL, + prop->info->parse ? qdev_set_legacy_property : NULL, + NULL, + prop, errp); g_free(type); g_free(name); @@ -1234,337 +581,87 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop, void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp) { - qdev_property_add(dev, prop->name, prop->info->name, - prop->info->get, prop->info->set, - NULL, - prop, errp); -} - -DeviceState *qdev_get_root(void) -{ - static DeviceState *qdev_root; - - if (!qdev_root) { - qdev_root = qdev_create(NULL, "container"); - qdev_init_nofail(qdev_root); - } - - return qdev_root; -} - -static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState *child = opaque; - gchar *path; - - path = qdev_get_canonical_path(child); - visit_type_str(v, &path, name, errp); - g_free(path); + object_property_add(OBJECT(dev), prop->name, prop->info->name, + prop->info->get, prop->info->set, + NULL, + prop, errp); } -static void qdev_release_child_property(DeviceState *dev, const char *name, - void *opaque) +static void device_initfn(Object *obj) { - DeviceState *child = opaque; - - qdev_unref(child); -} - -void qdev_property_add_child(DeviceState *dev, const char *name, - DeviceState *child, Error **errp) -{ - gchar *type; - - type = g_strdup_printf("child<%s>", child->info->name); - - qdev_property_add(dev, name, type, qdev_get_child_property, - NULL, qdev_release_child_property, - child, errp); - - qdev_ref(child); - g_assert(child->parent == NULL); - child->parent = dev; - - g_free(type); -} - -static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState **child = opaque; - gchar *path; - - if (*child) { - path = qdev_get_canonical_path(*child); - visit_type_str(v, &path, name, errp); - g_free(path); - } else { - path = (gchar *)""; - visit_type_str(v, &path, name, errp); - } -} - -static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - DeviceState **child = opaque; - bool ambiguous = false; - const char *type; - char *path; - - type = qdev_property_get_type(dev, name, NULL); - - visit_type_str(v, &path, name, errp); - - if (*child) { - qdev_unref(*child); - } - - if (strcmp(path, "") != 0) { - DeviceState *target; - - target = qdev_resolve_path(path, &ambiguous); - if (target) { - gchar *target_type; - - target_type = g_strdup_printf("link<%s>", target->info->name); - if (strcmp(target_type, type) == 0) { - *child = target; - qdev_ref(target); - } else { - error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type); - } + DeviceState *dev = DEVICE(obj); + Property *prop; - g_free(target_type); - } else { - error_set(errp, QERR_DEVICE_NOT_FOUND, path); - } - } else { - *child = NULL; + if (qdev_hotplug) { + dev->hotplugged = 1; + qdev_hot_added = true; } - g_free(path); -} - -void qdev_property_add_link(DeviceState *dev, const char *name, - const char *type, DeviceState **child, - Error **errp) -{ - gchar *full_type; - - full_type = g_strdup_printf("link<%s>", type); - - qdev_property_add(dev, name, full_type, - qdev_get_link_property, - qdev_set_link_property, - NULL, child, errp); - - g_free(full_type); -} - -gchar *qdev_get_canonical_path(DeviceState *dev) -{ - DeviceState *root = qdev_get_root(); - char *newpath = NULL, *path = NULL; - - while (dev != root) { - DeviceProperty *prop = NULL; - - g_assert(dev->parent != NULL); - - QTAILQ_FOREACH(prop, &dev->parent->properties, node) { - if (!strstart(prop->type, "child<", NULL)) { - continue; - } - - if (prop->opaque == dev) { - if (path) { - newpath = g_strdup_printf("%s/%s", prop->name, path); - g_free(path); - path = newpath; - } else { - path = g_strdup(prop->name); - } - break; - } - } - - g_assert(prop != NULL); + dev->instance_id_alias = -1; + dev->state = DEV_STATE_CREATED; - dev = dev->parent; + qdev_prop_set_defaults(dev, qdev_get_props(dev)); + for (prop = qdev_get_props(dev); prop && prop->name; prop++) { + qdev_property_add_legacy(dev, prop, NULL); + qdev_property_add_static(dev, prop, NULL); } - newpath = g_strdup_printf("/%s", path); - g_free(path); - - return newpath; + object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL); } -static DeviceState *qdev_resolve_abs_path(DeviceState *parent, - gchar **parts, - int index) +/* Unlink device from bus and free the structure. */ +static void device_finalize(Object *obj) { - DeviceProperty *prop; - DeviceState *child; - - if (parts[index] == NULL) { - return parent; - } - - if (strcmp(parts[index], "") == 0) { - return qdev_resolve_abs_path(parent, parts, index + 1); - } - - prop = qdev_property_find(parent, parts[index]); - if (prop == NULL) { - return NULL; - } + DeviceState *dev = DEVICE(obj); + BusState *bus; + Property *prop; + DeviceClass *dc = DEVICE_GET_CLASS(dev); - child = NULL; - if (strstart(prop->type, "link<", NULL)) { - DeviceState **pchild = prop->opaque; - if (*pchild) { - child = *pchild; + if (dev->state == DEV_STATE_INITIALIZED) { + while (dev->num_child_bus) { + bus = QLIST_FIRST(&dev->child_bus); + qbus_free(bus); } - } else if (strstart(prop->type, "child<", NULL)) { - child = prop->opaque; - } - - if (!child) { - return NULL; - } - - return qdev_resolve_abs_path(child, parts, index + 1); -} - -static DeviceState *qdev_resolve_partial_path(DeviceState *parent, - gchar **parts, - bool *ambiguous) -{ - DeviceState *dev; - DeviceProperty *prop; - - dev = qdev_resolve_abs_path(parent, parts, 0); - - QTAILQ_FOREACH(prop, &parent->properties, node) { - DeviceState *found; - - if (!strstart(prop->type, "child<", NULL)) { - continue; + if (qdev_get_vmsd(dev)) { + vmstate_unregister(dev, qdev_get_vmsd(dev), dev); } - - found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous); - if (found) { - if (dev) { - if (ambiguous) { - *ambiguous = true; - } - return NULL; - } - dev = found; + if (dc->exit) { + dc->exit(dev); } - - if (ambiguous && *ambiguous) { - return NULL; + if (dev->opts) { + qemu_opts_del(dev->opts); } } - - return dev; -} - -DeviceState *qdev_resolve_path(const char *path, bool *ambiguous) -{ - bool partial_path = true; - DeviceState *dev; - gchar **parts; - - parts = g_strsplit(path, "/", 0); - if (parts == NULL || parts[0] == NULL) { - g_strfreev(parts); - return qdev_get_root(); - } - - if (strcmp(parts[0], "") == 0) { - partial_path = false; - } - - if (partial_path) { - if (ambiguous) { - *ambiguous = false; + QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling); + for (prop = qdev_get_props(dev); prop && prop->name; prop++) { + if (prop->info->free) { + prop->info->free(dev, prop); } - dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous); - } else { - dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1); - } - - g_strfreev(parts); - - return dev; -} - -typedef struct StringProperty -{ - char *(*get)(DeviceState *, Error **); - void (*set)(DeviceState *, const char *, Error **); -} StringProperty; - -static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) -{ - StringProperty *prop = opaque; - char *value; - - value = prop->get(dev, errp); - if (value) { - visit_type_str(v, &value, name, errp); - g_free(value); } } -static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque, - const char *name, Error **errp) +void device_reset(DeviceState *dev) { - StringProperty *prop = opaque; - char *value; - Error *local_err = NULL; + DeviceClass *klass = DEVICE_GET_CLASS(dev); - visit_type_str(v, &value, name, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (klass->reset) { + klass->reset(dev); } - - prop->set(dev, value, errp); - g_free(value); } -static void qdev_property_release_str(DeviceState *dev, const char *name, - void *opaque) -{ - StringProperty *prop = opaque; - g_free(prop); -} +static TypeInfo device_type_info = { + .name = TYPE_DEVICE, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DeviceState), + .instance_init = device_initfn, + .instance_finalize = device_finalize, + .abstract = true, + .class_size = sizeof(DeviceClass), +}; -void qdev_property_add_str(DeviceState *dev, const char *name, - char *(*get)(DeviceState *, Error **), - void (*set)(DeviceState *, const char *, Error **), - Error **errp) +static void init_qdev(void) { - StringProperty *prop = g_malloc0(sizeof(*prop)); - - prop->get = get; - prop->set = set; - - qdev_property_add(dev, name, "string", - get ? qdev_property_get_str : NULL, - set ? qdev_property_set_str : NULL, - qdev_property_release_str, - prop, errp); + type_register_static(&device_type_info); } -void qdev_machine_init(void) -{ - qdev_get_peripheral_anon(); - qdev_get_peripheral(); -} +device_init(init_qdev); @@ -6,6 +6,7 @@ #include "qemu-char.h" #include "qemu-option.h" #include "qapi/qapi-visit-core.h" +#include "qemu/object.h" typedef struct Property Property; @@ -13,8 +14,6 @@ typedef struct PropertyInfo PropertyInfo; typedef struct CompatProperty CompatProperty; -typedef struct DeviceInfo DeviceInfo; - typedef struct BusState BusState; typedef struct BusInfo BusInfo; @@ -28,52 +27,45 @@ enum { DEV_NVECTORS_UNSPECIFIED = -1, }; -/** - * @DevicePropertyAccessor - called when trying to get/set a property - * - * @dev the device that owns the property - * @v the visitor that contains the property data - * @opaque the device property opaque - * @name the name of the property - * @errp a pointer to an Error that is filled if getting/setting fails. - */ -typedef void (DevicePropertyAccessor)(DeviceState *dev, - Visitor *v, - void *opaque, - const char *name, - Error **errp); +#define TYPE_DEVICE "device" +#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE) +#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) +#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) -/** - * @DevicePropertyRelease - called when a property is removed from a device - * - * @dev the device that owns the property - * @name the name of the property - * @opaque the opaque registered with the property - */ -typedef void (DevicePropertyRelease)(DeviceState *dev, - const char *name, - void *opaque); - -typedef struct DeviceProperty -{ - gchar *name; - gchar *type; - DevicePropertyAccessor *get; - DevicePropertyAccessor *set; - DevicePropertyRelease *release; - void *opaque; - - QTAILQ_ENTRY(DeviceProperty) node; -} DeviceProperty; +typedef int (*qdev_initfn)(DeviceState *dev); +typedef int (*qdev_event)(DeviceState *dev); +typedef void (*qdev_resetfn)(DeviceState *dev); + +typedef struct DeviceClass { + ObjectClass parent_class; + + const char *fw_name; + const char *desc; + Property *props; + int no_user; + + /* callbacks */ + void (*reset)(DeviceState *dev); + + /* device state */ + const VMStateDescription *vmsd; + + /* Private to qdev / bus. */ + qdev_initfn init; + qdev_event unplug; + qdev_event exit; + BusInfo *bus_info; +} DeviceClass; /* This structure should not be accessed directly. We declare it here so that it can be embedded in individual device state structures. */ struct DeviceState { + Object parent_obj; + const char *id; enum DevState state; QemuOpts *opts; int hotplugged; - DeviceInfo *info; BusState *parent_bus; int num_gpio_out; qemu_irq *gpio_out; @@ -84,18 +76,6 @@ struct DeviceState { QTAILQ_ENTRY(DeviceState) sibling; int instance_id_alias; int alias_required_for_version; - - /** - * This tracks the number of references between devices. See @qdev_ref for - * more information. - */ - uint32_t ref; - - QTAILQ_HEAD(, DeviceProperty) properties; - - /* Do not, under any circumstance, use this parent link below anywhere - * outside of qdev.c. You have been warned. */ - DeviceState *parent; }; typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent); @@ -145,6 +125,7 @@ enum PropertyType { PROP_TYPE_UINT64, PROP_TYPE_TADDR, PROP_TYPE_MACADDR, + PROP_TYPE_LOSTTICKPOLICY, PROP_TYPE_DRIVE, PROP_TYPE_CHR, PROP_TYPE_STRING, @@ -164,8 +145,8 @@ struct PropertyInfo { int (*parse)(DeviceState *dev, Property *prop, const char *str); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); void (*free)(DeviceState *dev, Property *prop); - DevicePropertyAccessor *get; - DevicePropertyAccessor *set; + ObjectPropertyAccessor *get; + ObjectPropertyAccessor *set; }; typedef struct GlobalProperty { @@ -179,6 +160,7 @@ typedef struct GlobalProperty { DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); +bool qdev_exists(const char *name); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; @@ -198,43 +180,11 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name); /*** Device API. ***/ -typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info); -typedef int (*qdev_event)(DeviceState *dev); -typedef void (*qdev_resetfn)(DeviceState *dev); - -struct DeviceInfo { - const char *name; - const char *fw_name; - const char *alias; - const char *desc; - size_t size; - Property *props; - int no_user; - - /* callbacks */ - qdev_resetfn reset; - - /* device state */ - const VMStateDescription *vmsd; - - /* Private to qdev / bus. */ - qdev_initfn init; - qdev_event unplug; - qdev_event exit; - BusInfo *bus_info; - struct DeviceInfo *next; -}; -extern DeviceInfo *device_info_list; - -void qdev_register(DeviceInfo *info); - /* Register device properties. */ /* GPIO inputs also double as IRQ sinks. */ 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); -CharDriverState *qdev_init_chardev(DeviceState *dev); - BusState *qdev_get_parent_bus(DeviceState *dev); /*** BUS API. ***/ @@ -287,6 +237,7 @@ extern PropertyInfo qdev_prop_string; extern PropertyInfo qdev_prop_chr; extern PropertyInfo qdev_prop_ptr; extern PropertyInfo qdev_prop_macaddr; +extern PropertyInfo qdev_prop_losttickpolicy; extern PropertyInfo qdev_prop_drive; extern PropertyInfo qdev_prop_netdev; extern PropertyInfo qdev_prop_vlan; @@ -347,6 +298,9 @@ extern PropertyInfo qdev_prop_pci_devfn; DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *) #define DEFINE_PROP_MACADDR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr) +#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \ + LostTickPolicy) #define DEFINE_PROP_END_OF_LIST() \ {} @@ -369,6 +323,8 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value); int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT; void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value); void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value); +void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name, + LostTickPolicy *value); /* FIXME: Remove opaque pointer properties. */ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_set_defaults(DeviceState *dev, Property *props); @@ -378,250 +334,43 @@ void qdev_prop_set_globals(DeviceState *dev); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, Property *prop, const char *value); -static inline const char *qdev_fw_name(DeviceState *dev) -{ - return dev->info->fw_name ? : dev->info->alias ? : dev->info->name; -} - char *qdev_get_fw_dev_path(DeviceState *dev); + /* This is a nasty hack to allow passing a NULL bus to qdev_create. */ extern struct BusInfo system_bus_info; /** - * @qdev_ref - * - * Increase the reference count of a device. A device cannot be freed as long - * as its reference count is greater than zero. - * - * @dev - the device - */ -void qdev_ref(DeviceState *dev); - -/** - * @qdef_unref - * - * Decrease the reference count of a device. A device cannot be freed as long - * as its reference count is greater than zero. - * - * @dev - the device - */ -void qdev_unref(DeviceState *dev); - -/** - * @qdev_property_add - add a new property to a device - * - * @dev - the device to add a property to - * - * @name - the name of the property. This can contain any character except for - * a forward slash. In general, you should use hyphens '-' instead of - * underscores '_' when naming properties. - * - * @type - the type name of the property. This namespace is pretty loosely - * defined. Sub namespaces are constructed by using a prefix and then - * to angle brackets. For instance, the type 'virtio-net-pci' in the - * 'link' namespace would be 'link<virtio-net-pci>'. - * - * @get - the getter to be called to read a property. If this is NULL, then - * the property cannot be read. - * - * @set - the setter to be called to write a property. If this is NULL, - * then the property cannot be written. - * - * @release - called when the property is removed from the device. This is - * meant to allow a property to free its opaque upon device - * destruction. This may be NULL. - * - * @opaque - an opaque pointer to pass to the callbacks for the property - * - * @errp - returns an error if this function fails - */ -void qdev_property_add(DeviceState *dev, const char *name, const char *type, - DevicePropertyAccessor *get, DevicePropertyAccessor *set, - DevicePropertyRelease *release, - void *opaque, Error **errp); - -/** - * @qdev_property_get - reads a property from a device - * - * @dev - the device - * - * @v - the visitor that will receive the property value. This should be an - * Output visitor and the data will be written with @name as the name. - * - * @name - the name of the property - * - * @errp - returns an error if this function fails - */ -void qdev_property_get(DeviceState *dev, Visitor *v, const char *name, - Error **errp); - -/** - * @qdev_property_set - writes a property to a device - * - * @dev - the device - * - * @v - the visitor that will be used to write the property value. This should - * be an Input visitor and the data will be first read with @name as the - * name and then written as the property value. - * - * @name - the name of the property - * - * @errp - returns an error if this function fails - */ -void qdev_property_set(DeviceState *dev, Visitor *v, const char *name, - Error **errp); - -/** - * @qdev_property_get_type - returns the type of a property - * - * @dev - the device - * - * @name - the name of the property - * - * @errp - returns an error if this function fails - * - * Returns: - * The type name of the property. - */ -const char *qdev_property_get_type(DeviceState *dev, const char *name, - Error **errp); - -/** * @qdev_property_add_static - add a @Property to a device referencing a * field in a struct. */ void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp); /** - * @qdev_get_root - returns the root device of the composition tree + * @qdev_machine_init * - * Returns: - * The root of the composition tree. + * Initialize platform devices before machine init. This is a hack until full + * support for composition is added. */ -DeviceState *qdev_get_root(void); +void qdev_machine_init(void); /** - * @qdev_get_canonical_path - returns the canonical path for a device. This - * is the path within the composition tree starting from the root. + * @device_reset * - * Returns: - * The canonical path in the composition tree. + * Reset a single device (by calling the reset method). */ -gchar *qdev_get_canonical_path(DeviceState *dev); +void device_reset(DeviceState *dev); -/** - * @qdev_resolve_path - resolves a path returning a device - * - * There are two types of supported paths--absolute paths and partial paths. - * - * Absolute paths are derived from the root device and can follow child<> or - * link<> properties. Since they can follow link<> properties, they can be - * arbitrarily long. Absolute paths look like absolute filenames and are - * prefixed with a leading slash. - * - * Partial paths look like relative filenames. They do not begin with a - * prefix. The matching rules for partial paths are subtle but designed to make - * specifying devices easy. At each level of the composition tree, the partial - * path is matched as an absolute path. The first match is not returned. At - * least two matches are searched for. A successful result is only returned if - * only one match is founded. If more than one match is found, a flag is - * return to indicate that the match was ambiguous. - * - * @path - the path to resolve - * - * @ambiguous - returns true if the path resolution failed because of an - * ambiguous match - * - * Returns: - * The matched device or NULL on path lookup failure. - */ -DeviceState *qdev_resolve_path(const char *path, bool *ambiguous); +const VMStateDescription *qdev_get_vmsd(DeviceState *dev); -/** - * @qdev_property_add_child - Add a child property to a device - * - * Child properties form the composition tree. All devices need to be a child - * of another device. Devices can only be a child of one device. - * - * There is no way for a child to determine what its parent is. It is not - * a bidirectional relationship. This is by design. - * - * @dev - the device to add a property to - * - * @name - the name of the property - * - * @child - the child device - * - * @errp - if an error occurs, a pointer to an area to store the area - */ -void qdev_property_add_child(DeviceState *dev, const char *name, - DeviceState *child, Error **errp); +const char *qdev_fw_name(DeviceState *dev); -/** - * @qdev_property_add_link - Add a link property to a device - * - * Links establish relationships between devices. Links are unidirectional - * although two links can be combined to form a bidirectional relationship - * between devices. - * - * Links form the graph in the device model. - * - * @dev - the device to add a property to - * - * @name - the name of the property - * - * @type - the qdev type of the link - * - * @child - a pointer to where the link device reference is stored - * - * @errp - if an error occurs, a pointer to an area to store the area - */ -void qdev_property_add_link(DeviceState *dev, const char *name, - const char *type, DeviceState **child, - Error **errp); +BusInfo *qdev_get_bus_info(DeviceState *dev); -/** - * @qdev_property_add_str - * - * Add a string property using getters/setters. This function will add a - * property of type 'string'. - * - * @dev - the device to add a property to - * - * @name - the name of the property - * - * @get - the getter or NULL if the property is write-only. This function must - * return a string to be freed by @g_free(). - * - * @set - the setter or NULL if the property is read-only - * - * @errp - if an error occurs, a pointer to an area to store the error - */ -void qdev_property_add_str(DeviceState *dev, const char *name, - char *(*get)(DeviceState *, Error **), - void (*set)(DeviceState *, const char *, Error **), - Error **errp); +Property *qdev_get_props(DeviceState *dev); -/** - * @qdev_get_type - * - * Returns the string representation of the type of this object. - * - * @dev - the device - * - * @errp - if an error occurs, a pointer to an area to store the error - * - * Returns: a string representing the type. This must be freed by the caller - * with g_free(). - */ -char *qdev_get_type(DeviceState *dev, Error **errp); +/* FIXME: make this a link<> */ +void qdev_set_parent_bus(DeviceState *dev, BusState *bus); -/** - * @qdev_machine_init - * - * Initialize platform devices before machine init. This is a hack until full - * support for composition is added. - */ -void qdev_machine_init(void); +extern int qdev_hotplug; #endif @@ -343,10 +343,7 @@ static void init_qxl_ram(PCIQXLDevice *d) /* can be called from spice server thread context */ static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end) { - while (addr < end) { - memory_region_set_dirty(mr, addr); - addr += TARGET_PAGE_SIZE; - } + memory_region_set_dirty(mr, addr, end - addr); } static void qxl_rom_set_dirty(PCIQXLDevice *qxl) @@ -1020,7 +1017,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) case MEMSLOT_GROUP_HOST: return (void*)offset; case MEMSLOT_GROUP_GUEST: - PANIC_ON(slot > NUM_MEMSLOTS); + PANIC_ON(slot >= NUM_MEMSLOTS); PANIC_ON(!qxl->guest_slots[slot].active); PANIC_ON(offset < qxl->guest_slots[slot].delta); offset -= qxl->guest_slots[slot].delta; @@ -1827,38 +1824,56 @@ static Property qxl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static PCIDeviceInfo qxl_info_primary = { - .qdev.name = "qxl-vga", - .qdev.desc = "Spice QXL GPU (primary, vga compatible)", - .qdev.size = sizeof(PCIQXLDevice), - .qdev.reset = qxl_reset_handler, - .qdev.vmsd = &qxl_vmstate, - .no_hotplug = 1, - .init = qxl_init_primary, - .romfile = "vgabios-qxl.bin", - .vendor_id = REDHAT_PCI_VENDOR_ID, - .device_id = QXL_DEVICE_ID_STABLE, - .class_id = PCI_CLASS_DISPLAY_VGA, - .qdev.props = qxl_properties, +static void qxl_primary_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = qxl_init_primary; + k->romfile = "vgabios-qxl.bin"; + k->vendor_id = REDHAT_PCI_VENDOR_ID; + k->device_id = QXL_DEVICE_ID_STABLE; + k->class_id = PCI_CLASS_DISPLAY_VGA; + dc->desc = "Spice QXL GPU (primary, vga compatible)"; + dc->reset = qxl_reset_handler; + dc->vmsd = &qxl_vmstate; + dc->props = qxl_properties; +} + +static TypeInfo qxl_primary_info = { + .name = "qxl-vga", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIQXLDevice), + .class_init = qxl_primary_class_init, }; -static PCIDeviceInfo qxl_info_secondary = { - .qdev.name = "qxl", - .qdev.desc = "Spice QXL GPU (secondary)", - .qdev.size = sizeof(PCIQXLDevice), - .qdev.reset = qxl_reset_handler, - .qdev.vmsd = &qxl_vmstate, - .init = qxl_init_secondary, - .vendor_id = REDHAT_PCI_VENDOR_ID, - .device_id = QXL_DEVICE_ID_STABLE, - .class_id = PCI_CLASS_DISPLAY_OTHER, - .qdev.props = qxl_properties, +static void qxl_secondary_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = qxl_init_secondary; + k->vendor_id = REDHAT_PCI_VENDOR_ID; + k->device_id = QXL_DEVICE_ID_STABLE; + k->class_id = PCI_CLASS_DISPLAY_OTHER; + dc->desc = "Spice QXL GPU (secondary)"; + dc->reset = qxl_reset_handler; + dc->vmsd = &qxl_vmstate; + dc->props = qxl_properties; +} + +static TypeInfo qxl_secondary_info = { + .name = "qxl", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIQXLDevice), + .class_init = qxl_secondary_class_init, }; static void qxl_register(void) { - pci_qdev_register(&qxl_info_primary); - pci_qdev_register(&qxl_info_secondary); + type_register_static(&qxl_primary_info); + type_register_static(&qxl_secondary_info); } device_init(qxl_register); diff --git a/hw/realview.c b/hw/realview.c index 3f35118f21..821e627560 100644 --- a/hw/realview.c +++ b/hw/realview.c @@ -82,15 +82,23 @@ static int realview_i2c_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo realview_i2c_info = { - .init = realview_i2c_init, - .qdev.name = "realview_i2c", - .qdev.size = sizeof(RealViewI2CState), +static void realview_i2c_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = realview_i2c_init; +} + +static TypeInfo realview_i2c_info = { + .name = "realview_i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RealViewI2CState), + .class_init = realview_i2c_class_init, }; static void realview_register_devices(void) { - sysbus_register_withprop(&realview_i2c_info); + type_register_static(&realview_i2c_info); } /* Board init. */ @@ -227,6 +235,8 @@ static void realview_init(ram_addr_t ram_size, for (n = 0; n < smp_cpus; n++) { sysbus_connect_irq(busdev, n, cpu_irq[n]); } + sysbus_create_varargs("l2x0", realview_binfo.smp_priv_base + 0x2000, + NULL); } else { uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; /* For now just create the nIRQ GIC, and ignore the others. */ diff --git a/hw/realview_gic.c b/hw/realview_gic.c index 8c4d509ee7..4121502c7b 100644 --- a/hw/realview_gic.c +++ b/hw/realview_gic.c @@ -9,7 +9,6 @@ #include "sysbus.h" -#define GIC_NIRQ 96 #define NCPU 1 /* Only a single "CPU" interface is present. */ @@ -37,16 +36,33 @@ static int realview_gic_init(SysBusDevice *dev) { RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); - gic_init(&s->gic); + /* The GICs on the RealView boards have a fixed nonconfigurable + * number of interrupt lines, so we don't need to expose this as + * a qdev property. + */ + gic_init(&s->gic, 96); realview_gic_map_setup(s); sysbus_init_mmio(dev, &s->container); return 0; } +static void realview_gic_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = realview_gic_init; +} + +static TypeInfo realview_gic_info = { + .name = "realview_gic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RealViewGICState), + .class_init = realview_gic_class_init, +}; + static void realview_gic_register_devices(void) { - sysbus_register_dev("realview_gic", sizeof(RealViewGICState), - realview_gic_init); + type_register_static(&realview_gic_info); } device_init(realview_gic_register_devices) diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 0ae9f5774b..1668390e1f 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3478,7 +3478,7 @@ static int pci_rtl8139_init(PCIDevice *dev) s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8; s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); s->cplus_txbuffer = NULL; @@ -3494,27 +3494,38 @@ static int pci_rtl8139_init(PCIDevice *dev) return 0; } -static PCIDeviceInfo rtl8139_info = { - .qdev.name = "rtl8139", - .qdev.size = sizeof(RTL8139State), - .qdev.reset = rtl8139_reset, - .qdev.vmsd = &vmstate_rtl8139, - .init = pci_rtl8139_init, - .exit = pci_rtl8139_uninit, - .romfile = "pxe-rtl8139.rom", - .vendor_id = PCI_VENDOR_ID_REALTEK, - .device_id = PCI_DEVICE_ID_REALTEK_8139, - .revision = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */ - .class_id = PCI_CLASS_NETWORK_ETHERNET, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(RTL8139State, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property rtl8139_properties[] = { + DEFINE_NIC_PROPERTIES(RTL8139State, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void rtl8139_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_rtl8139_init; + k->exit = pci_rtl8139_uninit; + k->romfile = "pxe-rtl8139.rom"; + k->vendor_id = PCI_VENDOR_ID_REALTEK; + k->device_id = PCI_DEVICE_ID_REALTEK_8139; + k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */ + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + dc->reset = rtl8139_reset; + dc->vmsd = &vmstate_rtl8139; + dc->props = rtl8139_properties; +} + +static TypeInfo rtl8139_info = { + .name = "rtl8139", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(RTL8139State), + .class_init = rtl8139_class_init, }; static void rtl8139_register_devices(void) { - pci_qdev_register(&rtl8139_info); + type_register_static(&rtl8139_info); } device_init(rtl8139_register_devices) diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c index 2efea9f184..49140f8a9e 100644 --- a/hw/s390-virtio-bus.c +++ b/hw/s390-virtio-bus.c @@ -50,12 +50,6 @@ struct BusInfo s390_virtio_bus_info = { .size = sizeof(VirtIOS390Bus), }; -typedef struct { - DeviceInfo qdev; - int (*init)(VirtIOS390Device *dev); -} VirtIOS390DeviceInfo; - - static const VirtIOBindings virtio_s390_bindings; static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev); @@ -343,69 +337,108 @@ static const VirtIOBindings virtio_s390_bindings = { .get_features = virtio_s390_get_features, }; -static VirtIOS390DeviceInfo s390_virtio_net = { - .init = s390_virtio_net_init, - .qdev.name = "virtio-net-s390", - .qdev.alias = "virtio-net", - .qdev.size = sizeof(VirtIOS390Device), - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic), - DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device, - net.txtimer, TX_TIMER_INTERVAL), - DEFINE_PROP_INT32("x-txburst", VirtIOS390Device, - net.txburst, TX_BURST), - DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx), - DEFINE_PROP_END_OF_LIST(), - }, +static Property s390_virtio_net_properties[] = { + DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic), + DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device, + net.txtimer, TX_TIMER_INTERVAL), + DEFINE_PROP_INT32("x-txburst", VirtIOS390Device, + net.txburst, TX_BURST), + DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx), + DEFINE_PROP_END_OF_LIST(), +}; + +static void s390_virtio_net_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass); + + k->init = s390_virtio_net_init; + dc->props = s390_virtio_net_properties; +} + +static TypeInfo s390_virtio_net = { + .name = "virtio-net-s390", + .parent = TYPE_VIRTIO_S390_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .class_init = s390_virtio_net_class_init, +}; + +static Property s390_virtio_blk_properties[] = { + DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), + DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), + DEFINE_PROP_END_OF_LIST(), +}; + +static void s390_virtio_blk_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass); + + k->init = s390_virtio_blk_init; + dc->props = s390_virtio_blk_properties; +} + +static TypeInfo s390_virtio_blk = { + .name = "virtio-blk-s390", + .parent = TYPE_VIRTIO_S390_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .class_init = s390_virtio_blk_class_init, }; -static VirtIOS390DeviceInfo s390_virtio_blk = { - .init = s390_virtio_blk_init, - .qdev.name = "virtio-blk-s390", - .qdev.alias = "virtio-blk", - .qdev.size = sizeof(VirtIOS390Device), - .qdev.props = (Property[]) { - DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block), - DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial), - DEFINE_PROP_END_OF_LIST(), - }, +static Property s390_virtio_serial_properties[] = { + DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, + serial.max_virtserial_ports, 31), + DEFINE_PROP_END_OF_LIST(), }; -static VirtIOS390DeviceInfo s390_virtio_serial = { - .init = s390_virtio_serial_init, - .qdev.name = "virtio-serial-s390", - .qdev.alias = "virtio-serial", - .qdev.size = sizeof(VirtIOS390Device), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("max_ports", VirtIOS390Device, - serial.max_virtserial_ports, 31), - DEFINE_PROP_END_OF_LIST(), - }, +static void s390_virtio_serial_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass); + + k->init = s390_virtio_serial_init; + dc->props = s390_virtio_serial_properties; +} + +static TypeInfo s390_virtio_serial = { + .name = "virtio-serial-s390", + .parent = TYPE_VIRTIO_S390_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .class_init = s390_virtio_serial_class_init, }; -static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info) +static int s390_virtio_busdev_init(DeviceState *dev) { - VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info; VirtIOS390Device *_dev = (VirtIOS390Device *)dev; + VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev); return _info->init(_dev); } -static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info) +static void virtio_s390_device_class_init(ObjectClass *klass, void *data) { - info->qdev.init = s390_virtio_busdev_init; - info->qdev.bus_info = &s390_virtio_bus_info; - info->qdev.unplug = qdev_simple_unplug_cb; + DeviceClass *dc = DEVICE_CLASS(klass); - assert(info->qdev.size >= sizeof(VirtIOS390Device)); - qdev_register(&info->qdev); + dc->init = s390_virtio_busdev_init; + dc->bus_info = &s390_virtio_bus_info; + dc->unplug = qdev_simple_unplug_cb; } +static TypeInfo virtio_s390_device_info = { + .name = TYPE_VIRTIO_S390_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIOS390Device), + .class_init = virtio_s390_device_class_init, + .class_size = sizeof(VirtIOS390DeviceClass), + .abstract = true, +}; + static void s390_virtio_register(void) { - s390_virtio_bus_register_withprop(&s390_virtio_serial); - s390_virtio_bus_register_withprop(&s390_virtio_blk); - s390_virtio_bus_register_withprop(&s390_virtio_net); + type_register_static(&virtio_s390_device_info); + type_register_static(&s390_virtio_serial); + type_register_static(&s390_virtio_blk); + type_register_static(&s390_virtio_net); } device_init(s390_virtio_register); @@ -419,16 +452,25 @@ static int s390_virtio_bridge_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo s390_virtio_bridge_info = { - .init = s390_virtio_bridge_init, - .qdev.name = "s390-virtio-bridge", - .qdev.size = sizeof(SysBusDevice), - .qdev.no_user = 1, +static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = s390_virtio_bridge_init; + dc->no_user = 1; +} + +static TypeInfo s390_virtio_bridge_info = { + .name = "s390-virtio-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = s390_virtio_bridge_class_init, }; static void s390_virtio_register_devices(void) { - sysbus_register_withprop(&s390_virtio_bridge_info); + type_register_static(&s390_virtio_bridge_info); } device_init(s390_virtio_register_devices) diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h index d02a90709d..b5e59b7d4b 100644 --- a/hw/s390-virtio-bus.h +++ b/hw/s390-virtio-bus.h @@ -40,7 +40,22 @@ #define VIRTIO_PARAM_CONFIG_CHANGED 0x1 #define VIRTIO_PARAM_DEV_ADD 0x2 -typedef struct VirtIOS390Device { +#define TYPE_VIRTIO_S390_DEVICE "virtio-s390-device" +#define VIRTIO_S390_DEVICE(obj) \ + OBJECT_CHECK(VirtIOS390Device, (obj), TYPE_VIRTIO_S390_DEVICE) +#define VIRTIO_S390_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOS390DeviceClass, (klass), TYPE_VIRTIO_S390_DEVICE) +#define VIRTIO_S390_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE) + +typedef struct VirtIOS390Device VirtIOS390Device; + +typedef struct VirtIOS390DeviceClass { + DeviceClass qdev; + int (*init)(VirtIOS390Device *dev); +} VirtIOS390DeviceClass; + +struct VirtIOS390Device { DeviceState qdev; ram_addr_t dev_offs; ram_addr_t feat_offs; @@ -52,7 +67,7 @@ typedef struct VirtIOS390Device { uint32_t host_features; virtio_serial_conf serial; virtio_net_conf net; -} VirtIOS390Device; +}; typedef struct VirtIOS390Bus { BusState bus; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 2210b8ac7e..51123a7535 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -317,7 +317,6 @@ static QEMUMachine s390_machine = { .no_serial = 1, .no_parallel = 1, .use_virtcon = 1, - .no_vga = 1, .max_cpus = 255, .is_default = 1, }; @@ -1289,55 +1289,55 @@ static const VMStateDescription vmstate_sb16 = { .minimum_version_id_old = 1, .post_load = sb16_post_load, .fields = (VMStateField []) { - VMSTATE_UINT32(irq, SB16State), - VMSTATE_UINT32(dma, SB16State), - VMSTATE_UINT32(hdma, SB16State), - VMSTATE_UINT32(port, SB16State), - VMSTATE_UINT32(ver, SB16State), - VMSTATE_INT32(in_index, SB16State), - VMSTATE_INT32(out_data_len, SB16State), - VMSTATE_INT32(fmt_stereo, SB16State), - VMSTATE_INT32(fmt_signed, SB16State), - VMSTATE_INT32(fmt_bits, SB16State), - VMSTATE_UINT32(fmt, SB16State), - VMSTATE_INT32(dma_auto, SB16State), - VMSTATE_INT32(block_size, SB16State), - VMSTATE_INT32(fifo, SB16State), - VMSTATE_INT32(freq, SB16State), - VMSTATE_INT32(time_const, SB16State), - VMSTATE_INT32(speaker, SB16State), - VMSTATE_INT32(needed_bytes, SB16State), - VMSTATE_INT32(cmd, SB16State), - VMSTATE_INT32(use_hdma, SB16State), - VMSTATE_INT32(highspeed, SB16State), - VMSTATE_INT32(can_write, SB16State), - VMSTATE_INT32(v2x6, SB16State), - - VMSTATE_UINT8(csp_param, SB16State), - VMSTATE_UINT8(csp_value, SB16State), - VMSTATE_UINT8(csp_mode, SB16State), - VMSTATE_UINT8(csp_param, SB16State), - VMSTATE_BUFFER(csp_regs, SB16State), - VMSTATE_UINT8(csp_index, SB16State), - VMSTATE_BUFFER(csp_reg83, SB16State), - VMSTATE_INT32(csp_reg83r, SB16State), - VMSTATE_INT32(csp_reg83w, SB16State), - - VMSTATE_BUFFER(in2_data, SB16State), - VMSTATE_BUFFER(out_data, SB16State), - VMSTATE_UINT8(test_reg, SB16State), - VMSTATE_UINT8(last_read_byte, SB16State), - - VMSTATE_INT32(nzero, SB16State), - VMSTATE_INT32(left_till_irq, SB16State), - VMSTATE_INT32(dma_running, SB16State), - VMSTATE_INT32(bytes_per_second, SB16State), - VMSTATE_INT32(align, SB16State), - - VMSTATE_INT32(mixer_nreg, SB16State), - VMSTATE_BUFFER(mixer_regs, SB16State), - - VMSTATE_END_OF_LIST() + VMSTATE_UINT32 (irq, SB16State), + VMSTATE_UINT32 (dma, SB16State), + VMSTATE_UINT32 (hdma, SB16State), + VMSTATE_UINT32 (port, SB16State), + VMSTATE_UINT32 (ver, SB16State), + VMSTATE_INT32 (in_index, SB16State), + VMSTATE_INT32 (out_data_len, SB16State), + VMSTATE_INT32 (fmt_stereo, SB16State), + VMSTATE_INT32 (fmt_signed, SB16State), + VMSTATE_INT32 (fmt_bits, SB16State), + VMSTATE_UINT32 (fmt, SB16State), + VMSTATE_INT32 (dma_auto, SB16State), + VMSTATE_INT32 (block_size, SB16State), + VMSTATE_INT32 (fifo, SB16State), + VMSTATE_INT32 (freq, SB16State), + VMSTATE_INT32 (time_const, SB16State), + VMSTATE_INT32 (speaker, SB16State), + VMSTATE_INT32 (needed_bytes, SB16State), + VMSTATE_INT32 (cmd, SB16State), + VMSTATE_INT32 (use_hdma, SB16State), + VMSTATE_INT32 (highspeed, SB16State), + VMSTATE_INT32 (can_write, SB16State), + VMSTATE_INT32 (v2x6, SB16State), + + VMSTATE_UINT8 (csp_param, SB16State), + VMSTATE_UINT8 (csp_value, SB16State), + VMSTATE_UINT8 (csp_mode, SB16State), + VMSTATE_UINT8 (csp_param, SB16State), + VMSTATE_BUFFER (csp_regs, SB16State), + VMSTATE_UINT8 (csp_index, SB16State), + VMSTATE_BUFFER (csp_reg83, SB16State), + VMSTATE_INT32 (csp_reg83r, SB16State), + VMSTATE_INT32 (csp_reg83w, SB16State), + + VMSTATE_BUFFER (in2_data, SB16State), + VMSTATE_BUFFER (out_data, SB16State), + VMSTATE_UINT8 (test_reg, SB16State), + VMSTATE_UINT8 (last_read_byte, SB16State), + + VMSTATE_INT32 (nzero, SB16State), + VMSTATE_INT32 (left_till_irq, SB16State), + VMSTATE_INT32 (dma_running, SB16State), + VMSTATE_INT32 (bytes_per_second, SB16State), + VMSTATE_INT32 (align, SB16State), + + VMSTATE_INT32 (mixer_nreg, SB16State), + VMSTATE_BUFFER (mixer_regs, SB16State), + + VMSTATE_END_OF_LIST () } }; @@ -1349,7 +1349,7 @@ static const MemoryRegionPortio sb16_ioport_list[] = { { 10, 1, 1, .read = dsp_read }, { 12, 1, 1, .write = dsp_write }, { 12, 4, 1, .read = dsp_read }, - PORTIO_END_OF_LIST(), + PORTIO_END_OF_LIST (), }; @@ -1391,24 +1391,34 @@ int SB16_init (ISABus *bus) return 0; } -static ISADeviceInfo sb16_info = { - .qdev.name = "sb16", - .qdev.desc = "Creative Sound Blaster 16", - .qdev.size = sizeof (SB16State), - .qdev.vmsd = &vmstate_sb16, - .init = sb16_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */ - DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220), - DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5), - DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1), - DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5), - DEFINE_PROP_END_OF_LIST (), - }, +static Property sb16_properties[] = { + DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */ + DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220), + DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5), + DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1), + DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5), + DEFINE_PROP_END_OF_LIST (), +}; + +static void sb16_class_initfn (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS (klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS (klass); + ic->init = sb16_initfn; + dc->desc = "Creative Sound Blaster 16"; + dc->vmsd = &vmstate_sb16; + dc->props = sb16_properties; +} + +static TypeInfo sb16_info = { + .name = "sb16", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof (SB16State), + .class_init = sb16_class_initfn, }; static void sb16_register (void) { - isa_qdev_register (&sb16_info); + type_register_static (&sb16_info); } device_init (sb16_register) @@ -131,17 +131,26 @@ static int sbi_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo sbi_info = { - .init = sbi_init1, - .qdev.name = "sbi", - .qdev.size = sizeof(SBIState), - .qdev.vmsd = &vmstate_sbi, - .qdev.reset = sbi_reset, +static void sbi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sbi_init1; + dc->reset = sbi_reset; + dc->vmsd = &vmstate_sbi; +} + +static TypeInfo sbi_info = { + .name = "sbi", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SBIState), + .class_init = sbi_class_init, }; static void sbi_register_devices(void) { - sysbus_register_withprop(&sbi_info); + type_register_static(&sbi_info); } device_init(sbi_register_devices) diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 64e709ee9f..0ee50a8360 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -23,6 +23,42 @@ static struct BusInfo scsi_bus_info = { }; static int next_scsi_bus; +static int scsi_device_init(SCSIDevice *s) +{ + SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); + if (sc->init) { + return sc->init(s); + } + return 0; +} + +static void scsi_device_destroy(SCSIDevice *s) +{ + SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); + if (sc->destroy) { + sc->destroy(s); + } +} + +static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun, + uint8_t *buf, void *hba_private) +{ + SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); + if (sc->alloc_req) { + return sc->alloc_req(s, tag, lun, buf, hba_private); + } + + return NULL; +} + +static void scsi_device_unit_attention_reported(SCSIDevice *s) +{ + SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s); + if (sc->unit_attention_reported) { + sc->unit_attention_reported(s); + } +} + /* Create a scsi bus, and attach devices to it. */ void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info) { @@ -79,10 +115,9 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state) } } -static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int scsi_qdev_init(DeviceState *qdev) { - SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); - SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base); + SCSIDevice *dev = SCSI_DEVICE(qdev); SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus); SCSIDevice *d; int rc = -1; @@ -126,9 +161,8 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base) } } - dev->info = info; QTAILQ_INIT(&dev->requests); - rc = dev->info->init(dev); + rc = scsi_device_init(dev); if (rc == 0) { dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb, dev); @@ -140,26 +174,15 @@ err: static int scsi_qdev_exit(DeviceState *qdev) { - SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); + SCSIDevice *dev = SCSI_DEVICE(qdev); if (dev->vmsentry) { qemu_del_vm_change_state_handler(dev->vmsentry); } - if (dev->info->destroy) { - dev->info->destroy(dev); - } + scsi_device_destroy(dev); return 0; } -void scsi_qdev_register(SCSIDeviceInfo *info) -{ - info->qdev.bus_info = &scsi_bus_info; - info->qdev.init = scsi_qdev_init; - info->qdev.unplug = qdev_simple_unplug_cb; - info->qdev.exit = scsi_qdev_exit; - qdev_register(&info->qdev); -} - /* handle legacy '-drive if=scsi,...' cmd line args */ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit, bool removable, int bootindex) @@ -182,7 +205,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, } if (qdev_init(dev) < 0) return NULL; - return DO_UPCAST(SCSIDevice, qdev, dev); + return SCSI_DEVICE(dev); } int scsi_bus_legacy_handle_cmdline(SCSIBus *bus) @@ -278,7 +301,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r) found_lun0 = false; n = 0; QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) { - SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); + SCSIDevice *dev = SCSI_DEVICE(qdev); if (dev->channel == channel && dev->id == id) { if (dev->lun == 0) { @@ -300,7 +323,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r) stl_be_p(&r->buf, n); i = found_lun0 ? 8 : 16; QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) { - SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); + SCSIDevice *dev = SCSI_DEVICE(qdev); if (dev->channel == channel && dev->id == id) { store_lun(&r->buf[i], dev->lun); @@ -398,9 +421,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) MIN(req->cmd.xfer, sizeof r->buf), (req->cmd.buf[1] & 1) == 0); if (r->req.dev->sense_is_ua) { - if (r->req.dev->info->unit_attention_reported) { - r->req.dev->info->unit_attention_reported(req->dev); - } + scsi_device_unit_attention_reported(req->dev); r->req.dev->sense_len = 0; r->req.dev->sense_is_ua = false; } @@ -507,7 +528,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, req = scsi_req_alloc(&reqops_target_command, d, tag, lun, hba_private); } else { - req = d->info->alloc_req(d, tag, lun, buf, hba_private); + req = scsi_device_alloc_req(d, tag, lun, buf, hba_private); } } @@ -597,9 +618,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len) * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b. */ if (req->dev->sense_is_ua) { - if (req->dev->info->unit_attention_reported) { - req->dev->info->unit_attention_reported(req->dev); - } + scsi_device_unit_attention_reported(req->dev); req->dev->sense_len = 0; req->dev->sense_is_ua = false; } @@ -1367,7 +1386,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense) static char *scsibus_get_fw_dev_path(DeviceState *dev) { - SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); + SCSIDevice *d = SCSI_DEVICE(dev); char path[100]; snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel, @@ -1382,7 +1401,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) SCSIDevice *target_dev = NULL; QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) { - SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev); + SCSIDevice *dev = SCSI_DEVICE(qdev); if (dev->channel == channel && dev->id == id) { if (dev->lun == lun) { @@ -1393,3 +1412,28 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) } return target_dev; } + +static void scsi_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->bus_info = &scsi_bus_info; + k->init = scsi_qdev_init; + k->unplug = qdev_simple_unplug_cb; + k->exit = scsi_qdev_exit; +} + +static TypeInfo scsi_device_type_info = { + .name = TYPE_SCSI_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SCSIDevice), + .abstract = true, + .class_size = sizeof(SCSIDeviceClass), + .class_init = scsi_device_class_init, +}; + +static void scsi_register_devices(void) +{ + type_register_static(&scsi_device_type_info); +} + +device_init(scsi_register_devices); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 5d8bf53586..399e51e494 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -391,9 +391,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) } l = strlen(s->serial); - if (l > req->cmd.xfer) { - l = req->cmd.xfer; - } if (l > 20) { l = 20; } @@ -1002,9 +999,6 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) outbuf[0] = ((buflen - 2) >> 8) & 0xff; outbuf[1] = (buflen - 2) & 0xff; } - if (buflen > r->req.cmd.xfer) { - buflen = r->req.cmd.xfer; - } return buflen; } @@ -1038,9 +1032,6 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) default: return -1; } - if (toclen > req->cmd.xfer) { - toclen = req->cmd.xfer; - } return toclen; } @@ -1251,6 +1242,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r) scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); return -1; } + buflen = MIN(buflen, req->cmd.xfer); return buflen; not_ready: @@ -1720,75 +1712,124 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ DEFINE_PROP_STRING("serial", SCSIDiskState, serial) -static SCSIDeviceInfo scsi_disk_info[] = { - { - .qdev.name = "scsi-hd", - .qdev.fw_name = "disk", - .qdev.desc = "virtual SCSI disk", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, - .init = scsi_hd_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, - .unit_attention_reported = scsi_disk_unit_attention_reported, - .qdev.props = (Property[]) { - DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), - DEFINE_PROP_END_OF_LIST(), - } - },{ - .qdev.name = "scsi-cd", - .qdev.fw_name = "disk", - .qdev.desc = "virtual SCSI CD-ROM", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, - .init = scsi_cd_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, - .unit_attention_reported = scsi_disk_unit_attention_reported, - .qdev.props = (Property[]) { - DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_END_OF_LIST(), - }, +static Property scsi_hd_properties[] = { + DEFINE_SCSI_DISK_PROPERTIES(), + DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void scsi_hd_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + + sc->init = scsi_hd_initfn; + sc->destroy = scsi_destroy; + sc->alloc_req = scsi_new_request; + sc->unit_attention_reported = scsi_disk_unit_attention_reported; + dc->fw_name = "disk"; + dc->desc = "virtual SCSI disk"; + dc->reset = scsi_disk_reset; + dc->props = scsi_hd_properties; +} + +static TypeInfo scsi_hd_info = { + .name = "scsi-hd", + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), + .class_init = scsi_hd_class_initfn, +}; + +static Property scsi_cd_properties[] = { + DEFINE_SCSI_DISK_PROPERTIES(), + DEFINE_PROP_END_OF_LIST(), +}; + +static void scsi_cd_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + + sc->init = scsi_cd_initfn; + sc->destroy = scsi_destroy; + sc->alloc_req = scsi_new_request; + sc->unit_attention_reported = scsi_disk_unit_attention_reported; + dc->fw_name = "disk"; + dc->desc = "virtual SCSI CD-ROM"; + dc->reset = scsi_disk_reset; + dc->props = scsi_cd_properties; +} + +static TypeInfo scsi_cd_info = { + .name = "scsi-cd", + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), + .class_init = scsi_cd_class_initfn, +}; + #ifdef __linux__ - },{ - .qdev.name = "scsi-block", - .qdev.fw_name = "disk", - .qdev.desc = "SCSI block device passthrough", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, - .init = scsi_block_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_block_new_request, - .qdev.props = (Property[]) { - DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_END_OF_LIST(), - }, +static Property scsi_block_properties[] = { + DEFINE_SCSI_DISK_PROPERTIES(), + DEFINE_PROP_END_OF_LIST(), +}; + +static void scsi_block_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + + sc->init = scsi_block_initfn; + sc->destroy = scsi_destroy; + sc->alloc_req = scsi_block_new_request; + dc->fw_name = "disk"; + dc->desc = "SCSI block device passthrough"; + dc->reset = scsi_disk_reset; + dc->props = scsi_block_properties; +} + +static TypeInfo scsi_block_info = { + .name = "scsi-block", + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), + .class_init = scsi_block_class_initfn, +}; #endif - },{ - .qdev.name = "scsi-disk", /* legacy -device scsi-disk */ - .qdev.fw_name = "disk", - .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, - .init = scsi_disk_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, - .unit_attention_reported = scsi_disk_unit_attention_reported, - .qdev.props = (Property[]) { - DEFINE_SCSI_DISK_PROPERTIES(), - DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), - DEFINE_PROP_END_OF_LIST(), - } - } + +static Property scsi_disk_properties[] = { + DEFINE_SCSI_DISK_PROPERTIES(), + DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false), + DEFINE_PROP_END_OF_LIST(), }; -static void scsi_disk_register_devices(void) +static void scsi_disk_class_initfn(ObjectClass *klass, void *data) { - int i; + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + + sc->init = scsi_disk_initfn; + sc->destroy = scsi_destroy; + sc->alloc_req = scsi_new_request; + sc->unit_attention_reported = scsi_disk_unit_attention_reported; + dc->fw_name = "disk"; + dc->desc = "virtual SCSI disk or CD-ROM (legacy)"; + dc->reset = scsi_disk_reset; + dc->props = scsi_disk_properties; +} - for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) { - scsi_qdev_register(&scsi_disk_info[i]); - } +static TypeInfo scsi_disk_info = { + .name = "scsi-disk", + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDiskState), + .class_init = scsi_disk_class_initfn, +}; + +static void scsi_disk_register_devices(void) +{ + type_register_static(&scsi_hd_info); + type_register_static(&scsi_cd_info); +#ifdef __linux__ + type_register_static(&scsi_block_info); +#endif + type_register_static(&scsi_disk_info); } device_init(scsi_disk_register_devices) diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index 0aebcddf6e..4859212734 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -357,7 +357,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv) static void scsi_generic_reset(DeviceState *dev) { - SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev); + SCSIDevice *s = SCSI_DEVICE(dev); scsi_device_purge_requests(s, SENSE_CODE(RESET)); } @@ -457,24 +457,35 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, return req; } -static SCSIDeviceInfo scsi_generic_info = { - .qdev.name = "scsi-generic", - .qdev.fw_name = "disk", - .qdev.desc = "pass through generic scsi device (/dev/sg*)", - .qdev.size = sizeof(SCSIDevice), - .qdev.reset = scsi_generic_reset, - .init = scsi_generic_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, - .qdev.props = (Property[]) { - DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf), - DEFINE_PROP_END_OF_LIST(), - }, +static Property scsi_generic_properties[] = { + DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void scsi_generic_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); + + sc->init = scsi_generic_initfn; + sc->destroy = scsi_destroy; + sc->alloc_req = scsi_new_request; + dc->fw_name = "disk"; + dc->desc = "pass through generic scsi device (/dev/sg*)"; + dc->reset = scsi_generic_reset; + dc->props = scsi_generic_properties; +} + +static TypeInfo scsi_generic_info = { + .name = "scsi-generic", + .parent = TYPE_SCSI_DEVICE, + .instance_size = sizeof(SCSIDevice), + .class_init = scsi_generic_class_initfn, }; static void scsi_generic_register_devices(void) { - scsi_qdev_register(&scsi_generic_info); + type_register_static(&scsi_generic_info); } device_init(scsi_generic_register_devices) @@ -13,7 +13,6 @@ typedef struct SCSIBus SCSIBus; typedef struct SCSIBusInfo SCSIBusInfo; typedef struct SCSICommand SCSICommand; typedef struct SCSIDevice SCSIDevice; -typedef struct SCSIDeviceInfo SCSIDeviceInfo; typedef struct SCSIRequest SCSIRequest; typedef struct SCSIReqOps SCSIReqOps; @@ -58,6 +57,23 @@ struct SCSIRequest { QTAILQ_ENTRY(SCSIRequest) next; }; +#define TYPE_SCSI_DEVICE "scsi-device" +#define SCSI_DEVICE(obj) \ + OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE) +#define SCSI_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE) +#define SCSI_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE) + +typedef struct SCSIDeviceClass { + DeviceClass parent_class; + int (*init)(SCSIDevice *dev); + void (*destroy)(SCSIDevice *s); + SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun, + uint8_t *buf, void *hba_private); + void (*unit_attention_reported)(SCSIDevice *s); +} SCSIDeviceClass; + struct SCSIDevice { DeviceState qdev; @@ -65,7 +81,6 @@ struct SCSIDevice QEMUBH *bh; uint32_t id; BlockConf conf; - SCSIDeviceInfo *info; SCSISense unit_attention; bool sense_is_ua; uint8_t sense[SCSI_SENSE_BUF_SIZE]; @@ -93,16 +108,6 @@ struct SCSIReqOps { uint8_t *(*get_buf)(SCSIRequest *req); }; -typedef int (*scsi_qdev_initfn)(SCSIDevice *dev); -struct SCSIDeviceInfo { - DeviceInfo qdev; - scsi_qdev_initfn init; - void (*destroy)(SCSIDevice *s); - SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun, - uint8_t *buf, void *hba_private); - void (*unit_attention_reported)(SCSIDevice *s); -}; - struct SCSIBusInfo { int tcq; int max_channel, max_target, max_lun; @@ -120,7 +125,6 @@ struct SCSIBus { }; void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info); -void scsi_qdev_register(SCSIDeviceInfo *info); static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d) { diff --git a/hw/serial.c b/hw/serial.c index d35c7a9207..82917e24d7 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -879,23 +879,33 @@ SerialState *serial_mm_init(MemoryRegion *address_space, return s; } -static ISADeviceInfo serial_isa_info = { - .qdev.name = "isa-serial", - .qdev.size = sizeof(ISASerialState), - .qdev.vmsd = &vmstate_isa_serial, - .init = serial_isa_initfn, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("index", ISASerialState, index, -1), - DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), - DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), - DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), - DEFINE_PROP_END_OF_LIST(), - }, +static Property serial_isa_properties[] = { + DEFINE_PROP_UINT32("index", ISASerialState, index, -1), + DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), + DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), + DEFINE_PROP_CHR("chardev", ISASerialState, state.chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void serial_isa_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = serial_isa_initfn; + dc->vmsd = &vmstate_isa_serial; + dc->props = serial_isa_properties; +} + +static TypeInfo serial_isa_info = { + .name = "isa-serial", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISASerialState), + .class_init = serial_isa_class_initfn, }; static void serial_register_devices(void) { - isa_qdev_register(&serial_isa_info); + type_register_static(&serial_isa_info); } device_init(serial_register_devices) @@ -35,22 +35,29 @@ typedef struct ISAGAState { ISADevice dev; } ISASGAState; -static int isa_cirrus_vga_initfn(ISADevice *dev) +static int sga_initfn(ISADevice *dev) { rom_add_vga(SGABIOS_FILENAME); return 0; } +static void sga_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = sga_initfn; + dc->desc = "Serial Graphics Adapter"; +} -static ISADeviceInfo sga_info = { - .qdev.name = "sga", - .qdev.desc = "Serial Graphics Adapter", - .qdev.size = sizeof(ISASGAState), - .init = isa_cirrus_vga_initfn, +static TypeInfo sga_info = { + .name = "sga", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISASGAState), + .class_init = sga_class_initfn, }; static void sga_register(void) { - isa_qdev_register(&sga_info); + type_register_static(&sga_info); } device_init(sga_register); diff --git a/hw/sh_pci.c b/hw/sh_pci.c index d4d028d811..4234d935e7 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -110,7 +110,7 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[irq_num], level); } -static int sh_pci_init_device(SysBusDevice *dev) +static int sh_pci_device_init(SysBusDevice *dev) { SHPCIState *s; int i; @@ -147,19 +147,40 @@ static int sh_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo sh_pci_host_info = { - .qdev.name = "sh_pci_host", - .qdev.size = sizeof(PCIDevice), - .init = sh_pci_host_init, - .vendor_id = PCI_VENDOR_ID_HITACHI, - .device_id = PCI_DEVICE_ID_HITACHI_SH7751R, +static void sh_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = sh_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_HITACHI; + k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R; +} + +static TypeInfo sh_pci_host_info = { + .name = "sh_pci_host", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = sh_pci_host_class_init, +}; + +static void sh_pci_device_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = sh_pci_device_init; +} + +static TypeInfo sh_pci_device_info = { + .name = "sh_pci", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SHPCIState), + .class_init = sh_pci_device_class_init, }; static void sh_pci_register_devices(void) { - sysbus_register_dev("sh_pci", sizeof(SHPCIState), - sh_pci_init_device); - pci_qdev_register(&sh_pci_host_info); + type_register_static(&sh_pci_device_info); + type_register_static(&sh_pci_host_info); } device_init(sh_pci_register_devices) diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index 9925e6460b..e3701c75d2 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -446,17 +446,26 @@ static int slavio_intctl_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo slavio_intctl_info = { - .init = slavio_intctl_init1, - .qdev.name = "slavio_intctl", - .qdev.size = sizeof(SLAVIO_INTCTLState), - .qdev.vmsd = &vmstate_intctl, - .qdev.reset = slavio_intctl_reset, +static void slavio_intctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = slavio_intctl_init1; + dc->reset = slavio_intctl_reset; + dc->vmsd = &vmstate_intctl; +} + +static TypeInfo slavio_intctl_info = { + .name = "slavio_intctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SLAVIO_INTCTLState), + .class_init = slavio_intctl_class_init, }; static void slavio_intctl_register_devices(void) { - sysbus_register_withprop(&slavio_intctl_info); + type_register_static(&slavio_intctl_info); } device_init(slavio_intctl_register_devices) diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c index 484301c48a..5a025186af 100644 --- a/hw/slavio_misc.c +++ b/hw/slavio_misc.c @@ -468,24 +468,41 @@ static int slavio_misc_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo slavio_misc_info = { - .init = slavio_misc_init1, - .qdev.name = "slavio_misc", - .qdev.size = sizeof(MiscState), - .qdev.vmsd = &vmstate_misc, - .qdev.reset = slavio_misc_reset, +static void slavio_misc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = slavio_misc_init1; + dc->reset = slavio_misc_reset; + dc->vmsd = &vmstate_misc; +} + +static TypeInfo slavio_misc_info = { + .name = "slavio_misc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MiscState), + .class_init = slavio_misc_class_init, }; -static SysBusDeviceInfo apc_info = { - .init = apc_init1, - .qdev.name = "apc", - .qdev.size = sizeof(MiscState), +static void apc_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = apc_init1; +} + +static TypeInfo apc_info = { + .name = "apc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MiscState), + .class_init = apc_class_init, }; static void slavio_misc_register_devices(void) { - sysbus_register_withprop(&slavio_misc_info); - sysbus_register_withprop(&apc_info); + type_register_static(&slavio_misc_info); + type_register_static(&apc_info); } device_init(slavio_misc_register_devices) diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c index 44b500a5fa..3878f6fa5e 100644 --- a/hw/slavio_timer.c +++ b/hw/slavio_timer.c @@ -404,21 +404,32 @@ static int slavio_timer_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo slavio_timer_info = { - .init = slavio_timer_init1, - .qdev.name = "slavio_timer", - .qdev.size = sizeof(SLAVIO_TIMERState), - .qdev.vmsd = &vmstate_slavio_timer, - .qdev.reset = slavio_timer_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property slavio_timer_properties[] = { + DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void slavio_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = slavio_timer_init1; + dc->reset = slavio_timer_reset; + dc->vmsd = &vmstate_slavio_timer; + dc->props = slavio_timer_properties; +} + +static TypeInfo slavio_timer_info = { + .name = "slavio_timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SLAVIO_TIMERState), + .class_init = slavio_timer_class_init, }; static void slavio_timer_register_devices(void) { - sysbus_register_withprop(&slavio_timer_info); + type_register_static(&slavio_timer_info); } device_init(slavio_timer_register_devices) diff --git a/hw/sm501.c b/hw/sm501.c index 09c5894cf9..94c0abf4cb 100644 --- a/hw/sm501.c +++ b/hw/sm501.c @@ -1323,15 +1323,12 @@ static void sm501_draw_crt(SM501State * s) for (y = 0; y < height; y++) { int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0; int update = full_update || update_hwc; - ram_addr_t page0 = offset & TARGET_PAGE_MASK; - ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK; - ram_addr_t page; + ram_addr_t page0 = offset; + ram_addr_t page1 = offset + width * src_bpp - 1; /* check dirty flags for each line */ - for (page = page0; page <= page1; page += TARGET_PAGE_SIZE) - if (memory_region_get_dirty(&s->local_mem_region, page, - DIRTY_MEMORY_VGA)) - update = 1; + update = memory_region_get_dirty(&s->local_mem_region, page0, page1, + DIRTY_MEMORY_VGA); /* draw line and change status */ if (update) { diff --git a/hw/smbus.c b/hw/smbus.c index ff027c814f..77626f3645 100644 --- a/hw/smbus.c +++ b/hw/smbus.c @@ -37,37 +37,38 @@ enum { static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) { - SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c); + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); DPRINTF("Quick Command %d\n", recv); - if (t->quick_cmd) - t->quick_cmd(dev, recv); + if (sc->quick_cmd) { + sc->quick_cmd(dev, recv); + } } static void smbus_do_write(SMBusDevice *dev) { - SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c); + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); if (dev->data_len == 0) { smbus_do_quick_cmd(dev, 0); } else if (dev->data_len == 1) { DPRINTF("Send Byte\n"); - if (t->send_byte) { - t->send_byte(dev, dev->data_buf[0]); + if (sc->send_byte) { + sc->send_byte(dev, dev->data_buf[0]); } } else { dev->command = dev->data_buf[0]; DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); - if (t->write_data) { - t->write_data(dev, dev->command, dev->data_buf + 1, - dev->data_len - 1); + if (sc->write_data) { + sc->write_data(dev, dev->command, dev->data_buf + 1, + dev->data_len - 1); } } } -static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) +static void smbus_i2c_event(I2CSlave *s, enum i2c_event event) { - SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); + SMBusDevice *dev = SMBUS_DEVICE(s); switch (event) { case I2C_START_SEND: @@ -148,16 +149,16 @@ static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) } } -static int smbus_i2c_recv(i2c_slave *s) +static int smbus_i2c_recv(I2CSlave *s) { - SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c); - SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); + SMBusDevice *dev = SMBUS_DEVICE(s); + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); int ret; switch (dev->mode) { case SMBUS_RECV_BYTE: - if (t->receive_byte) { - ret = t->receive_byte(dev); + if (sc->receive_byte) { + ret = sc->receive_byte(dev); } else { ret = 0; } @@ -165,8 +166,8 @@ static int smbus_i2c_recv(i2c_slave *s) dev->mode = SMBUS_DONE; break; case SMBUS_READ_DATA: - if (t->read_data) { - ret = t->read_data(dev, dev->command, dev->data_len); + if (sc->read_data) { + ret = sc->read_data(dev, dev->command, dev->data_len); dev->data_len++; } else { ret = 0; @@ -182,9 +183,9 @@ static int smbus_i2c_recv(i2c_slave *s) return ret; } -static int smbus_i2c_send(i2c_slave *s, uint8_t data) +static int smbus_i2c_send(I2CSlave *s, uint8_t data) { - SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s); + SMBusDevice *dev = SMBUS_DEVICE(s); switch (dev->mode) { case SMBUS_WRITE_DATA: @@ -198,22 +199,12 @@ static int smbus_i2c_send(i2c_slave *s, uint8_t data) return 0; } -static int smbus_device_init(i2c_slave *i2c) +static int smbus_device_init(I2CSlave *i2c) { - SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c); - SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c); - - return t->init(dev); -} + SMBusDevice *dev = SMBUS_DEVICE(i2c); + SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); -void smbus_register_device(SMBusDeviceInfo *info) -{ - assert(info->i2c.qdev.size >= sizeof(SMBusDevice)); - info->i2c.init = smbus_device_init; - info->i2c.event = smbus_i2c_event; - info->i2c.recv = smbus_i2c_recv; - info->i2c.send = smbus_i2c_send; - i2c_register_slave(&info->i2c); + return sc->init(dev); } /* Master device commands. */ @@ -316,3 +307,29 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat i2c_send(bus, data[i]); i2c_end_transfer(bus); } + +static void smbus_device_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + sc->init = smbus_device_init; + sc->event = smbus_i2c_event; + sc->recv = smbus_i2c_recv; + sc->send = smbus_i2c_send; +} + +static TypeInfo smbus_device_type_info = { + .name = TYPE_SMBUS_DEVICE, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(SMBusDevice), + .abstract = true, + .class_size = sizeof(SMBusDeviceClass), + .class_init = smbus_device_class_init, +}; + +static void smbus_device_register_devices(void) +{ + type_register_static(&smbus_device_type_info); +} + +device_init(smbus_device_register_devices); diff --git a/hw/smbus.h b/hw/smbus.h index a39871593b..6ed45bd03d 100644 --- a/hw/smbus.h +++ b/hw/smbus.h @@ -1,3 +1,6 @@ +#ifndef QEMU_SMBUS_H +#define QEMU_SMBUS_H + /* * QEMU SMBus API * @@ -24,19 +27,17 @@ #include "i2c.h" -struct SMBusDevice { - /* The SMBus protocol is implemented on top of I2C. */ - i2c_slave i2c; - - /* Remaining fields for internal use only. */ - int mode; - int data_len; - uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ - uint8_t command; -}; +#define TYPE_SMBUS_DEVICE "smbus-device" +#define SMBUS_DEVICE(obj) \ + OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE) +#define SMBUS_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE) +#define SMBUS_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE) -typedef struct { - I2CSlaveInfo i2c; +typedef struct SMBusDeviceClass +{ + I2CSlaveClass parent_class; int (*init)(SMBusDevice *dev); void (*quick_cmd)(SMBusDevice *dev, uint8_t read); void (*send_byte)(SMBusDevice *dev, uint8_t val); @@ -51,9 +52,18 @@ typedef struct { byte at a time. The device is responsible for adding the length byte on block reads. */ uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n); -} SMBusDeviceInfo; +} SMBusDeviceClass; -void smbus_register_device(SMBusDeviceInfo *info); +struct SMBusDevice { + /* The SMBus protocol is implemented on top of I2C. */ + I2CSlave i2c; + + /* Remaining fields for internal use only. */ + int mode; + int data_len; + uint8_t data_buf[34]; /* command + len + 32 bytes of data. */ + uint8_t command; +}; /* Master device commands. */ void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read); @@ -69,3 +79,5 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom, const uint8_t *eeprom_spd, int size); + +#endif diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c index 5d080abed7..9d96cbe41a 100644 --- a/hw/smbus_eeprom.c +++ b/hw/smbus_eeprom.c @@ -104,24 +104,35 @@ static int smbus_eeprom_initfn(SMBusDevice *dev) return 0; } -static SMBusDeviceInfo smbus_eeprom_info = { - .i2c.qdev.name = "smbus-eeprom", - .i2c.qdev.size = sizeof(SMBusEEPROMDevice), - .i2c.qdev.props = (Property[]) { - DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), - DEFINE_PROP_END_OF_LIST(), - }, - .init = smbus_eeprom_initfn, - .quick_cmd = eeprom_quick_cmd, - .send_byte = eeprom_send_byte, - .receive_byte = eeprom_receive_byte, - .write_data = eeprom_write_data, - .read_data = eeprom_read_data +static Property smbus_eeprom_properties[] = { + DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), + DEFINE_PROP_END_OF_LIST(), +}; + +static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + sc->init = smbus_eeprom_initfn; + sc->quick_cmd = eeprom_quick_cmd; + sc->send_byte = eeprom_send_byte; + sc->receive_byte = eeprom_receive_byte; + sc->write_data = eeprom_write_data; + sc->read_data = eeprom_read_data; + dc->props = smbus_eeprom_properties; +} + +static TypeInfo smbus_eeprom_info = { + .name = "smbus-eeprom", + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusEEPROMDevice), + .class_init = smbus_eeprom_class_initfn, }; static void smbus_eeprom_register_devices(void) { - smbus_register_device(&smbus_eeprom_info); + type_register_static(&smbus_eeprom_info); } device_init(smbus_eeprom_register_devices) diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 82b8811459..1bf2901d1a 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -752,27 +752,38 @@ static int smc91c111_init1(SysBusDevice *dev) sysbus_init_irq(dev, &s->irq); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); /* ??? Save/restore. */ return 0; } -static SysBusDeviceInfo smc91c111_info = { - .init = smc91c111_init1, - .qdev.name = "smc91c111", - .qdev.size = sizeof(smc91c111_state), - .qdev.vmsd = &vmstate_smc91c111, - .qdev.reset = smc91c111_reset, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(smc91c111_state, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property smc91c111_properties[] = { + DEFINE_NIC_PROPERTIES(smc91c111_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void smc91c111_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = smc91c111_init1; + dc->reset = smc91c111_reset; + dc->vmsd = &vmstate_smc91c111; + dc->props = smc91c111_properties; +} + +static TypeInfo smc91c111_info = { + .name = "smc91c111", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(smc91c111_state), + .class_init = smc91c111_class_init, }; static void smc91c111_register_devices(void) { - sysbus_register_withprop(&smc91c111_info); + type_register_static(&smc91c111_info); } /* Legacy helper function. Should go away when machine config files are diff --git a/hw/spapr.c b/hw/spapr.c index 0e1f80dfdc..dffb6a2a50 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -50,19 +50,29 @@ #include <libfdt.h> -#define KERNEL_LOAD_ADDR 0x00000000 -#define INITRD_LOAD_ADDR 0x02800000 +/* SLOF memory layout: + * + * SLOF raw image loaded at 0, copies its romfs right below the flat + * device-tree, then position SLOF itself 31M below that + * + * So we set FW_OVERHEAD to 40MB which should account for all of that + * and more + * + * We load our kernel at 4M, leaving space for SLOF initial image + */ #define FDT_MAX_SIZE 0x10000 #define RTAS_MAX_SIZE 0x10000 #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" +#define FW_OVERHEAD 0x2800000 +#define KERNEL_LOAD_ADDR FW_MAX_SIZE -#define MIN_RMA_SLOF 128UL +#define MIN_RMA_SLOF 128UL #define TIMEBASE_FREQ 512000000ULL #define MAX_CPUS 256 -#define XICS_IRQS 1024 +#define XICS_IRQS 1024 #define SPAPR_PCI_BUID 0x800000020000001ULL #define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) @@ -139,6 +149,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, + target_phys_addr_t kernel_size, const char *boot_device, const char *kernel_cmdline, long hash_shift) @@ -176,6 +187,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model, fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); + if (kernel_size) { + _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size))); + } + if (initrd_size) { + _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size))); + } _FDT((fdt_finish_reservemap(fdt))); /* Root node */ @@ -197,15 +214,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model, &start_prop, sizeof(start_prop)))); _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop)))); - _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + if (kernel_size) { + uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), + cpu_to_be64(kernel_size) }; - /* - * Because we don't always invoke any firmware, we can't rely on - * that to do BAR allocation. Long term, we should probably do - * that ourselves, but for now, this setting (plus advertising the - * current BARs as 0) causes sufficiently recent kernels to to the - * BAR assignment themselves */ - _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0))); + _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); + } + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); _FDT((fdt_end_node(fdt))); @@ -445,6 +460,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, _FDT((fdt_pack(fdt))); + if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { + hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n", + fdt_totalsize(fdt), FDT_MAX_SIZE); + exit(1); + } + cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); g_free(fdt); @@ -494,8 +515,9 @@ static void ppc_spapr_init(ram_addr_t ram_size, MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); target_phys_addr_t rma_alloc_size, rma_size; - uint32_t initrd_base; - long kernel_size, initrd_size, fw_size; + uint32_t initrd_base = 0; + long kernel_size = 0, initrd_size = 0; + long load_limit, rtas_limit, fw_size; long pteg_shift = 17; char *filename; @@ -517,11 +539,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, rma_size = ram_size; } - /* We place the device tree just below either the top of the RMA, + /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE; - spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE; + rtas_limit = MIN(rma_size, 0x80000000); + spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; + spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; + load_limit = spapr->fdt_addr - FW_OVERHEAD; /* init CPUs */ if (cpu_model == NULL) { @@ -577,13 +601,19 @@ static void ppc_spapr_init(ram_addr_t ram_size, filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, - ram_size - spapr->rtas_addr); + rtas_limit - spapr->rtas_addr); if (spapr->rtas_size < 0) { hw_error("qemu: could not load LPAR rtas '%s'\n", filename); exit(1); } + if (spapr->rtas_size > RTAS_MAX_SIZE) { + hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n", + spapr->rtas_size, RTAS_MAX_SIZE); + exit(1); + } g_free(filename); + /* Set up Interrupt Controller */ spapr->icp = xics_system_init(XICS_IRQS); spapr->next_irq = 16; @@ -622,6 +652,20 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr_vscsi_create(spapr->vio_bus, 0x2000 + i); } + if (rma_size < (MIN_RMA_SLOF << 20)) { + fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " + "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); + exit(1); + } + + fprintf(stderr, "sPAPR memory map:\n"); + fprintf(stderr, "RTAS : 0x%08lx..%08lx\n", + (unsigned long)spapr->rtas_addr, + (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1)); + fprintf(stderr, "FDT : 0x%08lx..%08lx\n", + (unsigned long)spapr->fdt_addr, + (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1)); + if (kernel_filename) { uint64_t lowaddr = 0; @@ -630,57 +674,60 @@ static void ppc_spapr_init(ram_addr_t ram_size, if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); + load_limit - KERNEL_LOAD_ADDR); } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } + fprintf(stderr, "Kernel : 0x%08x..%08lx\n", + KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1); /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + /* Try to locate the initrd in the gap between the kernel + * and the firmware. Add a bit of space just in case + */ + initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff; initrd_size = load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); + load_limit - initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } + fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n", + (long)initrd_base, (long)(initrd_base + initrd_size - 1)); } else { initrd_base = 0; initrd_size = 0; } + } - spapr->entry_point = KERNEL_LOAD_ADDR; - } else { - if (rma_size < (MIN_RMA_SLOF << 20)) { - fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " - "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); - exit(1); - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); - fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); - if (fw_size < 0) { - hw_error("qemu: could not load LPAR rtas '%s'\n", filename); - exit(1); - } - g_free(filename); - spapr->entry_point = 0x100; - initrd_base = 0; - initrd_size = 0; - - /* SLOF will startup the secondary CPUs using RTAS, - rather than expecting a kexec() style entry */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + g_free(filename); + fprintf(stderr, "Firmware load : 0x%08x..%08lx\n", + 0, fw_size); + fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n", + load_limit, (unsigned long)spapr->fdt_addr); + + spapr->entry_point = 0x100; + + /* SLOF will startup the secondary CPUs using RTAS */ + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->halted = 1; } /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, + kernel_size, boot_device, kernel_cmdline, pteg_shift + 7); assert(spapr->fdt_skel != NULL); @@ -693,7 +740,6 @@ static QEMUMachine spapr_machine = { .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, .max_cpus = MAX_CPUS, - .no_vga = 1, .no_parallel = 1, .use_scsi = 1, }; diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c index 45674c4cb9..79b394132b 100644 --- a/hw/spapr_llan.c +++ b/hw/spapr_llan.c @@ -189,7 +189,7 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev) qemu_macaddr_default_if_unset(&dev->nicconf.macaddr); dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf, - sdev->qdev.info->name, sdev->qdev.id, dev); + object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev); qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a); return 0; @@ -474,30 +474,41 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr, return H_SUCCESS; } -static VIOsPAPRDeviceInfo spapr_vlan = { - .init = spapr_vlan_init, - .devnode = spapr_vlan_devnode, - .dt_name = "l-lan", - .dt_type = "network", - .dt_compatible = "IBM,l-lan", - .signal_mask = 0x1, - .qdev.name = "spapr-vlan", - .qdev.size = sizeof(VIOsPAPRVLANDevice), - .qdev.props = (Property[]) { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000), - DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf), - DEFINE_PROP_END_OF_LIST(), - }, +static Property spapr_vlan_properties[] = { + DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000), + DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_vlan_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); + + k->init = spapr_vlan_init; + k->devnode = spapr_vlan_devnode; + k->dt_name = "l-lan"; + k->dt_type = "network"; + k->dt_compatible = "IBM,l-lan"; + k->signal_mask = 0x1; + dc->props = spapr_vlan_properties; +} + +static TypeInfo spapr_vlan_info = { + .name = "spapr-vlan", + .parent = TYPE_VIO_SPAPR_DEVICE, + .instance_size = sizeof(VIOsPAPRVLANDevice), + .class_init = spapr_vlan_class_init, }; static void spapr_vlan_register(void) { - spapr_vio_bus_register_withprop(&spapr_vlan); spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan); spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan); spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan); spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, h_add_logical_lan_buffer); spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl); + type_register_static(&spapr_vlan_info); } device_init(spapr_vlan_register); diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 9b6a032cce..ed2e4b33e7 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -62,6 +62,30 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, return NULL; } +static uint32_t rtas_pci_cfgaddr(uint32_t arg) +{ + return ((arg >> 20) & 0xf00) | (arg & 0xff); +} + +static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t len) +{ + if ((addr + len) <= limit) { + return pci_host_config_read_common(pci_dev, addr, limit, len); + } else { + return ~0x0; + } +} + +static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t val, + uint32_t len) +{ + if ((addr + len) <= limit) { + pci_host_config_write_common(pci_dev, addr, limit, val, len); + } +} + static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -76,8 +100,8 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, return; } size = rtas_ld(args, 3); - addr = rtas_ld(args, 0) & 0xFF; - val = pci_default_read_config(dev, addr, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); rtas_st(rets, 0, 0); rtas_st(rets, 1, val); } @@ -95,8 +119,8 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr, return; } size = rtas_ld(args, 1); - addr = rtas_ld(args, 0) & 0xFF; - val = pci_default_read_config(dev, addr, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); rtas_st(rets, 0, 0); rtas_st(rets, 1, val); } @@ -116,8 +140,8 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, } val = rtas_ld(args, 4); size = rtas_ld(args, 3); - addr = rtas_ld(args, 0) & 0xFF; - pci_default_write_config(dev, addr, val, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); rtas_st(rets, 0, 0); } @@ -135,8 +159,8 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, } val = rtas_ld(args, 2); size = rtas_ld(args, 1); - addr = rtas_ld(args, 0) & 0xFF; - pci_default_write_config(dev, addr, val, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); rtas_st(rets, 0, 0); } @@ -190,17 +214,38 @@ static int spapr_main_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo spapr_main_pci_host_info = { - .qdev.name = "spapr-pci-host-bridge", - .qdev.size = sizeof(PCIDevice), - .init = spapr_main_pci_host_init, +static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = spapr_main_pci_host_init; +} + +static TypeInfo spapr_main_pci_host_info = { + .name = "spapr-pci-host-bridge-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = spapr_main_pci_host_class_init, +}; + +static void spapr_phb_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = spapr_phb_init; +} + +static TypeInfo spapr_phb_info = { + .name = "spapr-pci-host-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(sPAPRPHBState), + .class_init = spapr_phb_class_init, }; static void spapr_register_devices(void) { - sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState), - spapr_phb_init); - pci_qdev_register(&spapr_main_pci_host_info); + type_register_static(&spapr_phb_info); + type_register_static(&spapr_main_pci_host_info); } device_init(spapr_register_devices) @@ -319,31 +364,13 @@ void spapr_create_phb(sPAPREnvironment *spapr, #define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ -static uint32_t regtype_to_ss(uint8_t type) -{ - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - return 3; - } - if (type == PCI_BASE_ADDRESS_SPACE_IO) { - return 1; - } - return 2; -} - int spapr_populate_pci_devices(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt) { PCIBus *bus = phb->host_state.bus; - int bus_off, node_off = 0, devid, fn, i, n, devices; - DeviceState *qdev; + int bus_off, i; char nodename[256]; - struct { - uint32_t hi; - uint64_t addr; - uint64_t size; - } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1], - assigned_addresses[PCI_NUM_REGIONS]; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; struct { uint32_t hi; @@ -364,7 +391,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, }; uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; uint32_t interrupt_map_mask[] = { - cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0}; + cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0}; uint32_t interrupt_map[bus->nirq][7]; /* Start populating the FDT */ @@ -392,117 +419,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range))); _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges))); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); + + /* Build the interrupt-map, this must matches what is done + * in pci_spapr_map_irq + */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", &interrupt_map_mask, sizeof(interrupt_map_mask))); - - /* Populate PCI devices and allocate IRQs */ - devices = 0; - QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) { - PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - int irq_index = pci_spapr_map_irq(dev, 0); - uint32_t *irqmap = interrupt_map[devices]; - uint8_t *config = dev->config; - - devid = dev->devfn >> 3; - fn = dev->devfn & 7; - - sprintf(nodename, "pci@%u,%u", devid, fn); - - /* Allocate interrupt from the map */ - if (devid > bus->nirq) { - printf("Unexpected behaviour in spapr_populate_pci_devices," - "wrong devid %u\n", devid); - exit(-1); - } - irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn)); + for (i = 0; i < 7; i++) { + uint32_t *irqmap = interrupt_map[i]; + irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); irqmap[1] = 0; irqmap[2] = 0; irqmap[3] = 0; irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq); + irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq); irqmap[6] = cpu_to_be32(0x8); - - /* Add node to FDT */ - node_off = fdt_add_subnode(fdt, bus_off, nodename); - if (node_off < 0) { - return node_off; - } - - _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id", - pci_get_word(&config[PCI_VENDOR_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "device-id", - pci_get_word(&config[PCI_DEVICE_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "revision-id", - pci_get_byte(&config[PCI_REVISION_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "class-code", - pci_get_long(&config[PCI_CLASS_REVISION]) >> 8)); - _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id", - pci_get_word(&config[PCI_SUBSYSTEM_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id", - pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID]))); - - /* Config space region comes first */ - reg[0].hi = cpu_to_be32( - b_n(0) | - b_p(0) | - b_t(0) | - b_ss(0/*config*/) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn)); - reg[0].addr = 0; - reg[0].size = 0; - - n = 0; - for (i = 0; i < ARRAY_SIZE(bars); ++i) { - if (0 == dev->io_regions[i].size) { - continue; - } - - reg[n+1].hi = cpu_to_be32( - b_n(0) | - b_p(0) | - b_t(0) | - b_ss(regtype_to_ss(dev->io_regions[i].type)) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn) | - b_rrrrrrrr(bars[i])); - reg[n+1].addr = 0; - reg[n+1].size = cpu_to_be64(dev->io_regions[i].size); - - assigned_addresses[n].hi = cpu_to_be32( - b_n(1) | - b_p(0) | - b_t(0) | - b_ss(regtype_to_ss(dev->io_regions[i].type)) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn) | - b_rrrrrrrr(bars[i])); - - /* - * Writing zeroes to assigned_addresses causes the guest kernel to - * reassign BARs - */ - assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr); - assigned_addresses[n].size = reg[n+1].size; - - ++n; - } - _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1))); - _FDT(fdt_setprop(fdt, node_off, "assigned-addresses", - assigned_addresses, - sizeof(assigned_addresses[0])*(n))); - _FDT(fdt_setprop_cell(fdt, node_off, "interrupts", - pci_get_byte(&config[PCI_INTERRUPT_PIN]))); - - ++devices; } - /* Write interrupt map */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, - devices * sizeof(interrupt_map[0]))); + 7 * sizeof(interrupt_map[0]))); return 0; } diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 7a86dc8d2c..64f0009814 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -75,11 +75,11 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) static char *vio_format_dev_name(VIOsPAPRDevice *dev) { - VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); char *name; /* Device tree style name device@reg */ - if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) { + if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) { return NULL; } @@ -90,7 +90,7 @@ static char *vio_format_dev_name(VIOsPAPRDevice *dev) static int vio_make_devnode(VIOsPAPRDevice *dev, void *fdt) { - VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); int vdevice_off, node_off, ret; char *dt_name; @@ -115,17 +115,17 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, return ret; } - if (info->dt_type) { + if (pc->dt_type) { ret = fdt_setprop_string(fdt, node_off, "device_type", - info->dt_type); + pc->dt_type); if (ret < 0) { return ret; } } - if (info->dt_compatible) { + if (pc->dt_compatible) { ret = fdt_setprop_string(fdt, node_off, "compatible", - info->dt_compatible); + pc->dt_compatible); if (ret < 0) { return ret; } @@ -163,8 +163,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } } - if (info->devnode) { - ret = (info->devnode)(dev, fdt, node_off); + if (pc->devnode) { + ret = (pc->devnode)(dev, fdt, node_off); if (ret < 0) { return ret; } @@ -621,7 +621,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, 0); } -static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info) +static int spapr_vio_check_reg(VIOsPAPRDevice *sdev) { VIOsPAPRDevice *other_sdev; DeviceState *qdev; @@ -639,7 +639,9 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info) if (other_sdev != sdev && other_sdev->reg == sdev->reg) { fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n", - info->qdev.name, other_sdev->qdev.info->name, sdev->reg); + object_get_typename(OBJECT(sdev)), + object_get_typename(OBJECT(qdev)), + sdev->reg); return -EEXIST; } } @@ -647,14 +649,14 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info) return 0; } -static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) +static int spapr_vio_busdev_init(DeviceState *qdev) { - VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; + VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); char *id; int ret; - ret = spapr_vio_check_reg(dev, info); + ret = spapr_vio_check_reg(dev); if (ret) { return ret; } @@ -675,16 +677,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) rtce_init(dev); - return info->init(dev); -} - -void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info) -{ - info->qdev.init = spapr_vio_busdev_init; - info->qdev.bus_info = &spapr_vio_bus_info; - - assert(info->qdev.size >= sizeof(VIOsPAPRDevice)); - qdev_register(&info->qdev); + return pc->init(dev); } static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr, @@ -694,15 +687,15 @@ static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr, target_ulong reg = args[0]; target_ulong mode = args[1]; VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); - VIOsPAPRDeviceInfo *info; + VIOsPAPRDeviceClass *pc; if (!dev) { return H_PARAMETER; } - info = (VIOsPAPRDeviceInfo *)dev->qdev.info; + pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - if (mode & ~info->signal_mask) { + if (mode & ~pc->signal_mask) { return H_PARAMETER; } @@ -753,16 +746,42 @@ static int spapr_vio_bridge_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo spapr_vio_bridge_info = { - .init = spapr_vio_bridge_init, - .qdev.name = "spapr-vio-bridge", - .qdev.size = sizeof(SysBusDevice), - .qdev.no_user = 1, +static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = spapr_vio_bridge_init; + dc->no_user = 1; +} + +static TypeInfo spapr_vio_bridge_info = { + .name = "spapr-vio-bridge", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SysBusDevice), + .class_init = spapr_vio_bridge_class_init, +}; + +static void vio_spapr_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = spapr_vio_busdev_init; + k->bus_info = &spapr_vio_bus_info; +} + +static TypeInfo spapr_vio_type_info = { + .name = TYPE_VIO_SPAPR_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VIOsPAPRDevice), + .abstract = true, + .class_size = sizeof(VIOsPAPRDeviceClass), + .class_init = vio_spapr_device_class_init, }; static void spapr_vio_register_devices(void) { - sysbus_register_withprop(&spapr_vio_bridge_info); + type_register_static(&spapr_vio_bridge_info); + type_register_static(&spapr_vio_type_info); } device_init(spapr_vio_register_devices) diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h index 0984d559db..d8527bed90 100644 --- a/hw/spapr_vio.h +++ b/hw/spapr_vio.h @@ -34,6 +34,14 @@ enum VIOsPAPR_TCEAccess { #define SPAPR_VTY_BASE_ADDRESS 0x30000000 +#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" +#define VIO_SPAPR_DEVICE(obj) \ + OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE) +#define VIO_SPAPR_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE) +#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE) + struct VIOsPAPRDevice; typedef struct VIOsPAPR_RTCE { @@ -47,7 +55,20 @@ typedef struct VIOsPAPR_CRQ { int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq); } VIOsPAPR_CRQ; -typedef struct VIOsPAPRDevice { +typedef struct VIOsPAPRDevice VIOsPAPRDevice; +typedef struct VIOsPAPRBus VIOsPAPRBus; + +typedef struct VIOsPAPRDeviceClass { + DeviceClass parent_class; + + const char *dt_name, *dt_type, *dt_compatible; + target_ulong signal_mask; + int (*init)(VIOsPAPRDevice *dev); + void (*hcalls)(VIOsPAPRBus *bus); + int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); +} VIOsPAPRDeviceClass; + +struct VIOsPAPRDevice { DeviceState qdev; uint32_t reg; uint32_t flags; @@ -59,28 +80,23 @@ typedef struct VIOsPAPRDevice { VIOsPAPR_RTCE *rtce_table; int kvmtce_fd; VIOsPAPR_CRQ crq; -} VIOsPAPRDevice; +}; #define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \ DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \ DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \ default_dma_window) -typedef struct VIOsPAPRBus { +struct VIOsPAPRBus { BusState bus; -} VIOsPAPRBus; - -typedef struct { - DeviceInfo qdev; const char *dt_name, *dt_type, *dt_compatible; target_ulong signal_mask; int (*init)(VIOsPAPRDevice *dev); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); -} VIOsPAPRDeviceInfo; +}; extern VIOsPAPRBus *spapr_vio_bus_init(void); extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); -extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus); diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c index 00e2d2d5d3..9cfce19a73 100644 --- a/hw/spapr_vscsi.c +++ b/hw/spapr_vscsi.c @@ -947,23 +947,34 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) return 0; } -static VIOsPAPRDeviceInfo spapr_vscsi = { - .init = spapr_vscsi_init, - .devnode = spapr_vscsi_devnode, - .dt_name = "v-scsi", - .dt_type = "vscsi", - .dt_compatible = "IBM,v-scsi", - .signal_mask = 0x00000001, - .qdev.name = "spapr-vscsi", - .qdev.size = sizeof(VSCSIState), - .qdev.props = (Property[]) { - DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000), - DEFINE_PROP_END_OF_LIST(), - }, +static Property spapr_vscsi_properties[] = { + DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_vscsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); + + k->init = spapr_vscsi_init; + k->devnode = spapr_vscsi_devnode; + k->dt_name = "v-scsi"; + k->dt_type = "vscsi"; + k->dt_compatible = "IBM,v-scsi"; + k->signal_mask = 0x00000001; + dc->props = spapr_vscsi_properties; +} + +static TypeInfo spapr_vscsi_info = { + .name = "spapr-vscsi", + .parent = TYPE_VIO_SPAPR_DEVICE, + .instance_size = sizeof(VSCSIState), + .class_init = spapr_vscsi_class_init, }; static void spapr_vscsi_register(void) { - spapr_vio_bus_register_withprop(&spapr_vscsi); + type_register_static(&spapr_vscsi_info); } device_init(spapr_vscsi_register); diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c index c5fb0968ed..a954e7d29b 100644 --- a/hw/spapr_vty.c +++ b/hw/spapr_vty.c @@ -135,18 +135,29 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev) qdev_init_nofail(dev); } -static VIOsPAPRDeviceInfo spapr_vty = { - .init = spapr_vty_init, - .dt_name = "vty", - .dt_type = "serial", - .dt_compatible = "hvterm1", - .qdev.name = "spapr-vty", - .qdev.size = sizeof(VIOsPAPRVTYDevice), - .qdev.props = (Property[]) { - DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0), - DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), - DEFINE_PROP_END_OF_LIST(), - }, +static Property spapr_vty_properties[] = { + DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0), + DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev), + DEFINE_PROP_END_OF_LIST(), +}; + +static void spapr_vty_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); + + k->init = spapr_vty_init; + k->dt_name = "vty"; + k->dt_type = "serial"; + k->dt_compatible = "hvterm1"; + dc->props = spapr_vty_properties; +} + +static TypeInfo spapr_vty_info = { + .name = "spapr-vty", + .parent = TYPE_VIO_SPAPR_DEVICE, + .instance_size = sizeof(VIOsPAPRVTYDevice), + .class_init = spapr_vty_class_init, }; VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) @@ -163,7 +174,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) selected = NULL; QTAILQ_FOREACH(iter, &bus->bus.children, sibling) { /* Only look at VTY devices */ - if (iter->info != &spapr_vty.qdev) { + if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) { continue; } @@ -203,8 +214,8 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) static void spapr_vty_register(void) { - spapr_vio_bus_register_withprop(&spapr_vty); spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char); spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char); + type_register_static(&spapr_vty_info); } device_init(spapr_vty_register); diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c index 035d2e205b..f07cc6fdf0 100644 --- a/hw/sparc32_dma.c +++ b/hw/sparc32_dma.c @@ -283,22 +283,33 @@ static int sparc32_dma_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo sparc32_dma_info = { - .init = sparc32_dma_init1, - .qdev.name = "sparc32_dma", - .qdev.size = sizeof(DMAState), - .qdev.vmsd = &vmstate_dma, - .qdev.reset = dma_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu), - DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property sparc32_dma_properties[] = { + DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu), + DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sparc32_dma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sparc32_dma_init1; + dc->reset = dma_reset; + dc->vmsd = &vmstate_dma; + dc->props = sparc32_dma_properties; +} + +static TypeInfo sparc32_dma_info = { + .name = "sparc32_dma", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DMAState), + .class_init = sparc32_dma_class_init, }; static void sparc32_dma_register_devices(void) { - sysbus_register_withprop(&sparc32_dma_info); + type_register_static(&sparc32_dma_info); } device_init(sparc32_dma_register_devices) diff --git a/hw/spitz.c b/hw/spitz.c index 9d129c22b9..4e6540d976 100644 --- a/hw/spitz.c +++ b/hw/spitz.c @@ -717,7 +717,7 @@ static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) static void spitz_wm8750_addr(void *opaque, int line, int level) { - i2c_slave *wm = (i2c_slave *) opaque; + I2CSlave *wm = (I2CSlave *) opaque; if (level) i2c_set_slave_address(wm, SPITZ_WM_ADDRH); else @@ -1023,16 +1023,27 @@ static VMStateDescription vmstate_sl_nand_info = { }, }; -static SysBusDeviceInfo sl_nand_info = { - .init = sl_nand_init, - .qdev.name = "sl-nand", - .qdev.size = sizeof(SLNANDState), - .qdev.vmsd = &vmstate_sl_nand_info, - .qdev.props = (Property []) { - DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG), - DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1), - DEFINE_PROP_END_OF_LIST(), - }, +static Property sl_nand_properties[] = { + DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG), + DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sl_nand_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sl_nand_init; + dc->vmsd = &vmstate_sl_nand_info; + dc->props = sl_nand_properties; +} + +static TypeInfo sl_nand_info = { + .name = "sl-nand", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SLNANDState), + .class_init = sl_nand_class_init, }; static VMStateDescription vmstate_spitz_kbd = { @@ -1049,14 +1060,25 @@ static VMStateDescription vmstate_spitz_kbd = { }, }; -static SysBusDeviceInfo spitz_keyboard_info = { - .init = spitz_keyboard_init, - .qdev.name = "spitz-keyboard", - .qdev.size = sizeof(SpitzKeyboardState), - .qdev.vmsd = &vmstate_spitz_kbd, - .qdev.props = (Property []) { - DEFINE_PROP_END_OF_LIST(), - }, +static Property spitz_keyboard_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void spitz_keyboard_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = spitz_keyboard_init; + dc->vmsd = &vmstate_spitz_kbd; + dc->props = spitz_keyboard_properties; +} + +static TypeInfo spitz_keyboard_info = { + .name = "spitz-keyboard", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SpitzKeyboardState), + .class_init = spitz_keyboard_class_init, }; static const VMStateDescription vmstate_corgi_ssp_regs = { @@ -1070,12 +1092,21 @@ static const VMStateDescription vmstate_corgi_ssp_regs = { } }; -static SSISlaveInfo corgi_ssp_info = { - .qdev.name = "corgi-ssp", - .qdev.size = sizeof(CorgiSSPState), - .qdev.vmsd = &vmstate_corgi_ssp_regs, - .init = corgi_ssp_init, - .transfer = corgi_ssp_transfer +static void corgi_ssp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = corgi_ssp_init; + k->transfer = corgi_ssp_transfer; + dc->vmsd = &vmstate_corgi_ssp_regs; +} + +static TypeInfo corgi_ssp_info = { + .name = "corgi-ssp", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(CorgiSSPState), + .class_init = corgi_ssp_class_init, }; static const VMStateDescription vmstate_spitz_lcdtg_regs = { @@ -1090,20 +1121,29 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = { } }; -static SSISlaveInfo spitz_lcdtg_info = { - .qdev.name = "spitz-lcdtg", - .qdev.size = sizeof(SpitzLCDTG), - .qdev.vmsd = &vmstate_spitz_lcdtg_regs, - .init = spitz_lcdtg_init, - .transfer = spitz_lcdtg_transfer +static void spitz_lcdtg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = spitz_lcdtg_init; + k->transfer = spitz_lcdtg_transfer; + dc->vmsd = &vmstate_spitz_lcdtg_regs; +} + +static TypeInfo spitz_lcdtg_info = { + .name = "spitz-lcdtg", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(SpitzLCDTG), + .class_init = spitz_lcdtg_class_init, }; static void spitz_register_devices(void) { - ssi_register_slave(&corgi_ssp_info); - ssi_register_slave(&spitz_lcdtg_info); - sysbus_register_withprop(&spitz_keyboard_info); - sysbus_register_withprop(&sl_nand_info); + type_register_static(&corgi_ssp_info); + type_register_static(&spitz_lcdtg_info); + type_register_static(&spitz_keyboard_info); + type_register_static(&sl_nand_info); } device_init(spitz_register_devices) diff --git a/hw/ssd0303.c b/hw/ssd0303.c index bcad7bf922..685602a584 100644 --- a/hw/ssd0303.c +++ b/hw/ssd0303.c @@ -42,7 +42,7 @@ enum ssd0303_cmd { }; typedef struct { - i2c_slave i2c; + I2CSlave i2c; DisplayState *ds; int row; int col; @@ -57,13 +57,13 @@ typedef struct { uint8_t framebuffer[132*8]; } ssd0303_state; -static int ssd0303_recv(i2c_slave *i2c) +static int ssd0303_recv(I2CSlave *i2c) { BADF("Reads not implemented\n"); return -1; } -static int ssd0303_send(i2c_slave *i2c, uint8_t data) +static int ssd0303_send(I2CSlave *i2c, uint8_t data) { ssd0303_state *s = (ssd0303_state *)i2c; enum ssd0303_cmd old_cmd_state; @@ -173,7 +173,7 @@ static int ssd0303_send(i2c_slave *i2c, uint8_t data) return 0; } -static void ssd0303_event(i2c_slave *i2c, enum i2c_event event) +static void ssd0303_event(I2CSlave *i2c, enum i2c_event event) { ssd0303_state *s = (ssd0303_state *)i2c; switch (event) { @@ -283,7 +283,7 @@ static const VMStateDescription vmstate_ssd0303 = { } }; -static int ssd0303_init(i2c_slave *i2c) +static int ssd0303_init(I2CSlave *i2c) { ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c); @@ -294,19 +294,28 @@ static int ssd0303_init(i2c_slave *i2c) return 0; } -static I2CSlaveInfo ssd0303_info = { - .qdev.name = "ssd0303", - .qdev.size = sizeof(ssd0303_state), - .qdev.vmsd = &vmstate_ssd0303, - .init = ssd0303_init, - .event = ssd0303_event, - .recv = ssd0303_recv, - .send = ssd0303_send +static void ssd0303_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = ssd0303_init; + k->event = ssd0303_event; + k->recv = ssd0303_recv; + k->send = ssd0303_send; + dc->vmsd = &vmstate_ssd0303; +} + +static TypeInfo ssd0303_info = { + .name = "ssd0303", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(ssd0303_state), + .class_init = ssd0303_class_init, }; static void ssd0303_register_devices(void) { - i2c_register_slave(&ssd0303_info); + type_register_static(&ssd0303_info); } device_init(ssd0303_register_devices) diff --git a/hw/ssd0323.c b/hw/ssd0323.c index 1eb3823fed..3c43738ae1 100644 --- a/hw/ssd0323.c +++ b/hw/ssd0323.c @@ -340,16 +340,24 @@ static int ssd0323_init(SSISlave *dev) return 0; } -static SSISlaveInfo ssd0323_info = { - .qdev.name = "ssd0323", - .qdev.size = sizeof(ssd0323_state), - .init = ssd0323_init, - .transfer = ssd0323_transfer +static void ssd0323_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = ssd0323_init; + k->transfer = ssd0323_transfer; +} + +static TypeInfo ssd0323_info = { + .name = "ssd0323", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(ssd0323_state), + .class_init = ssd0323_class_init, }; static void ssd03232_register_devices(void) { - ssi_register_slave(&ssd0323_info); + type_register_static(&ssd0323_info); } device_init(ssd03232_register_devices) diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c index 2d89cfe522..f2e6cecb71 100644 --- a/hw/ssi-sd.c +++ b/hw/ssi-sd.c @@ -244,16 +244,24 @@ static int ssi_sd_init(SSISlave *dev) return 0; } -static SSISlaveInfo ssi_sd_info = { - .qdev.name = "ssi-sd", - .qdev.size = sizeof(ssi_sd_state), - .init = ssi_sd_init, - .transfer = ssi_sd_transfer +static void ssi_sd_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = ssi_sd_init; + k->transfer = ssi_sd_transfer; +} + +static TypeInfo ssi_sd_info = { + .name = "ssi-sd", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(ssi_sd_state), + .class_init = ssi_sd_class_init, }; static void ssi_sd_register_devices(void) { - ssi_register_slave(&ssi_sd_info); + type_register_static(&ssi_sd_info); } device_init(ssi_sd_register_devices) @@ -21,10 +21,10 @@ static struct BusInfo ssi_bus_info = { .size = sizeof(SSIBus), }; -static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info) +static int ssi_slave_init(DeviceState *dev) { - SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev); - SSISlave *s = SSI_SLAVE_FROM_QDEV(dev); + SSISlave *s = SSI_SLAVE(dev); + SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); SSIBus *bus; bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev)); @@ -33,18 +33,24 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info) hw_error("Too many devices on SSI bus"); } - s->info = info; - return info->init(s); + return ssc->init(s); } -void ssi_register_slave(SSISlaveInfo *info) +static void ssi_slave_class_init(ObjectClass *klass, void *data) { - assert(info->qdev.size >= sizeof(SSISlave)); - info->qdev.init = ssi_slave_init; - info->qdev.bus_info = &ssi_bus_info; - qdev_register(&info->qdev); + DeviceClass *dc = DEVICE_CLASS(klass); + dc->init = ssi_slave_init; + dc->bus_info = &ssi_bus_info; } +static TypeInfo ssi_slave_info = { + .name = TYPE_SSI_SLAVE, + .parent = TYPE_DEVICE, + .class_init = ssi_slave_class_init, + .class_size = sizeof(SSISlaveClass), + .abstract = true, +}; + DeviceState *ssi_create_slave(SSIBus *bus, const char *name) { DeviceState *dev; @@ -64,10 +70,19 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { DeviceState *dev; SSISlave *slave; + SSISlaveClass *ssc; dev = QTAILQ_FIRST(&bus->qbus.children); if (!dev) { return 0; } - slave = SSI_SLAVE_FROM_QDEV(dev); - return slave->info->transfer(slave, val); + slave = SSI_SLAVE(dev); + ssc = SSI_SLAVE_GET_CLASS(slave); + return ssc->transfer(slave, val); +} + +static void register_ssi_slave(void) +{ + type_register_static(&ssi_slave_info); } + +device_init(register_ssi_slave); @@ -15,23 +15,29 @@ typedef struct SSISlave SSISlave; +#define TYPE_SSI_SLAVE "ssi-slave" +#define SSI_SLAVE(obj) \ + OBJECT_CHECK(SSISlave, (obj), TYPE_SSI_SLAVE) +#define SSI_SLAVE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SSISlaveClass, (klass), TYPE_SSI_SLAVE) +#define SSI_SLAVE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE) + /* Slave devices. */ -typedef struct { - DeviceInfo qdev; +typedef struct SSISlaveClass { + DeviceClass parent_class; + int (*init)(SSISlave *dev); uint32_t (*transfer)(SSISlave *dev, uint32_t val); -} SSISlaveInfo; +} SSISlaveClass; struct SSISlave { DeviceState qdev; - SSISlaveInfo *info; }; #define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) -void ssi_register_slave(SSISlaveInfo *info); - DeviceState *ssi_create_slave(SSIBus *bus, const char *name); /* Master interface. */ diff --git a/hw/stellaris.c b/hw/stellaris.c index 7a73074982..31a65cfb77 100644 --- a/hw/stellaris.c +++ b/hw/stellaris.c @@ -1394,22 +1394,69 @@ static void stellaris_machine_init(void) machine_init(stellaris_machine_init); -static SSISlaveInfo stellaris_ssi_bus_info = { - .qdev.name = "evb6965-ssi", - .qdev.size = sizeof(stellaris_ssi_bus_state), - .init = stellaris_ssi_bus_init, - .transfer = stellaris_ssi_bus_transfer +static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = stellaris_ssi_bus_init; + k->transfer = stellaris_ssi_bus_transfer; +} + +static TypeInfo stellaris_ssi_bus_info = { + .name = "evb6965-ssi", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(stellaris_ssi_bus_state), + .class_init = stellaris_ssi_bus_class_init, +}; + +static void stellaris_i2c_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_i2c_init; +} + +static TypeInfo stellaris_i2c_info = { + .name = "stellaris-i2c", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(stellaris_i2c_state), + .class_init = stellaris_i2c_class_init, +}; + +static void stellaris_gptm_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_gptm_init; +} + +static TypeInfo stellaris_gptm_info = { + .name = "stellaris-gptm", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(gptm_state), + .class_init = stellaris_gptm_class_init, +}; + +static void stellaris_adc_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = stellaris_adc_init; +} + +static TypeInfo stellaris_adc_info = { + .name = "stellaris-adc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(stellaris_adc_state), + .class_init = stellaris_adc_class_init, }; static void stellaris_register_devices(void) { - sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state), - stellaris_i2c_init); - sysbus_register_dev("stellaris-gptm", sizeof(gptm_state), - stellaris_gptm_init); - sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state), - stellaris_adc_init); - ssi_register_slave(&stellaris_ssi_bus_info); + type_register_static(&stellaris_i2c_info); + type_register_static(&stellaris_gptm_info); + type_register_static(&stellaris_adc_info); + type_register_static(&stellaris_ssi_bus_info); } device_init(stellaris_register_devices) diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 866c9a2381..9b1be8dadc 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -411,7 +411,7 @@ static int stellaris_enet_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); stellaris_enet_reset(s); @@ -420,19 +420,30 @@ static int stellaris_enet_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo stellaris_enet_info = { - .init = stellaris_enet_init, - .qdev.name = "stellaris_enet", - .qdev.size = sizeof(stellaris_enet_state), - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property stellaris_enet_properties[] = { + DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void stellaris_enet_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stellaris_enet_init; + dc->props = stellaris_enet_properties; +} + +static TypeInfo stellaris_enet_info = { + .name = "stellaris_enet", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(stellaris_enet_state), + .class_init = stellaris_enet_class_init, }; static void stellaris_enet_register_devices(void) { - sysbus_register_withprop(&stellaris_enet_info); + type_register_static(&stellaris_enet_info); } device_init(stellaris_enet_register_devices) diff --git a/hw/strongarm.c b/hw/strongarm.c index fe63fd7ab7..8d2e7eb6fe 100644 --- a/hw/strongarm.c +++ b/hw/strongarm.c @@ -201,12 +201,21 @@ static VMStateDescription vmstate_strongarm_pic_regs = { }, }; -static SysBusDeviceInfo strongarm_pic_info = { - .init = strongarm_pic_initfn, - .qdev.name = "strongarm_pic", - .qdev.desc = "StrongARM PIC", - .qdev.size = sizeof(StrongARMPICState), - .qdev.vmsd = &vmstate_strongarm_pic_regs, +static void strongarm_pic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_pic_initfn; + dc->desc = "StrongARM PIC"; + dc->vmsd = &vmstate_strongarm_pic_regs; +} + +static TypeInfo strongarm_pic_info = { + .name = "strongarm_pic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMPICState), + .class_init = strongarm_pic_class_init, }; /* Real-Time Clock */ @@ -413,12 +422,21 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = { }, }; -static SysBusDeviceInfo strongarm_rtc_sysbus_info = { - .init = strongarm_rtc_init, - .qdev.name = "strongarm-rtc", - .qdev.desc = "StrongARM RTC Controller", - .qdev.size = sizeof(StrongARMRTCState), - .qdev.vmsd = &vmstate_strongarm_rtc_regs, +static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_rtc_init; + dc->desc = "StrongARM RTC Controller"; + dc->vmsd = &vmstate_strongarm_rtc_regs; +} + +static TypeInfo strongarm_rtc_sysbus_info = { + .name = "strongarm-rtc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMRTCState), + .class_init = strongarm_rtc_sysbus_class_init, }; /* GPIO */ @@ -646,11 +664,20 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = { }, }; -static SysBusDeviceInfo strongarm_gpio_info = { - .init = strongarm_gpio_initfn, - .qdev.name = "strongarm-gpio", - .qdev.desc = "StrongARM GPIO controller", - .qdev.size = sizeof(StrongARMGPIOInfo), +static void strongarm_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_gpio_initfn; + dc->desc = "StrongARM GPIO controller"; +} + +static TypeInfo strongarm_gpio_info = { + .name = "strongarm-gpio", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMGPIOInfo), + .class_init = strongarm_gpio_class_init, }; /* Peripheral Pin Controller */ @@ -803,11 +830,20 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = { }, }; -static SysBusDeviceInfo strongarm_ppc_info = { - .init = strongarm_ppc_init, - .qdev.name = "strongarm-ppc", - .qdev.desc = "StrongARM PPC controller", - .qdev.size = sizeof(StrongARMPPCInfo), +static void strongarm_ppc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_ppc_init; + dc->desc = "StrongARM PPC controller"; +} + +static TypeInfo strongarm_ppc_info = { + .name = "strongarm-ppc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMPPCInfo), + .class_init = strongarm_ppc_class_init, }; /* UART Ports */ @@ -1245,17 +1281,28 @@ static const VMStateDescription vmstate_strongarm_uart_regs = { }, }; -static SysBusDeviceInfo strongarm_uart_info = { - .init = strongarm_uart_init, - .qdev.name = "strongarm-uart", - .qdev.desc = "StrongARM UART controller", - .qdev.size = sizeof(StrongARMUARTState), - .qdev.reset = strongarm_uart_reset, - .qdev.vmsd = &vmstate_strongarm_uart_regs, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), - DEFINE_PROP_END_OF_LIST(), - } +static Property strongarm_uart_properties[] = { + DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void strongarm_uart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_uart_init; + dc->desc = "StrongARM UART controller"; + dc->reset = strongarm_uart_reset; + dc->vmsd = &vmstate_strongarm_uart_regs; + dc->props = strongarm_uart_properties; +} + +static TypeInfo strongarm_uart_info = { + .name = "strongarm-uart", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMUARTState), + .class_init = strongarm_uart_class_init, }; /* Synchronous Serial Ports */ @@ -1479,13 +1526,22 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = { }, }; -static SysBusDeviceInfo strongarm_ssp_info = { - .init = strongarm_ssp_init, - .qdev.name = "strongarm-ssp", - .qdev.desc = "StrongARM SSP controller", - .qdev.size = sizeof(StrongARMSSPState), - .qdev.reset = strongarm_ssp_reset, - .qdev.vmsd = &vmstate_strongarm_ssp_regs, +static void strongarm_ssp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = strongarm_ssp_init; + dc->desc = "StrongARM SSP controller"; + dc->reset = strongarm_ssp_reset; + dc->vmsd = &vmstate_strongarm_ssp_regs; +} + +static TypeInfo strongarm_ssp_info = { + .name = "strongarm-ssp", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(StrongARMSSPState), + .class_init = strongarm_ssp_class_init, }; /* Main CPU functions */ @@ -1555,11 +1611,11 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem, static void strongarm_register_devices(void) { - sysbus_register_withprop(&strongarm_pic_info); - sysbus_register_withprop(&strongarm_rtc_sysbus_info); - sysbus_register_withprop(&strongarm_gpio_info); - sysbus_register_withprop(&strongarm_ppc_info); - sysbus_register_withprop(&strongarm_uart_info); - sysbus_register_withprop(&strongarm_ssp_info); + type_register_static(&strongarm_pic_info); + type_register_static(&strongarm_rtc_sysbus_info); + type_register_static(&strongarm_gpio_info); + type_register_static(&strongarm_ppc_info); + type_register_static(&strongarm_uart_info); + type_register_static(&strongarm_ssp_info); } device_init(strongarm_register_devices) diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c index e15b1674ce..081d6cc8bd 100644 --- a/hw/sun4c_intctl.c +++ b/hw/sun4c_intctl.c @@ -206,17 +206,26 @@ static int sun4c_intctl_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo sun4c_intctl_info = { - .init = sun4c_intctl_init1, - .qdev.name = "sun4c_intctl", - .qdev.size = sizeof(Sun4c_INTCTLState), - .qdev.vmsd = &vmstate_sun4c_intctl, - .qdev.reset = sun4c_intctl_reset, +static void sun4c_intctl_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = sun4c_intctl_init1; + dc->reset = sun4c_intctl_reset; + dc->vmsd = &vmstate_sun4c_intctl; +} + +static TypeInfo sun4c_intctl_info = { + .name = "sun4c_intctl", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(Sun4c_INTCTLState), + .class_init = sun4c_intctl_class_init, }; static void sun4c_intctl_register_devices(void) { - sysbus_register_withprop(&sun4c_intctl_info); + type_register_static(&sun4c_intctl_info); } device_init(sun4c_intctl_register_devices) diff --git a/hw/sun4m.c b/hw/sun4m.c index 941cc98b9b..b79d14c35a 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -609,15 +609,23 @@ static int idreg_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo idreg_info = { - .init = idreg_init1, - .qdev.name = "macio_idreg", - .qdev.size = sizeof(IDRegState), +static void idreg_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = idreg_init1; +} + +static TypeInfo idreg_info = { + .name = "macio_idreg", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IDRegState), + .class_init = idreg_class_init, }; static void idreg_register_devices(void) { - sysbus_register_withprop(&idreg_info); + type_register_static(&idreg_info); } device_init(idreg_register_devices); @@ -650,15 +658,23 @@ static int afx_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo afx_info = { - .init = afx_init1, - .qdev.name = "tcx_afx", - .qdev.size = sizeof(AFXState), +static void afx_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = afx_init1; +} + +static TypeInfo afx_info = { + .name = "tcx_afx", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AFXState), + .class_init = afx_class_init, }; static void afx_register_devices(void) { - sysbus_register_withprop(&afx_info); + type_register_static(&afx_info); } device_init(afx_register_devices); @@ -720,18 +736,29 @@ static int prom_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo prom_info = { - .init = prom_init1, - .qdev.name = "openprom", - .qdev.size = sizeof(PROMState), - .qdev.props = (Property[]) { - {/* end of property list */} - } +static Property prom_properties[] = { + {/* end of property list */}, +}; + +static void prom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = prom_init1; + dc->props = prom_properties; +} + +static TypeInfo prom_info = { + .name = "openprom", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PROMState), + .class_init = prom_class_init, }; static void prom_register_devices(void) { - sysbus_register_withprop(&prom_info); + type_register_static(&prom_info); } device_init(prom_register_devices); @@ -779,19 +806,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size, sysbus_mmio_map(s, 0, addr); } -static SysBusDeviceInfo ram_info = { - .init = ram_init1, - .qdev.name = "memory", - .qdev.size = sizeof(RamDevice), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT64("size", RamDevice, size, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property ram_properties[] = { + DEFINE_PROP_UINT64("size", RamDevice, size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ram_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ram_init1; + dc->props = ram_properties; +} + +static TypeInfo ram_info = { + .name = "memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RamDevice), + .class_init = ram_class_init, }; static void ram_register_devices(void) { - sysbus_register_withprop(&ram_info); + type_register_static(&ram_info); } device_init(ram_register_devices); diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c index ef7627c467..727532cb09 100644 --- a/hw/sun4m_iommu.c +++ b/hw/sun4m_iommu.c @@ -357,21 +357,32 @@ static int iommu_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo iommu_info = { - .init = iommu_init1, - .qdev.name = "iommu", - .qdev.size = sizeof(IOMMUState), - .qdev.vmsd = &vmstate_iommu, - .qdev.reset = iommu_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("version", IOMMUState, version, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property iommu_properties[] = { + DEFINE_PROP_HEX32("version", IOMMUState, version, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void iommu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = iommu_init1; + dc->reset = iommu_reset; + dc->vmsd = &vmstate_iommu; + dc->props = iommu_properties; +} + +static TypeInfo iommu_info = { + .name = "iommu", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOMMUState), + .class_init = iommu_class_init, }; static void iommu_register_devices(void) { - sysbus_register_withprop(&iommu_info); + type_register_static(&iommu_info); } device_init(iommu_register_devices) diff --git a/hw/sun4u.c b/hw/sun4u.c index 2dc3d0439f..79bbd495eb 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -562,19 +562,27 @@ pci_ebus_init1(PCIDevice *pci_dev) return 0; } -static PCIDeviceInfo ebus_info = { - .qdev.name = "ebus", - .qdev.size = sizeof(EbusState), - .init = pci_ebus_init1, - .vendor_id = PCI_VENDOR_ID_SUN, - .device_id = PCI_DEVICE_ID_SUN_EBUS, - .revision = 0x01, - .class_id = PCI_CLASS_BRIDGE_OTHER, +static void ebus_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = pci_ebus_init1; + k->vendor_id = PCI_VENDOR_ID_SUN; + k->device_id = PCI_DEVICE_ID_SUN_EBUS; + k->revision = 0x01; + k->class_id = PCI_CLASS_BRIDGE_OTHER; +} + +static TypeInfo ebus_info = { + .name = "ebus", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EbusState), + .class_init = ebus_class_init, }; static void pci_ebus_register(void) { - pci_qdev_register(&ebus_info); + type_register_static(&ebus_info); } device_init(pci_ebus_register); @@ -636,18 +644,29 @@ static int prom_init1(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo prom_info = { - .init = prom_init1, - .qdev.name = "openprom", - .qdev.size = sizeof(PROMState), - .qdev.props = (Property[]) { - {/* end of property list */} - } +static Property prom_properties[] = { + {/* end of property list */}, +}; + +static void prom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = prom_init1; + dc->props = prom_properties; +} + +static TypeInfo prom_info = { + .name = "openprom", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PROMState), + .class_init = prom_class_init, }; static void prom_register_devices(void) { - sysbus_register_withprop(&prom_info); + type_register_static(&prom_info); } device_init(prom_register_devices); @@ -688,19 +707,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size) sysbus_mmio_map(s, 0, addr); } -static SysBusDeviceInfo ram_info = { - .init = ram_init1, - .qdev.name = "memory", - .qdev.size = sizeof(RamDevice), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT64("size", RamDevice, size, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property ram_properties[] = { + DEFINE_PROP_UINT64("size", RamDevice, size, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ram_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = ram_init1; + dc->props = ram_properties; +} + +static TypeInfo ram_info = { + .name = "memory", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(RamDevice), + .class_init = ram_class_init, }; static void ram_register_devices(void) { - sysbus_register_withprop(&ram_info); + type_register_static(&ram_info); } device_init(ram_register_devices); diff --git a/hw/sysbus.c b/hw/sysbus.c index 2e06fe823c..282060abb6 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -105,31 +105,12 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size) } } -static int sysbus_device_init(DeviceState *dev, DeviceInfo *base) +static int sysbus_device_init(DeviceState *dev) { - SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev); + SysBusDevice *sd = SYS_BUS_DEVICE(dev); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd); - return info->init(sysbus_from_qdev(dev)); -} - -void sysbus_register_withprop(SysBusDeviceInfo *info) -{ - info->qdev.init = sysbus_device_init; - info->qdev.bus_info = &system_bus_info; - - assert(info->qdev.size >= sizeof(SysBusDevice)); - qdev_register(&info->qdev); -} - -void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init) -{ - SysBusDeviceInfo *info; - - info = g_malloc0(sizeof(*info)); - info->qdev.name = g_strdup(name); - info->qdev.size = size; - info->init = init; - sysbus_register_withprop(info); + return sbc->init(sd); } DeviceState *sysbus_create_varargs(const char *name, @@ -258,3 +239,26 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev) { return get_system_memory(); } + +static void sysbus_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = sysbus_device_init; + k->bus_info = &system_bus_info; +} + +static TypeInfo sysbus_device_type_info = { + .name = TYPE_SYS_BUS_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(SysBusDevice), + .abstract = true, + .class_size = sizeof(SysBusDeviceClass), + .class_init = sysbus_device_class_init, +}; + +static void sysbus_register(void) +{ + type_register_static(&sysbus_device_type_info); +} + +device_init(sysbus_register); diff --git a/hw/sysbus.h b/hw/sysbus.h index 7b8ca236bf..22555cd443 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -12,6 +12,20 @@ typedef struct SysBusDevice SysBusDevice; +#define TYPE_SYS_BUS_DEVICE "sys-bus-device" +#define SYS_BUS_DEVICE(obj) \ + OBJECT_CHECK(SysBusDevice, (obj), TYPE_SYS_BUS_DEVICE) +#define SYS_BUS_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SysBusDeviceClass, (klass), TYPE_SYS_BUS_DEVICE) +#define SYS_BUS_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SysBusDeviceClass, (obj), TYPE_SYS_BUS_DEVICE) + +typedef struct SysBusDeviceClass { + DeviceClass parent_class; + + int (*init)(SysBusDevice *dev); +} SysBusDeviceClass; + struct SysBusDevice { DeviceState qdev; int num_irq; @@ -26,19 +40,10 @@ struct SysBusDevice { pio_addr_t pio[QDEV_MAX_PIO]; }; -typedef int (*sysbus_initfn)(SysBusDevice *dev); - /* Macros to compensate for lack of type inheritance in C. */ #define sysbus_from_qdev(dev) ((SysBusDevice *)(dev)) #define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev) -typedef struct { - DeviceInfo qdev; - sysbus_initfn init; -} SysBusDeviceInfo; - -void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init); -void sysbus_register_withprop(SysBusDeviceInfo *info); void *sysbus_new(void); void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory); MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n); @@ -61,21 +61,13 @@ static void tcx24_screen_dump(void *opaque, const char *filename); static void tcx_set_dirty(TCXState *s) { - unsigned int i; - - for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) { - memory_region_set_dirty(&s->vram_mem, i); - } + memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY); } static void tcx24_set_dirty(TCXState *s) { - unsigned int i; - - for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) { - memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i); - memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i); - } + memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4); + memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4); } static void update_palette_entries(TCXState *s, int start, int end) @@ -186,15 +178,13 @@ static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24, ram_addr_t cpage) { int ret; - unsigned int off; - - ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA); - for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) { - ret |= memory_region_get_dirty(&s->vram_mem, page24 + off, - DIRTY_MEMORY_VGA); - ret |= memory_region_get_dirty(&s->vram_mem, cpage + off, - DIRTY_MEMORY_VGA); - } + + ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); + ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4, + DIRTY_MEMORY_VGA); return ret; } @@ -253,7 +243,8 @@ static void tcx_update_display(void *opaque) } for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { - if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) { + if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE, + DIRTY_MEMORY_VGA)) { if (y_start < 0) y_start = y; if (page < page_min) @@ -646,25 +637,36 @@ static void tcx24_screen_dump(void *opaque, const char *filename) return; } -static SysBusDeviceInfo tcx_info = { - .init = tcx_init1, - .qdev.name = "SUNW,tcx", - .qdev.size = sizeof(TCXState), - .qdev.reset = tcx_reset, - .qdev.vmsd = &vmstate_tcx, - .qdev.props = (Property[]) { - DEFINE_PROP_TADDR("addr", TCXState, addr, -1), - DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1), - DEFINE_PROP_UINT16("width", TCXState, width, -1), - DEFINE_PROP_UINT16("height", TCXState, height, -1), - DEFINE_PROP_UINT16("depth", TCXState, depth, -1), - DEFINE_PROP_END_OF_LIST(), - } +static Property tcx_properties[] = { + DEFINE_PROP_TADDR("addr", TCXState, addr, -1), + DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1), + DEFINE_PROP_UINT16("width", TCXState, width, -1), + DEFINE_PROP_UINT16("height", TCXState, height, -1), + DEFINE_PROP_UINT16("depth", TCXState, depth, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tcx_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = tcx_init1; + dc->reset = tcx_reset; + dc->vmsd = &vmstate_tcx; + dc->props = tcx_properties; +} + +static TypeInfo tcx_info = { + .name = "SUNW,tcx", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TCXState), + .class_init = tcx_class_init, }; static void tcx_register_devices(void) { - sysbus_register_withprop(&tcx_info); + type_register_static(&tcx_info); } device_init(tcx_register_devices) diff --git a/hw/tmp105.c b/hw/tmp105.c index f7e6f2b909..a3bdd91d40 100644 --- a/hw/tmp105.c +++ b/hw/tmp105.c @@ -22,7 +22,7 @@ #include "i2c.h" typedef struct { - i2c_slave i2c; + I2CSlave i2c; uint8_t len; uint8_t buf[2]; qemu_irq pin; @@ -65,7 +65,7 @@ static void tmp105_alarm_update(TMP105State *s) } /* Units are 0.001 centigrades relative to 0 C. */ -void tmp105_set(i2c_slave *i2c, int temp) +void tmp105_set(I2CSlave *i2c, int temp) { TMP105State *s = (TMP105State *) i2c; @@ -138,7 +138,7 @@ static void tmp105_write(TMP105State *s) } } -static int tmp105_rx(i2c_slave *i2c) +static int tmp105_rx(I2CSlave *i2c) { TMP105State *s = (TMP105State *) i2c; @@ -148,7 +148,7 @@ static int tmp105_rx(i2c_slave *i2c) return 0xff; } -static int tmp105_tx(i2c_slave *i2c, uint8_t data) +static int tmp105_tx(I2CSlave *i2c, uint8_t data) { TMP105State *s = (TMP105State *) i2c; @@ -163,7 +163,7 @@ static int tmp105_tx(i2c_slave *i2c, uint8_t data) return 0; } -static void tmp105_event(i2c_slave *i2c, enum i2c_event event) +static void tmp105_event(I2CSlave *i2c, enum i2c_event event) { TMP105State *s = (TMP105State *) i2c; @@ -202,7 +202,7 @@ static const VMStateDescription vmstate_tmp105 = { } }; -static void tmp105_reset(i2c_slave *i2c) +static void tmp105_reset(I2CSlave *i2c) { TMP105State *s = (TMP105State *) i2c; @@ -215,7 +215,7 @@ static void tmp105_reset(i2c_slave *i2c) tmp105_interrupt_update(s); } -static int tmp105_init(i2c_slave *i2c) +static int tmp105_init(I2CSlave *i2c) { TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c); @@ -226,19 +226,28 @@ static int tmp105_init(i2c_slave *i2c) return 0; } -static I2CSlaveInfo tmp105_info = { - .qdev.name = "tmp105", - .qdev.size = sizeof(TMP105State), - .qdev.vmsd = &vmstate_tmp105, - .init = tmp105_init, - .event = tmp105_event, - .recv = tmp105_rx, - .send = tmp105_tx +static void tmp105_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = tmp105_init; + k->event = tmp105_event; + k->recv = tmp105_rx; + k->send = tmp105_tx; + dc->vmsd = &vmstate_tmp105; +} + +static TypeInfo tmp105_info = { + .name = "tmp105", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(TMP105State), + .class_init = tmp105_class_init, }; static void tmp105_register_devices(void) { - i2c_register_slave(&tmp105_info); + type_register_static(&tmp105_info); } device_init(tmp105_register_devices) @@ -133,12 +133,12 @@ static int tosa_ssp_init(SSISlave *dev) } typedef struct { - i2c_slave i2c; + I2CSlave i2c; int len; char buf[3]; } TosaDACState; -static int tosa_dac_send(i2c_slave *i2c, uint8_t data) +static int tosa_dac_send(I2CSlave *i2c, uint8_t data) { TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); s->buf[s->len] = data; @@ -157,7 +157,7 @@ static int tosa_dac_send(i2c_slave *i2c, uint8_t data) return 0; } -static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event) +static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event) { TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c); s->len = 0; @@ -180,13 +180,13 @@ static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event) } } -static int tosa_dac_recv(i2c_slave *s) +static int tosa_dac_recv(I2CSlave *s) { printf("%s: recv not supported!!!\n", __FUNCTION__); return -1; } -static int tosa_dac_init(i2c_slave *i2c) +static int tosa_dac_init(I2CSlave *i2c) { /* Nothing to do. */ return 0; @@ -259,26 +259,42 @@ static void tosapda_machine_init(void) machine_init(tosapda_machine_init); -static I2CSlaveInfo tosa_dac_info = { - .qdev.name = "tosa_dac", - .qdev.size = sizeof(TosaDACState), - .init = tosa_dac_init, - .event = tosa_dac_event, - .recv = tosa_dac_recv, - .send = tosa_dac_send +static void tosa_dac_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = tosa_dac_init; + k->event = tosa_dac_event; + k->recv = tosa_dac_recv; + k->send = tosa_dac_send; +} + +static TypeInfo tosa_dac_info = { + .name = "tosa_dac", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(TosaDACState), + .class_init = tosa_dac_class_init, }; -static SSISlaveInfo tosa_ssp_info = { - .qdev.name = "tosa-ssp", - .qdev.size = sizeof(SSISlave), - .init = tosa_ssp_init, - .transfer = tosa_ssp_tansfer +static void tosa_ssp_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = tosa_ssp_init; + k->transfer = tosa_ssp_tansfer; +} + +static TypeInfo tosa_ssp_info = { + .name = "tosa-ssp", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(SSISlave), + .class_init = tosa_ssp_class_init, }; static void tosa_register_devices(void) { - i2c_register_slave(&tosa_dac_info); - ssi_register_slave(&tosa_ssp_info); + type_register_static(&tosa_dac_info); + type_register_static(&tosa_ssp_info); } device_init(tosa_register_devices) diff --git a/hw/tusb6010.c b/hw/tusb6010.c index 276300a302..0ade670906 100644 --- a/hw/tusb6010.c +++ b/hw/tusb6010.c @@ -789,16 +789,25 @@ static int tusb6010_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo tusb6010_info = { - .init = tusb6010_init, - .qdev.name = "tusb6010", - .qdev.size = sizeof(TUSBState), - .qdev.reset = tusb6010_reset, +static void tusb6010_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = tusb6010_init; + dc->reset = tusb6010_reset; +} + +static TypeInfo tusb6010_info = { + .name = "tusb6010", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TUSBState), + .class_init = tusb6010_class_init, }; static void tusb6010_register_device(void) { - sysbus_register_withprop(&tusb6010_info); + type_register_static(&tusb6010_info); } device_init(tusb6010_register_device) diff --git a/hw/twl92230.c b/hw/twl92230.c index a75448f06a..03fdccc8ce 100644 --- a/hw/twl92230.c +++ b/hw/twl92230.c @@ -27,7 +27,7 @@ #define VERBOSE 1 typedef struct { - i2c_slave i2c; + I2CSlave i2c; int firstbyte; uint8_t reg; @@ -126,7 +126,7 @@ static void menelaus_rtc_hz(void *opaque) menelaus_update(s); } -static void menelaus_reset(i2c_slave *i2c) +static void menelaus_reset(I2CSlave *i2c) { MenelausState *s = (MenelausState *) i2c; s->reg = 0x00; @@ -709,7 +709,7 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value) } } -static void menelaus_event(i2c_slave *i2c, enum i2c_event event) +static void menelaus_event(I2CSlave *i2c, enum i2c_event event) { MenelausState *s = (MenelausState *) i2c; @@ -717,7 +717,7 @@ static void menelaus_event(i2c_slave *i2c, enum i2c_event event) s->firstbyte = 1; } -static int menelaus_tx(i2c_slave *i2c, uint8_t data) +static int menelaus_tx(I2CSlave *i2c, uint8_t data) { MenelausState *s = (MenelausState *) i2c; /* Interpret register address byte */ @@ -730,7 +730,7 @@ static int menelaus_tx(i2c_slave *i2c, uint8_t data) return 0; } -static int menelaus_rx(i2c_slave *i2c) +static int menelaus_rx(I2CSlave *i2c) { MenelausState *s = (MenelausState *) i2c; @@ -842,7 +842,7 @@ static const VMStateDescription vmstate_menelaus = { } }; -static int twl92230_init(i2c_slave *i2c) +static int twl92230_init(I2CSlave *i2c) { MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c); @@ -857,19 +857,28 @@ static int twl92230_init(i2c_slave *i2c) return 0; } -static I2CSlaveInfo twl92230_info = { - .qdev.name ="twl92230", - .qdev.size = sizeof(MenelausState), - .qdev.vmsd = &vmstate_menelaus, - .init = twl92230_init, - .event = menelaus_event, - .recv = menelaus_rx, - .send = menelaus_tx +static void twl92230_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + sc->init = twl92230_init; + sc->event = menelaus_event; + sc->recv = menelaus_rx; + sc->send = menelaus_tx; + dc->vmsd = &vmstate_menelaus; +} + +static TypeInfo twl92230_info = { + .name = "twl92230", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(MenelausState), + .class_init = twl92230_class_init, }; static void twl92230_register_devices(void) { - i2c_register_slave(&twl92230_info); + type_register_static(&twl92230_info); } device_init(twl92230_register_devices) diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 14d99147f3..17d86aac68 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -39,7 +39,6 @@ static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e }; typedef struct UNINState { - SysBusDevice busdev; PCIHostState host_state; MemoryRegion pci_mmio; MemoryRegion pci_hole; @@ -64,10 +63,6 @@ static void pci_unin_set_irq(void *opaque, int irq_num, int level) qemu_set_irq(pic[unin_irq_line[irq_num]], level); } -static void pci_unin_reset(void *opaque) -{ -} - static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr) { uint32_t retval; @@ -134,11 +129,13 @@ static const MemoryRegionOps unin_data_ops = { static int pci_unin_main_init_device(SysBusDevice *dev) { + PCIHostState *h; UNINState *s; /* Use values found on a real PowerMac */ /* Uninorth main bus */ - s = FROM_SYSBUS(UNINState, dev); + h = FROM_SYSBUS(PCIHostState, dev); + s = DO_UPCAST(UNINState, host_state, h); memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, &s->host_state, "pci-conf-idx", 0x1000); @@ -147,17 +144,18 @@ static int pci_unin_main_init_device(SysBusDevice *dev) sysbus_init_mmio(dev, &s->host_state.conf_mem); sysbus_init_mmio(dev, &s->host_state.data_mem); - qemu_register_reset(pci_unin_reset, &s->host_state); return 0; } static int pci_u3_agp_init_device(SysBusDevice *dev) { + PCIHostState *h; UNINState *s; /* Uninorth U3 AGP bus */ - s = FROM_SYSBUS(UNINState, dev); + h = FROM_SYSBUS(PCIHostState, dev); + s = DO_UPCAST(UNINState, host_state, h); memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, &s->host_state, "pci-conf-idx", 0x1000); @@ -166,17 +164,17 @@ static int pci_u3_agp_init_device(SysBusDevice *dev) sysbus_init_mmio(dev, &s->host_state.conf_mem); sysbus_init_mmio(dev, &s->host_state.data_mem); - qemu_register_reset(pci_unin_reset, &s->host_state); - return 0; } static int pci_unin_agp_init_device(SysBusDevice *dev) { + PCIHostState *h; UNINState *s; /* Uninorth AGP bus */ - s = FROM_SYSBUS(UNINState, dev); + h = FROM_SYSBUS(PCIHostState, dev); + s = DO_UPCAST(UNINState, host_state, h); memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, &s->host_state, "pci-conf-idx", 0x1000); @@ -189,10 +187,12 @@ static int pci_unin_agp_init_device(SysBusDevice *dev) static int pci_unin_internal_init_device(SysBusDevice *dev) { + PCIHostState *h; UNINState *s; /* Uninorth internal bus */ - s = FROM_SYSBUS(UNINState, dev); + h = FROM_SYSBUS(PCIHostState, dev); + s = DO_UPCAST(UNINState, host_state, h); memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops, &s->host_state, "pci-conf-idx", 0x1000); @@ -209,21 +209,23 @@ PCIBus *pci_pmac_init(qemu_irq *pic, { DeviceState *dev; SysBusDevice *s; + PCIHostState *h; UNINState *d; /* Use values found on a real PowerMac */ /* Uninorth main bus */ - dev = qdev_create(NULL, "uni-north"); + dev = qdev_create(NULL, "uni-north-pci-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); - d = FROM_SYSBUS(UNINState, s); + h = FROM_SYSBUS(PCIHostState, s); + d = DO_UPCAST(UNINState, host_state, h); memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL); memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio, 0x80000000ULL, 0x70000000ULL); memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", + d->host_state.bus = pci_register_bus(dev, "pci", pci_unin_set_irq, pci_unin_map_irq, pic, &d->pci_mmio, @@ -245,7 +247,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, /* Uninorth AGP bus */ pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp"); - dev = qdev_create(NULL, "uni-north-agp"); + dev = qdev_create(NULL, "uni-north-agp-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); sysbus_mmio_map(s, 0, 0xf0800000); @@ -254,8 +256,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic, /* Uninorth internal bus */ #if 0 /* XXX: not needed for now */ - pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci"); - dev = qdev_create(NULL, "uni-north-pci"); + pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), + "uni-north-internal-pci"); + dev = qdev_create(NULL, "uni-north-internal-pci-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); sysbus_mmio_map(s, 0, 0xf4800000); @@ -271,14 +274,16 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, { DeviceState *dev; SysBusDevice *s; + PCIHostState *h; UNINState *d; /* Uninorth AGP bus */ - dev = qdev_create(NULL, "u3-agp"); + dev = qdev_create(NULL, "u3-agp-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); - d = FROM_SYSBUS(UNINState, s); + h = FROM_SYSBUS(PCIHostState, s); + d = DO_UPCAST(UNINState, host_state, h); memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL); memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio, @@ -286,7 +291,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, memory_region_add_subregion(address_space_mem, 0x80000000ULL, &d->pci_hole); - d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", + d->host_state.bus = pci_register_bus(dev, "pci", pci_unin_set_irq, pci_unin_map_irq, pic, &d->pci_mmio, @@ -334,60 +339,145 @@ static int unin_internal_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo unin_main_pci_host_info = { - .qdev.name = "uni-north", - .qdev.size = sizeof(PCIDevice), - .init = unin_main_pci_host_init, - .vendor_id = PCI_VENDOR_ID_APPLE, - .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI, - .revision = 0x00, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = unin_main_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static TypeInfo unin_main_pci_host_info = { + .name = "uni-north-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = unin_main_pci_host_class_init, +}; + +static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = u3_agp_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static TypeInfo u3_agp_pci_host_info = { + .name = "u3-agp", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = u3_agp_pci_host_class_init, +}; + +static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = unin_agp_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static TypeInfo unin_agp_pci_host_info = { + .name = "uni-north-agp", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = unin_agp_pci_host_class_init, +}; + +static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = unin_internal_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI; + k->revision = 0x00; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static TypeInfo unin_internal_pci_host_info = { + .name = "uni-north-internal-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = unin_internal_pci_host_class_init, }; -static PCIDeviceInfo u3_agp_pci_host_info = { - .qdev.name = "u3-agp", - .qdev.size = sizeof(PCIDevice), - .init = u3_agp_pci_host_init, - .vendor_id = PCI_VENDOR_ID_APPLE, - .device_id = PCI_DEVICE_ID_APPLE_U3_AGP, - .revision = 0x00, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void pci_unin_main_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = pci_unin_main_init_device; +} + +static TypeInfo pci_unin_main_info = { + .name = "uni-north-pci-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UNINState), + .class_init = pci_unin_main_class_init, +}; + +static void pci_u3_agp_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = pci_u3_agp_init_device; +} + +static TypeInfo pci_u3_agp_info = { + .name = "u3-agp-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UNINState), + .class_init = pci_u3_agp_class_init, }; -static PCIDeviceInfo unin_agp_pci_host_info = { - .qdev.name = "uni-north-agp", - .qdev.size = sizeof(PCIDevice), - .init = unin_agp_pci_host_init, - .vendor_id = PCI_VENDOR_ID_APPLE, - .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, - .revision = 0x00, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void pci_unin_agp_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = pci_unin_agp_init_device; +} + +static TypeInfo pci_unin_agp_info = { + .name = "uni-north-agp-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UNINState), + .class_init = pci_unin_agp_class_init, }; -static PCIDeviceInfo unin_internal_pci_host_info = { - .qdev.name = "uni-north-pci", - .qdev.size = sizeof(PCIDevice), - .init = unin_internal_pci_host_init, - .vendor_id = PCI_VENDOR_ID_APPLE, - .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI, - .revision = 0x00, - .class_id = PCI_CLASS_BRIDGE_HOST, +static void pci_unin_internal_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = pci_unin_internal_init_device; +} + +static TypeInfo pci_unin_internal_info = { + .name = "uni-north-internal-pci-pcihost", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(UNINState), + .class_init = pci_unin_internal_class_init, }; static void unin_register_devices(void) { - sysbus_register_dev("uni-north", sizeof(UNINState), - pci_unin_main_init_device); - pci_qdev_register(&unin_main_pci_host_info); - sysbus_register_dev("u3-agp", sizeof(UNINState), - pci_u3_agp_init_device); - pci_qdev_register(&u3_agp_pci_host_info); - sysbus_register_dev("uni-north-agp", sizeof(UNINState), - pci_unin_agp_init_device); - pci_qdev_register(&unin_agp_pci_host_info); - sysbus_register_dev("uni-north-pci", sizeof(UNINState), - pci_unin_internal_init_device); - pci_qdev_register(&unin_internal_pci_host_info); + type_register_static(&unin_main_pci_host_info); + type_register_static(&u3_agp_pci_host_info); + type_register_static(&unin_agp_pci_host_info); + type_register_static(&unin_internal_pci_host_info); + + type_register_static(&pci_unin_main_info); + type_register_static(&pci_u3_agp_info); + type_register_static(&pci_unin_agp_info); + type_register_static(&pci_unin_internal_info); } device_init(unin_register_devices) diff --git a/hw/usb-audio.c b/hw/usb-audio.c new file mode 100644 index 0000000000..cd589b718a --- /dev/null +++ b/hw/usb-audio.c @@ -0,0 +1,715 @@ +/* + * QEMU USB audio device + * + * written by: + * H. Peter Anvin <hpa@linux.intel.com> + * Gerd Hoffmann <kraxel@redhat.com> + * + * lousely based on usb net device code which is: + * + * Copyright (c) 2006 Thomas Sailer + * Copyright (c) 2008 Andrzej Zaborowski + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu-common.h" +#include "usb.h" +#include "usb-desc.h" +#include "hw.h" +#include "audiodev.h" +#include "audio/audio.h" + +#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */ +#define USBAUDIO_PRODUCT_NUM 0x0002 + +#define DEV_CONFIG_VALUE 1 /* The one and only */ + +/* Descriptor subtypes for AC interfaces */ +#define DST_AC_HEADER 1 +#define DST_AC_INPUT_TERMINAL 2 +#define DST_AC_OUTPUT_TERMINAL 3 +#define DST_AC_FEATURE_UNIT 6 +/* Descriptor subtypes for AS interfaces */ +#define DST_AS_GENERAL 1 +#define DST_AS_FORMAT_TYPE 2 +/* Descriptor subtypes for endpoints */ +#define DST_EP_GENERAL 1 + +enum usb_audio_strings { + STRING_NULL, + STRING_MANUFACTURER, + STRING_PRODUCT, + STRING_SERIALNUMBER, + STRING_CONFIG, + STRING_USBAUDIO_CONTROL, + STRING_INPUT_TERMINAL, + STRING_FEATURE_UNIT, + STRING_OUTPUT_TERMINAL, + STRING_NULL_STREAM, + STRING_REAL_STREAM, +}; + +static const USBDescStrings usb_audio_stringtable = { + [STRING_MANUFACTURER] = "QEMU", + [STRING_PRODUCT] = "QEMU USB Audio", + [STRING_SERIALNUMBER] = "1", + [STRING_CONFIG] = "Audio Configuration", + [STRING_USBAUDIO_CONTROL] = "Audio Device", + [STRING_INPUT_TERMINAL] = "Audio Output Pipe", + [STRING_FEATURE_UNIT] = "Audio Output Volume Control", + [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal", + [STRING_NULL_STREAM] = "Audio Output - Disabled", + [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo", +}; + +#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff) +#define U24(x) U16(x), (((x) >> 16) & 0xff) +#define U32(x) U24(x), (((x) >> 24) & 0xff) + +/* + * A Basic Audio Device uses these specific values + */ +#define USBAUDIO_PACKET_SIZE 192 +#define USBAUDIO_SAMPLE_RATE 48000 +#define USBAUDIO_PACKET_INTERVAL 1 + +static const USBDescIface desc_iface[] = { + { + .bInterfaceNumber = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .bInterfaceProtocol = 0x04, + .iInterface = STRING_USBAUDIO_CONTROL, + .ndesc = 4, + .descs = (USBDescOther[]) { + { + /* Headphone Class-Specific AC Interface Header Descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_HEADER, /* u8 bDescriptorSubtype */ + U16(0x0100), /* u16 bcdADC */ + U16(0x2b), /* u16 wTotalLength */ + 0x01, /* u8 bInCollection */ + 0x01, /* u8 baInterfaceNr */ + } + },{ + /* Generic Stereo Input Terminal ID1 Descriptor */ + .data = (uint8_t[]) { + 0x0c, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalID */ + U16(0x0101), /* u16 wTerminalType */ + 0x00, /* u8 bAssocTerminal */ + 0x02, /* u16 bNrChannels */ + U16(0x0003), /* u16 wChannelConfig */ + 0x00, /* u8 iChannelNames */ + STRING_INPUT_TERMINAL, /* u8 iTerminal */ + } + },{ + /* Generic Stereo Feature Unit ID2 Descriptor */ + .data = (uint8_t[]) { + 0x0d, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */ + 0x02, /* u8 bUnitID */ + 0x01, /* u8 bSourceID */ + 0x02, /* u8 bControlSize */ + U16(0x0001), /* u16 bmaControls(0) */ + U16(0x0002), /* u16 bmaControls(1) */ + U16(0x0002), /* u16 bmaControls(2) */ + STRING_FEATURE_UNIT, /* u8 iFeature */ + } + },{ + /* Headphone Ouptut Terminal ID3 Descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */ + 0x03, /* u8 bUnitID */ + U16(0x0301), /* u16 wTerminalType (SPK) */ + 0x00, /* u8 bAssocTerminal */ + 0x02, /* u8 bSourceID */ + STRING_OUTPUT_TERMINAL, /* u8 iTerminal */ + } + } + }, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_NULL_STREAM, + },{ + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING, + .iInterface = STRING_REAL_STREAM, + .ndesc = 2, + .descs = (USBDescOther[]) { + { + /* Headphone Class-specific AS General Interface Descriptor */ + .data = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_GENERAL, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bTerminalLink */ + 0x00, /* u8 bDelay */ + 0x01, 0x00, /* u16 wFormatTag */ + } + },{ + /* Headphone Type I Format Type Descriptor */ + .data = (uint8_t[]) { + 0x0b, /* u8 bLength */ + USB_DT_CS_INTERFACE, /* u8 bDescriptorType */ + DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */ + 0x01, /* u8 bFormatType */ + 0x02, /* u8 bNrChannels */ + 0x02, /* u8 bSubFrameSize */ + 0x10, /* u8 bBitResolution */ + 0x01, /* u8 bSamFreqType */ + U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */ + } + } + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_OUT | 0x01, + .bmAttributes = 0x0d, + .wMaxPacketSize = USBAUDIO_PACKET_SIZE, + .bInterval = 1, + .is_audio = 1, + /* Stereo Headphone Class-specific + AS Audio Data Endpoint Descriptor */ + .extra = (uint8_t[]) { + 0x07, /* u8 bLength */ + USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */ + DST_EP_GENERAL, /* u8 bDescriptorSubtype */ + 0x00, /* u8 bmAttributes */ + 0x00, /* u8 bLockDelayUnits */ + U16(0x0000), /* u16 wLockDelay */ + }, + }, + } + } +}; + +static const USBDescDevice desc_device = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 2, + .bConfigurationValue = DEV_CONFIG_VALUE, + .iConfiguration = STRING_CONFIG, + .bmAttributes = 0xc0, + .bMaxPower = 0x32, + .nif = ARRAY_SIZE(desc_iface), + .ifs = desc_iface, + }, + }, +}; + +static const USBDesc desc_audio = { + .id = { + .idVendor = USBAUDIO_VENDOR_NUM, + .idProduct = USBAUDIO_PRODUCT_NUM, + .bcdDevice = 0, + .iManufacturer = STRING_MANUFACTURER, + .iProduct = STRING_PRODUCT, + .iSerialNumber = STRING_SERIALNUMBER, + }, + .full = &desc_device, + .str = usb_audio_stringtable, +}; + +/* + * A USB audio device supports an arbitrary number of alternate + * interface settings for each interface. Each corresponds to a block + * diagram of parameterized blocks. This can thus refer to things like + * number of channels, data rates, or in fact completely different + * block diagrams. Alternative setting 0 is always the null block diagram, + * which is used by a disabled device. + */ +enum usb_audio_altset { + ALTSET_OFF = 0x00, /* No endpoint */ + ALTSET_ON = 0x01, /* Single endpoint */ +}; + +/* + * Class-specific control requests + */ +#define CR_SET_CUR 0x01 +#define CR_GET_CUR 0x81 +#define CR_SET_MIN 0x02 +#define CR_GET_MIN 0x82 +#define CR_SET_MAX 0x03 +#define CR_GET_MAX 0x83 +#define CR_SET_RES 0x04 +#define CR_GET_RES 0x84 +#define CR_SET_MEM 0x05 +#define CR_GET_MEM 0x85 +#define CR_GET_STAT 0xff + +/* + * Feature Unit Control Selectors + */ +#define MUTE_CONTROL 0x01 +#define VOLUME_CONTROL 0x02 +#define BASS_CONTROL 0x03 +#define MID_CONTROL 0x04 +#define TREBLE_CONTROL 0x05 +#define GRAPHIC_EQUALIZER_CONTROL 0x06 +#define AUTOMATIC_GAIN_CONTROL 0x07 +#define DELAY_CONTROL 0x08 +#define BASS_BOOST_CONTROL 0x09 +#define LOUDNESS_CONTROL 0x0a + +/* + * buffering + */ + +struct streambuf { + uint8_t *data; + uint32_t size; + uint32_t prod; + uint32_t cons; +}; + +static void streambuf_init(struct streambuf *buf, uint32_t size) +{ + g_free(buf->data); + buf->size = size - (size % USBAUDIO_PACKET_SIZE); + buf->data = g_malloc(buf->size); + buf->prod = 0; + buf->cons = 0; +} + +static void streambuf_fini(struct streambuf *buf) +{ + g_free(buf->data); + buf->data = NULL; +} + +static int streambuf_put(struct streambuf *buf, USBPacket *p) +{ + uint32_t free = buf->size - (buf->prod - buf->cons); + + if (!free) { + return 0; + } + assert(free >= USBAUDIO_PACKET_SIZE); + usb_packet_copy(p, buf->data + (buf->prod % buf->size), + USBAUDIO_PACKET_SIZE); + buf->prod += USBAUDIO_PACKET_SIZE; + return USBAUDIO_PACKET_SIZE; +} + +static uint8_t *streambuf_get(struct streambuf *buf) +{ + uint32_t used = buf->prod - buf->cons; + uint8_t *data; + + if (!used) { + return NULL; + } + assert(used >= USBAUDIO_PACKET_SIZE); + data = buf->data + (buf->cons % buf->size); + buf->cons += USBAUDIO_PACKET_SIZE; + return data; +} + +typedef struct USBAudioState { + /* qemu interfaces */ + USBDevice dev; + QEMUSoundCard card; + + /* state */ + struct { + enum usb_audio_altset altset; + struct audsettings as; + SWVoiceOut *voice; + bool mute; + uint8_t vol[2]; + struct streambuf buf; + } out; + + /* properties */ + uint32_t debug; + uint32_t buffer; +} USBAudioState; + +static void output_callback(void *opaque, int avail) +{ + USBAudioState *s = opaque; + uint8_t *data; + + for (;;) { + if (avail < USBAUDIO_PACKET_SIZE) { + return; + } + data = streambuf_get(&s->out.buf); + if (NULL == data) { + return; + } + AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE); + avail -= USBAUDIO_PACKET_SIZE; + } +} + +static int usb_audio_set_output_altset(USBAudioState *s, int altset) +{ + switch (altset) { + case ALTSET_OFF: + streambuf_init(&s->out.buf, s->buffer); + AUD_set_active_out(s->out.voice, false); + break; + case ALTSET_ON: + AUD_set_active_out(s->out.voice, true); + break; + default: + return -1; + } + + if (s->debug) { + fprintf(stderr, "usb-audio: set interface %d\n", altset); + } + s->out.altset = altset; + return 0; +} + +/* + * Note: we arbitrarily map the volume control range onto -inf..+8 dB + */ +#define ATTRIB_ID(cs, attrib, idif) \ + (((cs) << 24) | ((attrib) << 16) | (idif)) + +static int usb_audio_get_control(USBAudioState *s, uint8_t attrib, + uint16_t cscn, uint16_t idif, + int length, uint8_t *data) +{ + uint8_t cs = cscn >> 8; + uint8_t cn = cscn - 1; /* -1 for the non-present master control */ + uint32_t aid = ATTRIB_ID(cs, attrib, idif); + int ret = USB_RET_STALL; + + switch (aid) { + case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200): + data[0] = s->out.mute; + ret = 1; + break; + case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200): + if (cn < 2) { + uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000; + data[0] = vol; + data[1] = vol >> 8; + ret = 2; + } + break; + case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200): + if (cn < 2) { + data[0] = 0x01; + data[1] = 0x80; + ret = 2; + } + break; + case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200): + if (cn < 2) { + data[0] = 0x00; + data[1] = 0x08; + ret = 2; + } + break; + case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200): + if (cn < 2) { + data[0] = 0x88; + data[1] = 0x00; + ret = 2; + } + break; + } + + return ret; +} +static int usb_audio_set_control(USBAudioState *s, uint8_t attrib, + uint16_t cscn, uint16_t idif, + int length, uint8_t *data) +{ + uint8_t cs = cscn >> 8; + uint8_t cn = cscn - 1; /* -1 for the non-present master control */ + uint32_t aid = ATTRIB_ID(cs, attrib, idif); + int ret = USB_RET_STALL; + bool set_vol = false; + + switch (aid) { + case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200): + s->out.mute = data[0] & 1; + set_vol = true; + ret = 0; + break; + case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200): + if (cn < 2) { + uint16_t vol = data[0] + (data[1] << 8); + + if (s->debug) { + fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol); + } + + vol -= 0x8000; + vol = (vol * 255 + 0x4400) / 0x8800; + if (vol > 255) { + vol = 255; + } + + s->out.vol[cn] = vol; + set_vol = true; + ret = 0; + } + break; + } + + if (set_vol) { + if (s->debug) { + fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n", + s->out.mute, s->out.vol[0], s->out.vol[1]); + } + AUD_set_volume_out(s->out.voice, s->out.mute, + s->out.vol[0], s->out.vol[1]); + } + + return ret; +} + +static int usb_audio_handle_control(USBDevice *dev, USBPacket *p, + int request, int value, int index, + int length, uint8_t *data) +{ + USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); + int ret = 0; + + if (s->debug) { + fprintf(stderr, "usb-audio: control transaction: " + "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", + request, value, index, length); + } + + ret = usb_desc_handle_control(dev, p, request, value, index, length, data); + if (ret >= 0) { + return ret; + } + + switch (request) { + case ClassInterfaceRequest | CR_GET_CUR: + case ClassInterfaceRequest | CR_GET_MIN: + case ClassInterfaceRequest | CR_GET_MAX: + case ClassInterfaceRequest | CR_GET_RES: + ret = usb_audio_get_control(s, request & 0xff, value, index, + length, data); + if (ret < 0) { + if (s->debug) { + fprintf(stderr, "usb-audio: fail: get control\n"); + } + goto fail; + } + break; + + case ClassInterfaceOutRequest | CR_SET_CUR: + case ClassInterfaceOutRequest | CR_SET_MIN: + case ClassInterfaceOutRequest | CR_SET_MAX: + case ClassInterfaceOutRequest | CR_SET_RES: + ret = usb_audio_set_control(s, request & 0xff, value, index, + length, data); + if (ret < 0) { + if (s->debug) { + fprintf(stderr, "usb-audio: fail: set control\n"); + } + goto fail; + } + break; + + default: +fail: + if (s->debug) { + fprintf(stderr, "usb-audio: failed control transaction: " + "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n", + request, value, index, length); + } + ret = USB_RET_STALL; + break; + } + return ret; +} + +static void usb_audio_set_interface(USBDevice *dev, int iface, + int old, int value) +{ + USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); + + if (iface == 1) { + usb_audio_set_output_altset(s, value); + } +} + +static void usb_audio_handle_reset(USBDevice *dev) +{ + USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); + + if (s->debug) { + fprintf(stderr, "usb-audio: reset\n"); + } + usb_audio_set_output_altset(s, ALTSET_OFF); +} + +static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p) +{ + int rc; + + if (s->out.altset == ALTSET_OFF) { + return USB_RET_STALL; + } + + rc = streambuf_put(&s->out.buf, p); + if (rc < p->iov.size && s->debug > 1) { + fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n", + p->iov.size - rc); + } + + return 0; +} + +static int usb_audio_handle_data(USBDevice *dev, USBPacket *p) +{ + USBAudioState *s = (USBAudioState *) dev; + int ret = 0; + + switch (p->pid) { + case USB_TOKEN_OUT: + switch (p->devep) { + case 1: + ret = usb_audio_handle_dataout(s, p); + break; + default: + goto fail; + } + break; + + default: +fail: + ret = USB_RET_STALL; + break; + } + if (ret == USB_RET_STALL && s->debug) { + fprintf(stderr, "usb-audio: failed data transaction: " + "pid 0x%x ep 0x%x len 0x%zx\n", + p->pid, p->devep, p->iov.size); + } + return ret; +} + +static void usb_audio_handle_destroy(USBDevice *dev) +{ + USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); + + if (s->debug) { + fprintf(stderr, "usb-audio: destroy\n"); + } + + usb_audio_set_output_altset(s, ALTSET_OFF); + AUD_close_out(&s->card, s->out.voice); + AUD_remove_card(&s->card); + + streambuf_fini(&s->out.buf); +} + +static int usb_audio_initfn(USBDevice *dev) +{ + USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev); + + usb_desc_init(dev); + s->dev.opaque = s; + AUD_register_card("usb-audio", &s->card); + + s->out.altset = ALTSET_OFF; + s->out.mute = false; + s->out.vol[0] = 240; /* 0 dB */ + s->out.vol[1] = 240; /* 0 dB */ + s->out.as.freq = USBAUDIO_SAMPLE_RATE; + s->out.as.nchannels = 2; + s->out.as.fmt = AUD_FMT_S16; + s->out.as.endianness = 0; + streambuf_init(&s->out.buf, s->buffer); + + s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio", + s, output_callback, &s->out.as); + AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]); + AUD_set_active_out(s->out.voice, 0); + return 0; +} + +static const VMStateDescription vmstate_usb_audio = { + .name = "usb-audio", + .unmigratable = 1, +}; + +static Property usb_audio_properties[] = { + DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0), + DEFINE_PROP_UINT32("buffer", USBAudioState, buffer, + 8 * USBAUDIO_PACKET_SIZE), + DEFINE_PROP_END_OF_LIST(), +}; + +static void usb_audio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *k = USB_DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_usb_audio; + dc->props = usb_audio_properties; + k->product_desc = "QEMU USB Audio Interface"; + k->usb_desc = &desc_audio; + k->init = usb_audio_initfn; + k->handle_packet = usb_generic_handle_packet; + k->handle_reset = usb_audio_handle_reset; + k->handle_control = usb_audio_handle_control; + k->handle_data = usb_audio_handle_data; + k->handle_destroy = usb_audio_handle_destroy; + k->set_interface = usb_audio_set_interface; +} + +static TypeInfo usb_audio_info = { + .name = "usb-audio", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBAudioState), + .class_init = usb_audio_class_init, +}; + +static void usb_audio_register_devices(void) +{ + type_register_static(&usb_audio_info); + usb_legacy_register("usb-audio", "audio", NULL); +} + +device_init(usb_audio_register_devices) diff --git a/hw/usb-bt.c b/hw/usb-bt.c index f30eec1ea2..90c3b0e0eb 100644 --- a/hw/usb-bt.c +++ b/hw/usb-bt.c @@ -28,7 +28,6 @@ struct USBBtState { USBDevice dev; struct HCIInfo *hci; - int altsetting; int config; #define CFIFO_LEN_MASK 255 @@ -362,7 +361,6 @@ static void usb_bt_handle_reset(USBDevice *dev) s->outcmd.len = 0; s->outacl.len = 0; s->outsco.len = 0; - s->altsetting = 0; } static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, @@ -402,26 +400,6 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p, case EndpointOutRequest | USB_REQ_SET_FEATURE: goto fail; break; - case InterfaceRequest | USB_REQ_GET_INTERFACE: - if (value != 0 || (index & ~1) || length != 1) - goto fail; - if (index == 1) - data[0] = s->altsetting; - else - data[0] = 0; - ret = 1; - break; - case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - if ((index & ~1) || length != 0 || - (index == 1 && (value < 0 || value > 4)) || - (index == 0 && value != 0)) { - printf("%s: Wrong SET_INTERFACE request (%i, %i)\n", - __FUNCTION__, index, value); - goto fail; - } - s->altsetting = value; - ret = 0; - break; case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8): if (s->config) usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send, @@ -549,22 +527,31 @@ static const VMStateDescription vmstate_usb_bt = { .unmigratable = 1, }; -static struct USBDeviceInfo bt_info = { - .product_desc = "QEMU BT dongle", - .qdev.name = "usb-bt-dongle", - .qdev.size = sizeof(struct USBBtState), - .qdev.vmsd = &vmstate_usb_bt, - .usb_desc = &desc_bluetooth, - .init = usb_bt_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_bt_handle_reset, - .handle_control = usb_bt_handle_control, - .handle_data = usb_bt_handle_data, - .handle_destroy = usb_bt_handle_destroy, +static void usb_bt_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_bt_initfn; + uc->product_desc = "QEMU BT dongle"; + uc->usb_desc = &desc_bluetooth; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_bt_handle_reset; + uc->handle_control = usb_bt_handle_control; + uc->handle_data = usb_bt_handle_data; + uc->handle_destroy = usb_bt_handle_destroy; + dc->vmsd = &vmstate_usb_bt; +} + +static TypeInfo bt_info = { + .name = "usb-bt-dongle", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(struct USBBtState), + .class_init = usb_bt_class_initfn, }; static void usb_bt_register_devices(void) { - usb_qdev_register(&bt_info); + type_register_static(&bt_info); } device_init(usb_bt_register_devices) diff --git a/hw/usb-bus.c b/hw/usb-bus.c index bd4afa7e2b..b753834584 100644 --- a/hw/usb-bus.c +++ b/hw/usb-bus.c @@ -65,21 +65,112 @@ USBBus *usb_bus_find(int busnr) return NULL; } -static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int usb_device_init(USBDevice *dev) { - USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); - USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base); + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->init) { + return klass->init(dev); + } + return 0; +} + +static void usb_device_handle_destroy(USBDevice *dev) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_destroy) { + klass->handle_destroy(dev); + } +} + +int usb_device_handle_packet(USBDevice *dev, USBPacket *p) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_packet) { + return klass->handle_packet(dev, p); + } + return -ENOSYS; +} + +void usb_device_cancel_packet(USBDevice *dev, USBPacket *p) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->cancel_packet) { + klass->cancel_packet(dev, p); + } +} + +void usb_device_handle_attach(USBDevice *dev) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_attach) { + klass->handle_attach(dev); + } +} + +void usb_device_handle_reset(USBDevice *dev) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_reset) { + klass->handle_reset(dev); + } +} + +int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, + int value, int index, int length, uint8_t *data) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_control) { + return klass->handle_control(dev, p, request, value, index, length, + data); + } + return -ENOSYS; +} + +int usb_device_handle_data(USBDevice *dev, USBPacket *p) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->handle_data) { + return klass->handle_data(dev, p); + } + return -ENOSYS; +} + +const char *usb_device_get_product_desc(USBDevice *dev) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + return klass->product_desc; +} + +const USBDesc *usb_device_get_usb_desc(USBDevice *dev) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + return klass->usb_desc; +} + +void usb_device_set_interface(USBDevice *dev, int interface, + int alt_old, int alt_new) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->set_interface) { + klass->set_interface(dev, interface, alt_old, alt_new); + } +} + +static int usb_qdev_init(DeviceState *qdev) +{ + USBDevice *dev = USB_DEVICE(qdev); int rc; - pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc); - dev->info = info; + pstrcpy(dev->product_desc, sizeof(dev->product_desc), + usb_device_get_product_desc(dev)); dev->auto_attach = 1; QLIST_INIT(&dev->strings); + usb_ep_init(dev); rc = usb_claim_port(dev); if (rc != 0) { return rc; } - rc = dev->info->init(dev); + rc = usb_device_init(dev); if (rc != 0) { usb_release_port(dev); return rc; @@ -96,34 +187,36 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base) static int usb_qdev_exit(DeviceState *qdev) { - USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBDevice *dev = USB_DEVICE(qdev); if (dev->attached) { usb_device_detach(dev); } - if (dev->info->handle_destroy) { - dev->info->handle_destroy(dev); - } + usb_device_handle_destroy(dev); if (dev->port) { usb_release_port(dev); } return 0; } -void usb_qdev_register(USBDeviceInfo *info) +typedef struct LegacyUSBFactory { - info->qdev.bus_info = &usb_bus_info; - info->qdev.init = usb_qdev_init; - info->qdev.unplug = qdev_simple_unplug_cb; - info->qdev.exit = usb_qdev_exit; - qdev_register(&info->qdev); -} + const char *name; + const char *usbdevice_name; + USBDevice *(*usbdevice_init)(const char *params); +} LegacyUSBFactory; -void usb_qdev_register_many(USBDeviceInfo *info) +static GSList *legacy_usb_factory; + +void usb_legacy_register(const char *typename, const char *usbdevice_name, + USBDevice *(*usbdevice_init)(const char *params)) { - while (info->qdev.name) { - usb_qdev_register(info); - info++; + if (usbdevice_name) { + LegacyUSBFactory *f = g_malloc0(sizeof(*f)); + f->name = typename; + f->usbdevice_name = usbdevice_name; + f->usbdevice_init = usbdevice_init; + legacy_usb_factory = g_slist_append(legacy_usb_factory, f); } } @@ -143,7 +236,7 @@ USBDevice *usb_create(USBBus *bus, const char *name) #endif dev = qdev_create(&bus->qbus, name); - return DO_UPCAST(USBDevice, qdev, dev); + return USB_DEVICE(dev); } USBDevice *usb_create_simple(USBBus *bus, const char *name) @@ -249,7 +342,7 @@ int usb_claim_port(USBDevice *dev) return -1; } } else { - if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) { + if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) { /* Create a new hub and chain it on */ usb_create_simple(bus, "usb-hub"); } @@ -364,7 +457,7 @@ static const char *usb_speed(unsigned int speed) static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) { - USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBDevice *dev = USB_DEVICE(qdev); USBBus *bus = usb_bus_from_device(dev); monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n", @@ -376,13 +469,13 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent) static char *usb_get_dev_path(DeviceState *qdev) { - USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBDevice *dev = USB_DEVICE(qdev); return g_strdup(dev->port->path); } static char *usb_get_fw_dev_path(DeviceState *qdev) { - USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev); + USBDevice *dev = USB_DEVICE(qdev); char *fw_path, *in; ssize_t pos = 0, fw_len; long nr; @@ -433,8 +526,8 @@ void usb_info(Monitor *mon) USBDevice *usbdevice_create(const char *cmdline) { USBBus *bus = usb_bus_find(-1 /* any */); - DeviceInfo *info; - USBDeviceInfo *usb; + LegacyUSBFactory *f = NULL; + GSList *i; char driver[32]; const char *params; int len; @@ -451,17 +544,13 @@ USBDevice *usbdevice_create(const char *cmdline) pstrcpy(driver, sizeof(driver), cmdline); } - for (info = device_info_list; info != NULL; info = info->next) { - if (info->bus_info != &usb_bus_info) - continue; - usb = DO_UPCAST(USBDeviceInfo, qdev, info); - if (usb->usbdevice_name == NULL) - continue; - if (strcmp(usb->usbdevice_name, driver) != 0) - continue; - break; + for (i = legacy_usb_factory; i; i = i->next) { + f = i->data; + if (strcmp(f->usbdevice_name, driver) == 0) { + break; + } } - if (info == NULL) { + if (i == NULL) { #if 0 /* no error because some drivers are not converted (yet) */ error_report("usbdevice %s not found", driver); @@ -469,12 +558,37 @@ USBDevice *usbdevice_create(const char *cmdline) return NULL; } - if (!usb->usbdevice_init) { + if (!f->usbdevice_init) { if (*params) { error_report("usbdevice %s accepts no params", driver); return NULL; } - return usb_create_simple(bus, usb->qdev.name); + return usb_create_simple(bus, f->name); } - return usb->usbdevice_init(params); + return f->usbdevice_init(params); +} + +static void usb_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->bus_info = &usb_bus_info; + k->init = usb_qdev_init; + k->unplug = qdev_simple_unplug_cb; + k->exit = usb_qdev_exit; } + +static TypeInfo usb_device_type_info = { + .name = TYPE_USB_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(USBDevice), + .abstract = true, + .class_size = sizeof(USBDeviceClass), + .class_init = usb_device_class_init, +}; + +static void usb_register_devices(void) +{ + type_register_static(&usb_device_type_info); +} + +device_init(usb_register_devices); diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c index cd349f3f17..881da3002e 100644 --- a/hw/usb-ccid.c +++ b/hw/usb-ccid.c @@ -269,7 +269,6 @@ typedef struct USBCCIDState { USBDevice dev; CCIDBus bus; CCIDCardState *card; - CCIDCardInfo *cardinfo; /* caching the info pointer */ BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */ uint32_t bulk_in_pending_start; uint32_t bulk_in_pending_end; /* first free */ @@ -468,6 +467,43 @@ static const USBDesc desc_ccid = { .str = desc_strings, }; +static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len) +{ + CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->get_atr) { + return cc->get_atr(card, len); + } + return NULL; +} + +static void ccid_card_apdu_from_guest(CCIDCardState *card, + const uint8_t *apdu, + uint32_t len) +{ + CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->apdu_from_guest) { + cc->apdu_from_guest(card, apdu, len); + } +} + +static int ccid_card_exitfn(CCIDCardState *card) +{ + CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->exitfn) { + return cc->exitfn(card); + } + return 0; +} + +static int ccid_card_initfn(CCIDCardState *card) +{ + CCIDCardClass *cc = CCID_CARD_GET_CLASS(card); + if (cc->initfn) { + return cc->initfn(card); + } + return 0; +} + static bool ccid_has_pending_answers(USBCCIDState *s) { return s->pending_answers_num > 0; @@ -611,14 +647,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request, } switch (request) { - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; - /* Class specific requests. */ case InterfaceOutClass | CCID_CONTROL_ABORT: DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n"); @@ -749,7 +777,7 @@ static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv) uint32_t len = 0; if (s->card) { - atr = s->cardinfo->get_atr(s->card, &len); + atr = ccid_card_get_atr(s->card, &len); } ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len); } @@ -835,7 +863,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv) recv->hdr.bSeq, len); ccid_add_pending_answer(s, (CCID_Header *)recv); if (s->card) { - s->cardinfo->apdu_from_guest(s->card, recv->abData, len); + ccid_card_apdu_from_guest(s->card, recv->abData, len); } else { DPRINTF(s, D_WARN, "warning: discarded apdu\n"); } @@ -1121,26 +1149,21 @@ void ccid_card_card_inserted(CCIDCardState *card) static int ccid_card_exit(DeviceState *qdev) { int ret = 0; - CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev); - CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info); + CCIDCardState *card = CCID_CARD(qdev); USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); if (ccid_card_inserted(s)) { ccid_card_card_removed(card); } - if (info->exitfn) { - ret = info->exitfn(card); - } + ret = ccid_card_exitfn(card); s->card = NULL; - s->cardinfo = NULL; return ret; } -static int ccid_card_init(DeviceState *qdev, DeviceInfo *base) +static int ccid_card_init(DeviceState *qdev) { - CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev); - CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base); + CCIDCardState *card = CCID_CARD(qdev); USBCCIDState *s = DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent); int ret = 0; @@ -1154,22 +1177,13 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base) error_report("Warning: usb-ccid card already full, not adding"); return -1; } - ret = info->initfn ? info->initfn(card) : ret; + ret = ccid_card_initfn(card); if (ret == 0) { s->card = card; - s->cardinfo = info; } return ret; } -void ccid_card_qdev_register(CCIDCardInfo *card) -{ - card->qdev.bus_info = &ccid_bus_info; - card->qdev.init = ccid_card_init; - card->qdev.exit = ccid_card_exit; - qdev_register(&card->qdev); -} - static int ccid_initfn(USBDevice *dev) { USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev); @@ -1178,7 +1192,6 @@ static int ccid_initfn(USBDevice *dev) qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL); s->bus.qbus.allow_hotplug = 1; s->card = NULL; - s->cardinfo = NULL; s->migration_state = MIGRATION_NONE; s->migration_target_ip = 0; s->migration_target_port = 0; @@ -1294,28 +1307,57 @@ static VMStateDescription ccid_vmstate = { } }; -static struct USBDeviceInfo ccid_info = { - .product_desc = "QEMU USB CCID", - .qdev.name = CCID_DEV_NAME, - .qdev.desc = "CCID Rev 1.1 smartcard reader", - .qdev.size = sizeof(USBCCIDState), - .init = ccid_initfn, - .usb_desc = &desc_ccid, - .handle_packet = usb_generic_handle_packet, - .handle_reset = ccid_handle_reset, - .handle_control = ccid_handle_control, - .handle_data = ccid_handle_data, - .handle_destroy = ccid_handle_destroy, - .usbdevice_name = "ccid", - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.vmsd = &ccid_vmstate, +static Property ccid_properties[] = { + DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ccid_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = ccid_initfn; + uc->product_desc = "QEMU USB CCID"; + uc->usb_desc = &desc_ccid; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = ccid_handle_reset; + uc->handle_control = ccid_handle_control; + uc->handle_data = ccid_handle_data; + uc->handle_destroy = ccid_handle_destroy; + dc->desc = "CCID Rev 1.1 smartcard reader"; + dc->vmsd = &ccid_vmstate; + dc->props = ccid_properties; +} + +static TypeInfo ccid_info = { + .name = CCID_DEV_NAME, + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBCCIDState), + .class_init = ccid_class_initfn, +}; + +static void ccid_card_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->bus_info = &ccid_bus_info; + k->init = ccid_card_init; + k->exit = ccid_card_exit; +} + +static TypeInfo ccid_card_type_info = { + .name = TYPE_CCID_CARD, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CCIDCardState), + .abstract = true, + .class_size = sizeof(CCIDCardClass), + .class_init = ccid_card_class_init, }; static void ccid_register_devices(void) { - usb_qdev_register(&ccid_info); + type_register_static(&ccid_card_type_info); + type_register_static(&ccid_info); + usb_legacy_register(CCID_DEV_NAME, "ccid", NULL); } device_init(ccid_register_devices) diff --git a/hw/usb-desc.c b/hw/usb-desc.c index ae2d384bb3..3c3ed6a802 100644 --- a/hw/usb-desc.c +++ b/hw/usb-desc.c @@ -192,9 +192,10 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) { - uint8_t bLength = 0x07; + uint8_t bLength = ep->is_audio ? 0x09 : 0x07; + uint8_t extralen = ep->extra ? ep->extra[0] : 0; - if (len < bLength) { + if (len < bLength + extralen) { return -1; } @@ -205,8 +206,15 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) dest[0x04] = usb_lo(ep->wMaxPacketSize); dest[0x05] = usb_hi(ep->wMaxPacketSize); dest[0x06] = ep->bInterval; + if (ep->is_audio) { + dest[0x07] = ep->bRefresh; + dest[0x08] = ep->bSynchAddress; + } + if (ep->extra) { + memcpy(dest + bLength, ep->extra, extralen); + } - return bLength; + return bLength + extralen; } int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) @@ -223,9 +231,114 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) /* ------------------------------------------------------------------ */ +static void usb_desc_ep_init(USBDevice *dev) +{ + const USBDescIface *iface; + int i, e, pid, ep; + + usb_ep_init(dev); + for (i = 0; i < dev->ninterfaces; i++) { + iface = dev->ifaces[i]; + if (iface == NULL) { + continue; + } + for (e = 0; e < iface->bNumEndpoints; e++) { + pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? + USB_TOKEN_IN : USB_TOKEN_OUT; + ep = iface->eps[e].bEndpointAddress & 0x0f; + usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03); + usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber); + usb_ep_set_max_packet_size(dev, pid, ep, + iface->eps[e].wMaxPacketSize); + } + } +} + +static const USBDescIface *usb_desc_find_interface(USBDevice *dev, + int nif, int alt) +{ + const USBDescIface *iface; + int g, i; + + if (!dev->config) { + return NULL; + } + for (g = 0; g < dev->config->nif_groups; g++) { + for (i = 0; i < dev->config->if_groups[g].nif; i++) { + iface = &dev->config->if_groups[g].ifs[i]; + if (iface->bInterfaceNumber == nif && + iface->bAlternateSetting == alt) { + return iface; + } + } + } + for (i = 0; i < dev->config->nif; i++) { + iface = &dev->config->ifs[i]; + if (iface->bInterfaceNumber == nif && + iface->bAlternateSetting == alt) { + return iface; + } + } + return NULL; +} + +static int usb_desc_set_interface(USBDevice *dev, int index, int value) +{ + const USBDescIface *iface; + int old; + + iface = usb_desc_find_interface(dev, index, value); + if (iface == NULL) { + return -1; + } + + old = dev->altsetting[index]; + dev->altsetting[index] = value; + dev->ifaces[index] = iface; + usb_desc_ep_init(dev); + + if (old != value) { + usb_device_set_interface(dev, index, old, value); + } + return 0; +} + +static int usb_desc_set_config(USBDevice *dev, int value) +{ + int i; + + if (value == 0) { + dev->configuration = 0; + dev->ninterfaces = 0; + dev->config = NULL; + } else { + for (i = 0; i < dev->device->bNumConfigurations; i++) { + if (dev->device->confs[i].bConfigurationValue == value) { + dev->configuration = value; + dev->ninterfaces = dev->device->confs[i].bNumInterfaces; + dev->config = dev->device->confs + i; + assert(dev->ninterfaces <= USB_MAX_INTERFACES); + } + } + if (i < dev->device->bNumConfigurations) { + return -1; + } + } + + for (i = 0; i < dev->ninterfaces; i++) { + usb_desc_set_interface(dev, i, 0); + } + for (; i < USB_MAX_INTERFACES; i++) { + dev->altsetting[i] = 0; + dev->ifaces[i] = NULL; + } + + return 0; +} + static void usb_desc_setdefaults(USBDevice *dev) { - const USBDesc *desc = dev->info->usb_desc; + const USBDesc *desc = usb_device_get_usb_desc(dev); assert(desc != NULL); switch (dev->speed) { @@ -237,12 +350,12 @@ static void usb_desc_setdefaults(USBDevice *dev) dev->device = desc->high; break; } - dev->config = dev->device->confs; + usb_desc_set_config(dev, 0); } void usb_desc_init(USBDevice *dev) { - const USBDesc *desc = dev->info->usb_desc; + const USBDesc *desc = usb_device_get_usb_desc(dev); assert(desc != NULL); dev->speed = USB_SPEED_FULL; @@ -258,7 +371,7 @@ void usb_desc_init(USBDevice *dev) void usb_desc_attach(USBDevice *dev) { - const USBDesc *desc = dev->info->usb_desc; + const USBDesc *desc = usb_device_get_usb_desc(dev); assert(desc != NULL); if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { @@ -267,7 +380,7 @@ void usb_desc_attach(USBDevice *dev) dev->speed = USB_SPEED_FULL; } else { fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n", - dev->info->product_desc); + usb_device_get_product_desc(dev)); return; } usb_desc_setdefaults(dev); @@ -323,7 +436,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) str = usb_desc_get_string(dev, index); if (str == NULL) { - str = dev->info->usb_desc->str[index]; + str = usb_device_get_usb_desc(dev)->str[index]; if (str == NULL) { return 0; } @@ -342,7 +455,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len) int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len) { - const USBDesc *desc = dev->info->usb_desc; + const USBDesc *desc = usb_device_get_usb_desc(dev); const USBDescDevice *other_dev; uint8_t buf[256]; uint8_t type = value >> 8; @@ -350,9 +463,9 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len int ret = -1; if (dev->speed == USB_SPEED_HIGH) { - other_dev = dev->info->usb_desc->full; + other_dev = usb_device_get_usb_desc(dev)->full; } else { - other_dev = dev->info->usb_desc->high; + other_dev = usb_device_get_usb_desc(dev)->high; } switch(type) { @@ -407,8 +520,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len int usb_desc_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { - const USBDesc *desc = dev->info->usb_desc; - int i, ret = -1; + const USBDesc *desc = usb_device_get_usb_desc(dev); + int ret = -1; assert(desc != NULL); switch(request) { @@ -427,12 +540,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, ret = 1; break; case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - for (i = 0; i < dev->device->bNumConfigurations; i++) { - if (dev->device->confs[i].bConfigurationValue == value) { - dev->config = dev->device->confs + i; - ret = 0; - } - } + ret = usb_desc_set_config(dev, value); trace_usb_set_config(dev->addr, value, ret); break; @@ -461,6 +569,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p, } trace_usb_set_device_feature(dev->addr, value, ret); break; + + case InterfaceRequest | USB_REQ_GET_INTERFACE: + if (index < 0 || index >= dev->ninterfaces) { + break; + } + data[0] = dev->altsetting[index]; + ret = 1; + break; + case InterfaceOutRequest | USB_REQ_SET_INTERFACE: + ret = usb_desc_set_interface(dev, index, value); + trace_usb_set_interface(dev->addr, index, value, ret); + break; + } return ret; } diff --git a/hw/usb-desc.h b/hw/usb-desc.h index 5c14e4abdc..d6e07ea5d2 100644 --- a/hw/usb-desc.h +++ b/hw/usb-desc.h @@ -71,6 +71,11 @@ struct USBDescEndpoint { uint8_t bmAttributes; uint16_t wMaxPacketSize; uint8_t bInterval; + uint8_t bRefresh; + uint8_t bSynchAddress; + + uint8_t is_audio; /* has bRefresh + bSynchAddress */ + uint8_t *extra; }; struct USBDescOther { diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c index 7c926c0d47..75ef71e69e 100644 --- a/hw/usb-ehci.c +++ b/hw/usb-ehci.c @@ -715,7 +715,8 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev) EHCIQueue *q, *tmp; QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { - if (q->packet.owner != dev) { + if (q->packet.owner == NULL || + q->packet.owner->dev != dev) { continue; } ehci_free_queue(q); @@ -2262,30 +2263,46 @@ static Property ehci_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static PCIDeviceInfo ehci_info[] = { - { - .qdev.name = "usb-ehci", - .qdev.size = sizeof(EHCIState), - .qdev.vmsd = &vmstate_ehci, - .init = usb_ehci_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */ - .revision = 0x10, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = ehci_properties, - },{ - .qdev.name = "ich9-usb-ehci1", - .qdev.size = sizeof(EHCIState), - .qdev.vmsd = &vmstate_ehci, - .init = usb_ehci_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1, - .revision = 0x03, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = ehci_properties, - },{ - /* end of list */ - } +static void ehci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_ehci_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */ + k->revision = 0x10; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_ehci; + dc->props = ehci_properties; +} + +static TypeInfo ehci_info = { + .name = "usb-ehci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EHCIState), + .class_init = ehci_class_init, +}; + +static void ich9_ehci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_ehci_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1; + k->revision = 0x03; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_ehci; + dc->props = ehci_properties; +} + +static TypeInfo ich9_ehci_info = { + .name = "ich9-usb-ehci1", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(EHCIState), + .class_init = ich9_ehci_class_init, }; static int usb_ehci_initfn(PCIDevice *dev) @@ -2361,7 +2378,8 @@ static int usb_ehci_initfn(PCIDevice *dev) static void ehci_register(void) { - pci_qdev_register_many(ehci_info); + type_register_static(&ehci_info); + type_register_static(&ich9_ehci_info); } device_init(ehci_register); diff --git a/hw/usb-hid.c b/hw/usb-hid.c index a110c74dda..3c4e45da70 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -384,13 +384,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; /* hid specific requests */ case InterfaceRequest | USB_REQ_GET_DESCRIPTOR: switch (value >> 8) { @@ -560,53 +553,81 @@ static const VMStateDescription vmstate_usb_kbd = { } }; -static struct USBDeviceInfo hid_info[] = { - { - .product_desc = "QEMU USB Tablet", - .qdev.name = "usb-tablet", - .usbdevice_name = "tablet", - .qdev.size = sizeof(USBHIDState), - .qdev.vmsd = &vmstate_usb_ptr, - .usb_desc = &desc_tablet, - .init = usb_tablet_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_hid_handle_reset, - .handle_control = usb_hid_handle_control, - .handle_data = usb_hid_handle_data, - .handle_destroy = usb_hid_handle_destroy, - },{ - .product_desc = "QEMU USB Mouse", - .qdev.name = "usb-mouse", - .usbdevice_name = "mouse", - .qdev.size = sizeof(USBHIDState), - .qdev.vmsd = &vmstate_usb_ptr, - .usb_desc = &desc_mouse, - .init = usb_mouse_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_hid_handle_reset, - .handle_control = usb_hid_handle_control, - .handle_data = usb_hid_handle_data, - .handle_destroy = usb_hid_handle_destroy, - },{ - .product_desc = "QEMU USB Keyboard", - .qdev.name = "usb-kbd", - .usbdevice_name = "keyboard", - .qdev.size = sizeof(USBHIDState), - .qdev.vmsd = &vmstate_usb_kbd, - .usb_desc = &desc_keyboard, - .init = usb_keyboard_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_hid_handle_reset, - .handle_control = usb_hid_handle_control, - .handle_data = usb_hid_handle_data, - .handle_destroy = usb_hid_handle_destroy, - },{ - /* end of list */ - } +static void usb_hid_class_initfn(ObjectClass *klass, void *data) +{ + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_hid_handle_reset; + uc->handle_control = usb_hid_handle_control; + uc->handle_data = usb_hid_handle_data; + uc->handle_destroy = usb_hid_handle_destroy; +} + +static void usb_tablet_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + usb_hid_class_initfn(klass, data); + uc->init = usb_tablet_initfn; + uc->product_desc = "QEMU USB Tablet"; + uc->usb_desc = &desc_tablet; + dc->vmsd = &vmstate_usb_ptr; +} + +static TypeInfo usb_tablet_info = { + .name = "usb-tablet", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBHIDState), + .class_init = usb_tablet_class_initfn, +}; + +static void usb_mouse_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + usb_hid_class_initfn(klass, data); + uc->init = usb_mouse_initfn; + uc->product_desc = "QEMU USB Mouse"; + uc->usb_desc = &desc_mouse; + dc->vmsd = &vmstate_usb_ptr; +} + +static TypeInfo usb_mouse_info = { + .name = "usb-mouse", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBHIDState), + .class_init = usb_mouse_class_initfn, +}; + +static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + usb_hid_class_initfn(klass, data); + uc->init = usb_keyboard_initfn; + uc->product_desc = "QEMU USB Keyboard"; + uc->usb_desc = &desc_keyboard; + dc->vmsd = &vmstate_usb_kbd; +} + +static TypeInfo usb_keyboard_info = { + .name = "usb-kbd", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBHIDState), + .class_init = usb_keyboard_class_initfn, }; static void usb_hid_register_devices(void) { - usb_qdev_register_many(hid_info); + type_register_static(&usb_tablet_info); + usb_legacy_register("usb-tablet", "tablet", NULL); + type_register_static(&usb_mouse_info); + usb_legacy_register("usb-mouse", "mouse", NULL); + type_register_static(&usb_keyboard_info); + usb_legacy_register("usb-kbd", "keyboard", NULL); } device_init(usb_hid_register_devices) diff --git a/hw/usb-hub.c b/hw/usb-hub.c index e1959372e7..956b020eed 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -258,13 +258,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p, } ret = 0; break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; /* usb specific requests */ case GetHubStatus: data[0] = 0; @@ -540,23 +533,32 @@ static const VMStateDescription vmstate_usb_hub = { } }; -static struct USBDeviceInfo hub_info = { - .product_desc = "QEMU USB Hub", - .qdev.name = "usb-hub", - .qdev.fw_name = "hub", - .qdev.size = sizeof(USBHubState), - .qdev.vmsd = &vmstate_usb_hub, - .usb_desc = &desc_hub, - .init = usb_hub_initfn, - .handle_packet = usb_hub_handle_packet, - .handle_reset = usb_hub_handle_reset, - .handle_control = usb_hub_handle_control, - .handle_data = usb_hub_handle_data, - .handle_destroy = usb_hub_handle_destroy, +static void usb_hub_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_hub_initfn; + uc->product_desc = "QEMU USB Hub"; + uc->usb_desc = &desc_hub; + uc->handle_packet = usb_hub_handle_packet; + uc->handle_reset = usb_hub_handle_reset; + uc->handle_control = usb_hub_handle_control; + uc->handle_data = usb_hub_handle_data; + uc->handle_destroy = usb_hub_handle_destroy; + dc->fw_name = "hub"; + dc->vmsd = &vmstate_usb_hub; +} + +static TypeInfo hub_info = { + .name = "usb-hub", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBHubState), + .class_init = usb_hub_class_initfn, }; static void usb_hub_register_devices(void) { - usb_qdev_register(&hub_info); + type_register_static(&hub_info); } device_init(usb_hub_register_devices) diff --git a/hw/usb-msd.c b/hw/usb-msd.c index e42729699d..6153376f3f 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -306,19 +306,9 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ret = 0; break; - case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; /* Class specific requests. */ case ClassInterfaceOutRequest | MassStorageReset: /* Reset state ready for the next CBW. */ @@ -646,32 +636,42 @@ static const VMStateDescription vmstate_usb_msd = { } }; -static struct USBDeviceInfo msd_info = { - .product_desc = "QEMU USB MSD", - .qdev.name = "usb-storage", - .qdev.fw_name = "storage", - .qdev.size = sizeof(MSDState), - .qdev.vmsd = &vmstate_usb_msd, - .usb_desc = &desc, - .init = usb_msd_initfn, - .handle_packet = usb_generic_handle_packet, - .cancel_packet = usb_msd_cancel_io, - .handle_attach = usb_desc_attach, - .handle_reset = usb_msd_handle_reset, - .handle_control = usb_msd_handle_control, - .handle_data = usb_msd_handle_data, - .usbdevice_name = "disk", - .usbdevice_init = usb_msd_init, - .qdev.props = (Property[]) { - DEFINE_BLOCK_PROPERTIES(MSDState, conf), - DEFINE_PROP_STRING("serial", MSDState, serial), - DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), - DEFINE_PROP_END_OF_LIST(), - }, +static Property msd_properties[] = { + DEFINE_BLOCK_PROPERTIES(MSDState, conf), + DEFINE_PROP_STRING("serial", MSDState, serial), + DEFINE_PROP_BIT("removable", MSDState, removable, 0, false), + DEFINE_PROP_END_OF_LIST(), +}; + +static void usb_msd_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn; + uc->product_desc = "QEMU USB MSD"; + uc->usb_desc = &desc; + uc->handle_packet = usb_generic_handle_packet; + uc->cancel_packet = usb_msd_cancel_io; + uc->handle_attach = usb_desc_attach; + uc->handle_reset = usb_msd_handle_reset; + uc->handle_control = usb_msd_handle_control; + uc->handle_data = usb_msd_handle_data; + dc->fw_name = "storage"; + dc->vmsd = &vmstate_usb_msd; + dc->props = msd_properties; +} + +static TypeInfo msd_info = { + .name = "usb-storage", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(MSDState), + .class_init = usb_msd_class_initfn, }; static void usb_msd_register_devices(void) { - usb_qdev_register(&msd_info); + type_register_static(&msd_info); + usb_legacy_register("usb-storage", "disk", usb_msd_init); } device_init(usb_msd_register_devices) diff --git a/hw/usb-musb.c b/hw/usb-musb.c index 01e2e7c389..4f528d25e5 100644 --- a/hw/usb-musb.c +++ b/hw/usb-musb.c @@ -812,7 +812,8 @@ static void musb_async_cancel_device(MUSBState *s, USBDevice *dev) for (ep = 0; ep < 16; ep++) { for (dir = 0; dir < 2; dir++) { - if (s->ep[ep].packey[dir].p.owner != dev) { + if (s->ep[ep].packey[dir].p.owner == NULL || + s->ep[ep].packey[dir].p.owner->dev != dev) { continue; } usb_cancel_packet(&s->ep[ep].packey[dir].p); diff --git a/hw/usb-net.c b/hw/usb-net.c index f91fa32334..e2111413b4 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -71,9 +71,6 @@ enum usbstring_idx { #define USB_CDC_UNION_TYPE 0x06 /* union_desc */ #define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */ -#define USB_DT_CS_INTERFACE 0x24 -#define USB_DT_CS_ENDPOINT 0x25 - #define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00 #define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01 #define USB_CDC_REQ_SET_LINE_CODING 0x20 @@ -1098,17 +1095,6 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p, #endif break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - case InterfaceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; - default: fail: fprintf(stderr, "usbnet: failed control transaction: " @@ -1351,7 +1337,7 @@ static int usb_net_initfn(USBDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, - s->dev.qdev.info->name, s->dev.qdev.id, s); + object_get_typename(OBJECT(s)), s->dev.qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); snprintf(s->usbstring_mac, sizeof(s->usbstring_mac), "%02x%02x%02x%02x%02x%02x", @@ -1399,29 +1385,39 @@ static const VMStateDescription vmstate_usb_net = { .unmigratable = 1, }; -static struct USBDeviceInfo net_info = { - .product_desc = "QEMU USB Network Interface", - .qdev.name = "usb-net", - .qdev.fw_name = "network", - .qdev.size = sizeof(USBNetState), - .qdev.vmsd = &vmstate_usb_net, - .usb_desc = &desc_net, - .init = usb_net_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_net_handle_reset, - .handle_control = usb_net_handle_control, - .handle_data = usb_net_handle_data, - .handle_destroy = usb_net_handle_destroy, - .usbdevice_name = "net", - .usbdevice_init = usb_net_init, - .qdev.props = (Property[]) { - DEFINE_NIC_PROPERTIES(USBNetState, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property net_properties[] = { + DEFINE_NIC_PROPERTIES(USBNetState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void usb_net_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_net_initfn; + uc->product_desc = "QEMU USB Network Interface"; + uc->usb_desc = &desc_net; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_net_handle_reset; + uc->handle_control = usb_net_handle_control; + uc->handle_data = usb_net_handle_data; + uc->handle_destroy = usb_net_handle_destroy; + dc->fw_name = "network"; + dc->vmsd = &vmstate_usb_net; + dc->props = net_properties; +} + +static TypeInfo net_info = { + .name = "usb-net", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBNetState), + .class_init = usb_net_class_initfn, }; static void usb_net_register_devices(void) { - usb_qdev_register(&net_info); + type_register_static(&net_info); + usb_legacy_register("usb-net", "net", usb_net_init); } device_init(usb_net_register_devices) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 81488c48e2..425030f141 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -1707,7 +1707,9 @@ static void ohci_mem_write(void *opaque, static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev) { - if (ohci->async_td && ohci->usb_packet.owner == dev) { + if (ohci->async_td && + ohci->usb_packet.owner != NULL && + ohci->usb_packet.owner->dev == dev) { usb_cancel_packet(&ohci->usb_packet); ohci->async_td = 0; } @@ -1775,7 +1777,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev, memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256); ohci->localmem_base = localmem_base; - ohci->name = dev->info->name; + ohci->name = object_get_typename(OBJECT(dev)); usb_packet_init(&ohci->usb_packet); ohci->async_td = 0; @@ -1834,37 +1836,59 @@ static int ohci_init_pxa(SysBusDevice *dev) return 0; } -static PCIDeviceInfo ohci_pci_info = { - .qdev.name = "pci-ohci", - .qdev.desc = "Apple USB Controller", - .qdev.size = sizeof(OHCIPCIState), - .init = usb_ohci_initfn_pci, - .vendor_id = PCI_VENDOR_ID_APPLE, - .device_id = PCI_DEVICE_ID_APPLE_IPID_USB, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = (Property[]) { - DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), - DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), - DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), - DEFINE_PROP_END_OF_LIST(), - }, +static Property ohci_pci_properties[] = { + DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus), + DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3), + DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0), + DEFINE_PROP_END_OF_LIST(), }; -static SysBusDeviceInfo ohci_sysbus_info = { - .init = ohci_init_pxa, - .qdev.name = "sysbus-ohci", - .qdev.desc = "OHCI USB Controller", - .qdev.size = sizeof(OHCISysBusState), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), - DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3), - DEFINE_PROP_END_OF_LIST(), - } +static void ohci_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_ohci_initfn_pci; + k->vendor_id = PCI_VENDOR_ID_APPLE; + k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->desc = "Apple USB Controller"; + dc->props = ohci_pci_properties; +} + +static TypeInfo ohci_pci_info = { + .name = "pci-ohci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(OHCIPCIState), + .class_init = ohci_pci_class_init, +}; + +static Property ohci_sysbus_properties[] = { + DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), + DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ohci_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + + sbc->init = ohci_init_pxa; + dc->desc = "OHCI USB Controller"; + dc->props = ohci_sysbus_properties; +} + +static TypeInfo ohci_sysbus_info = { + .name = "sysbus-ohci", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OHCISysBusState), + .class_init = ohci_sysbus_class_init, }; static void ohci_register(void) { - pci_qdev_register(&ohci_pci_info); - sysbus_register_withprop(&ohci_sysbus_info); + type_register_static(&ohci_pci_info); + type_register_static(&ohci_sysbus_info); } device_init(ohci_register); diff --git a/hw/usb-serial.c b/hw/usb-serial.c index 7dbf6dfc6d..c2cb6d24e8 100644 --- a/hw/usb-serial.c +++ b/hw/usb-serial.c @@ -233,13 +233,6 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case InterfaceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: ret = 0; break; @@ -577,49 +570,69 @@ static const VMStateDescription vmstate_usb_serial = { .unmigratable = 1, }; -static struct USBDeviceInfo serial_info = { - .product_desc = "QEMU USB Serial", - .qdev.name = "usb-serial", - .qdev.size = sizeof(USBSerialState), - .qdev.vmsd = &vmstate_usb_serial, - .usb_desc = &desc_serial, - .init = usb_serial_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_serial_handle_reset, - .handle_control = usb_serial_handle_control, - .handle_data = usb_serial_handle_data, - .handle_destroy = usb_serial_handle_destroy, - .usbdevice_name = "serial", - .usbdevice_init = usb_serial_init, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", USBSerialState, cs), - DEFINE_PROP_END_OF_LIST(), - }, +static Property serial_properties[] = { + DEFINE_PROP_CHR("chardev", USBSerialState, cs), + DEFINE_PROP_END_OF_LIST(), }; -static struct USBDeviceInfo braille_info = { - .product_desc = "QEMU USB Braille", - .qdev.name = "usb-braille", - .qdev.size = sizeof(USBSerialState), - .qdev.vmsd = &vmstate_usb_serial, - .usb_desc = &desc_braille, - .init = usb_serial_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_serial_handle_reset, - .handle_control = usb_serial_handle_control, - .handle_data = usb_serial_handle_data, - .handle_destroy = usb_serial_handle_destroy, - .usbdevice_name = "braille", - .usbdevice_init = usb_braille_init, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", USBSerialState, cs), - DEFINE_PROP_END_OF_LIST(), - }, +static void usb_serial_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_serial_initfn; + uc->product_desc = "QEMU USB Serial"; + uc->usb_desc = &desc_serial; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_serial_handle_reset; + uc->handle_control = usb_serial_handle_control; + uc->handle_data = usb_serial_handle_data; + uc->handle_destroy = usb_serial_handle_destroy; + dc->vmsd = &vmstate_usb_serial; + dc->props = serial_properties; +} + +static TypeInfo serial_info = { + .name = "usb-serial", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBSerialState), + .class_init = usb_serial_class_initfn, +}; + +static Property braille_properties[] = { + DEFINE_PROP_CHR("chardev", USBSerialState, cs), + DEFINE_PROP_END_OF_LIST(), +}; + +static void usb_braille_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_serial_initfn; + uc->product_desc = "QEMU USB Braille"; + uc->usb_desc = &desc_braille; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_serial_handle_reset; + uc->handle_control = usb_serial_handle_control; + uc->handle_data = usb_serial_handle_data; + uc->handle_destroy = usb_serial_handle_destroy; + dc->vmsd = &vmstate_usb_serial; + dc->props = braille_properties; +} + +static TypeInfo braille_info = { + .name = "usb-braille", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBSerialState), + .class_init = usb_braille_class_initfn, }; static void usb_serial_register_devices(void) { - usb_qdev_register(&serial_info); - usb_qdev_register(&braille_info); + type_register_static(&serial_info); + usb_legacy_register("usb-serial", "serial", usb_serial_init); + type_register_static(&braille_info); + usb_legacy_register("usb-braille", "braille", usb_braille_init); } device_init(usb_serial_register_devices) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index f8912e2b0b..cddcc8927a 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -245,7 +245,8 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) UHCIAsync *curr, *n; QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) { - if (curr->packet.owner != dev) { + if (curr->packet.owner == NULL || + curr->packet.owner->dev != dev) { continue; } uhci_async_unlink(s, curr); @@ -1191,78 +1192,143 @@ static Property uhci_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static PCIDeviceInfo uhci_info[] = { - { - .qdev.name = "piix3-usb-uhci", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_common_initfn, - .exit = usb_uhci_exit, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371SB_2, - .revision = 0x01, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - .qdev.name = "piix4-usb-uhci", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_common_initfn, - .exit = usb_uhci_exit, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82371AB_2, - .revision = 0x01, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - .qdev.name = "vt82c686b-usb-uhci", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_vt82c686b_initfn, - .exit = usb_uhci_exit, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_UHCI, - .revision = 0x01, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - .qdev.name = "ich9-usb-uhci1", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_common_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1, - .revision = 0x03, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - .qdev.name = "ich9-usb-uhci2", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_common_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2, - .revision = 0x03, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - .qdev.name = "ich9-usb-uhci3", - .qdev.size = sizeof(UHCIState), - .qdev.vmsd = &vmstate_uhci, - .init = usb_uhci_common_initfn, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3, - .revision = 0x03, - .class_id = PCI_CLASS_SERIAL_USB, - .qdev.props = uhci_properties, - },{ - /* end of list */ - } +static void piix3_uhci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_common_initfn; + k->exit = usb_uhci_exit; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2; + k->revision = 0x01; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo piix3_uhci_info = { + .name = "piix3-usb-uhci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = piix3_uhci_class_init, +}; + +static void piix4_uhci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_common_initfn; + k->exit = usb_uhci_exit; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2; + k->revision = 0x01; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo piix4_uhci_info = { + .name = "piix4-usb-uhci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = piix4_uhci_class_init, +}; + +static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_vt82c686b_initfn; + k->exit = usb_uhci_exit; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_UHCI; + k->revision = 0x01; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo vt82c686b_uhci_info = { + .name = "vt82c686b-usb-uhci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = vt82c686b_uhci_class_init, +}; + +static void ich9_uhci1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_common_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1; + k->revision = 0x03; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo ich9_uhci1_info = { + .name = "ich9-usb-uhci1", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = ich9_uhci1_class_init, +}; + +static void ich9_uhci2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_common_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2; + k->revision = 0x03; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo ich9_uhci2_info = { + .name = "ich9-usb-uhci2", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = ich9_uhci2_class_init, +}; + +static void ich9_uhci3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = usb_uhci_common_initfn; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3; + k->revision = 0x03; + k->class_id = PCI_CLASS_SERIAL_USB; + dc->vmsd = &vmstate_uhci; + dc->props = uhci_properties; +} + +static TypeInfo ich9_uhci3_info = { + .name = "ich9-usb-uhci3", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(UHCIState), + .class_init = ich9_uhci3_class_init, }; static void uhci_register(void) { - pci_qdev_register_many(uhci_info); + type_register_static(&piix3_uhci_info); + type_register_static(&piix4_uhci_info); + type_register_static(&vt82c686b_uhci_info); + type_register_static(&ich9_uhci1_info); + type_register_static(&ich9_uhci2_info); + type_register_static(&ich9_uhci3_info); } device_init(uhci_register); diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c index 25580067f2..14de14d5f7 100644 --- a/hw/usb-wacom.c +++ b/hw/usb-wacom.c @@ -263,13 +263,6 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p, ret = 0; switch (request) { - case DeviceRequest | USB_REQ_GET_INTERFACE: - data[0] = 0; - ret = 1; - break; - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - ret = 0; - break; case WACOM_SET_REPORT: if (s->mouse_grabbed) { qemu_remove_mouse_event_handler(s->eh_entry); @@ -356,24 +349,33 @@ static const VMStateDescription vmstate_usb_wacom = { .unmigratable = 1, }; -static struct USBDeviceInfo wacom_info = { - .product_desc = "QEMU PenPartner Tablet", - .qdev.name = "usb-wacom-tablet", - .qdev.desc = "QEMU PenPartner Tablet", - .usbdevice_name = "wacom-tablet", - .usb_desc = &desc_wacom, - .qdev.size = sizeof(USBWacomState), - .qdev.vmsd = &vmstate_usb_wacom, - .init = usb_wacom_initfn, - .handle_packet = usb_generic_handle_packet, - .handle_reset = usb_wacom_handle_reset, - .handle_control = usb_wacom_handle_control, - .handle_data = usb_wacom_handle_data, - .handle_destroy = usb_wacom_handle_destroy, +static void usb_wacom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->product_desc = "QEMU PenPartner Tablet"; + uc->usb_desc = &desc_wacom; + uc->init = usb_wacom_initfn; + uc->handle_packet = usb_generic_handle_packet; + uc->handle_reset = usb_wacom_handle_reset; + uc->handle_control = usb_wacom_handle_control; + uc->handle_data = usb_wacom_handle_data; + uc->handle_destroy = usb_wacom_handle_destroy; + dc->desc = "QEMU PenPartner Tablet"; + dc->vmsd = &vmstate_usb_wacom; +} + +static TypeInfo wacom_info = { + .name = "usb-wacom-tablet", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(USBWacomState), + .class_init = usb_wacom_class_init, }; static void usb_wacom_register_devices(void) { - usb_qdev_register(&wacom_info); + type_register_static(&wacom_info); + usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL); } device_init(usb_wacom_register_devices) diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c new file mode 100644 index 0000000000..37e887c431 --- /dev/null +++ b/hw/usb-xhci.c @@ -0,0 +1,2759 @@ +/* + * USB xHCI controller emulation + * + * Copyright (c) 2011 Securiforest + * Date: 2011-05-11 ; Author: Hector Martin <hector@marcansoft.com> + * Based on usb-ohci.c, emulates Renesas NEC USB 3.0 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ +#include "hw.h" +#include "qemu-timer.h" +#include "usb.h" +#include "pci.h" +#include "qdev-addr.h" +#include "msi.h" + +//#define DEBUG_XHCI +//#define DEBUG_DATA + +#ifdef DEBUG_XHCI +#define DPRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DPRINTF(...) do {} while (0) +#endif +#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ + __func__, __LINE__); abort(); } while (0) + +#define MAXSLOTS 8 +#define MAXINTRS 1 + +#define USB2_PORTS 4 +#define USB3_PORTS 4 + +#define MAXPORTS (USB2_PORTS+USB3_PORTS) + +#define TD_QUEUE 24 +#define BG_XFERS 8 +#define BG_PKTS 8 + +/* Very pessimistic, let's hope it's enough for all cases */ +#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS) +/* Do not deliver ER Full events. NEC's driver does some things not bound + * to the specs when it gets them */ +#define ER_FULL_HACK + +#define LEN_CAP 0x40 +#define OFF_OPER LEN_CAP +#define LEN_OPER (0x400 + 0x10 * MAXPORTS) +#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f) +#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20) +#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME) +#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20) + +/* must be power of 2 */ +#define LEN_REGS 0x2000 + +#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS +# error Increase LEN_REGS +#endif + +#if MAXINTRS > 1 +# error TODO: only one interrupter supported +#endif + +/* bit definitions */ +#define USBCMD_RS (1<<0) +#define USBCMD_HCRST (1<<1) +#define USBCMD_INTE (1<<2) +#define USBCMD_HSEE (1<<3) +#define USBCMD_LHCRST (1<<7) +#define USBCMD_CSS (1<<8) +#define USBCMD_CRS (1<<9) +#define USBCMD_EWE (1<<10) +#define USBCMD_EU3S (1<<11) + +#define USBSTS_HCH (1<<0) +#define USBSTS_HSE (1<<2) +#define USBSTS_EINT (1<<3) +#define USBSTS_PCD (1<<4) +#define USBSTS_SSS (1<<8) +#define USBSTS_RSS (1<<9) +#define USBSTS_SRE (1<<10) +#define USBSTS_CNR (1<<11) +#define USBSTS_HCE (1<<12) + + +#define PORTSC_CCS (1<<0) +#define PORTSC_PED (1<<1) +#define PORTSC_OCA (1<<3) +#define PORTSC_PR (1<<4) +#define PORTSC_PLS_SHIFT 5 +#define PORTSC_PLS_MASK 0xf +#define PORTSC_PP (1<<9) +#define PORTSC_SPEED_SHIFT 10 +#define PORTSC_SPEED_MASK 0xf +#define PORTSC_SPEED_FULL (1<<10) +#define PORTSC_SPEED_LOW (2<<10) +#define PORTSC_SPEED_HIGH (3<<10) +#define PORTSC_SPEED_SUPER (4<<10) +#define PORTSC_PIC_SHIFT 14 +#define PORTSC_PIC_MASK 0x3 +#define PORTSC_LWS (1<<16) +#define PORTSC_CSC (1<<17) +#define PORTSC_PEC (1<<18) +#define PORTSC_WRC (1<<19) +#define PORTSC_OCC (1<<20) +#define PORTSC_PRC (1<<21) +#define PORTSC_PLC (1<<22) +#define PORTSC_CEC (1<<23) +#define PORTSC_CAS (1<<24) +#define PORTSC_WCE (1<<25) +#define PORTSC_WDE (1<<26) +#define PORTSC_WOE (1<<27) +#define PORTSC_DR (1<<30) +#define PORTSC_WPR (1<<31) + +#define CRCR_RCS (1<<0) +#define CRCR_CS (1<<1) +#define CRCR_CA (1<<2) +#define CRCR_CRR (1<<3) + +#define IMAN_IP (1<<0) +#define IMAN_IE (1<<1) + +#define ERDP_EHB (1<<3) + +#define TRB_SIZE 16 +typedef struct XHCITRB { + uint64_t parameter; + uint32_t status; + uint32_t control; + target_phys_addr_t addr; + bool ccs; +} XHCITRB; + + +typedef enum TRBType { + TRB_RESERVED = 0, + TR_NORMAL, + TR_SETUP, + TR_DATA, + TR_STATUS, + TR_ISOCH, + TR_LINK, + TR_EVDATA, + TR_NOOP, + CR_ENABLE_SLOT, + CR_DISABLE_SLOT, + CR_ADDRESS_DEVICE, + CR_CONFIGURE_ENDPOINT, + CR_EVALUATE_CONTEXT, + CR_RESET_ENDPOINT, + CR_STOP_ENDPOINT, + CR_SET_TR_DEQUEUE, + CR_RESET_DEVICE, + CR_FORCE_EVENT, + CR_NEGOTIATE_BW, + CR_SET_LATENCY_TOLERANCE, + CR_GET_PORT_BANDWIDTH, + CR_FORCE_HEADER, + CR_NOOP, + ER_TRANSFER = 32, + ER_COMMAND_COMPLETE, + ER_PORT_STATUS_CHANGE, + ER_BANDWIDTH_REQUEST, + ER_DOORBELL, + ER_HOST_CONTROLLER, + ER_DEVICE_NOTIFICATION, + ER_MFINDEX_WRAP, + /* vendor specific bits */ + CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48, + CR_VENDOR_NEC_FIRMWARE_REVISION = 49, + CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50, +} TRBType; + +#define CR_LINK TR_LINK + +typedef enum TRBCCode { + CC_INVALID = 0, + CC_SUCCESS, + CC_DATA_BUFFER_ERROR, + CC_BABBLE_DETECTED, + CC_USB_TRANSACTION_ERROR, + CC_TRB_ERROR, + CC_STALL_ERROR, + CC_RESOURCE_ERROR, + CC_BANDWIDTH_ERROR, + CC_NO_SLOTS_ERROR, + CC_INVALID_STREAM_TYPE_ERROR, + CC_SLOT_NOT_ENABLED_ERROR, + CC_EP_NOT_ENABLED_ERROR, + CC_SHORT_PACKET, + CC_RING_UNDERRUN, + CC_RING_OVERRUN, + CC_VF_ER_FULL, + CC_PARAMETER_ERROR, + CC_BANDWIDTH_OVERRUN, + CC_CONTEXT_STATE_ERROR, + CC_NO_PING_RESPONSE_ERROR, + CC_EVENT_RING_FULL_ERROR, + CC_INCOMPATIBLE_DEVICE_ERROR, + CC_MISSED_SERVICE_ERROR, + CC_COMMAND_RING_STOPPED, + CC_COMMAND_ABORTED, + CC_STOPPED, + CC_STOPPED_LENGTH_INVALID, + CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29, + CC_ISOCH_BUFFER_OVERRUN = 31, + CC_EVENT_LOST_ERROR, + CC_UNDEFINED_ERROR, + CC_INVALID_STREAM_ID_ERROR, + CC_SECONDARY_BANDWIDTH_ERROR, + CC_SPLIT_TRANSACTION_ERROR +} TRBCCode; + +#define TRB_C (1<<0) +#define TRB_TYPE_SHIFT 10 +#define TRB_TYPE_MASK 0x3f +#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK) + +#define TRB_EV_ED (1<<2) + +#define TRB_TR_ENT (1<<1) +#define TRB_TR_ISP (1<<2) +#define TRB_TR_NS (1<<3) +#define TRB_TR_CH (1<<4) +#define TRB_TR_IOC (1<<5) +#define TRB_TR_IDT (1<<6) +#define TRB_TR_TBC_SHIFT 7 +#define TRB_TR_TBC_MASK 0x3 +#define TRB_TR_BEI (1<<9) +#define TRB_TR_TLBPC_SHIFT 16 +#define TRB_TR_TLBPC_MASK 0xf +#define TRB_TR_FRAMEID_SHIFT 20 +#define TRB_TR_FRAMEID_MASK 0x7ff +#define TRB_TR_SIA (1<<31) + +#define TRB_TR_DIR (1<<16) + +#define TRB_CR_SLOTID_SHIFT 24 +#define TRB_CR_SLOTID_MASK 0xff +#define TRB_CR_EPID_SHIFT 16 +#define TRB_CR_EPID_MASK 0x1f + +#define TRB_CR_BSR (1<<9) +#define TRB_CR_DC (1<<9) + +#define TRB_LK_TC (1<<1) + +#define EP_TYPE_MASK 0x7 +#define EP_TYPE_SHIFT 3 + +#define EP_STATE_MASK 0x7 +#define EP_DISABLED (0<<0) +#define EP_RUNNING (1<<0) +#define EP_HALTED (2<<0) +#define EP_STOPPED (3<<0) +#define EP_ERROR (4<<0) + +#define SLOT_STATE_MASK 0x1f +#define SLOT_STATE_SHIFT 27 +#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK) +#define SLOT_ENABLED 0 +#define SLOT_DEFAULT 1 +#define SLOT_ADDRESSED 2 +#define SLOT_CONFIGURED 3 + +#define SLOT_CONTEXT_ENTRIES_MASK 0x1f +#define SLOT_CONTEXT_ENTRIES_SHIFT 27 + +typedef enum EPType { + ET_INVALID = 0, + ET_ISO_OUT, + ET_BULK_OUT, + ET_INTR_OUT, + ET_CONTROL, + ET_ISO_IN, + ET_BULK_IN, + ET_INTR_IN, +} EPType; + +typedef struct XHCIRing { + target_phys_addr_t base; + target_phys_addr_t dequeue; + bool ccs; +} XHCIRing; + +typedef struct XHCIPort { + USBPort port; + uint32_t portsc; +} XHCIPort; + +struct XHCIState; +typedef struct XHCIState XHCIState; + +typedef struct XHCITransfer { + XHCIState *xhci; + USBPacket packet; + bool running; + bool cancelled; + bool complete; + bool backgrounded; + unsigned int iso_pkts; + unsigned int slotid; + unsigned int epid; + bool in_xfer; + bool iso_xfer; + bool bg_xfer; + + unsigned int trb_count; + unsigned int trb_alloced; + XHCITRB *trbs; + + unsigned int data_length; + unsigned int data_alloced; + uint8_t *data; + + TRBCCode status; + + unsigned int pkts; + unsigned int pktsize; + unsigned int cur_pkt; +} XHCITransfer; + +typedef struct XHCIEPContext { + XHCIRing ring; + unsigned int next_xfer; + unsigned int comp_xfer; + XHCITransfer transfers[TD_QUEUE]; + bool bg_running; + bool bg_updating; + unsigned int next_bg; + XHCITransfer bg_transfers[BG_XFERS]; + EPType type; + target_phys_addr_t pctx; + unsigned int max_psize; + bool has_bg; + uint32_t state; +} XHCIEPContext; + +typedef struct XHCISlot { + bool enabled; + target_phys_addr_t ctx; + unsigned int port; + unsigned int devaddr; + XHCIEPContext * eps[31]; +} XHCISlot; + +typedef struct XHCIEvent { + TRBType type; + TRBCCode ccode; + uint64_t ptr; + uint32_t length; + uint32_t flags; + uint8_t slotid; + uint8_t epid; +} XHCIEvent; + +struct XHCIState { + PCIDevice pci_dev; + USBBus bus; + qemu_irq irq; + MemoryRegion mem; + const char *name; + uint32_t msi; + unsigned int devaddr; + + /* Operational Registers */ + uint32_t usbcmd; + uint32_t usbsts; + uint32_t dnctrl; + uint32_t crcr_low; + uint32_t crcr_high; + uint32_t dcbaap_low; + uint32_t dcbaap_high; + uint32_t config; + + XHCIPort ports[MAXPORTS]; + XHCISlot slots[MAXSLOTS]; + + /* Runtime Registers */ + uint32_t mfindex; + /* note: we only support one interrupter */ + uint32_t iman; + uint32_t imod; + uint32_t erstsz; + uint32_t erstba_low; + uint32_t erstba_high; + uint32_t erdp_low; + uint32_t erdp_high; + + target_phys_addr_t er_start; + uint32_t er_size; + bool er_pcs; + unsigned int er_ep_idx; + bool er_full; + + XHCIEvent ev_buffer[EV_QUEUE]; + unsigned int ev_buffer_put; + unsigned int ev_buffer_get; + + XHCIRing cmd_ring; +}; + +typedef struct XHCIEvRingSeg { + uint32_t addr_low; + uint32_t addr_high; + uint32_t size; + uint32_t rsvd; +} XHCIEvRingSeg; + +static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid); + +static inline target_phys_addr_t xhci_addr64(uint32_t low, uint32_t high) +{ +#if TARGET_PHYS_ADDR_BITS > 32 + return low | ((target_phys_addr_t)high << 32); +#else + return low; +#endif +} + +static inline target_phys_addr_t xhci_mask64(uint64_t addr) +{ +#if TARGET_PHYS_ADDR_BITS > 32 + return addr; +#else + return addr & 0xffffffff; +#endif +} + +static void xhci_irq_update(XHCIState *xhci) +{ + int level = 0; + + if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE && + xhci->usbcmd && USBCMD_INTE) { + level = 1; + } + + DPRINTF("xhci_irq_update(): %d\n", level); + + if (xhci->msi && msi_enabled(&xhci->pci_dev)) { + if (level) { + DPRINTF("xhci_irq_update(): MSI signal\n"); + msi_notify(&xhci->pci_dev, 0); + } + } else { + qemu_set_irq(xhci->irq, level); + } +} + +static inline int xhci_running(XHCIState *xhci) +{ + return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full; +} + +static void xhci_die(XHCIState *xhci) +{ + xhci->usbsts |= USBSTS_HCE; + fprintf(stderr, "xhci: asserted controller error\n"); +} + +static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) +{ + XHCITRB ev_trb; + target_phys_addr_t addr; + + ev_trb.parameter = cpu_to_le64(event->ptr); + ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24)); + ev_trb.control = (event->slotid << 24) | (event->epid << 16) | + event->flags | (event->type << TRB_TYPE_SHIFT); + if (xhci->er_pcs) { + ev_trb.control |= TRB_C; + } + ev_trb.control = cpu_to_le32(ev_trb.control); + + DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x\n", + xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control); + + addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; + cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE); + + xhci->er_ep_idx++; + if (xhci->er_ep_idx >= xhci->er_size) { + xhci->er_ep_idx = 0; + xhci->er_pcs = !xhci->er_pcs; + } +} + +static void xhci_events_update(XHCIState *xhci) +{ + target_phys_addr_t erdp; + unsigned int dp_idx; + bool do_irq = 0; + + if (xhci->usbsts & USBSTS_HCH) { + return; + } + + erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); + if (erdp < xhci->er_start || + erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { + fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp); + fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n", + xhci->er_start, xhci->er_size); + xhci_die(xhci); + return; + } + dp_idx = (erdp - xhci->er_start) / TRB_SIZE; + assert(dp_idx < xhci->er_size); + + /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus + * deadlocks when the ER is full. Hack it by holding off events until + * the driver decides to free at least half of the ring */ + if (xhci->er_full) { + int er_free = dp_idx - xhci->er_ep_idx; + if (er_free <= 0) { + er_free += xhci->er_size; + } + if (er_free < (xhci->er_size/2)) { + DPRINTF("xhci_events_update(): event ring still " + "more than half full (hack)\n"); + return; + } + } + + while (xhci->ev_buffer_put != xhci->ev_buffer_get) { + assert(xhci->er_full); + if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) { + DPRINTF("xhci_events_update(): event ring full again\n"); +#ifndef ER_FULL_HACK + XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; + xhci_write_event(xhci, &full); +#endif + do_irq = 1; + break; + } + XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get]; + xhci_write_event(xhci, event); + xhci->ev_buffer_get++; + do_irq = 1; + if (xhci->ev_buffer_get == EV_QUEUE) { + xhci->ev_buffer_get = 0; + } + } + + if (do_irq) { + xhci->erdp_low |= ERDP_EHB; + xhci->iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; + xhci_irq_update(xhci); + } + + if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { + DPRINTF("xhci_events_update(): event ring no longer full\n"); + xhci->er_full = 0; + } + return; +} + +static void xhci_event(XHCIState *xhci, XHCIEvent *event) +{ + target_phys_addr_t erdp; + unsigned int dp_idx; + + if (xhci->er_full) { + DPRINTF("xhci_event(): ER full, queueing\n"); + if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { + fprintf(stderr, "xhci: event queue full, dropping event!\n"); + return; + } + xhci->ev_buffer[xhci->ev_buffer_put++] = *event; + if (xhci->ev_buffer_put == EV_QUEUE) { + xhci->ev_buffer_put = 0; + } + return; + } + + erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); + if (erdp < xhci->er_start || + erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { + fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp); + fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n", + xhci->er_start, xhci->er_size); + xhci_die(xhci); + return; + } + + dp_idx = (erdp - xhci->er_start) / TRB_SIZE; + assert(dp_idx < xhci->er_size); + + if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) { + DPRINTF("xhci_event(): ER full, queueing\n"); +#ifndef ER_FULL_HACK + XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; + xhci_write_event(xhci, &full); +#endif + xhci->er_full = 1; + if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { + fprintf(stderr, "xhci: event queue full, dropping event!\n"); + return; + } + xhci->ev_buffer[xhci->ev_buffer_put++] = *event; + if (xhci->ev_buffer_put == EV_QUEUE) { + xhci->ev_buffer_put = 0; + } + } else { + xhci_write_event(xhci, event); + } + + xhci->erdp_low |= ERDP_EHB; + xhci->iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; + + xhci_irq_update(xhci); +} + +static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, + target_phys_addr_t base) +{ + ring->base = base; + ring->dequeue = base; + ring->ccs = 1; +} + +static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb, + target_phys_addr_t *addr) +{ + while (1) { + TRBType type; + cpu_physical_memory_read(ring->dequeue, (uint8_t *) trb, TRB_SIZE); + trb->addr = ring->dequeue; + trb->ccs = ring->ccs; + le64_to_cpus(&trb->parameter); + le32_to_cpus(&trb->status); + le32_to_cpus(&trb->control); + + DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: " + "%016" PRIx64 " %08x %08x\n", + ring->dequeue, trb->parameter, trb->status, trb->control); + + if ((trb->control & TRB_C) != ring->ccs) { + return 0; + } + + type = TRB_TYPE(*trb); + + if (type != TR_LINK) { + if (addr) { + *addr = ring->dequeue; + } + ring->dequeue += TRB_SIZE; + return type; + } else { + ring->dequeue = xhci_mask64(trb->parameter); + if (trb->control & TRB_LK_TC) { + ring->ccs = !ring->ccs; + } + } + } +} + +static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) +{ + XHCITRB trb; + int length = 0; + target_phys_addr_t dequeue = ring->dequeue; + bool ccs = ring->ccs; + /* hack to bundle together the two/three TDs that make a setup transfer */ + bool control_td_set = 0; + + while (1) { + TRBType type; + cpu_physical_memory_read(dequeue, (uint8_t *) &trb, TRB_SIZE); + le64_to_cpus(&trb.parameter); + le32_to_cpus(&trb.status); + le32_to_cpus(&trb.control); + + DPRINTF("xhci: TRB peeked [" TARGET_FMT_plx "]: " + "%016" PRIx64 " %08x %08x\n", + dequeue, trb.parameter, trb.status, trb.control); + + if ((trb.control & TRB_C) != ccs) { + return -length; + } + + type = TRB_TYPE(trb); + + if (type == TR_LINK) { + dequeue = xhci_mask64(trb.parameter); + if (trb.control & TRB_LK_TC) { + ccs = !ccs; + } + continue; + } + + length += 1; + dequeue += TRB_SIZE; + + if (type == TR_SETUP) { + control_td_set = 1; + } else if (type == TR_STATUS) { + control_td_set = 0; + } + + if (!control_td_set && !(trb.control & TRB_TR_CH)) { + return length; + } + } +} + +static void xhci_er_reset(XHCIState *xhci) +{ + XHCIEvRingSeg seg; + + /* cache the (sole) event ring segment location */ + if (xhci->erstsz != 1) { + fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz); + xhci_die(xhci); + return; + } + target_phys_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high); + cpu_physical_memory_read(erstba, (uint8_t *) &seg, sizeof(seg)); + le32_to_cpus(&seg.addr_low); + le32_to_cpus(&seg.addr_high); + le32_to_cpus(&seg.size); + if (seg.size < 16 || seg.size > 4096) { + fprintf(stderr, "xhci: invalid value for segment size: %d\n", seg.size); + xhci_die(xhci); + return; + } + xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high); + xhci->er_size = seg.size; + + xhci->er_ep_idx = 0; + xhci->er_pcs = 1; + xhci->er_full = 0; + + DPRINTF("xhci: event ring:" TARGET_FMT_plx " [%d]\n", + xhci->er_start, xhci->er_size); +} + +static void xhci_run(XHCIState *xhci) +{ + DPRINTF("xhci_run()\n"); + + xhci->usbsts &= ~USBSTS_HCH; +} + +static void xhci_stop(XHCIState *xhci) +{ + DPRINTF("xhci_stop()\n"); + xhci->usbsts |= USBSTS_HCH; + xhci->crcr_low &= ~CRCR_CRR; +} + +static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, + uint32_t state) +{ + uint32_t ctx[5]; + if (epctx->state == state) { + return; + } + + cpu_physical_memory_read(epctx->pctx, (uint8_t *) ctx, sizeof(ctx)); + ctx[0] &= ~EP_STATE_MASK; + ctx[0] |= state; + ctx[2] = epctx->ring.dequeue | epctx->ring.ccs; + ctx[3] = (epctx->ring.dequeue >> 16) >> 16; + DPRINTF("xhci: set epctx: " TARGET_FMT_plx " state=%d dequeue=%08x%08x\n", + epctx->pctx, state, ctx[3], ctx[2]); + cpu_physical_memory_write(epctx->pctx, (uint8_t *) ctx, sizeof(ctx)); + epctx->state = state; +} + +static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid, target_phys_addr_t pctx, + uint32_t *ctx) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + target_phys_addr_t dequeue; + int i; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(epid >= 1 && epid <= 31); + + DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid); + + slot = &xhci->slots[slotid-1]; + if (slot->eps[epid-1]) { + fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid); + return CC_TRB_ERROR; + } + + epctx = g_malloc(sizeof(XHCIEPContext)); + memset(epctx, 0, sizeof(XHCIEPContext)); + + slot->eps[epid-1] = epctx; + + dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]); + xhci_ring_init(xhci, &epctx->ring, dequeue); + epctx->ring.ccs = ctx[2] & 1; + + epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK; + DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type); + epctx->pctx = pctx; + epctx->max_psize = ctx[1]>>16; + epctx->max_psize *= 1+((ctx[1]>>8)&0xff); + epctx->has_bg = false; + if (epctx->type == ET_ISO_IN) { + epctx->has_bg = true; + } + DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", + epid/2, epid%2, epctx->max_psize); + for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { + usb_packet_init(&epctx->transfers[i].packet); + } + + epctx->state = EP_RUNNING; + ctx[0] &= ~EP_STATE_MASK; + ctx[0] |= EP_RUNNING; + + return CC_SUCCESS; +} + +static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, + unsigned int epid) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + int i, xferi, killed = 0; + assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(epid >= 1 && epid <= 31); + + DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid); + + slot = &xhci->slots[slotid-1]; + + if (!slot->eps[epid-1]) { + return 0; + } + + epctx = slot->eps[epid-1]; + + xferi = epctx->next_xfer; + for (i = 0; i < TD_QUEUE; i++) { + XHCITransfer *t = &epctx->transfers[xferi]; + if (t->running) { + t->cancelled = 1; + /* libusb_cancel_transfer(t->usbxfer) */ + DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i); + killed++; + } + if (t->backgrounded) { + t->backgrounded = 0; + } + if (t->trbs) { + g_free(t->trbs); + } + if (t->data) { + g_free(t->data); + } + + t->trbs = NULL; + t->data = NULL; + t->trb_count = t->trb_alloced = 0; + t->data_length = t->data_alloced = 0; + xferi = (xferi + 1) % TD_QUEUE; + } + if (epctx->has_bg) { + xferi = epctx->next_bg; + for (i = 0; i < BG_XFERS; i++) { + XHCITransfer *t = &epctx->bg_transfers[xferi]; + if (t->running) { + t->cancelled = 1; + /* libusb_cancel_transfer(t->usbxfer); */ + DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i); + killed++; + } + if (t->data) { + g_free(t->data); + } + + t->data = NULL; + xferi = (xferi + 1) % BG_XFERS; + } + } + return killed; +} + +static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(epid >= 1 && epid <= 31); + + DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid); + + slot = &xhci->slots[slotid-1]; + + if (!slot->eps[epid-1]) { + DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid); + return CC_SUCCESS; + } + + xhci_ep_nuke_xfers(xhci, slotid, epid); + + epctx = slot->eps[epid-1]; + + xhci_set_ep_state(xhci, epctx, EP_DISABLED); + + g_free(epctx); + slot->eps[epid-1] = NULL; + + return CC_SUCCESS; +} + +static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + + DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid); + + assert(slotid >= 1 && slotid <= MAXSLOTS); + + if (epid < 1 || epid > 31) { + fprintf(stderr, "xhci: bad ep %d\n", epid); + return CC_TRB_ERROR; + } + + slot = &xhci->slots[slotid-1]; + + if (!slot->eps[epid-1]) { + DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid); + return CC_EP_NOT_ENABLED_ERROR; + } + + if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) { + fprintf(stderr, "xhci: FIXME: endpoint stopped w/ xfers running, " + "data might be lost\n"); + } + + epctx = slot->eps[epid-1]; + + xhci_set_ep_state(xhci, epctx, EP_STOPPED); + + return CC_SUCCESS; +} + +static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + USBDevice *dev; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + + DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid); + + if (epid < 1 || epid > 31) { + fprintf(stderr, "xhci: bad ep %d\n", epid); + return CC_TRB_ERROR; + } + + slot = &xhci->slots[slotid-1]; + + if (!slot->eps[epid-1]) { + DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid); + return CC_EP_NOT_ENABLED_ERROR; + } + + epctx = slot->eps[epid-1]; + + if (epctx->state != EP_HALTED) { + fprintf(stderr, "xhci: reset EP while EP %d not halted (%d)\n", + epid, epctx->state); + return CC_CONTEXT_STATE_ERROR; + } + + if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) { + fprintf(stderr, "xhci: FIXME: endpoint reset w/ xfers running, " + "data might be lost\n"); + } + + uint8_t ep = epid>>1; + + if (epid & 1) { + ep |= 0x80; + } + + dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev; + if (!dev) { + return CC_USB_TRANSACTION_ERROR; + } + + xhci_set_ep_state(xhci, epctx, EP_STOPPED); + + return CC_SUCCESS; +} + +static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, + unsigned int epid, uint64_t pdequeue) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + target_phys_addr_t dequeue; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + + if (epid < 1 || epid > 31) { + fprintf(stderr, "xhci: bad ep %d\n", epid); + return CC_TRB_ERROR; + } + + DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue); + dequeue = xhci_mask64(pdequeue); + + slot = &xhci->slots[slotid-1]; + + if (!slot->eps[epid-1]) { + DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid); + return CC_EP_NOT_ENABLED_ERROR; + } + + epctx = slot->eps[epid-1]; + + + if (epctx->state != EP_STOPPED) { + fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid); + return CC_CONTEXT_STATE_ERROR; + } + + xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF); + epctx->ring.ccs = dequeue & 1; + + xhci_set_ep_state(xhci, epctx, EP_STOPPED); + + return CC_SUCCESS; +} + +static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, + unsigned int length, bool in_xfer, bool out_xfer, + bool report) +{ + int i; + uint32_t edtla = 0; + unsigned int transferred = 0; + unsigned int left = length; + bool reported = 0; + bool shortpkt = 0; + XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; + XHCIState *xhci = xfer->xhci; + + DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n", + length, in_xfer, out_xfer, report); + + assert(!(in_xfer && out_xfer)); + + for (i = 0; i < xfer->trb_count; i++) { + XHCITRB *trb = &xfer->trbs[i]; + target_phys_addr_t addr; + unsigned int chunk = 0; + + switch (TRB_TYPE(*trb)) { + case TR_DATA: + if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) { + fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n"); + xhci_die(xhci); + return transferred; + } + /* fallthrough */ + case TR_NORMAL: + case TR_ISOCH: + addr = xhci_mask64(trb->parameter); + chunk = trb->status & 0x1ffff; + if (chunk > left) { + chunk = left; + shortpkt = 1; + } + if (in_xfer || out_xfer) { + if (trb->control & TRB_TR_IDT) { + uint64_t idata; + if (chunk > 8 || in_xfer) { + fprintf(stderr, "xhci: invalid immediate data TRB\n"); + xhci_die(xhci); + return transferred; + } + idata = le64_to_cpu(trb->parameter); + memcpy(data, &idata, chunk); + } else { + DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at " + TARGET_FMT_plx "\n", in_xfer, chunk, addr); + if (in_xfer) { + cpu_physical_memory_write(addr, data, chunk); + } else { + cpu_physical_memory_read(addr, data, chunk); + } +#ifdef DEBUG_DATA + unsigned int count = chunk; + int i; + if (count > 16) { + count = 16; + } + DPRINTF(" ::"); + for (i = 0; i < count; i++) { + DPRINTF(" %02x", data[i]); + } + DPRINTF("\n"); +#endif + } + } + left -= chunk; + data += chunk; + edtla += chunk; + transferred += chunk; + break; + case TR_STATUS: + reported = 0; + shortpkt = 0; + break; + } + + if (report && !reported && (trb->control & TRB_TR_IOC || + (shortpkt && (trb->control & TRB_TR_ISP)))) { + event.slotid = xfer->slotid; + event.epid = xfer->epid; + event.length = (trb->status & 0x1ffff) - chunk; + event.flags = 0; + event.ptr = trb->addr; + if (xfer->status == CC_SUCCESS) { + event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS; + } else { + event.ccode = xfer->status; + } + if (TRB_TYPE(*trb) == TR_EVDATA) { + event.ptr = trb->parameter; + event.flags |= TRB_EV_ED; + event.length = edtla & 0xffffff; + DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); + edtla = 0; + } + xhci_event(xhci, &event); + reported = 1; + } + } + return transferred; +} + +static void xhci_stall_ep(XHCITransfer *xfer) +{ + XHCIState *xhci = xfer->xhci; + XHCISlot *slot = &xhci->slots[xfer->slotid-1]; + XHCIEPContext *epctx = slot->eps[xfer->epid-1]; + + epctx->ring.dequeue = xfer->trbs[0].addr; + epctx->ring.ccs = xfer->trbs[0].ccs; + xhci_set_ep_state(xhci, epctx, EP_HALTED); + DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid); + DPRINTF("xhci: will continue at "TARGET_FMT_plx"\n", epctx->ring.dequeue); +} + +static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, + XHCIEPContext *epctx); + +static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx) +{ + if (epctx->bg_updating) { + return; + } + DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx); + assert(epctx->has_bg); + DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg); + epctx->bg_updating = 1; + while (epctx->transfers[epctx->comp_xfer].backgrounded && + epctx->bg_transfers[epctx->next_bg].complete) { + XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer]; + XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg]; +#if 0 + DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n", + epctx->comp_xfer, epctx->next_bg, bg->cur_pkt, + bg->usbxfer->iso_packet_desc[bg->cur_pkt].status + ); +#endif + assert(epctx->type == ET_ISO_IN); + assert(bg->iso_xfer); + assert(bg->in_xfer); + uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize; +#if 0 + int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length; + fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status); +#else + int len = 0; + FIXME(); +#endif + fg->complete = 1; + fg->backgrounded = 0; + + if (fg->status == CC_STALL_ERROR) { + xhci_stall_ep(fg); + } + + xhci_xfer_data(fg, p, len, 1, 0, 1); + + epctx->comp_xfer++; + if (epctx->comp_xfer == TD_QUEUE) { + epctx->comp_xfer = 0; + } + DPRINTF("next fg xfer: %d\n", epctx->comp_xfer); + bg->cur_pkt++; + if (bg->cur_pkt == bg->pkts) { + bg->complete = 0; + if (xhci_submit(xhci, bg, epctx) < 0) { + fprintf(stderr, "xhci: bg resubmit failed\n"); + } + epctx->next_bg++; + if (epctx->next_bg == BG_XFERS) { + epctx->next_bg = 0; + } + DPRINTF("next bg xfer: %d\n", epctx->next_bg); + + xhci_kick_ep(xhci, fg->slotid, fg->epid); + } + } + epctx->bg_updating = 0; +} + +#if 0 +static void xhci_xfer_cb(struct libusb_transfer *transfer) +{ + XHCIState *xhci; + XHCITransfer *xfer; + + xfer = (XHCITransfer *)transfer->user_data; + xhci = xfer->xhci; + + DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid, + xfer->epid, transfer->status); + + assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS); + assert(xfer->epid >= 1 && xfer->epid <= 31); + + if (xfer->cancelled) { + DPRINTF("xhci: transfer cancelled, not reporting anything\n"); + xfer->running = 0; + return; + } + + XHCIEPContext *epctx; + XHCISlot *slot; + slot = &xhci->slots[xfer->slotid-1]; + assert(slot->eps[xfer->epid-1]); + epctx = slot->eps[xfer->epid-1]; + + if (xfer->bg_xfer) { + DPRINTF("xhci: background transfer, updating\n"); + xfer->complete = 1; + xfer->running = 0; + xhci_bg_update(xhci, epctx); + return; + } + + if (xfer->iso_xfer) { + transfer->status = transfer->iso_packet_desc[0].status; + transfer->actual_length = transfer->iso_packet_desc[0].actual_length; + } + + xfer->status = libusb_to_ccode(transfer->status); + + xfer->complete = 1; + xfer->running = 0; + + if (transfer->status == LIBUSB_TRANSFER_STALL) + xhci_stall_ep(xhci, epctx, xfer); + + DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length); + + if (xfer->in_xfer) { + if (xfer->epid == 1) { + xhci_xfer_data(xhci, xfer, xfer->data + 8, + transfer->actual_length, 1, 0, 1); + } else { + xhci_xfer_data(xhci, xfer, xfer->data, + transfer->actual_length, 1, 0, 1); + } + } else { + xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1); + } + + xhci_kick_ep(xhci, xfer->slotid, xfer->epid); +} + +static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer, + uint8_t bmRequestType, uint8_t bRequest, + uint16_t wValue, uint16_t wIndex, uint16_t wLength) +{ + uint16_t type_req = (bmRequestType << 8) | bRequest; + + switch (type_req) { + case 0x0000 | USB_REQ_SET_CONFIGURATION: + DPRINTF("xhci: HLE switch configuration\n"); + return xhci_switch_config(xhci, xfer->slotid, wValue) == 0; + case 0x0100 | USB_REQ_SET_INTERFACE: + DPRINTF("xhci: HLE set interface altsetting\n"); + return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0; + case 0x0200 | USB_REQ_CLEAR_FEATURE: + if (wValue == 0) { // endpoint halt + DPRINTF("xhci: HLE clear halt\n"); + return xhci_clear_halt(xhci, xfer->slotid, wIndex); + } + case 0x0000 | USB_REQ_SET_ADDRESS: + fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n"); + return 0; + default: + return 0; + } +} +#endif + +static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep) +{ + usb_packet_setup(&xfer->packet, + xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT, + xfer->xhci->slots[xfer->slotid-1].devaddr, + ep & 0x7f); + usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length); + DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", + xfer->packet.pid, xfer->packet.devaddr, xfer->packet.devep); + return 0; +} + +static int xhci_complete_packet(XHCITransfer *xfer, int ret) +{ + if (ret == USB_RET_ASYNC) { + xfer->running = 1; + xfer->complete = 0; + xfer->cancelled = 0; + return 0; + } else { + xfer->running = 0; + xfer->complete = 1; + } + + if (ret >= 0) { + xfer->status = CC_SUCCESS; + xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); + return 0; + } + + /* error */ + switch (ret) { + case USB_RET_NODEV: + xfer->status = CC_USB_TRANSACTION_ERROR; + xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); + xhci_stall_ep(xfer); + break; + case USB_RET_STALL: + xfer->status = CC_STALL_ERROR; + xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); + xhci_stall_ep(xfer); + break; + default: + fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret); + FIXME(); + } + return 0; +} + +static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) +{ + XHCITRB *trb_setup, *trb_status; + uint8_t bmRequestType, bRequest; + uint16_t wValue, wLength, wIndex; + XHCIPort *port; + USBDevice *dev; + int ret; + + DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid); + + trb_setup = &xfer->trbs[0]; + trb_status = &xfer->trbs[xfer->trb_count-1]; + + /* at most one Event Data TRB allowed after STATUS */ + if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { + trb_status--; + } + + /* do some sanity checks */ + if (TRB_TYPE(*trb_setup) != TR_SETUP) { + fprintf(stderr, "xhci: ep0 first TD not SETUP: %d\n", + TRB_TYPE(*trb_setup)); + return -1; + } + if (TRB_TYPE(*trb_status) != TR_STATUS) { + fprintf(stderr, "xhci: ep0 last TD not STATUS: %d\n", + TRB_TYPE(*trb_status)); + return -1; + } + if (!(trb_setup->control & TRB_TR_IDT)) { + fprintf(stderr, "xhci: Setup TRB doesn't have IDT set\n"); + return -1; + } + if ((trb_setup->status & 0x1ffff) != 8) { + fprintf(stderr, "xhci: Setup TRB has bad length (%d)\n", + (trb_setup->status & 0x1ffff)); + return -1; + } + + bmRequestType = trb_setup->parameter; + bRequest = trb_setup->parameter >> 8; + wValue = trb_setup->parameter >> 16; + wIndex = trb_setup->parameter >> 32; + wLength = trb_setup->parameter >> 48; + + if (xfer->data && xfer->data_alloced < wLength) { + xfer->data_alloced = 0; + g_free(xfer->data); + xfer->data = NULL; + } + if (!xfer->data) { + DPRINTF("xhci: alloc %d bytes data\n", wLength); + xfer->data = g_malloc(wLength+1); + xfer->data_alloced = wLength; + } + xfer->data_length = wLength; + + port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; + dev = port->port.dev; + if (!dev) { + fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, + xhci->slots[xfer->slotid-1].port); + return -1; + } + + xfer->in_xfer = bmRequestType & USB_DIR_IN; + xfer->iso_xfer = false; + + xhci_setup_packet(xfer, port, 0); + if (!xfer->in_xfer) { + xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0); + } + ret = usb_device_handle_control(dev, &xfer->packet, + (bmRequestType << 8) | bRequest, + wValue, wIndex, wLength, xfer->data); + + xhci_complete_packet(xfer, ret); + if (!xfer->running) { + xhci_kick_ep(xhci, xfer->slotid, xfer->epid); + } + return 0; +} + +static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) +{ + XHCIPort *port; + USBDevice *dev; + int ret; + + DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); + uint8_t ep = xfer->epid>>1; + + xfer->in_xfer = epctx->type>>2; + if (xfer->in_xfer) { + ep |= 0x80; + } + + if (xfer->data && xfer->data_alloced < xfer->data_length) { + xfer->data_alloced = 0; + g_free(xfer->data); + xfer->data = NULL; + } + if (!xfer->data && xfer->data_length) { + DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length); + xfer->data = g_malloc(xfer->data_length); + xfer->data_alloced = xfer->data_length; + } + if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { + if (!xfer->bg_xfer) { + xfer->pkts = 1; + } + } else { + xfer->pkts = 0; + } + + port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; + dev = port->port.dev; + if (!dev) { + fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, + xhci->slots[xfer->slotid-1].port); + return -1; + } + + xhci_setup_packet(xfer, port, ep); + + switch(epctx->type) { + case ET_INTR_OUT: + case ET_INTR_IN: + case ET_BULK_OUT: + case ET_BULK_IN: + break; + case ET_ISO_OUT: + case ET_ISO_IN: + FIXME(); + break; + default: + fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n", + epctx->type, ep); + return -1; + } + + if (!xfer->in_xfer) { + xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0); + } + ret = usb_handle_packet(dev, &xfer->packet); + + xhci_complete_packet(xfer, ret); + if (!xfer->running) { + xhci_kick_ep(xhci, xfer->slotid, xfer->epid); + } + return 0; +} + +static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) +{ + int i; + unsigned int length = 0; + XHCITRB *trb; + + DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); + + for (i = 0; i < xfer->trb_count; i++) { + trb = &xfer->trbs[i]; + if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { + length += trb->status & 0x1ffff; + } + } + DPRINTF("xhci: total TD length=%d\n", length); + + if (!epctx->has_bg) { + xfer->data_length = length; + xfer->backgrounded = 0; + return xhci_submit(xhci, xfer, epctx); + } else { + if (!epctx->bg_running) { + for (i = 0; i < BG_XFERS; i++) { + XHCITransfer *t = &epctx->bg_transfers[i]; + t->xhci = xhci; + t->epid = xfer->epid; + t->slotid = xfer->slotid; + t->pkts = BG_PKTS; + t->pktsize = epctx->max_psize; + t->data_length = t->pkts * t->pktsize; + t->bg_xfer = 1; + if (xhci_submit(xhci, t, epctx) < 0) { + fprintf(stderr, "xhci: bg submit failed\n"); + return -1; + } + } + epctx->bg_running = 1; + } + xfer->backgrounded = 1; + xhci_bg_update(xhci, epctx); + return 0; + } +} + +static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) +{ + XHCIEPContext *epctx; + int length; + int i; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + assert(epid >= 1 && epid <= 31); + DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid); + + if (!xhci->slots[slotid-1].enabled) { + fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid); + return; + } + epctx = xhci->slots[slotid-1].eps[epid-1]; + if (!epctx) { + fprintf(stderr, "xhci: xhci_kick_ep for disabled endpoint %d,%d\n", + epid, slotid); + return; + } + + if (epctx->state == EP_HALTED) { + DPRINTF("xhci: ep halted, not running schedule\n"); + return; + } + + xhci_set_ep_state(xhci, epctx, EP_RUNNING); + + while (1) { + XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; + if (xfer->running || xfer->backgrounded) { + DPRINTF("xhci: ep is busy\n"); + break; + } + length = xhci_ring_chain_length(xhci, &epctx->ring); + if (length < 0) { + DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length); + break; + } else if (length == 0) { + break; + } + DPRINTF("xhci: fetching %d-TRB TD\n", length); + if (xfer->trbs && xfer->trb_alloced < length) { + xfer->trb_count = 0; + xfer->trb_alloced = 0; + g_free(xfer->trbs); + xfer->trbs = NULL; + } + if (!xfer->trbs) { + xfer->trbs = g_malloc(sizeof(XHCITRB) * length); + xfer->trb_alloced = length; + } + xfer->trb_count = length; + + for (i = 0; i < length; i++) { + assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL)); + } + xfer->xhci = xhci; + xfer->epid = epid; + xfer->slotid = slotid; + + if (epid == 1) { + if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) { + epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; + } else { + fprintf(stderr, "xhci: error firing CTL transfer\n"); + } + } else { + if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { + epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; + } else { + fprintf(stderr, "xhci: error firing data transfer\n"); + } + } + + /* + * Qemu usb can't handle multiple in-flight xfers. + * Also xfers might be finished here already, + * possibly with an error. Stop here for now. + */ + break; + } +} + +static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) +{ + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_enable_slot(%d)\n", slotid); + xhci->slots[slotid-1].enabled = 1; + xhci->slots[slotid-1].port = 0; + memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); + + return CC_SUCCESS; +} + +static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid) +{ + int i; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_disable_slot(%d)\n", slotid); + + for (i = 1; i <= 31; i++) { + if (xhci->slots[slotid-1].eps[i-1]) { + xhci_disable_ep(xhci, slotid, i); + } + } + + xhci->slots[slotid-1].enabled = 0; + return CC_SUCCESS; +} + +static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, + uint64_t pictx, bool bsr) +{ + XHCISlot *slot; + USBDevice *dev; + target_phys_addr_t ictx, octx, dcbaap; + uint64_t poctx; + uint32_t ictl_ctx[2]; + uint32_t slot_ctx[4]; + uint32_t ep0_ctx[5]; + unsigned int port; + int i; + TRBCCode res; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_address_slot(%d)\n", slotid); + + dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); + cpu_physical_memory_read(dcbaap + 8*slotid, + (uint8_t *) &poctx, sizeof(poctx)); + ictx = xhci_mask64(pictx); + octx = xhci_mask64(le64_to_cpu(poctx)); + + DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx); + DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx); + + cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx)); + + if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) { + fprintf(stderr, "xhci: invalid input context control %08x %08x\n", + ictl_ctx[0], ictl_ctx[1]); + return CC_TRB_ERROR; + } + + cpu_physical_memory_read(ictx+32, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + cpu_physical_memory_read(ictx+64, (uint8_t *) ep0_ctx, sizeof(ep0_ctx)); + + DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + + DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", + ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); + + port = (slot_ctx[1]>>16) & 0xFF; + dev = xhci->ports[port-1].port.dev; + + if (port < 1 || port > MAXPORTS) { + fprintf(stderr, "xhci: bad port %d\n", port); + return CC_TRB_ERROR; + } else if (!dev) { + fprintf(stderr, "xhci: port %d not connected\n", port); + return CC_USB_TRANSACTION_ERROR; + } + + for (i = 0; i < MAXSLOTS; i++) { + if (xhci->slots[i].port == port) { + fprintf(stderr, "xhci: port %d already assigned to slot %d\n", + port, i+1); + return CC_TRB_ERROR; + } + } + + slot = &xhci->slots[slotid-1]; + slot->port = port; + slot->ctx = octx; + + if (bsr) { + slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT; + } else { + slot->devaddr = xhci->devaddr++; + slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr; + DPRINTF("xhci: device address is %d\n", slot->devaddr); + usb_device_handle_control(dev, NULL, + DeviceOutRequest | USB_REQ_SET_ADDRESS, + slot->devaddr, 0, 0, NULL); + } + + res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx); + + DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", + ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); + + cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + cpu_physical_memory_write(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx)); + + return res; +} + + +static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, + uint64_t pictx, bool dc) +{ + target_phys_addr_t ictx, octx; + uint32_t ictl_ctx[2]; + uint32_t slot_ctx[4]; + uint32_t islot_ctx[4]; + uint32_t ep_ctx[5]; + int i; + TRBCCode res; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_configure_slot(%d)\n", slotid); + + ictx = xhci_mask64(pictx); + octx = xhci->slots[slotid-1].ctx; + + DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx); + DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx); + + if (dc) { + for (i = 2; i <= 31; i++) { + if (xhci->slots[slotid-1].eps[i-1]) { + xhci_disable_ep(xhci, slotid, i); + } + } + + cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); + slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT; + DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + + return CC_SUCCESS; + } + + cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx)); + + if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) { + fprintf(stderr, "xhci: invalid input context control %08x %08x\n", + ictl_ctx[0], ictl_ctx[1]); + return CC_TRB_ERROR; + } + + cpu_physical_memory_read(ictx+32, (uint8_t *) islot_ctx, sizeof(islot_ctx)); + cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + + if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) { + fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]); + return CC_CONTEXT_STATE_ERROR; + } + + for (i = 2; i <= 31; i++) { + if (ictl_ctx[0] & (1<<i)) { + xhci_disable_ep(xhci, slotid, i); + } + if (ictl_ctx[1] & (1<<i)) { + cpu_physical_memory_read(ictx+32+(32*i), + (uint8_t *) ep_ctx, sizeof(ep_ctx)); + DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n", + i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], + ep_ctx[3], ep_ctx[4]); + xhci_disable_ep(xhci, slotid, i); + res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx); + if (res != CC_SUCCESS) { + return res; + } + DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n", + i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2], + ep_ctx[3], ep_ctx[4]); + cpu_physical_memory_write(octx+(32*i), + (uint8_t *) ep_ctx, sizeof(ep_ctx)); + } + } + + slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); + slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT; + slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT); + slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK << + SLOT_CONTEXT_ENTRIES_SHIFT); + DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + + cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + + return CC_SUCCESS; +} + + +static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid, + uint64_t pictx) +{ + target_phys_addr_t ictx, octx; + uint32_t ictl_ctx[2]; + uint32_t iep0_ctx[5]; + uint32_t ep0_ctx[5]; + uint32_t islot_ctx[4]; + uint32_t slot_ctx[4]; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_evaluate_slot(%d)\n", slotid); + + ictx = xhci_mask64(pictx); + octx = xhci->slots[slotid-1].ctx; + + DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx); + DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx); + + cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx)); + + if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) { + fprintf(stderr, "xhci: invalid input context control %08x %08x\n", + ictl_ctx[0], ictl_ctx[1]); + return CC_TRB_ERROR; + } + + if (ictl_ctx[1] & 0x1) { + cpu_physical_memory_read(ictx+32, + (uint8_t *) islot_ctx, sizeof(islot_ctx)); + + DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n", + islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]); + + cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + + slot_ctx[1] &= ~0xFFFF; /* max exit latency */ + slot_ctx[1] |= islot_ctx[1] & 0xFFFF; + slot_ctx[2] &= ~0xFF00000; /* interrupter target */ + slot_ctx[2] |= islot_ctx[2] & 0xFF000000; + + DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + + cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + } + + if (ictl_ctx[1] & 0x2) { + cpu_physical_memory_read(ictx+64, + (uint8_t *) iep0_ctx, sizeof(iep0_ctx)); + + DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n", + iep0_ctx[0], iep0_ctx[1], iep0_ctx[2], + iep0_ctx[3], iep0_ctx[4]); + + cpu_physical_memory_read(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx)); + + ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/ + ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000; + + DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n", + ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); + + cpu_physical_memory_write(octx+32, + (uint8_t *) ep0_ctx, sizeof(ep0_ctx)); + } + + return CC_SUCCESS; +} + +static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid) +{ + uint32_t slot_ctx[4]; + target_phys_addr_t octx; + int i; + + assert(slotid >= 1 && slotid <= MAXSLOTS); + DPRINTF("xhci_reset_slot(%d)\n", slotid); + + octx = xhci->slots[slotid-1].ctx; + + DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx); + + for (i = 2; i <= 31; i++) { + if (xhci->slots[slotid-1].eps[i-1]) { + xhci_disable_ep(xhci, slotid, i); + } + } + + cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); + slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT; + DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n", + slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]); + cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx)); + + return CC_SUCCESS; +} + +static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb) +{ + unsigned int slotid; + slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK; + if (slotid < 1 || slotid > MAXSLOTS) { + fprintf(stderr, "xhci: bad slot id %d\n", slotid); + event->ccode = CC_TRB_ERROR; + return 0; + } else if (!xhci->slots[slotid-1].enabled) { + fprintf(stderr, "xhci: slot id %d not enabled\n", slotid); + event->ccode = CC_SLOT_NOT_ENABLED_ERROR; + return 0; + } + return slotid; +} + +static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) +{ + target_phys_addr_t ctx; + uint8_t bw_ctx[MAXPORTS+1]; + + DPRINTF("xhci_get_port_bandwidth()\n"); + + ctx = xhci_mask64(pctx); + + DPRINTF("xhci: bandwidth context at "TARGET_FMT_plx"\n", ctx); + + /* TODO: actually implement real values here */ + bw_ctx[0] = 0; + memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */ + cpu_physical_memory_write(ctx, bw_ctx, sizeof(bw_ctx)); + + return CC_SUCCESS; +} + +static uint32_t rotl(uint32_t v, unsigned count) +{ + count &= 31; + return (v << count) | (v >> (32 - count)); +} + + +static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo) +{ + uint32_t val; + val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F)); + val += rotl(lo + 0x49434878, hi & 0x1F); + val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F); + return ~val; +} + +static void xhci_via_challenge(uint64_t addr) +{ + uint32_t buf[8]; + uint32_t obuf[8]; + target_phys_addr_t paddr = xhci_mask64(addr); + + cpu_physical_memory_read(paddr, (uint8_t *) &buf, 32); + + memcpy(obuf, buf, sizeof(obuf)); + + if ((buf[0] & 0xff) == 2) { + obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3]; + obuf[0] |= (buf[2] * buf[3]) & 0xff; + obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3]; + obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3]; + obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3]; + obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3]; + obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3]; + obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956; + obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593; + } + + cpu_physical_memory_write(paddr, (uint8_t *) &obuf, 32); +} + +static void xhci_process_commands(XHCIState *xhci) +{ + XHCITRB trb; + TRBType type; + XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS}; + target_phys_addr_t addr; + unsigned int i, slotid = 0; + + DPRINTF("xhci_process_commands()\n"); + if (!xhci_running(xhci)) { + DPRINTF("xhci_process_commands() called while xHC stopped or paused\n"); + return; + } + + xhci->crcr_low |= CRCR_CRR; + + while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) { + event.ptr = addr; + switch (type) { + case CR_ENABLE_SLOT: + for (i = 0; i < MAXSLOTS; i++) { + if (!xhci->slots[i].enabled) { + break; + } + } + if (i >= MAXSLOTS) { + fprintf(stderr, "xhci: no device slots available\n"); + event.ccode = CC_NO_SLOTS_ERROR; + } else { + slotid = i+1; + event.ccode = xhci_enable_slot(xhci, slotid); + } + break; + case CR_DISABLE_SLOT: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + event.ccode = xhci_disable_slot(xhci, slotid); + } + break; + case CR_ADDRESS_DEVICE: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + event.ccode = xhci_address_slot(xhci, slotid, trb.parameter, + trb.control & TRB_CR_BSR); + } + break; + case CR_CONFIGURE_ENDPOINT: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter, + trb.control & TRB_CR_DC); + } + break; + case CR_EVALUATE_CONTEXT: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter); + } + break; + case CR_STOP_ENDPOINT: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) + & TRB_CR_EPID_MASK; + event.ccode = xhci_stop_ep(xhci, slotid, epid); + } + break; + case CR_RESET_ENDPOINT: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) + & TRB_CR_EPID_MASK; + event.ccode = xhci_reset_ep(xhci, slotid, epid); + } + break; + case CR_SET_TR_DEQUEUE: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT) + & TRB_CR_EPID_MASK; + event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid, + trb.parameter); + } + break; + case CR_RESET_DEVICE: + slotid = xhci_get_slot(xhci, &event, &trb); + if (slotid) { + event.ccode = xhci_reset_slot(xhci, slotid); + } + break; + case CR_GET_PORT_BANDWIDTH: + event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter); + break; + case CR_VENDOR_VIA_CHALLENGE_RESPONSE: + xhci_via_challenge(trb.parameter); + break; + case CR_VENDOR_NEC_FIRMWARE_REVISION: + event.type = 48; /* NEC reply */ + event.length = 0x3025; + break; + case CR_VENDOR_NEC_CHALLENGE_RESPONSE: + { + uint32_t chi = trb.parameter >> 32; + uint32_t clo = trb.parameter; + uint32_t val = xhci_nec_challenge(chi, clo); + event.length = val & 0xFFFF; + event.epid = val >> 16; + slotid = val >> 24; + event.type = 48; /* NEC reply */ + } + break; + default: + fprintf(stderr, "xhci: unimplemented command %d\n", type); + event.ccode = CC_TRB_ERROR; + break; + } + event.slotid = slotid; + xhci_event(xhci, &event); + } +} + +static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) +{ + int nr = port->port.index + 1; + + port->portsc = PORTSC_PP; + if (port->port.dev && !is_detach) { + port->portsc |= PORTSC_CCS; + switch (port->port.dev->speed) { + case USB_SPEED_LOW: + port->portsc |= PORTSC_SPEED_LOW; + break; + case USB_SPEED_FULL: + port->portsc |= PORTSC_SPEED_FULL; + break; + case USB_SPEED_HIGH: + port->portsc |= PORTSC_SPEED_HIGH; + break; + } + } + + if (xhci_running(xhci)) { + port->portsc |= PORTSC_CSC; + XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; + xhci_event(xhci, &ev); + DPRINTF("xhci: port change event for port %d\n", nr); + } +} + +static void xhci_reset(void *opaque) +{ + XHCIState *xhci = opaque; + int i; + + DPRINTF("xhci: full reset\n"); + if (!(xhci->usbsts & USBSTS_HCH)) { + fprintf(stderr, "xhci: reset while running!\n"); + } + + xhci->usbcmd = 0; + xhci->usbsts = USBSTS_HCH; + xhci->dnctrl = 0; + xhci->crcr_low = 0; + xhci->crcr_high = 0; + xhci->dcbaap_low = 0; + xhci->dcbaap_high = 0; + xhci->config = 0; + xhci->devaddr = 2; + + for (i = 0; i < MAXSLOTS; i++) { + xhci_disable_slot(xhci, i+1); + } + + for (i = 0; i < MAXPORTS; i++) { + xhci_update_port(xhci, xhci->ports + i, 0); + } + + xhci->mfindex = 0; + xhci->iman = 0; + xhci->imod = 0; + xhci->erstsz = 0; + xhci->erstba_low = 0; + xhci->erstba_high = 0; + xhci->erdp_low = 0; + xhci->erdp_high = 0; + + xhci->er_ep_idx = 0; + xhci->er_pcs = 1; + xhci->er_full = 0; + xhci->ev_buffer_put = 0; + xhci->ev_buffer_get = 0; +} + +static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) +{ + DPRINTF("xhci_cap_read(0x%x)\n", reg); + + switch (reg) { + case 0x00: /* HCIVERSION, CAPLENGTH */ + return 0x01000000 | LEN_CAP; + case 0x04: /* HCSPARAMS 1 */ + return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; + case 0x08: /* HCSPARAMS 2 */ + return 0x0000000f; + case 0x0c: /* HCSPARAMS 3 */ + return 0x00000000; + case 0x10: /* HCCPARAMS */ +#if TARGET_PHYS_ADDR_BITS > 32 + return 0x00081001; +#else + return 0x00081000; +#endif + case 0x14: /* DBOFF */ + return OFF_DOORBELL; + case 0x18: /* RTSOFF */ + return OFF_RUNTIME; + + /* extended capabilities */ + case 0x20: /* Supported Protocol:00 */ +#if USB3_PORTS > 0 + return 0x02000402; /* USB 2.0 */ +#else + return 0x02000002; /* USB 2.0 */ +#endif + case 0x24: /* Supported Protocol:04 */ + return 0x20425455; /* "USB " */ + case 0x28: /* Supported Protocol:08 */ + return 0x00000001 | (USB2_PORTS<<8); + case 0x2c: /* Supported Protocol:0c */ + return 0x00000000; /* reserved */ +#if USB3_PORTS > 0 + case 0x30: /* Supported Protocol:00 */ + return 0x03000002; /* USB 3.0 */ + case 0x34: /* Supported Protocol:04 */ + return 0x20425455; /* "USB " */ + case 0x38: /* Supported Protocol:08 */ + return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); + case 0x3c: /* Supported Protocol:0c */ + return 0x00000000; /* reserved */ +#endif + default: + fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); + } + return 0; +} + +static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) +{ + uint32_t port = reg >> 4; + if (port >= MAXPORTS) { + fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); + return 0; + } + + switch (reg & 0xf) { + case 0x00: /* PORTSC */ + return xhci->ports[port].portsc; + case 0x04: /* PORTPMSC */ + case 0x08: /* PORTLI */ + return 0; + case 0x0c: /* reserved */ + default: + fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", + port, reg); + return 0; + } +} + +static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) +{ + uint32_t port = reg >> 4; + uint32_t portsc; + + if (port >= MAXPORTS) { + fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); + return; + } + + switch (reg & 0xf) { + case 0x00: /* PORTSC */ + portsc = xhci->ports[port].portsc; + /* write-1-to-clear bits*/ + portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC| + PORTSC_PRC|PORTSC_PLC|PORTSC_CEC)); + if (val & PORTSC_LWS) { + /* overwrite PLS only when LWS=1 */ + portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT); + portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT); + } + /* read/write bits */ + portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE); + portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE)); + /* write-1-to-start bits */ + if (val & PORTSC_PR) { + DPRINTF("xhci: port %d reset\n", port); + if (xhci->ports[port].port.dev) { + usb_send_msg(xhci->ports[port].port.dev, USB_MSG_RESET); + } + portsc |= PORTSC_PRC | PORTSC_PED; + } + xhci->ports[port].portsc = portsc; + break; + case 0x04: /* PORTPMSC */ + case 0x08: /* PORTLI */ + default: + fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n", + port, reg); + } +} + +static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) +{ + DPRINTF("xhci_oper_read(0x%x)\n", reg); + + if (reg >= 0x400) { + return xhci_port_read(xhci, reg - 0x400); + } + + switch (reg) { + case 0x00: /* USBCMD */ + return xhci->usbcmd; + case 0x04: /* USBSTS */ + return xhci->usbsts; + case 0x08: /* PAGESIZE */ + return 1; /* 4KiB */ + case 0x14: /* DNCTRL */ + return xhci->dnctrl; + case 0x18: /* CRCR low */ + return xhci->crcr_low & ~0xe; + case 0x1c: /* CRCR high */ + return xhci->crcr_high; + case 0x30: /* DCBAAP low */ + return xhci->dcbaap_low; + case 0x34: /* DCBAAP high */ + return xhci->dcbaap_high; + case 0x38: /* CONFIG */ + return xhci->config; + default: + fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); + } + return 0; +} + +static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) +{ + DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val); + + if (reg >= 0x400) { + xhci_port_write(xhci, reg - 0x400, val); + return; + } + + switch (reg) { + case 0x00: /* USBCMD */ + if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) { + xhci_run(xhci); + } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) { + xhci_stop(xhci); + } + xhci->usbcmd = val & 0xc0f; + if (val & USBCMD_HCRST) { + xhci_reset(xhci); + } + xhci_irq_update(xhci); + break; + + case 0x04: /* USBSTS */ + /* these bits are write-1-to-clear */ + xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE)); + xhci_irq_update(xhci); + break; + + case 0x14: /* DNCTRL */ + xhci->dnctrl = val & 0xffff; + break; + case 0x18: /* CRCR low */ + xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR); + break; + case 0x1c: /* CRCR high */ + xhci->crcr_high = val; + if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { + XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; + xhci->crcr_low &= ~CRCR_CRR; + xhci_event(xhci, &event); + DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); + } else { + target_phys_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); + xhci_ring_init(xhci, &xhci->cmd_ring, base); + } + xhci->crcr_low &= ~(CRCR_CA | CRCR_CS); + break; + case 0x30: /* DCBAAP low */ + xhci->dcbaap_low = val & 0xffffffc0; + break; + case 0x34: /* DCBAAP high */ + xhci->dcbaap_high = val; + break; + case 0x38: /* CONFIG */ + xhci->config = val & 0xff; + break; + default: + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); + } +} + +static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) +{ + DPRINTF("xhci_runtime_read(0x%x)\n", reg); + + switch (reg) { + case 0x00: /* MFINDEX */ + fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); + return xhci->mfindex; + case 0x20: /* IMAN */ + return xhci->iman; + case 0x24: /* IMOD */ + return xhci->imod; + case 0x28: /* ERSTSZ */ + return xhci->erstsz; + case 0x30: /* ERSTBA low */ + return xhci->erstba_low; + case 0x34: /* ERSTBA high */ + return xhci->erstba_high; + case 0x38: /* ERDP low */ + return xhci->erdp_low; + case 0x3c: /* ERDP high */ + return xhci->erdp_high; + default: + fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); + } + return 0; +} + +static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) +{ + DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val); + + switch (reg) { + case 0x20: /* IMAN */ + if (val & IMAN_IP) { + xhci->iman &= ~IMAN_IP; + } + xhci->iman &= ~IMAN_IE; + xhci->iman |= val & IMAN_IE; + xhci_irq_update(xhci); + break; + case 0x24: /* IMOD */ + xhci->imod = val; + break; + case 0x28: /* ERSTSZ */ + xhci->erstsz = val & 0xffff; + break; + case 0x30: /* ERSTBA low */ + /* XXX NEC driver bug: it doesn't align this to 64 bytes + xhci->erstba_low = val & 0xffffffc0; */ + xhci->erstba_low = val & 0xfffffff0; + break; + case 0x34: /* ERSTBA high */ + xhci->erstba_high = val; + xhci_er_reset(xhci); + break; + case 0x38: /* ERDP low */ + if (val & ERDP_EHB) { + xhci->erdp_low &= ~ERDP_EHB; + } + xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB); + break; + case 0x3c: /* ERDP high */ + xhci->erdp_high = val; + xhci_events_update(xhci); + break; + default: + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); + } +} + +static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) +{ + DPRINTF("xhci_doorbell_read(0x%x)\n", reg); + /* doorbells always read as 0 */ + return 0; +} + +static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) +{ + DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val); + + if (!xhci_running(xhci)) { + fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n"); + return; + } + + reg >>= 2; + + if (reg == 0) { + if (val == 0) { + xhci_process_commands(xhci); + } else { + fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val); + } + } else { + if (reg > MAXSLOTS) { + fprintf(stderr, "xhci: bad doorbell %d\n", reg); + } else if (val > 31) { + fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val); + } else { + xhci_kick_ep(xhci, reg, val); + } + } +} + +static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr, + unsigned size) +{ + XHCIState *xhci = ptr; + + /* Only aligned reads are allowed on xHCI */ + if (addr & 3) { + fprintf(stderr, "xhci_mem_read: Mis-aligned read\n"); + return 0; + } + + if (addr < LEN_CAP) { + return xhci_cap_read(xhci, addr); + } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { + return xhci_oper_read(xhci, addr - OFF_OPER); + } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { + return xhci_runtime_read(xhci, addr - OFF_RUNTIME); + } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { + return xhci_doorbell_read(xhci, addr - OFF_DOORBELL); + } else { + fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr); + return 0; + } +} + +static void xhci_mem_write(void *ptr, target_phys_addr_t addr, + uint64_t val, unsigned size) +{ + XHCIState *xhci = ptr; + + /* Only aligned writes are allowed on xHCI */ + if (addr & 3) { + fprintf(stderr, "xhci_mem_write: Mis-aligned write\n"); + return; + } + + if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { + xhci_oper_write(xhci, addr - OFF_OPER, val); + } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { + xhci_runtime_write(xhci, addr - OFF_RUNTIME, val); + } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { + xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val); + } else { + fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr); + } +} + +static const MemoryRegionOps xhci_mem_ops = { + .read = xhci_mem_read, + .write = xhci_mem_write, + .valid.min_access_size = 4, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void xhci_attach(USBPort *usbport) +{ + XHCIState *xhci = usbport->opaque; + XHCIPort *port = &xhci->ports[usbport->index]; + + xhci_update_port(xhci, port, 0); +} + +static void xhci_detach(USBPort *usbport) +{ + XHCIState *xhci = usbport->opaque; + XHCIPort *port = &xhci->ports[usbport->index]; + + xhci_update_port(xhci, port, 1); +} + +static void xhci_complete(USBPort *port, USBPacket *packet) +{ + XHCITransfer *xfer = container_of(packet, XHCITransfer, packet); + + xhci_complete_packet(xfer, packet->result); + xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid); +} + +static void xhci_child_detach(USBPort *port, USBDevice *child) +{ + FIXME(); +} + +static USBPortOps xhci_port_ops = { + .attach = xhci_attach, + .detach = xhci_detach, + .complete = xhci_complete, + .child_detach = xhci_child_detach, +}; + +static USBBusOps xhci_bus_ops = { +}; + +static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) +{ + int i; + + xhci->usbsts = USBSTS_HCH; + + usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev); + + for (i = 0; i < MAXPORTS; i++) { + memset(&xhci->ports[i], 0, sizeof(xhci->ports[i])); + usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i, + &xhci_port_ops, USB_SPEED_MASK_HIGH); + } + for (i = 0; i < MAXSLOTS; i++) { + xhci->slots[i].enabled = 0; + } + + qemu_register_reset(xhci_reset, xhci); +} + +static int usb_xhci_initfn(struct PCIDevice *dev) +{ + int ret; + + XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); + + xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30; /* xHCI */ + xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */ + xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10; + xhci->pci_dev.config[0x60] = 0x30; /* release number */ + + usb_xhci_init(xhci, &dev->qdev); + + xhci->irq = xhci->pci_dev.irq[0]; + + memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, + "xhci", LEN_REGS); + pci_register_bar(&xhci->pci_dev, 0, + PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, + &xhci->mem); + + ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0); + assert(ret >= 0); + + if (xhci->msi) { + ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false); + assert(ret >= 0); + } + + return 0; +} + +static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, + int len) +{ + XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); + + pci_default_write_config(dev, addr, val, len); + if (xhci->msi) { + msi_write_config(dev, addr, val, len); + } +} + +static const VMStateDescription vmstate_xhci = { + .name = "xhci", + .unmigratable = 1, +}; + +static Property xhci_properties[] = { + DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xhci_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_xhci; + dc->props = xhci_properties; + k->init = usb_xhci_initfn; + k->vendor_id = PCI_VENDOR_ID_NEC; + k->device_id = PCI_DEVICE_ID_NEC_UPD720200; + k->class_id = PCI_CLASS_SERIAL_USB; + k->revision = 0x03; + k->is_express = 1; + k->config_write = xhci_write_config; +} + +static TypeInfo xhci_info = { + .name = "nec-usb-xhci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(XHCIState), + .class_init = xhci_class_init, +}; + +static void xhci_register(void) +{ + type_register_static(&xhci_info); +} +device_init(xhci_register); @@ -95,8 +95,8 @@ static int do_token_setup(USBDevice *s, USBPacket *p) index = (s->setup_buf[5] << 8) | s->setup_buf[4]; if (s->setup_buf[0] & USB_DIR_IN) { - ret = s->info->handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); + ret = usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); if (ret == USB_RET_ASYNC) { s->setup_state = SETUP_STATE_SETUP; return USB_RET_ASYNC; @@ -129,7 +129,7 @@ static int do_token_in(USBDevice *s, USBPacket *p) int ret = 0; if (p->devep != 0) - return s->info->handle_data(s, p); + return usb_device_handle_data(s, p); request = (s->setup_buf[0] << 8) | s->setup_buf[1]; value = (s->setup_buf[3] << 8) | s->setup_buf[2]; @@ -138,8 +138,8 @@ static int do_token_in(USBDevice *s, USBPacket *p) switch(s->setup_state) { case SETUP_STATE_ACK: if (!(s->setup_buf[0] & USB_DIR_IN)) { - ret = s->info->handle_control(s, p, request, value, index, - s->setup_len, s->data_buf); + ret = usb_device_handle_control(s, p, request, value, index, + s->setup_len, s->data_buf); if (ret == USB_RET_ASYNC) { return USB_RET_ASYNC; } @@ -176,7 +176,7 @@ static int do_token_in(USBDevice *s, USBPacket *p) static int do_token_out(USBDevice *s, USBPacket *p) { if (p->devep != 0) - return s->info->handle_data(s, p); + return usb_device_handle_data(s, p); switch(s->setup_state) { case SETUP_STATE_ACK: @@ -220,9 +220,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) switch(p->pid) { case USB_MSG_ATTACH: s->state = USB_STATE_ATTACHED; - if (s->info->handle_attach) { - s->info->handle_attach(s); - } + usb_device_handle_attach(s); return 0; case USB_MSG_DETACH: @@ -233,9 +231,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p) s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - if (s->info->handle_reset) { - s->info->handle_reset(s); - } + usb_device_handle_reset(s); return 0; } @@ -326,10 +322,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) int ret; assert(p->owner == NULL); - ret = dev->info->handle_packet(dev, p); + ret = usb_device_handle_packet(dev, p); if (ret == USB_RET_ASYNC) { if (p->owner == NULL) { - p->owner = dev; + p->owner = usb_ep_get(dev, p->pid, p->devep); } else { /* We'll end up here when usb_handle_packet is called * recursively due to a hub being in the chain. Nothing @@ -357,7 +353,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p) void usb_cancel_packet(USBPacket * p) { assert(p->owner != NULL); - p->owner->info->cancel_packet(p->owner, p); + usb_device_cancel_packet(p->owner->dev, p); p->owner = NULL; } @@ -414,3 +410,124 @@ void usb_packet_cleanup(USBPacket *p) { qemu_iovec_destroy(&p->iov); } + +void usb_ep_init(USBDevice *dev) +{ + int ep; + + dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL; + dev->ep_ctl.ifnum = 0; + dev->ep_ctl.dev = dev; + for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { + dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID; + dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID; + dev->ep_in[ep].ifnum = 0; + dev->ep_out[ep].ifnum = 0; + dev->ep_in[ep].dev = dev; + dev->ep_out[ep].dev = dev; + } +} + +void usb_ep_dump(USBDevice *dev) +{ + static const char *tname[] = { + [USB_ENDPOINT_XFER_CONTROL] = "control", + [USB_ENDPOINT_XFER_ISOC] = "isoc", + [USB_ENDPOINT_XFER_BULK] = "bulk", + [USB_ENDPOINT_XFER_INT] = "int", + }; + int ifnum, ep, first; + + fprintf(stderr, "Device \"%s\", config %d\n", + dev->product_desc, dev->configuration); + for (ifnum = 0; ifnum < 16; ifnum++) { + first = 1; + for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { + if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID && + dev->ep_in[ep].ifnum == ifnum) { + if (first) { + first = 0; + fprintf(stderr, " Interface %d, alternative %d\n", + ifnum, dev->altsetting[ifnum]); + } + fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep, + tname[dev->ep_in[ep].type], + dev->ep_in[ep].max_packet_size); + } + if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID && + dev->ep_out[ep].ifnum == ifnum) { + if (first) { + first = 0; + fprintf(stderr, " Interface %d, alternative %d\n", + ifnum, dev->altsetting[ifnum]); + } + fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep, + tname[dev->ep_out[ep].type], + dev->ep_out[ep].max_packet_size); + } + } + } + fprintf(stderr, "--\n"); +} + +struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out; + if (ep == 0) { + return &dev->ep_ctl; + } + assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT); + assert(ep > 0 && ep <= USB_MAX_ENDPOINTS); + return eps + ep - 1; +} + +uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + return uep->type; +} + +void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + uep->type = type; +} + +uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + return uep->ifnum; +} + +void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + uep->ifnum = ifnum; +} + +void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, + uint16_t raw) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + int size, microframes; + + size = raw & 0x7ff; + switch ((raw >> 11) & 3) { + case 1: + microframes = 2; + break; + case 2: + microframes = 3; + break; + default: + microframes = 1; + break; + } + uep->max_packet_size = size * microframes; +} + +int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + return uep->max_packet_size; +} @@ -1,3 +1,6 @@ +#ifndef QEMU_USB_H +#define QEMU_USB_H + /* * QEMU USB API * @@ -79,6 +82,11 @@ #define USB_CLASS_APP_SPEC 0xfe #define USB_CLASS_VENDOR_SPEC 0xff +#define USB_SUBCLASS_UNDEFINED 0 +#define USB_SUBCLASS_AUDIO_CONTROL 1 +#define USB_SUBCLASS_AUDIO_STREAMING 2 +#define USB_SUBCLASS_AUDIO_MIDISTREAMING 3 + #define USB_DIR_OUT 0 #define USB_DIR_IN 0x80 @@ -132,18 +140,21 @@ #define USB_DT_OTHER_SPEED_CONFIG 0x07 #define USB_DT_DEBUG 0x0A #define USB_DT_INTERFACE_ASSOC 0x0B +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 #define USB_ENDPOINT_XFER_CONTROL 0 #define USB_ENDPOINT_XFER_ISOC 1 #define USB_ENDPOINT_XFER_BULK 2 #define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_XFER_INVALID 255 typedef struct USBBus USBBus; typedef struct USBBusOps USBBusOps; typedef struct USBPort USBPort; typedef struct USBDevice USBDevice; -typedef struct USBDeviceInfo USBDeviceInfo; typedef struct USBPacket USBPacket; +typedef struct USBEndpoint USBEndpoint; typedef struct USBDesc USBDesc; typedef struct USBDescID USBDescID; @@ -161,10 +172,19 @@ struct USBDescString { QLIST_ENTRY(USBDescString) next; }; +#define USB_MAX_ENDPOINTS 15 +#define USB_MAX_INTERFACES 16 + +struct USBEndpoint { + uint8_t type; + uint8_t ifnum; + int max_packet_size; + USBDevice *dev; +}; + /* definition of a USB device */ struct USBDevice { DeviceState qdev; - USBDeviceInfo *info; USBPort *port; char *port_path; void *opaque; @@ -186,13 +206,31 @@ struct USBDevice { int32_t setup_len; int32_t setup_index; + USBEndpoint ep_ctl; + USBEndpoint ep_in[USB_MAX_ENDPOINTS]; + USBEndpoint ep_out[USB_MAX_ENDPOINTS]; + QLIST_HEAD(, USBDescString) strings; const USBDescDevice *device; + + int configuration; + int ninterfaces; + int altsetting[USB_MAX_INTERFACES]; const USBDescConfig *config; + const USBDescIface *ifaces[USB_MAX_INTERFACES]; }; -struct USBDeviceInfo { - DeviceInfo qdev; +#define TYPE_USB_DEVICE "usb-device" +#define USB_DEVICE(obj) \ + OBJECT_CHECK(USBDevice, (obj), TYPE_USB_DEVICE) +#define USB_DEVICE_CLASS(klass) \ + OBJECT_CLASS_CHECK(USBDeviceClass, (klass), TYPE_USB_DEVICE) +#define USB_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(USBDeviceClass, (obj), TYPE_USB_DEVICE) + +typedef struct USBDeviceClass { + DeviceClass parent_class; + int (*init)(USBDevice *dev); /* @@ -241,13 +279,12 @@ struct USBDeviceInfo { */ int (*handle_data)(USBDevice *dev, USBPacket *p); + void (*set_interface)(USBDevice *dev, int interface, + int alt_old, int alt_new); + const char *product_desc; const USBDesc *usb_desc; - - /* handle legacy -usbdevice command line options */ - const char *usbdevice_name; - USBDevice *(*usbdevice_init)(const char *params); -}; +} USBDeviceClass; typedef struct USBPortOps { void (*attach)(USBPort *port); @@ -288,7 +325,7 @@ struct USBPacket { QEMUIOVector iov; int result; /* transfer length or USB_RET_* status code */ /* Internal use by the USB layer. */ - USBDevice *owner; + USBEndpoint *owner; }; void usb_packet_init(USBPacket *p); @@ -304,6 +341,17 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p); void usb_packet_complete(USBDevice *dev, USBPacket *p); void usb_cancel_packet(USBPacket * p); +void usb_ep_init(USBDevice *dev); +void usb_ep_dump(USBDevice *dev); +struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep); +uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep); +uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep); +void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type); +void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum); +void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, + uint16_t raw); +int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); + void usb_attach(USBPort *port); void usb_detach(USBPort *port); void usb_reset(USBPort *port); @@ -370,8 +418,8 @@ struct USBBusOps { void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host); USBBus *usb_bus_find(int busnr); -void usb_qdev_register(USBDeviceInfo *info); -void usb_qdev_register_many(USBDeviceInfo *info); +void usb_legacy_register(const char *typename, const char *usbdevice_name, + USBDevice *(*usbdevice_init)(const char *params)); USBDevice *usb_create(USBBus *bus, const char *name); USBDevice *usb_create_simple(USBBus *bus, const char *name); USBDevice *usbdevice_create(const char *cmdline); @@ -403,4 +451,25 @@ extern const VMStateDescription vmstate_usb_device; .offset = vmstate_offset_value(_state, _field, USBDevice), \ } +int usb_device_handle_packet(USBDevice *dev, USBPacket *p); + +void usb_device_cancel_packet(USBDevice *dev, USBPacket *p); + +void usb_device_handle_attach(USBDevice *dev); + +void usb_device_handle_reset(USBDevice *dev); + +int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value, + int index, int length, uint8_t *data); + +int usb_device_handle_data(USBDevice *dev, USBPacket *p); + +void usb_device_set_interface(USBDevice *dev, int interface, + int alt_old, int alt_new); + +const char *usb_device_get_product_desc(USBDevice *dev); + +const USBDesc *usb_device_get_usb_desc(USBDevice *dev); + +#endif diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index a285f7f383..c4105e977b 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -109,22 +109,56 @@ static int versatile_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo versatile_pci_host_info = { - .qdev.name = "versatile_pci_host", - .qdev.size = sizeof(PCIDevice), - .init = versatile_pci_host_init, - .vendor_id = PCI_VENDOR_ID_XILINX, - /* Both boards have the same device ID. Oh well. */ - .device_id = PCI_DEVICE_ID_XILINX_XC2VP30, - .class_id = PCI_CLASS_PROCESSOR_CO, +static void versatile_pci_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = versatile_pci_host_init; + k->vendor_id = PCI_VENDOR_ID_XILINX; + k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30; + k->class_id = PCI_CLASS_PROCESSOR_CO; +} + +static TypeInfo versatile_pci_host_info = { + .name = "versatile_pci_host", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIDevice), + .class_init = versatile_pci_host_class_init, +}; + +static void pci_vpb_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pci_vpb_init; +} + +static TypeInfo pci_vpb_info = { + .name = "versatile_pci", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PCIVPBState), + .class_init = pci_vpb_class_init, +}; + +static void pci_realview_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = pci_realview_init; +} + +static TypeInfo pci_realview_info = { + .name = "realview_pci", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PCIVPBState), + .class_init = pci_realview_class_init, }; static void versatile_pci_register_devices(void) { - sysbus_register_dev("versatile_pci", sizeof(PCIVPBState), pci_vpb_init); - sysbus_register_dev("realview_pci", sizeof(PCIVPBState), - pci_realview_init); - pci_qdev_register(&versatile_pci_host_info); + type_register_static(&pci_vpb_info); + type_register_static(&pci_realview_info); + type_register_static(&versatile_pci_host_info); } device_init(versatile_pci_register_devices) diff --git a/hw/versatilepb.c b/hw/versatilepb.c index 0312b7564a..6e28e78f44 100644 --- a/hw/versatilepb.c +++ b/hw/versatilepb.c @@ -365,17 +365,26 @@ static void versatile_machine_init(void) machine_init(versatile_machine_init); -static SysBusDeviceInfo vpb_sic_info = { - .init = vpb_sic_init, - .qdev.name = "versatilepb_sic", - .qdev.size = sizeof(vpb_sic_state), - .qdev.vmsd = &vmstate_vpb_sic, - .qdev.no_user = 1, +static void vpb_sic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = vpb_sic_init; + dc->no_user = 1; + dc->vmsd = &vmstate_vpb_sic; +} + +static TypeInfo vpb_sic_info = { + .name = "versatilepb_sic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(vpb_sic_state), + .class_init = vpb_sic_class_init, }; static void versatilepb_register_devices(void) { - sysbus_register_withprop(&vpb_sic_info); + type_register_static(&vpb_sic_info); } device_init(versatilepb_register_devices) diff --git a/hw/vexpress.c b/hw/vexpress.c index 71115564e0..64fab4574c 100644 --- a/hw/vexpress.c +++ b/hw/vexpress.c @@ -182,6 +182,7 @@ static void vexpress_a9_init(ram_addr_t ram_size, /* 0x100ec000 TrustZone Address Space Controller */ /* 0x10200000 CoreSight debug APB */ /* 0x1e00a000 PL310 L2 Cache Controller */ + sysbus_create_varargs("l2x0", 0x1e00a000, NULL); /* CS0: NOR0 flash : 0x40000000 .. 0x44000000 */ /* CS4: NOR1 flash : 0x44000000 .. 0x48000000 */ diff --git a/hw/vga-isa.c b/hw/vga-isa.c index 4825313f67..8d3ff0d47b 100644 --- a/hw/vga-isa.c +++ b/hw/vga-isa.c @@ -69,16 +69,24 @@ static int vga_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo vga_info = { - .qdev.name = "isa-vga", - .qdev.size = sizeof(ISAVGAState), - .qdev.vmsd = &vmstate_vga_common, - .qdev.reset = vga_reset_isa, - .init = vga_initfn, +static void vga_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = vga_initfn; + dc->reset = vga_reset_isa; + dc->vmsd = &vmstate_vga_common; +} + +static TypeInfo vga_info = { + .name = "isa-vga", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(ISAVGAState), + .class_init = vga_class_initfn, }; static void vga_register(void) { - isa_qdev_register(&vga_info); + type_register_static(&vga_info); } device_init(vga_register) diff --git a/hw/vga-pci.c b/hw/vga-pci.c index a75dbf3974..974a7a9d6f 100644 --- a/hw/vga-pci.c +++ b/hw/vga-pci.c @@ -75,22 +75,29 @@ DeviceState *pci_vga_init(PCIBus *bus) return &pci_create_simple(bus, -1, "VGA")->qdev; } -static PCIDeviceInfo vga_info = { - .qdev.name = "VGA", - .qdev.size = sizeof(PCIVGAState), - .qdev.vmsd = &vmstate_vga_pci, - .no_hotplug = 1, - .init = pci_vga_initfn, - .romfile = "vgabios-stdvga.bin", +static void vga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = pci_vga_initfn; + k->romfile = "vgabios-stdvga.bin"; + k->vendor_id = PCI_VENDOR_ID_QEMU; + k->device_id = PCI_DEVICE_ID_QEMU_VGA; + k->class_id = PCI_CLASS_DISPLAY_VGA; + dc->vmsd = &vmstate_vga_pci; +} - /* dummy VGA (same as Bochs ID) */ - .vendor_id = PCI_VENDOR_ID_QEMU, - .device_id = PCI_DEVICE_ID_QEMU_VGA, - .class_id = PCI_CLASS_DISPLAY_VGA, +static TypeInfo vga_info = { + .name = "VGA", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIVGAState), + .class_init = vga_class_init, }; static void vga_register(void) { - pci_qdev_register(&vga_info); + type_register_static(&vga_info); } device_init(vga_register); @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" +#include "vga.h" #include "console.h" #include "pc.h" #include "pci.h" @@ -36,6 +37,18 @@ //#define DEBUG_BOCHS_VBE +/* + * Video Graphics Array (VGA) + * + * Chipset docs for original IBM VGA: + * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf + * + * FreeVGA site: + * http://www.osdever.net/FreeVGA/home.htm + * + * Standard VGA features and Bochs VBE extensions are implemented. + */ + /* force some bits to zero */ const uint8_t sr_mask[8] = { 0x03, @@ -160,9 +173,10 @@ static void vga_update_memory_access(VGACommonState *s) s->chain4_alias = NULL; - if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) { + if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) == + VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { offset = 0; - switch ((s->gr[6] >> 2) & 3) { + switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) { case 0: base = 0xa0000; size = 0x20000; @@ -223,22 +237,20 @@ static void vga_precise_update_retrace_info(VGACommonState *s) int64_t chars_per_sec; struct vga_precise_retrace *r = &s->retrace_info.precise; - htotal_chars = s->cr[0x00] + 5; - hretr_start_char = s->cr[0x04]; - hretr_skew_chars = (s->cr[0x05] >> 5) & 3; - hretr_end_char = s->cr[0x05] & 0x1f; + htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5; + hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START]; + hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3; + hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f; - vtotal_lines = (s->cr[0x06] - | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2 - ; - vretr_start_line = s->cr[0x10] - | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8) - ; - vretr_end_line = s->cr[0x11] & 0xf; + vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] | + (((s->cr[VGA_CRTC_OVERFLOW] & 1) | + ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2; + vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] | + ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) | + ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8); + vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf; - - - clocking_mode = (s->sr[0x01] >> 3) & 1; + clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1; clock_sel = (s->msr >> 2) & 3; dots = (s->msr & 1) ? 8 : 9; @@ -261,8 +273,8 @@ static void vga_precise_update_retrace_info(VGACommonState *s) r->htotal = htotal_chars; #if 0 - div2 = (s->cr[0x17] >> 2) & 1; - sldiv2 = (s->cr[0x17] >> 3) & 1; + div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1; + sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1; printf ( "hz=%f\n" "htotal = %d\n" @@ -332,7 +344,7 @@ static uint8_t vga_dumb_retrace(VGACommonState *s) int vga_ioport_invalid(VGACommonState *s, uint32_t addr) { - if (s->msr & MSR_COLOR_EMULATION) { + if (s->msr & VGA_MIS_COLOR) { /* Color */ return (addr >= 0x3b0 && addr <= 0x3bf); } else { @@ -350,73 +362,74 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr) val = 0xff; } else { switch(addr) { - case 0x3c0: + case VGA_ATT_W: if (s->ar_flip_flop == 0) { val = s->ar_index; } else { val = 0; } break; - case 0x3c1: + case VGA_ATT_R: index = s->ar_index & 0x1f; - if (index < 21) + if (index < VGA_ATT_C) { val = s->ar[index]; - else + } else { val = 0; + } break; - case 0x3c2: + case VGA_MIS_W: val = s->st00; break; - case 0x3c4: + case VGA_SEQ_I: val = s->sr_index; break; - case 0x3c5: + case VGA_SEQ_D: val = s->sr[s->sr_index]; #ifdef DEBUG_VGA_REG printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); #endif break; - case 0x3c7: + case VGA_PEL_IR: val = s->dac_state; break; - case 0x3c8: + case VGA_PEL_IW: val = s->dac_write_index; break; - case 0x3c9: + case VGA_PEL_D: val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; if (++s->dac_sub_index == 3) { s->dac_sub_index = 0; s->dac_read_index++; } break; - case 0x3ca: + case VGA_FTC_R: val = s->fcr; break; - case 0x3cc: + case VGA_MIS_R: val = s->msr; break; - case 0x3ce: + case VGA_GFX_I: val = s->gr_index; break; - case 0x3cf: + case VGA_GFX_D: val = s->gr[s->gr_index]; #ifdef DEBUG_VGA_REG printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); #endif break; - case 0x3b4: - case 0x3d4: + case VGA_CRT_IM: + case VGA_CRT_IC: val = s->cr_index; break; - case 0x3b5: - case 0x3d5: + case VGA_CRT_DM: + case VGA_CRT_DC: val = s->cr[s->cr_index]; #ifdef DEBUG_VGA_REG printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); #endif break; - case 0x3ba: - case 0x3da: + case VGA_IS1_RM: + case VGA_IS1_RC: /* just toggle to fool polling */ val = s->st01 = s->retrace(s); s->ar_flip_flop = 0; @@ -446,29 +459,29 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) #endif switch(addr) { - case 0x3c0: + case VGA_ATT_W: if (s->ar_flip_flop == 0) { val &= 0x3f; s->ar_index = val; } else { index = s->ar_index & 0x1f; switch(index) { - case 0x00 ... 0x0f: + case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF: s->ar[index] = val & 0x3f; break; - case 0x10: + case VGA_ATC_MODE: s->ar[index] = val & ~0x10; break; - case 0x11: + case VGA_ATC_OVERSCAN: s->ar[index] = val; break; - case 0x12: + case VGA_ATC_PLANE_ENABLE: s->ar[index] = val & ~0xc0; break; - case 0x13: + case VGA_ATC_PEL: s->ar[index] = val & ~0xf0; break; - case 0x14: + case VGA_ATC_COLOR_PAGE: s->ar[index] = val & ~0xf0; break; default: @@ -477,32 +490,34 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) } s->ar_flip_flop ^= 1; break; - case 0x3c2: + case VGA_MIS_W: s->msr = val & ~0x10; s->update_retrace_info(s); break; - case 0x3c4: + case VGA_SEQ_I: s->sr_index = val & 7; break; - case 0x3c5: + case VGA_SEQ_D: #ifdef DEBUG_VGA_REG printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); #endif s->sr[s->sr_index] = val & sr_mask[s->sr_index]; - if (s->sr_index == 1) s->update_retrace_info(s); + if (s->sr_index == VGA_SEQ_CLOCK_MODE) { + s->update_retrace_info(s); + } vga_update_memory_access(s); break; - case 0x3c7: + case VGA_PEL_IR: s->dac_read_index = val; s->dac_sub_index = 0; s->dac_state = 3; break; - case 0x3c8: + case VGA_PEL_IW: s->dac_write_index = val; s->dac_sub_index = 0; s->dac_state = 0; break; - case 0x3c9: + case VGA_PEL_D: s->dac_cache[s->dac_sub_index] = val; if (++s->dac_sub_index == 3) { memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); @@ -510,48 +525,51 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) s->dac_write_index++; } break; - case 0x3ce: + case VGA_GFX_I: s->gr_index = val & 0x0f; break; - case 0x3cf: + case VGA_GFX_D: #ifdef DEBUG_VGA_REG printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); #endif s->gr[s->gr_index] = val & gr_mask[s->gr_index]; vga_update_memory_access(s); break; - case 0x3b4: - case 0x3d4: + case VGA_CRT_IM: + case VGA_CRT_IC: s->cr_index = val; break; - case 0x3b5: - case 0x3d5: + case VGA_CRT_DM: + case VGA_CRT_DC: #ifdef DEBUG_VGA_REG printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); #endif /* handle CR0-7 protection */ - if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { + if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) && + s->cr_index <= VGA_CRTC_OVERFLOW) { /* can always write bit 4 of CR7 */ - if (s->cr_index == 7) - s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); + if (s->cr_index == VGA_CRTC_OVERFLOW) { + s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) | + (val & 0x10); + } return; } s->cr[s->cr_index] = val; switch(s->cr_index) { - case 0x00: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x11: - case 0x17: + case VGA_CRTC_H_TOTAL: + case VGA_CRTC_H_SYNC_START: + case VGA_CRTC_H_SYNC_END: + case VGA_CRTC_V_TOTAL: + case VGA_CRTC_OVERFLOW: + case VGA_CRTC_V_SYNC_END: + case VGA_CRTC_MODE: s->update_retrace_info(s); break; } break; - case 0x3ba: - case 0x3da: + case VGA_IS1_RM: + case VGA_IS1_RC: s->fcr = val & 0x10; break; } @@ -681,31 +699,37 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) /* we initialize the VGA graphic mode (should be done in BIOS) */ - s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ - s->cr[0x17] |= 3; /* no CGA modes */ - s->cr[0x13] = s->vbe_line_offset >> 3; + /* graphic mode + memory map 1 */ + s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 | + VGA_GR06_GRAPHICS_MODE; + s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */ + s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3; /* width */ - s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; + s->cr[VGA_CRTC_H_DISP] = + (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; /* height (only meaningful if < 1024) */ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; - s->cr[0x12] = h; - s->cr[0x07] = (s->cr[0x07] & ~0x42) | + s->cr[VGA_CRTC_V_DISP_END] = h; + s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) | ((h >> 7) & 0x02) | ((h >> 3) & 0x40); /* line compare to 1023 */ - s->cr[0x18] = 0xff; - s->cr[0x07] |= 0x10; - s->cr[0x09] |= 0x40; + s->cr[VGA_CRTC_LINE_COMPARE] = 0xff; + s->cr[VGA_CRTC_OVERFLOW] |= 0x10; + s->cr[VGA_CRTC_MAX_SCAN] |= 0x40; if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { shift_control = 0; - s->sr[0x01] &= ~8; /* no double line */ + s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */ } else { shift_control = 2; - s->sr[4] |= 0x08; /* set chain 4 mode */ - s->sr[2] |= 0x0f; /* activate all planes */ + /* set chain 4 mode */ + s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M; + /* activate all planes */ + s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES; } - s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); - s->cr[0x09] &= ~0x9f; /* no double scan */ + s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) | + (shift_control << 5); + s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */ } else { /* XXX: the bios should do that */ s->bank_offset = 0; @@ -762,7 +786,7 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr) uint32_t ret; /* convert to VGA memory offset */ - memory_map_mode = (s->gr[6] >> 2) & 3; + memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3; addr &= 0x1ffff; switch(memory_map_mode) { case 0: @@ -785,24 +809,25 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr) break; } - if (s->sr[4] & 0x08) { + if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { /* chain 4 mode : simplest access */ ret = s->vram_ptr[addr]; - } else if (s->gr[5] & 0x10) { + } else if (s->gr[VGA_GFX_MODE] & 0x10) { /* odd/even mode (aka text mode mapping) */ - plane = (s->gr[4] & 2) | (addr & 1); + plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); ret = s->vram_ptr[((addr & ~1) << 1) | plane]; } else { /* standard VGA latched access */ s->latch = ((uint32_t *)s->vram_ptr)[addr]; - if (!(s->gr[5] & 0x08)) { + if (!(s->gr[VGA_GFX_MODE] & 0x08)) { /* read mode 0 */ - plane = s->gr[4]; + plane = s->gr[VGA_GFX_PLANE_READ]; ret = GET_PLANE(s->latch, plane); } else { /* read mode 1 */ - ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]]; + ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) & + mask16[s->gr[VGA_GFX_COMPARE_MASK]]; ret |= ret >> 16; ret |= ret >> 8; ret = (~ret) & 0xff; @@ -821,7 +846,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val) printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val); #endif /* convert to VGA memory offset */ - memory_map_mode = (s->gr[6] >> 2) & 3; + memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3; addr &= 0x1ffff; switch(memory_map_mode) { case 0: @@ -844,67 +869,68 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val) break; } - if (s->sr[4] & 0x08) { + if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) { /* chain 4 mode : simplest access */ plane = addr & 3; mask = (1 << plane); - if (s->sr[2] & mask) { + if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr); #endif s->plane_updated |= mask; /* only used to detect font change */ - memory_region_set_dirty(&s->vram, addr); + memory_region_set_dirty(&s->vram, addr, 1); } - } else if (s->gr[5] & 0x10) { + } else if (s->gr[VGA_GFX_MODE] & 0x10) { /* odd/even mode (aka text mode mapping) */ - plane = (s->gr[4] & 2) | (addr & 1); + plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1); mask = (1 << plane); - if (s->sr[2] & mask) { + if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) { addr = ((addr & ~1) << 1) | plane; s->vram_ptr[addr] = val; #ifdef DEBUG_VGA_MEM printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr); #endif s->plane_updated |= mask; /* only used to detect font change */ - memory_region_set_dirty(&s->vram, addr); + memory_region_set_dirty(&s->vram, addr, 1); } } else { /* standard VGA latched access */ - write_mode = s->gr[5] & 3; + write_mode = s->gr[VGA_GFX_MODE] & 3; switch(write_mode) { default: case 0: /* rotate */ - b = s->gr[3] & 7; + b = s->gr[VGA_GFX_DATA_ROTATE] & 7; val = ((val >> b) | (val << (8 - b))) & 0xff; val |= val << 8; val |= val << 16; /* apply set/reset mask */ - set_mask = mask16[s->gr[1]]; - val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask); - bit_mask = s->gr[8]; + set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]]; + val = (val & ~set_mask) | + (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask); + bit_mask = s->gr[VGA_GFX_BIT_MASK]; break; case 1: val = s->latch; goto do_write; case 2: val = mask16[val & 0x0f]; - bit_mask = s->gr[8]; + bit_mask = s->gr[VGA_GFX_BIT_MASK]; break; case 3: /* rotate */ - b = s->gr[3] & 7; + b = s->gr[VGA_GFX_DATA_ROTATE] & 7; val = (val >> b) | (val << (8 - b)); - bit_mask = s->gr[8] & val; - val = mask16[s->gr[0]]; + bit_mask = s->gr[VGA_GFX_BIT_MASK] & val; + val = mask16[s->gr[VGA_GFX_SR_VALUE]]; break; } /* apply logical operation */ - func_select = s->gr[3] >> 3; + func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3; switch(func_select) { case 0: default: @@ -931,7 +957,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val) do_write: /* mask data according to sr[2] */ - mask = s->sr[2]; + mask = s->sr[VGA_SEQ_PLANE_WRITE]; s->plane_updated |= mask; /* only used to detect font change */ write_mask = mask16[mask]; ((uint32_t *)s->vram_ptr)[addr] = @@ -941,7 +967,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val) printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n", addr * 4, write_mask, val); #endif - memory_region_set_dirty(&s->vram, addr << 2); + memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t)); } } @@ -1045,10 +1071,11 @@ static int update_palette16(VGACommonState *s) palette = s->last_palette; for(i = 0; i < 16; i++) { v = s->ar[i]; - if (s->ar[0x10] & 0x80) - v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf); - else - v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); + if (s->ar[VGA_ATC_MODE] & 0x80) { + v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf); + } else { + v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f); + } v = v * 3; col = s->rgb_to_pixel(c6_to_8(s->palette[v]), c6_to_8(s->palette[v + 1]), @@ -1104,16 +1131,17 @@ static void vga_get_offsets(VGACommonState *s, #endif { /* compute line_offset in bytes */ - line_offset = s->cr[0x13]; + line_offset = s->cr[VGA_CRTC_OFFSET]; line_offset <<= 3; /* starting address */ - start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); + start_addr = s->cr[VGA_CRTC_START_LO] | + (s->cr[VGA_CRTC_START_HI] << 8); /* line compare */ - line_compare = s->cr[0x18] | - ((s->cr[0x07] & 0x10) << 4) | - ((s->cr[0x09] & 0x40) << 3); + line_compare = s->cr[VGA_CRTC_LINE_COMPARE] | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) | + ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3); } *pline_offset = line_offset; *pstart_addr = start_addr; @@ -1216,20 +1244,22 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight int width, cwidth, height, cheight; /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; + cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1; cwidth = 8; - if (!(s->sr[1] & 0x01)) + if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) { cwidth = 9; - if (s->sr[1] & 0x08) + } + if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) { cwidth = 16; /* NOTE: no 18 pixel wide */ - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { + } + width = (s->cr[VGA_CRTC_H_DISP] + 1); + if (s->cr[VGA_CRTC_V_TOTAL] == 100) { /* ugly hack for CGA 160x100x16 - explain me the logic */ height = 100; } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); + height = s->cr[VGA_CRTC_V_DISP_END] | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); height = (height + 1) / cheight; } @@ -1273,7 +1303,7 @@ static void vga_draw_text(VGACommonState *s, int full_update) vga_draw_glyph9_func *vga_draw_glyph9; /* compute font data address (in plane 2) */ - v = s->sr[3]; + v = s->sr[VGA_SEQ_CHARACTER_MAP]; offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; if (offset != s->font_offsets[0]) { s->font_offsets[0] = offset; @@ -1321,10 +1351,11 @@ static void vga_draw_text(VGACommonState *s, int full_update) palette = s->last_palette; x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3); - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; + cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | + s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; if (cursor_offset != s->cursor_offset || - s->cr[0xa] != s->cursor_start || - s->cr[0xb] != s->cursor_end) { + s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start || + s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) { /* if the cursor position changed, we update the old and new chars */ if (s->cursor_offset < CH_ATTR_SIZE) @@ -1332,8 +1363,8 @@ static void vga_draw_text(VGACommonState *s, int full_update) if (cursor_offset < CH_ATTR_SIZE) s->last_ch_attr[cursor_offset] = -1; s->cursor_offset = cursor_offset; - s->cursor_start = s->cr[0xa]; - s->cursor_end = s->cr[0xb]; + s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; + s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; @@ -1378,17 +1409,19 @@ static void vga_draw_text(VGACommonState *s, int full_update) font_ptr, cheight, fgcol, bgcol); } else { dup9 = 0; - if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) + if (ch >= 0xb0 && ch <= 0xdf && + (s->ar[VGA_ATC_MODE] & 0x04)) { dup9 = 1; + } vga_draw_glyph9(d1, linesize, font_ptr, cheight, fgcol, bgcol, dup9); } if (src == cursor_ptr && - !(s->cr[0x0a] & 0x20)) { + !(s->cr[VGA_CRTC_CURSOR_START] & 0x20)) { int line_start, line_last, h; /* draw the cursor */ - line_start = s->cr[0x0a] & 0x1f; - line_last = s->cr[0x0b] & 0x1f; + line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f; + line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f; /* XXX: check that */ if (line_last > cheight - 1) line_last = cheight - 1; @@ -1544,10 +1577,10 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight) } else #endif { - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); + width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8; + height = s->cr[VGA_CRTC_V_DISP_END] | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); height = (height + 1); } *pwidth = width; @@ -1602,10 +1635,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) s->get_resolution(s, &width, &height); disp_width = width; - shift_control = (s->gr[0x05] >> 5) & 3; - double_scan = (s->cr[0x09] >> 7); + shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3; + double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7); if (shift_control != 1) { - multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; + multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan) + - 1; } else { /* in CGA modes, multi_scan is ignored */ /* XXX: is it correct ? */ @@ -1620,11 +1654,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } if (shift_control == 0) { - if (s->sr[0x01] & 8) { + if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { disp_width <<= 1; } } else if (shift_control == 1) { - if (s->sr[0x01] & 8) { + if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { disp_width <<= 1; } } @@ -1668,7 +1702,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) if (shift_control == 0) { full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { + if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { v = VGA_DRAW_LINE4D2; } else { v = VGA_DRAW_LINE4; @@ -1676,7 +1710,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) bits = 4; } else if (shift_control == 1) { full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { + if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) { v = VGA_DRAW_LINE2D2; } else { v = VGA_DRAW_LINE2; @@ -1721,7 +1755,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) line_offset = s->line_offset; #if 0 printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", - width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); + width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE], + s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]); #endif addr1 = (s->start_addr * 4); bwidth = (width * bits + 7) / 8; @@ -1733,26 +1768,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) y1 = 0; for(y = 0; y < height; y++) { addr = addr1; - if (!(s->cr[0x17] & 1)) { + if (!(s->cr[VGA_CRTC_MODE] & 1)) { int shift; /* CGA compatibility handling */ - shift = 14 + ((s->cr[0x17] >> 6) & 1); + shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1); addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); } - if (!(s->cr[0x17] & 2)) { + if (!(s->cr[VGA_CRTC_MODE] & 2)) { addr = (addr & ~0x8000) | ((y1 & 2) << 14); } - page0 = addr & TARGET_PAGE_MASK; - page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK; - update = full_update | - memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) | - memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA); - if ((page1 - page0) > TARGET_PAGE_SIZE) { - /* if wide line, can use another page */ - update |= memory_region_get_dirty(&s->vram, - page0 + TARGET_PAGE_SIZE, - DIRTY_MEMORY_VGA); - } + page0 = addr; + page1 = addr + bwidth - 1; + update = memory_region_get_dirty(&s->vram, page0, page1, + DIRTY_MEMORY_VGA); /* explicit invalidation for the hardware cursor */ update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; if (update) { @@ -1776,7 +1804,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) } } if (!multi_run) { - mask = (s->cr[0x17] & 3) ^ 3; + mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3; if ((y1 & mask) == mask) addr1 += line_offset; y1++; @@ -1798,7 +1826,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update) if (page_max >= page_min) { memory_region_reset_dirty(&s->vram, page_min, - page_max + TARGET_PAGE_SIZE - page_min, + page_max - page_min, DIRTY_MEMORY_VGA); } memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); @@ -1848,7 +1876,7 @@ static void vga_update_display(void *opaque) if (!(s->ar_index & 0x20)) { graphic_mode = GMODE_BLANK; } else { - graphic_mode = s->gr[6] & 1; + graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE; } if (graphic_mode != s->graphic_mode) { s->graphic_mode = graphic_mode; @@ -1966,7 +1994,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) if (!(s->ar_index & 0x20)) { graphic_mode = GMODE_BLANK; } else { - graphic_mode = s->gr[6] & 1; + graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE; } if (graphic_mode != s->graphic_mode) { s->graphic_mode = graphic_mode; @@ -1983,20 +2011,22 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) full_update |= update_basic_params(s); /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; + cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1; cw = 8; - if (!(s->sr[1] & 0x01)) + if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) { cw = 9; - if (s->sr[1] & 0x08) + } + if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) { cw = 16; /* NOTE: no 18 pixel wide */ - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { + } + width = (s->cr[VGA_CRTC_H_DISP] + 1); + if (s->cr[VGA_CRTC_V_TOTAL] == 100) { /* ugly hack for CGA 160x100x16 - explain me the logic */ height = 100; } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); + height = s->cr[VGA_CRTC_V_DISP_END] | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) | + ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3); height = (height + 1) / cheight; } @@ -2025,11 +2055,12 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) } /* Update "hardware" cursor */ - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; + cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) | + s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr; if (cursor_offset != s->cursor_offset || - s->cr[0xa] != s->cursor_start || - s->cr[0xb] != s->cursor_end || full_update) { - cursor_visible = !(s->cr[0xa] & 0x20); + s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start || + s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) { + cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20); if (cursor_visible && cursor_offset < size && cursor_offset >= 0) dpy_cursor(s->ds, TEXTMODE_X(cursor_offset), @@ -2037,8 +2068,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata) else dpy_cursor(s->ds, -1, -1); s->cursor_offset = cursor_offset; - s->cursor_start = s->cr[0xa]; - s->cursor_end = s->cr[0xb]; + s->cursor_start = s->cr[VGA_CRTC_CURSOR_START]; + s->cursor_end = s->cr[VGA_CRTC_CURSOR_END]; } src = (uint32_t *) s->vram_ptr + s->start_addr; diff --git a/hw/vga.h b/hw/vga.h new file mode 100644 index 0000000000..d917046da6 --- /dev/null +++ b/hw/vga.h @@ -0,0 +1,159 @@ +/* + * linux/include/video/vga.h -- standard VGA chipset interaction + * + * Copyright 1999 Jeff Garzik <jgarzik@pobox.com> + * + * Copyright history from vga16fb.c: + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm + * Based on VESA framebuffer (c) 1998 Gerd Knorr + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + */ + +#ifndef __linux_video_vga_h__ +#define __linux_video_vga_h__ + +/* Some of the code below is taken from SVGAlib. The original, + unmodified copyright notice for that code is below. */ +/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */ +/* */ +/* This library is free software; you can redistribute it and/or */ +/* modify it without any restrictions. This library is distributed */ +/* in the hope that it will be useful, but without any warranty. */ + +/* Multi-chipset support Copyright 1993 Harm Hanemaayer */ +/* partially copyrighted (C) 1993 by Hartmut Schirmer */ + +/* VGA data register ports */ +#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */ +#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */ +#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */ +#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */ +#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */ +#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */ +#define VGA_MIS_R 0x3CC /* Misc Output Read Register */ +#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */ +#define VGA_FTC_R 0x3CA /* Feature Control Read Register */ +#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */ +#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */ +#define VGA_PEL_D 0x3C9 /* PEL Data Register */ +#define VGA_PEL_MSK 0x3C6 /* PEL mask register */ + +/* EGA-specific registers */ +#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */ +#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */ + +/* VGA index register ports */ +#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */ +#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */ +#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */ +#define VGA_GFX_I 0x3CE /* Graphics Controller Index */ +#define VGA_SEQ_I 0x3C4 /* Sequencer Index */ +#define VGA_PEL_IW 0x3C8 /* PEL Write Index */ +#define VGA_PEL_IR 0x3C7 /* PEL Read Index */ + +/* standard VGA indexes max counts */ +#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */ +#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */ +#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */ +#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */ +#define VGA_MIS_C 0x01 /* Number of Misc Output Register */ + +/* VGA misc register bit masks */ +#define VGA_MIS_COLOR 0x01 +#define VGA_MIS_ENB_MEM_ACCESS 0x02 +#define VGA_MIS_DCLK_28322_720 0x04 +#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08) +#define VGA_MIS_SEL_HIGH_PAGE 0x20 + +/* VGA CRT controller register indices */ +#define VGA_CRTC_H_TOTAL 0 +#define VGA_CRTC_H_DISP 1 +#define VGA_CRTC_H_BLANK_START 2 +#define VGA_CRTC_H_BLANK_END 3 +#define VGA_CRTC_H_SYNC_START 4 +#define VGA_CRTC_H_SYNC_END 5 +#define VGA_CRTC_V_TOTAL 6 +#define VGA_CRTC_OVERFLOW 7 +#define VGA_CRTC_PRESET_ROW 8 +#define VGA_CRTC_MAX_SCAN 9 +#define VGA_CRTC_CURSOR_START 0x0A +#define VGA_CRTC_CURSOR_END 0x0B +#define VGA_CRTC_START_HI 0x0C +#define VGA_CRTC_START_LO 0x0D +#define VGA_CRTC_CURSOR_HI 0x0E +#define VGA_CRTC_CURSOR_LO 0x0F +#define VGA_CRTC_V_SYNC_START 0x10 +#define VGA_CRTC_V_SYNC_END 0x11 +#define VGA_CRTC_V_DISP_END 0x12 +#define VGA_CRTC_OFFSET 0x13 +#define VGA_CRTC_UNDERLINE 0x14 +#define VGA_CRTC_V_BLANK_START 0x15 +#define VGA_CRTC_V_BLANK_END 0x16 +#define VGA_CRTC_MODE 0x17 +#define VGA_CRTC_LINE_COMPARE 0x18 +#define VGA_CRTC_REGS VGA_CRT_C + +/* VGA CRT controller bit masks */ +#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */ +#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80 + +/* VGA attribute controller register indices */ +#define VGA_ATC_PALETTE0 0x00 +#define VGA_ATC_PALETTE1 0x01 +#define VGA_ATC_PALETTE2 0x02 +#define VGA_ATC_PALETTE3 0x03 +#define VGA_ATC_PALETTE4 0x04 +#define VGA_ATC_PALETTE5 0x05 +#define VGA_ATC_PALETTE6 0x06 +#define VGA_ATC_PALETTE7 0x07 +#define VGA_ATC_PALETTE8 0x08 +#define VGA_ATC_PALETTE9 0x09 +#define VGA_ATC_PALETTEA 0x0A +#define VGA_ATC_PALETTEB 0x0B +#define VGA_ATC_PALETTEC 0x0C +#define VGA_ATC_PALETTED 0x0D +#define VGA_ATC_PALETTEE 0x0E +#define VGA_ATC_PALETTEF 0x0F +#define VGA_ATC_MODE 0x10 +#define VGA_ATC_OVERSCAN 0x11 +#define VGA_ATC_PLANE_ENABLE 0x12 +#define VGA_ATC_PEL 0x13 +#define VGA_ATC_COLOR_PAGE 0x14 + +#define VGA_AR_ENABLE_DISPLAY 0x20 + +/* VGA sequencer register indices */ +#define VGA_SEQ_RESET 0x00 +#define VGA_SEQ_CLOCK_MODE 0x01 +#define VGA_SEQ_PLANE_WRITE 0x02 +#define VGA_SEQ_CHARACTER_MAP 0x03 +#define VGA_SEQ_MEMORY_MODE 0x04 + +/* VGA sequencer register bit masks */ +#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */ +#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */ +#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */ +#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */ +#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */ +#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */ + +/* VGA graphics controller register indices */ +#define VGA_GFX_SR_VALUE 0x00 +#define VGA_GFX_SR_ENABLE 0x01 +#define VGA_GFX_COMPARE_VALUE 0x02 +#define VGA_GFX_DATA_ROTATE 0x03 +#define VGA_GFX_PLANE_READ 0x04 +#define VGA_GFX_MODE 0x05 +#define VGA_GFX_MISC 0x06 +#define VGA_GFX_COMPARE_MASK 0x07 +#define VGA_GFX_BIT_MASK 0x08 + +/* VGA graphics controller bit masks */ +#define VGA_GR06_GRAPHICS_MODE 0x01 + +#endif /* __linux_video_vga_h__ */ diff --git a/hw/vga_int.h b/hw/vga_int.h index c1e700fa0b..7685b2b167 100644 --- a/hw/vga_int.h +++ b/hw/vga_int.h @@ -25,9 +25,6 @@ #include <hw/hw.h> #include "memory.h" -#define MSR_COLOR_EMULATION 0x01 -#define MSR_PAGE_SELECT 0x20 - #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 @@ -205,19 +202,6 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val); void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2); int ppm_save(const char *filename, struct DisplaySurface *ds); -void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); -void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); -void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); - int vga_ioport_invalid(VGACommonState *s, uint32_t addr); void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space); diff --git a/hw/vga_template.h b/hw/vga_template.h index 681425f9a2..f6f6a01d84 100644 --- a/hw/vga_template.h +++ b/hw/vga_template.h @@ -161,7 +161,7 @@ static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d, int x; palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; + plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; width >>= 3; for(x = 0; x < width; x++) { data = ((uint32_t *)s)[0]; @@ -203,7 +203,7 @@ static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d, int x; palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; + plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; width >>= 3; for(x = 0; x < width; x++) { data = ((uint32_t *)s)[0]; @@ -236,7 +236,7 @@ static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d, int x; palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; + plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; width >>= 3; for(x = 0; x < width; x++) { data = ((uint32_t *)s)[0]; @@ -268,7 +268,7 @@ static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d, int x; palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; + plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf]; width >>= 3; for(x = 0; x < width; x++) { data = ((uint32_t *)s)[0]; @@ -340,72 +340,6 @@ static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d, } } -void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, - const uint8_t *src1, - int poffset, int w, - unsigned int color0, - unsigned int color1, - unsigned int color_xor) -{ - const uint8_t *plane0, *plane1; - int x, b0, b1; - uint8_t *d; - - d = d1; - plane0 = src1; - plane1 = src1 + poffset; - for(x = 0; x < w; x++) { - b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; - b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; -#if DEPTH == 8 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - d[0] ^= color_xor; - break; - case 2: - d[0] = color0; - break; - case 3: - d[0] = color1; - break; - } -#elif DEPTH == 16 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint16_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint16_t *)d)[0] = color0; - break; - case 3: - ((uint16_t *)d)[0] = color1; - break; - } -#elif DEPTH == 32 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint32_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint32_t *)d)[0] = color0; - break; - case 3: - ((uint32_t *)d)[0] = color1; - break; - } -#else -#error unsupported depth -#endif - d += BPP; - } -} - #endif /* DEPTH != 15 */ diff --git a/hw/vhost.c b/hw/vhost.c index 4778521102..5ece659f4a 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -55,7 +55,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, ram_addr_t ram_addr; bit -= 1; ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE; - memory_region_set_dirty(section->mr, ram_addr); + memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE); log &= ~(0x1ull << bit); } addr += VHOST_LOG_CHUNK; diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index bd16b97934..f8d2b1be04 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -38,7 +38,6 @@ #include "ppc.h" #include "ppc4xx.h" -#include "ppc440.h" #include "ppc405.h" #include "blockdev.h" diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 5b416c36ee..a5a439668b 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -346,6 +346,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req) bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ); + trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512); + if (sector & req->dev->sector_mask) { virtio_blk_rw_complete(req, -EIO); return; diff --git a/hw/virtio-console.c b/hw/virtio-console.c index 0b28a30b8c..4f2c3e4379 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -109,10 +109,9 @@ static void chr_event(void *opaque, int event) static int virtconsole_initfn(VirtIOSerialPort *port) { VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); - VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, - vcon->port.dev.info); + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); - if (port->id == 0 && !info->is_console) { + if (port->id == 0 && !k->is_console) { error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility."); return -1; } @@ -125,41 +124,63 @@ static int virtconsole_initfn(VirtIOSerialPort *port) return 0; } -static VirtIOSerialPortInfo virtconsole_info = { - .qdev.name = "virtconsole", - .qdev.size = sizeof(VirtConsole), - .is_console = true, - .init = virtconsole_initfn, - .have_data = flush_buf, - .guest_open = guest_open, - .guest_close = guest_close, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", VirtConsole, chr), - DEFINE_PROP_END_OF_LIST(), - }, +static Property virtconsole_properties[] = { + DEFINE_PROP_CHR("chardev", VirtConsole, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtconsole_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); + + k->is_console = true; + k->init = virtconsole_initfn; + k->have_data = flush_buf; + k->guest_open = guest_open; + k->guest_close = guest_close; + dc->props = virtconsole_properties; +} + +static TypeInfo virtconsole_info = { + .name = "virtconsole", + .parent = TYPE_VIRTIO_SERIAL_PORT, + .instance_size = sizeof(VirtConsole), + .class_init = virtconsole_class_init, }; static void virtconsole_register(void) { - virtio_serial_port_qdev_register(&virtconsole_info); + type_register_static(&virtconsole_info); } device_init(virtconsole_register) -static VirtIOSerialPortInfo virtserialport_info = { - .qdev.name = "virtserialport", - .qdev.size = sizeof(VirtConsole), - .init = virtconsole_initfn, - .have_data = flush_buf, - .guest_open = guest_open, - .guest_close = guest_close, - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", VirtConsole, chr), - DEFINE_PROP_END_OF_LIST(), - }, +static Property virtserialport_properties[] = { + DEFINE_PROP_CHR("chardev", VirtConsole, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtserialport_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); + + k->init = virtconsole_initfn; + k->have_data = flush_buf; + k->guest_open = guest_open; + k->guest_close = guest_close; + dc->props = virtserialport_properties; +} + +static TypeInfo virtserialport_info = { + .name = "virtserialport", + .parent = TYPE_VIRTIO_SERIAL_PORT, + .instance_size = sizeof(VirtConsole), + .class_init = virtserialport_class_init, }; static void virtserialport_register(void) { - virtio_serial_port_qdev_register(&virtserialport_info); + type_register_static(&virtserialport_info); } device_init(virtserialport_register) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8c2f460147..bc5e3a83d1 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1030,7 +1030,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac)); n->status = VIRTIO_NET_S_LINK_UP; - n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n); + n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n); qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a); diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index caff0aa2eb..93fff54782 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -91,6 +91,9 @@ */ #define wmb() do { } while (0) +/* HACK for virtio to determine if it's running a big endian guest */ +bool virtio_is_big_endian(void); + /* virtio device */ static void virtio_pci_notify(void *opaque, uint16_t vector) @@ -414,20 +417,35 @@ static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint16_t val; if (addr < config) return virtio_ioport_read(proxy, addr); addr -= config; - return virtio_config_readw(proxy->vdev, addr); + val = virtio_config_readw(proxy->vdev, addr); + if (virtio_is_big_endian()) { + /* + * virtio is odd, ioports are LE but config space is target native + * endian. However, in qemu, all PIO is LE, so we need to re-swap + * on BE targets + */ + val = bswap16(val); + } + return val; } static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint32_t val; if (addr < config) return virtio_ioport_read(proxy, addr); addr -= config; - return virtio_config_readl(proxy->vdev, addr); + val = virtio_config_readl(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap32(val); + } + return val; } static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) @@ -451,6 +469,9 @@ static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; + if (virtio_is_big_endian()) { + val = bswap16(val); + } virtio_config_writew(proxy->vdev, addr, val); } @@ -463,6 +484,9 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; + if (virtio_is_big_endian()) { + val = bswap32(val); + } virtio_config_writel(proxy->vdev, addr, val); } @@ -782,98 +806,136 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) return virtio_exit_pci(pci_dev); } -static PCIDeviceInfo virtio_info[] = { - { - .qdev.name = "virtio-blk-pci", - .qdev.alias = "virtio-blk", - .qdev.size = sizeof(VirtIOPCIProxy), - .init = virtio_blk_init_pci, - .exit = virtio_blk_exit_pci, - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK, - .revision = VIRTIO_PCI_ABI_VERSION, - .class_id = PCI_CLASS_STORAGE_SCSI, - .qdev.props = (Property[]) { - DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), - DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), - DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = virtio_pci_reset, - },{ - .qdev.name = "virtio-net-pci", - .qdev.alias = "virtio-net", - .qdev.size = sizeof(VirtIOPCIProxy), - .init = virtio_net_init_pci, - .exit = virtio_net_exit_pci, - .romfile = "pxe-virtio.rom", - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_NET, - .revision = VIRTIO_PCI_ABI_VERSION, - .class_id = PCI_CLASS_NETWORK_ETHERNET, - .qdev.props = (Property[]) { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), - DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic), - DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, - net.txtimer, TX_TIMER_INTERVAL), - DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, - net.txburst, TX_BURST), - DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = virtio_pci_reset, - },{ - .qdev.name = "virtio-serial-pci", - .qdev.alias = "virtio-serial", - .qdev.size = sizeof(VirtIOPCIProxy), - .init = virtio_serial_init_pci, - .exit = virtio_serial_exit_pci, - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE, - .revision = VIRTIO_PCI_ABI_VERSION, - .class_id = PCI_CLASS_COMMUNICATION_OTHER, - .qdev.props = (Property[]) { - DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, - DEV_NVECTORS_UNSPECIFIED), - DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, - serial.max_virtserial_ports, 31), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = virtio_pci_reset, - },{ - .qdev.name = "virtio-balloon-pci", - .qdev.alias = "virtio-balloon", - .qdev.size = sizeof(VirtIOPCIProxy), - .init = virtio_balloon_init_pci, - .exit = virtio_balloon_exit_pci, - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON, - .revision = VIRTIO_PCI_ABI_VERSION, - .class_id = PCI_CLASS_MEMORY_RAM, - .qdev.props = (Property[]) { - DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), - DEFINE_PROP_END_OF_LIST(), - }, - .qdev.reset = virtio_pci_reset, - },{ - /* end of list */ - } +static Property virtio_blk_properties[] = { + DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block), + DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial), + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_blk_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_blk_init_pci; + k->exit = virtio_blk_exit_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_STORAGE_SCSI; + dc->reset = virtio_pci_reset; + dc->props = virtio_blk_properties; +} + +static TypeInfo virtio_blk_info = { + .name = "virtio-blk-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_blk_class_init, +}; + +static Property virtio_net_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), + DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic), + DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL), + DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST), + DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_net_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_net_init_pci; + k->exit = virtio_net_exit_pci; + k->romfile = "pxe-virtio.rom"; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_NET; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_NETWORK_ETHERNET; + dc->reset = virtio_pci_reset; + dc->props = virtio_net_properties; +} + +static TypeInfo virtio_net_info = { + .name = "virtio-net-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_net_class_init, +}; + +static Property virtio_serial_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED), + DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0), + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_serial_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_serial_init_pci; + k->exit = virtio_serial_exit_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_COMMUNICATION_OTHER; + dc->reset = virtio_pci_reset; + dc->props = virtio_serial_properties; +} + +static TypeInfo virtio_serial_info = { + .name = "virtio-serial-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_serial_class_init, +}; + +static Property virtio_balloon_properties[] = { + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_balloon_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = virtio_balloon_init_pci; + k->exit = virtio_balloon_exit_pci; + k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; + k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; + k->revision = VIRTIO_PCI_ABI_VERSION; + k->class_id = PCI_CLASS_MEMORY_RAM; + dc->reset = virtio_pci_reset; + dc->props = virtio_balloon_properties; +} + +static TypeInfo virtio_balloon_info = { + .name = "virtio-balloon-pci", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VirtIOPCIProxy), + .class_init = virtio_balloon_class_init, }; static void virtio_pci_register_devices(void) { - pci_qdev_register_many(virtio_info); + type_register_static(&virtio_blk_info); + type_register_static(&virtio_net_info); + type_register_static(&virtio_serial_info); + type_register_static(&virtio_balloon_info); } device_init(virtio_pci_register_devices) diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 32e46e98cb..61176299a3 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -133,12 +133,12 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, VirtIODevice *vdev) { - VirtIOSerialPortInfo *info; + VirtIOSerialPortClass *vsc; assert(port); assert(virtio_queue_ready(vq)); - info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); + vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); while (!port->throttled) { unsigned int i; @@ -157,7 +157,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, ssize_t ret; buf_size = port->elem.out_sg[i].iov_len - port->iov_offset; - ret = info->have_data(port, + ret = vsc->have_data(port, port->elem.out_sg[i].iov_base + port->iov_offset, buf_size); @@ -176,7 +176,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, * 1: chardevs can notify frondends * 2: the guest driver does not spin in these cases */ - if (!info->is_console) { + if (!vsc->is_console) { virtio_serial_throttle_port(port, true); } port->iov_idx = i; @@ -331,7 +331,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle) static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) { struct VirtIOSerialPort *port; - struct VirtIOSerialPortInfo *info; + VirtIOSerialPortClass *vsc; struct virtio_console_control cpkt, *gcpkt; uint8_t *buffer; size_t buffer_len; @@ -373,7 +373,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) trace_virtio_serial_handle_control_message_port(port->id); - info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); + vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); switch(cpkt.event) { case VIRTIO_CONSOLE_PORT_READY: @@ -389,7 +389,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) * this port is a console port so that the guest can hook it * up to hvc. */ - if (info->is_console) { + if (vsc->is_console) { send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1); } @@ -418,21 +418,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) * initialised. If some app is interested in knowing about * this event, let it know. */ - if (info->guest_ready) { - info->guest_ready(port); + if (vsc->guest_ready) { + vsc->guest_ready(port); } break; case VIRTIO_CONSOLE_PORT_OPEN: port->guest_connected = cpkt.value; - if (cpkt.value && info->guest_open) { + if (cpkt.value && vsc->guest_open) { /* Send the guest opened notification if an app is interested */ - info->guest_open(port); + vsc->guest_open(port); } - if (!cpkt.value && info->guest_close) { + if (!cpkt.value && vsc->guest_close) { /* Send the guest closed notification if an app is interested */ - info->guest_close(port); + vsc->guest_close(port); } break; } @@ -748,10 +748,10 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1); } -static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) +static int virtser_port_qdev_init(DeviceState *qdev) { VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); - VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base); + VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus); int ret, max_nr_ports; bool plugging_port0; @@ -759,14 +759,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) port->vser = bus->vser; port->bh = qemu_bh_new(flush_queued_data_bh, port); - assert(info->have_data); + assert(vsc->have_data); /* * Is the first console port we're seeing? If so, put it up at * location 0. This is done for backward compatibility (old * kernel, new qemu). */ - plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0); + plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0); if (find_port_by_id(port->vser, port->id)) { error_report("virtio-serial-bus: A port already exists at id %u", @@ -793,7 +793,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) return -1; } - ret = info->init(port); + ret = vsc->init(port); if (ret) { return ret; } @@ -823,8 +823,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) static int virtser_port_qdev_exit(DeviceState *qdev) { VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); - VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, - port->dev.info); + VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); VirtIOSerial *vser = port->vser; qemu_bh_delete(port->bh); @@ -832,21 +831,12 @@ static int virtser_port_qdev_exit(DeviceState *qdev) QTAILQ_REMOVE(&vser->ports, port, next); - if (info->exit) { - info->exit(port); + if (vsc->exit) { + vsc->exit(port); } return 0; } -void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info) -{ - info->qdev.init = virtser_port_qdev_init; - info->qdev.bus_info = &virtser_bus_info; - info->qdev.exit = virtser_port_qdev_exit; - info->qdev.unplug = qdev_simple_unplug_cb; - qdev_register(&info->qdev); -} - VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) { VirtIOSerial *vser; @@ -940,3 +930,28 @@ void virtio_serial_exit(VirtIODevice *vdev) virtio_cleanup(vdev); } + +static void virtio_serial_port_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *k = DEVICE_CLASS(klass); + k->init = virtser_port_qdev_init; + k->bus_info = &virtser_bus_info; + k->exit = virtser_port_qdev_exit; + k->unplug = qdev_simple_unplug_cb; +} + +static TypeInfo virtio_serial_port_type_info = { + .name = TYPE_VIRTIO_SERIAL_PORT, + .parent = TYPE_DEVICE, + .instance_size = sizeof(VirtIOSerialPort), + .abstract = true, + .class_size = sizeof(VirtIOSerialPortClass), + .class_init = virtio_serial_port_class_init, +}; + +static void virtio_serial_register_devices(void) +{ + type_register_static(&virtio_serial_port_type_info); +} + +device_init(virtio_serial_register_devices); diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index ab138038c0..16e39820a2 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -62,10 +62,52 @@ struct virtio_serial_conf { /* == In-qemu interface == */ +#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port" +#define VIRTIO_SERIAL_PORT(obj) \ + OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT) +#define VIRTIO_SERIAL_PORT_CLASS(klass) \ + OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT) +#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \ + OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT) + typedef struct VirtIOSerial VirtIOSerial; typedef struct VirtIOSerialBus VirtIOSerialBus; typedef struct VirtIOSerialPort VirtIOSerialPort; -typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo; + +typedef struct VirtIOSerialPortClass { + DeviceClass parent_class; + + /* Is this a device that binds with hvc in the guest? */ + bool is_console; + + /* + * The per-port (or per-app) init function that's called when a + * new device is found on the bus. + */ + int (*init)(VirtIOSerialPort *port); + /* + * Per-port exit function that's called when a port gets + * hot-unplugged or removed. + */ + int (*exit)(VirtIOSerialPort *port); + + /* Callbacks for guest events */ + /* Guest opened device. */ + void (*guest_open)(VirtIOSerialPort *port); + /* Guest closed device. */ + void (*guest_close)(VirtIOSerialPort *port); + + /* Guest is now ready to accept data (virtqueues set up). */ + void (*guest_ready)(VirtIOSerialPort *port); + + /* + * Guest wrote some data to the port. This data is handed over to + * the app via this callback. The app can return a size less than + * 'len'. In this case, throttling will be enabled for this port. + */ + ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, + size_t len); +} VirtIOSerialPortClass; /* * This is the state that's shared between all the ports. Some of the @@ -131,50 +173,9 @@ struct VirtIOSerialPort { bool throttled; }; -struct VirtIOSerialPortInfo { - DeviceInfo qdev; - - /* Is this a device that binds with hvc in the guest? */ - bool is_console; - - /* - * The per-port (or per-app) init function that's called when a - * new device is found on the bus. - */ - int (*init)(VirtIOSerialPort *port); - /* - * Per-port exit function that's called when a port gets - * hot-unplugged or removed. - */ - int (*exit)(VirtIOSerialPort *port); - - /* Callbacks for guest events */ - /* Guest opened device. */ - void (*guest_open)(VirtIOSerialPort *port); - /* Guest closed device. */ - void (*guest_close)(VirtIOSerialPort *port); - - /* Guest is now ready to accept data (virtqueues set up). */ - void (*guest_ready)(VirtIOSerialPort *port); - - /* - * Guest wrote some data to the port. This data is handed over to - * the app via this callback. The app can return a size less than - * 'len'. In this case, throttling will be enabled for this port. - */ - ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, - size_t len); -}; - /* Interface to the virtio-serial bus */ /* - * Individual ports/apps should call this function to register the port - * with the virtio-serial bus - */ -void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info); - -/* * Open a connection to the port * Returns 0 on success (always). */ diff --git a/hw/virtio.c b/hw/virtio.c index 81ecc40b31..74cc038af9 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -539,7 +539,7 @@ uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = ldub_p(vdev->config + addr); return val; } @@ -552,7 +552,7 @@ uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = lduw_p(vdev->config + addr); return val; } @@ -565,7 +565,7 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = ldl_p(vdev->config + addr); return val; } @@ -576,7 +576,7 @@ void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stb_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); @@ -589,7 +589,7 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stw_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); @@ -602,7 +602,7 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stl_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 1113f33d68..fda4f89a76 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -254,6 +254,8 @@ static void vmmouse_reset(DeviceState *d) s->status = 0xffff; s->queue_size = VMMOUSE_QUEUE_SIZE; + + vmmouse_disable(s); } static int vmmouse_initfn(ISADevice *dev) @@ -269,21 +271,31 @@ static int vmmouse_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo vmmouse_info = { - .init = vmmouse_initfn, - .qdev.name = "vmmouse", - .qdev.size = sizeof(VMMouseState), - .qdev.vmsd = &vmstate_vmmouse, - .qdev.no_user = 1, - .qdev.reset = vmmouse_reset, - .qdev.props = (Property[]) { - DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse), - DEFINE_PROP_END_OF_LIST(), - } +static Property vmmouse_properties[] = { + DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse), + DEFINE_PROP_END_OF_LIST(), +}; + +static void vmmouse_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = vmmouse_initfn; + dc->no_user = 1; + dc->reset = vmmouse_reset; + dc->vmsd = &vmstate_vmmouse; + dc->props = vmmouse_properties; +} + +static TypeInfo vmmouse_info = { + .name = "vmmouse", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(VMMouseState), + .class_init = vmmouse_class_initfn, }; static void vmmouse_dev_register(void) { - isa_qdev_register(&vmmouse_info); + type_register_static(&vmmouse_info); } device_init(vmmouse_dev_register) diff --git a/hw/vmport.c b/hw/vmport.c index 0a3dbc5ef5..a2c45e1950 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -144,15 +144,23 @@ static int vmport_initfn(ISADevice *dev) return 0; } -static ISADeviceInfo vmport_info = { - .qdev.name = "vmport", - .qdev.size = sizeof(VMPortState), - .qdev.no_user = 1, - .init = vmport_initfn, +static void vmport_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = vmport_initfn; + dc->no_user = 1; +} + +static TypeInfo vmport_info = { + .name = "vmport", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(VMPortState), + .class_init = vmport_class_initfn, }; static void vmport_dev_register(void) { - isa_qdev_register(&vmport_info); + type_register_static(&vmport_info); } device_init(vmport_dev_register) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index b1885c3c19..3f3eb21d02 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1199,24 +1199,32 @@ static int pci_vmsvga_initfn(PCIDevice *dev) return 0; } -static PCIDeviceInfo vmsvga_info = { - .qdev.name = "vmware-svga", - .qdev.size = sizeof(struct pci_vmsvga_state_s), - .qdev.vmsd = &vmstate_vmware_vga, - .qdev.reset = vmsvga_reset, - .no_hotplug = 1, - .init = pci_vmsvga_initfn, - .romfile = "vgabios-vmware.bin", - - .vendor_id = PCI_VENDOR_ID_VMWARE, - .device_id = SVGA_PCI_DEVICE_ID, - .class_id = PCI_CLASS_DISPLAY_VGA, - .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE, - .subsystem_id = SVGA_PCI_DEVICE_ID, +static void vmsvga_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = pci_vmsvga_initfn; + k->romfile = "vgabios-vmware.bin"; + k->vendor_id = PCI_VENDOR_ID_VMWARE; + k->device_id = SVGA_PCI_DEVICE_ID; + k->class_id = PCI_CLASS_DISPLAY_VGA; + k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; + k->subsystem_id = SVGA_PCI_DEVICE_ID; + dc->reset = vmsvga_reset; + dc->vmsd = &vmstate_vmware_vga; +} + +static TypeInfo vmsvga_info = { + .name = "vmware-svga", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(struct pci_vmsvga_state_s), + .class_init = vmsvga_class_init, }; static void vmsvga_register(void) { - pci_qdev_register(&vmsvga_info); + type_register_static(&vmsvga_info); } device_init(vmsvga_register); diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h index db11cbfac8..000fbddc0f 100644 --- a/hw/vmware_vga.h +++ b/hw/vmware_vga.h @@ -8,12 +8,8 @@ static inline DeviceState *pci_vmsvga_init(PCIBus *bus) { PCIDevice *dev; - dev = pci_try_create(bus, -1, "vmware-svga"); - if (!dev || qdev_init(&dev->qdev) < 0) { - return NULL; - } else { - return &dev->qdev; - } + dev = pci_create_simple(bus, -1, "vmware-svga"); + return &dev->qdev; } #endif diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 7fb88a53bf..aa0954f487 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -346,20 +346,29 @@ void vt82c686b_ac97_init(PCIBus *bus, int devfn) qdev_init_nofail(&dev->qdev); } -static PCIDeviceInfo via_ac97_info = { - .qdev.name = "VT82C686B_AC97", - .qdev.desc = "AC97", - .qdev.size = sizeof(VT686AC97State), - .init = vt82c686b_ac97_initfn, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_AC97, - .revision = 0x50, - .class_id = PCI_CLASS_MULTIMEDIA_AUDIO, +static void via_ac97_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = vt82c686b_ac97_initfn; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_AC97; + k->revision = 0x50; + k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + dc->desc = "AC97"; +} + +static TypeInfo via_ac97_info = { + .name = "VT82C686B_AC97", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VT686AC97State), + .class_init = via_ac97_class_init, }; static void vt82c686b_ac97_register(void) { - pci_qdev_register(&via_ac97_info); + type_register_static(&via_ac97_info); } device_init(vt82c686b_ac97_register); @@ -385,20 +394,29 @@ void vt82c686b_mc97_init(PCIBus *bus, int devfn) qdev_init_nofail(&dev->qdev); } -static PCIDeviceInfo via_mc97_info = { - .qdev.name = "VT82C686B_MC97", - .qdev.desc = "MC97", - .qdev.size = sizeof(VT686MC97State), - .init = vt82c686b_mc97_initfn, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_MC97, - .class_id = PCI_CLASS_COMMUNICATION_OTHER, - .revision = 0x30, +static void via_mc97_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = vt82c686b_mc97_initfn; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_MC97; + k->class_id = PCI_CLASS_COMMUNICATION_OTHER; + k->revision = 0x30; + dc->desc = "MC97"; +} + +static TypeInfo via_mc97_info = { + .name = "VT82C686B_MC97", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VT686MC97State), + .class_init = via_mc97_class_init, }; static void vt82c686b_mc97_register(void) { - pci_qdev_register(&via_mc97_info); + type_register_static(&via_mc97_info); } device_init(vt82c686b_mc97_register); @@ -451,26 +469,37 @@ i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, return s->smb.smbus; } -static PCIDeviceInfo via_pm_info = { - .qdev.name = "VT82C686B_PM", - .qdev.desc = "PM", - .qdev.size = sizeof(VT686PMState), - .qdev.vmsd = &vmstate_acpi, - .init = vt82c686b_pm_initfn, - .config_write = pm_write_config, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_ACPI, - .class_id = PCI_CLASS_BRIDGE_OTHER, - .revision = 0x40, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property via_pm_properties[] = { + DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void via_pm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = vt82c686b_pm_initfn; + k->config_write = pm_write_config; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_ACPI; + k->class_id = PCI_CLASS_BRIDGE_OTHER; + k->revision = 0x40; + dc->desc = "PM"; + dc->vmsd = &vmstate_acpi; + dc->props = via_pm_properties; +} + +static TypeInfo via_pm_info = { + .name = "VT82C686B_PM", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VT686PMState), + .class_init = via_pm_class_init, }; static void vt82c686b_pm_register(void) { - pci_qdev_register(&via_pm_info); + type_register_static(&via_pm_info); } device_init(vt82c686b_pm_register); @@ -519,22 +548,31 @@ ISABus *vt82c686b_init(PCIBus *bus, int devfn) return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0")); } -static PCIDeviceInfo via_info = { - .qdev.name = "VT82C686B", - .qdev.desc = "ISA bridge", - .qdev.size = sizeof(VT82C686BState), - .qdev.vmsd = &vmstate_via, - .qdev.no_user = 1, - .init = vt82c686b_initfn, - .config_write = vt82c686b_write_config, - .vendor_id = PCI_VENDOR_ID_VIA, - .device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE, - .class_id = PCI_CLASS_BRIDGE_ISA, - .revision = 0x40, +static void via_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = vt82c686b_initfn; + k->config_write = vt82c686b_write_config; + k->vendor_id = PCI_VENDOR_ID_VIA; + k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE; + k->class_id = PCI_CLASS_BRIDGE_ISA; + k->revision = 0x40; + dc->desc = "ISA bridge"; + dc->no_user = 1; + dc->vmsd = &vmstate_via; +} + +static TypeInfo via_info = { + .name = "VT82C686B", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(VT82C686BState), + .class_init = via_class_init, }; static void vt82c686b_register(void) { - pci_qdev_register(&via_info); + type_register_static(&via_info); } device_init(vt82c686b_register); diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 20d8673186..41325f0955 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -143,7 +143,7 @@ static void i6300esb_disable_timer(I6300State *d) static void i6300esb_reset(DeviceState *dev) { - PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev); + PCIDevice *pdev = PCI_DEVICE(dev); I6300State *d = DO_UPCAST(I6300State, dev, pdev); i6300esb_debug("I6300State = %p\n", d); @@ -425,24 +425,33 @@ static WatchdogTimerModel model = { .wdt_description = "Intel 6300ESB", }; -static PCIDeviceInfo i6300esb_info = { - .qdev.name = "i6300esb", - .qdev.size = sizeof(I6300State), - .qdev.vmsd = &vmstate_i6300esb, - .qdev.reset = i6300esb_reset, - .config_read = i6300esb_config_read, - .config_write = i6300esb_config_write, - .init = i6300esb_init, - .exit = i6300esb_exit, - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = PCI_DEVICE_ID_INTEL_ESB_9, - .class_id = PCI_CLASS_SYSTEM_OTHER, +static void i6300esb_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->config_read = i6300esb_config_read; + k->config_write = i6300esb_config_write; + k->init = i6300esb_init; + k->exit = i6300esb_exit; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_ESB_9; + k->class_id = PCI_CLASS_SYSTEM_OTHER; + dc->reset = i6300esb_reset; + dc->vmsd = &vmstate_i6300esb; +} + +static TypeInfo i6300esb_info = { + .name = "i6300esb", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(I6300State), + .class_init = i6300esb_class_init, }; static void i6300esb_register_devices(void) { watchdog_add_model(&model); - pci_qdev_register(&i6300esb_info); + type_register_static(&i6300esb_info); } device_init(i6300esb_register_devices); diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c index ba1d92d615..8faa2316c9 100644 --- a/hw/wdt_ib700.c +++ b/hw/wdt_ib700.c @@ -120,18 +120,26 @@ static WatchdogTimerModel model = { .wdt_description = "iBASE 700", }; -static ISADeviceInfo wdt_ib700_info = { - .qdev.name = "ib700", - .qdev.size = sizeof(IB700State), - .qdev.vmsd = &vmstate_ib700, - .qdev.reset = wdt_ib700_reset, - .init = wdt_ib700_init, +static void wdt_ib700_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); + ic->init = wdt_ib700_init; + dc->reset = wdt_ib700_reset; + dc->vmsd = &vmstate_ib700; +} + +static TypeInfo wdt_ib700_info = { + .name = "ib700", + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(IB700State), + .class_init = wdt_ib700_class_init, }; static void wdt_ib700_register_devices(void) { watchdog_add_model(&model); - isa_qdev_register(&wdt_ib700_info); + type_register_static(&wdt_ib700_info); } device_init(wdt_ib700_register_devices); diff --git a/hw/wm8750.c b/hw/wm8750.c index 9fbdf3d54b..18afa4c1ac 100644 --- a/hw/wm8750.c +++ b/hw/wm8750.c @@ -24,7 +24,7 @@ typedef struct { } WMRate; typedef struct { - i2c_slave i2c; + I2CSlave i2c; uint8_t i2c_data[2]; int i2c_len; QEMUSoundCard card; @@ -254,7 +254,7 @@ static void wm8750_clk_update(WM8750State *s, int ext) } } -static void wm8750_reset(i2c_slave *i2c) +static void wm8750_reset(I2CSlave *i2c) { WM8750State *s = (WM8750State *) i2c; s->rate = &wm_rate_table[0]; @@ -297,7 +297,7 @@ static void wm8750_reset(i2c_slave *i2c) s->i2c_len = 0; } -static void wm8750_event(i2c_slave *i2c, enum i2c_event event) +static void wm8750_event(I2CSlave *i2c, enum i2c_event event) { WM8750State *s = (WM8750State *) i2c; @@ -354,7 +354,7 @@ static void wm8750_event(i2c_slave *i2c, enum i2c_event event) #define WM8750_ROUT2V 0x29 #define WM8750_MOUTV 0x2a -static int wm8750_tx(i2c_slave *i2c, uint8_t data) +static int wm8750_tx(I2CSlave *i2c, uint8_t data) { WM8750State *s = (WM8750State *) i2c; uint8_t cmd; @@ -554,7 +554,7 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data) return 0; } -static int wm8750_rx(i2c_slave *i2c) +static int wm8750_rx(I2CSlave *i2c) { return 0x00; } @@ -609,7 +609,7 @@ static const VMStateDescription vmstate_wm8750 = { } }; -static int wm8750_init(i2c_slave *i2c) +static int wm8750_init(I2CSlave *i2c) { WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c); @@ -620,7 +620,7 @@ static int wm8750_init(i2c_slave *i2c) } #if 0 -static void wm8750_fini(i2c_slave *i2c) +static void wm8750_fini(I2CSlave *i2c) { WM8750State *s = (WM8750State *) i2c; wm8750_reset(&s->i2c); @@ -689,19 +689,28 @@ void wm8750_set_bclk_in(void *opaque, int new_hz) wm8750_clk_update(s, 1); } -static I2CSlaveInfo wm8750_info = { - .qdev.name = "wm8750", - .qdev.size = sizeof(WM8750State), - .qdev.vmsd = &vmstate_wm8750, - .init = wm8750_init, - .event = wm8750_event, - .recv = wm8750_rx, - .send = wm8750_tx +static void wm8750_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); + + sc->init = wm8750_init; + sc->event = wm8750_event; + sc->recv = wm8750_rx; + sc->send = wm8750_tx; + dc->vmsd = &vmstate_wm8750; +} + +static TypeInfo wm8750_info = { + .name = "wm8750", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(WM8750State), + .class_init = wm8750_class_init, }; static void wm8750_register_devices(void) { - i2c_register_slave(&wm8750_info); + type_register_static(&wm8750_info); } device_init(wm8750_register_devices) diff --git a/hw/xen_platform.c b/hw/xen_platform.c index e62eaef7d1..e7571022e4 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -372,25 +372,33 @@ static void platform_reset(DeviceState *dev) platform_fixed_ioport_reset(s); } -static PCIDeviceInfo xen_platform_info = { - .init = xen_platform_initfn, - .qdev.name = "xen-platform", - .qdev.desc = "XEN platform pci device", - .qdev.size = sizeof(PCIXenPlatformState), - .qdev.vmsd = &vmstate_xen_platform, - .qdev.reset = platform_reset, - - .vendor_id = PCI_VENDOR_ID_XEN, - .device_id = PCI_DEVICE_ID_XEN_PLATFORM, - .class_id = PCI_CLASS_OTHERS << 8 | 0x80, - .subsystem_vendor_id = PCI_VENDOR_ID_XEN, - .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM, - .revision = 1, +static void xen_platform_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->init = xen_platform_initfn; + k->vendor_id = PCI_VENDOR_ID_XEN; + k->device_id = PCI_DEVICE_ID_XEN_PLATFORM; + k->class_id = PCI_CLASS_OTHERS << 8 | 0x80; + k->subsystem_vendor_id = PCI_VENDOR_ID_XEN; + k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM; + k->revision = 1; + dc->desc = "XEN platform pci device"; + dc->reset = platform_reset; + dc->vmsd = &vmstate_xen_platform; +} + +static TypeInfo xen_platform_info = { + .name = "xen-platform", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIXenPlatformState), + .class_init = xen_platform_class_init, }; static void xen_platform_register(void) { - pci_qdev_register(&xen_platform_info); + type_register_static(&xen_platform_info); } device_init(xen_platform_register); diff --git a/hw/xgmac.c b/hw/xgmac.c new file mode 100644 index 0000000000..d395b1cc2d --- /dev/null +++ b/hw/xgmac.c @@ -0,0 +1,433 @@ +/* + * QEMU model of XGMAC Ethernet. + * + * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias. + * + * Copyright (c) 2011 Calxeda, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "qemu-char.h" +#include "qemu-log.h" +#include "net.h" +#include "net/checksum.h" + +#ifdef DEBUG_XGMAC +#define DEBUGF_BRK(message, args...) do { \ + fprintf(stderr, (message), ## args); \ + } while (0) +#else +#define DEBUGF_BRK(message, args...) do { } while (0) +#endif + +#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */ +#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */ +#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */ +#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */ +#define XGMAC_VERSION 0x00000008 /* Version */ +/* VLAN tag for insertion or replacement into tx frames */ +#define XGMAC_VLAN_INCL 0x00000009 +#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */ +#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */ +#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */ +#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */ +#define XGMAC_DEBUG 0x0000000e /* Debug */ +#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */ +/* HASH table registers */ +#define XGMAC_HASH(n) ((0x00000300/4) + (n)) +#define XGMAC_NUM_HASH 16 +/* Operation Mode */ +#define XGMAC_OPMODE (0x00000400/4) +/* Remote Wake-Up Frame Filter */ +#define XGMAC_REMOTE_WAKE (0x00000700/4) +/* PMT Control and Status */ +#define XGMAC_PMT (0x00000704/4) + +#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2)) +#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2)) + +#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */ +#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */ +#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */ +#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */ +#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */ +#define DMA_STATUS 0x000003c5 /* Status Register */ +#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */ +#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */ +#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */ +/* Receive Interrupt Watchdog Timer */ +#define DMA_RI_WATCHDOG_TIMER 0x000003c9 +#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */ +#define DMA_AXI_STATUS 0x000003cb /* AXI Status */ +#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */ +#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */ +#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */ +#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */ +#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */ + +/* DMA Status register defines */ +#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ +#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ +#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */ +#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */ +#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */ +#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */ +#define DMA_STATUS_TS_SHIFT 20 +#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */ +#define DMA_STATUS_RS_SHIFT 17 +#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */ +#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */ +#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */ +#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */ +#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */ +#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */ +#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */ +#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */ +#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */ +#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */ +#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */ +#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */ +#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */ +#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */ +#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */ + +/* DMA Control register defines */ +#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */ +#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */ +#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */ + +struct desc { + uint32_t ctl_stat; + uint16_t buffer1_size; + uint16_t buffer2_size; + uint32_t buffer1_addr; + uint32_t buffer2_addr; + uint32_t ext_stat; + uint32_t res[3]; +}; + +#define R_MAX 0x400 + +typedef struct RxTxStats { + uint64_t rx_bytes; + uint64_t tx_bytes; + + uint64_t rx; + uint64_t rx_bcast; + uint64_t rx_mcast; +} RxTxStats; + +typedef struct XgmacState { + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq sbd_irq; + qemu_irq pmt_irq; + qemu_irq mci_irq; + NICState *nic; + NICConf conf; + + struct RxTxStats stats; + uint32_t regs[R_MAX]; +} XgmacState; + +const VMStateDescription vmstate_rxtx_stats = { + .name = "xgmac_stats", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT64(rx_bytes, RxTxStats), + VMSTATE_UINT64(tx_bytes, RxTxStats), + VMSTATE_UINT64(rx, RxTxStats), + VMSTATE_UINT64(rx_bcast, RxTxStats), + VMSTATE_UINT64(rx_mcast, RxTxStats), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xgmac = { + .name = "xgmac", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats), + VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX), + VMSTATE_END_OF_LIST() + } +}; + +static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx) +{ + uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] : + s->regs[DMA_CUR_TX_DESC_ADDR]; + cpu_physical_memory_read(addr, d, sizeof(*d)); +} + +static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx) +{ + int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR; + uint32_t addr = s->regs[reg]; + + if (!rx && (d->ctl_stat & 0x00200000)) { + s->regs[reg] = s->regs[DMA_TX_BASE_ADDR]; + } else if (rx && (d->buffer1_size & 0x8000)) { + s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR]; + } else { + s->regs[reg] += sizeof(*d); + } + cpu_physical_memory_write(addr, d, sizeof(*d)); +} + +static void xgmac_enet_send(struct XgmacState *s) +{ + struct desc bd; + int frame_size; + int len; + uint8_t frame[8192]; + uint8_t *ptr; + + ptr = frame; + frame_size = 0; + while (1) { + xgmac_read_desc(s, &bd, 0); + if ((bd.ctl_stat & 0x80000000) == 0) { + /* Run out of descriptors to transmit. */ + break; + } + len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff); + + if ((bd.buffer1_size & 0xfff) > 2048) { + DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " + "xgmac buffer 1 len on send > 2048 (0x%x)\n", + __func__, bd.buffer1_size & 0xfff); + } + if ((bd.buffer2_size & 0xfff) != 0) { + DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- " + "xgmac buffer 2 len on send != 0 (0x%x)\n", + __func__, bd.buffer2_size & 0xfff); + } + if (len >= sizeof(frame)) { + DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu " + "buffer\n" , __func__, len, sizeof(frame)); + DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n", + __func__, bd.buffer1_size, bd.buffer2_size); + } + + cpu_physical_memory_read(bd.buffer1_addr, ptr, len); + ptr += len; + frame_size += len; + if (bd.ctl_stat & 0x20000000) { + /* Last buffer in frame. */ + qemu_send_packet(&s->nic->nc, frame, len); + ptr = frame; + frame_size = 0; + s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS; + } + bd.ctl_stat &= ~0x80000000; + /* Write back the modified descriptor. */ + xgmac_write_desc(s, &bd, 0); + } +} + +static void enet_update_irq(struct XgmacState *s) +{ + int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA]; + qemu_set_irq(s->sbd_irq, !!stat); +} + +static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size) +{ + struct XgmacState *s = opaque; + uint64_t r = 0; + addr >>= 2; + + switch (addr) { + case XGMAC_VERSION: + r = 0x1012; + break; + default: + if (addr < ARRAY_SIZE(s->regs)) { + r = s->regs[addr]; + } + break; + } + return r; +} + +static void enet_write(void *opaque, target_phys_addr_t addr, + uint64_t value, unsigned size) +{ + struct XgmacState *s = opaque; + + addr >>= 2; + switch (addr) { + case DMA_BUS_MODE: + s->regs[DMA_BUS_MODE] = value & ~0x1; + break; + case DMA_XMT_POLL_DEMAND: + xgmac_enet_send(s); + break; + case DMA_STATUS: + s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value; + break; + case DMA_RCV_BASE_ADDR: + s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value; + break; + case DMA_TX_BASE_ADDR: + s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value; + break; + default: + if (addr < ARRAY_SIZE(s->regs)) { + s->regs[addr] = value; + } + break; + } + enet_update_irq(s); +} + +static const MemoryRegionOps enet_mem_ops = { + .read = enet_read, + .write = enet_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static int eth_can_rx(VLANClientState *nc) +{ + struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + + /* RX enabled? */ + return s->regs[DMA_CONTROL] & DMA_CONTROL_SR; +} + +static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size) +{ + struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, + 0xff, 0xff, 0xff}; + int unicast, broadcast, multicast; + struct desc bd; + ssize_t ret; + + unicast = ~buf[0] & 0x1; + broadcast = memcmp(buf, sa_bcast, 6) == 0; + multicast = !unicast && !broadcast; + if (size < 12) { + s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; + ret = -1; + goto out; + } + + xgmac_read_desc(s, &bd, 1); + if ((bd.ctl_stat & 0x80000000) == 0) { + s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS; + ret = size; + goto out; + } + + cpu_physical_memory_write(bd.buffer1_addr, buf, size); + + /* Add in the 4 bytes for crc (the real hw returns length incl crc) */ + size += 4; + bd.ctl_stat = (size << 16) | 0x300; + xgmac_write_desc(s, &bd, 1); + + s->stats.rx_bytes += size; + s->stats.rx++; + if (multicast) { + s->stats.rx_mcast++; + } else if (broadcast) { + s->stats.rx_bcast++; + } + + s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS; + ret = size; + +out: + enet_update_irq(s); + return ret; +} + +static void eth_cleanup(VLANClientState *nc) +{ + struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque; + s->nic = NULL; +} + +static NetClientInfo net_xgmac_enet_info = { + .type = NET_CLIENT_TYPE_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_rx, + .receive = eth_rx, + .cleanup = eth_cleanup, +}; + +static int xgmac_enet_init(SysBusDevice *dev) +{ + struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev); + + memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000); + sysbus_init_mmio(dev, &s->iomem); + sysbus_init_irq(dev, &s->sbd_irq); + sysbus_init_irq(dev, &s->pmt_irq); + sysbus_init_irq(dev, &s->mci_irq); + + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf, + object_get_typename(OBJECT(dev)), dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + + s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) | + s->conf.macaddr.a[4]; + s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) | + (s->conf.macaddr.a[2] << 16) | + (s->conf.macaddr.a[1] << 8) | + s->conf.macaddr.a[0]; + + return 0; +} + +static Property xgmac_properties[] = { + DEFINE_NIC_PROPERTIES(struct XgmacState, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xgmac_enet_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + sbc->init = xgmac_enet_init; + dc->vmsd = &vmstate_xgmac; + dc->props = xgmac_properties; +} + +static TypeInfo xgmac_enet_info = { + .name = "xgmac", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct XgmacState), + .class_init = xgmac_enet_class_init, +}; + +static void xgmac_enet_register(void) +{ + type_register_static(&xgmac_enet_info); +} + +device_init(xgmac_enet_register) diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c index 0da20d9565..e8a53123f9 100644 --- a/hw/xilinx_axidma.c +++ b/hw/xilinx_axidma.c @@ -486,20 +486,31 @@ static int xilinx_axidma_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo axidma_info = { - .init = xilinx_axidma_init, - .qdev.name = "xilinx,axidma", - .qdev.size = sizeof(struct XilinxAXIDMA), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000), - DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach), - DEFINE_PROP_END_OF_LIST(), - } +static Property axidma_properties[] = { + DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000), + DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach), + DEFINE_PROP_END_OF_LIST(), +}; + +static void axidma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_axidma_init; + dc->props = axidma_properties; +} + +static TypeInfo axidma_info = { + .name = "xilinx,axidma", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct XilinxAXIDMA), + .class_init = axidma_class_init, }; static void xilinx_axidma_register(void) { - sysbus_register_withprop(&axidma_info); + type_register_static(&axidma_info); } device_init(xilinx_axidma_register) diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index a2eb3e6d5b..1ce2db4510 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -856,7 +856,7 @@ static int xilinx_enet_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); tdk_init(&s->TEMAC.phy); @@ -870,22 +870,33 @@ static int xilinx_enet_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo xilinx_enet_info = { - .init = xilinx_enet_init, - .qdev.name = "xilinx,axienet", - .qdev.size = sizeof(struct XilinxAXIEnet), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7), - DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000), - DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000), - DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach), - DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property xilinx_enet_properties[] = { + DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7), + DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000), + DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000), + DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach), + DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_enet_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_enet_init; + dc->props = xilinx_enet_properties; +} + +static TypeInfo xilinx_enet_info = { + .name = "xilinx,axienet", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct XilinxAXIEnet), + .class_init = xilinx_enet_class_init, }; static void xilinx_enet_register(void) { - sysbus_register_withprop(&xilinx_enet_info); + type_register_static(&xilinx_enet_info); } device_init(xilinx_enet_register) diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 6777254f35..499feef488 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -221,26 +221,37 @@ static int xilinx_ethlite_init(SysBusDevice *dev) qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, - dev->qdev.info->name, dev->qdev.id, s); + object_get_typename(OBJECT(dev)), dev->qdev.id, s); qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); return 0; } -static SysBusDeviceInfo xilinx_ethlite_info = { - .init = xilinx_ethlite_init, - .qdev.name = "xilinx,ethlite", - .qdev.size = sizeof(struct xlx_ethlite), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1), - DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1), - DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf), - DEFINE_PROP_END_OF_LIST(), - } +static Property xilinx_ethlite_properties[] = { + DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1), + DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1), + DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_ethlite_init; + dc->props = xilinx_ethlite_properties; +} + +static TypeInfo xilinx_ethlite_info = { + .name = "xilinx,ethlite", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct xlx_ethlite), + .class_init = xilinx_ethlite_class_init, }; static void xilinx_ethlite_register(void) { - sysbus_register_withprop(&xilinx_ethlite_info); + type_register_static(&xilinx_ethlite_info); } device_init(xilinx_ethlite_register) diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c index c567885bcf..73eed6dc5f 100644 --- a/hw/xilinx_intc.c +++ b/hw/xilinx_intc.c @@ -161,19 +161,30 @@ static int xilinx_intc_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo xilinx_intc_info = { - .init = xilinx_intc_init, - .qdev.name = "xilinx,intc", - .qdev.size = sizeof(struct xlx_pic), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property xilinx_intc_properties[] = { + DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_intc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_intc_init; + dc->props = xilinx_intc_properties; +} + +static TypeInfo xilinx_intc_info = { + .name = "xilinx,intc", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct xlx_pic), + .class_init = xilinx_intc_class_init, }; static void xilinx_intc_register(void) { - sysbus_register_withprop(&xilinx_intc_info); + type_register_static(&xilinx_intc_info); } device_init(xilinx_intc_register) diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c index adca53b98c..c8236d2e2a 100644 --- a/hw/xilinx_timer.c +++ b/hw/xilinx_timer.c @@ -219,20 +219,31 @@ static int xilinx_timer_init(SysBusDevice *dev) return 0; } -static SysBusDeviceInfo xilinx_timer_info = { - .init = xilinx_timer_init, - .qdev.name = "xilinx,timer", - .qdev.size = sizeof(struct timerblock), - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0), - DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0), - DEFINE_PROP_END_OF_LIST(), - } +static Property xilinx_timer_properties[] = { + DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0), + DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xilinx_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = xilinx_timer_init; + dc->props = xilinx_timer_properties; +} + +static TypeInfo xilinx_timer_info = { + .name = "xilinx,timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct timerblock), + .class_init = xilinx_timer_class_init, }; static void xilinx_timer_register(void) { - sysbus_register_withprop(&xilinx_timer_info); + type_register_static(&xilinx_timer_info); } device_init(xilinx_timer_register) diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index 6533df934f..1c2b9087b4 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -205,16 +205,29 @@ static int xilinx_uartlite_init(SysBusDevice *dev) memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); - s->chr = qdev_init_chardev(&dev->qdev); + s->chr = qemu_char_get_next_serial(); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); return 0; } +static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + + sdc->init = xilinx_uartlite_init; +} + +static TypeInfo xilinx_uartlite_info = { + .name = "xilinx,uartlite", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (struct xlx_uartlite), + .class_init = xilinx_uartlite_class_init, +}; + static void xilinx_uart_register(void) { - sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite), - xilinx_uartlite_init); + type_register_static(&xilinx_uartlite_info); } device_init(xilinx_uart_register) diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index d3c387d6cb..07e4fc1018 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -47,7 +47,7 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address, static void xio3130_downstream_reset(DeviceState *qdev) { - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *d = PCI_DEVICE(qdev); msi_reset(d); pcie_cap_deverr_reset(d); pcie_cap_slot_reset(d); @@ -167,36 +167,45 @@ static const VMStateDescription vmstate_xio3130_downstream = { } }; -static PCIDeviceInfo xio3130_downstream_info = { - .qdev.name = "xio3130-downstream", - .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch", - .qdev.size = sizeof(PCIESlot), - .qdev.reset = xio3130_downstream_reset, - .qdev.vmsd = &vmstate_xio3130_downstream, - - .is_express = 1, - .is_bridge = 1, - .config_write = xio3130_downstream_write_config, - .init = xio3130_downstream_initfn, - .exit = xio3130_downstream_exitfn, - .vendor_id = PCI_VENDOR_ID_TI, - .device_id = PCI_DEVICE_ID_TI_XIO3130D, - .revision = XIO3130_REVISION, - - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), - DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), - DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIESlot, - port.br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), - } +static Property xio3130_downstream_properties[] = { + DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0), + DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0), + DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0), + DEFINE_PROP_UINT16("aer_log_max", PCIESlot, + port.br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xio3130_downstream_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->is_express = 1; + k->is_bridge = 1; + k->config_write = xio3130_downstream_write_config; + k->init = xio3130_downstream_initfn; + k->exit = xio3130_downstream_exitfn; + k->vendor_id = PCI_VENDOR_ID_TI; + k->device_id = PCI_DEVICE_ID_TI_XIO3130D; + k->revision = XIO3130_REVISION; + dc->desc = "TI X3130 Downstream Port of PCI Express Switch"; + dc->reset = xio3130_downstream_reset; + dc->vmsd = &vmstate_xio3130_downstream; + dc->props = xio3130_downstream_properties; +} + +static TypeInfo xio3130_downstream_info = { + .name = "xio3130-downstream", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIESlot), + .class_init = xio3130_downstream_class_init, }; static void xio3130_downstream_register(void) { - pci_qdev_register(&xio3130_downstream_info); + type_register_static(&xio3130_downstream_info); } device_init(xio3130_downstream_register); diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 82836958a4..7887c92fcc 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -46,7 +46,7 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address, static void xio3130_upstream_reset(DeviceState *qdev) { - PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev); + PCIDevice *d = PCI_DEVICE(qdev); msi_reset(d); pci_bridge_reset(qdev); pcie_cap_deverr_reset(d); @@ -144,33 +144,42 @@ static const VMStateDescription vmstate_xio3130_upstream = { } }; -static PCIDeviceInfo xio3130_upstream_info = { - .qdev.name = "x3130-upstream", - .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch", - .qdev.size = sizeof(PCIEPort), - .qdev.reset = xio3130_upstream_reset, - .qdev.vmsd = &vmstate_xio3130_upstream, - - .is_express = 1, - .is_bridge = 1, - .config_write = xio3130_upstream_write_config, - .init = xio3130_upstream_initfn, - .exit = xio3130_upstream_exitfn, - .vendor_id = PCI_VENDOR_ID_TI, - .device_id = PCI_DEVICE_ID_TI_XIO3130U, - .revision = XIO3130_REVISION, - - .qdev.props = (Property[]) { - DEFINE_PROP_UINT8("port", PCIEPort, port, 0), - DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max, - PCIE_AER_LOG_MAX_DEFAULT), - DEFINE_PROP_END_OF_LIST(), - } +static Property xio3130_upstream_properties[] = { + DEFINE_PROP_UINT8("port", PCIEPort, port, 0), + DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max, + PCIE_AER_LOG_MAX_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xio3130_upstream_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->is_express = 1; + k->is_bridge = 1; + k->config_write = xio3130_upstream_write_config; + k->init = xio3130_upstream_initfn; + k->exit = xio3130_upstream_exitfn; + k->vendor_id = PCI_VENDOR_ID_TI; + k->device_id = PCI_DEVICE_ID_TI_XIO3130U; + k->revision = XIO3130_REVISION; + dc->desc = "TI X3130 Upstream Port of PCI Express Switch"; + dc->reset = xio3130_upstream_reset; + dc->vmsd = &vmstate_xio3130_upstream; + dc->props = xio3130_upstream_properties; +} + +static TypeInfo xio3130_upstream_info = { + .name = "x3130-upstream", + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PCIEPort), + .class_init = xio3130_upstream_class_init, }; static void xio3130_upstream_register(void) { - pci_qdev_register(&xio3130_upstream_info); + type_register_static(&xio3130_upstream_info); } device_init(xio3130_upstream_register); @@ -174,21 +174,30 @@ static VMStateDescription vmstate_zipit_lcd_state = { } }; -static SSISlaveInfo zipit_lcd_info = { - .qdev.name = "zipit-lcd", - .qdev.size = sizeof(ZipitLCD), - .qdev.vmsd = &vmstate_zipit_lcd_state, - .init = zipit_lcd_init, - .transfer = zipit_lcd_transfer +static void zipit_lcd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = zipit_lcd_init; + k->transfer = zipit_lcd_transfer; + dc->vmsd = &vmstate_zipit_lcd_state; +} + +static TypeInfo zipit_lcd_info = { + .name = "zipit-lcd", + .parent = TYPE_SSI_SLAVE, + .instance_size = sizeof(ZipitLCD), + .class_init = zipit_lcd_class_init, }; typedef struct { - i2c_slave i2c; + I2CSlave i2c; int len; uint8_t buf[3]; } AER915State; -static int aer915_send(i2c_slave *i2c, uint8_t data) +static int aer915_send(I2CSlave *i2c, uint8_t data) { AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); s->buf[s->len] = data; @@ -206,7 +215,7 @@ static int aer915_send(i2c_slave *i2c, uint8_t data) return 0; } -static void aer915_event(i2c_slave *i2c, enum i2c_event event) +static void aer915_event(I2CSlave *i2c, enum i2c_event event) { AER915State *s = FROM_I2C_SLAVE(AER915State, i2c); switch (event) { @@ -225,7 +234,7 @@ static void aer915_event(i2c_slave *i2c, enum i2c_event event) } } -static int aer915_recv(i2c_slave *slave) +static int aer915_recv(I2CSlave *slave) { int retval = 0x00; AER915State *s = FROM_I2C_SLAVE(AER915State, slave); @@ -248,7 +257,7 @@ static int aer915_recv(i2c_slave *slave) return retval; } -static int aer915_init(i2c_slave *i2c) +static int aer915_init(I2CSlave *i2c) { /* Nothing to do. */ return 0; @@ -266,14 +275,23 @@ static VMStateDescription vmstate_aer915_state = { } }; -static I2CSlaveInfo aer915_info = { - .qdev.name = "aer915", - .qdev.size = sizeof(AER915State), - .qdev.vmsd = &vmstate_aer915_state, - .init = aer915_init, - .event = aer915_event, - .recv = aer915_recv, - .send = aer915_send +static void aer915_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = aer915_init; + k->event = aer915_event; + k->recv = aer915_recv; + k->send = aer915_send; + dc->vmsd = &vmstate_aer915_state; +} + +static TypeInfo aer915_info = { + .name = "aer915", + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AER915State), + .class_init = aer915_class_init, }; static void z2_init(ram_addr_t ram_size, @@ -326,8 +344,8 @@ static void z2_init(ram_addr_t ram_size, NULL, qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT)); - ssi_register_slave(&zipit_lcd_info); - i2c_register_slave(&aer915_info); + type_register_static(&zipit_lcd_info); + type_register_static(&aer915_info); z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd"); bus = pxa2xx_i2c_bus(cpu->i2c[0]); i2c_create_slave(bus, "aer915", 0x55); diff --git a/hw/zaurus.c b/hw/zaurus.c index c4bcd29825..055df9b4e2 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -221,20 +221,31 @@ static const VMStateDescription vmstate_scoop_regs = { }, }; -static SysBusDeviceInfo scoop_sysbus_info = { - .init = scoop_init, - .qdev.name = "scoop", - .qdev.desc = "Scoop2 Sharp custom ASIC", - .qdev.size = sizeof(ScoopInfo), - .qdev.vmsd = &vmstate_scoop_regs, - .qdev.props = (Property[]) { - DEFINE_PROP_END_OF_LIST(), - } +static Property scoop_sysbus_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + +static void scoop_sysbus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = scoop_init; + dc->desc = "Scoop2 Sharp custom ASIC"; + dc->vmsd = &vmstate_scoop_regs; + dc->props = scoop_sysbus_properties; +} + +static TypeInfo scoop_sysbus_info = { + .name = "scoop", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(ScoopInfo), + .class_init = scoop_sysbus_class_init, }; static void scoop_register(void) { - sysbus_register_withprop(&scoop_sysbus_info); + type_register_static(&scoop_sysbus_info); } device_init(scoop_register); |