lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20180207112533.sk7re4ksoeywop2q@paasikivi.fi.intel.com>
Date:   Wed, 7 Feb 2018 13:25:33 +0200
From:   Sakari Ailus <sakari.ailus@...ux.intel.com>
To:     Alexandre Courbot <acourbot@...omium.org>
Cc:     Mauro Carvalho Chehab <mchehab@...nel.org>,
        Hans Verkuil <hverkuil@...all.nl>,
        Laurent Pinchart <laurent.pinchart@...asonboard.com>,
        Pawel Osciak <posciak@...omium.org>,
        Marek Szyprowski <m.szyprowski@...sung.com>,
        Tomasz Figa <tfiga@...omium.org>,
        Gustavo Padovan <gustavo.padovan@...labora.com>,
        linux-media@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [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@...omium.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@...ux.intel.com

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