macio.c 16.2 KB
Newer Older
G
Gerd Hoffmann 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * QEMU IDE Emulation: MacIO support.
 *
 * Copyright (c) 2003 Fabrice Bellard
 * Copyright (c) 2006 Openedhand Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
25 26
#include "hw/hw.h"
#include "hw/ppc/mac.h"
P
Paolo Bonzini 已提交
27
#include "hw/ppc/mac_dbdma.h"
28
#include "block/block.h"
29
#include "sysemu/dma.h"
G
Gerd Hoffmann 已提交
30 31

#include <hw/ide/internal.h>
G
Gerd Hoffmann 已提交
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/* debug MACIO */
// #define DEBUG_MACIO

#ifdef DEBUG_MACIO
static const int debug_macio = 1;
#else
static const int debug_macio = 0;
#endif

#define MACIO_DPRINTF(fmt, ...) do { \
        if (debug_macio) { \
            printf(fmt , ## __VA_ARGS__); \
        } \
    } while (0)


G
Gerd Hoffmann 已提交
49 50 51
/***********************************************************/
/* MacIO based PowerPC IDE */

B
Blue Swirl 已提交
52 53
#define MACIO_PAGE_SIZE 4096

G
Gerd Hoffmann 已提交
54 55 56 57 58
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
{
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);
59
    int unaligned;
G
Gerd Hoffmann 已提交
60 61 62 63 64

    if (ret < 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
        ide_atapi_io_error(s, ret);
65
        io->remainder_len = 0;
66
        goto done;
G
Gerd Hoffmann 已提交
67 68
    }

69 70 71 72 73 74 75 76
    if (!m->dma_active) {
        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
                      s->nsector, io->len, s->status);
        /* data not ready yet, wait for the channel to get restarted */
        io->processing = false;
        return;
    }

77 78
    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);

G
Gerd Hoffmann 已提交
79 80 81 82 83 84 85
    if (s->io_buffer_size > 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);

        s->packet_transfer_size -= s->io_buffer_size;

        s->io_buffer_index += s->io_buffer_size;
86
        s->lba += s->io_buffer_index >> 11;
G
Gerd Hoffmann 已提交
87 88 89
        s->io_buffer_index &= 0x7ff;
    }

90
    s->io_buffer_size = MIN(io->len, s->packet_transfer_size);
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

    MACIO_DPRINTF("remainder: %d io->len: %d size: %d\n", io->remainder_len,
                  io->len, s->packet_transfer_size);
    if (io->remainder_len && io->len) {
        /* guest wants the rest of its previous transfer */
        int remainder_len = MIN(io->remainder_len, io->len);

        MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len);

        cpu_physical_memory_write(io->addr, io->remainder + 0x200 -
                                  remainder_len, remainder_len);

        io->addr += remainder_len;
        io->len -= remainder_len;
        s->io_buffer_size = remainder_len;
        io->remainder_len -= remainder_len;
        /* treat remainder as individual transfer, start again */
        qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
                         &address_space_memory);
        pmac_ide_atapi_transfer_cb(opaque, 0);
        return;
    }

    if (!s->packet_transfer_size) {
115
        MACIO_DPRINTF("end of transfer\n");
G
Gerd Hoffmann 已提交
116
        ide_atapi_cmd_ok(s);
117
        m->dma_active = false;
118
    }
G
Gerd Hoffmann 已提交
119 120

    if (io->len == 0) {
121
        MACIO_DPRINTF("end of DMA\n");
122
        goto done;
G
Gerd Hoffmann 已提交
123 124 125 126
    }

    /* launch next transfer */

127 128 129 130 131 132
    /* handle unaligned accesses first, get them over with and only do the
       remaining bulk transfer using our async DMA helpers */
    unaligned = io->len & 0x1ff;
    if (unaligned) {
        int sector_num = (s->lba << 2) + (s->io_buffer_index >> 9);
        int nsector = io->len >> 9;
133

134 135 136 137 138 139 140 141 142 143 144
        MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n",
                      unaligned, io->addr + io->len - unaligned);

        bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
        cpu_physical_memory_write(io->addr + io->len - unaligned,
                                  io->remainder, unaligned);

        io->len -= unaligned;
    }

    MACIO_DPRINTF("io->len = %#x\n", io->len);
