博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
camera驱动(五)
阅读量:3897 次
发布时间:2019-05-23

本文共 5111 字,大约阅读时间需要 17 分钟。

1. 用户空间进行open操作

        在中master 端进行初始化和注册过程中添加了file_operations结构体

static const struct file_operations v4l2_fops = {	.owner = THIS_MODULE,	.open = v4l2_open,	.mmap = v4l2_mmap,	.unlocked_ioctl = v4l2_ioctl,	.release = v4l2_release,};

2. open操作的整体流程

v4l2_open    -->mxc_v4l_open    	-->ipu_csi_init_interface(...,cam_fmt.fmt.pix.pixelformat,csi_param)    		-->cam_fmt.fmt.pix.pixelformat    	-->vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt)    		-->ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f)    			-->f->fmt.pix = sensor->sen.pix    			-->struct sensor *sensor = s->priv

3. open操作的详细流程

//mxc_v4l2_capture.cstatic struct v4l2_file_operations mxc_v4l_fops = {	.owner = THIS_MODULE,	.open = mxc_v4l_open,	.ioctl = mxc_v4l_ioctl,	.mmap = mxc_mmap,};static struct video_device mxc_v4l_template = {	.name = "Mxc Camera",	.fops = &mxc_v4l_fops,};//v4l2-dev.cstatic int v4l2_open(struct inode *inode, struct file *filp){	struct video_device *vdev;	int ret = 0;    /*这里的vdev即init_camera_struct()函数中填充的cam->video_dev=mxc_v4l_template,可以回看camera驱动(三)进行确认*/	vdev = video_devdata(filp);	video_get(vdev);	if (vdev->fops->open) {		if (video_is_registered(vdev))			ret = vdev->fops->open(filp);	/*vdev->fops等于mxc_v4l_fops结构体,即调用mxc_v4l_open函数*/		else			ret = -ENODEV;	}	return ret;}
static int mxc_v4l_open(struct file *file){	struct v4l2_ifparm ifparm;	struct v4l2_format cam_fmt;	ipu_csi_signal_cfg_t csi_param;	struct video_device *dev = video_devdata(file);	/* 获取video_device结构体 */	cam_data *cam = video_get_drvdata(dev);	int err = 0;	struct sensor_data *sensor;	/*如果cam->sensor不存在或者它的类型不是slave就返回-EAGAIN*/	/*这个cam->sensor是在mxc_v4l2_master_attach函数中通过cam->sensor= slave设置的,所以cam->sensor就代表当前使用的slave设备*/	if (cam->sensor == NULL ||		    cam->sensor->type != v4l2_int_type_slave) {		pr_err("ERROR: v4l2 capture: slave not found!\n");		return -EAGAIN;	}	/*这个cam->sensor->priv是在slave设备的probe函数中设置的*/	sensor = cam->sensor->priv;	/*这个power_queue等待队列是在init_camera_struct函数中初始化的,等待上电以后继续往下运行,在mxc_v4l2_resume函数中,会将low_power标志位置为false,然后唤醒这个队列*/	if (cam->open_count++ == 0) {		wait_event_interruptible(cam->power_queue, cam->low_power == false);		/*cam->current_input在init_camera_struct中被初始化为0,所以会执行prp_enc_select()函数*/		if (strcmp(mxc_capture_inputs[cam->current_input].name, "CSI MEM") == 0) {				err = csi_enc_select(cam);  		} else if (strcmp(mxc_capture_inputs[cam->current_input].name, "CSI IC MEM") == 0) {			err = prp_enc_select(cam);		}		/*初始化三个队列头,这3个队列是在使用buffer过程中需要使用的*/		cam->enc_counter = 0;		INIT_LIST_HEAD(&cam->ready_q);		INIT_LIST_HEAD(&cam->working_q);		INIT_LIST_HEAD(&cam->done_q);		    	vidioc_int_g_ifparm(cam->sensor, &ifparm);/*从底层的slave设备里获取参数,跟cam->sensor没啥关系*/		csi_param.mclk = ifparm.u.bt656.clock_curr;	/*根据上面从底层slave设备获取的参数来对csi_param进行初始化*/		vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);				/*在init_camera_struct中直接将窗口位置和大小设置为(0,0)和640*480,现在根据从底层slave设备中获取的参数重新设置窗口位置和大小*/		ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, cam->crop_current.height, cam->csi);		ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, cam->crop_current.top, cam->csi);		/*根据这几个参数设置底层ipu寄存器的值,CSI_CCIR_CODE_1~3等寄存器*/		ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width,cam->crop_bounds.height,cam_fmt.fmt.pix.pixelformat,csi_param);		vidioc_int_s_power(cam->sensor, 1); /*最终会调用到slave里的ioctl_s_power函数,打开设备电源;(软件意义上的电源)*/		vidioc_int_init(cam->sensor);	/*调用ioctl_init函数,空函数*/		vidioc_int_dev_init(cam->sensor);	/*调用ioctl_dev_init函数,初始化摄像头本身的一些寄存器的值*/	}	file->private_data = dev;}int32_t ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height, uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param){	uint32_t data = 0;	uint32_t csi = cfg_param.csi;	/*首先根据传进来的不同pixel_fmt参数的值,设置cfg_param.data_fmt的值*/	switch (pixel_fmt) {	case IPU_PIX_FMT_YUYV:	/*ov5640里的pixel_fmt是这个*/		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;		break;	case IPU_PIX_FMT_UYVY:  /*ak8859和max9288里的pixel_fmt都是这个*/		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;		break;	case IPU_PIX_FMT_RGB24:	······	default:		return -EINVAL;	}	/* Setup sensor frame size */  /*根据传进来的width和height参数,设置CSI_SENS_FRM_SIZE寄存器的值*/	ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);	/* Set CCIR registers */  /*根据cfg_param.clk_mode参数的不同值来设置CSI_CCIR_CODE_1~3寄存器的值*/	if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {  /*在open函数中被赋值为0,所以这里不执行*/		ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);		ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);	}	else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||	(cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {		_ipu_csi_ccir_err_detection_disable(ipu, csi);  	}	return 0;}
vidioc_int_g_fmt_cap()即ioctl_g_fmt_cap()static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f){	struct sensor *sensor = s->priv;	switch (f->type) {		case V4L2_BUF_TYPE_VIDEO_CAPTURE:			f->fmt.pix = sensor->sen.pix;			break;		case V4L2_BUF_TYPE_PRIVATE: {			v4l2_std_id std;			ak8859_get_std(&std);			f->fmt.pix.pixelformat = (u32)std;		}		break;		default:			f->fmt.pix = sensor->sen.pix;			break;	}	return 0;}

