天天看点

Linux设备模型(中)之上层容器

基本概念 总线 

Linux设备模型是由总线(bus_type),设备(device),驱动(device_driver)这三个数据结构来描述的。

总线是处理器和一个或多个设备之间的通道。

在设备模型中, 所有的设备都通过总线相连, 甚至是内部的虚拟“platform”总线(下一篇介绍),注意,这里设备模型中只是为个更好方便管理,所以有些总线是pic,i2c,usb等,但都只是一个分类的名字而已,但有些比如s3c2440上集成的控制器(lcd,watchdog,rtc等),platform所描述的资源有一个共同点,就是在cpu的总线上直接取址,所以Linux定义了一个给别的找不到很明显属于哪个总线的设备所属的平台总线(platform),来维持总线,驱动,设备的关系。

总线可以相互插入。设备模型展示了总线和它们所控制的设备之间的实际连接。

 bus_type (总线)

 Linux 设备模型中, 总线由 bus_type 结构表示

 每个bus_type对象都对应/sys/bus目录下的一个子目录,如PCI总线类型对应于/sys/bus/pci。

 在每个这样的目录下都存在两个子目录:devices和drivers(分别对应于bustype结构中的devices和drivers域)。

 devices子目录描述连接在该总线上的所有设备

 Drivers子目录描述与该总线关联的所有驱动程序。

 bus_type结构还包含几个函数(match、hotplug等)处理相应的热插拔、即插即拔和电源管理事件。

01.struct bus_type {  
02.    const char      *name;       //总线类型的名称   
03.    struct bus_attribute    *bus_attrs;  //总线属性   
04.    struct device_attribute *dev_attrs;  //设备属性   
05.    struct driver_attribute *drv_attrs;  //驱动属性   
06.    int (*match)(struct device *dev, struct device_driver *drv);  
07.    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  
08.    int (*probe)(struct device *dev);  
09.    int (*remove)(struct device *dev);  
10.    void (*shutdown)(struct device *dev);  
11.    int (*suspend)(struct device *dev, pm_message_t state);  
12.    int (*suspend_late)(struct device *dev, pm_message_t state);  
13.    int (*resume_early)(struct device *dev);  
14.    int (*resume)(struct device *dev);  
15.    struct dev_pm_ops *pm;  
16.    struct bus_type_private *p;  
17.};  
           

int (*match)(struct device *device, struct device_driver *driver);

无论何时一个新设备或者驱动被添加给这个总线.如果给定的设备可被给

定的驱动处理,这个方法应当返回一个非零值 . 这个函数必须在总线级别

处理, 因为那是合适的逻辑存在的地方; 核心内核不能知道如何匹配每个

可能总线类型的设备和驱动.

这个函数只是简单对比驱动和设备的名字是不是相同而已,来匹配驱动和设备。 所以某个驱动和某个设备一定要同名才能让它们匹配起来。

int (*uevent)(struct device *dev, char **envp, int num_envp,

char *buffer, int buffer_size)

在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量。

总线属性由bus_attribute  结构描述,定义如下:

struct bus_attribute {
struct attribute
attr;
ssize_t (*show)(struct bus_type *, char * buf);
ssize_t (*store)(struct bus_type *, const char *
buf, size_t count);
}
           

需要注意的是,总线也是设备,也必须按设备注册

总线的注册使用:

bus_register(struct bus_type * bus)

若成功,新的总线将被添加进系统,并可在sysfs 的 /sys/bus 下看到。

总线的删除使用:

void bus_unregister(struct bus_type *bus)

  device(设备)

Linux 系统中的每个设备由一个 device对象描述

g_list 将该device对象挂接到全局设备链表中,所有的 device对象都包含在devices subsys中,并组织成层次结构。

 Node域将该对象挂接到其兄弟对象的链表中

 bus list则用于将连接到相同总线上的设备组织成链表

 driver list则将同一驱动程序管理的所有设备组织为链表。

Device对象内嵌一个kobject对象,用于引用计数管理并通过它实现设备层次结构。

 Driver域指向管理该设备的驱动程序对象,而 driver data则是提供给驱动程序的数据。

 Bus域描述设备所连接的总线类型。

内核提供了相应的函数用于操作device对象。

device_register()函数将一个新的device对象插入设备模型,并自

动在/sys/devices下创建一个对应的目录。

device_unregister()完成相反的操作,注销设备对象。 get_device()和put_device()分别增加与减少设备对象的引用计数。

 通常device结构不单独使用,而是包含在更大的结构中作为一个子结构使用,比如描述PCI设备的struct pci_dev

driver(驱动)

系统中的每个驱动程序由一个device_driver对象描述

struct device_driver {
char *name; 设备驱动程序的名称
struct bus_type *bus; 该驱动所管理的设备挂接的总线类型
struct kobject kobj; 内嵌kobject对象
struct list_head devices; 该驱动所管理的设备链表头
int (*probe)(struct device *dev); 指向设备探测函数,用于探测设备
是否可以被该驱动程序管理
int (*remove)(struct device *dev); 用于删除设备的函数
};

           

device_driver对象依靠内嵌的kobject对象实现引用计数管理和层次结构组织。

 对大多数驱动程序核心结构, device_driver 结构通常被嵌入到一个更高层的、总线相关的结构中。

注册与注销函数是:

 int driver_register(struct device_driver *drv);

 void driver_unregister(struct device_driver *drv);

继续阅读