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"
26 #include "hw/audio/soundhw.h"
27 #include "audio/audio.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"
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 typedef struct CSState CSState
;
67 DECLARE_INSTANCE_CHECKER(CSState
, CS4231A
,
75 uint32_t regs
[CS_REGS
];
76 uint8_t dregs
[CS_DREGS
];
90 #define MODE2 (1 << 6)
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
,
122 Error_Status_And_Initialization
,
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
,
134 Alternate_Feature_Enable_III
,
135 Alternate_Feature_Status
,
137 Mono_Input_And_Output_Control
,
141 Capture_Upper_Base_Count
,
142 Capture_Lower_Base_Count
145 static int freqs
[2][8] = {
146 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
147 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
150 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
151 static int16_t MuLawDecompressTable
[256] =
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
187 static int16_t ALawDecompressTable
[256] =
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
223 static void cs4231a_reset (DeviceState
*dev
)
225 CSState
*s
= CS4231A (dev
);
227 s
->regs
[Index_Address
] = 0x40;
228 s
->regs
[Index_Data
] = 0x00;
229 s
->regs
[Status
] = 0x00;
230 s
->regs
[PIO_Data
] = 0x00;
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;
266 static void cs_audio_callback (void *opaque
, int free
)
269 s
->audio_free
= free
;
272 static void cs_reset_voices (CSState
*s
, uint32_t val
)
275 struct audsettings as
;
276 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
279 if (val
== 0 || val
== 32)
280 val
= (1 << 4) | (1 << 5);
284 as
.freq
= freqs
[xtal
][(val
>> 1) & 7];
287 lerr ("unsupported frequency (val=%#x)\n", val
);
291 as
.nchannels
= (val
& (1 << 4)) ? 2 : 1;
295 switch ((val
>> 5) & ((s
->dregs
[MODE_And_ID
] & MODE2
) ? 7 : 3)) {
297 as
.fmt
= AUDIO_FORMAT_U8
;
298 s
->shift
= as
.nchannels
== 2;
302 s
->tab
= MuLawDecompressTable
;
305 s
->tab
= ALawDecompressTable
;
307 as
.fmt
= AUDIO_FORMAT_S16
;
308 as
.endianness
= AUDIO_HOST_ENDIANNESS
;
309 s
->shift
= as
.nchannels
== 2;
316 as
.fmt
= AUDIO_FORMAT_S16
;
317 s
->shift
= as
.nchannels
;
322 lerr ("attempt to use reserved format value (%#x)\n", val
);
326 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
330 s
->voice
= AUD_open_out (
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);
348 if (s
->dma_running
) {
349 k
->release_DREQ(s
->isa_dma
, s
->dma
);
350 AUD_set_active_out (s
->voice
, 0);
357 if (s
->dma_running
) {
358 k
->release_DREQ(s
->isa_dma
, s
->dma
);
359 AUD_set_active_out (s
->voice
, 0);
363 static uint64_t cs_read (void *opaque
, hwaddr addr
, unsigned size
)
366 uint32_t saddr
, iaddr
, ret
;
373 ret
= s
->regs
[saddr
] & ~0x80;
377 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
378 iaddr
= s
->regs
[Index_Address
] & 0x0f;
380 iaddr
= s
->regs
[Index_Address
] & 0x1f;
382 ret
= s
->dregs
[iaddr
];
383 if (iaddr
== Error_Status_And_Initialization
) {
384 /* keep SEAL happy */
385 if (s
->aci_counter
) {
393 ret
= s
->regs
[saddr
];
396 dolog ("read %d:%d -> %d\n", saddr
, iaddr
, ret
);
400 static void cs_write (void *opaque
, hwaddr addr
,
401 uint64_t val64
, unsigned size
)
404 uint32_t saddr
, iaddr
, val
;
411 if (!(s
->regs
[Index_Address
] & MCE
) && (val
& MCE
)
412 && (s
->dregs
[Interface_Configuration
] & (3 << 3)))
413 s
->aci_counter
= conf
.aci_counter
;
415 s
->regs
[Index_Address
] = val
& ~(1 << 7);
419 if (!(s
->dregs
[MODE_And_ID
] & MODE2
))
420 iaddr
= s
->regs
[Index_Address
] & 0x0f;
422 iaddr
= s
->regs
[Index_Address
] & 0x1f;
428 lwarn ("attempt to write %#x to reserved indirect register %d\n",
432 case FS_And_Playback_Data_Format
:
433 if (s
->regs
[Index_Address
] & MCE
) {
434 cs_reset_voices (s
, val
);
437 if (s
->dregs
[Alternate_Feature_Status
] & PMCE
) {
438 val
= (val
& ~0x0f) | (s
->dregs
[iaddr
] & 0x0f);
439 cs_reset_voices (s
, val
);
442 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
443 s
->regs
[Index_Address
],
444 s
->dregs
[Alternate_Feature_Status
],
449 s
->dregs
[iaddr
] = val
;
452 case Interface_Configuration
:
453 val
&= ~(1 << 5); /* D5 is reserved */
454 s
->dregs
[iaddr
] = val
;
456 lwarn ("PIO is not supported (%#x)\n", val
);
460 if (!s
->dma_running
) {
461 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
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);
474 case Error_Status_And_Initialization
:
475 lwarn ("attempt to write to read only register %d\n", iaddr
);
479 dolog ("val=%#x\n", val
);
481 s
->dregs
[iaddr
] |= MODE2
;
483 s
->dregs
[iaddr
] &= ~MODE2
;
486 case Alternate_Feature_Enable_I
:
488 lerr ("timer is not yet supported\n");
489 s
->dregs
[iaddr
] = val
;
492 case Alternate_Feature_Status
:
493 if ((s
->dregs
[iaddr
] & PI
) && !(val
& PI
)) {
495 qemu_irq_lower (s
->pic
);
496 s
->regs
[Status
] &= ~INT
;
498 s
->dregs
[iaddr
] = val
;
501 case Version_Chip_ID
:
502 lwarn ("write to Version_Chip_ID register %#x\n", val
);
503 s
->dregs
[iaddr
] = val
;
507 s
->dregs
[iaddr
] = val
;
510 dolog ("written value %#x to indirect register %d\n", val
, iaddr
);
514 if (s
->regs
[Status
] & INT
) {
515 qemu_irq_lower (s
->pic
);
517 s
->regs
[Status
] &= ~INT
;
518 s
->dregs
[Alternate_Feature_Status
] &= ~(PI
| CI
| TI
);
522 lwarn ("attempt to write value %#x to PIO register\n", val
);
527 static int cs_write_audio (CSState
*s
, int nchan
, int dma_pos
,
528 int dma_len
, int len
)
531 uint8_t tmpbuf
[4096];
532 IsaDmaClass
*k
= ISADMA_GET_CLASS(s
->isa_dma
);
538 int left
= dma_len
- dma_pos
;
542 to_copy
= MIN (temp
, left
);
543 if (to_copy
> sizeof (tmpbuf
)) {
544 to_copy
= sizeof (tmpbuf
);
547 copied
= k
->read_memory(s
->isa_dma
, nchan
, tmpbuf
, dma_pos
, to_copy
);
550 int16_t linbuf
[4096];
552 for (i
= 0; i
< copied
; ++i
)
553 linbuf
[i
] = s
->tab
[tmpbuf
[i
]];
554 copied
= AUD_write (s
->voice
, linbuf
, copied
<< 1);
558 copied
= AUD_write (s
->voice
, tmpbuf
, copied
);
562 dma_pos
= (dma_pos
+ copied
) % dma_len
;
573 static int cs_dma_read (void *opaque
, int nchan
, int dma_pos
, int dma_len
)
579 copy
= s
->voice
? (s
->audio_free
>> (s
->tab
!= NULL
)) : dma_len
;
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
);
588 if ((copy
<= 0) || (dma_len
<= 0)) {
592 written
= cs_write_audio (s
, nchan
, dma_pos
, dma_len
, copy
);
594 dma_pos
= (dma_pos
+ written
) % dma_len
;
595 s
->audio_free
-= (written
<< (s
->tab
!= NULL
));
597 if (written
== till
) {
598 s
->regs
[Status
] |= INT
;
599 s
->dregs
[Alternate_Feature_Status
] |= PI
;
601 qemu_irq_raise (s
->pic
);
604 s
->transferred
+= written
;
610 static int cs4231a_pre_load (void *opaque
)
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);
623 static int cs4231a_post_load (void *opaque
, int version_id
)
627 if (s
->dma_running
&& (s
->dregs
[Interface_Configuration
] & PEN
)) {
629 cs_reset_voices (s
, s
->dregs
[FS_And_Playback_Data_Format
]);
634 static const VMStateDescription vmstate_cs4231a
= {
637 .minimum_version_id
= 1,
638 .pre_load
= cs4231a_pre_load
,
639 .post_load
= cs4231a_post_load
,
640 .fields
= (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 ()
651 static const MemoryRegionOps cs_ioport_ops
= {
655 .min_access_size
= 1,
656 .max_access_size
= 1,
660 static void cs4231a_initfn (Object
*obj
)
662 CSState
*s
= CS4231A (obj
);
664 memory_region_init_io (&s
->ioports
, OBJECT(s
), &cs_ioport_ops
, s
,
668 static void cs4231a_realizefn (DeviceState
*dev
, Error
**errp
)
670 ISADevice
*d
= ISA_DEVICE (dev
);
671 CSState
*s
= CS4231A (dev
);
674 s
->isa_dma
= isa_get_dma(isa_bus_from_device(d
), s
->dma
);
676 error_setg(errp
, "ISA controller does not support DMA");
680 isa_init_irq(d
, &s
->pic
, s
->irq
);
681 k
= ISADMA_GET_CLASS(s
->isa_dma
);
682 k
->register_channel(s
->isa_dma
, s
->dma
, cs_dma_read
, s
);
684 isa_register_ioport (d
, &s
->ioports
, s
->port
);
686 AUD_register_card ("cs4231a", &s
->card
);
689 static Property cs4231a_properties
[] = {
690 DEFINE_AUDIO_PROPERTIES(CSState
, card
),
691 DEFINE_PROP_UINT32 ("iobase", CSState
, port
, 0x534),
692 DEFINE_PROP_UINT32 ("irq", CSState
, irq
, 9),
693 DEFINE_PROP_UINT32 ("dma", CSState
, dma
, 3),
694 DEFINE_PROP_END_OF_LIST (),
697 static void cs4231a_class_initfn (ObjectClass
*klass
, void *data
)
699 DeviceClass
*dc
= DEVICE_CLASS (klass
);
701 dc
->realize
= cs4231a_realizefn
;
702 dc
->reset
= cs4231a_reset
;
703 set_bit(DEVICE_CATEGORY_SOUND
, dc
->categories
);
704 dc
->desc
= "Crystal Semiconductor CS4231A";
705 dc
->vmsd
= &vmstate_cs4231a
;
706 device_class_set_props(dc
, cs4231a_properties
);
709 static const TypeInfo cs4231a_info
= {
710 .name
= TYPE_CS4231A
,
711 .parent
= TYPE_ISA_DEVICE
,
712 .instance_size
= sizeof (CSState
),
713 .instance_init
= cs4231a_initfn
,
714 .class_init
= cs4231a_class_initfn
,
717 static void cs4231a_register_types (void)
719 type_register_static (&cs4231a_info
);
720 deprecated_register_soundhw("cs4231a", "CS4231A", 1, TYPE_CS4231A
);
723 type_init (cs4231a_register_types
)