camera驱动框架分析(上)
前言
camera驱动框架涉及到的知识点比较多,特别是camera本身的接口就有很多,有些是直接连接到soc的camif口上的,有些是通过usb接口导出的,如usb camera。我这里主要讨论前者,也就是与soc直连的。我认为凡是涉及到usb的,都不是一两句话可以说明白的!如有错误,欢迎指正,谢谢!!!
环境说明
涉及到的基础知识点:
字符设备驱动
设备模型
平台设备驱动
v4l2框架
i2c驱动框架
涉及到的术语:
camera : 指的是整个camera,包括它本身的硬件连接方式及支持i2c控制的i2c设备
sensor : 指的是支持i2c控制的i2c设备,它属于camera的一部分,在内核实现里也能体现出来
camera host: 指的是与camera相连接的,一般内嵌在soc里面的控制器
涉及到的文件夹:
drivers/media/platform/soc_camera/ 主要存放camera host驱动,通用的camera驱动也存放在此
drivers/media/i2c/soc_camera/ 主要存放sensor驱动
分析所采用的内核版本:
VERSION = 3
PATCHLEVEL = 15
SUBLEVEL = 0
EXTRAVERSION =
NAME = Shuffling Zombie Juror
camera的驱动包括通用camera的驱动、camera host的驱动以及sensor的驱动,下面一个个来分析
这里先插一张图,来自:http://blog.csdn.net/kickxxx/article/details/8484498(该图片及图片后的文字是在我写完这篇博文后发现的,我认为对理解camera驱动会有帮助,所以就摘抄了_)