G
Gerd Hoffmann 已提交
145

146
    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
P
Paolo Bonzini 已提交
147
                     &address_space_memory);
G
Gerd Hoffmann 已提交
148
    qemu_sglist_add(&s->sg, io->addr, io->len);
149 150 151 152 153 154 155 156 157 158 159 160
    io->addr += s->io_buffer_size;
    io->remainder_len = MIN(s->packet_transfer_size - s->io_buffer_size,
                            (0x200 - unaligned) & 0x1ff);
    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);

    /* We would read no data from the block layer, thus not get a callback.
       Just fake completion manually. */
    if (!io->len) {
        pmac_ide_atapi_transfer_cb(opaque, 0);
        return;
    }

G
Gerd Hoffmann 已提交
161 162
    io->len = 0;

163 164 165 166
    MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n",
                  (s->lba << 2) + (s->io_buffer_index >> 9),
                  s->packet_transfer_size, s->dma_cmd);

G
Gerd Hoffmann 已提交
167 168 169
    m->aiocb = dma_bdrv_read(s->bs, &s->sg,
                             (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
                             pmac_ide_atapi_transfer_cb, io);
170 171 172
    return;

done:
173
    MACIO_DPRINTF("done DMA\n");
174 175
    bdrv_acct_done(s->bs, &s->acct);
    io->dma_end(opaque);
G
Gerd Hoffmann 已提交
176 177 178 179 180 181 182
}

static void pmac_ide_transfer_cb(void *opaque, int ret)
{
    DBDMA_io *io = opaque;
    MACIOIDEState *m = io->opaque;
    IDEState *s = idebus_active_if(&m->bus);
183
    int n = 0;
G
Gerd Hoffmann 已提交
184
    int64_t sector_num;
185
    int unaligned;
G
Gerd Hoffmann 已提交
186 187

    if (ret < 0) {
188
        MACIO_DPRINTF("DMA error\n");
G
Gerd Hoffmann 已提交
189 190
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
191
        ide_dma_error(s);
192
        io->remainder_len = 0;
193
        goto done;
G
Gerd Hoffmann 已提交
194 195
    }

196 197 198 199 200 201 202 203
    if (!m->dma_active) {
        MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n",
                      s->nsector, io->len, s->status);
        /* data not ready yet, wait for the channel to get restarted */
        io->processing = false;
        return;
    }

G
Gerd Hoffmann 已提交
204
    sector_num = ide_get_sector(s);
205
    MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size);
G
Gerd Hoffmann 已提交
206 207 208 209 210 211 212 213 214
    if (s->io_buffer_size > 0) {
        m->aiocb = NULL;
        qemu_sglist_destroy(&s->sg);
        n = (s->io_buffer_size + 0x1ff) >> 9;
        sector_num += n;
        ide_set_sector(s, sector_num);
        s->nsector -= n;
    }

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
    MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d sector_num: %ld\n",
                  io->remainder_len, io->len, s->nsector, sector_num);
    if (io->remainder_len && io->len) {
        /* guest wants the rest of its previous transfer */
        int remainder_len = MIN(io->remainder_len, io->len);
        uint8_t *p = &io->remainder[0x200 - remainder_len];

        MACIO_DPRINTF("copying remainder %d bytes at %#lx\n",
                      remainder_len, io->addr);

        switch (s->dma_cmd) {
        case IDE_DMA_READ:
            cpu_physical_memory_write(io->addr, p, remainder_len);
            break;
        case IDE_DMA_WRITE:
            cpu_physical_memory_read(io->addr, p, remainder_len);
            bdrv_write(s->bs, sector_num - 1, io->remainder, 1);
            break;
        case IDE_DMA_TRIM:
            break;
        }
        io->addr += remainder_len;
        io->len -= remainder_len;
        io->remainder_len -= remainder_len;
    }

    if (s->nsector == 0 && !io->remainder_len) {
242
        MACIO_DPRINTF("end of transfer\n");
G
Gerd Hoffmann 已提交
243
        s->status = READY_STAT | SEEK_STAT;
244
        ide_set_irq(s->bus);
245
        m->dma_active = false;
G
Gerd Hoffmann 已提交
246 247 248
    }

    if (io->len == 0) {
249
        MACIO_DPRINTF("end of DMA\n");
250
        goto done;
G
Gerd Hoffmann 已提交
251 252 253 254 255
    }

    /* launch next transfer */

    s->io_buffer_index = 0;
