在看Linux网络PHY设备驱动的时候一直有个问题萦绕心头,久久挥之不去,辗转反侧,难以入眠,不是因为看了不
懂,而是因为大体的流程都不明白,主要体现在以下几点:
  1、在注册PHY设备时,驱动所需要的总线是什么时候准备好的?
  2、总线、设备、驱动,这三者之间的相互联系关系到底是个什么关系,具体数据结构如何实现的?
  
要回答这两个问题,需要花点时间耐心的往下看,对于第一个问题:
  系统总线的注册也是代码完成的,所以问题是这段代码何时被调用的,总而言之,不论何时,肯定是在这里PHY驱
动注册之前应该完成,否则,驱动的注册就不能成功返回。
对于问题二:
  这是个驱动模型问题,所谓的驱动模型,就是驱动和设备怎样能更好的管理的问题,要知道设备很多,
usb、pci、isa、串口、声卡、显卡等等,对应的设备就有驱动,所以这时极有可能形成一个大杂烩,这个大杂烩就
是将所有的设备使用一个链表链接起来,所有的驱动的链接起来,有新设备了,就扫描驱动链表,有新驱动注册了,
那么就扫描设备这个链表,看看其可以为哪个设备服务。上面就是一种方法,那么还有一种方法,就是将设备分类,
这里的分类不是将设备分成字符设备、块设备、网络设备。而是按总线分类,usb总线对应就有usb鼠标、键盘、u
盘等;PCI总线对应于PCI网卡等;重点是这里的是开始讲述的PHY设备,PHY设备对应的总线在内核中称为mdio,
这是IEEE的标准定义的一种总线,内核对应的数据结构是mdio_bus。不同总线下的设备和驱动是没有交集的,各自生
活在各自的世界里,永世不会相见。内核就是按这里的第二种模型组织的,具体方法,参考我转载的文章。

第一个问题的释惑:
   可以这么说PHY的搞懂了,其它的大同小异;总线的代码是在系统启动时被执行的,换句话说就是在我们还没有登
录电脑时就完成了,如果使用的是命令行界面,那么就是在我们还没有获得shell的控制权就已经执行了总线初始化
的相关代码了。
系统启动过程是这样的,系统上电,运行0xFFF0处的第一条指令,这里是BIOS程序,也即运行Bios,bios自检完毕
---LILO/Grub(读入内核映像文件vmlinuz)---bootsec.S/setup.S(arch/X86/boot/)---
head.S(arch/X86/boot/compressed/解压内核)---main.c(init)---start_kernel---
kernel_init(Linux3.10)----do_basic_setup---创建以下三个线程,其中ideal为自身,init会执行/sbin/init启
动shell进程。kthreadd是内核守护进程,该进程是swapd等进程的始祖。
init
kthreadd
ideal
</pre><pre name="code" class="html" style="font-family: 宋体, Arial;">我们的故事是do_basic_setup这个不起眼的函数,名字没有main响亮,也没有启动shell将控制权移交用户空间或是内核守护进程进程这么高大尚,但是作用不可小觑,因为事关PHY总线注册的代码就在这里运行的;那段代码的函数是:<drivers/net/phy/phy_device.c>
1129 static int __init phy_init(void)
1130 {
1131     int rc;
1132 
1133     rc = mdio_bus_init();
1134     if (rc)
1135         return rc;
1136 
1137     rc = phy_driver_register(&genphy_driver);
1138     if (rc)
1139         mdio_bus_exit();
1140 
1141     return rc;
1142 }

为啥会是这个函数呢,__init应该知道,就是该函数只执行一次,并且是在系统init时执行的。
 
 
1150 subsys_initcall(phy_init);
1150的这一行的作用可不小了,

 
 这行的作用非比寻常,这一行就决定了内核在的do_basic_setup会执行该函数,该函数就是mdio总线的注册,注册完 
