全志 A20 camera移植

在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: 如果有全志工程师偶尔看到这篇Blog。 请通知Driver部门。修改这个明显错误。

你可能感兴趣的:(全志 A20 camera移植)