UVC框架下USB摄像头驱动之设置属性

1. 在视频驱动程序中设置属性主要涉及3个ioctl :

VIDIOC_QUERYCTRL
VIDIOC_G_CTRL
VIDIOC_S_CTRL

2. 硬件上怎么设置属性呢?

2.1 UVC规划定义了那些属性:定义在uvc_ctrl.c里面的数组


static struct uvc_control_info uvc_ctrls[] = {
	{
		.entity		= UVC_GUID_UVC_PROCESSING, //属于哪一个entity 
		.selector	= UVC_PU_BRIGHTNESS_CONTROL,//用于亮度
		.index		= 0,// 对应Processing Unit Descriptor 的bmControls[0]
		.size		= 2,//数据长度2个字节
		.flags		= UVC_CTRL_FLAG_SET_CUR| UVC_CTRL_FLAG_GET_RANGE| UVC_CTRL_FLAG_RESTORE,
	},
}

2.2 设备支持哪些属性呢

这需要具体去看设备描述符,比如 Processing Unit Descriptor 的bmControls值为7f 14
可知BIT0 为1 表示支持BRIGHTNESS
在这里插入图片描述

在uvc_probe 函数中对其属性进行了初始化代码中

uvc_ctrl_init_device(dev) 

对于每一个entity(IT,PU,SU,OT等)

list_for_each_entry(entity, &dev->entities, list) 

分别提取对应的控制集(bmControls) 以及 控制集的大小(bControlSize—》 指定了bmControls字段的大小)

if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
			bmControls = entity->extension.bmControls;
			bControlSize = entity->extension.bControlSize;
		} else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
			bmControls = entity->processing.bmControls;
			bControlSize = entity->processing.bControlSize;

计算bmControls 里面1 的个数 也就是支持的属性个数

		ncontrols = memweight(bmControls, bControlSize);

为每一个属性分配一个struct uvc_control

entity->controls = kcalloc(ncontrols, sizeof(*ctrl),
					   GFP_KERNEL);

设置这些struct uvc_control

ctrl = entity->controls;
   	for (i = 0; i < bControlSize * 8; ++i) 
   	{
   		if (uvc_test_bit(bmControls, i) == 0)
   			continue;

   		ctrl->entity = entity;
   		ctrl->index = i;

把uvc_control 和uvc_control_info 挂钩

uvc_ctrl_init_ctrl(dev, ctrl);

ctrl->info = 某个uvc_control_info数组项(同属于一个entity, index相同)

2.3 怎么去操控这些属性呢

参考

uvc_ioctl_queryctrl
---->uvc_query_v4l2_ctrl(chain, qc);
------>uvc_find_control
------> __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
--------> __uvc_ctrl_get
---------->uvc_query_ctrl
------------>__uvc_query_ctrl

__uvc_query_ctrl 包装了USB核心的usb_control_msg 函数,可以用来获得或设置特定的属性

/*  用来查询或者设置 uvc的属性
struct uvc_device *dev:指向表示UVC设备的结构体的指针。
__u8 query 			  :指定控制请求的类型,比如GET_CUR(获取当前值)、SET_CUR(设置当前值)等。
__u8 unit		      :指定请求目标的单元ID,例如摄像头控制单元(CCU)或处理单元(PU)。
__u8 intfnum		  :指定USB接口编号。
__u8 cs			      :指定控制选择符(Control Selector),定义了要控制的具体功能。
void *data		      :指向数据的指针,用于发送或接收控制消息的数据部分。
__u16 size		      :数据部分的大小,以字节为单位。
int timeout		      :控制请求的超时时间,以毫秒为单位。
*/

static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
			__u8 intfnum, __u8 cs, void *data, __u16 size,
			int timeout)
{
	__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
	 /*1.设置类型  USB_TYPE_CLASS 特定请求   USB_RECIP_INTERFACE 请求的接收者是一个接口*/
	unsigned int pipe;

	pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
			      : usb_sndctrlpipe(dev->udev, 0);
	/*2.根据query的最高位进行判断 是发送数据还是读取数据*/
	type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
	/*3.发送控制信息  data 缓冲区*/
	return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
			unit << 8 | intfnum, data, size, timeout);
}

关于结构体 uvc_control_mapping ,用来更加细致的描述 属性

例如 struct uvc_control_mapping uvc_ctrl_mapping[]
在这里插入图片描述

3. 比如设置亮度 如何操作呢

3.1 根据PU的描述符的bmControl 找到它的bot 0 = 1,也就找到了是否支持亮度调节

3.2 在uvc_ctrls数组中根据id和index 找到这一项:

{
		.entity		= UVC_GUID_UVC_PROCESSING,
		.selector	= UVC_PU_BRIGHTNESS_CONTROL,
		.index		= 0,
		.size		= 2,
		.flags		= UVC_CTRL_FLAG_SET_CUR
				| UVC_CTRL_FLAG_GET_RANGE
				| UVC_CTRL_FLAG_RESTORE,
	},

可以知道,这个设备支持 UVC_CTRL_FLAG_SET_CUR, UVC_CTRL_FLAG_GET_RANGE,UVC_CTRL_FLAG_RESTORE,要进行设置时可以向PU的selector 发送2字节数据

3.3 在uvc_control_mapping 数组中根据ID 找到对应的数组项,从而知道 更加细致的描述信息,然后使用usb_control_msg 读写数据

具体步骤

3.3.1 首先是设置控制值 参考: uvc_ctrl_set(chain, &xctrl);

  1. 需要根据 id 找到对应的uvc_ctrl_mapping
/*参考 static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
	struct uvc_control_mapping **mapping, struct uvc_control **control,
	int next)函数*/
	
	for (i = 0; i < entity->ncontrols; ++i) { /*遍历所有实体的控制项*/
			ctrl = &entity->controls[i];

		if (!ctrl->initialized)/*是否初始化*/
			continue;

		list_for_each_entry(map, &ctrl->info.mappings, list) { /*遍历其映射表*/
			if ((map->id == v4l2_id) && !next) {
				*control = ctrl;
				*mapping = map;
				return;
}
  1. 根据 属性类型 v4l2_type 设置不同的data_type 比如 UVC_CTRL_DATA_MIN
switch (mapping->v4l2_type)
  1. 将调整后的值写入到控制数据中
mapping->set(mapping, value,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));

3.3.2 然后就是提交控制值 参考: uvc_ctrl_commit(handle, &xctrl, 1);

一系列复杂调用之后 通过usb_control_msg 发送给硬件
参考这句代码

__uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,UVC_CTRL_CONTROL_TIMEOUT);
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值