ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CSI接口Camera驱动学习

2021-08-07 15:04:26  阅读:352  来源: 互联网

标签:csi ops 接口 ioctl Camera video CSI v4l2 sunxi


CSI

CSI:COMS Sensor Interface

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

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

  1. 基础知识 :
    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

  1. 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部门。修改这个明显错误。

标签:csi,ops,接口,ioctl,Camera,video,CSI,v4l2,sunxi
来源: https://blog.csdn.net/liuqingsongmsdn2014/article/details/119486591

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有