您的位置:首页 > 运维架构 > 网站架构

V4L2 soc camera 分析 - 系统架构图

2015-11-21 21:34 1306 查看

V4L2 soc camera 分析 - 系统架构图



图1 soc camera 子系统 系统架构图

Soc camera sub-system对应着drivers/media/video/下的soc_camera.c soc_camera_platform.c

Soc camera host 是host端实现,是由平台厂商实现的,向上实现soc_camera_host_ops接口,向下操作Camera host硬件以及通过平台特定的接口操作Soc camera device

Soc camera device 是平台的camera device(同时也是subdev),由驱动开发者来实现v4l2_subdev_call调用的subdev 接口,同时还要为soc camera host实现平台特定的操作接口;向下操作camera sensor或者video AD芯片。

Camera host hardware是平台硬件相关的,不同的平台有不同的host硬件,比如imx51的ipu,三星s5pv210的fimc控制器等。

V4L2 soc-camera 分析 - 调用关系

应用层通过设备节点/dev/videoX打开video4linux devices。/dev/videoX是一个字符设备,主设备号81,次设备号: (0~63)分配给capture设备,64~127分配给radio设备,223~255分配给VBI设备,128~191分配给其他类型的。

如果驱动要注册一个video4linux设备,那么需要调用video_register_device函数。

利用dump_stack函数,可以方便的获取内核函数调用关系。

open调用关系

从调用关系角度来看,open是最复杂的,因为它不仅要执行真正的打开操作,还需要为mmap ioctl设置操作函数。

1. Application 通过open打开设备节点/dev/videoX

2. 进入系统调用sys_open,sys_open调用do_sys_open

3. do_sys_open 调用 do_flip_open

4. do_filp_open 这个函数比较长,大部分都是路径查找相关的代码,这里只需要关注do_last

5. do_last 大部分是路径相关的代码,只需关注finish_open

6. finish_open 调用这个函数时,已经填充好了路径名对应的nameidata结构,调用nameidata_to_flip

7. nameidata_to_flip 调用__dentry_open

8. __dentry_open会调用chrdev_open,在__dentry_open中有如下代码片段

[cpp]
view plaincopy

f->f_op = fops_get(inode->i_fop);
.....
if (!open && f->f_op)
open = f->f_op->open;
if (open) {
error = open(inode, f);
if (error)
goto cleanup_all;
}

当系统进行路径lookup过程中,会把这个设备文件对应的inode读入到内存中,在读取文件inode的过程中,判断这个inode是下列类型中的哪一个:regualr,char,block,pipe。此时,会根据inode类型的不同,赋给inode->i_fop不同的操作函数

在当前的case,shmem_get_inode会调用init_special_inode初始化这个inode,由于/dev/videoX是字符设备,所以inode->i_fop = &def_chr_fops。def_chr_fops.open = chrdev_open

9. chrdev_open 根据设备节点的主次设备好在系统内查找对应的cdev对象,把cdev->ops赋给filp->f_op(这个赋值操作是很重要的步骤,它把filp和具体设备的操作函数联系到一起),当前的case,cdev->ops是v4l2_ops。调用filp->f_op->open就完成了打开操作,flip->f_op->open则是v4l2_open。

10. v4l2_open 中调用vdev->fops->open,对于soc camera来说,我们在调用video_register_device之前,已经把vdev->fops设置为soc_camera_fops。vdev->fops->open也就是调用soc_camera_open

11. 绕了很大一圈,终于调用了soc_camera_open。

mmap调用关系

1. 系统调用mmap_pgoff,mmap_pgoff调用do_mmap_pgoff

2. do_mmap_pgoff,调用mmap_region

3. mmap_region 调用filp->f_op->mmap,在第一次打开文件时,open操作设置了file->f_op为v4l2_ops,file->f_op->mmap则是v4l2_mmap

4. v4l2_mmap,v4l2_mmap调用vdev->fops->mmap,对于soc_camera来说,vdev->fops是soc_camera_ops,所以vdev->fops->mmap是soc_camera_mmap

5. soc_camera_mmap

ioctl调用关系

1. 系统调用ioctl,调用do_vfs_ioctl

2. do_vfs_ioctl ,调用vfs_ioctl

3. vfs_ioctl 代码片段

[cpp]
view plaincopy

