#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. virtualbox+vagrant学习-5-Boxes-2-Box Versioning

    Box Versioning 从Vagrant 1.5版本开始, box支持版本控制.这允许创建box的人将更新推送到box中,使用box的人有一个简单的工作流,用于检查更新.更新box以及查看发生了 ...

  2. linux各种压缩包的压缩和解压方法

    .tar/.war(tar是打包,不是压缩) 解包:tar xvf FileName.tar / FileName.war 打包:tar cvf FileName.tar DirName .gz 解压 ...

  3. Spring(九)之事件处理

    Spring的核心是ApplicationContext,它管理bean的完整生命周期.ApplicationContext在加载bean时发布某些类型的事件.例如,ContextStartedEve ...

  4. PHP面试系列 之Linux(五)---- 案例

    题:如何实现每天0点重新启动服务器? 答: (1)创建定时任务,并进行编辑 crontab -e (2)编写脚本内容 * * * reboot 0分  0时  每日  每月  每周 执行的命令:reb ...

  5. postman请求失败

    注意右上角 我点亮了左边的图标,导致任何请求都没法获取到结果,后来知道是右上角的问题,然后就可以成功请求了

  6. 单片机采集的MPU6050原始数据对应关系

    转自:https://blog.csdn.net/u013636775/article/details/69668860 单片机采集的MPU6050原始数据对应关系 1.陀螺仪 如下图, 陀螺仪的范围 ...

  7. ios开发UI篇—UISlider

    概述 UISlider用于从连续范围的值中选择单个值的控件. 当您移动滑块的大拇指时,会将其更新后的值传递给附加的任何动作.滑块的外观是可配置的; 您可以对曲目和大拇指进行着色,并提供出现在滑块末端的 ...

  8. CH4402 小Z的袜子(莫队)

    描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只袜子从1到N编号, ...

  9. 1005. Spell It Right(20)—PAT 甲级

    Given a non-negative integer N, your task is to compute the sum of all the digits of N, and output e ...

  10. Web前端---HTTP协议

    目录 HTTP协议 一.http协议概述 二.http请求报文 1.GET请求 2.POST请求 三.http响应报文 1.响应报文内容 2.状态码(Status Code) HTTP协议 一.htt ...