~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/cs4231a.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "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
    qemu_irq pic;
 
63
    uint32_t regs[CS_REGS];
 
64
    uint8_t dregs[CS_DREGS];
 
65
    uint32_t irq;
 
66
    uint32_t dma;
 
67
    uint32_t 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 int cs4231a_pre_load (void *opaque)
 
600
{
 
601
    CSState *s = opaque;
 
602
 
 
603
    if (s->dma_running) {
 
604
        DMA_release_DREQ (s->dma);
 
605
        AUD_set_active_out (s->voice, 0);
 
606
    }
 
607
    s->dma_running = 0;
 
608
    return 0;
 
609
}
 
610
 
 
611
static int cs4231a_post_load (void *opaque, int version_id)
 
612
{
 
613
    CSState *s = opaque;
 
614
 
 
615
    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
 
616
        s->dma_running = 0;
 
617
        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
 
618
    }
 
619
    return 0;
 
620
}
 
621
 
 
622
static const VMStateDescription vmstate_cs4231a = {
 
623
    .name = "cs4231a",
 
624
    .version_id = 1,
 
625
    .minimum_version_id = 1,
 
626
    .minimum_version_id_old = 1,
 
627
    .pre_load = cs4231a_pre_load,
 
628
    .post_load = cs4231a_post_load,
 
629
    .fields      = (VMStateField []) {
 
630
        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
 
631
        VMSTATE_BUFFER(dregs, CSState),
 
632
        VMSTATE_INT32(dma_running, CSState),
 
633
        VMSTATE_INT32(audio_free, CSState),
 
634
        VMSTATE_INT32(transferred, CSState),
 
635
        VMSTATE_INT32(aci_counter, CSState),
 
636
        VMSTATE_END_OF_LIST()
 
637
    }
 
638
};
 
639
 
 
640
static int cs4231a_initfn (ISADevice *dev)
 
641
{
 
642
    CSState *s = DO_UPCAST (CSState, dev, dev);
 
643
    int i;
 
644
 
 
645
    isa_init_irq (dev, &s->pic, s->irq);
 
646
 
 
647
    for (i = 0; i < 4; i++) {
 
648
        isa_init_ioport(dev, i);
 
649
        register_ioport_write (s->port + i, 1, 1, cs_write, s);
 
650
        register_ioport_read (s->port + i, 1, 1, cs_read, s);
 
651
    }
 
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
int cs4231a_init (qemu_irq *pic)
 
663
{
 
664
    isa_create_simple ("cs4231a");
 
665
    return 0;
 
666
}
 
667
 
 
668
static ISADeviceInfo cs4231a_info = {
 
669
    .qdev.name     = "cs4231a",
 
670
    .qdev.desc     = "Crystal Semiconductor CS4231A",
 
671
    .qdev.size     = sizeof (CSState),
 
672
    .qdev.vmsd     = &vmstate_cs4231a,
 
673
    .init          = cs4231a_initfn,
 
674
    .qdev.props    = (Property[]) {
 
675
        DEFINE_PROP_HEX32  ("iobase",  CSState, port, 0x534),
 
676
        DEFINE_PROP_UINT32 ("irq",     CSState, irq,  9),
 
677
        DEFINE_PROP_UINT32 ("dma",     CSState, dma,  3),
 
678
        DEFINE_PROP_END_OF_LIST (),
 
679
    },
 
680
};
 
681
 
 
682
static void cs4231a_register (void)
 
683
{
 
684
    isa_qdev_register (&cs4231a_info);
 
685
}
 
686
device_init (cs4231a_register)