qemu/hw/mac_dbdma.c
<<
>>
Prefs
   1/*
   2 * PowerMac descriptor-based DMA emulation
   3 *
   4 * Copyright (c) 2005-2007 Fabrice Bellard
   5 * Copyright (c) 2007 Jocelyn Mayer
   6 * Copyright (c) 2009 Laurent Vivier
   7 *
   8 * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
   9 *
  10 *   Definitions for using the Apple Descriptor-Based DMA controller
  11 *   in Power Macintosh computers.
  12 *
  13 *   Copyright (C) 1996 Paul Mackerras.
  14 *
  15 * some parts from mol 0.9.71
  16 *
  17 *   Descriptor based DMA emulation
  18 *
  19 *   Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
  20 *
  21 * Permission is hereby granted, free of charge, to any person obtaining a copy
  22 * of this software and associated documentation files (the "Software"), to deal
  23 * in the Software without restriction, including without limitation the rights
  24 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  25 * copies of the Software, and to permit persons to whom the Software is
  26 * furnished to do so, subject to the following conditions:
  27 *
  28 * The above copyright notice and this permission notice shall be included in
  29 * all copies or substantial portions of the Software.
  30 *
  31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  32 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  33 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  34 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  35 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  36 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  37 * THE SOFTWARE.
  38 */
  39#include "hw.h"
  40#include "isa.h"
  41#include "mac_dbdma.h"
  42
  43/* debug DBDMA */
  44//#define DEBUG_DBDMA
  45
  46#ifdef DEBUG_DBDMA
  47#define DBDMA_DPRINTF(fmt, ...)                                 \
  48    do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
  49#else
  50#define DBDMA_DPRINTF(fmt, ...)
  51#endif
  52
  53/*
  54 */
  55
  56/*
  57 * DBDMA control/status registers.  All little-endian.
  58 */
  59
  60#define DBDMA_CONTROL         0x00
  61#define DBDMA_STATUS          0x01
  62#define DBDMA_CMDPTR_HI       0x02
  63#define DBDMA_CMDPTR_LO       0x03
  64#define DBDMA_INTR_SEL        0x04
  65#define DBDMA_BRANCH_SEL      0x05
  66#define DBDMA_WAIT_SEL        0x06
  67#define DBDMA_XFER_MODE       0x07
  68#define DBDMA_DATA2PTR_HI     0x08
  69#define DBDMA_DATA2PTR_LO     0x09
  70#define DBDMA_RES1            0x0A
  71#define DBDMA_ADDRESS_HI      0x0B
  72#define DBDMA_BRANCH_ADDR_HI  0x0C
  73#define DBDMA_RES2            0x0D
  74#define DBDMA_RES3            0x0E
  75#define DBDMA_RES4            0x0F
  76
  77#define DBDMA_REGS            16
  78#define DBDMA_SIZE            (DBDMA_REGS * sizeof(uint32_t))
  79
  80#define DBDMA_CHANNEL_SHIFT   7
  81#define DBDMA_CHANNEL_SIZE    (1 << DBDMA_CHANNEL_SHIFT)
  82
  83#define DBDMA_CHANNELS        (0x1000 >> DBDMA_CHANNEL_SHIFT)
  84
  85/* Bits in control and status registers */
  86
  87#define RUN     0x8000
  88#define PAUSE   0x4000
  89#define FLUSH   0x2000
  90#define WAKE    0x1000
  91#define DEAD    0x0800
  92#define ACTIVE  0x0400
  93#define BT      0x0100
  94#define DEVSTAT 0x00ff
  95
  96/*
  97 * DBDMA command structure.  These fields are all little-endian!
  98 */
  99
 100typedef struct dbdma_cmd {
 101    uint16_t req_count;   /* requested byte transfer count */
 102    uint16_t command;     /* command word (has bit-fields) */
 103    uint32_t phy_addr;    /* physical data address */
 104    uint32_t cmd_dep;     /* command-dependent field */
 105    uint16_t res_count;   /* residual count after completion */
 106    uint16_t xfer_status; /* transfer status */
 107} dbdma_cmd;
 108
 109/* DBDMA command values in command field */
 110
 111#define COMMAND_MASK    0xf000
 112#define OUTPUT_MORE     0x0000  /* transfer memory data to stream */
 113#define OUTPUT_LAST     0x1000  /* ditto followed by end marker */
 114#define INPUT_MORE      0x2000  /* transfer stream data to memory */
 115#define INPUT_LAST      0x3000  /* ditto, expect end marker */
 116#define STORE_WORD      0x4000  /* write word (4 bytes) to device reg */
 117#define LOAD_WORD       0x5000  /* read word (4 bytes) from device reg */
 118#define DBDMA_NOP       0x6000  /* do nothing */
 119#define DBDMA_STOP      0x7000  /* suspend processing */
 120
 121/* Key values in command field */
 122
 123#define KEY_MASK        0x0700
 124#define KEY_STREAM0     0x0000  /* usual data stream */
 125#define KEY_STREAM1     0x0100  /* control/status stream */
 126#define KEY_STREAM2     0x0200  /* device-dependent stream */
 127#define KEY_STREAM3     0x0300  /* device-dependent stream */
 128#define KEY_STREAM4     0x0400  /* reserved */
 129#define KEY_REGS        0x0500  /* device register space */
 130#define KEY_SYSTEM      0x0600  /* system memory-mapped space */
 131#define KEY_DEVICE      0x0700  /* device memory-mapped space */
 132
 133/* Interrupt control values in command field */
 134
 135#define INTR_MASK       0x0030
 136#define INTR_NEVER      0x0000  /* don't interrupt */
 137#define INTR_IFSET      0x0010  /* intr if condition bit is 1 */
 138#define INTR_IFCLR      0x0020  /* intr if condition bit is 0 */
 139#define INTR_ALWAYS     0x0030  /* always interrupt */
 140
 141/* Branch control values in command field */
 142
 143#define BR_MASK         0x000c
 144#define BR_NEVER        0x0000  /* don't branch */
 145#define BR_IFSET        0x0004  /* branch if condition bit is 1 */
 146#define BR_IFCLR        0x0008  /* branch if condition bit is 0 */
 147#define BR_ALWAYS       0x000c  /* always branch */
 148
 149/* Wait control values in command field */
 150
 151#define WAIT_MASK       0x0003
 152#define WAIT_NEVER      0x0000  /* don't wait */
 153#define WAIT_IFSET      0x0001  /* wait if condition bit is 1 */
 154#define WAIT_IFCLR      0x0002  /* wait if condition bit is 0 */
 155#define WAIT_ALWAYS     0x0003  /* always wait */
 156
 157typedef struct DBDMA_channel {
 158    int channel;
 159    uint32_t regs[DBDMA_REGS];
 160    qemu_irq irq;
 161    DBDMA_io io;
 162    DBDMA_rw rw;
 163    DBDMA_flush flush;
 164    dbdma_cmd current;
 165    int processing;
 166} DBDMA_channel;
 167
 168#ifdef DEBUG_DBDMA
 169static void dump_dbdma_cmd(dbdma_cmd *cmd)
 170{
 171    printf("dbdma_cmd %p\n", cmd);
 172    printf("    req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
 173    printf("    command 0x%04x\n", le16_to_cpu(cmd->command));
 174    printf("    phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
 175    printf("    cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
 176    printf("    res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
 177    printf("    xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
 178}
 179#else
 180static void dump_dbdma_cmd(dbdma_cmd *cmd)
 181{
 182}
 183#endif
 184static void dbdma_cmdptr_load(DBDMA_channel *ch)
 185{
 186    DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
 187                  ch->regs[DBDMA_CMDPTR_LO]);
 188    cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
 189                             (uint8_t*)&ch->current, sizeof(dbdma_cmd));
 190}
 191
 192static void dbdma_cmdptr_save(DBDMA_channel *ch)
 193{
 194    DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
 195                  ch->regs[DBDMA_CMDPTR_LO]);
 196    DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
 197                  le16_to_cpu(ch->current.xfer_status),
 198                  le16_to_cpu(ch->current.res_count));
 199    cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
 200                              (uint8_t*)&ch->current, sizeof(dbdma_cmd));
 201}
 202
 203static void kill_channel(DBDMA_channel *ch)
 204{
 205    DBDMA_DPRINTF("kill_channel\n");
 206
 207    ch->regs[DBDMA_STATUS] |= DEAD;
 208    ch->regs[DBDMA_STATUS] &= ~ACTIVE;
 209
 210    qemu_irq_raise(ch->irq);
 211}
 212
 213static void conditional_interrupt(DBDMA_channel *ch)
 214{
 215    dbdma_cmd *current = &ch->current;
 216    uint16_t intr;
 217    uint16_t sel_mask, sel_value;
 218    uint32_t status;
 219    int cond;
 220
 221    DBDMA_DPRINTF("conditional_interrupt\n");
 222
 223    intr = le16_to_cpu(current->command) & INTR_MASK;
 224
 225    switch(intr) {
 226    case INTR_NEVER:  /* don't interrupt */
 227        return;
 228    case INTR_ALWAYS: /* always interrupt */
 229        qemu_irq_raise(ch->irq);
 230        return;
 231    }
 232
 233    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
 234
 235    sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
 236    sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
 237
 238    cond = (status & sel_mask) == (sel_value & sel_mask);
 239
 240    switch(intr) {
 241    case INTR_IFSET:  /* intr if condition bit is 1 */
 242        if (cond)
 243            qemu_irq_raise(ch->irq);
 244        return;
 245    case INTR_IFCLR:  /* intr if condition bit is 0 */
 246        if (!cond)
 247            qemu_irq_raise(ch->irq);
 248        return;
 249    }
 250}
 251
 252static int conditional_wait(DBDMA_channel *ch)
 253{
 254    dbdma_cmd *current = &ch->current;
 255    uint16_t wait;
 256    uint16_t sel_mask, sel_value;
 257    uint32_t status;
 258    int cond;
 259
 260    DBDMA_DPRINTF("conditional_wait\n");
 261
 262    wait = le16_to_cpu(current->command) & WAIT_MASK;
 263
 264    switch(wait) {
 265    case WAIT_NEVER:  /* don't wait */
 266        return 0;
 267    case WAIT_ALWAYS: /* always wait */
 268        return 1;
 269    }
 270
 271    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
 272
 273    sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
 274    sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
 275
 276    cond = (status & sel_mask) == (sel_value & sel_mask);
 277
 278    switch(wait) {
 279    case WAIT_IFSET:  /* wait if condition bit is 1 */
 280        if (cond)
 281            return 1;
 282        return 0;
 283    case WAIT_IFCLR:  /* wait if condition bit is 0 */
 284        if (!cond)
 285            return 1;
 286        return 0;
 287    }
 288    return 0;
 289}
 290
 291static void next(DBDMA_channel *ch)
 292{
 293    uint32_t cp;
 294
 295    ch->regs[DBDMA_STATUS] &= ~BT;
 296
 297    cp = ch->regs[DBDMA_CMDPTR_LO];
 298    ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
 299    dbdma_cmdptr_load(ch);
 300}
 301
 302static void branch(DBDMA_channel *ch)
 303{
 304    dbdma_cmd *current = &ch->current;
 305
 306    ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
 307    ch->regs[DBDMA_STATUS] |= BT;
 308    dbdma_cmdptr_load(ch);
 309}
 310
 311static void conditional_branch(DBDMA_channel *ch)
 312{
 313    dbdma_cmd *current = &ch->current;
 314    uint16_t br;
 315    uint16_t sel_mask, sel_value;
 316    uint32_t status;
 317    int cond;
 318
 319    DBDMA_DPRINTF("conditional_branch\n");
 320
 321    /* check if we must branch */
 322
 323    br = le16_to_cpu(current->command) & BR_MASK;
 324
 325    switch(br) {
 326    case BR_NEVER:  /* don't branch */
 327        next(ch);
 328        return;
 329    case BR_ALWAYS: /* always branch */
 330        branch(ch);
 331        return;
 332    }
 333
 334    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
 335
 336    sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
 337    sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
 338
 339    cond = (status & sel_mask) == (sel_value & sel_mask);
 340
 341    switch(br) {
 342    case BR_IFSET:  /* branch if condition bit is 1 */
 343        if (cond)
 344            branch(ch);
 345        else
 346            next(ch);
 347        return;
 348    case BR_IFCLR:  /* branch if condition bit is 0 */
 349        if (!cond)
 350            branch(ch);
 351        else
 352            next(ch);
 353        return;
 354    }
 355}
 356
 357static QEMUBH *dbdma_bh;
 358static void channel_run(DBDMA_channel *ch);
 359
 360static void dbdma_end(DBDMA_io *io)
 361{
 362    DBDMA_channel *ch = io->channel;
 363    dbdma_cmd *current = &ch->current;
 364
 365    if (conditional_wait(ch))
 366        goto wait;
 367
 368    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
 369    current->res_count = cpu_to_le16(io->len);
 370    dbdma_cmdptr_save(ch);
 371    if (io->is_last)
 372        ch->regs[DBDMA_STATUS] &= ~FLUSH;
 373
 374    conditional_interrupt(ch);
 375    conditional_branch(ch);
 376
 377wait:
 378    ch->processing = 0;
 379    if ((ch->regs[DBDMA_STATUS] & RUN) &&
 380        (ch->regs[DBDMA_STATUS] & ACTIVE))
 381        channel_run(ch);
 382}
 383
 384static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
 385                        uint16_t req_count, int is_last)
 386{
 387    DBDMA_DPRINTF("start_output\n");
 388
 389    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
 390     * are not implemented in the mac-io chip
 391     */
 392
 393    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
 394    if (!addr || key > KEY_STREAM3) {
 395        kill_channel(ch);
 396        return;
 397    }
 398
 399    ch->io.addr = addr;
 400    ch->io.len = req_count;
 401    ch->io.is_last = is_last;
 402    ch->io.dma_end = dbdma_end;
 403    ch->io.is_dma_out = 1;
 404    ch->processing = 1;
 405    if (ch->rw) {
 406        ch->rw(&ch->io);
 407    }
 408}
 409
 410static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
 411                       uint16_t req_count, int is_last)
 412{
 413    DBDMA_DPRINTF("start_input\n");
 414
 415    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
 416     * are not implemented in the mac-io chip
 417     */
 418
 419    if (!addr || key > KEY_STREAM3) {
 420        kill_channel(ch);
 421        return;
 422    }
 423
 424    ch->io.addr = addr;
 425    ch->io.len = req_count;
 426    ch->io.is_last = is_last;
 427    ch->io.dma_end = dbdma_end;
 428    ch->io.is_dma_out = 0;
 429    ch->processing = 1;
 430    if (ch->rw) {
 431        ch->rw(&ch->io);
 432    }
 433}
 434
 435static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
 436                     uint16_t len)
 437{
 438    dbdma_cmd *current = &ch->current;
 439    uint32_t val;
 440
 441    DBDMA_DPRINTF("load_word\n");
 442
 443    /* only implements KEY_SYSTEM */
 444
 445    if (key != KEY_SYSTEM) {
 446        printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
 447        kill_channel(ch);
 448        return;
 449    }
 450
 451    cpu_physical_memory_read(addr, (uint8_t*)&val, len);
 452
 453    if (len == 2)
 454        val = (val << 16) | (current->cmd_dep & 0x0000ffff);
 455    else if (len == 1)
 456        val = (val << 24) | (current->cmd_dep & 0x00ffffff);
 457
 458    current->cmd_dep = val;
 459
 460    if (conditional_wait(ch))
 461        goto wait;
 462
 463    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
 464    dbdma_cmdptr_save(ch);
 465    ch->regs[DBDMA_STATUS] &= ~FLUSH;
 466
 467    conditional_interrupt(ch);
 468    next(ch);
 469
 470wait:
 471    qemu_bh_schedule(dbdma_bh);
 472}
 473
 474static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
 475                      uint16_t len)
 476{
 477    dbdma_cmd *current = &ch->current;
 478    uint32_t val;
 479
 480    DBDMA_DPRINTF("store_word\n");
 481
 482    /* only implements KEY_SYSTEM */
 483
 484    if (key != KEY_SYSTEM) {
 485        printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
 486        kill_channel(ch);
 487        return;
 488    }
 489
 490    val = current->cmd_dep;
 491    if (len == 2)
 492        val >>= 16;
 493    else if (len == 1)
 494        val >>= 24;
 495
 496    cpu_physical_memory_write(addr, (uint8_t*)&val, len);
 497
 498    if (conditional_wait(ch))
 499        goto wait;
 500
 501    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
 502    dbdma_cmdptr_save(ch);
 503    ch->regs[DBDMA_STATUS] &= ~FLUSH;
 504
 505    conditional_interrupt(ch);
 506    next(ch);
 507
 508wait:
 509    qemu_bh_schedule(dbdma_bh);
 510}
 511
 512static void nop(DBDMA_channel *ch)
 513{
 514    dbdma_cmd *current = &ch->current;
 515
 516    if (conditional_wait(ch))
 517        goto wait;
 518
 519    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
 520    dbdma_cmdptr_save(ch);
 521
 522    conditional_interrupt(ch);
 523    conditional_branch(ch);
 524
 525wait:
 526    qemu_bh_schedule(dbdma_bh);
 527}
 528
 529static void stop(DBDMA_channel *ch)
 530{
 531    ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
 532
 533    /* the stop command does not increment command pointer */
 534}
 535
 536static void channel_run(DBDMA_channel *ch)
 537{
 538    dbdma_cmd *current = &ch->current;
 539    uint16_t cmd, key;
 540    uint16_t req_count;
 541    uint32_t phy_addr;
 542
 543    DBDMA_DPRINTF("channel_run\n");
 544    dump_dbdma_cmd(current);
 545
 546    /* clear WAKE flag at command fetch */
 547
 548    ch->regs[DBDMA_STATUS] &= ~WAKE;
 549
 550    cmd = le16_to_cpu(current->command) & COMMAND_MASK;
 551
 552    switch (cmd) {
 553    case DBDMA_NOP:
 554        nop(ch);
 555        return;
 556
 557    case DBDMA_STOP:
 558        stop(ch);
 559        return;
 560    }
 561
 562    key = le16_to_cpu(current->command) & 0x0700;
 563    req_count = le16_to_cpu(current->req_count);
 564    phy_addr = le32_to_cpu(current->phy_addr);
 565
 566    if (key == KEY_STREAM4) {
 567        printf("command %x, invalid key 4\n", cmd);
 568        kill_channel(ch);
 569        return;
 570    }
 571
 572    switch (cmd) {
 573    case OUTPUT_MORE:
 574        start_output(ch, key, phy_addr, req_count, 0);
 575        return;
 576
 577    case OUTPUT_LAST:
 578        start_output(ch, key, phy_addr, req_count, 1);
 579        return;
 580
 581    case INPUT_MORE:
 582        start_input(ch, key, phy_addr, req_count, 0);
 583        return;
 584
 585    case INPUT_LAST:
 586        start_input(ch, key, phy_addr, req_count, 1);
 587        return;
 588    }
 589
 590    if (key < KEY_REGS) {
 591        printf("command %x, invalid key %x\n", cmd, key);
 592        key = KEY_SYSTEM;
 593    }
 594
 595    /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
 596     * and BRANCH is invalid
 597     */
 598
 599    req_count = req_count & 0x0007;
 600    if (req_count & 0x4) {
 601        req_count = 4;
 602        phy_addr &= ~3;
 603    } else if (req_count & 0x2) {
 604        req_count = 2;
 605        phy_addr &= ~1;
 606    } else
 607        req_count = 1;
 608
 609    switch (cmd) {
 610    case LOAD_WORD:
 611        load_word(ch, key, phy_addr, req_count);
 612        return;
 613
 614    case STORE_WORD:
 615        store_word(ch, key, phy_addr, req_count);
 616        return;
 617    }
 618}
 619
 620static void DBDMA_run (DBDMA_channel *ch)
 621{
 622    int channel;
 623
 624    for (channel = 0; channel < DBDMA_CHANNELS; channel++, ch++) {
 625            uint32_t status = ch->regs[DBDMA_STATUS];
 626            if (!ch->processing && (status & RUN) && (status & ACTIVE))
 627                channel_run(ch);
 628    }
 629}
 630
 631static void DBDMA_run_bh(void *opaque)
 632{
 633    DBDMA_channel *ch = opaque;
 634
 635    DBDMA_DPRINTF("DBDMA_run_bh\n");
 636
 637    DBDMA_run(ch);
 638}
 639
 640void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
 641                            DBDMA_rw rw, DBDMA_flush flush,
 642                            void *opaque)
 643{
 644    DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
 645
 646    DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
 647
 648    ch->irq = irq;
 649    ch->channel = nchan;
 650    ch->rw = rw;
 651    ch->flush = flush;
 652    ch->io.opaque = opaque;
 653    ch->io.channel = ch;
 654}
 655
 656void DBDMA_schedule(void)
 657{
 658    qemu_notify_event();
 659}
 660
 661static void
 662dbdma_control_write(DBDMA_channel *ch)
 663{
 664    uint16_t mask, value;
 665    uint32_t status;
 666
 667    mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
 668    value = ch->regs[DBDMA_CONTROL] & 0xffff;
 669
 670    value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
 671
 672    status = ch->regs[DBDMA_STATUS];
 673
 674    status = (value & mask) | (status & ~mask);
 675
 676    if (status & WAKE)
 677        status |= ACTIVE;
 678    if (status & RUN) {
 679        status |= ACTIVE;
 680        status &= ~DEAD;
 681    }
 682    if (status & PAUSE)
 683        status &= ~ACTIVE;
 684    if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
 685        /* RUN is cleared */
 686        status &= ~(ACTIVE|DEAD);
 687    }
 688
 689    DBDMA_DPRINTF("    status 0x%08x\n", status);
 690
 691    ch->regs[DBDMA_STATUS] = status;
 692
 693    if (status & ACTIVE)
 694        qemu_bh_schedule(dbdma_bh);
 695    if ((status & FLUSH) && ch->flush)
 696        ch->flush(&ch->io);
 697}
 698
 699static void dbdma_writel (void *opaque,
 700                          target_phys_addr_t addr, uint32_t value)
 701{
 702    int channel = addr >> DBDMA_CHANNEL_SHIFT;
 703    DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
 704    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
 705
 706    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
 707    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
 708                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
 709
 710    /* cmdptr cannot be modified if channel is RUN or ACTIVE */
 711
 712    if (reg == DBDMA_CMDPTR_LO &&
 713        (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
 714        return;
 715
 716    ch->regs[reg] = value;
 717
 718    switch(reg) {
 719    case DBDMA_CONTROL:
 720        dbdma_control_write(ch);
 721        break;
 722    case DBDMA_CMDPTR_LO:
 723        /* 16-byte aligned */
 724        ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
 725        dbdma_cmdptr_load(ch);
 726        break;
 727    case DBDMA_STATUS:
 728    case DBDMA_INTR_SEL:
 729    case DBDMA_BRANCH_SEL:
 730    case DBDMA_WAIT_SEL:
 731        /* nothing to do */
 732        break;
 733    case DBDMA_XFER_MODE:
 734    case DBDMA_CMDPTR_HI:
 735    case DBDMA_DATA2PTR_HI:
 736    case DBDMA_DATA2PTR_LO:
 737    case DBDMA_ADDRESS_HI:
 738    case DBDMA_BRANCH_ADDR_HI:
 739    case DBDMA_RES1:
 740    case DBDMA_RES2:
 741    case DBDMA_RES3:
 742    case DBDMA_RES4:
 743        /* unused */
 744        break;
 745    }
 746}
 747
 748static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
 749{
 750    uint32_t value;
 751    int channel = addr >> DBDMA_CHANNEL_SHIFT;
 752    DBDMA_channel *ch = (DBDMA_channel *)opaque + channel;
 753    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
 754
 755    value = ch->regs[reg];
 756
 757    DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
 758    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
 759                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
 760
 761    switch(reg) {
 762    case DBDMA_CONTROL:
 763        value = 0;
 764        break;
 765    case DBDMA_STATUS:
 766    case DBDMA_CMDPTR_LO:
 767    case DBDMA_INTR_SEL:
 768    case DBDMA_BRANCH_SEL:
 769    case DBDMA_WAIT_SEL:
 770        /* nothing to do */
 771        break;
 772    case DBDMA_XFER_MODE:
 773    case DBDMA_CMDPTR_HI:
 774    case DBDMA_DATA2PTR_HI:
 775    case DBDMA_DATA2PTR_LO:
 776    case DBDMA_ADDRESS_HI:
 777    case DBDMA_BRANCH_ADDR_HI:
 778        /* unused */
 779        value = 0;
 780        break;
 781    case DBDMA_RES1:
 782    case DBDMA_RES2:
 783    case DBDMA_RES3:
 784    case DBDMA_RES4:
 785        /* reserved */
 786        break;
 787    }
 788
 789    return value;
 790}
 791
 792static CPUWriteMemoryFunc * const dbdma_write[] = {
 793    NULL,
 794    NULL,
 795    dbdma_writel,
 796};
 797
 798static CPUReadMemoryFunc * const dbdma_read[] = {
 799    NULL,
 800    NULL,
 801    dbdma_readl,
 802};
 803
 804static void dbdma_save(QEMUFile *f, void *opaque)
 805{
 806    DBDMA_channel *s = opaque;
 807    unsigned int i, j;
 808
 809    for (i = 0; i < DBDMA_CHANNELS; i++)
 810        for (j = 0; j < DBDMA_REGS; j++)
 811            qemu_put_be32s(f, &s[i].regs[j]);
 812}
 813
 814static int dbdma_load(QEMUFile *f, void *opaque, int version_id)
 815{
 816    DBDMA_channel *s = opaque;
 817    unsigned int i, j;
 818
 819    if (version_id != 2)
 820        return -EINVAL;
 821
 822    for (i = 0; i < DBDMA_CHANNELS; i++)
 823        for (j = 0; j < DBDMA_REGS; j++)
 824            qemu_get_be32s(f, &s[i].regs[j]);
 825
 826    return 0;
 827}
 828
 829static void dbdma_reset(void *opaque)
 830{
 831    DBDMA_channel *s = opaque;
 832    int i;
 833
 834    for (i = 0; i < DBDMA_CHANNELS; i++)
 835        memset(s[i].regs, 0, DBDMA_SIZE);
 836}
 837
 838void* DBDMA_init (int *dbdma_mem_index)
 839{
 840    DBDMA_channel *s;
 841
 842    s = qemu_mallocz(sizeof(DBDMA_channel) * DBDMA_CHANNELS);
 843
 844    *dbdma_mem_index = cpu_register_io_memory(dbdma_read, dbdma_write, s,
 845                                              DEVICE_LITTLE_ENDIAN);
 846    register_savevm(NULL, "dbdma", -1, 1, dbdma_save, dbdma_load, s);
 847    qemu_register_reset(dbdma_reset, s);
 848
 849    dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
 850
 851    return s;
 852}
 853