精华内容
下载资源
问答
  • CMOS 摄像头驱动

    2016-01-21 09:28:42
    准备好CMOS 摄像头驱动源码,包含5 个文件:s3c2440_ov9650.c s3c2440_camif.c s3c2440_camif.h sccb.c sccb.h 将这5 个文件复制到drivers/media/video 目录下,修改drivers/media/目录下Kconfig 文件,在101 行...

    准备好CMOS 摄像头驱动源码,包含5 个文件:s3c2440_ov9650.c s3c2440_camif.c s3c2440_camif.h sccb.c sccb.h

    将这5 个文件复制到drivers/media/video 目录下,修改drivers/media/目录下Kconfig 文件,在101 行加入:

    config S 3C 2440_CAMERA

    tristate "OV9650 on the S 3C 2440 driver"

    depends on VIDEO_DEV && ARCH_S 3C 2410

    default y if (VIDEO_DEV && ARCH_S 3C 2410)

    修改drivers/media/video 目录下Makefile 文件,在15 行加入:

    s 3c 2440_camera-objs := s 3c 2440_ov9650.o s 3c 2440_camif.o sccb.o

    在后面165 行加入:

    obj-$(CONFIG_S 3C 2440_CAMERA) += s 3c 2440_camera.o

     

    配置内核,支持CMOS 摄像头:

    Device Drivers --->

    <*> Multimedia support --->

    <*> OV9650 on the S 3C 2440 driver

     

    启动时输出:

    initializing s 3c 2440 camera interface......

    s 3c 2440 camif init done

    Loading OV9650 driver.........

    SCCB address 0x60, manufacture ID 0xFFFF, expect 0x7FA2

     

    解决系统下 camera 模块在LCD 上显示图像颠倒的问题

    方法:修改camera 驱动,在drivers/media/video/s3c2440_ov9650.c 文件中修改第25 行,把{0x1e, 0x0c}改成{0x1e, 0x1c}

    补丁文件

    文件:linux-2.6.31_CMOS.diff.tar.bz2
    大小:165KB
    下载:下载

    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
    阅读(99) | 评论(0) | 转发(0) |
    给主人留下些什么吧!~~
    评论热议
    展开全文
  • 嵌入式Linux下CMOS摄像头驱动的设计与实现.pdf
  • ov7620cmos摄像头驱动

    2010-11-16 21:26:08
    ov7620cmos摄像头驱动,单片机驱动,详细描述了寄存器内容
  • 嵌入式Linux下CMOS摄像头驱动的设计与实现
  • OV9650CMOS摄像头驱动解析

    热门讨论 2012-06-10 19:26:47
    略微简单的OV9650摄像头驱动解析,配合mini2440开发板的CMOS摄像头
  • Linux CMOS摄像头驱动

    千次阅读 2017-05-08 09:18:37
    1、CMOS摄像头原理 摄像头数据流向:自然景观 > 摄像头模块 > 接口 > S3C2440摄像头控制器 > LCD ov7740(摄像头模块) 输入信号:自然景观等的模拟信号 输出信号:RGB、YUV格式的数字信号 输出分辨率: VGA(640*480...

    1、CMOS摄像头原理

    摄像头数据流向:自然景观 > 摄像头模块 > 接口 > S3C2440摄像头控制器 > LCD

    ov7740(摄像头模块)
    输入信号:自然景观等的模拟信号
    输出信号:RGB、YUV格式的数字信号
    输出分辨率: VGA(640*480)、QVGA(240*320)、CIF(352*288)、更小的任意大小

    有效感光阵列的大小:656*488 = 320128(30W)
    镜头的大小:1/5寸
    像素点颗粒大小:4.2um * 4.2um
    以上三个参数,都是用来描述感光阵列,即使同为30w像素的摄像头,如果它的镜头尺寸
    越小, 那么对应的像素点颗粒尺寸也就越小,从而感光性就越差,进而拍摄效果就越差。

    输入时钟频率:6~27MHz(OV7740摄像头模组的工作频率范围)
    扫描模式:连续扫描(P)

    原理图(接口)
    控制类:
    IICSDA        --  IIC总线的数据线
    IICSCL        --  IIC总线的时钟线

    数据传输类:
    CAMRST -- 复位CMOS摄像头模块
    CAMCLK -- 摄像头模块工作的系统时钟(24MHz)
    CAM_HREF -- 行同步信号
    CAM_VSYNC -- 帧同步信号
    CAM_PCLK -- 像素时钟
    CAMDATA0~7 -- 数据线

    CMOS摄像头模块的接口分为两类:
    (1).控制类
    -- 初始化:对摄像头模块进行相应的初始化操作,让摄像头模块能够正常的输出数据。
    -- 控制:设置亮度、旋转、缩放等等的操作
    (2).数据传输类:与LCD的接口完全一样。

    CMOS摄像头模块,是一个IIC设备,需要给它写符合IIC设备那套架构的驱动,从而实现
    初始化工作和 灵活的控制。


    2、CMOS_OV7740设备驱动


    cmos_ov7740_dev.c:
    i2c_new_device() //申请一个i2c客户端client。
    i2c_unregister_device //注销i2c client。

    static struct i2c_board_info cmos_ov7740_info = {	
    	I2C_BOARD_INFO("cmos_ov7740", 0x21),
    };
    
    static struct i2c_client *cmos_ov7740_client;
    
    static int cmos_ov7740_dev_init(void)
    {
    	struct i2c_adapter *i2c_adap;
    
    	i2c_adap = i2c_get_adapter(0);
    	cmos_ov7740_client = i2c_new_device(i2c_adap, &cmos_ov7740_info);
    	i2c_put_adapter(i2c_adap);
    
    	return 0;
    }
    
    static void cmos_ov7740_dev_exit(void)
    {
    	i2c_unregister_device(cmos_ov7740_client);
    }

    设备地址:
    写指令 -- 0x42(01000010)
    读指令 -- 0x43(01000011)

    8bit的地址 = 7bit设备地址 + 1bit的读/写控制位

    设备地址 = 0100001 = 0x21


    展开全文
  • 本文采用一款高速CMOS摄像头,其驱动利用S3C6410内置的FIMC接口技术,采用DMA和ping-pong缓冲池机制,结合内存共享策略,有效提高了传输速率并充分利用了有限的内存资源。深入分析了该驱动的原理和实现细节,并提出...
  • 从零开始写CMOS摄像头驱动(一)

    千次阅读 2019-06-09 16:41:49
    本篇文章主要以OV7740 cmos摄像头以及s3c2440芯片为例,介绍CMOS摄像头,以及SoC芯片内部CMOS控制器部分的基础知识。 最终需要实现的目的是,在LCD上实时显示摄像头采集到的数据 二 what 显示摄像头采集的基本...

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题,二维码如下:
    在这里插入图片描述

    一 why

    本篇文章主要以OV7740 cmos摄像头以及s3c2440芯片为例,介绍CMOS摄像头,以及SoC芯片内部CMOS控制器部分的基础知识。
    最终需要实现的目的是,在LCD上实时显示摄像头采集到的数据

    二 what

    1. 显示摄像头采集的基本流程
      自然景观 --> 摄像头模块 --> 接口 --> S3C2440摄像头控制器
    2. OV7740 cmos摄像头模块的组成
      a. lens镜头
      b. 普通马达
      c. sensor传感器OV7740
    3. 先介绍OV7740摄像头模块
      A. 工作原理以及基本参数
      输入信号: 自然景观模拟信号
      输出信号:输出格式为RAW RGB、YUV格式的数字信号,输出分辨率:VGA(640x480)、QVGA(240x320)、CIF(352x288)或者更小的大小,输出接口为BT601或者BT656
      有效感光阵列大小:656x488
      镜头大小:1/5寸
      像素点颗粒大小:4.2um x 4.2um
      其中有效感光阵列、镜头大小、像素点颗粒大小都是用来描述感光阵列的
      输入时钟:6~27MHz
      扫描模式:连续扫描§
      B. OV7740内部数据的处理流程
      阅读OV7740的数据手册,发现OV7740从内部硬件功能模块上主要分为如下三个部分:
      (1). ISC,image sensor core:翻转、增益大小调整、黑电平校准、饱和度控制、OTP存储器
      (2). ISP,image sensor process:提供测试功能、镜头补偿功能、自动白平衡、RAW RGB -> RGB、RGB -> YUV、窗口功能、缩放功能
      (3). IOI,image output interface:RAW RGB/YUV、VGA/QVGA、BT601/BT656
      那么,我们如何设置OV7740的这些功能呢?显然根据我们设置其他芯片的经验,OV7740必然有一个控制访问接口,我们的SoC芯片通过这个控制访问接口,对OV7740进行初始化设置,根据查看原理图或者数据手册可知,SoC芯片通过I2C总线来访问OV7740。
      设置好OV7740的工作模式之后,显然OV7740会有图像数据输出接口,通过这些接口将图像数据传输到SoC,OV7740支持BT601或者BT656接口传输数据。
    4. S3C2440摄像头CMOS控制器
      这部分内容在数据手册的第23章内容,这里不做详细介绍,只介绍一个粗略部分。
      显然,OV7740的输出信号通过BT601或者BT656接口送到了S3C2440,SoC需要支持这些接口,以及对这些数据做正确处理的功能。
      S3C2440支持BT601或者BT656接口输入,最大支持的分辨率是4096x4096,输入的数据格式必须是8bit YUV;内部图像处理模块支持预览和编码功能,所谓预览就是现实画中画,编码就是对采集到的数据进行编码操作。
      S3C2440每次处理完一帧图像之后,都会产生一个IRQ信号
    5. s3c2440和ov7740 模组之间的接口
      a. 控制类
      s3c2440通过I2C总线控制ov7740模组的初始化设置
      b. 数据传输类
    CAMRST     --> 复位cmos摄像头模块
    CAMCLK     --> 摄像头模块供祖宗的系统时钟(24MHz)
    CAM_HREF   --> 行同步信号
    CAM_VSYNC  --> 帧同步信号
    CAM_PCLK   --> 像素时钟
    CAMDATA0~7 --> 数据线
    
    1. 一些基础概念
      a. RAW RGB和RGB的区别是什么?
      RAW RGB就是只有红绿蓝三种颜色的数据,自然景观经过感光阵列输出后的数字信号就是RAW RGB(感光阵列只支持R、G、B三种)。
      而RGB数据不仅表示红绿蓝三种颜色,而且还能表示由红绿蓝组合成的任何一种颜色
      b. RGB和YUV分别是什么
      两者是完全不同的颜色空间,它们之间可以相互转换
      c. YCrCr420和YCbCr422的区别是什么?
      d. BT601/和BT656传送方式有什么区别
      BT601有独立的行同步信号线、帧同步信号线,而BT656是将这两种信号线内嵌到数据中的

    三 how

    本篇暂时不涉及如何去设置访问模组,只做基础知识介绍,想要知道如何写一个cmos摄像头的驱动,请参照接下来的文章

    展开全文
  • cmos摄像头驱动设计主要分为几部分:1.ARM处理器摄像头接口部分,2.通过i2c接口控制的摄像头芯片部分,被称为senor部分,3.就是上述两部分直接的联系部分,写在板级文件mach-boardname.c文件中。 其实这个摄像头...

    linux下的cmos驱动设计分析:

    cmos摄像头驱动设计主要分为几部分:1.ARM处理器摄像头接口部分,2.通过i2c接口控制的摄像头芯片部分,被称为senor部分,3.就是上述两部分直接的联系部分,写在板级文件mach-boardname.c文件中。

    其实这个摄像头驱动不是太难,摄像头驱动设计的目标就是,ARM处理器控制摄像头芯片,使其能够采集图像然后处理器把图像读出来。

    围绕着这个目的,linux系统提供了v4l2架构,架构的目的是让我们程序员开发的时候更加方便,有个标准的规范,我们程序员在开发驱动的时候,就按着它给的标准的规范,把我们对硬件的操作写到框架中,这样在使用标准的应用程序操作这个设备的时候,,,就通过一层一层,内核中框架的调用对硬件进行了操作。

    对于摄像头驱动来说,

    我就写一写驱动的注册过程和应用程序对应的驱动程序中的操作吧

    驱动的注册:

    在我现在看的linux 3.0.12内核源码中,注册的关键代码主要在drivers/media/video/samsung/fimc/fimc_dev.c 文件的fimc_probe(struct platform_device *pdev)函数中

    在这个函数中,我看关键部分代码主要是以下几个函数

    1 . ctrl = fimc_register_controller(pdev);

    2. ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);

    3.ret = fimc_init_global(pdev);

    4.ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);

    接下来,一一分析这几个函数,我想,注册过程就大体知道了。

    1.ctrl = fimc_register_controller(pdev);

    ctrl是fimc_probe刚开始定义的一个结构体指针struct fimc_control *ctrl;

    形参pdev是什么呢?是fimc的平台设备struct platform_device *pdev,这个在哪定义?

    struct platform_device s3c_device_fimc0 = {
    .name = "s3c-fimc",
    .id = 0,
    .num_resources = ARRAY_SIZE(s3c_fimc0_resource),
    .resource = s3c_fimc0_resource,
    };

    还有一个很重要的函数就是在板级配置文件smdk4x12_machine_init函数中,s3c_fimc0_set_platdata(&fimc_plat);这句话的作用为

    s3c_device_fimc0.dev.platform_data=fimc_plat;

    fimc_plat为什么样的结构体呢?其定义为

    static struct s3c_platform_fimc fimc_plat = {

      .default_cam = CAMERA_PAR_A,

     .camera = &ov5640,

     .hw_ver = 0x51,

    }     它的作用主要是描述了fimc结构的设置,比如读取哪种格式的数据,读取时采用哪种形式的时序,fimc读取时的时钟频率等,

    其中ov5640这个结构展开为

    static struct s3c_platform_camera ov5640 = {
    .id = CAMERA_PAR_A,
    .clk_name = "sclk_cam0",
    .i2c_busnum = 7,
    .cam_power = smdk4x12_cam1_reset,


    .type = CAM_TYPE_ITU,
    .fmt = ITU_601_YCBCR422_8BIT,
    .order422 = CAM_ORDER422_8BIT_CBYCRY,
    .info = &ov5640_i2c_info,
    .pixelformat = V4L2_PIX_FMT_UYVY, //modify by cym V4L2_PIX_FMT_UYVY,
    .srclk_name = "xusbxti",
    .clk_rate = 24000000,
    .line_length = 1920,
    .width = 640,
    .height = 480,
    .window = {
    .left = 0,
    .top = 0,
    .width = 640,
    .height = 480,
    },

    /* Polarity */
    .inv_pclk = 0,
    .inv_vsync = 1,
    .inv_href = 0,
    .inv_hsync = 0,
    .reset_camera = 1,
    .initialized = 0,
                  .layout_rotate = 0 //for shuping, //180, 
    };

    上面是为我们分析函数进行了准备,把会用到的相关的结构体都进行了罗列,下面开始分析 ctrl = fimc_register_controller(pdev);

    static struct fimc_control *fimc_register_controller(struct platform_device *pdev)
    {
    	struct s3c_platform_fimc *pdata;
    	struct fimc_control *ctrl;
    	struct resource *res;
    	int id, err;
    	struct cma_info mem_info;
    	struct clk *sclk_fimc_lclk = NULL;
    	struct clk *fimc_src_clk = NULL;
    
    	id = pdev->id;
    	pdata = to_fimc_plat(&pdev->dev);
    
    	ctrl = get_fimc_ctrl(id);
    	ctrl->id = id;
    	ctrl->dev = &pdev->dev;
    	ctrl->vd = &fimc_video_device[id];
    	ctrl->vd->minor = id;
    	ctrl->log = FIMC_LOG_DEFAULT;
    	ctrl->power_status = FIMC_POWER_OFF;
    
    	/* CMA */
    	sprintf(ctrl->cma_name, "%s%d", FIMC_CMA_NAME, ctrl->id);
    	err = cma_info(&mem_info, ctrl->dev, 0);
    	fimc_info1("%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x, "
    			"total_size : 0x%x, free_size : 0x%x\n",
    			__func__, mem_info.lower_bound, mem_info.upper_bound,
    			mem_info.total_size, mem_info.free_size);
    	if (err) {
    		fimc_err("%s: get cma info failed\n", __func__);
    		ctrl->mem.size = 0;
    		ctrl->mem.base = 0;
    	} else {
    		ctrl->mem.size = mem_info.total_size;
    		ctrl->mem.base = (dma_addr_t)cma_alloc
    			(ctrl->dev, ctrl->cma_name, (size_t)ctrl->mem.size, 0);
    	}
    	printk(KERN_DEBUG "ctrl->mem.size = 0x%x\n", ctrl->mem.size);
    	printk(KERN_DEBUG "ctrl->mem.base = 0x%x\n", ctrl->mem.base);
    	ctrl->mem.curr = ctrl->mem.base;
    	ctrl->status = FIMC_STREAMOFF;
    
    	switch (pdata->hw_ver) {
    	case 0x40:
    		ctrl->limit = &fimc40_limits[id];
    		break;
    	case 0x43:
    	case 0x45:
    		ctrl->limit = &fimc43_limits[id];
    		break;
    	case 0x50:
    		ctrl->limit = &fimc50_limits[id];
    		break;
    	case 0x51:
    		ctrl->limit = &fimc51_limits[id];
    		break;
    	default:
    		ctrl->limit = &fimc51_limits[id];
    		fimc_err("%s: failed to get HW version\n", __func__);
    		break;
    	}
    
    	sprintf(ctrl->name, "%s%d", FIMC_NAME, id);
    	strcpy(ctrl->vd->name, ctrl->name);
    
    	atomic_set(&ctrl->in_use, 0);
    	mutex_init(&ctrl->lock);
    	mutex_init(&ctrl->v4l2_lock);
    	spin_lock_init(&ctrl->outq_lock);
    	init_waitqueue_head(&ctrl->wq);
    
    	/* get resource for io memory */
    	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    	if (!res) {
    		fimc_err("%s: failed to get io memory region\n", __func__);
    		return NULL;
    	}
    
    	/* request mem region */
    	res = request_mem_region(res->start, res->end - res->start + 1,
    			pdev->name);
    	if (!res) {
    		fimc_err("%s: failed to request io memory region\n", __func__);
    		return NULL;
    	}
    
    	/* ioremap for register block */
    	ctrl->regs = ioremap(res->start, res->end - res->start + 1);
    	if (!ctrl->regs) {
    		fimc_err("%s: failed to remap io region\n", __func__);
    		return NULL;
    	}
    
    	/* irq */
    	ctrl->irq = platform_get_irq(pdev, 0);
    	if (request_irq(ctrl->irq, fimc_irq, IRQF_DISABLED, ctrl->name, ctrl))
    		fimc_err("%s: request_irq failed\n", __func__);
    
    	if (soc_is_exynos4210())
    		fimc_src_clk = clk_get(&pdev->dev, "mout_mpll");
    	else
    		fimc_src_clk = clk_get(&pdev->dev, "mout_mpll_user");
    
    	if (IS_ERR(fimc_src_clk)) {
    		dev_err(&pdev->dev, "failed to get parent clock\n");
    		iounmap(ctrl->regs);
    		return NULL;
    	}
    
    	sclk_fimc_lclk = clk_get(&pdev->dev, FIMC_CORE_CLK);
    	if (IS_ERR(sclk_fimc_lclk)) {
    		dev_err(&pdev->dev, "failed to get sclk_fimc_lclk\n");
    		iounmap(ctrl->regs);
    		clk_put(fimc_src_clk);
    		return NULL;
    	}
    
    	if (clk_set_parent(sclk_fimc_lclk, fimc_src_clk)) {
    		dev_err(&pdev->dev, "unable to set parent %s of clock %s.\n",
    				fimc_src_clk->name, sclk_fimc_lclk->name);
    		iounmap(ctrl->regs);
    		clk_put(sclk_fimc_lclk);
    		clk_put(fimc_src_clk);
    		return NULL;
    	}
    	clk_set_rate(sclk_fimc_lclk, FIMC_CLK_RATE);
    	clk_put(sclk_fimc_lclk);
    	clk_put(fimc_src_clk);
    
    #if (!defined(CONFIG_EXYNOS_DEV_PD) || !defined(CONFIG_PM_RUNTIME))
    	fimc_hwset_reset(ctrl);
    #endif
    
    	return ctrl;
    }
    展开发现,上面代码主要做的了:

    1,填充了struct fimc_control *ctrl;这个结构,这个结构是用来描述fimc控制器的,

    2,映射了FIMC的的寄存器

    3.申请设置了FImc控制器的时钟

    *****************************************

    接下来分析第二个函数 ret = v4l2_device_register(&pdev->dev, &ctrl->v4l2_dev);

    这里的形参&pdev->dev,&ctrl,还是我们开始分析时提到的那些结构,

    展开函数

    int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
    {
    	if (v4l2_dev == NULL)
    		return -EINVAL;
    
    	INIT_LIST_HEAD(&v4l2_dev->subdevs);
    	spin_lock_init(&v4l2_dev->lock);
    	mutex_init(&v4l2_dev->ioctl_lock);
    	v4l2_prio_init(&v4l2_dev->prio);
    	kref_init(&v4l2_dev->ref);
    	v4l2_dev->dev = dev;
    	if (dev == NULL) {
    		/* If dev == NULL, then name must be filled in by the caller */
    		WARN_ON(!v4l2_dev->name[0]);
    		return 0;
    	}
    
    	/* Set name to driver name + device name if it is empty. */
    	if (!v4l2_dev->name[0])
    		snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s",
    			dev->driver->name, dev_name(dev));
    	if (!dev_get_drvdata(dev))
    		dev_set_drvdata(dev, v4l2_dev);
    	return 0;
    }
    这个函数主要干了几件事:
    1.初始化了一个链表

    2.稍微对&v4l2_dev进行了设置

    3.v4l2_dev->dev = dev;把形参平台设备结构中的dev关联到v4l2_dev->dev,以后有用

    4.if (!dev_get_drvdata(dev)) dev_set_drvdata(dev, v4l2_dev); 使得 平台设备结构中的dev和这个v4l2_dev,实现相互关联


    接下来看第3个关键函数,ret = fimc_init_global(pdev);

    static int fimc_init_global(struct platform_device *pdev)
    {
    	struct fimc_control *ctrl;
    	struct s3c_platform_fimc *pdata;
    	struct s3c_platform_camera *cam;
    	struct clk *srclk;
    	int id, i;
    
    	pdata = to_fimc_plat(&pdev->dev);
    	id = pdev->id;
    	ctrl = get_fimc_ctrl(id);
    
    	/* Registering external camera modules. re-arrange order to be sure */
    	for (i = 0; i < FIMC_MAXCAMS; i++) {
    		cam = pdata->camera[i];
    		if (!cam)
    			break;
    		/* WriteBack doesn't need clock setting */
    		if ((cam->id == CAMERA_WB) || (cam->id == CAMERA_WB_B)) {
    			fimc_dev->camera[i] = cam;
    			fimc_dev->camera_isvalid[i] = 1;
    			fimc_dev->camera[i]->initialized = 0;
    			continue;
    		}
    
    		/* source clk for MCLK*/
    		srclk = clk_get(&pdev->dev, cam->srclk_name);
    		if (IS_ERR(srclk)) {
    			fimc_err("%s: failed to get srclk source\n", __func__);
    			return -EINVAL;
    		}
    
    		/* mclk */
    		cam->clk = clk_get(&pdev->dev, cam->clk_name);
    		if (IS_ERR(cam->clk)) {
    			fimc_err("%s: failed to get mclk source\n", __func__);
    			return -EINVAL;
    		}
    
    		if (clk_set_parent(cam->clk, srclk)) {
    			dev_err(&pdev->dev, "unable to set parent %s of clock %s.\n",
    					srclk->name, cam->clk->name);
    			clk_put(srclk);
    			clk_put(cam->clk);
    			return -EINVAL;
    		}
    
    		/* Assign camera device to fimc */
    		fimc_dev->camera[i] = cam;
    		fimc_dev->camera_isvalid[i] = 1;
    		fimc_dev->camera[i]->initialized = 0;
    	}
    
    	fimc_dev->mclk_status = CAM_MCLK_OFF;
    	fimc_dev->active_camera = -1;
    	fimc_dev->initialized = 1;
    
    	return 0;
    }

    这个函数主要做的是:

    根据平台设备设置的信息,初始化fimc_dev这个结构体,这是一个全局变量,在fimc_dev.c中有定义,struct fimc_global *fimc_dev;

    /**
     * struct fimc_dev - abstraction for FIMC entity
     * @slock:	the spinlock protecting this data structure
     * @lock:	the mutex protecting this data structure
     * @pdev:	pointer to the FIMC platform device
     * @pdata:	pointer to the device platform data
     * @variant:	the IP variant information
     * @id:		FIMC device index (0..FIMC_MAX_DEVS)
     * @num_clocks: the number of clocks managed by this device instance
     * @clock:	clocks required for FIMC operation
     * @regs:	the mapped hardware registers
     * @regs_res:	the resource claimed for IO registers
     * @irq:	FIMC interrupt number
     * @irq_queue:	interrupt handler waitqueue
     * @m2m:	memory-to-memory V4L2 device information
     * @vid_cap:	camera capture device information
     * @state:	flags used to synchronize m2m and capture mode operation
     * @alloc_ctx:	videobuf2 memory allocator context
     */
    struct fimc_dev {
    	spinlock_t			slock;
    	struct mutex			lock;
    	struct platform_device		*pdev;
    	struct s5p_platform_fimc	*pdata;
    	struct samsung_fimc_variant	*variant;
    	u16				id;
    	u16				num_clocks;
    	struct clk			*clock[MAX_FIMC_CLOCKS];
    	void __iomem			*regs;
    	struct resource			*regs_res;
    	int				irq;
    	wait_queue_head_t		irq_queue;
    	struct work_struct		work_struct;
    	struct workqueue_struct		*irq_workqueue;
    	struct fimc_m2m_device		m2m;
    	struct fimc_vid_cap		vid_cap;
    	unsigned long			state;
    	struct vb2_alloc_ctx		*alloc_ctx;
    	struct fimc_addr		paddr[FIMC_MAX_OUT_BUFS];
    #ifdef CONFIG_VIDEOBUF2_SDVMM
    	enum vcm_dev_id			vcm_id;
    #endif
    	const struct fimc_vb2		*vb2;
    };

    接下来,看最后一个关键函数:4.ret = video_register_device(ctrl->vd, VFL_TYPE_GRABBER, ctrl->id);

    形参ctrl->vd为上面介绍的第一个函数中赋值的,为ctrl->vd = &fimc_video_device[id];ctrl->id代码是FIMC几,0,1,2或者3

    /* Register video devices. Note that if video_register_device fails,
       the release() callback of the video_device structure is *not* called, so
       the caller is responsible for freeing any data. Usually that means that
       you call video_device_release() on failure. */
    static inline int __must_check video_register_device(struct video_device *vdev,
    		int type, int nr)
    {
    	return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
    }
    注册video devices ,

    展开看看

    /**
     *	__video_register_device - register video4linux devices
     *	@vdev: video device structure we want to register
     *	@type: type of device to register
     *	@nr:   which device node number (0 == /dev/video0, 1 == /dev/video1, ...
     *             -1 == first free)
     *	@warn_if_nr_in_use: warn if the desired device node number
     *	       was already in use and another number was chosen instead.
     *	@owner: module that owns the video device node
     *
     *	The registration code assigns minor numbers and device node numbers
     *	based on the requested type and registers the new device node with
     *	the kernel.
     *
     *	This function assumes that struct video_device was zeroed when it
     *	was allocated and does not contain any stale date.
     *
     *	An error is returned if no free minor or device node number could be
     *	found, or if the registration of the device node failed.
     *
     *	Zero is returned on success.
     *
     *	Valid types are
     *
     *	%VFL_TYPE_GRABBER - A frame grabber
     *
     *	%VFL_TYPE_VBI - Vertical blank data (undecoded)
     *
     *	%VFL_TYPE_RADIO - A radio card
     *
     *	%VFL_TYPE_SUBDEV - A subdevice
     */
    int __video_register_device(struct video_device *vdev, int type, int nr,
    		int warn_if_nr_in_use, struct module *owner)
    {
    	int i = 0;
    	int ret;
    	int minor_offset = 0;
    	int minor_cnt = VIDEO_NUM_DEVICES;
    	const char *name_base;
    
    	/* A minor value of -1 marks this video device as never
    	   having been registered */
    	vdev->minor = -1;
    
    	/* the release callback MUST be present */
    	WARN_ON(!vdev->release);
    	if (!vdev->release)
    		return -EINVAL;
    
    	/* v4l2_fh support */
    	spin_lock_init(&vdev->fh_lock);
    	INIT_LIST_HEAD(&vdev->fh_list);
    
    	/* Part 1: check device type */
    	switch (type) {
    	case VFL_TYPE_GRABBER:
    		name_base = "video";
    		break;
    	case VFL_TYPE_VBI:
    		name_base = "vbi";
    		break;
    	case VFL_TYPE_RADIO:
    		name_base = "radio";
    		break;
    	case VFL_TYPE_SUBDEV:
    		name_base = "v4l-subdev";
    		break;
    	default:
    		printk(KERN_ERR "%s called with unknown type: %d\n",
    		       __func__, type);
    		return -EINVAL;
    	}
    
    	vdev->vfl_type = type;
    	vdev->cdev = NULL;
    	if (vdev->v4l2_dev) {
    		if (vdev->v4l2_dev->dev)
    			vdev->parent = vdev->v4l2_dev->dev;
    		if (vdev->ctrl_handler == NULL)
    			vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
    		/* If the prio state pointer is NULL, then use the v4l2_device
    		   prio state. */
    		if (vdev->prio == NULL)
    			vdev->prio = &vdev->v4l2_dev->prio;
    	}
    
    	/* Part 2: find a free minor, device node number and device index. */
    #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
    	/* Keep the ranges for the first four types for historical
    	 * reasons.
    	 * Newer devices (not yet in place) should use the range
    	 * of 128-191 and just pick the first free minor there
    	 * (new style). */
    	switch (type) {
    	case VFL_TYPE_GRABBER:
    		minor_offset = 0;
    		minor_cnt = 64;
    		break;
    	case VFL_TYPE_RADIO:
    		minor_offset = 64;
    		minor_cnt = 64;
    		break;
    	case VFL_TYPE_VBI:
    		minor_offset = 224;
    		minor_cnt = 32;
    		break;
    	default:
    		minor_offset = 128;
    		minor_cnt = 64;
    		break;
    	}
    #endif
    
    	/* Pick a device node number */
    	mutex_lock(&videodev_lock);
    	nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
    	if (nr == minor_cnt)
    		nr = devnode_find(vdev, 0, minor_cnt);
    	if (nr == minor_cnt) {
    		printk(KERN_ERR "could not get a free device node number\n");
    		mutex_unlock(&videodev_lock);
    		return -ENFILE;
    	}
    #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
    	/* 1-on-1 mapping of device node number to minor number */
    	i = nr;
    #else
    	/* The device node number and minor numbers are independent, so
    	   we just find the first free minor number. */
    	for (i = 0; i < VIDEO_NUM_DEVICES; i++)
    		if (video_device[i] == NULL)
    			break;
    	if (i == VIDEO_NUM_DEVICES) {
    		mutex_unlock(&videodev_lock);
    		printk(KERN_ERR "could not get a free minor\n");
    		return -ENFILE;
    	}
    #endif
    	vdev->minor = i + minor_offset;
    	vdev->num = nr;
    	devnode_set(vdev);
    
    	/* Should not happen since we thought this minor was free */
    	WARN_ON(video_device[vdev->minor] != NULL);
    	vdev->index = get_index(vdev);
    	mutex_unlock(&videodev_lock);
    
    	/* Part 3: Initialize the character device */
    	vdev->cdev = cdev_alloc();
    	if (vdev->cdev == NULL) {
    		ret = -ENOMEM;
    		goto cleanup;
    	}
    	vdev->cdev->ops = &v4l2_fops;
    	vdev->cdev->owner = owner;
    	ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
    	if (ret < 0) {
    		printk(KERN_ERR "%s: cdev_add failed\n", __func__);
    		kfree(vdev->cdev);
    		vdev->cdev = NULL;
    		goto cleanup;
    	}
    
    	/* Part 4: register the device with sysfs */
    	vdev->dev.class = &video_class;
    	vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
    	if (vdev->parent)
    		vdev->dev.parent = vdev->parent;
    	dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
    	ret = device_register(&vdev->dev);
    	if (ret < 0) {
    		printk(KERN_ERR "%s: device_register failed\n", __func__);
    		goto cleanup;
    	}
    	/* Register the release callback that will be called when the last
    	   reference to the device goes away. */
    	vdev->dev.release = v4l2_device_release;
    
    	if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
    		printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__,
    			name_base, nr, video_device_node_name(vdev));
    
    	/* Increase v4l2_device refcount */
    	if (vdev->v4l2_dev)
    		v4l2_device_get(vdev->v4l2_dev);
    
    #if defined(CONFIG_MEDIA_CONTROLLER)
    	/* Part 5: Register the entity. */
    	if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
    	    vdev->vfl_type != VFL_TYPE_SUBDEV) {
    		vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
    		vdev->entity.name = vdev->name;
    		vdev->entity.v4l.major = VIDEO_MAJOR;
    		vdev->entity.v4l.minor = vdev->minor;
    		ret = media_device_register_entity(vdev->v4l2_dev->mdev,
    			&vdev->entity);
    		if (ret < 0)
    			printk(KERN_WARNING
    			       "%s: media_device_register_entity failed\n",
    			       __func__);
    	}
    #endif
    	/* Part 6: Activate this minor. The char device can now be used. */
    	set_bit(V4L2_FL_REGISTERED, &vdev->flags);
    	mutex_lock(&videodev_lock);
    	video_device[vdev->minor] = vdev;
    	mutex_unlock(&videodev_lock);
    
    	return 0;
    
    cleanup:
    	mutex_lock(&videodev_lock);
    	if (vdev->cdev)
    		cdev_del(vdev->cdev);
    	devnode_clear(vdev);
    	mutex_unlock(&videodev_lock);
    	/* Mark this video device as never having been registered. */
    	vdev->minor = -1;
    	return ret;
    }

    这个函数做的主要是

    1.确定要注册的设备类型,与传入的那个形参有关,一般为video类型

    2.查找相同类型设备的设备节点号,比如这次注册了VIDEO0,那下次执行这个函数时,要检查出来,0这个号已经被注册,注册的就是VIDEO1

    3.注册设备,注册的是一个字符设备,所以某种意思上说,video设备也属于一个字符设备








    展开全文
  • 该文介绍了基于ARM9架构,采用CMOS图像传感器OV9650,在Linux操作系统下摄像头驱动的设计与实现.使用I2C总线配置摄像头控制寄存器,引入信号量机制,优化临界资源调度,编写及完善应用程序接口(API),实现了多任务多线程...
  • 视频监控—从零写CMOS摄像头驱动 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3),OV7740摄像头 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统 参考资料:OV7740_CSP_DS_1.51 data...
  • CMOS摄像头驱动分析笔记1

    千次阅读 2016-11-10 07:26:02
    最近学习摄像头驱动,刚刚大体上看完,有些地方换是不太明白,先做个笔记总结一下这几天看的,水平不行,语言很搓,有错误欢迎指正,十分感谢。 CMOS摄像头接口 接口主要由I2C控制总线部分和...
  • 上一节我们就知道CMOS是一个IIC驱动程序。 因为我们是通过读的方式来获得摄像头数据,因此查询/放入队列/取出队列这些操作函数将不在需要 **使用IIC初始化设置它为:**640*480的分辨率。帧率是30fps,输出的格式是...
  • TX2440 CMOS 摄像头驱动

    2014-07-22 13:46:19
    http://blog.chinaunix.net/uid-24219701-id-67491.html
  • CMOS摄像头驱动分析笔记2

    千次阅读 2014-07-07 11:06:05
    接下来分析fimc驱动部分,在
  • s5pv210 cmos摄像头驱动(二)

    千次阅读 2014-04-14 01:34:22
    在__video_do_ioctl函数中 struct video_device *vfd = video_devdata(file); ...通过打开的节点获取相应的...在应用层调用使用查询摄像头支持的格式 ioctl(fd, VIDIOC_QUERYCAP, &cap)) 相应驱动函数: ...
  • s5pv210 cmos摄像头驱动(一)

    千次阅读 2014-04-13 23:26:08
    一:s5pv210摄像头控制器
  • 上一篇写了,摄像头驱动的注册过程,这次写写应用程序的调用与驱动程序的关系,遵循V4L2架构的应用程序主要由几个ioctl组成, 其实也比较简单,有时候驱动写的不标准,应用程序按标准的操作操作就不行,出不来图像,...
  • DM642接CMOS摄像头驱动(OV7725)终于搞定了

    千次阅读 热门讨论 2010-04-20 10:33:00
    但是在最近一个项目中,摄像头不能用模拟的,要改用CMOS的,这样就不得不去该底层的驱动了,在查看了TI的一些文档后,发现VP口在接CMOS摄像头时,它接收的视频数据一般都是RAW data 格式的,这样在写它的驱动时与...
  • Linux摄像头驱动4——CMOS摄像头

    千次阅读 2019-05-07 08:48:40
    CSDN仅用于增加百度收录权重,排版未优化,日常不维护。...Linux摄像头驱动学习第四篇,对CMOS摄像头进行学习,实现在Tiny4412上使用CMOS摄像头采集图像,在LCD上显示图像。 坚持到了Linux摄像头学习的最后...
  • USB摄像头驱动--CMOS摄像头

    千次阅读 2019-07-31 16:40:17
    1.CMOS摄像头基础 本次使用的白问网提供的ov7740摄像头模组,基础机构如下: 1.1摄像头参数 OV7740_CSP_DS_1.51.pdf—ov7740的datasheet中的参数可知: 支持输出格式:RAW RGB与YUV格式 RAW RGB与RGB的区别...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,236
精华内容 894
关键字:

cmos摄像头驱动