diff mbox series

[RFC,14/25] virtio-snd: Add VIRTIO_SND_R_PCM_INFO handler

Message ID 20220211221319.193404-15-chouhan.shreyansh2702@gmail.com
State New
Headers show
Series None | expand

Commit Message

Shreyansh Chouhan Feb. 11, 2022, 10:13 p.m. UTC
Signed-off-by: Shreyansh Chouhan <chouhan.shreyansh2702@gmail.com>
---
 hw/audio/virtio-snd.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)

Comments

Laurent Vivier Feb. 12, 2022, 7:20 p.m. UTC | #1
Le 11/02/2022 à 23:13, Shreyansh Chouhan a écrit :
> Signed-off-by: Shreyansh Chouhan <chouhan.shreyansh2702@gmail.com>
> ---
>   hw/audio/virtio-snd.c | 88 ++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 87 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> index aec3e86db2..a53a6be168 100644
> --- a/hw/audio/virtio-snd.c
> +++ b/hw/audio/virtio-snd.c
> @@ -188,6 +188,91 @@ static uint32_t virtio_snd_handle_jack_remap(VirtIOSound *s,
>       return sz;
>   }
>   
> +/*
> + * Get a specific stream from the virtio sound card device.
> + *
> + * @s: VirtIOSound card device
> + * @stream: Stream id
> + *
> + * Returns NULL if function fails.
> + * TODO: Make failure more explicit. Output can be NULL if the stream number
> + *       is valid but the stream hasn't been allocated yet.
> + */
> +static virtio_snd_pcm_stream *virtio_snd_pcm_get_stream(VirtIOSound *s,
> +                                                        uint32_t stream)
> +{
> +    if (stream >= s->snd_conf.streams) {
> +        virtio_snd_err("Invalid stream request %d\n", stream);
> +        return NULL;
> +    }
> +    return s->streams[stream];
> +}
> +
> +/*
> + * Handle the VIRTIO_SND_R_PCM_INFO request.
> + * The function writes the info structs to the request element.
> + * Returns the used size in bytes.
> + *
> + * @s: VirtIOSound card device
> + * @elem: The request element from control queue
> + */
> +static uint32_t virtio_snd_handle_pcm_info(VirtIOSound *s,
> +                                           VirtQueueElement *elem)
> +{
> +    virtio_snd_query_info req;
> +    uint32_t sz;
> +    sz = iov_to_buf(elem->out_sg, elem->out_num, 0, &req, sizeof(req));
> +    assert(sz == sizeof(virtio_snd_query_info));
> +
> +    virtio_snd_hdr resp;
> +    if (iov_size(elem->in_sg, elem->in_num) <
> +        sizeof(virtio_snd_hdr) + req.size * req.count) {
> +        virtio_snd_err("pcm info: buffer too small, got: %lu, needed: %lu\n",
> +                iov_size(elem->in_sg, elem->in_num),
> +                sizeof(virtio_snd_pcm_info));
> +        resp.code = VIRTIO_SND_S_BAD_MSG;
> +        goto done;
> +    }
> +
> +    virtio_snd_pcm_stream *stream;
> +    virtio_snd_pcm_info *pcm_info = g_new0(virtio_snd_pcm_info, req.count);
> +    for (int i = req.start_id; i < req.start_id + req.count; i++) {
> +        stream = virtio_snd_pcm_get_stream(s, i);
> +
> +        if (!stream) {
> +            virtio_snd_err("Invalid stream id: %d\n", i);
> +            resp.code = VIRTIO_SND_S_BAD_MSG;
> +            goto done;
> +        }
> +
> +        pcm_info[i - req.start_id].hdr.hda_fn_nid = stream->hda_fn_nid;
> +        pcm_info[i - req.start_id].features = stream->features;
> +        pcm_info[i - req.start_id].formats = stream->formats;
> +        pcm_info[i - req.start_id].rates = stream->rates;
> +        pcm_info[i - req.start_id].direction = stream->direction;
> +        pcm_info[i - req.start_id].channels_min = stream->channels_min;
> +        pcm_info[i - req.start_id].channels_max = stream->channels_max;
> +
> +        memset(&pcm_info[i].padding, 0, sizeof(pcm_info[i].padding));
> +    }
> +
> +    resp.code = VIRTIO_SND_S_OK;
> +done:
> +    sz = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp, sizeof(resp));
> +    assert(sz == sizeof(virtio_snd_hdr));
> +
> +    if (resp.code == VIRTIO_SND_S_BAD_MSG) {
> +        g_free(pcm_info);
> +        return sz;
> +    }
> +
> +    sz = iov_from_buf(elem->in_sg, elem->in_num, sizeof(virtio_snd_hdr),
> +                      pcm_info, sizeof(virtio_snd_pcm_info) * req.count);

Same problem here:

In file included from ../../../Projects/qemu-next/hw/audio/virtio-snd.c:7:
.../hw/audio/virtio-snd.c: In function 'virtio_snd_handle_ctrl':
.../include/qemu/iov.h:49:16: error: 'pcm_info' may be used uninitialized in this function 
[-Werror=maybe-uninitialized]
    49 |         return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes);
       |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../hw/audio/virtio-snd.c:238:26: note: 'pcm_info' was declared here
   238 |     virtio_snd_pcm_info *pcm_info = g_new0(virtio_snd_pcm_info, req.count);
       |                          ^~~~~~~~

