您现在的位置: 万盛学电脑网 >> 程序编程 >> 服务器教程 >> 正文

linux驱动编程--设备模型

作者:佚名    责任编辑:admin    更新时间:2022-06-22

   在前面学习了 kobject和 kset之后,就迫不及待的想开始“研究”设备模型了。经过这几天的学习,感觉受益匪浅。所以就将自己的理解整理了下来

  想要完成一个设备的驱动,就要涉及三部分: Bus, device, driver。当然这些“新”节点都是最终继承于kobject。

  一.Bus

  这里先整理一下BUS,总线负责在设备与驱动间建立连接,包括 I2C, PCI, 串口,platform等。其中platform是虚拟总线。

  1.1 结构体

  信息结构体是 bus_type.

  struct bus_type {

  const char *name; //the name of bus

  struct bus_attribute *bus_attrs;

  //attribute for bus, contain attribute file and some operate function.

  // this is a interface between kernel space and user space.

  struct device_attribute *dev_attrs; //attribute for device,

  struct driver_attribute *drv_attrs; //attribute for deriver

  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; //power manage

  struct bus_type_private *p;

  //private data for bus. In fact, it is core of this structure

  };

  在其中 bus_attrs, dev_attrs 和 drv_attrs记录了该总线的一些属性信息,而最重要的被用来构建该总线的逻辑结构的信息都记录在了bus_type_private中。对应这个总线私有数据结构体的解析如下。

  struct bus_type_private {

  struct kset subsys;

  //there are two points:

  //1).this is a set. It is contain some devices and derivers about this bus.

  //2). it's parent is @bus_kset, which is the root of all other bus.@bus_kset have many subset, this is just one of them.

  //

  struct kset *drivers_kset;

  //all drivers about this bus will belong to this set.

  struct kset *devices_kset;

  //all devices of this bus will belong to this set.

  struct klist klist_devices;

  struct klist klist_drivers;

  //they are two lists , for mount all corresponding nodes.

  struct blocking_notifier_head bus_notifier;

  unsigned int drivers_autoprobe:1;

  //is this bus automaticly run when a new devices arrvied.

  //sometime, we can see some attribute files in user space.(for example:@drivers_autoprobe).

  //it is interface that kernel leave user to modify this argument.

  struct bus_type *bus;

  //just a port for return this bus.

  };

  其中的klist_devices, klist_drivers 链表会用来挂载该总线的设备与驱动。当需要找东西的时候就会去俩面翻。而上面的两个kset 分别是它们所属的集合。不同的集合对应于不同的操作特性。这是一种很给力的组织结构。就拿这里来说,我们用kobject来组织了一个二维链表(或其他什么数据结构),每个kobject在这个链表中充当了一个节点。但又想让其中指定的一些kobject节点具有一些属性。kset相当于kobject的属性。它包含了进行事件通知需要的一些数据信息。每当kobject有需要时,就会去找到自己所属的kset,或者上级kobject的kset来用。

  1.2 重要函数分析

  对于总线的注册需要使用到如下函数,通过分析它的行为对于理解bus_type的逻辑结构是很有帮助。

  /**

  * bus_register - register a bus with the system.

  * @bus: bus.

  *

  * Once we have that, we registered the bus with the kobject

  * infrastructure, then register the children subsystems it has:

  * the devices and drivers that belong to the bus.

  */

  int bus_register(struct bus_type *bus)

  {

  int retval;

  struct bus_type_private *priv;

  //alloc a private data package for @bus. It is the core of this structure,

  //include device list, deriver list and so on.

  priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);

  if (!priv)

  return -ENOMEM;

  priv->bus = bus;

  bus->p = priv;

  BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

  // before we keep on, what we should to know is that this bus is one of members of the great building,

  //so it must be inherit form @kobject.

  //and @(priv->subsys.kobj) is it's kobject.

  retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);

  if (retval)

  goto out;

  priv->subsys.kobj.kset = bus_kset; //1).@bus_kset is the root of all buses. 2). this structure is the type of bus.

  priv->subsys.kobj.ktype = &bus_ktype; //corresponding operation function for bus

  priv->drivers_autoprobe = 1; //automaticly probe when new device arrived.

  retval = kset_register(&priv->subsys);

  if (retval)

  goto out;

  retval = bus_create_file(bus, &bus_attr_uevent); //create attribute file for bus,it is a interface between user space and kernel space.

  if (retval)

  goto bus_uevent_fail;

  //给该总线创建一个设备子集,it is the set of all devices about this bus.

  //在文件系统中的表现就是在该总线的目录下多了一个名字叫"devices"的子目录

  //还需要提醒的一点就是:设备模型中的层次结构关系都是由kobject对象来指定,所以凡是属于这个设备模型的节点必须要继承kobject.

  priv->devices_kset = kset_create_and_add("devices", NULL,

  &priv->subsys.kobj);

  if (!priv->devices_kset) {

  retval = -ENOMEM;

  goto bus_devices_fail;

  }

  //create a deriver set for this bus

  priv->drivers_kset = kset_create_and_add("drivers", NULL,

  &priv->subsys.kobj);

  if (!priv->drivers_kset) {

  retval = -ENOMEM;

  goto bus_drivers_fail;

  }

  //thoes two list is used to mount some nodes. device-node or deriver-node.

  klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

  klist_init(&priv->klist_drivers, NULL, NULL);

  //create attribute file for this structure

  retval = add_probe_files(bus);

  if (retval)

  goto bus_probe_files_fail;

  retval = bus_add_attrs(bus); //create attribute file for @bus_attr

  if (retval)

  goto bus_attrs_fail;

  pr_debug("bus: '%s': registeredn", bus->name);

  return 0;

  bus_attrs_fail:

  remove_probe_files(bus);

  bus_probe_files_fail:

  kset_unregister(bus->p->drivers_kset);

  bus_drivers_fail:

  kset_unregister(bus->p->devices_kset);

  bus_devices_fail:

  bus_remove_file(bus, &bus_attr_uevent);

  bus_uevent_fail:

  kset_unregister(&bus->p->subsys);

  kfree(bus->p);

  out:

  bus->p = NULL;

  return retval;

  }

  在函数体中已经对行为进行了较详细的分析。

  1.3 device_bind_driver

  那么device到底又是怎么和一个driver进行绑定的呢?让它们在需要时能找到彼此

  //bind a driver to one device.

  int device_bind_driver(struct device *dev)

  {

  int ret;

  ret = driver_sysfs_add(dev);

  if (!ret)

  driver_bound(dev);

  return ret;

  }

  //这个函数是在设备已经绑定驱动之后使用,

  static voi