aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c47
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c2
2 files changed, 45 insertions, 4 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 5ff501390842..f38bc6bbc3d2 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1021,19 +1021,57 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1021{ 1021{
1022 struct uvc_control *ctrl; 1022 struct uvc_control *ctrl;
1023 struct uvc_control_mapping *mapping; 1023 struct uvc_control_mapping *mapping;
1024 s32 value = xctrl->value; 1024 s32 value;
1025 u32 step;
1026 s32 min;
1027 s32 max;
1025 int ret; 1028 int ret;
1026 1029
1027 ctrl = uvc_find_control(chain, xctrl->id, &mapping); 1030 ctrl = uvc_find_control(chain, xctrl->id, &mapping);
1028 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) 1031 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
1029 return -EINVAL; 1032 return -EINVAL;
1030 1033
1031 if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { 1034 /* Clamp out of range values. */
1032 if (value < 0 || value >= mapping->menu_count) 1035 switch (mapping->v4l2_type) {
1036 case V4L2_CTRL_TYPE_INTEGER:
1037 if (!ctrl->cached) {
1038 ret = uvc_ctrl_populate_cache(chain, ctrl);
1039 if (ret < 0)
1040 return ret;
1041 }
1042
1043 min = mapping->get(mapping, UVC_GET_MIN,
1044 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
1045 max = mapping->get(mapping, UVC_GET_MAX,
1046 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
1047 step = mapping->get(mapping, UVC_GET_RES,
1048 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
1049
1050 xctrl->value = min + (xctrl->value - min + step/2) / step * step;
1051 xctrl->value = clamp(xctrl->value, min, max);
1052 value = xctrl->value;
1053 break;
1054
1055 case V4L2_CTRL_TYPE_BOOLEAN:
1056 xctrl->value = clamp(xctrl->value, 0, 1);
1057 value = xctrl->value;
1058 break;
1059
1060 case V4L2_CTRL_TYPE_MENU:
1061 if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
1033 return -ERANGE; 1062 return -ERANGE;
1034 value = mapping->menu_info[value].value; 1063 value = mapping->menu_info[xctrl->value].value;
1064 break;
1065
1066 default:
1067 value = xctrl->value;
1068 break;
1035 } 1069 }
1036 1070
1071 /* If the mapping doesn't span the whole UVC control, the current value
1072 * needs to be loaded from the device to perform the read-modify-write
1073 * operation.
1074 */
1037 if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) { 1075 if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
1038 if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) { 1076 if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
1039 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1077 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@@ -1051,6 +1089,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1051 ctrl->loaded = 1; 1089 ctrl->loaded = 1;
1052 } 1090 }
1053 1091
1092 /* Backup the current value in case we need to rollback later. */
1054 if (!ctrl->dirty) { 1093 if (!ctrl->dirty) {
1055 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1094 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1056 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1095 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 23239a4adefe..bf1fc7f29ca7 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -549,6 +549,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
549 return ret; 549 return ret;
550 } 550 }
551 ret = uvc_ctrl_commit(chain); 551 ret = uvc_ctrl_commit(chain);
552 if (ret == 0)
553 ctrl->value = xctrl.value;
552 break; 554 break;
553 } 555 }
554 556