kobject,Kset,bus_type >>Linux设备驱动程序

状态不错,快要元旦了,这是我计划开始的第一年;时间过的真快啊!
也是逃离舒适圈的一年,不能在日复一日的无聊工作沉浸下去,要明白自己今生适合做哪些事情,而不是随波逐流;

[0x100]内容概述

  1. struct kobject
  2. struct Kset,
  3. struct bus_type

[0x110] 内核的设备管理特性

  1. 设备电源管理:启动到销毁遵照一定顺序,避免出现提前关闭需要的设备;
  2. 向用户空间传递参数:包括提供系统信息,操作参数接口等;
  3. 热插拔管理:
  4. 设备树维护;
  5. 设备类型遍历 :告知用户可以使用哪些设备;

[0x200] 内核对象数据结构

[0x201] 对象数据结构功能

  • 对象引用计数 :没有被引用的对象,所占用的资源将被释放;
  • 对象服务信息 :描述高级对象,并体现在设备模型中;
  • 系统文件系统 :使用对象数据结构将内核中存在对象实现可见表述;
  • 层次结构关系 :通过数据结构之间关联,维护更大的层次结构关系;

[0x202] kobject 初始化流程

  1. 分配struct kobject 空间,且存储kset 的空间必须提前清零;
  2. 初始化 struct kobj_type :操作对象释放或者事件处理的函数指针;
  3. 常规初始化 struct kobject :单设备对象属性信息;
  4. 设置显示于sysfs目录中的名称 :kobject_set_name();

[0x203] kset 初始化流程

  1. 分配struct kset空间,且存储kset 的空间必须提前清零
  2. 初始化 kset_obj ->kobj.ktype : 继承组中的对象释放或者事件处理的函数指针;
  3. 关联kset_obj ->kobj.ktype : 该成员优先与子对象中的ktype成员;
  4. 常规初始化struct kset :继承组对象属性信息;
  5. 设置显示于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]不同种类的属性

  1. 默认文本类属性 :用于 用户与硬件通过内核交换信息;
  2. 二进制执行属性 :用于 用户向硬件上传固件写入更新程序等等;
  3. 自定义文本属性;

[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);
        }
}

猜你喜欢

转载自blog.csdn.net/god1992/article/details/85366691
今日推荐