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

📄 uvc_ctrl.c

📁 linux camera下的uvc driver驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
}/* Extract the bit string specified by mapping->offset and mapping->size * from the little-endian data stored at 'data' and return the result as * a signed 32bit integer. Sign extension will be performed if the mapping * references a signed data type. */static __s32 uvc_get_le_value(const __u8 *data,	struct uvc_control_mapping *mapping){	int bits = mapping->size;	int offset = mapping->offset;	__s32 value = 0;	__u8 mask;	data += offset / 8;	offset &= 7;	mask = ((1LL << bits) - 1) << offset;	for (; bits > 0; data++) {		__u8 byte = *data & mask;		value |= offset > 0 ? (byte >> offset) : (byte << (-offset));		bits -= 8 - (offset > 0 ? offset : 0);		offset -= 8;		mask = (1 << bits) - 1;	}	/* Sign-extend the value if needed */	if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)		value |= -(value & (1 << (mapping->size - 1)));	return value;}/* Set the bit string specified by mapping->offset and mapping->size * in the little-endian data stored at 'data' to the value 'value'. */static void uvc_set_le_value(__s32 value, __u8 *data,	struct uvc_control_mapping *mapping){	int bits = mapping->size;	int offset = mapping->offset;	__u8 mask;	data += offset / 8;	offset &= 7;	for (; bits > 0; data++) {		mask = ((1LL << bits) - 1) << offset;		*data = (*data & ~mask) | ((value << offset) & mask);		value >>= offset ? offset : 8;		bits -= 8 - offset;		offset = 0;	}}/* ------------------------------------------------------------------------ * Terminal and unit management */static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;static const __u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16]){	switch (UVC_ENTITY_TYPE(entity)) {	case ITT_CAMERA:		return memcmp(uvc_camera_guid, guid, 16) == 0;	case ITT_MEDIA_TRANSPORT_INPUT:		return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;	case VC_PROCESSING_UNIT:		return memcmp(uvc_processing_guid, guid, 16) == 0;	case VC_EXTENSION_UNIT:		return memcmp(entity->extension.guidExtensionCode, guid, 16) == 0;	default:		return 0;	}}/* ------------------------------------------------------------------------ * UVC Controls */static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,	struct uvc_control_mapping **mapping, struct uvc_control **control,	int next){	struct uvc_control *ctrl;	struct uvc_control_mapping *map;	unsigned int i;	if (entity == NULL)		return;	for (i = 0; i < entity->ncontrols; ++i) {		ctrl = &entity->controls[i];		if (ctrl->info == NULL)			continue;		list_for_each_entry(map, &ctrl->info->mappings, list) {			if ((map->id == v4l2_id) && !next) {				*control = ctrl;				*mapping = map;				return;			}			if ((*mapping == NULL || (*mapping)->id > map->id) &&			    (map->id > v4l2_id) && next) {				*control = ctrl;				*mapping = map;			}		}	}}struct uvc_control *uvc_find_control(struct uvc_video_device *video,	__u32 v4l2_id, struct uvc_control_mapping **mapping){	struct uvc_control *ctrl = NULL;	struct uvc_entity *entity;	int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;	*mapping = NULL;	/* Mask the query flags. */	v4l2_id &= V4L2_CTRL_ID_MASK;	/* Find the control. */	__uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next);	if (ctrl && !next)		return ctrl;	list_for_each_entry(entity, &video->iterms, chain) {		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);		if (ctrl && !next)			return ctrl;	}	list_for_each_entry(entity, &video->extensions, chain) {		__uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);		if (ctrl && !next)			return ctrl;	}	if (ctrl == NULL && !next)		uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",				v4l2_id);	return ctrl;}int uvc_query_v4l2_ctrl(struct uvc_video_device *video, struct v4l2_queryctrl *v4l2_ctrl){	struct uvc_control *ctrl;	struct uvc_control_mapping *mapping;	struct uvc_menu_info *menu;	unsigned int i;	__u8 data[8];	int ret;	ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping);	if (ctrl == NULL)		return -EINVAL;	v4l2_ctrl->id = mapping->id;	v4l2_ctrl->type = mapping->v4l2_type;	strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);	v4l2_ctrl->flags = 0;	if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))		v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;	if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {		if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size)) < 0)			return ret;		v4l2_ctrl->default_value = uvc_get_le_value(data, mapping);	}	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {		v4l2_ctrl->minimum = 0;		v4l2_ctrl->maximum = mapping->menu_count - 1;		v4l2_ctrl->step = 1;		menu = mapping->menu_info;		for (i = 0; i < mapping->menu_count; ++i, ++menu) {			if (menu->value == v4l2_ctrl->default_value) {				v4l2_ctrl->default_value = i;				break;			}		}		return 0;	}	if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {		if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size)) < 0)			return ret;		v4l2_ctrl->minimum = uvc_get_le_value(data, mapping);	}	if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {		if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size)) < 0)			return ret;		v4l2_ctrl->maximum = uvc_get_le_value(data, mapping);	}	if (ctrl->info->flags & UVC_CONTROL_GET_RES) {		if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id,					video->dev->intfnum, ctrl->info->selector,					&data, ctrl->info->size)) < 0)			return ret;		v4l2_ctrl->step = uvc_get_le_value(data, mapping);	}	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_device *dev,	struct uvc_entity *entity, int rollback){	struct uvc_control *ctrl;	unsigned int i;	int ret;	if (entity == NULL)		return 0;	for (i = 0; i < entity->ncontrols; ++i) {		ctrl = &entity->controls[i];		if (ctrl->info == NULL || !ctrl->dirty)			continue;		if (!rollback)			ret = uvc_query_ctrl(dev, SET_CUR, ctrl->entity->id,				dev->intfnum, ctrl->info->selector,				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),				ctrl->info->size);		else			ret = 0;		if (rollback || ret < 0)			memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),			       uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),			       ctrl->info->size);		if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)			ctrl->loaded = 0;		ctrl->dirty = 0;		if (ret < 0)			return ret;	}	return 0;}int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback){	struct uvc_entity *entity;	int ret = 0;	/* Find the control. */	ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback);	if (ret < 0)		goto done;	list_for_each_entry(entity, &video->iterms, chain) {		ret = uvc_ctrl_commit_entity(video->dev, entity, rollback);		if (ret < 0)			goto done;	}	list_for_each_entry(entity, &video->extensions, chain) {		ret = uvc_ctrl_commit_entity(video->dev, 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;	struct uvc_menu_info *menu;	unsigned int i;	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;		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)			ctrl->loaded = 1;	}	xctrl->value = uvc_get_le_value(		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {		menu = mapping->menu_info;		for (i = 0; i < mapping->menu_count; ++i, ++menu) {			if (menu->value == xctrl->value) {				xctrl->value = i;				break;			}		}	}	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;	s32 value = xctrl->value;	int ret;	ctrl = uvc_find_control(video, xctrl->id, &mapping);	if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)		return -EINVAL;	if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {		if (value < 0 || value >= mapping->menu_count)			return -EINVAL;		value = mapping->menu_info[value].value;	}	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;		}		if ((ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) == 0)			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(value,		uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), mapping);	ctrl->dirty = 1;	ctrl->modified = 1;	return 0;}/* -------------------------------------------------------------------------- * Dynamic controls

⌨️ 快捷键说明

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