256
    s->io_buffer_size = MIN(io->len, s->nsector * 512);
G
Gerd Hoffmann 已提交
257

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
    /* handle unaligned accesses first, get them over with and only do the
       remaining bulk transfer using our async DMA helpers */
    unaligned = io->len & 0x1ff;
    if (unaligned) {
        int nsector = io->len >> 9;

        MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n",
                      unaligned, io->addr + io->len - unaligned);

        switch (s->dma_cmd) {
        case IDE_DMA_READ:
            bdrv_read(s->bs, sector_num + nsector, io->remainder, 1);
            cpu_physical_memory_write(io->addr + io->len - unaligned,
                                      io->remainder, unaligned);
            break;
        case IDE_DMA_WRITE:
            /* cache the contents in our io struct */
            cpu_physical_memory_read(io->addr + io->len - unaligned,
                                     io->remainder, unaligned);
            break;
        case IDE_DMA_TRIM:
            break;
        }

        io->len -= unaligned;
    }

285 286
    MACIO_DPRINTF("io->len = %#x\n", io->len);

287
    qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1,
P
Paolo Bonzini 已提交
288
                     &address_space_memory);
G
Gerd Hoffmann 已提交
289
    qemu_sglist_add(&s->sg, io->addr, io->len);
290 291 292 293 294 295 296 297 298 299 300
    io->addr += io->len + unaligned;
    io->remainder_len = (0x200 - unaligned) & 0x1ff;
    MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len);

    /* We would read no data from the block layer, thus not get a callback.
       Just fake completion manually. */
    if (!io->len) {
        pmac_ide_transfer_cb(opaque, 0);
        return;
    }

G
Gerd Hoffmann 已提交
301 302
    io->len = 0;

303 304 305
    MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n",
                  sector_num, n, s->nsector, s->dma_cmd);

306 307
    switch (s->dma_cmd) {
    case IDE_DMA_READ:
G
Gerd Hoffmann 已提交
308
        m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
309
                                 pmac_ide_transfer_cb, io);
310 311
        break;
    case IDE_DMA_WRITE:
G
Gerd Hoffmann 已提交
312
        m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
313
                                  pmac_ide_transfer_cb, io);
314
        break;
C
Christoph Hellwig 已提交
315 316
    case IDE_DMA_TRIM:
        m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
317
                               ide_issue_trim, pmac_ide_transfer_cb, io,
318
                               DMA_DIRECTION_TO_DEVICE);
C
Christoph Hellwig 已提交
319
        break;
320
    }
321
    return;
322

323 324 325 326 327
done:
    if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
        bdrv_acct_done(s->bs, &s->acct);
    }
    io->dma_end(io);
G
Gerd Hoffmann 已提交
328 329 330 331 332 333 334
}

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

335 336
    MACIO_DPRINTF("\n");

G
Gerd Hoffmann 已提交
337
    s->io_buffer_size = 0;
338
    if (s->drive_kind == IDE_CD) {
339
        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
G
Gerd Hoffmann 已提交
340 341 342 343
        pmac_ide_atapi_transfer_cb(io, 0);
        return;
    }

344 345 346 347 348 349 350 351 352 353 354
    switch (s->dma_cmd) {
    case IDE_DMA_READ:
        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ);
        break;
    case IDE_DMA_WRITE:
        bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_WRITE);
        break;
    default:
        break;
    }

