驱动注册和设备注册分析-1

1.驱动注册

  以i2c驱动注册为例分析驱动注册的代码,弄清楚两点东西
(1)都知道对应的驱动和设备匹配上了会跑它们总线bus_type 的match函数,但这是什么个逻辑呢?
(2)驱动和设备匹配上了跑驱动的probe()函数,传进去的形参是怎么来的?

分析前先了解一下内核里的一个链表数据结构
(1)struct klist; //链表,里面包括一个自旋锁,一个链表,两个设置链表节点的回调

(2)struct klist_node; //链表节点,里面包括一个链表用来连接前后节点; 一个void 变量用于指向struct klist,这个从后面代码可知; 而struct kref 结构体里面其实就是个原子量,充当标志位;

(3)struct klist_iter; //这个结构体是一个链表的包装,里面有个链表struct klist,以及一个链表节点指向当前链表节点;

下面开始分析代码,

--- module_i2c_driver(mt6370_pmu);  //带着i2c驱动实例去跑驱动注册函数


关注点,

(1)给i2c_driver里的device_driver 进行初始化,赋值了.owner 和 .bus,其中.bus就是device_driver里的bus_type,也即是i2c总线的bus_type,里面定义了设备与驱动的match函数,通过设备树来匹配的方法就写在这里;

(2)驱动注册,这也是要具体分析的点,这里记一下参数,是i2c_driver的device_driver;
(3)i2c_for_each_dev(driver, __process_new_driver); 和i2c_adapter的注册相关的

下面重点分析一下(2)driver_register(&driver->driver)、(3)i2c_for_each_dev(driver, __process_new_driver)

--- driver_register(&driver→driver);

(1)第一个if ,if (!drv->bus->p),是判断bus_type o不ok,我们看一下这个bus->p 是个什么
bus->p 就是 struct subsys_private 的变量,看到里面有一个设备的链表和驱动的链表,说明bus里面是有设备和驱动的链表的,猜想是不是设备和驱动注册的时候都会挂在这里,以及一个bus_type用来保存bus→p里的这个bus,那得到bus和 p任何一个都可以得到彼此了;
(2)ret = bus_add_driver(drv); 首先注意到前面很多的if,应该是为了排除一些错误的情况,就不想太多的看了,直接分析这个bus_add_driver 函数,函数的参数还是是i2c_driver的device_driver;

分析函数的前面部分,后面是驱动文件系统的创建就不想看了
(1)看到这里有个数据结构 struct driver_private *priv; 看名字是驱动的私有数据结构,那device_driver里面应该是有的,看看里面有什么


里面有个设备的链表和一个链表节点,这个链表节点的名字叫做knode_bus,看起来就是要挂在bus→p里的驱动链表上

(2)bus = bus_get(drv→bus); //获得bus_type
(3)priv = kzalloc(sizeof(*priv), GFP_KERNEL);
         ...
         priv->driver = drv;
         drv->p = priv;
         priv->kobj.kset = bus->p→drivers_kset;
分配空间,和device_driver 互相保存;
(4)klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);  这个函数就是把priv里的链表节点加到bus→p里去


(5)if (drv->bus->p->drivers_autoprobe) {
         ...
         error = driver_attach(drv);
if的前半部分什么异步probe,就直接看一下 driver_attach(drv); 这个关键函数吧,函数的参数还是是i2c_driver的device_driver;

--- driver_attach


跑bus_for_each_dev 函数,参数依次是bus_type,NULL,device_driver以及一个回调函数;

--- bus_for_each_dev

这个函数分析一下,
(1)struct klist_iter i;  定义了一个链表的包装,里面有个链表指针 *i_klist 和一个链表节点指针 *i_cur;
(2)klist_iter_init_node(&bus->p->klist_devices, &i,(start ? &start->p->knode_bus : NULL)); 这个函数是用来初始化klist_iter 的,也就是给它的*i_klist 和 *i_cur 赋值;
注意它的参数,第一个是bus→p里的设备链表 klist_devices,第二个就是要初始化的klist_iter *i,第三个是链表的开始节点,这里很明显是start = NULL,所以i→i_cur =NULL;


(3)while (!error && (dev = next_device(&i)))
              error = fn(dev, data);
while循环的第一个条件必然为true,主要看他第二个条件,第二个条件是用来得到dev的,这个dev会是传递到驱动probe里的吗,他又是哪里来的呢;

 

代码逻辑是从klist_iter里的设备链表去得到一个链表节点,然后通过这个设备节点去得到设备的私有数据,而设备的私有数据和驱动的私有数据是一样的,可以知其一而得到另外一个,这里主要还是得看看链表节点怎么得到的;

--- klist_next
前面这些就是定义了最近的节点last和下一个节点next,要是最近一个节点不为NULL,next就指向last的下一个节点,要是最近的节点为NULL,next就指向链表第一个节点然后进入while循环;
while循环遍历整个链表至链表头,直到找到对应的节点后退出循环同时用i→i_cur指向它;

这样我们就可以回到bus_for_each_dev 函数,next_device 函数就是得到了bus→p里面设备链表中合适的设备节点,我们看看得到了dev后做了什么

拿着得到的dev和data(也就是device_driver)跑了fn回调函数(就是前面的__driver_attach函数),那这个函数应该就是要绑定驱动和设备了,绑定就是要把设备dev作为驱动probe函数的参数然后跑probe;
这里看一下klist_iter_exit(&i);
对之前选中的设备节点执行设备链表的put函数,也就是删除这个设备的,因为它匹配了,当然可能不是物理删除,只是改了标志位让他不再参与匹配;

---__driver_attach


(1)ret = driver_match_device(drv, dev); 这个就是跑对应总线的bus_type里的match函数;

(2)然后根据(1)的匹配返回值来执行“重新匹配”(返回-EPROBE_DEFER)、匹配失败(小于0)、匹配成功(大于0)的操作;
(3)if (!dev->p->dead && !dev→driver)
                    driver_probe_device(drv, dev);

匹配成功后就跑driver_probe_device(drv, dev); 函数,条件是device 里的device_driver为空;

----driver_probe_device 参数是device_driver以及找到的dev

这里主要看一下really_repo 函数,参数是device_driver以及找到的dev

----really_probe
这个函数很长,截取关键的部分,可以看到对应总线的bus_type 里有probe函数就会跑总线里的,没有就跑驱动的probe的;

要是一般的platform设备驱动到这里就好了,因为一般platform驱动的probe如下,


传个dev就o了;

但是我们看看i2c设备的probe函数,

这很显然是跑了i2c总线bus_type里的probe导致的,猜测i2c总线bus_type里的probe 里会去调驱动的probe,分析一下i2c_bus_type

 

看看i2c_device_probe 函数

---- i2c_device_probe 参数是找到合适的设备链表里的dev


这里都是用contain_of,通过dev得到i2c_client,通过dev→driver得到i2c_driver;

代码比较多,挑关键的看一下


看到会调用驱动的probe 函数,第一个参数是i2c_client,第二个参数是i2c驱动具体匹配的设备id,可以看一下这个函数

 从这个驱动的匹配表(一个数组)里去根据名字来找到对应的匹配项,然后返回;

至此,第一部分驱动注册分析结束;

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值