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/audio.h"
27 #include "audio/audio.h"
28 #include "hw/isa/isa.h"
30 #include "qemu/timer.h"
42 /* #define DEBUG_XLAW */
49 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
54 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
55 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
60 #define TYPE_CS4231A "cs4231a"
61 #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A)
63 typedef struct CSState
{
68 uint32_t regs
[CS_REGS
];
69 uint8_t dregs
[CS_DREGS
];
83 #define MODE2 (1 << 6)
104 Left_ADC_Input_Control
,
105 Right_ADC_Input_Control
,
106 Left_AUX1_Input_Control
,
107 Right_AUX1_Input_Control
,
108 Left_AUX2_Input_Control
,
109 Right_AUX2_Input_Control
,
110 Left_DAC_Output_Control
,
111 Right_DAC_Output_Control
,
112 FS_And_Playback_Data_Format
,
113 Interface_Configuration
,
115 Error_Status_And_Initialization
,
118 Playback_Upper_Base_Count
,
119 Playback_Lower_Base_Count
,
120 Alternate_Feature_Enable_I
,
121 Alternate_Feature_Enable_II
,
122 Left_Line_Input_Control
,
123 Right_Line_Input_Control
,
127 Alternate_Feature_Enable_III
,
128 Alternate_Feature_Status
,
130 Mono_Input_And_Output_Control
,
134 Capture_Upper_Base_Count
,
135 Capture_Lower_Base_Count
138 static int freqs
[2][8] = {
139 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
140 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
143 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
144 static int16_t MuLawDecompressTable
[256] =
146 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
147 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
148 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
149 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
150 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
151 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
152 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
153 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
154 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
155 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
156 -876, -844, -812, -780, -748, -716, -684, -652,
157 -620, -588, -556, -524, -492, -460, -428, -396,
158 -372, -356, -340, -324, -308, -292, -276, -260,
159 -244, -228, -212, -196, -180, -164, -148, -132,
160 -120, -112, -104, -96, -88, -80, -72, -64,
161 -56, -48, -40, -32, -24, -16, -8, 0,
162 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
163 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
164 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
165 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
166 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
167 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
168 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
169 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
170 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
171 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
172 876, 844, 812, 780, 748, 716, 684, 652,
173 620, 588, 556, 524, 492, 460, 428, 396,
174 372, 356, 340, 324, 308, 292, 276, 260,
175 244, 228, 212, 196, 180, 164, 148, 132,
176 120, 112, 104, 96, 88, 80, 72, 64,
177 56, 48, 40, 32, 24, 16, 8, 0
180 static int16_t ALawDecompressTable
[256] =
182 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
183 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
184 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
185 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
186 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
187 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
188 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
189 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
190 -344, -328, -376, -360, -280, -264, -312, -296,
191 -472, -456, -504, -488, -408, -392, -440, -424,
192 -88, -72, -120, -104, -24, -8, -56, -40,
193 -216, -200, -248, -232, -152, -136, -184, -168,
194 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
195 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
196 -688, -656, -752, -720, -560, -528, -624, -592,
197 -944, -912, -1008, -976, -816, -784, -880, -848,
198 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
199 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
200 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
201 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
202 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
203 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
204 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
205 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
206 344, 328, 376, 360, 280, 264, 312, 296,
207 472, 456, 504, 488, 408, 392, 440, 424,
208 88, 72, 120, 104, 24, 8, 56, 40,
209 216, 200, 248, 232, 152, 136, 184, 168,
210 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
211 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
212 688, 656, 752, 720, 560, 528, 624, 592,
213 944, 912, 1008, 976, 816, 784, 880, 848
216 static void cs4231a_reset (DeviceState
*dev
)
218 CSState
*s
= CS4231A (dev
);
220 s
->regs
[Index_Address
] = 0x40;
221 s
->regs
[Index_Data
] = 0x00;
222 s
->regs
[Status
] = 0x00;
223 s
->regs
[PIO_Data
] = 0x00;
225 s
->dregs
[Left_ADC_Input_Control
] = 0x00;
226 s
->dregs
[Right_ADC_Input_Control
] = 0x00;
227 s
->dregs
[Left_AUX1_Input_Control
] = 0x88;
228 s
->dregs
[Right_AUX1_Input_Control
] = 0x88;
229 s
->dregs
[Left_AUX2_Input_Control
] = 0x88;
230 s
->dregs
[Right_AUX2_Input_Control
] = 0x88;
231 s
->dregs
[Left_DAC_Output_Control
] = 0x80;
232 s
->dregs
[Right_DAC_Output_Control
] = 0x80;
233 s
->dregs
[FS_And_Playback_Data_Format
] = 0x00;
234 s
->dregs
[Interface_Configuration
] = 0x08;
235 s
->dregs
[Pin_Control
] = 0x00;
236 s
->dregs
[Error_Status_And_Initialization
] = 0x00;
237 s
->dregs
[MODE_And_ID
] = 0x8a;
238 s
->dregs
[Loopback_Control
] = 0x00;
239 s
->dregs
[Playback_Upper_Base_Count
] = 0x00;
240 s
->dregs
[Playback_Lower_Base_Count
] = 0x00;
241 s
->dregs
[Alternate_Feature_Enable_I
] = 0x00;
242 s
->dregs
[Alternate_Feature_Enable_II
] = 0x00;
243 s
->dregs
[Left_Line_Input_Control
] = 0x88;
244 s
->dregs
[Right_Line_Input_Control
] = 0x88;
245 s
->dregs
[Timer_Low_Base
] = 0x00;
246 s
->dregs
[Timer_High_Base
] = 0x00;
247 s
->dregs
[RESERVED
] = 0x00;
248 s
->dregs
[Alternate_Feature_Enable_III
] = 0x00;
249 s
->dregs
[Alternate_Feature_Status
] = 0x00;
250 s
->dregs
[Version_Chip_ID
] = 0xa0;
251 s
->dregs
[Mono_Input_And_Output_Control
] = 0xa0;
252 s
->dregs
[RESERVED_2
] = 0x00;
253 s
->dregs
[Capture_Data_Format
] = 0x00;
254 s
->dregs
[RESERVED_3
] = 0x00;
255 s
->dregs
[Capture_Upper_Base_Count
] = 0x00;
256 s
->dregs
[Capture_Lower_Base_Count
] = 0x00;
259 static void cs_audio_callback (void *opaque
, int free
)
262 s
->audio_free
= free
;
265 static void cs_reset_voices (CSState
*s
, uint32_t val
)
268 struct audsettings as
;
269 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
272 if (val
== 0 || val
== 32)
273 val
= (1 << 4) | (1 << 5);
277 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
280 lerr ("unsupported frequency (val=%#x)\n", val
);
284 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
288 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
291 s
->shift
= as
.nchannels
== 2;
295 s
->tab
= MuLawDecompressTable
;
298 s
->tab
= ALawDecompressTable
;
300 as
.fmt
= AUD_FMT_S16
;
301 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
302 s
->shift
= as
.nchannels
== 2;
308 as
.fmt
= AUD_FMT_S16
;
309 s
->shift
= as
.nchannels
;
314 lerr ("attempt to use reserved format value (%#x)\n", val
);
318 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
322 s
->voice
= AUD_open_out (
331 if (s
->dregs
[Interface_Configuration
] & PEN
) {
332 if (!s
->dma_running
) {
333 k
->hold_DREQ(s
->isa_dma
, s
->dma
);
334 AUD_set_active_out (s
->voice
, 1);
340 if (s
->dma_running
) {
341 k
->release_DREQ(s
->isa_dma
, s
->dma
);
342 AUD_set_active_out (s
->voice
, 0);
349 if (s
->dma_running
) {
350 k
->release_DREQ(s
->isa_dma
, s
->dma
);
351 AUD_set_active_out (s
->voice
, 0);
355 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
358 uint32_t saddr
, iaddr
, ret
;
365 ret
= s
->regs
[saddr
] & ~0x80;
369 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
370 iaddr
= s
->regs
[Index_Address
] & 0x0f;
372 iaddr
= s
->regs
[Index_Address
] & 0x1f;
374 ret
= s
->dregs
[iaddr
];
375 if (iaddr
== Error_Status_And_Initialization
) {
376 /* keep SEAL happy */
377 if (s
->aci_counter
) {
385 ret
= s
->regs
[saddr
];
388 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
392 static void cs_write (void *opaque
, hwaddr addr
,
393 uint64_t val64
, unsigned size
)
396 uint32_t saddr
, iaddr
, val
;
403 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
404 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
405 s
->aci_counter
= conf
.aci_counter
;
407 s
->regs
[Index_Address
] = val
& ~(1 << 7);
411 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
412 iaddr
= s
->regs
[Index_Address
] & 0x0f;
414 iaddr
= s
->regs
[Index_Address
] & 0x1f;
420 lwarn ("attempt to write %#x to reserved indirect register %d\n",
424 case FS_And_Playback_Data_Format
:
425 if (s
->regs
[Index_Address
] & MCE
) {
426 cs_reset_voices (s
, val
);
429 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
430 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
431 cs_reset_voices (s
, val
);
434 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
435 s
->regs
[Index_Address
],
436 s
->dregs
[Alternate_Feature_Status
],
441 s
->dregs
[iaddr
] = val
;
444 case Interface_Configuration
:
445 val
&= ~(1 << 5); /* D5 is reserved */
446 s
->dregs
[iaddr
] = val
;
448 lwarn ("PIO is not supported (%#x)\n", val
);
452 if (!s
->dma_running
) {
453 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
457 if (s
->dma_running
) {
458 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
459 k
->release_DREQ(s
->isa_dma
, s
->dma
);
460 AUD_set_active_out (s
->voice
, 0);
466 case Error_Status_And_Initialization
:
467 lwarn ("attempt to write to read only register %d\n", iaddr
);
471 dolog ("val=%#x\n", val
);
473 s
->dregs
[iaddr
] |= MODE2
;
475 s
->dregs
[iaddr
] &= ~MODE2
;
478 case Alternate_Feature_Enable_I
:
480 lerr ("timer is not yet supported\n");
481 s
->dregs
[iaddr
] = val
;
484 case Alternate_Feature_Status
:
485 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
487 qemu_irq_lower (s
->pic
);
488 s
->regs
[Status
] &= ~INT
;
490 s
->dregs
[iaddr
] = val
;
493 case Version_Chip_ID
:
494 lwarn ("write to Version_Chip_ID register %#x\n", val
);
495 s
->dregs
[iaddr
] = val
;
499 s
->dregs
[iaddr
] = val
;
502 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
506 if (s
->regs
[Status
] & INT
) {
507 qemu_irq_lower (s
->pic
);
509 s
->regs
[Status
] &= ~INT
;
510 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
514 lwarn ("attempt to write value %#x to PIO register\n", val
);
519 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
520 int dma_len
, int len
)
523 uint8_t tmpbuf
[4096];
524 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
530 int left
= dma_len
- dma_pos
;
534 to_copy
= audio_MIN (temp
, left
);
535 if (to_copy
> sizeof (tmpbuf
)) {
536 to_copy
= sizeof (tmpbuf
);
539 copied
= k
->read_memory(s
->isa_dma
, nchan
, tmpbuf
, dma_pos
, to_copy
);
542 int16_t linbuf
[4096];
544 for (i
= 0; i
< copied
; ++i
)
545 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
546 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
550 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
554 dma_pos
= (dma_pos
+ copied
) % dma_len
;
565 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
571 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
573 if (s
->dregs
[Pin_Control
] & IEN
) {
574 till
= (s
->dregs
[Playback_Lower_Base_Count
]
575 | (s
->dregs
[Playback_Upper_Base_Count
] << 8)) << s
->shift
;
576 till
-= s
->transferred
;
577 copy
= audio_MIN (till
, copy
);
580 if ((copy
<= 0) || (dma_len
<= 0)) {
584 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
586 dma_pos
= (dma_pos
+ written
) % dma_len
;
587 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
589 if (written
== till
) {
590 s
->regs
[Status
] |= INT
;
591 s
->dregs
[Alternate_Feature_Status
] |= PI
;
593 qemu_irq_raise (s
->pic
);
596 s
->transferred
+= written
;
602 static int cs4231a_pre_load (void *opaque
)
606 if (s
->dma_running
) {
607 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
608 k
->release_DREQ(s
->isa_dma
, s
->dma
);
609 AUD_set_active_out (s
->voice
, 0);
615 static int cs4231a_post_load (void *opaque
, int version_id
)
619 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
621 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
626 static const VMStateDescription vmstate_cs4231a
= {
629 .minimum_version_id
= 1,
630 .pre_load
= cs4231a_pre_load
,
631 .post_load
= cs4231a_post_load
,
632 .fields
= (VMStateField
[]) {
633 VMSTATE_UINT32_ARRAY (regs
, CSState
, CS_REGS
),
634 VMSTATE_BUFFER (dregs
, CSState
),
635 VMSTATE_INT32 (dma_running
, CSState
),
636 VMSTATE_INT32 (audio_free
, CSState
),
637 VMSTATE_INT32 (transferred
, CSState
),
638 VMSTATE_INT32 (aci_counter
, CSState
),
639 VMSTATE_END_OF_LIST ()
643 static const MemoryRegionOps cs_ioport_ops
= {
647 .min_access_size
= 1,
648 .max_access_size
= 1,
652 static void cs4231a_initfn (Object
*obj
)
654 CSState
*s
= CS4231A (obj
);
656 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
660 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
662 ISADevice
*d
= ISA_DEVICE (dev
);
663 CSState
*s
= CS4231A (dev
);
666 isa_init_irq (d
, &s
->pic
, s
->irq
);
667 s
->isa_dma
= isa_get_dma(isa_bus_from_device(d
), s
->dma
);
668 k
= ISADMA_GET_CLASS(s
->isa_dma
);
669 k
->register_channel(s
->isa_dma
, s
->dma
, cs_dma_read
, s
);
671 isa_register_ioport (d
, &s
->ioports
, s
->port
);
673 AUD_register_card ("cs4231a", &s
->card
);
676 static int cs4231a_init (ISABus
*bus
)
678 isa_create_simple (bus
, TYPE_CS4231A
);
682 static Property cs4231a_properties
[] = {
683 DEFINE_PROP_UINT32 ("iobase", CSState
, port
, 0x534),
684 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
685 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
686 DEFINE_PROP_END_OF_LIST (),
689 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
691 DeviceClass
*dc
= DEVICE_CLASS (klass
);
693 dc
->realize
= cs4231a_realizefn
;
694 dc
->reset
= cs4231a_reset
;
695 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
696 dc
->desc
= "Crystal Semiconductor CS4231A";
697 dc
->vmsd
= &vmstate_cs4231a
;
698 dc
->props
= cs4231a_properties
;
701 static const TypeInfo cs4231a_info
= {
702 .name
= TYPE_CS4231A
,
703 .parent
= TYPE_ISA_DEVICE
,
704 .instance_size
= sizeof (CSState
),
705 .instance_init
= cs4231a_initfn
,
706 .class_init
= cs4231a_class_initfn
,
709 static void cs4231a_register_types (void)
711 type_register_static (&cs4231a_info
);
712 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init
);
715 type_init (cs4231a_register_types
)