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 IsaDma *isa_dma; 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 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 96 enum { 97 Index_Address, 98 Index_Data, 99 Status, 100 PIO_Data 101 }; 102 103 enum { 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 138 static 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 */ 144 static 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 180 static 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 216 static void cs4231a_reset (DeviceState *dev) 217 { 218 CSState *s = CS4231A (dev); 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 259 static void cs_audio_callback (void *opaque, int free) 260 { 261 CSState *s = opaque; 262 s->audio_free = free; 263 } 264 265 static void cs_reset_voices (CSState *s, uint32_t val) 266 { 267 int xtal; 268 struct audsettings as; 269 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); 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) { 333 k->hold_DREQ(s->isa_dma, s->dma); 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) { 341 k->release_DREQ(s->isa_dma, s->dma); 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) { 350 k->release_DREQ(s->isa_dma, s->dma); 351 AUD_set_active_out (s->voice, 0); 352 } 353 } 354 355 static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size) 356 { 357 CSState *s = opaque; 358 uint32_t saddr, iaddr, ret; 359 360 saddr = addr; 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 392 static void cs_write (void *opaque, hwaddr addr, 393 uint64_t val64, unsigned size) 394 { 395 CSState *s = opaque; 396 uint32_t saddr, iaddr, val; 397 398 saddr = addr; 399 val = val64; 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) { 458 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); 459 k->release_DREQ(s->isa_dma, s->dma); 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 */ 487 qemu_irq_lower (s->pic); 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) { 507 qemu_irq_lower (s->pic); 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 519 static 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]; 524 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); 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 539 copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy); 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 565 static 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; 593 qemu_irq_raise (s->pic); 594 } 595 else { 596 s->transferred += written; 597 } 598 599 return dma_pos; 600 } 601 602 static int cs4231a_pre_load (void *opaque) 603 { 604 CSState *s = opaque; 605 606 if (s->dma_running) { 607 IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); 608 k->release_DREQ(s->isa_dma, s->dma); 609 AUD_set_active_out (s->voice, 0); 610 } 611 s->dma_running = 0; 612 return 0; 613 } 614 615 static int cs4231a_post_load (void *opaque, int version_id) 616 { 617 CSState *s = opaque; 618 619 if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) { 620 s->dma_running = 0; 621 cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); 622 } 623 return 0; 624 } 625 626 static const VMStateDescription vmstate_cs4231a = { 627 .name = "cs4231a", 628 .version_id = 1, 629 .minimum_version_id = 1, 630 .pre_load = cs4231a_pre_load, 631 .post_load = cs4231a_post_load, 632 .fields = (VMStateField[]) { 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 () 640 } 641 }; 642 643 static 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 652 static void cs4231a_initfn (Object *obj) 653 { 654 CSState *s = CS4231A (obj); 655 656 memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s, 657 "cs4231a", 4); 658 } 659 660 static void cs4231a_realizefn (DeviceState *dev, Error **errp) 661 { 662 ISADevice *d = ISA_DEVICE (dev); 663 CSState *s = CS4231A (dev); 664 IsaDmaClass *k; 665 666 isa_init_irq (d, &s->pic, s->irq); 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); 670 671 isa_register_ioport (d, &s->ioports, s->port); 672 673 AUD_register_card ("cs4231a", &s->card); 674 } 675 676 static int cs4231a_init (ISABus *bus) 677 { 678 isa_create_simple (bus, TYPE_CS4231A); 679 return 0; 680 } 681 682 static Property cs4231a_properties[] = { 683 DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534), 684 DEFINE_PROP_UINT32 ("irq", CSState, irq, 9), 685 DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), 686 DEFINE_PROP_END_OF_LIST (), 687 }; 688 689 static void cs4231a_class_initfn (ObjectClass *klass, void *data) 690 { 691 DeviceClass *dc = DEVICE_CLASS (klass); 692 693 dc->realize = cs4231a_realizefn; 694 dc->reset = cs4231a_reset; 695 set_bit(DEVICE_CATEGORY_SOUND, dc->categories); 696 dc->desc = "Crystal Semiconductor CS4231A"; 697 dc->vmsd = &vmstate_cs4231a; 698 dc->props = cs4231a_properties; 699 } 700 701 static const TypeInfo cs4231a_info = { 702 .name = TYPE_CS4231A, 703 .parent = TYPE_ISA_DEVICE, 704 .instance_size = sizeof (CSState), 705 .instance_init = cs4231a_initfn, 706 .class_init = cs4231a_class_initfn, 707 }; 708 709 static void cs4231a_register_types (void) 710 { 711 type_register_static (&cs4231a_info); 712 isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init); 713 } 714 715 type_init (cs4231a_register_types) 716