2 * QEMU Crystal CS4231 audio chip emulation
4 * Copyright (c) 2006 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu/osdep.h"
26 #include "hw/audio/soundhw.h"
27 #include "audio/audio.h"
28 #include "hw/isa/isa.h"
30 #include "qemu/timer.h"
31 #include "qapi/error.h"
43 /* #define DEBUG_XLAW */
50 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
55 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
56 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
61 #define TYPE_CS4231A "cs4231a"
62 #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
64 typedef struct CSState
{
69 uint32_t regs
[CS_REGS
];
70 uint8_t dregs
[CS_DREGS
];
84 #define MODE2 (1 << 6)
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
,
116 Error_Status_And_Initialization
,
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
,
128 Alternate_Feature_Enable_III
,
129 Alternate_Feature_Status
,
131 Mono_Input_And_Output_Control
,
135 Capture_Upper_Base_Count
,
136 Capture_Lower_Base_Count
139 static int freqs
[2][8] = {
140 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
141 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
144 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
145 static int16_t MuLawDecompressTable
[256] =
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
181 static int16_t ALawDecompressTable
[256] =
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
217 static void cs4231a_reset (DeviceState
*dev
)
219 CSState
*s
= CS4231A (dev
);
221 s
->regs
[Index_Address
] = 0x40;
222 s
->regs
[Index_Data
] = 0x00;
223 s
->regs
[Status
] = 0x00;
224 s
->regs
[PIO_Data
] = 0x00;
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;
260 static void cs_audio_callback (void *opaque
, int free
)
263 s
->audio_free
= free
;
266 static void cs_reset_voices (CSState
*s
, uint32_t val
)
269 struct audsettings as
;
270 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
273 if (val
== 0 || val
== 32)
274 val
= (1 << 4) | (1 << 5);
278 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
281 lerr ("unsupported frequency (val=%#x)\n", val
);
285 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
289 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
291 as
.fmt
= AUDIO_FORMAT_U8
;
292 s
->shift
= as
.nchannels
== 2;
296 s
->tab
= MuLawDecompressTable
;
299 s
->tab
= ALawDecompressTable
;
301 as
.fmt
= AUDIO_FORMAT_S16
;
302 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
303 s
->shift
= as
.nchannels
== 2;
310 as
.fmt
= AUDIO_FORMAT_S16
;
311 s
->shift
= as
.nchannels
;
316 lerr ("attempt to use reserved format value (%#x)\n", val
);
320 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
324 s
->voice
= AUD_open_out (
333 if (s
->dregs
[Interface_Configuration
] & PEN
) {
334 if (!s
->dma_running
) {
335 k
->hold_DREQ(s
->isa_dma
, s
->dma
);
336 AUD_set_active_out (s
->voice
, 1);
342 if (s
->dma_running
) {
343 k
->release_DREQ(s
->isa_dma
, s
->dma
);
344 AUD_set_active_out (s
->voice
, 0);
351 if (s
->dma_running
) {
352 k
->release_DREQ(s
->isa_dma
, s
->dma
);
353 AUD_set_active_out (s
->voice
, 0);
357 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
360 uint32_t saddr
, iaddr
, ret
;
367 ret
= s
->regs
[saddr
] & ~0x80;
371 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
372 iaddr
= s
->regs
[Index_Address
] & 0x0f;
374 iaddr
= s
->regs
[Index_Address
] & 0x1f;
376 ret
= s
->dregs
[iaddr
];
377 if (iaddr
== Error_Status_And_Initialization
) {
378 /* keep SEAL happy */
379 if (s
->aci_counter
) {
387 ret
= s
->regs
[saddr
];
390 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
394 static void cs_write (void *opaque
, hwaddr addr
,
395 uint64_t val64
, unsigned size
)
398 uint32_t saddr
, iaddr
, val
;
405 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
406 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
407 s
->aci_counter
= conf
.aci_counter
;
409 s
->regs
[Index_Address
] = val
& ~(1 << 7);
413 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
414 iaddr
= s
->regs
[Index_Address
] & 0x0f;
416 iaddr
= s
->regs
[Index_Address
] & 0x1f;
422 lwarn ("attempt to write %#x to reserved indirect register %d\n",
426 case FS_And_Playback_Data_Format
:
427 if (s
->regs
[Index_Address
] & MCE
) {
428 cs_reset_voices (s
, val
);
431 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
432 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
433 cs_reset_voices (s
, val
);
436 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
437 s
->regs
[Index_Address
],
438 s
->dregs
[Alternate_Feature_Status
],
443 s
->dregs
[iaddr
] = val
;
446 case Interface_Configuration
:
447 val
&= ~(1 << 5); /* D5 is reserved */
448 s
->dregs
[iaddr
] = val
;
450 lwarn ("PIO is not supported (%#x)\n", val
);
454 if (!s
->dma_running
) {
455 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
459 if (s
->dma_running
) {
460 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
461 k
->release_DREQ(s
->isa_dma
, s
->dma
);
462 AUD_set_active_out (s
->voice
, 0);
468 case Error_Status_And_Initialization
:
469 lwarn ("attempt to write to read only register %d\n", iaddr
);
473 dolog ("val=%#x\n", val
);
475 s
->dregs
[iaddr
] |= MODE2
;
477 s
->dregs
[iaddr
] &= ~MODE2
;
480 case Alternate_Feature_Enable_I
:
482 lerr ("timer is not yet supported\n");
483 s
->dregs
[iaddr
] = val
;
486 case Alternate_Feature_Status
:
487 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
489 qemu_irq_lower (s
->pic
);
490 s
->regs
[Status
] &= ~INT
;
492 s
->dregs
[iaddr
] = val
;
495 case Version_Chip_ID
:
496 lwarn ("write to Version_Chip_ID register %#x\n", val
);
497 s
->dregs
[iaddr
] = val
;
501 s
->dregs
[iaddr
] = val
;
504 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
508 if (s
->regs
[Status
] & INT
) {
509 qemu_irq_lower (s
->pic
);
511 s
->regs
[Status
] &= ~INT
;
512 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
516 lwarn ("attempt to write value %#x to PIO register\n", val
);
521 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
522 int dma_len
, int len
)
525 uint8_t tmpbuf
[4096];
526 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
532 int left
= dma_len
- dma_pos
;
536 to_copy
= audio_MIN (temp
, left
);
537 if (to_copy
> sizeof (tmpbuf
)) {
538 to_copy
= sizeof (tmpbuf
);
541 copied
= k
->read_memory(s
->isa_dma
, nchan
, tmpbuf
, dma_pos
, to_copy
);
544 int16_t linbuf
[4096];
546 for (i
= 0; i
< copied
; ++i
)
547 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
548 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
552 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
556 dma_pos
= (dma_pos
+ copied
) % dma_len
;
567 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
573 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
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
);
582 if ((copy
<= 0) || (dma_len
<= 0)) {
586 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
588 dma_pos
= (dma_pos
+ written
) % dma_len
;
589 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
591 if (written
== till
) {
592 s
->regs
[Status
] |= INT
;
593 s
->dregs
[Alternate_Feature_Status
] |= PI
;
595 qemu_irq_raise (s
->pic
);
598 s
->transferred
+= written
;
604 static int cs4231a_pre_load (void *opaque
)
608 if (s
->dma_running
) {
609 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
610 k
->release_DREQ(s
->isa_dma
, s
->dma
);
611 AUD_set_active_out (s
->voice
, 0);
617 static int cs4231a_post_load (void *opaque
, int version_id
)
621 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
623 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
628 static const VMStateDescription vmstate_cs4231a
= {
631 .minimum_version_id
= 1,
632 .pre_load
= cs4231a_pre_load
,
633 .post_load
= cs4231a_post_load
,
634 .fields
= (VMStateField
[]) {
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 ()
645 static const MemoryRegionOps cs_ioport_ops
= {
649 .min_access_size
= 1,
650 .max_access_size
= 1,
654 static void cs4231a_initfn (Object
*obj
)
656 CSState
*s
= CS4231A (obj
);
658 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
662 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
664 ISADevice
*d
= ISA_DEVICE (dev
);
665 CSState
*s
= CS4231A (dev
);
668 s
->isa_dma
= isa_get_dma(isa_bus_from_device(d
), s
->dma
);
670 error_setg(errp
, "ISA controller does not support DMA");
674 isa_init_irq(d
, &s
->pic
, s
->irq
);
675 k
= ISADMA_GET_CLASS(s
->isa_dma
);
676 k
->register_channel(s
->isa_dma
, s
->dma
, cs_dma_read
, s
);
678 isa_register_ioport (d
, &s
->ioports
, s
->port
);
680 AUD_register_card ("cs4231a", &s
->card
);
683 static int cs4231a_init (ISABus
*bus
)
685 isa_create_simple (bus
, TYPE_CS4231A
);
689 static Property cs4231a_properties
[] = {
690 DEFINE_PROP_UINT32 ("iobase", CSState
, port
, 0x534),
691 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
692 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
693 DEFINE_PROP_END_OF_LIST (),
696 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
698 DeviceClass
*dc
= DEVICE_CLASS (klass
);
700 dc
->realize
= cs4231a_realizefn
;
701 dc
->reset
= cs4231a_reset
;
702 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
703 dc
->desc
= "Crystal Semiconductor CS4231A";
704 dc
->vmsd
= &vmstate_cs4231a
;
705 dc
->props
= cs4231a_properties
;
708 static const TypeInfo cs4231a_info
= {
709 .name
= TYPE_CS4231A
,
710 .parent
= TYPE_ISA_DEVICE
,
711 .instance_size
= sizeof (CSState
),
712 .instance_init
= cs4231a_initfn
,
713 .class_init
= cs4231a_class_initfn
,
716 static void cs4231a_register_types (void)
718 type_register_static (&cs4231a_info
);
719 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
722 type_init (cs4231a_register_types
)