kernel_init中do_basic_setup()->driver_init()->platform_bus_init()->...初始化platform bus(虚拟总线)
设备向内核注册的时候platform_device_register()->platform_device_add()->..
.内核把设备挂在虚拟的platform bus下
只是device的parent指针指向bus的device
驱动注册的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev()
对
每个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()->比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),
如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动.
驱动与设备绑定中涉及的一些概念
驱动绑定
驱动绑定就是将一个设备与能够控制它的驱动关联的过程。这一过程一般是由
总线驱动处理的,因为总线驱动都会有一组能够表征设备和设备驱动的与特定
总线相关的数据结构。通过嵌入通用的设备和驱动结构,大多数绑定都能够在
公共代码发生。
总线驱动处理的,因为总线驱动都会有一组能够表征设备和设备驱动的与特定
总线相关的数据结构。通过嵌入通用的设备和驱动结构,大多数绑定都能够在
公共代码发生。
译者见解:
这里的公共代码是指LDM核心的代码段。在内核的LDM层,公共总线结构中有两
个链表成员,分别将该总线上的设备和驱动链接在一起。公共驱动结构里也有
一个链表成员,用于将该驱动能够控制的已发现的设备链接在一起。在没有任
何绑定前,两个链表中的设备和驱动(结构)是互不关联的,绑定后,所谓的关
联可以直接理解为设备结构也被链接到一个能够控制它的驱动结构里面的链表
成员中。
个链表成员,分别将该总线上的设备和驱动链接在一起。公共驱动结构里也有
一个链表成员,用于将该驱动能够控制的已发现的设备链接在一起。在没有任
何绑定前,两个链表中的设备和驱动(结构)是互不关联的,绑定后,所谓的关
联可以直接理解为设备结构也被链接到一个能够控制它的驱动结构里面的链表
成员中。
总线
总线结构包含一个链表成员(注:设备链表成员),该成员将系统中属于该类总
线的所有设备链接在一起。当为一个设备调用device_register函数时,该设备
会被链接到设备链表成员的末端。同样,总线结构也包含一个驱动链表成员,
该成员将系统中属于该总线的所有驱动链接在一起。当为一个驱动调用
driver_register函数时,该驱动结构将会被链接到驱动链表成员的末端。上述
就是能够触发驱动绑定的两个事件。
线的所有设备链接在一起。当为一个设备调用device_register函数时,该设备
会被链接到设备链表成员的末端。同样,总线结构也包含一个驱动链表成员,
该成员将系统中属于该总线的所有驱动链接在一起。当为一个驱动调用
driver_register函数时,该驱动结构将会被链接到驱动链表成员的末端。上述
就是能够触发驱动绑定的两个事件。
设备注册
当一个设备被加入时,总线的驱动链表成员将会被遍历,以寻找能够支持该设备
的驱动。为了判定一个设备能否被驱动,设备ID必须与该驱动支持的ID列表中的
任意一个ID相匹配。ID的格式和比较的语义是与特定总线相关的。为了避免实现
一个复杂的状态机和比较逻辑,(LDM核心)为总线驱动提供了一个比较设备ID与
驱动ID的回调接口,如果比配总线向(LDM核心)返回1,否则返回0。
的驱动。为了判定一个设备能否被驱动,设备ID必须与该驱动支持的ID列表中的
任意一个ID相匹配。ID的格式和比较的语义是与特定总线相关的。为了避免实现
一个复杂的状态机和比较逻辑,(LDM核心)为总线驱动提供了一个比较设备ID与
驱动ID的回调接口,如果比配总线向(LDM核心)返回1,否则返回0。
int match(struct device * dev, struct device_driver * drv);
如果设备和驱动成功匹配,那么设备(结构)的驱动成员将会被设置为该驱动,接
着该驱动中的probe回调将会被调用。这样能够给驱动提供一次机会去判定它是否
支持该硬件或这该硬件已经被投入使用了。
着该驱动中的probe回调将会被调用。这样能够给驱动提供一次机会去判定它是否
支持该硬件或这该硬件已经被投入使用了。
读者见解:
match应该是总线行为,所以在驱动结构中并没有match回调成员。也应该注意
match的返回值,跟Linux的传统不同,这里成功返回1,失败返回0。
match应该是总线行为,所以在驱动结构中并没有match回调成员。也应该注意
match的返回值,跟Linux的传统不同,这里成功返回1,失败返回0。
设备类
当probe操作成功完成之后,设备会向它所属的类(class)申请注册。设备驱动有且
只有一个它所属于的类(class),这个类会设置在驱动的devclass成员中。(LDM核心)
会调用devclass_add_device向该类列举设备同时会在类结构的register_dev回调中
注册该设备。
只有一个它所属于的类(class),这个类会设置在驱动的devclass成员中。(LDM核心)
会调用devclass_add_device向该类列举设备同时会在类结构的register_dev回调中
注册该设备。
译者疑点:
devclass_add_device接口已被除名。class结构中没有register_dev回调。
devclass_add_device接口已被除名。class结构中没有register_dev回调。
译者见解:
设备类是对设备类型的抽象。它关系的不是设备所用的总线,而是设备的功能,所
以,与设备类直接关联的应该是设备驱动。这样也解释了为什么devclass成员会在
驱动结构中(属于同一个驱动的设备都有同样的功能)。
设备类是对设备类型的抽象。它关系的不是设备所用的总线,而是设备的功能,所
以,与设备类直接关联的应该是设备驱动。这样也解释了为什么devclass成员会在
驱动结构中(属于同一个驱动的设备都有同样的功能)。
驱动
当一个驱动被一个设备依附(attach)时,设备(结构)会被插入到驱动的设备链表成
员的末端。
员的末端。
sys文件系统
在总线的'devices'目录下创建一个指向设备物理层的符号链接。
(以platform举个例)
/sys/bus/platform/
├── devices
│ ├── Fixed MDIO bus.0 -> ../../../devices/platform/Fixed MDIO bus.0
│ ├── i8042 -> ../../../devices/platform/i8042
│ ├── iTCO_wdt -> ../../../devices/platform/iTCO_wdt
│ └── vesafb.0 -> ../../../devices/platform/vesafb.0
├── drivers
│ ├── dsa
│ ├── i8042
│ ├── iTCO_wdt
│ ├── serial8250
│ └── vesafb
├── drivers_autoprobe
└── uevent
├── devices
│ ├── Fixed MDIO bus.0 -> ../../../devices/platform/Fixed MDIO bus.0
│ ├── i8042 -> ../../../devices/platform/i8042
│ ├── iTCO_wdt -> ../../../devices/platform/iTCO_wdt
│ └── vesafb.0 -> ../../../devices/platform/vesafb.0
├── drivers
│ ├── dsa
│ ├── i8042
│ ├── iTCO_wdt
│ ├── serial8250
│ └── vesafb
├── drivers_autoprobe
└── uevent
在驱动的'devices'目录下创建一个指向设备物理层的符号链接。
/sys/bus/platform/drivers
├── dsa
│ ├── bind
│ ├── uevent
│ └── unbind
├── i8042
│ ├── i8042 -> ../../../../devices/platform/i8042
│ └── uevent
├── iTCO_wdt
│ ├── bind
│ └── unbind
├── dsa
│ ├── bind
│ ├── uevent
│ └── unbind
├── i8042
│ ├── i8042 -> ../../../../devices/platform/i8042
│ └── uevent
├── iTCO_wdt
│ ├── bind
│ └── unbind
在该类目录下给设备创建一个目录。在该目录下为设备创建一个指向设备物理层的
符号链接。
/sys/class/input
├── event0 -> ../../devices/LNXSYSTM:00/..../input/input0/event0
├── event4 -> ../../devices/platform/i8042/serio0/input/input4/event4
├── event5 -> ../../devices/platform/i8042/serio1/input/input5/event5
├── event6 -> ../../devices/pci0000:00/..../input/input6/event6
├── event7 -> ../../devices/LNXSYSTM:00/..../input/input7/event7
├── mice -> ../../devices/virtual/input/mice
├── mouse0 -> ../../devices/platform/i8042/serio1/input/input5/mouse0
└── mouse1 -> ../../devices/pci0000:00/..../input/input6/mouse1
├── event0 -> ../../devices/LNXSYSTM:00/..../input/input0/event0
├── event4 -> ../../devices/platform/i8042/serio0/input/input4/event4
├── event5 -> ../../devices/platform/i8042/serio1/input/input5/event5
├── event6 -> ../../devices/pci0000:00/..../input/input6/event6
├── event7 -> ../../devices/LNXSYSTM:00/..../input/input7/event7
├── mice -> ../../devices/virtual/input/mice
├── mouse0 -> ../../devices/platform/i8042/serio1/input/input5/mouse0
└── mouse1 -> ../../devices/pci0000:00/..../input/input6/mouse1
可以在设备的物理层目录下为设备创建指向该类的目录、设备类顶层目录的符号链
接。也可以为设备创建指向其驱动的符号链接。
驱动注册
过程跟设备注册差不多。总线(结构)的设备链表成员会被遍历,(LDM核心)会为
其中没有跟驱动绑定的设备与当前驱动尝试匹配(match),同时为当前驱动绑定
尽可能多的匹配设备。
其中没有跟驱动绑定的设备与当前驱动尝试匹配(match),同时为当前驱动绑定
尽可能多的匹配设备。
移除
当一个设备的引用计数减为0时,该设备会被移除。(LDM核心)会调用驱动中的
remove回调。该设备会从驱动的设备链表成员中移除,同时驱动的引用计数也
会减少。所有两者之间关联的符号链接会被移除。
remove回调。该设备会从驱动的设备链表成员中移除,同时驱动的引用计数也
会减少。所有两者之间关联的符号链接会被移除。
当一个驱动被移除时,(LDM核心)会遍历所有该驱动支持的设备,同时为每一个
设备调用remove回调。设备会从该链表中移除(注:但还链接在总线的设备链表
成员上)。同时,符号链接会移除。
设备调用remove回调。设备会从该链表中移除(注:但还链接在总线的设备链表
成员上)。同时,符号链接会移除。