原文地址:
一、总线(bus)
总线是CPU与外设之间的通道。在设备模型中,所有的设备都通过总线相连。用bus_type结构表示总线( ):
struct bus_type {
const char *name;//总线名,显示在/sysfs/bus/目录下,如/sysfs/bus/i2c
struct bus_attribute *bus_attrs;//总线的缺省属性
struct device_attribute *dev_attrs;//总线上设备的缺省属性
struct driver_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 dev_pm_ops *pm;//电源管理接口,这里不讨论
struct bus_type_private *p;//总线的私有数据,定义于driver/base/base.h
};
struct bus_type_private {
struct kset subsys;//代表该总线的kset
struct kset *drivers_kset;//挂接在该总线上的驱动的kset,如/sysfs/bus/i2c/drivers
struct kset *devices_kset;//挂载在该总线上的设备的kset,如/sysfs/bus/i2c/devices
struct klist klist_devices;//挂接在该总线上的设备链表
struct klist klist_drivers;//挂接在该总线上的驱动链表
struct blocking_notifier_head bus_notifier;//通知链,暂不讨论
unsigned int drivers_autoprobe:1;
struct bus_type *bus;//指向与之关联的bus_type
};
1、总线的注册
函数bus_register用来向系统注册一个总线:int bus_register(struct bus_type *bus);
以i2c总线为例,看看内核如何注册i2c总线的。首先,要准备名为“i2c”的bus_type结构:
/* drivers\i2c\i2c-core.c */
struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
/* 以下暂时省略总线的方法 */
};
然后调用bus_register来注册i2c总线:
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type);
......
}
在调用bus_register(&i2c_bus_type)之后,将会在/sysfs/bus下看到i2c目录,在/sysfs/bus/i2c目录下看到devices和drivers目录。下面简单跟一下bus_register的源码(不考虑操作失败的情况):
首先,分配bus_type对应的私有数据结构
struct bus_type_private *priv;
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
将私有数据结构和bus_type对应起来
priv->bus = bus;
bus->p = priv;
设置总线的名字如“i2c”
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
设置总线所属的kset,此处设置为bus_kset,bus_kset是在buses_init内创建的:
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
......
}
不清楚将bus_kset当成/sysfs/bus目录,而priv->subsys当成/sysfs/bus/xxx(如/sysfs/bus/i2c)目录是否更容易理解其中的层次关系?
priv->subsys.kobj.kset = bus_kset;
阅读(701) | 评论(0) | 转发(0) |