summaryrefslogtreecommitdiff
path: root/drivers/media/usb/uvc/uvc_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/uvc/uvc_ctrl.c')
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c79
1 files changed, 64 insertions, 15 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 2905505c240c..f0f6f8454d9c 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -483,6 +483,7 @@ static int uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping, u8 query,
return 0;
case UVC_GET_MIN:
+ /* Not used, we use -UVC_GET_MAX */
case UVC_GET_MAX:
case UVC_GET_RES:
case UVC_GET_DEF:
@@ -526,8 +527,7 @@ static int uvc_ctrl_get_rel_speed(struct uvc_control_mapping *mapping,
*out = (sign == 0) ? 0 : (sign > 0 ? value : -value);
return 0;
case UVC_GET_MIN:
- *out = -value;
- return 0;
+ /* Not used, we use -UVC_GET_MAX */
case UVC_GET_MAX:
case UVC_GET_RES:
case UVC_GET_DEF:
@@ -1432,7 +1432,7 @@ static bool uvc_ctrl_is_readable(u32 which, struct uvc_control *ctrl,
* auto_exposure=1, exposure_time_absolute=251.
*/
int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
- const struct v4l2_ext_controls *ctrls,
+ const struct v4l2_ext_controls *ctrls, u32 which,
unsigned long ioctl)
{
struct uvc_control_mapping *master_map = NULL;
@@ -1442,14 +1442,24 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
s32 val;
int ret;
int i;
+ /*
+ * There is no need to check the ioctl, all the ioctls except
+ * VIDIOC_G_EXT_CTRLS use which=V4L2_CTRL_WHICH_CUR_VAL.
+ */
+ bool is_which_min_max = which == V4L2_CTRL_WHICH_MIN_VAL ||
+ which == V4L2_CTRL_WHICH_MAX_VAL;
if (__uvc_query_v4l2_class(chain, v4l2_id, 0) >= 0)
- return -EACCES;
+ return is_which_min_max ? -EINVAL : -EACCES;
ctrl = uvc_find_control(chain, v4l2_id, &mapping);
if (!ctrl)
return -EINVAL;
+ if ((!(ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) ||
+ !(ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)) && is_which_min_max)
+ return -EINVAL;
+
if (ioctl == VIDIOC_G_EXT_CTRLS)
return uvc_ctrl_is_readable(ctrls->which, ctrl, mapping);
@@ -1517,6 +1527,17 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
return ~0;
}
+static bool uvc_ctrl_is_relative_ptz(__u32 ctrl_id)
+{
+ switch (ctrl_id) {
+ case V4L2_CID_ZOOM_CONTINUOUS:
+ case V4L2_CID_PAN_SPEED:
+ case V4L2_CID_TILT_SPEED:
+ return true;
+ }
+ return false;
+}
+
/*
* Maximum retry count to avoid spurious errors with controls. Increasing this
* value does no seem to produce better results in the tested hardware.
@@ -1576,18 +1597,32 @@ static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
break;
}
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
- v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- else
- v4l2_ctrl->minimum = 0;
-
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
v4l2_ctrl->maximum = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
else
v4l2_ctrl->maximum = 0;
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
+ /*
+ * For relative PTZ controls, UVC_GET_MIN for
+ * b(Pan|Tilt|Zoom)Speed returns the minimum speed of the
+ * movement in direction specified in the sign field.
+ * See in USB Device Class Definition for Video Devices:
+ * 4.2.2.1.13 Zoom (Relative) Control
+ * 4.2.2.1.15 PanTilt (Relative) Control
+ *
+ * For minimum value, use maximum speed but in negative direction.
+ */
+ if (uvc_ctrl_is_relative_ptz(v4l2_ctrl->id))
+ v4l2_ctrl->minimum = -v4l2_ctrl->maximum;
+ else
+ v4l2_ctrl->minimum = uvc_mapping_get_s32(mapping,
+ UVC_GET_MIN, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+ } else {
+ v4l2_ctrl->minimum = 0;
+ }
+
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
v4l2_ctrl->step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
@@ -2449,6 +2484,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, u32 which,
static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
+ u32 v4l2_id,
struct uvc_control_mapping *mapping,
s32 *value_in_out)
{
@@ -2466,10 +2502,24 @@ static int uvc_ctrl_clamp(struct uvc_video_chain *chain,
return ret;
}
- min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
max = uvc_mapping_get_s32(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+ /*
+ * For relative PTZ controls, UVC_GET_MIN for
+ * b(Pan|Tilt|Zoom)Speed returns the minimum speed of the
+ * movement in direction specified in the sign field.
+ * See in USB Device Class Definition for Video Devices:
+ * 4.2.2.1.13 Zoom (Relative) Control
+ * 4.2.2.1.15 PanTilt (Relative) Control
+ *
+ * For minimum value, use maximum speed but in negative direction.
+ */
+ if (uvc_ctrl_is_relative_ptz(v4l2_id))
+ min = -max;
+ else
+ min = uvc_mapping_get_s32(mapping, UVC_GET_MIN,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
+
step = uvc_mapping_get_s32(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (step == 0)
@@ -2583,7 +2633,7 @@ int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl)
if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
return -EACCES;
- ret = uvc_ctrl_clamp(chain, ctrl, mapping, &xctrl->value);
+ ret = uvc_ctrl_clamp(chain, ctrl, xctrl->id, mapping, &xctrl->value);
if (ret)
return ret;
/*
@@ -2929,8 +2979,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
if (!ctrl->initialized || !ctrl->modified ||
(ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
continue;
- dev_dbg(&dev->intf->dev,
- "restoring control %pUl/%u/%u\n",
+ uvc_dbg(dev, CONTROL, "restoring control %pUl/%u/%u\n",
ctrl->info.entity, ctrl->info.index,
ctrl->info.selector);
ctrl->dirty = 1;