The Linux Kernel Device Model
Patrick Mochel <>
Drafted 26 August 2002
Updated 31 January 2006
Overview
~~~~~~~~
The Linux Kernel Driver Model is a unification of all the disparate driver
models that were previously used in the kernel. It is intended to augment the
bus-specific drivers for bridges and devices by consolidating a set of data
and operations into globally accessible data structures.
Traditional driver models implemented some sort of tree-like structure
(sometimes just a list) for the devices they control. There wasn't any
uniformity across the different bus types.
The current driver model provides a common, uniform data model for describing
a bus and the devices that can appear under the bus. The unified bus
model includes a set of common attributes which all busses carry, and a set
of common callbacks, such as device discovery during bus probing, bus
shutdown, bus power management, etc.
The common device and bridge interface reflects the goals of the modern
computer: namely the ability to do seamless device "plug and play", power
management, and hot plug. In particular, the model dictated by Intel and
Microsoft (namely ACPI) ensures that almost every device on almost any bus
on an x86-compatible system can work within this paradigm. Of course,
not every bus is able to support all such operations, although most
buses support a most of those operations.
概述
----》
Linux内核驱动模型是内核对之前各自分离的驱动模型的统一。它的目的是:通
过在全局可见的数据结构上综合一组数据和一套方法(注:这里是指与总线或设
备相关的回调函数指针)的方式为桥接器和设备增加了与特定总线相关的驱动。
传统的驱动模型往往会为他们所控制的设备实现了某种树状结构(有些可能只是
链表结构)。这些结构在不同的总线类型之间得不到任何的统一。
现在的设备驱动模型为描述总线和出现在总线上的设备分别提供了一种公共、统
一的数据模型。这种统一的总线模型包括一套所有总线的拥有的共通的属性和一
套回调函数(注:代表总线的共通行为)。例如:在总线侦测时的发现设备,总线
的关闭行为,总线的电源管理等。
上述公共的设备和桥接器接口也反映了现代计算机的目标:也就是拥有设备即插
即用的无缝实现,电源管理和热插拔的能力。尤其是由Intel和Microsoft提出的
叫ACPI(注:Advanced Configuration and Power Interface 高级配置和电源管
理接口)的在x86兼容架构上几乎在任何总线上的所有设备都能工作在这种规范下
接口。虽然不是所有总线都能够支持这样的操作,但是许多总线都支持大部分的
上述操作。
译者见解:
对驱动模型的统一,可以使得内核中对象清晰,结构规范化,简化了代码。这里
所说的公共模型其实就是:
struct device ; struct device_driver ; struct bus_type ;
其中,驱动和总线结构中的回调函数,是对各类总线和驱动共同行为的抽象,同
时,也也预留接口(也就是上面的回调函数接口),保证给定总线行为在某个细节
上的特性得以实现(通常是驱动开发者自己去实现的)。
Downstream Access
~~~~~~~~~~~~~~~~~
Common data fields have been moved out of individual bus layers into a common
data structure. These fields must still be accessed by the bus layers,
and sometimes by the device-specific drivers.
Other bus layers are encouraged to do what has been done for the PCI layer.
struct pci_dev now looks like this:
struct pci_dev {
...
struct device dev;
};
Note first that it is statically allocated. This means only one allocation on
device discovery. Note also that it is at the _end_ of struct pci_dev. This is
to make people think about what they're doing when switching between the bus
driver and the global driver; and to prevent against mindless casts between
the two.
The PCI bus layer freely accesses the fields of struct device. It knows about
the structure of struct pci_dev, and it should know the structure of struct
device. Individual PCI device drivers that have been converted to the current
driver model generally do not and should not touch the fields of struct device,
unless there is a strong compelling reason to do so.
This abstraction is prevention of unnecessary pain during transitional phases.
If the name of the field changes or is removed, then every downstream driver
will break. On the other hand, if only the bus layer (and not the device
layer) accesses struct device, it is only that layer that needs to change.
底层访问
--------》
公共数据部分已经从独立的总线层中抽离出来加入到一个公共的数据结构。内核要求
该数据域必须仍能够被总线层访问,在特定情况下,还得被与设备相关的驱动访问。
提倡其它总线层以下面PCI层的方式去实现:
struct pci_dev {
...
struct device dev;
};
首先应该注意:上述结构是静态分配的。这意味着当一个设备被发现时,只能够有一
个上述结构被分配。同时也应该注意:公共数据结构(如上面的struct device)是
pci_dev结构的最后一个成员。这样使得人们在总线驱动和全局驱动之间切换时有所
察觉,从而阻止了对两者的无意混绕。
PCI总线层能够无碍地访问device结构的成员。它应该同时清楚pci_dev和device两个
结构的存在。然而,除非有逼不得已的原因,符合当前设备模型标准的PCI 设备驱动
一般都不需要也不应该触碰struct device结构的成员。
这样的抽象方法能够为过渡阶段减少很多不必要的工作。如果某一层结构的成员的名
字被改变或者直接被移除,那么底层所有(访问设备层的成员的)驱动将不可用。另一
方面,如果只有总线层(而不是设备层)访问了device结构,(当设备层发生改变时)那
么久只需要改那一层就可以了。
译者见解:
上面所述的其实是C++面向对象思想在C语言和内核架构上的灵活运用。device,
bus_type和device_driver其实就是它们每个对象的基类。设备驱动模型的分层思想
更将这种面向对象思想进行了升华。结合面向对象思想去理解设备模型,其实设备
模型没有传说中那么难。
User Interface
~~~~~~~~~~~~~~
By virtue of having a complete hierarchical view of all the devices in the
system, exporting a complete hierarchical view to userspace becomes relatively
easy. This has been accomplished by implementing a special purpose virtual
file system named sysfs. It is hence possible for the user to mount the
whole sysfs filesystem anywhere in userspace.
This can be done permanently by providing the following entry into the
/etc/fstab (under the provision that the mount point does exist, of course):
none /sys sysfs defaults 0 0
Or by hand on the command line:
# mount -t sysfs sysfs /sys
Whenever a device is inserted into the tree, a directory is created for it.
This directory may be populated at each layer of discovery - the global layer,
the bus layer, or the device layer.
The global layer currently creates two files - 'name' and 'power'. The
former only reports the name of the device. The latter reports the
current power state of the device. It will also be used to set the current
power state.
The bus layer may also create files for the devices it finds while probing the
bus. For example, the PCI layer currently creates 'irq' and 'resource' files
for each PCI device.
A device-specific driver may also export files in its directory to expose
device-specific data or tunable interfaces.
More information about the sysfs directory layout can be found in
the other documents in this directory and in the file
Documentation/filesystems/sysfs.txt.
用户接口
--------》
利用系统中所有设备的完整分层关系图,可以很容易的向用户空间导出一副完整的视
图。这已经被一个叫sysfs的特殊的虚拟文件系统实现了。因而,用户可以在用户空间
的任意节点挂载这一文件系统。
也可以在/etc/fstab中加入下面语句实现永久挂载(当然是在系统没有实现挂在的情况
下):
none /sys sysfs defaults 0 0
或者在命令行里输入:
# mount -t sysfs sysfs /sys
一旦设备被加入到设备树,内核就会为它(在sys下)创建一个目录。这一目录可能会出
现在能够发现设备的每一个层中包括:全局层,总线层或者设备层。
全局层通常会创建两个文件:"name"(姓名)和"power"(能源)。前者指代设备的名字,
后者指代设备当前的能源状态。同时也可通过修改"power"的值来改变设备的能源状态。
在侦测到设备时,总线层会为所发现的设备创建一个文件。例如,PCI层会为设备创建
"irq"和"resource"两个文件。
一个与特定设备相关的驱动可能会在他的目录下导出一些文件,这些文件用于公开一
些与特定设备相关的数据或者作为可调功能的接口。
译者见解:
或许这是对"Linux下一切皆文件"这一句话得很好的理解。sysfs将变量和功能都作为
接口向用户空间公开了。使得设备驱动变得相当透明。对设备驱动的操作也可以简单
的变成了文件操作。结合守护进程和内核事件层,sysfs是一个用户空间和内核空间
通信的完美的渠道。