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部门。修改这个明显错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值