1 /* 2 * QEMU Apple Sound Chip emulation 3 * 4 * Apple Sound Chip (ASC) 344S0063 5 * Enhanced Apple Sound Chip (EASC) 343S1063 6 * 7 * Copyright (c) 2012-2018 Laurent Vivier <laurent@vivier.eu> 8 * Copyright (c) 2022 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> 9 * 10 * SPDX-License-Identifier: GPL-2.0-or-later 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qemu/timer.h" 15 #include "qapi/error.h" 16 #include "hw/sysbus.h" 17 #include "hw/irq.h" 18 #include "audio/audio.h" 19 #include "hw/audio/asc.h" 20 #include "hw/qdev-properties.h" 21 #include "migration/vmstate.h" 22 #include "trace.h" 23 24 /* 25 * Linux doesn't provide information about ASC, see arch/m68k/mac/macboing.c 26 * and arch/m68k/include/asm/mac_asc.h 27 * 28 * best information is coming from MAME: 29 * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.h 30 * https://github.com/mamedev/mame/blob/master/src/devices/sound/asc.cpp 31 * Emulation by R. Belmont 32 * or MESS: 33 * http://mess.redump.net/mess/driver_info/easc 34 * 35 * 0x800: VERSION 36 * 0x801: MODE 37 * 1=FIFO mode, 38 * 2=wavetable mode 39 * 0x802: CONTROL 40 * bit 0=analog or PWM output, 41 * 1=stereo/mono, 42 * 7=processing time exceeded 43 * 0x803: FIFO MODE 44 * bit 7=clear FIFO, 45 * bit 1="non-ROM companding", 46 * bit 0="ROM companding") 47 * 0x804: FIFO IRQ STATUS 48 * bit 0=ch A 1/2 full, 49 * 1=ch A full, 50 * 2=ch B 1/2 full, 51 * 3=ch B full) 52 * 0x805: WAVETABLE CONTROL 53 * bits 0-3 wavetables 0-3 start 54 * 0x806: VOLUME 55 * bits 2-4 = 3 bit internal ASC volume, 56 * bits 5-7 = volume control sent to Sony sound chip 57 * 0x807: CLOCK RATE 58 * 0 = Mac 22257 Hz, 59 * 1 = undefined, 60 * 2 = 22050 Hz, 61 * 3 = 44100 Hz 62 * 0x80a: PLAY REC A 63 * 0x80f: TEST 64 * bits 6-7 = digital test, 65 * bits 4-5 = analog test 66 * 0x810: WAVETABLE 0 PHASE 67 * big-endian 9.15 fixed-point, only 24 bits valid 68 * 0x814: WAVETABLE 0 INCREMENT 69 * big-endian 9.15 fixed-point, only 24 bits valid 70 * 0x818: WAVETABLE 1 PHASE 71 * 0x81C: WAVETABLE 1 INCREMENT 72 * 0x820: WAVETABLE 2 PHASE 73 * 0x824: WAVETABLE 2 INCREMENT 74 * 0x828: WAVETABLE 3 PHASE 75 * 0x82C: WAVETABLE 3 INCREMENT 76 * 0x830: UNKNOWN START 77 * NetBSD writes Wavetable data here (are there more 78 * wavetables/channels than we know about?) 79 * 0x857: UNKNOWN END 80 */ 81 82 #define ASC_SIZE 0x2000 83 84 enum { 85 ASC_VERSION = 0x00, 86 ASC_MODE = 0x01, 87 ASC_CONTROL = 0x02, 88 ASC_FIFOMODE = 0x03, 89 ASC_FIFOIRQ = 0x04, 90 ASC_WAVECTRL = 0x05, 91 ASC_VOLUME = 0x06, 92 ASC_CLOCK = 0x07, 93 ASC_PLAYRECA = 0x0a, 94 ASC_TEST = 0x0f, 95 ASC_WAVETABLE = 0x10 96 }; 97 98 #define ASC_FIFO_STATUS_HALF_FULL 1 99 #define ASC_FIFO_STATUS_FULL_EMPTY 2 100 101 #define ASC_EXTREGS_FIFOCTRL 0x8 102 #define ASC_EXTREGS_INTCTRL 0x9 103 #define ASC_EXTREGS_CDXA_DECOMP_FILT 0x10 104 105 #define ASC_FIFO_CYCLE_TIME ((NANOSECONDS_PER_SECOND / ASC_FREQ) * \ 106 0x400) 107 108 static void asc_raise_irq(ASCState *s) 109 { 110 qemu_set_irq(s->irq, 1); 111 } 112 113 static void asc_lower_irq(ASCState *s) 114 { 115 qemu_set_irq(s->irq, 0); 116 } 117 118 static uint8_t asc_fifo_get(ASCFIFOState *fs) 119 { 120 ASCState *s = container_of(fs, ASCState, fifos[fs->index]); 121 bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1; 122 uint8_t val; 123 124 assert(fs->cnt); 125 126 val = fs->fifo[fs->rptr]; 127 trace_asc_fifo_get('A' + fs->index, fs->rptr, fs->cnt, val); 128 129 fs->rptr++; 130 fs->rptr &= 0x3ff; 131 fs->cnt--; 132 133 if (fs->cnt <= 0x1ff) { 134 /* FIFO less than half full */ 135 fs->int_status |= ASC_FIFO_STATUS_HALF_FULL; 136 } else { 137 /* FIFO more than half full */ 138 fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL; 139 } 140 141 if (fs->cnt == 0x1ff && fifo_half_irq_enabled) { 142 /* Raise FIFO half full IRQ */ 143 asc_raise_irq(s); 144 } 145 146 if (fs->cnt == 0) { 147 /* Raise FIFO empty IRQ */ 148 fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY; 149 asc_raise_irq(s); 150 } 151 152 return val; 153 } 154 155 static int generate_fifo(ASCState *s, int maxsamples) 156 { 157 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 158 uint8_t *buf = s->mixbuf; 159 int i, wcount = 0; 160 161 while (wcount < maxsamples) { 162 uint8_t val; 163 int16_t d, f0, f1; 164 int32_t t; 165 int shift, filter; 166 bool hasdata = false; 167 168 for (i = 0; i < 2; i++) { 169 ASCFIFOState *fs = &s->fifos[i]; 170 171 switch (fs->extregs[ASC_EXTREGS_FIFOCTRL] & 0x83) { 172 case 0x82: 173 /* 174 * CD-XA BRR mode: decompress 15 bytes into 28 16-bit 175 * samples 176 */ 177 if (!fs->cnt) { 178 val = 0x80; 179 break; 180 } 181 182 if (fs->xa_cnt == -1) { 183 /* Start of packet, get flags */ 184 fs->xa_flags = asc_fifo_get(fs); 185 fs->xa_cnt = 0; 186 } 187 188 shift = fs->xa_flags & 0xf; 189 filter = fs->xa_flags >> 4; 190 f0 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT + 191 (filter << 1) + 1]; 192 f1 = (int8_t)fs->extregs[ASC_EXTREGS_CDXA_DECOMP_FILT + 193 (filter << 1)]; 194 195 if ((fs->xa_cnt & 1) == 0) { 196 if (!fs->cnt) { 197 val = 0x80; 198 break; 199 } 200 201 fs->xa_val = asc_fifo_get(fs); 202 d = (fs->xa_val & 0xf) << 12; 203 } else { 204 d = (fs->xa_val & 0xf0) << 8; 205 } 206 t = (d >> shift) + (((fs->xa_last[0] * f0) + 207 (fs->xa_last[1] * f1) + 32) >> 6); 208 if (t < -32768) { 209 t = -32768; 210 } else if (t > 32767) { 211 t = 32767; 212 } 213 214 /* 215 * CD-XA BRR generates 16-bit signed output, so convert to 216 * 8-bit before writing to buffer. Does real hardware do the 217 * same? 218 */ 219 val = (uint8_t)(t / 256) ^ 0x80; 220 hasdata = true; 221 fs->xa_cnt++; 222 223 fs->xa_last[1] = fs->xa_last[0]; 224 fs->xa_last[0] = (int16_t)t; 225 226 if (fs->xa_cnt == 28) { 227 /* End of packet */ 228 fs->xa_cnt = -1; 229 } 230 break; 231 232 default: 233 /* fallthrough */ 234 case 0x80: 235 /* Raw mode */ 236 if (fs->cnt) { 237 val = asc_fifo_get(fs); 238 hasdata = true; 239 } else { 240 val = 0x80; 241 } 242 break; 243 } 244 245 buf[wcount * 2 + i] = val; 246 } 247 248 if (!hasdata) { 249 break; 250 } 251 252 wcount++; 253 } 254 255 /* 256 * MacOS (un)helpfully leaves the FIFO engine running even when it has 257 * finished writing out samples, but still expects the FIFO empty 258 * interrupts to be generated for each FIFO cycle (without these interrupts 259 * MacOS will freeze) 260 */ 261 if (s->fifos[0].cnt == 0 && s->fifos[1].cnt == 0) { 262 if (!s->fifo_empty_ns) { 263 /* FIFO has completed first empty cycle */ 264 s->fifo_empty_ns = now; 265 } else if (now > (s->fifo_empty_ns + ASC_FIFO_CYCLE_TIME)) { 266 /* FIFO has completed entire cycle with no data */ 267 s->fifos[0].int_status |= ASC_FIFO_STATUS_HALF_FULL | 268 ASC_FIFO_STATUS_FULL_EMPTY; 269 s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL | 270 ASC_FIFO_STATUS_FULL_EMPTY; 271 s->fifo_empty_ns = now; 272 asc_raise_irq(s); 273 } 274 } else { 275 /* FIFO contains data, reset empty time */ 276 s->fifo_empty_ns = 0; 277 } 278 279 return wcount; 280 } 281 282 static int generate_wavetable(ASCState *s, int maxsamples) 283 { 284 uint8_t *buf = s->mixbuf; 285 int channel, count = 0; 286 287 while (count < maxsamples) { 288 uint32_t left = 0, right = 0; 289 uint8_t sample; 290 291 for (channel = 0; channel < 4; channel++) { 292 ASCFIFOState *fs = &s->fifos[channel >> 1]; 293 int chanreg = ASC_WAVETABLE + (channel << 3); 294 uint32_t phase, incr, offset; 295 296 phase = ldl_be_p(&s->regs[chanreg]); 297 incr = ldl_be_p(&s->regs[chanreg + sizeof(uint32_t)]); 298 299 phase += incr; 300 offset = (phase >> 15) & 0x1ff; 301 sample = fs->fifo[0x200 * (channel >> 1) + offset]; 302 303 stl_be_p(&s->regs[chanreg], phase); 304 305 left += sample; 306 right += sample; 307 } 308 309 buf[count * 2] = left >> 2; 310 buf[count * 2 + 1] = right >> 2; 311 312 count++; 313 } 314 315 return count; 316 } 317 318 static void asc_out_cb(void *opaque, int free_b) 319 { 320 ASCState *s = opaque; 321 int samples, generated; 322 323 if (free_b == 0) { 324 return; 325 } 326 327 samples = MIN(s->samples, free_b >> s->shift); 328 329 switch (s->regs[ASC_MODE] & 3) { 330 default: 331 /* Off */ 332 generated = 0; 333 break; 334 case 1: 335 /* FIFO mode */ 336 generated = generate_fifo(s, samples); 337 break; 338 case 2: 339 /* Wave table mode */ 340 generated = generate_wavetable(s, samples); 341 break; 342 } 343 344 if (!generated) { 345 /* Workaround for audio underflow bug on Windows dsound backend */ 346 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 347 int silent_samples = muldiv64(now - s->fifo_empty_ns, 348 NANOSECONDS_PER_SECOND, ASC_FREQ); 349 350 if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) { 351 /* 352 * No new FIFO data within half a cycle time (~23ms) so fill the 353 * entire available buffer with silence. This prevents an issue 354 * with the Windows dsound backend whereby the sound appears to 355 * loop because the FIFO has run out of data, and the driver 356 * reuses the stale content in its circular audio buffer. 357 */ 358 AUD_write(s->voice, s->silentbuf, samples << s->shift); 359 } 360 return; 361 } 362 363 AUD_write(s->voice, s->mixbuf, generated << s->shift); 364 } 365 366 static uint64_t asc_fifo_read(void *opaque, hwaddr addr, 367 unsigned size) 368 { 369 ASCFIFOState *fs = opaque; 370 371 trace_asc_read_fifo('A' + fs->index, addr, size, fs->fifo[addr]); 372 return fs->fifo[addr]; 373 } 374 375 static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value, 376 unsigned size) 377 { 378 ASCFIFOState *fs = opaque; 379 ASCState *s = container_of(fs, ASCState, fifos[fs->index]); 380 bool fifo_half_irq_enabled = fs->extregs[ASC_EXTREGS_INTCTRL] & 1; 381 382 trace_asc_write_fifo('A' + fs->index, addr, size, fs->wptr, fs->cnt, value); 383 384 if (s->regs[ASC_MODE] == 1) { 385 fs->fifo[fs->wptr++] = value; 386 fs->wptr &= 0x3ff; 387 fs->cnt++; 388 389 if (fs->cnt <= 0x1ff) { 390 /* FIFO less than half full */ 391 fs->int_status |= ASC_FIFO_STATUS_HALF_FULL; 392 } else { 393 /* FIFO at least half full */ 394 fs->int_status &= ~ASC_FIFO_STATUS_HALF_FULL; 395 } 396 397 if (fs->cnt == 0x200 && fifo_half_irq_enabled) { 398 /* Raise FIFO half full interrupt */ 399 asc_raise_irq(s); 400 } 401 402 if (fs->cnt == 0x3ff) { 403 /* Raise FIFO full interrupt */ 404 fs->int_status |= ASC_FIFO_STATUS_FULL_EMPTY; 405 asc_raise_irq(s); 406 } 407 } else { 408 fs->fifo[addr] = value; 409 } 410 } 411 412 static const MemoryRegionOps asc_fifo_ops = { 413 .read = asc_fifo_read, 414 .write = asc_fifo_write, 415 .impl = { 416 .min_access_size = 1, 417 .max_access_size = 1, 418 }, 419 .endianness = DEVICE_BIG_ENDIAN, 420 }; 421 422 static void asc_fifo_reset(ASCFIFOState *fs); 423 424 static uint64_t asc_read(void *opaque, hwaddr addr, 425 unsigned size) 426 { 427 ASCState *s = opaque; 428 uint64_t prev, value; 429 430 switch (addr) { 431 case ASC_VERSION: 432 switch (s->type) { 433 default: 434 case ASC_TYPE_ASC: 435 value = 0; 436 break; 437 case ASC_TYPE_EASC: 438 value = 0xb0; 439 break; 440 } 441 break; 442 case ASC_FIFOIRQ: 443 prev = (s->fifos[0].int_status & 0x3) | 444 (s->fifos[1].int_status & 0x3) << 2; 445 446 s->fifos[0].int_status = 0; 447 s->fifos[1].int_status = 0; 448 asc_lower_irq(s); 449 value = prev; 450 break; 451 default: 452 value = s->regs[addr]; 453 break; 454 } 455 456 trace_asc_read_reg(addr, size, value); 457 return value; 458 } 459 460 static void asc_write(void *opaque, hwaddr addr, uint64_t value, 461 unsigned size) 462 { 463 ASCState *s = opaque; 464 465 switch (addr) { 466 case ASC_MODE: 467 value &= 3; 468 if (value != s->regs[ASC_MODE]) { 469 asc_fifo_reset(&s->fifos[0]); 470 asc_fifo_reset(&s->fifos[1]); 471 asc_lower_irq(s); 472 if (value != 0) { 473 AUD_set_active_out(s->voice, 1); 474 } else { 475 AUD_set_active_out(s->voice, 0); 476 } 477 } 478 break; 479 case ASC_FIFOMODE: 480 if (value & 0x80) { 481 asc_fifo_reset(&s->fifos[0]); 482 asc_fifo_reset(&s->fifos[1]); 483 asc_lower_irq(s); 484 } 485 break; 486 case ASC_WAVECTRL: 487 break; 488 case ASC_VOLUME: 489 { 490 int vol = (value & 0xe0); 491 492 AUD_set_volume_out(s->voice, 0, vol, vol); 493 break; 494 } 495 } 496 497 trace_asc_write_reg(addr, size, value); 498 s->regs[addr] = value; 499 } 500 501 static const MemoryRegionOps asc_regs_ops = { 502 .read = asc_read, 503 .write = asc_write, 504 .endianness = DEVICE_BIG_ENDIAN, 505 .impl = { 506 .min_access_size = 1, 507 .max_access_size = 1, 508 } 509 }; 510 511 static uint64_t asc_ext_read(void *opaque, hwaddr addr, 512 unsigned size) 513 { 514 ASCFIFOState *fs = opaque; 515 uint64_t value; 516 517 value = fs->extregs[addr]; 518 519 trace_asc_read_extreg('A' + fs->index, addr, size, value); 520 return value; 521 } 522 523 static void asc_ext_write(void *opaque, hwaddr addr, uint64_t value, 524 unsigned size) 525 { 526 ASCFIFOState *fs = opaque; 527 528 trace_asc_write_extreg('A' + fs->index, addr, size, value); 529 530 fs->extregs[addr] = value; 531 } 532 533 static const MemoryRegionOps asc_extregs_ops = { 534 .read = asc_ext_read, 535 .write = asc_ext_write, 536 .impl = { 537 .min_access_size = 1, 538 .max_access_size = 1, 539 }, 540 .endianness = DEVICE_BIG_ENDIAN, 541 }; 542 543 static int asc_post_load(void *opaque, int version) 544 { 545 ASCState *s = ASC(opaque); 546 547 if (s->regs[ASC_MODE] != 0) { 548 AUD_set_active_out(s->voice, 1); 549 } 550 551 return 0; 552 } 553 554 static const VMStateDescription vmstate_asc_fifo = { 555 .name = "apple-sound-chip.fifo", 556 .version_id = 0, 557 .minimum_version_id = 0, 558 .fields = (const VMStateField[]) { 559 VMSTATE_UINT8_ARRAY(fifo, ASCFIFOState, ASC_FIFO_SIZE), 560 VMSTATE_UINT8(int_status, ASCFIFOState), 561 VMSTATE_INT32(cnt, ASCFIFOState), 562 VMSTATE_INT32(wptr, ASCFIFOState), 563 VMSTATE_INT32(rptr, ASCFIFOState), 564 VMSTATE_UINT8_ARRAY(extregs, ASCFIFOState, ASC_EXTREG_SIZE), 565 VMSTATE_INT32(xa_cnt, ASCFIFOState), 566 VMSTATE_UINT8(xa_val, ASCFIFOState), 567 VMSTATE_UINT8(xa_flags, ASCFIFOState), 568 VMSTATE_INT16_ARRAY(xa_last, ASCFIFOState, 2), 569 VMSTATE_END_OF_LIST() 570 } 571 }; 572 573 static const VMStateDescription vmstate_asc = { 574 .name = "apple-sound-chip", 575 .version_id = 0, 576 .minimum_version_id = 0, 577 .post_load = asc_post_load, 578 .fields = (const VMStateField[]) { 579 VMSTATE_STRUCT_ARRAY(fifos, ASCState, 2, 0, vmstate_asc_fifo, 580 ASCFIFOState), 581 VMSTATE_UINT8_ARRAY(regs, ASCState, ASC_REG_SIZE), 582 VMSTATE_INT64(fifo_empty_ns, ASCState), 583 VMSTATE_END_OF_LIST() 584 } 585 }; 586 587 static void asc_fifo_reset(ASCFIFOState *fs) 588 { 589 fs->wptr = 0; 590 fs->rptr = 0; 591 fs->cnt = 0; 592 fs->xa_cnt = -1; 593 fs->int_status = 0; 594 } 595 596 static void asc_fifo_init(ASCFIFOState *fs, int index) 597 { 598 ASCState *s = container_of(fs, ASCState, fifos[index]); 599 char *name; 600 601 fs->index = index; 602 name = g_strdup_printf("asc.fifo%c", 'A' + index); 603 memory_region_init_io(&fs->mem_fifo, OBJECT(s), &asc_fifo_ops, fs, 604 name, ASC_FIFO_SIZE); 605 g_free(name); 606 607 name = g_strdup_printf("asc.extregs%c", 'A' + index); 608 memory_region_init_io(&fs->mem_extregs, OBJECT(s), &asc_extregs_ops, 609 fs, name, ASC_EXTREG_SIZE); 610 g_free(name); 611 } 612 613 static void asc_reset_hold(Object *obj, ResetType type) 614 { 615 ASCState *s = ASC(obj); 616 617 AUD_set_active_out(s->voice, 0); 618 619 memset(s->regs, 0, sizeof(s->regs)); 620 asc_fifo_reset(&s->fifos[0]); 621 asc_fifo_reset(&s->fifos[1]); 622 s->fifo_empty_ns = 0; 623 624 if (s->type == ASC_TYPE_ASC) { 625 /* FIFO half full IRQs enabled by default */ 626 s->fifos[0].extregs[ASC_EXTREGS_INTCTRL] = 1; 627 s->fifos[1].extregs[ASC_EXTREGS_INTCTRL] = 1; 628 } 629 } 630 631 static void asc_unrealize(DeviceState *dev) 632 { 633 ASCState *s = ASC(dev); 634 635 g_free(s->mixbuf); 636 g_free(s->silentbuf); 637 638 AUD_remove_card(&s->card); 639 } 640 641 static void asc_realize(DeviceState *dev, Error **errp) 642 { 643 ASCState *s = ASC(dev); 644 struct audsettings as; 645 646 if (!AUD_register_card("Apple Sound Chip", &s->card, errp)) { 647 return; 648 } 649 650 as.freq = ASC_FREQ; 651 as.nchannels = 2; 652 as.fmt = AUDIO_FORMAT_U8; 653 as.endianness = AUDIO_HOST_ENDIANNESS; 654 655 s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb, 656 &as); 657 if (!s->voice) { 658 AUD_remove_card(&s->card); 659 error_setg(errp, "Initializing audio stream failed"); 660 return; 661 } 662 663 s->shift = 1; 664 s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; 665 s->mixbuf = g_malloc0(s->samples << s->shift); 666 667 s->silentbuf = g_malloc(s->samples << s->shift); 668 memset(s->silentbuf, 0x80, s->samples << s->shift); 669 670 /* Add easc registers if required */ 671 if (s->type == ASC_TYPE_EASC) { 672 memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET, 673 &s->fifos[0].mem_extregs); 674 memory_region_add_subregion(&s->asc, 675 ASC_EXTREG_OFFSET + ASC_EXTREG_SIZE, 676 &s->fifos[1].mem_extregs); 677 } 678 } 679 680 static void asc_init(Object *obj) 681 { 682 ASCState *s = ASC(obj); 683 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 684 685 memory_region_init(&s->asc, OBJECT(obj), "asc", ASC_SIZE); 686 687 asc_fifo_init(&s->fifos[0], 0); 688 asc_fifo_init(&s->fifos[1], 1); 689 690 memory_region_add_subregion(&s->asc, ASC_FIFO_OFFSET, 691 &s->fifos[0].mem_fifo); 692 memory_region_add_subregion(&s->asc, 693 ASC_FIFO_OFFSET + ASC_FIFO_SIZE, 694 &s->fifos[1].mem_fifo); 695 696 memory_region_init_io(&s->mem_regs, OBJECT(obj), &asc_regs_ops, s, 697 "asc.regs", ASC_REG_SIZE); 698 memory_region_add_subregion(&s->asc, ASC_REG_OFFSET, &s->mem_regs); 699 700 sysbus_init_irq(sbd, &s->irq); 701 sysbus_init_mmio(sbd, &s->asc); 702 } 703 704 static const Property asc_properties[] = { 705 DEFINE_AUDIO_PROPERTIES(ASCState, card), 706 DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC), 707 }; 708 709 static void asc_class_init(ObjectClass *oc, const void *data) 710 { 711 DeviceClass *dc = DEVICE_CLASS(oc); 712 ResettableClass *rc = RESETTABLE_CLASS(oc); 713 714 dc->realize = asc_realize; 715 dc->unrealize = asc_unrealize; 716 set_bit(DEVICE_CATEGORY_SOUND, dc->categories); 717 dc->vmsd = &vmstate_asc; 718 device_class_set_props(dc, asc_properties); 719 rc->phases.hold = asc_reset_hold; 720 } 721 722 static const TypeInfo asc_info_types[] = { 723 { 724 .name = TYPE_ASC, 725 .parent = TYPE_SYS_BUS_DEVICE, 726 .instance_size = sizeof(ASCState), 727 .instance_init = asc_init, 728 .class_init = asc_class_init, 729 }, 730 }; 731 732 DEFINE_TYPES(asc_info_types) 733