Statistics
| Branch: | Revision:

root / hw / cs4231a.c @ 6693665a

History | View | Annotate | Download (19.5 kB)

1 cc53d26d malc
/*
2 cc53d26d malc
 * QEMU Crystal CS4231 audio chip emulation
3 cc53d26d malc
 *
4 cc53d26d malc
 * Copyright (c) 2006 Fabrice Bellard
5 cc53d26d malc
 *
6 cc53d26d malc
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 cc53d26d malc
 * of this software and associated documentation files (the "Software"), to deal
8 cc53d26d malc
 * in the Software without restriction, including without limitation the rights
9 cc53d26d malc
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 cc53d26d malc
 * copies of the Software, and to permit persons to whom the Software is
11 cc53d26d malc
 * furnished to do so, subject to the following conditions:
12 cc53d26d malc
 *
13 cc53d26d malc
 * The above copyright notice and this permission notice shall be included in
14 cc53d26d malc
 * all copies or substantial portions of the Software.
15 cc53d26d malc
 *
16 cc53d26d malc
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 cc53d26d malc
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 cc53d26d malc
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 cc53d26d malc
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 cc53d26d malc
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 cc53d26d malc
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 cc53d26d malc
 * THE SOFTWARE.
23 cc53d26d malc
 */
24 cc53d26d malc
#include "hw.h"
25 cc53d26d malc
#include "audiodev.h"
26 cc53d26d malc
#include "audio/audio.h"
27 cc53d26d malc
#include "isa.h"
28 cc53d26d malc
#include "qemu-timer.h"
29 cc53d26d malc
30 cc53d26d malc
/*
31 cc53d26d malc
  Missing features:
32 cc53d26d malc
  ADC
33 cc53d26d malc
  Loopback
34 cc53d26d malc
  Timer
35 cc53d26d malc
  ADPCM
36 cc53d26d malc
  More...
37 cc53d26d malc
*/
38 cc53d26d malc
39 cc53d26d malc
/* #define DEBUG */
40 77599a1f malc
/* #define DEBUG_XLAW */
41 cc53d26d malc
42 cc53d26d malc
static struct {
43 cc53d26d malc
    int irq;
44 cc53d26d malc
    int dma;
45 cc53d26d malc
    int port;
46 cc53d26d malc
    int aci_counter;
47 cc53d26d malc
} conf = {9, 3, 0x534, 1};
48 cc53d26d malc
49 cc53d26d malc
#ifdef DEBUG
50 cc53d26d malc
#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
51 cc53d26d malc
#else
52 cc53d26d malc
#define dolog(...)
53 cc53d26d malc
#endif
54 cc53d26d malc
55 cc53d26d malc
#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
56 cc53d26d malc
#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
57 cc53d26d malc
58 cc53d26d malc
#define CS_REGS 16
59 cc53d26d malc
#define CS_DREGS 32
60 cc53d26d malc
61 cc53d26d malc
typedef struct CSState {
62 cc53d26d malc
    QEMUSoundCard card;
63 cc53d26d malc
    qemu_irq *pic;
64 cc53d26d malc
    uint32_t regs[CS_REGS];
65 cc53d26d malc
    uint8_t dregs[CS_DREGS];
66 cc53d26d malc
    int irq;
67 cc53d26d malc
    int dma;
68 cc53d26d malc
    int port;
69 cc53d26d malc
    int shift;
70 cc53d26d malc
    int dma_running;
71 cc53d26d malc
    int audio_free;
72 cc53d26d malc
    int transferred;
73 cc53d26d malc
    int aci_counter;
74 cc53d26d malc
    SWVoiceOut *voice;
75 cc53d26d malc
    int16_t *tab;
76 cc53d26d malc
} CSState;
77 cc53d26d malc
78 cc53d26d malc
#define IO_READ_PROTO(name)                             \
79 cc53d26d malc
    static uint32_t name (void *opaque, uint32_t addr)
80 cc53d26d malc
81 cc53d26d malc
#define IO_WRITE_PROTO(name)                                            \
82 cc53d26d malc
    static void name (void *opaque, uint32_t addr, uint32_t val)
