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中有如下代码片段
- 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 代码片段
- 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定义如下
- 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 代码片段如下
- 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实现如下
- 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
- 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 }
soc_camera_pdrv_probe会probe系统内名称为"soc-camera-pdrv"的平台设备,系统内有几个这样的平台设备,那么就会创建几个soc_camera_device。这些平台设备可如下定义:
- 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
- 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,
- };
1465 注册一条新的总线soc-camera,这样在scan_add_host中调用device_register时,就会把这个设备挂到这个总线上。
- 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函数
- 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
- 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设备节点
- 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后,所有可执行的操作,都是通过这两个入口进行的,下面是他们的定义。
- 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 };
- 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可能没有被支持。
- 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这个循环
- 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
- 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函数
- 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的电源。
- 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。
- 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 }
- 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做初始化操作,否则,仅仅增加引用计数。