日期:2014-05-16  浏览次数:20691 次

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