Statistics
| Branch: | Revision:

root / hw / audio / cs4231a.c @ 36cd6f6f

History | View | Annotate | Download (20.3 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/hw.h"
25
#include "hw/audio/audio.h"
26
#include "audio/audio.h"
27
#include "hw/isa/isa.h"
28
#include "hw/qdev.h"
29
#include "qemu/timer.h"
30

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

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

    
43
static struct {
44
    int aci_counter;
45
} conf = {1};
46

    
47
#ifdef DEBUG
48
#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
49
#else
50
#define dolog(...)
51
#endif
52

    
53
#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
54
#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
55

    
56
#define CS_REGS 16
57
#define CS_DREGS 32
58

    
59
typedef struct CSState {
60
    ISADevice dev;
61
    QEMUSoundCard card;
62
    MemoryRegion ioports;
63
    qemu_irq pic;
64
    uint32_t regs[CS_REGS];
65
    uint8_t dregs[CS_DREGS];
66
    uint32_t irq;
67
    uint32_t dma;
68
    uint32_t 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 MODE2 (1 << 6)
79
#define MCE (1 << 6)
80
#define PMCE (1 << 4)
81
#define CMCE (1 << 5)
82
#define TE (1 << 6)
83
#define PEN (1 << 0)
84
#define INT (1 << 0)
85
#define IEN (1 << 1)
86
#define PPIO (1 << 6)
87
#define PI (1 << 4)
88
#define CI (1 << 5)
89
#define TI (1 << 6)
90

    
91
enum {
92
    Index_Address,
93
    Index_Data,
94
    Status,
95
    PIO_Data
96
};
97

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

    
133
static int freqs[2][8] = {
134
    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
135
    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
136
};
137

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

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

    
211
static void cs_reset (void *opaque)
212
{
213
    CSState *s = opaque;
214

    
215
    s->regs[Index_Address] = 0x40;
216
    s->regs[Index_Data]    = 0x00;
217
    s->regs[Status]        = 0x00;
218
    s->regs[PIO_Data]      = 0x00;
219

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

    
254
static void cs_audio_callback (void *opaque, int free)
255
{
256
    CSState *s = opaque;
257
    s->audio_free = free;
258
}
259

    
260
static void cs_reset_voices (CSState *s, uint32_t val)
261
{
262
    int xtal;
263
    struct audsettings as;
264

    
265
#ifdef DEBUG_XLAW
266
    if (val == 0 || val == 32)
267
        val = (1 << 4) | (1 << 5);
268
#endif
269

    
270
    xtal = val & 1;
271
    as.freq = freqs[xtal][(val >> 1) & 7];
272

    
273
    if (as.freq == -1) {
274
        lerr ("unsupported frequency (val=%#x)\n", val);
275
        goto error;
276
    }
277

    
278
    as.nchannels = (val & (1 << 4)) ? 2 : 1;
279
    as.endianness = 0;
280
    s->tab = NULL;
281

    
282
    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
283
    case 0:
284
        as.fmt = AUD_FMT_U8;
285
        s->shift = as.nchannels == 2;
286
        break;
287

    
288
    case 1:
289
        s->tab = MuLawDecompressTable;
290
        goto x_law;
291
    case 3:
292
        s->tab = ALawDecompressTable;
293
    x_law:
294
        as.fmt = AUD_FMT_S16;
295
        as.endianness = AUDIO_HOST_ENDIANNESS;
296
        s->shift = as.nchannels == 2;
297
        break;
298

    
299
    case 6:
300
        as.endianness = 1;
301
    case 2:
302
        as.fmt = AUD_FMT_S16;
303
        s->shift = as.nchannels;
304
        break;
305

    
306
    case 7:
307
    case 4:
308
        lerr ("attempt to use reserved format value (%#x)\n", val);
309
        goto error;
310

    
311
    case 5:
312
        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
313
        goto error;
314
    }
315

    
316
    s->voice = AUD_open_out (
317
        &s->card,
318
        s->voice,
319
        "cs4231a",
320
        s,
321
        cs_audio_callback,
322
        &as
323
        );
324

    
325
    if (s->dregs[Interface_Configuration] & PEN) {
326
        if (!s->dma_running) {
327
            DMA_hold_DREQ (s->dma);
328
            AUD_set_active_out (s->voice, 1);
329
            s->transferred = 0;
330
        }
331
        s->dma_running = 1;
332
    }
333
    else {
334
        if (s->dma_running) {
335
            DMA_release_DREQ (s->dma);
336
            AUD_set_active_out (s->voice, 0);
337
        }
338
        s->dma_running = 0;
339
    }
340
    return;
341

    
342
 error:
343
    if (s->dma_running) {
344
        DMA_release_DREQ (s->dma);
345
        AUD_set_active_out (s->voice, 0);
346
    }
347
}
348

    
349
static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
350
{
351
    CSState *s = opaque;
352
    uint32_t saddr, iaddr, ret;
353

    
354
    saddr = addr;
355
    iaddr = ~0U;
356

    
357
    switch (saddr) {
358
    case Index_Address:
359
        ret = s->regs[saddr] & ~0x80;
360
        break;
361

    
362
    case Index_Data:
363
        if (!(s->dregs[MODE_And_ID] & MODE2))
364
            iaddr = s->regs[Index_Address] & 0x0f;
365
        else
366
            iaddr = s->regs[Index_Address] & 0x1f;
367

    
368
        ret = s->dregs[iaddr];
369
        if (iaddr == Error_Status_And_Initialization) {
370
            /* keep SEAL happy */
371
            if (s->aci_counter) {
372
                ret |= 1 << 5;
373
                s->aci_counter -= 1;
374
            }
375
        }
376
        break;
377

    
378
    default:
379
        ret = s->regs[saddr];
380
        break;
381
    }
382
    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
383
    return ret;
384
}
385

    
386
static void cs_write (void *opaque, hwaddr addr,
387
                      uint64_t val64, unsigned size)
388
{
389
    CSState *s = opaque;
390
    uint32_t saddr, iaddr, val;
391

    
392
    saddr = addr;
393
    val = val64;
394

    
395
    switch (saddr) {
396
    case Index_Address:
397
        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
398
            && (s->dregs[Interface_Configuration] & (3 << 3)))
399
            s->aci_counter = conf.aci_counter;
400

    
401
        s->regs[Index_Address] = val & ~(1 << 7);
402
        break;
403

    
404
    case Index_Data:
405
        if (!(s->dregs[MODE_And_ID] & MODE2))
406
            iaddr = s->regs[Index_Address] & 0x0f;
407
        else
408
            iaddr = s->regs[Index_Address] & 0x1f;
409

    
410
        switch (iaddr) {
411
        case RESERVED:
412
        case RESERVED_2:
413
        case RESERVED_3:
414
            lwarn ("attempt to write %#x to reserved indirect register %d\n",
415
                   val, iaddr);
416
            break;
417

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

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

    
459
        case Error_Status_And_Initialization:
460
            lwarn ("attempt to write to read only register %d\n", iaddr);
461
            break;
462

    
463
        case MODE_And_ID:
464
            dolog ("val=%#x\n", val);
465
            if (val & MODE2)
466
                s->dregs[iaddr] |= MODE2;
467
            else
468
                s->dregs[iaddr] &= ~MODE2;
469
            break;
470

    
471
        case Alternate_Feature_Enable_I:
472
            if (val & TE)
473
                lerr ("timer is not yet supported\n");
474
            s->dregs[iaddr] = val;
475
            break;
476

    
477
        case Alternate_Feature_Status:
478
            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
479
                /* XXX: TI CI */
480
                qemu_irq_lower (s->pic);
481
                s->regs[Status] &= ~INT;
482
            }
483
            s->dregs[iaddr] = val;
484
            break;
485

    
486
        case Version_Chip_ID:
487
            lwarn ("write to Version_Chip_ID register %#x\n", val);
488
            s->dregs[iaddr] = val;
489
            break;
490

    
491
        default:
492
            s->dregs[iaddr] = val;
493
            break;
494
        }
495
        dolog ("written value %#x to indirect register %d\n", val, iaddr);
496
        break;
497

    
498
    case Status:
499
        if (s->regs[Status] & INT) {
500
            qemu_irq_lower (s->pic);
501
        }
502
        s->regs[Status] &= ~INT;
503
        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
504
        break;
505

    
506
    case PIO_Data:
507
        lwarn ("attempt to write value %#x to PIO register\n", val);
508
        break;
509
    }
510
}
511

    
512
static int cs_write_audio (CSState *s, int nchan, int dma_pos,
513
                           int dma_len, int len)
514
{
515
    int temp, net;
516
    uint8_t tmpbuf[4096];
517

    
518
    temp = len;
519
    net = 0;
520

    
521
    while (temp) {
522
        int left = dma_len - dma_pos;
523
        int copied;
524
        size_t to_copy;
525

    
526
        to_copy = audio_MIN (temp, left);
527
        if (to_copy > sizeof (tmpbuf)) {
528
            to_copy = sizeof (tmpbuf);
529
        }
530

    
531
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
532
        if (s->tab) {
533
            int i;
534
            int16_t linbuf[4096];
535

    
536
            for (i = 0; i < copied; ++i)
537
                linbuf[i] = s->tab[tmpbuf[i]];
538
            copied = AUD_write (s->voice, linbuf, copied << 1);
539
            copied >>= 1;
540
        }
541
        else {
542
            copied = AUD_write (s->voice, tmpbuf, copied);
543
        }
544

    
545
        temp -= copied;
546
        dma_pos = (dma_pos + copied) % dma_len;
547
        net += copied;
548

    
549
        if (!copied) {
550
            break;
551
        }
552
    }
553

    
554
    return net;
555
}
556

    
557
static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
558
{
559
    CSState *s = opaque;
560
    int copy, written;
561
    int till = -1;
562

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

    
565
    if (s->dregs[Pin_Control] & IEN) {
566
        till = (s->dregs[Playback_Lower_Base_Count]
567
            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
568
        till -= s->transferred;
569
        copy = audio_MIN (till, copy);
570
    }
571

    
572
    if ((copy <= 0) || (dma_len <= 0)) {
573
        return dma_pos;
574
    }
575

    
576
    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
577

    
578
    dma_pos = (dma_pos + written) % dma_len;
579
    s->audio_free -= (written << (s->tab != NULL));
580

    
581
    if (written == till) {
582
        s->regs[Status] |= INT;
583
        s->dregs[Alternate_Feature_Status] |= PI;
584
        s->transferred = 0;
585
        qemu_irq_raise (s->pic);
586
    }
587
    else {
588
        s->transferred += written;
589
    }
590

    
591
    return dma_pos;
592
}
593

    
594
static int cs4231a_pre_load (void *opaque)
595
{
596
    CSState *s = opaque;
597

    
598
    if (s->dma_running) {
599
        DMA_release_DREQ (s->dma);
600
        AUD_set_active_out (s->voice, 0);
601
    }
602
    s->dma_running = 0;
603
    return 0;
604
}
605

    
606
static int cs4231a_post_load (void *opaque, int version_id)
607
{
608
    CSState *s = opaque;
609

    
610
    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
611
        s->dma_running = 0;
612
        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
613
    }
614
    return 0;
615
}
616

    
617
static const VMStateDescription vmstate_cs4231a = {
618
    .name = "cs4231a",
619
    .version_id = 1,
620
    .minimum_version_id = 1,
621
    .minimum_version_id_old = 1,
622
    .pre_load = cs4231a_pre_load,
623
    .post_load = cs4231a_post_load,
624
    .fields      = (VMStateField []) {
625
        VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
626
        VMSTATE_BUFFER (dregs, CSState),
627
        VMSTATE_INT32 (dma_running, CSState),
628
        VMSTATE_INT32 (audio_free, CSState),
629
        VMSTATE_INT32 (transferred, CSState),
630
        VMSTATE_INT32 (aci_counter, CSState),
631
        VMSTATE_END_OF_LIST ()
632
    }
633
};
634

    
635
static const MemoryRegionOps cs_ioport_ops = {
636
    .read = cs_read,
637
    .write = cs_write,
638
    .impl = {
639
        .min_access_size = 1,
640
        .max_access_size = 1,
641
    }
642
};
643

    
644
static int cs4231a_initfn (ISADevice *dev)
645
{
646
    CSState *s = DO_UPCAST (CSState, dev, dev);
647

    
648
    isa_init_irq (dev, &s->pic, s->irq);
649

    
650
    memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
651
    isa_register_ioport (dev, &s->ioports, s->port);
652

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

    
655
    qemu_register_reset (cs_reset, s);
656
    cs_reset (s);
657

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

    
662
static int cs4231a_init (ISABus *bus)
663
{
664
    isa_create_simple (bus, "cs4231a");
665
    return 0;
666
}
667

    
668
static Property cs4231a_properties[] = {
669
    DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
670
    DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
671
    DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
672
    DEFINE_PROP_END_OF_LIST (),
673
};
674

    
675
static void cs4231a_class_initfn (ObjectClass *klass, void *data)
676
{
677
    DeviceClass *dc = DEVICE_CLASS (klass);
678
    ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
679
    ic->init = cs4231a_initfn;
680
    dc->desc = "Crystal Semiconductor CS4231A";
681
    dc->vmsd = &vmstate_cs4231a;
682
    dc->props = cs4231a_properties;
683
}
684

    
685
static const TypeInfo cs4231a_info = {
686
    .name          = "cs4231a",
687
    .parent        = TYPE_ISA_DEVICE,
688
    .instance_size = sizeof (CSState),
689
    .class_init    = cs4231a_class_initfn,
690
};
691

    
692
static void cs4231a_register_types (void)
693
{
694
    type_register_static (&cs4231a_info);
695
    isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
696
}
697

    
698
type_init (cs4231a_register_types)