本文共 5111 字,大约阅读时间需要 17 分钟。
在中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,};
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
//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/