83 cc53d26d malc
84 cc53d26d malc
#define GET_SADDR(addr) (addr & 3)
85 cc53d26d malc
86 cc53d26d malc
#define MODE2 (1 << 6)
87 cc53d26d malc
#define MCE (1 << 6)
88 cc53d26d malc
#define PMCE (1 << 4)
89 cc53d26d malc
#define CMCE (1 << 5)
90 cc53d26d malc
#define TE (1 << 6)
91 cc53d26d malc
#define PEN (1 << 0)
92 cc53d26d malc
#define INT (1 << 0)
93 cc53d26d malc
#define IEN (1 << 1)
94 cc53d26d malc
#define PPIO (1 << 6)
95 cc53d26d malc
#define PI (1 << 4)
96 cc53d26d malc
#define CI (1 << 5)
97 cc53d26d malc
#define TI (1 << 6)
98 cc53d26d malc
99 cc53d26d malc
enum {
100 cc53d26d malc
    Index_Address,
101 cc53d26d malc
    Index_Data,
102 cc53d26d malc
    Status,
103 cc53d26d malc
    PIO_Data
104 cc53d26d malc
};
105 cc53d26d malc
106 cc53d26d malc
enum {
107 cc53d26d malc
    Left_ADC_Input_Control,
108 cc53d26d malc
    Right_ADC_Input_Control,
109 cc53d26d malc
    Left_AUX1_Input_Control,
110 cc53d26d malc
    Right_AUX1_Input_Control,
111 cc53d26d malc
    Left_AUX2_Input_Control,
112 cc53d26d malc
    Right_AUX2_Input_Control,
113 cc53d26d malc
    Left_DAC_Output_Control,
114 cc53d26d malc
    Right_DAC_Output_Control,
115 cc53d26d malc
    FS_And_Playback_Data_Format,
116 cc53d26d malc
    Interface_Configuration,
117 cc53d26d malc
    Pin_Control,
118 cc53d26d malc
    Error_Status_And_Initialization,
119 cc53d26d malc
    MODE_And_ID,
120 cc53d26d malc
    Loopback_Control,
121 cc53d26d malc
    Playback_Upper_Base_Count,
122 cc53d26d malc
    Playback_Lower_Base_Count,
123 cc53d26d malc
    Alternate_Feature_Enable_I,
124 cc53d26d malc
    Alternate_Feature_Enable_II,
125 cc53d26d malc
    Left_Line_Input_Control,
126 cc53d26d malc
    Right_Line_Input_Control,
127 cc53d26d malc
    Timer_Low_Base,
128 cc53d26d malc
    Timer_High_Base,
129 cc53d26d malc
    RESERVED,
130 cc53d26d malc
    Alternate_Feature_Enable_III,
131 cc53d26d malc
    Alternate_Feature_Status,
132 cc53d26d malc
    Version_Chip_ID,
133 cc53d26d malc
    Mono_Input_And_Output_Control,
134 cc53d26d malc
    RESERVED_2,
135 cc53d26d malc
    Capture_Data_Format,
136 cc53d26d malc
    RESERVED_3,
137 cc53d26d malc
    Capture_Upper_Base_Count,
138 cc53d26d malc
    Capture_Lower_Base_Count
139 cc53d26d malc
};
140 cc53d26d malc
141 cc53d26d malc
static int freqs[2][8] = {
142 cc53d26d malc
    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
143 cc53d26d malc
    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
144 cc53d26d malc
};
145 cc53d26d malc
146 cc53d26d malc
/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
147 cc53d26d malc
static int16_t MuLawDecompressTable[256] =
148 cc53d26d malc
{
149 cc53d26d malc
     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
150 cc53d26d malc
     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
151 cc53d26d malc
     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
152 cc53d26d malc
     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
153 cc53d26d malc
      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
154 cc53d26d malc
      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
155 cc53d26d malc
      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
156 cc53d26d malc
      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
157 cc53d26d malc
      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
158 cc53d26d malc
      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
159 cc53d26d malc
       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
160 cc53d26d malc
       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
161 cc53d26d malc
       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
162 cc53d26d malc
       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
163 cc53d26d malc
       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
164 cc53d26d malc
        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
165 cc53d26d malc
      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
166 cc53d26d malc
      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
167 cc53d26d malc
      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
168 cc53d26d malc
      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
169 cc53d26d malc
       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
170 cc53d26d malc
       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
171 cc53d26d malc
       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
172 cc53d26d malc
       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
173 cc53d26d malc
       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
174 cc53d26d malc
       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
175 cc53d26d malc
        876,   844,   812,   780,   748,   716,   684,   652,
176 cc53d26d malc
        620,   588,   556,   524,   492,   460,   428,   396,
177 cc53d26d malc
        372,   356,   340,   324,   308,   292,   276,   260,
178 cc53d26d malc
        244,   228,   212,   196,   180,   164,   148,   132,
179 cc53d26d malc
        120,   112,   104,    96,    88,    80,    72,    64,
180 cc53d26d malc
         56,    48,    40,    32,    24,    16,     8,     0
181 cc53d26d malc
};
182 cc53d26d malc
183 cc53d26d malc
static int16_t ALawDecompressTable[256] =
184 cc53d26d malc
{
185 cc53d26d malc
     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
186 cc53d26d malc
     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
187 cc53d26d malc
     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
188 cc53d26d malc
     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
189 cc53d26d malc
     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
190 cc53d26d malc
     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
191 cc53d26d malc
     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
192 cc53d26d malc
     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
193 cc53d26d malc
     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
194 cc53d26d malc
     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
195 cc53d26d malc
     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
196 cc53d26d malc
     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
197 cc53d26d malc
     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
198 cc53d26d malc
     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
199 cc53d26d malc
     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
200 cc53d26d malc
     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
201 cc53d26d malc
      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
202 cc53d26d malc
      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
203 cc53d26d malc
      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
204 cc53d26d malc
      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
205 cc53d26d malc
      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
206 cc53d26d malc
      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
207 cc53d26d malc
      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
208 cc53d26d malc
      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
209 cc53d26d malc
      344,   328,   376,   360,   280,   264,   312,   296,
210 cc53d26d malc
      472,   456,   504,   488,   408,   392,   440,   424,
211 cc53d26d malc
      88,    72,   120,   104,    24,     8,    56,    40,
212 cc53d26d malc
      216,   200,   248,   232,   152,   136,   184,   168,
213 cc53d26d malc
      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
214 cc53d26d malc
      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
215 cc53d26d malc
      688,   656,   752,   720,   560,   528,   624,   592,
216 cc53d26d malc
      944,   912,  1008,   976,   816,   784,   880,   848
217 cc53d26d malc
};
218 cc53d26d malc
219 cc53d26d malc
static void cs_reset(void *opaque)
220 cc53d26d malc
{
221 cc53d26d malc
    CSState *s = opaque;
222 cc53d26d malc
223 cc53d26d malc
    s->regs[Index_Address] = 0x40;
224 cc53d26d malc
    s->regs[Index_Data]    = 0x00;
225 cc53d26d malc
    s->regs[Status]        = 0x00;
226 cc53d26d malc
    s->regs[PIO_Data]      = 0x00;
227 cc53d26d malc
228 cc53d26d malc
    s->dregs[Left_ADC_Input_Control]          = 0x00;
229 cc53d26d malc
    s->dregs[Right_ADC_Input_Control]         = 0x00;
230 cc53d26d malc
    s->dregs[Left_AUX1_Input_Control]         = 0x88;
231 cc53d26d malc
    s->dregs[Right_AUX1_Input_Control]        = 0x88;
232 cc53d26d malc
    s->dregs[Left_AUX2_Input_Control]         = 0x88;
233 cc53d26d malc
    s->dregs[Right_AUX2_Input_Control]        = 0x88;
234 cc53d26d malc
    s->dregs[Left_DAC_Output_Control]         = 0x80;
235 cc53d26d malc
    s->dregs[Right_DAC_Output_Control]        = 0x80;
236 cc53d26d malc
    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
237 cc53d26d malc
    s->dregs[Interface_Configuration]         = 0x08;
238 cc53d26d malc
    s->dregs[Pin_Control]                     = 0x00;
239 cc53d26d malc
    s->dregs[Error_Status_And_Initialization] = 0x00;
240 cc53d26d malc
    s->dregs[MODE_And_ID]                     = 0x8a;
241 cc53d26d malc
    s->dregs[Loopback_Control]                = 0x00;
242 cc53d26d malc
    s->dregs[Playback_Upper_Base_Count]       = 0x00;
243 cc53d26d malc
    s->dregs[Playback_Lower_Base_Count]       = 0x00;
244 cc53d26d malc
    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
245 cc53d26d malc
    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
246 cc53d26d malc
    s->dregs[Left_Line_Input_Control]         = 0x88;
247 cc53d26d malc
    s->dregs[Right_Line_Input_Control]        = 0x88;
248 cc53d26d malc
    s->dregs[Timer_Low_Base]                  = 0x00;
249 cc53d26d malc
    s->dregs[Timer_High_Base]                 = 0x00;
250 cc53d26d malc
    s->dregs[RESERVED]                        = 0x00;
251 cc53d26d malc
    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
252 cc53d26d malc
    s->dregs[Alternate_Feature_Status]        = 0x00;
253 cc53d26d malc
    s->dregs[Version_Chip_ID]                 = 0xa0;
254 cc53d26d malc
    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
255 cc53d26d malc
    s->dregs[RESERVED_2]                      = 0x00;
256 cc53d26d malc
    s->dregs[Capture_Data_Format]             = 0x00;
257 cc53d26d malc
    s->dregs[RESERVED_3]                      = 0x00;
258 cc53d26d malc
    s->dregs[Capture_Upper_Base_Count]        = 0x00;
259 cc53d26d malc
    s->dregs[Capture_Lower_Base_Count]        = 0x00;
260 cc53d26d malc
}
261 cc53d26d malc
262 cc53d26d malc
static void cs_audio_callback (void *opaque, int free)
263 cc53d26d malc
{
264 cc53d26d malc
    CSState *s = opaque;
265 cc53d26d malc
    s->audio_free = free;
266 cc53d26d malc
}
267 cc53d26d malc
268 cc53d26d malc
static void cs_reset_voices (CSState *s, uint32_t val)
269 cc53d26d malc
{
270 cc53d26d malc
    int xtal;
271 1ea879e5 malc
    struct audsettings as;
272 cc53d26d malc
273 cc53d26d malc
#ifdef DEBUG_XLAW
274 cc53d26d malc
    if (val == 0 || val == 32)
275 cc53d26d malc
        val = (1 << 4) | (1 << 5);
276 cc53d26d malc
#endif
277 cc53d26d malc
278 cc53d26d malc
    xtal = val & 1;
279 cc53d26d malc
    as.freq = freqs[xtal][(val >> 1) & 7];
280 cc53d26d malc
281 cc53d26d malc
    if (as.freq == -1) {
282 cc53d26d malc
        lerr ("unsupported frequency (val=%#x)\n", val);
283 cc53d26d malc
        goto error;
284 cc53d26d malc
    }
285 cc53d26d malc
286 cc53d26d malc
    as.nchannels = (val & (1 << 4)) ? 2 : 1;
287 cc53d26d malc
    as.endianness = 0;
288 cc53d26d malc
    s->tab = NULL;
289 cc53d26d malc
290 cc53d26d malc
    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
291 cc53d26d malc
    case 0:
292 cc53d26d malc
        as.fmt = AUD_FMT_U8;
293 cc53d26d malc
        s->shift = as.nchannels == 2;
294 cc53d26d malc
        break;
295 cc53d26d malc
296 cc53d26d malc
    case 1:
297 cc53d26d malc
        s->tab = MuLawDecompressTable;
298 cc53d26d malc
        goto x_law;
299 cc53d26d malc
    case 3:
300 cc53d26d malc
        s->tab = ALawDecompressTable;
301 cc53d26d malc
    x_law:
302 cc53d26d malc
        as.fmt = AUD_FMT_S16;
303 cc53d26d malc
        as.endianness = AUDIO_HOST_ENDIANNESS;
304 cc53d26d malc
        s->shift = as.nchannels == 2;
305 cc53d26d malc
        break;
306 cc53d26d malc
307 cc53d26d malc
    case 6:
308 cc53d26d malc
        as.endianness = 1;
309 cc53d26d malc
    case 2:
310 cc53d26d malc
        as.fmt = AUD_FMT_S16;
311 cc53d26d malc
        s->shift = as.nchannels;
312 cc53d26d malc
        break;
313 cc53d26d malc
314 cc53d26d malc
    case 7:
315 cc53d26d malc
    case 4:
316 cc53d26d malc
        lerr ("attempt to use reserved format value (%#x)\n", val);
317 cc53d26d malc
        goto error;
318 cc53d26d malc
319 cc53d26d malc
    case 5:
320 cc53d26d malc
        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
321 cc53d26d malc
        goto error;
322 cc53d26d malc
    }
