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