G
Gerd Hoffmann 已提交
355 356 357 358 359 360 361
    pmac_ide_transfer_cb(io, 0);
}

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

362 363 364
    if (m->aiocb) {
        bdrv_drain_all();
    }
G
Gerd Hoffmann 已提交
365 366 367 368
}

/* PowerMac IDE memory IO */
static void pmac_ide_writeb (void *opaque,
A
Avi Kivity 已提交
369
                             hwaddr addr, uint32_t val)
G
Gerd Hoffmann 已提交
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    switch (addr) {
    case 1 ... 7:
        ide_ioport_write(&d->bus, addr, val);
        break;
    case 8:
    case 22:
        ide_cmd_write(&d->bus, 0, val);
        break;
    default:
        break;
    }
}

A
Avi Kivity 已提交
387
static uint32_t pmac_ide_readb (void *opaque,hwaddr addr)
G
Gerd Hoffmann 已提交
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
{
    uint8_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    switch (addr) {
    case 1 ... 7:
        retval = ide_ioport_read(&d->bus, addr);
        break;
    case 8:
    case 22:
        retval = ide_status_read(&d->bus, 0);
        break;
    default:
        retval = 0xFF;
        break;
    }
    return retval;
}

static void pmac_ide_writew (void *opaque,
A
Avi Kivity 已提交
409
                             hwaddr addr, uint32_t val)
G
Gerd Hoffmann 已提交
410 411 412 413 414 415 416 417 418 419
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    val = bswap16(val);
    if (addr == 0) {
        ide_data_writew(&d->bus, 0, val);
    }
}

A
Avi Kivity 已提交
420
static uint32_t pmac_ide_readw (void *opaque,hwaddr addr)
G
Gerd Hoffmann 已提交
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
{
    uint16_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    if (addr == 0) {
        retval = ide_data_readw(&d->bus, 0);
    } else {
        retval = 0xFFFF;
    }
    retval = bswap16(retval);
    return retval;
}

static void pmac_ide_writel (void *opaque,
A
Avi Kivity 已提交
436
                             hwaddr addr, uint32_t val)
G
Gerd Hoffmann 已提交
437 438 439 440 441 442 443 444 445 446
{
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    val = bswap32(val);
    if (addr == 0) {
        ide_data_writel(&d->bus, 0, val);
    }
}

A
Avi Kivity 已提交
447
static uint32_t pmac_ide_readl (void *opaque,hwaddr addr)
G
Gerd Hoffmann 已提交
448 449 450 451 452 453 454 455 456 457 458 459 460 461
{
    uint32_t retval;
    MACIOIDEState *d = opaque;

    addr = (addr & 0xFFF) >> 4;
    if (addr == 0) {
        retval = ide_data_readl(&d->bus, 0);
    } else {
        retval = 0xFFFFFFFF;
    }
    retval = bswap32(retval);
    return retval;
}

462
static const MemoryRegionOps pmac_ide_ops = {
A
Avi Kivity 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475
    .old_mmio = {
        .write = {
            pmac_ide_writeb,
            pmac_ide_writew,
            pmac_ide_writel,
        },
        .read = {
            pmac_ide_readb,
            pmac_ide_readw,
            pmac_ide_readl,
        },
    },
    .endianness = DEVICE_NATIVE_ENDIAN,
G
Gerd Hoffmann 已提交
476 477
};

J
Juan Quintela 已提交
478 479 480 481 482 483 484 485 486
static const VMStateDescription vmstate_pmac = {
    .name = "ide",
    .version_id = 3,
    .minimum_version_id = 0,
    .minimum_version_id_old = 0,
    .fields      = (VMStateField []) {
        VMSTATE_IDE_BUS(bus, MACIOIDEState),
        VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
        VMSTATE_END_OF_LIST()
G
Gerd Hoffmann 已提交
487
    }
J
Juan Quintela 已提交
488
};
G
Gerd Hoffmann 已提交
489