if (filp->f_op->unlocked_ioctl) {
error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
if (error == -ENOIOCTLCMD)
error = -EINVAL;
goto out;
} else if (filp->f_op->ioctl) {
lock_kernel();
error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
filp, cmd, arg);
unlock_kernel();
}

在第一次打开文件时,已经设置了filp->f_op为v4l2_ops。注意不同内核版本中v4l2_ops实现是不同的,可能定义了ioctl,也可能定义了unlocked_ioctl。我的kernel v4l2_ops定义如下

[cpp]
view plaincopy

static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};

因此filep->f_op_unlocked_ioctl是v4l2_ioctl

5. v4l2_ioctl 代码片段如下

[cpp]
view plaincopy

if (vdev->fops->unlocked_ioctl) {
if (vdev->lock && mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
if (vdev->lock)
mutex_unlock(vdev->lock);

soc_camera_fops.unlocked_ioctl = video_ioctl2

6. video_ioctl2 调用__video_do_ioctl

7. __video_do_ioctl,这个函数对参数做一些基本的判断,然后调用video_device的ioctl_ops,对于soc_camera系统来说,是soc_camera_ioctl_ops

8 soc_camera_ioctl_ops实现如下

[cpp]
view plaincopy

static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_querycap = soc_camera_querycap,
.vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
.vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
.vidioc_enum_input = soc_camera_enum_input,
.vidioc_g_input = soc_camera_g_input,
.vidioc_s_input = soc_camera_s_input,
.vidioc_s_std = soc_camera_s_std,
.vidioc_reqbufs = soc_camera_reqbufs,
.vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
.vidioc_querybuf = soc_camera_querybuf,
.vidioc_qbuf = soc_camera_qbuf,
.vidioc_dqbuf = soc_camera_dqbuf,
.vidioc_streamon = soc_camera_streamon,
.vidioc_streamoff = soc_camera_streamoff,
.vidioc_queryctrl = soc_camera_queryctrl,
.vidioc_g_ctrl = soc_camera_g_ctrl,
.vidioc_s_ctrl = soc_camera_s_ctrl,
.vidioc_cropcap = soc_camera_cropcap,
.vidioc_g_crop = soc_camera_g_crop,
.vidioc_s_crop = soc_camera_s_crop,
.vidioc_g_parm = soc_camera_g_parm,
.vidioc_s_parm = soc_camera_s_parm,
.vidioc_g_chip_ident = soc_camera_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = soc_camera_g_register,
.vidioc_s_register = soc_camera_s_register,
#endif
};

v4L2 soc-camera 分析 - soc_camera.c

soc_camera.c

[cpp]
view plaincopy

1455 static struct platform_driver __refdata soc_camera_pdrv = {
1456 .remove = __devexit_p(soc_camera_pdrv_remove),
1457 .driver = {
1458 .name = "soc-camera-pdrv",
1459 .owner = THIS_MODULE,
1460 },
1461 };
1462
1463 static int __init soc_camera_init(void)
1464 {
1465 int ret = bus_register(&soc_camera_bus_type);
1466 if (ret)
1467 return ret;
1468 ret = driver_register(&ic_drv);
1469 if (ret)
1470 goto edrvr;
1471
1472 ret = platform_driver_probe(&soc_camera_pdrv, soc_camera_pdrv_probe);
1473 if (ret)
1474 goto epdr;
1475
1476 return 0;
1477
1478 epdr:
1479 driver_unregister(&ic_drv);
1480 edrvr:
1481 bus_unregister(&soc_camera_bus_type);
1482 return ret;
1483 }

1472 platform_driver_probe和platform_driver_register的区别:前者功能上和platform_driver_register是一样的,但是在内核启动完成后,这个函数就不能再执行了,这样可以释放函数soc_camera_pdrv_probe所占的空间。
soc_camera_pdrv_probe会probe系统内名称为"soc-camera-pdrv"的平台设备,系统内有几个这样的平台设备,那么就会创建几个soc_camera_device。这些平台设备可如下定义:

[cpp]
view plaincopy

struct platform_device your_mach_cameras[] = {
{
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = adv7180_link,
},
}, {
.name = "soc-camera-pdrv",
.id = 1,
.dev = {
.platform_data = tw9912_link,
},
}
};

