Commit 28955a61 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

media: v4l2-dev/event: add v4l2_event_wake_all()

When unregistering a V4L2 device node, make sure any filehandles
that are waiting for an event are woken up.

Add v4l2_event_wake_all() to v4l2-event.c and call it from
video_unregister_device().

Otherwise userspace might never know that a device node was removed.

[hverkuil: checkpatch: replaced 'if (vdev == NULL)' by 'if (!vdev)']
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 726daf6b
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#define VIDEO_NUM_DEVICES 256 #define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux" #define VIDEO_NAME "video4linux"
...@@ -1086,6 +1087,8 @@ void video_unregister_device(struct video_device *vdev) ...@@ -1086,6 +1087,8 @@ void video_unregister_device(struct video_device *vdev)
*/ */
clear_bit(V4L2_FL_REGISTERED, &vdev->flags); clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_unlock(&videodev_lock); mutex_unlock(&videodev_lock);
if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
v4l2_event_wake_all(vdev);
device_unregister(&vdev->dev); device_unregister(&vdev->dev);
} }
EXPORT_SYMBOL(video_unregister_device); EXPORT_SYMBOL(video_unregister_device);
......
...@@ -187,6 +187,23 @@ int v4l2_event_pending(struct v4l2_fh *fh) ...@@ -187,6 +187,23 @@ int v4l2_event_pending(struct v4l2_fh *fh)
} }
EXPORT_SYMBOL_GPL(v4l2_event_pending); EXPORT_SYMBOL_GPL(v4l2_event_pending);
void v4l2_event_wake_all(struct video_device *vdev)
{
struct v4l2_fh *fh;
unsigned long flags;
if (!vdev)
return;
spin_lock_irqsave(&vdev->fh_lock, flags);
list_for_each_entry(fh, &vdev->fh_list, list)
wake_up_all(&fh->wait);
spin_unlock_irqrestore(&vdev->fh_lock, flags);
}
EXPORT_SYMBOL_GPL(v4l2_event_wake_all);
static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev) static void __v4l2_event_unsubscribe(struct v4l2_subscribed_event *sev)
{ {
struct v4l2_fh *fh = sev->fh; struct v4l2_fh *fh = sev->fh;
......
...@@ -101,7 +101,7 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event, ...@@ -101,7 +101,7 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
* *
* .. note:: * .. note::
* The driver's only responsibility is to fill in the type and the data * The driver's only responsibility is to fill in the type and the data
* fields.The other fields will be filled in by V4L2. * fields. The other fields will be filled in by V4L2.
*/ */
void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev); void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
...@@ -116,10 +116,19 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev); ...@@ -116,10 +116,19 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
* *
* .. note:: * .. note::
* The driver's only responsibility is to fill in the type and the data * The driver's only responsibility is to fill in the type and the data
* fields.The other fields will be filled in by V4L2. * fields. The other fields will be filled in by V4L2.
*/ */
void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev); void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
/**
* v4l2_event_wake_all - Wake all filehandles.
*
* Used when unregistering a video device.
*
* @vdev: pointer to &struct video_device
*/
void v4l2_event_wake_all(struct video_device *vdev);
/** /**
* v4l2_event_pending - Check if an event is available * v4l2_event_pending - Check if an event is available
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment