@@ -458,30 +458,52 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s, uint32_t stream_id)
static const char *print_code(uint32_t code)
{
#define CASE(CODE) \
case VIRTIO_SND_R_##CODE: \
return "VIRTIO_SND_R_"#CODE
switch (code) {
CASE(JACK_INFO);
CASE(JACK_REMAP);
CASE(PCM_INFO);
CASE(PCM_SET_PARAMS);
CASE(PCM_PREPARE);
CASE(PCM_RELEASE);
CASE(PCM_START);
CASE(PCM_STOP);
CASE(CHMAP_INFO);
default:
return "invalid code";
}
#undef CASE
};
+/*
+ * Handles VIRTIO_SND_R_PCM_PREPARE.
+ *
+ * @s: VirtIOSound device
+ * @cmd: The request command queue element from VirtIOSound cmdq field
+ */
+static void virtio_snd_handle_pcm_prepare(VirtIOSound *s,
+ virtio_snd_ctrl_command *cmd)
+{
+ uint32_t stream_id;
+ size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
+ cmd->elem->out_num,
+ sizeof(virtio_snd_hdr),
+ &stream_id,
+ sizeof(stream_id));
+
+ stream_id = le32_to_cpu(stream_id);
+ cmd->resp.code = msg_sz == sizeof(stream_id)
+ ? virtio_snd_pcm_prepare(s, stream_id)
+ : cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+}
+
/*
* Handles VIRTIO_SND_R_PCM_START.
*
* @s: VirtIOSound device
* @cmd: The request command queue element from VirtIOSound cmdq field
* @start: whether to start or stop the device
*/
@@ -529,72 +551,74 @@ 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_START:
virtio_snd_handle_pcm_start_stop(s, cmd, true);
break;
case VIRTIO_SND_R_PCM_STOP:
virtio_snd_handle_pcm_start_stop(s, cmd, false);
break;
case VIRTIO_SND_R_PCM_SET_PARAMS:
virtio_snd_handle_pcm_set_params(s, cmd);
break;
case VIRTIO_SND_R_PCM_PREPARE:
+ virtio_snd_handle_pcm_prepare(s, cmd);
+ break;
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
*/