cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

cs4231a.c (21791B)


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