~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/ide/cmd646.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

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