总线类型

定义

请参阅 struct bus_type 的 kerneldoc。

int bus_register(struct bus_type * bus);

声明

内核中的每种总线类型(PCI、USB 等)都应声明此类型的静态对象。它们必须初始化 name 字段,并且可以选择初始化 match 回调。

struct bus_type pci_bus_type = {
       .name = "pci",
       .match        = pci_bus_match,
};

该结构应在头文件中导出到驱动程序

extern struct bus_type pci_bus_type;

注册

当总线驱动程序初始化时,它会调用 bus_register。这将初始化总线对象中的其余字段,并将其插入到全局总线类型列表中。一旦注册了总线对象,总线驱动程序就可以使用其中的字段。

回调

match(): 将驱动程序附加到设备

设备 ID 结构的格式和比较它们的语义本质上是总线特定的。驱动程序通常声明其支持的设备的设备 ID 数组,这些设备位于特定于总线的驱动程序结构中。

match 回调的目的是让总线有机会通过比较驱动程序支持的设备 ID 与特定设备的设备 ID 来确定特定驱动程序是否支持特定设备,而不会牺牲特定于总线的功能或类型安全。

当驱动程序在总线上注册时,会迭代总线的设备列表,并为每个未关联驱动程序的设备调用 match 回调。

设备和驱动程序列表

设备和驱动程序的列表旨在取代许多总线保留的本地列表。它们分别是 struct devices 和 struct device_drivers 的列表。总线驱动程序可以随意使用这些列表,但可能需要转换为特定于总线的类型。

LDM 核心提供了用于迭代每个列表的帮助函数

int bus_for_each_dev(struct bus_type * bus, struct device * start,
                     void * data,
                     int (*fn)(struct device *, void *));

int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
                     void * data, int (*fn)(struct device_driver *, void *));

这些助手会迭代相应的列表,并为列表中的每个设备或驱动程序调用回调。所有列表访问都通过获取总线的锁(当前为读取)来同步。在调用回调之前,列表中每个对象的引用计数都会递增;在获取下一个对象后,引用计数会递减。调用回调时不会持有锁。

sysfs

有一个名为 'bus' 的顶层目录。

每个总线在 bus 目录中都有一个目录,以及两个默认目录

/sys/bus/pci/
|-- devices
`-- drivers

在总线上注册的驱动程序在总线的 drivers 目录中获得一个目录

/sys/bus/pci/
|-- devices
`-- drivers
    |-- Intel ICH
    |-- Intel ICH Joystick
    |-- agpgart
    `-- e100

在总线上发现的每种类型的设备,都会在总线的 devices 目录中获得一个指向设备在物理层次结构中目录的符号链接

/sys/bus/pci/
|-- devices
|   |-- 00:00.0 -> ../../../root/pci0/00:00.0
|   |-- 00:01.0 -> ../../../root/pci0/00:01.0
|   `-- 00:02.0 -> ../../../root/pci0/00:02.0
`-- drivers

导出属性

struct bus_attribute {
      struct attribute        attr;
      ssize_t (*show)(const struct bus_type *, char * buf);
      ssize_t (*store)(const struct bus_type *, const char * buf, size_t count);
};

总线驱动程序可以使用 BUS_ATTR_RW 宏导出属性,该宏的工作方式类似于设备的 DEVICE_ATTR_RW 宏。例如,像这样的定义

static BUS_ATTR_RW(debug);

等效于声明

static bus_attribute bus_attr_debug;

然后可以使用以下方法从总线的 sysfs 目录添加和删除属性

int bus_create_file(struct bus_type *, struct bus_attribute *);
void bus_remove_file(struct bus_type *, struct bus_attribute *);