|
|
1.1 ! root 1: /* ! 2: * QEMU IDE Emulation: PCI cmd646 support. ! 3: * ! 4: * Copyright (c) 2003 Fabrice Bellard ! 5: * Copyright (c) 2006 Openedhand Ltd. ! 6: * ! 7: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 8: * of this software and associated documentation files (the "Software"), to deal ! 9: * in the Software without restriction, including without limitation the rights ! 10: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 11: * copies of the Software, and to permit persons to whom the Software is ! 12: * furnished to do so, subject to the following conditions: ! 13: * ! 14: * The above copyright notice and this permission notice shall be included in ! 15: * all copies or substantial portions of the Software. ! 16: * ! 17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 18: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 22: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 23: * THE SOFTWARE. ! 24: */ ! 25: #include <hw/hw.h> ! 26: #include <hw/pc.h> ! 27: #include <hw/pci.h> ! 28: #include <hw/isa.h> ! 29: #include "block.h" ! 30: #include "block_int.h" ! 31: #include "sysemu.h" ! 32: #include "dma.h" ! 33: ! 34: #include <hw/ide/pci.h> ! 35: ! 36: /* CMD646 specific */ ! 37: #define MRDMODE 0x71 ! 38: #define MRDMODE_INTR_CH0 0x04 ! 39: #define MRDMODE_INTR_CH1 0x08 ! 40: #define MRDMODE_BLK_CH0 0x10 ! 41: #define MRDMODE_BLK_CH1 0x20 ! 42: #define UDIDETCR0 0x73 ! 43: #define UDIDETCR1 0x7B ! 44: ! 45: static void cmd646_update_irq(PCIIDEState *d); ! 46: ! 47: static void ide_map(PCIDevice *pci_dev, int region_num, ! 48: pcibus_t addr, pcibus_t size, int type) ! 49: { ! 50: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev); ! 51: IDEBus *bus; ! 52: ! 53: if (region_num <= 3) { ! 54: bus = &d->bus[(region_num >> 1)]; ! 55: if (region_num & 1) { ! 56: register_ioport_read(addr + 2, 1, 1, ide_status_read, bus); ! 57: register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus); ! 58: } else { ! 59: register_ioport_write(addr, 8, 1, ide_ioport_write, bus); ! 60: register_ioport_read(addr, 8, 1, ide_ioport_read, bus); ! 61: ! 62: /* data ports */ ! 63: register_ioport_write(addr, 2, 2, ide_data_writew, bus); ! 64: register_ioport_read(addr, 2, 2, ide_data_readw, bus); ! 65: register_ioport_write(addr, 4, 4, ide_data_writel, bus); ! 66: register_ioport_read(addr, 4, 4, ide_data_readl, bus); ! 67: } ! 68: } ! 69: } ! 70: ! 71: static PCIIDEState *pci_from_bm(BMDMAState *bm) ! 72: { ! 73: if (bm->unit == 0) { ! 74: return container_of(bm, PCIIDEState, bmdma[0]); ! 75: } else { ! 76: return container_of(bm, PCIIDEState, bmdma[1]); ! 77: } ! 78: } ! 79: ! 80: static uint32_t bmdma_readb(void *opaque, uint32_t addr) ! 81: { ! 82: BMDMAState *bm = opaque; ! 83: PCIIDEState *pci_dev = pci_from_bm(bm); ! 84: uint32_t val; ! 85: ! 86: switch(addr & 3) { ! 87: case 0: ! 88: val = bm->cmd; ! 89: break; ! 90: case 1: ! 91: val = pci_dev->dev.config[MRDMODE]; ! 92: break; ! 93: case 2: ! 94: val = bm->status; ! 95: break; ! 96: case 3: ! 97: if (bm->unit == 0) { ! 98: val = pci_dev->dev.config[UDIDETCR0]; ! 99: } else { ! 100: val = pci_dev->dev.config[UDIDETCR1]; ! 101: } ! 102: break; ! 103: default: ! 104: val = 0xff; ! 105: break; ! 106: } ! 107: #ifdef DEBUG_IDE ! 108: printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); ! 109: #endif ! 110: return val; ! 111: } ! 112: ! 113: static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) ! 114: { ! 115: BMDMAState *bm = opaque; ! 116: PCIIDEState *pci_dev = pci_from_bm(bm); ! 117: #ifdef DEBUG_IDE ! 118: printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); ! 119: #endif ! 120: switch(addr & 3) { ! 121: case 1: ! 122: pci_dev->dev.config[MRDMODE] = ! 123: (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); ! 124: cmd646_update_irq(pci_dev); ! 125: break; ! 126: case 2: ! 127: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); ! 128: break; ! 129: case 3: ! 130: if (bm->unit == 0) ! 131: pci_dev->dev.config[UDIDETCR0] = val; ! 132: else ! 133: pci_dev->dev.config[UDIDETCR1] = val; ! 134: break; ! 135: } ! 136: } ! 137: ! 138: static void bmdma_map(PCIDevice *pci_dev, int region_num, ! 139: pcibus_t addr, pcibus_t size, int type) ! 140: { ! 141: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev); ! 142: int i; ! 143: ! 144: for(i = 0;i < 2; i++) { ! 145: BMDMAState *bm = &d->bmdma[i]; ! 146: d->bus[i].bmdma = bm; ! 147: bm->bus = d->bus+i; ! 148: qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); ! 149: ! 150: register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); ! 151: ! 152: register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); ! 153: register_ioport_read(addr, 4, 1, bmdma_readb, bm); ! 154: ! 155: register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); ! 156: register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); ! 157: register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); ! 158: register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); ! 159: register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); ! 160: register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); ! 161: addr += 8; ! 162: } ! 163: } ! 164: ! 165: /* XXX: call it also when the MRDMODE is changed from the PCI config ! 166: registers */ ! 167: static void cmd646_update_irq(PCIIDEState *d) ! 168: { ! 169: int pci_level; ! 170: pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) && ! 171: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || ! 172: ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && ! 173: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); ! 174: qemu_set_irq(d->dev.irq[0], pci_level); ! 175: } ! 176: ! 177: /* the PCI irq level is the logical OR of the two channels */ ! 178: static void cmd646_set_irq(void *opaque, int channel, int level) ! 179: { ! 180: PCIIDEState *d = opaque; ! 181: int irq_mask; ! 182: ! 183: irq_mask = MRDMODE_INTR_CH0 << channel; ! 184: if (level) ! 185: d->dev.config[MRDMODE] |= irq_mask; ! 186: else ! 187: d->dev.config[MRDMODE] &= ~irq_mask; ! 188: cmd646_update_irq(d); ! 189: } ! 190: ! 191: static void cmd646_reset(void *opaque) ! 192: { ! 193: PCIIDEState *d = opaque; ! 194: unsigned int i; ! 195: ! 196: for (i = 0; i < 2; i++) { ! 197: ide_bus_reset(&d->bus[i]); ! 198: ide_dma_reset(&d->bmdma[i]); ! 199: } ! 200: } ! 201: ! 202: /* CMD646 PCI IDE controller */ ! 203: static int pci_cmd646_ide_initfn(PCIDevice *dev) ! 204: { ! 205: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); ! 206: uint8_t *pci_conf = d->dev.config; ! 207: qemu_irq *irq; ! 208: ! 209: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD); ! 210: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646); ! 211: ! 212: pci_conf[0x08] = 0x07; // IDE controller revision ! 213: pci_conf[0x09] = 0x8f; ! 214: ! 215: pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE); ! 216: pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type ! 217: ! 218: pci_conf[0x51] = 0x04; // enable IDE0 ! 219: if (d->secondary) { ! 220: /* XXX: if not enabled, really disable the seconday IDE controller */ ! 221: pci_conf[0x51] |= 0x08; /* enable IDE1 */ ! 222: } ! 223: ! 224: pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map); ! 225: pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map); ! 226: pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map); ! 227: pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map); ! 228: pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map); ! 229: ! 230: pci_conf[0x3d] = 0x01; // interrupt on pin 1 ! 231: ! 232: irq = qemu_allocate_irqs(cmd646_set_irq, d, 2); ! 233: ide_bus_new(&d->bus[0], &d->dev.qdev); ! 234: ide_bus_new(&d->bus[1], &d->dev.qdev); ! 235: ide_init2(&d->bus[0], NULL, NULL, irq[0]); ! 236: ide_init2(&d->bus[1], NULL, NULL, irq[1]); ! 237: ! 238: vmstate_register(0, &vmstate_ide_pci, d); ! 239: qemu_register_reset(cmd646_reset, d); ! 240: return 0; ! 241: } ! 242: ! 243: void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table, ! 244: int secondary_ide_enabled) ! 245: { ! 246: PCIDevice *dev; ! 247: ! 248: dev = pci_create(bus, -1, "cmd646-ide"); ! 249: qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled); ! 250: qdev_init_nofail(&dev->qdev); ! 251: ! 252: pci_ide_create_devs(dev, hd_table); ! 253: } ! 254: ! 255: static PCIDeviceInfo cmd646_ide_info[] = { ! 256: { ! 257: .qdev.name = "cmd646-ide", ! 258: .qdev.size = sizeof(PCIIDEState), ! 259: .init = pci_cmd646_ide_initfn, ! 260: .qdev.props = (Property[]) { ! 261: DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), ! 262: DEFINE_PROP_END_OF_LIST(), ! 263: }, ! 264: },{ ! 265: /* end of list */ ! 266: } ! 267: }; ! 268: ! 269: static void cmd646_ide_register(void) ! 270: { ! 271: pci_qdev_register_many(cmd646_ide_info); ! 272: } ! 273: device_init(cmd646_ide_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.