OSDN Git Service

media: v4l2-dev/event: add v4l2_event_wake_all()
authorHans Verkuil <hverkuil-cisco@xs4all.nl>
Tue, 1 Dec 2020 12:44:43 +0000 (13:44 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 4 Jan 2021 12:14:25 +0000 (13:14 +0100)
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: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-event.c
include/media/v4l2-event.h

index a593ea0..0ddc355 100644 (file)
@@ -28,6 +28,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
 
 #define VIDEO_NUM_DEVICES      256
 #define VIDEO_NAME              "video4linux"
@@ -1086,6 +1087,8 @@ void video_unregister_device(struct video_device *vdev)
         */
        clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
        mutex_unlock(&videodev_lock);
+       if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
+               v4l2_event_wake_all(vdev);
        device_unregister(&vdev->dev);
 }
 EXPORT_SYMBOL(video_unregister_device);
index 290c6b2..caad58b 100644 (file)
@@ -187,6 +187,23 @@ int v4l2_event_pending(struct v4l2_fh *fh)
 }
 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)
 {
        struct v4l2_fh *fh = sev->fh;
index 3f0281d..4ffa914 100644 (file)
@@ -101,7 +101,7 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
  *
  * .. note::
  *    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);
 
@@ -116,11 +116,20 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
  *
  * .. note::
  *    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);
 
 /**
+ * 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
  *
  * @fh: pointer to &struct v4l2_fh