diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 56302b5..13e6f2f 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -44,35 +44,95 @@
 
 static void cmd646_update_irq(PCIIDEState *d);
 
-static void ide_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr,
+                                unsigned size)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
-    IDEBus *bus;
-
-    if (region_num <= 3) {
-        bus = &d->bus[(region_num >> 1)];
-        if (region_num & 1) {
-            register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
-            register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+    return ide_status_read(cmd646bar->bus, addr + 2);
+}
+
+static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (addr != 2 || size != 1) {
+        return;
+    }
+    ide_cmd_write(cmd646bar->bus, addr + 2, data);
+}
+
+static MemoryRegionOps cmd646_cmd_ops = {
+    .read = cmd646_cmd_read,
+    .write = cmd646_cmd_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_read(cmd646bar->bus, addr);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_readw(cmd646bar->bus, addr);
         } else {
-            register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
-            register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
-
-            /* data ports */
-            register_ioport_write(addr, 2, 2, ide_data_writew, bus);
-            register_ioport_read(addr, 2, 2, ide_data_readw, bus);
-            register_ioport_write(addr, 4, 4, ide_data_writel, bus);
-            register_ioport_read(addr, 4, 4, ide_data_readl, bus);
+            return ide_data_readl(cmd646bar->bus, addr);
         }
     }
+    return ((uint64_t)1 << (size * 8)) - 1;
 }
 
-static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                   uint32_t addr)
+static void cmd646_data_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned size)
 {
+    CMD646BAR *cmd646bar = opaque;
+
+    if (size == 1) {
+        return ide_ioport_write(cmd646bar->bus, addr, data);
+    } else if (addr == 0) {
+        if (size == 2) {
+            return ide_data_writew(cmd646bar->bus, addr, data);
+        } else {
+            return ide_data_writel(cmd646bar->bus, addr, data);
+        }
+    }
+}
+
+static MemoryRegionOps cmd646_data_ops = {
+    .read = cmd646_data_read,
+    .write = cmd646_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
+{
+    IDEBus *bus = &d->bus[bus_num];
+    CMD646BAR *bar = &d->cmd646_bar[bus_num];
+
+    bar->bus = bus;
+    bar->pci_dev = d;
+    memory_region_init_io(&bar->cmd, &cmd646_cmd_ops, bar, "cmd646-cmd", 4);
+    memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8);
+}
+
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
+{
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -100,31 +160,22 @@ static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     return val;
 }
 
-static uint32_t bmdma_readb_0(void *opaque, uint32_t addr)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
-
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
+    BMDMAState *bm = opaque;
+    PCIIDEState *pci_dev = bm->pci_dev;
 
-static uint32_t bmdma_readb_1(void *opaque, uint32_t addr)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    return bmdma_readb_common(pci_dev, bm, addr);
-}
+    if (size != 1) {
+        return;
+    }
 
-static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
-                                uint32_t addr, uint32_t val)
-{
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
     case 0:
-        bmdma_cmd_writeb(bm, addr, val);
+        bmdma_cmd_writeb(bm, val);
         break;
     case 1:
         pci_dev->dev.config[MRDMODE] =
@@ -143,42 +194,25 @@ static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
     }
 }
 
-static void bmdma_writeb_0(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[0];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
-
-static void bmdma_writeb_1(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIIDEState *pci_dev = opaque;
-    BMDMAState *bm = &pci_dev->bmdma[1];
-
-    bmdma_writeb_common(pci_dev, bm, addr, val);
-}
+static MemoryRegionOps cmd646_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
+    BMDMAState *bm;
     int i;
 
+    memory_region_init(&d->bmdma_bar, "cmd646-bmdma", 16);
     for(i = 0;i < 2; i++) {
-        BMDMAState *bm = &d->bmdma[i];
-
-        if (i == 0) {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
-        } else {
-            register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
-            register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
-        }
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        bm = &d->bmdma[i];
+        memory_region_init_io(&bm->extra_io, &cmd646_bmdma_ops, bm,
+                              "cmd646-bmdma-bus", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "cmd646-bmdma-ioport", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -234,11 +268,18 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         pci_conf[0x51] |= 0x08; /* enable IDE1 */
     }
 
-    pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
-    pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    setup_cmd646_bar(d, 0);
+    setup_cmd646_bar(d, 1);
+    pci_register_bar_region(dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[0].data);
+    pci_register_bar_region(dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[0].cmd);
+    pci_register_bar_region(dev, 2, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[1].data);
+    pci_register_bar_region(dev, 3, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->cmd646_bar[1].cmd);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 
     /* TODO: RST# value should be 0 */
     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
@@ -248,7 +289,7 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
         ide_init2(&d->bus[i], irq[i]);
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -259,6 +300,24 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int pci_cmd646_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->cmd646_bar[i].cmd);
+        memory_region_destroy(&d->cmd646_bar[i].data);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
                          int secondary_ide_enabled)
 {
@@ -276,6 +335,7 @@ 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
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 9f3050a..d1a14d7 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -287,9 +287,8 @@ static void bmdma_irq(void *opaque, int n, int level)
     qemu_set_irq(bm->irq, level);
 }
 
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
 {
-    BMDMAState *bm = opaque;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, val);
 #endif
