[media] uvcvideo: Lock controls mutex when querying menus
uvc_find_control() must be called with the controls mutex locked. Fix uvc_query_v4l2_menu() accordingly. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
ca9afe6f87
commit
23d9f3ef23
@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
|
static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
|
||||||
__u32 v4l2_id, struct uvc_control_mapping **mapping)
|
__u32 v4l2_id, struct uvc_control_mapping **mapping)
|
||||||
{
|
{
|
||||||
struct uvc_control *ctrl = NULL;
|
struct uvc_control *ctrl = NULL;
|
||||||
@ -944,6 +944,52 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping V4L2 controls to UVC controls can be straighforward if done well.
|
||||||
|
* Most of the UVC controls exist in V4L2, and can be mapped directly. Some
|
||||||
|
* must be grouped (for instance the Red Balance, Blue Balance and Do White
|
||||||
|
* Balance V4L2 controls use the White Balance Component UVC control) or
|
||||||
|
* otherwise translated. The approach we take here is to use a translation
|
||||||
|
* table for the controls that can be mapped directly, and handle the others
|
||||||
|
* manually.
|
||||||
|
*/
|
||||||
|
int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
|
||||||
|
struct v4l2_querymenu *query_menu)
|
||||||
|
{
|
||||||
|
struct uvc_menu_info *menu_info;
|
||||||
|
struct uvc_control_mapping *mapping;
|
||||||
|
struct uvc_control *ctrl;
|
||||||
|
u32 index = query_menu->index;
|
||||||
|
u32 id = query_menu->id;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(query_menu, 0, sizeof(*query_menu));
|
||||||
|
query_menu->id = id;
|
||||||
|
query_menu->index = index;
|
||||||
|
|
||||||
|
ret = mutex_lock_interruptible(&chain->ctrl_mutex);
|
||||||
|
if (ret < 0)
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
|
ctrl = uvc_find_control(chain, query_menu->id, &mapping);
|
||||||
|
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query_menu->index >= mapping->menu_count) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_info = &mapping->menu_info[query_menu->index];
|
||||||
|
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
|
||||||
|
|
||||||
|
done:
|
||||||
|
mutex_unlock(&chain->ctrl_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
* Control transactions
|
* Control transactions
|
||||||
|
@ -100,40 +100,6 @@ done:
|
|||||||
* V4L2 interface
|
* V4L2 interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Mapping V4L2 controls to UVC controls can be straighforward if done well.
|
|
||||||
* Most of the UVC controls exist in V4L2, and can be mapped directly. Some
|
|
||||||
* must be grouped (for instance the Red Balance, Blue Balance and Do White
|
|
||||||
* Balance V4L2 controls use the White Balance Component UVC control) or
|
|
||||||
* otherwise translated. The approach we take here is to use a translation
|
|
||||||
* table for the controls that can be mapped directly, and handle the others
|
|
||||||
* manually.
|
|
||||||
*/
|
|
||||||
static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
|
|
||||||
struct v4l2_querymenu *query_menu)
|
|
||||||
{
|
|
||||||
struct uvc_menu_info *menu_info;
|
|
||||||
struct uvc_control_mapping *mapping;
|
|
||||||
struct uvc_control *ctrl;
|
|
||||||
u32 index = query_menu->index;
|
|
||||||
u32 id = query_menu->id;
|
|
||||||
|
|
||||||
ctrl = uvc_find_control(chain, query_menu->id, &mapping);
|
|
||||||
if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (query_menu->index >= mapping->menu_count)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(query_menu, 0, sizeof(*query_menu));
|
|
||||||
query_menu->id = id;
|
|
||||||
query_menu->index = index;
|
|
||||||
|
|
||||||
menu_info = &mapping->menu_info[query_menu->index];
|
|
||||||
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the frame interval closest to the requested frame interval for the
|
* Find the frame interval closest to the requested frame interval for the
|
||||||
* given frame format and size. This should be done by the device as part of
|
* given frame format and size. This should be done by the device as part of
|
||||||
@ -624,7 +590,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case VIDIOC_QUERYMENU:
|
case VIDIOC_QUERYMENU:
|
||||||
return uvc_v4l2_query_menu(chain, arg);
|
return uvc_query_v4l2_menu(chain, arg);
|
||||||
|
|
||||||
case VIDIOC_G_EXT_CTRLS:
|
case VIDIOC_G_EXT_CTRLS:
|
||||||
{
|
{
|
||||||
|
@ -606,10 +606,10 @@ extern int uvc_status_suspend(struct uvc_device *dev);
|
|||||||
extern int uvc_status_resume(struct uvc_device *dev);
|
extern int uvc_status_resume(struct uvc_device *dev);
|
||||||
|
|
||||||
/* Controls */
|
/* Controls */
|
||||||
extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
|
|
||||||
__u32 v4l2_id, struct uvc_control_mapping **mapping);
|
|
||||||
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
|
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
|
||||||
struct v4l2_queryctrl *v4l2_ctrl);
|
struct v4l2_queryctrl *v4l2_ctrl);
|
||||||
|
extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
|
||||||
|
struct v4l2_querymenu *query_menu);
|
||||||
|
|
||||||
extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
|
extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
|
||||||
const struct uvc_control_mapping *mapping);
|
const struct uvc_control_mapping *mapping);
|
||||||
|
Loading…
Reference in New Issue
Block a user