了之后又在其上注册一个通用的PHY驱动。
<init.h>
#define pure_initcall(fn)		__define_initcall(fn, 0)

#define core_initcall(fn)		__define_initcall(fn, 1)
#define core_initcall_sync(fn)		__define_initcall(fn, 1s)
#define postcore_initcall(fn)		__define_initcall(fn, 2)
#define postcore_initcall_sync(fn)	__define_initcall(fn, 2s)
#define arch_initcall(fn)		__define_initcall(fn, 3)
#define arch_initcall_sync(fn)		__define_initcall(fn, 3s)
#define subsys_initcall(fn)		__define_initcall(fn, 4)
#define subsys_initcall_sync(fn)	__define_initcall(fn, 4s)
#define fs_initcall(fn)			__define_initcall(fn, 5)
#define fs_initcall_sync(fn)		__define_initcall(fn, 5s)
#define rootfs_initcall(fn)		__define_initcall(fn, rootfs)
#define device_initcall(fn)		__define_initcall(fn, 6)
#define device_initcall_sync(fn)	__define_initcall(fn, 6s)
#define late_initcall(fn)		__define_initcall(fn, 7)
#define late_initcall_sync(fn)		__define_initcall(fn, 7s)

在其中
subsys_initcall这个函数的定义
#define __define_initcall(level,fn) \
	static initcall_t __initcall_##fn __used \
	__attribute__((__section__(".initcall" level ".init"))) = fn
</pre><pre name="code" class="html" style="color: rgb(86, 86, 86); line-height: 10.909090995788574px;">它的定义如下,这涉及到了链接部分了,说白了就是会将该函数声明的对象,放在.init段,所有的上述一直到7S的<span style="font-family: 宋体, Arial;">函数都放在这个段,后面的数字是优先级,do_basic_setup将根据优先级执行相应的函数。至此,PHY总线怎么来的</span><span style="font-family: 宋体, Arial;">过程总算是明白了。</span>
 
  但是对于细节具体怎么实现的,还是需要阅读源代码的,源代码分成两个方面,第一个方面是实现具体同能代码如mdio总线、通用PHY驱动,另外一个方面就是设备模型管理代码了,自我感觉初学的话比较难,记得当时看LDD这本书时,觉得是在看天书,面转载的文章有助于更好的理解,对于初学者,也不急于彻彻底底的弄懂,后面遇到了再看
收获更大,然人真有,幡然醒悟的喜悦!
 
下为本文转载,因为写的比较好,图文并茂,所以就不花时间重新写了,直接转载了。


设备驱动基础0:设备模型之kobject,kset及其关系

Linux2.6以后的设备驱动,都是在设备模型的基础上构建的,因此,要编写linux下的设备驱动程序,不论是usb设备,pci设备等,都需要了解设备模型。

设备模型的基础结构体主要是kobject,kset这两个结构体:

struct kobject {

   char      * k_name;

   char      name[KOBJ_NAME_LEN];

   struct kref    kref;

   struct list_head  entry;

   struct kobject    * parent;

   struct kset    * kset;

   struct kobj_type  * ktype;

   struct dentry     * dentry;

};

 

struct kset {

   struct subsystem  * subsys;

   struct kobj_type  * ktype;

   struct list_head  list;

   struct kobject    kobj;

   struct kset_hotplug_ops  * hotplug_ops;

};

 

还有一个subsys结构体,但subsys结构体跟kset差不多,就多了一个互斥访问信号量,因此,就不需要列出了,另外还有一个结构体

struct kobj_type {

   void (*release)(struct kobject *);

   struct sysfs_ops  * sysfs_ops;

   struct attribute  ** default_attrs;

 };

用来表示kobject,kset的类型。 

