关键词:android camera CMM 模组 camera参数 CAMIF V4L2
平台信息:
内核:
linux
系统:android

平台:S5PV310(samsung exynos 4210)

android camera(一):camera模组CMM介绍

android camera(二):摄像头工作原理、s5PV310 摄像头接口(CAMIF)

android camera(三):camera V4L2 FIMC

android camera(四):camera 驱动 GT2005

下载:常用摄像头规格书(个别有android驱动程序) :bf3703 30W、gc0308 30W、ov7670、gt2005 200W、gt2015 200W、NT99250 200W、s5k5ba 200W、s5k4ba

前面两篇说的有点多了,不过多了解点东西也挺好的,遇到问题时可以有更多的思路,真正驱动是从这一块开始。一般BSP的camera都是完好的,我们只用关心驱动这些就可以了。

1. V4L2

1)简介

在Linux中,摄像头方面的标准化程度比较高,这个标准就是V4L2驱动程序,这也是业界比较公认的方式。

V4L全称是Video for Linux,是Linux内核中标准的关于视频驱动程序,目前使用比较多的版本是Video for Linux 2,简称V4L2。它为Linux下的视频驱动提供了统一的接口,使得应用程序可以使用统一的API操作不同的视频设备。从内核空间到用户空间,主要的数据流和控制类均由V4L2驱动程序的框架来定义。

V4L2驱动程序一般只提供Video数据的获得,而如何实现视频预览,如何向上层发送数据,如何把纯视频流和取景器、视频录制等实际业务组织起来,都是camera的硬件抽象层需要负责的工作。

V4L2驱动核心实现为如下文件:drivers/media/video/v4l2-dev.c。

V4l2-dev.h中定义的video_device是V4L2驱动程序的核心数据结构,它为具体的摄像头sensor驱动提供了接口调用。

V4l2的采集过程(应用程序):

1) 打开设备,获得文件描述符;

2) 设置图片格式;

3) 分配缓冲区;

4) 启动采集过程,读取数据;

5) 停止采集,关闭设备。


2)数据结构

V4L2的主要数据结构是video_device,定义在v4l2_dev.h中:

[cpp] view plain copy print ?
  1. structvideo_device
  2. {
  3. /*deviceops*/
  4. conststructv4l2_file_operations*fops;/*接口函数指针*/
  5. /*sysfs*/
  6. structdevicedev;/*v4l设备结构*/
  7. structcdev*cdev;/*字符设备结构*/
  8. /*Seteitherparentorv4l2_devifyourdriverusesv4l2_device*/
  9. structdevice*parent;/*设备父指针*/
  10. structv4l2_device*v4l2_dev;/*v4l2设备指针*/
  11. /*deviceinfo*/
  12. charname[32];/*设备名称*/
  13. intvfl_type;
  14. /*'minor'issetto-1iftheregistrationfailed*/
  15. intminor;/*次设备号*/
  16. u16num;
  17. /*usebitopstoset/clear/testflags*/
  18. unsignedlongflags;
  19. /*attributetodifferentiatemultipleindicesononephysicaldevice*/
  20. intindex;
  21. /*V4L2filehandles*/
  22. spinlock_tfh_lock;/*Lockforallv4l2_fhs*/
  23. structlist_headfh_list;/*Listofstructv4l2_fh*/
  24. intdebug;/*debug级别*/
  25. /*Video标准变量*/
  26. v4l2_std_idtvnorms;/*Supportedtvnorms*/
  27. v4l2_std_idcurrent_norm;/*Currenttvnorm*/
  28. /*回调函数*/
  29. void(*release)(structvideo_device*vdev);
  30. /*ioctl回调函数*/
  31. conststructv4l2_ioctl_ops*ioctl_ops;
  32. };

主要接口函数有:

intvideo_register_device(struct video_device *vdev, int type, int nr);

static intv4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

2. FIMC

1)简介

FIMC这个模块不仅仅是一个摄像头的控制接口,它还承担着V4L2的output功能和overlay的功能。

FIMC的驱动在内核中的位置:drivers/media/video/samsung/fimc

它包含下边的文件:

fimc_regs.c
fimc_capture.c
fimc_dev.c
fimc_output.c
fimc_overlay.c
fimc_v4l2.c

它们的组织关系如下:

可以看到,FIMC的驱动实现了v4l2所有的接口,可以分为v4l2-input设备接口,v4l2-output设备接口以及v4l2-overlay设备接口。这里我们主要关注v4l2-input设备接口,因为摄像头属于视频输入设备。

fimc_v4l2.c里面注册了很多的回调函数,都是用于实现v4l2的标准接口的,但是这些回调函数基本上都不是在fimc_v4l2.c里面实现的,而是有相应的.c分别去实现。比如:

v4l2-input设备的操作实现:fimc_capture.c
v4l2-output设备的操作实现: fimc_output.c
v4l2-overlay设备的操作实现: fimc_overlay.c

这些代码其实都是和具体硬件操作无关的,这个驱动把所有操作硬件寄存器的代码都写到一个文件里面了,就是fimc40_regs.c。这样把硬件相关的代码和硬件无关的代码分开来实现是非常好的方式,可以最大限度的实现代码复用。

2) 数据结构

FIMC的主要数据结构fimc_control,定义在fimc.h中:

[cpp] view plain copy print ?
  1. structfimc_control{
  2. intid;/*控制器id*/
  3. charname[16];
  4. atomic_tin_use;
  5. void__iomem*regs;/*寄存器i/o*/
  6. structclk*clk;/*interfaceclock*/
  7. structregulator*regulator;/*pdregulator*/
  8. structfimc_meminfomem;/*forreservedmem*/
  9. /*kernelhelpers*/
  10. structmutexlock;/*controllerlock*/
  11. structmutexalloc_lock;
  12. structmutexv4l2_lock;
  13. wait_queue_head_twq;
  14. structdevice*dev;
  15. intirq;
  16. /*v4l2related*/
  17. structvideo_device*vd;
  18. structv4l2_devicev4l2_dev;
  19. /*fimcspecific*/
  20. structfimc_limit*limit;/*H/Wlimitation*/
  21. structs3c_platform_camera*cam;/*activatedcamera*/
  22. structfimc_capinfo*cap;/*capturedevinfo*/
  23. structfimc_outinfo*out;/*outputdevinfo*/
  24. structfimc_fbinfofb;/*fimdinfo*/
  25. structfimc_scalersc;/*scalerinfo*/
  26. structfimc_effectfe;/*fimceffectinfo*/
  27. enumfimc_statusstatus;
  28. enumfimc_loglog;
  29. u32ctx_busy[FIMC_MAX_CTXS];
  30. };
因为FIMC一共有三套一样的控制器(fimc0, fimc1, fimc2),所以驱动里使用了一个数组来描述:
[cpp] view plain copy print ?
  1. structvideo_devicefimc_video_device[FIMC_DEVICES]={
  2. [0]={
  3. .fops=&fimc_fops,
  4. .ioctl_ops=&fimc_v4l2_ops,
  5. .release=fimc_vdev_release,
  6. },
  7. [1]={
  8. .fops=&fimc_fops,
  9. .ioctl_ops=&fimc_v4l2_ops,
  10. .release=fimc_vdev_release,
  11. },
  12. [2]={
  13. .fops=&fimc_fops,
  14. .ioctl_ops=&fimc_v4l2_ops,
  15. .release=fimc_vdev_release,
  16. },
  17. };

fb_ops结构体是针对v4l2设备的基本操作,定义如下:

[cpp] view plain copy print ?
  1. staticconststructv4l2_file_operationsfimc_fops={
  2. .owner=THIS_MODULE,
  3. .open=fimc_open,
  4. .release=fimc_release,
  5. .ioctl=video_ioctl2,
  6. .read=fimc_read,
  7. .write=fimc_write,
  8. .mmap=fimc_mmap,
  9. .poll=fimc_poll,
  10. };

3)FIMC初始设置

在S5PV210中,FIMC初始设置代码在 /drivers/ arch/arm/mach-s5pv210/mach-smdkv310.c中:

[cpp] view plain copy print ?
  1. staticstructs3c_platform_fimcfimc_plat={
  2. .srclk_name="mout_mpll",
  3. .clk_name="sclk_fimc",
  4. .lclk_name="sclk_fimc_lclk",
  5. .clk_rate=166750000,
  6. .default_cam=CAMERA_CSI_C,
  7. .camera={
  8. &mt9p111,//5Mbackcam
  9. &s5k6aafx,///1.3Mfrontcam
  10. },
  11. .hw_ver=0x43,
  12. };

对于GPIO的配置代码在 /drivers/ arch/arm/mach-s5pv210/setup-fimc0.c中:

[cpp] view plain copy print ?
  1. oids3c_fimc0_cfg_gpio(structplatform_device*pdev)
  2. {
  3. inti=0;
  4. /*CAMAport(b0010):PCLK,VSYNC,HREF,DATA[0-4]*/
  5. for(i=0;i<8;i++){
  6. s3c_gpio_cfgpin(S5PV210_GPE0(i),S3C_GPIO_SFN(2));
  7. s3c_gpio_setpull(S5PV210_GPE0(i),S3C_GPIO_PULL_NONE);
  8. }
  9. /*CAMAport(b0010):DATA[5-7],CLKOUT(MIPICAMalso),FIELD*/
  10. for(i=0;i<5;i++){
  11. s3c_gpio_cfgpin(S5PV210_GPE1(i),S3C_GPIO_SFN(2));
  12. s3c_gpio_setpull(S5PV210_GPE1(i),S3C_GPIO_PULL_NONE);
  13. }
  14. /*CAMBport(b0011):DATA[0-7]*/
  15. for(i=0;i<8;i++){
  16. s3c_gpio_cfgpin(S5PV210_GPJ0(i),S3C_GPIO_SFN(3));
  17. s3c_gpio_setpull(S5PV210_GPJ0(i),S3C_GPIO_PULL_NONE);
  18. }
  19. /*CAMBport(b0011):PCLK,VSYNC,HREF,FIELD,CLCKOUT*/
  20. for(i=0;i<5;i++){
  21. s3c_gpio_cfgpin(S5PV210_GPJ1(i),S3C_GPIO_SFN(3));
  22. s3c_gpio_setpull(S5PV210_GPJ1(i),S3C_GPIO_PULL_NONE);
  23. }
  24. }

4)接口函数

FIMC的主要回调函数如下,实现在fimc_v4l2.c中:

[cpp] view plain copy print ?
  1. onststructv4l2_ioctl_opsfimc_v4l2_ops={
  2. .vidioc_querycap=fimc_querycap,
  3. .vidioc_reqbufs=fimc_reqbufs,
  4. .vidioc_querybuf=fimc_querybuf,
  5. .vidioc_g_ctrl=fimc_g_ctrl,
  6. .vidioc_s_ctrl=fimc_s_ctrl,
  7. .vidioc_s_ext_ctrls=fimc_s_ext_ctrls,
  8. .vidioc_cropcap=fimc_cropcap,
  9. .vidioc_g_crop=fimc_g_crop,
  10. .vidioc_s_crop=fimc_s_crop,
  11. .vidioc_streamon=fimc_streamon,
  12. .vidioc_streamoff=fimc_streamoff,
  13. .vidioc_qbuf=fimc_qbuf,
  14. .vidioc_dqbuf=fimc_dqbuf,
  15. .vidioc_enum_fmt_vid_cap=fimc_enum_fmt_vid_capture,
  16. .vidioc_g_fmt_vid_cap=fimc_g_fmt_vid_capture,
  17. .vidioc_s_fmt_vid_cap=fimc_s_fmt_vid_capture,
  18. .vidioc_try_fmt_vid_cap=fimc_try_fmt_vid_capture,
  19. .vidioc_enum_input=fimc_enum_input,
  20. .vidioc_g_input=fimc_g_input,
  21. .vidioc_s_input=fimc_s_input,
  22. .vidioc_g_parm=fimc_g_parm,
  23. .vidioc_s_parm=fimc_s_parm,
  24. .vidioc_queryctrl=fimc_queryctrl,
  25. .vidioc_querymenu=fimc_querymenu,
  26. .vidioc_g_fmt_vid_out=fimc_g_fmt_vid_out,
  27. .vidioc_s_fmt_vid_out=fimc_s_fmt_vid_out,
  28. .vidioc_try_fmt_vid_out=fimc_try_fmt_vid_out,
  29. .vidioc_g_fbuf=fimc_g_fbuf,
  30. .vidioc_s_fbuf=fimc_s_fbuf,
  31. .vidioc_try_fmt_vid_overlay=fimc_try_fmt_overlay,
  32. .vidioc_g_fmt_vid_overlay=fimc_g_fmt_vid_overlay,
  33. .vidioc_s_fmt_vid_overlay=fimc_s_fmt_vid_overlay,
  34. };

对于寄存器的操作,实现都在fimc_regs.c文件中,如

[cpp] view plain copy print ?
  1. intfimc_hwset_camera_source(structfimc_control*ctrl)
  2. {
  3. structs3c_platform_camera*cam=ctrl->cam;
  4. u32cfg=0;
  5. cfg|=S3C_CISRCFMT_ITU601_8BIT;
  6. cfg|=cam->order422;
  7. if(cam->type==CAM_TYPE_ITU)
  8. cfg|=cam->fmt;
  9. cfg|=S3C_CISRCFMT_SOURCEHSIZE(cam->width);
  10. cfg|=S3C_CISRCFMT_SOURCEVSIZE(cam->height);
  11. writel(cfg,ctrl->regs+S3C_CISRCFMT);
  12. return0;
  13. }
  14. intfimc_hwset_enable_irq(structfimc_control*ctrl,intoverflow,intlevel)
  15. {
  16. u32cfg=readl(ctrl->regs+S3C_CIGCTRL);
  17. cfg&=~(S3C_CIGCTRL_IRQ_OVFEN|S3C_CIGCTRL_IRQ_LEVEL);
  18. cfg|=S3C_CIGCTRL_IRQ_ENABLE;
  19. if(overflow)
  20. cfg|=S3C_CIGCTRL_IRQ_OVFEN;
  21. if(level)
  22. cfg|=S3C_CIGCTRL_IRQ_LEVEL;
  23. writel(cfg,ctrl->regs+S3C_CIGCTRL);
  24. return0;
  25. }

本文来自http://blog.csdn.net/xubin341719/article/details/7727426

更多相关文章

  1. Android增加自定义监听事件
  2. Android设备信息管理工具类
  3. Android(安卓)app开机启动
  4. Android使用SAX解析XML(4)
  5. uiautomator2(用python控制android), 安装和连接脱坑
  6. Android线程间通信的Message机制
  7. Android硬件设备检测
  8. Android(安卓)蓝牙自动配对连接
  9. 箭头函数的基础使用

随机推荐

  1. 配置Android(安卓)SDK 开发环境
  2. Android UI目录
  3. Android 实现从网络上异步加载图像
  4. android layout_weight讲解
  5. android 中 application 的使用
  6. Drawable Mutations(Android Drawable 深
  7. Android Studio 解决错误 Could not find
  8. Android Drawable Resource学习(二)、Bitma
  9. [置顶] Android 65K问题之Multidex原理分
  10. Android 高手进阶教程(十三)之----Androi