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
25 #include "qemu/osdep.h"
27 #include "hw/audio/soundhw.h"
28 #include "audio/audio.h"
30 #include "hw/isa/isa.h"
32 #include "migration/vmstate.h"
33 #include "qemu/module.h"
34 #include "qemu/timer.h"
35 #include "qapi/error.h"
47 /* #define DEBUG_XLAW */
54 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
59 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
60 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
65 #define TYPE_CS4231A "cs4231a"
66 #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
68 typedef struct CSState
{
73 uint32_t regs
[CS_REGS
];
74 uint8_t dregs
[CS_DREGS
];
88 #define MODE2 (1 << 6)
109 Left_ADC_Input_Control
,
110 Right_ADC_Input_Control
,
111 Left_AUX1_Input_Control
,
112 Right_AUX1_Input_Control
,
113 Left_AUX2_Input_Control
,
114 Right_AUX2_Input_Control
,
115 Left_DAC_Output_Control
,
116 Right_DAC_Output_Control
,
117 FS_And_Playback_Data_Format
,
118 Interface_Configuration
,
120 Error_Status_And_Initialization
,
123 Playback_Upper_Base_Count
,
124 Playback_Lower_Base_Count
,
125 Alternate_Feature_Enable_I
,
126 Alternate_Feature_Enable_II
,
127 Left_Line_Input_Control
,
128 Right_Line_Input_Control
,
132 Alternate_Feature_Enable_III
,
133 Alternate_Feature_Status
,
135 Mono_Input_And_Output_Control
,
139 Capture_Upper_Base_Count
,
140 Capture_Lower_Base_Count
143 static int freqs
[2][8] = {
144 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
145 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
148 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
149 static int16_t MuLawDecompressTable
[256] =
151 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
152 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
153 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
154 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
155 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
156 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
157 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
158 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
159 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
160 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
161 -876, -844, -812, -780, -748, -716, -684, -652,
162 -620, -588, -556, -524, -492, -460, -428, -396,
163 -372, -356, -340, -324, -308, -292, -276, -260,
164 -244, -228, -212, -196, -180, -164, -148, -132,
165 -120, -112, -104, -96, -88, -80, -72, -64,
166 -56, -48, -40, -32, -24, -16, -8, 0,
167 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
168 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
169 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
170 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
171 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
172 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
173 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
174 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
175 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
176 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
177 876, 844, 812, 780, 748, 716, 684, 652,
178 620, 588, 556, 524, 492, 460, 428, 396,
179 372, 356, 340, 324, 308, 292, 276, 260,
180 244, 228, 212, 196, 180, 164, 148, 132,
181 120, 112, 104, 96, 88, 80, 72, 64,
182 56, 48, 40, 32, 24, 16, 8, 0
185 static int16_t ALawDecompressTable
[256] =
187 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
188 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
189 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
190 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
191 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
192 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
193 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
194 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
195 -344, -328, -376, -360, -280, -264, -312, -296,
196 -472, -456, -504, -488, -408, -392, -440, -424,
197 -88, -72, -120, -104, -24, -8, -56, -40,
198 -216, -200, -248, -232, -152, -136, -184, -168,
199 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
200 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
201 -688, -656, -752, -720, -560, -528, -624, -592,
202 -944, -912, -1008, -976, -816, -784, -880, -848,
203 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
204 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
205 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
206 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
207 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
208 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
209 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
210 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
211 344, 328, 376, 360, 280, 264, 312, 296,
212 472, 456, 504, 488, 408, 392, 440, 424,
213 88, 72, 120, 104, 24, 8, 56, 40,
214 216, 200, 248, 232, 152, 136, 184, 168,
215 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
216 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
217 688, 656, 752, 720, 560, 528, 624, 592,
218 944, 912, 1008, 976, 816, 784, 880, 848
221 static void cs4231a_reset (DeviceState
*dev
)
223 CSState
*s
= CS4231A (dev
);
225 s
->regs
[Index_Address
] = 0x40;
226 s
->regs
[Index_Data
] = 0x00;
227 s
->regs
[Status
] = 0x00;
228 s
->regs
[PIO_Data
] = 0x00;
230 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
231 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
232 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
233 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
234 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
235 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
236 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
237 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
238 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
239 s
->dregs
[Interface_Configuration
] = 0x08;
240 s
->dregs
[Pin_Control
] = 0x00;
241 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
242 s
->dregs
[MODE_And_ID
] = 0x8a;
243 s
->dregs
[Loopback_Control
] = 0x00;
244 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
245 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
246 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
247 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
248 s
->dregs
[Left_Line_Input_Control
] = 0x88;
249 s
->dregs
[Right_Line_Input_Control
] = 0x88;
250 s
->dregs
[Timer_Low_Base
] = 0x00;
251 s
->dregs
[Timer_High_Base
] = 0x00;
252 s
->dregs
[RESERVED
] = 0x00;
253 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
254 s
->dregs
[Alternate_Feature_Status
] = 0x00;
255 s
->dregs
[Version_Chip_ID
] = 0xa0;
256 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
257 s
->dregs
[RESERVED_2
] = 0x00;
258 s
->dregs
[Capture_Data_Format
] = 0x00;
259 s
->dregs
[RESERVED_3
] = 0x00;
260 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
261 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
264 static void cs_audio_callback (void *opaque
, int free
)
267 s
->audio_free
= free
;
270 static void cs_reset_voices (CSState
*s
, uint32_t val
)
273 struct audsettings as
;
274 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
277 if (val
== 0 || val
== 32)
278 val
= (1 << 4) | (1 << 5);
282 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
285 lerr ("unsupported frequency (val=%#x)\n", val
);
289 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
293 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
295 as
.fmt
= AUDIO_FORMAT_U8
;
296 s
->shift
= as
.nchannels
== 2;
300 s
->tab
= MuLawDecompressTable
;
303 s
->tab
= ALawDecompressTable
;
305 as
.fmt
= AUDIO_FORMAT_S16
;
306 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
307 s
->shift
= as
.nchannels
== 2;
314 as
.fmt
= AUDIO_FORMAT_S16
;
315 s
->shift
= as
.nchannels
;
320 lerr ("attempt to use reserved format value (%#x)\n", val
);
324 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
328 s
->voice
= AUD_open_out (
337 if (s
->dregs
[Interface_Configuration
] & PEN
) {
338 if (!s
->dma_running
) {
339 k
->hold_DREQ(s
->isa_dma
, s
->dma
);
340 AUD_set_active_out (s
->voice
, 1);
346 if (s
->dma_running
) {
347 k
->release_DREQ(s
->isa_dma
, s
->dma
);
348 AUD_set_active_out (s
->voice
, 0);
355 if (s
->dma_running
) {
356 k
->release_DREQ(s
->isa_dma
, s
->dma
);
357 AUD_set_active_out (s
->voice
, 0);
361 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
364 uint32_t saddr
, iaddr
, ret
;
371 ret
= s
->regs
[saddr
] & ~0x80;
375 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
376 iaddr
= s
->regs
[Index_Address
] & 0x0f;
378 iaddr
= s
->regs
[Index_Address
] & 0x1f;
380 ret
= s
->dregs
[iaddr
];
381 if (iaddr
== Error_Status_And_Initialization
) {
382 /* keep SEAL happy */
383 if (s
->aci_counter
) {
391 ret
= s
->regs
[saddr
];
394 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
398 static void cs_write (void *opaque
, hwaddr addr
,
399 uint64_t val64
, unsigned size
)
402 uint32_t saddr
, iaddr
, val
;
409 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
410 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
411 s
->aci_counter
= conf
.aci_counter
;
413 s
->regs
[Index_Address
] = val
& ~(1 << 7);
417 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
418 iaddr
= s
->regs
[Index_Address
] & 0x0f;
420 iaddr
= s
->regs
[Index_Address
] & 0x1f;
426 lwarn ("attempt to write %#x to reserved indirect register %d\n",
430 case FS_And_Playback_Data_Format
:
431 if (s
->regs
[Index_Address
] & MCE
) {
432 cs_reset_voices (s
, val
);
435 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
436 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
437 cs_reset_voices (s
, val
);
440 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
441 s
->regs
[Index_Address
],
442 s
->dregs
[Alternate_Feature_Status
],
447 s
->dregs
[iaddr
] = val
;
450 case Interface_Configuration
:
451 val
&= ~(1 << 5); /* D5 is reserved */
452 s
->dregs
[iaddr
] = val
;
454 lwarn ("PIO is not supported (%#x)\n", val
);
458 if (!s
->dma_running
) {
459 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
463 if (s
->dma_running
) {
464 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
465 k
->release_DREQ(s
->isa_dma
, s
->dma
);
466 AUD_set_active_out (s
->voice
, 0);
472 case Error_Status_And_Initialization
:
473 lwarn ("attempt to write to read only register %d\n", iaddr
);
477 dolog ("val=%#x\n", val
);
479 s
->dregs
[iaddr
] |= MODE2
;
481 s
->dregs
[iaddr
] &= ~MODE2
;
484 case Alternate_Feature_Enable_I
:
486 lerr ("timer is not yet supported\n");
487 s
->dregs
[iaddr
] = val
;
490 case Alternate_Feature_Status
:
491 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
493 qemu_irq_lower (s
->pic
);
494 s
->regs
[Status
] &= ~INT
;
496 s
->dregs
[iaddr
] = val
;
499 case Version_Chip_ID
:
500 lwarn ("write to Version_Chip_ID register %#x\n", val
);
501 s
->dregs
[iaddr
] = val
;
505 s
->dregs
[iaddr
] = val
;
508 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
512 if (s
->regs
[Status
] & INT
) {
513 qemu_irq_lower (s
->pic
);
515 s
->regs
[Status
] &= ~INT
;
516 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
520 lwarn ("attempt to write value %#x to PIO register\n", val
);
525 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
526 int dma_len
, int len
)
529 uint8_t tmpbuf
[4096];
530 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
536 int left
= dma_len
- dma_pos
;
540 to_copy
= audio_MIN (temp
, left
);
541 if (to_copy
> sizeof (tmpbuf
)) {
542 to_copy
= sizeof (tmpbuf
);
545 copied
= k
->read_memory(s
->isa_dma
, nchan
, tmpbuf
, dma_pos
, to_copy
);
548 int16_t linbuf
[4096];
550 for (i
= 0; i
< copied
; ++i
)
551 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
552 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
556 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
560 dma_pos
= (dma_pos
+ copied
) % dma_len
;
571 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
577 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
579 if (s
->dregs
[Pin_Control
] & IEN
) {
580 till
= (s
->dregs
[Playback_Lower_Base_Count
]
581 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
582 till
-= s
->transferred
;
583 copy
= audio_MIN (till
, copy
);
586 if ((copy
<= 0) || (dma_len
<= 0)) {
590 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
592 dma_pos
= (dma_pos
+ written
) % dma_len
;
593 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
595 if (written
== till
) {
596 s
->regs
[Status
] |= INT
;
597 s
->dregs
[Alternate_Feature_Status
] |= PI
;
599 qemu_irq_raise (s
->pic
);
602 s
->transferred
+= written
;
608 static int cs4231a_pre_load (void *opaque
)
612 if (s
->dma_running
) {
613 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
614 k
->release_DREQ(s
->isa_dma
, s
->dma
);
615 AUD_set_active_out (s
->voice
, 0);
621 static int cs4231a_post_load (void *opaque
, int version_id
)
625 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
627 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
632 static const VMStateDescription vmstate_cs4231a
= {
635 .minimum_version_id
= 1,
636 .pre_load
= cs4231a_pre_load
,
637 .post_load
= cs4231a_post_load
,
638 .fields
= (VMStateField
[]) {
639 VMSTATE_UINT32_ARRAY (regs
, CSState
, CS_REGS
),
640 VMSTATE_BUFFER (dregs
, CSState
),
641 VMSTATE_INT32 (dma_running
, CSState
),
642 VMSTATE_INT32 (audio_free
, CSState
),
643 VMSTATE_INT32 (transferred
, CSState
),
644 VMSTATE_INT32 (aci_counter
, CSState
),
645 VMSTATE_END_OF_LIST ()
649 static const MemoryRegionOps cs_ioport_ops
= {
653 .min_access_size
= 1,
654 .max_access_size
= 1,
658 static void cs4231a_initfn (Object
*obj
)
660 CSState
*s
= CS4231A (obj
);
662 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
666 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
668 ISADevice
*d
= ISA_DEVICE (dev
);
669 CSState
*s
= CS4231A (dev
);
672 s
->isa_dma
= isa_get_dma(isa_bus_from_device(d
), s
->dma
);
674 error_setg(errp
, "ISA controller does not support DMA");
678 isa_init_irq(d
, &s
->pic
, s
->irq
);
679 k
= ISADMA_GET_CLASS(s
->isa_dma
);
680 k
->register_channel(s
->isa_dma
, s
->dma
, cs_dma_read
, s
);
682 isa_register_ioport (d
, &s
->ioports
, s
->port
);
684 AUD_register_card ("cs4231a", &s
->card
);
687 static int cs4231a_init (ISABus
*bus
)
689 isa_create_simple (bus
, TYPE_CS4231A
);
693 static Property cs4231a_properties
[] = {
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 (),
700 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
702 DeviceClass
*dc
= DEVICE_CLASS (klass
);
704 dc
->realize
= cs4231a_realizefn
;
705 dc
->reset
= cs4231a_reset
;
706 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
707 dc
->desc
= "Crystal Semiconductor CS4231A";
708 dc
->vmsd
= &vmstate_cs4231a
;
709 dc
->props
= cs4231a_properties
;
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
,
720 static void cs4231a_register_types (void)
722 type_register_static (&cs4231a_info
);
723 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
726 type_init (cs4231a_register_types
)