Driver Binding
Driver binding is the process of associating a device with a device
driver that can control it. Bus drivers have typically handled this
because there have been bus-specific structures to represent the
devices and the drivers. With generic device and device driver
structures, most of the binding can take place using common code.
驱动绑定
驱动绑定就是将一个设备与能够控制它的驱动关联的过程。这一过程一般是由
总线驱动处理的,因为总线驱动都会有一组能够表征设备和设备驱动的与特定
总线相关的数据结构。通过嵌入通用的设备和驱动结构,大多数绑定都能够在
公共代码发生。
译者见解:
这里的公共代码是指LDM核心的代码段。在内核的LDM层,公共总线结构中有两
个链表成员,分别将该总线上的设备和驱动链接在一起。公共驱动结构里也有
一个链表成员,用于将该驱动能够控制的已发现的设备链接在一起。在没有任
何绑定前,两个链表中的设备和驱动(结构)是互不关联的,绑定后,所谓的关
联可以直接理解为设备结构也被链接到一个能够控制它的驱动结构里面的链表
成员中。
Bus
~~~
The bus type structure contains a list of all devices that are on that bus
type in the system. When device_register is called for a device, it is
inserted into the end of this list. The bus object also contains a
list of all drivers of that bus type. When driver_register is called
for a driver, it is inserted at the end of this list. These are the
two events which trigger driver binding.
总线
----》
总线结构包含一个链表成员(注:设备链表成员),该成员将系统中属于该类总
线的所有设备链接在一起。当为一个设备调用device_register函数时,该设备
会被链接到设备链表成员的末端。同样,总线结构也包含一个驱动链表成员,
该成员将系统中属于该总线的所有驱动链接在一起。当为一个驱动调用
driver_register函数时,该驱动结构将会被链接到驱动链表成员的末端。上述
就是能够触发驱动绑定的两个事件。
device_register
~~~~~~~~~~~~~~~
When a new device is added, the bus's list of drivers is iterated over
to find one that supports it. In order to determine that, the device
ID of the device must match one of the device IDs that the driver
supports. The format and semantics for comparing IDs is bus-specific.
Instead of trying to derive a complex state machine and matching
algorithm, it is up to the bus driver to provide a callback to compare
a device against the IDs of a driver. The bus returns 1 if a match was
found; 0 otherwise.
int match(struct device * dev, struct device_driver * drv);
If a match is found, the device's driver field is set to the driver
and the driver's probe callback is called. This gives the driver a
chance to verify that it really does support the hardware, and that
it's in a working state.
设备注册
--------》
当一个设备被加入时,总线的驱动链表成员将会被遍历,以寻找能够支持该设备
的驱动。为了判定一个设备能否被驱动,设备ID必须与该驱动支持的ID列表中的
任意一个ID相匹配。ID的格式和比较的语义是与特定总线相关的。为了避免实现
一个复杂的状态机和比较逻辑,(LDM核心)为总线驱动提供了一个比较设备ID与
驱动ID的回调接口,如果比配总线向(LDM核心)返回1,否则返回0。
int match(struct device * dev, struct device_driver * drv);
如果设备和驱动成功匹配,那么设备(结构)的驱动成员将会被设置为该驱动,接
着该驱动中的probe回调将会被调用。这样能够给驱动提供一次机会去判定它是否
支持该硬件或这该硬件已经被投入使用了。
读者见解:
match应该是总线行为,所以在驱动结构中并没有match回调成员。也应该注意
match的返回值,跟Linux的传统不同,这里成功返回1,失败返回0。
Device Class
~~~~~~~~~~~~
Upon the successful completion of probe, the device is registered with
the class to which it belongs. Device drivers belong to one and only one
class, and that is set in the driver's devclass field.
devclass_add_device is called to enumerate the device within the class
and actually register it with the class, which happens with the
class's register_dev callback.
NOTE: The device class structures and core routines to manipulate them
are not in the mainline kernel, so the discussion is still a bit
speculative.
设备类
------》
当probe操作成功完成之后,设备会向它所属的类(class)申请注册。设备驱动有且
只有一个它所属于的类(class),这个类会设置在驱动的devclass成员中。(LDM核心)
会调用devclass_add_device向该类列举设备同时会在类结构的register_dev回调中
注册该设备。
注意:
设备类结构及其核心操作规则尚未成熟,上述描述应该带着怀疑的心态去阅读。
译者疑点:
devclass_add_device接口已被除名。class结构中没有register_dev回调。
译者见解:
设备类是对设备类型的抽象。它关系的不是设备所用的总线,而是设备的功能,所
以,与设备类直接关联的应该是设备驱动。这样也解释了为什么devclass成员会在
驱动结构中(属于同一个驱动的设备都有同样的功能)。
Driver
~~~~~~
When a driver is attached to a device, the device is inserted into the
driver's list of devices.
驱动
----》
当一个驱动被一个设备依附(attach)时,设备(结构)会被插入到驱动的设备链表成
员的末端。
sysfs
~~~~~
A symlink is created in the bus's 'devices' directory that points to
the device's directory in the physical hierarchy.
A symlink is created in the driver's 'devices' directory that points
to the device's directory in the physical hierarchy.
A directory for the device is created in the class's directory. A
symlink is created in that directory that points to the device's
physical location in the sysfs tree.
A symlink can be created (though this isn't done yet) in the device's
physical directory to either its class directory, or the class's
top-level directory. One can also be created to point to its driver's
directory also.
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
│ ├── microcode -> ../../../devices/platform/microcode
│ ├── pcspkr -> ../../../devices/platform/pcspkr
│ ├── serial8250 -> ../../../devices/platform/serial8250
│ └── vesafb.0 -> ../../../devices/platform/vesafb.0
├── drivers
│ ├── dsa
│ ├── i8042
│ ├── iTCO_wdt
│ ├── serial8250
│ └── vesafb
├── drivers_autoprobe
├── drivers_probe
└── uevent
在驱动的'devices'目录下创建一个指向设备物理层的符号链接。
/sys/bus/platform/drivers
├── dsa
│ ├── bind
│ ├── uevent
│ └── unbind
├── i8042
│ ├── i8042 -> ../../../../devices/platform/i8042
│ └── uevent
├── iTCO_wdt
│ ├── bind
│ ├── iTCO_wdt -> ../../../../devices/platform/iTCO_wdt
│ ├── module -> ../../../../module/iTCO_wdt
│ ├── uevent
│ └── unbind
├── serial8250
│ ├── bind
│ ├── serial8250 -> ../../../../devices/platform/serial8250
│ ├── uevent
│ └── unbind
└── vesafb
├── uevent
└── vesafb.0 -> ../../../../devices/platform/vesafb.0
在该类目录下给设备创建一个目录。在该目录下为设备创建一个指向设备物理层的
符号链接。
/sys/class/input
├── event0 -> ../../devices/LNXSYSTM:00/..../input/input0/event0
├── event1 -> ../../devices/LNXSYSTM:00/..../input/input1/event1
├── event2 -> ../../devices/LNXSYSTM:00/..../input/input2/event2
├── event3 -> ../../devices/LNXSYSTM:00/LNXPWRBN:00/input/input3/event3
├── 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
├── event8 -> ../../devices/pci0000:00/..../input/input8/event8
├── input0 -> ../../devices/LNXSYSTM:00/..../input/input0
├── input1 -> ../../devices/LNXSYSTM:00/..../input/input1
├── input2 -> ../../devices/LNXSYSTM:00/..../input/input2
├── input3 -> ../../devices/LNXSYSTM:00/LNXPWRBN:00/input/input3
├── input4 -> ../../devices/platform/i8042/serio0/input/input4
├── input5 -> ../../devices/platform/i8042/serio1/input/input5
├── input6 -> ../../devices/pci0000:00/..../input/input6
├── input7 -> ../../devices/LNXSYSTM:00/..../input/input7
├── input8 -> ../../devices/pci0000:00/..../input/input8
├── mice -> ../../devices/virtual/input/mice
├── mouse0 -> ../../devices/platform/i8042/serio1/input/input5/mouse0
└── mouse1 -> ../../devices/pci0000:00/..../input/input6/mouse1
可以在设备的物理层目录下为设备创建指向该类的目录、设备类顶层目录的符号链
接。也可以为设备创建指向其驱动的符号链接。
driver_register
~~~~~~~~~~~~~~~
The process is almost identical for when a new driver is added.
The bus's list of devices is iterated over to find a match. Devices
that already have a driver are skipped. All the devices are iterated
over, to bind as many devices as possible to the driver.
驱动注册
--------》
过程跟设备注册差不多。总线(结构)的设备链表成员会被遍历,(LDM核心)会为
其中没有跟驱动绑定的设备与当前驱动尝试匹配(match),同时为当前驱动绑定
尽可能多的匹配设备。
Removal
~~~~~~~
When a device is removed, the reference count for it will eventually
go to 0. When it does, the remove callback of the driver is called. It
is removed from the driver's list of devices and the reference count
of the driver is decremented. All symlinks between the two are removed.
When a driver is removed, the list of devices that it supports is
iterated over, and the driver's remove callback is called for each
one. The device is removed from that list and the symlinks removed.
移除
----》
当一个设备的引用计数减为0时,该设备会被移除。(LDM核心)会调用驱动中的
remove回调。该设备会从驱动的设备链表成员中移除,同时驱动的引用计数也
会减少。所有两者之间关联的符号链接会被移除。
当一个驱动被移除时,(LDM核心)会遍历所有该驱动支持的设备,同时为每一个
设备调用remove回调。设备会从该链表中移除(注:但还链接在总线的设备链表
成员上)。同时,符号链接会移除。