正式步入v4l2_i2c_subdev_init
这个是什么呢,看代码:
这个是在v4l2-common里面:
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops)
{
        v4l2_subdev_init(sd, ops);    //这个地方属于初始化,也就是申请相关空间
        sd->flags |= V4L2_SUBDEV_FL_IS_I2C;  //说明这个是个i2c的
        /* the owner is the same as the i2c_client's driver owner */
        sd->owner = client->driver->driver.owner;
        /* i2c_client and v4l2_subdev point to one another */
        v4l2_set_subdevdata(sd, client);   //相互保存数据
        i2c_set_clientdata(client, sd);    //相互保存数据
        /* initialize name */
        snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",  //在这个地方这个name改变了,这里也就是注册mipi的时候用到的名字,每个mipi的每个线都要和这个名字对应,分别是name-所在的i2c总线-i2c的地址
                client->driver->driver.name, i2c_adapter_id(client->adapter),
                client->addr);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
这个函数主要起到保存参数的总用,后续调用更加的方便。
在这个函数后,真正对v4l2配置的在下面这个函数:
/* register a msm sensor into the msm device, which will probe the
 * sensor HW. if the HW exist then create a video device (/dev/videoX/)
 * to represent this sensor */
一个v4l2的接口在/dev/videoX/每一个videoX对应一个v4l2的设备节点,从这个开始才是v4l2的重点:
int msm_sensor_register(struct v4l2_subdev *sensor_sd)
{
       int rc = -EINVAL;
       struct msm_camera_sensor_info *sdata;
       struct msm_cam_v4l2_device *pcam;
       struct msm_sensor_ctrl_t *s_ctrl;
       D("%s for %s\n", __func__, sensor_sd->name);
       /* allocate the memory for the camera device first */
       pcam = kzalloc(sizeof(*pcam), GFP_KERNEL);
       if (!pcam) {
              pr_err("%s: could not allocate mem for msm_cam_v4l2_device\n",
                     __func__);
              return -ENOMEM;
       }
       pcam->sensor_sdev = sensor_sd;   //这个sensor_sd,就是一个v4l2的name而已,里面的成员只做了赋值为0的初始化动作,后面会看到它的羽翼逐渐丰满。
       s_ctrl = get_sctrl(sensor_sd);
       sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;//这个很眼熟,不就是那个board中的msm_camera_sensor_info嘛!它包含了对sensor的很多信息,power啊reset啊 是否是有yuv的还是raw的,有没有对焦啊,什么都有!
       pcam->act_sdev = msm_actuator_probe(sdata->actuator_info);//这个地方看了对马达的probe了没,马达的i2c的probe就是从这个地方开始的
       pcam->eeprom_sdev = msm_eeprom_probe(sdata->eeprom_info); //这个地方对应board中的eeprom_info
       D("%s: pcam =0x%p\n", __func__, pcam);
       pcam->sdata = sdata;   //msm_camera_sensor_info进去了
       /* init the user count and lock*/
       pcam->use_count = 0;
       mutex_init(&pcam->vid_lock);
       mutex_init(&pcam->mctl_node.dev_lock);
       /* Initialize the formats supported */
       rc  = msm_mctl_init_user_formats(pcam);
/**************************************************************************************************/
这个函数主要是对camera输出的格式定义,这样v4l2才可以接受
int msm_mctl_init_user_formats(struct msm_cam_v4l2_device *pcam)
{
       struct v4l2_subdev *sd = pcam->sensor_sdev;
       enum v4l2_mbus_pixelcode pxlcode;
       int numfmt_sensor = 0;
       int numfmt = 0;
       int rc = 0;
       int i, j;
       D("%s\n", __func__);
       while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, numfmt_sensor,    //别看了这个是用来判断是否存在pxlcode空指针的,用这个来判断你个v4l2支持多个格式
                                                        &pxlcode))
              numfmt_sensor++;       //格式的数量加加~
       D("%s, numfmt_sensor = %d\n", __func__, numfmt_sensor);
       if (!numfmt_sensor)
              return -ENXIO;
       pcam->usr_fmts = vmalloc(numfmt_sensor * ARRAY_SIZE(msm_isp_formats) * //知不知道v4l2对sensor输出格式的接受是有
                            sizeof(struct msm_isp_color_fmt));  //明确的定义的?这个函数的意思是在所有的可以接受的格式先保存下来,很多十多组吧。
       if (!pcam->usr_fmts)
              return -ENOMEM;
       /* from sensor to ISP.. fill the data structure */
       for (i = 0; i < numfmt_sensor; i++) {                                  //这里对每一个v4l2选择他对应的输出格式,有一个,配一个,可配置多个,也就是说一个sensor可能支持多个格式的输出嘛~
              rc = v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &pxlcode);   //循环取pxlcode空指针的,空了推出
              D("rc is  %d\n", rc);
              if (rc < 0) {
                     vfree(pcam->usr_fmts);
                     return rc;
              }
              for (j = 0; j < ARRAY_SIZE(msm_isp_formats); j++) {             //找一找pxlcode是否能匹配,不能换下一个pxlcode,一个sensor能提供多个pxlcode
                     /* find the corresponding format */
                     if (pxlcode == msm_isp_formats[j].pxlcode) {
                            pcam->usr_fmts[numfmt] = msm_isp_formats[j];
                            D("pcam->usr_fmts=0x%x\n", (u32)pcam->usr_fmts);
                            D("format pxlcode 0x%x (0x%x) found\n",
                                     pcam->usr_fmts[numfmt].pxlcode,//如果你配置的参数在列表中有,恭喜你匹配成功,记录在pcam->usr_fmts[numfmt].pxlcode
                                     pcam->usr_fmts[numfmt].fourcc);////如果你配置的参数在列表中有,恭喜你匹配成功,记录在pcam->usr_fmts[numfmt].pxlcode
                            numfmt++;
                     }
              }
       }
       pcam->num_fmts = numfmt;   //你有多少个支持的格式啊?
       if (numfmt == 0) {      //老子没有!
              pr_err("%s: No supported formats.\n", __func__);
              vfree(pcam->usr_fmts);
              return -EINVAL;  //滚粗!
       }
       D("Found %d supported formats.\n", pcam->num_fmts);
       /* set the default pxlcode, in any case, it will be set through
        * setfmt */
       return 0;
}

