2. master和slave的匹配过程

(一)master的注册过程

1. 首先来看看master的注册过程,在mxc_v4l2_capture.c文件中,从module_init(camera_init)函数开始,在camera_init函数中通过

err= platform_driver_register(&mxc_v4l2_driver)

来将mxc_v4l2_driver这个驱动注册到platform平台上面,如果有匹配的设备的话,就会调用到mxc_v4l2_driver里面的probe函数。

(下面的分析都是从流程上面来分析,去掉了函数中一些与分析无关的代码,关于函数的详细分析,看《mxc_v4l2_capture.c分析》那一节)


2. 下面来看看这个probe函数

[cpp]  view plain  copy
  1. static int mxc_v4l2_probe(struct platform_device *pdev)   
  2. {   
  3.     /* Create cam and initialize it. */   
  4.     cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL);   
  5.   
  6.     init_camera_struct(cam, pdev);  //初始化cam_data结构体,分析见2.1  
  7.     pdev->dev.release = camera_platform_release;   
  8.   
  9.     /* Set up the v4l2 device and register it*/   
  10.     cam->self->priv = cam;    //将cam_data结构体里面的self里面的priv指针指向自己,在下面的 v4l2_int_device_register 函数中就会用到。  
  11.     v4l2_int_device_register(cam->self); //分析见2.2  
  12.   
  13.     /* register v4l video device */   
  14.     if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) {    //注册video设备  
  15.         kfree(cam);   
  16.         cam = NULL;   
  17.         pr_err("ERROR: v4l2 capture: video_register_device failed\n");   
  18.         return -1;   
  19.     }   
  20. }  

在这个函数中,首先是为cam_data结构体分配了内存,然后就调用init_camera_struct函数来初始化这个cam_data结构体。

2.1 我们来看看这个init_camera_struct函数里面都做了什么:

[cpp]  view plain  copy
  1. static int init_camera_struct(cam_data *cam, struct platform_device *pdev)   
  2. {   
  3.     const struct of_device_id *of_id =   
  4.             of_match_device(mxc_v4l2_dt_ids, &pdev->dev);   
  5.     struct device_node *np = pdev->dev.of_node;   
  6.     int ipu_id, csi_id, mclk_source;   
  7.     int ret = 0;   
  8.     struct v4l2_device *v4l2_dev;   
  9.   
  10.     /* Default everything to 0 */   
  11.     memset(cam, 0, sizeof(cam_data));   
  12.   
  13.     init_MUTEX(&cam->param_lock);   
  14.     init_MUTEX(&cam->busy_lock);   
  15.   
  16.     cam->video_dev = video_device_alloc(); //分配一个video_device结构体  
  17.     *(cam->video_dev) = mxc_v4l_template; //设置ops操作  
  18.   
  19.     video_set_drvdata(cam->video_dev, cam);  //将cam设置为cam->video_dev的私有数据  
  20.     dev_set_drvdata(&pdev->dev, (void *)cam);   
  21.     cam->video_dev->minor = -1;   
  22.   
  23.     v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL);   
  24.   
  25.     if (v4l2_device_register(&pdev->dev, v4l2_dev) < 0) {   
  26.         dev_err(&pdev->dev, "register v4l2 device failed\n");   
  27.         video_device_release(cam->video_dev);   
  28.         kfree(v4l2_dev);   
  29.         return -ENODEV;   
  30.     }   
  31.     cam->video_dev->v4l2_dev = v4l2_dev;   
  32.   
  33.     init_waitqueue_head(&cam->enc_queue);   
  34.     init_waitqueue_head(&cam->still_queue);   
  35.   
  36.     /* setup cropping */   
  37.     cam->crop_bounds.left = 0;   
  38.     cam->crop_bounds.width = 640;   
  39.     cam->crop_bounds.top = 0;   
  40.     cam->crop_bounds.height = 480;   
  41.     cam->crop_current = cam->crop_defrect = cam->crop_bounds;   
  42.     ipu_csi_set_window_size(cam->ipu, cam->crop_current.width,   
  43.                 cam->crop_current.height, cam->csi);   
  44.     ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left,   
  45.                 cam->crop_current.top, cam->csi);   
  46.     cam->streamparm.parm.capture.capturemode = 0;   
  47.   
  48.     cam->standard.index = 0;   
  49.     cam->standard.id = V4L2_STD_UNKNOWN;   
  50.     cam->standard.frameperiod.denominator = 30;   
  51.     cam->standard.frameperiod.numerator = 1;   
  52.     cam->standard.framelines = 480;   
  53.     cam->standard_autodetect = true;   
  54.     cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   
  55.     cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;   
  56.     cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;   
  57.     cam->overlay_on = false;   
  58.     cam->capture_on = false;   
  59.     cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;   
  60.   
  61.     cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;   
  62.     cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;   
  63.     cam->v2f.fmt.pix.width = 288;   
  64.     cam->v2f.fmt.pix.height = 352;   
  65.     cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;   
  66.     cam->win.w.width = 160;   
  67.     cam->win.w.height = 160;   
  68.     cam->win.w.left = 0;   
  69.     cam->win.w.top = 0;   
  70.   
  71.     cam->ipu_id = ipu_id;   
  72.     cam->csi = csi_id;   
  73.     cam->mclk_source = mclk_source;   
  74.     cam->mclk_on[cam->mclk_source] = false;   
  75.   
  76.     cam->enc_callback = camera_callback;     //设置回调函数,这个函数很重要  
  77.     init_waitqueue_head(&cam->power_queue);   
  78.     spin_lock_init(&cam->queue_int_lock);   
  79.     spin_lock_init(&cam->dqueue_int_lock);   
  80.    
  81.     cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);   
  82.     cam->self->module = THIS_MODULE;   
  83.     sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);   
  84.     cam->self->type = v4l2_int_type_master;   
  85.     cam->self->u.master = &mxc_v4l2_master;   
  86.   
  87.     return 0;   
  88. }  

