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"
29 #include "hw/isa/isa.h"
31 #include "qemu/module.h"
32 #include "qemu/timer.h"
33 #include "qapi/error.h"
45 /* #define DEBUG_XLAW */
52 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
57 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
58 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
63 #define TYPE_CS4231A "cs4231a"
64 #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
66 typedef struct CSState
{
71 uint32_t regs
[CS_REGS
];
72 uint8_t dregs
[CS_DREGS
];
86 #define MODE2 (1 << 6)
107 Left_ADC_Input_Control
,
108 Right_ADC_Input_Control
,
109 Left_AUX1_Input_Control
,
110 Right_AUX1_Input_Control
,
111 Left_AUX2_Input_Control
,
112 Right_AUX2_Input_Control
,
113 Left_DAC_Output_Control
,
114 Right_DAC_Output_Control
,
115 FS_And_Playback_Data_Format
,
116 Interface_Configuration
,
118 Error_Status_And_Initialization
,
121 Playback_Upper_Base_Count
,
122 Playback_Lower_Base_Count
,
123 Alternate_Feature_Enable_I
,
124 Alternate_Feature_Enable_II
,
125 Left_Line_Input_Control
,
126 Right_Line_Input_Control
,
130 Alternate_Feature_Enable_III
,
131 Alternate_Feature_Status
,
133 Mono_Input_And_Output_Control
,
137 Capture_Upper_Base_Count
,
138 Capture_Lower_Base_Count
141 static int freqs
[2][8] = {
142 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
143 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
146 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
147 static int16_t MuLawDecompressTable
[256] =
149 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
150 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
151 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
152 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
153 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
154 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
155 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
156 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
157 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
158 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
159 -876, -844, -812, -780, -748, -716, -684, -652,
160 -620, -588, -556, -524, -492, -460, -428, -396,
161 -372, -356, -340, -324, -308, -292, -276, -260,
162 -244, -228, -212, -196, -180, -164, -148, -132,
163 -120, -112, -104, -96, -88, -80, -72, -64,
164 -56, -48, -40, -32, -24, -16, -8, 0,
165 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
166 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
167 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
168 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
169 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
170 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
171 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
172 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
173 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
174 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
175 876, 844, 812, 780, 748, 716, 684, 652,
176 620, 588, 556, 524, 492, 460, 428, 396,
177 372, 356, 340, 324, 308, 292, 276, 260,
178 244, 228, 212, 196, 180, 164, 148, 132,
179 120, 112, 104, 96, 88, 80, 72, 64,
180 56, 48, 40, 32, 24, 16, 8, 0
183 static int16_t ALawDecompressTable
[256] =
185 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
186 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
187 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
188 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
189 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
190 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
191 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
192 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
193 -344, -328, -376, -360, -280, -264, -312, -296,
194 -472, -456, -504, -488, -408, -392, -440, -424,
195 -88, -72, -120, -104, -24, -8, -56, -40,
196 -216, -200, -248, -232, -152, -136, -184, -168,
197 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
198 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
199 -688, -656, -752, -720, -560, -528, -624, -592,
200 -944, -912, -1008, -976, -816, -784, -880, -848,
201 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
202 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
203 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
204 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
205 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
206 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
207 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
208 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
209 344, 328, 376, 360, 280, 264, 312, 296,
210 472, 456, 504, 488, 408, 392, 440, 424,
211 88, 72, 120, 104, 24, 8, 56, 40,
212 216, 200, 248, 232, 152, 136, 184, 168,
213 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
214 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
215 688, 656, 752, 720, 560, 528, 624, 592,
216 944, 912, 1008, 976, 816, 784, 880, 848
219 static void cs4231a_reset (DeviceState
*dev
)
221 CSState
*s
= CS4231A (dev
);
223 s
->regs
[Index_Address
] = 0x40;
224 s
->regs
[Index_Data
] = 0x00;
225 s
->regs
[Status
] = 0x00;
226 s
->regs
[PIO_Data
] = 0x00;
228 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
229 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
230 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
231 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
232 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
233 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
234 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
235 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
236 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
237 s
->dregs
[Interface_Configuration
] = 0x08;
238 s
->dregs
[Pin_Control
] = 0x00;
239 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
240 s
->dregs
[MODE_And_ID
] = 0x8a;
241 s
->dregs
[Loopback_Control
] = 0x00;
242 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
243 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
244 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
245 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
246 s
->dregs
[Left_Line_Input_Control
] = 0x88;
247 s
->dregs
[Right_Line_Input_Control
] = 0x88;
248 s
->dregs
[Timer_Low_Base
] = 0x00;
249 s
->dregs
[Timer_High_Base
] = 0x00;
250 s
->dregs
[RESERVED
] = 0x00;
251 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
252 s
->dregs
[Alternate_Feature_Status
] = 0x00;
253 s
->dregs
[Version_Chip_ID
] = 0xa0;
254 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
255 s
->dregs
[RESERVED_2
] = 0x00;
256 s
->dregs
[Capture_Data_Format
] = 0x00;
257 s
->dregs
[RESERVED_3
] = 0x00;
258 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
259 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
262 static void cs_audio_callback (void *opaque
, int free
)
265 s
->audio_free
= free
;
268 static void cs_reset_voices (CSState
*s
, uint32_t val
)
271 struct audsettings as
;
272 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
275 if (val
== 0 || val
== 32)
276 val
= (1 << 4) | (1 << 5);
280 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
283 lerr ("unsupported frequency (val=%#x)\n", val
);
287 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
291 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
293 as
.fmt
= AUDIO_FORMAT_U8
;
294 s
->shift
= as
.nchannels
== 2;
298 s
->tab
= MuLawDecompressTable
;
301 s
->tab
= ALawDecompressTable
;
303 as
.fmt
= AUDIO_FORMAT_S16
;
304 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
305 s
->shift
= as
.nchannels
== 2;
312 as
.fmt
= AUDIO_FORMAT_S16
;
313 s
->shift
= as
.nchannels
;
318 lerr ("attempt to use reserved format value (%#x)\n", val
);
322 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
326 s
->voice
= AUD_open_out (
335 if (s
->dregs
[Interface_Configuration
] & PEN
) {
336 if (!s
->dma_running
) {
337 k
->hold_DREQ(s
->isa_dma
, s
->dma
);
338 AUD_set_active_out (s
->voice
, 1);
344 if (s
->dma_running
) {
345 k
->release_DREQ(s
->isa_dma
, s
->dma
);
346 AUD_set_active_out (s
->voice
, 0);
353 if (s
->dma_running
) {
354 k
->release_DREQ(s
->isa_dma
, s
->dma
);
355 AUD_set_active_out (s
->voice
, 0);
359 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
362 uint32_t saddr
, iaddr
, ret
;
369 ret
= s
->regs
[saddr
] & ~0x80;
373 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
374 iaddr
= s
->regs
[Index_Address
] & 0x0f;
376 iaddr
= s
->regs
[Index_Address
] & 0x1f;
378 ret
= s
->dregs
[iaddr
];
379 if (iaddr
== Error_Status_And_Initialization
) {
380 /* keep SEAL happy */
381 if (s
->aci_counter
) {
389 ret
= s
->regs
[saddr
];
392 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
396 static void cs_write (void *opaque
, hwaddr addr
,
397 uint64_t val64
, unsigned size
)
400 uint32_t saddr
, iaddr
, val
;
407 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
408 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
409 s
->aci_counter
= conf
.aci_counter
;
411 s
->regs
[Index_Address
] = val
& ~(1 << 7);
415 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
416 iaddr
= s
->regs
[Index_Address
] & 0x0f;
418 iaddr
= s
->regs
[Index_Address
] & 0x1f;
424 lwarn ("attempt to write %#x to reserved indirect register %d\n",
428 case FS_And_Playback_Data_Format
:
429 if (s
->regs
[Index_Address
] & MCE
) {
430 cs_reset_voices (s
, val
);
433 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
434 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
435 cs_reset_voices (s
, val
);
438 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
439 s
->regs
[Index_Address
],
440 s
->dregs
[Alternate_Feature_Status
],
445 s
->dregs
[iaddr
] = val
;
448 case Interface_Configuration
:
449 val
&= ~(1 << 5); /* D5 is reserved */
450 s
->dregs
[iaddr
] = val
;
452 lwarn ("PIO is not supported (%#x)\n", val
);
456 if (!s
->dma_running
) {
457 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
461 if (s
->dma_running
) {
462 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
463 k
->release_DREQ(s
->isa_dma
, s
->dma
);
464 AUD_set_active_out (s
->voice
, 0);
470 case Error_Status_And_Initialization
:
471 lwarn ("attempt to write to read only register %d\n", iaddr
);
475 dolog ("val=%#x\n", val
);
477 s
->dregs
[iaddr
] |= MODE2
;
479 s
->dregs
[iaddr
] &= ~MODE2
;
482 case Alternate_Feature_Enable_I
:
484 lerr ("timer is not yet supported\n");
485 s
->dregs
[iaddr
] = val
;
488 case Alternate_Feature_Status
:
489 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
491 qemu_irq_lower (s
->pic
);
492 s
->regs
[Status
] &= ~INT
;
494 s
->dregs
[iaddr
] = val
;
497 case Version_Chip_ID
:
498 lwarn ("write to Version_Chip_ID register %#x\n", val
);
499 s
->dregs
[iaddr
] = val
;
503 s
->dregs
[iaddr
] = val
;
506 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
510 if (s
->regs
[Status
] & INT
) {
511 qemu_irq_lower (s
->pic
);
513 s
->regs
[Status
] &= ~INT
;
514 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
518 lwarn ("attempt to write value %#x to PIO register\n", val
);
523 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
524 int dma_len
, int len
)
527 uint8_t tmpbuf
[4096];
528 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
534 int left
= dma_len
- dma_pos
;
538 to_copy
= audio_MIN (temp
, left
);
539 if (to_copy
> sizeof (tmpbuf
)) {
540 to_copy
= sizeof (tmpbuf
);
543 copied
= k
->read_memory(s
->isa_dma
, nchan
, tmpbuf
, dma_pos
, to_copy
);
546 int16_t linbuf
[4096];
548 for (i
= 0; i
< copied
; ++i
)
549 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
550 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
554 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
558 dma_pos
= (dma_pos
+ copied
) % dma_len
;
569 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
575 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
577 if (s
->dregs
[Pin_Control
] & IEN
) {
578 till
= (s
->dregs
[Playback_Lower_Base_Count
]
579 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
580 till
-= s
->transferred
;
581 copy
= audio_MIN (till
, copy
);
584 if ((copy
<= 0) || (dma_len
<= 0)) {
588 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
590 dma_pos
= (dma_pos
+ written
) % dma_len
;
591 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
593 if (written
== till
) {
594 s
->regs
[Status
] |= INT
;
595 s
->dregs
[Alternate_Feature_Status
] |= PI
;
597 qemu_irq_raise (s
->pic
);
600 s
->transferred
+= written
;
606 static int cs4231a_pre_load (void *opaque
)
610 if (s
->dma_running
) {
611 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
612 k
->release_DREQ(s
->isa_dma
, s
->dma
);
613 AUD_set_active_out (s
->voice
, 0);
619 static int cs4231a_post_load (void *opaque
, int version_id
)
623 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
625 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
630 static const VMStateDescription vmstate_cs4231a
= {
633 .minimum_version_id
= 1,
634 .pre_load
= cs4231a_pre_load
,
635 .post_load
= cs4231a_post_load
,
636 .fields
= (VMStateField
[]) {
637 VMSTATE_UINT32_ARRAY (regs
, CSState
, CS_REGS
),
638 VMSTATE_BUFFER (dregs
, CSState
),
639 VMSTATE_INT32 (dma_running
, CSState
),
640 VMSTATE_INT32 (audio_free
, CSState
),
641 VMSTATE_INT32 (transferred
, CSState
),
642 VMSTATE_INT32 (aci_counter
, CSState
),
643 VMSTATE_END_OF_LIST ()
647 static const MemoryRegionOps cs_ioport_ops
= {
651 .min_access_size
= 1,
652 .max_access_size
= 1,
656 static void cs4231a_initfn (Object
*obj
)
658 CSState
*s
= CS4231A (obj
);
660 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
664 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
666 ISADevice
*d
= ISA_DEVICE (dev
);
667 CSState
*s
= CS4231A (dev
);
670 s
->isa_dma
= isa_get_dma(isa_bus_from_device(d
), s
->dma
);
672 error_setg(errp
, "ISA controller does not support DMA");
676 isa_init_irq(d
, &s
->pic
, s
->irq
);
677 k
= ISADMA_GET_CLASS(s
->isa_dma
);
678 k
->register_channel(s
->isa_dma
, s
->dma
, cs_dma_read
, s
);
680 isa_register_ioport (d
, &s
->ioports
, s
->port
);
682 AUD_register_card ("cs4231a", &s
->card
);
685 static int cs4231a_init (ISABus
*bus
)
687 isa_create_simple (bus
, TYPE_CS4231A
);
691 static Property cs4231a_properties
[] = {
692 DEFINE_PROP_UINT32 ("iobase", CSState
, port
, 0x534),
693 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
694 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
695 DEFINE_PROP_END_OF_LIST (),
698 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
700 DeviceClass
*dc
= DEVICE_CLASS (klass
);
702 dc
->realize
= cs4231a_realizefn
;
703 dc
->reset
= cs4231a_reset
;
704 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
705 dc
->desc
= "Crystal Semiconductor CS4231A";
706 dc
->vmsd
= &vmstate_cs4231a
;
707 dc
->props
= cs4231a_properties
;
710 static const TypeInfo cs4231a_info
= {
711 .name
= TYPE_CS4231A
,
712 .parent
= TYPE_ISA_DEVICE
,
713 .instance_size
= sizeof (CSState
),
714 .instance_init
= cs4231a_initfn
,
715 .class_init
= cs4231a_class_initfn
,
718 static void cs4231a_register_types (void)
720 type_register_static (&cs4231a_info
);
721 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
724 type_init (cs4231a_register_types
)