深入浅出,camera v4l2理解(2)v4l2注册

来源:互联网 发布:mysql手机版 编辑:程序博客网 时间:2024/05/22 16:43
正式步入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);
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 洗车把内饰划了怎么办 新车销售没销量怎么办 住院时间重叠了怎么办 长安cs75油耗高怎么办 墙内线烧了怎么办 如果没买票想进高铁站怎么办 老赖拒绝还款怎么办 gta5资产不兼容怎么办 平板黑屏闪退怎么办 施工证学历不够怎么办 隧道放炮声大怎么办 58工作被骗了怎么办 学历国家不承认怎么办 福州居住证一年到期怎么办 居住证过期2年怎么办 被房东坑了怎么办 房东违反了合同怎么办 上海居住证过期了怎么办 地铁卡消磁了怎么办 学生卡消磁了怎么办 家属院没房产证怎么办 邮箱收不到邮件怎么办 大学宿舍八人间怎么办 高中档案袋拆了怎么办 公派教师回国后怎么办? 事业单位辞职后档案怎么办 学信支付不了怎么办 校外怎么办北邮校园卡 报考身份证丢了怎么办 买房怎么办不取消低保 自考找不到真题怎么办 自考生考研没有档案怎么办 自考本科无学位怎么办 自考学位证书没拿到怎么办 自考毕业证出生日期错误怎么办 成考没有学位证怎么办 评职称学历认证怎么办 国家不承认学历怎么办 高考分数错了怎么办 签合同了不想干怎么办 贵港教育小学插班生怎么办