一个kobject结构如下图的kobject 类型部分,而一个kset结构如下图的kset 类型部分,一个kobject加入一个kset,主要是kobject结构体中的相关字段记录了对应的kset信息,①记录了kobject所对应 kset,其所指向的是kset所包含的kobject的地址,②记录了kobject所对应的kset的kset指针,③记录了kobject的类 型,④记录了kset所有的kobject的链子,这个链子是一个双向链表,每当有一个kobject加入到当前的kset,就会调用 list_add_tail()函数,把要加入kset的kobject连入链表的结尾,最终形成一个链表。

当有另外一个kobject要加入当前的kset,其中的①②③步跟第一个加入当前kset的kobject是一样的,即把要加入 的kobject的成员设置,使之指向当前的kset对应数据,而④需要把kobject添加到kset的list的尾部,下图表示了kobject b加入到kset A的图示:

当有一个kset,需要加入到当前的kset,其方法也跟一个kobject要加入到当前kset一样,即把要加入的kset中所 包含的kobject的成员设置,使这些成员指向对应的kset的对应数据。而当前kset要加入另一个kset,其方式也是跟一个kset加入到当前 kset一样,都是设备kset中的kobject,使kobject的成员指向要加入的kset的对应数据即可,下图显示了一个kset B加入到kset A中的图示。

一个简单的kset,kobject关系图如下:



设备驱动基础1:设备模型之总线,驱动,设备

Kobject,kset 是设备模型的基本结构体,设备模型使用这两个结构体来完成设备的层次关系,但在实际的设备驱动编写中,我们基本上用不到kobject,kset这些结构 体,是因为这些结构体又被嵌入到更大的结构体中,原因在于kobject,kset结构体只能表征设备的层次关系,但是一个设备的驱动,并不是简单的一个 层次关系而已,因此,必需要把kobject,kset结构体嵌入到更大的结构体中,使用kobject,kset来表征层次关系,用其他的成员表示设备 驱动的具体功能。

在设备模型中,我们将看到,设备驱动主要是由总线,驱动程序,设备三个部分构成,通过这三个标准部件,把各种纷繁杂乱的设备归结过来,达到简化设备驱动编写的目的,也即我们编写的设备驱动,其实也只是这三部分中的一个很小的部分的。

 

我们编写的设备驱动程序,一定是先属于一个总线的驱动,比如属于 USB总线,或者属于PCI总线,或者属于I2C总线,等等,因为我们编写的设备驱动,在注册,安装到系统时,系统会先检查驱动是属于哪个总线的(设备驱 动编写时已经定义好),会把驱动加入到对应的总线的kset中,即把当前设备驱动的kobject加入到对应总线的kset中,形成层次关联。而当系统检 测到有设备存在(硬件),也会先判断设备是属于哪个总线的(硬件连接),然后遍历当前总线下的所有设备驱动程序,通过所属总线的探测函数,查找是否有设备 驱动程序匹配可以驱动当前的设备(一般是通过获得设备的PID,VID,跟驱动程序的PID,VID比较,看是否匹配而定),如果有驱动程序可以驱动设 备,则把当前设备也加入到所属总线的kset中,如果没有可驱动设备的驱动程序,则只能在总线的设备链表中存在,而如果设备都无法通过总线的匹配,则也没 有办法存在于总线的设备链表中。由于一条总线要管理总线上的所有驱动,同时要管理总线上的有所设备,则需要再把所有设备和所有驱动都分开,分别设立一个设 备kset和一个设备驱动kset,用于管理所有的设备和设备驱动,如此,则总线kset实际上包含了两个kset(设备kset,设备驱动kset), 设备kset又包含了所有的当前总线的设备的kobject,设备驱动kset包含了所有的当前总线的设备驱动的kobject;而所有的总线,又形成了 bus的kset,归结起来就形成下图的层次关系:

