media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS
Create all the class controls for the device defined controls. Fixes v4l2-compliance: Control ioctls (Input 0): fail: v4l2-test-controls.cpp(216): missing control class for class 00980000 fail: v4l2-test-controls.cpp(216): missing control tclass for class 009a0000 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Родитель
866c6bdd56
Коммит
9b31ea808a
|
@ -357,6 +357,11 @@ static const struct uvc_control_info uvc_ctrls[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const u32 uvc_control_classes[] = {
|
||||
V4L2_CID_CAMERA_CLASS,
|
||||
V4L2_CID_USER_CLASS,
|
||||
};
|
||||
|
||||
static const struct uvc_menu_info power_line_frequency_controls[] = {
|
||||
{ 0, "Disabled" },
|
||||
{ 1, "50 Hz" },
|
||||
|
@ -1024,6 +1029,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
|
||||
u32 found_id)
|
||||
{
|
||||
bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
|
||||
unsigned int i;
|
||||
|
||||
req_id &= V4L2_CTRL_ID_MASK;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
|
||||
if (!(chain->ctrl_class_bitmap & BIT(i)))
|
||||
continue;
|
||||
if (!find_next) {
|
||||
if (uvc_control_classes[i] == req_id)
|
||||
return i;
|
||||
continue;
|
||||
}
|
||||
if (uvc_control_classes[i] > req_id &&
|
||||
uvc_control_classes[i] < found_id)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int uvc_query_v4l2_class(struct uvc_video_chain *chain, u32 req_id,
|
||||
u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = __uvc_query_v4l2_class(chain, req_id, found_id);
|
||||
if (idx < 0)
|
||||
return -ENODEV;
|
||||
|
||||
memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
|
||||
v4l2_ctrl->id = uvc_control_classes[idx];
|
||||
strscpy(v4l2_ctrl->name, v4l2_ctrl_get_name(v4l2_ctrl->id),
|
||||
sizeof(v4l2_ctrl->name));
|
||||
v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
|
||||
v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
|
||||
| V4L2_CTRL_FLAG_READ_ONLY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
|
||||
struct uvc_control *ctrl,
|
||||
struct uvc_control_mapping *mapping,
|
||||
|
@ -1127,12 +1175,31 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
|
|||
if (ret < 0)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* Check if the ctrl is a know class */
|
||||
if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
|
||||
ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, 0, v4l2_ctrl);
|
||||
if (!ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
|
||||
if (ctrl == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if
|
||||
* a class should be inserted between the previous control and the one
|
||||
* we have just found.
|
||||
*/
|
||||
if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
|
||||
ret = uvc_query_v4l2_class(chain, v4l2_ctrl->id, mapping->id,
|
||||
v4l2_ctrl);
|
||||
if (!ret)
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
|
||||
done:
|
||||
mutex_unlock(&chain->ctrl_mutex);
|
||||
|
@ -1426,6 +1493,11 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
|
|||
if (ret < 0)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
|
||||
if (ctrl == NULL) {
|
||||
ret = -EINVAL;
|
||||
|
@ -1459,7 +1531,10 @@ static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
|
|||
struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
|
||||
|
||||
mutex_lock(&handle->chain->ctrl_mutex);
|
||||
if (__uvc_query_v4l2_class(handle->chain, sev->id, 0) >= 0)
|
||||
goto done;
|
||||
list_del(&sev->node);
|
||||
done:
|
||||
mutex_unlock(&handle->chain->ctrl_mutex);
|
||||
}
|
||||
|
||||
|
@ -1577,6 +1652,9 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
|
|||
struct uvc_control *ctrl;
|
||||
struct uvc_control_mapping *mapping;
|
||||
|
||||
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
|
||||
return -EACCES;
|
||||
|
||||
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
|
||||
if (ctrl == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -1596,6 +1674,9 @@ int uvc_ctrl_set(struct uvc_fh *handle,
|
|||
s32 max;
|
||||
int ret;
|
||||
|
||||
if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
|
||||
return -EACCES;
|
||||
|
||||
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
|
||||
if (ctrl == NULL)
|
||||
return -EINVAL;
|
||||
|
@ -2062,6 +2143,7 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
|
|||
{
|
||||
struct uvc_control_mapping *map;
|
||||
unsigned int size;
|
||||
unsigned int i;
|
||||
|
||||
/* Most mappings come from static kernel data and need to be duplicated.
|
||||
* Mappings that come from userspace will be unnecessarily duplicated,
|
||||
|
@ -2085,6 +2167,14 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
|
|||
if (map->set == NULL)
|
||||
map->set = uvc_set_le_value;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uvc_control_classes); i++) {
|
||||
if (V4L2_CTRL_ID2WHICH(uvc_control_classes[i]) ==
|
||||
V4L2_CTRL_ID2WHICH(map->id)) {
|
||||
chain->ctrl_class_bitmap |= BIT(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&map->list, &ctrl->info.mappings);
|
||||
uvc_dbg(chain->dev, CONTROL, "Adding mapping '%s' to control %pUl/%u\n",
|
||||
map->name, ctrl->info.entity, ctrl->info.selector);
|
||||
|
|
|
@ -476,6 +476,7 @@ struct uvc_video_chain {
|
|||
|
||||
struct v4l2_prio_state prio; /* V4L2 priority state */
|
||||
u32 caps; /* V4L2 chain-wide caps */
|
||||
u8 ctrl_class_bitmap; /* Bitmap of valid classes */
|
||||
};
|
||||
|
||||
struct uvc_stats_frame {
|
||||
|
|
Загрузка…
Ссылка в новой задаче