linux设备驱动框架 一、概述 Linux的设备驱动框架是以bus
,driver
,device
,class
为基石,kobject
为基本元素所构成的,配合sysfs
文件系统对操作系统软硬件进行组织,管理的框架。
每个kobject
都对应sysfs
文件系统里面的一个目录,出现在该目录中的文件称为该对象的属性。
二、kobject,kset,subsystem kobject
包含在一个层次化的组织当中,它可以有一个父对象,可以包含在一个kset
对象中。
基本数据结构 kobject 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 struct kobject { char * k_name; char name[KOBJ_NAME_LEN]; struct kref kref ; struct list_head entry ; struct kobject * parent ; struct kset * kset ; struct kobj_type * ktype ; struct dentry * dentry ; };
kset 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 struct kset { struct subsystem * subsys ; struct kobj_type * ktype ; struct list_head list ; struct kobject kobj ; struct kset_hotplug_ops * hotplug_ops ; };
kobj_type 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops * sysfs_ops ; struct attribute ** default_attrs ; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct kset_hotplug_ops { int (*filter)(struct kset *kset, struct kobject *kobj); char *(*name)(struct kset *kset, struct kobject *kobj); int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size); };
subsystem
在高版本中,将其废弃,因为其与kset功能重复,读写信号量的功能被klist替代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct subsystem { struct kset kset ; struct rw_semaphore rwsem ; };
subsys_attribute 1 2 3 4 5 6 7 8 struct subsys_attribute { struct attribute attr ; ssize_t (*show)(struct subsystem *, char *); ssize_t (*store)(struct subsystem *, const char *, size_t ); };
内部API kobject_name
返回其k_name,这是在这个kobj对象分配后才会指定的,其他情况下为NULL,可用用来判断kobj对象是否合法
1 2 3 4 static inline char * kobject_name (struct kobject * kobj) { return kobj->k_name; }
populate_dir
填充目录(kobject是一个目录,这个API使用默认属性建立该目录下的文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 static int populate_dir (struct kobject * kobj) { struct kobj_type * t = get_ktype(kobj); struct attribute * attr ; int error = 0 ; int i; if (t && t->default_attrs) { for (i = 0 ; (attr = t->default_attrs[i]) != NULL ; i++) { if ((error = sysfs_create_file(kobj,attr))) break ; } } return error; }
create_dir
建立kobject
对应的目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static int create_dir (struct kobject * kobj) { int error = 0 ; if (kobject_name(kobj)) { error = sysfs_create_dir(kobj); if (!error) { if ((error = populate_dir(kobj))) sysfs_remove_dir(kobj); } } return error; }
to_kobj
从链表节点得到其kobj
1 2 3 4 static inline struct kobject * to_kobj (struct list_head * entry) { return container_of(entry,struct kobject,entry); }
get_kobj_path_length
得到kobj目录的路径长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 static int get_kobj_path_length (struct kobject *kobj) { int length = 1 ; struct kobject * parent = kobj; do { length += strlen (kobject_name(parent)) + 1 ; parent = parent->parent; } while (parent); return length; }
fill_kobj_path
填充kobject
的路径,第二个参数path
是申请好的内存空间,用以存放kobject
的绝对路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static void fill_kobj_path (struct kobject *kobj, char *path, int length) { struct kobject * parent ; --length; for (parent = kobj; parent; parent = parent->parent) { int cur = strlen (kobject_name(parent)); length -= cur; strncpy (path + length, kobject_name(parent), cur); *(path + --length) = '/' ; } pr_debug("%s: path = '%s'\n" ,__FUNCTION__,path); }
to_kset
由kobj得到其对应的kset
1 2 3 4 static inline struct kset * to_kset (struct kobject * kobj) { return kobj ? container_of(kobj,struct kset,kobj) : NULL ; }
kset_get
若kset存在,递增这个kset->kobj的计数,并将其返回,否则返回NULL
1 2 3 4 static inline struct kset * kset_get (struct kset * k) { return k ? to_kset(kobject_get(&k->kobj)) : NULL ; }
kset_put
递减kset->kobj的计数
1 2 3 4 static inline void kset_put (struct kset * k) { kobject_put(&k->kobj); }
get_ktype
如果这个kobj属于某个kset,并且这个kset有ktype,那么返回这个ktype,否则返回kobj->ktype
由此可以看到,优先返回kset的ktype,因为这一个kset的kobj类型一致
1 2 3 4 5 6 7 static inline struct kobj_type * get_ktype (struct kobject * k) { if (k->kset && k->kset->ktype) return k->kset->ktype; else return k->ktype; }
unlink
将一个kobj从其kset中移除
1 2 3 4 5 6 7 8 9 10 11 static void unlink (struct kobject * kobj) { if (kobj->kset) { down_write(&kobj->kset->subsys->rwsem); list_del_init(&kobj->entry); up_write(&kobj->kset->subsys->rwsem); } kobject_put(kobj); }
to_kset
从kobj得到其kset
1 2 3 4 static inline struct kset * to_kset (struct kobject * kobj) { return kobj ? container_of(kobj,struct kset,kobj) : NULL ; }
kset_get
主要是递增kset中的kobj的引用计数
1 2 3 4 5 static inline struct kset * kset_get (struct kset * k) { return k ? to_kset(kobject_get(&k->kobj)) : NULL ; }
kset_put
递减kset中的kobj的引用计数
1 2 3 4 static inline void kset_put (struct kset * k) { kobject_put(&k->kobj); }
kobj_set_kset_s
为某个对象设置其kset为子系统的kset,这个obj是内嵌有一个kobj对象的结构
1 2 #define kobj_set_kset_s(obj,subsys) \ (obj)->kobj.kset = &(subsys).kset
kset_set_kset_s
子系统下面也是可以有子系统的,这种就是设置子系统的子系统,比如,bus子系统下面有pci子系统,这个宏是为这个子系统内嵌的kset的kobj的上级kset设置为某个子系统的kset
1 2 #define kset_set_kset_s(obj,subsys) \ (obj)->kset.kobj.kset = &(subsys).kset
subsys_set_kset
设置这个对象的子系统的所属kset,一般用于注册总线
1 2 #define subsys_set_kset(obj,_subsys) \ (obj)->subsys.kset.kobj.kset = &(_subsys).kset
subsys_get
递增子系统的计数,其实就是子系统里面的kset的计数
1 2 3 4 static inline struct subsystem * subsys_get (struct subsystem * s) { return s ? container_of(kset_get(&s->kset),struct subsystem,kset) : NULL ; }
subsys_put
递减子系统的计数
1 2 3 4 static inline void subsys_put (struct subsystem * s) { kset_put(&s->kset); }
kobject_release
回调函数,用来kobject_put时,如果计数变为0,将这个kobj资源释放
1 2 3 4 static void kobject_release (struct kref *kref) { kobject_cleanup(container_of(kref, struct kobject, kref)); }
decl_subsys
定义一个子系统
1 2 3 4 5 6 7 8 #define decl_subsys(_name,_type,_hotplug_ops) \ struct subsystem _name##_subsys = { \ .kset = { \ .kobj = { .name = __stringify(_name) }, \ .ktype = _type, \ .hotplug_ops =_hotplug_ops, \ } \ }
decl_subsys_name
定义一个子系统,但是子系统名字和kobj名字不一样
1 2 3 4 5 6 7 8 #define decl_subsys_name(_varname,_name,_type,_hotplug_ops) \ struct subsystem _varname##_subsys = { \ .kset = { \ .kobj = { .name = __stringify(_name) }, \ .ktype = _type, \ .hotplug_ops =_hotplug_ops, \ } \ }
API kobject_get_path
得到这个kobj的完整路径名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 char *kobject_get_path (struct kobject *kobj, int gfp_mask) { char *path; int len; len = get_kobj_path_length(kobj); path = kmalloc(len, gfp_mask); if (!path) return NULL ; memset (path, 0x00 , len); fill_kobj_path(kobj, path, len); return path; }
kobject_init
部分初始化kobj
1 2 3 4 5 6 7 void kobject_init (struct kobject * kobj) { kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); kobj->kset = kset_get(kobj->kset); }
kobject_get
通用的获取kobj对象的方法,会递增其计数
1 2 3 4 5 6 struct kobject * kobject_get (struct kobject * kobj) { if (kobj) kref_get(&kobj->kref); return kobj; }
kobject_add
增加一个kobj对象,也就是在sysfs的目录树中增加一个目录,这里很重要的一个动作是,赋值kobj->k_name
,标识这个kobj是有效的,本函数也会构建好kobj和kset的层级关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int kobject_add (struct kobject * kobj) { int error = 0 ; struct kobject * parent ; if (!(kobj = kobject_get(kobj))) return -ENOENT; if (!kobj->k_name) kobj->k_name = kobj->name; parent = kobject_get(kobj->parent); pr_debug("kobject %s: registering. parent: %s, set: %s\n" , kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>" , kobj->kset ? kobj->kset->kobj.name : "<NULL>" ); if (kobj->kset) { down_write(&kobj->kset->subsys->rwsem); if (!parent) parent = kobject_get(&kobj->kset->kobj); list_add_tail(&kobj->entry,&kobj->kset->list ); up_write(&kobj->kset->subsys->rwsem); } kobj->parent = parent; error = create_dir(kobj); if (error) { unlink(kobj); if (parent) kobject_put(parent); } else { kobject_hotplug(kobj, KOBJ_ADD); } return error; }
kobject_register
初始化并添加一个kobj对象到kset,并增加其对应的sysfs文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int kobject_register (struct kobject * kobj) { int error = 0 ; if (kobj) { kobject_init(kobj); error = kobject_add(kobj); if (error) { printk("kobject_register failed for %s (%d)\n" , kobject_name(kobj),error); dump_stack(); } } else error = -EINVAL; return error; }
kobject_set_name
设置kobject对象的名字
这个函数为何要使用变参?
答:这涉及到操作系统中对kobj对象的命名,对应于device结构中的bus_id,它可能是一个设备名本身,也可能是设备名+ID,这个ID取决于该设备所属的总线分配方式,比如该总线上有五个同类型设备,那么这五个设备的名字可能是xxx0,xxx1,…,xxx4。
这意味着,kobj对象的name可能是多个部分构成的,那么一个可变参数的函数就很有必要了,它可以根据fmt
的格式,拼凑出想要的字符串。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int kobject_set_name (struct kobject * kobj, const char * fmt, ...) { int error = 0 ; int limit = KOBJ_NAME_LEN; int need; va_list args; char * name; va_start(args,fmt); need = vsnprintf(kobj->name,limit,fmt,args); va_end(args); if (need < limit) name = kobj->name; else { limit = need + 1 ; name = kmalloc(limit,GFP_KERNEL); if (!name) { error = -ENOMEM; goto Done; } va_start(args,fmt); need = vsnprintf(name,limit,fmt,args); va_end(args); if (need >= limit) { kfree(name); error = -EFAULT; goto Done; } } if (kobj->k_name && kobj->k_name != kobj->name) kfree(kobj->k_name); kobj->k_name = name; Done: return error; }
kobject_rename
重命名kobj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int kobject_rename (struct kobject * kobj, char *new_name) { int error = 0 ; kobj = kobject_get(kobj); if (!kobj) return -EINVAL; error = sysfs_rename_dir(kobj, new_name); kobject_put(kobj); return error; }
kobject_del
删除kobj对象,如果它在一个kset中,也将其从kset的list中删除
1 2 3 4 5 6 void kobject_del (struct kobject * kobj) { kobject_hotplug(kobj, KOBJ_REMOVE); sysfs_remove_dir(kobj); unlink(kobj); }
kobject_unregister
注销一个kobj对象
1 2 3 4 5 6 void kobject_unregister (struct kobject * kobj) { pr_debug("kobject %s: unregistering\n" ,kobject_name(kobj)); kobject_del(kobj); kobject_put(kobj); }
kobject_cleanup
释放kobj对象对应的资源,通过其注册时的kobj->ktype->release
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void kobject_cleanup (struct kobject * kobj) { struct kobj_type * t = get_ktype(kobj); struct kset * s = kobj->kset; struct kobject * parent = kobj->parent; pr_debug("kobject %s: cleaning up\n" ,kobject_name(kobj)); if (kobj->k_name != kobj->name) kfree(kobj->k_name); kobj->k_name = NULL ; if (t && t->release) t->release(kobj); if (s) kset_put(s); if (parent) kobject_put(parent); }
kobject_put
递减kobj的计数,如果降为0,调用kobject_release
1 2 3 4 5 void kobject_put (struct kobject * kobj) { if (kobj) kref_put(&kobj->kref, kobject_release); }
kset_init
初始化一个kset
1 2 3 4 5 6 7 void kset_init (struct kset * k) { kobject_init(&k->kobj); INIT_LIST_HEAD(&k->list ); }
kset_add
增加一个kset
1 2 3 4 5 6 7 8 int kset_add (struct kset * k) { if (!k->kobj.parent && !k->kobj.kset && k->subsys) k->kobj.parent = &k->subsys->kset.kobj; return kobject_add(&k->kobj); }
kset_register
注册kset
1 2 3 4 5 int kset_register (struct kset * k) { kset_init(k); return kset_add(k); }
kset_unregister
注销kset,其实就是注销kset中的kobj而已
1 2 3 4 void kset_unregister (struct kset * k) { kobject_unregister(&k->kobj); }
kset_find_obj
在kset中搜索一个对象(遍历kset->list)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 struct kobject * kset_find_obj (struct kset * kset, const char * name) { struct list_head * entry ; struct kobject * ret = NULL ; down_read(&kset->subsys->rwsem); list_for_each(entry,&kset->list ) { struct kobject * k = to_kobj(entry); if (kobject_name(k) && !strcmp (kobject_name(k),name)) { ret = kobject_get(k); break ; } } up_read(&kset->subsys->rwsem); return ret; }
subsystem_init
初始化一个子系统
1 2 3 4 5 6 void subsystem_init (struct subsystem * s) { init_rwsem(&s->rwsem); kset_init(&s->kset); }
subsystem_register
注册一个子系统
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int subsystem_register (struct subsystem * s) { int error; subsystem_init(s); pr_debug("subsystem %s: registering\n" ,s->kset.kobj.name); if (!(error = kset_add(&s->kset))) { if (!s->kset.subsys) s->kset.subsys = s; } return error; }
subsystem_unregister
注销子系统
1 2 3 4 5 6 void subsystem_unregister (struct subsystem * s) { pr_debug("subsystem %s: unregistering\n" ,s->kset.kobj.name); kset_unregister(&s->kset); }
subsys_create_file
导出sysfs属性文件
1 2 3 4 5 6 7 8 9 10 int subsys_create_file (struct subsystem * s, struct subsys_attribute * a) { int error = 0 ; if (subsys_get(s)) { error = sysfs_create_file(&s->kset.kobj,&a->attr); subsys_put(s); } return error; }
subsys_remove_file
移除sysfs属性文件
1 2 3 4 5 6 7 void subsys_remove_file (struct subsystem * s, struct subsys_attribute * a) { if (subsys_get(s)) { sysfs_remove_file(&s->kset.kobj,&a->attr); subsys_put(s); } }
三、kobj体系流程梳理 子系统注册流程 在梳理注册流程时,需要谨记所涉及到的数据结构内容。
注册最重要的功能就是为你新增的内容构建其层级关系
subsystem_register
的参数是一个子系统结构体指针,其中有一个读写信号量和一个kset
,因此在注册时,使用subsystem_init
来先初始化这个子系统结构,其内容分别是初始化读写信号量和kset
,这个kset
是内嵌到子系统结构体中的,而kset
中又内嵌了一个kobj
表示其自身,因此这个kobj
也要初始化,还有kset
中的list
链表结构,表示这个kset
没有包含任何子节点。
kobj
的初始化则是初始化其计数器,表示kobj
自身的链表结点,最后,重点来了,这个kobj
如果有其上级节点,就将其上级节点的kobj
计数加一,举个例子,比如一个kset
含有5个kobj
子节点,那么这个kset
本身的kobj
的计数应该是6,包含kset
本身。
此时subsystem_init
的流程走完,subsystem
结构的基础内容已被填充(其实主要是链表,信号量和计数的初始化),接下来,这个新增的子系统需要添加到/sys
的树中,通过的就是kset_add
,因为subsystem
本身的存在是通过kset
来表示的,这也是高版本中删除了subsystem
的原因。
kset_add
中,会进行一个判断,如果你新增的这个kset
没有parent
,也没有上级kset
,但是有所属的子系统,那么将这个kset
的parent
设置为这个子系统,注意,这里并没有为其上级kset
赋值,这种情况一般对应于某个kset
直接挂在子系统下,除了顶级子系统,其他节点都应该在树中的某个位置。
在初始化devices
子系统时,其parent
和上级kset
均为NULL,但是,没有其所属子系统,因此顶级子系统是没有parent
和kset
的。
随后调用kobject_add
,因为kobj
是基石,整个模型是依据kobj
构建的,对子系统,kset
的操作,最终都会落到kobj
上。kobject_add
中最重要的操作,就是给k_name
赋值,因为kobj->name
一般是静态声明时写好的,但是注册是动态的,如何判断这个kobj
已经注册了呢?就是在kobject_add
中为k_name
赋值的操作来声明,这个kobj
已经注册了。
还要通过kobject_get
来递增kobj
的统计计数,如果其parent
存在的话,也需要递增其计数。
然后,如果这个kobj
归属于某个kset
,就将这个kobj
加到其所属kset
的list
链表中,此时,其所属kset
就是这个kobj
的parent
,所以此时,如果之前其parent
不存在的话,这里将其parent
设置为其kset
的kobj
。
还记得之前说的kobj
就是一个目录么?然后为这个kobj
在/sys
中创建对应的目录。
回到subsystem_register
,如果创建kset
成功,则error返回0,满足if的条件,那么如果这个子系统没有归属的子系统时,就将其子系统设置为其自身,至此,子系统注册流程结束。
以devices子系统为例,在其注册完成后,其s->kset->kobj->parent=NULL,s->kset->kobj->kset=NULL,s->kset->subsys=s。可以看到,顶级子系统没有parent,没有kset,但是有subsys
例子:devices_init
设备子系统初始化,即一级目录devices
1 2 3 4 int __init devices_init (void ) { return subsystem_register(&devices_subsys); }
这里初始化一个设备子系统,其中的devices_subsys
由宏生成
1 decl_subsys(devices, &ktype_device, &device_hotplug_ops);
它声明了一个子系统结构体,并将其kset进行赋值,分别是kset->kobj->name,kset->ktype,kset->hotplug_ops。
有一个值得注意的小细节,devices子系统是顶层子系统,因此没有上级节点,在注册时,这个子系统的subsys->kset->kobj->parent=NULL
,作为对比,当注册system
子系统时,由于该子系统归属于devices
子系统, 因此在其注册时,这个区别会在kset_add时显示出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 decl_subsys(system, &ktype_sysdev, NULL );int __init system_bus_init (void ) { system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj; return subsystem_register(&system_subsys); }int kset_add (struct kset * k) { if (!k->kobj.parent && !k->kobj.kset && k->subsys) k->kobj.parent = &k->subsys->kset.kobj; return kobject_add(&k->kobj); }
bus_init
总线子系统初始化,即一级目录bus
同devices_init
差不多
四、linux驱动模型 driver_init——驱动模型初始化 linux的驱动初始化由driver_init
开始,该函数准备好驱动框架,注册好一些/sys
目录下的一级目录,比如devices
,bus
,class
,等等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void __init driver_init (void ) { devices_init(); buses_init(); classes_init(); firmware_init(); platform_bus_init(); system_bus_init(); cpu_dev_init(); attribute_container_init(); }
然后在do_initcalls
里面进行具体某个驱动的注册。
bus_register——总线注册 向系统注册一个总线,会被增加到/sys/bus
目录中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 int bus_register (struct bus_type * bus) { int retval; retval = kobject_set_name(&bus->subsys.kset.kobj, "%s" , bus->name); if (retval) goto out; subsys_set_kset(bus, bus_subsys); retval = subsystem_register(&bus->subsys); if (retval) goto out; kobject_set_name(&bus->devices.kobj, "devices" ); bus->devices.subsys = &bus->subsys; retval = kset_register(&bus->devices); if (retval) goto bus_devices_fail; kobject_set_name(&bus->drivers.kobj, "drivers" ); bus->drivers.subsys = &bus->subsys; bus->drivers.ktype = &ktype_driver; retval = kset_register(&bus->drivers); if (retval) goto bus_drivers_fail; bus_add_attrs(bus); pr_debug("bus type '%s' registered\n" , bus->name); return 0 ; bus_drivers_fail: kset_unregister(&bus->devices); bus_devices_fail: subsystem_unregister(&bus->subsys); out: return retval; }
device_register——设备注册 向系统注册一个设备
1 2 3 4 5 6 7 int device_register (struct device *dev) { device_initialize(dev); return device_add(dev); }
设备的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 void device_initialize (struct device *dev) { kobj_set_kset_s(dev, devices_subsys); kobject_init(&dev->kobj); INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->children); INIT_LIST_HEAD(&dev->driver_list); INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->dma_pools); }
增加一个设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 int device_add (struct device *dev) { struct device *parent = NULL ; int error = -EINVAL; dev = get_device(dev); if (!dev || !strlen (dev->bus_id)) goto Error; parent = get_device(dev->parent); pr_debug("DEV: registering device: ID = '%s'\n" , dev->bus_id); kobject_set_name(&dev->kobj, "%s" , dev->bus_id); if (parent) dev->kobj.parent = &parent->kobj; if ((error = kobject_add(&dev->kobj))) goto Error; if ((error = device_pm_add(dev))) goto PMError; if ((error = bus_add_device(dev))) goto BusError; down_write(&devices_subsys.rwsem); if (parent) list_add_tail(&dev->node, &parent->children); up_write(&devices_subsys.rwsem); if (platform_notify) platform_notify(dev); Done: put_device(dev); return error; BusError: device_pm_remove(dev); PMError: kobject_del(&dev->kobj); Error: if (parent) put_device(parent); goto Done; }
总线去增加这个设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int bus_add_device (struct device * dev) { struct bus_type * bus = get_bus(dev->bus); int error = 0 ; if (bus) { down_write(&dev->bus->subsys.rwsem); pr_debug("bus %s: add device %s\n" , bus->name, dev->bus_id); list_add_tail(&dev->bus_list, &dev->bus->devices.list ); device_attach(dev); up_write(&dev->bus->subsys.rwsem); device_add_attrs(bus, dev); sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); } return error; }
核心函数——找一个驱动去匹配这个设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 int device_attach (struct device * dev) { struct bus_type * bus = dev->bus; struct list_head * entry ; int error; if (dev->driver) { device_bind_driver(dev); return 1 ; } if (bus->match) { list_for_each(entry, &bus->drivers.list ) { struct device_driver * drv = to_drv(entry); error = driver_probe_device(drv, dev); if (!error) return 1 ; if (error != -ENODEV && error != -ENXIO) printk(KERN_WARNING "%s: probe of %s failed with error %d\n" , drv->name, dev->bus_id, error); } } return 0 ; }
驱动去尝试probe设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 int driver_probe_device (struct device_driver * drv, struct device * dev) { if (drv->bus->match && !drv->bus->match(dev, drv)) return -ENODEV; dev->driver = drv; if (drv->probe) { int error = drv->probe(dev); if (error) { dev->driver = NULL ; return error; } } device_bind_driver(dev); return 0 ; }
设备绑定驱动
1 2 3 4 5 6 7 8 9 10 void device_bind_driver (struct device * dev) { pr_debug("bound device '%s' to driver '%s'\n" , dev->bus_id, dev->driver->name); list_add_tail(&dev->driver_list, &dev->driver->devices); sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver" ); }
driver_register——驱动注册 向系统注册一个驱动
1 2 3 4 5 6 7 8 9 int driver_register (struct device_driver * drv) { INIT_LIST_HEAD(&drv->devices); init_MUTEX_LOCKED(&drv->unload_sem); return bus_add_driver(drv); }
向bus增加一个驱动,可以和bus增加一个设备比较一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 int bus_add_driver (struct device_driver * drv) { struct bus_type * bus = get_bus(drv->bus); int error = 0 ; if (bus) { pr_debug("bus %s: add driver %s\n" , bus->name, drv->name); error = kobject_set_name(&drv->kobj, "%s" , drv->name); if (error) { put_bus(bus); return error; } drv->kobj.kset = &bus->drivers; if ((error = kobject_register(&drv->kobj))) { put_bus(bus); return error; } down_write(&bus->subsys.rwsem); driver_attach(drv); up_write(&bus->subsys.rwsem); module_add_driver(drv->owner, drv); driver_add_attrs(bus, drv); } return error; }
驱动绑定设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void driver_attach (struct device_driver * drv) { struct bus_type * bus = drv->bus; struct list_head * entry ; int error; if (!bus->match) return ; list_for_each(entry, &bus->devices.list ) { struct device * dev = container_of(entry, struct device, bus_list); if (!dev->driver) { error = driver_probe_device(drv, dev); if (error && (error != -ENODEV)) printk(KERN_WARNING "%s: probe of %s failed with error %d\n" , drv->name, dev->bus_id, error); } } }