注意,这里假定系统的camera处理模块,接了两个camera sensor, adv7180_link和tw9912_link

[cpp]
view plaincopy

static struct i2c_board_info decoder_i2c_adv7180 = {
I2C_BOARD_INFO("adv7180", (0x42 >> 1)),
};
struct soc_camera_link adv7180_link = {
.bus_id = 0,
.board_info = &decoder_i2c_adv7180,
.i2c_adapter_id = 0,
};

soc_camera_link主要用来定义i2c地址,如果sensor不是通过i2c连接到host上,那么要定义add_device和del_device函数

1465 注册一条新的总线soc-camera,这样在scan_add_host中调用device_register时,就会把这个设备挂到这个总线上。

[cpp]
view plaincopy

1135 struct bus_type soc_camera_bus_type = {
1136 .name = "soc-camera",
1137 .probe = soc_camera_probe,
1138 .remove = soc_camera_remove,
1139 .suspend = soc_camera_suspend,
1140 .resume = soc_camera_resume,
1141 };
1142 EXPORT_SYMBOL_GPL(soc_camera_bus_type);

当一个soc-camera-device设备通过device_register注册设备时,就会调用soc_camera_probe函数

[cpp]
view plaincopy

1402 static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
1403 {
1404 struct soc_camera_link *icl = pdev->dev.platform_data;
1405 struct soc_camera_device *icd;
1406 int ret;
1407
1408 if (!icl)
1409 return -EINVAL;
1410
1411 icd = kzalloc(sizeof(*icd), GFP_KERNEL);
1412 if (!icd)
1413 return -ENOMEM;
1414
1415 icd->iface = icl->bus_id;
1416 icd->pdev = &pdev->dev;
1417 platform_set_drvdata(pdev, icd);
1418
1419 ret = soc_camera_device_register(icd);
1420 if (ret < 0)
1421 goto escdevreg;
1422
1423 soc_camera_device_init(&icd->dev, icl);
1424
1425 icd->user_width = DEFAULT_WIDTH;
1426 icd->user_height = DEFAULT_HEIGHT;
1427
1428 return 0;
1429
1430 escdevreg:
1431 kfree(icd);
1432
1433 return ret;
1434 }

查找匹配名为soc-camera-pdrv的platform device时,调用该函数。

1419 调用soc_camera_device_register,把这个soc_camera_device加到全局camera device链表@devices上,并且为它分配设备号,做一些必要的初始化

1423 设置soc_came_device对应device的bus为soc_camera_bus_type,这样当我们注册设备时,就会调用soc_camera_probe

[cpp]
view plaincopy

1374 /*
1375 * Called from soc_camera_probe() above (with .video_lock held???)
1376 */
1377 static int soc_camera_video_start(struct soc_camera_device *icd)
1378 {
1379 struct device_type *type = icd->vdev->dev.type;
1380 int ret;
1381
1382 if (!icd->dev.parent)
1383 return -ENODEV;
1384
1385 if (!icd->ops ||
1386 !icd->ops->query_bus_param ||
1387 !icd->ops->set_bus_param)
1388 return -EINVAL;
1389
1390 ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
1391 if (ret < 0) {
1392 dev_err(&icd->dev, "video_register_device failed: %d\n", ret);
1393 return ret;
1394 }
1395
1396 /* Restore device type, possibly set by the subdevice driver */
1397 icd->vdev->dev.type = type;
1398
1399 return 0;
1400 }

在当前的上下文,soc_camera_video_start的调用路径如下

soc_camera_host_register ==> scan_add_host ==> device_register ==> bus_probe_device ==> soc_camera_bus_type.probe ==> soc_camera_video_start

1390 我们可以看出,系统为每一个soc-camera-device创建了一个video device设备节点

[cpp]
view plaincopy

1352 static int video_dev_create(struct soc_camera_device *icd)
1353 {
1354 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
1355 struct video_device *vdev = video_device_alloc();
1356
1357 if (!vdev)
1358 return -ENOMEM;
1359
1360 strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
1361
1362 vdev->parent = &icd->dev;
1363 vdev->current_norm = V4L2_STD_UNKNOWN;
1364 vdev->fops = &soc_camera_fops;
1365 vdev->ioctl_ops = &soc_camera_ioctl_ops;
1366 vdev->release = video_device_release;
1367 vdev->tvnorms = V4L2_STD_UNKNOWN;
1368
1369 icd->vdev = vdev;
1370
1371 return 0;
1372 }

