Statistics
| Branch: | Revision:

root / hw / cs4231a.c @ 7f5feab4

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