1.the linux device model--kobject kset学习笔记


http://blog.chinaunix.net/uid-22547469-id-4590385.html?utm_source=jiancool

Linux设备模型就是一栋规模宏大的建筑,为了构建它,需要基本的建筑材料钢筋:kobject、若干钢筋组成的钢架结构:kset,还需要一种机制sysfs,来向外界(用户空间的程序)展示其内部构造。并且通过文件接口的方式实现与外界沟通与互动。

设备文件系统:Linux下一切皆是文件,而设备文件系统包括设备文件、设备节点以及设备特定文件,它们是驱动程序的接口 ,而在文件系统中,他们就像普通文件一样。

devfs是一种Linux2.4内核引入的设备文件系统,用来解决Linux中设备管理混乱的问题位于内核空间,可以通过程序在设备初始化时在/dev下创建设备文件,卸载时将它删除,现已被udev取代。

udevudev是一种工具,它能够根据系统中的硬件设备的状况动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下,使用udev,/dev下面只包含系统中真实存在的设备。它于硬件平台无关的,位于用户空间,需要内核sysfstmpfs的支持,sysfsudev提供设备入口和uevent通道,tmpfsudev设备文件提供存放空间。

mdev在嵌入式系统中,通常可以用udev的轻量级版本mdev,集成于busybox

sysfsLinux2.6所提供的一种跟devfs一样的虚拟文件系统,基于ramfs(内存文件系统)开发,挂在到/sys目录,也是用来对系统的设备进行管理的。sysfs以文件目录层次结构展示了系统硬件设备间的一个拓扑图。

设备、驱动、总线:这些都是对象,已经是宏伟建筑给外界的展现形式的那部分了,主要是与这三个打交道。

详细实现:

1kobject[钢筋]

kobject是组成设备模型的一个最底层的核心数据结构,与sysfs文件系统自然的绑定在一起:每个kobject对应sysfs文件系统中一个目录。kobject结构所能处理的任务以及所支持的代码包括:

1)引用计数;

2维持容器的层次列表和组。

3为容器的属性提供一种用户态查看的视图。

4)热插拔事件的处理:当系统中的硬件热插拔时,在kset(其内嵌有kobject)内核对象的控制下,将产生事件以通知用户空间,该结构一般没有单独定义而是嵌入到其他设备结构体中。

kobject定义如下:

点击(此处)折叠或打开

  1. <kobject.h>
  2. struct kobject{
  3.         const char *name; //该内核对象的名称,在sysfs中,表现形式是一个新的目录名
  4.         struct list_head entry;//用来将一些列的内核对象构成链表
  5.         struct kobject *parent;//指向设备分层的上一层的节点,构建层次化关系
  6.         struct kset *kset;    //所属的kset对象的指针
  7.         struct kobj_type ktype;//用于保存属性,在sysfs中表现为属性文件
  8.         struct sysfs_dirent *sd;
  9.         struct kref kref;//对象引用计数
  10.         ......
  11. }

创建kobject的时候,都回、会给每个kobject一系列默认属性。这些属性保存在kobj_type结构中。



点击(此处)折叠或打开

  1. <kobject.h>
  2. struct kobj_type {
  3.     void (*release)(struct kobject *);
  4.     struct sysfs_ops    * sysfs_ops;//真正实现这些属性
  5.     struct attribute    ** default_attrs;//属性列表,最后一个元素用零填充。
  6. };
  7. <sysfs.h>
  8. struct attribute {
  9.     const char        * name;//属性的名字
  10.     struct module         * owner;//指向模块的指针
  11.     mode_t            mode;//保护位,只读:S_IRUGO。可写:S_IWUSR
  12. };
  13. struct sysfs_ops {
  14.     ssize_t    (*show)(struct kobject *, struct attribute *,char *);
  15.     ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);
  16. }

kobject一般不单独定义,常内嵌于其他结构体中。

经常遇到相反的问题,对于给定的一个kobject指针,如何获得包含他的结构指针呢?嘎嘎,大名鼎鼎的container_of宏有有用了。

比如kp是指向kobj的指针,而kobjcdev device的一个成员,如何根据kp获取只想cdev的指针,如下:

struct cdev *device=container_of(kp,struct cdev,kobj);

 

kobject相关函数:

(1)初始化前第一个操作,将整个kobject设置为0,通常使用memset函数,例如:memset(&kobj,0,sizeof(struct kobject));

(2)设定kobject中的name成员,使用如下函数:
int kobject_set_name(struct kobject *kobj,const char *fmt,...)

(3)初始化一个内核对象的kobject结构,建立kojbect对象间的层次关系,在sysfs中建立一个目录:

int kobject_init_and_add(struct kobject *kobj,

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

(4)从linux设备层次中删除kobj对象:

void kobject_del(struct kobject *kobj);

(5)增加kobject引用计数:

struct kobject * kobject_get(struct kobject * kobj)

(6)减少kobject引用计数:

void kobject_put(struct kobject * kobj)

(7)每个kobject都必须有一个release方法,该方法保存在kobject相关联的kobj_type中。

sysfs中,kobject对应目录,kobject的属性对应这个目录下的文件。调用showstore函数来读写文件,就可以得到属性中的内容。


点击(此处)折叠或打开

  1. kobject.c
  2. #include <linux/device.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/init.h>
  6. #include <linux/string.h>
  7. #include <linux/sysfs.h>
  8. #include <linux/stat.h>
  9. #include <linux/mm.h>

  10. /* 每个kobject必须有一个release方法,该方法保存在kobject相关联的kobj_type中 */
  11. void kobj_release(struct kobject *kobj)
  12. {
  13.     printk("obj_release!\n");
  14. }

  15. ssize_t ops_show(struct kobject *kobj,struct attribute *attr,char *c)
  16. {
  17.     printk("ops_show\n");
  18.     printk("attr->name:%s \n",attr->name);
  19.     return strlen(attr->name);
  20. }

  21. ssize_t ops_store(struct kobject *kobj,struct attribute *attr,const char *buf,size_t count)
  22. {
  23.     printk("ops_store\n");
  24.     printk("buf:%s\n",buf);
  25.     return count;
  26. }

  27. struct attribute first_attr={
  28.     .name="first_attr",//属性名字
  29.     .mode=S_IRWXUGO,    //读写执行权限
  30. };
  31. struct attribute second_attr={
  32.     .name="second_attr",//属性名字
  33.     .mode=S_IRUGO,        //只读
  34. };
  35. static struct attribute *def_attrs[]={//指针数组,每个成员存储了一个attribute的地址。
  36.     &first_attr,
  37.     &second_attr,
  38.     NULL,
  39. };    
  40. struct sysfs_ops sysops={        //定义sysops
  41.     .show        =    ops_show,
  42.     .store    =    ops_store,
  43. };

  44. struct kobj_type ktype={    //定义ktype
  45.     .release    =    kobj_release,    //每个kojbect必须包含的release方法
  46.     .sysfs_ops    =    &sysops,        //实现属性的函数
  47.     .default_attrs    =    def_attrs,//属性列表,二级指针,最后一个元素必须用NULL填充
  48. };

  49. struct kobject kobj;    //定义kobject结构体变量

  50. static __init int kobj_test_init(void) {        //加载kobject.ko时执行该函数
  51.     printk("\n kobj_test_init\n");
  52.     memset(&kobj,0,sizeof(struct kobject));
  53.     printk("memset kobj\n");
  54.     kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
  55.     printk("kobject_init_and_add\n");
  56.     return 0;
  57. }

  58. static __exit void kobj_test_exit(void) {    //卸载kobject时执行此函数
  59.     printk("kobj_test_exit\n");
  60.     kobject_del(&kobj);
  61.     //return 0;
  62. }

  63. module_init(kobj_test_init);
  64. module_exit(kobj_test_exit);
  65. MODULE_AUTHOR("MANGO");
  66. MODULE_LICENSE("Dual BSD/GPL")

编译完成后生成kobject.ko文件,执行sudo insmod kobject.ko



加载成功,因该kobjectparentNULL,会在sys的目录之间建立如下文件:


打开文件夹后,会看到两个属性文件:



first_attr777权限,second_attr是只读权限,和程序中写的相同。

接下来,执行 cat first_attr,会发现驱动层自动调用了ktype中的sysfs_opsshow函数:



同理,执行echo “123” > first_attr,应该调用ops_store函数,执行结果如下:


和预想完全相同。同理可测试second_attr文件,只是不能写而已。

2、kset[由若干个kobject(钢筋)组成的钢架结构]

kset是同种类型的kobject对象的集合,也可以说是对象的容器,通过kset数据结构可以将kobjects组成一颗层次树。kset的名字保存在内嵌的kobject中。

包含在kset中的所有kobject被组织成一个双向循环链表,list是这个链表的链表头。kset数据结构还内嵌了一个kobject对象(kobj),所有属于这个ksetkobject对象的parent域均指向这个内嵌的对象。此外,kset还依赖kobj维护引用计数。

kset和它的kobject的关系如下图所示:


黑线:kset child list

绿线:kobject->parent

蓝线:kobject->kset

注意:一个kobject的父节点不一定是包含他的kset

 

数据结构如下:


点击(此处)折叠或打开

  1. struct kset {
  2.     struct kobj_type    * ktype;
  3.     struct list_head    list;//用于连接该kset中所有kobject的链表头
  4.     spinlock_t        list_lock;//用于互斥访问
  5.     struct kobject        kobj;//嵌入的kobject
  6.     struct kset_uevent_ops    * uevent_ops;
  7. }

kset相关函数:

创建一个对象时,通常要把一个kobject添加到kset中去。两个步骤:

先把kobject内的kset指针指向目的kset

int kobject_add(struct kobject *kobj);

1)初始化一个kset对象:

void kset_init(struct kset * k);

2)用来初始化并向系统注册一个kset对象:

int kobject_register(struct kobject *kobj);

(3)注销kset

void kset_unregister(struct kset *k);

(4)某些时候,将kobjectkset中删除,使用:

void kobject_del(struct kobject *kobj);



点击(此处)折叠或打开

  1. kset.c
  2. #include <linux/device.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/init.h>
  6. #include <linux/string.h>
  7. #include <linux/sysfs.h>
  8. #include <linux/stat.h>
  9. #include <linux/mm.h>

  10. struct kset kset_p;    //父级kset结构体变量
  11. struct kset kset_c;    //子级kset结构体变量

  12. int kset_filter(struct kset *kset,struct kobject *kobj) {
  13.     printk("kset_filter()kobj->name:%s\n",kobj->name);
  14.     return 1;
  15. }
  16. const char *kset_name(struct kset *kset,struct kobject *kobj) {
  17.     static char buf[20];
  18.     printk("kset_name()kobj->name:%s\n",kobj->name);
  19.     sprintf(buf,"%s","kset_name");
  20.     return buf;
  21. }

  22. int kset_uevent(struct kset *kset,struct kobject *kobj,struct kobj_uevent_env *env){
  23.     int i=0;
  24.     printk("kset_uevent()kobj->name:%s\n",kobj->name);
  25.     printk("env:\n");
  26.     while(i<env->envp_idx){
  27.         printk("%s\n",env->envp[i]);
  28.         i++;
  29.         }
  30.     return 0;
  31. }
  32. struct kset_uevent_ops uevent_ops={
  33.     .filter        =    kset_filter,
  34.     .name            =    kset_name,
  35.     .uevent        =    kset_uevent,
  36. };

  37. struct kobj_type my_kobj_type;    //定义ktype变量

  38. static __init int kset_test_init(void) {    //sudo insmod kset.ko调用此函数
  39.     printk("\n kset_test_init\n");
  40.     kobject_set_name(&kset_p.kobj,"kset_p");    //由于kset名字保存在内嵌的kobject中
  41.     kset_p.uevent_ops=&uevent_ops;            //事件通知机制。
  42.         kset_p.kobj.ktype=&my_kobj_type;    //为了规避oops的问题。
  43.     if(kset_register(&kset_p)){                    //向系统注册一个kset对象
  44.             printk("register kset p error\n");
  45.         return -1;
  46.     }
  47.     kobject_set_name(&kset_c.kobj,"kset_c");
  48.     kset_c.kobj.kset=&kset_p;
  49.         kset_c.kobj.ktype=&my_kobj_type;
  50.     if(kset_register(&kset_c)){
  51.             printk("register kset c error\n");
  52.         return -1;
  53.     }
  54.     return 0;
  55. }

  56. static __exit void kset_test_exit(void)    {
  57.     printk("\nkset exit\n");
  58.     kset_unregister(&kset_p);
  59.     kset_unregister(&kset_c);
  60. }

  61. module_init(kset_test_init);
  62. module_exit(kset_test_exit);
  63. MODULE_AUTHOR("MANGO");
  64. MODULE_LICENSE("Dual BSD/GPL");

