Bus Types
Definition~~~~~~~~~~
See the kernel doc for the struct bus_type.(include/linux/device.h)
struct bus_type {
const char *name;
structbus_attribute *bus_attrs;
struct device_attribute *dev_attrs;
structdriver_attribute *drv_attrs;
int(*match)(struct device *dev, struct device_driver *drv);
int(*uevent)(struct device *dev, struct kobj_uevent_env *env);
int(*probe)(struct device *dev);
int(*remove)(struct device *dev);
void(*shutdown)(struct device *dev);
int(*suspend)(struct device *dev, pm_message_t state);
int(*suspend_late)(struct device *dev, pm_message_t state);
int(*resume_early)(struct device *dev);
int(*resume)(struct device *dev);
struct pm_ext_ops*pm;
structbus_type_private *p;
};
int bus_register(struct bus_type * bus);
Declaration~~~~~~~~~~~
内核中的每种总线(PCI, USB, 等等) 都应该要声明一个该类型的静态对象,并初始化其name域。对match()回调函数的初始化则是可选的.
struct bus_type pci_bus_type = {
.name = "pci",
.match = pci_bus_match,
};
这个数据结构应被包含在头文件中以使驱动程序可以访问:
extern struct bus_type pci_bus_type;
Registration~~~~~~~~~~~~
总线驱动在初始化时调用bus_register(),以初始化其它的域并将该结构对象插入到一个全局的总线类型列表中. 一旦这个总线对象注册完成,总线驱动就可以访问该结构中的所有域.
Callbacks~~~~~~~~~
match(): 绑定设备和驱动
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
结构device ID的格式以及比较设备和驱动的方法依总线类型而不同. 驱动总是将其所支持的设备声明为一组device ID,这个组被嵌入到该总线的驱动的数据结构中.
Match()互调函数的目的是使总线有机会去对比特定设备的device ID和某个驱动所支持的device ID组,以确定该驱动是否支持这个特定设备, 而不必牺牲总线的功能性或类型安全性.
当驱动注册到总线上,该总线的设备列表会被遍历一次,针对每一个尚未绑定驱动的设备都会调用一次match().
Device and Driver Lists
~~~~~~~~~~~~~~~~~~~~~~~
设备/驱动列表用于取代之前由很多总线在本地维护的列表. 它们的类型分别为
struct devices 和structdevice_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, structdevice_driver * start,
void * data, int (*fn)(structdevice_driver *, void *));
这两个辅助函数分别遍历设备/驱动列表,并未列表中的每一个设备/驱动调用回调函数. 所有对列表的访问都由总线锁(表示正在读)进行同步. 列表中每一个对象的reference count 在调用回调函数前都会+1;而在操作下一个对象时会-1. 调用回调函数是不会保持总线锁.
sysfs
~~~~~~~~
/sysfs下的顶级子目录是'bus'.
每种总线在/sysfs/bus/下都有自己的子目录, 其中又有两个默认的目录:
/sys/bus/pci/
|-- devices
`-- drivers
注册到总线的驱动在bus/drivers下都有自己的子目录:
/sys/bus/pci/
|-- devices
`-- drivers
|-- Intel ICH
|-- Intel ICH Joystick
|-- agpgart
`-- e100
总线上探测到的每个设备则在bus/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
Exporting Attributes
~~~~~~~~~~~~~~~~~~~~
struct bus_attribute {
structattribute attr;
ssize_t(*show)(struct bus_type *, char * buf);
ssize_t(*store)(struct bus_type *, const char * buf, size_t count);
};
使用和宏DEVICE_ATTR类似的宏,BUS_ATTR,总线去驱动可以导出其属性. 比如如下定义:
static BUS_ATTR(debug,0644,show_debug,store_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 *, structbus_attribute *);