|
|
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: {
1.1.1.2 ! root 73: return bm->pci_dev;
1.1 root 74: }
75:
76: static uint32_t bmdma_readb(void *opaque, uint32_t addr)
77: {
78: BMDMAState *bm = opaque;
79: PCIIDEState *pci_dev = pci_from_bm(bm);
80: uint32_t val;
81:
82: switch(addr & 3) {
83: case 0:
84: val = bm->cmd;
85: break;
86: case 1:
87: val = pci_dev->dev.config[MRDMODE];
88: break;
89: case 2:
90: val = bm->status;
91: break;
92: case 3:
93: if (bm->unit == 0) {
94: val = pci_dev->dev.config[UDIDETCR0];
95: } else {
96: val = pci_dev->dev.config[UDIDETCR1];
97: }
98: break;
99: default:
100: val = 0xff;
101: break;
102: }
103: #ifdef DEBUG_IDE
104: printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
105: #endif
106: return val;
107: }
108:
109: static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
110: {
111: BMDMAState *bm = opaque;
112: PCIIDEState *pci_dev = pci_from_bm(bm);
113: #ifdef DEBUG_IDE
114: printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
115: #endif
116: switch(addr & 3) {
117: case 1:
118: pci_dev->dev.config[MRDMODE] =
119: (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
120: cmd646_update_irq(pci_dev);
121: break;
122: case 2:
123: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
124: break;
125: case 3:
126: if (bm->unit == 0)
127: pci_dev->dev.config[UDIDETCR0] = val;
128: else
129: pci_dev->dev.config[UDIDETCR1] = val;
130: break;
131: }
132: }
133:
134: static void bmdma_map(PCIDevice *pci_dev, int region_num,
135: pcibus_t addr, pcibus_t size, int type)
136: {
137: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
138: int i;
139:
140: for(i = 0;i < 2; i++) {
141: BMDMAState *bm = &d->bmdma[i];
142: d->bus[i].bmdma = bm;
143: bm->bus = d->bus+i;
1.1.1.2 ! root 144: bm->pci_dev = d;
1.1 root 145: qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
146:
147: register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
148:
149: register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
150: register_ioport_read(addr, 4, 1, bmdma_readb, bm);
151:
152: register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
153: register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
154: register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
155: register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
156: register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
157: register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
158: addr += 8;
159: }
160: }
161:
162: /* XXX: call it also when the MRDMODE is changed from the PCI config
163: registers */
164: static void cmd646_update_irq(PCIIDEState *d)
165: {
166: int pci_level;
167: pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
168: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
169: ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
170: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
171: qemu_set_irq(d->dev.irq[0], pci_level);
172: }
173:
174: /* the PCI irq level is the logical OR of the two channels */
175: static void cmd646_set_irq(void *opaque, int channel, int level)
176: {
177: PCIIDEState *d = opaque;
178: int irq_mask;
179:
180: irq_mask = MRDMODE_INTR_CH0 << channel;
181: if (level)
182: d->dev.config[MRDMODE] |= irq_mask;
183: else
184: d->dev.config[MRDMODE] &= ~irq_mask;
185: cmd646_update_irq(d);
186: }
187:
188: static void cmd646_reset(void *opaque)
189: {
190: PCIIDEState *d = opaque;
191: unsigned int i;
192:
193: for (i = 0; i < 2; i++) {
194: ide_bus_reset(&d->bus[i]);
195: ide_dma_reset(&d->bmdma[i]);
196: }
197: }
198:
199: /* CMD646 PCI IDE controller */
200: static int pci_cmd646_ide_initfn(PCIDevice *dev)
201: {
202: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
203: uint8_t *pci_conf = d->dev.config;
204: qemu_irq *irq;
205:
206: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
207: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
208:
209: pci_conf[0x08] = 0x07; // IDE controller revision
210: pci_conf[0x09] = 0x8f;
211:
212: pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
213: pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
214:
215: pci_conf[0x51] = 0x04; // enable IDE0
216: if (d->secondary) {
217: /* XXX: if not enabled, really disable the seconday IDE controller */
218: pci_conf[0x51] |= 0x08; /* enable IDE1 */
219: }
220:
221: pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
222: pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
223: pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
224: pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
225: pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
226:
227: pci_conf[0x3d] = 0x01; // interrupt on pin 1
228:
229: irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
230: ide_bus_new(&d->bus[0], &d->dev.qdev);
231: ide_bus_new(&d->bus[1], &d->dev.qdev);
232: ide_init2(&d->bus[0], NULL, NULL, irq[0]);
233: ide_init2(&d->bus[1], NULL, NULL, irq[1]);
234:
235: vmstate_register(0, &vmstate_ide_pci, d);
236: qemu_register_reset(cmd646_reset, d);
237: return 0;
238: }
239:
240: void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
241: int secondary_ide_enabled)
242: {
243: PCIDevice *dev;
244:
245: dev = pci_create(bus, -1, "cmd646-ide");
246: qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
247: qdev_init_nofail(&dev->qdev);
248:
249: pci_ide_create_devs(dev, hd_table);
250: }
251:
252: static PCIDeviceInfo cmd646_ide_info[] = {
253: {
254: .qdev.name = "cmd646-ide",
255: .qdev.size = sizeof(PCIIDEState),
256: .init = pci_cmd646_ide_initfn,
257: .qdev.props = (Property[]) {
258: DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
259: DEFINE_PROP_END_OF_LIST(),
260: },
261: },{
262: /* end of list */
263: }
264: };
265:
266: static void cmd646_ide_register(void)
267: {
268: pci_qdev_register_many(cmd646_ide_info);
269: }
270: device_init(cmd646_ide_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.