From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: linux-media@vger.kernel.org
Cc: laurent.pinchart@ideasonboard.com, hverkuil@xs4all.nl,
mchehab@osg.samsung.com,
Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Subject: [RFC 01/22] media: Add request API
Date: Fri, 6 May 2016 13:53:10 +0300 [thread overview]
Message-ID: <1462532011-15527-2-git-send-email-sakari.ailus@linux.intel.com> (raw)
In-Reply-To: <1462532011-15527-1-git-send-email-sakari.ailus@linux.intel.com>
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
The request API allows bundling media device parameters with request
objects and applying them atomically, either synchronously or
asynchronously.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
Changes since v0:
- Make the request ID 32 bits wide internally
---
- Strip off the reserved fields
- Use __attribute__ ((packed)) for the IOCTL argument struct.
- Manage request ID space using ida_simple
- Fix compat handling for requests
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/media-device.c | 194 ++++++++++++++++++++++++++++++++++++++++++-
include/media/media-device.h | 41 +++++++++
include/uapi/linux/media.h | 11 +++
3 files changed, 243 insertions(+), 3 deletions(-)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 3b9a1bf..4fc1eb1 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -41,6 +41,7 @@
struct media_device_fh {
struct media_devnode_fh fh;
+ struct list_head requests;
};
static inline struct media_device_fh *media_device_fh(struct file *filp)
@@ -49,6 +50,170 @@ static inline struct media_device_fh *media_device_fh(struct file *filp)
}
/* -----------------------------------------------------------------------------
+ * Requests
+ */
+
+/**
+ * media_device_request_find - Find a request based from its ID
+ * @mdev: The media device
+ * @reqid: The request ID
+ *
+ * Find and return the request associated with the given ID, or NULL if no such
+ * request exists.
+ *
+ * When the function returns a non-NULL request it increases its reference
+ * count. The caller is responsible for releasing the reference by calling
+ * media_device_request_put() on the request.
+ */
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid)
+{
+ struct media_device_request *req;
+ unsigned long flags;
+ bool found = false;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ list_for_each_entry(req, &mdev->requests, list) {
+ if (req->id == reqid) {
+ kref_get(&req->kref);
+ found = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ return found ? req : NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_request_find);
+
+void media_device_request_get(struct media_device_request *req)
+{
+ kref_get(&req->kref);
+}
+EXPORT_SYMBOL_GPL(media_device_request_get);
+
+static void media_device_request_release(struct kref *kref)
+{
+ struct media_device_request *req =
+ container_of(kref, struct media_device_request, kref);
+ struct media_device *mdev = req->mdev;
+
+ ida_simple_remove(&mdev->req_ids, req->id);
+
+ mdev->ops->req_free(mdev, req);
+}
+
+void media_device_request_put(struct media_device_request *req)
+{
+ kref_put(&req->kref, media_device_request_release);
+}
+EXPORT_SYMBOL_GPL(media_device_request_put);
+
+static int media_device_request_alloc(struct media_device *mdev,
+ struct media_device_fh *fh,
+ struct media_request_cmd *cmd)
+{
+ struct media_device_request *req;
+ unsigned long flags;
+ int id = ida_simple_get(&mdev->req_ids, 1, 0, GFP_KERNEL);
+ int ret;
+
+ if (id < 0)
+ return id;
+
+ req = mdev->ops->req_alloc(mdev);
+ if (!req) {
+ ret = -ENOMEM;
+ goto out_ida_simple_remove;
+ }
+
+ req->mdev = mdev;
+ req->id = id;
+ kref_init(&req->kref);
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ list_add_tail(&req->list, &mdev->requests);
+ list_add_tail(&req->fh_list, &fh->requests);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ cmd->request = req->id;
+
+ return 0;
+
+out_ida_simple_remove:
+ ida_simple_remove(&mdev->req_ids, id);
+
+ return ret;
+}
+
+static void media_device_request_delete(struct media_device *mdev,
+ struct media_device_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ list_del(&req->list);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+
+ media_device_request_put(req);
+}
+
+static long media_device_request_cmd(struct media_device *mdev,
+ struct file *filp,
+ struct media_request_cmd *cmd)
+{
+ struct media_device_fh *fh = media_device_fh(filp);
+ struct media_device_request *req = NULL;
+ int ret;
+
+ if (!mdev->ops || !mdev->ops->req_alloc || !mdev->ops->req_free)
+ return -ENOTTY;
+
+ if (cmd->cmd != MEDIA_REQ_CMD_ALLOC) {
+ req = media_device_request_find(mdev, cmd->request);
+ if (!req)
+ return -EINVAL;
+ }
+
+ switch (cmd->cmd) {
+ case MEDIA_REQ_CMD_ALLOC:
+ ret = media_device_request_alloc(mdev, fh, cmd);
+ break;
+
+ case MEDIA_REQ_CMD_DELETE:
+ media_device_request_delete(mdev, req);
+ ret = 0;
+ break;
+
+ case MEDIA_REQ_CMD_APPLY:
+ if (!mdev->ops->req_apply)
+ return -ENOSYS;
+
+ ret = mdev->ops->req_apply(mdev, req);
+ break;
+
+ case MEDIA_REQ_CMD_QUEUE:
+ if (!mdev->ops->req_queue)
+ return -ENOSYS;
+
+ ret = mdev->ops->req_queue(mdev, req);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (req)
+ media_device_request_put(req);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
* Userspace API
*/
@@ -65,6 +230,7 @@ static int media_device_open(struct file *filp)
if (!fh)
return -ENOMEM;
+ INIT_LIST_HEAD(&fh->requests);
filp->private_data = &fh->fh;
return 0;
@@ -73,6 +239,15 @@ static int media_device_open(struct file *filp)
static int media_device_close(struct file *filp)
{
struct media_device_fh *fh = media_device_fh(filp);
+ struct media_device *mdev = to_media_device(fh->fh.devnode);
+ struct media_device_request *req, *next;
+
+ spin_lock_irq(&mdev->req_lock);
+ list_for_each_entry_safe(req, next, &fh->requests, fh_list) {
+ list_del(&req->fh_list);
+ media_device_request_put(req);
+ }
+ spin_unlock_irq(&mdev->req_lock);
kfree(fh);
@@ -80,6 +255,7 @@ static int media_device_close(struct file *filp)
}
static int media_device_get_info(struct media_device *dev,
+ struct file *filp,
struct media_device_info *info)
{
memset(info, 0, sizeof(*info));
@@ -119,6 +295,7 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
}
static long media_device_enum_entities(struct media_device *mdev,
+ struct file *filp,
struct media_entity_desc *entd)
{
struct media_entity *ent;
@@ -172,6 +349,7 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad,
}
static long media_device_enum_links(struct media_device *mdev,
+ struct file *filp,
struct media_links_enum *links)
{
struct media_entity *entity;
@@ -220,6 +398,7 @@ static long media_device_enum_links(struct media_device *mdev,
}
static long media_device_setup_link(struct media_device *mdev,
+ struct file *filp,
struct media_link_desc *linkd)
{
struct media_link *link = NULL;
@@ -248,6 +427,7 @@ static long media_device_setup_link(struct media_device *mdev,
}
static long media_device_get_topology(struct media_device *mdev,
+ struct file *filp,
struct media_v2_topology *topo)
{
struct media_entity *entity;
@@ -417,7 +597,8 @@ static long copy_arg_to_user_nop(void __user *uarg, void *karg,
#define MEDIA_IOC_SZ_ARG(__cmd, func, fl, alt_sz, from_user, to_user) \
[_IOC_NR(MEDIA_IOC_##__cmd)] = { \
.cmd = MEDIA_IOC_##__cmd, \
- .fn = (long (*)(struct media_device *, void *))func, \
+ .fn = (long (*)(struct media_device *, \
+ struct file *, void *))func, \
.flags = fl, \
.alt_arg_sizes = alt_sz, \
.arg_from_user = from_user, \
@@ -438,7 +619,7 @@ static long copy_arg_to_user_nop(void __user *uarg, void *karg,
/* the table is indexed by _IOC_NR(cmd) */
struct media_ioctl_info {
unsigned int cmd;
- long (*fn)(struct media_device *dev, void *arg);
+ long (*fn)(struct media_device *dev, struct file *file, void *arg);
unsigned short flags;
const unsigned short *alt_arg_sizes;
long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd);
@@ -511,7 +692,7 @@ static long __media_device_ioctl(
if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
mutex_lock(&dev->graph_mutex);
- ret = info->fn(dev, karg);
+ ret = info->fn(dev, filp, karg);
if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
mutex_unlock(&dev->graph_mutex);
@@ -531,6 +712,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,
@@ -578,6 +760,7 @@ static const struct media_ioctl_info compat_ioctl_info[] = {
MEDIA_IOC_ARG(ENUM_LINKS32, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX, from_user_enum_links32, copy_arg_to_user_nop),
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_compat_ioctl(struct file *filp, unsigned int cmd,
@@ -762,6 +945,7 @@ void media_device_init(struct media_device *mdev)
INIT_LIST_HEAD(&mdev->entity_notify);
mutex_init(&mdev->graph_mutex);
ida_init(&mdev->entity_internal_idx);
+ ida_init(&mdev->req_ids);
dev_dbg(mdev->dev, "Media device initialized\n");
}
@@ -769,6 +953,7 @@ EXPORT_SYMBOL_GPL(media_device_init);
void media_device_cleanup(struct media_device *mdev)
{
+ ida_destroy(&mdev->req_ids);
ida_destroy(&mdev->entity_internal_idx);
mdev->entity_internal_idx_max = 0;
media_entity_graph_walk_cleanup(&mdev->pm_count_walk);
@@ -781,6 +966,9 @@ int __must_check __media_device_register(struct media_device *mdev,
{
int ret;
+ spin_lock_init(&mdev->req_lock);
+ INIT_LIST_HEAD(&mdev->requests);
+
/* Register the device node. */
mdev->devnode.fops = &media_device_fops;
mdev->devnode.parent = mdev->dev;
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 19c8ed4..49c3367a 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -23,6 +23,7 @@
#ifndef _MEDIA_DEVICE_H
#define _MEDIA_DEVICE_H
+#include <linux/kref.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -262,6 +263,23 @@
struct ida;
struct device;
+struct media_device;
+
+/**
+ * struct media_device_request - Media device request
+ * @id: Request ID
+ * @mdev: Media device this request belongs to
+ * @kref: Reference count
+ * @list: List entry in the media device requests list
+ * @fh_list: List entry in the media file handle requests list
+ */
+struct media_device_request {
+ u32 id;
+ struct media_device *mdev;
+ struct kref kref;
+ struct list_head list;
+ struct list_head fh_list;
+};
/**
* struct media_entity_notify - Media Entity Notify
@@ -283,10 +301,21 @@ struct media_entity_notify {
* struct media_device_ops - Media device operations
* @link_notify: Link state change notification callback. This callback is
* called with the graph_mutex held.
+ * @req_alloc: Allocate a request
+ * @req_free: Free a request
+ * @req_apply: Apply a request
+ * @req_queue: Queue a request
*/
struct media_device_ops {
int (*link_notify)(struct media_link *link, u32 flags,
unsigned int notification);
+ struct media_device_request *(*req_alloc)(struct media_device *mdev);
+ void (*req_free)(struct media_device *mdev,
+ struct media_device_request *req);
+ int (*req_apply)(struct media_device *mdev,
+ struct media_device_request *req);
+ int (*req_queue)(struct media_device *mdev,
+ struct media_device_request *req);
};
/**
@@ -322,6 +351,9 @@ struct media_device_ops {
* @disable_source: Disable Source Handler function pointer
*
* @ops: Operation handler callbacks
+ * @req_ids: Allocated request IDs
+ * @req_lock: Serialise access to requests list
+ * @requests: List of allocated requests
*
* This structure represents an abstract high-level media device. It allows easy
* access to entities and provides basic media device-level support. The
@@ -389,6 +421,10 @@ struct media_device {
void (*disable_source)(struct media_entity *entity);
const struct media_device_ops *ops;
+
+ struct ida req_ids;
+ spinlock_t req_lock;
+ struct list_head requests;
};
/* We don't need to include pci.h or usb.h here */
@@ -715,4 +751,9 @@ static inline void __media_device_usb_init(struct media_device *mdev,
#define media_device_usb_init(mdev, udev, name) \
__media_device_usb_init(mdev, udev, name, KBUILD_MODNAME)
+struct media_device_request *
+media_device_request_find(struct media_device *mdev, u16 reqid);
+void media_device_request_get(struct media_device_request *req);
+void media_device_request_put(struct media_device_request *req);
+
#endif
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index df59ede..e8922ea 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -389,10 +389,21 @@ struct media_v2_topology {
/* ioctls */
+#define MEDIA_REQ_CMD_ALLOC 0
+#define MEDIA_REQ_CMD_DELETE 1
+#define MEDIA_REQ_CMD_APPLY 2
+#define MEDIA_REQ_CMD_QUEUE 3
+
+struct __attribute__ ((packed)) media_request_cmd {
+ __u32 cmd;
+ __u32 request;
+};
+
#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc)
#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 */
--
1.9.1
next prev parent reply other threads:[~2016-05-06 10:56 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-06 10:53 [RFC 00/22] Media request API Sakari Ailus
2016-05-06 10:53 ` Sakari Ailus [this message]
2016-05-06 10:53 ` [RFC 02/22] media: Add media device request state Sakari Ailus
2016-05-06 10:53 ` [RFC 03/22] media: Prevent queueing queued requests Sakari Ailus
2016-05-06 10:53 ` [RFC 04/22] media: Only requests in IDLE state may be deleted Sakari Ailus
2016-05-06 10:53 ` [RFC 05/22] media: Add media_device_request_complete() to mark requests complete Sakari Ailus
2016-05-06 10:53 ` [RFC 06/22] media: Add per-entity request data support Sakari Ailus
2016-05-06 10:53 ` [RFC 07/22] videodev2.h: Add request field to v4l2_buffer Sakari Ailus
2016-05-06 10:53 ` [RFC 08/22] videodev2.h: Add request field to v4l2_pix_format_mplane Sakari Ailus
2016-05-06 16:33 ` Nicolas Dufresne
2016-05-06 21:48 ` Sakari Ailus
2016-05-06 10:53 ` [RFC 09/22] v4l2-subdev.h: Add request field to format and selection structures Sakari Ailus
2016-05-06 10:53 ` [RFC 10/22] v4l: Support the request API in format operations Sakari Ailus
2016-05-06 10:53 ` [RFC 11/22] v4l: subdev: Support the request API in format and selection operations Sakari Ailus
2016-05-06 10:53 ` [RFC 12/22] vb2: Add allow_requests flag Sakari Ailus
2016-05-06 10:53 ` [RFC 13/22] vb2: Add helper function to check for request buffers Sakari Ailus
2016-05-06 10:53 ` [RFC 14/22] media: Add MEDIA_IOC_DQEVENT Sakari Ailus
2016-05-06 10:53 ` [RFC 15/22] media: Make events on request completion optional, disabled by default Sakari Ailus
2016-05-06 11:05 ` Sakari Ailus
2016-05-06 10:53 ` [RFC 16/22] media: Add poll support Sakari Ailus
2016-05-06 10:53 ` [RFC 17/22] DocBook: media: Document the media request API Sakari Ailus
2016-05-06 10:53 ` [RFC 18/22] DocBook: media: Document the V4L2 " Sakari Ailus
2016-05-06 10:53 ` [RFC 19/22] DocBook: media: Document the subdev selection API Sakari Ailus
2016-05-06 10:53 ` [RFC 20/22] DocBook: media: Document the V4L2 subdev request API Sakari Ailus
2016-05-06 10:53 ` [RFC 21/22] DocBook: media: Document media events (MEDIA_IOC_DQEVENT IOCTL) Sakari Ailus
2016-05-06 10:53 ` [RFC 22/22] DocBook: media: Document request flags Sakari Ailus
2016-05-06 15:25 ` [RFC 00/22] Media request API Sakari Ailus
2016-05-17 8:05 ` Sakari Ailus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1462532011-15527-2-git-send-email-sakari.ailus@linux.intel.com \
--to=sakari.ailus@linux.intel.com \
--cc=hverkuil@xs4all.nl \
--cc=laurent.pinchart+renesas@ideasonboard.com \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@osg.samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.