转载地址:http://zeuen.baihongyu.com/

你可能感兴趣的文章
Emacs for vim Users---from http://www.crazyshell.org/blog/
查看>>
静态库和动态库链接那些事--http://www.crazyshell.org/blog/?p=50
查看>>
使用samba实现linux,windows间文件共享
查看>>
多线程调试必杀技 - GDB的non-stop模式
查看>>
一年成为Emacs高手(像神一样使用编辑器) .--http://blog.csdn.net/redguardtoo/article/details/7222501
查看>>
GNU make 指南
查看>>
配置 vim
查看>>
CentOS6.3 minimal SSH中文显示
查看>>
centos 安装emacs24
查看>>
【转】结构体中Char a[0]用法——柔性数组
查看>>
结构体最后定义一个char p[0];这样的成员有何意义(转)
查看>>
一步一学Linux与Windows 共享文件Samba (v0.2b)
查看>>
Linux 下忘记root密码怎么办
查看>>
Linux软件下载源码编程文章资料周立发--之调试
查看>>
GIT分支管理是一门艺术
查看>>
Cscope在emacs中的配置与使用
查看>>
emacs 2.4安装问题 ecb
查看>>
ecb里使用自定义快捷键切换窗口
查看>>
vim(gvim)支持对齐线
查看>>
CentOS编译安装Lighttpd1.4.28
查看>>