#include <linux/module.h>

  #include <linux/kernel.h>

  #include <linux/kobject.h>

  #include <linux/sysfs.h>

  #include <linux/slab.h>

  static struct kobject * parent;

  static struct kobject *child;

  static struct kset *c_kset;

  static unsigned long flag= 1;

  static ssize_t att_show(struct kobject *kobj,struct attribute *attr,char *buf)

  {

  size_t count = 0;

  count += sprintf(&buf[count],"%lu\n",flag);

  return count;

  }

  static ssize_t att_store(struct kobject *kobj,struct attribute *attr,

  const char *buf,size_t count)

  {

  flag = buf[0]-'0';

  //通过kobject_uevent来将内核对象kobj的状态变化通知用户程序

  switch(flag){

  case 0:

  kobject_uevent(kobj,KOBJ_ADD);

  break;

  case 1:

  kobject_uevent(kobj,KOBJ_REMOVE);

  break;

  case 2:

  kobject_uevent(kobj,KOBJ_CHANGE);

  break;

  case 3:

  kobject_uevent(kobj,KOBJ_MOVE);

  break;

  case 4:

  kobject_uevent(kobj,KOBJ_ONLINE);

  break;

  case 5:

  kobject_uevent(kobj,KOBJ_OFFLINE);

  break;

  }

  return count;

  }

  static struct attribute cld_att = {

  .name = "cldatt",

  .mode = 0777,

  };

  static const struct sysfs_ops att_ops = {

  .show = att_show,

  .store = att_store,

  };

  static struct kobj_type cld_ktype = {

  .sysfs_ops = &att_ops,

  };

  static int kobj_demo_init(void)

  {

  int err;

  parent = kobject_create_and_add("pa_obj",NULL);

  child = kzalloc(sizeof(*child),GFP_KERNEL);

  if(!child)

  return PTR_ERR(child);

  //一个能够通知用户空间状态变化的kobject必须隶属于某一个kset,也就是所谓的

  //subsystem,所以此处给内核对象child创建一个kset对象c_kset

  c_kset = kset_create_and_add("c_kset",NULL,parent);

  if(!c_kset)

  return -1;

  child->kset = c_kset;

  err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");

  if(err)

  return err;

  err = sysfs_create_file(child,&cld_att);

  return err;

  }

  static void kobj_demo_exit(void)

  {

  sysfs_remove_file(child,&cld_att);

  kset_unregister(c_kset);

  kobject_del(child);

  kobject_del(parent);

  }

  module_init(kobj_demo_init);

  module_exit(kobj_demo_exit);

  MODULE_LICENSE("GPL");

  陈学松大虾的这个例子十分好。赞一个。

  kobject_create_and_add这个函数首先会调用kobject_create来分配并初始化一个kobject对象,

  然后调用kobject_add函数在sysfs文件系统中为新生成的kobject对象建立一个新的目录。那么这个目录建立在

  sysfs文件系统中的哪个位置呢?kobject_add最后是通过sysfs_craete_dir函数来创建一个目录的,看一下这个函数

  的关键代码便能知道

  /*fs/sysfs/dir.c*/

  int sysfs_create_dir(struct kobject *kobj)

  {

  ...

  if(kobj->parent)

  parent_sd = kobj->parent->sd;

  else

  parent_sd = &sysfs_root;

  ...

  error =create_dir(kobj,parent_sd,type,ns,kobject_name(kobj),&sd);

  if(!error)

  kobj->sd = sd;

  return error;

  }

  可以看到,如果kobj->parent字段为空,那么该函数就会调用create_dir在sysfs文件树的根目录下为kobj创建

  一个新的目录,否则就在parent的目录下为该kobj创建一个新的目录。

  kobject_add首先会将参数parent赋值给kobj的parent成员 kobj->parent =parent,然后调用kobject_add_internal(kobj)函数,

  在kobject_add_internal函数内部,如果调用kobject_add时parent是一个NULL指针,那么要看该kobj是否在一个

  kset对象中,如果是就把该kset中的kobject成员作为kobj的parent;否则kobj的parent值仍然为NULL,那么在接下来

  调用sysfs_create_dir的时候,该kobj就会在/sys目录创建一个新的文件夹。

  /*struct kobject * kobject_create_and_add(const char * name,struct kobject *parent)*/

  例如上面的kobject_create_and_add("pa_obj",NULL);这个函数传入的parent为空,那么他将会在/sys下创建一个目录名为pa_obj的新目录。

  /*struct kset *kset_create_and_add(const char *name,

  struct kset_uevent_ops *uevent_ops,

  struct kobject *parent_kobj)*/

  再看下面的kset_create_and_add("c_kset",NULL,parent);kset里面也有一个内嵌的kobject,所以传入的第一个和第三个参数是

  给这个内嵌的kobject用的,第二个参数是给kset用的。

  看一下kset的结构体原形:

  struct kset {

  struct list_head list;

  spinlock_t list_lock;

  struct kobject kobj;

  struct kset_uevent_ops *uevent_ops;

  };

  多么简单,其实kset在sysfs文件系统中没有实体表现的,他不像kobject,一个kobject对应一个sysfs文件系统下的一个目录,kset的存在无法就是为了

  方便管理kobject。

  kset_create_and_add最终也会调用kobject_create_and_add,传入的参数肯定是""c_kset"和parent,那么将会在/sys/pa_obj的目录下面创建

  一个目录名为c_kset的新目录.

  再来看下面的

  child->kset = c_kset;

  err = kobject_init_and_add(child,&cld_ktype,NULL,"cld_obj");

  kobject_init_and_add与kobject_create_and_add的其中一个区别便是前者可以使用自己定义的kobj_type,而后者内核会提供一个默认的kobj_type

  (读者自己深入函数内部就会看到这个默认的kobj_type)。

  这个函数原型为:int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,

  struct kobject *parent, const char *fmt, ...)

  上面的程序在调用这个函数的时候把parent设置为NULL,由于在调用这个函数之前有这么一行:child->kset = c_kset,如上所分析的那样,

  由于设置了child所属的kset,那么在kobject_init_and_add内部会把child->parent设置为c_kset->kobj,这意味着将会在/sys/pa_obj/c_kset目录下

  创建一个目录名为cld_obj的新目录,如果你把这kobject_init_and_add参数中的NULL改为parent(parent = kobject_create_and_add("pa_obj",NULL);

  这个parent就是pa_obj的对象kobj),那么这么一改,cld_obj目录就和c_kset目录一样都是在/sys/pa_obj目录之下了。

  再下面的sysfs_create_file是在相应的目录下面创建一个属性文件(注意,现在是创建文件而不是目录了)

  上面几个函数是构建linux设备模型框架的最基本的函数。。如果说linux设备模型是一栋摩天大厦,那么这几个函数就是把这个大厦建立起来的最

  底层的建筑工人。