在这个函数中,对cam_data结构体里面的一些变量进行了初始化,设置了一些默认值。同时注意这个函数的最后几步操作,它为cam->self分配了内存,然后设置cam->self->typev4l2_int_type_master,指定了cam->self->u.master&mxc_v4l2_master。这几步有什么作用呢?这个在2.2中分析。


2.2 v4l2_int_device_register数分析

[cpp]  view plain  copy
  1. int v4l2_int_device_register(struct v4l2_int_device *d)   
  2. {   
  3.     if (d->type == v4l2_int_type_slave)   
  4.         sort(d->u.slave->ioctls, d->u.slave->num_ioctls,   
  5.              sizeof(struct v4l2_int_ioctl_desc),   
  6.              &ioctl_sort_cmp, NULL);   
  7.     mutex_lock(&mutex);   
  8.     list_add(&d->head, &int_list);   
  9.     v4l2_int_device_try_attach_all();   
  10.     mutex_unlock(&mutex);   
  11.   
  12.     return 0;   
  13. }   
  14. EXPORT_SYMBOL_GPL(v4l2_int_device_register);  

在这个函数中,首先通过list_add将这个cam->self结构体添加到int_list链表中,最重要的操作就是v4l2_int_device_try_attach_all()函数

[cpp]  view plain  copy
  1. void v4l2_int_device_try_attach_all(void)   
  2. {   
  3.     struct v4l2_int_device *m, *s;   
  4.   
  5.     list_for_each_entry(m, &int_list, head) {   
  6.         if (m->type != v4l2_int_type_master)   
  7.             continue;   
  8.   
  9.         list_for_each_entry(s, &int_list, head) {   
  10.             if (s->type != v4l2_int_type_slave)   
  11.                 continue;   
  12.   
  13.             /* Slave is connected? */   
  14.             if (s->u.slave->master)   
  15.                 continue;   
  16.   
  17.             /* Slave wants to attach to master? */   
  18.             if (s->u.slave->attach_to[0] != 0   
  19.                 && strncmp(m->name, s->u.slave->attach_to,   
  20.                        V4L2NAMESIZE))   
  21.                 continue;   
  22.   
  23.             if (!try_module_get(m->module))   
  24.                 continue;   
  25.   
  26.             s->u.slave->master = m;   
  27.             if (m->u.master->attach(s)) {   
  28.                 s->u.slave->master = NULL;   
  29.                 module_put(m->module);   
  30.                 continue;   
  31.             }   
  32.         }   
  33.     }   
  34. }   
  35. EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);  

