天天看點

linux總線裝置驅動模型之Kobject&Kset

sysfs檔案系統:linux2.6引入的全新的檔案系統,它是基于核心的虛拟檔案系統,其作用是将核心資訊一檔案的形式呈現給使用者。

sys部分目錄結構:

.
├── block
│   ├── loop0 -> ../devices/virtual/block/loop0
│   ├── loop1 -> ../devices/virtual/block/loop1
│   ├── loop2 -> ../devices/virtual/block/loop2
├── bus
│   ├── acpi
│   │   ├── devices
│   │   │   ├── ACPI0003:00 -> ../../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00
│   │   │   ├── AUI1627:00 -> ../../../devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:01/AUI1627:00
│   │   │   ├── device:00 -> ../../../devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:00
│   │   ├── drivers
│   │   │   ├── ac
│   │   │   │   ├── ACPI0003:00 -> ../../../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0003:00
│   │   │   ├── battery
│   │   │   │   ├── bind
│   │   └── uevent
├── class
│   ├── ata_device
│   │   ├── dev1.0 -> ../../devices/pci0000:00/0000:00:1f.2/ata1/link1/dev1.0/ata_device/dev1.0
│   │   ├── dev2.0 -> ../../devices/pci0000:00/0000:00:1f.2/ata2/link2/dev2.0/ata_device/dev2.0
│   │   ├── dev3.0 -> ../../devices/pci0000:00/0000:00:1f.2/ata3/link3/dev3.0/ata_device/dev3.0
├── dev
│   ├── block
│   │   ├── 1:0 -> ../../devices/virtual/block/ram0
│   │   └── 8:9 -> ../../devices/pci0000:00/0000:00:1f.2/ata5/host4/target4:0:0/4:0:0:0/block/sda/sda9
│   └── char
│       ├── 10:1 -> ../../devices/virtual/misc/psaux
│       ├── 10:183 -> ../../devices/virtual/misc/hw_random
│       ├── 10:184 -> ../../devices/virtual/misc/microcode
│       ├── 89:8 -> ../../devices/pci0000:00/0000:00:01.1/0000:07:00.0/i2c-8/i2c-dev/i2c-8
│       └── 89:9 -> ../../devices/pci0000:00/0000:00:01.1/0000:07:00.0/i2c-9/i2c-dev/i2c-9
├── devices
│   ├── breakpoint
│   │   ├── perf_event_mux_interval_ms
│   │   ├── power
│   │   ├── events
│   │   │   ├── branch-instructions
├── fs
│   ├── bpf
│   ├── cgroup
│   │   ├── blkio
│   │   │   ├── blkio.io_merged
│   │   │   ├── blkio.io_merged_recursive
│   │   │   ├── blkio.io_queued
│   │   │   ├── blkio.io_queued_recursive
│   │   │   ├── blkio.io_service_bytes
│   │   │   ├── blkio.io_service_bytes_recursive
│   │   │   ├── blkio.io_serviced
├── hypervisor
├── kernel
│   ├── boot_params
│   │   ├── data
│   │   └── version
│   ├── debug [error opening dir]
│   ├── fscaps
└── power
    ├── disk
    ├── image_size
    ├── pm_async
    ├── pm_freeze_timeout
           

kobject:實作了基本的面向對象的管理機制,是構成linux2.6裝置模型的核心結構,是所有總線、裝置和驅動的抽象基類,每一個kobject對應一個sysfs檔案系統中的一個目錄。

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;  
    unsigned int uevent_suppress:1;  
};  
           

對kobject的初始化、添加、删除、等操作函數:

void kobject_init(struct kobject *kobj); //初始化
int kobject_add(struct kobject *kobj);//添加
void kobject_init_and_add(struct kobject* kobj,struct kobj_type *ktpye,struct kobject *parent,const char *fmt,...);
void kobject_del(struct kobject *kobj);
struct kobject *kobject_get(struct kobject *kobj);//将kobject對象的引用加一,同時傳回該對象的指針。
void kobject_put(struct kobject *kobj);//将kobject對象的引用減一,若為0則調用relase函數釋放該kobject對象。
           

struct kobj_type原型:

struct kobj_type{
     void (*release)(struct kobject *kobj);
     struct sysfs_ops *sysfs_ops;
     strcut attribute **default_attrs;
};
           

release:釋放kobject占用的資源,當kobject的應用為0時調用。

sysfs_ops:設定擷取檔案的屬性資訊。

attribute:對應object目錄下的一個檔案。

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:使用者讀檔案屬性時,該函數将屬性值存入buf中傳回給使用者。

store:使用者寫屬性檔案時,該函數将使用者寫入的值傳入屬性值中。

struct attribute原型:

struct attribute{
        char *name; //屬性(檔案)名
        struct module *owner;
        mode_t mode;//屬性(檔案)保護位
};
           

kset具有相同類型的kobject集合,在sysfs檔案系統中形成一個目錄。

struct kest原型:

struct kset{
         struct list_head list; //連接配接該kest中所有kobject的連結清單頭
         spinlock_t list_lock;
         struct kobject kobj;  //内嵌的kobject
         struct kset_uevent_ops *uevent_ops; //處理熱插拔事件的操作集合
};
           

struct kest_uevent_ops原型:

struct kest_uevent_ops{
         int (*filter)(struct kest *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);
};
           

filter:決定是否将事件傳遞到使用者,若filter傳回值為0,将不傳遞事件。

name:用于将字元串傳遞給使用者空間的熱插拔處理程式。

uevent:将使用者空間需要的參數添加到環境變量中。

熱插拔事件:

在linux系統中,當系統配置發生變化時,如添加kset到系統、移動kobject,一個通知會從核心發送到使用者空間,這就是熱插拔事件。熱插拔事件會導緻使用者空間中相應的處理程式被調用,這些處理程式,會通過加載驅動程式,建立裝置節點等來響應熱插拔事件。

kobject具體事例:

/*
 * kobj.c
 *
 *  Created on: 2016年10月16日
 *      Author: chy
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <linux/stat.h>

void release_test(struct kobject *test);
ssize_t test_show(struct kobject *obj,struct attribute *attr,char *buff);
ssize_t test_store(struct kobject *obj,struct attribute *attr,char *buff,size_t zie);

struct attribute attr = {
		.name = "lobject_test",
		.mode = S_IRWXUGO,
};
struct attribute att[] = {
		&attr,
		NULL,
};

struct sysfs_ops sysfs = {
		.show = test_show,
		.store = test_store,
};

struct kobj_type type = {
		.release = release_test,
		.sysfs_ops = &sysfs,
		.default_attrs = att,
};
void release_test(struct kobject *test)
{
	printk("del test");
	return;
}

ssize_t test_show(struct kobject *obj,struct attribute *attr,char *buff)
{
	printk("show_func test\n");
	printk("this name is %s\n",attr->name);
	sprintf(buff,"%s",attr->name);
	return strlen(attr->name) + 2;
}

ssize_t test_store(struct kobject *obj,struct attribute *attr,char *buff,size_t szie)
{
	printk("write %s\n",buff);
	return szie;
}

struct kobject s;

static int __init kobj_init(void)
{
	printk("this test start\n");
	kobject_init_and_add(&s,&type,NULL,"obj_test");
	return 0;
}

static int __exit kobj_exit(void)
{
	printk("this is test end\n");
	kobject_del(&s);
	return 0;
}

MODULE_AUTHOR("David Xie");
MODULE_LICENSE("GPL v2");

module_init(kobj_init);
module_exit(kobj_exit);

           

Makefile:

obj-m := /src/kobj.o

all: kobj
kobj: 
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
           

kset具體執行個體:

/*
 * obj_set.c
 *
 *  Created on: 2016年10月16日
 *      Author: chy
 */

#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/sysfs.h>

int filter_test(struct kset *kset,struct kobject *kobj)
{
	printk("this is filter\n");
	return 1;
}

const char *name_test(struct kset *kset,struct kobject *kobj)
{
	char buff[256];
	printk("kobj name is %s\n",kobj->name);
	sprintf(&buff,"%s","kset");
	return buff;
}

int ssenv(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 envs = {
		.filter = filter_test,
		.name = name_test,
		.uevent = ssenv,
};

struct kset set_s,set_p;

static int __init test_init(void)
{
	printk("init test\n");

	kobject_set_name(&set_s.kobj,"set.s");
	set_s.uevent_ops = &envs;
	kset_register(&set_s);

	kobject_set_name(&set_p.kobj,"set.p");
	set_p.kobj.kset = &set_s;
	kset_register(&set_p);
	return 0;
}

static int __exit test_exit(void)
{
	printk("set test end\n");
	kset_unregister(&set_s);
	kset_unregister(&set_p);

	return 0;
}

module_init(test_init);
module_exit(test_exit);</span><span style="font-size:18px;">

           

Makefile:

obj-m :=kset.o

all: kset
kset:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean</span><span style="font-size:18px;">