[glsdk/meta-ti-glsdk.git] / recipes-bsp / linux / linux-omap / media / 0007-v4l-subdev-Events-support.patch
1 From 127fac73175e73c509ba203717be618a611294cd Mon Sep 17 00:00:00 2001
2 From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
3 Date: Wed, 3 Mar 2010 17:49:38 +0200
4 Subject: [PATCH 07/43] v4l: subdev: Events support
6 Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very
7 little to support events.
9 Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
10 Signed-off-by: David Cohen <david.cohen@nokia.com>
11 Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
12 ---
13 Documentation/video4linux/v4l2-framework.txt | 18 ++++++
14 drivers/media/video/v4l2-subdev.c | 75 +++++++++++++++++++++++++-
15 include/media/v4l2-subdev.h | 10 ++++
16 3 files changed, 102 insertions(+), 1 deletions(-)
18 diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
19 index f683f63..4db1def 100644
20 --- a/Documentation/video4linux/v4l2-framework.txt
21 +++ b/Documentation/video4linux/v4l2-framework.txt
22 @@ -352,6 +352,24 @@ VIDIOC_TRY_EXT_CTRLS
23 controls can be also be accessed through one (or several) V4L2 device
24 nodes.
26 +VIDIOC_DQEVENT
27 +VIDIOC_SUBSCRIBE_EVENT
28 +VIDIOC_UNSUBSCRIBE_EVENT
29 +
30 + The events ioctls are identical to the ones defined in V4L2. They
31 + behave identically, with the only exception that they deal only with
32 + events generated by the sub-device. Depending on the driver, those
33 + events can also be reported by one (or several) V4L2 device nodes.
34 +
35 + Sub-device drivers that want to use events need to set the
36 + V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize
37 + v4l2_subdev::nevents to events queue depth before registering the
38 + sub-device. After registration events can be queued as usual on the
39 + v4l2_subdev::devnode device node.
40 +
41 + To properly support events, the poll() file operation is also
42 + implemented.
43 +
45 I2C sub-device drivers
46 ----------------------
47 diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
48 index fc57ce7..fbccefd 100644
49 --- a/drivers/media/video/v4l2-subdev.c
50 +++ b/drivers/media/video/v4l2-subdev.c
51 @@ -20,27 +20,69 @@
52 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
53 */
55 -#include <linux/types.h>
56 #include <linux/ioctl.h>
57 +#include <linux/slab.h>
58 +#include <linux/types.h>
59 #include <linux/videodev2.h>
61 #include <media/v4l2-ctrls.h>
62 #include <media/v4l2-device.h>
63 #include <media/v4l2-ioctl.h>
64 +#include <media/v4l2-fh.h>
65 +#include <media/v4l2-event.h>
67 static int subdev_open(struct file *file)
68 {
69 struct video_device *vdev = video_devdata(file);
70 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
71 + struct v4l2_fh *vfh;
72 + int ret;
74 if (!sd->initialized)
75 return -EAGAIN;
77 + if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
78 + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
79 + if (vfh == NULL)
80 + return -ENOMEM;
81 +
82 + ret = v4l2_fh_init(vfh, vdev);
83 + if (ret)
84 + goto err;
85 +
86 + ret = v4l2_event_init(vfh);
87 + if (ret)
88 + goto err;
89 +
90 + ret = v4l2_event_alloc(vfh, sd->nevents);
91 + if (ret)
92 + goto err;
93 +
94 + v4l2_fh_add(vfh);
95 + file->private_data = vfh;
96 + }
97 +
98 return 0;
99 +
100 +err:
101 + if (vfh != NULL) {
102 + v4l2_fh_exit(vfh);
103 + kfree(vfh);
104 + }
105 +
106 + return ret;
107 }
109 static int subdev_close(struct file *file)
110 {
111 + struct v4l2_fh *vfh = file->private_data;
112 +
113 + if (vfh != NULL) {
114 + v4l2_fh_del(vfh);
115 + v4l2_fh_exit(vfh);
116 + kfree(vfh);
117 + }
118 +
119 return 0;
120 }
122 @@ -48,6 +90,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
123 {
124 struct video_device *vdev = video_devdata(file);
125 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
126 + struct v4l2_fh *fh = file->private_data;
128 switch (cmd) {
129 case VIDIOC_QUERYCTRL:
130 @@ -71,6 +114,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
131 case VIDIOC_TRY_EXT_CTRLS:
132 return v4l2_subdev_try_ext_ctrls(sd, arg);
134 + case VIDIOC_DQEVENT:
135 + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
136 + return -ENOIOCTLCMD;
137 +
138 + return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
139 +
140 + case VIDIOC_SUBSCRIBE_EVENT:
141 + return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
142 +
143 + case VIDIOC_UNSUBSCRIBE_EVENT:
144 + return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
145 +
146 default:
147 return -ENOIOCTLCMD;
148 }
149 @@ -84,11 +139,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd,
150 return __video_usercopy(file, cmd, arg, subdev_do_ioctl);
151 }
153 +static unsigned int subdev_poll(struct file *file, poll_table *wait)
154 +{
155 + struct video_device *vdev = video_devdata(file);
156 + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
157 + struct v4l2_fh *fh = file->private_data;
158 +
159 + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
160 + return POLLERR;
161 +
162 + poll_wait(file, &fh->events->wait, wait);
163 +
164 + if (v4l2_event_pending(fh))
165 + return POLLPRI;
166 +
167 + return 0;
168 +}
169 +
170 const struct v4l2_file_operations v4l2_subdev_fops = {
171 .owner = THIS_MODULE,
172 .open = subdev_open,
173 .unlocked_ioctl = subdev_ioctl,
174 .release = subdev_close,
175 + .poll = subdev_poll,
176 };
178 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
179 diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
180 index 90022f5..68cbe48 100644
181 --- a/include/media/v4l2-subdev.h
182 +++ b/include/media/v4l2-subdev.h
183 @@ -37,6 +37,8 @@
185 struct v4l2_device;
186 struct v4l2_ctrl_handler;
187 +struct v4l2_event_subscription;
188 +struct v4l2_fh;
189 struct v4l2_subdev;
190 struct tuner_setup;
192 @@ -165,6 +167,10 @@ struct v4l2_subdev_core_ops {
193 int (*s_power)(struct v4l2_subdev *sd, int on);
194 int (*interrupt_service_routine)(struct v4l2_subdev *sd,
195 u32 status, bool *handled);
196 + int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
197 + struct v4l2_event_subscription *sub);
198 + int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,
199 + struct v4l2_event_subscription *sub);
200 };
202 /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio.
203 @@ -424,6 +430,8 @@ struct v4l2_subdev_ops {
204 #define V4L2_SUBDEV_FL_IS_SPI (1U << 1)
205 /* Set this flag if this subdev needs a device node. */
206 #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2)
207 +/* Set this flag if this subdev generates events. */
208 +#define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3)
210 /* Each instance of a subdev driver should create this struct, either
211 stand-alone or embedded in a larger struct.
212 @@ -446,6 +454,8 @@ struct v4l2_subdev {
213 /* subdev device node */
214 struct video_device devnode;
215 unsigned int initialized;
216 + /* number of events to be allocated on open */
217 + unsigned int nevents;
218 };
220 #define vdev_to_v4l2_subdev(vdev) \
221 --
222 1.6.6.1