|
|
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.