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