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