linux驱动结构

来源:互联网 发布:数据决策分析系统 编辑:程序博客网 时间:2024/06/04 18:55
kobject 
    ->kobject *parent 
    ->kset
          ->struct list_head    //指向了所包含的kobject的链表头
          ->struct kobject kobj    
    ->kobj_type
          ->void (*release) (struct kobject *kobj)
 ->struct sysfs_ops *sysfs_ops;
          ....
          
(1).kobject如果没有指定父节点,parent将指向kset内嵌的kobject。
(2)每个kobject都有它的kobj_type字段指针,用来表示kobject在文件系统中
   的操作方法。relase方法是在kobject释放时调用,sysfs_ops指向kobject
   对应的文件操作,default_attrskobject的默认属性,sysfs_ops将使用这
   个属性。


一、kobject在内核的结构:
(1)kobject_create_and_add()函数创建kobject,挂到父kobject,并设置其kobj_type,在文件系统中为其创建目录和属性文件等。
kobject_create_and_add()
->kobject_create()
                ->kobject_init()
->kobject_init_internal()
        ->kobject_add()
->kobject_add_varg()
                    ->kobject_set_name_vargs(kobj, fmt, vargs)
                                ->kvasprintf()
->kobject_add_internal()
->kobject_get(kobj->parent);
->create_dir(kobj)
->sysfs_create_dir(kobj);
->populate_dir(kobj)
->sysfs_remove_dir(kobj)
函数说明:
kobject_create_and_add()接口函数,kobject添加到文件系统中去(实际上是添加到其父节点所代表的kset中去)
kobject_create()为要创建的kobject分配内存空间并对其初始化.
kobject_init()对kobject基本字段进行初始化,用输入参数设置kobj_type属性.
kobject_add_varg中将把fmt指向的内容赋给kobject的name字段。 
kobject_set_name_vargs(kobj, fmt, vargs),如果kobj的name字段指向的内容为空,则为分配一个内存空间并用fmt指向的内容初始化,把地址赋给kobj的name字段。   
kobject_add_varg()返回kobject_add_internal(kobj),就是在这个函数理为kobj创建文件系统结构
kobject_add_internal()检查kobj和它的name字段,不存在则返回错误信息
arent = kobject_get(kobj->parent);获得其父节点,并增加父节点的计数器,kobject结构中的 kref字段用于容器的计数,kobject_get和kobject_put分别   增加和减少计数器,如果计数器为0,则释放该kobject,  kobject_get返回该kobject。
create_dir()函数中具体创建了那些内容
sysfs_create_dir()先为kobj创建了一个目录文件     
如果kobj->parent为NULL,就把&sysfs_root作为父节点sd,即在/sys下面创建结点。
populate_dir:然后调用
由于上面kobject_init(kobj, &dynamic_kobj_ktype)用默认dynamic_kobj_ktype作为kobj_type参数,而dynamic_kobj_ktype的default_attrs为NULL,所以这里没有创建属性文件。
至此,我们已经知道了kobject_create_and_add()函数创建kobject,挂到父kobject,并设置其kobj_type,在文件系统中为其创建目录和属性文件等。
另外,如果我们已静态定义了要创建的kobject,则可以调用kobject_init_and_add()来注册kobject
int kobject_init_and_add()

(2)我们已静态定义了要创建的kobject,则可以调用kobject_init_and_add()来注册kobject


(3)内核提供注销kobject的函数是kobject_del()


二、kset在内核中的结构:
(1)内核同样提供了创建和注册kset的函数kset_create_and_add()
->先调用kset_create ()创建一个kset,接着调用kset_register()注册它
               ->kset_create()中kset内嵌的kobject(这里还未将kobject注册到文件系统),另外用输入参数初始化kset的uevent_ops字段。
               ->kset_register()调用kobject_add_internal()将kset内嵌的kobject注册到文件系统,                 这个函数我们在上面已经分析。
                     ->注册kset会产生一个事件,就是在这里调用了kobject_uevent(&k->kobj,                                KOBJ_ADD)
                          ->如果kobj的kset和parent字段都不存在,说明找不到所属kset,也就没有                                uevent_ops,不能产生事件,返回错误信息;相反则找到了存在kset的kobj                              或父kobject(依次往上找),并赋值给uevent_ops。
->add_uevent_var()kobj_uevent_env填充action_string,kobject路径, 子系统名称以及其他指定环境变量
->调用uevent_ops的uevent函数,编程人员可在此函数中实现自定义的 功能。
                                ->设置KOBJ_ADD和KOBJ_REMOVE的标志。
->添加HOME和PATH环境变量。
->调用hotplug函数。
(2)kset_unregister() 减少其内嵌的kobj计数,为0则释放其内存空间。


常用函数:
1 #define MKDEV(major,minor) (((major) << MINORBITS) | (minor))  将主设备号和次设备号转换成        dev_t类型
2 struct list_head {
        struct list_head *next, *prev;
  };
  #define LIST_HEAD_INIT(name) { &(name), &(name) } 
  相关的几个接口:
->LIST_HEAD() 
  #define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)


  static inline void INIT_LIST_HEAD(struct list_head *list)
  {
        list->next = list;
        list->prev = list;
   }


常见函数:
cdev_alloc(void)
-> kzalloc(sizeof(struct cdev), GFP_KERNEL)
        ->INIT_LIST_HEAD(&p->list)
->kobject_init(&p->kobj, &ktype_cdev_dynamic)


cdev_init(...)
->INIT_LIST_HEAD(&cdev->list)
->kobject_init(&cdev->kobj, &ktype_cdev_default)
->cdev->ops = fops;


cdev_add(...)
->kobj_map(...)   kobj_map 结构的 cdev_map 变量中包含一个散列表用来快速存取所有的对象。
                                   kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保                                     存到 cdev_map 这个散列表里。当后续要打开一个字符设备文件时,                                    通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev 结                                     构变量,从而取出其中的 ops 字段。
0 0
原创粉丝点击