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