V4L2框架分析

——————/
uvc_probe	//uvc_driver.c硬件相关层,定会分配设置向核心层注册一结构体
	v4l2_device_register
	uvc_register_chains
		uvc_register_terms
			uvc_register_video
				struct video_device *vdev=video_device_alloc();
				vdev->fops = &uvc_fops;
				video_register_device(vdev,……	//核心v4l2_dev.c

static const struct file_operations v4l2_fops = {	//标准统一接口
	.owner = THIS_MODULE,
	.read = v4l2_read,
	.write = v4l2_write,
	.open = v4l2_open,
	.get_unmapped_area = v4l2_get_unmapped_area,
	.unlocked_ioctl = v4l2_ioctl,
	……
}
APP调用open,导致调用v4l2_fops中v4l2_open,最终用到video_device提供的各种函数及属性
——————/
vivi_init
	vivi_create_instance
		v4l2_device_register	//初始化
		
		//struct vivi_dev *dev;    struct v4l2_ctrl*volume;
		dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,	//添加新的标准ctrl
			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);  //id,最小最大默认
		…………
		dev->button =v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
		…………
		
		struct video_device *vfd=video_device_alloc;//分配
		*vfd = vivi_template; //设置
		vfd->v4l2_dev = &dev->v4l2_dev;
		video_register_device(struct video_device *vdev,int type, int nr) //注册
			__video_register_device
				switch (type) {
				case VFL_TYPE_GRABBER:
					name_base = "video";
					break;
					……	//根据类型得到不同名字
				switch (type) {
				case VFL_TYPE_GRABBER:
					minor_offset = 0;
					minor_cnt = 64;
					break;
					……	//根据类型得到不同次设备号
				//以上用于创建设备节点
				vdev->cdev = cdev_alloc();
				vdev->cdev->ops = &v4l2_fops;
				cdev_add;
				video_device[vdev->minor] = vdev;	
				//以次设备号为下标,在数组中放入…
——————/
static struct video_device vivi_template = {
	.name		= "vivi",
	.fops           = &vivi_fops,
	.ioctl_ops 	= &vivi_ioctl_ops,
	.release	= video_device_release,
	……
};

static const struct v4l2_file_operations vivi_fops = {
	.owner		= THIS_MODULE,
	.open           = v4l2_fh_open,
	.release        = vivi_close,
	.read           = vivi_read,
	.poll		= vivi_poll,
	.unlocked_ioctl = video_ioctl2, 	/* V4L2 ioctl handler */
	.mmap           = vivi_mmap,
};
file_operations中函数会调用到v4l2_file_operations中的函数
——————/分析读写过程
APP	:	open(“/dev/video0”,……)
	v4l2_open
		struct video_device *vdev = video_devdata(filp);
		//据次…从数组中得到video_device结构体
			return video_device[iminor(file->f_path.dentry->d_inode)];
		if (vdev->fops->open)
			……//若存在则调用,实际调用v4l2_file_operations的v4l2_fh_open
read、write过程同上
——————/
APP	:	ioctl 
	v4l2_ioctl
		struct video_device *vdev = video_devdata(filp);
		if (vdev->fops->unlocked_ioctl)
			vdev->fops->unlocked_ioctl(filp, cmd, arg);
				video_ioctl2
					return video_usercopy(file, cmd, arg, __video_do_ioctl);
						__video_do_ioctl(struct file *file,unsigned int cmd, void *arg)
							struct video_device *vfd = video_devdata(file);
							switch (cmd)
								case VIDIOC_QUERYCAP:		//v4l2-ioctl.c
								……
								//根据APP传入cmd,设置、获得相关属性
——————/
怎么写v4l2驱动?
① 分配/设置/注册v4l2_device结构:v4l2_device_register
② 分配video_device:video_device_alloc
设置(包含v4l2_device指针,使其指向①所分配设置的)
注册
——————/
APP通过ioctl设置亮度等信息,驱动中谁来接收/存储/提供/设置到硬件?驱动抽象出struct v4l2_ctrl结构,一个v4l2_ctrl对应一项,谁来管理众多v4l2_ctrl?v4l2_ctrl_handler
vivi_create_instance
	struct video_device *vfd;
	struct	 vivi_dev *dev;
	struct 	v4l2_ctrl_handler *hdl;
	hdl = &dev->ctrl_handler;
	v4l2_ctrl_handler_init(hdl, 11);	//初始化ctrl_handler
	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); 
	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
	…………
	//handler含链表头,用v4l2_ctrl_new_std、v4l2_ctrl_new_custom向其添加v4l2_ctrl(属性)
	
	dev->v4l2_dev.ctrl_handler = hdl;	//与v4l2_device关联
	vfd->v4l2_dev = &dev->v4l2_dev;

__video_register_device开头
	struct video_device *vdev;
	if (vdev->ctrl_handler == NULL)
		vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
	.vidioc_querycap      = vidioc_querycap,
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
	…………
	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
v4l2_ctrl_handler使用过程:
__video_do_ioctl
	struct video_device *vfd = video_devdata(file);
	const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
	switch (cmd)
		case VIDIOC_QUERYCAP:
			ops->vidioc_querycap(file, fh, cap);	//部分情况直接调用
		……
		case VIDIOC_QUERYCTRL:
			if (vfd->ctrl_handler)
				ret = v4l2_queryctrl(vfd->ctrl_handler, p);
					struct v4l2_ctrl *ctrl;
					struct v4l2_ctrl_ref *ref;
					ref = find_ref(hdl, id); //据id从v4l2_ctrl_handler找到v4l2_ctrl
					ctrl = ref->ctrl;
					qc->minimum = ctrl->minimum; //返回其最小最大值默认值
					qc->maximum = ctrl->maximum;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值