(一)Kobject & Kset
Sysfs文件系统:
"sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel data structures, their attributes, and the linkages between them to userspace.”
--- documentation/filesystems/sysfs.txt
Linux2.6内核引入了 sysfs 文件系统。sysfs 被看成是与 proc同类别的文件系统。sysfs 把连接在系统上的设备和总线组织成分级的文件,使其从用户空间可以访问到。
Sysfs 被加载在 /sys/ 目录下,它的子目录包括:
-
- Block:在系统中发现的每个块设备在该目录下对应一个子目录。每个子目录中又包含一些属性文件,它们描述了这个块设备的各方面属性,如:设备大小。(loop块设备是使用文件来模拟的)
- Bus:在内核中注册的每条总线在该目录下对应一个子目录, 如:ide pci scsi usb pcmcia 其中每个总线目录内又包含两个子目录:devices 和 drivers , devices目录包含了在整个系统中发现的属于该总线类型的设备,drivers目录包含了注册到该总线的所有驱动。
- Class:将设备按照功能进行的分类,如/sys/class/net目录下包含了所有网络接口
- Devices:包含系统所有的设备。
- Kernel:内核中的配置参数
- Module:系统中所有模块的信息
- Firmware:系统中的固件
- Fs: 描述系统中的文件系统
- Power:系统中电源选项
Kobject
Kobject 实现了基本的面向对象管理机制,是构成Linux2.6设备模型的核心结构。它与sysfs文件系统紧密相连,在内核中注册的每个kobject对象对应sysfs文件系统中的一个目录。
类似于C++中的基类,Kobject常被嵌入于其他类型(即:容器)中。如bus,devices, drivers 都是典型的容器。这些容器通过kobject连接起来,形成了一个树状结构。
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent; //指向父对象
struct kset *kset;
struct kobj_type *ktype;
struct sysfs_dirent *sd;
struct kref kref; //对象引用计数
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
};
Kobject操作:
void kobject_init(struct kobject * kobj)
初始化kobject结构
int kobject_add(struct kobject * kobj)
将kobject对象注册到Linux系统
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...)
初始化kobject,并将其注册到linux系统
void kobject_del(struct kobject * kobj)
从Linux系统中删除kobject对象
struct kobject *kobject_get(struct kobject *kobj)
将kobject对象的引用计数加1,同时返回该对象指针。
void kobject_put(struct kobject * kobj)
将kobject对象的引用计数减1,如果引用计数降为0,则调用release方法释放该kobject对象。
Struct kobj_type:
Kobject的ktype成员是一个指向kobj_type结构的指针,该结构中记录了kobject对象的一些属性。
struct kobj_type {
void (*release)(struct kobject *kobj);
struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
};
release:
用于释放kobject占用的资源,当kobject的引用计数为0时被调用。
Struct attribute:
struct attribute {
char * name; /*属性文件名*/
struct module * owner;
mode_t mode; /*属性的保护位*/
};
struct attribute (属性):
对应于kobject的目录下的一个文件,Name成员就是文件名
Struct sysfs_ops:
struct sysfs_ops
{
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *,size_t);
};
-
- Show:当用户读属性文件时,该函数被调用,该函数将属性值存入buffer中返回给用户态;
- Store:当用户写属性文件时,该函数被调用,用于存储用户传入的属性值。
实例分析:
Kobject.c
Kset
kset是具有相同类型的kobject的集合,在sysfs中体现成一个目录,在内核中用kset数据结构表示,定义为:
struct kset {
struct list_head list; //连接该kset中所有kobject的链表头
spinlock_t list_lock;
struct kobject kobj; //内嵌的kobject
struct kset_uevent_ops *uevent_ops; //处理热插拔事件的操作集合
}
Kset操作:
int kset_register(struct kset *kset)
在内核中注册一个kset
void kset_unregister(struct kset *kset)
从内核中注销一个kset
热插拔事件:
在Linux系统中,当系统配置发生变化时,如:添加kset到系统;移动kobject, 一个通知会从内核空间发送到用户空间,这就是热插拔事件。热插拔事件会导致用户空间中相应的处理程序(如udev,mdev)被调用, 这些处理程序会通过加载驱动程序, 创建设备节点等来响应热插拔事件。
操作集合:
Struct kset_uevent_ops {
int (*filter)(struct kset *kset, struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj);
int (*uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
}
kset_uevent_ops:
这三个函数什么时候调用?
-
- 当该kset所管理的kobject和kset状态发生变化时(如被加入,移动),这三个函数将被调用。(例:kobject_uevent调用)
这三个函数的功能是什么?
-
- filter:决定是否将事件传递到用户空间。如果 filter 返回 0,将不传递事件。(例: uevent_filter)
- name:用于将字符串传递给用户空间的热插拔处理程序。
- uevent:将用户空间需要的参数添加到环境变量中。(例:dev_uevent)
Kset.c
(二)设备模型
随着技术的不断进步,系统的拓扑结构也越来越复杂,对智能电源管理、热插拔的支持要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,
Linux 2.6内核提供了全新的内核设备模型。
设备模型元素
- 总线
- 驱动
- 设备
总线
总线是处理器和设备之间的通道,在设备模型中, 所有的设备都通过总线相连, 甚至是内部的虚拟“platform”总线。 在 Linux 设备模型中, 总线由 bus_type 结构表示, 定义在 <linux/device.h>
总线描述
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;
}
总线注册/删除
总线的注册使用:
bus_register(struct bus_type * bus)
若成功,新的总线将被添加进系统,并可在sysfs 的 /sys/bus 下看到。
总线的删除使用:
void bus_unregister(struct bus_type *bus)
总线方法
int (*match)(struct device * dev, struct device_driver * drv)
当一个新设备或者驱动被添加到这个总线时,该方法被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零值
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);
}
创建属性
int bus_create_file(struct bus_type *bus,struct bus_attribute *attr)
删除属性
void bus_remove_file(struct bus_type*bus, struct bus_attribute *attr)
设备
设备描述
Linux 系统中的每个设备由一个 struct device 描述:
struct device {
…… …… …… …… …… ……
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /*在总线上唯一标识该设备的字符串 */
struct bus_type *bus; /* 设备所在总线 */
struct device_driver *driver; /*管理该设备的驱动*/
void *driver_data; /*该设备驱动使用的私有数据成员 *
struct klist_node knode_class;
struct class *class;
struct attribute_group **groups;
void (*release)(struct device *dev);
}
设备注册
int device_register(struct device *dev)
注册设备
void device_unregister(struct device *dev)
注销设备
**一条总线也是个设备,也必须按设备注册**
设备属性
设备属性由struct device_attribute 描述:
struct device_attribute
{
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute
*attr,char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
}
int device_create_file(struct device*device, struct device_attribute * entry)
创建属性
void device_remove_file(struct device *dev, struct device_attribute * attr)
删除属性
驱动
驱动描述
驱动程序由struct device_driver 描述 :
struct device_driver {
const char *name; /*驱动程序的名字( 体现在 sysfs 中 )*/
struct bus_type *bus; /*驱动程序所在的总线*/
struct module *owner;
const char *mod_name;
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;
}
驱动注册/注销
int driver_register(struct device_driver *drv)
注册驱动
void driver_unregister(struct device_driver *drv)
注销驱动
驱动属性
驱动的属性使用struct driver_attribute 来描述:
struct driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *drv,
char *buf);
ssize_t (*store)(struct device_driver *drv,
const char *buf, size_t count);
}
int driver_create_file(struct device_driver * drv,struct driver_attribute * attr)
创建属性
void driver_remove_file(struct device_driver * drv,struct driver_attribute * attr)
删除属性
Platform总线
Platform总线是linux2.6内核加入的一种虚拟总线。platform机制的本身使用并不复杂,由两部分组成:
platform_device和platform_driver
Platform 驱动与传统的设备驱动模型相比,优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。
platform_device
平台设备描述
平台设备使用Struct Platform_device来描述:
struct platform_device {
const char *name; /*设备名*/
int id; /*设备编号,配合设备名使用*/
struct device dev;
u32 num_resources;
struct resource *resource; /*设备资源*/
}
Struct Platform_device的分配使用:
struct platform_device *platform_device_alloc(const char *name, int id)
参数:
-
-
- name: 设备名
- id: 设备id,一般为-1
-
平台设备注册
注册平台设备,使用函数:
int platform_device_add(struct platform_device *pdev)
设备资源
平台设备资源使用struct resource来描述:
struct resource {
resource_size_t start; //资源的起始物理地址
resource_size_t end; //资源的结束物理地址
const char *name; //资源的名称
unsigned long flags; //资源的类型,比如MEM,IO,IRQ类型
struct resource *parent, *sibling, *child; //资源链表指针
}
设备资源-例
static struct resource s3c_wdt_resource1 = {
.start = 0x44100000,
.end = 0x44200000,
.flags = IORESOURCE_MEM,
}
static struct resource s3c_wdt_resource2 = {
.start = 20,
.end = 20,
.flags = IORESOURCE_IRQ,
}
获取资源
struct resource *platform_get_resource(struct platform_device*dev, unsigned int type, unsigned int num)
参数:
-
- dev: 资源所属的设备
- type: 获取的资源类型
- num: 获取的资源数
例:
platform_get_resource(pdev, IORESOURCE_IRQ, 0)获取中断号
platform_driver
平台驱动描述
平台驱动使用struct platform_driver 描述:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
}
平台驱动注册
平台驱动注册使用函数:
int platform_driver_register(struct platform_driver *)
版权说明:
内容由网上找到的一套国嵌的培训视频整理而来