1c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus/*
2c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * v4l2-event.c
3c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
4c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * V4L2 events.
5c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
6c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * Copyright (C) 2009--2010 Nokia Corporation.
7c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
8c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
9c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
10c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * This program is free software; you can redistribute it and/or
11c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * modify it under the terms of the GNU General Public License
12c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * version 2 as published by the Free Software Foundation.
13c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
14c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * This program is distributed in the hope that it will be useful, but
15c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * WITHOUT ANY WARRANTY; without even the implied warranty of
16c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * General Public License for more details.
18c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus *
19c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * You should have received a copy of the GNU General Public License
20c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * along with this program; if not, write to the Free Software
21c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus * 02110-1301 USA
23c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus */
24c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
25c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus#include <media/v4l2-dev.h>
26c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus#include <media/v4l2-fh.h>
27c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus#include <media/v4l2-event.h>
286e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil#include <media/v4l2-ctrls.h>
29c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
30c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus#include <linux/sched.h>
31c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus#include <linux/slab.h>
3235a246363ec41e7b19f7887a97ef3d01ab41356aPaul Gortmaker#include <linux/export.h>
33c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
34f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuilstatic unsigned sev_pos(const struct v4l2_subscribed_event *sev, unsigned idx)
35c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
36f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	idx += sev->first;
37f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	return idx >= sev->elems ? idx - sev->elems : idx;
38c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
39c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
40c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusstatic int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event)
41c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
42c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct v4l2_kevent *kev;
43c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	unsigned long flags;
44c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
45c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
46c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
47523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	if (list_empty(&fh->available)) {
48c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
49c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		return -ENOENT;
50c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	}
51c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
52523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	WARN_ON(fh->navailable == 0);
53c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
54523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	kev = list_first_entry(&fh->available, struct v4l2_kevent, list);
55f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	list_del(&kev->list);
56523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	fh->navailable--;
57c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
58523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	kev->event.pending = fh->navailable;
59c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	*event = kev->event;
60f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	kev->sev->first = sev_pos(kev->sev, 1);
61f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	kev->sev->in_use--;
62c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
63c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
64c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
65c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	return 0;
66c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
67c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
68c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusint v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
69c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		       int nonblocking)
70c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
71c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	int ret;
72c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
73c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	if (nonblocking)
74c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		return __v4l2_event_dequeue(fh, event);
75c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
76ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil	/* Release the vdev lock while waiting */
77ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil	if (fh->vdev->lock)
78ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil		mutex_unlock(fh->vdev->lock);
79ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil
80c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	do {
81523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil		ret = wait_event_interruptible(fh->wait,
82523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil					       fh->navailable != 0);
83c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		if (ret < 0)
84ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil			break;
85c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
86c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		ret = __v4l2_event_dequeue(fh, event);
87c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	} while (ret == -ENOENT);
88c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
89ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil	if (fh->vdev->lock)
90ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil		mutex_lock(fh->vdev->lock);
91ee6869afc922a9849979e49bb3bbcad794872fcbHans Verkuil
92c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	return ret;
93c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
940a4f8d0798c834472b9d8d50df32b62c733009fdLaurent PinchartEXPORT_SYMBOL_GPL(v4l2_event_dequeue);
95c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
966e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil/* Caller must hold fh->vdev->fh_lock! */
97c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusstatic struct v4l2_subscribed_event *v4l2_event_subscribed(
986e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		struct v4l2_fh *fh, u32 type, u32 id)
99c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
100c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct v4l2_subscribed_event *sev;
101c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
102f3cd385a9c95e1ea90e886448ab1e83ee2fc7e51Sakari Ailus	assert_spin_locked(&fh->vdev->fh_lock);
103c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
1043f66f0ed319505555f45ceac04775b23f9279ee6Hans Verkuil	list_for_each_entry(sev, &fh->subscribed, list)
1056e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		if (sev->type == type && sev->id == id)
106c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus			return sev;
107c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
108c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	return NULL;
109c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
110c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
1116e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuilstatic void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev,
1126e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		const struct timespec *ts)
1136e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil{
1146e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct v4l2_subscribed_event *sev;
1156e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct v4l2_kevent *kev;
1162151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	bool copy_payload = true;
1176e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1186e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	/* Are we subscribed? */
1196e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	sev = v4l2_event_subscribed(fh, ev->type, ev->id);
1206e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	if (sev == NULL)
1216e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		return;
1226e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1236e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	/* Increase event sequence number on fh. */
124523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	fh->sequence++;
1256e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1266e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	/* Do we have any free events? */
127f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	if (sev->in_use == sev->elems) {
128f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		/* no, remove the oldest one */
129f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		kev = sev->events + sev_pos(sev, 0);
130f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		list_del(&kev->list);
131f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		sev->in_use--;
132f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		sev->first = sev_pos(sev, 1);
133f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		fh->navailable--;
1342151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		if (sev->elems == 1) {
1352151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil			if (sev->replace) {
1362151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil				sev->replace(&kev->event, ev);
1372151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil				copy_payload = false;
1382151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil			}
1392151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		} else if (sev->merge) {
1402151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil			struct v4l2_kevent *second_oldest =
1412151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil				sev->events + sev_pos(sev, 0);
1422151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil			sev->merge(&kev->event, &second_oldest->event);
1432151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		}
144f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	}
1456e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1466e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	/* Take one and fill it. */
147f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	kev = sev->events + sev_pos(sev, sev->in_use);
1486e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	kev->event.type = ev->type;
1492151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	if (copy_payload)
1502151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		kev->event.u = ev->u;
1516e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	kev->event.id = ev->id;
1526e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	kev->event.timestamp = *ts;
153523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	kev->event.sequence = fh->sequence;
154f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->in_use++;
155f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	list_add_tail(&kev->list, &fh->available);
1566e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
157523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	fh->navailable++;
1586e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
159523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	wake_up_all(&fh->wait);
1606e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil}
1616e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
162c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusvoid v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
163c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
164c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct v4l2_fh *fh;
165c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	unsigned long flags;
166c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct timespec timestamp;
167c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
168c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	ktime_get_ts(&timestamp);
169c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
170c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_lock_irqsave(&vdev->fh_lock, flags);
171c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
1723f66f0ed319505555f45ceac04775b23f9279ee6Hans Verkuil	list_for_each_entry(fh, &vdev->fh_list, list)
1736e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		__v4l2_event_queue_fh(fh, ev, &timestamp);
174c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
175c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_unlock_irqrestore(&vdev->fh_lock, flags);
176c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
177c3b5b0241f620a356c97d8f43343e721c718806dSakari AilusEXPORT_SYMBOL_GPL(v4l2_event_queue);
178c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
1796e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuilvoid v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev)
1806e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil{
1816e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	unsigned long flags;
1826e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct timespec timestamp;
1836e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1846e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	ktime_get_ts(&timestamp);
1856e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
1866e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
1876e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	__v4l2_event_queue_fh(fh, ev, &timestamp);
1886e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
1896e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil}
1906e239399e5807132f86f64af6c659411c6a3d1a5Hans VerkuilEXPORT_SYMBOL_GPL(v4l2_event_queue_fh);
1916e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
192c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusint v4l2_event_pending(struct v4l2_fh *fh)
193c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
194523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil	return fh->navailable;
195c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
196c3b5b0241f620a356c97d8f43343e721c718806dSakari AilusEXPORT_SYMBOL_GPL(v4l2_event_pending);
197c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
1982151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuilstatic void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new)
1992151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil{
2002151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	u32 old_changes = old->u.ctrl.changes;
2012151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil
2022151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	old->u.ctrl = new->u.ctrl;
2032151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	old->u.ctrl.changes |= old_changes;
2042151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil}
2052151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil
2062151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuilstatic void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
2072151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil{
2082151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	new->u.ctrl.changes |= old->u.ctrl.changes;
2092151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil}
2102151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil
211c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusint v4l2_event_subscribe(struct v4l2_fh *fh,
212f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil			 struct v4l2_event_subscription *sub, unsigned elems)
213c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
2146e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct v4l2_subscribed_event *sev, *found_ev;
2156e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct v4l2_ctrl *ctrl = NULL;
216c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	unsigned long flags;
217f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	unsigned i;
218c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
219b36b505965e374b284166c2e6b9c1d369d663ea9Hans de Goede	if (sub->type == V4L2_EVENT_ALL)
220b36b505965e374b284166c2e6b9c1d369d663ea9Hans de Goede		return -EINVAL;
221b36b505965e374b284166c2e6b9c1d369d663ea9Hans de Goede
222f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	if (elems < 1)
223f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		elems = 1;
2246e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	if (sub->type == V4L2_EVENT_CTRL) {
2256e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
2266e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		if (ctrl == NULL)
2276e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil			return -EINVAL;
2286e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	}
2296e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
230f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
231c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	if (!sev)
232c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		return -ENOMEM;
233f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	for (i = 0; i < elems; i++)
234f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil		sev->events[i].sev = sev;
235f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->type = sub->type;
236f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->id = sub->id;
237f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->flags = sub->flags;
238f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->fh = fh;
239f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	sev->elems = elems;
2402151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	if (ctrl) {
2412151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		sev->replace = ctrls_replace;
2422151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil		sev->merge = ctrls_merge;
2432151bdc887acfd6dc2c931b4d3c01f95e30b7df8Hans Verkuil	}
244c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
245c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
2466e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
247f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	if (!found_ev)
248523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil		list_add(&sev->list, &fh->subscribed);
249c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
250c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
251f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuil	/* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
25277068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil	if (found_ev)
25377068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil		kfree(sev);
25477068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil	else if (ctrl)
25577068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil		v4l2_ctrl_add_event(ctrl, sev);
256c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
257c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	return 0;
258c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
259c3b5b0241f620a356c97d8f43343e721c718806dSakari AilusEXPORT_SYMBOL_GPL(v4l2_event_subscribe);
260c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
261f1e393de382af9b9bd2462a42bfa16b8c501d81bHans Verkuilvoid v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
262c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
2636e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	struct v4l2_event_subscription sub;
264c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct v4l2_subscribed_event *sev;
265c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	unsigned long flags;
266c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
267c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	do {
268c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		sev = NULL;
269c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
270c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		spin_lock_irqsave(&fh->vdev->fh_lock, flags);
271523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil		if (!list_empty(&fh->subscribed)) {
272523f46d6aba9dcb0a2d0fc474ca884e93a7cf198Hans Verkuil			sev = list_first_entry(&fh->subscribed,
2736e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil					struct v4l2_subscribed_event, list);
2746e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil			sub.type = sev->type;
2756e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil			sub.id = sev->id;
276c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		}
277c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
2786e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		if (sev)
2796e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil			v4l2_event_unsubscribe(fh, &sub);
280c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	} while (sev);
281c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
282f1e393de382af9b9bd2462a42bfa16b8c501d81bHans VerkuilEXPORT_SYMBOL_GPL(v4l2_event_unsubscribe_all);
283c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
284c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailusint v4l2_event_unsubscribe(struct v4l2_fh *fh,
285c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus			   struct v4l2_event_subscription *sub)
286c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus{
287c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	struct v4l2_subscribed_event *sev;
288c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	unsigned long flags;
28978c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede	int i;
290c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
291c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	if (sub->type == V4L2_EVENT_ALL) {
292c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		v4l2_event_unsubscribe_all(fh);
293c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		return 0;
294c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	}
295c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
296c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_lock_irqsave(&fh->vdev->fh_lock, flags);
297c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
2986e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	sev = v4l2_event_subscribed(fh, sub->type, sub->id);
29977068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil	if (sev != NULL) {
30078c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede		/* Remove any pending events for this subscription */
30178c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede		for (i = 0; i < sev->in_use; i++) {
30278c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede			list_del(&sev->events[sev_pos(sev, i)].list);
30378c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede			fh->navailable--;
30478c87e863bb3350426fecd14912fd0a546c58ec0Hans de Goede		}
305c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus		list_del(&sev->list);
30677068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil	}
307c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
308c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
30977068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil	if (sev && sev->type == V4L2_EVENT_CTRL) {
3106e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
3116e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil
3126e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil		if (ctrl)
31377068d36d8b9e9902a89b4bb01011d41926f5420Hans Verkuil			v4l2_ctrl_del_event(ctrl, sev);
3146e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil	}
315c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
316c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	kfree(sev);
317c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus
318c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus	return 0;
319c3b5b0241f620a356c97d8f43343e721c718806dSakari Ailus}
320c3b5b0241f620a356c97d8f43343e721c718806dSakari AilusEXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
321