当前的上下文,video_dev_create的调用路径如下

soc_camera_host_register ==> scan_add_host ==> device_register ==> bus_probe_device ==> soc_camera_bus_type.probe ==> soc_camera_video_start

这里面设置了video_device的两个非常重要的参数:soc_camera_ioctl_ops和soc_camera_fops,当user space打开video device后,所有可执行的操作,都是通过这两个入口进行的,下面是他们的定义。

[cpp]
view plaincopy

549 static struct v4l2_file_operations soc_camera_fops = {
550 .owner = THIS_MODULE,
551 .open = soc_camera_open,
552 .release = soc_camera_close,
553 .unlocked_ioctl = video_ioctl2,
554 .read = soc_camera_read,
555 .mmap = soc_camera_mmap,
556 .poll = soc_camera_poll,
557 };

[cpp]
view plaincopy

1321 static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
1322 .vidioc_querycap = soc_camera_querycap,
1323 .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap,
1324 .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,
1325 .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap,
1326 .vidioc_enum_input = soc_camera_enum_input,
1327 .vidioc_g_input = soc_camera_g_input,
1328 .vidioc_s_input = soc_camera_s_input,
1329 .vidioc_s_std = soc_camera_s_std,
1330 .vidioc_reqbufs = soc_camera_reqbufs,
1331 .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap,
1332 .vidioc_querybuf = soc_camera_querybuf,
1333 .vidioc_qbuf = soc_camera_qbuf,
1334 .vidioc_dqbuf = soc_camera_dqbuf,
1335 .vidioc_streamon = soc_camera_streamon,
1336 .vidioc_streamoff = soc_camera_streamoff,
1337 .vidioc_queryctrl = soc_camera_queryctrl,
1338 .vidioc_g_ctrl = soc_camera_g_ctrl,
1339 .vidioc_s_ctrl = soc_camera_s_ctrl,
1340 .vidioc_cropcap = soc_camera_cropcap,
1341 .vidioc_g_crop = soc_camera_g_crop,
1342 .vidioc_s_crop = soc_camera_s_crop,
1343 .vidioc_g_parm = soc_camera_g_parm,
1344 .vidioc_s_parm = soc_camera_s_parm,
1345 .vidioc_g_chip_ident = soc_camera_g_chip_ident,
1346 #ifdef CONFIG_VIDEO_ADV_DEBUG
1347 .vidioc_g_register = soc_camera_g_register,
1348 .vidioc_s_register = soc_camera_s_register,
1349 #endif
1350 };

soc_camera_ops 不支持read操作,因此如果使用了soc camera子系统,那么应用层就无法再使用read操作获取camera 数据,而只能选择使用mmap方式。不支持read操作没什么关系,大部分camera操作都是使用mmap方式进行的。samsung的s5pv210不支持read操作,而freescale mxc系列则支持read操作获取camera数据。

soc_camera_ioctl_ops也仅仅支持了v4l2_ioctl_ops的一个子集,这就意味着应用程序的作者需要考虑ioctl可能没有被支持。

[cpp]
view plaincopy

1281 /* Image capture device */
1282 static int soc_camera_device_register(struct soc_camera_device *icd)
1283 {
1284 struct soc_camera_device *ix;
1285 int num = -1, i;
1286
1287 for (i = 0; i < 256 && num < 0; i++) {
1288 num = i;
1289 /* Check if this index is available on this interface */
1290 list_for_each_entry(ix, &devices, list) {
1291 if (ix->iface == icd->iface && ix->devnum == i) {
1292 num = -1;
1293 break;
1294 }
1295 }
1296 }
1297
1298 if (num < 0)
1299 /*
1300 * ok, we have 256 cameras on this host...
1301 * man, stay reasonable...
1302 */
1303 return -ENOMEM;
1304
1305 icd->devnum = num;
1306 icd->use_count = 0;
1307 icd->host_priv = NULL;
1308 mutex_init(&icd->video_lock);
1309
1310 list_add_tail(&icd->list, &devices);
1311
1312 return 0;
1313 }

把给定的@icd加到全局soc camera device列表中

1290~1294 @devices是一个全局soc camera device列表,这段代码相当拗口,注意1293行是break 1290这个循环

