xref: /qemu/hw/ide/cmd646.c (revision a9deb8c69abdc7ff85ec81920cbc350437fc8a2f)
14c3df0ecSJuan Quintela /*
24c3df0ecSJuan Quintela  * QEMU IDE Emulation: PCI cmd646 support.
34c3df0ecSJuan Quintela  *
44c3df0ecSJuan Quintela  * Copyright (c) 2003 Fabrice Bellard
54c3df0ecSJuan Quintela  * Copyright (c) 2006 Openedhand Ltd.
64c3df0ecSJuan Quintela  *
74c3df0ecSJuan Quintela  * Permission is hereby granted, free of charge, to any person obtaining a copy
84c3df0ecSJuan Quintela  * of this software and associated documentation files (the "Software"), to deal
94c3df0ecSJuan Quintela  * in the Software without restriction, including without limitation the rights
104c3df0ecSJuan Quintela  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
114c3df0ecSJuan Quintela  * copies of the Software, and to permit persons to whom the Software is
124c3df0ecSJuan Quintela  * furnished to do so, subject to the following conditions:
134c3df0ecSJuan Quintela  *
144c3df0ecSJuan Quintela  * The above copyright notice and this permission notice shall be included in
154c3df0ecSJuan Quintela  * all copies or substantial portions of the Software.
164c3df0ecSJuan Quintela  *
174c3df0ecSJuan Quintela  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
184c3df0ecSJuan Quintela  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
194c3df0ecSJuan Quintela  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
204c3df0ecSJuan Quintela  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
214c3df0ecSJuan Quintela  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
224c3df0ecSJuan Quintela  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
234c3df0ecSJuan Quintela  * THE SOFTWARE.
244c3df0ecSJuan Quintela  */
254c3df0ecSJuan Quintela #include <hw/hw.h>
264c3df0ecSJuan Quintela #include <hw/pc.h>
274c3df0ecSJuan Quintela #include <hw/pci.h>
284c3df0ecSJuan Quintela #include <hw/isa.h>
294c3df0ecSJuan Quintela #include "block.h"
304c3df0ecSJuan Quintela #include "block_int.h"
314c3df0ecSJuan Quintela #include "sysemu.h"
324c3df0ecSJuan Quintela #include "dma.h"
334c3df0ecSJuan Quintela 
344c3df0ecSJuan Quintela #include <hw/ide/pci.h>
354c3df0ecSJuan Quintela 
364c3df0ecSJuan Quintela /* CMD646 specific */
374c3df0ecSJuan Quintela #define MRDMODE		0x71
384c3df0ecSJuan Quintela #define   MRDMODE_INTR_CH0	0x04
394c3df0ecSJuan Quintela #define   MRDMODE_INTR_CH1	0x08
404c3df0ecSJuan Quintela #define   MRDMODE_BLK_CH0	0x10
414c3df0ecSJuan Quintela #define   MRDMODE_BLK_CH1	0x20
424c3df0ecSJuan Quintela #define UDIDETCR0	0x73
434c3df0ecSJuan Quintela #define UDIDETCR1	0x7B
444c3df0ecSJuan Quintela 
454c3df0ecSJuan Quintela static void cmd646_update_irq(PCIIDEState *d);
464c3df0ecSJuan Quintela 
47*a9deb8c6SAvi Kivity static uint64_t cmd646_cmd_read(void *opaque, target_phys_addr_t addr,
48*a9deb8c6SAvi Kivity                                 unsigned size)
494c3df0ecSJuan Quintela {
50*a9deb8c6SAvi Kivity     CMD646BAR *cmd646bar = opaque;
514c3df0ecSJuan Quintela 
52*a9deb8c6SAvi Kivity     if (addr != 2 || size != 1) {
53*a9deb8c6SAvi Kivity         return ((uint64_t)1 << (size * 8)) - 1;
54*a9deb8c6SAvi Kivity     }
55*a9deb8c6SAvi Kivity     return ide_status_read(cmd646bar->bus, addr + 2);
56*a9deb8c6SAvi Kivity }
57*a9deb8c6SAvi Kivity 
58*a9deb8c6SAvi Kivity static void cmd646_cmd_write(void *opaque, target_phys_addr_t addr,
59*a9deb8c6SAvi Kivity                              uint64_t data, unsigned size)
60*a9deb8c6SAvi Kivity {
61*a9deb8c6SAvi Kivity     CMD646BAR *cmd646bar = opaque;
62*a9deb8c6SAvi Kivity 
63*a9deb8c6SAvi Kivity     if (addr != 2 || size != 1) {
64*a9deb8c6SAvi Kivity         return;
65*a9deb8c6SAvi Kivity     }
66*a9deb8c6SAvi Kivity     ide_cmd_write(cmd646bar->bus, addr + 2, data);
67*a9deb8c6SAvi Kivity }
68*a9deb8c6SAvi Kivity 
69*a9deb8c6SAvi Kivity static MemoryRegionOps cmd646_cmd_ops = {
70*a9deb8c6SAvi Kivity     .read = cmd646_cmd_read,
71*a9deb8c6SAvi Kivity     .write = cmd646_cmd_write,
72*a9deb8c6SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
73*a9deb8c6SAvi Kivity };
74*a9deb8c6SAvi Kivity 
75*a9deb8c6SAvi Kivity static uint64_t cmd646_data_read(void *opaque, target_phys_addr_t addr,
76*a9deb8c6SAvi Kivity                                  unsigned size)
77*a9deb8c6SAvi Kivity {
78*a9deb8c6SAvi Kivity     CMD646BAR *cmd646bar = opaque;
79*a9deb8c6SAvi Kivity 
80*a9deb8c6SAvi Kivity     if (size == 1) {
81*a9deb8c6SAvi Kivity         return ide_ioport_read(cmd646bar->bus, addr);
82*a9deb8c6SAvi Kivity     } else if (addr == 0) {
83*a9deb8c6SAvi Kivity         if (size == 2) {
84*a9deb8c6SAvi Kivity             return ide_data_readw(cmd646bar->bus, addr);
854c3df0ecSJuan Quintela         } else {
86*a9deb8c6SAvi Kivity             return ide_data_readl(cmd646bar->bus, addr);
874c3df0ecSJuan Quintela         }
884c3df0ecSJuan Quintela     }
89*a9deb8c6SAvi Kivity     return ((uint64_t)1 << (size * 8)) - 1;
904c3df0ecSJuan Quintela }
914c3df0ecSJuan Quintela 
92*a9deb8c6SAvi Kivity static void cmd646_data_write(void *opaque, target_phys_addr_t addr,
93*a9deb8c6SAvi Kivity                              uint64_t data, unsigned size)
9461f58e59SJuan Quintela {
95*a9deb8c6SAvi Kivity     CMD646BAR *cmd646bar = opaque;
96*a9deb8c6SAvi Kivity 
97*a9deb8c6SAvi Kivity     if (size == 1) {
98*a9deb8c6SAvi Kivity         return ide_ioport_write(cmd646bar->bus, addr, data);
99*a9deb8c6SAvi Kivity     } else if (addr == 0) {
100*a9deb8c6SAvi Kivity         if (size == 2) {
101*a9deb8c6SAvi Kivity             return ide_data_writew(cmd646bar->bus, addr, data);
102*a9deb8c6SAvi Kivity         } else {
103*a9deb8c6SAvi Kivity             return ide_data_writel(cmd646bar->bus, addr, data);
104*a9deb8c6SAvi Kivity         }
105*a9deb8c6SAvi Kivity     }
106*a9deb8c6SAvi Kivity }
107*a9deb8c6SAvi Kivity 
108*a9deb8c6SAvi Kivity static MemoryRegionOps cmd646_data_ops = {
109*a9deb8c6SAvi Kivity     .read = cmd646_data_read,
110*a9deb8c6SAvi Kivity     .write = cmd646_data_write,
111*a9deb8c6SAvi Kivity     .endianness = DEVICE_LITTLE_ENDIAN,
112*a9deb8c6SAvi Kivity };
113*a9deb8c6SAvi Kivity 
114*a9deb8c6SAvi Kivity static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
115*a9deb8c6SAvi Kivity {
116*a9deb8c6SAvi Kivity     IDEBus *bus = &d->bus[bus_num];
117*a9deb8c6SAvi Kivity     CMD646BAR *bar = &d->cmd646_bar[bus_num];
118*a9deb8c6SAvi Kivity 
119*a9deb8c6SAvi Kivity     bar->bus = bus;
120*a9deb8c6SAvi Kivity     bar->pci_dev = d;
121*a9deb8c6SAvi Kivity     memory_region_init_io(&bar->cmd, &cmd646_cmd_ops, bar, "cmd646-cmd", 4);
122*a9deb8c6SAvi Kivity     memory_region_init_io(&bar->data, &cmd646_data_ops, bar, "cmd646-data", 8);
123*a9deb8c6SAvi Kivity }
124*a9deb8c6SAvi Kivity 
125*a9deb8c6SAvi Kivity static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr,
126*a9deb8c6SAvi Kivity                            unsigned size)
127*a9deb8c6SAvi Kivity {
128*a9deb8c6SAvi Kivity     BMDMAState *bm = opaque;
129*a9deb8c6SAvi Kivity     PCIIDEState *pci_dev = bm->pci_dev;
1304c3df0ecSJuan Quintela     uint32_t val;
1314c3df0ecSJuan Quintela 
132*a9deb8c6SAvi Kivity     if (size != 1) {
133*a9deb8c6SAvi Kivity         return ((uint64_t)1 << (size * 8)) - 1;
134*a9deb8c6SAvi Kivity     }
135*a9deb8c6SAvi Kivity 
1364c3df0ecSJuan Quintela     switch(addr & 3) {
1374c3df0ecSJuan Quintela     case 0:
1384c3df0ecSJuan Quintela         val = bm->cmd;
1394c3df0ecSJuan Quintela         break;
1404c3df0ecSJuan Quintela     case 1:
1414c3df0ecSJuan Quintela         val = pci_dev->dev.config[MRDMODE];
1424c3df0ecSJuan Quintela         break;
1434c3df0ecSJuan Quintela     case 2:
1444c3df0ecSJuan Quintela         val = bm->status;
1454c3df0ecSJuan Quintela         break;
1464c3df0ecSJuan Quintela     case 3:
14770ae65f5SIgor V. Kovalenko         if (bm == &pci_dev->bmdma[0]) {
1484c3df0ecSJuan Quintela             val = pci_dev->dev.config[UDIDETCR0];
1494c3df0ecSJuan Quintela         } else {
15058c0e732SJuan Quintela             val = pci_dev->dev.config[UDIDETCR1];
1514c3df0ecSJuan Quintela         }
1524c3df0ecSJuan Quintela         break;
1534c3df0ecSJuan Quintela     default:
1544c3df0ecSJuan Quintela         val = 0xff;
1554c3df0ecSJuan Quintela         break;
1564c3df0ecSJuan Quintela     }
1574c3df0ecSJuan Quintela #ifdef DEBUG_IDE
1584c3df0ecSJuan Quintela     printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
1594c3df0ecSJuan Quintela #endif
1604c3df0ecSJuan Quintela     return val;
1614c3df0ecSJuan Quintela }
1624c3df0ecSJuan Quintela 
163*a9deb8c6SAvi Kivity static void bmdma_write(void *opaque, target_phys_addr_t addr,
164*a9deb8c6SAvi Kivity                         uint64_t val, unsigned size)
1654c3df0ecSJuan Quintela {
166*a9deb8c6SAvi Kivity     BMDMAState *bm = opaque;
167*a9deb8c6SAvi Kivity     PCIIDEState *pci_dev = bm->pci_dev;
16870ae65f5SIgor V. Kovalenko 
169*a9deb8c6SAvi Kivity     if (size != 1) {
170*a9deb8c6SAvi Kivity         return;
17170ae65f5SIgor V. Kovalenko     }
17270ae65f5SIgor V. Kovalenko 
1734c3df0ecSJuan Quintela #ifdef DEBUG_IDE
1744c3df0ecSJuan Quintela     printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
1754c3df0ecSJuan Quintela #endif
1764c3df0ecSJuan Quintela     switch(addr & 3) {
17750a48094SIgor V. Kovalenko     case 0:
178*a9deb8c6SAvi Kivity         bmdma_cmd_writeb(bm, val);
17950a48094SIgor V. Kovalenko         break;
1804c3df0ecSJuan Quintela     case 1:
1814c3df0ecSJuan Quintela         pci_dev->dev.config[MRDMODE] =
1824c3df0ecSJuan Quintela             (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
1834c3df0ecSJuan Quintela         cmd646_update_irq(pci_dev);
1844c3df0ecSJuan Quintela         break;
1854c3df0ecSJuan Quintela     case 2:
1864c3df0ecSJuan Quintela         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
1874c3df0ecSJuan Quintela         break;
1884c3df0ecSJuan Quintela     case 3:
18970ae65f5SIgor V. Kovalenko         if (bm == &pci_dev->bmdma[0])
1904c3df0ecSJuan Quintela             pci_dev->dev.config[UDIDETCR0] = val;
1914c3df0ecSJuan Quintela         else
1924c3df0ecSJuan Quintela             pci_dev->dev.config[UDIDETCR1] = val;
1934c3df0ecSJuan Quintela         break;
1944c3df0ecSJuan Quintela     }
1954c3df0ecSJuan Quintela }
1964c3df0ecSJuan Quintela 
197*a9deb8c6SAvi Kivity static MemoryRegionOps cmd646_bmdma_ops = {
198*a9deb8c6SAvi Kivity     .read = bmdma_read,
199*a9deb8c6SAvi Kivity     .write = bmdma_write,
200*a9deb8c6SAvi Kivity };
201*a9deb8c6SAvi Kivity 
202*a9deb8c6SAvi Kivity static void bmdma_setup_bar(PCIIDEState *d)
20370ae65f5SIgor V. Kovalenko {
204*a9deb8c6SAvi Kivity     BMDMAState *bm;
2054c3df0ecSJuan Quintela     int i;
2064c3df0ecSJuan Quintela 
207*a9deb8c6SAvi Kivity     memory_region_init(&d->bmdma_bar, "cmd646-bmdma", 16);
2084c3df0ecSJuan Quintela     for(i = 0;i < 2; i++) {
209*a9deb8c6SAvi Kivity         bm = &d->bmdma[i];
210*a9deb8c6SAvi Kivity         memory_region_init_io(&bm->extra_io, &cmd646_bmdma_ops, bm,
211*a9deb8c6SAvi Kivity                               "cmd646-bmdma-bus", 4);
212*a9deb8c6SAvi Kivity         memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
213*a9deb8c6SAvi Kivity         memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm,
214*a9deb8c6SAvi Kivity                               "cmd646-bmdma-ioport", 4);
215*a9deb8c6SAvi Kivity         memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
2164c3df0ecSJuan Quintela     }
2174c3df0ecSJuan Quintela }
2184c3df0ecSJuan Quintela 
2194c3df0ecSJuan Quintela /* XXX: call it also when the MRDMODE is changed from the PCI config
2204c3df0ecSJuan Quintela    registers */
2214c3df0ecSJuan Quintela static void cmd646_update_irq(PCIIDEState *d)
2224c3df0ecSJuan Quintela {
2234c3df0ecSJuan Quintela     int pci_level;
2244c3df0ecSJuan Quintela     pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
2254c3df0ecSJuan Quintela                  !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
2264c3df0ecSJuan Quintela         ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
2274c3df0ecSJuan Quintela          !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
2284c3df0ecSJuan Quintela     qemu_set_irq(d->dev.irq[0], pci_level);
2294c3df0ecSJuan Quintela }
2304c3df0ecSJuan Quintela 
2314c3df0ecSJuan Quintela /* the PCI irq level is the logical OR of the two channels */
2324c3df0ecSJuan Quintela static void cmd646_set_irq(void *opaque, int channel, int level)
2334c3df0ecSJuan Quintela {
2344c3df0ecSJuan Quintela     PCIIDEState *d = opaque;
2354c3df0ecSJuan Quintela     int irq_mask;
2364c3df0ecSJuan Quintela 
2374c3df0ecSJuan Quintela     irq_mask = MRDMODE_INTR_CH0 << channel;
2384c3df0ecSJuan Quintela     if (level)
2394c3df0ecSJuan Quintela         d->dev.config[MRDMODE] |= irq_mask;
2404c3df0ecSJuan Quintela     else
2414c3df0ecSJuan Quintela         d->dev.config[MRDMODE] &= ~irq_mask;
2424c3df0ecSJuan Quintela     cmd646_update_irq(d);
2434c3df0ecSJuan Quintela }
2444c3df0ecSJuan Quintela 
2454c3df0ecSJuan Quintela static void cmd646_reset(void *opaque)
2464c3df0ecSJuan Quintela {
2474c3df0ecSJuan Quintela     PCIIDEState *d = opaque;
2484c3df0ecSJuan Quintela     unsigned int i;
2494c3df0ecSJuan Quintela 
2504a643563SBlue Swirl     for (i = 0; i < 2; i++) {
2514a643563SBlue Swirl         ide_bus_reset(&d->bus[i]);
2524a643563SBlue Swirl     }
2534c3df0ecSJuan Quintela }
2544c3df0ecSJuan Quintela 
2554c3df0ecSJuan Quintela /* CMD646 PCI IDE controller */
2564c3df0ecSJuan Quintela static int pci_cmd646_ide_initfn(PCIDevice *dev)
2574c3df0ecSJuan Quintela {
2584c3df0ecSJuan Quintela     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
2594c3df0ecSJuan Quintela     uint8_t *pci_conf = d->dev.config;
2604c3df0ecSJuan Quintela     qemu_irq *irq;
26161d9d6b0SStefan Hajnoczi     int i;
2624c3df0ecSJuan Quintela 
263409570a7SMichael S. Tsirkin     pci_conf[PCI_CLASS_PROG] = 0x8f;
2644c3df0ecSJuan Quintela 
2654c3df0ecSJuan Quintela     pci_conf[0x51] = 0x04; // enable IDE0
2664c3df0ecSJuan Quintela     if (d->secondary) {
2674c3df0ecSJuan Quintela         /* XXX: if not enabled, really disable the seconday IDE controller */
2684c3df0ecSJuan Quintela         pci_conf[0x51] |= 0x08; /* enable IDE1 */
2694c3df0ecSJuan Quintela     }
2704c3df0ecSJuan Quintela 
271*a9deb8c6SAvi Kivity     setup_cmd646_bar(d, 0);
272*a9deb8c6SAvi Kivity     setup_cmd646_bar(d, 1);
273*a9deb8c6SAvi Kivity     pci_register_bar_region(dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
274*a9deb8c6SAvi Kivity                             &d->cmd646_bar[0].data);
275*a9deb8c6SAvi Kivity     pci_register_bar_region(dev, 1, PCI_BASE_ADDRESS_SPACE_IO,
276*a9deb8c6SAvi Kivity                             &d->cmd646_bar[0].cmd);
277*a9deb8c6SAvi Kivity     pci_register_bar_region(dev, 2, PCI_BASE_ADDRESS_SPACE_IO,
278*a9deb8c6SAvi Kivity                             &d->cmd646_bar[1].data);
279*a9deb8c6SAvi Kivity     pci_register_bar_region(dev, 3, PCI_BASE_ADDRESS_SPACE_IO,
280*a9deb8c6SAvi Kivity                             &d->cmd646_bar[1].cmd);
281*a9deb8c6SAvi Kivity     bmdma_setup_bar(d);
282*a9deb8c6SAvi Kivity     pci_register_bar_region(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
2834c3df0ecSJuan Quintela 
284409570a7SMichael S. Tsirkin     /* TODO: RST# value should be 0 */
285409570a7SMichael S. Tsirkin     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
2864c3df0ecSJuan Quintela 
2874c3df0ecSJuan Quintela     irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
28861d9d6b0SStefan Hajnoczi     for (i = 0; i < 2; i++) {
28961d9d6b0SStefan Hajnoczi         ide_bus_new(&d->bus[i], &d->dev.qdev, i);
29061d9d6b0SStefan Hajnoczi         ide_init2(&d->bus[i], irq[i]);
29161d9d6b0SStefan Hajnoczi 
292*a9deb8c6SAvi Kivity         bmdma_init(&d->bus[i], &d->bmdma[i], d);
293f56b18c0SKevin Wolf         d->bmdma[i].bus = &d->bus[i];
29461d9d6b0SStefan Hajnoczi         qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
295f56b18c0SKevin Wolf                                          &d->bmdma[i].dma);
29661d9d6b0SStefan Hajnoczi     }
2974c3df0ecSJuan Quintela 
2980be71e32SAlex Williamson     vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
2994c3df0ecSJuan Quintela     qemu_register_reset(cmd646_reset, d);
3004c3df0ecSJuan Quintela     return 0;
3014c3df0ecSJuan Quintela }
3024c3df0ecSJuan Quintela 
303*a9deb8c6SAvi Kivity static int pci_cmd646_ide_exitfn(PCIDevice *dev)
304*a9deb8c6SAvi Kivity {
305*a9deb8c6SAvi Kivity     PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
306*a9deb8c6SAvi Kivity     unsigned i;
307*a9deb8c6SAvi Kivity 
308*a9deb8c6SAvi Kivity     for (i = 0; i < 2; ++i) {
309*a9deb8c6SAvi Kivity         memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
310*a9deb8c6SAvi Kivity         memory_region_destroy(&d->bmdma[i].extra_io);
311*a9deb8c6SAvi Kivity         memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
312*a9deb8c6SAvi Kivity         memory_region_destroy(&d->bmdma[i].addr_ioport);
313*a9deb8c6SAvi Kivity         memory_region_destroy(&d->cmd646_bar[i].cmd);
314*a9deb8c6SAvi Kivity         memory_region_destroy(&d->cmd646_bar[i].data);
315*a9deb8c6SAvi Kivity     }
316*a9deb8c6SAvi Kivity     memory_region_destroy(&d->bmdma_bar);
317*a9deb8c6SAvi Kivity 
318*a9deb8c6SAvi Kivity     return 0;
319*a9deb8c6SAvi Kivity }
320*a9deb8c6SAvi Kivity 
3214c3df0ecSJuan Quintela void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
3224c3df0ecSJuan Quintela                          int secondary_ide_enabled)
3234c3df0ecSJuan Quintela {
3244c3df0ecSJuan Quintela     PCIDevice *dev;
3254c3df0ecSJuan Quintela 
326556cd098SMarkus Armbruster     dev = pci_create(bus, -1, "cmd646-ide");
3274c3df0ecSJuan Quintela     qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
3284c3df0ecSJuan Quintela     qdev_init_nofail(&dev->qdev);
3294c3df0ecSJuan Quintela 
3304c3df0ecSJuan Quintela     pci_ide_create_devs(dev, hd_table);
3314c3df0ecSJuan Quintela }
3324c3df0ecSJuan Quintela 
3334c3df0ecSJuan Quintela static PCIDeviceInfo cmd646_ide_info[] = {
3344c3df0ecSJuan Quintela     {
335556cd098SMarkus Armbruster         .qdev.name    = "cmd646-ide",
3364c3df0ecSJuan Quintela         .qdev.size    = sizeof(PCIIDEState),
3374c3df0ecSJuan Quintela         .init         = pci_cmd646_ide_initfn,
338*a9deb8c6SAvi Kivity         .exit         = pci_cmd646_ide_exitfn,
339c04ca075SIsaku Yamahata         .vendor_id    = PCI_VENDOR_ID_CMD,
340c04ca075SIsaku Yamahata         .device_id    = PCI_DEVICE_ID_CMD_646,
341c04ca075SIsaku Yamahata         .revision     = 0x07, // IDE controller revision
342c04ca075SIsaku Yamahata         .class_id     = PCI_CLASS_STORAGE_IDE,
3434c3df0ecSJuan Quintela         .qdev.props   = (Property[]) {
3444c3df0ecSJuan Quintela             DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
3454c3df0ecSJuan Quintela             DEFINE_PROP_END_OF_LIST(),
3464c3df0ecSJuan Quintela         },
3474c3df0ecSJuan Quintela     },{
3484c3df0ecSJuan Quintela         /* end of list */
3494c3df0ecSJuan Quintela     }
3504c3df0ecSJuan Quintela };
3514c3df0ecSJuan Quintela 
3524c3df0ecSJuan Quintela static void cmd646_ide_register(void)
3534c3df0ecSJuan Quintela {
3544c3df0ecSJuan Quintela     pci_qdev_register_many(cmd646_ide_info);
3554c3df0ecSJuan Quintela }
3564c3df0ecSJuan Quintela device_init(cmd646_ide_register);
357