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