V4L2 soc-camera 子系统

soc-camera的作者之所以引入这个子系统,我想一个主要目的就是把camera驱动划分为camera host端,camera device端,这样同一个camera sensor驱动就可以方便的移植到多个camera host下,而无须做较多的改动。


本译文取自kernel文档:Documentation/video4linux/soc-camera.txt


术语

在阅读本文档前先明确几个术语:

  • camera / camera device / camera sensor - 是一个video-camera sensor chip,可以连接到各种系统和接口,典型的使用i2c来控制和配置设备,使用并行或者串行总线来传输数据。
  • camera host - 一个接口,camera连接到它上面。存在于SoCs之上的特定的接口,比如PXA27X PXA3xx, SuperH, AVR32, i.MX27, i.MX31等等。我觉得i.MX51以及s5pv210物理上和这些host没有什么区别,只是二者的开发人员出于某种考虑而没有使用这个子系统实现。
  • camera host bus - camera host和camera之间的连接,可以是串行的或者并行的,保存着数据线和控制线,比如clock,水平和垂直同步信号。

soc-camera subsystem的目的

soc-camera 子系统在camera host驱动和camera sensor驱动间提供了统一的接口。soc camera子系统向上提供了V4L2接口,当前仅支持open, mmap, ioctl, mmap,不支持read

这个子系统连接SoC video capture接口和CMOS camera sensor chips,使得sensor驱动可以在其他的hosts驱动上复用。子系统在设计时也考虑到了多个camera host接口的存在,以及每个接口存在多个camera sensor,尽管在大部分情况下仅有一个camera sensor。

现存的驱动

在2.6.27-rc4中,主线内核有两个host 驱动:PXA27x的pxa_camera.c和SuperH SoCs的sh_mobile_ceu_camera.c,有四个sensor驱动:mt9m001.c,mt9v002.c以及一个通用的 soc_camera_platform.c驱动。这个列表可能不是最新的,所以在你的源码树中查看,可能有更多的例子存在。

实际开发中,新的sensor驱动可以参照mt9m001.c和mt9v002.c这两个sensor驱动框架,根据项目所用的sensor稍加修改即可。

Camera host API

一个host camera driver使用soc_camera_host_register(struct soc_camera_host *)函数来注册。host object可以如下初始化

  1. static struct soc_camera_host pxa_soc_camera_host = {  
  2.     .drv_name   = PXA_CAM_DRV_NAME,  
  3.     .ops        = &pxa_soc_camera_host_ops,  
  4. };   

所有的方法都是通过struct soc_camera_host_ops

  1. static struct soc_camera_host_ops pxa_soc_camera_host_ops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .add        = pxa_camera_add_device,  
  4.     .remove     = pxa_camera_remove_device,  
  5.     .suspend    = pxa_camera_suspend,  
  6.     .resume     = pxa_camera_resume,  
  7.     .set_fmt_cap    = pxa_camera_set_fmt_cap,  
  8.     .try_fmt_cap    = pxa_camera_try_fmt_cap,  
  9.     .init_videobuf  = pxa_camera_init_videobuf,  
  10.     .reqbufs    = pxa_camera_reqbufs,  
  11.     .poll       = pxa_camera_poll,  
  12.     .querycap   = pxa_camera_querycap,  
  13.     .try_bus_param  = pxa_camera_try_bus_param,  
  14.     .set_bus_param  = pxa_camera_set_bus_param,  
  15. };  

.add是把camera sensor接入host;.remove方法从host卸载camera sensor时调用,除了执行host内部的初始化工作外,还应该调用camera sensor的.init和.release方法。(.add方法仅仅在soc_camera_open中被调用,也就是说当应用层第一个打开一个/dev/videoX设备节点时,此时进行camera host以及camera sensor的初始化是合理的)

.suspend和.resume方法实现host的电源管理功能, 他们要负责调用相应的sensor 方法。

.try_bus_param和.set_bus_param用来协商host和sensor间的物理连接参数。

.init_videobuf是当一个video-device被打开时调用,video-buffer管理的实现是完全依赖于特定的host

其余部分被V4L2的相应部分调用。

Camera API

Sensor drivers可以使用struct soc_camera_link,典型的由platform提供,用来代表sensor连接到的host总线,这个结构还提供了.power和.reset接口。本节所描述的代码和当前代码已经发生了很大的变化,所以暂时略过本节。

VIDIOC_S_CROP和VIDIOC_S_FMT调用的行为

VIDIOC_S_CROP:设置sensor窗口的位置和尺寸,单位是sensor的像素。改变sensor窗口尺寸时维持缩放因子没变,因此用户窗口尺寸也相应的变化了。

VIDIOC_S_FMT:设置用户窗口。通过修改缩放因子,尽可能的保持之前设置的窗口尺寸。如果sensor窗口无法保持不变,那么也可以修改。

soc-camera中有两个地方,可以进行缩放和剪切:camera sensor驱动,和camera host驱动。User ioctl首先发送到host dirver,然后再向下发送给camera driver。在camera sensor驱动执行缩放和剪切可能更有效,因为会节约camera总线带宽以及最大帧率(如果放大还成立吗,对于AD video芯片来说,缩放只能在host driver来做)。然而,如果camera sensor驱动无法实现要求的参数,那么host 驱动可以决定用它自己的缩放和剪切功能来满足用户需求。

Camera sensor驱动soc-camera core以及host驱动交互,完全是功能上的,不涉及任何数据传输。因而所有的camera sensor驱动应该用当前输出格式响应.g_fmt请求。这对于正确配置camera bus是必要的。s_fmt() 和try_fmt也不得不实现。sensor窗口和缩放因子也应该在camera sensor驱动内维护。按照V4L2 API,所有的capture驱动应该支持VIDIOC_CROPCAP ioctl,因此我们依赖于camera drivers实现.cropcap()。如果camera sensor驱动不支持cropping,那么可以选择不支持.s_crop,但是必须在camera host驱动实现cropping支持,起码g_crop方法必须支持。

用户设置的几何尺寸保存在struct soc_camera_device的.user_width和.user_height成员中,以供soc_camera core和host drivers使用。core在成功调用s_fmt后会修改这些成员,但是如果是在其他地方修改了他们,比如s_crop,那么host driver要负责更型他们。


posted on 2013-04-11 17:18  simon_god  阅读(793)  评论(0编辑  收藏  举报