每个设备,都被挂接到不同的总线上,当设备挂接到对应的总线上 后,其所对应的总线类型就确定了,而设备在挂接到总线上时,总线先要扫描设备,看看设备是否适合总线的要求,如果适合了,那接着就要扫描整个总线上的设备 驱动链表,查找是否有驱动程序可以管理设备,如果找到,则把设备结构体中的相应指针成员指向对应的驱动程序,如果暂时没有找到对应的设备驱动程序,则设备 结构体中的指向驱动程序的指针暂时为空,表示还没有设备驱动,还在总线的设备队列中等待;而如果设备不能通过总线的检查,即不会出现在总线的设备列表上, 自然不会去扫描设备驱动链表,查找匹配的驱动了。

而每个设备驱动程序,都是被安装到对应的总线上的,不论是手动安 装,还是自动安装,所谓安装,就是把驱动程序挂载到对应总线的驱动链表中,而挂载到对应的总线驱动链表,首先要满足总线的匹配要求,只有适合了要求,才能 挂载到总线的驱动链表,也只有到达这个步骤,系统才会扫描整个总线的设备链表,来查找是否有设备需要此驱动来管理,如果找到这个设备,则驱动程序中的设备 管理链表,会记录这个设备的地址,从而达到管理设备的目的。

经过上述的设备插入,或者驱动安装,系统就会出现只有设备,而没 有设备驱动程序的情况,也会出现,只有设备驱动程序,没有对应的设备的情况,此时,设备或者设备驱动程序,就会暂时在各自的队列里等待,一旦有驱动程序安 装,或新的设备插入,就都会自动的去扫描对应的链表,来检测是否有配对的可能。

综合上述三者的关系,如图:

 

Linux设备模型 之 总线类型 - bus_typebus_type

相关数据结构:

struct bus_type {
 char   * name;

 struct subsystem subsys;
 struct kset  drivers;
 struct kset  devices;

 struct bus_attribute * bus_attrs;
 struct device_attribute * dev_attrs;
 struct driver_attribute * drv_attrs;

 int  (*match)(struct device * dev, struct device_driver * drv);
 int  (*hotplug) (struct device *dev, char **envp,
        int num_envp, char *buffer, int buffer_size);
 int  (*suspend)(struct device * dev, pm_message_t state);
 int  (*resume)(struct device * dev);
};


内核所支持的每一种总线类型都由一个bus_type对象表示。
bus_type中内嵌了一个subsystem - subsys。
系统中的bus_subsys子系统将所有的bus_type中的subsys集合在一起。
bus_subsys对应sysfs中的/sys/bus目录.