这个函数首先从int_list链表中取出type类型为v4l2_int_type_master的结构体保存在m中,然后再取出type类型为v4l2_int_type_slave的结构体保存在s中。然后判断s->u.slave->master是否存在,如果存在的话就跳过继续寻找。这个变量就代表了这个slave设备已经设置了它所对应的master。那么这个变量是在哪设置的呢?继续看这个函数,就在后面设置了:s->u.slave->master= m; 

这两个list_for_each_entry的最终结果就是找到master设备和第一个没有设置masterslave设备。

然后将这个slave设备的u.slave->master设置成找到的master设备m,然后调用mu.master->atach(s)函数,这个函数就是在init_camera_struct函数最后设置的:cam->self->u.master= &mxc_v4l2_master;

[cpp]  view plain  copy
  1. static struct v4l2_int_master mxc_v4l2_master = {   
  2.     .attach = mxc_v4l2_master_attach,   
  3.     .detach = mxc_v4l2_master_detach,   
  4. };  

所以最终会调用到mxc_v4l2_master_attach函数,同时这个函数的行参是这个slave设备s

[cpp]  view plain  copy
  1. static int mxc_v4l2_master_attach(struct v4l2_int_device *slave)   
  2. {   
  3.     cam_data *cam = slave->u.slave->master->priv;   
  4.     struct v4l2_format cam_fmt;   
  5.     int i;   
  6.     struct sensor_data *sdata = slave->priv;   
  7.   
  8.     pr_debug("In MVC: mxc_v4l2_master_attach\n");   
  9.     pr_debug("   slave.name = %s\n", slave->name);   
  10.     pr_debug("   master.name = %s\n", slave->u.slave->master->name);   
  11.   
  12.     if (slave == NULL) {   
  13.         pr_err("ERROR: v4l2 capture: slave parameter not valid.\n");   
  14.         return -1;   
  15.     }   
  16.   
  17.     if (sdata->csi != cam->csi) {   
  18.         pr_debug("%s: csi doesn't match\n", __func__);   
  19.         return -1;   
  20.     }   
  21.   
  22.     cam->sensor = slave;   
  23.   
  24.     if (cam->sensor_index < MXC_SENSOR_NUM) {   
  25.         cam->all_sensors[cam->sensor_index] = slave;   
  26.         cam->sensor_index++;   
  27.     } else {   
  28.         pr_err("ERROR: v4l2 capture: slave number exceeds "   
  29.                "the maximum.\n");   
  30.         return -1;   
  31.     }   
  32.   
  33.     for (i = 0; i < cam->sensor_index; i++) {   
  34.         vidioc_int_dev_exit(cam->all_sensors[i]);   
  35.         vidioc_int_s_power(cam->all_sensors[i], 0);   
  36.     }   
  37.    
  38.     cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;   
  39.     vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt);   
  40.   
  41.     /* Used to detect TV in (type 1) vs. camera (type 0)*/   
  42.     cam->device_type = cam_fmt.fmt.pix.priv;   
  43.   
  44.     /* Set the input size to the ipu for this device */   
  45.     cam->crop_bounds.top = cam->crop_bounds.left = 0;   
  46.     cam->crop_bounds.width = cam_fmt.fmt.pix.width;   
  47.     cam->crop_bounds.height = cam_fmt.fmt.pix.height;   
  48.   
  49.     /* This also is the max crop size for this device. */   
  50.     cam->crop_defrect.top = cam->crop_defrect.left = 0;   
  51.     cam->crop_defrect.width = cam_fmt.fmt.pix.width;   
  52.     cam->crop_defrect.height = cam_fmt.fmt.pix.height;   
  53.   
  54.     /* At this point, this is also the current image size. */   
  55.     cam->crop_current.top = cam->crop_current.left = 0;   
  56.     cam->crop_current.width = cam_fmt.fmt.pix.width;   
  57.     cam->crop_current.height = cam_fmt.fmt.pix.height;   
  58.   
  59.     return 0;   
  60. }  