Soc camera sub-system对应着drivers/media/video/下的soc_camera.c soc_camera_platform.c
Soc camera host 是host端实现,是由平台厂商实现的,向上实现soc_camera_host_ops接口,向下操作Camera host硬件以及通过平台特定的接口操作Soc camera device
Soc camera device 是平台的camera device(同时也是subdev),由驱动开发者来实现v4l2_subdev_call调用的subdev 接口,同时还要为soc camera host实现平台特定的操作接口;向下操作camera sensor或者video AD芯片。
Camera host hardware是平台硬件相关的,不同的平台有不同的host硬件,比如imx51的ipu,三星s5pv210的fimc控制器等。
soc_camera_host,soc_camera_device,v4l2_device,v4l2_subdev关系如下:
理论上系统内可以有多个soc_camera_host,物理上soc_camera_host就是系统的camera处理模块驱动
一个soc_camera_host可以对应多个soc_camera_device,物理上soc_camera_device是一个camera接口,每个soc_camera_host对应一个v4l2_dev
每个soc_camera_device,系统会为他们创建设备节点/dev/videoX。
每个soc_camera_device有多个v4l2_subdev,物理上v4l2_subdev可以是sensor,video AD芯片
v4l2_subdev可以通过i2c挂接到v4l2_device,也可以通过soc_camera_link提供的add_device来增加,这依赖于sensor和video AD芯片挂接到MCU camera接口的方式。
通用camera驱动
对应文件drivers/media/platform/soc_camera/soc_camera.c:
static struct platform_driver __refdata soc_camera_pdrv = {
.probe = soc_camera_pdrv_probe,
.remove = soc_camera_pdrv_remove,
.driver = {
.name = "soc-camera-pdrv",
.owner = THIS_MODULE,
},
};
module_platform_driver(soc_camera_pdrv);
从这里可以看出,我们要使该驱动probe得到调用,先得注册一个平台设备,且名字为soc-camera-pdrv。通用camera的驱动就是定义了一套数据结构,然后告诉大家,你如果想用通用的camera驱动,那就照着数据结构填好,然后用soc-camera-pdrv的名字通过平台总线注册上来就可以了。平台设备的注册可以通过两种方式来实现,一种是通过设备树,它是最新的一种机制,通过dts文件来描述硬件信息,使得内核里面不会再硬编码一堆和用于描述硬件信息的代码。对应到这里的硬件信息就是camera sensor硬件信息以及camera硬件布线信息。另一种就是以前采用的方式,直接用代码在板子相关的启动文件里来描述那些信息并通过平台设备的注册。soc_camera_pdrv里面没有设备树的相关支持,说明这类设备的添加还是采用后面那种方式,通过下面的命令输出也可以证实这一点:
我用命令(grep -rns soc-camera-pdrv arch/arm*/)搜索一下,就可以得到以下结果:
arch/arm/mach-shmobile/board-lager.c:394: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
arch/arm/mach-shmobile/board-bockw.c:606: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 0,
arch/arm/mach-shmobile/board-bockw.c:609: platform_device_register_data(&platform_bus, "soc-camera-pdrv", 1,
arch/arm/mach-shmobile/board-mackerel.c:1224: .name = "soc-camera-pdrv",
arch/arm/mach-shmobile/board-armadillo800eva.c:910: .name = "soc-camera-pdrv",
arch/arm/mach-shmobile/board-marzen.c:299: .name = "soc-camera-pdrv", \
arch/arm/mach-at91/board-sam9m10g45ek.c:241: .name = "soc-camera-pdrv",
arch/arm/mach-omap1/board-ams-delta.c:435: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/ezx.c:788: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/ezx.c:1062: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/em-x270.c:1034: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/palmz72.c:339: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/pcm990-baseboard.c:507: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/pcm990-baseboard.c:513: .name = "soc-camera-pdrv",
arch/arm/mach-pxa/mioa701.c:682:MIO_SIMPLE_DEV(mioa701_camera, "soc-camera-pdrv",&iclink);
arch/arm/mach-imx/mach-imx27_visstrim_m10.c:572: platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
arch/arm/mach-imx/mach-mx31_3ds.c:248: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mach-mx31_3ds.c:412: REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx31_3ds.c:444: REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx35_3ds.c:305: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mach-mx35_3ds.c:324: REGULATOR_SUPPLY("cmos_vio", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:272: REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:302: REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"),
arch/arm/mach-imx/mach-mx27_3ds.c:410: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mx31moboard-smartbot.c:91: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mx31moboard-marxbot.c:181: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mach-pcm037.c:329: .name = "soc-camera-pdrv",
arch/arm/mach-imx/mach-pcm037.c:337: .name = "soc-camera-pdrv",
我选一个稍微简单的mach来进行后面的分析,at91平台(arch/arm/mach-at91/board-sam9m10g45ek.c),我把相关的代码截取出来:
* soc-camera OV2640
*/
#if defined(CONFIG_SOC_CAMERA_OV2640) || \
defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
{
/* ISI board for ek using default 8-bits connection */
return SOCAM_DATAWIDTH_8;
}
static int i2c_camera_power(struct device *dev, int on)
{
/* enable or disable the camera */
pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
at91_set_gpio_output(AT91_PIN_PD13, !on);
if (!on)
goto out;
/* If enabled, give a reset impulse */
at91_set_gpio_output(AT91_PIN_PD12, 0);
msleep(20);
at91_set_gpio_output(AT91_PIN_PD12, 1);
msleep(100);
out:
return 0;
}
static struct i2c_board_info i2c_camera = {
I2C_BOARD_INFO("ov2640", 0x30),
};
static struct soc_camera_link iclink_ov2640 = {
.bus_id = 0,
.board_info = &i2c_camera,
.i2c_adapter_id = 0,
.power = i2c_camera_power,
.query_bus_param = isi_camera_query_bus_param,
};
static struct platform_device isi_ov2640 = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = &iclink_ov2640,
},
};
#endif
最重要的结构就是soc_camera_link,它是所有camera这类设备都需要用到的结构体。bus_id用来描述它是连接到哪条soc camera host总线上,后面会再讲这个。board_info用来描述i2c设备的信息,比如它的型号名称,它的i2c地址,相信研究过i2c驱动的人都比较熟悉。i2c_adapter_id用来描述i2c设备挂载哪条i2c总线上。sensor的控制一般通过i2c来实现,所以这里才会有i2c设备的描述,因为需要对应的i2c驱动来驱动它啊。power一般指sensor的电源模块的开启和关闭,一般是单独通过一个gpio来控制的。query_bus_param这个成员先不看吧,用到的时候再看。
总之,通过上面的信息以及后面的平台设备注册后,就将soc-camera-pdrv平台设备添加到平台总线了。也就是说只要这段代码编译进入了内核并调用了这段代码,那么soc_camera_pdrv_probe就一定会执行了。下面继续分析前面列出来的soc_camera_pdrv_probe吧!
soc_camera_pdrv_probe的实现很短,为了方面说明,也贴出来吧:
static int soc_camera_pdrv_probe(struct platform_device *pdev)
{
struct soc_camera_desc *sdesc = pdev->dev.platform_data;
struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc;
struct soc_camera_device *icd;
int ret;
if (!sdesc)
return -EINVAL;
icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL);
if (!icd)
return -ENOMEM;
/*
* In the asynchronous case ssdd->num_regulators == 0 yet, so, the below
* regulator allocation is a dummy. They are actually requested by the
* subdevice driver, using soc_camera_power_init(). Also note, that in
* that case regulators are attached to the I2C device and not to the
* camera platform device.
*/
ret = devm_regulator_bulk_get(&pdev->dev, ssdd->sd_pdata.num_regulators,
ssdd->sd_pdata.regulators);
if (ret < 0)
return ret;
icd->iface = sdesc->host_desc.bus_id;
icd->sdesc = sdesc;
icd->pdev = &pdev->dev;
platform_set_drvdata(pdev, icd);
icd->user_width = DEFAULT_WIDTH;
icd->user_height = DEFAULT_HEIGHT;
return soc_camera_device_register(icd);
}
这里我们会开始接触第二个重要的数据结构soc_camera_device,它在内核里代表的就是一个camera sensor设备。有一点需要提前说明下,我们之前谈到数据结构soc_camera_link,对应到驱动使用的时候,将其拆分成两个结构体了,我想也是为了代码更清晰吧!对应的结构如下:
struct soc_camera_desc {
struct soc_camera_subdev_desc subdev_desc;
struct soc_camera_host_desc host_desc;
};
因此,soc_camera_pdrv_probe里面的icd->iface = sdesc->host_desc.bus_id其实就是上面我说过的bus_id,用来描述它是连接到哪条soc camera host线上。soc_camera_pdrv_probe主要是创建对象 soc_camera_device,它代表着一个camera sensor设备。当然可以有多个这样的设备同时存在,且都由该驱动负责创建。并将platform设备传过来的各种数据放到soc_camera_device里面,最终调用soc_camera_device_register将该camera sensor注册。
soc_camera_device_register的代码就不贴了,它其实主要就做了一件事情,将代表着camera sensor的对象soc_camera_device放到了全局链表devices中,其他的就是做参数检查等等。
好了,到这里,我们的系统里的devices全局链表里已经有一个用于代表camera sensor的设备了,它就在这里静静的等待着负责它的驱动的到来,我们应该可以想象到,负责它的就是camera host咯。顺便说一下,如果我们仅仅需要写一个sensor驱动,那么到这里,就算完成了一小半了,剩下的就是完成我们camera sensor里对应的i2c设备的驱动(参考drivers/media/i2c/soc_camera/,里面有一些已经实现了的i2c sensor驱动),至于camera host驱动,一般对应的soc的sdk都会实现啦。
未完,待续!
2015年6月
camera驱动框架分析(上)的更多相关文章
- camera驱动框架分析(上)【转】
转自:https://www.cnblogs.com/rongpmcu/p/7662738.html 前言 camera驱动框架涉及到的知识点比较多,特别是camera本身的接口就有很多,有些是直接连 ...
- camera驱动框架分析(中)
camera host的驱动 下面开始分析camera host吧,如果仅仅是想知道camera sensor驱动怎么写,而不想知道内部具体怎么个调用流程,怎么个架构设计,那可以跳过该部分,直接去看i ...
- camera驱动框架分析(下)
sensor的驱动 v4l2_i2c_new_subdev_board先用client = i2c_new_device(adapter, info);创建info对应的i2c_client对象(代表 ...
- Linux USB驱动框架分析(2)【转】
转自:http://blog.chinaunix.net/uid-23046336-id-3243543.html 看了http://blog.chinaunix.net/uid-11848011 ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- linux驱动基础系列--linux spi驱动框架分析
前言 主要是想对Linux 下spi驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.设备模型等也不进行详细说明原理.如果有任何错误地方,请指出,谢谢! spi ...
- linux驱动基础系列--linux spi驱动框架分析(续)
前言 这篇文章是对linux驱动基础系列--linux spi驱动框架分析的补充,主要是添加了最新的linux内核里设备树相关内容. spi设备树相关信息 如之前的文章里所述,控制器的device和s ...
- Linux下USB驱动框架分析【转】
转自:http://blog.csdn.net/brucexu1978/article/details/17583407 版权声明:本文为博主原创文章,未经博主允许不得转载. http://www.c ...
- Linux USB驱动框架分析【转】
转自:http://blog.csdn.net/jeffade/article/details/7701431 Linux USB驱动框架分析(一) 初次接触和OS相关的设备驱动编写,感觉还挺有意思的 ...
随机推荐
- 第二阶段Sprint10
昨天:查看有关“共享平台”的资料,看如何实现上传下载功能,并尝试编码,没有成功 今天:集合三个人的代码,整合到一起,修复出现的Bug 遇到的问题:看Bug没有出现,但功能不是停止运行就是部分不能用,只 ...
- 《当大数据遇见网络:大数据与SDN》
总体结构: <当大数据遇见网络:大数据与SDN> 摘要 大数据和SDN无论是对于学术界还是工业界来说都极具吸引力.传统上人们都是分别在最前沿工作中研究这两个重要的领域.然而一方面,SDN的 ...
- Installing OpenSSH from the Settings UI on Windows Server 2019 or Windows 10 1809
Installing OpenSSH from the Settings UI on Windows Server 2019 or Windows 10 1809 OpenSSH client and ...
- thinkphp在app接口开发过程中的通讯安全认证
对于我们写好的接口,如果不经过安全认证就可以直接访问的话,则将对我们网站产生非常大的安全隐患,一些hack可能直接用你的接口去操作数据库,后果无法估量.那么如何才能进行有效的安全验证呢? 这里我采用了 ...
- postman 学习网址
postman使用详解: http://gold.xitu.io/entry/57597a62a341310061337885 https://www.getpostman.com/docs/writ ...
- java使用JMail通过QQ邮件服务器实现自动发送邮件
前言:项目开发的过程中,我们项目需要一个自动发送邮件提醒的小功能,于是简单的研究了一下java的JMail来实现自动发送邮件的功能.已被后期需要参考. 一.准备 实现的原理很简单:发送人 , 中转的邮 ...
- ssh中文乱码解决
在终端执行命令:export LC_ALL=zh_CN.GB2312;export LANG=zh_CN.GB2312是最有效的.=======================1.不管用那种ssh客户 ...
- 本地安装apk后直接打开,按下Home键再重新打开,然后按下返回键时页面展示错误的处理方法
情景: 1.下载apk到手机本地,点击本地apk开始安装 2.安装完成后,一般会有 “完成” 和 “打开” 两个按钮,点击 “完成” 按钮时是没有问题的,不管它 3.点击 “打开” 按钮,进入到首页( ...
- ef 更新数据库
//一:数据库不存在时重新创建数据库 Database.SetInitializer<testContext>(new CreateDatabaseIfNotExists<testC ...
- Berland and the Shortest Paths CodeForces - 1005F(最短路树)
最短路树就是用bfs走一遍就可以了 d[v] = d[u] + 1 表示v是u的前驱边 然后遍历每个结点 存下它的前驱边 再用dfs遍历每个结点 依次取每个结点的某个前驱边即可 #include &l ...