diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index aab2fb639ef118d85098d6d902286cf484ef363f..d78f184f40c5e67d5a9fc5a009daf156453c5d0d 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -34,7 +34,16 @@ int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) INIT_LIST_HEAD(&fh->list); set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags); - return v4l2_event_init(fh); + /* + * fh->events only needs to be initialized if the driver + * supports the VIDIOC_SUBSCRIBE_EVENT ioctl. + */ + if (vdev->ioctl_ops && vdev->ioctl_ops->vidioc_subscribe_event) + return v4l2_event_init(fh); + + fh->events = NULL; + + return 0; } EXPORT_SYMBOL_GPL(v4l2_fh_init); diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 2ceaa152a4507aff808c0b1090c79e7472c04a3f..0eeceae503293da68debf793fb40e10906f17acb 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -26,6 +26,8 @@ #endif #include #include +#include +#include #include #define dbgarg(cmd, fmt, arg...) \ @@ -1951,7 +1953,55 @@ static long __video_do_ioctl(struct file *file, } break; } + case VIDIOC_DQEVENT: + { + struct v4l2_event *ev = arg; + + if (!ops->vidioc_subscribe_event) + break; + + ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK); + if (ret < 0) { + dbgarg(cmd, "no pending events?"); + break; + } + dbgarg(cmd, + "pending=%d, type=0x%8.8x, sequence=%d, " + "timestamp=%lu.%9.9lu ", + ev->pending, ev->type, ev->sequence, + ev->timestamp.tv_sec, ev->timestamp.tv_nsec); + break; + } + case VIDIOC_SUBSCRIBE_EVENT: + { + struct v4l2_event_subscription *sub = arg; + if (!ops->vidioc_subscribe_event) + break; + + ret = ops->vidioc_subscribe_event(fh, sub); + if (ret < 0) { + dbgarg(cmd, "failed, ret=%ld", ret); + break; + } + dbgarg(cmd, "type=0x%8.8x", sub->type); + break; + } + case VIDIOC_UNSUBSCRIBE_EVENT: + { + struct v4l2_event_subscription *sub = arg; + + if (!ops->vidioc_unsubscribe_event) + break; + + ret = ops->vidioc_unsubscribe_event(fh, sub); + if (ret < 0) { + dbgarg(cmd, "failed, ret=%ld", ret); + break; + } + dbgarg(cmd, "type=0x%8.8x", sub->type); + break; + } default: { if (!ops->vidioc_default) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index e8ba0f2efbae559887d7f75cfb1d70a19861245c..06daa6e8e051d6a24b196476d7d47707b1e375e6 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -21,6 +21,8 @@ #include #endif +struct v4l2_fh; + struct v4l2_ioctl_ops { /* ioctl callbacks */ @@ -254,6 +256,11 @@ struct v4l2_ioctl_ops { int (*vidioc_g_dv_timings) (struct file *file, void *fh, struct v4l2_dv_timings *timings); + int (*vidioc_subscribe_event) (struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); + /* For other private ioctls */ long (*vidioc_default) (struct file *file, void *fh, int cmd, void *arg);