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