深入浅出,camera v4l2理解

 

深入浅出,camera v4l2理解(1)v4l2准备使用的参数 1,probe


2,读id,id读完了并且成功才能注册v4l2
 
3,注册v4l2,
v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,s_ctrl->sensor_v4l2_subdev_ops);
这里v4l2的注册需要几个参数
s_ctrl->sensor_v4l2_subdev
这个参数主要是v4l2的名字,这个name是从驱动中去读的,如下
snprintf(s_ctrl->sensor_v4l2_subdev.name,sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);


client
这个参数是i2c的client,从驱动中获取,读id的时候使用的那个


s_ctrl->sensor_v4l2_subdev_ops
这个参数是驱动中的imx111_subdev_ops
static struct v4l2_subdev_core_ops imx111_subdev_core_ops = {
  .ioctl                     = msm_sensor_subdev_ioctl,   //各种效果等控制参数的传递
  .s_power                   = msm_sensor_power,          //power
};


static struct v4l2_subdev_video_ops imx111_subdev_video_ops = {
  .enum_mbus_fmt             = msm_sensor_v4l2_enum_fmt,
};


static struct v4l2_subdev_ops imx111_subdev_ops = {
  .core                      = &imx111_subdev_core_ops,   //见上面
  .video                     = &imx111_subdev_video_ops,  //见上面
};


int32_t msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
                        enum v4l2_mbus_pixelcode *code)
{
       struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);   //这边不用说,还是驱动那个s_ctrl


       if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size) //这里就是看你准备了多少种code,看看是不是超出了所定义的 
              return -EINVAL;


       *code = s_ctrl->sensor_v4l2_subdev_info[index].code;   //调用驱动中的code
       return 0;
}
static struct v4l2_subdev_info imx111_subdev_info[] = {       //这个在驱动里面,就是上面的那个info
  {
    .code                    = V4L2_MBUS_FMT_SRGGB10_1X10,
    .colorspace              = V4L2_COLORSPACE_JPEG,
    .fmt                     = 1,
    .order                   = 0,
  },
};
深入浅出,camera v4l2理解(2)v4l2注册
2013-06-04 16:36 290人阅读 评论(0) 收藏 举报
正式步入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);

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值