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