执行sudo insmod kset.ko:出现如下信息;


在/sys文件夹,会生成kset_p文件夹,打开该文件夹后,出现kset_c文件夹。



3、子系统(一个子系统其实就是对kset和一个信号量的封装)


点击(此处)折叠或打开

  1. struct subsystem{
  2. struct kset kset;
  3. struct rw_semaphore rwsem;
  4. }

子系统函数列表如下:

void subsystem_init(struct kset *);

int  subsystem_register(struct kset *);

void subsystem_unregister(struct kset *);

struct kset *subsys_get(struct kset *s);

void subsys_put(struct kset *s);

4、属性

非默认属性

如果希望在kobject的sysfs目录中添加新的属性,只需要填写一个attribute结构,并把它传递给下面的函数。

int sysfs_create_file(struct kobject *kobj,struct attribute *attr);

删除属性:

int sysfs_remove_file(struct kobject *kobj,struct attribute *attr);

二进制属性(比如支持向设备上载固件的功能)

先定义一个二进制属性结构:

struct bin_attribute {

struct attribute attr;//名字,所有者,二进制属性的权限

size_t size;//最大长度,如果没有最大值设置为0

void *private;

ssize_t (*read)(struct kobject *, char *, loff_t, size_t);

ssize_t (*write)(struct kobject *, char *, loff_t, size_t);

int (*mmap)(struct kobject *, struct bin_attribute *attr,

    struct vm_area_struct *vma);

};

必须显式的创建二进制属性

int  sysfs_create_bin_file(struct kobject *kobj,struct bin_attribute *attr);

void sysfs_remove_bin_file(struct kobject *kobj,struct bin_attribute *attr);

符号链接

sysfs具有常用的树形结构,但是内核中各对象之间的关系远比这复杂。这些树并不能表示驱动程序及其管理的设备之间的关系,为了表示这种关系还需要其他的指针,那就是符号链接。

int sysfs_create_link(struct kobject *kobj,struct kobject *target,const char *name);

void sysfs_remove_link(struct kobject *, const char * name);


5、热插拔机制(从内核空间发送到用户空间的通知)

当一个设备动态加入系统时(比如插入一个U盘),设备驱动程序可以检查到这种设备状态的变化(加入或移除),然后通过某种机制使得在用户空间找到该设备对应的驱动程序模块并加载之。在linux系统上有两种机制可以在设备状态发生变化时,通知用户空间去加载或者卸载该设备所对应的驱动程序模块:一个是udev,另一个是/sbin/hotplug。在Linux早期阶段只有唯一的/sbin/hotplug工具,随着内核的发展,udev机制逐渐取代了/sbin/hotplug。很多ubuntu系统已经不提供/sbin/hotplug工具了。



udev热插拔机制:以守护进程的形式运行,通过侦听内核发出来的 uevent 来管理 /dev目录下的设备文件。不像之前的设备管理工具,udev 在用户空间 (user space) 运行,而不在内核空间 (kernel space) 运行。(验证:ps aux | grep udevd);当设备添加 删除时,udev的守护进程侦听来自内核的uevent,以此添加或者删除 /dev下的设备文件,所以udev只为已经连接的设备产生设备文件,而不会在/dev下产生大量虚无的设备文件;通过 Linux 默认的规则文件,udev/dev/ 里为所有的设备定义了内核设备名称,比如/dev/sda、/dev/hda/dev/fd等等。由于udev是在用户空间(user space)运行,Linux 用户可以通过自定义的规则文件,灵活地产生标识性强的设备文件名,比如 /dev/boot_disk/dev/root_disk/dev/color_printer等等。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信公众号开发笔记1-获取Access Token

获取你的Access Token a&#xff09;可以采用网址的形式&#xff1a; 用appid和appsecert获得access token&#xff0c;接口为https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appid你的APPID&secret你的APPSECRET 替换中间的你的APPID和APPSEC…

ant更改主题色报错Inline JavaScript is not enabled. Is it set in your options? vue ant主题色更改 vue-cli3

问题&#xff1a;使用vue-cli3更改ant的主题色时候报错&#xff1a;Inline JavaScript is not enabled. Is it set in your options? 原因&#xff1a;我的问题是less-loader依赖包的版本为5.0.0&#xff0c;而官方要求必须是6.0.0&#xff1b; ERROR Failed to compile …

ant中table表格的多选框如何清空

项目需求&#xff1a;表格前加一列多选框&#xff0c;可以做多选和提交&#xff0c;还可以在提交后、重置或者翻页后对多选框清空 使用的组件是ant中下的可操作选择的table&#xff1b;这样我们就知道复选框选中的那些数据id&#xff0c;其实就是selectedRowKeys数组里的id&am…

SCCM 2012系列1 服务器准备上

各位您好&#xff0c;今天我将开始给大家分享微软最新的SCCM 2012系列文章&#xff0c;让大家逐步了解在企业内如何搭建SCCM 2012的同时&#xff0c;了解各个功能模块&#xff0c;对应自己的企业环境来看&#xff0c;那些功能是您现在所需要的。当然还可以看看SCCM 2012比之前…

近期H5项目开发小结

前言&#xff1a;2016差不多又过了半啦&#xff0c;最近参与了公司好几个h5项目&#xff08;严格来说&#xff0c;也只能算是推广页面活动&#xff09;。主要是新品牌的推广需要&#xff0c;当然也有给公司以前老客户做的案例。今天主要总结下为新品牌开发的2个h5推广&#xff…

依赖包报错Invalid options object. Less Loader has been initialized using an options object that does not

1.问题&#xff1a;yarn安装依赖包&#xff0c;启动项目报错 error in ./node_modules/ant-design-vue/dist/antd.less Module build failed: ValidationError: Invalid options object. Less Loader has been initialized using an options object that does not match the A…

Asp.net页面和Html页面之间的关系

Asp.net页面显然要转化为普通的html页面才能在浏览器中显示&#xff0c;但是对于两者的关系&#xff0c;或者说从服务器在接受请求处理请求这段时间内对asp.net页面的操作一直不是很明白&#xff0c;下边的一段话可以让人豁然开朗&#xff0c;虽然并未谈论技术&#xff0c;但简…

vue-cli2定制ant-design-vue主题

本篇是vue-cli2定制主题&#xff0c;vue-cli3通过vue.config.js定制主题点击此处 1.引入less和less-loader&#xff08;如果报错&#xff0c;请将less-loader版本更改到5.0.0&#xff09; npm install less less-loader --save2.在 vue cli 2 中定制主题&#xff0c;修改build…

YUV视频格式分析

Andrew Huang <bluedrum163.com> 转载请注明作者及联络方式在摄像头之类编程经常是会碰到YUV格式,而非大家比较熟悉的RGB格式. 我们可以把YUV看成是一个RGB的变种来理解.YUV的原理是把亮度与色度分离&#xff0c;研究证明,人眼对亮度的敏感超过色度。利用这个原理&#x…

自定义ant中table表格的展开图标 修改ant-vue-design中嵌套表格table的expandIcon自定义图标

效果&#xff1a; 1. <a-table:expandIcon"expandIcon":loading"loading":columns"columns":data-source"data"class"components-table-demo-nested"change"onChangeTable":scroll"{x:1300,y:y}":p…

Foundationd和Application Kit的类层次

Foundationd类 Application Kit类 转载于:https://www.cnblogs.com/ikodota/archive/2012/08/01/2618590.html

dup和dup2的使用方法

/*本文通过标准输出的重定向和恢复的过程来解释dup和dup2的使用方法*/#include <stdio.h> #include <unistd.h>#include <fcntl.h>//STDIN_FILENO标准输入描述符&#xff08;0&#xff09;//STDOUT_FILENO标准输出描述符&#xff08;1&#xff09; //STDERR_…

python多线程编程(2): 线程的创建、启动、挂起和退出

From: http://www.cnblogs.com/holbrook/archive/2012/03/02/2376940.html 如上一节&#xff0c;python的threading.Thread类有一个run方法&#xff0c;用于定义线程的功能函数&#xff0c;可以在自己的线程类中覆盖该方法。而创建自己的线程实例后&#xff0c;通过Thread类的…

记录ie下报XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。

问题&#xff1a; 同样的调用接口&#xff0c;在谷歌是没有问题的&#xff0c;但是在ie下报错XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。 1.分析&#xff1a; 对比了一下&#xff0c;相同的是接口传递参数错误导致报错&#xff0c;传递的参数自动带上了 " "…

MVC3.0+DWZ探索

将themes 文件移到 js文件 index.html 转载于:https://www.cnblogs.com/acyy/archive/2012/08/03/2621594.html

棋盘覆盖

在一个2k x 2k ( 即&#xff1a;2^k x 2^k )个方格组成的棋盘中&#xff0c;恰有一个方格与其他方格不同&#xff0c;称该方格为一特殊方格&#xff0c;且称该棋盘为一特殊棋盘。在棋盘覆盖问题中&#xff0c;要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外…

VMM2012应用指南之12- 创建自助服务用户并分配云

河北经贸大学 王春海如果要在云中创建、管理虚拟机&#xff0c;首先要创建自助服务帐户&#xff0c;在创建用户角色的同时即可以分配云。本节介绍这部分内容。【说明】在做下面的这个操作的时候&#xff0c;需要向“库”服务器再添加另外一个库的路径&#xff0c;用于保存云中的…

解决vue项目在ie浏览器下白屏问题;ie运行项目报正在兼容性是图中运行,因为选中了“在兼容性视图中显示Intranet站点”

如果已经配置了babel-polyfill&#xff0c;在ie下依然白屏&#xff0c;打开控制台刷新&#xff0c;看看是否报 正在兼容性是图中运行&#xff0c;因为选中了“在兼容性视图中显示Intranet站点” 如图 解决方案 在ie浏览器—设置—兼容性视图设置&#xff08;B&#xff09;…

python多线程编程(4): 死锁和可重入锁

From: http://www.cnblogs.com/holbrook/archive/2012/03/08/2385449.html 在线程间共享多个资源的时候&#xff0c;如果两个线程分别占有一部分资源并且同时等待对方的资源&#xff0c;就会造成死锁。尽管死锁很少发生&#xff0c;但一旦发生就会造成应用的停止响应。下面看一…