qemu/hw/audio/cs4231a.c
<<
>>
Prefs
   1/*
   2 * QEMU Crystal CS4231 audio chip emulation
   3 *
   4 * Copyright (c) 2006 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "hw/hw.h"
  26#include "hw/audio/soundhw.h"
  27#include "audio/audio.h"
  28#include "hw/isa/isa.h"
  29#include "hw/qdev.h"
  30#include "qemu/timer.h"
  31#include "qapi/error.h"
  32
  33/*
  34  Missing features:
  35  ADC
  36  Loopback
  37  Timer
  38  ADPCM
  39  More...
  40*/
  41
  42/* #define DEBUG */
  43/* #define DEBUG_XLAW */
  44
  45static struct {
  46    int aci_counter;
  47} conf = {1};
  48
  49#ifdef DEBUG
  50#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
  51#else
  52#define dolog(...)
  53#endif
  54
  55#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
  56#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
  57
  58#define CS_REGS 16
  59#define CS_DREGS 32
  60
  61#define TYPE_CS4231A "cs4231a"
  62#define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
  63
  64typedef struct CSState {
  65    ISADevice dev;
  66    QEMUSoundCard card;
  67    MemoryRegion ioports;
  68    qemu_irq pic;
  69    uint32_t regs[CS_REGS];
  70    uint8_t dregs[CS_DREGS];
  71    uint32_t irq;
  72    uint32_t dma;
  73    uint32_t port;
  74    IsaDma *isa_dma;
  75    int shift;
  76    int dma_running;
  77    int audio_free;
  78    int transferred;
  79    int aci_counter;
  80    SWVoiceOut *voice;
  81    int16_t *tab;
  82} CSState;
  83
  84#define MODE2 (1 << 6)
  85#define MCE (1 << 6)
  86#define PMCE (1 << 4)
  87#define CMCE (1 << 5)
  88#define TE (1 << 6)
  89#define PEN (1 << 0)
  90#define INT (1 << 0)
  91#define IEN (1 << 1)
  92#define PPIO (1 << 6)
  93#define PI (1 << 4)
  94#define CI (1 << 5)
  95#define TI (1 << 6)
  96
  97enum {
  98    Index_Address,
  99    Index_Data,
 100    Status,
 101    PIO_Data
 102};
 103
 104enum {
 105    Left_ADC_Input_Control,
 106    Right_ADC_Input_Control,
 107    Left_AUX1_Input_Control,
 108    Right_AUX1_Input_Control,
 109    Left_AUX2_Input_Control,
 110    Right_AUX2_Input_Control,
 111    Left_DAC_Output_Control,
 112    Right_DAC_Output_Control,
 113    FS_And_Playback_Data_Format,
 114    Interface_Configuration,
 115    Pin_Control,
 116    Error_Status_And_Initialization,
 117    MODE_And_ID,
 118    Loopback_Control,
 119    Playback_Upper_Base_Count,
 120    Playback_Lower_Base_Count,
 121    Alternate_Feature_Enable_I,
 122    Alternate_Feature_Enable_II,
 123    Left_Line_Input_Control,
 124    Right_Line_Input_Control,
 125    Timer_Low_Base,
 126    Timer_High_Base,
 127    RESERVED,
 128    Alternate_Feature_Enable_III,
 129    Alternate_Feature_Status,
 130    Version_Chip_ID,
 131    Mono_Input_And_Output_Control,
 132    RESERVED_2,
 133    Capture_Data_Format,
 134    RESERVED_3,
 135    Capture_Upper_Base_Count,
 136    Capture_Lower_Base_Count
 137};
 138
 139static int freqs[2][8] = {
 140    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
 141    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
 142};
 143
 144/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
 145static int16_t MuLawDecompressTable[256] =
 146{
 147     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
 148     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
 149     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
 150     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
 151      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
 152      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
 153      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
 154      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
 155      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
 156      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
 157       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
 158       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
 159       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
 160       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
 161       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
 162        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
 163      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
 164      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
 165      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
 166      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
 167       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
 168       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
 169       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
 170       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
 171       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
 172       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
 173        876,   844,   812,   780,   748,   716,   684,   652,
 174        620,   588,   556,   524,   492,   460,   428,   396,
 175        372,   356,   340,   324,   308,   292,   276,   260,
 176        244,   228,   212,   196,   180,   164,   148,   132,
 177        120,   112,   104,    96,    88,    80,    72,    64,
 178         56,    48,    40,    32,    24,    16,     8,     0
 179};
 180
 181static int16_t ALawDecompressTable[256] =
 182{
 183     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
 184     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
 185     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
 186     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
 187     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
 188     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
 189     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
 190     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
 191     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
 192     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
 193     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
 194     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
 195     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
 196     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
 197     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
 198     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
 199      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
 200      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
 201      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
 202      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
 203      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
 204      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
 205      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
 206      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
 207      344,   328,   376,   360,   280,   264,   312,   296,
 208      472,   456,   504,   488,   408,   392,   440,   424,
 209      88,    72,   120,   104,    24,     8,    56,    40,
 210      216,   200,   248,   232,   152,   136,   184,   168,
 211      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
 212      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
 213      688,   656,   752,   720,   560,   528,   624,   592,
 214      944,   912,  1008,   976,   816,   784,   880,   848
 215};
 216
 217static void cs4231a_reset (DeviceState *dev)
 218{
 219    CSState *s = CS4231A (dev);
 220
 221    s->regs[Index_Address] = 0x40;
 222    s->regs[Index_Data]    = 0x00;
 223    s->regs[Status]        = 0x00;
 224    s->regs[PIO_Data]      = 0x00;
 225
 226    s->dregs[Left_ADC_Input_Control]          = 0x00;
 227    s->dregs[Right_ADC_Input_Control]         = 0x00;
 228    s->dregs[Left_AUX1_Input_Control]         = 0x88;
 229    s->dregs[Right_AUX1_Input_Control]        = 0x88;
 230    s->dregs[Left_AUX2_Input_Control]         = 0x88;
 231    s->dregs[Right_AUX2_Input_Control]        = 0x88;
 232    s->dregs[Left_DAC_Output_Control]         = 0x80;
 233    s->dregs[Right_DAC_Output_Control]        = 0x80;
 234    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
 235    s->dregs[Interface_Configuration]         = 0x08;
 236    s->dregs[Pin_Control]                     = 0x00;
 237    s->dregs[Error_Status_And_Initialization] = 0x00;
 238    s->dregs[MODE_And_ID]                     = 0x8a;
 239    s->dregs[Loopback_Control]                = 0x00;
 240    s->dregs[Playback_Upper_Base_Count]       = 0x00;
 241    s->dregs[Playback_Lower_Base_Count]       = 0x00;
 242    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
 243    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
 244    s->dregs[Left_Line_Input_Control]         = 0x88;
 245    s->dregs[Right_Line_Input_Control]        = 0x88;
 246    s->dregs[Timer_Low_Base]                  = 0x00;
 247    s->dregs[Timer_High_Base]                 = 0x00;
 248    s->dregs[RESERVED]                        = 0x00;
 249    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
 250    s->dregs[Alternate_Feature_Status]        = 0x00;
 251    s->dregs[Version_Chip_ID]                 = 0xa0;
 252    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
 253    s->dregs[RESERVED_2]                      = 0x00;
 254    s->dregs[Capture_Data_Format]             = 0x00;
 255    s->dregs[RESERVED_3]                      = 0x00;
 256    s->dregs[Capture_Upper_Base_Count]        = 0x00;
 257    s->dregs[Capture_Lower_Base_Count]        = 0x00;
 258}
 259
 260static void cs_audio_callback (void *opaque, int free)
 261{
 262    CSState *s = opaque;
 263    s->audio_free = free;
 264}
 265
 266static void cs_reset_voices (CSState *s, uint32_t val)
 267{
 268    int xtal;
 269    struct audsettings as;
 270    IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 271
 272#ifdef DEBUG_XLAW
 273    if (val == 0 || val == 32)
 274        val = (1 << 4) | (1 << 5);
 275#endif
 276
 277    xtal = val & 1;
 278    as.freq = freqs[xtal][(val >> 1) & 7];
 279
 280    if (as.freq == -1) {
 281        lerr ("unsupported frequency (val=%#x)\n", val);
 282        goto error;
 283    }
 284
 285    as.nchannels = (val & (1 << 4)) ? 2 : 1;
 286    as.endianness = 0;
 287    s->tab = NULL;
 288
 289    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
 290    case 0:
 291        as.fmt = AUD_FMT_U8;
 292        s->shift = as.nchannels == 2;
 293        break;
 294
 295    case 1:
 296        s->tab = MuLawDecompressTable;
 297        goto x_law;
 298    case 3:
 299        s->tab = ALawDecompressTable;
 300    x_law:
 301        as.fmt = AUD_FMT_S16;
 302        as.endianness = AUDIO_HOST_ENDIANNESS;
 303        s->shift = as.nchannels == 2;
 304        break;
 305
 306    case 6:
 307        as.endianness = 1;
 308    case 2:
 309        as.fmt = AUD_FMT_S16;
 310        s->shift = as.nchannels;
 311        break;
 312
 313    case 7:
 314    case 4:
 315        lerr ("attempt to use reserved format value (%#x)\n", val);
 316        goto error;
 317
 318    case 5:
 319        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
 320        goto error;
 321    }
 322
 323    s->voice = AUD_open_out (
 324        &s->card,
 325        s->voice,
 326        "cs4231a",
 327        s,
 328        cs_audio_callback,
 329        &as
 330        );
 331
 332    if (s->dregs[Interface_Configuration] & PEN) {
 333        if (!s->dma_running) {
 334            k->hold_DREQ(s->isa_dma, s->dma);
 335            AUD_set_active_out (s->voice, 1);
 336            s->transferred = 0;
 337        }
 338        s->dma_running = 1;
 339    }
 340    else {
 341        if (s->dma_running) {
 342            k->release_DREQ(s->isa_dma, s->dma);
 343            AUD_set_active_out (s->voice, 0);
 344        }
 345        s->dma_running = 0;
 346    }
 347    return;
 348
 349 error:
 350    if (s->dma_running) {
 351        k->release_DREQ(s->isa_dma, s->dma);
 352        AUD_set_active_out (s->voice, 0);
 353    }
 354}
 355
 356static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
 357{
 358    CSState *s = opaque;
 359    uint32_t saddr, iaddr, ret;
 360
 361    saddr = addr;
 362    iaddr = ~0U;
 363
 364    switch (saddr) {
 365    case Index_Address:
 366        ret = s->regs[saddr] & ~0x80;
 367        break;
 368
 369    case Index_Data:
 370        if (!(s->dregs[MODE_And_ID] & MODE2))
 371            iaddr = s->regs[Index_Address] & 0x0f;
 372        else
 373            iaddr = s->regs[Index_Address] & 0x1f;
 374
 375        ret = s->dregs[iaddr];
 376        if (iaddr == Error_Status_And_Initialization) {
 377            /* keep SEAL happy */
 378            if (s->aci_counter) {
 379                ret |= 1 << 5;
 380                s->aci_counter -= 1;
 381            }
 382        }
 383        break;
 384
 385    default:
 386        ret = s->regs[saddr];
 387        break;
 388    }
 389    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
 390    return ret;
 391}
 392
 393static void cs_write (void *opaque, hwaddr addr,
 394                      uint64_t val64, unsigned size)
 395{
 396    CSState *s = opaque;
 397    uint32_t saddr, iaddr, val;
 398
 399    saddr = addr;
 400    val = val64;
 401
 402    switch (saddr) {
 403    case Index_Address:
 404        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
 405            && (s->dregs[Interface_Configuration] & (3 << 3)))
 406            s->aci_counter = conf.aci_counter;
 407
 408        s->regs[Index_Address] = val & ~(1 << 7);
 409        break;
 410
 411    case Index_Data:
 412        if (!(s->dregs[MODE_And_ID] & MODE2))
 413            iaddr = s->regs[Index_Address] & 0x0f;
 414        else
 415            iaddr = s->regs[Index_Address] & 0x1f;
 416
 417        switch (iaddr) {
 418        case RESERVED:
 419        case RESERVED_2:
 420        case RESERVED_3:
 421            lwarn ("attempt to write %#x to reserved indirect register %d\n",
 422                   val, iaddr);
 423            break;
 424
 425        case FS_And_Playback_Data_Format:
 426            if (s->regs[Index_Address] & MCE) {
 427                cs_reset_voices (s, val);
 428            }
 429            else {
 430                if (s->dregs[Alternate_Feature_Status] & PMCE) {
 431                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
 432                    cs_reset_voices (s, val);
 433                }
 434                else {
 435                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
 436                           s->regs[Index_Address],
 437                           s->dregs[Alternate_Feature_Status],
 438                           val);
 439                    break;
 440                }
 441            }
 442            s->dregs[iaddr] = val;
 443            break;
 444
 445        case Interface_Configuration:
 446            val &= ~(1 << 5);   /* D5 is reserved */
 447            s->dregs[iaddr] = val;
 448            if (val & PPIO) {
 449                lwarn ("PIO is not supported (%#x)\n", val);
 450                break;
 451            }
 452            if (val & PEN) {
 453                if (!s->dma_running) {
 454                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
 455                }
 456            }
 457            else {
 458                if (s->dma_running) {
 459                    IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 460                    k->release_DREQ(s->isa_dma, s->dma);
 461                    AUD_set_active_out (s->voice, 0);
 462                    s->dma_running = 0;
 463                }
 464            }
 465            break;
 466
 467        case Error_Status_And_Initialization:
 468            lwarn ("attempt to write to read only register %d\n", iaddr);
 469            break;
 470
 471        case MODE_And_ID:
 472            dolog ("val=%#x\n", val);
 473            if (val & MODE2)
 474                s->dregs[iaddr] |= MODE2;
 475            else
 476                s->dregs[iaddr] &= ~MODE2;
 477            break;
 478
 479        case Alternate_Feature_Enable_I:
 480            if (val & TE)
 481                lerr ("timer is not yet supported\n");
 482            s->dregs[iaddr] = val;
 483            break;
 484
 485        case Alternate_Feature_Status:
 486            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
 487                /* XXX: TI CI */
 488                qemu_irq_lower (s->pic);
 489                s->regs[Status] &= ~INT;
 490            }
 491            s->dregs[iaddr] = val;
 492            break;
 493
 494        case Version_Chip_ID:
 495            lwarn ("write to Version_Chip_ID register %#x\n", val);
 496            s->dregs[iaddr] = val;
 497            break;
 498
 499        default:
 500            s->dregs[iaddr] = val;
 501            break;
 502        }
 503        dolog ("written value %#x to indirect register %d\n", val, iaddr);
 504        break;
 505
 506    case Status:
 507        if (s->regs[Status] & INT) {
 508            qemu_irq_lower (s->pic);
 509        }
 510        s->regs[Status] &= ~INT;
 511        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
 512        break;
 513
 514    case PIO_Data:
 515        lwarn ("attempt to write value %#x to PIO register\n", val);
 516        break;
 517    }
 518}
 519
 520static int cs_write_audio (CSState *s, int nchan, int dma_pos,
 521                           int dma_len, int len)
 522{
 523    int temp, net;
 524    uint8_t tmpbuf[4096];
 525    IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 526
 527    temp = len;
 528    net = 0;
 529
 530    while (temp) {
 531        int left = dma_len - dma_pos;
 532        int copied;
 533        size_t to_copy;
 534
 535        to_copy = audio_MIN (temp, left);
 536        if (to_copy > sizeof (tmpbuf)) {
 537            to_copy = sizeof (tmpbuf);
 538        }
 539
 540        copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
 541        if (s->tab) {
 542            int i;
 543            int16_t linbuf[4096];
 544
 545            for (i = 0; i < copied; ++i)
 546                linbuf[i] = s->tab[tmpbuf[i]];
 547            copied = AUD_write (s->voice, linbuf, copied << 1);
 548            copied >>= 1;
 549        }
 550        else {
 551            copied = AUD_write (s->voice, tmpbuf, copied);
 552        }
 553
 554        temp -= copied;
 555        dma_pos = (dma_pos + copied) % dma_len;
 556        net += copied;
 557
 558        if (!copied) {
 559            break;
 560        }
 561    }
 562
 563    return net;
 564}
 565
 566static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
 567{
 568    CSState *s = opaque;
 569    int copy, written;
 570    int till = -1;
 571
 572    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
 573
 574    if (s->dregs[Pin_Control] & IEN) {
 575        till = (s->dregs[Playback_Lower_Base_Count]
 576            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
 577        till -= s->transferred;
 578        copy = audio_MIN (till, copy);
 579    }
 580
 581    if ((copy <= 0) || (dma_len <= 0)) {
 582        return dma_pos;
 583    }
 584
 585    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
 586
 587    dma_pos = (dma_pos + written) % dma_len;
 588    s->audio_free -= (written << (s->tab != NULL));
 589
 590    if (written == till) {
 591        s->regs[Status] |= INT;
 592        s->dregs[Alternate_Feature_Status] |= PI;
 593        s->transferred = 0;
 594        qemu_irq_raise (s->pic);
 595    }
 596    else {
 597        s->transferred += written;
 598    }
 599
 600    return dma_pos;
 601}
 602
 603static int cs4231a_pre_load (void *opaque)
 604{
 605    CSState *s = opaque;
 606
 607    if (s->dma_running) {
 608        IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 609        k->release_DREQ(s->isa_dma, s->dma);
 610        AUD_set_active_out (s->voice, 0);
 611    }
 612    s->dma_running = 0;
 613    return 0;
 614}
 615
 616static int cs4231a_post_load (void *opaque, int version_id)
 617{
 618    CSState *s = opaque;
 619
 620    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
 621        s->dma_running = 0;
 622        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
 623    }
 624    return 0;
 625}
 626
 627static const VMStateDescription vmstate_cs4231a = {
 628    .name = "cs4231a",
 629    .version_id = 1,
 630    .minimum_version_id = 1,
 631    .pre_load = cs4231a_pre_load,
 632    .post_load = cs4231a_post_load,
 633    .fields = (VMStateField[]) {
 634        VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
 635        VMSTATE_BUFFER (dregs, CSState),
 636        VMSTATE_INT32 (dma_running, CSState),
 637        VMSTATE_INT32 (audio_free, CSState),
 638        VMSTATE_INT32 (transferred, CSState),
 639        VMSTATE_INT32 (aci_counter, CSState),
 640        VMSTATE_END_OF_LIST ()
 641    }
 642};
 643
 644static const MemoryRegionOps cs_ioport_ops = {
 645    .read = cs_read,
 646    .write = cs_write,
 647    .impl = {
 648        .min_access_size = 1,
 649        .max_access_size = 1,
 650    }
 651};
 652
 653static void cs4231a_initfn (Object *obj)
 654{
 655    CSState *s = CS4231A (obj);
 656
 657    memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
 658                           "cs4231a", 4);
 659}
 660
 661static void cs4231a_realizefn (DeviceState *dev, Error **errp)
 662{
 663    ISADevice *d = ISA_DEVICE (dev);
 664    CSState *s = CS4231A (dev);
 665    IsaDmaClass *k;
 666
 667    s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->dma);
 668    if (!s->isa_dma) {
 669        error_setg(errp, "ISA controller does not support DMA");
 670        return;
 671    }
 672
 673    isa_init_irq(d, &s->pic, s->irq);
 674    k = ISADMA_GET_CLASS(s->isa_dma);
 675    k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
 676
 677    isa_register_ioport (d, &s->ioports, s->port);
 678
 679    AUD_register_card ("cs4231a", &s->card);
 680}
 681
 682static int cs4231a_init (ISABus *bus)
 683{
 684    isa_create_simple (bus, TYPE_CS4231A);
 685    return 0;
 686}
 687
 688static Property cs4231a_properties[] = {
 689    DEFINE_PROP_UINT32 ("iobase",  CSState, port, 0x534),
 690    DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
 691    DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
 692    DEFINE_PROP_END_OF_LIST (),
 693};
 694
 695static void cs4231a_class_initfn (ObjectClass *klass, void *data)
 696{
 697    DeviceClass *dc = DEVICE_CLASS (klass);
 698
 699    dc->realize = cs4231a_realizefn;
 700    dc->reset = cs4231a_reset;
 701    set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
 702    dc->desc = "Crystal Semiconductor CS4231A";
 703    dc->vmsd = &vmstate_cs4231a;
 704    dc->props = cs4231a_properties;
 705}
 706
 707static const TypeInfo cs4231a_info = {
 708    .name          = TYPE_CS4231A,
 709    .parent        = TYPE_ISA_DEVICE,
 710    .instance_size = sizeof (CSState),
 711    .instance_init = cs4231a_initfn,
 712    .class_init    = cs4231a_class_initfn,
 713};
 714
 715static void cs4231a_register_types (void)
 716{
 717    type_register_static (&cs4231a_info);
 718    isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
 719}
 720
 721type_init (cs4231a_register_types)
 722