@@ -163,6 +163,7 @@ virtio_snd_vm_state_running(void) "vm state running"
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_pcm_set_params(uint32_t stream) "VIRTIO_SND_PCM_SET_PARAMS called for stream %"PRIu32
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_pcm_start_stop(const char *code, uint32_t stream) "%s called for stream %"PRIu32
@@ -250,43 +250,75 @@ static
uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
uint32_t stream_id,
virtio_snd_pcm_set_params *params)
{
virtio_snd_pcm_set_params *st_params;
if (stream_id >= s->snd_conf.streams || s->pcm->pcm_params == NULL) {
/*
* TODO: do we need to set DEVICE_NEEDS_RESET?
*/
virtio_error(VIRTIO_DEVICE(s), "Streams have not been initialized.\n");
return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
}
st_params = virtio_snd_pcm_get_params(s, stream_id);
if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
error_report("Number of channels is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
if (!(supported_formats & BIT(params->format))) {
error_report("Stream format is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
if (!(supported_rates & BIT(params->rate))) {
error_report("Stream rate is not supported.");
return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
}
st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
st_params->period_bytes = le32_to_cpu(params->period_bytes);
st_params->features = le32_to_cpu(params->features);
/* the following are uint8_t, so there's no need to bswap the values. */
st_params->channels = params->channels;
st_params->format = params->format;
st_params->rate = params->rate;
return cpu_to_le32(VIRTIO_SND_S_OK);
}
+/*
+ * Handles the VIRTIO_SND_R_PCM_SET_PARAMS request.
+ *
+ * @s: VirtIOSound device
+ * @cmd: The request command queue element from VirtIOSound cmdq field
+ */
+static void virtio_snd_handle_pcm_set_params(VirtIOSound *s,
+ virtio_snd_ctrl_command *cmd)
+{
+ virtio_snd_pcm_set_params req = { 0 };
+ uint32_t stream_id;
+ size_t msg_sz = iov_to_buf(cmd->elem->out_sg,
+ cmd->elem->out_num,
+ 0,
+ &req,
+ sizeof(virtio_snd_pcm_set_params));
+
+ if (msg_sz != sizeof(virtio_snd_pcm_set_params)) {
+ /*
+ * 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_pcm_set_params));
+ cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
+ return;
+ }
+ stream_id = le32_to_cpu(req.hdr.stream_id);
+ trace_virtio_snd_handle_pcm_set_params(stream_id);
+ cmd->resp.code = virtio_snd_set_pcm_params(s, stream_id, &req);
+}
+
/*
* Get a QEMU Audiosystem compatible format value from a VIRTIO_SND_PCM_FMT_*
*/
@@ -497,70 +529,72 @@ 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:
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
*/