深入浅出,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);