您的位置:首页 > 其它

全志 A20 camera移植

2016-05-21 01:01 375 查看
在Android4.0升级后,突然发现大量平台对Camera的支持均非常不好。要么Camera使用不稳定,要么各类ioctl设置不能使用,更有甚者,连Camera Device都不能创建。

 

而我们的产品,基于Camera的正常工作,必须解决此类问题。选择了其中一款使用CSI接口Camera的平台:全志A20来做研究和解决。

 

0. 基础知识 : 

0.0. 目录结构:

除了常见的,在linux-3.3/drivers/media/video/ 目录下有v4l2一些文件外,全志还在另一个目录下放置了csi以及做支持模组芯片的代码:linux-3.3/drivers/media/video/sunxi_csi/

其中,csi部分在csi0或者csi1中。 模组对应代码在device中。

这些代码,基本组成了全志CSI 接口 Camera的全部驱动代码。

 

0.1. CSI:

COMS Sensor Interface:

CSI接口通常从COMS Sensor,Video Encoder和其它视频输出设备收集数据。

 

0.2. 模组芯片:

手头这块板子上自带GT2005模组。所以需要看linux-3.3/drivers/media/video/sunxi_csi/device/gt2005.c

 

1. 驱动结构:

CSI 模组Driver的基本思路其实挺简单,就是需要创建主设备号为81的device. /dev/videoX。并将其open,close,ioctl 与Driver联系起来,最终反应到Sensor (gt2005)层面。

 

我们首先从linux-3.3/drivers/media/video/sunxi_csi/csi0部分开始着手,这个文件夹内的三个文件:sunxi_csi_reg.c ,sunxi_drv_csi.c, sunxi_csi_reg.h 最终会生成sunxi_csi0.ko。 会被以modules形式insmod 进系统。

 

1.1:CSI0 modules学习:

当sunxi_csi0.ko被insmod时,sunxi_drv_csi.c中的csi_init()被调用。

csi_init() 中注册了一个driver--csi_driver.

platform_driver_register(&csi_driver);

 

csi_driver中有侦测函数:.probe = csi_probe,

Sam的理解是:因为CSI接口一直连接着,所以当此Driver刚被注册时,csi_probe就被调用。

请注意:csi_probe中作了相当多事情,是sunxi_csi0.ko的重点。

 

它做了很多准备工作.并通过video_register_device()创建了Device. /dev/videoX. 并将此device的操作与v4l2_fops联系起来。

所以,对此Device的open,close, ioctl等, 都使用v4l2_fops中提供的函数指证。

 

而我们看v4l2_fops中的ioctl. 它最终是 video_device ->fops->ioctl()。

其实就是:csi_template 中的:.fops       = &csi_fops, 的ioctl. 即:video_ioctl2

 

video_ioctl2,在v4l2-ioctl.c中定义:其实就是:

static long __video_do_ioctl(struct file *file,unsigned int cmd, void *arg)

 

所以,经过CSI程序的链接。最终,对Device /dev/videoX的操作,最终都被归结到__video_do_ioctl

 

同时,csi_ioctl_ops也被链接到ioctl_ops。请注意,未来要用到这里。

 

看到这里,大家都会疑惑。 这怎么和Sensor操作练习起来了。这部分只将CSI和V4L2 连起来了。

这就是下一部要说的gt2005.ko了。

 

 

1.2: GT2005模块学习:

同样道理,insmod gt2005.ko时,gt2005.c中的init_sensor()会被启动。

在init_sensor()中,只执行了:i2c_add_driver(&sensor_driver); 其中,sensor_driver 同样会在驱动安装后立刻启动。

 

static int sensor_probe(struct i2c_client *client,const struct i2c_device_id *id)

v4l2_i2c_subdev_init(sd, client, &sensor_ops);

这一句代码是关键。

它将sensor_ops加入v4l2_subdev->ops中去了。而v4l2_subdev类型的sd被加入list.未来会用。(关键3)

 

分析下:sensor_ops.

static const struct v4l2_subdev_ops sensor_ops = {
.core = &sensor_core_ops,
.video = &sensor_video_ops,
};

也就是有:core和video 两个。一定要注意了,这里和未来很有关系。(关键4)

 

 

 