/**************************************************************************************************/
       if (rc < 0)
              goto failure;
       rc  = msm_cam_dev_init(pcam);
       if (rc < 0)
              goto failure;

/*************************************************************************************************

static int msm_cam_dev_init(struct msm_cam_v4l2_device *pcam)
{
       int rc = -ENOMEM;
       struct video_device *pvdev = NULL;
       struct i2c_client *client =v4l2_get_subdevdata(pcam->sensor_sdev);  //之前保存的现在拿出来用了
       D("%s\n", __func__);
       /* first register the v4l2 device */
       pcam->v4l2_dev.dev = &client->dev;
       rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);    //初始化参数用
       if (rc < 0)
              return -EINVAL;
          /*********************************************
             int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
           {
               if (v4l2_dev == NULL)
                 return -EINVAL;
              INIT_LIST_HEAD(&v4l2_dev->subdevs);
              spin_lock_init(&v4l2_dev->lock);
              mutex_init(&v4l2_dev->ioctl_lock);
              v4l2_prio_init(&v4l2_dev->prio);
              kref_init(&v4l2_dev->ref);
              get_device(dev);
              v4l2_dev->dev = dev;
              if (dev == NULL) {
                 /* If dev == NULL, then name must be filled in by the caller */
                  WARN_ON(!v4l2_dev->name[0]);
                 return 0;
           }
       /* Set name to driver name + device name if it is empty. */
       if (!v4l2_dev->name[0])
              snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
                     dev->driver->name, dev_name(dev));
       if (!dev_get_drvdata(dev))
              dev_set_drvdata(dev, v4l2_dev);
       return 0;
}
EXPORT_SYMBOL_GPL(v4l2_device_register);
/**********************************************

       else
              pcam->v4l2_dev.notify = msm_cam_v4l2_subdev_notify;
       /* now setup video device */
       pvdev = video_device_alloc();                  //申请一个video
       if (pvdev == NULL) {
              pr_err("%s: video_device_alloc failed\n", __func__);
              return rc;
       }
       strlcpy(pcam->media_dev.model, QCAMERA_NAME,
                     sizeof(pcam->media_dev.model));
       pcam->media_dev.dev = &client->dev;            
       rc = media_device_register(&pcam->media_dev);   //注册一个media
       pvdev->v4l2_dev = &pcam->v4l2_dev;
       pcam->v4l2_dev.mdev = &pcam->media_dev;      //注意这个v4l2_dev,包含了很多,很重要
       /* init video device's driver interface */   //接口和操作
       D("sensor name = %s, sizeof(pvdev->name)=%d\n",
              pcam->sensor_sdev->name, sizeof(pvdev->name));
       /* device info - strlcpy is safer than strncpy but
          only if architecture supports*/
       strlcpy(pvdev->name, pcam->sensor_sdev->name, sizeof(pvdev->name));
       pvdev->release   = video_device_release;
       pvdev->fops     = &g_msm_fops;
       pvdev->ioctl_ops = &g_msm_ioctl_ops;
       pvdev->minor   = -1;
       pvdev->vfl_type  = 1;
       media_entity_init(&pvdev->entity, 0, NULL, 0);
       pvdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
       pvdev->entity.group_id = QCAMERA_VNODE_GROUP_ID;
       /* register v4l2 video device to kernel as /dev/videoXX */
       D("video_register_device\n");
       rc = video_register_device(pvdev,
                                   VFL_TYPE_GRABBER,
                                   msm_camera_v4l2_nr);
       if (rc) {
              pr_err("%s: video_register_device failed\n", __func__);
              goto reg_fail;
       }
       pvdev->entity.name = video_device_node_name(pvdev);
       D("%s: video device registered as /dev/video%d\n",
              __func__, pvdev->num);
       /* connect pcam and video dev to each other */
       pcam->pvdev   = pvdev;
       video_set_drvdata(pcam->pvdev, pcam);
       /* If isp HW registeration is successful,
        * then create event queue to
        * receievent event froms HW
       */
       /* yyan: no global - each sensor will
        * create a new vidoe node! */
       /* g_pmsm_camera_v4l2_dev = pmsm_camera_v4l2_dev; */
       /* g_pmsm_camera_v4l2_dev->pvdev = pvdev; */
       return rc ;
reg_fail:
       video_device_release(pvdev);
       v4l2_device_unregister(&pcam->v4l2_dev);
       pcam->v4l2_dev.dev = NULL;
       return rc;
}

/************************************************************************************************

       rc = msm_setup_mctl_node(pcam);
       if (rc < 0) {
              pr_err("%s:failed to create mctl device: %d\n",
                      __func__, rc);
              goto failure;
       }
       g_server_dev.camera_info.video_dev_name
       [g_server_dev.camera_info.num_cameras]
       = video_device_node_name(pcam->pvdev);
       D("%s Connected video device %s\n", __func__,
              g_server_dev.camera_info.video_dev_name
              [g_server_dev.camera_info.num_cameras]);
       g_server_dev.camera_info.s_mount_angle
       [g_server_dev.camera_info.num_cameras]
       = sdata->sensor_platform_info->mount_angle;
       g_server_dev.camera_info.is_internal_cam
       [g_server_dev.camera_info.num_cameras]
       = sdata->camera_type;
       g_server_dev.mctl_node_info.mctl_node_name
       [g_server_dev.mctl_node_info.num_mctl_nodes]
       = video_device_node_name(pcam->mctl_node.pvdev);
       pr_info("%s mctl_node_name[%d] = %s\n", __func__,
              g_server_dev.mctl_node_info.num_mctl_nodes,
              g_server_dev.mctl_node_info.mctl_node_name
              [g_server_dev.mctl_node_info.num_mctl_nodes]);
       /*Temporary solution to store info in media device structure
         until we can expand media device structure to support more
         device info*/
       snprintf(pcam->media_dev.serial,
                     sizeof(pcam->media_dev.serial),
                     "%s-%d-%d", QCAMERA_NAME,
                     sdata->sensor_platform_info->mount_angle,
                     sdata->camera_type);
       g_server_dev.camera_info.num_cameras++;
       g_server_dev.mctl_node_info.num_mctl_nodes++;
       D("%s done, rc = %d\n", __func__, rc);
       D("%s number of sensors connected is %d\n", __func__,
              g_server_dev.camera_info.num_cameras);
       /* register the subdevice, must be done for callbacks */
       rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
       if (rc < 0) {
              D("%s sensor sub device register failed\n",
                     __func__);
              goto failure;
       }
       if (pcam->act_sdev) {
              rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
                            pcam->act_sdev);
              if (rc < 0) {
                     D("%s actuator sub device register failed\n",
                       __func__);
                     goto failure;
              }
       }
       if (pcam->eeprom_sdev) {
              rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
                     pcam->eeprom_sdev);
              if (rc < 0) {
                     D("%s eeprom sub device register failed\n", __func__);
                     goto failure;
              }
       }
       pcam->vnode_id = vnode_count++;
       return rc;
failure:
       kzfree(pcam);
       return rc;
}
EXPORT_SYMBOL(msm_sensor_register);

