From b05512b81bbe1c90b71da9c571e742f162fc0575 Mon Sep 17 00:00:00 2001 From: Michele Paolino Date: Tue, 14 Nov 2023 18:07:09 +0100 Subject: CAN, GPIO, RNG vhost-devices for virtio-loopback [v6] This patch adds key components of the viritio-loopback architecture: - kernel-module-virtio-loopback: the virtio loopback kernel driver - CAN, GPIO and RNG vhost-user devices from meta-virtualization (commit a215d8320edee0a317a6511e7e2efa5bba867486) Notes: - libgpiod, comes from meta-openembedded commit 3029554ceb0b0bb52a8d8ec3f0a75c5113662fe6 - cleaned eg-virt from unused drivers (kernel-module-virtio-video) Bug-AGL: SPEC-4834 V2 changes: - related meta-virtualization commit message added in the cover letter - updated libgpio recipe to v2.1 - SPEC reference added in cover letter v3 - add vhost-device-can preliminary version. This is placed here with the objective to share the link when proposing the new device to the rust-vmm/vhost-device community - remove cargo-update-recipe-crates includes in bb file because it is not supported by the rust mixin layer - vhost-device folder README changes v4 - fixed libgpiod required version - tested ref hw and qemu x86/64 builds - vsock, scsi and i2c rust devices removed from the build as they are not yet integrated in virtiod-loopback - cleaned-up kernel modules kernel-module-virtio-video and gstreamer1.0-plugins-bad - virtio-loopback-driver set to 2-or-later v5 - Merge with Jan-Simon version v4: - remove broken kernel-module-virtio-video - use FEATURE_PACKAGES instead of IMAGE_INSTALL:append - rename virtio-loopback-driver.bb to kernel-module-virtio-loopback_git.bb for consistency v6 - adding version in the title - removing MODULE_GIT_REPOSITORY in kernel-modules Change-Id: Id6cc58e777b9edad03b6c50d0dddaac8601edeaf Signed-off-by: Michele Paolino Signed-off-by: Jan-Simon Moeller --- .../files/virtio_video_vq.c | 981 --------------------- 1 file changed, 981 deletions(-) delete mode 100644 meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_vq.c (limited to 'meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_vq.c') diff --git a/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_vq.c b/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_vq.c deleted file mode 100644 index f3c97c7e..00000000 --- a/meta-egvirt/recipes-kernel/kernel-module-virtio-video/files/virtio_video_vq.c +++ /dev/null @@ -1,981 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Driver for virtio video device. - * - * Copyright 2020 OpenSynergy GmbH. - * - * Based on drivers/gpu/drm/virtio/virtgpu_vq.c - * Copyright (C) 2015 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "virtio_video.h" - -#define MAX_INLINE_CMD_SIZE 298 -#define MAX_INLINE_RESP_SIZE 298 -#define VBUFFER_SIZE (sizeof(struct virtio_video_vbuffer) \ - + MAX_INLINE_CMD_SIZE \ - + MAX_INLINE_RESP_SIZE) - -static int virtio_video_queue_event_buffer(struct virtio_video_device *vvd, - struct virtio_video_event *evt); -static void virtio_video_handle_event(struct virtio_video_device *vvd, - struct virtio_video_event *evt); - -void virtio_video_resource_id_get(struct virtio_video_device *vvd, uint32_t *id) -{ - int handle; - - idr_preload(GFP_KERNEL); - spin_lock(&vvd->resource_idr_lock); - handle = idr_alloc(&vvd->resource_idr, NULL, 1, 0, GFP_NOWAIT); - spin_unlock(&vvd->resource_idr_lock); - idr_preload_end(); - *id = handle; -} - -void virtio_video_resource_id_put(struct virtio_video_device *vvd, uint32_t id) -{ - spin_lock(&vvd->resource_idr_lock); - idr_remove(&vvd->resource_idr, id); - spin_unlock(&vvd->resource_idr_lock); -} - -void virtio_video_stream_id_get(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - uint32_t *id) -{ - int handle; - - idr_preload(GFP_KERNEL); - spin_lock(&vvd->stream_idr_lock); - handle = idr_alloc(&vvd->stream_idr, stream, 1, 0, 0); - spin_unlock(&vvd->stream_idr_lock); - idr_preload_end(); - *id = handle; -} - -void virtio_video_stream_id_put(struct virtio_video_device *vvd, uint32_t id) -{ - spin_lock(&vvd->stream_idr_lock); - idr_remove(&vvd->stream_idr, id); - spin_unlock(&vvd->stream_idr_lock); -} - -static bool vbuf_is_pending(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - struct virtio_video_vbuffer *entry; - - list_for_each_entry(entry, &vvd->pending_vbuf_list, pending_list_entry) - { - if (entry == vbuf && entry->id == vbuf->id) - return true; - } - - return false; -} - -static void free_vbuf(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - list_del(&vbuf->pending_list_entry); - kfree(vbuf->data_buf); - kmem_cache_free(vvd->vbufs, vbuf); -} - -void virtio_video_cmd_cb(struct virtqueue *vq) -{ - struct virtio_video_device *vvd = vq->vdev->priv; - struct virtio_video_vbuffer *vbuf; - unsigned long flags; - unsigned int len; - - spin_lock_irqsave(&vvd->commandq.qlock, flags); - while (vvd->commandq.ready) { - virtqueue_disable_cb(vq); - - while ((vbuf = virtqueue_get_buf(vq, &len))) { - if (!vbuf_is_pending(vvd, vbuf)) - continue; - - if (vbuf->resp_cb) - vbuf->resp_cb(vvd, vbuf); - - if (vbuf->is_sync) - complete(&vbuf->reclaimed); - else - free_vbuf(vvd, vbuf); - } - - if (unlikely(virtqueue_is_broken(vq))) - break; - - if (virtqueue_enable_cb(vq)) - break; - } - spin_unlock_irqrestore(&vvd->commandq.qlock, flags); - - wake_up(&vvd->commandq.reclaim_queue); -} - -void virtio_video_process_events(struct work_struct *work) -{ - struct virtio_video_device *vvd = container_of(work, - struct virtio_video_device, eventq.work); - struct virtqueue *vq = vvd->eventq.vq; - struct virtio_video_event *evt; - unsigned int len; - - while (vvd->eventq.ready) { - virtqueue_disable_cb(vq); - - while ((evt = virtqueue_get_buf(vq, &len))) { - virtio_video_handle_event(vvd, evt); - virtio_video_queue_event_buffer(vvd, evt); - } - - if (unlikely(virtqueue_is_broken(vq))) - break; - - if (virtqueue_enable_cb(vq)) - break; - } -} - -void virtio_video_event_cb(struct virtqueue *vq) -{ - struct virtio_video_device *vvd = vq->vdev->priv; - - schedule_work(&vvd->eventq.work); -} - -static struct virtio_video_vbuffer * -virtio_video_get_vbuf(struct virtio_video_device *vvd, int size, int resp_size, - void *resp_buf, virtio_video_resp_cb resp_cb) -{ - struct virtio_video_vbuffer *vbuf; - - vbuf = kmem_cache_alloc(vvd->vbufs, GFP_KERNEL); - if (!vbuf) - return ERR_PTR(-ENOMEM); - memset(vbuf, 0, VBUFFER_SIZE); - - BUG_ON(size > MAX_INLINE_CMD_SIZE); - vbuf->buf = (void *)vbuf + sizeof(*vbuf); - vbuf->size = size; - - vbuf->resp_cb = resp_cb; - vbuf->resp_size = resp_size; - if (resp_size <= MAX_INLINE_RESP_SIZE && !resp_buf) - vbuf->resp_buf = (void *)vbuf->buf + size; - else - vbuf->resp_buf = resp_buf; - BUG_ON(!vbuf->resp_buf); - - return vbuf; -} - -int virtio_video_alloc_vbufs(struct virtio_video_device *vvd) -{ - vvd->vbufs = - kmem_cache_create("virtio-video-vbufs", VBUFFER_SIZE, - __alignof__(struct virtio_video_vbuffer), 0, - NULL); - if (!vvd->vbufs) - return -ENOMEM; - - return 0; -} - -void virtio_video_free_vbufs(struct virtio_video_device *vvd) -{ - struct virtio_video_vbuffer *vbuf; - - /* Release command buffers. Operation on vbufs here is lock safe, - since before device was deinitialized and queues was stopped - (in not ready state) */ - while ((vbuf = virtqueue_detach_unused_buf(vvd->commandq.vq))) { - if (vbuf_is_pending(vvd, vbuf)) - free_vbuf(vvd, vbuf); - } - - kmem_cache_destroy(vvd->vbufs); - vvd->vbufs = NULL; - - /* Release event buffers */ - while (virtqueue_detach_unused_buf(vvd->eventq.vq)); - - kfree(vvd->evts); - vvd->evts = NULL; -} - -static void *virtio_video_alloc_req(struct virtio_video_device *vvd, - struct virtio_video_vbuffer **vbuffer_p, - int size) -{ - struct virtio_video_vbuffer *vbuf; - - vbuf = virtio_video_get_vbuf(vvd, size, - sizeof(struct virtio_video_cmd_hdr), - NULL, NULL); - if (IS_ERR(vbuf)) { - *vbuffer_p = NULL; - return ERR_CAST(vbuf); - } - *vbuffer_p = vbuf; - - return vbuf->buf; -} - -static void * -virtio_video_alloc_req_resp(struct virtio_video_device *vvd, - virtio_video_resp_cb cb, - struct virtio_video_vbuffer **vbuffer_p, - int req_size, int resp_size, - void *resp_buf) -{ - struct virtio_video_vbuffer *vbuf; - - vbuf = virtio_video_get_vbuf(vvd, req_size, resp_size, resp_buf, cb); - if (IS_ERR(vbuf)) { - *vbuffer_p = NULL; - return ERR_CAST(vbuf); - } - *vbuffer_p = vbuf; - - return vbuf->buf; -} - -static int -virtio_video_queue_cmd_buffer(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - unsigned long flags; - struct virtqueue *vq = vvd->commandq.vq; - struct scatterlist *sgs[3], vreq, vout, vresp; - int outcnt = 0, incnt = 0; - int ret; - - if (!vvd->commandq.ready) - return -ENODEV; - - spin_lock_irqsave(&vvd->commandq.qlock, flags); - - vbuf->id = vvd->vbufs_sent++; - list_add_tail(&vbuf->pending_list_entry, &vvd->pending_vbuf_list); - - sg_init_one(&vreq, vbuf->buf, vbuf->size); - sgs[outcnt + incnt] = &vreq; - outcnt++; - - if (vbuf->data_size) { - sg_init_one(&vout, vbuf->data_buf, vbuf->data_size); - sgs[outcnt + incnt] = &vout; - outcnt++; - } - - if (vbuf->resp_size) { - sg_init_one(&vresp, vbuf->resp_buf, vbuf->resp_size); - sgs[outcnt + incnt] = &vresp; - incnt++; - } - -retry: - ret = virtqueue_add_sgs(vq, sgs, outcnt, incnt, vbuf, GFP_ATOMIC); - if (ret == -ENOSPC) { - spin_unlock_irqrestore(&vvd->commandq.qlock, flags); - wait_event(vvd->commandq.reclaim_queue, vq->num_free); - spin_lock_irqsave(&vvd->commandq.qlock, flags); - goto retry; - } else { - virtqueue_kick(vq); - } - - spin_unlock_irqrestore(&vvd->commandq.qlock, flags); - - return ret; -} - -static int -virtio_video_queue_cmd_buffer_sync(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - int ret; - unsigned long rem; - unsigned long flags; - - vbuf->is_sync = true; - init_completion(&vbuf->reclaimed); - - ret = virtio_video_queue_cmd_buffer(vvd, vbuf); - if (ret) - return ret; - - rem = wait_for_completion_timeout(&vbuf->reclaimed, 5 * HZ); - if (rem == 0) - ret = -ETIMEDOUT; - - spin_lock_irqsave(&vvd->commandq.qlock, flags); - if (vbuf_is_pending(vvd, vbuf)) - free_vbuf(vvd, vbuf); - spin_unlock_irqrestore(&vvd->commandq.qlock, flags); - - return ret; -} - -static int virtio_video_queue_event_buffer(struct virtio_video_device *vvd, - struct virtio_video_event *evt) -{ - int ret; - struct scatterlist sg; - struct virtqueue *vq = vvd->eventq.vq; - - memset(evt, 0, sizeof(struct virtio_video_event)); - sg_init_one(&sg, evt, sizeof(struct virtio_video_event)); - - ret = virtqueue_add_inbuf(vq, &sg, 1, evt, GFP_KERNEL); - if (ret) { - v4l2_err(&vvd->v4l2_dev, "failed to queue event buffer\n"); - return ret; - } - - virtqueue_kick(vq); - - return 0; -} - -static void virtio_video_handle_event(struct virtio_video_device *vvd, - struct virtio_video_event *evt) -{ - int ret; - struct virtio_video_stream *stream; - uint32_t stream_id = evt->stream_id; - struct video_device *vd = &vvd->video_dev; - - mutex_lock(vd->lock); - - stream = idr_find(&vvd->stream_idr, stream_id); - if (!stream) { - v4l2_warn(&vvd->v4l2_dev, "stream_id=%u not found for event\n", - stream_id); - mutex_unlock(vd->lock); - return; - } - - switch (le32_to_cpu(evt->event_type)) { - case VIRTIO_VIDEO_EVENT_DECODER_RESOLUTION_CHANGED: - v4l2_dbg(1, vvd->debug, &vvd->v4l2_dev, - "stream_id=%u: resolution change event\n", stream_id); - virtio_video_cmd_get_params(vvd, stream, - VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT); - virtio_video_queue_res_chg_event(stream); - if (virtio_video_state(stream) == STREAM_STATE_INIT) { - virtio_video_state_update(stream, - STREAM_STATE_DYNAMIC_RES_CHANGE); - wake_up(&vvd->wq); - } - break; - case VIRTIO_VIDEO_EVENT_ERROR: - v4l2_err(&vvd->v4l2_dev, "stream_id=%i: error event\n", - stream_id); - virtio_video_state_update(stream, STREAM_STATE_ERROR); - virtio_video_handle_error(stream); - break; - default: - v4l2_warn(&vvd->v4l2_dev, "stream_id=%i: unknown event\n", - stream_id); - break; - } - - mutex_unlock(vd->lock); -} - -int virtio_video_alloc_events(struct virtio_video_device *vvd) -{ - int ret; - size_t i; - struct virtio_video_event *evts; - size_t num = vvd->eventq.vq->num_free; - - evts = kzalloc(num * sizeof(struct virtio_video_event), GFP_KERNEL); - if (!evts) { - v4l2_err(&vvd->v4l2_dev, "failed to alloc event buffers!!!\n"); - return -ENOMEM; - } - vvd->evts = evts; - - for (i = 0; i < num; i++) { - ret = virtio_video_queue_event_buffer(vvd, &evts[i]); - if (ret) { - v4l2_err(&vvd->v4l2_dev, - "failed to queue event buffer\n"); - return ret; - } - } - - return 0; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_stream_create(struct virtio_video_device *vvd, - uint32_t stream_id, - enum virtio_video_format format, - const char *tag) -{ - struct virtio_video_stream_create *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_STREAM_CREATE); - req_p->hdr.stream_id = cpu_to_le32(stream_id); - req_p->in_mem_type = cpu_to_le32(VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES); - req_p->out_mem_type = cpu_to_le32(VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES); - req_p->coded_format = cpu_to_le32(format); - if (strscpy(req_p->tag, tag, sizeof(req_p->tag) - 1) < 0) - v4l2_err(&vvd->v4l2_dev, "failed to copy stream tag\n"); - req_p->tag[sizeof(req_p->tag) - 1] = 0; - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_stream_destroy(struct virtio_video_device *vvd, - uint32_t stream_id) -{ - struct virtio_video_stream_destroy *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_STREAM_DESTROY); - req_p->hdr.stream_id = cpu_to_le32(stream_id); - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_stream_drain(struct virtio_video_device *vvd, - uint32_t stream_id) -{ - struct virtio_video_stream_drain *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_STREAM_DRAIN); - req_p->hdr.stream_id = cpu_to_le32(stream_id); - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -int virtio_video_cmd_resource_attach(struct virtio_video_device *vvd, - uint32_t stream_id, uint32_t resource_id, - enum virtio_video_queue_type queue_type, - void *buf, size_t buf_size) -{ - struct virtio_video_resource_attach *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->cmd_type = cpu_to_le32(VIRTIO_VIDEO_CMD_RESOURCE_ATTACH); - req_p->stream_id = cpu_to_le32(stream_id); - req_p->queue_type = cpu_to_le32(queue_type); - req_p->resource_id = cpu_to_le32(resource_id); - - vbuf->data_buf = buf; - vbuf->data_size = buf_size; - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -int virtio_video_cmd_queue_detach_resources(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - enum virtio_video_queue_type queue_type) -{ - int ret; - struct virtio_video_queue_detach_resources *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->cmd_type = cpu_to_le32(VIRTIO_VIDEO_CMD_QUEUE_DETACH_RESOURCES); - req_p->stream_id = cpu_to_le32(stream->stream_id); - req_p->queue_type = cpu_to_le32(queue_type); - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for resource destruction for %s\n", - (queue_type == VIRTIO_VIDEO_QUEUE_TYPE_INPUT) ? - "OUTPUT" : "CAPTURE"); - return ret; -} - -static void -virtio_video_cmd_resource_queue_cb(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - uint32_t flags; - uint64_t timestamp; - struct virtio_video_buffer *virtio_vb = vbuf->priv; - struct virtio_video_resource_queue_resp *resp = - (struct virtio_video_resource_queue_resp *)vbuf->resp_buf; - - flags = le32_to_cpu(resp->flags); - timestamp = le64_to_cpu(resp->timestamp); - - virtio_video_buf_done(virtio_vb, flags, timestamp, resp->data_sizes); -} - -int virtio_video_cmd_resource_queue(struct virtio_video_device *vvd, - uint32_t stream_id, - struct virtio_video_buffer *virtio_vb, - uint32_t data_size[], - uint8_t num_data_size, - enum virtio_video_queue_type queue_type) -{ - uint8_t i; - struct virtio_video_resource_queue *req_p; - struct virtio_video_resource_queue_resp *resp_p; - struct virtio_video_vbuffer *vbuf; - size_t resp_size = sizeof(struct virtio_video_resource_queue_resp); - - req_p = virtio_video_alloc_req_resp(vvd, - &virtio_video_cmd_resource_queue_cb, - &vbuf, sizeof(*req_p), resp_size, - NULL); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->cmd_type = cpu_to_le32(VIRTIO_VIDEO_CMD_RESOURCE_QUEUE); - req_p->stream_id = cpu_to_le32(stream_id); - req_p->queue_type = cpu_to_le32(queue_type); - req_p->resource_id = cpu_to_le32(virtio_vb->resource_id); - req_p->flags = 0; - req_p->timestamp = - cpu_to_le64(virtio_vb->v4l2_m2m_vb.vb.vb2_buf.timestamp); - - for (i = 0; i < num_data_size; ++i) - req_p->data_sizes[i] = cpu_to_le32(data_size[i]); - - resp_p = (struct virtio_video_resource_queue_resp *)vbuf->resp_buf; - memset(resp_p, 0, sizeof(*resp_p)); - - vbuf->priv = virtio_vb; - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_queue_clear(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - enum virtio_video_queue_type queue_type) -{ - int ret; - struct virtio_video_queue_clear *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_QUEUE_CLEAR); - req_p->hdr.stream_id = cpu_to_le32(stream->stream_id); - req_p->queue_type = cpu_to_le32(queue_type); - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for %s queue clear\n", - (queue_type == VIRTIO_VIDEO_QUEUE_TYPE_INPUT) ? - "OUTPUT" : "CAPTURE"); - return ret; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_query_capability(struct virtio_video_device *vvd, - void *resp_buf, size_t resp_size, - enum virtio_video_queue_type queue_type) -{ - int ret; - struct virtio_video_query_capability *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req_resp(vvd, NULL, &vbuf, sizeof(*req_p), - resp_size, resp_buf); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_QUERY_CAPABILITY); - req_p->queue_type = cpu_to_le32(queue_type); - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for capabilities for %s\n", - (queue_type == VIRTIO_VIDEO_QUEUE_TYPE_INPUT) ? - "OUTPUT" : "CAPTURE"); - return ret; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_query_control_level(struct virtio_video_device *vvd, - void *resp_buf, size_t resp_size, - enum virtio_video_format format) -{ - int ret; - struct virtio_video_query_control *req_p; - struct virtio_video_query_control_level *ctrl_l; - struct virtio_video_vbuffer *vbuf; - uint32_t req_size = 0; - - req_size = sizeof(struct virtio_video_query_control) + - sizeof(struct virtio_video_query_control_level); - - req_p = virtio_video_alloc_req_resp(vvd, NULL, &vbuf, req_size, - resp_size, resp_buf); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_QUERY_CONTROL); - req_p->control = cpu_to_le32(VIRTIO_VIDEO_CONTROL_LEVEL); - ctrl_l = (void *)((char *)req_p + - sizeof(struct virtio_video_query_control)); - ctrl_l->format = cpu_to_le32(format); - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for level query\n"); - return ret; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_query_control_profile(struct virtio_video_device *vvd, - void *resp_buf, size_t resp_size, - enum virtio_video_format format) -{ - int ret; - struct virtio_video_query_control *req_p; - struct virtio_video_query_control_profile *ctrl_p; - struct virtio_video_vbuffer *vbuf; - uint32_t req_size = 0; - - req_size = sizeof(struct virtio_video_query_control) + - sizeof(struct virtio_video_query_control_profile); - - req_p = virtio_video_alloc_req_resp(vvd, NULL, &vbuf, req_size, - resp_size, resp_buf); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_QUERY_CONTROL); - req_p->control = cpu_to_le32(VIRTIO_VIDEO_CONTROL_PROFILE); - ctrl_p = (void *)((char *)req_p + - sizeof(struct virtio_video_query_control)); - ctrl_p->format = cpu_to_le32(format); - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for profile query\n"); - return ret; -} - -static void -virtio_video_cmd_get_params_cb(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - int i; - struct virtio_video_get_params_resp *resp = - (struct virtio_video_get_params_resp *)vbuf->resp_buf; - struct virtio_video_params *params = &resp->params; - struct virtio_video_stream *stream = vbuf->priv; - enum virtio_video_queue_type queue_type; - struct video_format_info *format_info; - - queue_type = le32_to_cpu(params->queue_type); - if (queue_type == VIRTIO_VIDEO_QUEUE_TYPE_INPUT) - format_info = &stream->in_info; - else - format_info = &stream->out_info; - - format_info->frame_rate = le32_to_cpu(params->frame_rate); - format_info->frame_width = le32_to_cpu(params->frame_width); - format_info->frame_height = le32_to_cpu(params->frame_height); - format_info->min_buffers = le32_to_cpu(params->min_buffers); - format_info->max_buffers = le32_to_cpu(params->max_buffers); - format_info->fourcc_format = - virtio_video_format_to_v4l2(le32_to_cpu(params->format)); - - format_info->crop.top = le32_to_cpu(params->crop.top); - format_info->crop.left = le32_to_cpu(params->crop.left); - format_info->crop.width = le32_to_cpu(params->crop.width); - format_info->crop.height = le32_to_cpu(params->crop.height); - - format_info->num_planes = le32_to_cpu(params->num_planes); - for (i = 0; i < le32_to_cpu(params->num_planes); i++) { - struct virtio_video_plane_format *plane_formats = - ¶ms->plane_formats[i]; - struct video_plane_format *plane_format = - &format_info->plane_format[i]; - - plane_format->plane_size = - le32_to_cpu(plane_formats->plane_size); - plane_format->stride = le32_to_cpu(plane_formats->stride); - } -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_get_params(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - enum virtio_video_queue_type queue_type) -{ - int ret; - struct virtio_video_get_params *req_p; - struct virtio_video_vbuffer *vbuf; - struct virtio_video_get_params_resp *resp_p; - size_t resp_size = sizeof(struct virtio_video_get_params_resp); - - req_p = virtio_video_alloc_req_resp(vvd, - &virtio_video_cmd_get_params_cb, - &vbuf, sizeof(*req_p), resp_size, - NULL); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_GET_PARAMS); - req_p->hdr.stream_id = cpu_to_le32(stream->stream_id); - req_p->queue_type = cpu_to_le32(queue_type); - - resp_p = (struct virtio_video_get_params_resp *)vbuf->resp_buf; - - vbuf->priv = stream; - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for get_params\n"); - return ret; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int -virtio_video_cmd_set_params(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - struct video_format_info *format_info, - enum virtio_video_queue_type queue_type) -{ - int i; - struct virtio_video_set_params *req_p; - struct virtio_video_vbuffer *vbuf; - - req_p = virtio_video_alloc_req(vvd, &vbuf, sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_SET_PARAMS); - req_p->hdr.stream_id = cpu_to_le32(stream->stream_id); - req_p->params.queue_type = cpu_to_le32(queue_type); - req_p->params.frame_rate = cpu_to_le32(format_info->frame_rate); - req_p->params.frame_width = cpu_to_le32(format_info->frame_width); - req_p->params.frame_height = cpu_to_le32(format_info->frame_height); - req_p->params.format = virtio_video_v4l2_format_to_virtio( - cpu_to_le32(format_info->fourcc_format)); - req_p->params.min_buffers = cpu_to_le32(format_info->min_buffers); - req_p->params.max_buffers = cpu_to_le32(format_info->max_buffers); - req_p->params.num_planes = cpu_to_le32(format_info->num_planes); - - for (i = 0; i < format_info->num_planes; i++) { - struct virtio_video_plane_format *plane_formats = - &req_p->params.plane_formats[i]; - struct video_plane_format *plane_format = - &format_info->plane_format[i]; - plane_formats->plane_size = - cpu_to_le32(plane_format->plane_size); - plane_formats->stride = cpu_to_le32(plane_format->stride); - } - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -static void -virtio_video_cmd_get_ctrl_profile_cb(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - struct virtio_video_get_control_resp *resp = - (struct virtio_video_get_control_resp *)vbuf->resp_buf; - struct virtio_video_control_val_profile *resp_p = NULL; - struct virtio_video_stream *stream = vbuf->priv; - struct video_control_info *control = &stream->control; - - resp_p = (void *)((char *)resp + - sizeof(struct virtio_video_get_control_resp)); - - control->profile = le32_to_cpu(resp_p->profile); -} - -static void -virtio_video_cmd_get_ctrl_level_cb(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - struct virtio_video_get_control_resp *resp = - (struct virtio_video_get_control_resp *)vbuf->resp_buf; - struct virtio_video_control_val_level *resp_p; - struct virtio_video_stream *stream = vbuf->priv; - struct video_control_info *control = &stream->control; - - resp_p = (void *)((char *)resp + - sizeof(struct virtio_video_get_control_resp)); - - control->level = le32_to_cpu(resp_p->level); -} - -static void -virtio_video_cmd_get_ctrl_bitrate_cb(struct virtio_video_device *vvd, - struct virtio_video_vbuffer *vbuf) -{ - struct virtio_video_get_control_resp *resp = - (struct virtio_video_get_control_resp *)vbuf->resp_buf; - struct virtio_video_control_val_bitrate *resp_p = NULL; - struct virtio_video_stream *stream = vbuf->priv; - struct video_control_info *control = &stream->control; - - resp_p = (void *)((char *) resp + - sizeof(struct virtio_video_get_control_resp)); - - control->bitrate = le32_to_cpu(resp_p->bitrate); -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_get_control(struct virtio_video_device *vvd, - struct virtio_video_stream *stream, - enum virtio_video_control_type control) -{ - int ret; - struct virtio_video_get_control *req_p; - struct virtio_video_get_control_resp *resp_p; - struct virtio_video_vbuffer *vbuf; - size_t resp_size = sizeof(struct virtio_video_get_control_resp); - virtio_video_resp_cb cb; - - switch (control) { - case VIRTIO_VIDEO_CONTROL_PROFILE: - resp_size += sizeof(struct virtio_video_control_val_profile); - cb = &virtio_video_cmd_get_ctrl_profile_cb; - break; - case VIRTIO_VIDEO_CONTROL_LEVEL: - resp_size += sizeof(struct virtio_video_control_val_level); - cb = &virtio_video_cmd_get_ctrl_level_cb; - break; - case VIRTIO_VIDEO_CONTROL_BITRATE: - resp_size += sizeof(struct virtio_video_control_val_bitrate); - cb = &virtio_video_cmd_get_ctrl_bitrate_cb; - break; - default: - return -EINVAL; - } - - req_p = virtio_video_alloc_req_resp(vvd, cb, &vbuf, - sizeof(*req_p), resp_size, NULL); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_GET_CONTROL); - req_p->hdr.stream_id = cpu_to_le32(stream->stream_id); - req_p->control = cpu_to_le32(control); - - resp_p = (struct virtio_video_get_control_resp *)vbuf->resp_buf; - - vbuf->priv = stream; - - ret = virtio_video_queue_cmd_buffer_sync(vvd, vbuf); - if (ret == -ETIMEDOUT) - v4l2_err(&vvd->v4l2_dev, - "timed out waiting for get_control\n"); - return ret; -} - -// TODO: replace virtio_video_cmd_hdr accoring to specification v4 -int virtio_video_cmd_set_control(struct virtio_video_device *vvd, - uint32_t stream_id, - enum virtio_video_control_type control, - uint32_t value) -{ - struct virtio_video_set_control *req_p; - struct virtio_video_vbuffer *vbuf; - struct virtio_video_control_val_level *ctrl_l; - struct virtio_video_control_val_profile *ctrl_p; - struct virtio_video_control_val_bitrate *ctrl_b; - size_t size; - - if (value == 0) - return -EINVAL; - - switch (control) { - case VIRTIO_VIDEO_CONTROL_PROFILE: - size = sizeof(struct virtio_video_control_val_profile); - break; - case VIRTIO_VIDEO_CONTROL_LEVEL: - size = sizeof(struct virtio_video_control_val_level); - break; - case VIRTIO_VIDEO_CONTROL_BITRATE: - size = sizeof(struct virtio_video_control_val_bitrate); - break; - default: - return -EINVAL; - } - - req_p = virtio_video_alloc_req(vvd, &vbuf, size + sizeof(*req_p)); - if (IS_ERR(req_p)) - return PTR_ERR(req_p); - - req_p->hdr.type = cpu_to_le32(VIRTIO_VIDEO_CMD_SET_CONTROL); - req_p->hdr.stream_id = cpu_to_le32(stream_id); - req_p->control = cpu_to_le32(control); - - switch (control) { - case VIRTIO_VIDEO_CONTROL_PROFILE: - ctrl_p = (void *)((char *)req_p + - sizeof(struct virtio_video_set_control)); - ctrl_p->profile = cpu_to_le32(value); - break; - case VIRTIO_VIDEO_CONTROL_LEVEL: - ctrl_l = (void *)((char *)req_p + - sizeof(struct virtio_video_set_control)); - ctrl_l->level = cpu_to_le32(value); - break; - case VIRTIO_VIDEO_CONTROL_BITRATE: - ctrl_b = (void *)((char *)req_p + - sizeof(struct virtio_video_set_control)); - ctrl_b->bitrate = cpu_to_le32(value); - break; - } - - return virtio_video_queue_cmd_buffer(vvd, vbuf); -} - -- cgit 1.2.3-korg