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 = AUDIO_FORMAT_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 = AUDIO_FORMAT_S16;
 302        as.endianness = AUDIO_HOST_ENDIANNESS;
 303        s->shift = as.nchannels == 2;
 304        break;
 305
 306    case 6:
 307        as.endianness = 1;
 308        /* fall through */
 309    case 2:
 310        as.fmt = AUDIO_FORMAT_S16;
 311        s->shift = as.nchannels;
 312        break;
 313
 314    case 7:
 315    case 4:
 316        lerr ("attempt to use reserved format value (%#x)\n", val);
 317        goto error;
 318
 319    case 5:
 320        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
 321        goto error;
 322    }
 323
 324    s->voice = AUD_open_out (
 325        &s->card,
 326        s->voice,
 327        "cs4231a",
 328        s,
 329        cs_audio_callback,
 330        &as
 331        );
 332
 333    if (s->dregs[Interface_Configuration] & PEN) {
 334        if (!s->dma_running) {
 335            k->hold_DREQ(s->isa_dma, s->dma);
 336            AUD_set_active_out (s->voice, 1);
 337            s->transferred = 0;
 338        }
 339        s->dma_running = 1;
 340    }
 341    else {
 342        if (s->dma_running) {
 343            k->release_DREQ(s->isa_dma, s->dma);
 344            AUD_set_active_out (s->voice, 0);
 345        }
 346        s->dma_running = 0;
 347    }
 348    return;
 349
 350 error:
 351    if (s->dma_running) {
 352        k->release_DREQ(s->isa_dma, s->dma);
 353        AUD_set_active_out (s->voice, 0);
 354    }
 355}
 356
 357static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
 358{
 359    CSState *s = opaque;
 360    uint32_t saddr, iaddr, ret;
 361
 362    saddr = addr;
 363    iaddr = ~0U;
 364
 365    switch (saddr) {
 366    case Index_Address:
 367        ret = s->regs[saddr] & ~0x80;
 368        break;
 369
 370    case Index_Data:
 371        if (!(s->dregs[MODE_And_ID] & MODE2))
 372            iaddr = s->regs[Index_Address] & 0x0f;
 373        else
 374            iaddr = s->regs[Index_Address] & 0x1f;
 375
 376        ret = s->dregs[iaddr];
 377        if (iaddr == Error_Status_And_Initialization) {
 378            /* keep SEAL happy */
 379            if (s->aci_counter) {
 380                ret |= 1 << 5;
 381                s->aci_counter -= 1;
 382            }
 383        }
 384        break;
 385
 386    default:
 387        ret = s->regs[saddr];
 388        break;
 389    }
 390    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
 391    return ret;
 392}
 393
 394static void cs_write (void *opaque, hwaddr addr,
 395                      uint64_t val64, unsigned size)
 396{
 397    CSState *s = opaque;
 398    uint32_t saddr, iaddr, val;
 399
 400    saddr = addr;
 401    val = val64;
 402
 403    switch (saddr) {
 404    case Index_Address:
 405        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
 406            && (s->dregs[Interface_Configuration] & (3 << 3)))
 407            s->aci_counter = conf.aci_counter;
 408
 409        s->regs[Index_Address] = val & ~(1 << 7);
 410        break;
 411
 412    case Index_Data:
 413        if (!(s->dregs[MODE_And_ID] & MODE2))
 414            iaddr = s->regs[Index_Address] & 0x0f;
 415        else
 416            iaddr = s->regs[Index_Address] & 0x1f;
 417
 418        switch (iaddr) {
 419        case RESERVED:
 420        case RESERVED_2:
 421        case RESERVED_3:
 422            lwarn ("attempt to write %#x to reserved indirect register %d\n",
 423                   val, iaddr);
 424            break;
 425
 426        case FS_And_Playback_Data_Format:
 427            if (s->regs[Index_Address] & MCE) {
 428                cs_reset_voices (s, val);
 429            }
 430            else {
 431                if (s->dregs[Alternate_Feature_Status] & PMCE) {
 432                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
 433                    cs_reset_voices (s, val);
 434                }
 435                else {
 436                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
 437                           s->regs[Index_Address],
 438                           s->dregs[Alternate_Feature_Status],
 439                           val);
 440                    break;
 441                }
 442            }
 443            s->dregs[iaddr] = val;
 444            break;
 445
 446        case Interface_Configuration:
 447            val &= ~(1 << 5);   /* D5 is reserved */
 448            s->dregs[iaddr] = val;
 449            if (val & PPIO) {
 450                lwarn ("PIO is not supported (%#x)\n", val);
 451                break;
 452            }
 453            if (val & PEN) {
 454                if (!s->dma_running) {
 455                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
 456                }
 457            }
 458            else {
 459                if (s->dma_running) {
 460                    IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 461                    k->release_DREQ(s->isa_dma, s->dma);
 462                    AUD_set_active_out (s->voice, 0);
 463                    s->dma_running = 0;
 464                }
 465            }
 466            break;
 467
 468        case Error_Status_And_Initialization:
 469            lwarn ("attempt to write to read only register %d\n", iaddr);
 470            break;
 471
 472        case MODE_And_ID:
 473            dolog ("val=%#x\n", val);
 474            if (val & MODE2)
 475                s->dregs[iaddr] |= MODE2;
 476            else
 477                s->dregs[iaddr] &= ~MODE2;
 478            break;
 479
 480        case Alternate_Feature_Enable_I:
 481            if (val & TE)
 482                lerr ("timer is not yet supported\n");
 483            s->dregs[iaddr] = val;
 484            break;
 485
 486        case Alternate_Feature_Status:
 487            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
 488                /* XXX: TI CI */
 489                qemu_irq_lower (s->pic);
 490                s->regs[Status] &= ~INT;
 491            }
 492            s->dregs[iaddr] = val;
 493            break;
 494
 495        case Version_Chip_ID:
 496            lwarn ("write to Version_Chip_ID register %#x\n", val);
 497            s->dregs[iaddr] = val;
 498            break;
 499
 500        default:
 501            s->dregs[iaddr] = val;
 502            break;
 503        }
 504        dolog ("written value %#x to indirect register %d\n", val, iaddr);
 505        break;
 506
 507    case Status:
 508        if (s->regs[Status] & INT) {
 509            qemu_irq_lower (s->pic);
 510        }
 511        s->regs[Status] &= ~INT;
 512        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
 513        break;
 514
 515    case PIO_Data:
 516        lwarn ("attempt to write value %#x to PIO register\n", val);
 517        break;
 518    }
 519}
 520
 521static int cs_write_audio (CSState *s, int nchan, int dma_pos,
 522                           int dma_len, int len)
 523{
 524    int temp, net;
 525    uint8_t tmpbuf[4096];
 526    IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 527
 528    temp = len;
 529    net = 0;
 530
 531    while (temp) {
 532        int left = dma_len - dma_pos;
 533        int copied;
 534        size_t to_copy;
 535
 536        to_copy = audio_MIN (temp, left);
 537        if (to_copy > sizeof (tmpbuf)) {
 538            to_copy = sizeof (tmpbuf);
 539        }
 540
 541        copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
 542        if (s->tab) {
 543            int i;
 544            int16_t linbuf[4096];
 545
 546            for (i = 0; i < copied; ++i)
 547                linbuf[i] = s->tab[tmpbuf[i]];
 548            copied = AUD_write (s->voice, linbuf, copied << 1);
 549            copied >>= 1;
 550        }
 551        else {
 552            copied = AUD_write (s->voice, tmpbuf, copied);
 553        }
 554
 555        temp -= copied;
 556        dma_pos = (dma_pos + copied) % dma_len;
 557        net += copied;
 558
 559        if (!copied) {
 560            break;
 561        }
 562    }
 563
 564    return net;
 565}
 566
 567static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
 568{
 569    CSState *s = opaque;
 570    int copy, written;
 571    int till = -1;
 572
 573    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
 574
 575    if (s->dregs[Pin_Control] & IEN) {
 576        till = (s->dregs[Playback_Lower_Base_Count]
 577            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
 578        till -= s->transferred;
 579        copy = audio_MIN (till, copy);
 580    }
 581
 582    if ((copy <= 0) || (dma_len <= 0)) {
 583        return dma_pos;
 584    }
 585
 586    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
 587
 588    dma_pos = (dma_pos + written) % dma_len;
 589    s->audio_free -= (written << (s->tab != NULL));
 590
 591    if (written == till) {
 592        s->regs[Status] |= INT;
 593        s->dregs[Alternate_Feature_Status] |= PI;
 594        s->transferred = 0;
 595        qemu_irq_raise (s->pic);
 596    }
 597    else {
 598        s->transferred += written;
 599    }
 600
 601    return dma_pos;
 602}
 603
 604static int cs4231a_pre_load (void *opaque)
 605{
 606    CSState *s = opaque;
 607
 608    if (s->dma_running) {
 609        IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
 610        k->release_DREQ(s->isa_dma, s->dma);
 611        AUD_set_active_out (s->voice, 0);
 612    }
 613    s->dma_running = 0;
 614    return 0;
 615}
 616
 617static int cs4231a_post_load (void *opaque, int version_id)
 618{
 619    CSState *s = opaque;
 620
 621    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
 622        s->dma_running = 0;
 623        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
 624    }
 625    return 0;
 626}
 627
 628static const VMStateDescription vmstate_cs4231a = {
 629    .name = "cs4231a",
 630    .version_id = 1,
 631    .minimum_version_id = 1,
 632    .pre_load = cs4231a_pre_load,
 633    .post_load = cs4231a_post_load,
 634    .fields = (VMStateField[]) {
 635        VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
 636        VMSTATE_BUFFER (dregs, CSState),
 637        VMSTATE_INT32 (dma_running, CSState),
 638        VMSTATE_INT32 (audio_free, CSState),
 639        VMSTATE_INT32 (transferred, CSState),
 640        VMSTATE_INT32 (aci_counter, CSState),
 641        VMSTATE_END_OF_LIST ()
 642    }
 643};
 644
 645static const MemoryRegionOps cs_ioport_ops = {
 646    .read = cs_read,
 647    .write = cs_write,
 648    .impl = {
 649        .min_access_size = 1,
 650        .max_access_size = 1,
 651    }
 652};
 653
 654static void cs4231a_initfn (Object *obj)
 655{
 656    CSState *s = CS4231A (obj);
 657
 658    memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
 659                           "cs4231a", 4);
 660}
 661
 662static void cs4231a_realizefn (DeviceState *dev, Error **errp)
 663{
 664    ISADevice *d = ISA_DEVICE (dev);
 665    CSState *s = CS4231A (dev);
 666    IsaDmaClass *k;
 667
 668    s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->dma);
 669    if (!s->isa_dma) {
 670        error_setg(errp, "ISA controller does not support DMA");
 671        return;
 672    }
 673
 674    isa_init_irq(d, &s->pic, s->irq);
 675    k = ISADMA_GET_CLASS(s->isa_dma);
 676    k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
 677
 678    isa_register_ioport (d, &s->ioports, s->port);
 679
 680    AUD_register_card ("cs4231a", &s->card);
 681}
 682
 683static int cs4231a_init (ISABus *bus)
 684{
 685    isa_create_simple (bus, TYPE_CS4231A);
 686    return 0;
 687}
 688
 689static Property cs4231a_properties[] = {
 690    DEFINE_PROP_UINT32 ("iobase",  CSState, port, 0x534),
 691    DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
 692    DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
 693    DEFINE_PROP_END_OF_LIST (),
 694};
 695
 696static void cs4231a_class_initfn (ObjectClass *klass, void *data)
 697{
 698    DeviceClass *dc = DEVICE_CLASS (klass);
 699
 700    dc->realize = cs4231a_realizefn;
 701    dc->reset = cs4231a_reset;
 702    set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
 703    dc->desc = "Crystal Semiconductor CS4231A";
 704    dc->vmsd = &vmstate_cs4231a;
 705    dc->props = cs4231a_properties;
 706}
 707
 708static const TypeInfo cs4231a_info = {
 709    .name          = TYPE_CS4231A,
 710    .parent        = TYPE_ISA_DEVICE,
 711    .instance_size = sizeof (CSState),
 712    .instance_init = cs4231a_initfn,
 713    .class_init    = cs4231a_class_initfn,
 714};
 715
 716static void cs4231a_register_types (void)
 717{
 718    type_register_static (&cs4231a_info);
 719    isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
 720}
 721
 722type_init (cs4231a_register_types)
 723