Statistics
| Branch: | Revision:

root / hw / cs4231a.c @ a1e47211

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