#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. saltstack安装配置(yum)

    主机规划: (主)master:192.168.25.130 (从)minion:192.168.25.131     192.168.25.132 1.yum安装: 服务端:安装master yum ...

  2. JDK(六)JDK1.8源码分析【集合】LinkedHashMap

    本文转载自joemsu,原文连接 [JDK1.8]JDK1.8集合源码阅读——LinkedHashMap LinkedHashMap的数据结构 可以从上图中看到,LinkedHashMap数据结构相比 ...

  3. i2c 通信

    时间长了记忆就会模糊, 保存下逻辑分析抓到的图像, 什么时候需要可以看一眼. 当clk处于高电平时, data线有下降,说明开始传输, 有上升说明结束传输. 发送地址无回应: 发送地址有回应 正常数据 ...

  4. JavaScript编写简单的增加与减少元素

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 使用interface与类型诊断机制判断一个类型是否实现了某个方法

    Golang中的interface通常用来定义接口,在接口里提供一些方法,其他类型可以实现(implement)这些方法,通过将接口指针指向不同的类型实例实现多态(polymorphism),这是in ...

  6. staticmethod classmethod

    1. 静态方法 @staticmethod 只是名义上归类管,实际上静态方法里访问不了类或者实例中的任何属性 2. 类方法 @classmethod 只能访问类变量,不能访问实例变量 3.属性方法 @ ...

  7. pycharm多行注释

    选中需要注释的代码 ctrl+/ #首字母大写# test = 'alex'# v = test.capitalize()# print (v)## 字符串的加法# n1 = 'my '# n2 = ...

  8. Web—12-详解CSS的相对定位和绝对定位

    CSS的相对定位和绝对定位通常情况下,我们元素的position属性的值默认为static 就是没有定位,元素出现在正常的文档流中,,这个时候你给这个元素设置的left,right,bottom,to ...

  9. jQuery之scroll用法实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. python 基础 切片 迭代 列表生成式

    对list 进行切片 如列表 L = ['Adam', 'Lisa', 'Bart', 'Paul'] L[0:3] ['Adam', 'Lisa', 'Bart'] L[0:3]表示,从索引0开始取 ...