深入浅出,camera v4l2理解(2)v4l2注册相关推荐

  1. 深入浅出,camera v4l2理解

    深入浅出,camera v4l2理解(1)v4l2准备使用的参数 1,probe 2,读id,id读完了并且成功才能注册v4l2   3,注册v4l2, v4l2_i2c_subdev_init(&a ...

  2. [深入浅出C语言]理解取整、取余和取模

    关于C语言的取模运算,也许你只了解正数取模,而从未接触过负数取模,本文就来分享一波C语言取整.取模和取余的个人学习经验与心得,希望对你有所帮助. 笔者水平有限,难免存在纰漏,欢迎指正交流. 关于取整 ...

  3. 网络编程懒人入门(七):深入浅出,全面理解HTTP协议

    转自即时通讯网:http://www.52im.net/ 本文引用了自简书作者"涤生_Woo"的文章,内容有删减,感谢原作者的分享. 1.前言 HTTP(全称超文本传输协议,英文全 ...

  4. three.js基础教程学习之camera的理解

    最近学习了three.js基础教程,由于WebGL中文网中对camera的解说不够详细,自己又找了几篇博文看,以下是我对camera的理解,有错误的地方希望得到大佬们的指出,同时也希望能帮到像我一样的 ...

  5. 网络编程之深入浅出,全面理解HTTP协议

    网络编程之深入浅出,全面理解HTTP协议 前言 "HTTP之父"其人 HTTP概述 计算机网络体系结构分层 TCP/IP 通信传输流 HTTP 请求如下图所示: HTTP 工作过程 ...

  6. java单点登录跨域_深入浅出让你理解跨域与SSO单点登录原理与技术

    原标题:深入浅出让你理解跨域与SSO单点登录原理与技术 一:SSO体系结构 SSO SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互 ...

  7. camera、sensor,v4l2基础知识

    结构和工作原理 (1).工作原理:物体通过镜头(lens)聚集的光,通过CMOS或CCD集成电路,把光信号转换成电信号,再经过内部图像处理器(ISP)转换成数字图像信号输出到数字信号处理器(DSP)加 ...

  8. Open images from USB camera on linux using V4L2 with OpenCV

    I have always been using OpenCV's VideoCapture API to capture images from webcam or USB cameras. Ope ...

  9. Linux驱动学习--V4L2设备(一)驱动注册流程及meida_device介绍

    目录 一.引言 二.v4l2设备注册过程 ------> v4l2_device_register ------> video_register_device ------> v4l ...

最新文章

  1. [leetcode]Multiply Strings @ Python
  2. c语言 memset 段错误,段错误之memset对类对象的误用
  3. 第七章 oracle的服务启动顺序、认证方式、
  4. slope one matlab代码,经典推荐算法之 Slope one
  5. 计算机应用基础win7.pdf,计算机应用基础WIn7操作题(12页)-原创力文档
  6. Ubuntu 系统调整LVM卷/home分区到 / 分区
  7. python教程视频-Python基础视频教程(600集)【传智播客精品教程】
  8. uestc--758--P酱的冒险旅途
  9. centos7 redis分布式集群问题总结
  10. 泰坦尼克号python数据分析统计服_Python数据分析及可视化实例之泰坦尼克号存活预测(23)...
  11. 网格搜索、随机搜索机器学习实战
  12. softmax 惩罚函数推到过程 转载
  13. win32 x64 x86 区别
  14. 金融人都在选择的硕士项目---中国人民大学与加拿大女王大学金融硕士
  15. 支付宝小程序沙箱支付提示(系统繁忙,请稍后再试)
  16. 蔡学镛:如何进入程序设计的领域- -
  17. 〖Python自动化办公篇⑬〗- Excel 文件自动化 - 写入 excel 数据(xlsxwriter)
  18. 全面了解风控指标体系
  19. 第05章 深度卷积神经网络模型
  20. vc mfc Edit SetFocus 设置焦点 无效 失败

热门文章

  1. linux 中ps -ef | grep java命令
  2. python selenium unittest_python+selenium+unittest UI自动化
  3. 杰里之关于 PWM 部分的补充篇
  4. Java转大数据开发全套视频资料
  5. 2.4.2 算术逻辑单元的功能和结构(改进)
  6. 统计1到N(含)之间所有立方数的个数,并输出这个数目
  7. 详解固态硬盘的有趣知识及其底层原理
  8. 上海航芯技术分享 | 基于SPI Flash的U盘程序,从STM32F103到ACM32F403
  9. 有关S-D5舵机的控制
  10. 虚拟内存不足造成的蓝屏_问题分析及解决