状态不错,快要元旦了,这是我计划开始的第一年;时间过的真快啊!
也是逃离舒适圈的一年,不能在日复一日的无聊工作沉浸下去,要明白自己今生适合做哪些事情,而不是随波逐流;
文章目录
[0x100]内容概述
- struct kobject
- struct Kset,
- struct bus_type
[0x110] 内核的设备管理特性
- 设备电源管理:启动到销毁遵照一定顺序,避免出现提前关闭需要的设备;
- 向用户空间传递参数:包括提供系统信息,操作参数接口等;
- 热插拔管理:
- 设备树维护;
- 设备类型遍历 :告知用户可以使用哪些设备;
[0x200] 内核对象数据结构
[0x201] 对象数据结构功能
- 对象引用计数 :没有被引用的对象,所占用的资源将被释放;
- 对象服务信息 :描述高级对象,并体现在设备模型中;
- 系统文件系统 :使用对象数据结构将内核中存在对象实现可见表述;
- 层次结构关系 :通过数据结构之间关联,维护更大的层次结构关系;
[0x202] kobject 初始化流程
- 分配struct kobject 空间,且存储kset 的空间必须提前清零;
- 初始化 struct kobj_type :操作对象释放或者事件处理的函数指针;
- 常规初始化 struct kobject :单设备对象属性信息;
- 设置显示于sysfs目录中的名称 :kobject_set_name();
[0x203] kset 初始化流程
- 分配struct kset空间,且存储kset 的空间必须提前清零
- 初始化 kset_obj ->kobj.ktype : 继承组中的对象释放或者事件处理的函数指针;
- 关联kset_obj ->kobj.ktype : 该成员优先与子对象中的ktype成员;
- 常规初始化struct kset :继承组对象属性信息;
- 设置显示于sysfs目录中的名称 :kobject_set_name();
[0x210]初始化结构
[0x211] 常规初始化对象结构-- struct kobject
#include<linux/kobject.h>
/*对象属性*/
struct kobject {
const char *name; /*sysfs目录中显示的名称*/
struct list_head entry; /*内核双向链表头 */
struct kobject *parent; /*父对象关联,常用于树形的链接主类与不同对象*/
struct kset *kset; /*对象组属性集*/
struct kobj_type *ktype; /*对象操作函数指针,必须实现release函数*/
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;/*等待事件移除状态位*/
unsigned int uevent_suppress:1; /*等待事件抑制状态位*/
};
/*操作函数集*/
struct kobj_type {
void (*release)(struct kobject *kobj); /*当对象的引用数为0时,释放该对象*/
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
/*1.初始化对象属性内容,填充结构体,对象引用计数 = 1,初始化状态位,这个必须优先做*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype);
/*2.设置kobject显示在sysfs目录中的名称,可能失败*/
int kobject_set_name(struct kobject *kobj, const char *name, ...);
[0x212] 常规初始化对象集合-- struct kset
#include <linux/kobject.h>
/*对象组集合 */
struct kset {
struct list_head list; /*内核的自定义链表*/
spinlock_t list_lock;
struct kobject kobj; /*main kobject*/
const struct kset_uevent_ops *uevent_ops;
};
/*1.初始化对象集合条件*/
int kset_register(struct kset *k)
{
int err;
if (!k)
return -EINVAL;
/*第一步 填充kset 结构体*/
kset_init(k);
/*第二步 相当于 kobject_add()将kset中内嵌的kobject 结构添加到kset本身关联*/
err = kobject_add_internal(&k->kobj);
if (err)
return err;
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;
}
/*2.设置kset 中内嵌的kobject显示在sysfs目录中的名称,可能失败*/
int kobject_set_name(struct kobject *kobj, const char *name, ...);
[0x220] 操作对象结构相关函数
[0x221] 操作对象引用计数
/*添加模块引用与对象引用 :添加对象引用计数之前必须添加模块引用计数,优先使用这个函数*/
static struct kobject *cdev_get(struct cdev *p)
{
struct module *owner = p->owner;
struct kobject *kobj;
/*检查模块拥有者是否存在,添加模块引用计数,成功后添加对象引用计数*/
if (owner && !try_module_get(owner))
return NULL;
kobj = kobject_get(&p->kobj);
/*如果对象已销毁 即kobj == NULL('\0')*/
if (!kobj)
/*如果对象不存在,取消模块引用*/
module_put(owner);
return kobj;
}
#include<linux/kobject.h>
/*单功能函数:增加对象应用计数,如果对象被销毁将返回NULL*/
struct kobject *kobject_get(struct kobject *kobj)
{
if (kobj)
/*从这个函数中可以看见对象的引用计数是一个原子变量*/
kref_get(&kobj->kref);
return kobj;
}
/*单功能函数:减少对象应用计数,如果对象被销毁将返回NULL,如果引用计数为0 对象将使用release函数被销毁*/
void kobject_put(struct kobject *kobj)
{
if (kobj) {
if (!kobj->state_initialized)
WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
"initialized, yet kobject_put() is being "
"called.\n", kobject_name(kobj), kobj);
/*struct kobj_type 中release函数,当 kobject 引用数归零时,就原子干掉kobject*/
kref_put(&kobj->kref, kobject_release);
}
}
[0x222] 添加到对象集合
#include<linux/kobject.h>
/*确认待添加的kobject已经初始化完毕,且已经把kset成员指向目的kset,后执行以下函数*/
/*implement kernel-dir/lib/kobject.c */
int kobject_add(struct kobject *kobj, struct kobject *parent,const char *fmt, ...)
{
va_list args;
int retval;
if (!kobj)
return -EINVAL;
if (!kobj->state_initialized) {
printk(KERN_ERR "kobject '%s' (%p): tried to add an "
"uninitialized object, something is seriously wrong.\n",
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
}
va_start(args, fmt);
/*如果 parent 为 NULL 将对应kobject 绑定到kset的 parent 上,如kset的parent也是NULL,将绑定到sysfs 根目录*/
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
/**
Func :添加新对象的到对象组集合kset 中;
args1:待添加对象的指针:注意这里的结构一定要kobject_init()初始化过的指针;
args2 :待添加对象的父类:如果NULL 将绑定到kset->kobj.parent,如果kset中不存在parent ,将绑定到sysfs 根目录;
args3 :待添加对象的名称;
retval :成功返回0 失败返回错误码;如果失败就必须调用 kobject_put()清理引用,或者直接kfree();
[0x223] 从对象集合移除对象
#include<linux/kobject.h>
void kobject_del(struct kobject *kobj)
{
if (!kobj)
return;
sysfs_remove_dir(kobj);
kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj);
kobject_put(kobj->parent);
kobj->parent = NULL;
}
[0x230] 操作对象集合相关函数
[0x231] 操作对象集合引用计数
#include<linux/kobject.h>
/*添加集合引用计数*/
static inline struct kset *kset_get(struct kset *k)
{
return k ? to_kset(kobject_get(&k->kobj)) : NULL;
}
/*减少集合引用计数,必须实现release 函数*/
static inline void kset_put(struct kset *k)
{
kobject_put(&k->kobj);
}
[0x232] 销毁对象集合
#include<linux/kobject.h>
/*注意这里直接干掉的是kset中 对象主类,干掉前必须确保 主类没有关联任何子类,否则不能删除*/
void kset_unregister(struct kset *k)
{
if (!k)
return;
kobject_put(&k->kobj);
}
[0x240]硬件对象结构属性
[0x241]不同种类的属性
- 默认文本类属性 :用于 用户与硬件通过内核交换信息;
- 二进制执行属性 :用于 用户向硬件上传固件写入更新程序等等;
- 自定义文本属性;
[0x242] 默认属性数据结构
#include<linux/kobject.h>
struct kobj_type {
void (*release)(struct kobject *kobj); /*当对象的引用数为0时,释放该对象*/
const struct sysfs_ops /*sysfs 的操作函数*/
{
/*用户读取属性 :根据 attribute 中信息确定,用户空间需要哪个属性数据,一次读取的数据不能大于PAGE_SIZE*/
ssize_t (*show)(struct kobject *, struct attribute *,char *);
/*用户写入属性 :一次写入的数据不能大于PAGE_SIZE*/
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
const void *(*namespace)(struct kobject *, const struct attribute *);
}*sysfs_ops;
struct attribute **default_attrs; /*保存在sysfs中可用的模块的属性信息,*/
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};
#include <linux/sysfs.h>
struct attribute {
const char *name; /*sysfs 系统文件名*/
umode_t mode; /*读写权限*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lock_class_key *key;
struct lock_class_key skey;
#endif
/*RSIC 处理器架构上好像没有实现这个功能*/
/*创建 于对象的sysfs目录中创建自定义属性文件*/
int __must_check sysfs_create_file(struct kobject *kobj,const struct attribute *attr);
/*销毁 于对象的sysfs目录中创建自定义属性文件*/
void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
};
[0x243] 二进制属性
#include <linux/sysfs.h>
struct bin_attribute
{
/*默认的属性结构,名称,所有者,读写权限等*/
struct attribute attr;
/*二进制值的最大长度,如果不知道大小可以设置为0,不限制*/
size_t size;
void *private;
/*类似驱动中的文件读写函数,每次最大数据量仍然是PAGE_SIZE*/
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,char *, loff_t, size_t);
ssize_t (*write)(struct file *,struct kobject *, struct bin_attribute *,char *, loff_t, size_t);
int(*mmap)(struct file *, struct kobject *, struct bin_attribute *attr,struct vm_area_struct *vma);
};
/*RSIC 处理器架构上好像没有实现这个功能*/
/*创建 于对象的sysfs目录中创建自定义二进制属性文件*/
static inline int sysfs_create_bin_file(struct kobject *kobj,const struct bin_attribute *attr)
/*销毁 于对象的sysfs目录中创建自定义二进制属性文件*/
static inline void sysfs_remove_bin_file(struct kobject *kobj,const struct bin_attribute *attr)
[0x300] 设备间通信总线
[0x301]总线传递信息的范围
- 处理器 到 其它设备
- 不同设备间通讯数据
- 虚拟平台之间的数据
[0x302]注册通讯总线
#include <linux/device.h >
struct bus_type {
const char *name; /*总线标识名称*/
const char *dev_name; /*设备顺序名称*/
struct device *dev_root; /*设备的父类*/
struct bus_attribute *bus_attrs; /*总线默认总线属性*/
struct device_attribute *dev_attrs; /*设备默认总线属性*/
struct driver_attribute *drv_attrs; /*驱动默认总线属性*/
/*新增驱动或者设备是否匹配当前总线,如匹配,返回非0值*/
int (*match)(struct device *dev, struct device_driver *drv);
/*处理设备常规事件:添加到环境变量*/
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
/*初始化设备:根据添加的设备,匹配对应驱动程序probe*/
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);
/*电源模式管理操作函数指针*/
const struct dev_pm_ops *pm;
/*总线内存管理操作函数指针*/
struct iommu_ops *iommu_ops;
/*驱动核心私有数据指针*/
struct subsys_private
{
struct kset subsys;
struct kset *devices_kset;
struct list_head interfaces;
struct mutex mutex;
struct kset *drivers_kset;
struct klist klist_devices;
struct klist klist_drivers;
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
struct bus_type *bus;
struct kset glue_dirs;
struct class *class;
}*p;
};
#define bus_register(subsys) \
({ \
static struct lock_class_key __key; \
__bus_register(subsys, &__key); \
})
/*注册总线 :设备kobject、驱动kobject 绑定kset 然后注册sysfs的过程,内核链表,添加总线的属性 */
int __must_check __bus_register(struct bus_type *bus,struct lock_class_key *key)
void bus_unregister(struct bus_type *bus);
[0x303]遍历指定总线
/*遍历设备,避免同时使用 有可能会导致自旋死锁*/
int
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 *bus, struct device_driver *start,void *data,
int (*fn)(struct device *, void *))
Func :根据 start 位置开始遍历设备,如果start = NULL 将从头遍历;
args1:待遍历总线标识;
args2:待遍历总线起始位置,如果是NULL 将从头遍历,如果不是则后一个开始遍历;
args3:向处理函数传递的参数;
args4:处理函数指针;
retval:返回非零值
[0x304]初始化总线属性
#include <linux/device.h >
/*跟kobject的默认属性差不多,毕竟都是需要添加到sysfs 文件系统中的*/
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
};
/*1.初始化总线属性,填充属性结构*/
#define BUS_ATTR(_name, _mode, _show, _store) \
struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
/*2.需要提前实现对应show函数和store函数*/
/*3.sysfs下创建对应总线文件*/
nt bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
{
int error;
if (bus_get(bus)) {
error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
bus_put(bus);
} else
error = -EINVAL;
return error;
}
/*销毁sysfs文件*/
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
{
if (bus_get(bus)) {
sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
bus_put(bus);
}
}