]> git.proxmox.com Git - qemu.git/blame - hw/cs4231a.c
Merge branch 'vga.1' of git://git.kraxel.org/qemu
[qemu.git] / hw / cs4231a.c
CommitLineData
cc53d26d 1/*
2 * QEMU Crystal CS4231 audio chip emulation
3 *
4 * Copyright (c) 2006 Fabrice Bellard
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
24#include "hw.h"
25#include "audiodev.h"
26#include "audio/audio.h"
27#include "isa.h"
f8ba7846 28#include "qdev.h"
cc53d26d 29#include "qemu-timer.h"
30
31/*
32 Missing features:
33 ADC
34 Loopback
35 Timer
36 ADPCM
37 More...
38*/
39
40/* #define DEBUG */
77599a1f 41/* #define DEBUG_XLAW */
cc53d26d 42
43static struct {
cc53d26d 44 int aci_counter;
f8ba7846 45} conf = {1};
cc53d26d 46
47#ifdef DEBUG
48#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
49#else
50#define dolog(...)
51#endif
52
53#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
54#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
55
56#define CS_REGS 16
57#define CS_DREGS 32
58
59typedef struct CSState {
f8ba7846 60 ISADevice dev;
cc53d26d 61 QEMUSoundCard card;
beae3979 62 MemoryRegion ioports;
3a38d437 63 qemu_irq pic;
cc53d26d 64 uint32_t regs[CS_REGS];
65 uint8_t dregs[CS_DREGS];
f8ba7846
GH
66 uint32_t irq;
67 uint32_t dma;
68 uint32_t port;
cc53d26d 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;
77
cc53d26d 78#define MODE2 (1 << 6)
79#define MCE (1 << 6)
80#define PMCE (1 << 4)
81#define CMCE (1 << 5)
82#define TE (1 << 6)
83#define PEN (1 << 0)
84#define INT (1 << 0)
85#define IEN (1 << 1)
86#define PPIO (1 << 6)
87#define PI (1 << 4)
88#define CI (1 << 5)
89#define TI (1 << 6)
90
91enum {
92 Index_Address,
93 Index_Data,
94 Status,
95 PIO_Data
96};
97
98enum {
99 Left_ADC_Input_Control,
100 Right_ADC_Input_Control,
101 Left_AUX1_Input_Control,
102 Right_AUX1_Input_Control,
103 Left_AUX2_Input_Control,
104 Right_AUX2_Input_Control,
105 Left_DAC_Output_Control,
106 Right_DAC_Output_Control,
107 FS_And_Playback_Data_Format,
108 Interface_Configuration,
109 Pin_Control,
110 Error_Status_And_Initialization,
111 MODE_And_ID,
112 Loopback_Control,
113 Playback_Upper_Base_Count,
114 Playback_Lower_Base_Count,
115 Alternate_Feature_Enable_I,
116 Alternate_Feature_Enable_II,
117 Left_Line_Input_Control,
118 Right_Line_Input_Control,
119 Timer_Low_Base,
120 Timer_High_Base,
121 RESERVED,
122 Alternate_Feature_Enable_III,
123 Alternate_Feature_Status,
124 Version_Chip_ID,
125 Mono_Input_And_Output_Control,
126 RESERVED_2,
127 Capture_Data_Format,
128 RESERVED_3,
129 Capture_Upper_Base_Count,
130 Capture_Lower_Base_Count
131};
132
133static int freqs[2][8] = {
134 { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
135 { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
136};
137
138/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
139static int16_t MuLawDecompressTable[256] =
140{
141 -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
142 -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
143 -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
144 -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
145 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
146 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
147 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
148 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
149 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
150 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
151 -876, -844, -812, -780, -748, -716, -684, -652,
152 -620, -588, -556, -524, -492, -460, -428, -396,
153 -372, -356, -340, -324, -308, -292, -276, -260,
154 -244, -228, -212, -196, -180, -164, -148, -132,
155 -120, -112, -104, -96, -88, -80, -72, -64,
156 -56, -48, -40, -32, -24, -16, -8, 0,
157 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
158 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
159 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
160 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
161 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
162 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
163 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
164 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
165 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
166 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
167 876, 844, 812, 780, 748, 716, 684, 652,
168 620, 588, 556, 524, 492, 460, 428, 396,
169 372, 356, 340, 324, 308, 292, 276, 260,
170 244, 228, 212, 196, 180, 164, 148, 132,
171 120, 112, 104, 96, 88, 80, 72, 64,
172 56, 48, 40, 32, 24, 16, 8, 0
173};
174
175static int16_t ALawDecompressTable[256] =
176{
177 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
178 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
179 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
180 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
181 -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
182 -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
183 -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
184 -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
185 -344, -328, -376, -360, -280, -264, -312, -296,
186 -472, -456, -504, -488, -408, -392, -440, -424,
187 -88, -72, -120, -104, -24, -8, -56, -40,
188 -216, -200, -248, -232, -152, -136, -184, -168,
189 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
190 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
191 -688, -656, -752, -720, -560, -528, -624, -592,
192 -944, -912, -1008, -976, -816, -784, -880, -848,
193 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
194 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
195 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
196 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
197 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
198 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
199 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
200 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
201 344, 328, 376, 360, 280, 264, 312, 296,
202 472, 456, 504, 488, 408, 392, 440, 424,
203 88, 72, 120, 104, 24, 8, 56, 40,
204 216, 200, 248, 232, 152, 136, 184, 168,
205 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
206 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
207 688, 656, 752, 720, 560, 528, 624, 592,
208 944, 912, 1008, 976, 816, 784, 880, 848
209};
210
d999f7e0 211static void cs_reset (void *opaque)
cc53d26d 212{
213 CSState *s = opaque;
214
215 s->regs[Index_Address] = 0x40;
216 s->regs[Index_Data] = 0x00;
217 s->regs[Status] = 0x00;
218 s->regs[PIO_Data] = 0x00;
219
220 s->dregs[Left_ADC_Input_Control] = 0x00;
221 s->dregs[Right_ADC_Input_Control] = 0x00;
222 s->dregs[Left_AUX1_Input_Control] = 0x88;
223 s->dregs[Right_AUX1_Input_Control] = 0x88;
224 s->dregs[Left_AUX2_Input_Control] = 0x88;
225 s->dregs[Right_AUX2_Input_Control] = 0x88;
226 s->dregs[Left_DAC_Output_Control] = 0x80;
227 s->dregs[Right_DAC_Output_Control] = 0x80;
228 s->dregs[FS_And_Playback_Data_Format] = 0x00;
229 s->dregs[Interface_Configuration] = 0x08;
230 s->dregs[Pin_Control] = 0x00;
231 s->dregs[Error_Status_And_Initialization] = 0x00;
232 s->dregs[MODE_And_ID] = 0x8a;
233 s->dregs[Loopback_Control] = 0x00;
234 s->dregs[Playback_Upper_Base_Count] = 0x00;
235 s->dregs[Playback_Lower_Base_Count] = 0x00;
236 s->dregs[Alternate_Feature_Enable_I] = 0x00;
237 s->dregs[Alternate_Feature_Enable_II] = 0x00;
238 s->dregs[Left_Line_Input_Control] = 0x88;
239 s->dregs[Right_Line_Input_Control] = 0x88;
240 s->dregs[Timer_Low_Base] = 0x00;
241 s->dregs[Timer_High_Base] = 0x00;
242 s->dregs[RESERVED] = 0x00;
243 s->dregs[Alternate_Feature_Enable_III] = 0x00;
244 s->dregs[Alternate_Feature_Status] = 0x00;
245 s->dregs[Version_Chip_ID] = 0xa0;
246 s->dregs[Mono_Input_And_Output_Control] = 0xa0;
247 s->dregs[RESERVED_2] = 0x00;
248 s->dregs[Capture_Data_Format] = 0x00;
249 s->dregs[RESERVED_3] = 0x00;
250 s->dregs[Capture_Upper_Base_Count] = 0x00;
251 s->dregs[Capture_Lower_Base_Count] = 0x00;
252}
253
254static void cs_audio_callback (void *opaque, int free)
255{
256 CSState *s = opaque;
257 s->audio_free = free;
258}
259
260static void cs_reset_voices (CSState *s, uint32_t val)
261{
262 int xtal;
1ea879e5 263 struct audsettings as;
cc53d26d 264
265#ifdef DEBUG_XLAW
266 if (val == 0 || val == 32)
267 val = (1 << 4) | (1 << 5);
268#endif
269
270 xtal = val & 1;
271 as.freq = freqs[xtal][(val >> 1) & 7];
272
273 if (as.freq == -1) {
274 lerr ("unsupported frequency (val=%#x)\n", val);
275 goto error;
276 }
277
278 as.nchannels = (val & (1 << 4)) ? 2 : 1;
279 as.endianness = 0;
280 s->tab = NULL;
281
282 switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
283 case 0:
284 as.fmt = AUD_FMT_U8;
285 s->shift = as.nchannels == 2;
286 break;
287
288 case 1:
289 s->tab = MuLawDecompressTable;
290 goto x_law;
291 case 3:
292 s->tab = ALawDecompressTable;
293 x_law:
294 as.fmt = AUD_FMT_S16;
295 as.endianness = AUDIO_HOST_ENDIANNESS;
296 s->shift = as.nchannels == 2;
297 break;
298
299 case 6:
300 as.endianness = 1;
301 case 2:
302 as.fmt = AUD_FMT_S16;
303 s->shift = as.nchannels;
304 break;
305
306 case 7:
307 case 4:
308 lerr ("attempt to use reserved format value (%#x)\n", val);
309 goto error;
310
311 case 5:
312 lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
313 goto error;
314 }
315
316 s->voice = AUD_open_out (
317 &s->card,
318 s->voice,
319 "cs4231a",
320 s,
321 cs_audio_callback,
322 &as
323 );
324
325 if (s->dregs[Interface_Configuration] & PEN) {
326 if (!s->dma_running) {
327 DMA_hold_DREQ (s->dma);
328 AUD_set_active_out (s->voice, 1);
329 s->transferred = 0;
330 }
331 s->dma_running = 1;
332 }
333 else {
334 if (s->dma_running) {
335 DMA_release_DREQ (s->dma);
336 AUD_set_active_out (s->voice, 0);
337 }
338 s->dma_running = 0;
339 }
340 return;
341
342 error:
343 if (s->dma_running) {
344 DMA_release_DREQ (s->dma);
345 AUD_set_active_out (s->voice, 0);
346 }
347}
348
a8170e5e 349static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
cc53d26d 350{
351 CSState *s = opaque;
352 uint32_t saddr, iaddr, ret;
353
beae3979 354 saddr = addr;
cc53d26d 355 iaddr = ~0U;
356
357 switch (saddr) {
358 case Index_Address:
359 ret = s->regs[saddr] & ~0x80;
360 break;
361
362 case Index_Data:
363 if (!(s->dregs[MODE_And_ID] & MODE2))
364 iaddr = s->regs[Index_Address] & 0x0f;
365 else
366 iaddr = s->regs[Index_Address] & 0x1f;
367
368 ret = s->dregs[iaddr];
369 if (iaddr == Error_Status_And_Initialization) {
370 /* keep SEAL happy */
371 if (s->aci_counter) {
372 ret |= 1 << 5;
373 s->aci_counter -= 1;
374 }
375 }
376 break;
377
378 default:
379 ret = s->regs[saddr];
380 break;
381 }
382 dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
383 return ret;
384}
385
a8170e5e 386static void cs_write (void *opaque, hwaddr addr,
8acbc9b2 387 uint64_t val64, unsigned size)
cc53d26d 388{
389 CSState *s = opaque;
beae3979 390 uint32_t saddr, iaddr, val;
cc53d26d 391
beae3979
RH
392 saddr = addr;
393 val = val64;
cc53d26d 394
395 switch (saddr) {
396 case Index_Address:
397 if (!(s->regs[Index_Address] & MCE) && (val & MCE)
398 && (s->dregs[Interface_Configuration] & (3 << 3)))
399 s->aci_counter = conf.aci_counter;
400
401 s->regs[Index_Address] = val & ~(1 << 7);
402 break;
403
404 case Index_Data:
405 if (!(s->dregs[MODE_And_ID] & MODE2))
406 iaddr = s->regs[Index_Address] & 0x0f;
407 else
408 iaddr = s->regs[Index_Address] & 0x1f;
409
410 switch (iaddr) {
411 case RESERVED:
412 case RESERVED_2:
413 case RESERVED_3:
414 lwarn ("attempt to write %#x to reserved indirect register %d\n",
415 val, iaddr);
416 break;
417
418 case FS_And_Playback_Data_Format:
419 if (s->regs[Index_Address] & MCE) {
420 cs_reset_voices (s, val);
421 }
422 else {
423 if (s->dregs[Alternate_Feature_Status] & PMCE) {
424 val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
425 cs_reset_voices (s, val);
426 }
427 else {
428 lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
429 s->regs[Index_Address],
430 s->dregs[Alternate_Feature_Status],
431 val);
432 break;
433 }
434 }
435 s->dregs[iaddr] = val;
436 break;
437
438 case Interface_Configuration:
439 val &= ~(1 << 5); /* D5 is reserved */
440 s->dregs[iaddr] = val;
441 if (val & PPIO) {
442 lwarn ("PIO is not supported (%#x)\n", val);
443 break;
444 }
445 if (val & PEN) {
446 if (!s->dma_running) {
447 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
448 }
449 }
450 else {
451 if (s->dma_running) {
452 DMA_release_DREQ (s->dma);
453 AUD_set_active_out (s->voice, 0);
454 s->dma_running = 0;
455 }
456 }
457 break;
458
459 case Error_Status_And_Initialization:
460 lwarn ("attempt to write to read only register %d\n", iaddr);
461 break;
462
463 case MODE_And_ID:
464 dolog ("val=%#x\n", val);
465 if (val & MODE2)
466 s->dregs[iaddr] |= MODE2;
467 else
468 s->dregs[iaddr] &= ~MODE2;
469 break;
470
471 case Alternate_Feature_Enable_I:
472 if (val & TE)
473 lerr ("timer is not yet supported\n");
474 s->dregs[iaddr] = val;
475 break;
476
477 case Alternate_Feature_Status:
478 if ((s->dregs[iaddr] & PI) && !(val & PI)) {
479 /* XXX: TI CI */
3a38d437 480 qemu_irq_lower (s->pic);
cc53d26d 481 s->regs[Status] &= ~INT;
482 }
483 s->dregs[iaddr] = val;
484 break;
485
486 case Version_Chip_ID:
487 lwarn ("write to Version_Chip_ID register %#x\n", val);
488 s->dregs[iaddr] = val;
489 break;
490
491 default:
492 s->dregs[iaddr] = val;
493 break;
494 }
495 dolog ("written value %#x to indirect register %d\n", val, iaddr);
496 break;
497
498 case Status:
499 if (s->regs[Status] & INT) {
3a38d437 500 qemu_irq_lower (s->pic);
cc53d26d 501 }
502 s->regs[Status] &= ~INT;
503 s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
504 break;
505
506 case PIO_Data:
507 lwarn ("attempt to write value %#x to PIO register\n", val);
508 break;
509 }
510}
511
512static int cs_write_audio (CSState *s, int nchan, int dma_pos,
513 int dma_len, int len)
514{
515 int temp, net;
516 uint8_t tmpbuf[4096];
517
518 temp = len;
519 net = 0;
520
521 while (temp) {
522 int left = dma_len - dma_pos;
523 int copied;
524 size_t to_copy;
525
526 to_copy = audio_MIN (temp, left);
527 if (to_copy > sizeof (tmpbuf)) {
528 to_copy = sizeof (tmpbuf);
529 }
530
531 copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
532 if (s->tab) {
533 int i;
534 int16_t linbuf[4096];
535
536 for (i = 0; i < copied; ++i)
537 linbuf[i] = s->tab[tmpbuf[i]];
538 copied = AUD_write (s->voice, linbuf, copied << 1);
539 copied >>= 1;
540 }
541 else {
542 copied = AUD_write (s->voice, tmpbuf, copied);
543 }
544
545 temp -= copied;
546 dma_pos = (dma_pos + copied) % dma_len;
547 net += copied;
548
549 if (!copied) {
550 break;
551 }
552 }
553
554 return net;
555}
556
557static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
558{
559 CSState *s = opaque;
560 int copy, written;
561 int till = -1;
562
563 copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
564
565 if (s->dregs[Pin_Control] & IEN) {
566 till = (s->dregs[Playback_Lower_Base_Count]
567 | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
568 till -= s->transferred;
569 copy = audio_MIN (till, copy);
570 }
571
572 if ((copy <= 0) || (dma_len <= 0)) {
573 return dma_pos;
574 }
575
576 written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
577
578 dma_pos = (dma_pos + written) % dma_len;
579 s->audio_free -= (written << (s->tab != NULL));
580
581 if (written == till) {
582 s->regs[Status] |= INT;
583 s->dregs[Alternate_Feature_Status] |= PI;
584 s->transferred = 0;
3a38d437 585 qemu_irq_raise (s->pic);
cc53d26d 586 }
587 else {
588 s->transferred += written;
589 }
590
591 return dma_pos;
592}
593
1d190d5c 594static int cs4231a_pre_load (void *opaque)
cc53d26d 595{
596 CSState *s = opaque;
cc53d26d 597
1d190d5c
JQ
598 if (s->dma_running) {
599 DMA_release_DREQ (s->dma);
600 AUD_set_active_out (s->voice, 0);
601 }
602 s->dma_running = 0;
603 return 0;
cc53d26d 604}
605
1d190d5c 606static int cs4231a_post_load (void *opaque, int version_id)
cc53d26d 607{
608 CSState *s = opaque;
cc53d26d 609
1d190d5c
JQ
610 if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
611 s->dma_running = 0;
4143f3e0 612 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
1d190d5c 613 }
cc53d26d 614 return 0;
615}
616
1d190d5c
JQ
617static const VMStateDescription vmstate_cs4231a = {
618 .name = "cs4231a",
619 .version_id = 1,
620 .minimum_version_id = 1,
621 .minimum_version_id_old = 1,
622 .pre_load = cs4231a_pre_load,
623 .post_load = cs4231a_post_load,
624 .fields = (VMStateField []) {
cf4dc461 625 VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
626 VMSTATE_BUFFER (dregs, CSState),
627 VMSTATE_INT32 (dma_running, CSState),
628 VMSTATE_INT32 (audio_free, CSState),
629 VMSTATE_INT32 (transferred, CSState),
630 VMSTATE_INT32 (aci_counter, CSState),
631 VMSTATE_END_OF_LIST ()
1d190d5c
JQ
632 }
633};
634
beae3979
RH
635static const MemoryRegionOps cs_ioport_ops = {
636 .read = cs_read,
637 .write = cs_write,
638 .impl = {
639 .min_access_size = 1,
640 .max_access_size = 1,
641 }
642};
643
f8ba7846 644static int cs4231a_initfn (ISADevice *dev)
cc53d26d 645{
f8ba7846 646 CSState *s = DO_UPCAST (CSState, dev, dev);
cc53d26d 647
f8ba7846 648 isa_init_irq (dev, &s->pic, s->irq);
cc53d26d 649
8acbc9b2 650 memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
651 isa_register_ioport (dev, &s->ioports, s->port);
cc53d26d 652
653 DMA_register_channel (s->dma, cs_dma_read, s);
654
a08d4367 655 qemu_register_reset (cs_reset, s);
cc53d26d 656 cs_reset (s);
657
1a7dafce 658 AUD_register_card ("cs4231a", &s->card);
cc53d26d 659 return 0;
660}
f8ba7846 661
4a0f031d 662int cs4231a_init (ISABus *bus)
f8ba7846 663{
48a18b3c 664 isa_create_simple (bus, "cs4231a");
f8ba7846
GH
665 return 0;
666}
667
39bffca2
AL
668static Property cs4231a_properties[] = {
669 DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534),
670 DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
671 DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
672 DEFINE_PROP_END_OF_LIST (),
673};
674
cf4dc461 675static void cs4231a_class_initfn (ObjectClass *klass, void *data)
8f04ee08 676{
cf4dc461 677 DeviceClass *dc = DEVICE_CLASS (klass);
678 ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
8f04ee08 679 ic->init = cs4231a_initfn;
39bffca2
AL
680 dc->desc = "Crystal Semiconductor CS4231A";
681 dc->vmsd = &vmstate_cs4231a;
682 dc->props = cs4231a_properties;
8f04ee08
AL
683}
684
39bffca2
AL
685static TypeInfo cs4231a_info = {
686 .name = "cs4231a",
687 .parent = TYPE_ISA_DEVICE,
688 .instance_size = sizeof (CSState),
689 .class_init = cs4231a_class_initfn,
f8ba7846
GH
690};
691
83f7d43a 692static void cs4231a_register_types (void)
f8ba7846 693{
cf4dc461 694 type_register_static (&cs4231a_info);
f8ba7846 695}
83f7d43a
AF
696
697type_init (cs4231a_register_types)