From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Guennadi Liakhovetski <guennadi.liakhovetski@intel.com>
Cc: linux-media@vger.kernel.org
Subject: Re: [PATCH v8 2/3] uvcvideo: send a control event when a Control Change interrupt arrives
Date: Wed, 25 Jul 2018 20:25:16 +0300 [thread overview]
Message-ID: <54761357.L2epZVyRJX@avalon> (raw)
In-Reply-To: <1525792064-30836-3-git-send-email-guennadi.liakhovetski@intel.com>
Hi Guennadi,
On Tuesday, 8 May 2018 18:07:43 EEST Guennadi Liakhovetski wrote:
> UVC defines a method of handling asynchronous controls, which sends a
> USB packet over the interrupt pipe. This patch implements support for
> such packets by sending a control event to the user. Since this can
> involve USB traffic and, therefore, scheduling, this has to be done
> in a work queue.
>
> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@intel.com>
> ---
>
> v8:
>
> * avoid losing events by delaying the status URB resubmission until
> after completion of the current event
> * extract control value calculation into __uvc_ctrl_get_value()
> * do not proactively return EBUSY if the previous control hasn't
> completed yet, let the camera handle such cases
> * multiple cosmetic changes
>
> drivers/media/usb/uvc/uvc_ctrl.c | 166 ++++++++++++++++++++++++++++------
> drivers/media/usb/uvc/uvc_status.c | 112 ++++++++++++++++++++++---
> drivers/media/usb/uvc/uvc_v4l2.c | 4 +-
> drivers/media/usb/uvc/uvcvideo.h | 15 +++-
> include/uapi/linux/uvcvideo.h | 2 +
> 5 files changed, 255 insertions(+), 44 deletions(-)
As mentioned in a previous e-mail, here's my review of small issues in the
form of diff on top of this patch. I'll reply inline with comments.
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index d57a176a03d5..04d779e3f039 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1225,38 +1225,41 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
ev->u.ctrl.default_value = v4l2_ctrl.default_value;
}
-static void uvc_ctrl_send_event(struct uvc_fh *handle,
- struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
- s32 value, u32 changes)
+/*
+ * Send control change events to all subscribers for the @ctrl control. By
+ * default the subscriber that generated the event, as identified by @handle,
+ * is not notified unless it has set the V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK flag.
+ * @handle can be NULL for asynchronous events related to auto-update controls,
+ * in which case all subscribers are notified.
+ */
+static void uvc_ctrl_send_event(struct uvc_video_chain *chain,
+ struct uvc_fh *handle, struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping, s32 value, u32 changes)
{
+ struct v4l2_fh *originator = handle ? &handle->vfh : NULL;
struct v4l2_subscribed_event *sev;
struct v4l2_event ev;
- bool autoupdate;
if (list_empty(&mapping->ev_subs))
return;
- if (!handle) {
- autoupdate = true;
- sev = list_first_entry(&mapping->ev_subs,
- struct v4l2_subscribed_event, node);
- handle = container_of(sev->fh, struct uvc_fh, vfh);
- } else {
- autoupdate = false;
- }
-
- uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes);
+ uvc_ctrl_fill_event(chain, &ev, ctrl, mapping, value, changes);
list_for_each_entry(sev, &mapping->ev_subs, node) {
- if (sev->fh != &handle->vfh ||
+ if (sev->fh != originator ||
(sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) ||
- (changes & V4L2_EVENT_CTRL_CH_FLAGS) || autoupdate)
+ (changes & V4L2_EVENT_CTRL_CH_FLAGS))
v4l2_event_queue_fh(sev->fh, &ev);
}
}
-static void __uvc_ctrl_send_slave_event(struct uvc_fh *handle,
- struct uvc_video_chain *chain, struct uvc_control *master, u32 slave_id)
+/*
+ * Send control change events for the slave of the @master control identified
+ * by the V4L2 ID @slave_id. The @handle identifies the event subscriber that
+ * generated the event and may be NULL for auto-update events.
+ */
+static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
+ struct uvc_fh *handle, struct uvc_control *master, u32 slave_id)
{
struct uvc_control_mapping *mapping = NULL;
struct uvc_control *ctrl = NULL;
@@ -1267,11 +1270,10 @@ static void __uvc_ctrl_send_slave_event(struct uvc_fh *handle,
if (ctrl == NULL)
return;
- if (__uvc_ctrl_get(handle ? handle->chain : chain, ctrl, mapping,
- &val) == 0)
+ if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0)
changes |= V4L2_EVENT_CTRL_CH_VALUE;
- uvc_ctrl_send_event(handle, ctrl, mapping, val, changes);
+ uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
}
static void uvc_ctrl_status_event_work(struct work_struct *work)
@@ -1279,38 +1281,37 @@ static void uvc_ctrl_status_event_work(struct work_struct *work)
struct uvc_device *dev = container_of(work, struct uvc_device,
async_ctrl.work);
struct uvc_ctrl_work *w = &dev->async_ctrl;
+ struct uvc_video_chain *chain = w->chain;
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl = w->ctrl;
unsigned int i;
int ret;
- mutex_lock(&w->chain->ctrl_mutex);
+ mutex_lock(&chain->ctrl_mutex);
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
s32 value = __uvc_ctrl_get_value(mapping, w->data);
/*
- * So far none of the auto-update controls in the uvc_ctrls[]
- * table is mapped to a V4L control with slaves in the
- * uvc_ctrl_mappings[] list, so slave controls so far never have
- * handle == NULL, but this can change in the future
+ * ctrl->handle may be NULL here if the device sends auto-update
+ * events without a prior related control set from userspace.
*/
for (i = 0; i < ARRAY_SIZE(mapping->slave_ids); ++i) {
if (!mapping->slave_ids[i])
break;
- __uvc_ctrl_send_slave_event(ctrl->handle, w->chain,
- ctrl, mapping->slave_ids[i]);
+ uvc_ctrl_send_slave_event(chain, ctrl->handle, ctrl,
+ mapping->slave_ids[i]);
}
- uvc_ctrl_send_event(ctrl->handle, ctrl, mapping, value,
+ uvc_ctrl_send_event(chain, ctrl->handle, ctrl, mapping, value,
V4L2_EVENT_CTRL_CH_VALUE);
}
- mutex_unlock(&w->chain->ctrl_mutex);
-
ctrl->handle = NULL;
+ mutex_unlock(&chain->ctrl_mutex);
+
/* Resubmit the URB. */
w->urb->interval = dev->int_ep->desc.bInterval;
ret = usb_submit_urb(w->urb, GFP_KERNEL);
@@ -1340,23 +1341,17 @@ bool uvc_ctrl_status_event(struct urb *urb, struct uvc_video_chain *chain,
return true;
}
-static void uvc_ctrl_send_slave_event(struct uvc_fh *handle,
- struct uvc_control *master, u32 slave_id,
- const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
+static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count, u32 id)
{
unsigned int i;
- /*
- * We can skip sending an event for the slave if the slave
- * is being modified in the same transaction.
- */
- for (i = 0; i < xctrls_count; i++) {
- if (xctrls[i].id == slave_id)
- return;
+ for (i = 0; i < xctrls_count; ++i) {
+ if (xctrls[i].id == id)
+ return true;
}
- /* handle != NULL */
- __uvc_ctrl_send_slave_event(handle, NULL, master, slave_id);
+ return false;
}
static void uvc_ctrl_send_events(struct uvc_fh *handle,
@@ -1376,28 +1371,34 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
continue;
for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) {
- if (!mapping->slave_ids[j])
+ u32 slave_id = mapping->slave_ids[j];
+
+ if (!slave_id)
break;
- uvc_ctrl_send_slave_event(handle, ctrl,
- mapping->slave_ids[j],
- xctrls, xctrls_count);
+
+ /*
+ * We can skip sending an event for the slave if the
+ * slave is being modified in the same transaction.
+ */
+ if (uvc_ctrl_xctrls_has_control(xctrls, xctrls_count,
+ slave_id))
+ continue;
+
+ uvc_ctrl_send_slave_event(handle->chain, handle, ctrl,
+ slave_id);
}
/*
* If the master is being modified in the same transaction
* flags may change too.
*/
- if (mapping->master_id) {
- for (j = 0; j < xctrls_count; j++) {
- if (xctrls[j].id == mapping->master_id) {
- changes |= V4L2_EVENT_CTRL_CH_FLAGS;
- break;
- }
- }
- }
+ if (mapping->master_id &&
+ uvc_ctrl_xctrls_has_control(xctrls, xctrls_count,
+ mapping->master_id))
+ changes |= V4L2_EVENT_CTRL_CH_FLAGS;
- uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value,
- changes);
+ uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping,
+ xctrls[i].value, changes);
}
}
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index a0f2feaee7c6..0722dc684378 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -150,8 +150,7 @@ static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
ctrl = uvc_event_entity_find_ctrl(entity,
status->bSelector);
- if (ctrl && (!ctrl->handle ||
- ctrl->handle->chain == *chain))
+ if (ctrl)
return ctrl;
}
}
@@ -222,17 +221,23 @@ static void uvc_status_complete(struct urb *urb)
len = urb->actual_length;
if (len > 0) {
switch (dev->status[0] & 0x0f) {
- case UVC_STATUS_TYPE_CONTROL:
- if (uvc_event_control(urb,
- (struct uvc_control_status *)dev->status, len))
- /* The URB will be resubmitted in work context */
+ case UVC_STATUS_TYPE_CONTROL: {
+ struct uvc_control_status *status =
+ (struct uvc_control_status *)dev->status;
+
+ if (uvc_event_control(urb, status, len))
+ /* The URB will be resubmitted in work context. */
return;
break;
+ }
- case UVC_STATUS_TYPE_STREAMING:
- uvc_event_streaming(dev,
- (struct uvc_streaming_status *)dev->status, len);
+ case UVC_STATUS_TYPE_STREAMING: {
+ struct uvc_streaming_status *status =
+ (struct uvc_streaming_status *)dev->status;
+
+ uvc_event_streaming(dev, status, len);
break;
+ }
default:
uvc_trace(UVC_TRACE_STATUS, "Unknown status event "
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index b36ad9eb8c80..e5f5d84f1d1d 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -261,7 +261,7 @@ struct uvc_control {
u8 *uvc_data;
- struct uvc_fh *handle; /* Used for asynchronous event delivery */
+ struct uvc_fh *handle; /* File handle that last changed the control. */
};
struct uvc_format_desc {
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2018-07-25 18:37 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-08 15:07 [PATCH v8 0/3] uvcvideo: asynchronous controls Guennadi Liakhovetski
2018-05-08 15:07 ` [PATCH v8 1/3] uvcvideo: remove a redundant check Guennadi Liakhovetski
2018-07-10 22:18 ` Laurent Pinchart
2018-05-08 15:07 ` [PATCH v8 2/3] uvcvideo: send a control event when a Control Change interrupt arrives Guennadi Liakhovetski
2018-07-11 23:25 ` Laurent Pinchart
2018-07-12 7:30 ` Guennadi Liakhovetski
2018-07-17 13:07 ` Guennadi Liakhovetski
2018-07-17 20:26 ` Laurent Pinchart
2018-07-17 21:30 ` Guennadi Liakhovetski
2018-07-17 23:44 ` Laurent Pinchart
2018-07-18 6:55 ` Guennadi Liakhovetski
2018-07-25 17:10 ` Laurent Pinchart
2018-07-25 17:21 ` Guennadi Liakhovetski
2018-07-25 19:13 ` Laurent Pinchart
2018-07-26 7:03 ` Guennadi Liakhovetski
2018-07-26 8:17 ` [PATCH v9] " Guennadi Liakhovetski
2018-07-26 12:24 ` Laurent Pinchart
2018-07-26 12:42 ` Guennadi Liakhovetski
2018-07-25 17:25 ` Laurent Pinchart [this message]
2018-07-25 19:06 ` [PATCH v8 2/3] " Laurent Pinchart
2018-05-08 15:07 ` [PATCH v8 3/3] uvcvideo: handle control pipe protocol STALLs Guennadi Liakhovetski
2018-07-17 20:58 ` Laurent Pinchart
2018-07-17 23:17 ` Laurent Pinchart
2018-05-31 21:03 ` [PATCH v8 0/3] uvcvideo: asynchronous controls Guennadi Liakhovetski
2018-06-22 14:27 ` Guennadi Liakhovetski
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=54761357.L2epZVyRJX@avalon \
--to=laurent.pinchart@ideasonboard.com \
--cc=guennadi.liakhovetski@intel.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.