kobject和kset的一些学习心得的更多相关文章

  1. [翻译]你不会想知道的kobject,kset,和ktypes

    ---------------------------------------------------------------------------------------------------- ...

  2. linux设备驱动模型(kobject与kset)

    Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...

  3. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  4. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  5. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  6. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  7. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  8. 我的MYSQL学习心得(六) 函数

    我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  9. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

随机推荐

  1. 【jQuery mobile】启程跨平台开发之旅

    APICloud创建跨平台应用有两种方法,一种在云端直接创建,一种是在APICloud Studio中创建. 创建一个应用 1.注册账号 2.创建HelloApp应用 3.留意应用的ID . 4.下载 ...

  2. javascript学习2

    上次我们了解到 JavaScript提供了一组以window为核心的对象,实现了对浏览器窗口的访问控制.JavaScript中定义了6种重要的对象: window对象       表示浏览器中打开的窗 ...

  3. Java中使用OpenSSL生成的RSA公私钥

    RSA是什么:RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力的 ...

  4. 面试 : C语言 功底 被 鄙视了

    第一道:被鄙视 的 C语言语法问题 请看 下面 程序 : 错误程序: void GetMemory( char *p ){ p = (char *) malloc( 100 );}void Test( ...

  5. ACM-SG函数之S-Nim——hdu1536 hdu1944 poj2960

    S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  6. 基于oracle数据库存储过程的创建及调用

    1.PLSQL编程 1.1概念和目的 PL/SQL(Procedure Language/SQL) PLSQL是Oracle对sql语言的过程化扩展 指在SQL命令语言中增加了过程处理语句(如分支.循 ...

  7. [Oracle]Oracle良性SQL建议

    (1)选择最有效率的表名顺序(只在基于规则的优化器中有效): Oracle的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处 ...

  8. 修改Mac系统host文件

    第一步.在终端里面输入 sudo -i 获取临时获取管理员权限,会提示你输入密码,就是启动的密码. 第二步.输入 vi /etc/hosts  前面的vi是编辑器,当然也可以换用其他的,例如上面的na ...

  9. iOS之Custom UIViewController Transition

    本文学习下自定义ViewController的切换,从无交互的到交互式切换. (本文已同步到我的小站:icocoa,欢迎访问.) iOS7中定义了3个协议: UIViewControllerTrans ...

  10. ztz11的noip模拟赛T3:评分系统

    代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> ...