linux设备模型之kobject与kset


kobjectkset 之前,先介绍与它们相关联的 sysfs 文件系统

sysfs文件系统

linux2.6内核引入了sysfs文件系统,sysfs被看成是与proc同类别的文件系统。Sysfs把连接在系统上的设备和总线组织成分级的文件,使其从用户空间可以访问到。

sysfs被加载到/sys/目录下,它的子目录包括:

  • Block:在系统中发现的每个块设备在该目录下对应一个子目录。每个子目录中又包含一些属性文件,它们描述了这个 块设备的各方面属性,如:设备大小。(loop块设备是使用文件来模拟的)
  • Bus:在内核中注册的每条总线在该目录下对应一个子目录。其中每个总线目录内又包含两个子目录:devices 和 drivers,devices目录包含了整个系统中发现的属于该总线类型的设备;
    drivers目录包含了注册到该总线的所有驱动。
  • Class:将设备按照功能进行的分类,如/sys/class/net目录下包含了所有的网络接口
  • Devices:包含系统所有的设备
  • Kernel:内核中的配置参数
  • Module:系统中所有模块信息
  • Firmware:系统中的固件
  • Fs:描述系统中的文件系统
  • Power:系统中电源选项

在看 sysfs 文件系统时候,可能会发现一个设备在不同的目录下都有,这是因为 sysfs 文件下的目录有些是相互关联的,如:

在这里插入图片描述

kobject

(1)介绍
kobject 实现了基本面向对象管理机制,是构成 linux2.6 设备模型的核心结构。它与 sysfs 文件系统紧密相连,在内核中注册的每一个kobiect 对象对应 sysfs 文件系统中的一个目录。
代码中的一个 kobject 就代表了 sysfs 文件系统下的一个目录)

(1)kobject 结构体中的成员

在这里插入图片描述

(3)kobject 操作

  • void kobject_init (struct kobject * kobj)
    初始化 kobject 结构
  • int kobject_add (struct kobject * kobj)
    将 kobjet 对象注册到 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 *,char *,size_t);
		};
  • show:当用户读属性文件时,该函数被调用,该函数将属性值存入 buffer 中返回用户态;
  • store:当用户写属性文件时,该函数被调用,用于存储用户传入的属性值。

kobject代码实现

			#include <linux/device.h>
			#include <linux/module.h>
			#include <linux/kernel.h>
			#include <linux/init.h>
			#include <linux/string.h>
			#include <linux/sysfs.h>
			#include <linux/stat.h>
			
			MODULE_AUTHOR("zhangbin");
			MODULE_LICENSE("Dual BSD/GPL");
			
			void obj_test_release(struct kobject *kobject);
			ssize_t kobj_test_show(struct kobject *kobject,struct attribute *attr,char *buf);
			ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,char *buf,size_t count);
			
			struct attribute test_attr =
			{
			        .name = "kobj_config",
			        .mode = S_IRWXUGO,
			};

			static struct attribute *def_attrs[]=
			{
			        &test_attr,
			        NULL,
			};
			
			struct sysfs_ops obj_test_sysops=
			{
			        .show = kobj_test_show,
			        .store = kobj_test_store,
			};
			
			struct kobj_type ktype =
			{
			        .release = obj_test_release,
			        .sysfs_ops = &obj_test_sysops,
			        .default_attrs = def_attrs,
			};

			void obj_test_release(struct kobject *kobject)
			{
			        printk("eric_test:release\n");
			}
			
			ssize_t kobj_test_show(struct kobject *kobject,struct attribute *attr,char *buf)
			{
			        printk("have show:\n");
			        printk("attrname:%s\n",attr->name);
			        sprintf(buf,"%s\n",attr->name);
			        return strlen(attr->name) + 2;
			}
			
					ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,char *buf,size_t count)
					{
					        printk("have store\n");
					        printk("write:%s\n",buf);
					        return count;
					}
					
					struct kobject kobj;
					static int kobj_test_init()
					{
					        printk("kobject test init.\n");
					        kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
					        return 0;
					}
					
					static int kobj_test_exit()
					{
					        printk("kobject tesst exit.\n");
					        kobject_del(&kobj);
					        return 0;
					}

				module_init(kobj_test_init);
				module_exit(kobj_test_exit);
	

kobject开发板验证(linux2.6.38内核)

在这里插入图片描述

kobject 总结

(1)kobject 是用来创建sysfs文件系统下的目录的
(2)kobject 里面有属性,这个属性就对应这个文件

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 (*event)(struct kset *kset,struct kobject *kobj,struct kobj_uevent_env *env);
		};

但是上述结构中的三个函数什么时候被调用呢?
当该kset所管理的 kobject 和 kset 状态发生变化时(如被加入,移动),这三个函数将被调用。

这三个函数的功能是:

  • filter:决定是否将事件传递到用户空间。如果 filter 返回0,将不传递事件。
  • name:用于将字符串传递给用户空间的热插拔处理程序。
  • uevent:将用户空间需要的参数添加到环境变量中。

kset代码实现

		#include <linux/device.h>
		#include <linux/module.h>
		#include <linux/kernel.h>
		#include <linux/init.h>
		#include <linux/string.h>
		#include <linux/sysfs.h>
		#include <linux/stat.h>
		#include <linux/kobject.h>
		
		MODULE_AUTHOR("zhangbin");
		MODULE_LICENSE("Dual BSD/GPL");
		
		struct kset kset_p;
		struct kset kset_c;
		
		int kset_filter(struct kset *kset,struct kobject *kobj)
		{
		        printk("Filter:kobj %s.\n",kobj->name);
		        return 1;
		}
		
		const char *kset_name(struct kset *kset,struct kobject *kobj)
		{
		        static char buf[20];
		        printk("Name:kobj %s.\n",kobj->name);
		        sprintf(buf,"%s\n","kset_name");
		        return buf;
		}
		
		int kset_uevent(struct kset *kset,struct kobject *kobj,struct kobj_uevent_env *env)
		{
		        int i = 0;
		        printk("uevent:kobj %s.\n",kobj->name);
		
		        while( i < env->envp_idx)
		        {
		                printk("%s.\n",env->envp[i]);
		                i++;
		        }
		
		        return 0;
		}
		
		struct kset_uevent_ops uevent_ops =
		{
		        .filter = kset_filter,
		        .name = kset_name,
		        .uevent = kset_uevent,
		};
		
		int kset_test_init()
		{
		        printk("kset test init.\n");
		        kobject_set_name(&kset_p.kobj,"kset_p");
		        kset_p.uevent_ops = &uevent_ops;
		        kset_register(&kset_p);
		
		        kobject_set_name(&kset_c.kobj,"kset_c");
		        kset_c.kobj.kset = &kset_p;
		        kset_register(&kset_c);
		        return 0;
		}

		void kset_test_exit()
		{
		        printk("kset test exit\n");
		        kset_unregister(&kset_p);
		        kset_unregister(&kset_c);
		}
		
		module_init(kset_test_init);
		module_exit(kset_test_exit);

Makefile

		ifneq ($(KERNELRELEASE),)

		obj-m := kset.o 
		
		else
		
		KDIR := /home/zhangbin/mini6410/linux-2.6.38 
		all:
		        make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=arm-linux-
		clean:
		        rm -f *.ko *.o *.mod.c *.symvers
		
		endif
			

kset实现gif图

kset总结

(1)kset也是对应目录
()和kobject的区别在于:kset可以再包含子目录的目录,kset结构中也包含了kobject

猜你喜欢

转载自blog.csdn.net/qq_41782149/article/details/89373946