总线类型

定义

请参阅 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 数组,这些设备 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”的顶级目录。

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

/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 *);