~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to hw/cs4231a.c

  • Committer: ths
  • Date: 2007-06-17 15:32:30 UTC
  • Revision ID: git-v1:ffb04fcf089865952592f1f8855c2848d4514a89
Allow relative paths for the interpreter prefix in linux-user emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2984 c046a42c-6fe2-441c-8c8c-71466251a162

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 "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
 
    audsettings_t 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
 
    if (!s) {
651
 
        lerr ("Could not allocate memory for cs4231a (%zu bytes)\n",
652
 
               sizeof (*s));
653
 
        return -1;
654
 
    }
655
 
 
656
 
    s->pic = pic;
657
 
    s->irq = conf.irq;
658
 
    s->dma = conf.dma;
659
 
    s->port = conf.port;
660
 
 
661
 
    for (i = 0; i < 4; i++) {
662
 
        register_ioport_write (s->port + i, 1, 1, cs_write, s);
663
 
        register_ioport_read (s->port + i, 1, 1, cs_read, s);
664
 
    }
665
 
 
666
 
    DMA_register_channel (s->dma, cs_dma_read, s);
667
 
 
668
 
    register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
669
 
    qemu_register_reset (cs_reset, s);
670
 
    cs_reset (s);
671
 
 
672
 
    AUD_register_card (audio,"cs4231a", &s->card);
673
 
    return 0;
674
 
}