@@ -328,22 +327,24 @@ void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
     bm->cmd = val & 0x09;
 }
 
-static void bmdma_addr_read(IORange *ioport, uint64_t addr,
-                            unsigned width, uint64_t *data)
+static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
+                                unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     uint32_t mask = (1ULL << (width * 8)) - 1;
+    uint64_t data;
 
-    *data = (bm->addr >> (addr * 8)) & mask;
+    data = (bm->addr >> (addr * 8)) & mask;
 #ifdef DEBUG_IDE
     printf("%s: 0x%08x\n", __func__, (unsigned)*data);
 #endif
+    return data;
 }
 
-static void bmdma_addr_write(IORange *ioport, uint64_t addr,
-                             unsigned width, uint64_t data)
+static void bmdma_addr_write(void *opaque, target_phys_addr_t addr,
+                             uint64_t data, unsigned width)
 {
-    BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport);
+    BMDMAState *bm = opaque;
     int shift = addr * 8;
     uint32_t mask = (1ULL << (width * 8)) - 1;
 
@@ -354,9 +355,10 @@ static void bmdma_addr_write(IORange *ioport, uint64_t addr,
     bm->addr |= ((data & mask) << shift) & ~3;
 }
 
-const IORangeOps bmdma_addr_ioport_ops = {
+MemoryRegionOps bmdma_addr_ioport_ops = {
     .read = bmdma_addr_read,
     .write = bmdma_addr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static bool ide_bmdma_current_needed(void *opaque)
@@ -514,7 +516,7 @@ static const struct IDEDMAOps bmdma_ops = {
     .reset = bmdma_reset,
 };
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm)
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d)
 {
     qemu_irq *irq;
 
@@ -527,4 +529,5 @@ void bmdma_init(IDEBus *bus, BMDMAState *bm)
     bm->irq = bus->irq;
     irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
     bus->irq = *irq;
+    bm->pci_dev = d;
 }
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index b4f3691..a694e54 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -19,20 +19,31 @@ typedef struct BMDMAState {
     BlockDriverCompletionFunc *dma_cb;
     int64_t sector_num;
     uint32_t nsector;
-    IORange addr_ioport;
+    MemoryRegion addr_ioport;
+    MemoryRegion extra_io;
     QEMUBH *bh;
     qemu_irq irq;
 
     /* Bit 0-2 and 7:   BM status register
      * Bit 3-6:         bus->error_status */
     uint8_t migration_compat_status;
+    struct PCIIDEState *pci_dev;
 } BMDMAState;
 
+typedef struct CMD646BAR {
+    MemoryRegion cmd;
+    MemoryRegion data;
+    IDEBus *bus;
+    struct PCIIDEState *pci_dev;
+} CMD646BAR;
+
 typedef struct PCIIDEState {
     PCIDevice dev;
     IDEBus bus[2];
     BMDMAState bmdma[2];
     uint32_t secondary; /* used only for cmd646 */
+    MemoryRegion bmdma_bar;
+    CMD646BAR cmd646_bar[2]; /* used only for cmd646 */
 } PCIIDEState;
 
 
@@ -43,9 +54,9 @@ static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
 }
 
 
