免费咨询热线
13621929115Linux设备模型是对系统设备组织架构进行抽象的一个数据结构,旨在为设备驱动进行分层、分类、组织降低设备多样性带来的Linux驱动开发的复杂度,以及设备热拔插处理、电源管理等Overview设计目的电源管理和系统关机(Power management and system shutdown)
设备之间工厂设备沙盘大多情况下有依赖、耦合,因此要实现电源管理就必须对系统的设备结构有清楚的理解,应知道先关哪个然后才能再关哪个设计设备模型就是为了使系统可以按照正确顺序进行硬件的遍历与用户空间的交互(Communications with user space)。
实现了sysfs虚拟文件系统它可以将设备模型中定义的设工厂设备沙盘备属性信息等导出到用户空间,使得在用户空间可以实现对设备属性的访问及参数的更改详见Documentation/filesystems/sysfs.txt。
可热插拔设备(Hotpluggable devices)设备模型管理内核所使用的处理用户空间热插拔的机制,支持设备的动态添加与移除设备类别(Dev工厂设备沙盘ice classes)系统的许多部分对设备如何连接没有兴趣, 但是它们需要知道什么类型的设备可用。
设备模型也实现了一个给设备分类的机制, 它在一个更高的功能性级别描述了这些设备对象生命期(Object lifecycles)设备模型的实现一套机制来处理对象生命期设备模型框图Linux 设备模型是一工厂设备沙盘个复杂的数据结构。
如图所示为和USB鼠标相关联的设备模型的一小部分:
这个框图展示了设备模型最重要的四个部分的组织关系(在顶层容器中详解):Devices描述了设备如何连接到系统Drivers系统中可用的驱动Buses跟踪什么连接到每个总线,负责匹配设备与驱动classes。
设备底层细节的抽象,描述了工厂设备沙盘设备所提供的功能底层实现kobject作用与目的Kobject是将整个设备模型连接在一起的基础主要用来实现以下功能:对象的引用计数(Reference counting of objects)。
通常, 当一个内核对象被创建, 没有方法知道它会存在多长时间 一种跟踪这种对象生命周期的方法是通过引用计数工厂设备沙盘 当没有内核代码持有对给定对象的引用, 那个对象已经完成了它的有用寿命并且可以被删除sysfs 表示(Sysfs representation)。
在sysfs中显示的每一个项目都是通过一个与内核交互的kobject实现的数据结构粘和(Data structure glue)设备模型整体来看是一个极端工厂设备沙盘复杂的由多级组成的数据结构, kobject实现各级之间的连接粘和。
热插拔事件处理(Hotplug event handling)kobject处理热插拔事件并通知用户空间数据结构/* include in */struct kobject { 。
constchar *name; /* 该ko工厂设备沙盘bject的名称,同时也是sysfs中的目录名称 */struct list_head entry; /* kobjetct双向链表 */struct kobject *parent;
/* 指向kset中的kobject,相当于指向父目录 */struct kset *kset; /*指向所属的ks工厂设备沙盘et*/struct kobj_type *ktype; /*负责对kobject结构跟踪*/
...
};/* 定义kobject的类型及释放回调 */struct kobj_type { void (*release)(struct kobject *); /* kobjec工厂设备沙盘t释放函数指针 */
struct sysfs_ops *sysfs_ops; /* 默认属性操作方法 */struct attribute **default_attrs; /* 默认属性 */};/* kobject上层容器 */
struct kset {
struc工厂设备沙盘t list_head list; /* 用于连接kset中所有kobject的链表头 */spinlock_t list_lock; /* 扫描kobject组成的链表时使用的锁 */
struct kobject kobj; /* 嵌入的kobject */conststruct kset_uev工厂设备沙盘ent_ops *uevent_ops; /* kset的uevent操作 */};/* 包含kset的更高级抽象 */
struct subsystem { struct kset kset; /* 定义一个kset */struct rw_semaphore rwsem; /* 用于串行访问工厂设备沙盘kset内部链表的读写信号量 */
};kobject和kset关系:
如图所示,kset将它的children(kobjects)组成一个标准的内核链表所以说kset是一个包含嵌入在同种类型结构中的kobject的集合它自身也内嵌一个kobject,所以也是一个特殊的kobject。
设计kset的主要工厂设备沙盘目的是容纳,可以说是kobject的顶层容器kset总是会在sysfs中以目录的形式呈现需要注意的是图中所示的kobject其实是嵌入在其他类型中(很少单独使用),也可能是其他kset中。
kset和subsystem关系:一个子系统subsystem, 其实只是一个附加了个读写信号量的kset的包装工厂设备沙盘,反过来就是说每个 kset 必须属于一个子系统根据subsystem之间的成员关系建立kset在整个层级中的位置。
子系统常常使用宏直接静态定义:/* 定义一个struct subsystem name_subsys 并初始化kset的type及hotplug_ops */
d工厂设备沙盘ecl_subsys(name,
struct kobj_type *type,struct kset_hotplug_ops *hotplug_ops);操作函数初始化/* 初始化kobject内部结构 */void kobject_init(
struct kobject *kobj);/* 设置n工厂设备沙盘ame */int kobject_set_name(struct kobject *kobj, constchar *format, ...);
/* 先将kobj->kset指向要添加的kset中,然后调用会将kobject加入到指定的kset中 */int kobject_add(struct 工厂设备沙盘kobject *kobj);/* kobject_register = kobject_init + kobject_add */
extern int kobject_register(struct kobject *kobj);/* 对应的Kobject删除函数 */void kobject_d工厂设备沙盘el(struct kobject *kobj)
;void kobject_unregister(struct kobject *kobj);/* 与kobject类似的kset操作函数 */void kset_init(struct kset *kset)
;
kobject_set工厂设备沙盘_name(&my_set->kobj, "The name");int kset_add(struct kset *kset);int kset_register(struct
kset *kset);void kset_unregister(struct kset *kset);Tip: 初始化前工厂设备沙盘应先使用memset将kobj清零;初始化完成后引用计数为1引用计数管理/* 引用计数加1并返回指向kobject的指针 */
struct kobject *kobject_get(struct kobject *kobj);/* 当一个引用被释放, 调用kobject_put递减引用计数,当引用为工厂设备沙盘0时free这个object */
void kobject_put(struct kobject *kobj);/* 与kobject类似的kset操作函数 */struct kset *kset_get(struct kset *kset)
;void kset_put(struct kset *k工厂设备沙盘set);释放当引用计数为0时,会调用ktype中的release,因此可以这样定义release回调函数:void my_object_release(
struct kobject *kobj){ struct my_object *mine = container_of(kobj, str工厂设备沙盘uct my_object, kobj); /* Perform any additional cleanup on this object, then... */
kfree(mine);
}/* 查找ktype */struct kobj_type *get_ktype(st工厂设备沙盘ruct kobject *kobj);subsystem相关decl_subsys(name, type, hotplug_ops);
void subsystem_init(struct subsystem *subsys);int subsystem_register(struct subsys工厂设备沙盘tem *subsys);void subsystem_unregister(
struct subsystem *subsys);struct subsystem *subsys_get(struct subsystem *subsys);void subsys_put(struct
subsyste工厂设备沙盘m *subsys);Low-Level Sysfs Operationskobject和sysfs关系kobject是实现sysfs虚拟文件系统背后的机制sysfs中的每一个目录都对应内核中的一个kobject。
将kobject的属性(atrributes)导出就会在sysfs对应的目录下产生由内工厂设备沙盘核自动生成的包含这些属性信息的文件只需简单的调用前面所提到的kobject_add就会在sysfs中生成一个对应kobject的入口,但值得注意的是:。
这个入口总会以目录呈现, 也就是说生成一个入口就是创建一个目录通常这个目录会包含一个或多个属性文件(见下文)分配给kobject的名字(用kobje工厂设备沙盘ct_set_name)就是给 sysfs 目录使用的名字,因此在sysfs层级中相同部分的kobject命名必须唯一,不能包含下划线,避免使用空格。
这个入口所处的目录表示kobject的parent指针,如果parent为NULL,则指向的是它的kset,因此可以说sysfs的层级其实对应的就是k工厂设备沙盘set的层级但当kset也为NULL时,这个入口就会创建在sysfs的top level,不过实际中很少出现这种情况。
属性(atrributes)属性即为上面所提到的一旦导出就会由内核自动生成的包含kobject内核信息的文件结构如下:struct attribute { char *name工厂设备沙盘; /* 属性名,也是sysfs对应entry下的文件名 */。
struct module *owner; /* 指向负责实现这个属性的模块 */mode_t mode; /* 权限位,在中定义 */};属性的导出显示及导入存储函数:/* kobj: 需要处理的kobject
a工厂设备沙盘ttr: 需要处理的属性
buffer: 存储编码后的属性信息,大小为PAGE_SIZE
return: 实际编码的属性信息长度
*/
struct sysfs_ops { ssize_t (*show)(struct kobject 工厂设备沙盘*kobj, struct attribute *attr,char *buffer); /* 导出到用户空间 */
ssize_t (*store)(struct kobject *kobj, struct attribute *attr,constchar *buffer, size_t size工厂设备沙盘); /* 存储进内核空间 */
};需要注意的是:每个属性都是用name=value表示,name即使属性的文件名,value即文件内容,如果value超过PAGE_SIZE,则应分为多个属性来处理;上述函数可以处理不同的属性可以在内部实现时同过属性名进行区分来实现;。
由于store是从用户空间到内工厂设备沙盘核,所以实现时首先要检查参数的合法行,以免内核崩溃及其他问题缺省属性(Default Attributes)在kobject创建时都会赋予一些缺省的默认属性,即上面所提到的kobj_type中的default_attrs数组,这个数组的最后一个成员须设置成NULL,以表示数组大小。
所有使用这个kob工厂设备沙盘j_type的kobject都是通过kobj_type中的sfsfs_ops回调函数入口实现对缺省属性的定义非缺省属性(Nondefault Attributes)一般来说,定义时就可以通过default_attrs完成所有的属性,但这里也提供了后续动态添加和删除属性的方法:
int sysfs_cr工厂设备沙盘eate_file(struct kobject *kobj, struct attribute *attr); int sysfs_remove_file(struct kobject *kobj,
struct attribute *attr);二进制属性(Binary Attributes)工厂设备沙盘上述属性包含的可读的文本值,二进制属性很少使用,大多用在从用户空间传递一些不改动的文件如firmware给设备的情况下。
struct bin_attribute { struct attribute attr; /* 定义name,owner,mode */size_t siz工厂设备沙盘e; /* 属性最大长度,如没有最大长度则设为0 */
ssize_t (*read)(struct kobject *kobj, char *buffer,loff_t pos, size_t size); ssize_t (*write)(
struct kobject *ko工厂设备沙盘bj, char *buffer,loff_t pos, size_t size);
};read/write一次加载多次调用,每次最多PAGE_SIZE大小。
注意write无法指示最后一个写操作,得通过其他方式判断操作的结束二进制属性不能定义为缺省值,因此需明确的创建工厂设备沙盘与删除:int sysfs_create_bin_file(struct kobject *kobj,
struct bin_attribute *attr); int sysfs_remove_bin_file(struct kobject *kobj,struct bin_attri工厂设备沙盘bute *attr)
;符号连接(Symbolic Links)方法:int sysfs_create_link(struct kobject *kobj, struct kobject *target,char *name)
; void sysfs_remove_link(struct ko工厂设备沙盘bject *kobj, char *name);热插拔事件生成(Hotplug Event Generation)热插拔事件即当系统配置发生改变是内核向用户空间的通知。
然后用户空间会调用/sbin/hotplug通过创建节点、加载驱动等动作进行响应这个热插拔事件的产生是在kobject_add和k工厂设备沙盘object_del时我们可以通过上面kset中定义的uevent_ops对热插拔事件产生进行配置:。
struct kset_uevent_ops { /* 实现事件的过滤,其返回值为0时不产生事件 */int (* const filter)(struct kset *kset, struc工厂设备沙盘t kobject *kobj);
/* 生成传递给/sbin/hotplug的name参数 */constchar *(* const name)(struct kset *kset, struct kobject *kobj);
/* 其他传递给/sbin/hotplug的参数通过这种设置环境变量的工厂设备沙盘方式传递 */int (* const uevent)(struct kset *kset, struct kobject *kobj,
struct kobj_uevent_env *env);
};顶层容器Buses, Devices, Drivers and ClassesBus工厂设备沙盘es总线Buses是处理器和设备的通道在设备模型中,所有设备都是通过总线连接在一起的,哪怕是一个内部虚拟的platform总线。
/* defined in */struct bus_type {
constchar *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);
/*在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量(参数和 kset 的uevent方法相同)*/int (*uevent)(struct工厂设备沙盘
device *dev, struct kobj_uevent_env *env);
... struct subsys_private *p; /* 一个很重要的域,包含了device链表和drivers链表 */
}/* 定义bus_attrs的快捷方式 */B工厂设备沙盘US_ATTR(name, mode, show, store);/* bus属性文件的创建移除 */int bus_create_file(struct
bus_type *bus, struct bus_attribute *attr);void bus_remove_file(struct bu工厂设备沙盘s_type *bus, struct bus_attribute *attr)
;/* 总线注册 */int bus_register(struct bus_type *bus);void bus_unregister(struct bus_type *bus);/* 遍历总线上的设备与驱动 */
i工厂设备沙盘nt bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int(*fn)(struct device *,
void *));int bus_for_each_drv(struct bus_type *bu工厂设备沙盘s, struct device_driver *start, void *data, int(*fn)(
struct device_driver *, void *));DevicesLinux中,每一个底层设备都是structure device的一个实例:struct device { 工厂设备沙盘 struct
device *parent; /* 父设备,总线设备指定为NULL */struct device_private *p; /* 包含设备链表,driver_data(驱动程序要使用数据)等信息 */
struct kobject kobj;
const工厂设备沙盘char *init_name; /* 初始默认的设备名 */struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this de工厂设备沙盘vice */
... void (*release)(
struct device *dev);
};int device_register(struct device *dev);void device_unregister(struct devic工厂设备沙盘e *dev)
;
DEVICE_ATTR(name, mode, show, store);int device_create_file(struct device *device,struct device_attribute *entry)
;void device_remove工厂设备沙盘_file(struct device *dev,struct device_attribute *attr);Drivers设备模型跟踪所有系统已知的驱动struct。
device_driver {
constchar *name; /* 驱动名称,在sysfs中以文工厂设备沙盘件夹名出现 */struct bus_type *bus; /* 驱动关联的总线类型 */
int (*probe) (struct device *dev); /* 查询设备的存在 */int (*remove) (struct device *dev); /* 设备移除回调 */void (*sh工厂设备沙盘utdown) (
struct device *dev);
...
}int driver_register(struct device_driver *drv);void driver_unregister(struct
device_driver *drv);工厂设备沙盘
DRIVER_ATTR(name, mode, show, store);int driver_create_file(struct device_driver *drv,
struct driver_attribute *attr);void driver_remove_file工厂设备沙盘(struct device_driver *drv,struct driver_attribute *attr)
;Classes类是设备的一个高级视图,实现了底层细节通过对设备进行分类,同类代码可共享,减少了内核代码的冗余structclass { constchar *name;工厂设备沙盘 /* class的名称,会在“/sys/class/”目录下体现 */。
struct class_attribute *class_attrs; struct device_attribute *dev_attrs; /* 该class下每个设备的attribute */
s工厂设备沙盘truct kobject *dev_kobj; /* 当该class下有设备发生变化时,会调用class的uevent回调函数 */int (*dev_uevent)(struct
device *dev, struct kobj_uevent_env *env); c工厂设备沙盘har *(*devnode)(struct device *dev, mode_t *mode);
void (*class_release)(structclass *class); void (*dev_release)(struct device *dev); int (*susp工厂设备沙盘end)(
struct device *dev, pm_message_t state); int (*resume)(struct device *dev); struct class_private *p;
};
int class_register(structcla工厂设备沙盘ss *cls);void class_unregister(structclass *cls);
CLASS_ATTR(name, mode, show, store);
int class_create_file(structclass *cls,conststruct clas工厂设备沙盘s_attribute *attr);void class_remove_file(struct
class *cls,conststruct class_attribute *attr);Putting It All Together
嵌入式Linux中文站最专业的中文嵌入式Linux网站,8年磨剑,工厂设备沙盘注册用户数万人!分享嵌入式 & Linux技术干货、教程、资讯、高薪职位订阅点击标题下方“嵌入式Linux中文站”分享点击右上角按钮投稿
Copyright © 2002-2020 上海润之模型设计有限公司 版权所有 展示模型,展品模型,展厅模型,展示道具,展厅展品,展品道具,模型定制,模型公司,上海模型公司 备案号:沪ICP备20018260号