Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Sakari Ailus and committed by
Mauro Carvalho Chehab
02adb1cc ea8aa434

+105 -1
+18
Documentation/video4linux/v4l2-framework.txt
··· 350 350 controls can be also be accessed through one (or several) V4L2 device 351 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 372 I2C sub-device drivers 355 373 ----------------------
+77 -1
drivers/media/video/v4l2-subdev.c
··· 20 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 21 */ 22 22 23 - #include <linux/types.h> 24 23 #include <linux/ioctl.h> 24 + #include <linux/slab.h> 25 + #include <linux/types.h> 25 26 #include <linux/videodev2.h> 26 27 27 28 #include <media/v4l2-ctrls.h> 28 29 #include <media/v4l2-device.h> 29 30 #include <media/v4l2-ioctl.h> 31 + #include <media/v4l2-fh.h> 32 + #include <media/v4l2-event.h> 30 33 31 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 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 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 83 return 0; 39 84 } 40 85 ··· 87 42 { 88 43 struct video_device *vdev = video_devdata(file); 89 44 struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 45 + struct v4l2_fh *fh = file->private_data; 90 46 91 47 switch (cmd) { 92 48 case VIDIOC_QUERYCTRL: ··· 111 65 case VIDIOC_TRY_EXT_CTRLS: 112 66 return v4l2_subdev_try_ext_ctrls(sd, arg); 113 67 68 + case VIDIOC_DQEVENT: 69 + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 70 + return -ENOIOCTLCMD; 71 + 72 + return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); 73 + 74 + case VIDIOC_SUBSCRIBE_EVENT: 75 + return v4l2_subdev_call(sd, core, subscribe_event, fh, arg); 76 + 77 + case VIDIOC_UNSUBSCRIBE_EVENT: 78 + return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg); 79 + 114 80 default: 115 81 return -ENOIOCTLCMD; 116 82 } ··· 136 78 return video_usercopy(file, cmd, arg, subdev_do_ioctl); 137 79 } 138 80 81 + static unsigned int subdev_poll(struct file *file, poll_table *wait) 82 + { 83 + struct video_device *vdev = video_devdata(file); 84 + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); 85 + struct v4l2_fh *fh = file->private_data; 86 + 87 + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) 88 + return POLLERR; 89 + 90 + poll_wait(file, &fh->events->wait, wait); 91 + 92 + if (v4l2_event_pending(fh)) 93 + return POLLPRI; 94 + 95 + return 0; 96 + } 97 + 139 98 const struct v4l2_file_operations v4l2_subdev_fops = { 140 99 .owner = THIS_MODULE, 141 100 .open = subdev_open, 142 101 .unlocked_ioctl = subdev_ioctl, 143 102 .release = subdev_close, 103 + .poll = subdev_poll, 144 104 }; 145 105 146 106 void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
+10
include/media/v4l2-subdev.h
··· 37 37 38 38 struct v4l2_device; 39 39 struct v4l2_ctrl_handler; 40 + struct v4l2_event_subscription; 41 + struct v4l2_fh; 40 42 struct v4l2_subdev; 41 43 struct tuner_setup; 42 44 ··· 163 161 int (*s_power)(struct v4l2_subdev *sd, int on); 164 162 int (*interrupt_service_routine)(struct v4l2_subdev *sd, 165 163 u32 status, bool *handled); 164 + int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, 165 + struct v4l2_event_subscription *sub); 166 + int (*unsubscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh, 167 + struct v4l2_event_subscription *sub); 166 168 }; 167 169 168 170 /* s_mode: switch the tuner to a specific tuner mode. Replacement of s_radio. ··· 443 437 #define V4L2_SUBDEV_FL_IS_SPI (1U << 1) 444 438 /* Set this flag if this subdev needs a device node. */ 445 439 #define V4L2_SUBDEV_FL_HAS_DEVNODE (1U << 2) 440 + /* Set this flag if this subdev generates events. */ 441 + #define V4L2_SUBDEV_FL_HAS_EVENTS (1U << 3) 446 442 447 443 /* Each instance of a subdev driver should create this struct, either 448 444 stand-alone or embedded in a larger struct. ··· 468 460 void *host_priv; 469 461 /* subdev device node */ 470 462 struct video_device devnode; 463 + /* number of events to be allocated on open */ 464 + unsigned int nevents; 471 465 }; 472 466 473 467 #define vdev_to_v4l2_subdev(vdev) \