另外,bus_type中有两个内嵌的kset对象:devices 和 drivers。分别表示该bus上的设备和驱动。

                                                          
                            
                                                           
                                                           
                                                           
  /------------------------>       bus_type       <-------------------------\
  |                         +--------------------+                          |
  |                         |                    |                          |
  |                         |    name            |                          |
  |                         +--------------------+                          |
  |                         |            kset    |                          |
  |                         |         +--------+ |                          |
  |                         |         | subsys | |                          |
  |                         | drivers +--------+ |                          |
  |                         |         | kobj   | |                          |
  |                         |         +--------+ |                          |
  |                         |         | list   | |                          |
  |                         |         +--------+ |                          |
  |                         |         |        | |                          |
  |                         +--------------------+                          |
  |                         |            kset    |                          |
  |                         |         +--------+ |                          |
  |                         |         | subsys | |                          |
  |                         | devices +--------+ |                          |
  |                         |         | kobj   | |                          |
  |                         |         +--------+ |                          |
  |  /------------------------------->| list   |<----------------------\    |
  |  |                      |         +--------+ |                     |    |
  |  |                      |         |        | |                     |    |
  |  |                      +--------------------+                     |    |
  |  |                      |                    |                     |    |
  |  |                      |   subsys           |                     |    |
  |  |                      |                    |                     |    |
  |  |                      +--------------------+                     |    |
  |  |                      |                    |                     |    |
  |  |                      |                    |                     |    |
  |  |                      |                    |                     |    |
  |  |                                                                 |    |
  |  |                                                                 |    |
  |  |       device                                      device        |    |
  |  |   +-------------+                             +-------------+   |    |
  |  |   |    node     |                             |    node     |   |    |
  |  |   +-------------+                             +-------------+   |    |
  |  \-->|  bus_list   |<-------  ......  ---------->|  bus_list   |<--/    |
  |      +-------------+                             +-------------+        |
  |      |  driver_list|                             |  driver_list|        |
  |      +-------------+                             +-------------+        |
  |      |  children   |                             |  children   |        |
  |      +-------------+                             +-------------+        |
  |      |   parent    |                             |   parent    |        |
  |      +-------------+                             +-------------+        |
  |      |   kobj      |                             |   kobj      |        |
  |      +-------------+                             +-------------+        |
  \------|   bus       |                             |   bus       |--------/
         +-------------+                             +-------------+   
         |   driver    |                             |   driver    |   
         +-------------+                             +-------------+   
         |             |                             |             |   
                                                                       

 

 

 

 


                                                                             
                                                                             
                                                                             
                                                                             
                                                                             
   /------------------------>       bus_type       <-------------------------\
   |                         +--------------------+                          |
   |                         |                    |                          |
   |                         |    name            |                          |
   |                         +--------------------+                          |
   |                         |            kset    |                          |
   |                         |         +--------+ |                          |
   |                         |         | subsys | |                          |
   |                         | drivers +--------+ |                          |
   |                         |         | kobj   | |                          |
   |                         |         +--------+ |                          |
   |  /------------------------------->| list   |<----------------------\    |
   |  |                      |         +--------+ |                     |    |
   |  |                      |         |        | |                     |    |
   |  |                      +--------------------+                     |    |
   |  |                      |            kset    |                     |    |
   |  |                      |         +--------+ |                     |    |
   |  |                      |         | subsys | |                     |    |
   |  |                      | devices +--------+ |                     |    |
   |  |                      |         | kobj   | |                     |    |
   |  |                      |         +--------+ |                     |    |
   |  |                      |         | list   | |                     |    |
   |  |                      |         +--------+ |                     |    |
   |  |                      |         |        | |                     |    |
   |  |                      +--------------------+                     |    |
   |  |                      |                    |                     |    |
   |  |                      |   subsys           |                     |    |
   |  |                      |                    |                     |    |
   |  |                      +--------------------+                     |    |
   |  |                      |                    |                     |    |
   |  |                      |                    |                     |    |
   |  |                      |                    |                     |    |
   |  |                                                                 |    |
   |  |                                                                 |    |
   |  |                                                                 |    |
   |  |                                                                 |    |
   |  |          driver                               driver            |    |
   |  |    +------------------+                 +------------------+    |    |
   |  |    |                  |                 |                  |    |    |
   |  |    |    name          |                 |    name          |    |    |
   |  |    |                  |                 |                  |    |    |
   |  |    +------------------+                 +------------------+    |    |
   |  |    |          kset    |                 |          kset    |    |    |
   |  |    |       +--------+ |                 |       +--------+ |    |    |
   |  |    |       | parent | |                 |       | parent | |    |    |
   |  |    | kobj  +--------+ |                 | kobj  +--------+ |    |    |
   |  |    |       | kset   | |                 |       | kset   | |    |    |
   |  |    |       +--------+ |                 |       +--------+ |    |    |
   |  \----------->| entry  |<------------------------->| entry  |<-----/    |
   |       |       +--------+ |                 |       +--------+ |         |
   |       |       |        | |                 |       |        | |         |
   |       +------------------+                 +------------------+         |
   |       |                  |                 |                  |         |
   \-------|    bus           |                 |    bus           |---------/
           |                  |                 |                  |  
           +------------------+                 +------------------+  
           |                  |                 |                  |  
           |                  |                 |                  |  
           |                  |                 |                  |  
                                                                      
                          
     
函数bus_for_each_dev() 和 bus_for_each_drv()分别用于遍历bus上devices和drivers链表中的所有元素。

Logo

更多推荐