目錄
一. 設備驅動模型簡介
Linux設備模型的核心是使用Bus、Class、Device、Driver四個核心數據結構,將大量的、不同功能的硬件設備(以及驅動該硬件設備的方法),以樹狀結構的形式,進行歸納、抽象,從而方便Kernel的統一管理。
linux將這些數據結構的共同功能抽象出來,同一實現, 表示爲 kobject。
- 通過parent指針,將所有kobject以層次結構的形式組合起來。
- 使用引用計數(reference count)來表示kobject被引用的次數,並且在ref變爲0時,釋放掉。
- 它與sysfs文件系統緊密相連,每個註冊的kobject都對應sysfs文件系統中的一個目錄。即"/sys/"下的某個目錄。
- kobject:是總線、驅動、設備的三種對象的一個基類,實現公共接口。
- ktype:記錄了kobject對象的一些屬性。
- kset:是同類型kobject對象的集合,即一個容器; 是特殊的kobject,故也會在"/sys/"下的某個目錄。
二. kobject簡介
Kobject實現了基本的面向對象管理機制,是構成Linux設備模型的核心結構。它與sysfs文件系統緊密相連,在內核中註冊的每個kobject對象對應sysfs文件系統中的一個目錄。
類似於C++中的基類,Kobject常被嵌入於其他類型(即:容器 kset)中。如bus,devices, drivers 都是典型的容器。這些容器通過kobject連接起來,形成了一個樹狀結構。
kset與kobject的關係:
kset, kobject,sysfs的關係:
2.1 kobject內核數據結構
struct kobject {
const char *name; /*名字*/
struct list_head entry; /*連接到kset建立層次結構*/
struct kobject *parent; /*指向父節點,面向對象的層次架構。即反應到sysfs中爲父目錄*/
struct kset *kset; /*指向所屬的kset*/
struct kobj_type *ktype; /*屬性文件*/
struct kernfs_node *sd; /*sysfs directory entry,對接虛擬文件系統*/
struct kref kref; /*引用計數*/
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
/*初始化狀態*/
unsigned int state_initialized:1;
/*是否處在sysfs下了*/
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;
};
/*成員變量結構*/
/*1. 名稱:kobj_type
作用:Kobject的ktype成員是一個指向kobj_type結構的指針,該結構中記錄了kobject對象的一些屬性。
注:
release:用於釋放kobject佔用的資源,當kobject的引用計數爲0時被調用。
*/
struct kobj_type {
void (*release)(struct kobject *kobj); /*用於釋放kobject佔用的資源*/
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);
};
/*2. 名稱:sysfs_ops
作用:kobj讀寫操作回調函數,負責分發到各個attribute的show和store函數中。
注:
*/
struct sysfs_ops {
/*應用層讀數據:當用戶讀屬性文件時,該函數被調用,該函數將屬性值存入buffer中返回給用戶態;*/
ssize_t (*show)(struct kobject *, struct attribute *, char *);
/*應用層寫數據:當用戶寫屬性文件時,該函數被調用,用於存儲用戶傳入的屬性值。*/
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
/*3. 名稱:attribute
作用:屬性。對應於kobject的目錄下的一個文件,Name成員就是文件名。
注:
*/
struct attribute {
const char *name; /*屬性文件名*/
umode_t mode; /*屬性的文件屬性*/
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};
/*4. 名稱:kobj_attribute
作用:讀寫操作回調函數。
注:
*/
struct kobj_attribute {
struct attribute attr;
/*具體attribute屬性文件的讀操作函數*/
ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
/*具體attribute屬性文件的寫寫操作函數*/
ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
};
2.2 kobject操作內核接口
/*1.初始化kobject結構*/
void kobject_init(struct kobject * kobj)
/*2.將kobject對象註冊到Linux系統*/
int kobject_add(struct kobject * kobj)
/*3.初始化kobject,並將其註冊到linux系統*/
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
/*4.從Linux系統中刪除kobject對象*/
void kobject_del(struct kobject * kobj)
/*5.將kobject對象的引用計數加1,同時返回該對象指針。*/
struct kobject *kobject_get(struct kobject *kobj)
/*6.將kobject對象的引用計數減1,如果引用計數降爲0,則調用release方法釋放該kobject對象。*/
void kobject_put(struct kobject * kobj)
三. kobject實例
3.1 Makefile
ifneq ($(KERNELRELEASE),)
obj-m := object_test.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers
endif
3.2 實例1
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/slab.h>
static struct kobject *my_kobj = NULL;
static void my_release(struct kobject *kobj)
{
printk("%s :in\n", __FUNCTION__);
kfree(my_kobj);
}
static struct kobj_type my_ktype = {
.release = my_release,
};
static int __init kobj_test_init(void)
{
int err = 0;
printk("%s :in\n", __FUNCTION__);
my_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
if (!my_kobj)
return -ENOMEM;
kobject_init(my_kobj, &my_ktype);
err = kobject_add(my_kobj, NULL, "%s_kobj", "my");
if (err) {
printk("kobj_test init kobject_add error!\n");
goto err;
}
return 0;
err:
kobject_put(my_kobj);
return err;
}
static void __exit kobj_test_exit(void)
{
printk("%s :in\n", __FUNCTION__);
kobject_del(my_kobj);
kobject_put(my_kobj);
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
MODULE_AUTHOR("vector");
MODULE_LICENSE("Dual BSD/GPL");
結果:
3.3 實例2
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/slab.h>
static struct kobject *my_kobj = NULL;
static void my_release(struct kobject *kobj)
{
printk("%s :in\n", __FUNCTION__);
kfree(my_kobj);
}
/*用於分發到各個具體的attr屬性文件中的show,store函數中*/
static ssize_t my_sysfs_ops_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
struct kobj_attribute *my_attr;
ssize_t ret = -EIO;
my_attr = container_of(attr, struct kobj_attribute, attr);
if (my_attr->show)
ret = my_attr->show(kobj, my_attr, buf);
return ret;
}
static ssize_t my_sysfs_ops_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
{
struct kobj_attribute *my_attr;
ssize_t ret = -EIO;
my_attr = container_of(attr, struct kobj_attribute, attr);
if (my_attr->store)
ret = my_attr->store(kobj, my_attr, buf, count);
return ret;
}
/*
static ssize_t my_sysfs_ops_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
strcpy(buf, "sysfs ops show");
return strlen("sysfs ops show");
}
static ssize_t my_sysfs_ops_store(struct kobject *kobj, struct attribute *attr,const char *buf, size_t count)
{
printk("sysfs ops store %s", buf);
return count;
}
*/
static const struct sysfs_ops my_sysfs_ops = {
.show = my_sysfs_ops_show,
.store = my_sysfs_ops_store,
};
static struct kobj_type my_ktype = {
.sysfs_ops = &my_sysfs_ops,
.release = my_release,
};
static ssize_t my_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
printk("%s :in\n", __FUNCTION__);
strcpy(buf, "my kobject show");
return strlen("my kobject show");
}
static ssize_t my_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
printk("%s :in, %s!\n", __FUNCTION__, buf);
return count;
}
static struct kobj_attribute my_attr =
__ATTR(my, 0644, my_show, my_store);
static ssize_t your_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
printk("%s :in\n", __FUNCTION__);
strcpy(buf, "your kobject show");
return strlen("your kobject show");
}
static ssize_t your_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
printk("%s :in, %s!\n", __FUNCTION__, buf);
return count;
}
static struct kobj_attribute your_attr =
__ATTR(your, 0644, your_show, your_store);
static int __init kobj_test_init(void)
{
int err = 0;
printk("%s :in\n", __FUNCTION__);
my_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
if (!my_kobj)
return -ENOMEM;
kobject_init(my_kobj, &my_ktype);
err = kobject_add(my_kobj, NULL, "%s_kobj", "my");
if (err) {
printk("kobj_test init kobject_add error!\n");
kobject_put(my_kobj);
goto err;
}
err = sysfs_create_file(my_kobj, &my_attr.attr);
if (err)
printk("kobj_test_init, sysfs_create_file error!\n");
err = sysfs_create_file(my_kobj, &your_attr.attr);
if (err)
printk("kobj_test_init, sysfs_create_file error!\n");
return 0;
err:
kobject_put(my_kobj);
return err;
}
static void __exit kobj_test_exit(void)
{
printk("%s :in\n", __FUNCTION__);
sysfs_remove_file(my_kobj, &my_attr.attr);
sysfs_remove_file(my_kobj, &your_attr.attr);
kobject_del(my_kobj);
kobject_put(my_kobj);
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
MODULE_AUTHOR("vector");
MODULE_LICENSE("Dual BSD/GPL");
結果:
3.4 實例3
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/io.h>
#include <linux/slab.h>
static struct kobject *my_kobj = NULL;
static ssize_t my_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
printk("%s :in\n", __FUNCTION__);
strcpy(buf, "my kobject show");
return strlen("my kobject show");
}
static ssize_t my_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
printk("%s :in, %s!\n", __FUNCTION__, buf);
return count;
}
static struct kobj_attribute my_attr =
__ATTR(my, 0644, my_show, my_store);
static ssize_t your_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
printk("%s :in\n", __FUNCTION__);
strcpy(buf, "your kobject show");
return strlen("your kobject show");
}
static ssize_t your_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
printk("%s :in, %s!\n", __FUNCTION__, buf);
return count;
}
static struct kobj_attribute your_attr =
__ATTR(your, 0644, your_show, your_store);
/*group way*/
static struct attribute *kobject_attrs[] = {
&my_attr.attr,
&your_attr.attr,
NULL,
};
static const struct attribute_group kobject_attr_group = {
.attrs = kobject_attrs,
};
static int __init kobj_test_init(void)
{
int err = 0;
printk("%s :in\n", __FUNCTION__);
my_kobj = kobject_create_and_add("my_kobj", NULL);
if (!my_kobj)
return -1;
/*
err = sysfs_create_file(my_kobj, &my_attr.attr);
if (err)
printk("kobj_test_init, sysfs_create_file error!\n");
err = sysfs_create_file(my_kobj, &your_attr.attr);
if (err)
printk("kobj_test_init, sysfs_create_file error!\n");
*/
err = sysfs_create_group(my_kobj, &kobject_attr_group);
if (err) {
printk("failed to create kobject attr group!\n");
goto err;
}
return 0;
err:
kobject_put(my_kobj);
return err;
}
static void __exit kobj_test_exit(void)
{
printk("%s :in\n", __FUNCTION__);
sysfs_remove_file(my_kobj, &my_attr.attr);
sysfs_remove_file(my_kobj, &your_attr.attr);
kobject_del(my_kobj);
kobject_put(my_kobj);
}
module_init(kobj_test_init);
module_exit(kobj_test_exit);
MODULE_AUTHOR("vector");
MODULE_LICENSE("Dual BSD/GPL");
相關博客:
https://blog.csdn.net/Guet_Kite/article/details/78368928