162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * uvc_ctrl.c -- USB Video Class driver - Controls 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005-2010 662306a36Sopenharmony_ci * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/barrier.h> 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include <linux/uaccess.h> 1662306a36Sopenharmony_ci#include <linux/usb.h> 1762306a36Sopenharmony_ci#include <linux/usb/uvc.h> 1862306a36Sopenharmony_ci#include <linux/videodev2.h> 1962306a36Sopenharmony_ci#include <linux/vmalloc.h> 2062306a36Sopenharmony_ci#include <linux/wait.h> 2162306a36Sopenharmony_ci#include <linux/workqueue.h> 2262306a36Sopenharmony_ci#include <linux/atomic.h> 2362306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "uvcvideo.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define UVC_CTRL_DATA_CURRENT 0 2862306a36Sopenharmony_ci#define UVC_CTRL_DATA_BACKUP 1 2962306a36Sopenharmony_ci#define UVC_CTRL_DATA_MIN 2 3062306a36Sopenharmony_ci#define UVC_CTRL_DATA_MAX 3 3162306a36Sopenharmony_ci#define UVC_CTRL_DATA_RES 4 3262306a36Sopenharmony_ci#define UVC_CTRL_DATA_DEF 5 3362306a36Sopenharmony_ci#define UVC_CTRL_DATA_LAST 6 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* ------------------------------------------------------------------------ 3662306a36Sopenharmony_ci * Controls 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct uvc_control_info uvc_ctrls[] = { 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 4262306a36Sopenharmony_ci .selector = UVC_PU_BRIGHTNESS_CONTROL, 4362306a36Sopenharmony_ci .index = 0, 4462306a36Sopenharmony_ci .size = 2, 4562306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 4662306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 4762306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 4862306a36Sopenharmony_ci }, 4962306a36Sopenharmony_ci { 5062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 5162306a36Sopenharmony_ci .selector = UVC_PU_CONTRAST_CONTROL, 5262306a36Sopenharmony_ci .index = 1, 5362306a36Sopenharmony_ci .size = 2, 5462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 5562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 5662306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 5762306a36Sopenharmony_ci }, 5862306a36Sopenharmony_ci { 5962306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 6062306a36Sopenharmony_ci .selector = UVC_PU_HUE_CONTROL, 6162306a36Sopenharmony_ci .index = 2, 6262306a36Sopenharmony_ci .size = 2, 6362306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 6462306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 6562306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 6662306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 6762306a36Sopenharmony_ci }, 6862306a36Sopenharmony_ci { 6962306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 7062306a36Sopenharmony_ci .selector = UVC_PU_SATURATION_CONTROL, 7162306a36Sopenharmony_ci .index = 3, 7262306a36Sopenharmony_ci .size = 2, 7362306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 7462306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 7562306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 7662306a36Sopenharmony_ci }, 7762306a36Sopenharmony_ci { 7862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 7962306a36Sopenharmony_ci .selector = UVC_PU_SHARPNESS_CONTROL, 8062306a36Sopenharmony_ci .index = 4, 8162306a36Sopenharmony_ci .size = 2, 8262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 8362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 8462306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 8562306a36Sopenharmony_ci }, 8662306a36Sopenharmony_ci { 8762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 8862306a36Sopenharmony_ci .selector = UVC_PU_GAMMA_CONTROL, 8962306a36Sopenharmony_ci .index = 5, 9062306a36Sopenharmony_ci .size = 2, 9162306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 9262306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 9362306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 9462306a36Sopenharmony_ci }, 9562306a36Sopenharmony_ci { 9662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 9762306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, 9862306a36Sopenharmony_ci .index = 6, 9962306a36Sopenharmony_ci .size = 2, 10062306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 10162306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 10262306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 10362306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 10462306a36Sopenharmony_ci }, 10562306a36Sopenharmony_ci { 10662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 10762306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, 10862306a36Sopenharmony_ci .index = 7, 10962306a36Sopenharmony_ci .size = 4, 11062306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 11162306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 11262306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 11362306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 11462306a36Sopenharmony_ci }, 11562306a36Sopenharmony_ci { 11662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 11762306a36Sopenharmony_ci .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, 11862306a36Sopenharmony_ci .index = 8, 11962306a36Sopenharmony_ci .size = 2, 12062306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 12162306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 12262306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 12362306a36Sopenharmony_ci }, 12462306a36Sopenharmony_ci { 12562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 12662306a36Sopenharmony_ci .selector = UVC_PU_GAIN_CONTROL, 12762306a36Sopenharmony_ci .index = 9, 12862306a36Sopenharmony_ci .size = 2, 12962306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 13062306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 13162306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 13262306a36Sopenharmony_ci }, 13362306a36Sopenharmony_ci { 13462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 13562306a36Sopenharmony_ci .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, 13662306a36Sopenharmony_ci .index = 10, 13762306a36Sopenharmony_ci .size = 1, 13862306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 13962306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 14362306a36Sopenharmony_ci .selector = UVC_PU_HUE_AUTO_CONTROL, 14462306a36Sopenharmony_ci .index = 11, 14562306a36Sopenharmony_ci .size = 1, 14662306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 14762306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, 14862306a36Sopenharmony_ci }, 14962306a36Sopenharmony_ci { 15062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 15162306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, 15262306a36Sopenharmony_ci .index = 12, 15362306a36Sopenharmony_ci .size = 1, 15462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 15562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci { 15862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 15962306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, 16062306a36Sopenharmony_ci .index = 13, 16162306a36Sopenharmony_ci .size = 1, 16262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 16362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci { 16662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 16762306a36Sopenharmony_ci .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL, 16862306a36Sopenharmony_ci .index = 14, 16962306a36Sopenharmony_ci .size = 2, 17062306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 17162306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 17262306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 17362306a36Sopenharmony_ci }, 17462306a36Sopenharmony_ci { 17562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 17662306a36Sopenharmony_ci .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL, 17762306a36Sopenharmony_ci .index = 15, 17862306a36Sopenharmony_ci .size = 2, 17962306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 18062306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 18162306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 18262306a36Sopenharmony_ci }, 18362306a36Sopenharmony_ci { 18462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 18562306a36Sopenharmony_ci .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL, 18662306a36Sopenharmony_ci .index = 16, 18762306a36Sopenharmony_ci .size = 1, 18862306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_GET_CUR, 18962306a36Sopenharmony_ci }, 19062306a36Sopenharmony_ci { 19162306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 19262306a36Sopenharmony_ci .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL, 19362306a36Sopenharmony_ci .index = 17, 19462306a36Sopenharmony_ci .size = 1, 19562306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_GET_CUR, 19662306a36Sopenharmony_ci }, 19762306a36Sopenharmony_ci { 19862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 19962306a36Sopenharmony_ci .selector = UVC_CT_SCANNING_MODE_CONTROL, 20062306a36Sopenharmony_ci .index = 0, 20162306a36Sopenharmony_ci .size = 1, 20262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 20362306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 20462306a36Sopenharmony_ci }, 20562306a36Sopenharmony_ci { 20662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 20762306a36Sopenharmony_ci .selector = UVC_CT_AE_MODE_CONTROL, 20862306a36Sopenharmony_ci .index = 1, 20962306a36Sopenharmony_ci .size = 1, 21062306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 21162306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES 21262306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci { 21562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 21662306a36Sopenharmony_ci .selector = UVC_CT_AE_PRIORITY_CONTROL, 21762306a36Sopenharmony_ci .index = 2, 21862306a36Sopenharmony_ci .size = 1, 21962306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 22062306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci { 22362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 22462306a36Sopenharmony_ci .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, 22562306a36Sopenharmony_ci .index = 3, 22662306a36Sopenharmony_ci .size = 4, 22762306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 22862306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 22962306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 23062306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 23162306a36Sopenharmony_ci }, 23262306a36Sopenharmony_ci { 23362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 23462306a36Sopenharmony_ci .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL, 23562306a36Sopenharmony_ci .index = 4, 23662306a36Sopenharmony_ci .size = 1, 23762306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE, 23862306a36Sopenharmony_ci }, 23962306a36Sopenharmony_ci { 24062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 24162306a36Sopenharmony_ci .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, 24262306a36Sopenharmony_ci .index = 5, 24362306a36Sopenharmony_ci .size = 2, 24462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 24562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 24662306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 24762306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 24862306a36Sopenharmony_ci }, 24962306a36Sopenharmony_ci { 25062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 25162306a36Sopenharmony_ci .selector = UVC_CT_FOCUS_RELATIVE_CONTROL, 25262306a36Sopenharmony_ci .index = 6, 25362306a36Sopenharmony_ci .size = 2, 25462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN 25562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES 25662306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF 25762306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 25862306a36Sopenharmony_ci }, 25962306a36Sopenharmony_ci { 26062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 26162306a36Sopenharmony_ci .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, 26262306a36Sopenharmony_ci .index = 7, 26362306a36Sopenharmony_ci .size = 2, 26462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 26562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 26662306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 26762306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 26862306a36Sopenharmony_ci }, 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 27162306a36Sopenharmony_ci .selector = UVC_CT_IRIS_RELATIVE_CONTROL, 27262306a36Sopenharmony_ci .index = 8, 27362306a36Sopenharmony_ci .size = 1, 27462306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 27562306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 27662306a36Sopenharmony_ci }, 27762306a36Sopenharmony_ci { 27862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 27962306a36Sopenharmony_ci .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, 28062306a36Sopenharmony_ci .index = 9, 28162306a36Sopenharmony_ci .size = 2, 28262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 28362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 28462306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 28562306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 28662306a36Sopenharmony_ci }, 28762306a36Sopenharmony_ci { 28862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 28962306a36Sopenharmony_ci .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, 29062306a36Sopenharmony_ci .index = 10, 29162306a36Sopenharmony_ci .size = 3, 29262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN 29362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES 29462306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF 29562306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 29662306a36Sopenharmony_ci }, 29762306a36Sopenharmony_ci { 29862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 29962306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, 30062306a36Sopenharmony_ci .index = 11, 30162306a36Sopenharmony_ci .size = 8, 30262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 30362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 30462306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 30562306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 30662306a36Sopenharmony_ci }, 30762306a36Sopenharmony_ci { 30862306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 30962306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, 31062306a36Sopenharmony_ci .index = 12, 31162306a36Sopenharmony_ci .size = 4, 31262306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 31362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 31462306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 31562306a36Sopenharmony_ci }, 31662306a36Sopenharmony_ci { 31762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 31862306a36Sopenharmony_ci .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL, 31962306a36Sopenharmony_ci .index = 13, 32062306a36Sopenharmony_ci .size = 2, 32162306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR 32262306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RANGE 32362306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 32462306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 32562306a36Sopenharmony_ci }, 32662306a36Sopenharmony_ci { 32762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 32862306a36Sopenharmony_ci .selector = UVC_CT_ROLL_RELATIVE_CONTROL, 32962306a36Sopenharmony_ci .index = 14, 33062306a36Sopenharmony_ci .size = 2, 33162306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN 33262306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES 33362306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF 33462306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 33562306a36Sopenharmony_ci }, 33662306a36Sopenharmony_ci { 33762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 33862306a36Sopenharmony_ci .selector = UVC_CT_FOCUS_AUTO_CONTROL, 33962306a36Sopenharmony_ci .index = 17, 34062306a36Sopenharmony_ci .size = 1, 34162306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 34262306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE, 34362306a36Sopenharmony_ci }, 34462306a36Sopenharmony_ci { 34562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 34662306a36Sopenharmony_ci .selector = UVC_CT_PRIVACY_CONTROL, 34762306a36Sopenharmony_ci .index = 18, 34862306a36Sopenharmony_ci .size = 1, 34962306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR 35062306a36Sopenharmony_ci | UVC_CTRL_FLAG_RESTORE 35162306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 35262306a36Sopenharmony_ci }, 35362306a36Sopenharmony_ci { 35462306a36Sopenharmony_ci .entity = UVC_GUID_EXT_GPIO_CONTROLLER, 35562306a36Sopenharmony_ci .selector = UVC_CT_PRIVACY_CONTROL, 35662306a36Sopenharmony_ci .index = 0, 35762306a36Sopenharmony_ci .size = 1, 35862306a36Sopenharmony_ci .flags = UVC_CTRL_FLAG_GET_CUR 35962306a36Sopenharmony_ci | UVC_CTRL_FLAG_AUTO_UPDATE, 36062306a36Sopenharmony_ci }, 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic const u32 uvc_control_classes[] = { 36462306a36Sopenharmony_ci V4L2_CID_CAMERA_CLASS, 36562306a36Sopenharmony_ci V4L2_CID_USER_CLASS, 36662306a36Sopenharmony_ci}; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * This function translates the V4L2 menu index @idx, as exposed to userspace as 37262306a36Sopenharmony_ci * the V4L2 control value, to the corresponding UVC control value used by the 37362306a36Sopenharmony_ci * device. The custom menu_mapping in the control @mapping is used when 37462306a36Sopenharmony_ci * available, otherwise the function assumes that the V4L2 and UVC values are 37562306a36Sopenharmony_ci * identical. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * For controls of type UVC_CTRL_DATA_TYPE_BITMASK, the UVC control value is 37862306a36Sopenharmony_ci * expressed as a bitmask and is thus guaranteed to have a single bit set. 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * The function returns -EINVAL if the V4L2 menu index @idx isn't valid for the 38162306a36Sopenharmony_ci * control, which includes all controls whose type isn't UVC_CTRL_DATA_TYPE_ENUM 38262306a36Sopenharmony_ci * or UVC_CTRL_DATA_TYPE_BITMASK. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic int uvc_mapping_get_menu_value(const struct uvc_control_mapping *mapping, 38562306a36Sopenharmony_ci u32 idx) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci if (!test_bit(idx, &mapping->menu_mask)) 38862306a36Sopenharmony_ci return -EINVAL; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (mapping->menu_mapping) 39162306a36Sopenharmony_ci return mapping->menu_mapping[idx]; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return idx; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic const char * 39762306a36Sopenharmony_ciuvc_mapping_get_menu_name(const struct uvc_control_mapping *mapping, u32 idx) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci if (!test_bit(idx, &mapping->menu_mask)) 40062306a36Sopenharmony_ci return NULL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (mapping->menu_names) 40362306a36Sopenharmony_ci return mapping->menu_names[idx]; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return v4l2_ctrl_get_menu(mapping->id)[idx]; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, 40962306a36Sopenharmony_ci u8 query, const u8 *data) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci s8 zoom = (s8)data[0]; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci switch (query) { 41462306a36Sopenharmony_ci case UVC_GET_CUR: 41562306a36Sopenharmony_ci return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci case UVC_GET_MIN: 41862306a36Sopenharmony_ci case UVC_GET_MAX: 41962306a36Sopenharmony_ci case UVC_GET_RES: 42062306a36Sopenharmony_ci case UVC_GET_DEF: 42162306a36Sopenharmony_ci default: 42262306a36Sopenharmony_ci return data[2]; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping, 42762306a36Sopenharmony_ci s32 value, u8 *data) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 43062306a36Sopenharmony_ci data[2] = min((int)abs(value), 0xff); 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic s32 uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping, 43462306a36Sopenharmony_ci u8 query, const u8 *data) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci unsigned int first = mapping->offset / 8; 43762306a36Sopenharmony_ci s8 rel = (s8)data[first]; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci switch (query) { 44062306a36Sopenharmony_ci case UVC_GET_CUR: 44162306a36Sopenharmony_ci return (rel == 0) ? 0 : (rel > 0 ? data[first+1] 44262306a36Sopenharmony_ci : -data[first+1]); 44362306a36Sopenharmony_ci case UVC_GET_MIN: 44462306a36Sopenharmony_ci return -data[first+1]; 44562306a36Sopenharmony_ci case UVC_GET_MAX: 44662306a36Sopenharmony_ci case UVC_GET_RES: 44762306a36Sopenharmony_ci case UVC_GET_DEF: 44862306a36Sopenharmony_ci default: 44962306a36Sopenharmony_ci return data[first+1]; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping, 45462306a36Sopenharmony_ci s32 value, u8 *data) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci unsigned int first = mapping->offset / 8; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci data[first] = value == 0 ? 0 : (value > 0) ? 1 : 0xff; 45962306a36Sopenharmony_ci data[first+1] = min_t(int, abs(value), 0xff); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic const struct uvc_control_mapping uvc_ctrl_mappings[] = { 46362306a36Sopenharmony_ci { 46462306a36Sopenharmony_ci .id = V4L2_CID_BRIGHTNESS, 46562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 46662306a36Sopenharmony_ci .selector = UVC_PU_BRIGHTNESS_CONTROL, 46762306a36Sopenharmony_ci .size = 16, 46862306a36Sopenharmony_ci .offset = 0, 46962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 47062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 47162306a36Sopenharmony_ci }, 47262306a36Sopenharmony_ci { 47362306a36Sopenharmony_ci .id = V4L2_CID_CONTRAST, 47462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 47562306a36Sopenharmony_ci .selector = UVC_PU_CONTRAST_CONTROL, 47662306a36Sopenharmony_ci .size = 16, 47762306a36Sopenharmony_ci .offset = 0, 47862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 47962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 48062306a36Sopenharmony_ci }, 48162306a36Sopenharmony_ci { 48262306a36Sopenharmony_ci .id = V4L2_CID_HUE, 48362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 48462306a36Sopenharmony_ci .selector = UVC_PU_HUE_CONTROL, 48562306a36Sopenharmony_ci .size = 16, 48662306a36Sopenharmony_ci .offset = 0, 48762306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 48862306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 48962306a36Sopenharmony_ci .master_id = V4L2_CID_HUE_AUTO, 49062306a36Sopenharmony_ci .master_manual = 0, 49162306a36Sopenharmony_ci }, 49262306a36Sopenharmony_ci { 49362306a36Sopenharmony_ci .id = V4L2_CID_SATURATION, 49462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 49562306a36Sopenharmony_ci .selector = UVC_PU_SATURATION_CONTROL, 49662306a36Sopenharmony_ci .size = 16, 49762306a36Sopenharmony_ci .offset = 0, 49862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 49962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 50062306a36Sopenharmony_ci }, 50162306a36Sopenharmony_ci { 50262306a36Sopenharmony_ci .id = V4L2_CID_SHARPNESS, 50362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 50462306a36Sopenharmony_ci .selector = UVC_PU_SHARPNESS_CONTROL, 50562306a36Sopenharmony_ci .size = 16, 50662306a36Sopenharmony_ci .offset = 0, 50762306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 50862306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 50962306a36Sopenharmony_ci }, 51062306a36Sopenharmony_ci { 51162306a36Sopenharmony_ci .id = V4L2_CID_GAMMA, 51262306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 51362306a36Sopenharmony_ci .selector = UVC_PU_GAMMA_CONTROL, 51462306a36Sopenharmony_ci .size = 16, 51562306a36Sopenharmony_ci .offset = 0, 51662306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 51762306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 51862306a36Sopenharmony_ci }, 51962306a36Sopenharmony_ci { 52062306a36Sopenharmony_ci .id = V4L2_CID_BACKLIGHT_COMPENSATION, 52162306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 52262306a36Sopenharmony_ci .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL, 52362306a36Sopenharmony_ci .size = 16, 52462306a36Sopenharmony_ci .offset = 0, 52562306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 52662306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 52762306a36Sopenharmony_ci }, 52862306a36Sopenharmony_ci { 52962306a36Sopenharmony_ci .id = V4L2_CID_GAIN, 53062306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 53162306a36Sopenharmony_ci .selector = UVC_PU_GAIN_CONTROL, 53262306a36Sopenharmony_ci .size = 16, 53362306a36Sopenharmony_ci .offset = 0, 53462306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 53562306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 53662306a36Sopenharmony_ci }, 53762306a36Sopenharmony_ci { 53862306a36Sopenharmony_ci .id = V4L2_CID_HUE_AUTO, 53962306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 54062306a36Sopenharmony_ci .selector = UVC_PU_HUE_AUTO_CONTROL, 54162306a36Sopenharmony_ci .size = 1, 54262306a36Sopenharmony_ci .offset = 0, 54362306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 54462306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 54562306a36Sopenharmony_ci .slave_ids = { V4L2_CID_HUE, }, 54662306a36Sopenharmony_ci }, 54762306a36Sopenharmony_ci { 54862306a36Sopenharmony_ci .id = V4L2_CID_EXPOSURE_AUTO, 54962306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 55062306a36Sopenharmony_ci .selector = UVC_CT_AE_MODE_CONTROL, 55162306a36Sopenharmony_ci .size = 4, 55262306a36Sopenharmony_ci .offset = 0, 55362306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_MENU, 55462306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BITMASK, 55562306a36Sopenharmony_ci .menu_mapping = exposure_auto_mapping, 55662306a36Sopenharmony_ci .menu_mask = GENMASK(V4L2_EXPOSURE_APERTURE_PRIORITY, 55762306a36Sopenharmony_ci V4L2_EXPOSURE_AUTO), 55862306a36Sopenharmony_ci .slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, }, 55962306a36Sopenharmony_ci }, 56062306a36Sopenharmony_ci { 56162306a36Sopenharmony_ci .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY, 56262306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 56362306a36Sopenharmony_ci .selector = UVC_CT_AE_PRIORITY_CONTROL, 56462306a36Sopenharmony_ci .size = 1, 56562306a36Sopenharmony_ci .offset = 0, 56662306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 56762306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 56862306a36Sopenharmony_ci }, 56962306a36Sopenharmony_ci { 57062306a36Sopenharmony_ci .id = V4L2_CID_EXPOSURE_ABSOLUTE, 57162306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 57262306a36Sopenharmony_ci .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, 57362306a36Sopenharmony_ci .size = 32, 57462306a36Sopenharmony_ci .offset = 0, 57562306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 57662306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 57762306a36Sopenharmony_ci .master_id = V4L2_CID_EXPOSURE_AUTO, 57862306a36Sopenharmony_ci .master_manual = V4L2_EXPOSURE_MANUAL, 57962306a36Sopenharmony_ci }, 58062306a36Sopenharmony_ci { 58162306a36Sopenharmony_ci .id = V4L2_CID_AUTO_WHITE_BALANCE, 58262306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 58362306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, 58462306a36Sopenharmony_ci .size = 1, 58562306a36Sopenharmony_ci .offset = 0, 58662306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 58762306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 58862306a36Sopenharmony_ci .slave_ids = { V4L2_CID_WHITE_BALANCE_TEMPERATURE, }, 58962306a36Sopenharmony_ci }, 59062306a36Sopenharmony_ci { 59162306a36Sopenharmony_ci .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, 59262306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 59362306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL, 59462306a36Sopenharmony_ci .size = 16, 59562306a36Sopenharmony_ci .offset = 0, 59662306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 59762306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 59862306a36Sopenharmony_ci .master_id = V4L2_CID_AUTO_WHITE_BALANCE, 59962306a36Sopenharmony_ci .master_manual = 0, 60062306a36Sopenharmony_ci }, 60162306a36Sopenharmony_ci { 60262306a36Sopenharmony_ci .id = V4L2_CID_AUTO_WHITE_BALANCE, 60362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 60462306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL, 60562306a36Sopenharmony_ci .size = 1, 60662306a36Sopenharmony_ci .offset = 0, 60762306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 60862306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 60962306a36Sopenharmony_ci .slave_ids = { V4L2_CID_BLUE_BALANCE, 61062306a36Sopenharmony_ci V4L2_CID_RED_BALANCE }, 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci { 61362306a36Sopenharmony_ci .id = V4L2_CID_BLUE_BALANCE, 61462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 61562306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, 61662306a36Sopenharmony_ci .size = 16, 61762306a36Sopenharmony_ci .offset = 0, 61862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 61962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 62062306a36Sopenharmony_ci .master_id = V4L2_CID_AUTO_WHITE_BALANCE, 62162306a36Sopenharmony_ci .master_manual = 0, 62262306a36Sopenharmony_ci }, 62362306a36Sopenharmony_ci { 62462306a36Sopenharmony_ci .id = V4L2_CID_RED_BALANCE, 62562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 62662306a36Sopenharmony_ci .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL, 62762306a36Sopenharmony_ci .size = 16, 62862306a36Sopenharmony_ci .offset = 16, 62962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 63062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 63162306a36Sopenharmony_ci .master_id = V4L2_CID_AUTO_WHITE_BALANCE, 63262306a36Sopenharmony_ci .master_manual = 0, 63362306a36Sopenharmony_ci }, 63462306a36Sopenharmony_ci { 63562306a36Sopenharmony_ci .id = V4L2_CID_FOCUS_ABSOLUTE, 63662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 63762306a36Sopenharmony_ci .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL, 63862306a36Sopenharmony_ci .size = 16, 63962306a36Sopenharmony_ci .offset = 0, 64062306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 64162306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 64262306a36Sopenharmony_ci .master_id = V4L2_CID_FOCUS_AUTO, 64362306a36Sopenharmony_ci .master_manual = 0, 64462306a36Sopenharmony_ci }, 64562306a36Sopenharmony_ci { 64662306a36Sopenharmony_ci .id = V4L2_CID_FOCUS_AUTO, 64762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 64862306a36Sopenharmony_ci .selector = UVC_CT_FOCUS_AUTO_CONTROL, 64962306a36Sopenharmony_ci .size = 1, 65062306a36Sopenharmony_ci .offset = 0, 65162306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 65262306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 65362306a36Sopenharmony_ci .slave_ids = { V4L2_CID_FOCUS_ABSOLUTE, }, 65462306a36Sopenharmony_ci }, 65562306a36Sopenharmony_ci { 65662306a36Sopenharmony_ci .id = V4L2_CID_IRIS_ABSOLUTE, 65762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 65862306a36Sopenharmony_ci .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL, 65962306a36Sopenharmony_ci .size = 16, 66062306a36Sopenharmony_ci .offset = 0, 66162306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 66262306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 66362306a36Sopenharmony_ci }, 66462306a36Sopenharmony_ci { 66562306a36Sopenharmony_ci .id = V4L2_CID_IRIS_RELATIVE, 66662306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 66762306a36Sopenharmony_ci .selector = UVC_CT_IRIS_RELATIVE_CONTROL, 66862306a36Sopenharmony_ci .size = 8, 66962306a36Sopenharmony_ci .offset = 0, 67062306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 67162306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 67262306a36Sopenharmony_ci }, 67362306a36Sopenharmony_ci { 67462306a36Sopenharmony_ci .id = V4L2_CID_ZOOM_ABSOLUTE, 67562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 67662306a36Sopenharmony_ci .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL, 67762306a36Sopenharmony_ci .size = 16, 67862306a36Sopenharmony_ci .offset = 0, 67962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 68062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, 68162306a36Sopenharmony_ci }, 68262306a36Sopenharmony_ci { 68362306a36Sopenharmony_ci .id = V4L2_CID_ZOOM_CONTINUOUS, 68462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 68562306a36Sopenharmony_ci .selector = UVC_CT_ZOOM_RELATIVE_CONTROL, 68662306a36Sopenharmony_ci .size = 0, 68762306a36Sopenharmony_ci .offset = 0, 68862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 68962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 69062306a36Sopenharmony_ci .get = uvc_ctrl_get_zoom, 69162306a36Sopenharmony_ci .set = uvc_ctrl_set_zoom, 69262306a36Sopenharmony_ci }, 69362306a36Sopenharmony_ci { 69462306a36Sopenharmony_ci .id = V4L2_CID_PAN_ABSOLUTE, 69562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 69662306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, 69762306a36Sopenharmony_ci .size = 32, 69862306a36Sopenharmony_ci .offset = 0, 69962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 70062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 70162306a36Sopenharmony_ci }, 70262306a36Sopenharmony_ci { 70362306a36Sopenharmony_ci .id = V4L2_CID_TILT_ABSOLUTE, 70462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 70562306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL, 70662306a36Sopenharmony_ci .size = 32, 70762306a36Sopenharmony_ci .offset = 32, 70862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 70962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 71062306a36Sopenharmony_ci }, 71162306a36Sopenharmony_ci { 71262306a36Sopenharmony_ci .id = V4L2_CID_PAN_SPEED, 71362306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 71462306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, 71562306a36Sopenharmony_ci .size = 16, 71662306a36Sopenharmony_ci .offset = 0, 71762306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 71862306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 71962306a36Sopenharmony_ci .get = uvc_ctrl_get_rel_speed, 72062306a36Sopenharmony_ci .set = uvc_ctrl_set_rel_speed, 72162306a36Sopenharmony_ci }, 72262306a36Sopenharmony_ci { 72362306a36Sopenharmony_ci .id = V4L2_CID_TILT_SPEED, 72462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 72562306a36Sopenharmony_ci .selector = UVC_CT_PANTILT_RELATIVE_CONTROL, 72662306a36Sopenharmony_ci .size = 16, 72762306a36Sopenharmony_ci .offset = 16, 72862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_INTEGER, 72962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_SIGNED, 73062306a36Sopenharmony_ci .get = uvc_ctrl_get_rel_speed, 73162306a36Sopenharmony_ci .set = uvc_ctrl_set_rel_speed, 73262306a36Sopenharmony_ci }, 73362306a36Sopenharmony_ci { 73462306a36Sopenharmony_ci .id = V4L2_CID_PRIVACY, 73562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_CAMERA, 73662306a36Sopenharmony_ci .selector = UVC_CT_PRIVACY_CONTROL, 73762306a36Sopenharmony_ci .size = 1, 73862306a36Sopenharmony_ci .offset = 0, 73962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 74062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 74162306a36Sopenharmony_ci }, 74262306a36Sopenharmony_ci { 74362306a36Sopenharmony_ci .id = V4L2_CID_PRIVACY, 74462306a36Sopenharmony_ci .entity = UVC_GUID_EXT_GPIO_CONTROLLER, 74562306a36Sopenharmony_ci .selector = UVC_CT_PRIVACY_CONTROL, 74662306a36Sopenharmony_ci .size = 1, 74762306a36Sopenharmony_ci .offset = 0, 74862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, 74962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, 75062306a36Sopenharmony_ci }, 75162306a36Sopenharmony_ci}; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ciconst struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = { 75462306a36Sopenharmony_ci .id = V4L2_CID_POWER_LINE_FREQUENCY, 75562306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 75662306a36Sopenharmony_ci .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, 75762306a36Sopenharmony_ci .size = 2, 75862306a36Sopenharmony_ci .offset = 0, 75962306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_MENU, 76062306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_ENUM, 76162306a36Sopenharmony_ci .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 76262306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_50HZ), 76362306a36Sopenharmony_ci}; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ciconst struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11 = { 76662306a36Sopenharmony_ci .id = V4L2_CID_POWER_LINE_FREQUENCY, 76762306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 76862306a36Sopenharmony_ci .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, 76962306a36Sopenharmony_ci .size = 2, 77062306a36Sopenharmony_ci .offset = 0, 77162306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_MENU, 77262306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_ENUM, 77362306a36Sopenharmony_ci .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 77462306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), 77562306a36Sopenharmony_ci}; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic const struct uvc_control_mapping *uvc_ctrl_mappings_uvc11[] = { 77862306a36Sopenharmony_ci &uvc_ctrl_power_line_mapping_uvc11, 77962306a36Sopenharmony_ci NULL, /* Sentinel */ 78062306a36Sopenharmony_ci}; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc15 = { 78362306a36Sopenharmony_ci .id = V4L2_CID_POWER_LINE_FREQUENCY, 78462306a36Sopenharmony_ci .entity = UVC_GUID_UVC_PROCESSING, 78562306a36Sopenharmony_ci .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL, 78662306a36Sopenharmony_ci .size = 2, 78762306a36Sopenharmony_ci .offset = 0, 78862306a36Sopenharmony_ci .v4l2_type = V4L2_CTRL_TYPE_MENU, 78962306a36Sopenharmony_ci .data_type = UVC_CTRL_DATA_TYPE_ENUM, 79062306a36Sopenharmony_ci .menu_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 79162306a36Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_DISABLED), 79262306a36Sopenharmony_ci}; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cistatic const struct uvc_control_mapping *uvc_ctrl_mappings_uvc15[] = { 79562306a36Sopenharmony_ci &uvc_ctrl_power_line_mapping_uvc15, 79662306a36Sopenharmony_ci NULL, /* Sentinel */ 79762306a36Sopenharmony_ci}; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/* ------------------------------------------------------------------------ 80062306a36Sopenharmony_ci * Utility functions 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic inline u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci return ctrl->uvc_data + id * ctrl->info.size; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic inline int uvc_test_bit(const u8 *data, int bit) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci return (data[bit >> 3] >> (bit & 7)) & 1; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic inline void uvc_clear_bit(u8 *data, int bit) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci data[bit >> 3] &= ~(1 << (bit & 7)); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/* 81962306a36Sopenharmony_ci * Extract the bit string specified by mapping->offset and mapping->size 82062306a36Sopenharmony_ci * from the little-endian data stored at 'data' and return the result as 82162306a36Sopenharmony_ci * a signed 32bit integer. Sign extension will be performed if the mapping 82262306a36Sopenharmony_ci * references a signed data type. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_cistatic s32 uvc_get_le_value(struct uvc_control_mapping *mapping, 82562306a36Sopenharmony_ci u8 query, const u8 *data) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci int bits = mapping->size; 82862306a36Sopenharmony_ci int offset = mapping->offset; 82962306a36Sopenharmony_ci s32 value = 0; 83062306a36Sopenharmony_ci u8 mask; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci data += offset / 8; 83362306a36Sopenharmony_ci offset &= 7; 83462306a36Sopenharmony_ci mask = ((1LL << bits) - 1) << offset; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci while (1) { 83762306a36Sopenharmony_ci u8 byte = *data & mask; 83862306a36Sopenharmony_ci value |= offset > 0 ? (byte >> offset) : (byte << (-offset)); 83962306a36Sopenharmony_ci bits -= 8 - (offset > 0 ? offset : 0); 84062306a36Sopenharmony_ci if (bits <= 0) 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci offset -= 8; 84462306a36Sopenharmony_ci mask = (1 << bits) - 1; 84562306a36Sopenharmony_ci data++; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Sign-extend the value if needed. */ 84962306a36Sopenharmony_ci if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) 85062306a36Sopenharmony_ci value |= -(value & (1 << (mapping->size - 1))); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci return value; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci/* 85662306a36Sopenharmony_ci * Set the bit string specified by mapping->offset and mapping->size 85762306a36Sopenharmony_ci * in the little-endian data stored at 'data' to the value 'value'. 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_cistatic void uvc_set_le_value(struct uvc_control_mapping *mapping, 86062306a36Sopenharmony_ci s32 value, u8 *data) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci int bits = mapping->size; 86362306a36Sopenharmony_ci int offset = mapping->offset; 86462306a36Sopenharmony_ci u8 mask; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci /* 86762306a36Sopenharmony_ci * According to the v4l2 spec, writing any value to a button control 86862306a36Sopenharmony_ci * should result in the action belonging to the button control being 86962306a36Sopenharmony_ci * triggered. UVC devices however want to see a 1 written -> override 87062306a36Sopenharmony_ci * value. 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_ci if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON) 87362306a36Sopenharmony_ci value = -1; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci data += offset / 8; 87662306a36Sopenharmony_ci offset &= 7; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci for (; bits > 0; data++) { 87962306a36Sopenharmony_ci mask = ((1LL << bits) - 1) << offset; 88062306a36Sopenharmony_ci *data = (*data & ~mask) | ((value << offset) & mask); 88162306a36Sopenharmony_ci value >>= offset ? offset : 8; 88262306a36Sopenharmony_ci bits -= 8 - offset; 88362306a36Sopenharmony_ci offset = 0; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/* ------------------------------------------------------------------------ 88862306a36Sopenharmony_ci * Terminal and unit management 88962306a36Sopenharmony_ci */ 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int uvc_entity_match_guid(const struct uvc_entity *entity, 89262306a36Sopenharmony_ci const u8 guid[16]) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci return memcmp(entity->guid, guid, sizeof(entity->guid)) == 0; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci/* ------------------------------------------------------------------------ 89862306a36Sopenharmony_ci * UVC Controls 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic void __uvc_find_control(struct uvc_entity *entity, u32 v4l2_id, 90262306a36Sopenharmony_ci struct uvc_control_mapping **mapping, struct uvc_control **control, 90362306a36Sopenharmony_ci int next) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct uvc_control *ctrl; 90662306a36Sopenharmony_ci struct uvc_control_mapping *map; 90762306a36Sopenharmony_ci unsigned int i; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (entity == NULL) 91062306a36Sopenharmony_ci return; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 91362306a36Sopenharmony_ci ctrl = &entity->controls[i]; 91462306a36Sopenharmony_ci if (!ctrl->initialized) 91562306a36Sopenharmony_ci continue; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci list_for_each_entry(map, &ctrl->info.mappings, list) { 91862306a36Sopenharmony_ci if ((map->id == v4l2_id) && !next) { 91962306a36Sopenharmony_ci *control = ctrl; 92062306a36Sopenharmony_ci *mapping = map; 92162306a36Sopenharmony_ci return; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if ((*mapping == NULL || (*mapping)->id > map->id) && 92562306a36Sopenharmony_ci (map->id > v4l2_id) && next) { 92662306a36Sopenharmony_ci *control = ctrl; 92762306a36Sopenharmony_ci *mapping = map; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, 93462306a36Sopenharmony_ci u32 v4l2_id, struct uvc_control_mapping **mapping) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci struct uvc_control *ctrl = NULL; 93762306a36Sopenharmony_ci struct uvc_entity *entity; 93862306a36Sopenharmony_ci int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci *mapping = NULL; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* Mask the query flags. */ 94362306a36Sopenharmony_ci v4l2_id &= V4L2_CTRL_ID_MASK; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Find the control. */ 94662306a36Sopenharmony_ci list_for_each_entry(entity, &chain->entities, chain) { 94762306a36Sopenharmony_ci __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); 94862306a36Sopenharmony_ci if (ctrl && !next) 94962306a36Sopenharmony_ci return ctrl; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (ctrl == NULL && !next) 95362306a36Sopenharmony_ci uvc_dbg(chain->dev, CONTROL, "Control 0x%08x not found\n", 95462306a36Sopenharmony_ci v4l2_id); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci return ctrl; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, 96062306a36Sopenharmony_ci struct uvc_control *ctrl) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci int ret; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { 96562306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, 96662306a36Sopenharmony_ci chain->dev->intfnum, ctrl->info.selector, 96762306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), 96862306a36Sopenharmony_ci ctrl->info.size); 96962306a36Sopenharmony_ci if (ret < 0) 97062306a36Sopenharmony_ci return ret; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) { 97462306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, 97562306a36Sopenharmony_ci chain->dev->intfnum, ctrl->info.selector, 97662306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), 97762306a36Sopenharmony_ci ctrl->info.size); 97862306a36Sopenharmony_ci if (ret < 0) 97962306a36Sopenharmony_ci return ret; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) { 98262306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, 98362306a36Sopenharmony_ci chain->dev->intfnum, ctrl->info.selector, 98462306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), 98562306a36Sopenharmony_ci ctrl->info.size); 98662306a36Sopenharmony_ci if (ret < 0) 98762306a36Sopenharmony_ci return ret; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { 99062306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, 99162306a36Sopenharmony_ci chain->dev->intfnum, ctrl->info.selector, 99262306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 99362306a36Sopenharmony_ci ctrl->info.size); 99462306a36Sopenharmony_ci if (ret < 0) { 99562306a36Sopenharmony_ci if (UVC_ENTITY_TYPE(ctrl->entity) != 99662306a36Sopenharmony_ci UVC_VC_EXTENSION_UNIT) 99762306a36Sopenharmony_ci return ret; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* 100062306a36Sopenharmony_ci * GET_RES is mandatory for XU controls, but some 100162306a36Sopenharmony_ci * cameras still choke on it. Ignore errors and set the 100262306a36Sopenharmony_ci * resolution value to zero. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES, 100562306a36Sopenharmony_ci "UVC non compliance - GET_RES failed on " 100662306a36Sopenharmony_ci "an XU control. Enabling workaround.\n"); 100762306a36Sopenharmony_ci memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0, 100862306a36Sopenharmony_ci ctrl->info.size); 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci ctrl->cached = 1; 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_cistatic s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, 101762306a36Sopenharmony_ci const u8 *data) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci s32 value = mapping->get(mapping, UVC_GET_CUR, data); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { 102262306a36Sopenharmony_ci unsigned int i; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { 102562306a36Sopenharmony_ci u32 menu_value; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (!test_bit(i, &mapping->menu_mask)) 102862306a36Sopenharmony_ci continue; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci menu_value = uvc_mapping_get_menu_value(mapping, i); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (menu_value == value) { 103362306a36Sopenharmony_ci value = i; 103462306a36Sopenharmony_ci break; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return value; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, 104362306a36Sopenharmony_ci struct uvc_control *ctrl) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci u8 *data; 104662306a36Sopenharmony_ci int ret; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (ctrl->loaded) 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) { 105462306a36Sopenharmony_ci memset(data, 0, ctrl->info.size); 105562306a36Sopenharmony_ci ctrl->loaded = 1; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci } 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (ctrl->entity->get_cur) 106162306a36Sopenharmony_ci ret = ctrl->entity->get_cur(chain->dev, ctrl->entity, 106262306a36Sopenharmony_ci ctrl->info.selector, data, 106362306a36Sopenharmony_ci ctrl->info.size); 106462306a36Sopenharmony_ci else 106562306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, 106662306a36Sopenharmony_ci ctrl->entity->id, chain->dev->intfnum, 106762306a36Sopenharmony_ci ctrl->info.selector, data, 106862306a36Sopenharmony_ci ctrl->info.size); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (ret < 0) 107162306a36Sopenharmony_ci return ret; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ctrl->loaded = 1; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return ret; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic int __uvc_ctrl_get(struct uvc_video_chain *chain, 107962306a36Sopenharmony_ci struct uvc_control *ctrl, 108062306a36Sopenharmony_ci struct uvc_control_mapping *mapping, 108162306a36Sopenharmony_ci s32 *value) 108262306a36Sopenharmony_ci{ 108362306a36Sopenharmony_ci int ret; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) 108662306a36Sopenharmony_ci return -EACCES; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ret = __uvc_ctrl_load_cur(chain, ctrl); 108962306a36Sopenharmony_ci if (ret < 0) 109062306a36Sopenharmony_ci return ret; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci *value = __uvc_ctrl_get_value(mapping, 109362306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci return 0; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, 109962306a36Sopenharmony_ci u32 found_id) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL; 110262306a36Sopenharmony_ci unsigned int i; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci req_id &= V4L2_CTRL_ID_MASK; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { 110762306a36Sopenharmony_ci if (!(chain->ctrl_class_bitmap & BIT(i))) 110862306a36Sopenharmony_ci continue; 110962306a36Sopenharmony_ci if (!find_next) { 111062306a36Sopenharmony_ci if (uvc_control_classes[i] == req_id) 111162306a36Sopenharmony_ci return i; 111262306a36Sopenharmony_ci continue; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci if (uvc_control_classes[i] > req_id && 111562306a36Sopenharmony_ci uvc_control_classes[i] < found_id) 111662306a36Sopenharmony_ci return i; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci return -ENODEV; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id, 112362306a36Sopenharmony_ci u32 found_id, struct v4l2_queryctrl *v4l2_ctrl) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci int idx; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci idx = __uvc_query_v4l2_class(chain, req_id, found_id); 112862306a36Sopenharmony_ci if (idx < 0) 112962306a36Sopenharmony_ci return -ENODEV; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); 113262306a36Sopenharmony_ci v4l2_ctrl->id = uvc_control_classes[idx]; 113362306a36Sopenharmony_ci strscpy(v4l2_ctrl->name, v4l2_ctrl_get_name(v4l2_ctrl->id), 113462306a36Sopenharmony_ci sizeof(v4l2_ctrl->name)); 113562306a36Sopenharmony_ci v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS; 113662306a36Sopenharmony_ci v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY 113762306a36Sopenharmony_ci | V4L2_CTRL_FLAG_READ_ONLY; 113862306a36Sopenharmony_ci return 0; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci/* 114262306a36Sopenharmony_ci * Check if control @v4l2_id can be accessed by the given control @ioctl 114362306a36Sopenharmony_ci * (VIDIOC_G_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS or VIDIOC_S_EXT_CTRLS). 114462306a36Sopenharmony_ci * 114562306a36Sopenharmony_ci * For set operations on slave controls, check if the master's value is set to 114662306a36Sopenharmony_ci * manual, either in the others controls set in the same ioctl call, or from 114762306a36Sopenharmony_ci * the master's current value. This catches VIDIOC_S_EXT_CTRLS calls that set 114862306a36Sopenharmony_ci * both the master and slave control, such as for instance setting 114962306a36Sopenharmony_ci * auto_exposure=1, exposure_time_absolute=251. 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ciint uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id, 115262306a36Sopenharmony_ci const struct v4l2_ext_controls *ctrls, 115362306a36Sopenharmony_ci unsigned long ioctl) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct uvc_control_mapping *master_map = NULL; 115662306a36Sopenharmony_ci struct uvc_control *master_ctrl = NULL; 115762306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 115862306a36Sopenharmony_ci struct uvc_control *ctrl; 115962306a36Sopenharmony_ci bool read = ioctl == VIDIOC_G_EXT_CTRLS; 116062306a36Sopenharmony_ci s32 val; 116162306a36Sopenharmony_ci int ret; 116262306a36Sopenharmony_ci int i; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0) 116562306a36Sopenharmony_ci return -EACCES; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci ctrl = uvc_find_control(chain, v4l2_id, &mapping); 116862306a36Sopenharmony_ci if (!ctrl) 116962306a36Sopenharmony_ci return -EINVAL; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) && read) 117262306a36Sopenharmony_ci return -EACCES; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) && !read) 117562306a36Sopenharmony_ci return -EACCES; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (ioctl != VIDIOC_S_EXT_CTRLS || !mapping->master_id) 117862306a36Sopenharmony_ci return 0; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* 118162306a36Sopenharmony_ci * Iterate backwards in cases where the master control is accessed 118262306a36Sopenharmony_ci * multiple times in the same ioctl. We want the last value. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_ci for (i = ctrls->count - 1; i >= 0; i--) { 118562306a36Sopenharmony_ci if (ctrls->controls[i].id == mapping->master_id) 118662306a36Sopenharmony_ci return ctrls->controls[i].value == 118762306a36Sopenharmony_ci mapping->master_manual ? 0 : -EACCES; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci __uvc_find_control(ctrl->entity, mapping->master_id, &master_map, 119162306a36Sopenharmony_ci &master_ctrl, 0); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (!master_ctrl || !(master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) 119462306a36Sopenharmony_ci return 0; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); 119762306a36Sopenharmony_ci if (ret >= 0 && val != mapping->master_manual) 119862306a36Sopenharmony_ci return -EACCES; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci} 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_cistatic const char *uvc_map_get_name(const struct uvc_control_mapping *map) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci const char *name; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (map->name) 120862306a36Sopenharmony_ci return map->name; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci name = v4l2_ctrl_get_name(map->id); 121162306a36Sopenharmony_ci if (name) 121262306a36Sopenharmony_ci return name; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci return "Unknown Control"; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl, 121862306a36Sopenharmony_ci struct uvc_control_mapping *mapping) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci /* 122162306a36Sopenharmony_ci * Some controls, like CT_AE_MODE_CONTROL, use GET_RES to represent 122262306a36Sopenharmony_ci * the number of bits supported. Those controls do not list GET_MAX 122362306a36Sopenharmony_ci * as supported. 122462306a36Sopenharmony_ci */ 122562306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) 122662306a36Sopenharmony_ci return mapping->get(mapping, UVC_GET_RES, 122762306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) 123062306a36Sopenharmony_ci return mapping->get(mapping, UVC_GET_MAX, 123162306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci return ~0; 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, 123762306a36Sopenharmony_ci struct uvc_control *ctrl, 123862306a36Sopenharmony_ci struct uvc_control_mapping *mapping, 123962306a36Sopenharmony_ci struct v4l2_queryctrl *v4l2_ctrl) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct uvc_control_mapping *master_map = NULL; 124262306a36Sopenharmony_ci struct uvc_control *master_ctrl = NULL; 124362306a36Sopenharmony_ci unsigned int i; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); 124662306a36Sopenharmony_ci v4l2_ctrl->id = mapping->id; 124762306a36Sopenharmony_ci v4l2_ctrl->type = mapping->v4l2_type; 124862306a36Sopenharmony_ci strscpy(v4l2_ctrl->name, uvc_map_get_name(mapping), 124962306a36Sopenharmony_ci sizeof(v4l2_ctrl->name)); 125062306a36Sopenharmony_ci v4l2_ctrl->flags = 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) 125362306a36Sopenharmony_ci v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; 125462306a36Sopenharmony_ci if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) 125562306a36Sopenharmony_ci v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (mapping->master_id) 125862306a36Sopenharmony_ci __uvc_find_control(ctrl->entity, mapping->master_id, 125962306a36Sopenharmony_ci &master_map, &master_ctrl, 0); 126062306a36Sopenharmony_ci if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { 126162306a36Sopenharmony_ci s32 val; 126262306a36Sopenharmony_ci int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); 126362306a36Sopenharmony_ci if (ret < 0) 126462306a36Sopenharmony_ci return ret; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (val != mapping->master_manual) 126762306a36Sopenharmony_ci v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (!ctrl->cached) { 127162306a36Sopenharmony_ci int ret = uvc_ctrl_populate_cache(chain, ctrl); 127262306a36Sopenharmony_ci if (ret < 0) 127362306a36Sopenharmony_ci return ret; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) { 127762306a36Sopenharmony_ci v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, 127862306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci switch (mapping->v4l2_type) { 128262306a36Sopenharmony_ci case V4L2_CTRL_TYPE_MENU: 128362306a36Sopenharmony_ci v4l2_ctrl->minimum = ffs(mapping->menu_mask) - 1; 128462306a36Sopenharmony_ci v4l2_ctrl->maximum = fls(mapping->menu_mask) - 1; 128562306a36Sopenharmony_ci v4l2_ctrl->step = 1; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci for (i = 0; BIT(i) <= mapping->menu_mask; ++i) { 128862306a36Sopenharmony_ci u32 menu_value; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (!test_bit(i, &mapping->menu_mask)) 129162306a36Sopenharmony_ci continue; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci menu_value = uvc_mapping_get_menu_value(mapping, i); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (menu_value == v4l2_ctrl->default_value) { 129662306a36Sopenharmony_ci v4l2_ctrl->default_value = i; 129762306a36Sopenharmony_ci break; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci return 0; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BOOLEAN: 130462306a36Sopenharmony_ci v4l2_ctrl->minimum = 0; 130562306a36Sopenharmony_ci v4l2_ctrl->maximum = 1; 130662306a36Sopenharmony_ci v4l2_ctrl->step = 1; 130762306a36Sopenharmony_ci return 0; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BUTTON: 131062306a36Sopenharmony_ci v4l2_ctrl->minimum = 0; 131162306a36Sopenharmony_ci v4l2_ctrl->maximum = 0; 131262306a36Sopenharmony_ci v4l2_ctrl->step = 0; 131362306a36Sopenharmony_ci return 0; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BITMASK: 131662306a36Sopenharmony_ci v4l2_ctrl->minimum = 0; 131762306a36Sopenharmony_ci v4l2_ctrl->maximum = uvc_get_ctrl_bitmap(ctrl, mapping); 131862306a36Sopenharmony_ci v4l2_ctrl->step = 0; 131962306a36Sopenharmony_ci return 0; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci default: 132262306a36Sopenharmony_ci break; 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) 132662306a36Sopenharmony_ci v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, 132762306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) 133062306a36Sopenharmony_ci v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, 133162306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) 133462306a36Sopenharmony_ci v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, 133562306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci return 0; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ciint uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, 134162306a36Sopenharmony_ci struct v4l2_queryctrl *v4l2_ctrl) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci struct uvc_control *ctrl; 134462306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 134562306a36Sopenharmony_ci int ret; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci ret = mutex_lock_interruptible(&chain->ctrl_mutex); 134862306a36Sopenharmony_ci if (ret < 0) 134962306a36Sopenharmony_ci return -ERESTARTSYS; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* Check if the ctrl is a know class */ 135262306a36Sopenharmony_ci if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) { 135362306a36Sopenharmony_ci ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, 0, v4l2_ctrl); 135462306a36Sopenharmony_ci if (!ret) 135562306a36Sopenharmony_ci goto done; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); 135962306a36Sopenharmony_ci if (ctrl == NULL) { 136062306a36Sopenharmony_ci ret = -EINVAL; 136162306a36Sopenharmony_ci goto done; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* 136562306a36Sopenharmony_ci * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if 136662306a36Sopenharmony_ci * a class should be inserted between the previous control and the one 136762306a36Sopenharmony_ci * we have just found. 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_ci if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) { 137062306a36Sopenharmony_ci ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, mapping->id, 137162306a36Sopenharmony_ci v4l2_ctrl); 137262306a36Sopenharmony_ci if (!ret) 137362306a36Sopenharmony_ci goto done; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl); 137762306a36Sopenharmony_cidone: 137862306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 137962306a36Sopenharmony_ci return ret; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/* 138362306a36Sopenharmony_ci * Mapping V4L2 controls to UVC controls can be straightforward if done well. 138462306a36Sopenharmony_ci * Most of the UVC controls exist in V4L2, and can be mapped directly. Some 138562306a36Sopenharmony_ci * must be grouped (for instance the Red Balance, Blue Balance and Do White 138662306a36Sopenharmony_ci * Balance V4L2 controls use the White Balance Component UVC control) or 138762306a36Sopenharmony_ci * otherwise translated. The approach we take here is to use a translation 138862306a36Sopenharmony_ci * table for the controls that can be mapped directly, and handle the others 138962306a36Sopenharmony_ci * manually. 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ciint uvc_query_v4l2_menu(struct uvc_video_chain *chain, 139262306a36Sopenharmony_ci struct v4l2_querymenu *query_menu) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 139562306a36Sopenharmony_ci struct uvc_control *ctrl; 139662306a36Sopenharmony_ci u32 index = query_menu->index; 139762306a36Sopenharmony_ci u32 id = query_menu->id; 139862306a36Sopenharmony_ci const char *name; 139962306a36Sopenharmony_ci int ret; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci memset(query_menu, 0, sizeof(*query_menu)); 140262306a36Sopenharmony_ci query_menu->id = id; 140362306a36Sopenharmony_ci query_menu->index = index; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (index >= BITS_PER_TYPE(mapping->menu_mask)) 140662306a36Sopenharmony_ci return -EINVAL; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci ret = mutex_lock_interruptible(&chain->ctrl_mutex); 140962306a36Sopenharmony_ci if (ret < 0) 141062306a36Sopenharmony_ci return -ERESTARTSYS; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci ctrl = uvc_find_control(chain, query_menu->id, &mapping); 141362306a36Sopenharmony_ci if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { 141462306a36Sopenharmony_ci ret = -EINVAL; 141562306a36Sopenharmony_ci goto done; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (!test_bit(query_menu->index, &mapping->menu_mask)) { 141962306a36Sopenharmony_ci ret = -EINVAL; 142062306a36Sopenharmony_ci goto done; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) { 142462306a36Sopenharmony_ci int mask; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (!ctrl->cached) { 142762306a36Sopenharmony_ci ret = uvc_ctrl_populate_cache(chain, ctrl); 142862306a36Sopenharmony_ci if (ret < 0) 142962306a36Sopenharmony_ci goto done; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci mask = uvc_mapping_get_menu_value(mapping, query_menu->index); 143362306a36Sopenharmony_ci if (mask < 0) { 143462306a36Sopenharmony_ci ret = mask; 143562306a36Sopenharmony_ci goto done; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & mask)) { 143962306a36Sopenharmony_ci ret = -EINVAL; 144062306a36Sopenharmony_ci goto done; 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci name = uvc_mapping_get_menu_name(mapping, query_menu->index); 144562306a36Sopenharmony_ci if (!name) { 144662306a36Sopenharmony_ci ret = -EINVAL; 144762306a36Sopenharmony_ci goto done; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci strscpy(query_menu->name, name, sizeof(query_menu->name)); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cidone: 145362306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 145462306a36Sopenharmony_ci return ret; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 145862306a36Sopenharmony_ci * Ctrl event handling 145962306a36Sopenharmony_ci */ 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic void uvc_ctrl_fill_event(struct uvc_video_chain *chain, 146262306a36Sopenharmony_ci struct v4l2_event *ev, 146362306a36Sopenharmony_ci struct uvc_control *ctrl, 146462306a36Sopenharmony_ci struct uvc_control_mapping *mapping, 146562306a36Sopenharmony_ci s32 value, u32 changes) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci struct v4l2_queryctrl v4l2_ctrl; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci memset(ev, 0, sizeof(*ev)); 147262306a36Sopenharmony_ci ev->type = V4L2_EVENT_CTRL; 147362306a36Sopenharmony_ci ev->id = v4l2_ctrl.id; 147462306a36Sopenharmony_ci ev->u.ctrl.value = value; 147562306a36Sopenharmony_ci ev->u.ctrl.changes = changes; 147662306a36Sopenharmony_ci ev->u.ctrl.type = v4l2_ctrl.type; 147762306a36Sopenharmony_ci ev->u.ctrl.flags = v4l2_ctrl.flags; 147862306a36Sopenharmony_ci ev->u.ctrl.minimum = v4l2_ctrl.minimum; 147962306a36Sopenharmony_ci ev->u.ctrl.maximum = v4l2_ctrl.maximum; 148062306a36Sopenharmony_ci ev->u.ctrl.step = v4l2_ctrl.step; 148162306a36Sopenharmony_ci ev->u.ctrl.default_value = v4l2_ctrl.default_value; 148262306a36Sopenharmony_ci} 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci/* 148562306a36Sopenharmony_ci * Send control change events to all subscribers for the @ctrl control. By 148662306a36Sopenharmony_ci * default the subscriber that generated the event, as identified by @handle, 148762306a36Sopenharmony_ci * is not notified unless it has set the V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK flag. 148862306a36Sopenharmony_ci * @handle can be NULL for asynchronous events related to auto-update controls, 148962306a36Sopenharmony_ci * in which case all subscribers are notified. 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_cistatic void uvc_ctrl_send_event(struct uvc_video_chain *chain, 149262306a36Sopenharmony_ci struct uvc_fh *handle, struct uvc_control *ctrl, 149362306a36Sopenharmony_ci struct uvc_control_mapping *mapping, s32 value, u32 changes) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct v4l2_fh *originator = handle ? &handle->vfh : NULL; 149662306a36Sopenharmony_ci struct v4l2_subscribed_event *sev; 149762306a36Sopenharmony_ci struct v4l2_event ev; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci if (list_empty(&mapping->ev_subs)) 150062306a36Sopenharmony_ci return; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci uvc_ctrl_fill_event(chain, &ev, ctrl, mapping, value, changes); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci list_for_each_entry(sev, &mapping->ev_subs, node) { 150562306a36Sopenharmony_ci if (sev->fh != originator || 150662306a36Sopenharmony_ci (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) || 150762306a36Sopenharmony_ci (changes & V4L2_EVENT_CTRL_CH_FLAGS)) 150862306a36Sopenharmony_ci v4l2_event_queue_fh(sev->fh, &ev); 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci} 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci/* 151362306a36Sopenharmony_ci * Send control change events for the slave of the @master control identified 151462306a36Sopenharmony_ci * by the V4L2 ID @slave_id. The @handle identifies the event subscriber that 151562306a36Sopenharmony_ci * generated the event and may be NULL for auto-update events. 151662306a36Sopenharmony_ci */ 151762306a36Sopenharmony_cistatic void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, 151862306a36Sopenharmony_ci struct uvc_fh *handle, struct uvc_control *master, u32 slave_id) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci struct uvc_control_mapping *mapping = NULL; 152162306a36Sopenharmony_ci struct uvc_control *ctrl = NULL; 152262306a36Sopenharmony_ci u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; 152362306a36Sopenharmony_ci s32 val = 0; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0); 152662306a36Sopenharmony_ci if (ctrl == NULL) 152762306a36Sopenharmony_ci return; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (__uvc_ctrl_get(chain, ctrl, mapping, &val) == 0) 153062306a36Sopenharmony_ci changes |= V4L2_EVENT_CTRL_CH_VALUE; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_civoid uvc_ctrl_status_event(struct uvc_video_chain *chain, 153662306a36Sopenharmony_ci struct uvc_control *ctrl, const u8 *data) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 153962306a36Sopenharmony_ci struct uvc_fh *handle; 154062306a36Sopenharmony_ci unsigned int i; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci mutex_lock(&chain->ctrl_mutex); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci handle = ctrl->handle; 154562306a36Sopenharmony_ci ctrl->handle = NULL; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci list_for_each_entry(mapping, &ctrl->info.mappings, list) { 154862306a36Sopenharmony_ci s32 value = __uvc_ctrl_get_value(mapping, data); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci /* 155162306a36Sopenharmony_ci * handle may be NULL here if the device sends auto-update 155262306a36Sopenharmony_ci * events without a prior related control set from userspace. 155362306a36Sopenharmony_ci */ 155462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mapping->slave_ids); ++i) { 155562306a36Sopenharmony_ci if (!mapping->slave_ids[i]) 155662306a36Sopenharmony_ci break; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci uvc_ctrl_send_slave_event(chain, handle, ctrl, 155962306a36Sopenharmony_ci mapping->slave_ids[i]); 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci uvc_ctrl_send_event(chain, handle, ctrl, mapping, value, 156362306a36Sopenharmony_ci V4L2_EVENT_CTRL_CH_VALUE); 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic void uvc_ctrl_status_event_work(struct work_struct *work) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct uvc_device *dev = container_of(work, struct uvc_device, 157262306a36Sopenharmony_ci async_ctrl.work); 157362306a36Sopenharmony_ci struct uvc_ctrl_work *w = &dev->async_ctrl; 157462306a36Sopenharmony_ci int ret; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci uvc_ctrl_status_event(w->chain, w->ctrl, w->data); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* The barrier is needed to synchronize with uvc_status_stop(). */ 157962306a36Sopenharmony_ci if (smp_load_acquire(&dev->flush_status)) 158062306a36Sopenharmony_ci return; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* Resubmit the URB. */ 158362306a36Sopenharmony_ci w->urb->interval = dev->int_ep->desc.bInterval; 158462306a36Sopenharmony_ci ret = usb_submit_urb(w->urb, GFP_KERNEL); 158562306a36Sopenharmony_ci if (ret < 0) 158662306a36Sopenharmony_ci dev_err(&dev->udev->dev, 158762306a36Sopenharmony_ci "Failed to resubmit status URB (%d).\n", ret); 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_cibool uvc_ctrl_status_event_async(struct urb *urb, struct uvc_video_chain *chain, 159162306a36Sopenharmony_ci struct uvc_control *ctrl, const u8 *data) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct uvc_device *dev = chain->dev; 159462306a36Sopenharmony_ci struct uvc_ctrl_work *w = &dev->async_ctrl; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (list_empty(&ctrl->info.mappings)) { 159762306a36Sopenharmony_ci ctrl->handle = NULL; 159862306a36Sopenharmony_ci return false; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci w->data = data; 160262306a36Sopenharmony_ci w->urb = urb; 160362306a36Sopenharmony_ci w->chain = chain; 160462306a36Sopenharmony_ci w->ctrl = ctrl; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci schedule_work(&w->work); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci return true; 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls, 161262306a36Sopenharmony_ci unsigned int xctrls_count, u32 id) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci unsigned int i; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci for (i = 0; i < xctrls_count; ++i) { 161762306a36Sopenharmony_ci if (xctrls[i].id == id) 161862306a36Sopenharmony_ci return true; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return false; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_cistatic void uvc_ctrl_send_events(struct uvc_fh *handle, 162562306a36Sopenharmony_ci const struct v4l2_ext_control *xctrls, unsigned int xctrls_count) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 162862306a36Sopenharmony_ci struct uvc_control *ctrl; 162962306a36Sopenharmony_ci u32 changes = V4L2_EVENT_CTRL_CH_VALUE; 163062306a36Sopenharmony_ci unsigned int i; 163162306a36Sopenharmony_ci unsigned int j; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci for (i = 0; i < xctrls_count; ++i) { 163462306a36Sopenharmony_ci ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) 163762306a36Sopenharmony_ci /* Notification will be sent from an Interrupt event. */ 163862306a36Sopenharmony_ci continue; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) { 164162306a36Sopenharmony_ci u32 slave_id = mapping->slave_ids[j]; 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (!slave_id) 164462306a36Sopenharmony_ci break; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci /* 164762306a36Sopenharmony_ci * We can skip sending an event for the slave if the 164862306a36Sopenharmony_ci * slave is being modified in the same transaction. 164962306a36Sopenharmony_ci */ 165062306a36Sopenharmony_ci if (uvc_ctrl_xctrls_has_control(xctrls, xctrls_count, 165162306a36Sopenharmony_ci slave_id)) 165262306a36Sopenharmony_ci continue; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci uvc_ctrl_send_slave_event(handle->chain, handle, ctrl, 165562306a36Sopenharmony_ci slave_id); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * If the master is being modified in the same transaction 166062306a36Sopenharmony_ci * flags may change too. 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci if (mapping->master_id && 166362306a36Sopenharmony_ci uvc_ctrl_xctrls_has_control(xctrls, xctrls_count, 166462306a36Sopenharmony_ci mapping->master_id)) 166562306a36Sopenharmony_ci changes |= V4L2_EVENT_CTRL_CH_FLAGS; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci uvc_ctrl_send_event(handle->chain, handle, ctrl, mapping, 166862306a36Sopenharmony_ci xctrls[i].value, changes); 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci} 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_cistatic int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) 167362306a36Sopenharmony_ci{ 167462306a36Sopenharmony_ci struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh); 167562306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 167662306a36Sopenharmony_ci struct uvc_control *ctrl; 167762306a36Sopenharmony_ci int ret; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex); 168062306a36Sopenharmony_ci if (ret < 0) 168162306a36Sopenharmony_ci return -ERESTARTSYS; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) { 168462306a36Sopenharmony_ci ret = 0; 168562306a36Sopenharmony_ci goto done; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci ctrl = uvc_find_control(handle->chain, sev->id, &mapping); 168962306a36Sopenharmony_ci if (ctrl == NULL) { 169062306a36Sopenharmony_ci ret = -EINVAL; 169162306a36Sopenharmony_ci goto done; 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci list_add_tail(&sev->node, &mapping->ev_subs); 169562306a36Sopenharmony_ci if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { 169662306a36Sopenharmony_ci struct v4l2_event ev; 169762306a36Sopenharmony_ci u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; 169862306a36Sopenharmony_ci s32 val = 0; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) 170162306a36Sopenharmony_ci changes |= V4L2_EVENT_CTRL_CH_VALUE; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, 170462306a36Sopenharmony_ci changes); 170562306a36Sopenharmony_ci /* 170662306a36Sopenharmony_ci * Mark the queue as active, allowing this initial event to be 170762306a36Sopenharmony_ci * accepted. 170862306a36Sopenharmony_ci */ 170962306a36Sopenharmony_ci sev->elems = elems; 171062306a36Sopenharmony_ci v4l2_event_queue_fh(sev->fh, &ev); 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_cidone: 171462306a36Sopenharmony_ci mutex_unlock(&handle->chain->ctrl_mutex); 171562306a36Sopenharmony_ci return ret; 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_cistatic void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci mutex_lock(&handle->chain->ctrl_mutex); 172362306a36Sopenharmony_ci if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) 172462306a36Sopenharmony_ci goto done; 172562306a36Sopenharmony_ci list_del(&sev->node); 172662306a36Sopenharmony_cidone: 172762306a36Sopenharmony_ci mutex_unlock(&handle->chain->ctrl_mutex); 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ciconst struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = { 173162306a36Sopenharmony_ci .add = uvc_ctrl_add_event, 173262306a36Sopenharmony_ci .del = uvc_ctrl_del_event, 173362306a36Sopenharmony_ci .replace = v4l2_ctrl_replace, 173462306a36Sopenharmony_ci .merge = v4l2_ctrl_merge, 173562306a36Sopenharmony_ci}; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 173862306a36Sopenharmony_ci * Control transactions 173962306a36Sopenharmony_ci * 174062306a36Sopenharmony_ci * To make extended set operations as atomic as the hardware allows, controls 174162306a36Sopenharmony_ci * are handled using begin/commit/rollback operations. 174262306a36Sopenharmony_ci * 174362306a36Sopenharmony_ci * At the beginning of a set request, uvc_ctrl_begin should be called to 174462306a36Sopenharmony_ci * initialize the request. This function acquires the control lock. 174562306a36Sopenharmony_ci * 174662306a36Sopenharmony_ci * When setting a control, the new value is stored in the control data field 174762306a36Sopenharmony_ci * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for 174862306a36Sopenharmony_ci * later processing. If the UVC and V4L2 control sizes differ, the current 174962306a36Sopenharmony_ci * value is loaded from the hardware before storing the new value in the data 175062306a36Sopenharmony_ci * field. 175162306a36Sopenharmony_ci * 175262306a36Sopenharmony_ci * After processing all controls in the transaction, uvc_ctrl_commit or 175362306a36Sopenharmony_ci * uvc_ctrl_rollback must be called to apply the pending changes to the 175462306a36Sopenharmony_ci * hardware or revert them. When applying changes, all controls marked as 175562306a36Sopenharmony_ci * dirty will be modified in the UVC device, and the dirty flag will be 175662306a36Sopenharmony_ci * cleared. When reverting controls, the control data field 175762306a36Sopenharmony_ci * UVC_CTRL_DATA_CURRENT is reverted to its previous value 175862306a36Sopenharmony_ci * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the 175962306a36Sopenharmony_ci * control lock. 176062306a36Sopenharmony_ci */ 176162306a36Sopenharmony_ciint uvc_ctrl_begin(struct uvc_video_chain *chain) 176262306a36Sopenharmony_ci{ 176362306a36Sopenharmony_ci return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; 176462306a36Sopenharmony_ci} 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_cistatic int uvc_ctrl_commit_entity(struct uvc_device *dev, 176762306a36Sopenharmony_ci struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct uvc_control *ctrl; 177062306a36Sopenharmony_ci unsigned int i; 177162306a36Sopenharmony_ci int ret; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (entity == NULL) 177462306a36Sopenharmony_ci return 0; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 177762306a36Sopenharmony_ci ctrl = &entity->controls[i]; 177862306a36Sopenharmony_ci if (!ctrl->initialized) 177962306a36Sopenharmony_ci continue; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci /* 178262306a36Sopenharmony_ci * Reset the loaded flag for auto-update controls that were 178362306a36Sopenharmony_ci * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent 178462306a36Sopenharmony_ci * uvc_ctrl_get from using the cached value, and for write-only 178562306a36Sopenharmony_ci * controls to prevent uvc_ctrl_set from setting bits not 178662306a36Sopenharmony_ci * explicitly set by the user. 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE || 178962306a36Sopenharmony_ci !(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) 179062306a36Sopenharmony_ci ctrl->loaded = 0; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci if (!ctrl->dirty) 179362306a36Sopenharmony_ci continue; 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (!rollback) 179662306a36Sopenharmony_ci ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id, 179762306a36Sopenharmony_ci dev->intfnum, ctrl->info.selector, 179862306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 179962306a36Sopenharmony_ci ctrl->info.size); 180062306a36Sopenharmony_ci else 180162306a36Sopenharmony_ci ret = 0; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci if (rollback || ret < 0) 180462306a36Sopenharmony_ci memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 180562306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 180662306a36Sopenharmony_ci ctrl->info.size); 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci ctrl->dirty = 0; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci if (ret < 0) { 181162306a36Sopenharmony_ci if (err_ctrl) 181262306a36Sopenharmony_ci *err_ctrl = ctrl; 181362306a36Sopenharmony_ci return ret; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci } 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci return 0; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, 182162306a36Sopenharmony_ci struct v4l2_ext_controls *ctrls, 182262306a36Sopenharmony_ci struct uvc_control *uvc_control) 182362306a36Sopenharmony_ci{ 182462306a36Sopenharmony_ci struct uvc_control_mapping *mapping = NULL; 182562306a36Sopenharmony_ci struct uvc_control *ctrl_found = NULL; 182662306a36Sopenharmony_ci unsigned int i; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (!entity) 182962306a36Sopenharmony_ci return ctrls->count; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci for (i = 0; i < ctrls->count; i++) { 183262306a36Sopenharmony_ci __uvc_find_control(entity, ctrls->controls[i].id, &mapping, 183362306a36Sopenharmony_ci &ctrl_found, 0); 183462306a36Sopenharmony_ci if (uvc_control == ctrl_found) 183562306a36Sopenharmony_ci return i; 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci return ctrls->count; 183962306a36Sopenharmony_ci} 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ciint __uvc_ctrl_commit(struct uvc_fh *handle, int rollback, 184262306a36Sopenharmony_ci struct v4l2_ext_controls *ctrls) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct uvc_video_chain *chain = handle->chain; 184562306a36Sopenharmony_ci struct uvc_control *err_ctrl; 184662306a36Sopenharmony_ci struct uvc_entity *entity; 184762306a36Sopenharmony_ci int ret = 0; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci /* Find the control. */ 185062306a36Sopenharmony_ci list_for_each_entry(entity, &chain->entities, chain) { 185162306a36Sopenharmony_ci ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback, 185262306a36Sopenharmony_ci &err_ctrl); 185362306a36Sopenharmony_ci if (ret < 0) 185462306a36Sopenharmony_ci goto done; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (!rollback) 185862306a36Sopenharmony_ci uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count); 185962306a36Sopenharmony_cidone: 186062306a36Sopenharmony_ci if (ret < 0 && ctrls) 186162306a36Sopenharmony_ci ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls, 186262306a36Sopenharmony_ci err_ctrl); 186362306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 186462306a36Sopenharmony_ci return ret; 186562306a36Sopenharmony_ci} 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ciint uvc_ctrl_get(struct uvc_video_chain *chain, 186862306a36Sopenharmony_ci struct v4l2_ext_control *xctrl) 186962306a36Sopenharmony_ci{ 187062306a36Sopenharmony_ci struct uvc_control *ctrl; 187162306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) 187462306a36Sopenharmony_ci return -EACCES; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci ctrl = uvc_find_control(chain, xctrl->id, &mapping); 187762306a36Sopenharmony_ci if (ctrl == NULL) 187862306a36Sopenharmony_ci return -EINVAL; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ciint uvc_ctrl_set(struct uvc_fh *handle, 188462306a36Sopenharmony_ci struct v4l2_ext_control *xctrl) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct uvc_video_chain *chain = handle->chain; 188762306a36Sopenharmony_ci struct uvc_control *ctrl; 188862306a36Sopenharmony_ci struct uvc_control_mapping *mapping; 188962306a36Sopenharmony_ci s32 value; 189062306a36Sopenharmony_ci u32 step; 189162306a36Sopenharmony_ci s32 min; 189262306a36Sopenharmony_ci s32 max; 189362306a36Sopenharmony_ci int ret; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0) 189662306a36Sopenharmony_ci return -EACCES; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci ctrl = uvc_find_control(chain, xctrl->id, &mapping); 189962306a36Sopenharmony_ci if (ctrl == NULL) 190062306a36Sopenharmony_ci return -EINVAL; 190162306a36Sopenharmony_ci if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) 190262306a36Sopenharmony_ci return -EACCES; 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci /* Clamp out of range values. */ 190562306a36Sopenharmony_ci switch (mapping->v4l2_type) { 190662306a36Sopenharmony_ci case V4L2_CTRL_TYPE_INTEGER: 190762306a36Sopenharmony_ci if (!ctrl->cached) { 190862306a36Sopenharmony_ci ret = uvc_ctrl_populate_cache(chain, ctrl); 190962306a36Sopenharmony_ci if (ret < 0) 191062306a36Sopenharmony_ci return ret; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci min = mapping->get(mapping, UVC_GET_MIN, 191462306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 191562306a36Sopenharmony_ci max = mapping->get(mapping, UVC_GET_MAX, 191662306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 191762306a36Sopenharmony_ci step = mapping->get(mapping, UVC_GET_RES, 191862306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 191962306a36Sopenharmony_ci if (step == 0) 192062306a36Sopenharmony_ci step = 1; 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci xctrl->value = min + DIV_ROUND_CLOSEST((u32)(xctrl->value - min), 192362306a36Sopenharmony_ci step) * step; 192462306a36Sopenharmony_ci if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) 192562306a36Sopenharmony_ci xctrl->value = clamp(xctrl->value, min, max); 192662306a36Sopenharmony_ci else 192762306a36Sopenharmony_ci xctrl->value = clamp_t(u32, xctrl->value, min, max); 192862306a36Sopenharmony_ci value = xctrl->value; 192962306a36Sopenharmony_ci break; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BITMASK: 193262306a36Sopenharmony_ci if (!ctrl->cached) { 193362306a36Sopenharmony_ci ret = uvc_ctrl_populate_cache(chain, ctrl); 193462306a36Sopenharmony_ci if (ret < 0) 193562306a36Sopenharmony_ci return ret; 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci xctrl->value &= uvc_get_ctrl_bitmap(ctrl, mapping); 193962306a36Sopenharmony_ci value = xctrl->value; 194062306a36Sopenharmony_ci break; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci case V4L2_CTRL_TYPE_BOOLEAN: 194362306a36Sopenharmony_ci xctrl->value = clamp(xctrl->value, 0, 1); 194462306a36Sopenharmony_ci value = xctrl->value; 194562306a36Sopenharmony_ci break; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci case V4L2_CTRL_TYPE_MENU: 194862306a36Sopenharmony_ci if (xctrl->value < (ffs(mapping->menu_mask) - 1) || 194962306a36Sopenharmony_ci xctrl->value > (fls(mapping->menu_mask) - 1)) 195062306a36Sopenharmony_ci return -ERANGE; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci if (!test_bit(xctrl->value, &mapping->menu_mask)) 195362306a36Sopenharmony_ci return -EINVAL; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci value = uvc_mapping_get_menu_value(mapping, xctrl->value); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* 195862306a36Sopenharmony_ci * Valid menu indices are reported by the GET_RES request for 195962306a36Sopenharmony_ci * UVC controls that support it. 196062306a36Sopenharmony_ci */ 196162306a36Sopenharmony_ci if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK) { 196262306a36Sopenharmony_ci if (!ctrl->cached) { 196362306a36Sopenharmony_ci ret = uvc_ctrl_populate_cache(chain, ctrl); 196462306a36Sopenharmony_ci if (ret < 0) 196562306a36Sopenharmony_ci return ret; 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (!(uvc_get_ctrl_bitmap(ctrl, mapping) & value)) 196962306a36Sopenharmony_ci return -EINVAL; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci break; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci default: 197562306a36Sopenharmony_ci value = xctrl->value; 197662306a36Sopenharmony_ci break; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci /* 198062306a36Sopenharmony_ci * If the mapping doesn't span the whole UVC control, the current value 198162306a36Sopenharmony_ci * needs to be loaded from the device to perform the read-modify-write 198262306a36Sopenharmony_ci * operation. 198362306a36Sopenharmony_ci */ 198462306a36Sopenharmony_ci if ((ctrl->info.size * 8) != mapping->size) { 198562306a36Sopenharmony_ci ret = __uvc_ctrl_load_cur(chain, ctrl); 198662306a36Sopenharmony_ci if (ret < 0) 198762306a36Sopenharmony_ci return ret; 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci /* Backup the current value in case we need to rollback later. */ 199162306a36Sopenharmony_ci if (!ctrl->dirty) { 199262306a36Sopenharmony_ci memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 199362306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 199462306a36Sopenharmony_ci ctrl->info.size); 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci mapping->set(mapping, value, 199862306a36Sopenharmony_ci uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) 200162306a36Sopenharmony_ci ctrl->handle = handle; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci ctrl->dirty = 1; 200462306a36Sopenharmony_ci ctrl->modified = 1; 200562306a36Sopenharmony_ci return 0; 200662306a36Sopenharmony_ci} 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 200962306a36Sopenharmony_ci * Dynamic controls 201062306a36Sopenharmony_ci */ 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci/* 201362306a36Sopenharmony_ci * Retrieve flags for a given control 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_cistatic int uvc_ctrl_get_flags(struct uvc_device *dev, 201662306a36Sopenharmony_ci const struct uvc_control *ctrl, 201762306a36Sopenharmony_ci struct uvc_control_info *info) 201862306a36Sopenharmony_ci{ 201962306a36Sopenharmony_ci u8 *data; 202062306a36Sopenharmony_ci int ret; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci data = kmalloc(1, GFP_KERNEL); 202362306a36Sopenharmony_ci if (data == NULL) 202462306a36Sopenharmony_ci return -ENOMEM; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (ctrl->entity->get_info) 202762306a36Sopenharmony_ci ret = ctrl->entity->get_info(dev, ctrl->entity, 202862306a36Sopenharmony_ci ctrl->info.selector, data); 202962306a36Sopenharmony_ci else 203062306a36Sopenharmony_ci ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, 203162306a36Sopenharmony_ci dev->intfnum, info->selector, data, 1); 203262306a36Sopenharmony_ci if (!ret) 203362306a36Sopenharmony_ci info->flags |= (data[0] & UVC_CONTROL_CAP_GET ? 203462306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_CUR : 0) 203562306a36Sopenharmony_ci | (data[0] & UVC_CONTROL_CAP_SET ? 203662306a36Sopenharmony_ci UVC_CTRL_FLAG_SET_CUR : 0) 203762306a36Sopenharmony_ci | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ? 203862306a36Sopenharmony_ci UVC_CTRL_FLAG_AUTO_UPDATE : 0) 203962306a36Sopenharmony_ci | (data[0] & UVC_CONTROL_CAP_ASYNCHRONOUS ? 204062306a36Sopenharmony_ci UVC_CTRL_FLAG_ASYNCHRONOUS : 0); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci kfree(data); 204362306a36Sopenharmony_ci return ret; 204462306a36Sopenharmony_ci} 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_cistatic void uvc_ctrl_fixup_xu_info(struct uvc_device *dev, 204762306a36Sopenharmony_ci const struct uvc_control *ctrl, struct uvc_control_info *info) 204862306a36Sopenharmony_ci{ 204962306a36Sopenharmony_ci struct uvc_ctrl_fixup { 205062306a36Sopenharmony_ci struct usb_device_id id; 205162306a36Sopenharmony_ci u8 entity; 205262306a36Sopenharmony_ci u8 selector; 205362306a36Sopenharmony_ci u8 flags; 205462306a36Sopenharmony_ci }; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci static const struct uvc_ctrl_fixup fixups[] = { 205762306a36Sopenharmony_ci { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1, 205862306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | 205962306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | 206062306a36Sopenharmony_ci UVC_CTRL_FLAG_AUTO_UPDATE }, 206162306a36Sopenharmony_ci { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1, 206262306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | 206362306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | 206462306a36Sopenharmony_ci UVC_CTRL_FLAG_AUTO_UPDATE }, 206562306a36Sopenharmony_ci { { USB_DEVICE(0x046d, 0x0994) }, 9, 1, 206662306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | 206762306a36Sopenharmony_ci UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR | 206862306a36Sopenharmony_ci UVC_CTRL_FLAG_AUTO_UPDATE }, 206962306a36Sopenharmony_ci }; 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci unsigned int i; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fixups); ++i) { 207462306a36Sopenharmony_ci if (!usb_match_one_id(dev->intf, &fixups[i].id)) 207562306a36Sopenharmony_ci continue; 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci if (fixups[i].entity == ctrl->entity->id && 207862306a36Sopenharmony_ci fixups[i].selector == info->selector) { 207962306a36Sopenharmony_ci info->flags = fixups[i].flags; 208062306a36Sopenharmony_ci return; 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci/* 208662306a36Sopenharmony_ci * Query control information (size and flags) for XU controls. 208762306a36Sopenharmony_ci */ 208862306a36Sopenharmony_cistatic int uvc_ctrl_fill_xu_info(struct uvc_device *dev, 208962306a36Sopenharmony_ci const struct uvc_control *ctrl, struct uvc_control_info *info) 209062306a36Sopenharmony_ci{ 209162306a36Sopenharmony_ci u8 *data; 209262306a36Sopenharmony_ci int ret; 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci data = kmalloc(2, GFP_KERNEL); 209562306a36Sopenharmony_ci if (data == NULL) 209662306a36Sopenharmony_ci return -ENOMEM; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci memcpy(info->entity, ctrl->entity->guid, sizeof(info->entity)); 209962306a36Sopenharmony_ci info->index = ctrl->index; 210062306a36Sopenharmony_ci info->selector = ctrl->index + 1; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* Query and verify the control length (GET_LEN) */ 210362306a36Sopenharmony_ci ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum, 210462306a36Sopenharmony_ci info->selector, data, 2); 210562306a36Sopenharmony_ci if (ret < 0) { 210662306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 210762306a36Sopenharmony_ci "GET_LEN failed on control %pUl/%u (%d)\n", 210862306a36Sopenharmony_ci info->entity, info->selector, ret); 210962306a36Sopenharmony_ci goto done; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci info->size = le16_to_cpup((__le16 *)data); 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX 211562306a36Sopenharmony_ci | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci ret = uvc_ctrl_get_flags(dev, ctrl, info); 211862306a36Sopenharmony_ci if (ret < 0) { 211962306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 212062306a36Sopenharmony_ci "Failed to get flags for control %pUl/%u (%d)\n", 212162306a36Sopenharmony_ci info->entity, info->selector, ret); 212262306a36Sopenharmony_ci goto done; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci uvc_ctrl_fixup_xu_info(dev, ctrl, info); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 212862306a36Sopenharmony_ci "XU control %pUl/%u queried: len %u, flags { get %u set %u auto %u }\n", 212962306a36Sopenharmony_ci info->entity, info->selector, info->size, 213062306a36Sopenharmony_ci (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0, 213162306a36Sopenharmony_ci (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0, 213262306a36Sopenharmony_ci (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0); 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_cidone: 213562306a36Sopenharmony_ci kfree(data); 213662306a36Sopenharmony_ci return ret; 213762306a36Sopenharmony_ci} 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_cistatic int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, 214062306a36Sopenharmony_ci const struct uvc_control_info *info); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_cistatic int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev, 214362306a36Sopenharmony_ci struct uvc_control *ctrl) 214462306a36Sopenharmony_ci{ 214562306a36Sopenharmony_ci struct uvc_control_info info; 214662306a36Sopenharmony_ci int ret; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci if (ctrl->initialized) 214962306a36Sopenharmony_ci return 0; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info); 215262306a36Sopenharmony_ci if (ret < 0) 215362306a36Sopenharmony_ci return ret; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci ret = uvc_ctrl_add_info(dev, ctrl, &info); 215662306a36Sopenharmony_ci if (ret < 0) 215762306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 215862306a36Sopenharmony_ci "Failed to initialize control %pUl/%u on device %s entity %u\n", 215962306a36Sopenharmony_ci info.entity, info.selector, dev->udev->devpath, 216062306a36Sopenharmony_ci ctrl->entity->id); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci return ret; 216362306a36Sopenharmony_ci} 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ciint uvc_xu_ctrl_query(struct uvc_video_chain *chain, 216662306a36Sopenharmony_ci struct uvc_xu_control_query *xqry) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci struct uvc_entity *entity; 216962306a36Sopenharmony_ci struct uvc_control *ctrl; 217062306a36Sopenharmony_ci unsigned int i; 217162306a36Sopenharmony_ci bool found; 217262306a36Sopenharmony_ci u32 reqflags; 217362306a36Sopenharmony_ci u16 size; 217462306a36Sopenharmony_ci u8 *data = NULL; 217562306a36Sopenharmony_ci int ret; 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci /* Find the extension unit. */ 217862306a36Sopenharmony_ci found = false; 217962306a36Sopenharmony_ci list_for_each_entry(entity, &chain->entities, chain) { 218062306a36Sopenharmony_ci if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT && 218162306a36Sopenharmony_ci entity->id == xqry->unit) { 218262306a36Sopenharmony_ci found = true; 218362306a36Sopenharmony_ci break; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (!found) { 218862306a36Sopenharmony_ci uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n", 218962306a36Sopenharmony_ci xqry->unit); 219062306a36Sopenharmony_ci return -ENOENT; 219162306a36Sopenharmony_ci } 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci /* Find the control and perform delayed initialization if needed. */ 219462306a36Sopenharmony_ci found = false; 219562306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 219662306a36Sopenharmony_ci ctrl = &entity->controls[i]; 219762306a36Sopenharmony_ci if (ctrl->index == xqry->selector - 1) { 219862306a36Sopenharmony_ci found = true; 219962306a36Sopenharmony_ci break; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci if (!found) { 220462306a36Sopenharmony_ci uvc_dbg(chain->dev, CONTROL, "Control %pUl/%u not found\n", 220562306a36Sopenharmony_ci entity->guid, xqry->selector); 220662306a36Sopenharmony_ci return -ENOENT; 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci if (mutex_lock_interruptible(&chain->ctrl_mutex)) 221062306a36Sopenharmony_ci return -ERESTARTSYS; 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl); 221362306a36Sopenharmony_ci if (ret < 0) { 221462306a36Sopenharmony_ci ret = -ENOENT; 221562306a36Sopenharmony_ci goto done; 221662306a36Sopenharmony_ci } 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci /* Validate the required buffer size and flags for the request */ 221962306a36Sopenharmony_ci reqflags = 0; 222062306a36Sopenharmony_ci size = ctrl->info.size; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci switch (xqry->query) { 222362306a36Sopenharmony_ci case UVC_GET_CUR: 222462306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_GET_CUR; 222562306a36Sopenharmony_ci break; 222662306a36Sopenharmony_ci case UVC_GET_MIN: 222762306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_GET_MIN; 222862306a36Sopenharmony_ci break; 222962306a36Sopenharmony_ci case UVC_GET_MAX: 223062306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_GET_MAX; 223162306a36Sopenharmony_ci break; 223262306a36Sopenharmony_ci case UVC_GET_DEF: 223362306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_GET_DEF; 223462306a36Sopenharmony_ci break; 223562306a36Sopenharmony_ci case UVC_GET_RES: 223662306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_GET_RES; 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci case UVC_SET_CUR: 223962306a36Sopenharmony_ci reqflags = UVC_CTRL_FLAG_SET_CUR; 224062306a36Sopenharmony_ci break; 224162306a36Sopenharmony_ci case UVC_GET_LEN: 224262306a36Sopenharmony_ci size = 2; 224362306a36Sopenharmony_ci break; 224462306a36Sopenharmony_ci case UVC_GET_INFO: 224562306a36Sopenharmony_ci size = 1; 224662306a36Sopenharmony_ci break; 224762306a36Sopenharmony_ci default: 224862306a36Sopenharmony_ci ret = -EINVAL; 224962306a36Sopenharmony_ci goto done; 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci if (size != xqry->size) { 225362306a36Sopenharmony_ci ret = -ENOBUFS; 225462306a36Sopenharmony_ci goto done; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci if (reqflags && !(ctrl->info.flags & reqflags)) { 225862306a36Sopenharmony_ci ret = -EBADRQC; 225962306a36Sopenharmony_ci goto done; 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci data = kmalloc(size, GFP_KERNEL); 226362306a36Sopenharmony_ci if (data == NULL) { 226462306a36Sopenharmony_ci ret = -ENOMEM; 226562306a36Sopenharmony_ci goto done; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci if (xqry->query == UVC_SET_CUR && 226962306a36Sopenharmony_ci copy_from_user(data, xqry->data, size)) { 227062306a36Sopenharmony_ci ret = -EFAULT; 227162306a36Sopenharmony_ci goto done; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit, 227562306a36Sopenharmony_ci chain->dev->intfnum, xqry->selector, data, size); 227662306a36Sopenharmony_ci if (ret < 0) 227762306a36Sopenharmony_ci goto done; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (xqry->query != UVC_SET_CUR && 228062306a36Sopenharmony_ci copy_to_user(xqry->data, data, size)) 228162306a36Sopenharmony_ci ret = -EFAULT; 228262306a36Sopenharmony_cidone: 228362306a36Sopenharmony_ci kfree(data); 228462306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 228562306a36Sopenharmony_ci return ret; 228662306a36Sopenharmony_ci} 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 228962306a36Sopenharmony_ci * Suspend/resume 229062306a36Sopenharmony_ci */ 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci/* 229362306a36Sopenharmony_ci * Restore control values after resume, skipping controls that haven't been 229462306a36Sopenharmony_ci * changed. 229562306a36Sopenharmony_ci * 229662306a36Sopenharmony_ci * TODO 229762306a36Sopenharmony_ci * - Don't restore modified controls that are back to their default value. 229862306a36Sopenharmony_ci * - Handle restore order (Auto-Exposure Mode should be restored before 229962306a36Sopenharmony_ci * Exposure Time). 230062306a36Sopenharmony_ci */ 230162306a36Sopenharmony_ciint uvc_ctrl_restore_values(struct uvc_device *dev) 230262306a36Sopenharmony_ci{ 230362306a36Sopenharmony_ci struct uvc_control *ctrl; 230462306a36Sopenharmony_ci struct uvc_entity *entity; 230562306a36Sopenharmony_ci unsigned int i; 230662306a36Sopenharmony_ci int ret; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci /* Walk the entities list and restore controls when possible. */ 230962306a36Sopenharmony_ci list_for_each_entry(entity, &dev->entities, list) { 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 231262306a36Sopenharmony_ci ctrl = &entity->controls[i]; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci if (!ctrl->initialized || !ctrl->modified || 231562306a36Sopenharmony_ci (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) 231662306a36Sopenharmony_ci continue; 231762306a36Sopenharmony_ci dev_dbg(&dev->udev->dev, 231862306a36Sopenharmony_ci "restoring control %pUl/%u/%u\n", 231962306a36Sopenharmony_ci ctrl->info.entity, ctrl->info.index, 232062306a36Sopenharmony_ci ctrl->info.selector); 232162306a36Sopenharmony_ci ctrl->dirty = 1; 232262306a36Sopenharmony_ci } 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL); 232562306a36Sopenharmony_ci if (ret < 0) 232662306a36Sopenharmony_ci return ret; 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci return 0; 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 233362306a36Sopenharmony_ci * Control and mapping handling 233462306a36Sopenharmony_ci */ 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci/* 233762306a36Sopenharmony_ci * Add control information to a given control. 233862306a36Sopenharmony_ci */ 233962306a36Sopenharmony_cistatic int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl, 234062306a36Sopenharmony_ci const struct uvc_control_info *info) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci ctrl->info = *info; 234362306a36Sopenharmony_ci INIT_LIST_HEAD(&ctrl->info.mappings); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci /* Allocate an array to save control values (cur, def, max, etc.) */ 234662306a36Sopenharmony_ci ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1, 234762306a36Sopenharmony_ci GFP_KERNEL); 234862306a36Sopenharmony_ci if (!ctrl->uvc_data) 234962306a36Sopenharmony_ci return -ENOMEM; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci ctrl->initialized = 1; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, "Added control %pUl/%u to device %s entity %u\n", 235462306a36Sopenharmony_ci ctrl->info.entity, ctrl->info.selector, dev->udev->devpath, 235562306a36Sopenharmony_ci ctrl->entity->id); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci return 0; 235862306a36Sopenharmony_ci} 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci/* 236162306a36Sopenharmony_ci * Add a control mapping to a given control. 236262306a36Sopenharmony_ci */ 236362306a36Sopenharmony_cistatic int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, 236462306a36Sopenharmony_ci struct uvc_control *ctrl, const struct uvc_control_mapping *mapping) 236562306a36Sopenharmony_ci{ 236662306a36Sopenharmony_ci struct uvc_control_mapping *map; 236762306a36Sopenharmony_ci unsigned int size; 236862306a36Sopenharmony_ci unsigned int i; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* 237162306a36Sopenharmony_ci * Most mappings come from static kernel data, and need to be duplicated. 237262306a36Sopenharmony_ci * Mappings that come from userspace will be unnecessarily duplicated, 237362306a36Sopenharmony_ci * this could be optimized. 237462306a36Sopenharmony_ci */ 237562306a36Sopenharmony_ci map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL); 237662306a36Sopenharmony_ci if (!map) 237762306a36Sopenharmony_ci return -ENOMEM; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci map->name = NULL; 238062306a36Sopenharmony_ci map->menu_names = NULL; 238162306a36Sopenharmony_ci map->menu_mapping = NULL; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci /* For UVCIOC_CTRL_MAP custom control */ 238462306a36Sopenharmony_ci if (mapping->name) { 238562306a36Sopenharmony_ci map->name = kstrdup(mapping->name, GFP_KERNEL); 238662306a36Sopenharmony_ci if (!map->name) 238762306a36Sopenharmony_ci goto err_nomem; 238862306a36Sopenharmony_ci } 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci INIT_LIST_HEAD(&map->ev_subs); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (mapping->menu_mapping && mapping->menu_mask) { 239362306a36Sopenharmony_ci size = sizeof(mapping->menu_mapping[0]) 239462306a36Sopenharmony_ci * fls(mapping->menu_mask); 239562306a36Sopenharmony_ci map->menu_mapping = kmemdup(mapping->menu_mapping, size, 239662306a36Sopenharmony_ci GFP_KERNEL); 239762306a36Sopenharmony_ci if (!map->menu_mapping) 239862306a36Sopenharmony_ci goto err_nomem; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci if (mapping->menu_names && mapping->menu_mask) { 240162306a36Sopenharmony_ci size = sizeof(mapping->menu_names[0]) 240262306a36Sopenharmony_ci * fls(mapping->menu_mask); 240362306a36Sopenharmony_ci map->menu_names = kmemdup(mapping->menu_names, size, 240462306a36Sopenharmony_ci GFP_KERNEL); 240562306a36Sopenharmony_ci if (!map->menu_names) 240662306a36Sopenharmony_ci goto err_nomem; 240762306a36Sopenharmony_ci } 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci if (map->get == NULL) 241062306a36Sopenharmony_ci map->get = uvc_get_le_value; 241162306a36Sopenharmony_ci if (map->set == NULL) 241262306a36Sopenharmony_ci map->set = uvc_set_le_value; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) { 241562306a36Sopenharmony_ci if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) == 241662306a36Sopenharmony_ci V4L2_CTRL_ID2WHICH(map->id)) { 241762306a36Sopenharmony_ci chain->ctrl_class_bitmap |= BIT(i); 241862306a36Sopenharmony_ci break; 241962306a36Sopenharmony_ci } 242062306a36Sopenharmony_ci } 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci list_add_tail(&map->list, &ctrl->info.mappings); 242362306a36Sopenharmony_ci uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n", 242462306a36Sopenharmony_ci uvc_map_get_name(map), ctrl->info.entity, 242562306a36Sopenharmony_ci ctrl->info.selector); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci return 0; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_cierr_nomem: 243062306a36Sopenharmony_ci kfree(map->menu_names); 243162306a36Sopenharmony_ci kfree(map->menu_mapping); 243262306a36Sopenharmony_ci kfree(map->name); 243362306a36Sopenharmony_ci kfree(map); 243462306a36Sopenharmony_ci return -ENOMEM; 243562306a36Sopenharmony_ci} 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ciint uvc_ctrl_add_mapping(struct uvc_video_chain *chain, 243862306a36Sopenharmony_ci const struct uvc_control_mapping *mapping) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci struct uvc_device *dev = chain->dev; 244162306a36Sopenharmony_ci struct uvc_control_mapping *map; 244262306a36Sopenharmony_ci struct uvc_entity *entity; 244362306a36Sopenharmony_ci struct uvc_control *ctrl; 244462306a36Sopenharmony_ci int found = 0; 244562306a36Sopenharmony_ci int ret; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci if (mapping->id & ~V4L2_CTRL_ID_MASK) { 244862306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 244962306a36Sopenharmony_ci "Can't add mapping '%s', control id 0x%08x is invalid\n", 245062306a36Sopenharmony_ci uvc_map_get_name(mapping), mapping->id); 245162306a36Sopenharmony_ci return -EINVAL; 245262306a36Sopenharmony_ci } 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci /* Search for the matching (GUID/CS) control on the current chain */ 245562306a36Sopenharmony_ci list_for_each_entry(entity, &chain->entities, chain) { 245662306a36Sopenharmony_ci unsigned int i; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT || 245962306a36Sopenharmony_ci !uvc_entity_match_guid(entity, mapping->entity)) 246062306a36Sopenharmony_ci continue; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 246362306a36Sopenharmony_ci ctrl = &entity->controls[i]; 246462306a36Sopenharmony_ci if (ctrl->index == mapping->selector - 1) { 246562306a36Sopenharmony_ci found = 1; 246662306a36Sopenharmony_ci break; 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci if (found) 247162306a36Sopenharmony_ci break; 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci if (!found) 247462306a36Sopenharmony_ci return -ENOENT; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci if (mutex_lock_interruptible(&chain->ctrl_mutex)) 247762306a36Sopenharmony_ci return -ERESTARTSYS; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci /* Perform delayed initialization of XU controls */ 248062306a36Sopenharmony_ci ret = uvc_ctrl_init_xu_ctrl(dev, ctrl); 248162306a36Sopenharmony_ci if (ret < 0) { 248262306a36Sopenharmony_ci ret = -ENOENT; 248362306a36Sopenharmony_ci goto done; 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci /* Validate the user-provided bit-size and offset */ 248762306a36Sopenharmony_ci if (mapping->size > 32 || 248862306a36Sopenharmony_ci mapping->offset + mapping->size > ctrl->info.size * 8) { 248962306a36Sopenharmony_ci ret = -EINVAL; 249062306a36Sopenharmony_ci goto done; 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci list_for_each_entry(map, &ctrl->info.mappings, list) { 249462306a36Sopenharmony_ci if (mapping->id == map->id) { 249562306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 249662306a36Sopenharmony_ci "Can't add mapping '%s', control id 0x%08x already exists\n", 249762306a36Sopenharmony_ci uvc_map_get_name(mapping), mapping->id); 249862306a36Sopenharmony_ci ret = -EEXIST; 249962306a36Sopenharmony_ci goto done; 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci } 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci /* Prevent excess memory consumption */ 250462306a36Sopenharmony_ci if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) { 250562306a36Sopenharmony_ci atomic_dec(&dev->nmappings); 250662306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 250762306a36Sopenharmony_ci "Can't add mapping '%s', maximum mappings count (%u) exceeded\n", 250862306a36Sopenharmony_ci uvc_map_get_name(mapping), UVC_MAX_CONTROL_MAPPINGS); 250962306a36Sopenharmony_ci ret = -ENOMEM; 251062306a36Sopenharmony_ci goto done; 251162306a36Sopenharmony_ci } 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci ret = __uvc_ctrl_add_mapping(chain, ctrl, mapping); 251462306a36Sopenharmony_ci if (ret < 0) 251562306a36Sopenharmony_ci atomic_dec(&dev->nmappings); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_cidone: 251862306a36Sopenharmony_ci mutex_unlock(&chain->ctrl_mutex); 251962306a36Sopenharmony_ci return ret; 252062306a36Sopenharmony_ci} 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci/* 252362306a36Sopenharmony_ci * Prune an entity of its bogus controls using a blacklist. Bogus controls 252462306a36Sopenharmony_ci * are currently the ones that crash the camera or unconditionally return an 252562306a36Sopenharmony_ci * error when queried. 252662306a36Sopenharmony_ci */ 252762306a36Sopenharmony_cistatic void uvc_ctrl_prune_entity(struct uvc_device *dev, 252862306a36Sopenharmony_ci struct uvc_entity *entity) 252962306a36Sopenharmony_ci{ 253062306a36Sopenharmony_ci struct uvc_ctrl_blacklist { 253162306a36Sopenharmony_ci struct usb_device_id id; 253262306a36Sopenharmony_ci u8 index; 253362306a36Sopenharmony_ci }; 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci static const struct uvc_ctrl_blacklist processing_blacklist[] = { 253662306a36Sopenharmony_ci { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */ 253762306a36Sopenharmony_ci { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */ 253862306a36Sopenharmony_ci { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */ 253962306a36Sopenharmony_ci }; 254062306a36Sopenharmony_ci static const struct uvc_ctrl_blacklist camera_blacklist[] = { 254162306a36Sopenharmony_ci { { USB_DEVICE(0x06f8, 0x3005) }, 9 }, /* Zoom, Absolute */ 254262306a36Sopenharmony_ci }; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci const struct uvc_ctrl_blacklist *blacklist; 254562306a36Sopenharmony_ci unsigned int size; 254662306a36Sopenharmony_ci unsigned int count; 254762306a36Sopenharmony_ci unsigned int i; 254862306a36Sopenharmony_ci u8 *controls; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci switch (UVC_ENTITY_TYPE(entity)) { 255162306a36Sopenharmony_ci case UVC_VC_PROCESSING_UNIT: 255262306a36Sopenharmony_ci blacklist = processing_blacklist; 255362306a36Sopenharmony_ci count = ARRAY_SIZE(processing_blacklist); 255462306a36Sopenharmony_ci controls = entity->processing.bmControls; 255562306a36Sopenharmony_ci size = entity->processing.bControlSize; 255662306a36Sopenharmony_ci break; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci case UVC_ITT_CAMERA: 255962306a36Sopenharmony_ci blacklist = camera_blacklist; 256062306a36Sopenharmony_ci count = ARRAY_SIZE(camera_blacklist); 256162306a36Sopenharmony_ci controls = entity->camera.bmControls; 256262306a36Sopenharmony_ci size = entity->camera.bControlSize; 256362306a36Sopenharmony_ci break; 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci default: 256662306a36Sopenharmony_ci return; 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 257062306a36Sopenharmony_ci if (!usb_match_one_id(dev->intf, &blacklist[i].id)) 257162306a36Sopenharmony_ci continue; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (blacklist[i].index >= 8 * size || 257462306a36Sopenharmony_ci !uvc_test_bit(controls, blacklist[i].index)) 257562306a36Sopenharmony_ci continue; 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci uvc_dbg(dev, CONTROL, 257862306a36Sopenharmony_ci "%u/%u control is black listed, removing it\n", 257962306a36Sopenharmony_ci entity->id, blacklist[i].index); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci uvc_clear_bit(controls, blacklist[i].index); 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci} 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci/* 258662306a36Sopenharmony_ci * Add control information and hardcoded stock control mappings to the given 258762306a36Sopenharmony_ci * device. 258862306a36Sopenharmony_ci */ 258962306a36Sopenharmony_cistatic void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, 259062306a36Sopenharmony_ci struct uvc_control *ctrl) 259162306a36Sopenharmony_ci{ 259262306a36Sopenharmony_ci const struct uvc_control_mapping **mappings; 259362306a36Sopenharmony_ci unsigned int i; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci /* 259662306a36Sopenharmony_ci * XU controls initialization requires querying the device for control 259762306a36Sopenharmony_ci * information. As some buggy UVC devices will crash when queried 259862306a36Sopenharmony_ci * repeatedly in a tight loop, delay XU controls initialization until 259962306a36Sopenharmony_ci * first use. 260062306a36Sopenharmony_ci */ 260162306a36Sopenharmony_ci if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) 260262306a36Sopenharmony_ci return; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { 260562306a36Sopenharmony_ci const struct uvc_control_info *info = &uvc_ctrls[i]; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci if (uvc_entity_match_guid(ctrl->entity, info->entity) && 260862306a36Sopenharmony_ci ctrl->index == info->index) { 260962306a36Sopenharmony_ci uvc_ctrl_add_info(chain->dev, ctrl, info); 261062306a36Sopenharmony_ci /* 261162306a36Sopenharmony_ci * Retrieve control flags from the device. Ignore errors 261262306a36Sopenharmony_ci * and work with default flag values from the uvc_ctrl 261362306a36Sopenharmony_ci * array when the device doesn't properly implement 261462306a36Sopenharmony_ci * GET_INFO on standard controls. 261562306a36Sopenharmony_ci */ 261662306a36Sopenharmony_ci uvc_ctrl_get_flags(chain->dev, ctrl, &ctrl->info); 261762306a36Sopenharmony_ci break; 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci if (!ctrl->initialized) 262262306a36Sopenharmony_ci return; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci /* 262562306a36Sopenharmony_ci * First check if the device provides a custom mapping for this control, 262662306a36Sopenharmony_ci * used to override standard mappings for non-conformant devices. Don't 262762306a36Sopenharmony_ci * process standard mappings if a custom mapping is found. This 262862306a36Sopenharmony_ci * mechanism doesn't support combining standard and custom mappings for 262962306a36Sopenharmony_ci * a single control. 263062306a36Sopenharmony_ci */ 263162306a36Sopenharmony_ci if (chain->dev->info->mappings) { 263262306a36Sopenharmony_ci bool custom = false; 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci for (i = 0; chain->dev->info->mappings[i]; ++i) { 263562306a36Sopenharmony_ci const struct uvc_control_mapping *mapping = 263662306a36Sopenharmony_ci chain->dev->info->mappings[i]; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && 263962306a36Sopenharmony_ci ctrl->info.selector == mapping->selector) { 264062306a36Sopenharmony_ci __uvc_ctrl_add_mapping(chain, ctrl, mapping); 264162306a36Sopenharmony_ci custom = true; 264262306a36Sopenharmony_ci } 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci 264562306a36Sopenharmony_ci if (custom) 264662306a36Sopenharmony_ci return; 264762306a36Sopenharmony_ci } 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci /* Process common mappings next. */ 265062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) { 265162306a36Sopenharmony_ci const struct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i]; 265262306a36Sopenharmony_ci 265362306a36Sopenharmony_ci if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && 265462306a36Sopenharmony_ci ctrl->info.selector == mapping->selector) 265562306a36Sopenharmony_ci __uvc_ctrl_add_mapping(chain, ctrl, mapping); 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci /* Finally process version-specific mappings. */ 265962306a36Sopenharmony_ci mappings = chain->dev->uvc_version < 0x0150 266062306a36Sopenharmony_ci ? uvc_ctrl_mappings_uvc11 : uvc_ctrl_mappings_uvc15; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci for (i = 0; mappings[i]; ++i) { 266362306a36Sopenharmony_ci const struct uvc_control_mapping *mapping = mappings[i]; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && 266662306a36Sopenharmony_ci ctrl->info.selector == mapping->selector) 266762306a36Sopenharmony_ci __uvc_ctrl_add_mapping(chain, ctrl, mapping); 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci} 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci/* 267262306a36Sopenharmony_ci * Initialize device controls. 267362306a36Sopenharmony_ci */ 267462306a36Sopenharmony_cistatic int uvc_ctrl_init_chain(struct uvc_video_chain *chain) 267562306a36Sopenharmony_ci{ 267662306a36Sopenharmony_ci struct uvc_entity *entity; 267762306a36Sopenharmony_ci unsigned int i; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci /* Walk the entities list and instantiate controls */ 268062306a36Sopenharmony_ci list_for_each_entry(entity, &chain->entities, chain) { 268162306a36Sopenharmony_ci struct uvc_control *ctrl; 268262306a36Sopenharmony_ci unsigned int bControlSize = 0, ncontrols; 268362306a36Sopenharmony_ci u8 *bmControls = NULL; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { 268662306a36Sopenharmony_ci bmControls = entity->extension.bmControls; 268762306a36Sopenharmony_ci bControlSize = entity->extension.bControlSize; 268862306a36Sopenharmony_ci } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) { 268962306a36Sopenharmony_ci bmControls = entity->processing.bmControls; 269062306a36Sopenharmony_ci bControlSize = entity->processing.bControlSize; 269162306a36Sopenharmony_ci } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) { 269262306a36Sopenharmony_ci bmControls = entity->camera.bmControls; 269362306a36Sopenharmony_ci bControlSize = entity->camera.bControlSize; 269462306a36Sopenharmony_ci } else if (UVC_ENTITY_TYPE(entity) == UVC_EXT_GPIO_UNIT) { 269562306a36Sopenharmony_ci bmControls = entity->gpio.bmControls; 269662306a36Sopenharmony_ci bControlSize = entity->gpio.bControlSize; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci /* Remove bogus/blacklisted controls */ 270062306a36Sopenharmony_ci uvc_ctrl_prune_entity(chain->dev, entity); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci /* Count supported controls and allocate the controls array */ 270362306a36Sopenharmony_ci ncontrols = memweight(bmControls, bControlSize); 270462306a36Sopenharmony_ci if (ncontrols == 0) 270562306a36Sopenharmony_ci continue; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci entity->controls = kcalloc(ncontrols, sizeof(*ctrl), 270862306a36Sopenharmony_ci GFP_KERNEL); 270962306a36Sopenharmony_ci if (entity->controls == NULL) 271062306a36Sopenharmony_ci return -ENOMEM; 271162306a36Sopenharmony_ci entity->ncontrols = ncontrols; 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci /* Initialize all supported controls */ 271462306a36Sopenharmony_ci ctrl = entity->controls; 271562306a36Sopenharmony_ci for (i = 0; i < bControlSize * 8; ++i) { 271662306a36Sopenharmony_ci if (uvc_test_bit(bmControls, i) == 0) 271762306a36Sopenharmony_ci continue; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci ctrl->entity = entity; 272062306a36Sopenharmony_ci ctrl->index = i; 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci uvc_ctrl_init_ctrl(chain, ctrl); 272362306a36Sopenharmony_ci ctrl++; 272462306a36Sopenharmony_ci } 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci return 0; 272862306a36Sopenharmony_ci} 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ciint uvc_ctrl_init_device(struct uvc_device *dev) 273162306a36Sopenharmony_ci{ 273262306a36Sopenharmony_ci struct uvc_video_chain *chain; 273362306a36Sopenharmony_ci int ret; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci INIT_WORK(&dev->async_ctrl.work, uvc_ctrl_status_event_work); 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci list_for_each_entry(chain, &dev->chains, list) { 273862306a36Sopenharmony_ci ret = uvc_ctrl_init_chain(chain); 273962306a36Sopenharmony_ci if (ret) 274062306a36Sopenharmony_ci return ret; 274162306a36Sopenharmony_ci } 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci return 0; 274462306a36Sopenharmony_ci} 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci/* 274762306a36Sopenharmony_ci * Cleanup device controls. 274862306a36Sopenharmony_ci */ 274962306a36Sopenharmony_cistatic void uvc_ctrl_cleanup_mappings(struct uvc_device *dev, 275062306a36Sopenharmony_ci struct uvc_control *ctrl) 275162306a36Sopenharmony_ci{ 275262306a36Sopenharmony_ci struct uvc_control_mapping *mapping, *nm; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) { 275562306a36Sopenharmony_ci list_del(&mapping->list); 275662306a36Sopenharmony_ci kfree(mapping->menu_names); 275762306a36Sopenharmony_ci kfree(mapping->menu_mapping); 275862306a36Sopenharmony_ci kfree(mapping->name); 275962306a36Sopenharmony_ci kfree(mapping); 276062306a36Sopenharmony_ci } 276162306a36Sopenharmony_ci} 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_civoid uvc_ctrl_cleanup_device(struct uvc_device *dev) 276462306a36Sopenharmony_ci{ 276562306a36Sopenharmony_ci struct uvc_entity *entity; 276662306a36Sopenharmony_ci unsigned int i; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci /* Can be uninitialized if we are aborting on probe error. */ 276962306a36Sopenharmony_ci if (dev->async_ctrl.work.func) 277062306a36Sopenharmony_ci cancel_work_sync(&dev->async_ctrl.work); 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci /* Free controls and control mappings for all entities. */ 277362306a36Sopenharmony_ci list_for_each_entry(entity, &dev->entities, list) { 277462306a36Sopenharmony_ci for (i = 0; i < entity->ncontrols; ++i) { 277562306a36Sopenharmony_ci struct uvc_control *ctrl = &entity->controls[i]; 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (!ctrl->initialized) 277862306a36Sopenharmony_ci continue; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci uvc_ctrl_cleanup_mappings(dev, ctrl); 278162306a36Sopenharmony_ci kfree(ctrl->uvc_data); 278262306a36Sopenharmony_ci } 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci kfree(entity->controls); 278562306a36Sopenharmony_ci } 278662306a36Sopenharmony_ci} 2787