> +    assert(sz == req.size * req.count);
> +    g_free(pcm_info);
> +    return sizeof(virtio_snd_hdr) + sz;
> +}
> +
>   /* The control queue handler. Pops an element from the control virtqueue,
>    * checks the header and performs the requested action. Finally marks the
>    * element as used.
> @@ -233,7 +318,8 @@ static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
>               sz = virtio_snd_handle_jack_remap(s, elem);
>               goto done;
>           } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
> -            virtio_snd_log("VIRTIO_SND_R_PCM_INFO");
> +            sz = virtio_snd_handle_pcm_info(s, elem);
> +            goto done;
>           } else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
>               virtio_snd_log("VIRTIO_SND_R_PCM_SET_PARAMS");
>           } else if (ctrl.code == VIRTIO_SND_R_PCM_PREPARE) {
diff mbox series

Patch

diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index aec3e86db2..a53a6be168 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -188,6 +188,91 @@  static uint32_t virtio_snd_handle_jack_remap(VirtIOSound *s,
     return sz;
 }
 
+/*
+ * Get a specific stream from the virtio sound card device.
+ *
+ * @s: VirtIOSound card device
+ * @stream: Stream id
+ *
+ * Returns NULL if function fails.
+ * TODO: Make failure more explicit. Output can be NULL if the stream number
+ *       is valid but the stream hasn't been allocated yet.
+ */
+static virtio_snd_pcm_stream *virtio_snd_pcm_get_stream(VirtIOSound *s,
+                                                        uint32_t stream)
+{
+    if (stream >= s->snd_conf.streams) {
+        virtio_snd_err("Invalid stream request %d\n", stream);
+        return NULL;
+    }
+    return s->streams[stream];
+}
+
+/*
+ * Handle the VIRTIO_SND_R_PCM_INFO request.
+ * The function writes the info structs to the request element.
+ * Returns the used size in bytes.
+ *
+ * @s: VirtIOSound card device
+ * @elem: The request element from control queue
+ */
+static uint32_t virtio_snd_handle_pcm_info(VirtIOSound *s,
+                                           VirtQueueElement *elem)
+{
+    virtio_snd_query_info req;
+    uint32_t sz;
+    sz = iov_to_buf(elem->out_sg, elem->out_num, 0, &req, sizeof(req));
+    assert(sz == sizeof(virtio_snd_query_info));
+
+    virtio_snd_hdr resp;
+    if (iov_size(elem->in_sg, elem->in_num) <
+        sizeof(virtio_snd_hdr) + req.size * req.count) {
+        virtio_snd_err("pcm info: buffer too small, got: %lu, needed: %lu\n",
+                iov_size(elem->in_sg, elem->in_num),
+                sizeof(virtio_snd_pcm_info));
+        resp.code = VIRTIO_SND_S_BAD_MSG;
+        goto done;
+    }
+
+    virtio_snd_pcm_stream *stream;
+    virtio_snd_pcm_info *pcm_info = g_new0(virtio_snd_pcm_info, req.count);
+    for (int i = req.start_id; i < req.start_id + req.count; i++) {
+        stream = virtio_snd_pcm_get_stream(s, i);
+
+        if (!stream) {
+            virtio_snd_err("Invalid stream id: %d\n", i);
+            resp.code = VIRTIO_SND_S_BAD_MSG;
+            goto done;
+        }
+
+        pcm_info[i - req.start_id].hdr.hda_fn_nid = stream->hda_fn_nid;
+        pcm_info[i - req.start_id].features = stream->features;
+        pcm_info[i - req.start_id].formats = stream->formats;
+        pcm_info[i - req.start_id].rates = stream->rates;
+        pcm_info[i - req.start_id].direction = stream->direction;
+        pcm_info[i - req.start_id].channels_min = stream->channels_min;
+        pcm_info[i - req.start_id].channels_max = stream->channels_max;
+
+        memset(&pcm_info[i].padding, 0, sizeof(pcm_info[i].padding));
+    }
+
+    resp.code = VIRTIO_SND_S_OK;
+done:
+    sz = iov_from_buf(elem->in_sg, elem->in_num, 0, &resp, sizeof(resp));
+    assert(sz == sizeof(virtio_snd_hdr));
+
+    if (resp.code == VIRTIO_SND_S_BAD_MSG) {
+        g_free(pcm_info);
+        return sz;
+    }
+
+    sz = iov_from_buf(elem->in_sg, elem->in_num, sizeof(virtio_snd_hdr),
+                      pcm_info, sizeof(virtio_snd_pcm_info) * req.count);
+    assert(sz == req.size * req.count);
+    g_free(pcm_info);
+    return sizeof(virtio_snd_hdr) + sz;
+}
+
 /* The control queue handler. Pops an element from the control virtqueue,
  * checks the header and performs the requested action. Finally marks the
  * element as used.
@@ -233,7 +318,8 @@  static void virtio_snd_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
             sz = virtio_snd_handle_jack_remap(s, elem);
             goto done;
         } else if (ctrl.code == VIRTIO_SND_R_PCM_INFO) {
-            virtio_snd_log("VIRTIO_SND_R_PCM_INFO");
+            sz = virtio_snd_handle_pcm_info(s, elem);
+            goto done;
         } else if (ctrl.code == VIRTIO_SND_R_PCM_SET_PARAMS) {
             virtio_snd_log("VIRTIO_SND_R_PCM_SET_PARAMS");
         } else if (ctrl.code == VIRTIO_SND_R_PCM_PREPARE) {