在这个函数中设置了cam->sensor= slave;然后又设置了crop的一些参数。而这些crop参数都是根据slave结构体来设置的。在init_camera_struct函数中只是给了这些crop参数一些初始默认值,在这个函数中才是根据真正从slave设备中获取到的参数来填充crop参数。



(二)slave的注册过程

3. 以上是master的注册过程,再来看看slave的注册过程。以ov5640.c为例:

3.1 module_i2c_driver(ov5640_i2c_driver);

[cpp]  view plain  copy
  1. static struct i2c_driver ov5640_i2c_driver = {   
  2.     .driver = {   
  3.           .owner = THIS_MODULE,   
  4.           .name  = "ov564x",   
  5.           },   
  6.     .probe  = ov5640_probe,   
  7.     .remove = ov5640_remove,   
  8.     .id_table = ov5640_id,   
  9. };   

之后就会调用到ov5640_probe函数。


3.2 ov5640_probe函数

[cpp]  view plain  copy
  1. static int ov5640_probe(struct i2c_client *client,   
  2.             const struct i2c_device_id *id)   
  3. {   
  4.     struct pinctrl *pinctrl;   
  5.     struct device *dev = &client->dev;   
  6.     int retval;   
  7.     u8 chip_id_high, chip_id_low;   
  8.   
  9.     /* ov5640 pinctrl */   
  10.     pinctrl = devm_pinctrl_get_select_default(dev);   
  11.     if (IS_ERR(pinctrl)) {   
  12.         dev_err(dev, "setup pinctrl failed\n");   
  13.         return PTR_ERR(pinctrl);   
  14.     }   
  15.   
  16.     /* request power down pin */   
  17.     pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0);   
  18.     if (!gpio_is_valid(pwn_gpio)) {   
  19.         dev_err(dev, "no sensor pwdn pin available\n");   
  20.         return -ENODEV;   
  21.     }   
  22.     retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH,   
  23.                     "ov5640_pwdn");   
  24.     if (retval < 0)   
  25.         return retval;   
  26.   
  27.     /* request reset pin */   
  28.     rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);   
  29.     if (!gpio_is_valid(rst_gpio)) {   
  30.         dev_err(dev, "no sensor reset pin available\n");   
  31.         return -EINVAL;   
  32.     }   
  33.     retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH,   
  34.                     "ov5640_reset");   
  35.     if (retval < 0)   
  36.         return retval;   
  37.   
  38.     /* Set initial values for the sensor struct. */   
  39.     memset(&ov5640_data, 0, sizeof(ov5640_data));   
  40.     ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk");   
  41.     if (IS_ERR(ov5640_data.sensor_clk)) {   
  42.         dev_err(dev, "get mclk failed\n");   
  43.         return PTR_ERR(ov5640_data.sensor_clk);   
  44.     }   
  45.   
  46.     retval = of_property_read_u32(dev->of_node, "mclk",   
  47.                     &ov5640_data.mclk);   
  48.     if (retval) {   
  49.         dev_err(dev, "mclk frequency is invalid\n");   
  50.         return retval;   
  51.     }   
  52.   
  53.     retval = of_property_read_u32(dev->of_node, "mclk_source",   
  54.                     (u32 *) &(ov5640_data.mclk_source));   
  55.     if (retval) {   
  56.         dev_err(dev, "mclk_source invalid\n");   
  57.         return retval;   
  58.     }   
  59.   
  60.     retval = of_property_read_u32(dev->of_node, "csi_id",   
  61.                     &(ov5640_data.csi));   
  62.     if (retval) {   
  63.         dev_err(dev, "csi_id invalid\n");   
  64.         return retval;   
  65.     }   
  66.   
  67.     clk_prepare_enable(ov5640_data.sensor_clk);   
  68.   
  69.     ov5640_data.io_init = ov5640_reset;   
  70.     ov5640_data.i2c_client = client;   
  71.     ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV;   
  72.     ov5640_data.pix.width = 640;   
  73.     ov5640_data.pix.height = 480;   
  74.     ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY |   
  75.                        V4L2_CAP_TIMEPERFRAME;   
  76.     ov5640_data.streamcap.capturemode = 0;   
  77.     ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS;   
  78.     ov5640_data.streamcap.timeperframe.numerator = 1;   
  79.   
  80.     ov5640_regulator_enable(&client->dev);   
  81.   
  82.     ov5640_reset();   
  83.   
  84.     ov5640_power_down(0);   
  85.   
  86.     retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high);   
  87.     if (retval < 0 || chip_id_high != 0x56) {   
  88.         clk_disable_unprepare(ov5640_data.sensor_clk);   
  89.         pr_warning("camera ov5640 is not found\n");   
  90.         return -ENODEV;   
  91.     }   
  92.     retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low);   
  93.     if (retval < 0 || chip_id_low != 0x40) {   
  94.         clk_disable_unprepare(ov5640_data.sensor_clk);   
  95.         pr_warning("camera ov5640 is not found\n");   
  96.         return -ENODEV;   
  97.     }   
  98.   
  99.     ov5640_power_down(1);   
  100.   
  101.     clk_disable_unprepare(ov5640_data.sensor_clk);   
  102.   
  103.     ov5640_int_device.priv = &ov5640_data;   
  104.     retval = v4l2_int_device_register(&ov5640_int_device);   
  105.   
  106.     pr_info("camera ov5640 is found\n");   
  107.     return retval;   
  108. }  

