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
Subject: [RFC 14/22] media: Add MEDIA_IOC_DQEVENT
Date: Fri, 6 May 2016 13:53:23 +0300 [thread overview]
Message-ID: <1462532011-15527-15-git-send-email-sakari.ailus@linux.intel.com> (raw)
In-Reply-To: <1462532011-15527-1-git-send-email-sakari.ailus@linux.intel.com>
Events on a media device tell about completion of requests. Blocking and
non-blocking operation is supported.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/media-device.c | 114 +++++++++++++++++++++++++++++++++++++++++--
include/media/media-device.h | 11 +++++
include/uapi/linux/media.h | 17 +++++++
3 files changed, 137 insertions(+), 5 deletions(-)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 10b9a4a..357c3cb 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -23,6 +23,7 @@
/* We need to access legacy defines from linux/media.h */
#define __NEED_MEDIA_LEGACY_API
+#include <linux/atomic.h>
#include <linux/compat.h>
#include <linux/export.h>
#include <linux/idr.h>
@@ -32,6 +33,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/usb.h>
+#include <linux/wait.h>
#include <media/media-device.h>
#include <media/media-devnode.h>
@@ -42,6 +44,12 @@
struct media_device_fh {
struct media_devnode_fh fh;
struct list_head requests;
+ struct {
+ spinlock_t lock;
+ struct list_head head;
+ wait_queue_head_t wait;
+ atomic_t sequence;
+ } kevents;
};
static inline struct media_device_fh *media_device_fh(struct file *filp)
@@ -92,6 +100,33 @@ void media_device_request_get(struct media_device_request *req)
}
EXPORT_SYMBOL_GPL(media_device_request_get);
+static void media_device_request_queue_event(struct media_device *mdev,
+ struct media_device_request *req)
+{
+ struct media_kevent *kev = req->kev;
+ struct media_event *ev = &kev->ev;
+ struct media_device_fh *fh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdev->req_lock, flags);
+ if (!req->filp) {
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+ return;
+ }
+ fh = media_device_fh(req->filp);
+
+ ev->sequence = atomic_inc_return(&fh->kevents.sequence);
+ ev->type = MEDIA_EVENT_TYPE_REQUEST_COMPLETE;
+ ev->req_complete.id = req->id;
+ ev->req_complete.status = 0;
+
+ list_add(&kev->list, &fh->kevents.head);
+ req->kev = NULL;
+ req->state = MEDIA_DEVICE_REQUEST_STATE_COMPLETE;
+ wake_up(&fh->kevents.wait);
+ spin_unlock_irqrestore(&mdev->req_lock, flags);
+}
+
static void media_device_request_release(struct kref *kref)
{
struct media_entity_request_data *data, *next;
@@ -106,6 +141,9 @@ static void media_device_request_release(struct kref *kref)
ida_simple_remove(&mdev->req_ids, req->id);
+ kfree(req->kev);
+ req->kev = NULL;
+
mdev->ops->req_free(mdev, req);
}
@@ -180,10 +218,12 @@ void media_device_request_set_entity_data(struct media_device_request *req,
EXPORT_SYMBOL_GPL(media_device_request_set_entity_data);
static int media_device_request_alloc(struct media_device *mdev,
- struct media_device_fh *fh,
+ struct file *filp,
struct media_request_cmd *cmd)
{
+ struct media_device_fh *fh = media_device_fh(filp);
struct media_device_request *req;
+ struct media_kevent *kev;
unsigned long flags;
int id = ida_simple_get(&mdev->req_ids, 1, 0, GFP_KERNEL);
int ret;
@@ -191,14 +231,22 @@ static int media_device_request_alloc(struct media_device *mdev,
if (id < 0)
return id;
+ kev = kzalloc(sizeof(*kev), GFP_KERNEL);
+ if (!kev) {
+ ret = -ENOMEM;
+ goto out_ida_simple_remove;
+ }
+
req = mdev->ops->req_alloc(mdev);
if (!req) {
ret = -ENOMEM;
- goto out_ida_simple_remove;
+ goto out_kev_free;
}
req->mdev = mdev;
req->id = id;
+ req->filp = filp;
+ req->kev = kev;
kref_init(&req->kref);
INIT_LIST_HEAD(&req->data);
@@ -211,6 +259,9 @@ static int media_device_request_alloc(struct media_device *mdev,
return 0;
+out_kev_free:
+ kfree(kev);
+
out_ida_simple_remove:
ida_simple_remove(&mdev->req_ids, id);
@@ -233,6 +284,8 @@ static void media_device_request_delete(struct media_device *mdev,
void media_device_request_complete(struct media_device *mdev,
struct media_device_request *req)
{
+ media_device_request_queue_event(mdev, req);
+
media_device_request_delete(mdev, req);
}
EXPORT_SYMBOL_GPL(media_device_request_complete);
@@ -272,7 +325,6 @@ 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;
unsigned long flags;
int ret;
@@ -288,7 +340,7 @@ static long media_device_request_cmd(struct media_device *mdev,
switch (cmd->cmd) {
case MEDIA_REQ_CMD_ALLOC:
- ret = media_device_request_alloc(mdev, fh, cmd);
+ ret = media_device_request_alloc(mdev, filp, cmd);
break;
case MEDIA_REQ_CMD_DELETE:
@@ -347,6 +399,10 @@ static int media_device_open(struct file *filp)
return -ENOMEM;
INIT_LIST_HEAD(&fh->requests);
+ INIT_LIST_HEAD(&fh->kevents.head);
+ spin_lock_init(&fh->kevents.lock);
+ init_waitqueue_head(&fh->kevents.wait);
+ atomic_set(&fh->kevents.sequence, -1);
filp->private_data = &fh->fh;
return 0;
@@ -356,6 +412,7 @@ 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_kevent *kev, *kev_safe;
spin_lock_irq(&mdev->req_lock);
while (!list_empty(&fh->requests)) {
@@ -364,13 +421,17 @@ static int media_device_close(struct file *filp)
req = list_first_entry(&fh->requests, typeof(*req), fh_list);
list_del(&req->list);
list_del(&req->fh_list);
-
+ req->filp = NULL;
spin_unlock_irq(&mdev->req_lock);
media_device_request_put(req);
spin_lock_irq(&mdev->req_lock);
}
spin_unlock_irq(&mdev->req_lock);
+ /* No other users around --- no lock needed. */
+ list_for_each_entry_safe(kev, kev_safe, &fh->kevents.head, list)
+ list_del(&kev->list);
+
kfree(fh);
return 0;
@@ -686,6 +747,47 @@ static long media_device_get_topology(struct media_device *mdev,
return ret;
}
+static struct media_kevent *opportunistic_dqevent(struct file *filp)
+{
+ struct media_device_fh *fh = media_device_fh(filp);
+ struct media_kevent *kev = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fh->kevents.lock, flags);
+ if (!list_empty(&fh->kevents.head)) {
+ kev = list_last_entry(&fh->kevents.head,
+ struct media_kevent, list);
+ list_del(&kev->list);
+ }
+ spin_unlock_irqrestore(&fh->kevents.lock, flags);
+
+ return kev;
+}
+
+static int media_device_dqevent(struct media_device *mdev,
+ struct file *filp,
+ struct media_event *ev)
+{
+ struct media_device_fh *fh = media_device_fh(filp);
+ struct media_kevent *kev;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ kev = opportunistic_dqevent(filp);
+ if (!kev)
+ return -ENODATA;
+ } else {
+ int ret = wait_event_interruptible(
+ fh->kevents.wait, (kev = opportunistic_dqevent(filp)));
+ if (ret == -ERESTARTSYS)
+ return ret;
+ }
+
+ *ev = kev->ev;
+ kfree(kev);
+
+ return 0;
+}
+
static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
{
/* All media IOCTLs are _IOWR() */
@@ -835,6 +937,7 @@ static const struct media_ioctl_info ioctl_info[] = {
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),
+ MEDIA_IOC(DQEVENT, media_device_dqevent, 0),
};
static long media_device_ioctl(struct file *filp, unsigned int cmd,
@@ -883,6 +986,7 @@ static const struct media_ioctl_info compat_ioctl_info[] = {
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),
+ MEDIA_IOC(DQEVENT, media_device_dqevent, 0),
};
static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 2082108..e62ad13 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -30,6 +30,8 @@
#include <media/media-devnode.h>
#include <media/media-entity.h>
+#include <uapi/linux/media.h>
+
/**
* DOC: Media Controller
*
@@ -263,7 +265,9 @@
struct ida;
struct device;
+struct file;
struct media_device;
+struct media_device_fh;
enum media_device_request_state {
MEDIA_DEVICE_REQUEST_STATE_IDLE,
@@ -272,6 +276,11 @@ enum media_device_request_state {
MEDIA_DEVICE_REQUEST_STATE_COMPLETE,
};
+struct media_kevent {
+ struct list_head list;
+ struct media_event ev;
+};
+
/**
* struct media_device_request - Media device request
* @id: Request ID
@@ -286,6 +295,8 @@ enum media_device_request_state {
struct media_device_request {
u32 id;
struct media_device *mdev;
+ struct file *filp;
+ struct media_kevent *kev;
struct kref kref;
struct list_head list;
struct list_head fh_list;
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index e8922ea..f6e1efe 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -399,11 +399,28 @@ struct __attribute__ ((packed)) media_request_cmd {
__u32 request;
};
+#define MEDIA_EVENT_TYPE_REQUEST_COMPLETE 1
+
+struct media_event_request_complete {
+ __u32 id;
+ __s32 status;
+};
+
+struct media_event {
+ __u32 type;
+ __u32 sequence;
+
+ union {
+ struct media_event_request_complete req_complete;
+ };
+} __attribute__ ((packed));
+
#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)
+#define MEDIA_IOC_DQEVENT _IOWR('|', 0x06, struct media_event)
#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 ` [RFC 01/22] media: Add " Sakari Ailus
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 ` Sakari Ailus [this message]
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-15-git-send-email-sakari.ailus@linux.intel.com \
--to=sakari.ailus@linux.intel.com \
--cc=hverkuil@xs4all.nl \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox