diff options
Diffstat (limited to 'drivers/media/usb')
-rw-r--r-- | drivers/media/usb/uvc/uvc_ctrl.c | 49 |
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[] = { |