Statistics
| Branch: | Revision:

root / hw / ide / macio.c @ c227f099

History | View | Annotate | Download (8.6 kB)

1
/*
2
 * QEMU IDE Emulation: MacIO 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/ppc_mac.h>
27
#include <hw/mac_dbdma.h>
28
#include "block.h"
29
#include "block_int.h"
30
#include "sysemu.h"
31
#include "dma.h"
32

    
33
#include <hw/ide/internal.h>
34

    
35
/***********************************************************/
36
/* MacIO based PowerPC IDE */
37

    
38
typedef struct MACIOIDEState {
39
    IDEBus bus;
40
    BlockDriverAIOCB *aiocb;
41
} MACIOIDEState;
42

    
43
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
44
{
45
    DBDMA_io *io = opaque;
46
    MACIOIDEState *m = io->opaque;
47
    IDEState *s = idebus_active_if(&m->bus);
48

    
49
    if (ret < 0) {
50
        m->aiocb = NULL;
51
        qemu_sglist_destroy(&s->sg);
52
        ide_atapi_io_error(s, ret);
53
        io->dma_end(opaque);
54
        return;
55
    }
56

    
57
    if (s->io_buffer_size > 0) {
58
        m->aiocb = NULL;
59
        qemu_sglist_destroy(&s->sg);
60

    
61
        s->packet_transfer_size -= s->io_buffer_size;
62

    
63
        s->io_buffer_index += s->io_buffer_size;
64
        s->lba += s->io_buffer_index >> 11;
65
        s->io_buffer_index &= 0x7ff;
66
    }
67

    
68
    if (s->packet_transfer_size <= 0)
69
        ide_atapi_cmd_ok(s);
70

    
71
    if (io->len == 0) {
72
        io->dma_end(opaque);
73
        return;
74
    }
75

    
76
    /* launch next transfer */
77

    
78
    s->io_buffer_size = io->len;
79

    
80
    qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
81
    qemu_sglist_add(&s->sg, io->addr, io->len);
82
    io->addr += io->len;
83
    io->len = 0;
84

    
85
    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
86
                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
87
                             pmac_ide_atapi_transfer_cb, io);
88
    if (!m->aiocb) {
89
        qemu_sglist_destroy(&s->sg);
90
        /* Note: media not present is the most likely case */
91
        ide_atapi_cmd_error(s, SENSE_NOT_READY,
92
                            ASC_MEDIUM_NOT_PRESENT);
93
        io->dma_end(opaque);
94
        return;
95
    }
96
}
97

    
98
static void pmac_ide_transfer_cb(void *opaque, int ret)
99
{
100
    DBDMA_io *io = opaque;
101
    MACIOIDEState *m = io->opaque;
102
    IDEState *s = idebus_active_if(&m->bus);
103
    int n;
104
    int64_t sector_num;
105

    
106
    if (ret < 0) {
107
        m->aiocb = NULL;
108
        qemu_sglist_destroy(&s->sg);
109
        ide_dma_error(s);
110
        io->dma_end(io);
111
        return;
112
    }
113

    
114
    sector_num = ide_get_sector(s);
115
    if (s->io_buffer_size > 0) {
116
        m->aiocb = NULL;
117
        qemu_sglist_destroy(&s->sg);
118
        n = (s->io_buffer_size + 0x1ff) >> 9;
119
        sector_num += n;
120
        ide_set_sector(s, sector_num);
121
        s->nsector -= n;
122
    }
123

    
124
    /* end of transfer ? */
125
    if (s->nsector == 0) {
126
        s->status = READY_STAT | SEEK_STAT;
127
        ide_set_irq(s->bus);
128
    }
129

    
130
    /* end of DMA ? */
131

    
132
    if (io->len == 0) {
133
        io->dma_end(io);
134
        return;
135
    }
136

    
137
    /* launch next transfer */
138

    
139
    s->io_buffer_index = 0;
140
    s->io_buffer_size = io->len;
141

    
142
    qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
143
    qemu_sglist_add(&s->sg, io->addr, io->len);
144
    io->addr += io->len;
145
    io->len = 0;
146

    
147
    if (s->is_read)
148
        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
149
                                 pmac_ide_transfer_cb, io);
150
    else
151
        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
152
                                  pmac_ide_transfer_cb, io);
153
    if (!m->aiocb)
154
        pmac_ide_transfer_cb(io, -1);
155
}
156

    
157
static void pmac_ide_transfer(DBDMA_io *io)
158
{
159
    MACIOIDEState *m = io->opaque;
160
    IDEState *s = idebus_active_if(&m->bus);
161

    
162
    s->io_buffer_size = 0;
163
    if (s->is_cdrom) {
164
        pmac_ide_atapi_transfer_cb(io, 0);
165
        return;
166
    }
167

    
168
    pmac_ide_transfer_cb(io, 0);
169
}
170

    
171
static void pmac_ide_flush(DBDMA_io *io)
172
{
173
    MACIOIDEState *m = io->opaque;
174

    
175
    if (m->aiocb)
176
        qemu_aio_flush();
177
}
178

    
179
/* PowerMac IDE memory IO */
180
static void pmac_ide_writeb (void *opaque,
181
                             target_phys_addr_t addr, uint32_t val)
