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 <acour...@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.ai...@linux.intel.com

Reply via email to