diff --git a/hw/ide/via.c b/hw/ide/via.c
index fff23803a6..82f2af1c78 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -28,12 +28,27 @@
#include "hw/pci/pci.h"
#include "migration/vmstate.h"
#include "qemu/module.h"
+#include "qemu/range.h"
#include "sysemu/dma.h"
#include "hw/isa/vt82c686.h"
#include "hw/ide/pci.h"
#include "hw/irq.h"
#include "trace.h"
+
+/* FIXME: export these from hw/ide/ioport.c */
+static const MemoryRegionPortio ide_portio_list[] = {
+ { 0, 8, 1, .read = ide_ioport_read, .write = ide_ioport_write },
+ { 0, 1, 2, .read = ide_data_readw, .write = ide_data_writew },
+ { 0, 1, 4, .read = ide_data_readl, .write = ide_data_writel },
+ PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio ide_portio2_list[] = {
+ { 0, 1, 1, .read = ide_status_read, .write = ide_ctrl_write },
+ PORTIO_END_OF_LIST(),
+};
+
static uint64_t bmdma_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -137,7 +152,10 @@ static void via_ide_reset(DeviceState *dev)
pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA:
20-23h */
- pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
+ pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000000e);
+
+ /* Clear subsystem to match real hardware */
+ pci_set_long(pci_conf + 0x2c, 0x0);
/* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
pci_set_long(pci_conf + 0x40, 0x0a090600);
@@ -159,6 +177,89 @@ static void via_ide_reset(DeviceState *dev)
pci_set_long(pci_conf + 0xc0, 0x00020001);
}
+static void via_ide_cfg_write(PCIDevice *pd, uint32_t addr,
+ uint32_t val, int len)
+{
+ uint8_t *pci_conf = pd->config;
+ PCIIDEState *d = PCI_IDE(pd);
+
+ pci_default_write_config(pd, addr, val, len);
+
+ if (range_covers_byte(addr, len, PCI_CLASS_PROG)) {
+ if (pci_conf[PCI_CLASS_PROG] == 0x8a) {
+ /* FIXME: don't disable BARs
+ pci_default_write_config(pd, PCI_BASE_ADDRESS_0, 0x1, 4);
+ pci_default_write_config(pd, PCI_BASE_ADDRESS_1, 0x1, 4);
+ pci_default_write_config(pd, PCI_BASE_ADDRESS_2, 0x1, 4);
+ pci_default_write_config(pd, PCI_BASE_ADDRESS_3, 0x1, 4);
+ */
+
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x0);
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x0);
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x0);
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x0);
+
+ /* Clear interrupt pin */
+ pci_config_set_interrupt_pin(pci_conf, 0);
+
+ /* Add legacy IDE ports */
+ if (!d->bus[0].portio_list.owner) {
+ portio_list_init(&d->bus[0].portio_list, OBJECT(pd),
+ ide_portio_list, &d->bus[0], "ide");
+ portio_list_add(&d->bus[0].portio_list,
+ pci_address_space_io(pd), 0x1f0);
+ }
+
+ if (!d->bus[0].portio2_list.owner) {
+ portio_list_init(&d->bus[0].portio2_list, OBJECT(pd),
+ ide_portio2_list, &d->bus[0], "ide");
+ portio_list_add(&d->bus[0].portio2_list,
+ pci_address_space_io(pd), 0x3f6);
+ }
+
+ if (!d->bus[1].portio_list.owner) {
+ portio_list_init(&d->bus[1].portio_list, OBJECT(pd),
+ ide_portio_list, &d->bus[1], "ide");
+ portio_list_add(&d->bus[1].portio_list,
+ pci_address_space_io(pd), 0x170);
+ }
+
+ if (!d->bus[1].portio2_list.owner) {
+ portio_list_init(&d->bus[1].portio2_list, OBJECT(pd),
+ ide_portio2_list, &d->bus[1], "ide");
+ portio_list_add(&d->bus[1].portio2_list,
+ pci_address_space_io(pd), 0x376);
+ }
+ }
+
+ if (pci_conf[PCI_CLASS_PROG] == 0x8f) {
+ /* Set interrupt pin */
+ pci_config_set_interrupt_pin(pci_conf, 1);
+
+ /* Remove legacy IDE ports */
+ if (d->bus[0].portio_list.owner) {
+ portio_list_del(&d->bus[0].portio_list);
+ portio_list_destroy(&d->bus[0].portio_list);
+ }
+
+ if (d->bus[0].portio2_list.owner) {
+ portio_list_del(&d->bus[0].portio2_list);
+ portio_list_destroy(&d->bus[0].portio2_list);
+ }
+
+ if (d->bus[1].portio_list.owner) {
+ portio_list_del(&d->bus[1].portio_list);
+ portio_list_destroy(&d->bus[1].portio_list);
+ }
+
+ if (d->bus[1].portio2_list.owner) {
+ portio_list_del(&d->bus[1].portio2_list);
+ portio_list_destroy(&d->bus[1].portio2_list);
+ }
+ }
+ }
+}
+
static void via_ide_realize(PCIDevice *dev, Error **errp)
{
PCIIDEState *d = PCI_IDE(dev);
@@ -221,6 +322,7 @@ static void via_ide_class_init(ObjectClass *klass, void
*data)
/* Reason: only works as function of VIA southbridge */
dc->user_creatable = false;
+ k->config_write = via_ide_cfg_write;
k->realize = via_ide_realize;
k->exit = via_ide_exitfn;
k->vendor_id = PCI_VENDOR_ID_VIA;
Note that this also fixes the output of "lspci -vv" on Linux:
0000:00:0c.1 IDE interface: VIA Technologies, Inc.
VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06) (prog-if 8a
[Master SecP PriP])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping+ SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin ? routed to IRQ 14
Region 0: [virtual] I/O ports at 1000 [size=8]
Region 1: [virtual] I/O ports at 100c [size=4]
Region 2: [virtual] I/O ports at 1010 [size=8]
Region 3: [virtual] I/O ports at 101c [size=4]
Region 4: I/O ports at 1020 [size=16]
Kernel driver in use: pata_via
Currently the "[virtual]" prefix is missing in QEMU when compared with your
lspci output from real hardware: this patch fixes it, because it allows the
legacy IDE ioports to exist whilst having the BARs set to zero which isn't
possible with your current patch.
ATB,
Mark.