From: Emmanouil Pitsidianakis <manos.pitsidiana...@linaro.org> Respond to the VIRTIO_SND_R_PCM_INFO control request with the parameters of each requested PCM stream.
Based-on: https://github.com/OpenSynergy/qemu/commit/5a2f350eec5d157b90d9c7b40a8e603f4da92471 Signed-off-by: Igor Skalkin <igor.skal...@opensynergy.com> Signed-off-by: Anton Yakovlev <anton.yakov...@opensynergy.com> Signed-off-by: Emmanouil Pitsidianakis <manos.pitsidiana...@linaro.org> Reviewed-by: Alex Bennée <alex.ben...@linaro.org> --- hw/virtio/trace-events | 1 + hw/virtio/virtio-snd.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 48043fed3e..88de2021c8 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -164,6 +164,7 @@ virtio_snd_vm_state_stopped(void) "vm state stopped" virtio_snd_realize(void *snd) "snd %p: realize" virtio_snd_unrealize(void *snd) "snd %p: unrealize" virtio_snd_handle_ctrl(void *vdev, void *vq) "snd %p: handle ctrl event for queue %p" +virtio_snd_handle_pcm_info(uint32_t stream) "VIRTIO_SND_R_PCM_INFO called for stream %"PRIu32 virtio_snd_handle_code(uint32_t val, const char *code) "ctrl code msg val = %"PRIu32" == %s" virtio_snd_handle_chmap_info(void) "VIRTIO_SND_CHMAP_INFO called" virtio_snd_handle_event(void) "event queue callback called" diff --git a/hw/virtio/virtio-snd.c b/hw/virtio/virtio-snd.c index 705dc07212..ec945d55a7 100644 --- a/hw/virtio/virtio-snd.c +++ b/hw/virtio/virtio-snd.c @@ -147,22 +147,102 @@ static VirtIOSoundPCMStream *virtio_snd_pcm_get_stream(VirtIOSound *s, /* * Get params for a specific stream. * * @s: VirtIOSound device * @stream_id: stream id */ static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s, uint32_t stream_id) { return stream_id >= s->snd_conf.streams ? NULL : &s->pcm->pcm_params[stream_id]; } +/* + * Handle the VIRTIO_SND_R_PCM_INFO request. + * The function writes the info structs to the request element. + * + * @s: VirtIOSound device + * @cmd: The request command queue element from VirtIOSound cmdq field + */ +static void virtio_snd_handle_pcm_info(VirtIOSound *s, + virtio_snd_ctrl_command *cmd) +{ + uint32_t stream_id, start_id, count, size; + virtio_snd_pcm_info val; + virtio_snd_query_info req; + VirtIOSoundPCMStream *stream = NULL; + g_autofree virtio_snd_pcm_info *pcm_info = NULL; + size_t msg_sz = iov_to_buf(cmd->elem->out_sg, + cmd->elem->out_num, + 0, + &req, + sizeof(virtio_snd_query_info)); + + if (msg_sz != sizeof(virtio_snd_query_info)) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: virtio-snd command size incorrect %zu vs \ + %zu\n", __func__, msg_sz, sizeof(virtio_snd_query_info)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + start_id = le32_to_cpu(req.start_id); + count = le32_to_cpu(req.count); + size = le32_to_cpu(req.size); + + if (iov_size(cmd->elem->in_sg, cmd->elem->in_num) < + sizeof(virtio_snd_hdr) + size * count) { + /* + * TODO: do we need to set DEVICE_NEEDS_RESET? + */ + error_report("pcm info: buffer too small, got: %zu, needed: %zu", + iov_size(cmd->elem->in_sg, cmd->elem->in_num), + sizeof(virtio_snd_pcm_info)); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + + pcm_info = g_new0(virtio_snd_pcm_info, count); + for (uint32_t i = 0; i < count; i++) { + stream_id = i + start_id; + trace_virtio_snd_handle_pcm_info(stream_id); + stream = virtio_snd_pcm_get_stream(s, stream_id); + if (!stream) { + error_report("Invalid stream id: %"PRIu32, stream_id); + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); + return; + } + val = stream->info; + val.hdr.hda_fn_nid = cpu_to_le32(val.hdr.hda_fn_nid); + val.features = cpu_to_le32(val.features); + val.formats = cpu_to_le64(val.formats); + val.rates = cpu_to_le64(val.rates); + /* + * 5.14.6.6.2.1 Device Requirements: Stream Information The device MUST + * NOT set undefined feature, format, rate and direction values. The + * device MUST initialize the padding bytes to 0. + */ + pcm_info[i] = val; + memset(&pcm_info[i].padding, 0, 5); + } + + cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK); + iov_from_buf(cmd->elem->in_sg, + cmd->elem->in_num, + sizeof(virtio_snd_hdr), + pcm_info, + sizeof(virtio_snd_pcm_info) * count); +} + /* * Set the given stream params. * Called by both virtio_snd_handle_pcm_set_params and during device * initialization. * Returns the response status code. (VIRTIO_SND_S_*). * * @s: VirtIOSound device * @params: The PCM params as defined in the virtio specification */ @@ -376,64 +456,66 @@ static inline void process_cmd(VirtIOSound *s, virtio_snd_ctrl_command *cmd) { uint32_t code; size_t msg_sz = iov_to_buf(cmd->elem->out_sg, cmd->elem->out_num, 0, &cmd->ctrl, sizeof(virtio_snd_hdr)); if (msg_sz != sizeof(virtio_snd_hdr)) { /* * TODO: do we need to set DEVICE_NEEDS_RESET? */ qemu_log_mask(LOG_GUEST_ERROR, "%s: virtio-snd command size incorrect %zu vs \ %zu\n", __func__, msg_sz, sizeof(virtio_snd_hdr)); return; } code = le32_to_cpu(cmd->ctrl.code); trace_virtio_snd_handle_code(code, print_code(code)); switch (code) { case VIRTIO_SND_R_JACK_INFO: case VIRTIO_SND_R_JACK_REMAP: qemu_log_mask(LOG_UNIMP, "virtio_snd: jack functionality is unimplemented.\n"); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_PCM_INFO: + virtio_snd_handle_pcm_info(s, cmd); + break; case VIRTIO_SND_R_PCM_SET_PARAMS: case VIRTIO_SND_R_PCM_PREPARE: case VIRTIO_SND_R_PCM_START: case VIRTIO_SND_R_PCM_STOP: case VIRTIO_SND_R_PCM_RELEASE: cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; case VIRTIO_SND_R_CHMAP_INFO: qemu_log_mask(LOG_UNIMP, "virtio_snd: chmap info functionality is unimplemented.\n"); trace_virtio_snd_handle_chmap_info(); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_NOT_SUPP); break; default: /* error */ error_report("virtio snd header not recognized: %"PRIu32, code); cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG); } iov_from_buf(cmd->elem->in_sg, cmd->elem->in_num, 0, &cmd->resp, sizeof(virtio_snd_hdr)); virtqueue_push(cmd->vq, cmd->elem, sizeof(virtio_snd_hdr)); virtio_notify(VIRTIO_DEVICE(s), cmd->vq); } /* * Consume all elements in command queue. * * @s: VirtIOSound device */ -- 2.39.2