linux设备模型浅析

Linux设备模型解析

linux设备模型浅析  

2012-10-16 22:22:32|  分类: 默认分类 |  标签:linux设备模型  |字号 订阅

 说明:基于linux-2.6.30.4的内核源码

一、linux设备模型作用

       Linux 2.6内核最初为了应付电源管理的需要,提出了一个设备模型来管理所有的设备。在物理上,外设之间是有一种层次关系的,比如把一个U盘插到笔记本上,实际上这个U盘是接在一个USB Hub上,USB Hub又是接在USB 2.0 Host Controller (EHCI)上,最终EHCI又是一个挂在PCI Bus上的设备。这里的一个层次关系是:PCI->EHCI->USB Hub->USB Disk。如果操作系统要进入休眠状态,首先要逐层通知所有的外设进入休眠模式,然后整个系统才可以休眠。因此,需要有一个树状的结构可以把所有的外设组织起来。这就是最初建立Linux设备模型的目的。

      当然,Linux设备模型给我们带来的便利远不止如此。既然已经建立了一个组织所有设备和驱动的树状结构,用户就可以通过这棵树去遍历所有的设备建立设备和驱动程序之间的联系,根据类型不同也可以对设备进行归类,这样就可以更清晰的去“看”这颗枝繁叶茂的大树。另外,Linux驱动模型把很多设备共有的一些操作抽象出来,大大减少了重复造轮子的可能。同时Linux设备模型提供了一些辅助的机制,比如引用计数,让开发者可以安全高效的开发驱动程序。达成了以上这些好处之后,我们还得到了一个非常方便的副产品,这就是sysfs----一个虚拟的文件系统。sysfs给用户提供了一个从用户空间去访问内核设备的方法,它在Linux里的路径是/sys。

二、linux设备模型的构成

      linux设备模型对外封装后提供给我们使用的一般是:struct bus_type(总线),struct device(设备),struct device_driver (驱动)这三个结构体:即经典的总线、设备、驱动模型

      每个bus_type对象都对应/sys/bus目录下的一个子目录,如PCI总线类型对应于/sys/bus/pci。在每个这样的目录下都存在两个子目录:devices和drivers(分别对应于bus type结构中的devices和drivers域)。其中devices子目录描述连接在该总线上的所有设备,而drivers目录则描述与该总线关联的所有驱动程序。与device_driver对象类似,bus_type结构还包含几个函数(match()、hotplug()等)处理相应的热插拔、即插即拔和电源管理事件。

      系统中的任一设备在设备模型中都由一个device对象描述。内核提供了相应的函数用于操作device对象。其中device_register()函数将一个新的device对象插入设备模型,并自动在/sys/devices下创建一个对应的目录。device_unregister()完成相反的操作,注销设备对象。get_device()和put_device()分别增加与减少设备对象的引用计数。通常device结构不单独使用,而是包含在更大的结构中作为一个子结构使用,比如描述PCI设备的struct pci_dev结构体里面就内嵌一个struct device。

       系统中的每个驱动程序由一个device_driver对象描述。与device 结构类似,device_driver对象依靠内嵌的kobject对象实现引用计数管理和层次结构组织。内核提供类似的函数用于操作device_driver对象,如get_driver()增加引用计数,driver_register()用于将一个新的driver对象插入设备模型,并自动在/sys/drivers下创建一个对应的目录。device_driver()结构还包括几个函数,用于处理热拔插、即插即用和电源管理事件。

三、linux设备模型的操作流程

       1、注册总线:总线是设备和驱动挂载的地方,总线中有加入该总线的设备列表和驱动列表,这些用于管理加入总线中的设备。

       2、向设备模型(总线)中加入设备/驱动:加入设备使用device_register(device_add将被调用),加入驱动一般使用driver_register(driver_add被调用)

       3、设备和驱动的首次匹配:加入新的设备/驱动后,会导致总线的match函数被调用,用来检查这个新加入的设备/驱动,在总线已有的驱动/设备中有没有跟它匹配的。

       4、驱动的probe函数的再次检查:在总线的match函数匹配成功后会调用驱动的probe探测函数做进一步细致的匹配工作。如果不出什么问题,这个驱动/设备就算成功加入到这个总线当中(设备模型)

struct bus_type {

      const char         *name;//总线的名称

      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;//总线的私有数据

};

struct device {

      struct device           *parent; //设备的父设备

      struct device_private *p;//设备的私有数据

      struct kobject kobj;

      const char         *init_name;

      struct device_type    *type;//设备的类型

      struct semaphore     sem;//信号量,用于同步访问驱动

      struct bus_type  *bus;    //设备挂接的总线的类型

      struct device_driver *driver;  //设备的驱动

      void      *driver_data;     /* data private to the driver */

      void      *platform_data; /* Platform specific data, device core doesn't touch it */

      struct dev_pm_info  power;

 #ifdef CONFIG_NUMA

      int        numa_node;      /* NUMA node this device is close to */

#endif

      u64      *dma_mask;     /* dma mask (if dma'able device) */

      u64      coherent_dma_mask ;

      struct device_dma_parameters *dma_parms;

      struct list_head  dma_pools; /* dma pools (if dma'ble) */

      struct dma_coherent_mem   *dma_mem;     

      struct dev_archdata  archdata;

      dev_t               devt;    //设备号,驱动程序的号码

      spinlock_t         devres_lock;

      struct list_head  devres_head;

      struct klist_node knode_class;

      struct class        *class;

      struct attribute_group     **groups;   /* optional groups */

      void      (*release)(struct device *dev);

}

  struct device_driver {

      const char         *name;//驱动的名字

      struct bus_type       *bus; //驱动挂接的总线

      struct module          *owner;

      const char        *mod_name;     /* used for built-in modules */

      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);

      struct attribute_group **groups; //驱动支持的设备集合(推测)

      struct dev_pm_ops *pm;

      struct driver_private *p;

};

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值