aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicardo Ribalda <[email protected]>2024-06-10 23:09:54 +0000
committerLaurent Pinchart <[email protected]>2024-06-17 23:21:10 +0300
commitb2b5fcb1c5b645d5177ef3e3f41c7a706fc2688d (patch)
tree2dcb9b5d3ec783a97a8fc91cb98299bce083175b
parenta8505ad3be3e931c02d7dea505ab7783530fcdaa (diff)
media: uvcvideo: Probe the PLF characteristics
The UVC 1.5 standard defines 4 values for the PLF control: Off, 50Hz, 60Hz and Auto. But it does not clearly define if all the values must be implemented or not. Instead of just using the UVC version to determine what the PLF control can do, probe it. Reviewed-by: Sergey Senozhatsky <[email protected]> Signed-off-by: Ricardo Ribalda <[email protected]> Reviewed-by: Laurent Pinchart <[email protected]> Signed-off-by: Laurent Pinchart <[email protected]> Reviewed-by: Ricardo Ribalda <[email protected]>
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index f5230cd14577..1ce1caaccfb7 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -498,10 +498,53 @@ static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = {
static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
struct uvc_video_chain *chain, struct uvc_control *ctrl)
{
+ const struct uvc_control_mapping *out_mapping =
+ &uvc_ctrl_power_line_mapping_uvc11;
+ u8 *buf __free(kfree) = NULL;
+ u8 init_val;
+ int ret;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ /* Save the current PLF value, so we can restore it. */
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ /* If we cannot read the control skip it. */
+ if (ret)
+ return NULL;
+ init_val = *buf;
+
+ /* If PLF value cannot be set to off, it is limited. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (ret)
+ return &uvc_ctrl_power_line_mapping_limited;
+
+ /* UVC 1.1 does not define auto, we can exit. */
if (chain->dev->uvc_version < 0x150)
- return &uvc_ctrl_power_line_mapping_uvc11;
- else
- return &uvc_ctrl_power_line_mapping_uvc15;
+ goto end;
+
+ /* Check if the device supports auto. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (!ret)
+ out_mapping = &uvc_ctrl_power_line_mapping_uvc15;
+
+end:
+ /* Restore initial value and add mapping. */
+ *buf = init_val;
+ uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+
+ return out_mapping;
}
static const struct uvc_control_mapping uvc_ctrl_mappings[] = {