From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
To: Hans Verkuil <hans.verkuil@cisco.com>
Cc: linux-media@vger.kernel.org
Subject: Re: [RFCv1 PATCH 4/9] v4l2-ctrls: add per-control events.
Date: Mon, 11 Apr 2011 10:29:42 +0300 [thread overview]
Message-ID: <4DA2ADE6.2080704@maxwell.research.nokia.com> (raw)
In-Reply-To: <54721c1be23beb8c885ef56cdf7f782205c9dfdb.1301916466.git.hans.verkuil@cisco.com>
Hi Hans,
Thanks for the patchset! This looks really nice!
Hans Verkuil wrote:
> Whenever a control changes value an event is sent to anyone that subscribed
> to it.
>
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
> drivers/media/video/v4l2-ctrls.c | 59 ++++++++++++++++++
> drivers/media/video/v4l2-event.c | 126 +++++++++++++++++++++++++++-----------
> drivers/media/video/v4l2-fh.c | 4 +-
> include/linux/videodev2.h | 17 +++++-
> include/media/v4l2-ctrls.h | 9 +++
> include/media/v4l2-event.h | 2 +
> 6 files changed, 177 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
> index f75a1d4..163f412 100644
> --- a/drivers/media/video/v4l2-ctrls.c
> +++ b/drivers/media/video/v4l2-ctrls.c
> @@ -23,6 +23,7 @@
> #include <media/v4l2-ioctl.h>
> #include <media/v4l2-device.h>
> #include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> #include <media/v4l2-dev.h>
>
> /* Internal temporary helper struct, one for each v4l2_ext_control */
> @@ -537,6 +538,16 @@ static bool type_is_int(const struct v4l2_ctrl *ctrl)
> }
> }
>
> +static void send_event(struct v4l2_ctrl *ctrl, struct v4l2_event *ev)
> +{
> + struct v4l2_ctrl_fh *pos;
> +
> + ev->id = ctrl->id;
> + list_for_each_entry(pos, &ctrl->fhs, node) {
> + v4l2_event_queue_fh(pos->fh, ev);
> + }
No need for braces here.
> +}
> +
> /* Helper function: copy the current control value back to the caller */
> static int cur_to_user(struct v4l2_ext_control *c,
> struct v4l2_ctrl *ctrl)
> @@ -626,20 +637,38 @@ static int new_to_user(struct v4l2_ext_control *c,
> /* Copy the new value to the current value. */
> static void new_to_cur(struct v4l2_ctrl *ctrl)
> {
> + struct v4l2_event ev;
> + bool changed = false;
> +
> if (ctrl == NULL)
> return;
> switch (ctrl->type) {
> + case V4L2_CTRL_TYPE_BUTTON:
> + changed = true;
> + ev.u.ctrl_ch_value.value = 0;
> + break;
> case V4L2_CTRL_TYPE_STRING:
> /* strings are always 0-terminated */
> + changed = strcmp(ctrl->string, ctrl->cur.string);
> strcpy(ctrl->cur.string, ctrl->string);
> + ev.u.ctrl_ch_value.value64 = 0;
> break;
> case V4L2_CTRL_TYPE_INTEGER64:
> + changed = ctrl->val64 != ctrl->cur.val64;
> ctrl->cur.val64 = ctrl->val64;
> + ev.u.ctrl_ch_value.value64 = ctrl->val64;
> break;
> default:
> + changed = ctrl->val != ctrl->cur.val;
> ctrl->cur.val = ctrl->val;
> + ev.u.ctrl_ch_value.value = ctrl->val;
> break;
> }
> + if (changed) {
> + ev.type = V4L2_EVENT_CTRL_CH_VALUE;
> + ev.u.ctrl_ch_value.type = ctrl->type;
> + send_event(ctrl, &ev);
> + }
> }
>
> /* Copy the current value to the new value */
> @@ -784,6 +813,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
> {
> struct v4l2_ctrl_ref *ref, *next_ref;
> struct v4l2_ctrl *ctrl, *next_ctrl;
> + struct v4l2_ctrl_fh *ctrl_fh, *next_ctrl_fh;
>
> if (hdl == NULL || hdl->buckets == NULL)
> return;
> @@ -797,6 +827,10 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
> /* Free all controls owned by the handler */
> list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
> list_del(&ctrl->node);
> + list_for_each_entry_safe(ctrl_fh, next_ctrl_fh, &ctrl->fhs, node) {
> + list_del(&ctrl_fh->node);
> + kfree(ctrl_fh);
> + }
> kfree(ctrl);
> }
> kfree(hdl->buckets);
> @@ -1003,6 +1037,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
> }
>
> INIT_LIST_HEAD(&ctrl->node);
> + INIT_LIST_HEAD(&ctrl->fhs);
> ctrl->handler = hdl;
> ctrl->ops = ops;
> ctrl->id = id;
> @@ -1888,3 +1923,27 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
> return set_ctrl(ctrl, &val);
> }
> EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
> +
> +void v4l2_ctrl_add_fh(struct v4l2_ctrl *ctrl, struct v4l2_ctrl_fh *ctrl_fh)
> +{
> + v4l2_ctrl_lock(ctrl);
> + list_add_tail(&ctrl_fh->node, &ctrl->fhs);
> + v4l2_ctrl_unlock(ctrl);
> +}
> +EXPORT_SYMBOL(v4l2_ctrl_add_fh);
> +
> +void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh)
> +{
> + struct v4l2_ctrl_fh *pos;
> +
> + v4l2_ctrl_lock(ctrl);
> + list_for_each_entry(pos, &ctrl->fhs, node) {
> + if (pos->fh == fh) {
> + list_del(&pos->node);
> + kfree(pos);
> + break;
> + }
> + }
> + v4l2_ctrl_unlock(ctrl);
> +}
> +EXPORT_SYMBOL(v4l2_ctrl_del_fh);
> diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
> index 69fd343..c9251a5 100644
> --- a/drivers/media/video/v4l2-event.c
> +++ b/drivers/media/video/v4l2-event.c
> @@ -25,10 +25,13 @@
> #include <media/v4l2-dev.h>
> #include <media/v4l2-fh.h>
> #include <media/v4l2-event.h>
> +#include <media/v4l2-ctrls.h>
>
> #include <linux/sched.h>
> #include <linux/slab.h>
>
> +static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
> +
> int v4l2_event_init(struct v4l2_fh *fh)
> {
> fh->events = kzalloc(sizeof(*fh->events), GFP_KERNEL);
> @@ -91,7 +94,7 @@ void v4l2_event_free(struct v4l2_fh *fh)
>
> list_kfree(&events->free, struct v4l2_kevent, list);
> list_kfree(&events->available, struct v4l2_kevent, list);
> - list_kfree(&events->subscribed, struct v4l2_subscribed_event, list);
> + v4l2_event_unsubscribe_all(fh);
>
> kfree(events);
> fh->events = NULL;
> @@ -154,9 +157,9 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
> }
> EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
>
> -/* Caller must hold fh->event->lock! */
> +/* Caller must hold fh->vdev->fh_lock! */
> static struct v4l2_subscribed_event *v4l2_event_subscribed(
> - struct v4l2_fh *fh, u32 type)
> + struct v4l2_fh *fh, u32 type, u32 id)
> {
> struct v4l2_events *events = fh->events;
> struct v4l2_subscribed_event *sev;
> @@ -164,13 +167,46 @@ static struct v4l2_subscribed_event *v4l2_event_subscribed(
> assert_spin_locked(&fh->vdev->fh_lock);
>
> list_for_each_entry(sev, &events->subscribed, list) {
> - if (sev->type == type)
> + if (sev->type == type && sev->id == id)
> return sev;
> }
>
> return NULL;
> }
>
> +static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev,
> + const struct timespec *ts)
> +{
> + struct v4l2_events *events = fh->events;
> + struct v4l2_subscribed_event *sev;
> + struct v4l2_kevent *kev;
> +
> + /* Are we subscribed? */
> + sev = v4l2_event_subscribed(fh, ev->type, ev->id);
> + if (sev == NULL)
> + return;
> +
> + /* Increase event sequence number on fh. */
> + events->sequence++;
> +
> + /* Do we have any free events? */
> + if (list_empty(&events->free))
> + return;
> +
> + /* Take one and fill it. */
> + kev = list_first_entry(&events->free, struct v4l2_kevent, list);
> + kev->event.type = ev->type;
> + kev->event.u = ev->u;
> + kev->event.id = ev->id;
> + kev->event.timestamp = *ts;
> + kev->event.sequence = events->sequence;
> + list_move_tail(&kev->list, &events->available);
> +
> + events->navailable++;
> +
> + wake_up_all(&events->wait);
> +}
> +
> void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
> {
> struct v4l2_fh *fh;
> @@ -182,37 +218,26 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
> spin_lock_irqsave(&vdev->fh_lock, flags);
>
> list_for_each_entry(fh, &vdev->fh_list, list) {
> - struct v4l2_events *events = fh->events;
> - struct v4l2_kevent *kev;
> -
> - /* Are we subscribed? */
> - if (!v4l2_event_subscribed(fh, ev->type))
> - continue;
> -
> - /* Increase event sequence number on fh. */
> - events->sequence++;
> -
> - /* Do we have any free events? */
> - if (list_empty(&events->free))
> - continue;
> -
> - /* Take one and fill it. */
> - kev = list_first_entry(&events->free, struct v4l2_kevent, list);
> - kev->event.type = ev->type;
> - kev->event.u = ev->u;
> - kev->event.timestamp = timestamp;
> - kev->event.sequence = events->sequence;
> - list_move_tail(&kev->list, &events->available);
> -
> - events->navailable++;
> -
> - wake_up_all(&events->wait);
> + __v4l2_event_queue_fh(fh, ev, ×tamp);
> }
>
> spin_unlock_irqrestore(&vdev->fh_lock, flags);
> }
> EXPORT_SYMBOL_GPL(v4l2_event_queue);
>
> +void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev)
> +{
> + unsigned long flags;
> + struct timespec timestamp;
> +
> + ktime_get_ts(×tamp);
> +
> + spin_lock_irqsave(&fh->vdev->fh_lock, flags);
> + __v4l2_event_queue_fh(fh, ev, ×tamp);
> + spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_event_queue_fh);
> +
> int v4l2_event_pending(struct v4l2_fh *fh)
> {
> return fh->events->navailable;
> @@ -223,7 +248,9 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
> struct v4l2_event_subscription *sub)
> {
> struct v4l2_events *events = fh->events;
> - struct v4l2_subscribed_event *sev;
> + struct v4l2_subscribed_event *sev, *found_ev;
> + struct v4l2_ctrl *ctrl = NULL;
> + struct v4l2_ctrl_fh *ctrl_fh = NULL;
> unsigned long flags;
>
> if (fh->events == NULL) {
> @@ -231,15 +258,31 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
> return -ENOMEM;
> }
>
> + if (sub->type == V4L2_EVENT_CTRL_CH_VALUE) {
> + ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
> + if (ctrl == NULL)
> + return -EINVAL;
> + }
> +
> sev = kmalloc(sizeof(*sev), GFP_KERNEL);
> if (!sev)
> return -ENOMEM;
> + if (ctrl) {
> + ctrl_fh = kzalloc(sizeof(*ctrl_fh), GFP_KERNEL);
> + if (!ctrl_fh) {
> + kfree(sev);
> + return -ENOMEM;
> + }
> + ctrl_fh->fh = fh;
> + }
>
> spin_lock_irqsave(&fh->vdev->fh_lock, flags);
>
> - if (v4l2_event_subscribed(fh, sub->type) == NULL) {
> + found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
> + if (!found_ev) {
> INIT_LIST_HEAD(&sev->list);
> sev->type = sub->type;
> + sev->id = sub->id;
>
> list_add(&sev->list, &events->subscribed);
> sev = NULL;
> @@ -247,6 +290,10 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
>
> spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
>
> + /* v4l2_ctrl_add_fh uses a mutex, so do this outside the spin lock */
> + if (!found_ev && ctrl)
> + v4l2_ctrl_add_fh(ctrl, ctrl_fh);
> +
> kfree(sev);
>
> return 0;
> @@ -256,6 +303,7 @@ EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
> static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
> {
> struct v4l2_events *events = fh->events;
> + struct v4l2_event_subscription sub;
> struct v4l2_subscribed_event *sev;
> unsigned long flags;
>
> @@ -265,11 +313,13 @@ static void v4l2_event_unsubscribe_all(struct v4l2_fh *fh)
> spin_lock_irqsave(&fh->vdev->fh_lock, flags);
> if (!list_empty(&events->subscribed)) {
> sev = list_first_entry(&events->subscribed,
> - struct v4l2_subscribed_event, list);
> - list_del(&sev->list);
> + struct v4l2_subscribed_event, list);
> + sub.type = sev->type;
> + sub.id = sev->id;
> }
> spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
> - kfree(sev);
> + if (sev)
> + v4l2_event_unsubscribe(fh, &sub);
> } while (sev);
> }
>
> @@ -286,11 +336,17 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
>
> spin_lock_irqsave(&fh->vdev->fh_lock, flags);
>
> - sev = v4l2_event_subscribed(fh, sub->type);
> + sev = v4l2_event_subscribed(fh, sub->type, sub->id);
> if (sev != NULL)
> list_del(&sev->list);
>
> spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
> + if (sev->type == V4L2_EVENT_CTRL_CH_VALUE) {
> + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
> +
> + if (ctrl)
> + v4l2_ctrl_del_fh(ctrl, fh);
> + }
>
> kfree(sev);
>
> diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
> index 8635011..c6aef84 100644
> --- a/drivers/media/video/v4l2-fh.c
> +++ b/drivers/media/video/v4l2-fh.c
> @@ -93,10 +93,8 @@ void v4l2_fh_exit(struct v4l2_fh *fh)
> {
> if (fh->vdev == NULL)
> return;
> -
> - fh->vdev = NULL;
> -
> v4l2_event_free(fh);
> + fh->vdev = NULL;
This looks like a bugfix.
> }
> EXPORT_SYMBOL_GPL(v4l2_fh_exit);
>
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index 92d2fdd..f7238c1 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -1787,6 +1787,7 @@ struct v4l2_streamparm {
> #define V4L2_EVENT_ALL 0
> #define V4L2_EVENT_VSYNC 1
> #define V4L2_EVENT_EOS 2
> +#define V4L2_EVENT_CTRL_CH_VALUE 3
> #define V4L2_EVENT_PRIVATE_START 0x08000000
>
> /* Payload for V4L2_EVENT_VSYNC */
> @@ -1795,21 +1796,33 @@ struct v4l2_event_vsync {
> __u8 field;
> } __attribute__ ((packed));
>
> +/* Payload for V4L2_EVENT_CTRL_CH_VALUE */
> +struct v4l2_event_ctrl_ch_value {
> + __u32 type;
type is enum v4l2_ctrl_type in struct v4l2_ctrl and struct v4l2_queryctrl.
> + union {
> + __s32 value;
> + __s64 value64;
> + };
> +} __attribute__ ((packed));
> +
> struct v4l2_event {
> __u32 type;
> union {
> struct v4l2_event_vsync vsync;
> + struct v4l2_event_ctrl_ch_value ctrl_ch_value;
> __u8 data[64];
> } u;
> __u32 pending;
> __u32 sequence;
> struct timespec timestamp;
> - __u32 reserved[9];
> + __u32 id;
id is valid only for control related events. Shouldn't it be part of the
control related structures instead, or another union for control related
event types? E.g.
struct {
enum v4l2_ctrl_type id;
union {
struct v4l2_event_ctrl_ch_value ch_value;
};
} ctrl;
> + __u32 reserved[8];
> };
>
> struct v4l2_event_subscription {
> __u32 type;
> - __u32 reserved[7];
> + __u32 id;
> + __u32 reserved[6];
> };
Similar situation here, but no existing union where id would fit in.
> /*
> diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
> index 97d0638..7ca45a5 100644
> --- a/include/media/v4l2-ctrls.h
> +++ b/include/media/v4l2-ctrls.h
> @@ -30,6 +30,7 @@ struct v4l2_ctrl_handler;
> struct v4l2_ctrl;
> struct video_device;
> struct v4l2_subdev;
> +struct v4l2_fh;
>
> /** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
> * @g_volatile_ctrl: Get a new value for this control. Generally only relevant
> @@ -97,6 +98,7 @@ struct v4l2_ctrl_ops {
> struct v4l2_ctrl {
> /* Administrative fields */
> struct list_head node;
> + struct list_head fhs;
> struct v4l2_ctrl_handler *handler;
> struct v4l2_ctrl **cluster;
> unsigned ncontrols;
> @@ -168,6 +170,11 @@ struct v4l2_ctrl_handler {
> int error;
> };
>
> +struct v4l2_ctrl_fh {
> + struct list_head node;
> + struct v4l2_fh *fh;
> +};
> +
> /** struct v4l2_ctrl_config - Control configuration structure.
> * @ops: The control ops.
> * @id: The control ID.
> @@ -440,6 +447,8 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
> */
> int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
>
> +void v4l2_ctrl_add_fh(struct v4l2_ctrl *ctrl, struct v4l2_ctrl_fh *ctrl_fh);
> +void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh);
>
> /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */
> int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
> diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
> index 3b86177..45e9c1e 100644
> --- a/include/media/v4l2-event.h
> +++ b/include/media/v4l2-event.h
> @@ -40,6 +40,7 @@ struct v4l2_kevent {
> struct v4l2_subscribed_event {
> struct list_head list;
> u32 type;
> + u32 id;
> };
And here.
> struct v4l2_events {
> @@ -58,6 +59,7 @@ void v4l2_event_free(struct v4l2_fh *fh);
> int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
> int nonblocking);
> void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
> +void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
> int v4l2_event_pending(struct v4l2_fh *fh);
> int v4l2_event_subscribe(struct v4l2_fh *fh,
> struct v4l2_event_subscription *sub);
Regards,
--
Sakari Ailus
sakari.ailus@maxwell.research.nokia.com
next prev parent reply other threads:[~2011-04-11 7:29 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-04-04 11:51 [RFCv1 PATCH 0/9] Control Events Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 1/9] v4l2-ctrls: add new bitmask control type Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 2/9] vivi: add bitmask test control Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 3/9] v4l2-ioctl: add ctrl_handler to v4l2_fh Hans Verkuil
2011-04-08 15:10 ` Laurent Pinchart
2011-04-08 15:39 ` Hans Verkuil
2011-04-11 14:54 ` Laurent Pinchart
2011-04-04 11:51 ` [RFCv1 PATCH 4/9] v4l2-ctrls: add per-control events Hans Verkuil
2011-04-11 7:29 ` Sakari Ailus [this message]
2011-04-11 14:57 ` Hans Verkuil
2011-04-12 8:12 ` Sakari Ailus
2011-04-12 13:40 ` Hans Verkuil
2011-04-15 10:51 ` Sakari Ailus
2011-04-15 16:25 ` Hans Verkuil
2011-04-16 8:51 ` Sakari Ailus
2011-04-19 12:19 ` Laurent Pinchart
2011-04-21 11:41 ` Sakari Ailus
2011-04-21 12:16 ` Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 5/9] vb2_poll: don't start DMA, leave that to the first read() Hans Verkuil
2011-04-08 7:00 ` Marek Szyprowski
2011-04-08 8:07 ` Hans Verkuil
2011-04-08 8:13 ` Marek Szyprowski
2011-04-04 11:51 ` [RFCv1 PATCH 6/9] vivi: add support for control events Hans Verkuil
2011-04-08 15:19 ` Laurent Pinchart
2011-04-08 15:43 ` Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 7/9] v4l2-ctrls: add new V4L2_EVENT_CTRL_CH_STATE event Hans Verkuil
2011-04-04 11:51 ` [RFCv1 PATCH 8/9] vivi: add support for CTRL_CH_STATE events Hans Verkuil
2011-04-08 15:13 ` Laurent Pinchart
2011-04-04 11:51 ` [RFCv1 PATCH 9/9] v4l2-ctrls: add new SEND_INITIAL flag to force an initial event Hans Verkuil
2011-04-08 15:08 ` [RFCv1 PATCH 1/9] v4l2-ctrls: add new bitmask control type Laurent Pinchart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4DA2ADE6.2080704@maxwell.research.nokia.com \
--to=sakari.ailus@maxwell.research.nokia.com \
--cc=hans.verkuil@cisco.com \
--cc=linux-media@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.