323 cc53d26d malc
324 cc53d26d malc
    s->voice = AUD_open_out (
325 cc53d26d malc
        &s->card,
326 cc53d26d malc
        s->voice,
327 cc53d26d malc
        "cs4231a",
328 cc53d26d malc
        s,
329 cc53d26d malc
        cs_audio_callback,
330 cc53d26d malc
        &as
331 cc53d26d malc
        );
332 cc53d26d malc
333 cc53d26d malc
    if (s->dregs[Interface_Configuration] & PEN) {
334 cc53d26d malc
        if (!s->dma_running) {
335 cc53d26d malc
            DMA_hold_DREQ (s->dma);
336 cc53d26d malc
            AUD_set_active_out (s->voice, 1);
337 cc53d26d malc
            s->transferred = 0;
338 cc53d26d malc
        }
339 cc53d26d malc
        s->dma_running = 1;
340 cc53d26d malc
    }
341 cc53d26d malc
    else {
342 cc53d26d malc
        if (s->dma_running) {
343 cc53d26d malc
            DMA_release_DREQ (s->dma);
344 cc53d26d malc
            AUD_set_active_out (s->voice, 0);
345 cc53d26d malc
        }
346 cc53d26d malc
        s->dma_running = 0;
347 cc53d26d malc
    }
348 cc53d26d malc
    return;
349 cc53d26d malc
350 cc53d26d malc
 error:
351 cc53d26d malc
    if (s->dma_running) {
352 cc53d26d malc
        DMA_release_DREQ (s->dma);
353 cc53d26d malc
        AUD_set_active_out (s->voice, 0);
354 cc53d26d malc
    }
355 cc53d26d malc
}
356 cc53d26d malc
357 cc53d26d malc
IO_READ_PROTO (cs_read)
358 cc53d26d malc
{
359 cc53d26d malc
    CSState *s = opaque;
360 cc53d26d malc
    uint32_t saddr, iaddr, ret;
361 cc53d26d malc
362 cc53d26d malc
    saddr = GET_SADDR (addr);
363 cc53d26d malc
    iaddr = ~0U;
364 cc53d26d malc
365 cc53d26d malc
    switch (saddr) {
366 cc53d26d malc
    case Index_Address:
367 cc53d26d malc
        ret = s->regs[saddr] & ~0x80;
368 cc53d26d malc
        break;
369 cc53d26d malc
370 cc53d26d malc
    case Index_Data:
371 cc53d26d malc
        if (!(s->dregs[MODE_And_ID] & MODE2))
372 cc53d26d malc
            iaddr = s->regs[Index_Address] & 0x0f;
373 cc53d26d malc
        else
374 cc53d26d malc
            iaddr = s->regs[Index_Address] & 0x1f;
375 cc53d26d malc
376 cc53d26d malc
        ret = s->dregs[iaddr];
377 cc53d26d malc
        if (iaddr == Error_Status_And_Initialization) {
378 cc53d26d malc
            /* keep SEAL happy */
379 cc53d26d malc
            if (s->aci_counter) {
380 cc53d26d malc
                ret |= 1 << 5;
381 cc53d26d malc
                s->aci_counter -= 1;
382 cc53d26d malc
            }
383 cc53d26d malc
        }
384 cc53d26d malc
        break;
385 cc53d26d malc
386 cc53d26d malc
    default:
387 cc53d26d malc
        ret = s->regs[saddr];
388 cc53d26d malc
        break;
389 cc53d26d malc
    }
390 cc53d26d malc
    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
391 cc53d26d malc
    return ret;
392 cc53d26d malc
}
393 cc53d26d malc
394 cc53d26d malc
IO_WRITE_PROTO (cs_write)
395 cc53d26d malc
{
396 cc53d26d malc
    CSState *s = opaque;
397 cc53d26d malc
    uint32_t saddr, iaddr;
398 cc53d26d malc
399 cc53d26d malc
    saddr = GET_SADDR (addr);
400 cc53d26d malc
401 cc53d26d malc
    switch (saddr) {
402 cc53d26d malc
    case Index_Address:
403 cc53d26d malc
        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
404 cc53d26d malc
            && (s->dregs[Interface_Configuration] & (3 << 3)))
405 cc53d26d malc
            s->aci_counter = conf.aci_counter;
406 cc53d26d malc
407 cc53d26d malc
        s->regs[Index_Address] = val & ~(1 << 7);
408 cc53d26d malc
        break;
409 cc53d26d malc
410 cc53d26d malc
    case Index_Data:
411 cc53d26d malc
        if (!(s->dregs[MODE_And_ID] & MODE2))
412 cc53d26d malc
            iaddr = s->regs[Index_Address] & 0x0f;
413 cc53d26d malc
        else
414 cc53d26d malc
            iaddr = s->regs[Index_Address] & 0x1f;
415 cc53d26d malc
416 cc53d26d malc
        switch (iaddr) {
417 cc53d26d malc
        case RESERVED:
418 cc53d26d malc
        case RESERVED_2:
419 cc53d26d malc
        case RESERVED_3:
420 cc53d26d malc
            lwarn ("attempt to write %#x to reserved indirect register %d\n",
421 cc53d26d malc
                   val, iaddr);
422 cc53d26d malc
            break;
423 cc53d26d malc
424 cc53d26d malc
        case FS_And_Playback_Data_Format:
425 cc53d26d malc
            if (s->regs[Index_Address] & MCE) {
426 cc53d26d malc
                cs_reset_voices (s, val);
427 cc53d26d malc
            }
428 cc53d26d malc
            else {
429 cc53d26d malc
                if (s->dregs[Alternate_Feature_Status] & PMCE) {
430 cc53d26d malc
                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
431 cc53d26d malc
                    cs_reset_voices (s, val);
432 cc53d26d malc
                }
433 cc53d26d malc
                else {
434 cc53d26d malc
                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
435 cc53d26d malc
                           s->regs[Index_Address],
436 cc53d26d malc
                           s->dregs[Alternate_Feature_Status],
437 cc53d26d malc
                           val);
438 cc53d26d malc
                    break;
439 cc53d26d malc
                }
440 cc53d26d malc
            }
441 cc53d26d malc
            s->dregs[iaddr] = val;
442 cc53d26d malc
            break;
443 cc53d26d malc
444 cc53d26d malc
        case Interface_Configuration:
445 cc53d26d malc
            val &= ~(1 << 5);   /* D5 is reserved */
446 cc53d26d malc
            s->dregs[iaddr] = val;
447 cc53d26d malc
            if (val & PPIO) {
448 cc53d26d malc
                lwarn ("PIO is not supported (%#x)\n", val);
449 cc53d26d malc
                break;
450 cc53d26d malc
            }
451 cc53d26d malc
            if (val & PEN) {
452 cc53d26d malc
                if (!s->dma_running) {
453 cc53d26d malc
                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
454 cc53d26d malc
                }
455 cc53d26d malc
            }
456 cc53d26d malc
            else {
457 cc53d26d malc
                if (s->dma_running) {
458 cc53d26d malc
                    DMA_release_DREQ (s->dma);
459 cc53d26d malc
                    AUD_set_active_out (s->voice, 0);
460 cc53d26d malc
                    s->dma_running = 0;
461 cc53d26d malc
                }
462 cc53d26d malc
            }
463 cc53d26d malc
            break;
464 cc53d26d malc
465 cc53d26d malc
        case Error_Status_And_Initialization:
466 cc53d26d malc
            lwarn ("attempt to write to read only register %d\n", iaddr);
467 cc53d26d malc
            break;
468 cc53d26d malc
469 cc53d26d malc
        case MODE_And_ID:
470 cc53d26d malc
            dolog ("val=%#x\n", val);
471 cc53d26d malc
            if (val & MODE2)
472 cc53d26d malc
                s->dregs[iaddr] |= MODE2;
473 cc53d26d malc
            else
474 cc53d26d malc
                s->dregs[iaddr] &= ~MODE2;
475 cc53d26d malc
            break;
476 cc53d26d malc
477 cc53d26d malc
        case Alternate_Feature_Enable_I:
478 cc53d26d malc
            if (val & TE)
479 cc53d26d malc
                lerr ("timer is not yet supported\n");
480 cc53d26d malc
            s->dregs[iaddr] = val;
481 cc53d26d malc
            break;
482 cc53d26d malc
483 cc53d26d malc
        case Alternate_Feature_Status:
484 cc53d26d malc
            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
485 cc53d26d malc
                /* XXX: TI CI */
486 cc53d26d malc
                qemu_irq_lower (s->pic[s->irq]);
487 cc53d26d malc
                s->regs[Status] &= ~INT;
488 cc53d26d malc
            }