-void bmdma_init(IDEBus *bus, BMDMAState *bm);
-void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val);
-extern const IORangeOps bmdma_addr_ioport_ops;
+void bmdma_init(IDEBus *bus, BMDMAState *bm, PCIIDEState *d);
+void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val);
+extern MemoryRegionOps bmdma_addr_ioport_ops;
 void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table);
 
 extern const VMStateDescription vmstate_ide_pci;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index f527dbd..5aa0a30 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -33,11 +33,15 @@
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch(addr & 3) {
     case 0:
         val = bm->cmd;
@@ -55,36 +59,46 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch(addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps piix_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "piix-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &piix_bmdma_ops, bm,
+                              "piix-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -124,7 +138,7 @@ static void pci_piix_init_ports(PCIIDEState *d) {
         ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -140,7 +154,9 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
 
     qemu_register_reset(piix3_reset, d);
 
-    pci_register_bar(&d->dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->bmdma_bar);
 
     vmstate_register(&d->dev.qdev, 0, &vmstate_ide_pci, d);
 
@@ -185,6 +201,22 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
     return dev;
 }
 
+static int pci_piix_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
 PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
@@ -214,6 +246,7 @@ static PCIDeviceInfo piix_ide_info[] = {
         .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,
@@ -231,6 +264,7 @@ static PCIDeviceInfo piix_ide_info[] = {
         .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,
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 3474c37..eb6a409 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -34,11 +34,16 @@
 
 #include <hw/ide/pci.h>
 
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
+static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
+                           unsigned size)
 {
     BMDMAState *bm = opaque;
     uint32_t val;
 
+    if (size != 1) {
+        return ((uint64_t)1 << (size * 8)) - 1;
+    }
+
     switch (addr & 3) {
     case 0:
         val = bm->cmd;
@@ -56,13 +61,21 @@ static uint32_t bmdma_readb(void *opaque, uint32_t addr)
     return val;
 }
 
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void bmdma_write(void *opaque, target_phys_addr_t addr,
+                        uint64_t val, unsigned size)
 {
     BMDMAState *bm = opaque;
+
+    if (size != 1) {
+        return;
+    }
+
 #ifdef DEBUG_IDE
     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
 #endif
     switch (addr & 3) {
+    case 0:
+        return bmdma_cmd_writeb(bm, val);
     case 2:
         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
         break;
@@ -70,23 +83,25 @@ static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
     }
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
-                    pcibus_t addr, pcibus_t size, int type)
+static MemoryRegionOps via_bmdma_ops = {
+    .read = bmdma_read,
+    .write = bmdma_write,
+};
+
+static void bmdma_setup_bar(PCIIDEState *d)
 {
-    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
     int i;
 
+    memory_region_init(&d->bmdma_bar, "via-bmdma-container", 16);
     for(i = 0;i < 2; i++) {
         BMDMAState *bm = &d->bmdma[i];
 
-        register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
-        register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
-        register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
-        iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
-        ioport_register(&bm->addr_ioport);
-        addr += 8;
+        memory_region_init_io(&bm->extra_io, &via_bmdma_ops, bm,
+                              "via-bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
+        memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
+                              "bmdma", 4);
+        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
     }
 }
 
@@ -147,7 +162,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
         ide_init_ioport(&d->bus[i], port_info[i].iobase, port_info[i].iobase2);
         ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq));
 
-        bmdma_init(&d->bus[i], &d->bmdma[i]);
+        bmdma_init(&d->bus[i], &d->bmdma[i], d);
         d->bmdma[i].bus = &d->bus[i];
         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
                                          &d->bmdma[i].dma);
@@ -164,8 +179,9 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 
     qemu_register_reset(via_reset, d);
-    pci_register_bar(&d->dev, 4, 0x10,
-                           PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
+    bmdma_setup_bar(d);
+    pci_register_bar_region(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO,
+                            &d->bmdma_bar);
 
     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
 
@@ -174,6 +190,22 @@ static int vt82c686b_ide_initfn(PCIDevice *dev)
     return 0;
 }
 
+static int vt82c686b_ide_exitfn(PCIDevice *dev)
+{
+    PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
+    unsigned i;
+
+    for (i = 0; i < 2; ++i) {
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
+        memory_region_destroy(&d->bmdma[i].extra_io);
+        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
+        memory_region_destroy(&d->bmdma[i].addr_ioport);
+    }
+    memory_region_destroy(&d->bmdma_bar);
+
+    return 0;
+}
+
 void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 {
     PCIDevice *dev;
@@ -187,6 +219,7 @@ static PCIDeviceInfo via_ide_info = {
     .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,
