On 10/03/21 02:37 , Scott K Logan wrote: > At least some of the Microsoft LifeCam series of webcams exhibit a > behavior which requires a 'quirk' to be handled properly. When > configuring the absolute exposure value of the image, there are only a > handful of values which will result in a consistent change to the image > exposure, while all other values appear to result in a maximum > exposure. > The valid values appear to follow an exponential pattern from the > maximum value (10000) down to the minimum, yielding less than 15 > possible values depending on the device's reported minimum. FTR, I have not tested patch (yet), but I checked idVendor 0x045e Microsoft Corp. idProduct 0x0810 LifeCam HD-3000 bcdDevice 1.08 iManufacturer 1 iProduct 2 iSerial 0 and it exhibit same behavior (only (1e4>>i) works, other values interpreted as max), so you may want to add chunk below > Signed-off-by: Scott K Logan <logans@xxxxxxxxxxx> > --- > drivers/media/usb/uvc/uvc_ctrl.c | 41 ++++++++++++++++++++++++++++++ > drivers/media/usb/uvc/uvc_driver.c | 18 +++++++++++++ > drivers/media/usb/uvc/uvcvideo.h | 1 + > 3 files changed, 60 insertions(+) > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c > index 30bfe9069a1f..2dfc70597858 100644 > --- a/drivers/media/usb/uvc/uvc_ctrl.c > +++ b/drivers/media/usb/uvc/uvc_ctrl.c > @@ -2142,6 +2142,40 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) > return 0; > } > > +/* -------------------------------------------------------------------------- > + * Quirks > + */ > + > +static s32 uvc_ctrl_get_abs_exposure_exponential( > + struct uvc_control_mapping *mapping, u8 query, const u8 *data) > +{ > + s32 i; > + s32 value = uvc_get_le_value(mapping, query, data); > + > + switch (query) { > + case UVC_GET_CUR: > + case UVC_GET_MIN: > + case UVC_GET_MAX: > + case UVC_GET_DEF: > + for (i = 0; i < 14; ++i) { > + if (10000 >> i <= value) > + break; > + } > + return 14 - i; > + case UVC_GET_RES: > + return 1; > + default: > + return value; > + } > +} > + > +static void uvc_ctrl_set_abs_exposure_exponential( > + struct uvc_control_mapping *mapping, s32 value, u8 *data) > +{ > + value = 10000 >> (14 - value); > + uvc_set_le_value(mapping, value, data); > +} > + > /* -------------------------------------------------------------------------- > * Control and mapping handling > */ > @@ -2210,6 +2244,13 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, > } > } > > + if ((chain->dev->quirks & UVC_QUIRK_EXPONENTIAL_EXPOSURE) && > + ctrl->info.selector == UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL) { > + uvc_dbg(chain->dev, CONTROL, "Applying exponential exposure quirk\n"); > + map->get = uvc_ctrl_get_abs_exposure_exponential; > + map->set = uvc_ctrl_set_abs_exposure_exponential; > + } > + > list_add_tail(&map->list, &ctrl->info.mappings); > uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", > uvc_map_get_name(map), ctrl->info.entity, > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c > index 7c007426e082..fa34802dfb33 100644 > --- a/drivers/media/usb/uvc/uvc_driver.c > +++ b/drivers/media/usb/uvc/uvc_driver.c > @@ -2718,6 +2718,24 @@ static const struct usb_device_id uvc_ids[] = { > .bInterfaceSubClass = 1, > .bInterfaceProtocol = 0, > .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, > + /* Microsoft Lifecam HD-5000 */ > + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE > + | USB_DEVICE_ID_MATCH_INT_INFO, > + .idVendor = 0x045e, > + .idProduct = 0x076d, > + .bInterfaceClass = USB_CLASS_VIDEO, > + .bInterfaceSubClass = 1, > + .bInterfaceProtocol = 0, > + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_EXPONENTIAL_EXPOSURE) }, + /* Microsoft Lifecam HD-3000 */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x045e, + .idProduct = 0x0810, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_EXPONENTIAL_EXPOSURE) }, > + /* Microsoft Lifecam Studio */ > + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE > + | USB_DEVICE_ID_MATCH_INT_INFO, > + .idVendor = 0x045e, > + .idProduct = 0x0772, > + .bInterfaceClass = USB_CLASS_VIDEO, > + .bInterfaceSubClass = 1, > + .bInterfaceProtocol = 0, > + .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_EXPONENTIAL_EXPOSURE) }, > /* Logitech Quickcam Fusion */ > { .match_flags = USB_DEVICE_ID_MATCH_DEVICE > | USB_DEVICE_ID_MATCH_INT_INFO, > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h > index 2e5366143b81..b6d5ae0b1c90 100644 > --- a/drivers/media/usb/uvc/uvcvideo.h > +++ b/drivers/media/usb/uvc/uvcvideo.h > @@ -209,6 +209,7 @@ > #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400 > #define UVC_QUIRK_FORCE_Y8 0x00000800 > #define UVC_QUIRK_FORCE_BPP 0x00001000 > +#define UVC_QUIRK_EXPONENTIAL_EXPOSURE 0x00002000 > > /* Format flags */ > #define UVC_FMT_FLAG_COMPRESSED 0x00000001 > -- > > 2.31.1