A
Andreas Färber 已提交
490
static void macio_ide_reset(DeviceState *dev)
G
Gerd Hoffmann 已提交
491
{
A
Andreas Färber 已提交
492
    MACIOIDEState *d = MACIO_IDE(dev);
G
Gerd Hoffmann 已提交
493

B
Blue Swirl 已提交
494
    ide_bus_reset(&d->bus);
G
Gerd Hoffmann 已提交
495 496
}

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
static int ide_nop(IDEDMA *dma)
{
    return 0;
}

static int ide_nop_int(IDEDMA *dma, int x)
{
    return 0;
}

static void ide_nop_restart(void *opaque, int x, RunState y)
{
}

static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
                            BlockDriverCompletionFunc *cb)
{
    MACIOIDEState *m = container_of(dma, MACIOIDEState, dma);

    MACIO_DPRINTF("\n");
517
    m->dma_active = true;
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
    DBDMA_kick(m->dbdma);
}

static const IDEDMAOps dbdma_ops = {
    .start_dma      = ide_dbdma_start,
    .start_transfer = ide_nop,
    .prepare_buf    = ide_nop_int,
    .rw_buf         = ide_nop_int,
    .set_unit       = ide_nop_int,
    .add_status     = ide_nop_int,
    .set_inactive   = ide_nop,
    .restart_cb     = ide_nop_restart,
    .reset          = ide_nop,
};

A
Andreas Färber 已提交
533
static void macio_ide_realizefn(DeviceState *dev, Error **errp)
G
Gerd Hoffmann 已提交
534
{
A
Andreas Färber 已提交
535 536 537
    MACIOIDEState *s = MACIO_IDE(dev);

    ide_init2(&s->bus, s->irq);
538 539 540 541

    /* Register DMA callbacks */
    s->dma.ops = &dbdma_ops;
    s->bus.dma = &s->dma;
A
Andreas Färber 已提交
542 543 544 545 546 547 548
}

static void macio_ide_initfn(Object *obj)
{
    SysBusDevice *d = SYS_BUS_DEVICE(obj);
    MACIOIDEState *s = MACIO_IDE(obj);

549
    ide_bus_new(&s->bus, DEVICE(obj), 0, 2);
550
    memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000);
A
Andreas Färber 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563
    sysbus_init_mmio(d, &s->mem);
    sysbus_init_irq(d, &s->irq);
    sysbus_init_irq(d, &s->dma_irq);
}

static void macio_ide_class_init(ObjectClass *oc, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(oc);

    dc->realize = macio_ide_realizefn;
    dc->reset = macio_ide_reset;
    dc->vmsd = &vmstate_pmac;
}
G
Gerd Hoffmann 已提交
564

A
Andreas Färber 已提交
565 566 567 568 569 570 571
static const TypeInfo macio_ide_type_info = {
    .name = TYPE_MACIO_IDE,
    .parent = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(MACIOIDEState),
    .instance_init = macio_ide_initfn,
    .class_init = macio_ide_class_init,
};
G
Gerd Hoffmann 已提交
572

A
Andreas Färber 已提交
573 574 575 576
static void macio_ide_register_types(void)
{
    type_register_static(&macio_ide_type_info);
}
G
Gerd Hoffmann 已提交
577

578
/* hd_table must contain 2 block drivers */
A
Andreas Färber 已提交
579 580 581
void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table)
{
    int i;
G
Gerd Hoffmann 已提交
582

A
Andreas Färber 已提交
583 584 585 586 587
    for (i = 0; i < 2; i++) {
        if (hd_table[i]) {
            ide_create_drive(&s->bus, i, hd_table[i]);
        }
    }
G
Gerd Hoffmann 已提交
588
}
A
Andreas Färber 已提交
589 590 591

void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel)
{
592
    s->dbdma = dbdma;
A
Andreas Färber 已提交
593 594 595 596 597
    DBDMA_register_channel(dbdma, channel, s->dma_irq,
                           pmac_ide_transfer, pmac_ide_flush, s);
}

type_init(macio_ide_register_types)