aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ide/pci.c84
-rw-r--r--include/hw/ide/pci.h1
2 files changed, 85 insertions, 0 deletions
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index a25b352..810c6b6 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -104,6 +104,90 @@ const MemoryRegionOps pci_ide_data_le_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+void pci_ide_update_mode(PCIIDEState *s)
+{
+ PCIDevice *d = PCI_DEVICE(s);
+ uint8_t mode = d->config[PCI_CLASS_PROG];
+
+ /*
+ * This function only configures the BARs/ioports for now: PCI IDE
+ * controllers must manage their own IRQ routing
+ */
+
+ switch (mode & 0xf) {
+ case 0xa:
+ /* Both channels legacy mode */
+
+ /*
+ * TODO: according to the PCI IDE specification the BARs should
+ * be completely disabled, however Linux for the pegasos2
+ * machine stil accesses the BAR addresses after switching to legacy
+ * mode. Hence we leave them active for now.
+ */
+
+ /* Clear interrupt pin */
+ pci_config_set_interrupt_pin(d->config, 0);
+
+ /* Add legacy IDE ports */
+ if (!s->bus[0].portio_list.owner) {
+ portio_list_init(&s->bus[0].portio_list, OBJECT(d),
+ ide_portio_list, &s->bus[0], "ide");
+ portio_list_add(&s->bus[0].portio_list,
+ pci_address_space_io(d), 0x1f0);
+ }
+
+ if (!s->bus[0].portio2_list.owner) {
+ portio_list_init(&s->bus[0].portio2_list, OBJECT(d),
+ ide_portio2_list, &s->bus[0], "ide");
+ portio_list_add(&s->bus[0].portio2_list,
+ pci_address_space_io(d), 0x3f6);
+ }
+
+ if (!s->bus[1].portio_list.owner) {
+ portio_list_init(&s->bus[1].portio_list, OBJECT(d),
+ ide_portio_list, &s->bus[1], "ide");
+ portio_list_add(&s->bus[1].portio_list,
+ pci_address_space_io(d), 0x170);
+ }
+
+ if (!s->bus[1].portio2_list.owner) {
+ portio_list_init(&s->bus[1].portio2_list, OBJECT(d),
+ ide_portio2_list, &s->bus[1], "ide");
+ portio_list_add(&s->bus[1].portio2_list,
+ pci_address_space_io(d), 0x376);
+ }
+ break;
+
+ case 0xf:
+ /* Both channels native mode */
+
+ /* Set interrupt pin */
+ pci_config_set_interrupt_pin(d->config, 1);
+
+ /* Remove legacy IDE ports */
+ if (s->bus[0].portio_list.owner) {
+ portio_list_del(&s->bus[0].portio_list);
+ portio_list_destroy(&s->bus[0].portio_list);
+ }
+
+ if (s->bus[0].portio2_list.owner) {
+ portio_list_del(&s->bus[0].portio2_list);
+ portio_list_destroy(&s->bus[0].portio2_list);
+ }
+
+ if (s->bus[1].portio_list.owner) {
+ portio_list_del(&s->bus[1].portio_list);
+ portio_list_destroy(&s->bus[1].portio_list);
+ }
+
+ if (s->bus[1].portio2_list.owner) {
+ portio_list_del(&s->bus[1].portio2_list);
+ portio_list_destroy(&s->bus[1].portio2_list);
+ }
+ break;
+ }
+}
+
static IDEState *bmdma_active_if(BMDMAState *bmdma)
{
assert(bmdma->bus->retry_unit != (uint8_t)-1);
diff --git a/include/hw/ide/pci.h b/include/hw/ide/pci.h
index 1ff469d..a814a0a 100644
--- a/include/hw/ide/pci.h
+++ b/include/hw/ide/pci.h
@@ -61,6 +61,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
void bmdma_status_writeb(BMDMAState *bm, uint32_t val);
extern MemoryRegionOps bmdma_addr_ioport_ops;
void pci_ide_create_devs(PCIDevice *dev);
+void pci_ide_update_mode(PCIIDEState *s);
extern const VMStateDescription vmstate_ide_pci;
extern const MemoryRegionOps pci_ide_cmd_le_ops;