摄像头驱动框架分析

声明:视频来源韦东山老师视频第三期的摄像头一章,如有侵权,请联系作者,我会自行删除
一、摄像图框架属于字符驱动框架,是一个通用的框架:
1. 构造file_operations:
2. 告诉内核,注册register_chrdev(major, file_ops, name) //名字无所谓,不重要
有的书认为这个函数很老了,会用另外三个函数代替这个函数:
2.2 分配cdev
2.3 设置cdev
2.4 cdev_add
3. 入口函数
4. 出口函数

二、对于复杂的字符驱动程序,就会引入分层的概念,例如第二期中的LCD驱动程序
	1.  fbmen.c   //内核已经提供好了
		1.1 file_operation
		1.2 register_chrdev
		1.3 入口、出口
	2. 硬件相关   //这个是需要我们做的
		2.1 分配fb_info
		2.2 设置fb_info
		2.3 注册   //所谓的注册就是告诉fbmen.c,当应用程序调用open等函数操作LCD的时候,首先调用fbmen.c中的open等函数
					 调用open的时候就会调用我们注册的fb_info结构体里面提供的函数或者属性操作硬件,分层的好处我们只需要关注
					 硬件相关的操作,其他通用的部分部分内核已经做好了。
		2.4 硬件相关的操作
		总结: 如何写分层的驱动程序?
		      内核已经写好了软件相关层,我们只需需要去构造硬件相关的一层,所以这样写就可以了
			  2.4.1 分配某个结构体,具体是什么结构体,具体驱动具体分析
			  2.4.2 设置它
			  2.4.3 注册结构体
			  2.4.4 硬件相关的操作
			  