182
{
183
    MACIOIDEState *d = opaque;
184

    
185
    addr = (addr & 0xFFF) >> 4;
186
    switch (addr) {
187
    case 1 ... 7:
188
        ide_ioport_write(&d->bus, addr, val);
189
        break;
190
    case 8:
191
    case 22:
192
        ide_cmd_write(&d->bus, 0, val);
193
        break;
194
    default:
195
        break;
196
    }
197
}
198

    
199
static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
200
{
201
    uint8_t retval;
202
    MACIOIDEState *d = opaque;
203

    
204
    addr = (addr & 0xFFF) >> 4;
205
    switch (addr) {
206
    case 1 ... 7:
207
        retval = ide_ioport_read(&d->bus, addr);
208
        break;
209
    case 8:
210
    case 22:
211
        retval = ide_status_read(&d->bus, 0);
212
        break;
213
    default:
214
        retval = 0xFF;
215
        break;
216
    }
217
    return retval;
218
}
219

    
220
static void pmac_ide_writew (void *opaque,
221
                             target_phys_addr_t addr, uint32_t val)
222
{
223
    MACIOIDEState *d = opaque;
224

    
225
    addr = (addr & 0xFFF) >> 4;
226
#ifdef TARGET_WORDS_BIGENDIAN
227
    val = bswap16(val);
228
#endif
229
    if (addr == 0) {
230
        ide_data_writew(&d->bus, 0, val);
231
    }
232
}
233

    
234
static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
235
{
236
    uint16_t retval;
237
    MACIOIDEState *d = opaque;
238

    
239
    addr = (addr & 0xFFF) >> 4;
240
    if (addr == 0) {
241
        retval = ide_data_readw(&d->bus, 0);
242
    } else {
243
        retval = 0xFFFF;
244
    }
245
#ifdef TARGET_WORDS_BIGENDIAN
246
    retval = bswap16(retval);
247
#endif
248
    return retval;
249
}
250

    
251
static void pmac_ide_writel (void *opaque,
252
                             target_phys_addr_t addr, uint32_t val)
253
{
254
    MACIOIDEState *d = opaque;
255

    
256
    addr = (addr & 0xFFF) >> 4;
257
#ifdef TARGET_WORDS_BIGENDIAN
258
    val = bswap32(val);
259
#endif
260
    if (addr == 0) {
261
        ide_data_writel(&d->bus, 0, val);
262
    }
263
}
264

    
265
static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
266
{
267
    uint32_t retval;
268
    MACIOIDEState *d = opaque;
269

    
270
    addr = (addr & 0xFFF) >> 4;
271
    if (addr == 0) {
272
        retval = ide_data_readl(&d->bus, 0);
273
    } else {
274
        retval = 0xFFFFFFFF;
275
    }
276
#ifdef TARGET_WORDS_BIGENDIAN
277
    retval = bswap32(retval);
278
#endif
279
    return retval;
280
}
281

    
282
static CPUWriteMemoryFunc * const pmac_ide_write[] = {
283
    pmac_ide_writeb,
284
    pmac_ide_writew,
285
    pmac_ide_writel,
286
};
287

    
288
static CPUReadMemoryFunc * const pmac_ide_read[] = {
289
    pmac_ide_readb,
290
    pmac_ide_readw,
291
    pmac_ide_readl,
292
};
293

    
294
static void pmac_ide_save(QEMUFile *f, void *opaque)
295
{
296
    MACIOIDEState *d = opaque;
297
    unsigned int i;
298

    
299
    /* per IDE interface data */
300
    idebus_save(f, &d->bus);
301

    
302
    /* per IDE drive data */
303
    for(i = 0; i < 2; i++) {
304
        ide_save(f, &d->bus.ifs[i]);
305
    }
306
}
307

    
308
static int pmac_ide_load(QEMUFile *f, void *opaque, int version_id)
309
{
310
    MACIOIDEState *d = opaque;
311
    unsigned int i;
312

    
313
    if (version_id != 1 && version_id != 3)
314
        return -EINVAL;
315

    
316
    /* per IDE interface data */
317
    idebus_load(f, &d->bus, version_id);
318

    
319
    /* per IDE drive data */
320
    for(i = 0; i < 2; i++) {
321
        ide_load(f, &d->bus.ifs[i], version_id);
322
    }
323
    return 0;
324
}
325

    
326
static void pmac_ide_reset(void *opaque)
327
{
328
    MACIOIDEState *d = opaque;
329

    
330
    ide_reset(d->bus.ifs +0);
331
    ide_reset(d->bus.ifs +1);
332
}
333

    
334
/* hd_table must contain 4 block drivers */
335
/* PowerMac uses memory mapped registers, not I/O. Return the memory
336
   I/O index to access the ide. */
337
int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
338
                   void *dbdma, int channel, qemu_irq dma_irq)
339
{
340
    MACIOIDEState *d;
341
    int pmac_ide_memory;
342

    
343
    d = qemu_mallocz(sizeof(MACIOIDEState));
344
    ide_init2(&d->bus, hd_table[0], hd_table[1], irq);
345

    
346
    if (dbdma)
347
        DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
348

    
349
    pmac_ide_memory = cpu_register_io_memory(pmac_ide_read,
350
                                             pmac_ide_write, d);
351
    register_savevm("ide", 0, 3, pmac_ide_save, pmac_ide_load, d);
352
    qemu_register_reset(pmac_ide_reset, d);
353
    pmac_ide_reset(d);
354

    
355
    return pmac_ide_memory;
356
}