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

正式步入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 = v4 l2_get_subdevdata( pcam->sens or_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注册)