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