[cpp]
view plaincopy

1194 int soc_camera_host_register(struct soc_camera_host *ici)
1195 {
1196 struct soc_camera_host *ix;
1197 int ret;
1198
1199 if (!ici || !ici->ops ||
1200 !ici->ops->try_fmt ||
1201 !ici->ops->set_fmt ||
1202 !ici->ops->set_bus_param ||
1203 !ici->ops->querycap ||
1204 !ici->ops->init_videobuf ||
1205 !ici->ops->reqbufs ||
1206 !ici->ops->add ||
1207 !ici->ops->remove ||
1208 !ici->ops->poll ||
1209 !ici->v4l2_dev.dev)
1210 return -EINVAL;
1211
1212 if (!ici->ops->set_crop)
1213 ici->ops->set_crop = default_s_crop;
1214 if (!ici->ops->get_crop)
1215 ici->ops->get_crop = default_g_crop;
1216 if (!ici->ops->cropcap)
1217 ici->ops->cropcap = default_cropcap;
1218 if (!ici->ops->set_parm)
1219 ici->ops->set_parm = default_s_parm;
1220 if (!ici->ops->get_parm)
1221 ici->ops->get_parm = default_g_parm;
1222
1223 mutex_lock(&list_lock);
1224 list_for_each_entry(ix, &hosts, list) {
1225 if (ix->nr == ici->nr) {
1226 ret = -EBUSY;
1227 goto edevreg;
1228 }
1229 }
1230
1231 ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
1232 if (ret < 0)
1233 goto edevreg;
1234
1235 list_add_tail(&ici->list, &hosts);
1236 mutex_unlock(&list_lock);
1237
1238 scan_add_host(ici);
1239
1240 return 0;
1241
1242 edevreg:
1243 mutex_unlock(&list_lock);
1244 return ret;
1245 }
1246 EXPORT_SYMBOL(soc_camera_host_register);

1231 每个camera host对应一个v4l2 device(注意不是video device),host上device对应的才是video device

1235 @host是一个全局camera host 链表

1238 scan_add_host 关联系统内属于这个host的video device

[cpp]
view plaincopy

1135 struct bus_type soc_camera_bus_type = {
1136 .name = "soc-camera",
1137 .probe = soc_camera_probe,
1138 .remove = soc_camera_remove,
1139 .suspend = soc_camera_suspend,
1140 .resume = soc_camera_resume,
1141 };
1142 EXPORT_SYMBOL_GPL(soc_camera_bus_type);

soc camera总线代码,当调用device_register注册一个新设备时,会调用probe函数

[cpp]
view plaincopy

