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