lkml.org 
[lkml]   [2018]   [Feb]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [RFCv3 01/17] media: add request API core and UAPI
    Hi Alexandre,

    On Wed, Feb 07, 2018 at 10:48:05AM +0900, Alexandre Courbot wrote:
    > The request API provides a way to group buffers and device parameters
    > into units of work to be queued and executed. This patch introduces the
    > UAPI and core framework.
    >
    > This patch is based on the previous work by Laurent Pinchart. The core
    > has changed considerably, but the UAPI is mostly untouched.

    Thanks for the rebase.

    What's the purpose of the split between media-request.c and
    media-request-mgr.c? The use of ops for the request manager suggests it
    could be replaced by an alternative implementation but then again the media
    request is almost entirely initialised in the media-request-mgr. Either
    could make some sense but not both --- I'd simply move the code from the
    media-request-mgr to the functions calling them in media-request.c. That
    should make this easier to read, too.

    A few more comments below.

    >
    > Signed-off-by: Alexandre Courbot <acourbot@chromium.org>
    > ---
    > drivers/media/Makefile | 3 +-
    > drivers/media/media-device.c | 7 +
    > drivers/media/media-request-mgr.c | 105 ++++++++++++
    > drivers/media/media-request.c | 311 +++++++++++++++++++++++++++++++++++
    > drivers/media/v4l2-core/v4l2-ioctl.c | 2 +-
    > include/media/media-device.h | 3 +
    > include/media/media-entity.h | 9 +
    > include/media/media-request-mgr.h | 73 ++++++++
    > include/media/media-request.h | 186 +++++++++++++++++++++
    > include/uapi/linux/media.h | 10 ++
    > 10 files changed, 707 insertions(+), 2 deletions(-)
    > create mode 100644 drivers/media/media-request-mgr.c
    > create mode 100644 drivers/media/media-request.c
    > create mode 100644 include/media/media-request-mgr.h
    > create mode 100644 include/media/media-request.h
    >
    > diff --git a/drivers/media/Makefile b/drivers/media/Makefile
    > index 594b462ddf0e..06c43ddb52ea 100644
    > --- a/drivers/media/Makefile
    > +++ b/drivers/media/Makefile
    > @@ -3,7 +3,8 @@
    > # Makefile for the kernel multimedia device drivers.
    > #
    >
    > -media-objs := media-device.o media-devnode.o media-entity.o
    > +media-objs := media-device.o media-devnode.o media-entity.o \
    > + media-request.o media-request-mgr.o
    >
    > #
    > # I2C drivers should come before other drivers, otherwise they'll fail
    > diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
    > index e79f72b8b858..024ee81a8334 100644
    > --- a/drivers/media/media-device.c
    > +++ b/drivers/media/media-device.c
    > @@ -32,6 +32,8 @@
    > #include <media/media-device.h>
    > #include <media/media-devnode.h>
    > #include <media/media-entity.h>
    > +#include <media/media-request.h>
    > +#include <media/media-request-mgr.h>
    >
    > #ifdef CONFIG_MEDIA_CONTROLLER
    >
    > @@ -407,6 +409,7 @@ static const struct media_ioctl_info ioctl_info[] = {
    > MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
    > MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
    > MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
    > + MEDIA_IOC(REQUEST_CMD, media_device_request_cmd, 0),
    > };
    >
    > static long media_device_ioctl(struct file *filp, unsigned int cmd,
    > @@ -688,6 +691,10 @@ EXPORT_SYMBOL_GPL(media_device_init);
    >
    > void media_device_cleanup(struct media_device *mdev)
    > {
    > + if (mdev->req_mgr) {
    > + media_request_mgr_free(mdev->req_mgr);
    > + mdev->req_mgr = NULL;
    > + }
    > ida_destroy(&mdev->entity_internal_idx);
    > mdev->entity_internal_idx_max = 0;
    > media_graph_walk_cleanup(&mdev->pm_count_walk);
    > diff --git a/drivers/media/media-request-mgr.c b/drivers/media/media-request-mgr.c
    > new file mode 100644
    > index 000000000000..686e877a884b
    > --- /dev/null
    > +++ b/drivers/media/media-request-mgr.c
    > @@ -0,0 +1,105 @@
    > +/*
    > + * Generic request manager implementation.
    > + *
    > + * Copyright (C) 2018, The Chromium OS Authors. All rights reserved.
    > + *
    > + * This program is free software; you can redistribute it and/or modify
    > + * it under the terms of the GNU General Public License version 2 as
    > + * published by the Free Software Foundation.
    > + *
    > + * 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.
    > + */
    > +
    > +#include <linux/device.h>
    > +#include <linux/slab.h>
    > +
    > +#include <media/media-device.h>
    > +#include <media/media-request.h>
    > +#include <media/media-request-mgr.h>
    > +
    > +static struct media_request *
    > +media_request_alloc(struct media_request_mgr *mgr)
    > +{
    > + struct media_request *req;
    > +
    > + req = kzalloc(sizeof(*req), GFP_KERNEL);
    > + if (!req)
    > + return ERR_PTR(-ENOMEM);
    > +
    > + req->mgr = mgr;
    > + req->state = MEDIA_REQUEST_STATE_IDLE;
    > + kref_init(&req->kref);
    > + INIT_LIST_HEAD(&req->data);
    > + init_waitqueue_head(&req->complete_wait);
    > + ATOMIC_INIT_NOTIFIER_HEAD(&req->submit_notif);
    > + mutex_init(&req->lock);
    > +
    > + mutex_lock(&mgr->mutex);
    > + req->id = ++mgr->req_id;
    > + list_add_tail(&req->list, &mgr->requests);
    > + mutex_unlock(&mgr->mutex);
    > +
    > + return req;
    > +}
    > +
    > +static void media_request_free(struct media_request *req)
    > +{
    > + struct media_request_mgr *mgr = req->mgr;
    > + struct media_request_entity_data *data, *next;
    > +
    > + mutex_lock(&mgr->mutex);
    > + list_del(&req->list);
    > + mutex_unlock(&mgr->mutex);
    > +
    > + list_for_each_entry_safe(data, next, &req->data, list) {
    > + list_del(&data->list);
    > + data->entity->req_ops->data_free(data);
    > + }
    > +
    > + kfree(req);
    > +}
    > +
    > +void media_request_mgr_free(struct media_request_mgr *mgr)
    > +{
    > + struct media_device *mdev = mgr->mdev;
    > +
    > + /* Just a sanity check - we should have no remaining requests */
    > + while (!list_empty(&mgr->requests)) {
    > + struct media_request *req;
    > +
    > + req = list_first_entry(&mgr->requests, typeof(*req), list);
    > + dev_warn(mdev->dev,
    > + "%s: request %u still referenced, deleting forcibly!\n",
    > + __func__, req->id);
    > + mgr->ops->req_free(req);
    > + }
    > +
    > + kfree(mgr);
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_mgr_free);
    > +
    > +static const struct media_request_mgr_ops request_mgr_generic_ops = {
    > + .req_alloc = media_request_alloc,
    > + .req_free = media_request_free,
    > +};
    > +
    > +struct media_request_mgr *
    > +media_request_mgr_alloc(struct media_device *mdev)
    > +{
    > + struct media_request_mgr *mgr;
    > +
    > + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
    > + if (!mgr)
    > + return ERR_PTR(-ENOMEM);
    > +
    > + mgr->mdev = mdev;
    > + mutex_init(&mgr->mutex);
    > + INIT_LIST_HEAD(&mgr->requests);
    > + mgr->ops = &request_mgr_generic_ops;
    > +
    > + return mgr;
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_mgr_alloc);
    > diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
    > new file mode 100644
    > index 000000000000..30a23235b019
    > --- /dev/null
    > +++ b/drivers/media/media-request.c
    > @@ -0,0 +1,311 @@
    > +/*
    > + * Request base implementation
    > + *
    > + * Copyright (C) 2018, The Chromium OS Authors. All rights reserved.
    > + *
    > + * This program is free software; you can redistribute it and/or modify
    > + * it under the terms of the GNU General Public License version 2 as
    > + * published by the Free Software Foundation.
    > + *
    > + * 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.
    > + */
    > +
    > +#include <linux/anon_inodes.h>
    > +#include <linux/media.h>
    > +#include <linux/fs.h>
    > +#include <linux/file.h>
    > +#include <linux/slab.h>
    > +#include <linux/list.h>
    > +
    > +#include <media/media-device.h>
    > +#include <media/media-request.h>
    > +#include <media/media-request-mgr.h>
    > +
    > +const struct file_operations request_fops;
    > +
    > +struct media_request *media_request_get(struct media_request *req)
    > +{
    > + kref_get(&req->kref);
    > + return req;
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_get);
    > +
    > +struct media_request *
    > +media_request_get_from_fd(int fd)
    > +{
    > + struct file *f;
    > + struct media_request *req;
    > +
    > + f = fget(fd);
    > + if (!f)
    > + return NULL;
    > +
    > + /* Not a request FD? */
    > + if (f->f_op != &request_fops) {
    > + fput(f);
    > + return NULL;
    > + }
    > +
    > + req = f->private_data;
    > + media_request_get(req);
    > + fput(f);
    > +
    > + return req;
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_get_from_fd);
    > +
    > +static void media_request_release(struct kref *kref)
    > +{
    > + struct media_request *req =
    > + container_of(kref, typeof(*req), kref);
    > +
    > + req->mgr->ops->req_free(req);
    > +}
    > +
    > +void media_request_put(struct media_request *req)
    > +{
    > + if (WARN_ON(req == NULL))
    > + return;
    > +
    > + kref_put(&req->kref, media_request_release);
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_put);
    > +
    > +struct media_request_entity_data *
    > +media_request_get_entity_data(struct media_request *req,
    > + struct media_entity *entity, void *fh)
    > +{
    > + struct media_request_entity_data *data;
    > +
    > + mutex_lock(&req->lock);
    > +
    > + /* First look whether we already have entity data */
    > + list_for_each_entry(data, &req->data, list) {
    > + if (data->entity == entity) {
    > + /*
    > + * If so, then the fh must match otherwise this means
    > + * we are trying to set the same entity through
    > + * different handles
    > + */
    > + if (data->fh != fh)
    > + data = ERR_PTR(-EINVAL);
    > + goto done;
    > + }
    > + }
    > +
    > + /* No entity data found, let's create it */
    > + data = entity->req_ops->data_alloc(entity, fh);
    > + if (IS_ERR(data))
    > + goto done;
    > + data->fh = fh;
    > + data->entity = entity;
    > + list_add_tail(&data->list, &req->data);
    > +
    > +done:
    > + mutex_unlock(&req->lock);
    > + return data;
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_get_entity_data);
    > +
    > +static const char * const media_request_states[] __maybe_unused = {
    > + "IDLE",
    > + "SUBMITTED",
    > + "COMPLETED",
    > + "DELETED",
    > +};
    > +
    > +static const char *media_request_state(enum media_request_state state)
    > +{
    > + return state < ARRAY_SIZE(media_request_states) ?
    > + media_request_states[state] : "INVALID";
    > +}
    > +
    > +static int media_device_request_close(struct inode *inode, struct file *filp)
    > +{
    > + struct media_request *req = filp->private_data;
    > +
    > + if (req == NULL)
    > + return 0;
    > +
    > + media_request_put(req);
    > +
    > + return 0;
    > +}
    > +
    > +static unsigned int media_request_poll(struct file *file, poll_table *wait)
    > +{
    > + struct media_request *req = file->private_data;
    > +
    > + poll_wait(file, &req->complete_wait, wait);
    > +
    > + if (req->state == MEDIA_REQUEST_STATE_COMPLETED)
    > + return POLLIN | POLLRDNORM;
    > +
    > + return 0;
    > +}
    > +
    > +const struct file_operations request_fops = {
    > + .owner = THIS_MODULE,
    > + .poll = media_request_poll,
    > + .release = media_device_request_close,
    > +};
    > +
    > +void media_request_complete(struct media_request *req)
    > +{
    > + struct media_request_mgr *mgr = req->mgr;
    > + struct media_device *mdev = mgr->mdev;
    > +
    > + mutex_lock(&req->lock);
    > +
    > + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_SUBMITTED)) {
    > + dev_dbg(mdev->dev, "%s: can't complete %u, state %s\n",
    > + __func__, req->id, media_request_state(req->state));
    > + mutex_unlock(&req->lock);
    > + return;
    > + }
    > +
    > + req->state = MEDIA_REQUEST_STATE_COMPLETED;
    > +
    > + if (mgr->ops->req_complete)
    > + mgr->ops->req_complete(req);
    > +
    > + wake_up_interruptible(&req->complete_wait);
    > +
    > + mutex_unlock(&req->lock);
    > +
    > + /* Release the reference acquired when we submitted the request */
    > + media_request_put(req);
    > +}
    > +EXPORT_SYMBOL_GPL(media_request_complete);
    > +
    > +/*
    > + * Process the MEDIA_REQ_CMD_ALLOC command
    > + */
    > +static int media_request_cmd_alloc(struct media_request_mgr *mgr,
    > + struct media_request_cmd *cmd)
    > +{
    > + struct media_request *req;
    > + int fd;
    > +
    > + req = mgr->ops->req_alloc(mgr);
    > + if (!req)
    > + return -ENOMEM;
    > +
    > + fd = anon_inode_getfd("media_request", &request_fops, req, O_CLOEXEC);
    > + if (fd < 0)
    > + return fd;
    > +
    > + cmd->fd = fd;
    > +
    > + return 0;
    > +}
    > +
    > +/*
    > + * Process the MEDIA_REQ_CMD_SUBMIT command
    > + */
    > +static int media_request_cmd_submit(struct media_request *req)
    > +{
    > + mutex_lock(&req->lock);
    > +
    > + if (req->state != MEDIA_REQUEST_STATE_IDLE) {
    > + dev_dbg(req->mgr->mdev->dev,
    > + "%s: unable to submit request in state %s\n",
    > + __func__, media_request_state(req->state));
    > + mutex_unlock(&req->lock);
    > + return -EINVAL;
    > + }
    > +
    > + if (atomic_read(&req->buf_cpt) == 0) {
    > + dev_dbg(req->mgr->mdev->dev,
    > + "%s: request has no buffers!\n", __func__);
    > + mutex_unlock(&req->lock);
    > + return -EINVAL;
    > + }
    > +
    > + req->state = MEDIA_REQUEST_STATE_SUBMITTED;
    > +
    > + /* Hold a reference to the request until it is completed */
    > + media_request_get(req);
    > +
    > + mutex_unlock(&req->lock);
    > +
    > + atomic_notifier_call_chain(&req->submit_notif, req->state, req);
    > +
    > + return 0;
    > +}
    > +
    > +static int media_request_cmd_reinit(struct media_request *req)
    > +{
    > + struct media_request_entity_data *data, *next;
    > +
    > + mutex_lock(&req->lock);
    > +
    > + if (req->state == MEDIA_REQUEST_STATE_SUBMITTED) {
    > + dev_dbg(req->mgr->mdev->dev,
    > + "%s: unable to reinit submitted request\n", __func__);
    > + mutex_unlock(&req->lock);
    > + return -EINVAL;
    > + }
    > +
    > + /* delete all entity data */
    > + list_for_each_entry_safe(data, next, &req->data, list) {
    > + list_del(&data->list);
    > + data->entity->req_ops->data_free(data);
    > + }
    > +
    > + /* reinitialize request to idle state */
    > + req->state = MEDIA_REQUEST_STATE_IDLE;
    > + atomic_set(&req->buf_cpt, 0);
    > +
    > + mutex_unlock(&req->lock);
    > +
    > + return 0;
    > +}
    > +
    > +long media_device_request_cmd(struct media_device *mdev,
    > + struct media_request_cmd *cmd)
    > +{
    > + struct media_request *req = NULL;
    > + int ret;
    > +
    > + if (!mdev->req_mgr)
    > + return -ENOTTY;
    > +
    > + if (cmd->cmd != MEDIA_REQ_CMD_ALLOC) {
    > + req = media_request_get_from_fd(cmd->fd);
    > + if (IS_ERR(req))
    > + return PTR_ERR(req);
    > +
    > + /* requests must belong to this media device's manager */
    > + if (req->mgr != mdev->req_mgr) {
    > + media_request_put(req);
    > + return -EINVAL;
    > + }
    > + }
    > +
    > + switch (cmd->cmd) {
    > + case MEDIA_REQ_CMD_ALLOC:
    > + ret = media_request_cmd_alloc(mdev->req_mgr, cmd);
    > + break;
    > +
    > + case MEDIA_REQ_CMD_SUBMIT:
    > + ret = media_request_cmd_submit(req);
    > + break;
    > +
    > + case MEDIA_REQ_CMD_REINIT:
    > + ret = media_request_cmd_reinit(req);
    > + break;
    > +
    > + default:
    > + ret = -EINVAL;
    > + break;
    > + }
    > +
    > + if (req)
    > + media_request_put(req);
    > +
    > + return ret;
    > +}
    > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
    > index 260288ca4f55..e5109e5b8bf5 100644
    > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
    > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
    > @@ -870,7 +870,7 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
    > __u32 i;
    >
    > /* zero the reserved fields */
    > - c->reserved[0] = c->reserved[1] = 0;
    > + c->reserved[0] = 0;
    > for (i = 0; i < c->count; i++)
    > c->controls[i].reserved2[0] = 0;
    >
    > diff --git a/include/media/media-device.h b/include/media/media-device.h
    > index bcc6ec434f1f..f2d471b8a53f 100644
    > --- a/include/media/media-device.h
    > +++ b/include/media/media-device.h
    > @@ -27,6 +27,7 @@
    >
    > struct ida;
    > struct device;
    > +struct media_request_mgr;
    >
    > /**
    > * struct media_entity_notify - Media Entity Notify
    > @@ -158,6 +159,8 @@ struct media_device {
    > void (*disable_source)(struct media_entity *entity);
    >
    > const struct media_device_ops *ops;
    > +
    > + struct media_request_mgr *req_mgr;
    > };
    >
    > /* We don't need to include pci.h or usb.h here */
    > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
    > index a732af1dbba0..39f5e88e2b23 100644
    > --- a/include/media/media-entity.h
    > +++ b/include/media/media-entity.h
    > @@ -172,6 +172,8 @@ struct media_pad {
    > unsigned long flags;
    > };
    >
    > +struct media_request;
    > +struct v4l2_ext_controls;
    > /**
    > * struct media_entity_operations - Media entity operations
    > * @get_fwnode_pad: Return the pad number based on a fwnode endpoint or
    > @@ -197,6 +199,11 @@ struct media_entity_operations {
    > int (*link_validate)(struct media_link *link);
    > };
    >
    > +struct media_entity_request_ops {
    > + struct media_request_entity_data *(*data_alloc)(struct media_entity *entity, void *fh);
    > + void (*data_free)(struct media_request_entity_data *data);
    > +};
    > +
    > /**
    > * enum media_entity_type - Media entity type
    > *
    > @@ -281,6 +288,8 @@ struct media_entity {
    >
    > const struct media_entity_operations *ops;
    >
    > + const struct media_entity_request_ops *req_ops;
    > +
    > int stream_count;
    > int use_count;
    >
    > diff --git a/include/media/media-request-mgr.h b/include/media/media-request-mgr.h
    > new file mode 100644
    > index 000000000000..a3161fa2add0
    > --- /dev/null
    > +++ b/include/media/media-request-mgr.h
    > @@ -0,0 +1,73 @@
    > +/*
    > + * Generic request manager.
    > + *
    > + * Copyright (C) 2018, The Chromium OS Authors. All rights reserved.
    > + *
    > + * This program is free software; you can redistribute it and/or modify
    > + * it under the terms of the GNU General Public License version 2 as
    > + * published by the Free Software Foundation.
    > + *
    > + * 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.
    > + */
    > +
    > +#ifndef _MEDIA_REQUEST_MGR_H
    > +#define _MEDIA_REQUEST_MGR_H
    > +
    > +#include <linux/mutex.h>
    > +
    > +struct media_request_mgr;
    > +
    > +/**
    > + * struct media_request_mgr_ops - request manager operations
    > + *
    > + * @req_alloc: allocate a request
    > + * @req_free: free a previously allocated request
    > + * @req_complete: callback invoked when a request has completed
    > + *
    > + */
    > +struct media_request_mgr_ops {
    > + struct media_request *(*req_alloc)(struct media_request_mgr *mgr);
    > + void (*req_free)(struct media_request *req);
    > + void (*req_complete)(struct media_request *req);
    > +};
    > +
    > +/**
    > + * struct media_request_mgr - requests manager
    > + *
    > + * @mdev: media_device owning this manager
    > + * @ops: implementation of the manager
    > + * @mutex: protects requests, active_request, req_id, and all members of
    > + * struct media_request

    The media request has a mutex as well. Is this outdated?

    > + * @requests: list of alive requests produced by this manager
    > + * @req_id: counter used to identify requests for debugging purposes
    > + */
    > +struct media_request_mgr {
    > + struct media_device *mdev;
    > + const struct media_request_mgr_ops *ops;
    > +
    > + struct mutex mutex;
    > + struct list_head requests;
    > + u32 req_id;
    > +};
    > +
    > +/**
    > + * media_request_mgr_alloc() - return an instance of the generic manager
    > + *
    > + * @mdev: owning media device
    > + */
    > +struct media_request_mgr *
    > +media_request_mgr_alloc(struct media_device *mdev);
    > +
    > +/**
    > + * media_request_mgr_free() - free a media manager
    > + *
    > + * This should only be called when all requests produced by this manager
    > + * has been destroyed. Will warn if that is not the case.
    > + *
    > + */
    > +void media_request_mgr_free(struct media_request_mgr *mgr);
    > +
    > +#endif
    > diff --git a/include/media/media-request.h b/include/media/media-request.h
    > new file mode 100644
    > index 000000000000..817df13ef6e3
    > --- /dev/null
    > +++ b/include/media/media-request.h
    > @@ -0,0 +1,186 @@
    > +/*
    > + * Media requests.
    > + *
    > + * Copyright (C) 2018, The Chromium OS Authors. All rights reserved.
    > + *
    > + * This program is free software; you can redistribute it and/or modify
    > + * it under the terms of the GNU General Public License version 2 as
    > + * published by the Free Software Foundation.
    > + *
    > + * 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.
    > + */
    > +
    > +#ifndef _MEDIA_REQUEST_H
    > +#define _MEDIA_REQUEST_H
    > +
    > +#include <linux/kref.h>
    > +#include <linux/list.h>
    > +#include <linux/notifier.h>
    > +#include <linux/wait.h>
    > +
    > +struct media_device;
    > +struct media_entity;
    > +struct media_request_cmd;
    > +struct media_request_entity_data;
    > +struct media_request_mgr;
    > +
    > +#ifdef CONFIG_MEDIA_CONTROLLER
    > +
    > +enum media_request_state {
    > + MEDIA_REQUEST_STATE_IDLE,
    > + MEDIA_REQUEST_STATE_SUBMITTED,
    > + MEDIA_REQUEST_STATE_COMPLETED,
    > + MEDIA_REQUEST_STATE_DELETED,
    > +};
    > +
    > +/**
    > + * struct media_request - Media request base structure
    > + * @id: request id, used internally for debugging
    > + * @mgr: manager this request belongs to
    > + * @kref: reference count
    > + * @list: list entry in the media device requests list
    > + * @lock: protects internal state against concurrent accesses
    > + * @state: current state of the request
    > + * @data: per-entity data list
    > + * @complete_wait: wait queue that signals once the request has completed
    > + * @submit_notif: notification list to call when the request is submitted
    > + * @buf_cpt: counter of queued/completed buffers used to decide when the
    > + * request is completed
    > + */
    > +struct media_request {
    > + u32 id;
    > + struct media_request_mgr *mgr;
    > + struct kref kref;
    > + struct list_head list;
    > +
    > + struct mutex lock;
    > + enum media_request_state state;
    > + struct list_head data;
    > + wait_queue_head_t complete_wait;
    > + struct atomic_notifier_head submit_notif;
    > + atomic_t buf_cpt;
    > +};
    > +
    > +/**
    > + * media_request_get() - increment the reference counter of a request
    > + *
    > + * The calling context must call media_request_put() once it does not need
    > + * the reference to the request anymore.
    > + *
    > + * Returns the request that has been passed as argument.
    > + *
    > + * @req: request to acquire a reference of
    > + */
    > +struct media_request *media_request_get(struct media_request *req);
    > +
    > +/**
    > + * media_request_get_from_fd() - lookup request by fd and acquire a reference.
    > + *
    > + * Look a request up from its fd, acquire a reference and return a pointer to
    > + * the request. As for media_request_get(), media_request_put() must be called
    > + * once the reference is not used anymore.
    > + *
    > + * @req: request to lookup and acquire.
    > + *
    > + */
    > +struct media_request *media_request_get_from_fd(int fd);
    > +
    > +/**
    > + * media_request_put() - decrement the reference counter of a request
    > + *
    > + * Mirror function of media_request_get() and media_request_get_from_fd(). Will
    > + * free the request if this was the last valid reference.
    > + *
    > + * @req: request to release.
    > + */
    > +void media_request_put(struct media_request *req);
    > +
    > +/**
    > + * media_request_get_entity_data() - get per-entity data for a request
    > + * @req: request to get entity data from
    > + * @entity: entity to get data of
    > + * @fh: cookie identifying the handle from which the entity is accessed
    > + *
    > + * Search and return the entity data associated associated to the request. If no
    > + * such data exists, it is allocated as per the entity operations.
    > + *
    > + * The fh arguments serves as a cookie to make sure the same entity is not
    > + * accessed through different opened file handles. The same handle must be
    > + * passed to all calls of this function for the same entity. Failure to do so
    > + * will return an error.
    > + *
    > + * Returns the per-entity data, or an error code if a problem happened. -EINVAL
    > + * means that data for the entity already existed, but has been allocated under
    > + * a different cookie.
    > + */
    > +struct media_request_entity_data *
    > +media_request_get_entity_data(struct media_request *req,
    > + struct media_entity *entity, void *fh);
    > +
    > +
    > +/**
    > + * media_request_complete() - to be invoked when the request is complete
    > + *
    > + * @req: request which has completed
    > + */
    > +void media_request_complete(struct media_request *req);
    > +
    > +/**
    > + * struct media_request_entity_data - per-entity request data
    > + *
    > + * Base structure used to store request state data. To be extended by actual
    > + * implementation.
    > + *
    > + * @entity: entity this data belongs to
    > + * @fh: subsystem-dependent. For V4L2, the v4l2_fh of the opened device
    > + * @list: entry in media_request::data
    > + * @applied: whether this request has already been applied for this entity
    > + */
    > +struct media_request_entity_data {
    > + struct media_entity *entity;
    > + void *fh;
    > + struct list_head list;
    > + bool applied;
    > +};
    > +
    > +/**
    > + * media_device_request_cmd() - perform the REQUEST_CMD ioctl
    > + *
    > + * @mdev: media device the ioctl has been called on
    > + * @cmd: user-space request command structure
    > + */
    > +long media_device_request_cmd(struct media_device *mdev,
    > + struct media_request_cmd *cmd);
    > +
    > +#else /* CONFIG_MEDIA_CONTROLLER */
    > +
    > +static inline media_request_get(struct media_request *req)
    > +{
    > +}
    > +
    > +static inline struct media_request *media_request_get_from_fd(int fd)
    > +{
    > + return ERR_PTR(-ENOSYS);
    > +}
    > +
    > +static inline void media_request_put(struct media_request *req)
    > +{
    > +}
    > +
    > +static inline struct media_request *media_request_get_entity_data(
    > + struct media_request *req,
    > + struct media_entity *entity, void *fh)
    > +{
    > + return ERR_PTR(-ENOSYS);
    > +}
    > +
    > +static inline void media_request_entity_complete(struct media_request *req)
    > +{
    > +}
    > +
    > +#endif /* CONFIG_MEDIA_CONTROLLER */
    > +
    > +#endif
    > diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
    > index b9b9446095e9..6e20ac9848b5 100644
    > --- a/include/uapi/linux/media.h
    > +++ b/include/uapi/linux/media.h
    > @@ -406,6 +406,15 @@ struct media_v2_topology {
    > __u64 ptr_links;
    > } __attribute__ ((packed));
    >
    > +#define MEDIA_REQ_CMD_ALLOC 0
    > +#define MEDIA_REQ_CMD_SUBMIT 1
    > +#define MEDIA_REQ_CMD_REINIT 2
    > +
    > +struct media_request_cmd {
    > + __u32 cmd;
    > + __s32 fd;
    > +} __attribute__ ((packed));
    > +
    > /* ioctls */
    >
    > #define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
    > @@ -413,5 +422,6 @@ struct media_v2_topology {
    > #define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
    > #define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
    > #define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
    > +#define MEDIA_IOC_REQUEST_CMD _IOWR('|', 0x05, struct media_request_cmd)
    >
    > #endif /* __LINUX_MEDIA_H */
    > --
    > 2.16.0.rc1.238.g530d649a79-goog
    >

    --
    Sakari Ailus
    sakari.ailus@linux.intel.com

    \
     
     \ /
      Last update: 2018-02-07 12:26    [W:3.384 / U:0.224 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site