489 cc53d26d malc
            s->dregs[iaddr] = val;
490 cc53d26d malc
            break;
491 cc53d26d malc
492 cc53d26d malc
        case Version_Chip_ID:
493 cc53d26d malc
            lwarn ("write to Version_Chip_ID register %#x\n", val);
494 cc53d26d malc
            s->dregs[iaddr] = val;
495 cc53d26d malc
            break;
496 cc53d26d malc
497 cc53d26d malc
        default:
498 cc53d26d malc
            s->dregs[iaddr] = val;
499 cc53d26d malc
            break;
500 cc53d26d malc
        }
501 cc53d26d malc
        dolog ("written value %#x to indirect register %d\n", val, iaddr);
502 cc53d26d malc
        break;
503 cc53d26d malc
504 cc53d26d malc
    case Status:
505 cc53d26d malc
        if (s->regs[Status] & INT) {
506 cc53d26d malc
            qemu_irq_lower (s->pic[s->irq]);
507 cc53d26d malc
        }
508 cc53d26d malc
        s->regs[Status] &= ~INT;
509 cc53d26d malc
        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
510 cc53d26d malc
        break;
511 cc53d26d malc
512 cc53d26d malc
    case PIO_Data:
513 cc53d26d malc
        lwarn ("attempt to write value %#x to PIO register\n", val);