三、分析摄像头的驱动框架(V4L2)
	猜测这个应该也是一个分层形式的驱动框架
	book@www.100ask.org:/work/system/linux-3.4.2/drivers$ grep -nR "Found UVC" *
	Binary file built-in.o matches
	Binary file media/video/uvc/uvc_driver.o matches
	media/video/uvc/uvc_driver.c:1848:	uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
	Binary file media/video/uvc/uvcvideo.o matches
	Binary file media/video/uvc/built-in.o matches
	Binary file media/video/built-in.o matches
	Binary file media/built-in.o matches
	
	进入函数uvc_driver:
	uvc_driver
		uvc_init
			usb_register(&uvc_driver.driver)
				uvc_probe
					v4l2_device_register   //这个不是主要的,用来一些初始化
					uvc_register_chains   chain链
						uvc_register_terms   term条目
							uvc_register_video
								video_device_alloc
								video_register_device
									__video_register_device
										vdev->cdev = cdev_alloc();
										vdev->cdev->ops = &v4l2_fops;
										cdev_add
	v4l2_fops将会调用video_device函数中的各种属性
	分析一个比较不错的函数vivi.c,作为分析的例子
	虚拟视频驱动vivi.c分析
	关键点:
		分配video_device
		设置
		注册video_register_device
	vivi.c
		vivi_init
			vivi_create_instance
				v4l2_device_register  //不重要,只是用来初始化一些东西,例如自锁锁等
				分配
				video_device_alloc
				设置
				1.*vfd = vivi_template;
					.fops           = &vivi_fops,	(v4l2_file_operations)  	// 命名有点智障,把我都搞糊涂了
					.ioctl_ops 	= &vivi_ioctl_ops,
				2.vfd->v4l2_dev = &dev->v4l2_dev;
				3.设置"ctrl",用于app的ioctl
				dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
					V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
				dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
					V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
				注册
				video_register_device(video_device: vfd, type :VFL_TYPE_GRABBER, number: video_nr)根据不同类型自动创建相应的节点						
					vdev->cdev = cdev_alloc();
					vdev->cdev->ops = &v4l2_fops(file_operations);//忍不住了,再吐槽一次,智障的命名,这个智障调用上面的那个智障
					cdev_add
	猜测file_operations会调用v4   l2_file_operations
	
	彻底了解一个驱动程序最好的方式及时分析函数里面的open,read,write函数等
	open 
	vdev = video_devdata(filp);   
		return video_device[iminor(file->f_path.dentry->d_inode)];  //根据此设备号从数组中得到video_device结构体
	在下面两句话里将video_device存进数组里(在video_register_device里面可以看见)
	if (vdev->cdev == NULL)
	video_device[vdev->minor] = vdev;
	
	open:
	file_operations v4l2_fops
		.open = v4l2_open
			vdev = video_devdata(filp);
			if (vdev->fops->open)         //v4l2_file_operations,从这里就可以看见了file_operations调用了v4l2_file_operations
				ret = vdev->fops->open(filp);
	
	read:
	write函数都是一样的,差不多
	
	ioctl:
	file_operations v4l2_fops
		.unlocked_ioctl = v4l2_ioctl,
			struct video_device *vdev = video_devdata(filp);
			if (vdev->fops->unlocked_ioctl) { 		//下面是vivi_fops 的确含有ioctl
			//	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,
			//	};		
			ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
			//  实质上就是这个函数video_ioctl2
			video_ioctl2
				video_usercopy(file, cmd, arg, __video_do_ioctl);//从用户空间复制参数调用函数__video_do_ioctl
					__video_do_ioctl
						struct video_device *vfd = video_devdata(file);   //到这一步的时候已经和read函数一样了
						switch (cmd)   //根据app传入的参数来设置、获得一些属性。
	问题是这些属性是谁提供的呢
	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
			
	总结: 怎么写驱动程序呢?
		  分配设置注册v4l2_device   v4l2_device_register   //注意一下,这个命名有点奇葩,这个不是主要的,主要的是video_device
		  分配一个结构体video_device     video_device_alloc
		  设置这个结构体,就称之为vfd   结构体v4l2_device结构体就是在这里面,这个结构体仅仅是辅助作用(v4l2_device)
		  
	看看这个函数:
	*vfd = vivi_template;
		.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_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
			........
	在和v4l2_fops一个文件里应该会有一个函数调用ioctl_ops,但是我没找到,估计不是我想的这样,不过没事
	
	分离分层的时候,v4l2_file_operations在底层,file_operation在中层,上面是app
	ioctl_ops就是底层文件,app可以通过他来设置亮度等之类的属性,那么驱动程序里谁来接收存储接收到这些硬件,提供这些信息呢
	这个就是v4l2_ctrl,由v42l_ctrl_handler来管理这些信息
	v42l_ctrl_handler
		1. 初始化
		v4l2_ctrl_handler_init   初始化v42l_ctrl_handler
		2. 设置
		v4l2_ctrl_new_std        
		v4l2_ctrl_new_custom 	  这两个函数的作用就是创建v4l2_ctrl	,清切放入v42l_ctrl_handler链表中
		3. 使用
		dev->v4l2_dev.ctrl_handler = hdl;    //和video_device关联
		因为video_device.v42l_dev
		
	v4l2_ctrl_handler的使用过程:
	ioctl:
	file_operations v4l2_fops
		.unlocked_ioctl = v4l2_ioctl,
			struct video_device *vdev = video_devdata(filp);
				ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
					video_ioctl2
						video_usercopy(file, cmd, arg, __video_do_ioctl);//从用户空间复制参数调用函数__video_do_ioctl
							__video_do_ioctl
								struct video_device *vfd = video_devdata(file);   //到这一步的时候已经和read函数一样了
								switch (cmd)   //根据app传入的参数来设置、获得一些属性。
								
									case VIDIOC_QUERYCTRL:
										{
											struct v4l2_queryctrl *p = arg;

											if (vfh && vfh->ctrl_handler)    
												ret = v4l2_queryctrl(vfh->ctrl_handler, p);   
											else if (vfd->ctrl_handler)
											//搜索ctrl_handler ,lookup references可以看到在__video_register_device中已经有了设置
											//if (vdev->ctrl_handler == NULL)
											//vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
												ret = v4l2_queryctrl(vfd->ctrl_handler, p);		

暂时到这儿,后续会补上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值