static int milkymist_ac97_init(SysBusDevice *dev) { MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev); struct audsettings as; sysbus_init_irq(dev, &s->crrequest_irq); sysbus_init_irq(dev, &s->crreply_irq); sysbus_init_irq(dev, &s->dmar_irq); sysbus_init_irq(dev, &s->dmaw_irq); AUD_register_card("Milkymist AC'97", &s->card); as.freq = 48000; as.nchannels = 2; as.fmt = AUD_FMT_S16; as.endianness = 1; s->voice_in = AUD_open_in(&s->card, s->voice_in, "mm_ac97.in", s, ac97_in_cb, &as); s->voice_out = AUD_open_out(&s->card, s->voice_out, "mm_ac97.out", s, ac97_out_cb, &as); memory_region_init_io(&s->regs_region, &ac97_mmio_ops, s, "milkymist-ac97", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); return 0; }
static int virtio_audio_load(QEMUFile *f, void *opaque, int version_id) { VirtIOAudio *s = opaque; VirtIOAudioStream *stream; int i; int mode; if (version_id != 1) return -EINVAL; /* FIXME: Do bad things happen if there is a transfer in progress? */ virtio_load(&s->vdev, f); for (i = 0; i < NUM_STREAMS; i++) { stream = &s->stream[i]; stream->has_buffer = 0; stream->data_left = 0; if (stream->in_voice) { AUD_close_in(&s->card, stream->in_voice); stream->in_voice = NULL; } if (stream->out_voice) { AUD_close_out(&s->card, stream->out_voice); stream->out_voice = NULL; } mode = qemu_get_byte(f); stream->fmt.endianness = qemu_get_byte(f); stream->fmt.nchannels = qemu_get_be16(f); stream->fmt.fmt = qemu_get_be32(f); stream->fmt.freq = qemu_get_be32(f); if (mode & 2) { stream->in_voice = AUD_open_in(&s->card, stream->in_voice, "virtio-audio.in", stream, virtio_audio_callback, &stream->fmt); AUD_set_active_in(stream->in_voice, mode & 1); } else if (mode & 4) { stream->out_voice = AUD_open_out(&s->card, stream->out_voice, "virtio-audio.out", stream, virtio_audio_callback, &stream->fmt); AUD_set_active_out(stream->out_voice, mode & 1); } } return 0; }
static void milkymist_ac97_realize(DeviceState *dev, Error **errp) { MilkymistAC97State *s = MILKYMIST_AC97(dev); struct audsettings as; AUD_register_card("Milkymist AC'97", &s->card); as.freq = 48000; as.nchannels = 2; as.fmt = AUD_FMT_S16; as.endianness = 1; s->voice_in = AUD_open_in(&s->card, s->voice_in, "mm_ac97.in", s, ac97_in_cb, &as); s->voice_out = AUD_open_out(&s->card, s->voice_out, "mm_ac97.out", s, ac97_out_cb, &as); }
static void hda_audio_setup(HDAAudioStream *st) { if (st->node == NULL) { return; } dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", st->node->name, st->as.nchannels, fmt2name[st->as.fmt], st->as.freq); if (st->output) { st->voice.out = AUD_open_out(&st->state->card, st->voice.out, st->node->name, st, hda_audio_output_cb, &st->as); } else { st->voice.in = AUD_open_in(&st->state->card, st->voice.in, st->node->name, st, hda_audio_input_cb, &st->as); } }
static void continue_dma8 (SB16State *s) { if (s->freq > 0) { struct audsettings as; s->audio_free = 0; as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; as.endianness = 0; s->voice = AUD_open_out ( &s->card, s->voice, "sb16", s, SB_audio_callback, &as ); } control (s, 1); }
static void cs_reset_voices (CSState *s, uint32_t val) { int xtal; struct audsettings as; #ifdef DEBUG_XLAW if (val == 0 || val == 32) val = (1 << 4) | (1 << 5); #endif xtal = val & 1; as.freq = freqs[xtal][(val >> 1) & 7]; if (as.freq == -1) { lerr ("unsupported frequency (val=%#x)\n", val); goto error; } as.nchannels = (val & (1 << 4)) ? 2 : 1; as.endianness = 0; s->tab = NULL; switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) { case 0: as.fmt = AUD_FMT_U8; s->shift = as.nchannels == 2; break; case 1: s->tab = MuLawDecompressTable; goto x_law; case 3: s->tab = ALawDecompressTable; x_law: as.fmt = AUD_FMT_S16; as.endianness = AUDIO_HOST_ENDIANNESS; s->shift = as.nchannels == 2; break; case 6: as.endianness = 1; case 2: as.fmt = AUD_FMT_S16; s->shift = as.nchannels; break; case 7: case 4: lerr ("attempt to use reserved format value (%#x)\n", val); goto error; case 5: lerr ("ADPCM 4 bit IMA compatible format is not supported\n"); goto error; } s->voice = AUD_open_out ( &s->card, s->voice, "cs4231a", s, cs_audio_callback, &as ); if (s->dregs[Interface_Configuration] & PEN) { if (!s->dma_running) { DMA_hold_DREQ (s->dma); AUD_set_active_out (s->voice, 1); s->transferred = 0; } s->dma_running = 1; } else { if (s->dma_running) { DMA_release_DREQ (s->dma); AUD_set_active_out (s->voice, 0); } s->dma_running = 0; } return; error: if (s->dma_running) { DMA_release_DREQ (s->dma); AUD_set_active_out (s->voice, 0); } }
static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) { s->use_hdma = cmd < 0xc0; s->fifo = (cmd >> 1) & 1; s->dma_auto = (cmd >> 2) & 1; s->fmt_signed = (d0 >> 4) & 1; s->fmt_stereo = (d0 >> 5) & 1; switch (cmd >> 4) { case 11: s->fmt_bits = 16; break; case 12: s->fmt_bits = 8; break; } if (-1 != s->time_const) { #if 1 int tmp = 256 - s->time_const; s->freq = (1000000 + (tmp / 2)) / tmp; #else /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */ s->freq = 1000000 / ((255 - s->time_const)); #endif s->time_const = -1; } s->block_size = dma_len + 1; s->block_size <<= (s->fmt_bits == 16); if (!s->dma_auto) { /* It is clear that for DOOM and auto-init this value shouldn't take stereo into account, while Miles Sound Systems setsound.exe with single transfer mode wouldn't work without it wonders of SB16 yet again */ s->block_size <<= s->fmt_stereo; } ldebug ("freq %d, stereo %d, sign %d, bits %d, " "dma %d, auto %d, fifo %d, high %d\n", s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, s->block_size, s->dma_auto, s->fifo, s->highspeed); if (16 == s->fmt_bits) { if (s->fmt_signed) { s->fmt = AUD_FMT_S16; } else { s->fmt = AUD_FMT_U16; } } else { if (s->fmt_signed) { s->fmt = AUD_FMT_S8; } else { s->fmt = AUD_FMT_U8; } } s->left_till_irq = s->block_size; s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); s->highspeed = 0; s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; if (s->block_size & s->align) { dolog ("warning: misaligned block size %d, alignment %d\n", s->block_size, s->align + 1); } if (s->freq) { struct audsettings as; s->audio_free = 0; as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; as.endianness = 0; s->voice = AUD_open_out ( &s->card, s->voice, "sb16", s, SB_audio_callback, &as ); } control (s, 1); speaker (s, 1); }
/* Command queue. */ static void virtio_audio_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) { VirtIOAudio *s = to_virtio_audio(vdev); VirtIOAudioStream *stream; VirtQueueElement elem; int out_n; uint32_t *p; int len; size_t out_bytes; uint32_t value; while (virtqueue_pop(s->cmd_vq, &elem)) { size_t bytes_transferred = 0; for (out_n = 0; out_n < elem.out_num; out_n++) { p = (uint32_t *)elem.out_sg[out_n].iov_base; len = elem.out_sg[out_n].iov_len; while (len > 0) { if (len < 12) { BADF("Bad command length\n"); break; } DPRINTF("Command %d %d %d\n", ldl_p(p), ldl_p(p + 1), ldl_p (p + 2)); value = ldl_p(p + 1); if (value >= NUM_STREAMS) break; stream = &s->stream[value]; value = ldl_p(p + 2); switch (ldl_p(p)) { case VIRTIO_AUDIO_CMD_SET_ENDIAN: stream->fmt.endianness = value; break; case VIRTIO_AUDIO_CMD_SET_CHANNELS: stream->fmt.nchannels = value; break; case VIRTIO_AUDIO_CMD_SET_FMT: stream->fmt.fmt = value; break; case VIRTIO_AUDIO_CMD_SET_FREQ: stream->fmt.freq = value; break; case VIRTIO_AUDIO_CMD_INIT: out_bytes = 0; if (value == 1) { if (stream->out_voice) { AUD_close_out(&s->card, stream->out_voice); stream->out_voice = NULL; } stream->in_voice = AUD_open_in(&s->card, stream->in_voice, "virtio-audio.in", stream, virtio_audio_callback, &stream->fmt); virtio_audio_cmd_result(0, &elem, &out_bytes); } else if (value == 0) { if (stream->in_voice) { AUD_close_in(&s->card, stream->in_voice); stream->in_voice = NULL; } stream->out_voice = AUD_open_out(&s->card, stream->out_voice, "virtio-audio.out", stream, virtio_audio_callback, &stream->fmt); value = AUD_get_buffer_size_out(stream->out_voice); virtio_audio_cmd_result(value, &elem, &out_bytes); } else { // let us close all down if (stream->out_voice) { AUD_close_out(&s->card, stream->out_voice); stream->out_voice = NULL; } if (stream->in_voice) { AUD_close_in(&s->card, stream->in_voice); stream->in_voice = NULL; } } bytes_transferred += out_bytes; break; case VIRTIO_AUDIO_CMD_RUN: if (stream->in_voice) { AUD_set_active_in(stream->in_voice, value); } else if (stream->out_voice) { AUD_set_active_out(stream->out_voice, value); } else { DPRINTF("Cannot execute CMD_RUN as no voice is active\n"); } break; } p += 3; len -= 12; bytes_transferred += 12; } } virtqueue_push(s->cmd_vq, &elem, bytes_transferred); virtio_notify(vdev, s->cmd_vq); } }