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