linux设备模型学习参考

欢迎进入Linux社区论坛,与200万技术人员互动交流 >>进入

  看LDD3中设备模型一章,觉得思维有些混乱。这里从整体的角度来理理思路。

  本文从四个方面来总结一些内容:

  1.底层数据结构:kobject,kset.

  2.linux设备模型层次关系:bus_type,device,device_driver.

  3.集成:PCI设备驱动模型实例及设备,设备驱动注册源码的简单分析.

  4.面向对象的思想在linux设备模型中的应用分析.

  一、底层数据结构:kobject,kset

  先说说模型的意义:

  总体来说是为了系统地管理所有设备。

  在具体实现方面分两个层次:

  一是底层数据结构来实现基本对象及其层次关系:kobjects和ksets。

  二是基于这两个底层数据结构上实现的设备模型:总线,设备,驱动。

  kobject

  结合面向对象的思维。这个kobject属于最基础的结构,也就是最高抽象层(有点像java中的Cobject类)。任何一个设备模型如总线,设备,驱动都属于一个kobject 。在实现上这种派生关系就是在结构体中包含一个kobject的变量。

  这个在层次上处理最顶层的kobject结构提供了所有模型需要的最基本的功能:

  1 引用计数 用于内核维护其存在与消亡

  2 sysfs表示 每个sys/下的对象对应着一个kobject。

  3 热拔插事件处理。 处理设备的热拔插事件。

  Kobjects 在内核中对应有一套申请,初始化,添加,注册,计数操作,释放等函数

  struct kobject {

  const char * k_name; 名

  char name[KOBJ_NAME_LEN];

  struct kref kref; 计数

  struct list_head entry; 用于连接到同类kobjects的链表

  struct kobject * parent; 用于实现层次,指向其父对象。

  struct kset * kset; 用于实现层次,所属的集合

  struct kobj_type * ktype; 指向对象的类型。

  struct dentry * dentry; 指示在sysfs 中的目录项

  wait_queue_head_t poll;

  }; (linux 2.6.18)

  Kset 和kobj_type

  Kset 在概念上是一个集合或者叫容器。实现了对象的层次。所有属于一个ksets的对象(kobject)的parent都指向该ksets的kobj.同时这个对象都连接到kset 的list表上。同时位于ksets层次之上的是subsys,在最新的内核中已经取消subsys,因为它本质上也就是一个ksets。Kset有一套类似kobject的操作,实现上只是进一步调用其自身kobj的相应操作,毕竟ksets本质上也是一个kobject。

  struct kset {

  struct subsystem * subsys; 在最新内核中已经没有subsys概念了。统一用ksets

  struct kobj_type * ktype; 类型。

  struct list_head list; 同一kset的链表

  spinlock_t list_lock;

  struct kobject kobj; 自身的kobjects

  struct kset_uevent_ops * uevent_ops;

  };(linux 2.6.18)

  最后 属于同一个集合的对象可以拥有共同的属性:ktype 。

  struct kobj_type {

  void (*release)(struct kobject *);

  struct sysfs_ops * sysfs_ops;

  struct attribute ** default_attrs;

  };

  所谓的属性更具体一点说就是一些键值对。并且在sysfs_ops中的show函数被文件系统调用来显示sys/下面对应入口各属性的值。

  如此 ,kobjects与ksets实现层次树的底层骨架。

  进一步地,通过封装这些底层结构来实现上层的设备驱动模型。

  内核设备驱动模型层次划分三个方面:总线,设备,驱动。

  二、linux设备模型层次关系:bus_type,device,device_driver

  基本关系简要的概括如下:

  驱动核心可以注册多种类型的总线。

  每种总线下面可以挂载许多设备。(通过kset devices)

  每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}

  每个驱动可以处理一组设备。

  这种基本关系的建立源于实际系统中各种总线,设备,驱动结构的抽象。

  下面看看三者数据结构的定义。

  首先是总线,bus_type.

  struct bus_type {

  const char * name;

  struct subsystem subsys;//代表自身

  struct kset drivers; //当前总线的设备驱动集合

  struct kset devices; //所有设备集合

  struct klist klist_devices;

  struct klist klist_drivers;

  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, char **envp,

  int num_envp, char *buffer, int buffer_size);//热拔插事件

  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 (*resume)(struct device * dev);

  };

  这是2.6.18的定义。源码能说明一切。下面是设备device的定义:

  struct device {

  struct device * parent; //父设备,一般一个bus也对应一个设备。

  struct kobject kobj;//代表自身

  char bus_id[BUS_ID_SIZE];

  struct bus_type * bus; /* 所属的总线 */

  struct device_driver *driver; /* 匹配的驱动*/

  void *driver_data; /* data private to the driver 指向驱动 */

  void *platform_data; /* Platform specific data,由驱动定义并使用*/

  ///更多字段忽略了

  };

  下面是设备驱动定义:

  struct device_driver {

  const char * name;

  struct bus_type * bus;//所属总线

  struct completion unloaded;

  struct kobject kobj;//代表自身

  struct klist klist_devices;//设备列表

  struct klist_node knode_bus;

  struct module * owner;

  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 (*resume) (struct device * dev);

  };

  OK。基本的东西弄明白了。通过PCI驱动中设备模型的实例来看看细节。

[1][2][3]

坦然接受生活给你的馈赠吧,不管是好的还是坏的。

linux设备模型学习参考

相关文章:

你感兴趣的文章:

标签云: