Chinaunix首页 | 论坛 | 博客
  • 博客访问: 47915
  • 博文数量: 18
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-07 14:00
文章分类
文章存档

2013年(18)

我的朋友

分类: LINUX

2013-05-08 14:50:09

原文地址:i2c驱动 作者:阿尔发828

i2c驱动第一步-加载
我们来讲述i2c驱动工作的第一步...加载.

i2c驱动的加载有两种情况:

对于编译到内核镜像里的驱动,驱动的加载是在内核运行,也就是开机时发生的.

对于以模块方式存在的驱动,驱动的加载是在insmod时发生的.

但无论如何,其过程都是一样的.即,运行static int __init i2c_dev_init(void)函数,此函数存在于//i2c-dev.c

请大家点击这个链接i2c_dev_init,开两个窗口一起阅读,互相印证.

有用语句一:res = register_chrdev(, "i2c", &i2cdev_fops);

这个函数向内核注册了一个主设备号是I2C_MAJOR=89的字符型设备.其操作对应的file_operations结构为:i2cdev_ops.i2cdev_ops 存在于i2c-dev.c 这个驱动块.

注册这个字符型设备,就将主设备号为89的设备文件的所有操作指向了i2cdev_ops,对这个设备文件的所有操作,均由这些函数来执行.

这上步如下图:

i2c设备驱动


这个初始化函数中还有另外两个有用函数:

i2c_dev_class = (THIS_MODULE, "i2c-dev");

此函数生成一个类,用于向sysfs中注册,这里不作详述.

另一个函数是:

res = (&i2cdev_driver);
这里向内核注册了i2cdev_driver,一个结构体.i2c_driver我还没搞懂,这里就先不说了.
i2c驱动第二步-打开

 当一个驱动被注册后,我们就可以通过创建设备节点,对设备节点进操作来操作设备.

操作一个设备节点的第一步就是打开设备文件.由第一步中可以,此时调用open函数,实则是调用i2cdev_fops中的i2cdev_fops大家可以打开这个函数对应着看.

第一个有用的语句是:i2c_dev = i2c_dev_get_by_minor(minor);
这个语句通过设备节点所对应的次设备号,去轮询i2c_dev_list,这是一个i2c_dev的链表,这个链表中每个i2c_dev 结构的adap成员对应一个次设备号,也就对应一个.上面所用到的函数就是通过对比次设备号,来判断并取得对应i2c从设备的i2c_dev.然后通这个结构是否为空来判断对应节点是否对应真实的设备.
第二个有用的语句是:adap = (i2c_dev->adap->nr);
通过这个函数取得要操作的设备所在的适配器结构.
实际上这个open函数的主要作用除了判断设备是否真实存在之外,还要为设备生成一个i2c_client结构.下面部分就是生成了这样一个结构,并且把这个结构的一此信息进行添充.
如图:
i2c设备驱打开文件

i2c驱动第三步-写入
从前两步,我们很容易体会到,drivers/i2c/i2c-dev.c这个文件中的模块是与上层的VFS打交道,但一个驱动显然不能只与上层打交道,与上层怎么做呢?我们还要再看下去.

第三步动作不一定是写入,但当成是写入我也无碍,我们只是想看看这个驱动到底是怎么工作的,实际上写入与读出大体上也差不了多少.

显然,执行上层VFS传来的写入操作是drivers/i2c/i2c-dev.c这个文件中i2cdev_ops中的i2cdev_write函数,而当我们来看这个函数的时候,我们发现,显然它什么也没做,只不过像我们自己写字符驱动时一样,从形参的file->中找到代表这个设备的i2c_dev结构,并把用户空间传入的数据做了备分,就把问题全部推给了另一个函数.

这个倒霉的函数名字叫做.现在让我们来围观一下,这个倒霉家伙是如何辛苦劳动的。

如何所见,它似乎也很坏,只是从中找到这个设备的适配器,并把要传的信息整理一下,就又把事情传给了另一个更加倒霉的孩子。但是让我们围观那个倒霉的孩子之间,先看看现在我们的结构:

i2c驱动i2c_msg

i2c驱动第三步-写入续

接上一篇

本系列的第一篇是:

如我们所料,这个世界上,很多时候,一些道理是相通,我们现在看的倒霉家伙仍然不是最最倒霉的那个的,经过简单的一些辅助性处理,它又把问题推给了:

adap->algo->也就是我们现在的结构中i2c_client中的i2c_adapter成员中的algo成员中的.我们当初在第二步:
中建立的i2c_client结构,当时添充其i2c_adapter成员时是通过(i2c_dev->adap->nr);来得到的。也是就说,我们根据次设备号,找到i2c_dev然后再通过它的成员的成员找到这个adapter结构。但至今为止我们还不知道这个i2c_adapter结构是发生的呢。好,我们来找找,
其实有一段话,我该写在这个系统的前面,但是忘记了没有写,现在写在这里,那就是:
linux系统的i2c驱动只有非常少的代码,都放在//目录下,我们发现这个目录下面只有三个文件夹,和三个.c文件,而我们来看编译后的代码树里,真正生成了.o文件的只有5个文件。/  / i2c-dev.c  共 5个,通过我们前的讨论看来,i2c-dev.c这个文件是一个驱动中与VFS打交道的模块。i2c-core.c则是一个中间层,提供上层,底层中间的 隔离,另外三个文件我们还没有看,但显然i2c-s3c2410.c更像是与底层硬件相关的。而i2c-algo-bit.c是讨论算法的。i2c- boardinfo.c大家可以看,只有一个函数。所以我们可以三个文件都看看,找找那个 i2c_adapter添加的代码在哪里。
而实际上,我们可以上网搜一下。
最终发现添加i2c_adapter的函数有两个,而我们显然要用i2c-s3c2410.c中用了的那一个。
这两个为:()和()而根据这个文件里一段话说,前一个函数是总线号固定的时候用的,后一个则是动态的,显然s3c2410上总线号是固定的,所以那里用的是前者。到这里不得不看一下这个文件里都写了些什么,只看了下框架,发现这里是一个平台驱动的注册模块,最终向系统注册的是 ,而上面提到的那个函数则是在s3c2410_i2c_driver中的probe函数:s3c24xx_i2c_probe中被调用的。也就是说,这个i2c_client中的adapter是要在 注册时才能加进去的。这样,我们又不得不先看一下,这个模块初始化时做了些什么,因为初妈化是在probe函数之前工作的。还好这个初始化代码十分简单。就是注册了一下,这样的话,我们就可以直接来看probe函数了:
这个比较长,另开一篇。
阅读(873) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~