由于在下能力相当有限,有不当之处,还望大家批评指正^_^
本文基于Linux内核2.6.32
一、宏观架构
在内核中,大量的驱动与设备(但不是全部),都按总线进行分类管理。
例如,凡是pci设备或pci设备的驱动,都归到pci总线下管理。
1. 从sys文件系统感受这种架构。
/sys/bus/目录下列出了各种总线类型,像pci、i2c、usb、platform等。
我们以pci总线为例,看看相关概念。
/sys/bus/pci/devices/目录下则则列出了所有系统中存在的所有pci设备(不管有没有安装对应的驱动程序)的名称,pci设备的名称即pci地址(即 "域:pci总线号:槽位号:功能号")。下面的示例输出,限于篇幅,只列出了几个设备作为样例。
[root@211-157-CGSLV5 char]# ls /sys/bus/pci/devices/
0000:00:00.0 0000:03:00.0 0000:06:12.7 0000:06:16.3
/sys/bus/pci/drivers目录下则列出了所有已加载的所有pci设备的驱动。
下面的示例输出,列出了pci设备驱动ixgbe(一款网卡驱动程序),以及当前接管了哪些设备(0000:06:00.0和0000:06:00.1)。
[root@211-157-CGSLV5 char]# ls /sys/bus/pci/drivers/ixgbe
0000:06:00.0 0000:06:00.1 bind module new_id remove_id uevent unbind
示例输出中还有一些别的文件,像bind用来指定某个pci设备由此驱动接管,unbind则起相反的作用。通常,一个驱动都有自己支持的设备型号的列表。new_id用于动态增加此驱动可以接管的设备型号,remove_id则起相反作用。
【注】
pci设备的名称,是通过如下方式设置的
dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
dev->bus->number, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn));
而其他类型的设备,命名方式也名异。下面列出了其他几种设备的命名方式
(i) isa
dev_set_name(&isa_dev->dev, "%s.%u",
isa_driver->driver.name, id);
(ii)platform
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, "%s", pdev->name);
(iii)I2C
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
【注】
有时候,可能会存在多个驱动,都可以驱动某一个设备的情况。
这时候,用户可以执行将设备与驱动进行绑定或解除绑定的操作。
将设备与驱动绑定的方法为:
echo dev_name > /sys/bus/bus_type/drivers/driver_name/bind
将设备与驱动解除绑定的方法为:
echo dev_name > /sys/bus/bus_type/drivers/driver_name/unbind
例如,将名称为 0000:06:00.1的pci设备与名为ixgbe的驱动绑定,则命令如下:echo 0000:06:00.1 > /sys/bus/pci/drivers/ixgbe/bind
echo命令执行后,由driver_bind/driver_unbind函数执行具体的绑定与解绑。
这两个函数对应于sys文件系统的store操作。
当然,除了pci总线,还有别的总线类型。
不同类型的总线,有着不同的原理与概念。
下面列出了若干不同类型总线的设备,可以看到其命名风格的不同。
[root@211-157-CGSLV5 char]# ls /sys/bus/i2c/devices/
2-007c i2c-0 i2c-1 i2c-2 i2c-3
[root@211-157-CGSLV5 char]# ls /sys/bus/usb/devices/
1-0:1.0 1-1 1-1:1.0 1-1.3 1-1.3:1.0 1-1.3:1.1 2-0:1.0 2-1 2-1:1.0 usb1 usb2
[root@211-157-CGSLV5 char]# ls /sys/bus/platform/devices/
alarmtimer coretemp.1 GHES.0 gpio_ich iTCO_wdt pcspkr
coretemp.0 Fixed MDIO bus.0 GHES.1 ipmi_bmc.3060.8 microcode serial8250
2. 从源代码中感受这种架构。
设备驱动方面的核心代码,位于drivers/base目录下。core.c是设备管理的核心文件,driver.c是驱动管理的核心文件,bus.c是总线处理的核心文件。我们可以以他们为线索,看出不同模块之间的调用关系,同时也能看出内核在管理设备与驱动方面的精妙设计理念。
在看代码之前,先来聊聊设备、驱动、总线之间的关系,同时引出一些内核中的重要数据结构。首先说说设备。不管是什么奇奇怪怪的设备,它毕竟都是一个设备。所以,在这个层次上,可以将一切设备都归纳到设备这个集合中去管理。就像动物一样,不管是人,还是猪马牛羊,站在动物这个层次上,都可以归属到动物这个类别中去。
在内核中,用于表示一个设备的数据结构是 struct device。
再来说说驱动。同理,一切驱动都是驱动,自然也是统一管理。
内核中,表示一个驱动的数据结构是 struct device_driver。
好了,现在已经有了设备与驱动的表示方法。但是,这是站在最高层次上做出的概念抽象。
不同类型总线的设备,其标识方法也各有不同。
实际上,内核源码中也为此定义了不同类型的结构来标识之。
例如,struct platform_device_id用于标识platform设备,struct pci_device_id用于标识pci设备。
未完...