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