947 static int soc_camera_probe(struct device *dev)
948 {
949 struct soc_camera_device *icd = to_soc_camera_dev(dev);
950 struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
951 struct soc_camera_link *icl = to_soc_camera_link(icd);
952 struct device *control = NULL;
953 struct v4l2_subdev *sd;
954 struct v4l2_mbus_framefmt mf;
955 int ret;
956
957 dev_info(dev, "Probing %s\n", dev_name(dev));
958
959 ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
960 icl->regulators);
961 if (ret < 0)
962 goto ereg;
963
964 ret = soc_camera_power_set(icd, icl, 1);
965 if (ret < 0)
966 goto epower;
967
968 /* The camera could have been already on, try to reset */
969 if (icl->reset)
970 icl->reset(icd->pdev);
971
972 ret = ici->ops->add(icd);
973 if (ret < 0)
974 goto eadd;
975
976 /* Must have icd->vdev before registering the device */
977 ret = video_dev_create(icd);
978 if (ret < 0)
979 goto evdc;
980
981 /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */
982 if (icl->board_info) {
983 ret = soc_camera_init_i2c(icd, icl);
984 if (ret < 0) {
985 goto eadddev;
986 }
987 } else if (!icl->add_device || !icl->del_device) {
988 ret = -EINVAL;
989 goto eadddev;
990 } else {
991 if (icl->module_name)
992 ret = request_module(icl->module_name);
993
994 ret = icl->add_device(icl, &icd->dev);
995 if (ret < 0)
996 goto eadddev;
997
998 /*
999 * FIXME: this is racy, have to use driver-binding notification,
1000 * when it is available
1001 */
1002 control = to_soc_camera_control(icd);
1003 if (!control || !control->driver || !dev_get_drvdata(control) ||
1004 !try_module_get(control->driver->owner)) {
1005 icl->del_device(icl);
1006 goto enodrv;
1007 }
1008 }
1009
1010 /* At this point client .probe() should have run already */
1011 ret = soc_camera_init_user_formats(icd);
1012 if (ret < 0)
1013 goto eiufmt;
1014
1015 icd->field = V4L2_FIELD_ANY;
1016
1017 icd->vdev->lock = &icd->video_lock;
1018
1019 /*
1020 * ..._video_start() will create a device node, video_register_device()
1021 * itself is protected against concurrent open() calls, but we also have
1022 * to protect our data.
1023 */
1024 mutex_lock(&icd->video_lock);
1025
1026 ret = soc_camera_video_start(icd);
1027 if (ret < 0)
1028 goto evidstart;
1029
1030 /* Try to improve our guess of a reasonable window format */
1031 sd = soc_camera_to_subdev(icd);
1032 if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) {
1033 icd->user_width = mf.width;
1034 icd->user_height = mf.height;
1035 icd->colorspace = mf.colorspace;
1036 icd->field = mf.field;
1037 }
1038
1039 /* Do we have to sysfs_remove_link() before device_unregister()? */
1040 if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
1041 "control"))
1042 dev_warn(&icd->dev, "Failed creating the control symlink\n");
1043
1044 ici->ops->remove(icd);
1045
1046 soc_camera_power_set(icd, icl, 0);
1047
1048 mutex_unlock(&icd->video_lock);
1049
1050 return 0;
1051
1052 evidstart:
1053 mutex_unlock(&icd->video_lock);
1054 soc_camera_free_user_formats(icd);
1055 eiufmt:
1056 if (icl->board_info) {
1057 soc_camera_free_i2c(icd);
1058 } else {
1059 icl->del_device(icl);
1060 module_put(control->driver->owner);
1061 }
1062 enodrv:
1063 eadddev:
1064 video_device_release(icd->vdev);
1065 evdc:
1066 ici->ops->remove(icd);
1067 eadd:
1068 soc_camera_power_set(icd, icl, 0);
1069 epower:
1070 regulator_bulk_free(icl->num_regulators, icl->regulators);
1071 ereg:
1072 return ret;
1073 }

在host-driver probe函数中调用,soc_camera_host_register ==> scan_add_host ==> device_register ==> bus_probe_device ==> soc_camera_probe

972 调用camera host驱动的add函数,比如pxa平台的pxa_camera_add_device

977 在调用video_device_register之前,要先创建video_device

982~1008 如果是i2c camera,那么调用soc_camera_init_i2c来初始华i2c,否则就调用add_device增加设备。soc_camera_init_i2c会调用到芯片驱动i2c_driver.probe,对于我们的项目,则是adv7180_probe

1010~1013 初始化client format,调用soc_camera_init_user_format之前,已经执行了芯片的probe函数,已经可以对芯片进一步的操作。

1026 调用soc_camera_video_start注册一个video device

1031 每一个soc camera device都一一对应一个v4l2 subdev

1044 ~ 1046 已经获取了soc camera device必要的信息后,调用remove_device关闭soc camera device,然后调用soc_camera_power_set关闭soc camera device的电源。

[cpp]
view plaincopy

869 /* So far this function cannot fail */
870 static void scan_add_host(struct soc_camera_host *ici)
871 {
872 struct soc_camera_device *icd;
873
874 mutex_lock(&list_lock);
875
876 list_for_each_entry(icd, &devices, list) {
877 if (icd->iface == ici->nr) {
878 int ret;
879 icd->dev.parent = ici->v4l2_dev.dev;
880 dev_set_name(&icd->dev, "%u-%u", icd->iface,
881 icd->devnum);
882 ret = device_register(&icd->dev);
883 if (ret < 0) {
884 icd->dev.parent = NULL;
885 dev_err(&icd->dev,
886 "Cannot register device: %d\n", ret);
887 }
888 }
889 }
890
891 mutex_unlock(&list_lock);
892 }

这个函数只被soc_camera_host_register调用。扫描系统所有的camera device,把属于这个camera host(参数@ici指定)的所有camera device注册到系统中。