__video_do_ioctl()最终会通过vfd->ioctl_ops 来做实际动作。而ioctl_ops是谁呢?就是在在sunxi_drv_csi.c中的csi_ioctl_ops

 

 

 

2. ioctl的完整流程:

当用户open /dev/videoX后,使用ioctl()时,

 

例1:得到能力集:

rel = ioctl(Handle, VIDIOC_QUERYCAP, &cap);

通过上面的分析, 它通过 __video_do_ioctl 最终调用到:vfd->ioctl_ops->vidioc_querycap.

也就是 csi_ioctl_ops 的 .vidioc_querycap          = vidioc_querycap,

 

也就是说: 调用ioctl(VIDIOC_QUERYCAP). 会通过__vidoe_do_ioctl() 最终调用到sunxi_drv_sic.c中的vidioc_querycap()

为什么没有进Sensor呢? 是因为能力集在代码层面维护。不需要去问Sensor。

 

 

例2:得到像素格式

ioctl(Handle, VIDIOC_G_FMT, &Format)

它最终被调用sunxi_drv_csi.c中的vidioc_g_fmt_vid_cap()

因为格式也是由程序维护,所以没有访问Sensor。 

 

例3:设置像素格式

ioctl(Handle, VIDIOC_S_FMT, &Format);

最终被调用sunxi_drv_csi.c中的vidioc_s_fmt_vid_cap()

注意: 设置像素格式,需要通知Sensor。

所以会被调用:

 v4l2_subdev_call(dev->sd,video,s_mbus_fmt,&ccm_fmt);

这里的video. 就是表明调用的是关键4 那个的sensor_video_ops

这里的sd,其实就是关键3 那里的v4l2_subdev类型sd.

所以,又被调用到gt2005.c中的sensor_s_fmt()

此时会向Sensor中写入数据。sensor_write

 

 

例4:

ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm)

会通过__vidoe_do_ioctl()

调用到sunxi_drv_csi.c中vidioc_g_parm() 

这里会:v4l2_subdev_call(dev->sd,video,g_parm,parms);

在gt2005.c中写死的。 如果格式大于 800x600. 则15帧。 小于800x600. 则30帧。

 

 

例5:

ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm)

会通过__vidoe_do_ioctl()
调用到sunxi_drv_csi.c中vidioc_s_parm() 
这里会:v4l2_subdev_call(dev->sd,video,s_parm,parms);

在gt2005.c 中。这里打空。所以其实不能调。

 

例6:

ioctl(Handle, VIDIOC_G_CTRL, &ctrl)

会通过__vidoe_do_ioctl()
调用到sunxi_drv_csi.c中vidioc_g_ctrl() 
这里会:v4l2_subdev_call(dev->sd,core,g_ctrl,ctrl);

注意:这里是core. 所以调用gt2005.c中的sensor_g_ctrl()

 

 

 

例7:

ioctl(Handle, VIDIOC_S_CTRL, &ctrl)

会通过__vidoe_do_ioctl()
调用到sunxi_drv_csi.c中vidioc_s_ctrl() 
这里会:v4l2_subdev_call(dev->sd,core,s_ctrl,ctrl);

注意:这里是core. 所以调用gt2005.c中的sensor_s_ctrl()

 

 

 

但有一点需要注意:在A20平台编程中,大家会发现所有VIDIOC_G_CTRL, VIDIOC_S_CTRL全不可用。Sam查了一下代码。发现是全志修改Kernel时弄错了。

错误如下:

struct v4l2_control {
__u32     id;
__s32     value;
__u32 user_pt;
};

看起来,是全志一位叫Raymon的工程师非常随意的修改了v4l2_control结构体。添加了4个字节的user_pt;

但这会造成严重后果,首先,大量使用v4l2_control的接口会出现未知问题。

更严重的是:ioctl的cmd这一项是计算出来的。v4l2_control的大小会影响到cmd的值。

 

所以,在A20平台上,应用程序使用VIDIOC_G_CTRL, VIDIOC_S_CTRL时,

__video_do_ioctl(struct file *file,unsigned int cmd, void *arg)

参数2:cmd这一项和Kernel中算出的cmd值对不上。所以无法进入:

case VIDIOC_G_CTRL:

case VIDIOC_S_CTRL:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: