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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/v4l2-subdev.c | 78 |
1 files changed, 77 insertions, 1 deletions
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) |