media: uvcvideo: Add support for per-device control mapping overrides
authorRicardo Ribalda <ribalda@chromium.org>
Tue, 7 Jun 2022 13:43:59 +0000 (14:43 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Sat, 16 Jul 2022 07:50:27 +0000 (08:50 +0100)
Some devices do not implement all their controls in a way that complies
with the UVC specification. This is for instance the case for several
devices that do not support the disabled mode for the power line
frequency control. Add a mechanism to allow per-device control mapping
overrides to avoid errors when accessing non-compliant controls.

Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvcvideo.h

index 95fdd41ab20b440d07fe2bde3b07cfb7fff3f033..e4826a846861b80ad60efea237c3c997f09d95bb 100644 (file)
@@ -2444,14 +2444,37 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
        if (!ctrl->initialized)
                return;
 
-       /* Process common mappings first. */
+       /*
+        * First check if the device provides a custom mapping for this control,
+        * used to override standard mappings for non-conformant devices. Don't
+        * process standard mappings if a custom mapping is found. This
+        * mechanism doesn't support combining standard and custom mappings for
+        * a single control.
+        */
+       if (chain->dev->info->mappings) {
+               bool custom = false;
+               unsigned int i;
+
+               for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) {
+                       if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+                           ctrl->info.selector == mapping->selector) {
+                               __uvc_ctrl_add_mapping(chain, ctrl, mapping);
+                               custom = true;
+                       }
+               }
+
+               if (custom)
+                       return;
+       }
+
+       /* Process common mappings next. */
        for (; mapping < mend; ++mapping) {
                if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
                    ctrl->info.selector == mapping->selector)
                        __uvc_ctrl_add_mapping(chain, ctrl, mapping);
        }
 
-       /* And then version-specific mappings. */
+       /* Finally process version-specific mappings. */
        if (chain->dev->uvc_version < 0x0150) {
                mapping = uvc_ctrl_mappings_uvc11;
                mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11);
index d2eb107347ea5dab649941cfb527257e3394a645..24c911aeebce569277cb2bc3ec06449fafdf425e 100644 (file)
@@ -668,6 +668,7 @@ struct uvc_device_info {
        u32     quirks;
        u32     meta_format;
        u16     uvc_version;
+       const struct uvc_control_mapping **mappings;
 };
 
 struct uvc_device {