#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. [Python 网络编程] TCP Client (四)

    TCP Client 客户端编程步骤: 创建socket对象 连接到服务端的ip和port,connect()方法 传输数据 使用send.recv方法发送.接收数据 关闭连接,释放资源 最简单的客户 ...

  2. [译] MVP模式的14条规则

    笔者在前文<MVP和MVC>中提到了两者的区别,以及MVP日趋流行的原因:即随着各种给力UI框架的发布,View的功能越来越强,已经足以完成一些简单的不需要与后台或其他view交互的eve ...

  3. 【Git】将项目下的.git目录隐藏

    将项目下的.git目录隐藏 在apache配置文件httpd.conf中添加配置: <Directory "${INSTALL_DIR}/www/mypro/.git"> ...

  4. 关于python接口基础到进阶随笔

    想了很久,闲来无事,今天想了下还是总结了下写下来,部分参考官方源码理解,还有就是这么久的理解, 如果觉得有帮助请记得点赞 先讲下接口url组成拿后台服务为例 通常一个后台请求url格式: http:/ ...

  5. 使用Fiddler监控来自手机客户端的请求

    环境配置组成: 1 手机 2 安装Fiddler的PC 设置要点: 1 手机和PC应在同一个局域网内 我的做法是:PC安装WIFI热点,手机连接热点上网 PC的IP是192.168.95.1  手机的 ...

  6. 多线程系列之 java多线程的个人理解(二)

    前言:上一篇多线程系列之 java多线程的个人理解(一) 讲到了线程.进程.多线程的基本概念,以及多线程在java中的基本实现方式,本篇主要接着上一篇继续讲述多线程在实际项目中的应用以及遇到的诸多问题 ...

  7. JS知识点整理(二)

    前言 这是对平时的一些读书笔记和理解进行整理的第二部分,第一部分请前往:JS知识点整理(一).本文包含一些易混淆.遗漏的知识点,也会配上一些例子,也许不是很完整,也许还会有点杂,但也许会有你需要的,后 ...

  8. iOS 第三方库、插件、知名博客总结

    iOS 第三方库.插件.知名博客总结 用到的组件 1.通过CocoaPods安装 项目名称 项目信息 AFNetworking 网络请求组件 FMDB 本地数据库组件 SDWebImage 多个缩略图 ...

  9. 有关集合的foreach循环里的add/remove

    转自:Hollis(微信号:hollischuang) 在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体原因,本文就来深入分析一下该规定背后的思考. 1 .foreach循环 ...

  10. php图片上传存储源码,可实现预览

    <?php header("content-Type: text/html; charset=gb2312"); $uptypes=array('image/jpg', // ...