Convert machine registration to use module init functions
[qemu.git] / hw / cs4231a.c
blob33c9460722935ed563203ef64a9fc8ea9c6d21e8
1 /*
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
22 * THE SOFTWARE.
24 #include "hw.h"
25 #include "audiodev.h"
26 #include "audio/audio.h"
27 #include "isa.h"
28 #include "qemu-timer.h"
31 Missing features:
32 ADC
33 Loopback
34 Timer
35 ADPCM
36 More...
39 /* #define DEBUG */
40 /* #define DEBUG_XLAW */
42 static struct {
43 int irq;
44 int dma;
45 int port;
46 int aci_counter;
47 } conf = {9, 3, 0x534, 1};
49 #ifdef DEBUG
50 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
51 #else
52 #define dolog(...)
53 #endif
55 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
56 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
58 #define CS_REGS 16
59 #define CS_DREGS 32
61 typedef struct CSState {
62 QEMUSoundCard card;
63 qemu_irq *pic;
64 uint32_t regs[CS_REGS];
65 uint8_t dregs[CS_DREGS];
66 int irq;
67 int dma;
68 int port;
69 int shift;
70 int dma_running;
71 int audio_free;
72 int transferred;
73 int aci_counter;
74 SWVoiceOut *voice;
75 int16_t *tab;
76 } CSState;
78 #define IO_READ_PROTO(name) \
79 static uint32_t name (void *opaque, uint32_t addr)
81 #define IO_WRITE_PROTO(name) \
82 static void name (void *opaque, uint32_t addr, uint32_t val)
84 #define GET_SADDR(addr) (addr & 3)
86 #define MODE2 (1 << 6)
87 #define MCE (1 << 6)
88 #define PMCE (1 << 4)
89 #define CMCE (1 << 5)
90 #define TE (1 << 6)
91 #define PEN (1 << 0)
92 #define INT (1 << 0)
93 #define IEN (1 << 1)
94 #define PPIO (1 << 6)
95 #define PI (1 << 4)
96 #define CI (1 << 5)
97 #define TI (1 << 6)
99 enum {
100 Index_Address,
101 Index_Data,
102 Status,
103 PIO_Data
106 enum {
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,
117 Pin_Control,
118 Error_Status_And_Initialization,
119 MODE_And_ID,
120 Loopback_Control,
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,
127 Timer_Low_Base,
128 Timer_High_Base,
129 RESERVED,
130 Alternate_Feature_Enable_III,
131 Alternate_Feature_Status,
132 Version_Chip_ID,
133 Mono_Input_And_Output_Control,
134 RESERVED_2,
135 Capture_Data_Format,
136 RESERVED_3,
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 cs_reset(void *opaque)
221 CSState *s = opaque;
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)
264 CSState *s = opaque;
265 s->audio_free = free;
268 static void cs_reset_voices (CSState *s, uint32_t val)
270 int xtal;
271 struct audsettings as;
273 #ifdef DEBUG_XLAW
274 if (val == 0 || val == 32)
275 val = (1 << 4) | (1 << 5);
276 #endif
278 xtal = val & 1;
279 as.freq = freqs[xtal][(val >> 1) & 7];
281 if (as.freq == -1) {
282 lerr ("unsupported frequency (val=%#x)\n", val);
283 goto error;
286 as.nchannels = (val & (1 << 4)) ? 2 : 1;
287 as.endianness = 0;
288 s->tab = NULL;
290 switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
291 case 0:
292 as.fmt = AUD_FMT_U8;
293 s->shift = as.nchannels == 2;
294 break;
296 case 1:
297 s->tab = MuLawDecompressTable;
298 goto x_law;
299 case 3:
300 s->tab = ALawDecompressTable;
301 x_law:
302 as.fmt = AUD_FMT_S16;
303 as.endianness = AUDIO_HOST_ENDIANNESS;
304 s->shift = as.nchannels == 2;
305 break;
307 case 6:
308 as.endianness = 1;
309 case 2:
310 as.fmt = AUD_FMT_S16;
311 s->shift = as.nchannels;
312 break;
314 case 7:
315 case 4:
316 lerr ("attempt to use reserved format value (%#x)\n", val);
317 goto error;
319 case 5:
320 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
321 goto error;
324 s->voice = AUD_open_out (
325 &s->card,
326 s->voice,
327 "cs4231a",
329 cs_audio_callback,
333 if (s->dregs[Interface_Configuration] & PEN) {
334 if (!s->dma_running) {
335 DMA_hold_DREQ (s->dma);
336 AUD_set_active_out (s->voice, 1);
337 s->transferred = 0;
339 s->dma_running = 1;
341 else {
342 if (s->dma_running) {
343 DMA_release_DREQ (s->dma);
344 AUD_set_active_out (s->voice, 0);
346 s->dma_running = 0;
348 return;
350 error:
351 if (s->dma_running) {
352 DMA_release_DREQ (s->dma);
353 AUD_set_active_out (s->voice, 0);
357 IO_READ_PROTO (cs_read)
359 CSState *s = opaque;
360 uint32_t saddr, iaddr, ret;
362 saddr = GET_SADDR (addr);
363 iaddr = ~0U;
365 switch (saddr) {
366 case Index_Address:
367 ret = s->regs[saddr] & ~0x80;
368 break;
370 case Index_Data:
371 if (!(s->dregs[MODE_And_ID] & MODE2))
372 iaddr = s->regs[Index_Address] & 0x0f;
373 else
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) {
380 ret |= 1 << 5;
381 s->aci_counter -= 1;
384 break;
386 default:
387 ret = s->regs[saddr];
388 break;
390 dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
391 return ret;
394 IO_WRITE_PROTO (cs_write)
396 CSState *s = opaque;
397 uint32_t saddr, iaddr;
399 saddr = GET_SADDR (addr);
401 switch (saddr) {
402 case Index_Address:
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);
408 break;
410 case Index_Data:
411 if (!(s->dregs[MODE_And_ID] & MODE2))
412 iaddr = s->regs[Index_Address] & 0x0f;
413 else
414 iaddr = s->regs[Index_Address] & 0x1f;
416 switch (iaddr) {
417 case RESERVED:
418 case RESERVED_2:
419 case RESERVED_3:
420 lwarn ("attempt to write %#x to reserved indirect register %d\n",
421 val, iaddr);
422 break;
424 case FS_And_Playback_Data_Format:
425 if (s->regs[Index_Address] & MCE) {
426 cs_reset_voices (s, val);
428 else {
429 if (s->dregs[Alternate_Feature_Status] & PMCE) {
430 val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
431 cs_reset_voices (s, val);
433 else {
434 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
435 s->regs[Index_Address],
436 s->dregs[Alternate_Feature_Status],
437 val);
438 break;
441 s->dregs[iaddr] = val;
442 break;
444 case Interface_Configuration:
445 val &= ~(1 << 5); /* D5 is reserved */
446 s->dregs[iaddr] = val;
447 if (val & PPIO) {
448 lwarn ("PIO is not supported (%#x)\n", val);
449 break;
451 if (val & PEN) {
452 if (!s->dma_running) {
453 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
456 else {
457 if (s->dma_running) {
458 DMA_release_DREQ (s->dma);
459 AUD_set_active_out (s->voice, 0);
460 s->dma_running = 0;
463 break;
465 case Error_Status_And_Initialization:
466 lwarn ("attempt to write to read only register %d\n", iaddr);
467 break;
469 case MODE_And_ID:
470 dolog ("val=%#x\n", val);
471 if (val & MODE2)
472 s->dregs[iaddr] |= MODE2;
473 else
474 s->dregs[iaddr] &= ~MODE2;
475 break;
477 case Alternate_Feature_Enable_I:
478 if (val & TE)
479 lerr ("timer is not yet supported\n");
480 s->dregs[iaddr] = val;
481 break;
483 case Alternate_Feature_Status:
484 if ((s->dregs[iaddr] & PI) && !(val & PI)) {
485 /* XXX: TI CI */
486 qemu_irq_lower (s->pic[s->irq]);
487 s->regs[Status] &= ~INT;
489 s->dregs[iaddr] = val;
490 break;
492 case Version_Chip_ID:
493 lwarn ("write to Version_Chip_ID register %#x\n", val);
494 s->dregs[iaddr] = val;
495 break;
497 default:
498 s->dregs[iaddr] = val;
499 break;
501 dolog ("written value %#x to indirect register %d\n", val, iaddr);
502 break;
504 case Status:
505 if (s->regs[Status] & INT) {
506 qemu_irq_lower (s->pic[s->irq]);
508 s->regs[Status] &= ~INT;
509 s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
510 break;
512 case PIO_Data:
513 lwarn ("attempt to write value %#x to PIO register\n", val);
514 break;
518 static int cs_write_audio (CSState *s, int nchan, int dma_pos,
519 int dma_len, int len)
521 int temp, net;
522 uint8_t tmpbuf[4096];
524 temp = len;
525 net = 0;
527 while (temp) {
528 int left = dma_len - dma_pos;
529 int copied;
530 size_t to_copy;
532 to_copy = audio_MIN (temp, left);
533 if (to_copy > sizeof (tmpbuf)) {
534 to_copy = sizeof (tmpbuf);
537 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
538 if (s->tab) {
539 int i;
540 int16_t linbuf[4096];
542 for (i = 0; i < copied; ++i)
543 linbuf[i] = s->tab[tmpbuf[i]];
544 copied = AUD_write (s->voice, linbuf, copied << 1);
545 copied >>= 1;
547 else {
548 copied = AUD_write (s->voice, tmpbuf, copied);
551 temp -= copied;
552 dma_pos = (dma_pos + copied) % dma_len;
553 net += copied;
555 if (!copied) {
556 break;
560 return net;
563 static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
565 CSState *s = opaque;
566 int copy, written;
567 int till = -1;
569 copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
571 if (s->dregs[Pin_Control] & IEN) {
572 till = (s->dregs[Playback_Lower_Base_Count]
573 | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
574 till -= s->transferred;
575 copy = audio_MIN (till, copy);
578 if ((copy <= 0) || (dma_len <= 0)) {
579 return dma_pos;
582 written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
584 dma_pos = (dma_pos + written) % dma_len;
585 s->audio_free -= (written << (s->tab != NULL));
587 if (written == till) {
588 s->regs[Status] |= INT;
589 s->dregs[Alternate_Feature_Status] |= PI;
590 s->transferred = 0;
591 qemu_irq_raise (s->pic[s->irq]);
593 else {
594 s->transferred += written;
597 return dma_pos;
600 static void cs_save(QEMUFile *f, void *opaque)
602 CSState *s = opaque;
603 unsigned int i;
604 uint32_t val;
606 for (i = 0; i < CS_REGS; i++)
607 qemu_put_be32s(f, &s->regs[i]);
609 qemu_put_buffer(f, s->dregs, CS_DREGS);
610 val = s->dma_running; qemu_put_be32s(f, &val);
611 val = s->audio_free; qemu_put_be32s(f, &val);
612 val = s->transferred; qemu_put_be32s(f, &val);
613 val = s->aci_counter; qemu_put_be32s(f, &val);
616 static int cs_load(QEMUFile *f, void *opaque, int version_id)
618 CSState *s = opaque;
619 unsigned int i;
620 uint32_t val, dma_running;
622 if (version_id > 1)
623 return -EINVAL;
625 for (i = 0; i < CS_REGS; i++)
626 qemu_get_be32s(f, &s->regs[i]);
628 qemu_get_buffer(f, s->dregs, CS_DREGS);
630 qemu_get_be32s(f, &dma_running);
631 qemu_get_be32s(f, &val); s->audio_free = val;
632 qemu_get_be32s(f, &val); s->transferred = val;
633 qemu_get_be32s(f, &val); s->aci_counter = val;
634 if (dma_running && (s->dregs[Interface_Configuration] & PEN))
635 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
636 return 0;
639 int cs4231a_init (qemu_irq *pic)
641 int i;
642 CSState *s;
644 s = qemu_mallocz (sizeof (*s));
646 s->pic = pic;
647 s->irq = conf.irq;
648 s->dma = conf.dma;
649 s->port = conf.port;
651 for (i = 0; i < 4; i++) {
652 register_ioport_write (s->port + i, 1, 1, cs_write, s);
653 register_ioport_read (s->port + i, 1, 1, cs_read, s);
656 DMA_register_channel (s->dma, cs_dma_read, s);
658 register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
659 qemu_register_reset (cs_reset, s);
660 cs_reset (s);
662 AUD_register_card ("cs4231a", &s->card);
663 return 0;