diff options
author | Sakari Ailus <sakari.ailus@iki.fi> | 2010-03-03 10:49:38 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:32:42 -0400 |
commit | 02adb1cc765b8c29dc83c6602bda19003cce62f1 (patch) | |
tree | 067fd5a73251f6dc33567926c409a0b1070710ab | |
parent | ea8aa4349e11c62242a8908fc172de27d7a151d7 (diff) |
[media] v4l: subdev: Events support
Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very
little to support events.
Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: David Cohen <dacohen@gmail.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | Documentation/video4linux/v4l2-framework.txt | 18 | ||||
-rw-r--r-- | drivers/media/video/v4l2-subdev.c | 78 | ||||
-rw-r--r-- | include/media/v4l2-subdev.h | 10 |
3 files changed, 105 insertions, 1 deletions
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index 1feecfc59c3d..eb8479565dc4 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt | |||
@@ -350,6 +350,24 @@ VIDIOC_TRY_EXT_CTRLS | |||
350 | controls can be also be accessed through one (or several) V4L2 device | 350 | controls can be also be accessed through one (or several) V4L2 device |
351 | nodes. | 351 | nodes. |
352 | 352 | ||
353 | VIDIOC_DQEVENT | ||
354 | VIDIOC_SUBSCRIBE_EVENT | ||
355 | VIDIOC_UNSUBSCRIBE_EVENT | ||
356 | |||
357 | The events ioctls are identical to the ones defined in V4L2. They | ||
358 | behave identically, with the only exception that they deal only with | ||
359 | events generated by the sub-device. Depending on the driver, those | ||
360 | events can also be reported by one (or several) V4L2 device nodes. | ||
361 | |||
362 | Sub-device drivers that want to use events need to set the | ||
363 | V4L2_SUBDEV_USES_EVENTS v4l2_subdev::flags and initialize | ||
364 | v4l2_subdev::nevents to events queue depth before registering the | ||
365 | sub-device. After registration events can be queued as usual on the | ||
366 | v4l2_subdev::devnode device node. | ||
367 | |||
368 | To properly support events, the poll() file operation is also | ||
369 | implemented. | ||
370 | |||
353 | 371 | ||
354 | I2C sub-device drivers | 372 | I2C sub-device drivers |
355 | ---------------------- | 373 | ---------------------- |
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index da10430051c0..0c67f5a278fb 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c | |||
@@ -20,21 +20,66 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/ioctl.h> | 23 | #include <linux/ioctl.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/types.h> | ||
25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
26 | 27 | ||
27 | #include <media/v4l2-ctrls.h> | 28 | #include <media/v4l2-ctrls.h> |
28 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
29 | #include <media/v4l2-ioctl.h> | 30 | #include <media/v4l2-ioctl.h> |
31 | #include <media/v4l2-fh.h> | ||
32 | #include <media/v4l2-event.h> | ||
30 | 33 | ||
31 | static int subdev_open(struct file *file) | 34 | static int subdev_open(struct file *file) |
32 | { | 35 | { |
36 | struct video_device *vdev = video_devdata(file); | ||
37 | struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); | ||
38 | struct v4l2_fh *vfh; | ||
39 | int ret; | ||
40 | |||
41 | if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { | ||
42 | vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); | ||
43 | if (vfh == NULL) | ||
44 | return -ENOMEM; | ||
45 | |||
46 | ret = v4l2_fh_init(vfh, vdev); | ||
47 | if (ret) | ||
48 | goto err; | ||
49 | |||
50 | ret = v4l2_event_init(vfh); | ||
51 | if (ret) | ||
52 | goto err; | ||
53 | |||
54 | ret = v4l2_event_alloc(vfh, sd->nevents); | ||
55 | if (ret) | ||
56 | goto err; | ||
57 | |||
58 | v4l2_fh_add(vfh); | ||
59 | file->private_data = vfh; | ||
60 | } | ||
61 | |||
33 | return 0; | 62 | return 0; |
63 | |||
64 | err: | ||
65 | if (vfh != NULL) { | ||
66 | v4l2_fh_exit(vfh); | ||
67 | kfree(vfh); | ||
68 | } | ||
69 | |||
70 | return ret; | ||
34 | } | 71 | } |
35 | 72 | ||
36 | static int subdev_close(struct file *file) | 73 | static int subdev_close(struct file *file) |
37 | { | 74 | { |
75 | struct v4l2_fh *vfh = file->private_data; | ||
76 | |||
77 | if (vfh != NULL) { | ||
78 | v4l2_fh_del(vfh); | ||
79 | v4l2_fh_exit(vfh); | ||
80 | kfree(vfh); | ||
81 | } | ||
82 | |||
38 | return 0; | 83 | return 0; |
39 | } | 84 | } |
40 | 85 | ||
@@ -42,6 +87,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
42 | { | 87 | { |
43 | struct video_device *vdev = video_devdata(file); | 88 | struct video_device *vdev = video_devdata(file); |
44 | struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); | 89 | struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); |
90 | struct v4l2_fh *fh = file->private_data; | ||
45 | 91 | ||
46 | switch (cmd) { | 92 | switch (cmd) { |
47 | case VIDIOC_QUERYCTRL: | 93 | case VIDIOC_QUERYCTRL: |
@@ -65,6 +111,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
65 | case VIDIOC_TRY_EXT_CTRLS: | 111 | case VIDIOC_TRY_EXT_CTRLS: |
66 | return v4l2_subdev_try_ext_ctrls(sd, arg); | 112 | return v4l2_subdev_try_ext_ctrls(sd, arg); |
67 | 113 | ||
114 | case VIDIOC_DQEVENT: | ||
115 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) | ||
116 | return -ENOIOCTLCMD; | ||
117 | |||
118 | return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); | ||
119 | |||
120 | case VIDIOC_SUBSCRIBE_EVENT: | ||
121 | return v4l2_subdev_call(sd, core, subscribe_event, fh, arg); | ||
122 | |||
123 | case VIDIOC_UNSUBSCRIBE_EVENT: | ||
124 | return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg); | ||
125 | |||
68 | default: | 126 | default: |
69 | return -ENOIOCTLCMD; | 127 | return -ENOIOCTLCMD; |
70 | } | 128 | } |
@@ -78,11 +136,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd, | |||
78 | return video_usercopy(file, cmd, arg, subdev_do_ioctl); | 136 | return video_usercopy(file, cmd, arg, subdev_do_ioctl); |
79 | } | 137 | } |
80 | 138 | ||
139 | static unsigned int subdev_poll(struct file *file, poll_table *wait) | ||
140 | { | ||
141 | struct video_device *vdev = video_devdata(file); | ||
142 | struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); | ||
143 | struct v4l2_fh *fh = file->private_data; | ||
144 | |||
145 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) | ||
146 | return POLLERR; | ||
147 | |||
148 | poll_wait(file, &fh->events->wait, wait); | ||
149 | |||
150 | if (v4l2_event_pending(fh)) | ||
151 | return POLLPRI; | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
81 | const struct v4l2_file_operations v4l2_subdev_fops = { | 156 | const struct v4l2_file_operations v4l2_subdev_fops = { |
82 | .owner = THIS_MODULE, | 157 | .owner = THIS_MODULE, |
83 | .open = subdev_open, | 158 | .open = subdev_open, |
84 | .unlocked_ioctl = subdev_ioctl, | 159 | .unlocked_ioctl = subdev_ioctl, |
85 | .release = subdev_close, | 160 | .release = subdev_close, |
161 | .poll = subdev_poll, | ||
86 | }; | 162 | }; |
87 | 163 | ||
88 | void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) | 164 | void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) |
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 3276065022ef..0f9937be53d2 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
@@ -37,6 +37,8 @@ | |||
37 | 37 | ||
38 | struct v4l2_device; | 38 | struct v4l2_device; |
39 | struct v4l2_ctrl_handler; | 39 | struct v4l2_ctrl_handler; |
40 | struct v4l2_event_subscription; | ||
41 | struct v4l2_fh; | ||
40 | struct v4l2_subdev; | 42 | struct v4l2_subdev; |
41 | struct tuner_setup; | 43 | struct tuner_setup; |
42 | 44 | ||
@@ -161,6 +163,10 @@ struct v4l2_subdev_core_ops { | |||
161 | int (*s_power)(struct v4l2_subdev *sd, int on); | 163 | int (*s_power)(struct v4l2_subdev *sd, int on); |
162 | int (*interrupt_service_routine)(struct v4l2_subdev *sd, | 164 | int (*interrupt_service_routine)(struct v4l2_subdev *sd, |
163 | u32 status, bool *handled); | 165 | u32 status, bool *handled); |
166 | int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, | ||
167 | struct v4l2_event_subscription *sub); | ||
168 | int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, | ||
169 | struct v4l2_event_subscription *sub); | ||
164 | }; | 170 | }; |
165 | 171 | ||
166 | /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio. | 172 | /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio. |
@@ -437,6 +443,8 @@ struct v4l2_subdev_internal_ops { | |||
437 | #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) | 443 | #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) |
438 | /* Set this flag if this subdev needs a device node. */ | 444 | /* Set this flag if this subdev needs a device node. */ |
439 | #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) | 445 | #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) |
446 | /* Set this flag if this subdev generates events. */ | ||
447 | #define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3) | ||
440 | 448 | ||
441 | /* Each instance of a subdev driver should create this struct, either | 449 | /* Each instance of a subdev driver should create this struct, either |
442 | stand-alone or embedded in a larger struct. | 450 | stand-alone or embedded in a larger struct. |
@@ -460,6 +468,8 @@ struct v4l2_subdev { | |||
460 | void *host_priv; | 468 | void *host_priv; |
461 | /* subdev device node */ | 469 | /* subdev device node */ |
462 | struct video_device devnode; | 470 | struct video_device devnode; |
471 | /* number of events to be allocated on open */ | ||
472 | unsigned int nevents; | ||
463 | }; | 473 | }; |
464 | 474 | ||
465 | #define vdev_to_v4l2_subdev(vdev) \ | 475 | #define vdev_to_v4l2_subdev(vdev) \ |