Linux设备模型-3-_Kobject 实例

来源:互联网 发布:淘宝卖家如何取消订单 编辑:程序博客网 时间:2024/05/20 10:52

本文将从Linux内核的角度来看一看这个设备模型是如何构建的。本实例基本上没有什么实际意义,只是为了理解kobject这个内核对象。

我的测试环境是openwrt15.05 trunk版,硬件平台是mtk7620a。

文件名称:my_kobj.c

#include <linux/device.h>/* include the structure of the device and class */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>/* include kcalloc(),kzalloc() functions,and so on */MODULE_AUTHOR("Tupelo Shen");MODULE_LICENSE("Dual BSD/GPL");/* * the macro container_of is included in <include/linux/kernel.h> * prototype: * #define container_of(ptr,type,member) ({\ * const typeof(((type *)0)->member) *__mptr = (ptr);\ * (type *)((char *)__mptr - offsetof(type,member));}) *  * cast a member of a structure out to the containing structure. */#define to_my_kobj(data)container_of(data, struct my_kobj, kobj)/* * define an object for my_kobj which type is kobject */struct my_kobj {int val;struct kobject kobj;};/* * the tree structure in /sys/ directory. * *   mykobj1/ *   |-- mykobj2 *   | |-- name *   | `-- val *   |-- name *   `-- val */struct attribute name_attr = {    .name = "name",    .mode = 0444,}; struct attribute val_attr = {    .name = "val",    .mode = 0666,}; struct attribute *my_attrs[] = {    &name_attr,    &val_attr,    NULL,};ssize_t my_show(struct kobject *kobj, struct attribute *attr, char *buffer){    struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);    ssize_t count = 0;     if (strcmp(attr->name, "name") == 0) {        count = sprintf(buffer, "%s\n", kobject_name(kobj));    } else if (strcmp(attr->name, "val") == 0) {        count = sprintf(buffer, "%d\n", obj->val);    }     return count;} ssize_t my_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size){    struct my_kobj *obj = container_of(kobj, struct my_kobj, kobj);     if (strcmp(attr->name, "val") == 0) {        sscanf(buffer, "%d", &obj->val);    }     return size;} struct sysfs_ops my_sysfsops = {    .show = my_show,    .store = my_store,};struct my_kobj *obj1;struct my_kobj *obj2;struct kobj_type my_type;void obj_release(struct kobject *kobj){    struct my_kobj *my_kobj_free = to_my_kobj(kobj);printk(KERN_INFO "my_kobj_release\n");    kfree(my_kobj_free);} static int __init my_kobj_init(void){    printk(KERN_INFO "mykobj_init\n");     obj1 = (struct my_kobj *)kzalloc(sizeof(struct my_kobj), GFP_KERNEL);    if (!obj1) {        return -ENOMEM;    }    obj1->val = 1;     obj2 = (struct my_kobj *)kzalloc(sizeof(struct my_kobj), GFP_KERNEL);    if (!obj2) {        kfree(obj1);        return -ENOMEM;    }    obj2->val = 2;     my_type.release = obj_release;    my_type.default_attrs = my_attrs;    my_type.sysfs_ops = &my_sysfsops;     kobject_init_and_add(&obj1->kobj, &my_type, NULL, "mykobj1");kobject_init_and_add(&obj2->kobj,&my_type,&obj1->kobj, "mykobj2");    return 0;}static void __exit my_kobj_exit(void){    printk(KERN_INFO "mykobj_exit\n");     kobject_del(&obj2->kobj);    kobject_put(&obj2->kobj);         kobject_del(&obj1->kobj);    kobject_put(&obj1->kobj);     return;}module_init(my_kobj_init);module_exit(my_kobj_exit);

在这个实例里,我们定义一个内嵌kobject的结构。

struct my_kobj {    int val;    struct kobject kobj;};

最终我们的目的是在内核里构建这样的架构。

对应sysfs里的目录关系是:

    mykobj1/    |-- mykobj2    | |-- name    | `-- val    |-- name    `-- val

初始化代码可以分作三个部分。

第一部分是分配obj1obj2并赋值;

第二部分是初始化kobj_type变量my_type

第三部分是调用kobject_init_and_add函数来初始化kobject并把它加入到设备模型的体系架构(也就是上文中提到的内核中的那棵树)中。

kobject_init_and_add是简化的写法,这个函数也可以分两步完成:kobject_initkobject_add


结构体struct attribute里的name变量用来指定文件名,mode变量用来指定文件的访问权限。

这里需要着重指出的是,数组my_attrs的最后一项一定要赋为NULL,否则会造成内核oops


kobject_del的作用是把kobject从设备模型的那棵树里摘掉,同时sysfs里相应的目录也会删除。这里需要指出的是,释放的顺序应该是先子对象,后父对象。因为kobject_init_and_addkobject_add这两个函数会调用kobject_get来增加父对象的引用计数,所以kobject_del需要调用kobject_put来减少父对象的引用计数。在本例中,如果先通过kobject_put来释放obj1,那kobject_del(&obj2->kobj)就会出现内存错误。

 

在这个实例中,我们建立了两个对象obj1obj2obj1obj2的父对象,如果推广开来,obj1可以有更多的子对象。在Linux内核中,这种架构方式其实并无太大的实际价值,有限的用处之一是在sysfs里创建子目录(Linux内核里有这种用法,这种情况下,直接调用内核提供的kobject_create来实现,不需要自定义数据结构并内嵌kobject),而且,创建子目录也是有其他的办法的。我们知道,Linux设备模型最初的目的是为了方便电源管理,这就需要从上到下的遍历,在这种架构里,通过obj1并无法访问其所有的子对象。这个实例最大的意义在于可以让我们比较清晰的理解kobject如何使用。通常情况下,kobject只需要在叶节点里使用,上层的节点要使用kset。 

另外,再把makefile文件贴出来。

#Kernel module exampleinclude $(TOPDIR)/rules.mkinclude $(INCLUDE_DIR)/kernel.mkinclude $(INCLUDE_DIR)/package.mkPKG_NAME:=my_kobjPKG_RELEASE:=1EXTRA_KCONFIG:= \CONFIG_MY_KOBJ=mEXTRA_CFLAGS:= \$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG))))MAKE_OPTS:= \ARCH="$(LINUX_KARCH)" \CROSS_COMPILE="$(TARGET_CROSS)" \SUBDIRS="$(PKG_BUILD_DIR)" \EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \$(EXTRA_KCONFIG)define KernelPackage/my_kobj# CATEGORY:=Kernel modulesSUBMENU:=Other modulesTITLE:=Test kobject#KCONFIG:=$(CONFIG_MY_KOBJ)# DEPENDS:=@XXX   #如果有依赖,这个名字可去make menuconfig里面找到 Symbol:XXXFILES:=$(PKG_BUILD_DIR)/my_kobj.ko#AUTOLOAD:=$(call AutoLoad,81,example) #系统启动时自动装载endefdefine KernelPackage/my_kobj/descriptionKernel module to test kobjectendef#PKG_BUILD_DIR:/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7621/example#建立 PKG_BUILD_DIR ,并将代码拷贝到此处define Build/Preparemkdir -p $(PKG_BUILD_DIR)/$(CP) -R ./src/* $(PKG_BUILD_DIR)/endefdefine Build/Compile#$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) CONFIG_MY_KOBJ=m modules$(MAKE) -C "$(LINUX_DIR)" $(MAKE_OPTS) modulesendef      $(eval $(call KernelPackage,my_kobj))
/src目录下的makefile文件很简单,就一行:

obj-${CONFIG_MY_KOBJ}+= my_kobj.o



0 0
原创粉丝点击