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