Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23d9f3ef authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent ca9afe6f
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -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)
{
	struct uvc_control *ctrl = NULL;
@@ -944,6 +944,52 @@ done:
	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
+1 −35
Original line number Diff line number Diff line
@@ -100,40 +100,6 @@ done:
 * 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
 * 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:
		return uvc_v4l2_query_menu(chain, arg);
		return uvc_query_v4l2_menu(chain, arg);

	case VIDIOC_G_EXT_CTRLS:
	{
+2 −2
Original line number Diff line number Diff line
@@ -606,10 +606,10 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);

/* 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,
		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,
		const struct uvc_control_mapping *mapping);