Statistics
| Branch: | Revision:

root / hw / cs4231a.c @ 3a38d437

History | View | Annotate | Download (19.4 kB)

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 "hw.h"
25
#include "audiodev.h"
26
#include "audio/audio.h"
27
#include "isa.h"
28
#include "qemu-timer.h"
29

    
30
/*
31
  Missing features:
32
  ADC
33
  Loopback
34
  Timer
35
  ADPCM
36
  More...
37
*/
38

    
39
/* #define DEBUG */
40
/* #define DEBUG_XLAW */
41

    
42
static struct {
43
    int irq;
44
    int dma;
45
    int port;
46
    int aci_counter;
47
} conf = {9, 3, 0x534, 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
typedef struct CSState {
62
    QEMUSoundCard card;
63
    qemu_irq pic;
64
    uint32_t regs[CS_REGS];
65
    uint8_t dregs[CS_DREGS];
66
    int dma;
67
    int port;
68
    int shift;
69
    int dma_running;
70
    int audio_free;
71
    int transferred;
72
    int aci_counter;
73
    SWVoiceOut *voice;
74
    int16_t *tab;
75
} CSState;
76

    
77
#define IO_READ_PROTO(name)                             \
78
    static uint32_t name (void *opaque, uint32_t addr)
79

    
80
#define IO_WRITE_PROTO(name)                                            \
81
    static void name (void *opaque, uint32_t addr, uint32_t val)
82

    
83
#define GET_SADDR(addr) (addr & 3)
84

    
85
#define MODE2 (1 << 6)
86
#define MCE (1 << 6)
87
#define PMCE (1 << 4)
88
#define CMCE (1 << 5)
89
#define TE (1 << 6)
90
#define PEN (1 << 0)
91
#define INT (1 << 0)
92
#define IEN (1 << 1)
93
#define PPIO (1 << 6)
94
#define PI (1 << 4)
95
#define CI (1 << 5)
96
#define TI (1 << 6)
97

    
98
enum {
99
    Index_Address,
100
    Index_Data,
101
    Status,
102
    PIO_Data
103
};
104

    
105
enum {
106
    Left_ADC_Input_Control,
107
    Right_ADC_Input_Control,
108
    Left_AUX1_Input_Control,
109
    Right_AUX1_Input_Control,
110
    Left_AUX2_Input_Control,
111
    Right_AUX2_Input_Control,
112
    Left_DAC_Output_Control,
113
    Right_DAC_Output_Control,
114
    FS_And_Playback_Data_Format,
115
    Interface_Configuration,
116
    Pin_Control,
117
    Error_Status_And_Initialization,
118
    MODE_And_ID,
119
    Loopback_Control,
120
    Playback_Upper_Base_Count,
121
    Playback_Lower_Base_Count,
122
    Alternate_Feature_Enable_I,
123
    Alternate_Feature_Enable_II,
124
    Left_Line_Input_Control,
125
    Right_Line_Input_Control,
126
    Timer_Low_Base,
127
    Timer_High_Base,
128
    RESERVED,
129
    Alternate_Feature_Enable_III,
130
    Alternate_Feature_Status,
131
    Version_Chip_ID,
132
    Mono_Input_And_Output_Control,
133
    RESERVED_2,
134
    Capture_Data_Format,
135
    RESERVED_3,
136
    Capture_Upper_Base_Count,
137
    Capture_Lower_Base_Count
138
};
139

    
140
static int freqs[2][8] = {
141
    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
142
    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
143
};
144

    
145
/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
146
static int16_t MuLawDecompressTable[256] =
147
{
148
     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
149
     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
150
     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
151
     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
152
      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
153
      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
154
      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
155
      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
156
      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
157
      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
158
       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
159
       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
160
       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
161
       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
162
       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
163
        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
164
      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
165
      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
166
      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
167
      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
168
       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
169
       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
170
       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
171
       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
172
       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
173
       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
174
        876,   844,   812,   780,   748,   716,   684,   652,
175
        620,   588,   556,   524,   492,   460,   428,   396,
176
        372,   356,   340,   324,   308,   292,   276,   260,
177
        244,   228,   212,   196,   180,   164,   148,   132,
178
        120,   112,   104,    96,    88,    80,    72,    64,
179
         56,    48,    40,    32,    24,    16,     8,     0
180
};
181

    
182
static int16_t ALawDecompressTable[256] =
183
{
184
     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
185
     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
186
     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
187
     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
188
     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
189
     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
190
     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
191
     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
192
     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
193
     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
194
     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
195
     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
196
     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
197
     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
198
     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
199
     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
200
      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
201
      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
202
      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
203
      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
204
      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
205
      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
206
      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
207
      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
208
      344,   328,   376,   360,   280,   264,   312,   296,
209
      472,   456,   504,   488,   408,   392,   440,   424,
210
      88,    72,   120,   104,    24,     8,    56,    40,
211
      216,   200,   248,   232,   152,   136,   184,   168,
212
      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
213
      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
214
      688,   656,   752,   720,   560,   528,   624,   592,
215
      944,   912,  1008,   976,   816,   784,   880,   848
216
};
217

    
218
static void cs_reset (void *opaque)
219
{
220
    CSState *s = opaque;
221

    
222
    s->regs[Index_Address] = 0x40;
223
    s->regs[Index_Data]    = 0x00;
224
    s->regs[Status]        = 0x00;
225
    s->regs[PIO_Data]      = 0x00;
226

    
227
    s->dregs[Left_ADC_Input_Control]          = 0x00;
228
    s->dregs[Right_ADC_Input_Control]         = 0x00;
229
    s->dregs[Left_AUX1_Input_Control]         = 0x88;
230
    s->dregs[Right_AUX1_Input_Control]        = 0x88;
231
    s->dregs[Left_AUX2_Input_Control]         = 0x88;
232
    s->dregs[Right_AUX2_Input_Control]        = 0x88;
233
    s->dregs[Left_DAC_Output_Control]         = 0x80;
234
    s->dregs[Right_DAC_Output_Control]        = 0x80;
235
    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
236
    s->dregs[Interface_Configuration]         = 0x08;
237
    s->dregs[Pin_Control]                     = 0x00;
238
    s->dregs[Error_Status_And_Initialization] = 0x00;
239
    s->dregs[MODE_And_ID]                     = 0x8a;
240
    s->dregs[Loopback_Control]                = 0x00;
241
    s->dregs[Playback_Upper_Base_Count]       = 0x00;
242
    s->dregs[Playback_Lower_Base_Count]       = 0x00;
243
    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
244
    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
245
    s->dregs[Left_Line_Input_Control]         = 0x88;
246
    s->dregs[Right_Line_Input_Control]        = 0x88;
247
    s->dregs[Timer_Low_Base]                  = 0x00;
248
    s->dregs[Timer_High_Base]                 = 0x00;
249
    s->dregs[RESERVED]                        = 0x00;
250
    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
251
    s->dregs[Alternate_Feature_Status]        = 0x00;
252
    s->dregs[Version_Chip_ID]                 = 0xa0;
253
    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
254
    s->dregs[RESERVED_2]                      = 0x00;
255
    s->dregs[Capture_Data_Format]             = 0x00;
256
    s->dregs[RESERVED_3]                      = 0x00;
257
    s->dregs[Capture_Upper_Base_Count]        = 0x00;
258
    s->dregs[Capture_Lower_Base_Count]        = 0x00;
259
}
260

    
261
static void cs_audio_callback (void *opaque, int free)
262
{
263
    CSState *s = opaque;
264
    s->audio_free = free;
265
}
266

    
267
static void cs_reset_voices (CSState *s, uint32_t val)
268
{
269
    int xtal;
270
    struct audsettings as;
271

    
272
#ifdef DEBUG_XLAW
273
    if (val == 0 || val == 32)
274
        val = (1 << 4) | (1 << 5);
275
#endif
276

    
277
    xtal = val & 1;
278
    as.freq = freqs[xtal][(val >> 1) & 7];
279

    
280
    if (as.freq == -1) {
281
        lerr ("unsupported frequency (val=%#x)\n", val);
282
        goto error;
283
    }
284

    
285
    as.nchannels = (val & (1 << 4)) ? 2 : 1;
286
    as.endianness = 0;
287
    s->tab = NULL;
288

    
289
    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
290
    case 0:
291
        as.fmt = AUD_FMT_U8;
292
        s->shift = as.nchannels == 2;
293
        break;
294

    
295
    case 1:
296
        s->tab = MuLawDecompressTable;
297
        goto x_law;
298
    case 3:
299
        s->tab = ALawDecompressTable;
300
    x_law:
301
        as.fmt = AUD_FMT_S16;
302
        as.endianness = AUDIO_HOST_ENDIANNESS;
303
        s->shift = as.nchannels == 2;
304
        break;
305

    
306
    case 6:
307
        as.endianness = 1;
308
    case 2:
309
        as.fmt = AUD_FMT_S16;
310
        s->shift = as.nchannels;
311
        break;
312

    
313
    case 7:
314
    case 4:
315
        lerr ("attempt to use reserved format value (%#x)\n", val);
316
        goto error;
317

    
318
    case 5:
319
        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
320
        goto error;
321
    }
322

    
323
    s->voice = AUD_open_out (
324
        &s->card,
325
        s->voice,
326
        "cs4231a",
327
        s,
328
        cs_audio_callback,
329
        &as
330
        );
331

    
332
    if (s->dregs[Interface_Configuration] & PEN) {
333
        if (!s->dma_running) {
334
            DMA_hold_DREQ (s->dma);
335
            AUD_set_active_out (s->voice, 1);
336
            s->transferred = 0;
337
        }
338
        s->dma_running = 1;
339
    }
340
    else {
341
        if (s->dma_running) {
342
            DMA_release_DREQ (s->dma);
343
            AUD_set_active_out (s->voice, 0);
344
        }
345
        s->dma_running = 0;
346
    }
347
    return;
348

    
349
 error:
350
    if (s->dma_running) {
351
        DMA_release_DREQ (s->dma);
352
        AUD_set_active_out (s->voice, 0);
353
    }
354
}
355

    
356
IO_READ_PROTO (cs_read)
357
{
358
    CSState *s = opaque;
359
    uint32_t saddr, iaddr, ret;
360

    
361
    saddr = GET_SADDR (addr);
362
    iaddr = ~0U;
363

    
364
    switch (saddr) {
365
    case Index_Address:
366
        ret = s->regs[saddr] & ~0x80;
367
        break;
368

    
369
    case Index_Data:
370
        if (!(s->dregs[MODE_And_ID] & MODE2))
371
            iaddr = s->regs[Index_Address] & 0x0f;
372
        else
373
            iaddr = s->regs[Index_Address] & 0x1f;
374

    
375
        ret = s->dregs[iaddr];
376
        if (iaddr == Error_Status_And_Initialization) {
377
            /* keep SEAL happy */
378
            if (s->aci_counter) {
379
                ret |= 1 << 5;
380
                s->aci_counter -= 1;
381
            }
382
        }
383
        break;
384

    
385
    default:
386
        ret = s->regs[saddr];
387
        break;
388
    }
389
    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
390
    return ret;
391
}
392

    
393
IO_WRITE_PROTO (cs_write)
394
{
395
    CSState *s = opaque;
396
    uint32_t saddr, iaddr;
397

    
398
    saddr = GET_SADDR (addr);
399

    
400
    switch (saddr) {
401
    case Index_Address:
402
        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
403
            && (s->dregs[Interface_Configuration] & (3 << 3)))
404
            s->aci_counter = conf.aci_counter;
405

    
406
        s->regs[Index_Address] = val & ~(1 << 7);
407
        break;
408

    
409
    case Index_Data:
410
        if (!(s->dregs[MODE_And_ID] & MODE2))
411
            iaddr = s->regs[Index_Address] & 0x0f;
412
        else
413
            iaddr = s->regs[Index_Address] & 0x1f;
414

    
415
        switch (iaddr) {
416
        case RESERVED:
417
        case RESERVED_2:
418
        case RESERVED_3:
419
            lwarn ("attempt to write %#x to reserved indirect register %d\n",
420
                   val, iaddr);
421
            break;
422

    
423
        case FS_And_Playback_Data_Format:
424
            if (s->regs[Index_Address] & MCE) {
425
                cs_reset_voices (s, val);
426
            }
427
            else {
428
                if (s->dregs[Alternate_Feature_Status] & PMCE) {
429
                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
430
                    cs_reset_voices (s, val);
431
                }
432
                else {
433
                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
434
                           s->regs[Index_Address],
435
                           s->dregs[Alternate_Feature_Status],
436
                           val);
437
                    break;
438
                }
439
            }
440
            s->dregs[iaddr] = val;
441
            break;
442

    
443
        case Interface_Configuration:
444
            val &= ~(1 << 5);   /* D5 is reserved */
445
            s->dregs[iaddr] = val;
446
            if (val & PPIO) {
447
                lwarn ("PIO is not supported (%#x)\n", val);
448
                break;
449
            }
450
            if (val & PEN) {
451
                if (!s->dma_running) {
452
                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
453
                }
454
            }
455
            else {
456
                if (s->dma_running) {
457
                    DMA_release_DREQ (s->dma);
458
                    AUD_set_active_out (s->voice, 0);
459
                    s->dma_running = 0;
460
                }
461
            }
462
            break;
463

    
464
        case Error_Status_And_Initialization:
465
            lwarn ("attempt to write to read only register %d\n", iaddr);
466
            break;
467

    
468
        case MODE_And_ID:
469
            dolog ("val=%#x\n", val);
470
            if (val & MODE2)
471
                s->dregs[iaddr] |= MODE2;
472
            else
473
                s->dregs[iaddr] &= ~MODE2;
474
            break;
475

    
476
        case Alternate_Feature_Enable_I:
477
            if (val & TE)
478
                lerr ("timer is not yet supported\n");
479
            s->dregs[iaddr] = val;
480
            break;
481

    
482
        case Alternate_Feature_Status:
483
            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
484
                /* XXX: TI CI */
485
                qemu_irq_lower (s->pic);
486
                s->regs[Status] &= ~INT;
487
            }
