On Mon Sep 28 17:50:19 2026 -0400, Michael Jordan wrote:
> The flags fixup table is only applied to extension unit controls.
> Apply it to all controls, and skip GET_INFO when an entry matches.
> 
> Suggested-by: Ricardo Ribalda <[email protected]>
> Reviewed-by: Ricardo Ribalda <[email protected]>
> Reviewed-by: Hans de Goede <[email protected]>
> Assisted-by: LLM
> Signed-off-by: Michael Jordan <[email protected]>
> Link: https://patch.msgid.link/[email protected]
> Signed-off-by: Hans de Goede <[email protected]>
> Signed-off-by: Laurent Pinchart <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/usb/uvc/uvc_ctrl.c | 91 ++++++++++++++++++++++------------------
 1 file changed, 50 insertions(+), 41 deletions(-)

---

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index ea28c4e819bd..97f0fc48321e 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2841,6 +2841,48 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct 
v4l2_ext_control *xctrl)
  * Dynamic controls
  */
 
+static bool uvc_ctrl_fixup_flags(struct uvc_device *dev,
+                                const struct uvc_control *ctrl,
+                                struct uvc_control_info *info)
+{
+       struct uvc_ctrl_fixup {
+               struct usb_device_id id;
+               u8 entity;
+               u8 selector;
+               u8 flags;
+       };
+
+       static const struct uvc_ctrl_fixup fixups[] = {
+               { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
+               { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
+               { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
+                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+                       UVC_CTRL_FLAG_AUTO_UPDATE },
+       };
+
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
+               if (!usb_match_one_id(dev->intf, &fixups[i].id))
+                       continue;
+
+               if (fixups[i].entity == ctrl->entity->id &&
+                   fixups[i].selector == info->selector) {
+                       info->flags = fixups[i].flags;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /*
  * Retrieve flags for a given control
  */
@@ -2851,6 +2893,14 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
        u8 *data;
        int ret;
 
+       /*
+        * Some devices report bogus capabilities through GET_INFO. If the
+        * fixup table covers this control, take the flags from the table and
+        * skip the query altogether.
+        */
+       if (uvc_ctrl_fixup_flags(dev, ctrl, info))
+               return 0;
+
        data = kmalloc(1, GFP_KERNEL);
        if (data == NULL)
                return -ENOMEM;
@@ -2882,45 +2932,6 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
        return ret;
 }
 
-static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
-       const struct uvc_control *ctrl, struct uvc_control_info *info)
-{
-       struct uvc_ctrl_fixup {
-               struct usb_device_id id;
-               u8 entity;
-               u8 selector;
-               u8 flags;
-       };
-
-       static const struct uvc_ctrl_fixup fixups[] = {
-               { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
-                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
-                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
-                       UVC_CTRL_FLAG_AUTO_UPDATE },
-               { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
-                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
-                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
-                       UVC_CTRL_FLAG_AUTO_UPDATE },
-               { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
-                       UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
-                       UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
-                       UVC_CTRL_FLAG_AUTO_UPDATE },
-       };
-
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
-               if (!usb_match_one_id(dev->intf, &fixups[i].id))
-                       continue;
-
-               if (fixups[i].entity == ctrl->entity->id &&
-                   fixups[i].selector == info->selector) {
-                       info->flags = fixups[i].flags;
-                       return;
-               }
-       }
-}
-
 /*
  * Query control information (size and flags) for XU controls.
  */
@@ -2961,8 +2972,6 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
                goto done;
        }
 
-       uvc_ctrl_fixup_xu_info(dev, ctrl, info);
-
        uvc_dbg(dev, CONTROL,
                "XU control %pUl/%u queried: len %u, flags { get %u set %u auto 
%u }\n",
                info->entity, info->selector, info->size,
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to