Loading accel/stubs/tcg-stub.c +0 −4 Original line number Diff line number Diff line Loading @@ -21,10 +21,6 @@ void tb_flush(CPUState *cpu) { } void tb_unlock(void) { } void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { } audio/audio.c +1 −2 Original line number Diff line number Diff line Loading @@ -335,9 +335,8 @@ static int audio_get_conf_int (const char *key, int defval, int *defaultp) char *strval; strval = getenv (key); if (strval) { if (strval && !qemu_strtoi(strval, NULL, 10, &val)) { *defaultp = 0; val = atoi (strval); return val; } else { Loading cpus.c +4 −0 Original line number Diff line number Diff line Loading @@ -1355,6 +1355,7 @@ static int tcg_cpu_exec(CPUState *cpu) int64_t ti; #endif assert(tcg_enabled()); #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif Loading Loading @@ -1397,6 +1398,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) { CPUState *cpu = arg; assert(tcg_enabled()); rcu_register_thread(); tcg_register_thread(); Loading Loading @@ -1631,6 +1633,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *cpu = arg; assert(tcg_enabled()); g_assert(!use_icount); rcu_register_thread(); Loading Loading @@ -1854,6 +1857,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) static QemuThread *single_tcg_cpu_thread; static int tcg_region_inited; assert(tcg_enabled()); /* * Initialize TCG regions--once. Now is a good time, because: * (1) TCG's init context, prologue and target globals have been set up. Loading exec.c +3 −0 Original line number Diff line number Diff line Loading @@ -1323,6 +1323,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length) RAMBlock *block; ram_addr_t end; assert(tcg_enabled()); end = TARGET_PAGE_ALIGN(start + length); start &= TARGET_PAGE_MASK; Loading Loading @@ -2655,6 +2656,7 @@ void memory_notdirty_write_prepare(NotDirtyInfo *ndi, void memory_notdirty_write_complete(NotDirtyInfo *ndi) { if (ndi->pages) { assert(tcg_enabled()); page_collection_unlock(ndi->pages); ndi->pages = NULL; } Loading Loading @@ -3046,6 +3048,7 @@ static void tcg_commit(MemoryListener *listener) CPUAddressSpace *cpuas; AddressSpaceDispatch *d; assert(tcg_enabled()); /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); Loading hw/audio/hda-codec.c +256 −31 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ */ #include "qemu/osdep.h" #include "qemu/atomic.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "audio/audio.h" #include "trace.h" /* -------------------------------------------------------------------------- */ Loading Loading @@ -126,6 +128,10 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define PARAM nomixemu #include "hda-codec-common.h" #define HDA_TIMER_TICKS (SCALE_MS) #define B_SIZE sizeof(st->buf) #define B_MASK (sizeof(st->buf) - 1) /* -------------------------------------------------------------------------- */ static const char *fmt2name[] = { Loading Loading @@ -154,8 +160,13 @@ struct HDAAudioStream { SWVoiceIn *in; SWVoiceOut *out; } voice; uint8_t buf[HDA_BUFFER_SIZE]; uint32_t bpos; uint8_t compat_buf[HDA_BUFFER_SIZE]; uint32_t compat_bpos; uint8_t buf[8192]; /* size must be power of two */ int64_t rpos; int64_t wpos; QEMUTimer *buft; int64_t buft_start; }; #define TYPE_HDA_AUDIO "hda-audio" Loading @@ -174,55 +185,217 @@ struct HDAAudioState { /* properties */ uint32_t debug; bool mixer; bool use_timer; }; static inline int64_t hda_bytes_per_second(HDAAudioStream *st) { return 2 * st->as.nchannels * st->as.freq; } static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) { int64_t limit = B_SIZE / 8; int64_t corr = 0; if (target_pos > limit) { corr = HDA_TIMER_TICKS; } if (target_pos < -limit) { corr = -HDA_TIMER_TICKS; } if (corr == 0) { return; } trace_hda_audio_adjust(st->node->name, target_pos); atomic_fetch_add(&st->buft_start, corr); } static void hda_audio_input_timer(void *opaque) { HDAAudioStream *st = opaque; int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; wanted_rpos &= -4; /* IMPORTANT! clip to frames */ if (wanted_rpos <= rpos) { /* we already transmitted the data */ goto out_timer; } int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos); while (to_transfer) { uint32_t start = (rpos & B_MASK); uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); int rc = hda_codec_xfer( &st->state->hda, st->stream, false, st->buf + start, chunk); if (!rc) { break; } rpos += chunk; to_transfer -= chunk; atomic_fetch_add(&st->rpos, chunk); } out_timer: if (st->running) { timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } } static void hda_audio_input_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); while (to_transfer) { uint32_t start = (uint32_t) (wpos & B_MASK); uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); wpos += read; to_transfer -= read; atomic_fetch_add(&st->wpos, read); if (chunk != read) { break; } } } static void hda_audio_output_timer(void *opaque) { HDAAudioStream *st = opaque; int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; wanted_wpos &= -4; /* IMPORTANT! clip to frames */ if (wanted_wpos <= wpos) { /* we already received the data */ goto out_timer; } int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); while (to_transfer) { uint32_t start = (wpos & B_MASK); uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); int rc = hda_codec_xfer( &st->state->hda, st->stream, true, st->buf + start, chunk); if (!rc) { break; } wpos += chunk; to_transfer -= chunk; atomic_fetch_add(&st->wpos, chunk); } out_timer: if (st->running) { timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } } static void hda_audio_output_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t to_transfer = audio_MIN(wpos - rpos, avail); if (wpos - rpos == B_SIZE) { /* drop buffer, reset timer adjust */ st->rpos = 0; st->wpos = 0; st->buft_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); trace_hda_audio_overrun(st->node->name); return; } hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); while (to_transfer) { uint32_t start = (uint32_t) (rpos & B_MASK); uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); rpos += written; to_transfer -= written; atomic_fetch_add(&st->rpos, written); if (chunk != written) { break; } } } static void hda_audio_compat_input_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int recv = 0; int len; bool rc; while (avail - recv >= sizeof(st->buf)) { if (st->bpos != sizeof(st->buf)) { len = AUD_read(st->voice.in, st->buf + st->bpos, sizeof(st->buf) - st->bpos); st->bpos += len; while (avail - recv >= sizeof(st->compat_buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { len = AUD_read(st->voice.in, st->compat_buf + st->compat_bpos, sizeof(st->compat_buf) - st->compat_bpos); st->compat_bpos += len; recv += len; if (st->bpos != sizeof(st->buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } rc = hda_codec_xfer(&st->state->hda, st->stream, false, st->buf, sizeof(st->buf)); st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } st->bpos = 0; st->compat_bpos = 0; } } static void hda_audio_output_cb(void *opaque, int avail) static void hda_audio_compat_output_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int sent = 0; int len; bool rc; while (avail - sent >= sizeof(st->buf)) { if (st->bpos == sizeof(st->buf)) { while (avail - sent >= sizeof(st->compat_buf)) { if (st->compat_bpos == sizeof(st->compat_buf)) { rc = hda_codec_xfer(&st->state->hda, st->stream, true, st->buf, sizeof(st->buf)); st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } st->bpos = 0; st->compat_bpos = 0; } len = AUD_write(st->voice.out, st->buf + st->bpos, sizeof(st->buf) - st->bpos); st->bpos += len; len = AUD_write(st->voice.out, st->compat_buf + st->compat_bpos, sizeof(st->compat_buf) - st->compat_bpos); st->compat_bpos += len; sent += len; if (st->bpos != sizeof(st->buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } Loading @@ -237,8 +410,18 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) return; } st->running = running; dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, st->running ? "on" : "off", st->stream); trace_hda_audio_running(st->node->name, st->stream, st->running); if (st->state->use_timer) { if (running) { int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); st->rpos = 0; st->wpos = 0; st->buft_start = now; timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } else { timer_del(st->buft); } } if (st->output) { AUD_set_active_out(st->voice.out, st->running); } else { Loading Loading @@ -274,22 +457,36 @@ static void hda_audio_set_amp(HDAAudioStream *st) static void hda_audio_setup(HDAAudioStream *st) { bool use_timer = st->state->use_timer; audio_callback_fn cb; if (st->node == NULL) { return; } dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", st->node->name, st->as.nchannels, trace_hda_audio_format(st->node->name, st->as.nchannels, fmt2name[st->as.fmt], st->as.freq); if (st->output) { if (use_timer) { cb = hda_audio_output_cb; st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_output_timer, st); } else { cb = hda_audio_compat_output_cb; } st->voice.out = AUD_open_out(&st->state->card, st->voice.out, st->node->name, st, hda_audio_output_cb, &st->as); st->node->name, st, cb, &st->as); } else { if (use_timer) { cb = hda_audio_input_cb; st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_input_timer, st); } else { cb = hda_audio_compat_input_cb; } st->voice.in = AUD_open_in(&st->state->card, st->voice.in, st->node->name, st, hda_audio_input_cb, &st->as); st->node->name, st, cb, &st->as); } } Loading Loading @@ -505,7 +702,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) /* unmute output by default */ st->gain_left = QEMU_HDA_AMP_STEPS; st->gain_right = QEMU_HDA_AMP_STEPS; st->bpos = sizeof(st->buf); st->compat_bpos = sizeof(st->compat_buf); st->output = true; } else { st->output = false; Loading @@ -532,6 +729,9 @@ static void hda_audio_exit(HDACodecDevice *hda) if (st->node == NULL) { continue; } if (a->use_timer) { timer_del(st->buft); } if (st->output) { AUD_close_out(&a->card, st->voice.out); } else { Loading Loading @@ -581,6 +781,26 @@ static void hda_audio_reset(DeviceState *dev) } } static bool vmstate_hda_audio_stream_buf_needed(void *opaque) { HDAAudioStream *st = opaque; return st->state->use_timer; } static const VMStateDescription vmstate_hda_audio_stream_buf = { .name = "hda-audio-stream/buffer", .version_id = 1, .needed = vmstate_hda_audio_stream_buf_needed, .fields = (VMStateField[]) { VMSTATE_BUFFER(buf, HDAAudioStream), VMSTATE_INT64(rpos, HDAAudioStream), VMSTATE_INT64(wpos, HDAAudioStream), VMSTATE_TIMER_PTR(buft, HDAAudioStream), VMSTATE_INT64(buft_start, HDAAudioStream), VMSTATE_END_OF_LIST() } }; static const VMStateDescription vmstate_hda_audio_stream = { .name = "hda-audio-stream", .version_id = 1, Loading @@ -592,9 +812,13 @@ static const VMStateDescription vmstate_hda_audio_stream = { VMSTATE_UINT32(gain_right, HDAAudioStream), VMSTATE_BOOL(mute_left, HDAAudioStream), VMSTATE_BOOL(mute_right, HDAAudioStream), VMSTATE_UINT32(bpos, HDAAudioStream), VMSTATE_BUFFER(buf, HDAAudioStream), VMSTATE_UINT32(compat_bpos, HDAAudioStream), VMSTATE_BUFFER(compat_buf, HDAAudioStream), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription * []) { &vmstate_hda_audio_stream_buf, NULL } }; Loading @@ -615,6 +839,7 @@ static const VMStateDescription vmstate_hda_audio = { static Property hda_audio_properties[] = { DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0), DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true), DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true), DEFINE_PROP_END_OF_LIST(), }; Loading Loading
accel/stubs/tcg-stub.c +0 −4 Original line number Diff line number Diff line Loading @@ -21,10 +21,6 @@ void tb_flush(CPUState *cpu) { } void tb_unlock(void) { } void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) { }
audio/audio.c +1 −2 Original line number Diff line number Diff line Loading @@ -335,9 +335,8 @@ static int audio_get_conf_int (const char *key, int defval, int *defaultp) char *strval; strval = getenv (key); if (strval) { if (strval && !qemu_strtoi(strval, NULL, 10, &val)) { *defaultp = 0; val = atoi (strval); return val; } else { Loading
cpus.c +4 −0 Original line number Diff line number Diff line Loading @@ -1355,6 +1355,7 @@ static int tcg_cpu_exec(CPUState *cpu) int64_t ti; #endif assert(tcg_enabled()); #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif Loading Loading @@ -1397,6 +1398,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) { CPUState *cpu = arg; assert(tcg_enabled()); rcu_register_thread(); tcg_register_thread(); Loading Loading @@ -1631,6 +1633,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *cpu = arg; assert(tcg_enabled()); g_assert(!use_icount); rcu_register_thread(); Loading Loading @@ -1854,6 +1857,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) static QemuThread *single_tcg_cpu_thread; static int tcg_region_inited; assert(tcg_enabled()); /* * Initialize TCG regions--once. Now is a good time, because: * (1) TCG's init context, prologue and target globals have been set up. Loading
exec.c +3 −0 Original line number Diff line number Diff line Loading @@ -1323,6 +1323,7 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length) RAMBlock *block; ram_addr_t end; assert(tcg_enabled()); end = TARGET_PAGE_ALIGN(start + length); start &= TARGET_PAGE_MASK; Loading Loading @@ -2655,6 +2656,7 @@ void memory_notdirty_write_prepare(NotDirtyInfo *ndi, void memory_notdirty_write_complete(NotDirtyInfo *ndi) { if (ndi->pages) { assert(tcg_enabled()); page_collection_unlock(ndi->pages); ndi->pages = NULL; } Loading Loading @@ -3046,6 +3048,7 @@ static void tcg_commit(MemoryListener *listener) CPUAddressSpace *cpuas; AddressSpaceDispatch *d; assert(tcg_enabled()); /* since each CPU stores ram addresses in its TLB cache, we must reset the modified entries */ cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener); Loading
hw/audio/hda-codec.c +256 −31 Original line number Diff line number Diff line Loading @@ -18,11 +18,13 @@ */ #include "qemu/osdep.h" #include "qemu/atomic.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "intel-hda.h" #include "intel-hda-defs.h" #include "audio/audio.h" #include "trace.h" /* -------------------------------------------------------------------------- */ Loading Loading @@ -126,6 +128,10 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define PARAM nomixemu #include "hda-codec-common.h" #define HDA_TIMER_TICKS (SCALE_MS) #define B_SIZE sizeof(st->buf) #define B_MASK (sizeof(st->buf) - 1) /* -------------------------------------------------------------------------- */ static const char *fmt2name[] = { Loading Loading @@ -154,8 +160,13 @@ struct HDAAudioStream { SWVoiceIn *in; SWVoiceOut *out; } voice; uint8_t buf[HDA_BUFFER_SIZE]; uint32_t bpos; uint8_t compat_buf[HDA_BUFFER_SIZE]; uint32_t compat_bpos; uint8_t buf[8192]; /* size must be power of two */ int64_t rpos; int64_t wpos; QEMUTimer *buft; int64_t buft_start; }; #define TYPE_HDA_AUDIO "hda-audio" Loading @@ -174,55 +185,217 @@ struct HDAAudioState { /* properties */ uint32_t debug; bool mixer; bool use_timer; }; static inline int64_t hda_bytes_per_second(HDAAudioStream *st) { return 2 * st->as.nchannels * st->as.freq; } static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) { int64_t limit = B_SIZE / 8; int64_t corr = 0; if (target_pos > limit) { corr = HDA_TIMER_TICKS; } if (target_pos < -limit) { corr = -HDA_TIMER_TICKS; } if (corr == 0) { return; } trace_hda_audio_adjust(st->node->name, target_pos); atomic_fetch_add(&st->buft_start, corr); } static void hda_audio_input_timer(void *opaque) { HDAAudioStream *st = opaque; int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; wanted_rpos &= -4; /* IMPORTANT! clip to frames */ if (wanted_rpos <= rpos) { /* we already transmitted the data */ goto out_timer; } int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos); while (to_transfer) { uint32_t start = (rpos & B_MASK); uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); int rc = hda_codec_xfer( &st->state->hda, st->stream, false, st->buf + start, chunk); if (!rc) { break; } rpos += chunk; to_transfer -= chunk; atomic_fetch_add(&st->rpos, chunk); } out_timer: if (st->running) { timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } } static void hda_audio_input_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); while (to_transfer) { uint32_t start = (uint32_t) (wpos & B_MASK); uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); wpos += read; to_transfer -= read; atomic_fetch_add(&st->wpos, read); if (chunk != read) { break; } } } static void hda_audio_output_timer(void *opaque) { HDAAudioStream *st = opaque; int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; wanted_wpos &= -4; /* IMPORTANT! clip to frames */ if (wanted_wpos <= wpos) { /* we already received the data */ goto out_timer; } int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); while (to_transfer) { uint32_t start = (wpos & B_MASK); uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); int rc = hda_codec_xfer( &st->state->hda, st->stream, true, st->buf + start, chunk); if (!rc) { break; } wpos += chunk; to_transfer -= chunk; atomic_fetch_add(&st->wpos, chunk); } out_timer: if (st->running) { timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } } static void hda_audio_output_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int64_t wpos = atomic_fetch_add(&st->wpos, 0); int64_t rpos = atomic_fetch_add(&st->rpos, 0); int64_t to_transfer = audio_MIN(wpos - rpos, avail); if (wpos - rpos == B_SIZE) { /* drop buffer, reset timer adjust */ st->rpos = 0; st->wpos = 0; st->buft_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); trace_hda_audio_overrun(st->node->name); return; } hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); while (to_transfer) { uint32_t start = (uint32_t) (rpos & B_MASK); uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); rpos += written; to_transfer -= written; atomic_fetch_add(&st->rpos, written); if (chunk != written) { break; } } } static void hda_audio_compat_input_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int recv = 0; int len; bool rc; while (avail - recv >= sizeof(st->buf)) { if (st->bpos != sizeof(st->buf)) { len = AUD_read(st->voice.in, st->buf + st->bpos, sizeof(st->buf) - st->bpos); st->bpos += len; while (avail - recv >= sizeof(st->compat_buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { len = AUD_read(st->voice.in, st->compat_buf + st->compat_bpos, sizeof(st->compat_buf) - st->compat_bpos); st->compat_bpos += len; recv += len; if (st->bpos != sizeof(st->buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } rc = hda_codec_xfer(&st->state->hda, st->stream, false, st->buf, sizeof(st->buf)); st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } st->bpos = 0; st->compat_bpos = 0; } } static void hda_audio_output_cb(void *opaque, int avail) static void hda_audio_compat_output_cb(void *opaque, int avail) { HDAAudioStream *st = opaque; int sent = 0; int len; bool rc; while (avail - sent >= sizeof(st->buf)) { if (st->bpos == sizeof(st->buf)) { while (avail - sent >= sizeof(st->compat_buf)) { if (st->compat_bpos == sizeof(st->compat_buf)) { rc = hda_codec_xfer(&st->state->hda, st->stream, true, st->buf, sizeof(st->buf)); st->compat_buf, sizeof(st->compat_buf)); if (!rc) { break; } st->bpos = 0; st->compat_bpos = 0; } len = AUD_write(st->voice.out, st->buf + st->bpos, sizeof(st->buf) - st->bpos); st->bpos += len; len = AUD_write(st->voice.out, st->compat_buf + st->compat_bpos, sizeof(st->compat_buf) - st->compat_bpos); st->compat_bpos += len; sent += len; if (st->bpos != sizeof(st->buf)) { if (st->compat_bpos != sizeof(st->compat_buf)) { break; } } Loading @@ -237,8 +410,18 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) return; } st->running = running; dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, st->running ? "on" : "off", st->stream); trace_hda_audio_running(st->node->name, st->stream, st->running); if (st->state->use_timer) { if (running) { int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); st->rpos = 0; st->wpos = 0; st->buft_start = now; timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); } else { timer_del(st->buft); } } if (st->output) { AUD_set_active_out(st->voice.out, st->running); } else { Loading Loading @@ -274,22 +457,36 @@ static void hda_audio_set_amp(HDAAudioStream *st) static void hda_audio_setup(HDAAudioStream *st) { bool use_timer = st->state->use_timer; audio_callback_fn cb; if (st->node == NULL) { return; } dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", st->node->name, st->as.nchannels, trace_hda_audio_format(st->node->name, st->as.nchannels, fmt2name[st->as.fmt], st->as.freq); if (st->output) { if (use_timer) { cb = hda_audio_output_cb; st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_output_timer, st); } else { cb = hda_audio_compat_output_cb; } st->voice.out = AUD_open_out(&st->state->card, st->voice.out, st->node->name, st, hda_audio_output_cb, &st->as); st->node->name, st, cb, &st->as); } else { if (use_timer) { cb = hda_audio_input_cb; st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_input_timer, st); } else { cb = hda_audio_compat_input_cb; } st->voice.in = AUD_open_in(&st->state->card, st->voice.in, st->node->name, st, hda_audio_input_cb, &st->as); st->node->name, st, cb, &st->as); } } Loading Loading @@ -505,7 +702,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) /* unmute output by default */ st->gain_left = QEMU_HDA_AMP_STEPS; st->gain_right = QEMU_HDA_AMP_STEPS; st->bpos = sizeof(st->buf); st->compat_bpos = sizeof(st->compat_buf); st->output = true; } else { st->output = false; Loading @@ -532,6 +729,9 @@ static void hda_audio_exit(HDACodecDevice *hda) if (st->node == NULL) { continue; } if (a->use_timer) { timer_del(st->buft); } if (st->output) { AUD_close_out(&a->card, st->voice.out); } else { Loading Loading @@ -581,6 +781,26 @@ static void hda_audio_reset(DeviceState *dev) } } static bool vmstate_hda_audio_stream_buf_needed(void *opaque) { HDAAudioStream *st = opaque; return st->state->use_timer; } static const VMStateDescription vmstate_hda_audio_stream_buf = { .name = "hda-audio-stream/buffer", .version_id = 1, .needed = vmstate_hda_audio_stream_buf_needed, .fields = (VMStateField[]) { VMSTATE_BUFFER(buf, HDAAudioStream), VMSTATE_INT64(rpos, HDAAudioStream), VMSTATE_INT64(wpos, HDAAudioStream), VMSTATE_TIMER_PTR(buft, HDAAudioStream), VMSTATE_INT64(buft_start, HDAAudioStream), VMSTATE_END_OF_LIST() } }; static const VMStateDescription vmstate_hda_audio_stream = { .name = "hda-audio-stream", .version_id = 1, Loading @@ -592,9 +812,13 @@ static const VMStateDescription vmstate_hda_audio_stream = { VMSTATE_UINT32(gain_right, HDAAudioStream), VMSTATE_BOOL(mute_left, HDAAudioStream), VMSTATE_BOOL(mute_right, HDAAudioStream), VMSTATE_UINT32(bpos, HDAAudioStream), VMSTATE_BUFFER(buf, HDAAudioStream), VMSTATE_UINT32(compat_bpos, HDAAudioStream), VMSTATE_BUFFER(compat_buf, HDAAudioStream), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription * []) { &vmstate_hda_audio_stream_buf, NULL } }; Loading @@ -615,6 +839,7 @@ static const VMStateDescription vmstate_hda_audio = { static Property hda_audio_properties[] = { DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0), DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true), DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true), DEFINE_PROP_END_OF_LIST(), }; Loading