488
            s->dregs[iaddr] = val;
489
            break;
490

    
491
        case Version_Chip_ID:
492
            lwarn ("write to Version_Chip_ID register %#x\n", val);
493
            s->dregs[iaddr] = val;
494
            break;
495

    
496
        default:
497
            s->dregs[iaddr] = val;
498
            break;
499
        }
500
        dolog ("written value %#x to indirect register %d\n", val, iaddr);
501
        break;
502

    
503
    case Status:
504
        if (s->regs[Status] & INT) {
505
            qemu_irq_lower (s->pic);
506
        }
507
        s->regs[Status] &= ~INT;
508
        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
509
        break;
510

    
511
    case PIO_Data:
512
        lwarn ("attempt to write value %#x to PIO register\n", val);
513
        break;
514
    }
515
}
516

    
517
static int cs_write_audio (CSState *s, int nchan, int dma_pos,
518
                           int dma_len, int len)
519
{
520
    int temp, net;
521
    uint8_t tmpbuf[4096];
522

    
523
    temp = len;
524
    net = 0;
525

    
526
    while (temp) {
527
        int left = dma_len - dma_pos;
528
        int copied;
529
        size_t to_copy;
530

    
531
        to_copy = audio_MIN (temp, left);
532
        if (to_copy > sizeof (tmpbuf)) {
533
            to_copy = sizeof (tmpbuf);
534
        }
535

    
536
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
537
        if (s->tab) {
538
            int i;
539
            int16_t linbuf[4096];
540

    
541
            for (i = 0; i < copied; ++i)
542
                linbuf[i] = s->tab[tmpbuf[i]];
543
            copied = AUD_write (s->voice, linbuf, copied << 1);
544
            copied >>= 1;
545
        }
546
        else {
547
            copied = AUD_write (s->voice, tmpbuf, copied);
548
        }
549

    
550
        temp -= copied;
551
        dma_pos = (dma_pos + copied) % dma_len;
552
        net += copied;
553

    
554
        if (!copied) {
555
            break;
556
        }
557
    }
558

    
559
    return net;
560
}
561

    
562
static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
563
{
564
    CSState *s = opaque;
565
    int copy, written;
566
    int till = -1;
567

    
568
    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
569

    
570
    if (s->dregs[Pin_Control] & IEN) {
571
        till = (s->dregs[Playback_Lower_Base_Count]
572
            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
573
        till -= s->transferred;
574
        copy = audio_MIN (till, copy);
575
    }
576

    
577
    if ((copy <= 0) || (dma_len <= 0)) {
578
        return dma_pos;
579
    }
580

    
581
    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
582

    
583
    dma_pos = (dma_pos + written) % dma_len;
584
    s->audio_free -= (written << (s->tab != NULL));
585

    
586
    if (written == till) {
587
        s->regs[Status] |= INT;
588
        s->dregs[Alternate_Feature_Status] |= PI;
589
        s->transferred = 0;
590
        qemu_irq_raise (s->pic);
591
    }
592
    else {
593
        s->transferred += written;
594
    }
595

    
596
    return dma_pos;
597
}
598

    
599
static void cs_save (QEMUFile *f, void *opaque)
600
{
601
    CSState *s = opaque;
602
    unsigned int i;
603
    uint32_t val;
604

    
605
    for (i = 0; i < CS_REGS; i++)
606
        qemu_put_be32s (f, &s->regs[i]);
607

    
608
    qemu_put_buffer (f, s->dregs, CS_DREGS);
609
    val = s->dma_running; qemu_put_be32s (f, &val);
610
    val = s->audio_free;  qemu_put_be32s (f, &val);
611
    val = s->transferred; qemu_put_be32s (f, &val);
612
    val = s->aci_counter; qemu_put_be32s (f, &val);
613
}
614

    
615
static int cs_load (QEMUFile *f, void *opaque, int version_id)
616
{
617
    CSState *s = opaque;
618
    unsigned int i;
619
    uint32_t val, dma_running;
620

    
621
    if (version_id > 1)
622
        return -EINVAL;
623

    
624
    for (i = 0; i < CS_REGS; i++)
625
        qemu_get_be32s (f, &s->regs[i]);
626

    
627
    qemu_get_buffer (f, s->dregs, CS_DREGS);
628

    
629
    qemu_get_be32s (f, &dma_running);
630
    qemu_get_be32s (f, &val); s->audio_free  = val;
631
    qemu_get_be32s (f, &val); s->transferred = val;
632
    qemu_get_be32s (f, &val); s->aci_counter = val;
633
    if (dma_running && (s->dregs[Interface_Configuration] & PEN))
634
        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
635
    return 0;
636
}
637

    
638
int cs4231a_init (qemu_irq *pic)
639
{
640
    int i;
641
    CSState *s;
642

    
643
    s = qemu_mallocz (sizeof (*s));
644

    
645
    s->pic = isa_reserve_irq(conf.irq);
646
    s->dma = conf.dma;
647
    s->port = conf.port;
648

    
649
    for (i = 0; i < 4; i++) {
650
        register_ioport_write (s->port + i, 1, 1, cs_write, s);
651
        register_ioport_read (s->port + i, 1, 1, cs_read, s);
652
    }
653

    
654
    DMA_register_channel (s->dma, cs_dma_read, s);
655

    
656
    register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
657
    qemu_register_reset (cs_reset, s);
658
    cs_reset (s);
659

    
660
    AUD_register_card ("cs4231a", &s->card);
661
    return 0;
662
}