Linux camera驱动(5) - open详解

1. 用户空间进行open操作

        在Linux camera驱动(3) - 框架中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.c
static 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.c
static 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,可以回看《Linux camera驱动(3) - 框架》进行确认*/
	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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值