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(×tamp); 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, ×tamp); 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(×tamp); 1856e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil 1866e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil spin_lock_irqsave(&fh->vdev->fh_lock, flags); 1876e239399e5807132f86f64af6c659411c6a3d1a5Hans Verkuil __v4l2_event_queue_fh(fh, ev, ×tamp); 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