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 */
24
25 #include "qemu/osdep.h"
26 #include "hw/audio/soundhw.h"
27 #include "audio/audio.h"
28 #include "hw/irq.h"
29 #include "hw/isa/isa.h"
30 #include "hw/qdev-properties.h"
31 #include "migration/vmstate.h"
32 #include "qemu/module.h"
33 #include "qemu/timer.h"
34 #include "qapi/error.h"
35 #include "qom/object.h"
36
37 /*
38 Missing features:
39 ADC
40 Loopback
41 Timer
42 ADPCM
43 More...
44 */
45
46 /* #define DEBUG */
47 /* #define DEBUG_XLAW */
48
49 static struct {
50 int aci_counter;
51 } conf = {1};
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
65 #define TYPE_CS4231A "cs4231a"
66 typedef struct CSState CSState;
67 DECLARE_INSTANCE_CHECKER(CSState, CS4231A,
68 TYPE_CS4231A)
69
70 struct CSState {
71 ISADevice dev;
72 QEMUSoundCard card;
73 MemoryRegion ioports;
74 qemu_irq pic;
75 uint32_t regs[CS_REGS];
76 uint8_t dregs[CS_DREGS];
77 uint32_t irq;
78 uint32_t dma;
79 uint32_t port;
80 IsaDma *isa_dma;
81 int shift;
82 int dma_running;
83 int audio_free;
84 int transferred;
85 int aci_counter;
86 SWVoiceOut *voice;
87 const int16_t *tab;
88 };
89
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
103 enum {
104 Index_Address,
105 Index_Data,
106 Status,
107 PIO_Data
108 };
109
110 enum {
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
145 static const 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 */
151 static const 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
187 static const 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
cs4231a_reset(DeviceState * dev)223 static void cs4231a_reset (DeviceState *dev)
224 {
225 CSState *s = CS4231A (dev);
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
cs_audio_callback(void * opaque,int free)266 static void cs_audio_callback (void *opaque, int free)
267 {
268 CSState *s = opaque;
269 s->audio_free = free;
270 }
271
cs_reset_voices(CSState * s,uint32_t val)272 static void cs_reset_voices (CSState *s, uint32_t val)
273 {
274 int xtal;
275 struct audsettings as;
276 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
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:
297 as.fmt = AUDIO_FORMAT_U8;
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:
307 as.fmt = AUDIO_FORMAT_S16;
308 as.endianness = AUDIO_HOST_ENDIANNESS;
309 s->shift = as.nchannels == 2;
310 break;
311
312 case 6:
313 as.endianness = 1;
314 /* fall through */
315 case 2:
316 as.fmt = AUDIO_FORMAT_S16;
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) {
341 k->hold_DREQ(s->isa_dma, s->dma);
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) {
349 k->release_DREQ(s->isa_dma, s->dma);
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) {
358 k->release_DREQ(s->isa_dma, s->dma);
359 AUD_set_active_out (s->voice, 0);
360 }
361 }
362
cs_read(void * opaque,hwaddr addr,unsigned size)363 static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
364 {
365 CSState *s = opaque;
366 uint32_t saddr, iaddr, ret;
367
368 saddr = addr;
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
cs_write(void * opaque,hwaddr addr,uint64_t val64,unsigned size)400 static void cs_write (void *opaque, hwaddr addr,
401 uint64_t val64, unsigned size)
402 {
403 CSState *s = opaque;
404 uint32_t saddr, iaddr, val;
405
406 saddr = addr;
407 val = val64;
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) {
466 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
467 k->release_DREQ(s->isa_dma, s->dma);
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 */
495 qemu_irq_lower (s->pic);
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) {
515 qemu_irq_lower (s->pic);
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
cs_write_audio(CSState * s,int nchan,int dma_pos,int dma_len,int len)527 static 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];
532 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
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
542 to_copy = MIN (temp, left);
543 if (to_copy > sizeof (tmpbuf)) {
544 to_copy = sizeof (tmpbuf);
545 }
546
547 copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
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
cs_dma_read(void * opaque,int nchan,int dma_pos,int dma_len)573 static 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;
585 copy = MIN (till, copy);
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;
601 qemu_irq_raise (s->pic);
602 }
603 else {
604 s->transferred += written;
605 }
606
607 return dma_pos;
608 }
609
cs4231a_pre_load(void * opaque)610 static int cs4231a_pre_load (void *opaque)
611 {
612 CSState *s = opaque;
613
614 if (s->dma_running) {
615 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
616 k->release_DREQ(s->isa_dma, s->dma);
617 AUD_set_active_out (s->voice, 0);
618 }
619 s->dma_running = 0;
620 return 0;
621 }
622
cs4231a_post_load(void * opaque,int version_id)623 static int cs4231a_post_load (void *opaque, int version_id)
624 {
625 CSState *s = opaque;
626
627 if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
628 s->dma_running = 0;
629 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
630 }
631 return 0;
632 }
633
634 static const VMStateDescription vmstate_cs4231a = {
635 .name = "cs4231a",
636 .version_id = 1,
637 .minimum_version_id = 1,
638 .pre_load = cs4231a_pre_load,
639 .post_load = cs4231a_post_load,
640 .fields = (const VMStateField[]) {
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 ()
648 }
649 };
650
651 static 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
cs4231a_initfn(Object * obj)660 static void cs4231a_initfn (Object *obj)
661 {
662 CSState *s = CS4231A (obj);
663
664 memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
665 "cs4231a", 4);
666 }
667
cs4231a_realizefn(DeviceState * dev,Error ** errp)668 static void cs4231a_realizefn (DeviceState *dev, Error **errp)
669 {
670 ISADevice *d = ISA_DEVICE (dev);
671 ISABus *bus = isa_bus_from_device(d);
672 CSState *s = CS4231A (dev);
673 IsaDmaClass *k;
674
675 s->isa_dma = isa_bus_get_dma(bus, s->dma);
676 if (!s->isa_dma) {
677 error_setg(errp, "ISA controller does not support DMA");
678 return;
679 }
680
681 if (!AUD_register_card ("cs4231a", &s->card, errp)) {
682 return;
683 }
684
685 s->pic = isa_bus_get_irq(bus, s->irq);
686 k = ISADMA_GET_CLASS(s->isa_dma);
687 k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
688
689 isa_register_ioport (d, &s->ioports, s->port);
690 }
691
692 static Property cs4231a_properties[] = {
693 DEFINE_AUDIO_PROPERTIES(CSState, card),
694 DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
695 DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
696 DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
697 DEFINE_PROP_END_OF_LIST (),
698 };
699
cs4231a_class_initfn(ObjectClass * klass,void * data)700 static void cs4231a_class_initfn (ObjectClass *klass, void *data)
701 {
702 DeviceClass *dc = DEVICE_CLASS (klass);
703
704 dc->realize = cs4231a_realizefn;
705 device_class_set_legacy_reset(dc, cs4231a_reset);
706 set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
707 dc->desc = "Crystal Semiconductor CS4231A";
708 dc->vmsd = &vmstate_cs4231a;
709 device_class_set_props(dc, cs4231a_properties);
710 }
711
712 static const TypeInfo cs4231a_info = {
713 .name = TYPE_CS4231A,
714 .parent = TYPE_ISA_DEVICE,
715 .instance_size = sizeof (CSState),
716 .instance_init = cs4231a_initfn,
717 .class_init = cs4231a_class_initfn,
718 };
719
cs4231a_register_types(void)720 static void cs4231a_register_types (void)
721 {
722 type_register_static (&cs4231a_info);
723 deprecated_register_soundhw("cs4231a", "CS4231A", 1, TYPE_CS4231A);
724 }
725
726 type_init (cs4231a_register_types)
727