876 系统所有的camera device,在没有被camera host注册前,这些camera device仅保存在@devices链表中

877 比较camera device的host number是否等于这个camera host

882 device_register 注册一个设备到系统中,这个函数会调用bus_probe_device,而bus_probe_device则会调用soc_camera_bus_type.probe,也就是soc_camera_probe。这样soc_camera_host_register就会注册所有属于这个host的camera device到系统中,并且创建了相应的设备节点/dev/videoX,整个设备的注册过程全部结束了,从现在开始,可以在设备节点/dev/videoX上调用open read
write ioctl以及poll。

[cpp]
view plaincopy

178 static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
179 {
180 int ret;
181 struct soc_camera_device *icd = file->private_data;
182 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
183
184 /* call s_routing to select the input of camera sensor */
185 ret = v4l2_subdev_call(sd, video, s_routing, i, 0, 0);
186
187 return ret;
188 }

185 soc_camera驱动并没有实现这句话,而是直接 return 0,这就导致当前的soc camera子系统不支持S_INPUT接口。

[cpp]
view plaincopy

384 static int soc_camera_open(struct file *file)
385 {
386 struct video_device *vdev = video_devdata(file);
387 struct soc_camera_device *icd = container_of(vdev->parent,
388 struct soc_camera_device,
389 dev);
390 struct soc_camera_link *icl = to_soc_camera_link(icd);
391 struct soc_camera_host *ici;
392 int ret;
393
394 if (!icd->ops)
395 /* No device driver attached */
396 return -ENODEV;
397
398 ici = to_soc_camera_host(icd->dev.parent);
399
400 if (!try_module_get(ici->ops->owner)) {
401 dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
402 return -EINVAL;
403 }
404
405 icd->use_count++;
406
407 /* Now we really have to activate the camera */
408 if (icd->use_count == 1) {
409 /* Restore parameters before the last close() per V4L2 API */
410 struct v4l2_format f = {
411 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
412 .fmt.pix = {
413 .width = icd->user_width,
414 .height = icd->user_height,
415 .field = icd->field,
416 .colorspace = icd->colorspace,
417 .pixelformat =
418 icd->current_fmt->host_fmt->fourcc,
419 },
420 };
421
422 ret = soc_camera_power_set(icd, icl, 1);
423 if (ret < 0)
424 goto epower;
425
426 /* The camera could have been already on, try to reset */
427 if (icl->reset)
428 icl->reset(icd->pdev);
429
430 ret = ici->ops->add(icd);
431 if (ret < 0) {
432 dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
433 goto eiciadd;
434 }
435
436 pm_runtime_enable(&icd->vdev->dev);
437 ret = pm_runtime_resume(&icd->vdev->dev);
438 if (ret < 0 && ret != -ENOSYS)
439 goto eresume;
440
441 /*
442 * Try to configure with default parameters. Notice: this is the
443 * very first open, so, we cannot race against other calls,
444 * apart from someone else calling open() simultaneously, but
445 * .video_lock is protecting us against it.
446 */
447 ret = soc_camera_set_fmt(icd, &f);
448 if (ret < 0)
449 goto esfmt;
450
451 ici->ops->init_videobuf(&icd->vb_vidq, icd);
452 }
453
454 file->private_data = icd;
455 dev_dbg(&icd->dev, "camera device open\n");
456
457 return 0;
458
459 /*
460 * First four errors are entered with the .video_lock held
461 * and use_count == 1
462 */
463 esfmt:
464 pm_runtime_disable(&icd->vdev->dev);
465 eresume:
466 ici->ops->remove(icd);
467 eiciadd:
468 soc_camera_power_set(icd, icl, 0);
469 epower:
470 icd->use_count--;
471 module_put(ici->ops->owner);
472
473 return ret;
474 }

当应用通过open系统调用,打开设备节点/dev/videoX时,会调用soc_camera_open

430 ici->ops->add 不仅要执行host内部的初始化,还会调用camera sensor(参数icd指定)的init

447 配置camera sensor缺省的格式参数,从我个人理解,一切合理的fmt都应该在调用S_INPUT之后进行设置。当然,这需要应用程序编程时先调用S_INPUT再进行S_FMT。

405~408 仅在第一次打开时,才对camera host和camera sensor做初始化操作,否则,仅仅增加引用计数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: