blob: f96f561c7fa5bc839f43b4b4dcab96279867bbc6 [file] [log] [blame]
malccc53d262008-06-13 10:48:22 +00001/*
2 * QEMU Crystal CS4231 audio chip emulation
3 *
4 * Copyright (c) 2006 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010024#include "hw/hw.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010025#include "hw/audio/audio.h"
malccc53d262008-06-13 10:48:22 +000026#include "audio/audio.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010027#include "hw/isa/isa.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010028#include "hw/qdev.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010029#include "qemu/timer.h"
malccc53d262008-06-13 10:48:22 +000030
31/*
32 Missing features:
33 ADC
34 Loopback
35 Timer
36 ADPCM
37 More...
38*/
39
40/* #define DEBUG */
malc77599a12008-06-21 17:15:00 +000041/* #define DEBUG_XLAW */
malccc53d262008-06-13 10:48:22 +000042
43static struct {
malccc53d262008-06-13 10:48:22 +000044 int aci_counter;
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +020045} conf = {1};
malccc53d262008-06-13 10:48:22 +000046
47#ifdef DEBUG
48#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
49#else
50#define dolog(...)
51#endif
52
53#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
54#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
55
56#define CS_REGS 16
57#define CS_DREGS 32
58
Andreas Färbera3dcca52013-06-06 16:40:02 +020059#define TYPE_CS4231A "cs4231a"
60#define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
61
malccc53d262008-06-13 10:48:22 +000062typedef struct CSState {
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +020063 ISADevice dev;
malccc53d262008-06-13 10:48:22 +000064 QEMUSoundCard card;
Richard Hendersonbeae3972011-08-10 15:28:14 -070065 MemoryRegion ioports;
Jes Sorensen3a38d432009-08-14 11:36:15 +020066 qemu_irq pic;
malccc53d262008-06-13 10:48:22 +000067 uint32_t regs[CS_REGS];
68 uint8_t dregs[CS_DREGS];
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +020069 uint32_t irq;
70 uint32_t dma;
71 uint32_t port;
malccc53d262008-06-13 10:48:22 +000072 int shift;
73 int dma_running;
74 int audio_free;
75 int transferred;
76 int aci_counter;
77 SWVoiceOut *voice;
78 int16_t *tab;
79} CSState;
80
malccc53d262008-06-13 10:48:22 +000081#define MODE2 (1 << 6)
82#define MCE (1 << 6)
83#define PMCE (1 << 4)
84#define CMCE (1 << 5)
85#define TE (1 << 6)
86#define PEN (1 << 0)
87#define INT (1 << 0)
88#define IEN (1 << 1)
89#define PPIO (1 << 6)
90#define PI (1 << 4)
91#define CI (1 << 5)
92#define TI (1 << 6)
93
94enum {
95 Index_Address,
96 Index_Data,
97 Status,
98 PIO_Data
99};
100
101enum {
102 Left_ADC_Input_Control,
103 Right_ADC_Input_Control,
104 Left_AUX1_Input_Control,
105 Right_AUX1_Input_Control,
106 Left_AUX2_Input_Control,
107 Right_AUX2_Input_Control,
108 Left_DAC_Output_Control,
109 Right_DAC_Output_Control,
110 FS_And_Playback_Data_Format,
111 Interface_Configuration,
112 Pin_Control,
113 Error_Status_And_Initialization,
114 MODE_And_ID,
115 Loopback_Control,
116 Playback_Upper_Base_Count,
117 Playback_Lower_Base_Count,
118 Alternate_Feature_Enable_I,
119 Alternate_Feature_Enable_II,
120 Left_Line_Input_Control,
121 Right_Line_Input_Control,
122 Timer_Low_Base,
123 Timer_High_Base,
124 RESERVED,
125 Alternate_Feature_Enable_III,
126 Alternate_Feature_Status,
127 Version_Chip_ID,
128 Mono_Input_And_Output_Control,
129 RESERVED_2,
130 Capture_Data_Format,
131 RESERVED_3,
132 Capture_Upper_Base_Count,
133 Capture_Lower_Base_Count
134};
135
136static int freqs[2][8] = {
137 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
138 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
139};
140
141/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
142static int16_t MuLawDecompressTable[256] =
143{
144 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
145 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
146 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
147 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
148 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
149 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
150 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
151 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
152 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
153 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
154 -876, -844, -812, -780, -748, -716, -684, -652,
155 -620, -588, -556, -524, -492, -460, -428, -396,
156 -372, -356, -340, -324, -308, -292, -276, -260,
157 -244, -228, -212, -196, -180, -164, -148, -132,
158 -120, -112, -104, -96, -88, -80, -72, -64,
159 -56, -48, -40, -32, -24, -16, -8, 0,
160 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
161 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
162 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
163 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
164 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
165 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
166 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
167 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
168 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
169 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
170 876, 844, 812, 780, 748, 716, 684, 652,
171 620, 588, 556, 524, 492, 460, 428, 396,
172 372, 356, 340, 324, 308, 292, 276, 260,
173 244, 228, 212, 196, 180, 164, 148, 132,
174 120, 112, 104, 96, 88, 80, 72, 64,
175 56, 48, 40, 32, 24, 16, 8, 0
176};
177
178static int16_t ALawDecompressTable[256] =
179{
180 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
181 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
182 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
183 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
184 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
185 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
186 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
187 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
188 -344, -328, -376, -360, -280, -264, -312, -296,
189 -472, -456, -504, -488, -408, -392, -440, -424,
190 -88, -72, -120, -104, -24, -8, -56, -40,
191 -216, -200, -248, -232, -152, -136, -184, -168,
192 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
193 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
194 -688, -656, -752, -720, -560, -528, -624, -592,
195 -944, -912, -1008, -976, -816, -784, -880, -848,
196 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
197 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
198 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
199 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
200 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
201 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
202 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
203 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
204 344, 328, 376, 360, 280, 264, 312, 296,
205 472, 456, 504, 488, 408, 392, 440, 424,
206 88, 72, 120, 104, 24, 8, 56, 40,
207 216, 200, 248, 232, 152, 136, 184, 168,
208 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
209 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
210 688, 656, 752, 720, 560, 528, 624, 592,
211 944, 912, 1008, 976, 816, 784, 880, 848
212};
213
Andreas Färbera3dcca52013-06-06 16:40:02 +0200214static void cs4231a_reset (DeviceState *dev)
malccc53d262008-06-13 10:48:22 +0000215{
Andreas Färbera3dcca52013-06-06 16:40:02 +0200216 CSState *s = CS4231A (dev);
malccc53d262008-06-13 10:48:22 +0000217
218 s->regs[Index_Address] = 0x40;
219 s->regs[Index_Data] = 0x00;
220 s->regs[Status] = 0x00;
221 s->regs[PIO_Data] = 0x00;
222
223 s->dregs[Left_ADC_Input_Control] = 0x00;
224 s->dregs[Right_ADC_Input_Control] = 0x00;
225 s->dregs[Left_AUX1_Input_Control] = 0x88;
226 s->dregs[Right_AUX1_Input_Control] = 0x88;
227 s->dregs[Left_AUX2_Input_Control] = 0x88;
228 s->dregs[Right_AUX2_Input_Control] = 0x88;
229 s->dregs[Left_DAC_Output_Control] = 0x80;
230 s->dregs[Right_DAC_Output_Control] = 0x80;
231 s->dregs[FS_And_Playback_Data_Format] = 0x00;
232 s->dregs[Interface_Configuration] = 0x08;
233 s->dregs[Pin_Control] = 0x00;
234 s->dregs[Error_Status_And_Initialization] = 0x00;
235 s->dregs[MODE_And_ID] = 0x8a;
236 s->dregs[Loopback_Control] = 0x00;
237 s->dregs[Playback_Upper_Base_Count] = 0x00;
238 s->dregs[Playback_Lower_Base_Count] = 0x00;
239 s->dregs[Alternate_Feature_Enable_I] = 0x00;
240 s->dregs[Alternate_Feature_Enable_II] = 0x00;
241 s->dregs[Left_Line_Input_Control] = 0x88;
242 s->dregs[Right_Line_Input_Control] = 0x88;
243 s->dregs[Timer_Low_Base] = 0x00;
244 s->dregs[Timer_High_Base] = 0x00;
245 s->dregs[RESERVED] = 0x00;
246 s->dregs[Alternate_Feature_Enable_III] = 0x00;
247 s->dregs[Alternate_Feature_Status] = 0x00;
248 s->dregs[Version_Chip_ID] = 0xa0;
249 s->dregs[Mono_Input_And_Output_Control] = 0xa0;
250 s->dregs[RESERVED_2] = 0x00;
251 s->dregs[Capture_Data_Format] = 0x00;
252 s->dregs[RESERVED_3] = 0x00;
253 s->dregs[Capture_Upper_Base_Count] = 0x00;
254 s->dregs[Capture_Lower_Base_Count] = 0x00;
255}
256
257static void cs_audio_callback (void *opaque, int free)
258{
259 CSState *s = opaque;
260 s->audio_free = free;
261}
262
263static void cs_reset_voices (CSState *s, uint32_t val)
264{
265 int xtal;
malc1ea879e2008-12-03 22:48:44 +0000266 struct audsettings as;
malccc53d262008-06-13 10:48:22 +0000267
268#ifdef DEBUG_XLAW
269 if (val == 0 || val == 32)
270 val = (1 << 4) | (1 << 5);
271#endif
272
273 xtal = val & 1;
274 as.freq = freqs[xtal][(val >> 1) & 7];
275
276 if (as.freq == -1) {
277 lerr ("unsupported frequency (val=%#x)\n", val);
278 goto error;
279 }
280
281 as.nchannels = (val & (1 << 4)) ? 2 : 1;
282 as.endianness = 0;
283 s->tab = NULL;
284
285 switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
286 case 0:
287 as.fmt = AUD_FMT_U8;
288 s->shift = as.nchannels == 2;
289 break;
290
291 case 1:
292 s->tab = MuLawDecompressTable;
293 goto x_law;
294 case 3:
295 s->tab = ALawDecompressTable;
296 x_law:
297 as.fmt = AUD_FMT_S16;
298 as.endianness = AUDIO_HOST_ENDIANNESS;
299 s->shift = as.nchannels == 2;
300 break;
301
302 case 6:
303 as.endianness = 1;
304 case 2:
305 as.fmt = AUD_FMT_S16;
306 s->shift = as.nchannels;
307 break;
308
309 case 7:
310 case 4:
311 lerr ("attempt to use reserved format value (%#x)\n", val);
312 goto error;
313
314 case 5:
315 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
316 goto error;
317 }
318
319 s->voice = AUD_open_out (
320 &s->card,
321 s->voice,
322 "cs4231a",
323 s,
324 cs_audio_callback,
325 &as
326 );
327
328 if (s->dregs[Interface_Configuration] & PEN) {
329 if (!s->dma_running) {
330 DMA_hold_DREQ (s->dma);
331 AUD_set_active_out (s->voice, 1);
332 s->transferred = 0;
333 }
334 s->dma_running = 1;
335 }
336 else {
337 if (s->dma_running) {
338 DMA_release_DREQ (s->dma);
339 AUD_set_active_out (s->voice, 0);
340 }
341 s->dma_running = 0;
342 }
343 return;
344
345 error:
346 if (s->dma_running) {
347 DMA_release_DREQ (s->dma);
348 AUD_set_active_out (s->voice, 0);
349 }
350}
351
Avi Kivitya8170e52012-10-23 12:30:10 +0200352static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
malccc53d262008-06-13 10:48:22 +0000353{
354 CSState *s = opaque;
355 uint32_t saddr, iaddr, ret;
356
Richard Hendersonbeae3972011-08-10 15:28:14 -0700357 saddr = addr;
malccc53d262008-06-13 10:48:22 +0000358 iaddr = ~0U;
359
360 switch (saddr) {
361 case Index_Address:
362 ret = s->regs[saddr] & ~0x80;
363 break;
364
365 case Index_Data:
366 if (!(s->dregs[MODE_And_ID] & MODE2))
367 iaddr = s->regs[Index_Address] & 0x0f;
368 else
369 iaddr = s->regs[Index_Address] & 0x1f;
370
371 ret = s->dregs[iaddr];
372 if (iaddr == Error_Status_And_Initialization) {
373 /* keep SEAL happy */
374 if (s->aci_counter) {
375 ret |= 1 << 5;
376 s->aci_counter -= 1;
377 }
378 }
379 break;
380
381 default:
382 ret = s->regs[saddr];
383 break;
384 }
385 dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
386 return ret;
387}
388
Avi Kivitya8170e52012-10-23 12:30:10 +0200389static void cs_write (void *opaque, hwaddr addr,
malc8acbc9b2011-10-09 19:04:16 +0400390 uint64_t val64, unsigned size)
malccc53d262008-06-13 10:48:22 +0000391{
392 CSState *s = opaque;
Richard Hendersonbeae3972011-08-10 15:28:14 -0700393 uint32_t saddr, iaddr, val;
malccc53d262008-06-13 10:48:22 +0000394
Richard Hendersonbeae3972011-08-10 15:28:14 -0700395 saddr = addr;
396 val = val64;
malccc53d262008-06-13 10:48:22 +0000397
398 switch (saddr) {
399 case Index_Address:
400 if (!(s->regs[Index_Address] & MCE) && (val & MCE)
401 && (s->dregs[Interface_Configuration] & (3 << 3)))
402 s->aci_counter = conf.aci_counter;
403
404 s->regs[Index_Address] = val & ~(1 << 7);
405 break;
406
407 case Index_Data:
408 if (!(s->dregs[MODE_And_ID] & MODE2))
409 iaddr = s->regs[Index_Address] & 0x0f;
410 else
411 iaddr = s->regs[Index_Address] & 0x1f;
412
413 switch (iaddr) {
414 case RESERVED:
415 case RESERVED_2:
416 case RESERVED_3:
417 lwarn ("attempt to write %#x to reserved indirect register %d\n",
418 val, iaddr);
419 break;
420
421 case FS_And_Playback_Data_Format:
422 if (s->regs[Index_Address] & MCE) {
423 cs_reset_voices (s, val);
424 }
425 else {
426 if (s->dregs[Alternate_Feature_Status] & PMCE) {
427 val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
428 cs_reset_voices (s, val);
429 }
430 else {
431 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
432 s->regs[Index_Address],
433 s->dregs[Alternate_Feature_Status],
434 val);
435 break;
436 }
437 }
438 s->dregs[iaddr] = val;
439 break;
440
441 case Interface_Configuration:
442 val &= ~(1 << 5); /* D5 is reserved */
443 s->dregs[iaddr] = val;
444 if (val & PPIO) {
445 lwarn ("PIO is not supported (%#x)\n", val);
446 break;
447 }
448 if (val & PEN) {
449 if (!s->dma_running) {
450 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
451 }
452 }
453 else {
454 if (s->dma_running) {
455 DMA_release_DREQ (s->dma);
456 AUD_set_active_out (s->voice, 0);
457 s->dma_running = 0;
458 }
459 }
460 break;
461
462 case Error_Status_And_Initialization:
463 lwarn ("attempt to write to read only register %d\n", iaddr);
464 break;
465
466 case MODE_And_ID:
467 dolog ("val=%#x\n", val);
468 if (val & MODE2)
469 s->dregs[iaddr] |= MODE2;
470 else
471 s->dregs[iaddr] &= ~MODE2;
472 break;
473
474 case Alternate_Feature_Enable_I:
475 if (val & TE)
476 lerr ("timer is not yet supported\n");
477 s->dregs[iaddr] = val;
478 break;
479
480 case Alternate_Feature_Status:
481 if ((s->dregs[iaddr] & PI) && !(val & PI)) {
482 /* XXX: TI CI */
Jes Sorensen3a38d432009-08-14 11:36:15 +0200483 qemu_irq_lower (s->pic);
malccc53d262008-06-13 10:48:22 +0000484 s->regs[Status] &= ~INT;
485 }
486 s->dregs[iaddr] = val;
487 break;
488
489 case Version_Chip_ID:
490 lwarn ("write to Version_Chip_ID register %#x\n", val);
491 s->dregs[iaddr] = val;
492 break;
493
494 default:
495 s->dregs[iaddr] = val;
496 break;
497 }
498 dolog ("written value %#x to indirect register %d\n", val, iaddr);
499 break;
500
501 case Status:
502 if (s->regs[Status] & INT) {
Jes Sorensen3a38d432009-08-14 11:36:15 +0200503 qemu_irq_lower (s->pic);
malccc53d262008-06-13 10:48:22 +0000504 }
505 s->regs[Status] &= ~INT;
506 s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
507 break;
508
509 case PIO_Data:
510 lwarn ("attempt to write value %#x to PIO register\n", val);
511 break;
512 }
513}
514
515static int cs_write_audio (CSState *s, int nchan, int dma_pos,
516 int dma_len, int len)
517{
518 int temp, net;
519 uint8_t tmpbuf[4096];
520
521 temp = len;
522 net = 0;
523
524 while (temp) {
525 int left = dma_len - dma_pos;
526 int copied;
527 size_t to_copy;
528
529 to_copy = audio_MIN (temp, left);
530 if (to_copy > sizeof (tmpbuf)) {
531 to_copy = sizeof (tmpbuf);
532 }
533
534 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
535 if (s->tab) {
536 int i;
537 int16_t linbuf[4096];
538
539 for (i = 0; i < copied; ++i)
540 linbuf[i] = s->tab[tmpbuf[i]];
541 copied = AUD_write (s->voice, linbuf, copied << 1);
542 copied >>= 1;
543 }
544 else {
545 copied = AUD_write (s->voice, tmpbuf, copied);
546 }
547
548 temp -= copied;
549 dma_pos = (dma_pos + copied) % dma_len;
550 net += copied;
551
552 if (!copied) {
553 break;
554 }
555 }
556
557 return net;
558}
559
560static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
561{
562 CSState *s = opaque;
563 int copy, written;
564 int till = -1;
565
566 copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
567
568 if (s->dregs[Pin_Control] & IEN) {
569 till = (s->dregs[Playback_Lower_Base_Count]
570 | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
571 till -= s->transferred;
572 copy = audio_MIN (till, copy);
573 }
574
575 if ((copy <= 0) || (dma_len <= 0)) {
576 return dma_pos;
577 }
578
579 written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
580
581 dma_pos = (dma_pos + written) % dma_len;
582 s->audio_free -= (written << (s->tab != NULL));
583
584 if (written == till) {
585 s->regs[Status] |= INT;
586 s->dregs[Alternate_Feature_Status] |= PI;
587 s->transferred = 0;
Jes Sorensen3a38d432009-08-14 11:36:15 +0200588 qemu_irq_raise (s->pic);
malccc53d262008-06-13 10:48:22 +0000589 }
590 else {
591 s->transferred += written;
592 }
593
594 return dma_pos;
595}
596
Juan Quintela1d190d52009-12-02 11:49:37 +0100597static int cs4231a_pre_load (void *opaque)
malccc53d262008-06-13 10:48:22 +0000598{
599 CSState *s = opaque;
malccc53d262008-06-13 10:48:22 +0000600
Juan Quintela1d190d52009-12-02 11:49:37 +0100601 if (s->dma_running) {
602 DMA_release_DREQ (s->dma);
603 AUD_set_active_out (s->voice, 0);
604 }
605 s->dma_running = 0;
malccc53d262008-06-13 10:48:22 +0000606 return 0;
607}
608
Juan Quintela1d190d52009-12-02 11:49:37 +0100609static int cs4231a_post_load (void *opaque, int version_id)
610{
611 CSState *s = opaque;
612
613 if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
614 s->dma_running = 0;
615 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
616 }
617 return 0;
618}
619
620static const VMStateDescription vmstate_cs4231a = {
621 .name = "cs4231a",
622 .version_id = 1,
623 .minimum_version_id = 1,
Juan Quintela1d190d52009-12-02 11:49:37 +0100624 .pre_load = cs4231a_pre_load,
625 .post_load = cs4231a_post_load,
Juan Quintelad49805a2014-04-16 15:32:32 +0200626 .fields = (VMStateField[]) {
malccf4dc462012-02-07 22:11:04 +0400627 VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
628 VMSTATE_BUFFER (dregs, CSState),
629 VMSTATE_INT32 (dma_running, CSState),
630 VMSTATE_INT32 (audio_free, CSState),
631 VMSTATE_INT32 (transferred, CSState),
632 VMSTATE_INT32 (aci_counter, CSState),
633 VMSTATE_END_OF_LIST ()
Juan Quintela1d190d52009-12-02 11:49:37 +0100634 }
635};
636
Richard Hendersonbeae3972011-08-10 15:28:14 -0700637static const MemoryRegionOps cs_ioport_ops = {
638 .read = cs_read,
639 .write = cs_write,
640 .impl = {
641 .min_access_size = 1,
642 .max_access_size = 1,
643 }
644};
645
Andreas Färberdb895a12012-11-25 02:37:14 +0100646static void cs4231a_initfn (Object *obj)
malccc53d262008-06-13 10:48:22 +0000647{
Andreas Färberdb895a12012-11-25 02:37:14 +0100648 CSState *s = CS4231A (obj);
malccc53d262008-06-13 10:48:22 +0000649
Paolo Bonzini64bde0f2013-06-06 21:25:08 -0400650 memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
651 "cs4231a", 4);
Andreas Färberdb895a12012-11-25 02:37:14 +0100652}
653
654static void cs4231a_realizefn (DeviceState *dev, Error **errp)
655{
656 ISADevice *d = ISA_DEVICE (dev);
657 CSState *s = CS4231A (dev);
658
659 isa_init_irq (d, &s->pic, s->irq);
660
661 isa_register_ioport (d, &s->ioports, s->port);
malccc53d262008-06-13 10:48:22 +0000662
663 DMA_register_channel (s->dma, cs_dma_read, s);
664
malc1a7dafc2009-05-14 03:11:35 +0400665 AUD_register_card ("cs4231a", &s->card);
malccc53d262008-06-13 10:48:22 +0000666}
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200667
Paolo Bonzini36cd6f62013-04-18 18:43:58 +0200668static int cs4231a_init (ISABus *bus)
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200669{
Andreas Färbera3dcca52013-06-06 16:40:02 +0200670 isa_create_simple (bus, TYPE_CS4231A);
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200671 return 0;
672}
673
Anthony Liguori39bffca2011-12-07 21:34:16 -0600674static Property cs4231a_properties[] = {
Paolo Bonzinic7bcc852014-02-08 11:01:53 +0100675 DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
Anthony Liguori39bffca2011-12-07 21:34:16 -0600676 DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
677 DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
678 DEFINE_PROP_END_OF_LIST (),
679};
680
malccf4dc462012-02-07 22:11:04 +0400681static void cs4231a_class_initfn (ObjectClass *klass, void *data)
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600682{
malccf4dc462012-02-07 22:11:04 +0400683 DeviceClass *dc = DEVICE_CLASS (klass);
Andreas Färberdb895a12012-11-25 02:37:14 +0100684
685 dc->realize = cs4231a_realizefn;
Andreas Färbera3dcca52013-06-06 16:40:02 +0200686 dc->reset = cs4231a_reset;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300687 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600688 dc->desc = "Crystal Semiconductor CS4231A";
689 dc->vmsd = &vmstate_cs4231a;
690 dc->props = cs4231a_properties;
Anthony Liguori8f04ee02011-12-04 11:52:49 -0600691}
692
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100693static const TypeInfo cs4231a_info = {
Andreas Färbera3dcca52013-06-06 16:40:02 +0200694 .name = TYPE_CS4231A,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600695 .parent = TYPE_ISA_DEVICE,
696 .instance_size = sizeof (CSState),
Andreas Färberdb895a12012-11-25 02:37:14 +0100697 .instance_init = cs4231a_initfn,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600698 .class_init = cs4231a_class_initfn,
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200699};
700
Andreas Färber83f7d432012-02-09 15:20:55 +0100701static void cs4231a_register_types (void)
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200702{
malccf4dc462012-02-07 22:11:04 +0400703 type_register_static (&cs4231a_info);
Paolo Bonzini36cd6f62013-04-18 18:43:58 +0200704 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init);
Gerd Hoffmannf8ba7842009-09-10 11:43:31 +0200705}
Andreas Färber83f7d432012-02-09 15:20:55 +0100706
707type_init (cs4231a_register_types)