这个函数主要是设置ov5640_data结构体的一些值,通过几个of函数来获取到的信息填充到这个结构体中。然后最后调用到了v4l2_int_device_register这个函数。这个函数同样在上面的mxc_v4l2_probe中调用了。不同的是注册的ov5640_int_device结构体,在mxc_v4l2_probe中注册的是cam->self结构体,这两个结构体都是v4l2_int_device类型的:

[cpp]  view plain  copy
  1. static struct v4l2_int_device ov5640_int_device = {   
  2.     .module = THIS_MODULE,   
  3.     .name = "ov564x",   
  4.     .type = v4l2_int_type_slave,   
  5.     .u = {   
  6.         .slave = &ov5640_slave,   
  7.     },   
  8. };  

可以看到,这个ov5640_int_device构体中设置的type类型是v4l2_int_type_slave,同时u设置的是slave。再次对比init_camera_struct函数中master是怎么设置的:

[cpp]  view plain  copy
  1. cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL);   
  2. cam->self->module = THIS_MODULE;   
  3. sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi);   
  4. cam->self->type = v4l2_int_type_master;   
  5. cam->self->u.master = &mxc_v4l2_master;  

然后调用v4l2_int_device_register函数,在里面通过list_add将这个设备添加到int_list链表中,所以这个链表中的设备既包括master设备,同时也包括slave设备。在这里,每添加进去一个设备,这个int_list链表中都会增加一个slave设备,同时master设备就是cam->self结构体。从这个链表中取出设备的话,需要根据这个type类型来区分。

之后在v4l2_int_device_register函数继续调用v4l2_int_device_try_attach_all()函数,这个函数在上面已经分析很清楚了,会从int_list链表找到master设备和第一个没有设置masterslave设备,然后将这个slave设备的u.slave->master设置成找到的master设备m,然后调用mu.master->attach(s)函数,完成匹配过程。

这个v4l2_int_device_try_attach_all()函数在master设备或者slave设备注册进链表的时候,都会调用到,都会互相去匹配。

4.当在应用程序执行open的时候,再次通过vidioc_int_g_fmt_cap函数获取了cam->sensor的信息,此时经过上面那些步骤,cam->sensor已经指向了找到的slave设备。重新设置crop的一些值,在这里通过ipu_csi_set_window_sizeipu_csi_set_window_pos等操作将这些值写到了寄存器中。


关于这个流程,我画了一个思维导图来辅助理解:







  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值