Statistics
| Branch: | Revision:

root / hw / cs4231a.c @ 487414f1

History | View | Annotate | Download (19.6 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 irq;
67
    int dma;
68
    int port;
69
    int shift;
70
    int dma_running;
71
    int audio_free;
72
    int transferred;
73
    int aci_counter;
74
    SWVoiceOut *voice;
75
    int16_t *tab;
76
} CSState;
77

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
307
    case 6:
308
        as.endianness = 1;
309
    case 2:
310
        as.fmt = AUD_FMT_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
            DMA_hold_DREQ (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
            DMA_release_DREQ (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
        DMA_release_DREQ (s->dma);
353
        AUD_set_active_out (s->voice, 0);
354
    }
355
}
356

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

    
362
    saddr = GET_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

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

    
399
    saddr = GET_SADDR (addr);
400

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
524
    temp = len;
525
    net = 0;
526

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

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

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

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

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

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

    
560
    return net;
561
}
562

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

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

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

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

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

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

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

    
597
    return dma_pos;
598
}
599

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

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

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

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

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

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

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

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

    
639
int cs4231a_init (AudioState *audio, qemu_irq *pic)
640
{
641
    int i;
642
    CSState *s;
643

    
644
    if (!audio) {
645
        lerr ("No audio state\n");
646
        return -1;
647
    }
648

    
649
    s = qemu_mallocz (sizeof (*s));
650

    
651
    s->pic = pic;
652
    s->irq = conf.irq;
653
    s->dma = conf.dma;
654
    s->port = conf.port;
655

    
656
    for (i = 0; i < 4; i++) {
657
        register_ioport_write (s->port + i, 1, 1, cs_write, s);
658
        register_ioport_read (s->port + i, 1, 1, cs_read, s);
659
    }
660

    
661
    DMA_register_channel (s->dma, cs_dma_read, s);
662

    
663
    register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
664
    qemu_register_reset (cs_reset, s);
665
    cs_reset (s);
666

    
667
    AUD_register_card (audio,"cs4231a", &s->card);
668
    return 0;
669
}