⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uvc_ctrl.c

📁 LINUXvideopPREVIEW, LINUX下面打开图像的工具源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	__u32 v4l2_id, struct uvc_control_mapping **mapping){	struct uvc_control *ctrl;	struct uvc_entity *entity;	unsigned int i;	/* Find the control. */	ctrl = __uvc_find_control(video->processing, v4l2_id, mapping);	if (ctrl)		return ctrl;	ctrl = __uvc_find_control(video->iterm, v4l2_id, mapping);	if (ctrl)		return ctrl;	for (i = 0; i < 8; ++i) {		entity = video->extension[i];		if (entity == NULL)			break;		ctrl = __uvc_find_control(entity, v4l2_id, mapping);		if (ctrl)			return ctrl;	}	uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n", v4l2_id);	return NULL;}int uvc_query_v4l2_ctrl(struct uvc_video_device *video, struct v4l2_queryctrl *v4l2_ctrl){	struct uvc_control *ctrl;	struct uvc_control_mapping *mapping;	__u8 data[4];	int ret = 0;	ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);	if (ctrl == NULL) {		/* If the V4L2 control ID is in the private control ID range,		 * there's a chance the application is enumerating our private		 * controls, so we can't return EINVAL because (according to the		 * V4L2 spec) it will think that this was the last one. However,		 * it might just be this particular control that is not		 * supported and we want the enumeration to continue.		 */		if (v4l2_ctrl->id < V4L2_CID_PRIVATE_BASE ||		    v4l2_ctrl->id > V4L2_CID_PRIVATE_LAST) {			return -EINVAL;		} else {			v4l2_ctrl->name[0] = '\0';			v4l2_ctrl->flags = V4L2_CTRL_FLAG_DISABLED;			return 0;		}	}	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {		ret |= uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size);		v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);	}	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {		ret |= uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size);		v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);	}	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {		ret |= uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size);		v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);	}	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {		ret |= uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size);		v4l2_ctrl->step = uvc_get_le_value(data, mapping);	}	if (ret != 0)		return -EIO;	v4l2_ctrl->type = mapping->v4l2_type;	strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);	v4l2_ctrl->flags = 0;	return 0;}/* -------------------------------------------------------------------------- * Control transactions * * To make extended set operations as atomic as the hardware allows, controls * are handled using begin/commit/rollback operations. * * At the beginning of a set request, uvc_ctrl_begin should be called to * initialize the request. This function acquires the control lock. * * When setting a control, the new value is stored in the control data field * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for * later processing. If the UVC and V4L2 control sizes differ, the current * value is loaded from the hardware before storing the new value in the data * field. * * After processing all controls in the transaction, uvc_ctrl_commit or * uvc_ctrl_rollback must be called to apply the pending changes to the * hardware or revert them. When applying changes, all controls marked as * dirty will be modified in the UVC device, and the dirty flag will be * cleared. When reverting controls, the control data field * UVC_CTRL_DATA_CURRENT is reverted to its previous value * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the * control lock. */int uvc_ctrl_begin(struct uvc_video_device *video){	return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0;}static int uvc_ctrl_commit_entity(struct uvc_video_device *video,	struct uvc_entity *entity, int rollback){	struct uvc_control *ctrl;	unsigned int i;	for (i = 0; i < entity->ncontrols; ++i) {		ctrl = &entity->controls[i];		if (ctrl->info == NULL || !ctrl->dirty)			continue;		if (rollback)			memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),			       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),			       ctrl->info->size);		else			uvc_query_ctrl(video->dev, SET_CUR, ctrl->entity->id,				video->dev->intfnum, ctrl->info->selector,				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),				ctrl->info->size);		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)			ctrl->loaded = 0;		ctrl->dirty = 0;	}	return 0;}int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback){	struct uvc_entity *entity;	unsigned int i;	int ret = 0;	/* Find the control. */	ret = uvc_ctrl_commit_entity(video, video->processing, rollback);	if (ret < 0)		goto done;	ret = uvc_ctrl_commit_entity(video, video->iterm, rollback);	if (ret < 0)		goto done;	for (i = 0; i < 8; ++i) {		entity = video->extension[i];		if (entity == NULL)			break;		ret = uvc_ctrl_commit_entity(video, entity, rollback);		if (ret < 0)			goto done;	}done:	mutex_unlock(&video->ctrl_mutex);	return ret;}int uvc_ctrl_get(struct uvc_video_device *video,	struct v4l2_ext_control *xctrl){	struct uvc_control *ctrl;	struct uvc_control_mapping *mapping;	int ret;	ctrl = uvc_find_control(video, xctrl->id, &mapping);	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)		return -EINVAL;	if (!ctrl->loaded) {		ret = uvc_query_ctrl(video->dev, GET_CUR, ctrl->entity->id,				video->dev->intfnum, ctrl->info->selector,				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),				ctrl->info->size);		if (ret < 0)			return ret;		ctrl->loaded = 1;	}	xctrl->value = uvc_get_le_value(		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);	return 0;}int uvc_ctrl_set(struct uvc_video_device *video,	struct v4l2_ext_control *xctrl){	struct uvc_control *ctrl;	struct uvc_control_mapping *mapping;	int ret;	ctrl = uvc_find_control(video, xctrl->id, &mapping);	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)		return -EINVAL;	if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {			memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),				0, ctrl->info->size);		} else {			ret = uvc_query_ctrl(video->dev, GET_CUR,				ctrl->entity->id, video->dev->intfnum,				ctrl->info->selector,				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),				ctrl->info->size);			if (ret < 0)				return ret;		}		ctrl->loaded = 1;	}	if (!ctrl->dirty) {		memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),		       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),		       ctrl->info->size);	}	uvc_set_le_value(xctrl->value,		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);	ctrl->dirty = 1;	return 0;}/* -------------------------------------------------------------------------- * Control and mapping handling */static void uvc_ctrl_add_ctrl(struct uvc_device *dev,	struct uvc_control_info *info){	struct uvc_entity *entity;	struct uvc_control *ctrl;	unsigned int i;	list_for_each_entry(entity, &dev->entities, list) {		if (!uvc_entity_match_guid(entity, info->entity))			continue;		for (i = 0; i < entity->ncontrols; ++i) {			ctrl = &entity->controls[i];			if (ctrl->index == info->index) {				ctrl->info = info;				ctrl->data = kmalloc(info->size * UVC_CTRL_NDATA, GFP_KERNEL);				uvc_trace(UVC_TRACE_CONTROL, "Added control "					UVC_GUID_FORMAT "/%u to device %s entity %u\n",					UVC_GUID_ARGS(ctrl->info->entity),					ctrl->info->selector,					dev->udev->devpath, entity->id);				break;			}		}	}}/* * Add an item to the UVC control information list, and instanciate a control * structure for each device that supports the control. */void uvc_ctrl_add_info(struct uvc_control_info *info){	struct uvc_control_info *ctrl;	struct uvc_device *dev;	/* Find matching controls by walking the devices, entities and	 * controls list.	 */	mutex_lock(&uvc_driver.ctrl_mutex);	/* First check if the list contains a control matching the new one.	 * Bail out if it does.	 */	list_for_each_entry(ctrl, &uvc_driver.controls, list) {		if (memcmp(ctrl->entity, info->entity, 16))			continue;		if (ctrl->selector == info->selector) {			uvc_trace(UVC_TRACE_CONTROL, "Control "				UVC_GUID_FORMAT "/%u is already defined.\n",				UVC_GUID_ARGS(info->entity), info->selector);			goto end;		}		if (ctrl->index == info->index) {			uvc_trace(UVC_TRACE_CONTROL, "Control "				UVC_GUID_FORMAT "/%u would overwrite index "				"%d.\n", UVC_GUID_ARGS(info->entity),				info->selector, info->index);			goto end;		}	}	list_for_each_entry(dev, &uvc_driver.devices, list)		uvc_ctrl_add_ctrl(dev, info);	INIT_LIST_HEAD(&info->mappings);	list_add_tail(&info->list, &uvc_driver.controls);end:	mutex_unlock(&uvc_driver.ctrl_mutex);}void uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping){	struct uvc_control_info *info;	struct uvc_control_mapping *map;	mutex_lock(&uvc_driver.ctrl_mutex);	list_for_each_entry(info, &uvc_driver.controls, list) {		if (memcmp(info->entity, mapping->entity, 16) ||			info->selector != mapping->selector)			continue;		if (info->size * 8 < mapping->size + mapping->offset) {			uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' would "				"overflow control " UVC_GUID_FORMAT "/%u\n",				mapping->name, UVC_GUID_ARGS(info->entity),				info->selector);			goto end;		}		/* Check if the list contains a mapping matching the new one.		 * Bail out if it does.		 */		list_for_each_entry(map, &info->mappings, list) {			if (map->id == mapping->id) {				uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is already "					"defined.\n", mapping->name);				goto end;			}		}		mapping->ctrl = info;		list_add_tail(&mapping->list, &info->mappings);		uvc_trace(UVC_TRACE_CONTROL, "Adding mapping %s to control "			UVC_GUID_FORMAT "/%u.\n", mapping->name,			UVC_GUID_ARGS(info->entity), info->selector);		break;	}end:	mutex_unlock(&uvc_driver.ctrl_mutex);}/* * Initialize device controls. */int uvc_ctrl_init_device(struct uvc_device *dev){	struct uvc_control_info *info;	struct uvc_control *ctrl;	struct uvc_entity *entity;	unsigned int i;	/* Walk the entities list and instanciate controls */	list_for_each_entry(entity, &dev->entities, list) {		unsigned int bControlSize = 0, ncontrols = 0;		__u8 *bmControls = NULL;		if (entity->type == VC_EXTENSION_UNIT) {			bmControls = entity->extension.bmControls;			bControlSize = entity->extension.bControlSize;		} else if (entity->type == VC_PROCESSING_UNIT) {			bmControls = entity->processing.bmControls;			bControlSize = entity->processing.bControlSize;		} else if (entity->type == ITT_CAMERA) {			bmControls = entity->camera.bmControls;			bControlSize = entity->camera.bControlSize;		}		for (i = 0; i < bControlSize; ++i)			ncontrols += hweight8(bmControls[i]);		if (ncontrols == 0)			continue;		entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);		if (entity->controls == NULL)			return -ENOMEM;		entity->ncontrols = ncontrols;		ctrl = entity->controls;		for (i = 0; i < bControlSize * 8; ++i) {			if (uvc_get_bit(bmControls, i) == 0)				continue;			ctrl->entity = entity;			ctrl->index = i;			ctrl++;		}	}	/* Walk the controls info list and associate them with the device	 * controls, then add the device to the global device list. This has	 * to be done while holding the controls lock, to make sure	 * uvc_ctrl_add_info() will not get called in-between.	 */	mutex_lock(&uvc_driver.ctrl_mutex);	list_for_each_entry(info, &uvc_driver.controls, list)		uvc_ctrl_add_ctrl(dev, info);	list_add_tail(&dev->list, &uvc_driver.devices);	mutex_unlock(&uvc_driver.ctrl_mutex);	return 0;}/* * Cleanup device controls. */void uvc_ctrl_cleanup_device(struct uvc_device *dev){	struct uvc_entity *entity;	unsigned int i;	/* Remove the device from the global devices list */	mutex_lock(&uvc_driver.ctrl_mutex);	list_del(&dev->list);	mutex_unlock(&uvc_driver.ctrl_mutex);	list_for_each_entry(entity, &dev->entities, list) {		for (i = 0; i < entity->ncontrols; ++i)			kfree(entity->controls[i].data);		kfree(entity->controls);	}}void uvc_ctrl_init(void){	struct uvc_control_info *ctrl = uvc_ctrls;	struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);	struct uvc_control_mapping *mapping = uvc_ctrl_mappings;	struct uvc_control_mapping *mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings);	for (; ctrl < cend; ++ctrl)		uvc_ctrl_add_info(ctrl);	for (; mapping < mend; ++mapping)		uvc_ctrl_add_mapping(mapping);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -