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