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

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

V4L/DVB: uvcvideo: Cache control min, max, res and def query results

parent 8a4e76c1
Loading
Loading
Loading
Loading
+72 −48
Original line number Original line Diff line number Diff line
@@ -23,9 +23,13 @@


#include "uvcvideo.h"
#include "uvcvideo.h"


#define UVC_CTRL_NDATA		2
#define UVC_CTRL_DATA_CURRENT	0
#define UVC_CTRL_DATA_CURRENT	0
#define UVC_CTRL_DATA_BACKUP	1
#define UVC_CTRL_DATA_BACKUP	1
#define UVC_CTRL_DATA_MIN	2
#define UVC_CTRL_DATA_MAX	3
#define UVC_CTRL_DATA_RES	4
#define UVC_CTRL_DATA_DEF	5
#define UVC_CTRL_DATA_LAST	6


/* ------------------------------------------------------------------------
/* ------------------------------------------------------------------------
 * Controls
 * Controls
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
	return ctrl;
	return ctrl;
}
}


static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
	struct uvc_control *ctrl)
{
	int ret;

	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
				     ctrl->info->size);
		if (ret < 0)
			return ret;
	}

	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
				     ctrl->info->size);
		if (ret < 0)
			return ret;
	}
	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
				     ctrl->info->size);
		if (ret < 0)
			return ret;
	}
	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
				     ctrl->info->size);
		if (ret < 0)
			return ret;
	}

	ctrl->cached = 1;
	return 0;
}

int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
	struct v4l2_queryctrl *v4l2_ctrl)
	struct v4l2_queryctrl *v4l2_ctrl)
{
{
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
	struct uvc_control_mapping *mapping;
	struct uvc_control_mapping *mapping;
	struct uvc_menu_info *menu;
	struct uvc_menu_info *menu;
	unsigned int i;
	unsigned int i;
	__u8 *data;
	int ret;
	int ret;


	ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
	ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
	if (ctrl == NULL)
	if (ctrl == NULL)
		return -EINVAL;
		return -EINVAL;


	data = kmalloc(ctrl->info->size, GFP_KERNEL);
	if (data == NULL)
		return -ENOMEM;

	memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
	memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
	v4l2_ctrl->id = mapping->id;
	v4l2_ctrl->id = mapping->id;
	v4l2_ctrl->type = mapping->v4l2_type;
	v4l2_ctrl->type = mapping->v4l2_type;
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;


	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
	if (!ctrl->cached) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
		ret = uvc_ctrl_populate_cache(chain, ctrl);
				     chain->dev->intfnum, ctrl->info->selector,
				     data, ctrl->info->size);
		if (ret < 0)
		if (ret < 0)
			goto out;
			return ret;
		v4l2_ctrl->default_value =
	}
			mapping->get(mapping, UVC_GET_DEF, data);

	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
		v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
	}
	}


	switch (mapping->v4l2_type) {
	switch (mapping->v4l2_type) {
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
			}
			}
		}
		}


		ret = 0;
		return 0;
		goto out;


	case V4L2_CTRL_TYPE_BOOLEAN:
	case V4L2_CTRL_TYPE_BOOLEAN:
		v4l2_ctrl->minimum = 0;
		v4l2_ctrl->minimum = 0;
		v4l2_ctrl->maximum = 1;
		v4l2_ctrl->maximum = 1;
		v4l2_ctrl->step = 1;
		v4l2_ctrl->step = 1;
		ret = 0;
		return 0;
		goto out;


	case V4L2_CTRL_TYPE_BUTTON:
	case V4L2_CTRL_TYPE_BUTTON:
		v4l2_ctrl->minimum = 0;
		v4l2_ctrl->minimum = 0;
		v4l2_ctrl->maximum = 0;
		v4l2_ctrl->maximum = 0;
		v4l2_ctrl->step = 0;
		v4l2_ctrl->step = 0;
		ret = 0;
		return 0;
		goto out;


	default:
	default:
		break;
		break;
	}
	}


	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
	if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
		ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
		v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
				     chain->dev->intfnum, ctrl->info->selector,
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
				     data, ctrl->info->size);
		if (ret < 0)
			goto out;
		v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data);
	}
	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     data, ctrl->info->size);
		if (ret < 0)
			goto out;
		v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data);
	}
	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
		ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
				     chain->dev->intfnum, ctrl->info->selector,
				     data, ctrl->info->size);
		if (ret < 0)
			goto out;
		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data);
	}


	ret = 0;
	if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
out:
		v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
	kfree(data);
				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
	return ret;

	if (ctrl->info->flags & UVC_CONTROL_GET_RES)
		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
				  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));

	return 0;
}
}




@@ -1246,7 +1270,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
	}
	}


	ctrl->info = info;
	ctrl->info = info;
	ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL);
	ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
		"entity %u\n", ctrl->info->entity, ctrl->info->selector,
		"entity %u\n", ctrl->info->entity, ctrl->info->selector,
		dev->udev->devpath, entity->id);
		dev->udev->devpath, entity->id);
+2 −1
Original line number Original line Diff line number Diff line
@@ -245,7 +245,8 @@ struct uvc_control {
			   uvc_control_info. */
			   uvc_control_info. */
	__u8 dirty : 1,
	__u8 dirty : 1,
	     loaded : 1,
	     loaded : 1,
	     modified : 1;
	     modified : 1,
	     cached : 1;


	__u8 *data;
	__u8 *data;
};
};