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