linux设备模型深探(2)【转】
linux设备模型深探(2)【转】
2011年12月07日
这段代码中比较繁锁的就是bus_type对应目录下的属性文件建立,为了直观的说明,将属性文件的建立统一放到一起分析
从上面的代码中可以看,创建属性文件对应的属性分别为:
bus_attr_uevent bus_attr_drivers_probe, bus_attr_drivers_autoprobe
分别定义如下:
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
show_drivers_autoprobe, store_drivers_autoprobe);
BUS_ATTR定义如下:
#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
由此可见.上面这三个属性对应的名称为别为uevent, drivers_probe, drivers_autoprobe.也就是说,会在bus_types目录下生成三个文件,分别为uevent,probe,autoprobe.
根据之前的分析,我们知道在sysfs文件系统中,对普通属性文件的读写都会回溯到kobject->ktype->sysfs_ops中.在这里,注意到有:
priv->subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
显然,读写操作就回溯到了bus_ktype中.定义如下:
static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
};
static struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
Show和store函数对应的代码为:
static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
struct bus_type_private *bus_priv = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->show)
ret = bus_attr->show(bus_priv->bus, buf);
return ret;
}
static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
struct bus_type_private *bus_priv = to_bus(kobj);
ssize_t ret = 0;
if (bus_attr->store)
ret = bus_attr->store(bus_priv->bus, buf, count);
return ret;
}
从代码可以看出.读写操作又会回溯到bus_attribute中的show和store中.在自定义结构里嵌入struct attribute,.然后再操作回溯到自定义结构中,这是一种比较高明的架构设计手法.
闲言少叙.我们对应看一下上面三个文件对应的最终操作:
Uevent对应的读写操作为:NULL, bus_uevent_store.对于这个文件没有读操作,只有写操作.用cat 命令去查看这个文件的时候,可能会返回”设备不存在”的错误.bus_uevent_store()代码如下:
static ssize_t bus_uevent_store(struct bus_type *bus,
const char *buf, size_t count)
{
enum kobject_action action;
if (kobject_action_type(buf, count, &action) == 0)
kobject_uevent(&bus->p->subsys.kobj, action);
return count;
}
从这里可以看到,可以在用户空间控制事件的发生,如echo add > event就会产生一个add的事件,
Probe文件对应的读写操作为:NULL store_drivers_probe.
store_drivers_probe()这个函数的代码涉及到struct device.等分析完struct device可以自行回过来看下这个函数的实现.实际上,这个函数是将用户输和的设备名称对应的设备与驱动匹配一次.
Autoprobe文件对应的读写操作为show_drivers_autoprobe, store_drivers_autoprobe.对应读的代码为:
static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
{
return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
}
它将总线对应的drivers_autoprobe的值输出到用户空间,这个值为1时,自动将驱动与设备进行匹配.否则,反之.
写操作的代码如下:
static ssize_t store_drivers_autoprobe(struct bus_type *bus,
const char *buf, size_t count)
{
if (buf[0] == '0')
bus->p->drivers_autoprobe = 0;
else
bus->p->drivers_autoprobe = 1;
return count;
}
写操作就会改变bu