写陀螺仪smi130的驱动,以及hardware 层的接口之驱动(一)

来源:互联网 发布:开发java程序的一般步骤 编辑:程序博客网 时间:2024/05/01 04:24

       哎!这个过程真的真的是转了好几圈。为了给像我这样初写驱动的人关于驱动的许多的疑问进行详细解答(详解到调用probe前),也因为学习的最好方式是  学习新东西------>用语言总结出来(除了能锻炼自己的表达能力外,更能让自己记忆深刻,还能理清思路,也能以免自己忘记的时候可以参考,好处多多,但是有一点不好,就是   麻-----烦。不过学习的最高效的方法就是这个,就算麻烦也得做)。以及hardware层代码的编写。

       环境: imx6 平台。kernel-3.0。

      当然一下内容很多都是个人的理解,如有不妥之处,还望指出,不要让我在错误的道路上越走越远,而你也成为罪人。好!下面进入正题。

      我觉得要写驱动之前需要搞懂如何几个问题:

            1、驱动是拿来做什么的啊,为什么我们需要驱动?

            2、驱动的模型是什么?(是个大头)


一、驱动是拿来做什么的啊,为什么我们需要驱动?

      答:驱动(名词,代表我们写的驱动代码)是 拿来驱动(动词)硬件的,说得更直白一点就是向下获取硬件的数据,向上为上层的应用程序提供数据(这也是我们为什么要驱动的原因)。那我们的驱动是怎么向下获取数据的呢?又是怎么向上汇报数据的呢?在应用层我们又是通过什么来获取驱动获得的数据的呢? 这等等的问题,这一堆的问题,就需要我们提到驱动的模型了。且看下文分解。(怎么感觉自己身上有股八股气,哈哈!)。

二、驱动的模型是什么?

     | ------------------|        驱动             |--------------------|

     |驱动(程序) |       ------------->   |   设备(硬件)|

     |-------------------|                            |---------------------|


       自己弄的模型,虽然丑了点大笑,意思应该表达清楚了。还是解释解释,左边是我们写的驱动程序,右边是我们的具体的、实实在在的硬件设备。那么有如下几点疑问:

       1、注册什么驱动,是i2c驱动、还是spi、platform驱动。怎么注册驱动?

       2、注册设备,怎么注册设备?

       3、驱动是怎么识别设备的?

       4、识别驱动过后又发生了什么事情?

       5、怎么在很多的驱动代码中没有看到i2c_new_device 或者i2c_register_board_info 注册设备而网上却有很多?

      以下一 一解答:

      (1)、注册什么驱动,是i2c驱动、还是spi、platform驱动。怎么注册驱动?

         答:注册什么驱动, 首先你应该确定你的设备是挂在哪里的。我最近在写陀螺仪smi130的驱动,那就以它为例,方便!我的车载机子总共有4个i2c总线,设备smi130 就挂载i2c总线上第三根总线上,即I2C2(可能你会问,我怎么知道它挂在哪个总线上的那根线上?第一种方式就是你被告知,第二种方式就是看硬件电路图)。所以注册i2c驱动。

               那我们怎么注册i2c驱动呢?其实linux 早就为我们提供好了接口函数, 就在 kernel/include/linux/i2c.h(可能有人会问我怎么在这个目录下呢?哎!看多了就知道了,  还有就是有一点需要记好,*.h的文件基本上都是提供接口的文件,这里也为大家推荐一款软件source insight ,你值得拥有)我们就可以从源码i2c.h中这个文件寻找注册i2c驱动相关的接口函数,找到了 i2c_add_driver(driver)  、i2c_del_driver、i2c_register_driver 。其中i2c_add_driver是通过i2c_register_driver 来操作的。 所以就用i2c_add_driveri2c_del_driver 这组函数来注册、注销i2c驱动那么,我们通过这两个函数怎么来注册呢?那就需要看函数需要的参数。需要的参数为struct i2c_driver 这种类型 。那你需要声明一个这样的变量并且填充这个函数像下面这样

struct i2c_driver   mydriver = {       .probe = myprobe,       .remove= myremove,       .driver{                   .name = mydri,                   .owner = THIS_MODULE       },       .id_table = & my_table,};

其中参数probe ,是当驱动和设备匹配成功时会调用,remove 是移除驱动的时候会调用,driver.name 是驱动的名字,owner是表明是这个模块。id_table 是你这个驱动可以驱动的设备,然后再通过
i2c_add_driver(&mydriver);  // 像i2c总线添加驱动

          那到这里怎么注册驱动就到此结束。

       (2)、注册设备,怎么注册设备?

             答:在i2c.h头文件中呢也已经给我们提供好了接口,可以看到有两个。第一个,extern struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);第二个,extern int

 i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);那我们怎么知道用哪一个呢?一般去选择参数看起来一看就知道、就明白的函数。所以这里我在这里选择的是第二个函数i2c_register_board_info,它的三个参数busnum(就是你的设备挂在哪根总线上)、info( struct i2c_board_info  这种参数类型,在i2c.h中有定义, 其中最主要的就是type(就是我们所说的name,这个也有点蛋疼,name就name 还来个type ,弄得有点不好理解,这里要注意type 要和驱动前面id_table中的name相同,这也就让我们清楚了驱动和设备之间是怎么联系起来的了) 和addr,这样你取的设备的名字也就和地址联系起来了,也可理解成名字和设备联系起来了。)、n(你需要注册几个info,我这里填的1。), 当我填充好这个函数编译的时候说没有找到这个函数i2c_register_board_info,不管怎么添加头文件都找不到这个函数。

             最后只有用i2c_new_device(说也奇怪,大家都在一个文件i2c.h申明,凭什么i2c_register_board_info就不能用,很是奇怪,这个问题姑且放在这里,没有进行深究。)看i2c_new_device需要两个参数,一个adap,一个info。第一个参数adap,可是我怎么获得这个适配器呢?找了半天终于在头文件i2c.h(竟然还是这个头文件中找到了函数)找到了extern struct i2c_adapter *i2c_get_adapter(int nr);  其中nr就是我们设备挂的哪根总线。这里我是挂在i2c2上的,所以填2(这里有一点需要注意就是nr是从0开始算的。),这样就可以获得适配器了,操作方法如下:

struct i2c_adapter *adap = i2c_get_adapter(2);i2c_new_device(adap, &info);

这样我们的设备也就注册好了。

        (3)、驱动是怎么识别设备的?

            答:第二点中有提到,就不重复了。这里说另一个问题,我们到底是先注册驱动还是设备呢?答案是随便,都可以。因为如若你先注册i2c驱动,i2c驱动就会在i2c设备中去找有没有可疑匹配的设备;如若你先注册设备,则设备会在i2c驱动中取找有没有能和自己匹配的驱动。所以没有先后,都可以。

         (4)、识别驱动过后又发生了什么事情?

           答:驱动和设备匹配过后就会调用probe 函数。在probe函数中会去注册杂项类设备或者字符设备或者使用sysfs_create_group();然后去绑定具体的操作,操作在去和硬件打交道,读数据、写数据。(这里就不在详述了,网上一大把的资料)

          (5)、怎么在很多的驱动代码中没有看到i2c_new_device 或者i2c_register_board_info 注册设备而网上却有很多?

            答:这是因为它们是在设备树里注册的设备。没有用过这种方式,但是我们一定要知道这个概念,如若你的代码是需要在设备树里注册设备的话,那你只能搜一下linux设备树详解了。


          后面写得越来越粗略。因为后面的内容实在是网上的太多了。如若看到网上probe之后不懂得,可以告知,我们讨论讨论。




原创粉丝点击