为什么ARM Linux社区要部署设备树
Linux的父亲Linus Torvalds很闲,看着ARM Linux代码,有一天终于忍不住了。 他在2011年3月17日的ARM Linux邮件列表中说:“thiswholearmthingisaf * ckingpainintheass。” 通过这句话,ARM Linux社区现在部署设备树。
Linus Torvalds为什么生气呢? ARM Linux社区的牛为什么又乖乖听话了? 首先,必须了解Linux设备驱动框架中的非常好的设计。 设备信息和驱动分离。
为了说明设备信息与驱动程序分离的概念,我们来看一个简单的模拟代码示例。
【例-1】实现代码,将使用的信息轻松写在代码中死亡:
int add ()/*模拟驱动代码) /
{
返回3 5; /*模拟设备信息*
}
优点:简单
缺点:加数和被加数变化时必须改变代码
将设计改进如下:
【例-2】实现将使用的信息和操作代码分离的代码:
结构dev {
int id;
int x;
int y;
(; /*模拟设备信息结构*
结构drv {
int id;
int(*add ) ) struct dev *info );
(; /*模拟驱动机构*
intadd(structdev*info )/*模拟驱动代码(/
{
返回信息- x信息- y; /*模拟设备信息-通过参数传递*
}
结构drv drv={
. id=1,
. add=add,
(;
/*模拟设备信息*
struct dev dev={
. id=1,
. x=3,
. y=5,
(;
/*模拟总线初始化匹配设备信息和驱动程序代码*
int bus () )
{
if(dev.id==drv.id ) {
返回drv.add (dev;
}
.
}
优点:无论加数和被加数如何变化,都不需要修改代码,只需修改信息即可
缺点:结构复杂
那么,该器件信息和驱动隔离的设计与驱动有什么关系呢? 熟悉硬件编程的学生知道,硬件的一般配置可以通过下图简单地表达出来。
如果硬件相同,操作外围设备的驱动程序代码逻辑不会发生变化。 但是,如果外围设备悬挂在不同的主机上,I/O地址可能会发生变化。 即使有中断也一样,中断号码也可能不同。 这些I/O地址和中断编号是设备信息,驱动程序使用这些信息来操作控制硬件的代码。
如果采用【例-1】的设计方式,同一硬件外围设备连接到不同主机、更改地址线或/中断线时,设备信息会发生变化,必须修改驱动程序。 但是,用【例-2】的方式设计,就解决了问题。 无论同一外围硬件连接在哪里或连接在其平台上,其驱动程序代码逻辑都不需要更改,只需更改设备信息即可,主要是I/O地址和中断号。
说了这么久,和设备树的引进有什么关系? 华清教学中使用的开发板(A8/A9 )均使用DM 9000网卡芯片。 DM9000驱动程序是开源的,位于主线内核源中。 每次我们基于A8/A9板移植时,DM9000驱动程序都没有被修改。 只是选择下面,主要工作是向板级文件添加设备信息。 由于DM9000驱动程序使用平台框架,因此添加了DM9000网卡芯片的平台_设备信息。 发生了问题。 如果以c代码的形式编写设备信息,则内核源代码中将包含多个DM9000的platform_device设备信息,从而冗馀内核代码。
解决这个问题的方法是引入工厂树,改造【例-2】说明工厂树的作用。
【例-3】不仅将使用的信息和操作码分开,而且信息不是用c码写的,而是实现文档中存储的代码:
结构dev {
int id;
int x;
int y;
(; /*模拟设备信息结构*
结构drv {
int id;
int(*add ) ) struct dev *info );
(; /*模拟驱动机构*
intadd(structdev*info )/*模拟驱动代码(/
{
返回信息- x信息- y; /*模拟设备信息-通过参数传递*
}
结构drv drv={
. id=1,
. add=add,
(;
/*模拟设备树xxx.dtbs的特殊配置文件*/
//{
.
Dm9000{
x=3;
y=5;
(;
.
(;
/*模拟总线初始化匹配设备信息和驱动程序代码*
int bus () )
{
/*模拟设备树初始化处理*
阅读文件(xxx.dtbs;
分析文件内容(根据设备树的规则进行分析);
生成结构dev设备信息;
if(dev.id==drv.id ) {
返回drv.add (dev;
}
.
}
通过【例-3】,可以解决大量设备信息的代码冗馀性问题。
广泛而言,系统的硬件和软件的信息都可以使用设备树来描述。 这样,由于ARM Linux社区对板和驱动程序的支持越来越多,内核源中就不会出现过多的冗馀代码(主要是板级文件)。 移植者只需要通过设备树提供系统硬件和软件信息,并选择内核代码即可。