514 cc53d26d malc
        break;
515 cc53d26d malc
    }
516 cc53d26d malc
}
517 cc53d26d malc
518 cc53d26d malc
static int cs_write_audio (CSState *s, int nchan, int dma_pos,
519 cc53d26d malc
                           int dma_len, int len)
520 cc53d26d malc
{
521 cc53d26d malc
    int temp, net;
522 cc53d26d malc
    uint8_t tmpbuf[4096];
523 cc53d26d malc
524 cc53d26d malc
    temp = len;
525 cc53d26d malc
    net = 0;
526 cc53d26d malc
527 cc53d26d malc
    while (temp) {
528 cc53d26d malc
        int left = dma_len - dma_pos;
529 cc53d26d malc
        int copied;
530 cc53d26d malc
        size_t to_copy;
531 cc53d26d malc
532 cc53d26d malc
        to_copy = audio_MIN (temp, left);
533 cc53d26d malc
        if (to_copy > sizeof (tmpbuf)) {
534 cc53d26d malc
            to_copy = sizeof (tmpbuf);
535 cc53d26d malc
        }
536 cc53d26d malc
537 cc53d26d malc
        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
538 cc53d26d malc
        if (s->tab) {
539 cc53d26d malc
            int i;
540 cc53d26d malc
            int16_t linbuf[4096];
541 cc53d26d malc
542 cc53d26d malc
            for (i = 0; i < copied; ++i)
543 cc53d26d malc
                linbuf[i] = s->tab[tmpbuf[i]];
544 cc53d26d malc
            copied = AUD_write (s->voice, linbuf, copied << 1);
545 cc53d26d malc
            copied >>= 1;
546 cc53d26d malc
        }
547 cc53d26d malc
        else {
548 cc53d26d malc
            copied = AUD_write (s->voice, tmpbuf, copied);
549 cc53d26d malc
        }
550 cc53d26d malc
551 cc53d26d malc
        temp -= copied;
552 cc53d26d malc
        dma_pos = (dma_pos + copied) % dma_len;
553 cc53d26d malc
        net += copied;
554 cc53d26d malc
555 cc53d26d malc
        if (!copied) {
556 cc53d26d malc
            break;
557 cc53d26d malc
        }
558 cc53d26d malc
    }
559 cc53d26d malc
560 cc53d26d malc
    return net;
561 cc53d26d malc
}
562 cc53d26d malc
563 cc53d26d malc
static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
564 cc53d26d malc
{
565 cc53d26d malc
    CSState *s = opaque;
566 cc53d26d malc
    int copy, written;
567 cc53d26d malc
    int till = -1;
568 cc53d26d malc
569 cc53d26d malc
    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
570 cc53d26d malc
571 cc53d26d malc
    if (s->dregs[Pin_Control] & IEN) {
572 cc53d26d malc
        till = (s->dregs[Playback_Lower_Base_Count]
573 cc53d26d malc
            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
574 cc53d26d malc
        till -= s->transferred;
575 cc53d26d malc
        copy = audio_MIN (till, copy);
576 cc53d26d malc
    }
577 cc53d26d malc
578 cc53d26d malc
    if ((copy <= 0) || (dma_len <= 0)) {
579 cc53d26d malc
        return dma_pos;
580 cc53d26d malc
    }
581 cc53d26d malc
582 cc53d26d malc
    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
583 cc53d26d malc
584 cc53d26d malc
    dma_pos = (dma_pos + written) % dma_len;
585 cc53d26d malc
    s->audio_free -= (written << (s->tab != NULL));
586 cc53d26d malc
587 cc53d26d malc
    if (written == till) {
588 cc53d26d malc
        s->regs[Status] |= INT;
589 cc53d26d malc
        s->dregs[Alternate_Feature_Status] |= PI;
590 cc53d26d malc
        s->transferred = 0;
591 cc53d26d malc
        qemu_irq_raise (s->pic[s->irq]);
592 cc53d26d malc
    }
593 cc53d26d malc
    else {
594 cc53d26d malc
        s->transferred += written;
595 cc53d26d malc
    }
596 cc53d26d malc
597 cc53d26d malc
    return dma_pos;
598 cc53d26d malc
}
599 cc53d26d malc
600 cc53d26d malc
static void cs_save(QEMUFile *f, void *opaque)
601 cc53d26d malc
{
602 cc53d26d malc
    CSState *s = opaque;
603 cc53d26d malc
    unsigned int i;
604 4143f3e0 malc
    uint32_t val;
605 cc53d26d malc
606 cc53d26d malc
    for (i = 0; i < CS_REGS; i++)
607 cc53d26d malc
        qemu_put_be32s(f, &s->regs[i]);
608 cc53d26d malc
609 cc53d26d malc
    qemu_put_buffer(f, s->dregs, CS_DREGS);
610 4143f3e0 malc
    val = s->dma_running; qemu_put_be32s(f, &val);
611 4143f3e0 malc
    val = s->audio_free;  qemu_put_be32s(f, &val);
612 4143f3e0 malc
    val = s->transferred; qemu_put_be32s(f, &val);
613 4143f3e0 malc
    val = s->aci_counter; qemu_put_be32s(f, &val);
614 cc53d26d malc
}
615 cc53d26d malc
616 cc53d26d malc
static int cs_load(QEMUFile *f, void *opaque, int version_id)
617 cc53d26d malc
{
618 cc53d26d malc
    CSState *s = opaque;
619 cc53d26d malc
    unsigned int i;
620 4143f3e0 malc
    uint32_t val, dma_running;
621 cc53d26d malc
622 cc53d26d malc
    if (version_id > 1)
623 cc53d26d malc
        return -EINVAL;
624 cc53d26d malc
625 cc53d26d malc
    for (i = 0; i < CS_REGS; i++)
626 cc53d26d malc
        qemu_get_be32s(f, &s->regs[i]);
627 cc53d26d malc
628 cc53d26d malc
    qemu_get_buffer(f, s->dregs, CS_DREGS);
629 4143f3e0 malc
630 4143f3e0 malc
    qemu_get_be32s(f, &dma_running);
631 4143f3e0 malc
    qemu_get_be32s(f, &val); s->audio_free  = val;
632 4143f3e0 malc
    qemu_get_be32s(f, &val); s->transferred = val;
633 4143f3e0 malc
    qemu_get_be32s(f, &val); s->aci_counter = val;
634 4143f3e0 malc
    if (dma_running && (s->dregs[Interface_Configuration] & PEN))
635 4143f3e0 malc
        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
636 cc53d26d malc
    return 0;
637 cc53d26d malc
}
638 cc53d26d malc
639 22d83b14 Paul Brook
int cs4231a_init (qemu_irq *pic)
640 cc53d26d malc
{
641 cc53d26d malc
    int i;
642 cc53d26d malc
    CSState *s;
643 cc53d26d malc
644 cc53d26d malc
    s = qemu_mallocz (sizeof (*s));
645 cc53d26d malc
646 cc53d26d malc
    s->pic = pic;
647 cc53d26d malc
    s->irq = conf.irq;
648 cc53d26d malc
    s->dma = conf.dma;
649 cc53d26d malc
    s->port = conf.port;
650 cc53d26d malc
651 cc53d26d malc
    for (i = 0; i < 4; i++) {
652 cc53d26d malc
        register_ioport_write (s->port + i, 1, 1, cs_write, s);
653 cc53d26d malc
        register_ioport_read (s->port + i, 1, 1, cs_read, s);
654 cc53d26d malc
    }
655 cc53d26d malc
656 cc53d26d malc
    DMA_register_channel (s->dma, cs_dma_read, s);
657 cc53d26d malc
658 cc53d26d malc
    register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
659 8217606e Jan Kiszka
    qemu_register_reset (cs_reset, 0, s);
660 cc53d26d malc
    cs_reset (s);
661 cc53d26d malc
662 1a7dafce malc
    AUD_register_card ("cs4231a", &s->card);
663 cc53d26d malc
    return 0;
664 cc53d26d malc
}