From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Ricardo Ribalda <ribalda@chromium.org>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Lili Orosz <lily@floofy.city>,
Hans Verkuil <hverkuil+cisco@kernel.org>,
Sasha Levin <sashal@kernel.org>,
hansg@kernel.org, linux-media@vger.kernel.org
Subject: [PATCH AUTOSEL 6.19-6.18] media: uvcvideo: Create an ID namespace for streaming output terminals
Date: Fri, 13 Feb 2026 19:59:00 -0500 [thread overview]
Message-ID: <20260214010245.3671907-60-sashal@kernel.org> (raw)
In-Reply-To: <20260214010245.3671907-1-sashal@kernel.org>
From: Ricardo Ribalda <ribalda@chromium.org>
[ Upstream commit 3d9f32e02c2ed85338be627de672e2b81b88a836 ]
Some devices, such as the Grandstream GUV3100 and the LSK Meeting Eye
for Business & Home, exhibit entity ID collisions between units and
streaming output terminals.
The UVC specification requires unit and terminal IDs to be unique, and
uses the ID to reference entities:
- In control requests, to identify the target entity
- In the UVC units and terminals descriptors' bSourceID field, to
identify source entities
- In the UVC input header descriptor's bTerminalLink, to identify the
terminal associated with a streaming interface
Entity ID collisions break accessing controls and make the graph
description in the UVC descriptors ambiguous. However, collisions where
one of the entities is a streaming output terminal and the other entity
is not a streaming terminal are less severe. Streaming output terminals
have no controls, and, as they are the final entity in pipelines, they
are never referenced in descriptors as source entities. They are
referenced by ID only from innput header descriptors, which by
definition only reference streaming terminals.
For these reasons, we can work around the collision by giving streaming
output terminals their own ID namespace. Do so by setting bit
UVC_TERM_OUTPUT (15) in the uvc_entity.id field, which is normally never
set as the ID is a 8-bit value.
This ID change doesn't affect the entity name in the media controller
graph as the name isn't constructed from the ID, so there should not be
any impact on the uAPI.
Although this change handles some ID collisions automagically, keep
printing an error in uvc_alloc_new_entity() when a camera has invalid
descriptors. Hopefully this message will help vendors fix their invalid
descriptors.
This new method of handling ID collisions includes a revert of commit
758dbc756aad ("media: uvcvideo: Use heuristic to find stream entity")
that attempted to fix the problem urgently due to regression reports.
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Lili Orosz <lily@floofy.city>
Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patch.msgid.link/20251113210400.28618-1-laurent.pinchart@ideasonboard.com
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
### Risk Assessment
**Benefits**:
- Fixes webcam functionality for devices with entity ID collisions
(Grandstream GUV3100, LSK Meeting Eye, potentially others)
- Provides a cleaner, more robust solution than the heuristic approach
in 758dbc756aad
- The approach is well-motivated by the UVC spec (streaming output
terminals have no controls and are terminal nodes)
**Risks**:
- Medium complexity - it's not a trivial one-liner, but the logic is
well-contained
- If 758dbc756aad is already in stable, this commit effectively replaces
it, which is the intended behavior
- The namespace bit approach could theoretically break something if any
code path uses entity IDs for streaming output terminals in unexpected
ways, but the commit message and review argue convincingly this
doesn't happen
**Dependencies**:
- This commit depends on `0e2ee70291e6` ("Mark invalid entities with id
UVC_INVALID_ENTITY_ID") being present
- It also implicitly reverts `758dbc756aad` which was sent to stable
- Both of these are likely in recent stable trees given the `Cc: stable`
tag on 758dbc756aad
### Conclusion
This commit fixes a real device compatibility bug that breaks webcam
functionality for specific hardware. The previous fix (758dbc756aad) was
already sent to stable with `Cc: stable`, and this commit is its proper
replacement. It's developed and reviewed by the UVC subsystem
maintainers, tested by users, and contained entirely within the UVC
driver. The approach is sound - leveraging the fact that streaming
output terminals have properties that make a separate ID namespace safe.
Since the heuristic fix (758dbc756aad) is likely already in stable trees
and this is the proper/robust replacement for it, it should also go to
stable.
**YES**
drivers/media/usb/uvc/uvc_driver.c | 54 ++++++++++++++++++------------
drivers/media/usb/uvc/uvcvideo.h | 3 +-
2 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index ee4f54d683496..aa3e8d295e0f5 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -165,28 +165,17 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
return NULL;
}
-static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
+static struct uvc_streaming *uvc_stream_for_terminal(struct uvc_device *dev,
+ struct uvc_entity *term)
{
- struct uvc_streaming *stream, *last_stream;
- unsigned int count = 0;
+ u16 id = UVC_HARDWARE_ENTITY_ID(term->id);
+ struct uvc_streaming *stream;
list_for_each_entry(stream, &dev->streams, list) {
- count += 1;
- last_stream = stream;
if (stream->header.bTerminalLink == id)
return stream;
}
- /*
- * If the streaming entity is referenced by an invalid ID, notify the
- * user and use heuristics to guess the correct entity.
- */
- if (count == 1 && id == UVC_INVALID_ENTITY_ID) {
- dev_warn(&dev->intf->dev,
- "UVC non compliance: Invalid USB header. The streaming entity has an invalid ID, guessing the correct one.");
- return last_stream;
- }
-
return NULL;
}
@@ -823,10 +812,12 @@ static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type,
}
/* Per UVC 1.1+ spec 3.7.2, the ID is unique. */
- if (uvc_entity_by_id(dev, id)) {
- dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id);
+ if (uvc_entity_by_id(dev, UVC_HARDWARE_ENTITY_ID(id)))
+ dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n",
+ UVC_HARDWARE_ENTITY_ID(id));
+
+ if (uvc_entity_by_id(dev, id))
id = UVC_INVALID_ENTITY_ID;
- }
extra_size = roundup(extra_size, sizeof(*entity->pads));
if (num_pads)
@@ -982,6 +973,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
struct usb_host_interface *alts = dev->intf->cur_altsetting;
unsigned int i, n, p, len;
const char *type_name;
+ unsigned int id;
u16 type;
switch (buffer[2]) {
@@ -1120,8 +1112,28 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return 0;
}
+ id = buffer[3];
+
+ /*
+ * Some devices, such as the Grandstream GUV3100, exhibit entity
+ * ID collisions between units and streaming output terminals.
+ * Move streaming output terminals to their own ID namespace by
+ * setting bit UVC_TERM_OUTPUT (15), above the ID's 8-bit value.
+ * The bit is ignored in uvc_stream_for_terminal() when looking
+ * up the streaming interface for the terminal.
+ *
+ * This hack is safe to enable unconditionally, as the ID is not
+ * used for any other purpose (streaming output terminals have
+ * no controls and are never referenced as sources in UVC
+ * descriptors). Other types output terminals can have controls,
+ * so limit usage of this separate namespace to streaming output
+ * terminals.
+ */
+ if (type & UVC_TT_STREAMING)
+ id |= UVC_TERM_OUTPUT;
+
term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT,
- buffer[3], 1, 0);
+ id, 1, 0);
if (IS_ERR(term))
return PTR_ERR(term);
@@ -2118,8 +2130,8 @@ static int uvc_register_terms(struct uvc_device *dev,
if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
continue;
- stream = uvc_stream_by_id(dev, term->id);
- if (stream == NULL) {
+ stream = uvc_stream_for_terminal(dev, term);
+ if (!stream) {
dev_info(&dev->intf->dev,
"No streaming interface found for terminal %u.",
term->id);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index ed7bad31f75ca..3f2e832025e71 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -41,7 +41,8 @@
#define UVC_EXT_GPIO_UNIT 0x7ffe
#define UVC_EXT_GPIO_UNIT_ID 0x100
-#define UVC_INVALID_ENTITY_ID 0xffff
+#define UVC_HARDWARE_ENTITY_ID(id) ((id) & 0xff)
+#define UVC_INVALID_ENTITY_ID 0xffff
/* ------------------------------------------------------------------------
* Driver specific constants.
--
2.51.0
next prev parent reply other threads:[~2026-02-14 1:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-14 0:58 [PATCH AUTOSEL 6.19-6.12] media: ipu6: Close firmware streams on streaming enable failure Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Fix conditional in start_streaming Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Avoid a reset low spike during probe() Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.1] media: amphion: Clear last_buffer_dequeued flag for DEC_CMD_START Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-5.10] media: adv7180: fix frame interval in progressive mode Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.6] media: v4l2-async: Fix error handling on steps after finding a match Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.1] media: rkisp1: Fix filter mode register configuration Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Ensure stream_mutex is acquired when dealing with node list Sasha Levin
2026-02-14 0:58 ` [PATCH AUTOSEL 6.19-6.12] media: mt9m114: Return -EPROBE_DEFER if no endpoint is found Sasha Levin
2026-02-14 0:59 ` Sasha Levin [this message]
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.12] media: ipu6: Always close firmware stream Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.18] media: qcom: camss: Do not enable cpas fast ahb clock for SM8550 VFE lite Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-5.10] media: solo6x10: Check for out of bounds chip_id Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.18] drm/amdgpu: Refactor amdgpu_gem_va_ioctl for Handling Last Fence Update and Timeline Management v4 Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-6.12] media: chips-media: wave5: Process ready frames when CMD_STOP sent to Encoder Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-5.10] media: pvrusb2: fix URB leak in pvr2_send_request_ex Sasha Levin
2026-02-14 0:59 ` [PATCH AUTOSEL 6.19-5.10] media: dvb-core: dmxdevfilter must always flush bufs Sasha Levin
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=20260214010245.3671907-60-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=hansg@kernel.org \
--cc=hverkuil+cisco@kernel.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=lily@floofy.city \
--cc=linux-media@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=ribalda@chromium.org \
--cc=stable@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox