您的位置:首页 > 运维架构 > Linux

linux设备模型浅析

2013-01-01 17:00 288 查看


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;

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: