Statistics
| Branch: | Revision:

root / hw / audio / cs4231a.c @ 831aab9b

History | View | Annotate | Download (20.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/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
#define TYPE_CS4231A "cs4231a"
60
#define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
61

    
62
typedef struct CSState {
63
    ISADevice dev;
64
    QEMUSoundCard card;
65
    MemoryRegion ioports;
66
    qemu_irq pic;
67
    uint32_t regs[CS_REGS];
68
    uint8_t dregs[CS_DREGS];
69
    uint32_t irq;
70
    uint32_t dma;
71
    uint32_t port;
72
    int shift;
73
    int dma_running;
74
    int audio_free;
75
    int transferred;
76
    int aci_counter;
77
    SWVoiceOut *voice;
78
    int16_t *tab;
79
} CSState;
80

    
81
#define MODE2 (1 << 6)
82
#define MCE (1 << 6)
83
#define PMCE (1 << 4)
84
#define CMCE (1 << 5)
85
#define TE (1 << 6)
86
#define PEN (1 << 0)
87
#define INT (1 << 0)
88
#define IEN (1 << 1)
89
#define PPIO (1 << 6)
90
#define PI (1 << 4)
91
#define CI (1 << 5)
92
#define TI (1 << 6)
93

    
94
enum {
95
    Index_Address,
96
    Index_Data,
97
    Status,
98
    PIO_Data
99
};
100

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

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

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

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

    
214
static void cs4231a_reset (DeviceState *dev)
215
{
216
    CSState *s = CS4231A (dev);
217

    
218
    s->regs[Index_Address] = 0x40;
219
    s->regs[Index_Data]    = 0x00;
220
    s->regs[Status]        = 0x00;
221
    s->regs[PIO_Data]      = 0x00;
222

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

    
257
static void cs_audio_callback (void *opaque, int free)
258
{
259
    CSState *s = opaque;
260
    s->audio_free = free;
261
}
262

    
263
static void cs_reset_voices (CSState *s, uint32_t val)
264
{
265
    int xtal;
266
    struct audsettings as;
267

    
268
#ifdef DEBUG_XLAW
269
    if (val == 0 || val == 32)
270
        val = (1 << 4) | (1 << 5);
271
#endif
272

    
273
    xtal = val & 1;
274
    as.freq = freqs[xtal][(val >> 1) & 7];
275

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

    
281
    as.nchannels = (val & (1 << 4)) ? 2 : 1;
282
    as.endianness = 0;
283
    s->tab = NULL;
284

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

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

    
302
    case 6:
303
        as.endianness = 1;
304
    case 2:
305
        as.fmt = AUD_FMT_S16;
306
        s->shift = as.nchannels;
307
        break;
308

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

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

    
319
    s->voice = AUD_open_out (
320
        &s->card,
321
        s->voice,
322
        "cs4231a",
323
        s,
324
        cs_audio_callback,
325
        &as
326
        );
327

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

    
345
 error:
346
    if (s->dma_running) {
347
        DMA_release_DREQ (s->dma);
348
        AUD_set_active_out (s->voice, 0);
349
    }
350
}
351

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

    
357
    saddr = addr;
358
    iaddr = ~0U;
359

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

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

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

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

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

    
395
    saddr = addr;
396
    val = val64;
397

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
521
    temp = len;
522
    net = 0;
523

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

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

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

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

    
548
        temp -= copied;
549
        dma_pos = (dma_pos + copied) % dma_len;
550
        net += copied;
551

    
552
        if (!copied) {
553
            break;
554
        }
555
    }
556

    
557
    return net;
558
}
559

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

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

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

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

    
579
    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
580

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

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

    
594
    return dma_pos;
595
}
596

    
597
static int cs4231a_pre_load (void *opaque)
598
{
599
    CSState *s = opaque;
600

    
601
    if (s->dma_running) {
602
        DMA_release_DREQ (s->dma);
603
        AUD_set_active_out (s->voice, 0);
604
    }
605
    s->dma_running = 0;
606
    return 0;
607
}
608

    
609
static int cs4231a_post_load (void *opaque, int version_id)
610
{
611
    CSState *s = opaque;
612

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

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

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

    
647
static void cs4231a_initfn (Object *obj)
648
{
649
    CSState *s = CS4231A (obj);
650

    
651
    memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
652
                           "cs4231a", 4);
653
}
654

    
655
static void cs4231a_realizefn (DeviceState *dev, Error **errp)
656
{
657
    ISADevice *d = ISA_DEVICE (dev);
658
    CSState *s = CS4231A (dev);
659

    
660
    isa_init_irq (d, &s->pic, s->irq);
661

    
662
    isa_register_ioport (d, &s->ioports, s->port);
663

    
664
    DMA_register_channel (s->dma, cs_dma_read, s);
665

    
666
    AUD_register_card ("cs4231a", &s->card);
667
}
668

    
669
static int cs4231a_init (ISABus *bus)
670
{
671
    isa_create_simple (bus, TYPE_CS4231A);
672
    return 0;
673
}
674

    
675
static Property cs4231a_properties[] = {
676
    DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
677
    DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
678
    DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
679
    DEFINE_PROP_END_OF_LIST (),
680
};
681

    
682
static void cs4231a_class_initfn (ObjectClass *klass, void *data)
683
{
684
    DeviceClass *dc = DEVICE_CLASS (klass);
685

    
686
    dc->realize = cs4231a_realizefn;
687
    dc->reset = cs4231a_reset;
688
    set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
689
    dc->desc = "Crystal Semiconductor CS4231A";
690
    dc->vmsd = &vmstate_cs4231a;
691
    dc->props = cs4231a_properties;
692
}
693

    
694
static const TypeInfo cs4231a_info = {
695
    .name          = TYPE_CS4231A,
696
    .parent        = TYPE_ISA_DEVICE,
697
    .instance_size = sizeof (CSState),
698
    .instance_init = cs4231a_initfn,
699
    .class_init    = cs4231a_class_initfn,
700
};
701

    
702
static void cs4231a_register_types (void)
703
{
704
    type_register_static (&cs4231a_info);
705
    isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
706
}
707

    
708
type_init (cs4231a_register_types)