找回密码
 注册
关于网站域名变更的通知
查看: 291|回复: 1
打印 上一主题 下一主题

Linux设备模型——设备驱动模型和sysfs文件系统解读

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-6-17 16:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。
: z" g4 I. b9 Q& V5 \8 H5 @* H
% F! c9 M9 }( o6 @/ v/ ]2 G& U) F0 T内核版本:2.6.30( H! ]1 _) R9 {0 |+ \4 H0 Q$ R$ c
( i, D& O$ L' |! E' z
1. What is sysfs?. ~$ T5 h$ t3 v3 E3 x
  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。
6 G3 _8 ?& M* J' \9 {/ e& _7 W& [$ F
  我们来看看sysfs的文件结构:
/ I& n' ?. J! d; i
/ Q( b; s) ]% r2 l* |2 a+ J- p" }! Z[root@yj423 /sys]#ls
( q; v( w- |- N2 E5 Eblock     class     devices   fs        module
: f0 L  T' T3 E# g+ sbus       dev       firmware  kernel    power$ k9 |  R8 d  k* x
. m! S; @& O7 L4 i: s/ ?5 W9 M
block:块设备4 n" h1 O+ d* H( @

) o; U- o% p: C; kbus:系统中的总线8 X$ X0 A' B3 w5 z

2 V1 \" u( v8 ]+ Tclass: 设备类型,比如输入设备
. o- N4 R5 P" a3 e1 e3 }/ T; j
( s4 R+ \' A, ~! @dev:系统中已注册的设备节点的视图,有两个子目录char和block。
" B! H: D' f# }/ ~# b9 {7 F7 E+ @- J: `& ^0 B4 N( R" u
devices:系统中所有设备拓扑结构视图1 z6 @+ b. m3 Y4 L7 m8 v' @
7 h  n  D/ j' H% t; D
fireware:固件8 ^' T  i/ ?4 x

6 X: W% X) |; Cfs:文件系统
' Q* N- o& \1 ^; [9 Z* [
. l7 u+ W  W+ |; a- b; W2 Tkernel:内核配置选项和状态信息
. O: n" p& r2 }, p* m! o' d0 u9 z; T; d( P, W/ l0 w
module:模块
! y# L, _; q7 E2 K+ x+ L
  E! s* v! z; H# f0 z% S8 Epower:系统的电源管理数据
$ k- u  _7 m1 x' l( h8 B' L3 `! }; t0 W; r& G% q1 x
2. kobject ,kset和ktype) W1 e+ Q; v0 |- k  y
  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。
* e9 |& g6 e" ~$ X+ A7 d
2 r8 f1 Z' P4 }5 y2 u3 m2.1 kobject
/ U0 k# g  Z: {. Y  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。- u5 F4 z1 s4 A0 a4 q5 O& ?

: q8 A" t" T+ n) W7 l) l  kobject用struct kobject来描述。
! q. x) ]  i5 N$ k* }' M; M
4 j$ j4 x' v1 ^0 v9 Y  \9 ^) zstruct kobject {2 t. H& E1 X: U  I' a0 ^9 W2 i
    const char        *name;            /*在sysfs建立目录的名字*/4 V# b) G7 a2 L9 a8 r4 J! a
    struct list_head    entry;        /*用于连接到所属kset的链表中*/
- V5 r% G  h7 ^# ]- O    struct kobject        *parent;    /*父对象*/
3 H( V) @2 i2 u- F+ b% Y8 P: p    struct kset        *kset;            /*属于哪个kset*/; S$ G* b& J( h/ l
    struct kobj_type    *ktype;        /*类型*/; ~4 p8 N8 G  n. z, r" g8 [
    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
. C- A2 ^0 @) k    struct kref        kref;            /*对象的应用计数*/
5 S( o( \. f/ m/ E( Z    unsigned int state_initialized:1;8 N& g# w7 W7 {3 z* }, J# U
    unsigned int state_in_sysfs:1;
3 t: m& w6 [+ o    unsigned int state_add_uevent_sent:1;5 {% T' p/ S3 W
    unsigned int state_remove_uevent_sent:1;) N0 Z& b5 U- e  @% q
    unsigned int uevent_suppress:1;& w* h8 j/ o0 S3 T* t: a
};
' {' R: T' f& s- `2.2 kset2 @# g( k7 U% o; S9 N$ W
  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。, ^" L, C" ?1 V

! p5 Q2 f% ~* \4 J+ L) {. l  kset使用struct kset来描述。
: I0 ]0 y# s1 b5 b; U
& m9 Y; N: A  J/**
6 t; z1 s% |* R4 @8 n4 a( c. D5 A * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.6 |9 ^6 S6 V' S) L* W: M/ r; j3 V
*2 h5 Q5 D/ n9 @( B1 R
* A kset defines a group of kobjects.  They can be individually8 M7 [# I/ r# ?- l- P4 Z' [9 E
* different "types" but overall these kobjects all want to be grouped
3 T. T" n5 C  A) |  M; ~$ d * together and operated on in the same manner.  ksets are used to
* V- H: @' C# } * define the attribute callbacks and other common events that happen to" z( }- c' N- M2 {5 p: v
* a kobject.. R, n6 |; j  A5 {
*
8 V) J% M" P! i  U5 c: ] * @list: the list of all kobjects for this kset
0 R1 K2 d0 I* L3 L( G# b* P* ?9 C! O * @list_lock: a lock for iterating over the kobjects
' p6 a* e6 [& n0 \$ [ * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)) K: q* J  V% e: Y
* @uevent_ops: the set of uevent operations for this kset.  These are# m: ?6 @3 L4 A8 ^, t& e
* called whenever a kobject has something happen to it so that the kset
: d5 e/ x% t+ a+ p/ T1 U. P( h* \ * can add new environment variables, or filter out the uevents if so) w* }7 W$ c; e# W/ e( T6 T
* desired.- G3 T+ I  P5 }. n5 o6 m
*/% F) `+ S4 c4 S$ F
struct kset {) D# t) Z) _. \0 b+ r7 r6 f& @
        struct list_head list;                /*属于该kset的kobject链表*/! a- M( v4 O! V
        spinlock_t list_lock;        8 i: z- v# u( a
        struct kobject kobj;        /*该kset内嵌的kobj*/; B: H$ a" `7 v7 w
; B' K) D2 N: Q2 Y
        struct kset_uevent_ops *uevent_ops;7 z& V% K3 j1 B% F2 J1 u* R
};" l# o/ L- i' ^9 H
8 C/ m' @- V/ Q  F( c( E
2.3 ktype
6 B) T" l5 g1 w, M每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。" M6 t. p" q# a' X  Q
$ w7 m6 Z) W6 y& N% o) s
struct kobj_type {
+ \% I! T/ E; b/ s    void (*release)(struct kobject *kobj);8 ?  Y% A2 ]9 K6 L2 M" ^
    struct sysfs_ops *sysfs_ops;
7 }7 p" ]" s: V    struct attribute **default_attrs;1 B, ^# Q: k# R# l2 T
};0 B$ W; @0 H+ J
6 M+ O  ~& M% P1 F* D: E
struct sysfs_ops {
( k3 j6 _% F" f. B( `0 a    ssize_t    (*show)(struct kobject *, struct attribute *,char *);
. ?" y; ^6 f1 c/ Y) n& z# w    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);! t; ?  k9 X$ N) b6 f- i# }8 k( y
};# C/ |3 W7 p- R" x* Z

. o, \# V7 n( W! w' W' D5 n- o# R, g/* FIXME* m9 b4 t( i" ~9 {  a
* The *owner field is no longer used.* X3 ]3 ]( d- [3 m' f$ y
* x86 tree has been cleaned up. The owner
  n- F4 Z- T. z" `" L * attribute is still left for other arches.
4 J$ R9 [2 ]' B */: `! p9 M/ W& L' v
struct attribute {$ i4 d! Q5 i, q! M5 G* j8 Y
    const char        *name;
2 d& E: s+ ?. I: G    struct module        *owner;
; f8 {1 y& N3 w, h6 r0 f    mode_t            mode;
/ Y) f4 f6 s* a$ b# ^7 G; [};% K- G, f8 q  u

9 Y7 m3 i# E5 U  U2 T5 O; A% T+ r$ t" P
当kobject的引用计数为0时,通过release方法来释放相关的资源。
, f$ N& B3 e1 Z" H1 k. s' @attribute为属性,每个属性在sysfs中都有对应的属性文件。* H" ^, N$ d: a& Q6 o1 N! D4 N

7 ?2 J2 j3 C& z/ csysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。
( I2 N" H+ c3 ~; d9 I5 @0 \# Z2 {1 j
2.4 kobject与kset的关系  ^7 B3 k* g; N& p/ a( H
  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。
7 a/ L* [/ I- n. o7 Y- N
  a! P! {0 l& u# ~3 r: f( R* Z   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。- S/ i  o) }: v  b3 Z$ k. s
/ X- B$ z0 X0 K2 q

* w3 M) Z" i( V$ q
7 f* P* t9 \: [7 y0 d  S$ Y3.举例8 Y. x0 V+ i# g$ D: D
在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。
5 _- X: a* i, Q/ T5 B, \5 d. F, r  e& f: |; h# B" _
下面代码位于drivers/base/bus.c
& X: X# ^- z7 j# m) ]int __init buses_init(void)
9 ]; E* x+ v* B3 z( O) e$ `3 r{
! @  X* f$ y7 s        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
: {3 U7 Z6 s2 b- }" b" E1 u        if (!bus_kset)
. [" N( \+ |5 j# Y7 G3 }+ w, c                return -ENOMEM;
+ V% E' P% y2 R+ N" N        return 0;# l$ K( K8 R0 [
}+ J0 I) C1 k- |7 J7 q/ Q

% r; W- |9 Z2 `/ _$ Nstatic struct kset_uevent_ops bus_uevent_ops = {5 q8 J, Z+ g' g3 L  s, {
    .filter = bus_uevent_filter,/ R2 p& {0 C/ T5 M
};
/ z+ `1 J. V% O$ n
) I' N, Q! W- \9 \# B: lstatic int bus_uevent_filter(struct kset *kset, struct kobject *kobj)& H" G" {8 Z6 ^$ O
{
! O) O+ O& _$ j. Q* `; m4 h5 Z    struct kobj_type *ktype = get_ktype(kobj);
$ E. U8 g' @; h3 m! m" W! [! K/ B& p1 g; P; I0 a4 W
    if (ktype == &bus_ktype)' e8 g" `: `) \0 o2 Y& ~
        return 1;
/ V' b. T3 \  _    return 0;& H2 p7 v) |2 g( P8 b
}6 f# E' V/ q+ s
这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。6 Z2 g. \; T! A" y/ Q# p* r
下面代码位于drivers/base/kobject.c
/ |& F1 Q7 A$ o/ I8 \: K8 O/**
4 \; ~% P% _- Q- e * kset_create_and_add - create a struct kset dynamically and add it to sysfs7 c1 v9 v, A( T! `* V3 }
*8 c0 Z3 e5 i8 e9 \
* @name: the name for the kset
/ Q) E; f: q( O# u# X- S# F  @ * @uevent_ops: a struct kset_uevent_ops for the kset( c, I* L( L, |: K
* @parent_kobj: the parent kobject of this kset, if any.
8 o5 C% @. p0 o7 w3 R; U *
4 {: c9 i" z# v0 m2 V8 l * This function creates a kset structure dynamically and registers it
& q4 g' ]/ f1 v6 L1 q4 h * with sysfs.  When you are finished with this structure, call
% ?" L" u8 i' \+ U! K# m9 ?' Q * kset_unregister() and the structure will be dynamically freed when it* v" a. }; _  `5 p, G- f
* is no longer being used.' {$ @2 X" S- p) }
*( H$ N( s" n3 r; e0 l
* If the kset was not able to be created, NULL will be returned.1 f1 Q  ]2 V7 W6 p) i+ w+ Q
*/
* r7 \4 a5 N+ U# G: L' xstruct kset *kset_create_and_add(const char *name,
& ?. h  i/ m' G9 E# m                                 struct kset_uevent_ops *uevent_ops,: E) q. [1 r1 _
                                 struct kobject *parent_kobj)# W/ o: u2 L+ {% `$ y: K
{
# `/ I$ D3 G$ H  r3 o- C( W        struct kset *kset;
/ q1 }- F; ~8 A/ {/ D* R# b7 @        int error;$ h. b6 ^/ v0 T& u! C9 G! ^% W
( k2 _% @9 E+ h8 J% q  a, H2 ~
        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/6 V" l1 u& x3 I
        if (!kset)9 H9 e0 j" L4 s. U* J+ P
                return NULL;
$ f% f( u' z1 [        error = kset_register(kset);        /*添加kset到sysfs*/
+ ?7 c/ s* `' T1 G, R        if (error) {' t) B3 L' y+ |6 x- H
                kfree(kset);
8 ?% x* V" ^/ D1 |                return NULL;5 N" j+ m6 _) C' h
        }0 j! E& s; D9 X
        return kset;+ D+ c6 K, v1 h, b) z3 t
}2 j* x9 {7 Y0 x6 C
这里主要调用了两个函数,接下分别来看下。
. A" X3 z& k2 G# o- X7 J
# _: m$ a3 s+ |% e% t0 g5 n3.1 kset_create函数
: u6 C# |, ]& x  l9 W# [- n+ {2 d" B下面代码位于drivers/base/kobject.c0 n8 ^" E+ }0 ?* n( P" R8 X

# H7 Y% d# z; E7 C  p& M1 |/**1 W9 l2 c2 e( [& [! ]6 H
* kset_create - create a struct kset dynamically
9 F, r9 e: Q/ ] *
6 s0 M0 G: S  ]+ ]* K * @name: the name for the kset
, t) f1 y3 Q1 U( s" [( g * @uevent_ops: a struct kset_uevent_ops for the kset
" p5 @4 E  K' i+ E * @parent_kobj: the parent kobject of this kset, if any.* b$ A  v5 ~6 T. L
*& d5 t/ L; g+ M3 f/ l0 c8 r4 z
* This function creates a kset structure dynamically.  This structure can
/ Z& t( T3 k" G9 c) x; @ * then be registered with the system and show up in sysfs with a call to
2 R' o' e9 I9 w * kset_register().  When you are finished with this structure, if* Y4 Z' t9 v1 X) `$ b- y
* kset_register() has been called, call kset_unregister() and the% G9 u4 N( l; n1 l" N& H6 e
* structure will be dynamically freed when it is no longer being used.
0 i6 [, U* K2 U3 x! N *
* m: r+ B3 ]9 \5 W# u0 E% N6 N * If the kset was not able to be created, NULL will be returned.9 v/ d* B% t( u1 ]6 x: X- e
*/3 F# P5 P& R+ I( P8 ~
static struct kset *kset_create(const char *name,$ {: [9 E0 P* j4 l& g* o
                                struct kset_uevent_ops *uevent_ops,+ ?  x" q% R9 N% k
                                struct kobject *parent_kobj)
* a( T. V% j6 H8 |; t+ k{
% x7 h( T5 r& H/ A3 S5 }5 N" C        struct kset *kset;
' ]& J; Z/ l6 i+ G: m: f
' q* u+ [% S' d/ g7 s        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/% O) A' b6 b( Y( r! w
        if (!kset)
9 F8 f! G0 |- q( E1 N- H8 m                return NULL;
: ?4 S0 o7 P% A! s2 J" J# x% [        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/) j9 G5 S6 _5 d& m. e% Y  k
        kset->uevent_ops = uevent_ops;: ?- M3 [6 q. E
        kset->kobj.parent = parent_kobj;        /*设置父对象*/0 J; P1 R& f/ V* o0 a' X. B
6 [' E1 e/ I" d' e: C4 \5 p
        /*
# T! v7 `4 u2 K% T1 }/ i- b         * The kobject of this kset will have a type of kset_ktype and belong to* d% I: l; U/ C2 K
         * no kset itself.  That way we can properly free it when it is, L5 {8 F7 ^; G* H& l* d; Q
         * finished being used., V' O2 m9 C8 A* w) I
         */7 i3 u- g6 V$ l+ i! N! U) K3 \
        kset->kobj.ktype = &kset_ktype;
, q/ \+ ]6 E. P  \        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/
+ A' A, \$ e7 A& D& G& F. d9 ^# P
8 r( i+ v: D8 ]- r! \7 y. \        return kset;
) M4 H3 e& _. T" v}; L# V# ]4 ]3 S+ ?7 _" N

( Q4 ~' K: J/ |  a1 ^0 {这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,9 h$ ]+ g' I- D
) E1 n5 a1 F3 d6 h% C$ H
也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。
# p& C, j9 B7 G2 d4 f+ ^- I. u6 Q( u& K  v0 h" u- q" {' O3 H/ q
随后简要看下由kobject_set_name函数调用引发的一系列调用。( o* p4 e2 V# S' h

* V5 q+ i5 H3 q6 {( i& a/**- y" I  j4 j) z
* kobject_set_name - Set the name of a kobject: _% Z4 q9 h1 G3 _# [. I
* @kobj: struct kobject to set the name of0 g% r  z' d+ w' L' a: D
* @fmt: format string used to build the name" N: r+ H5 f* @3 J
*
- {" ?. _% ^  C * This sets the name of the kobject.  If you have already added the
# d8 _% E; \) e * kobject to the system, you must call kobject_rename() in order to
% u+ m% F* w: H, ~) I * change the name of the kobject.; }' q7 u$ q# }# ^! S% A, I0 P) H0 Z) n+ X
*/
9 x+ e9 \3 p( z+ x0 u2 D5 f% w( Lint kobject_set_name(struct kobject *kobj, const char *fmt, ...)* ?6 C0 V) o( F: L& V7 z
{9 N) v5 o$ q% a5 E1 Q4 Y; D& p
        va_list vargs;
- m6 G* n  S+ ^' P% [. C        int retval;2 T2 X6 |7 |, ?! s) p9 Y0 @7 [/ S
9 Q0 H7 j! Z/ N1 P' C
        va_start(vargs, fmt);2 V. J8 }5 h% A, J5 K$ U/ E
        retval = kobject_set_name_vargs(kobj, fmt, vargs);
  e# F' a: P/ i( S" K# j$ n        va_end(vargs);
. |) K2 p* {" z) E- v. c2 C, C4 E
, U3 }8 z6 J9 W2 g5 {        return retval;+ Y  d0 W, }' G/ o& j9 G
}
7 J6 s- q8 b2 {  a: t  A
! |. z8 I7 C" S: s  p& F/ A  @/**
# Q* ~2 Z& l6 U2 d * kobject_set_name_vargs - Set the name of an kobject9 x* S/ x  n. d+ @4 i9 H
* @kobj: struct kobject to set the name of! W5 ?( q( j, `& C5 ~
* @fmt: format string used to build the name
  h8 k! p; b9 w. v7 e * @vargs: vargs to format the string.  F' ~3 X& l; \0 x
*/
! s8 Z1 i1 f! a5 ^int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,# s3 f! W, w' m% J- J! V! q
                  va_list vargs)
1 e/ a1 G* q2 t$ G. i% |# Z{
# X4 X9 f8 S# f* O) z    const char *old_name = kobj->name;. D0 g# I3 B! n8 @
    char *s;/ {9 \4 f: k2 k4 j
1 {5 G5 E" U4 e7 H
    if (kobj->name && !fmt)
% X: W$ k( y2 k- w        return 0;
: D" I; N& n+ ]- Z. A
0 @  P0 M; X" ?+ w    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
. J2 S8 r* j. C! T8 F    if (!kobj->name)2 T: p. n5 r" _
        return -ENOMEM;3 h4 C7 A+ R0 i* m
& R5 j' A$ L( o0 ^" f3 X
    /* ewww... some of these buggers have '/' in the name ... */
- l9 V; D3 d2 e' r    while ((s = strchr(kobj->name, '/')))
% o2 S) k) ^4 W/ ~( s        s[0] = '!';
. ~# o9 k. E, f/ I& q; ?
2 |; e" }6 n+ K3 b    kfree(old_name);
1 T# u, R6 e/ E; m, `  P' f    return 0;
: Y! q- y6 t; o0 g# q' K}1 m( S6 `1 }6 c8 Y: K- T) f- S
: _+ f& p6 e8 F8 u' e0 V& T
/* Simplified asprintf. */
# N7 R. S& n9 i" J; o& b6 cchar *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
. p* J' O5 X1 b/ a# s" X  O{
  x, t1 a1 [8 o8 C    unsigned int len;$ b! e+ t+ X. H5 O8 G, @  \
    char *p;
* F+ n& L/ v( T, ~    va_list aq;3 w4 `6 B4 w2 I0 J, L# V
* n% R  V$ f& E; U
    va_copy(aq, ap);
" B/ p2 }) S! m1 c0 u- }    len = vsnprintf(NULL, 0, fmt, aq);
) @( Z, w9 |$ g5 E- i4 m    va_end(aq);) h2 o" `% F7 v( ^( c5 e
( I( A9 c4 U. Q3 C9 ^0 q' r) \, h. v
    p = kmalloc(len+1, gfp);
7 ]% C  p- d1 x, v    if (!p)
  p  Z, D% D( ?, u" K! O, u        return NULL;7 Y) d2 k$ z: X; q/ `5 F

9 `5 y9 i& E: t2 f  z' c    vsnprintf(p, len+1, fmt, ap);
9 n, B; x5 O7 S' \0 [9 ?
! y. L5 n& G* }; h7 a2 I, v    return p;. Q7 V: j8 T; u% x
}7 Y3 P  [2 p/ J  K( W( y( d
3.2 kset_register$ z: o: i& l# r5 S/ n
下面代码位于drivers/base/kobject.c。
) t% H* t6 K: V1 B/**
- D" T  N$ }. j. S1 D1 o * kset_register - initialize and add a kset.
6 p$ {# O$ p" f, s * @k: kset.
6 Y! C# V8 t9 Z1 }; T3 x */
# L: `# Q% D0 I' Nint kset_register(struct kset *k)
4 \9 l6 Z( H  b# W& ^{6 r$ C) b  ^0 s
        int err;
) {+ o9 i3 `# a. F: F3 e5 G
* h0 {  r, @$ D' W6 {        if (!k)2 H1 M2 L' l- ^# {
                return -EINVAL;
  X% y3 P" g8 _& \5 ^: N
2 z8 w! r; `& Q; q        kset_init(k);           /*初始化kset*/
( r3 j2 }/ _) x( Y( R) j        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/
- r) G. U6 A* H& w. i, M        if (err)
3 P) Q" @  Z% r& l* ^4 E. j: I                return err;
7 ?% N9 |6 e3 m: \: R/ N; k; T* `        kobject_uevent(&k->kobj, KOBJ_ADD);
8 H% y8 p$ {) y& x- q4 O        return 0;0 S' X* o8 A8 N% N- S9 ]: a
}
: o/ p7 c3 A7 ?4 q# |& a这里面调用了3个函数。这里先介绍前两个函数。# H' P1 K6 }, J& G( e9 S" q1 b

4 W' b5 [  Z% k9 \9 I+ q' c3.2.1 kset_init) y' M  @% z: r% `7 B
  该函数用于初始化kset。
( j; o9 @3 ]3 ~  [0 e* i6 V
9 M" p. h0 N/ ^! \  下面代码位于drivers/base/kobject.c。% R3 ?; _8 }2 T

/ V) g! F' [' H0 z/**
: i# D7 m# v$ z * kset_init - initialize a kset for use. g8 b7 n* V2 {
* @k: kset) B& T+ V8 l- T5 H: ?
*/
; u) S* m1 e: w, L7 Dvoid kset_init(struct kset *k)
6 i1 F2 X6 y1 R) |. q, ~+ N{. }6 n- ^) N( I5 a( W' R3 s
        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
- }6 o* q. o3 O6 ~" y8 r8 r        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/$ U# L- o2 H/ z- b, D  J
        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/
) D3 m! [0 Y7 s# B6 e2 V}
8 G" l4 M7 u; ?& }
, q) b4 W1 z$ `4 R! f$ P" r- Nstatic void kobject_init_internal(struct kobject *kobj)
  ?* F6 Q0 h) O) `: O- S$ I{1 {% K. z! x9 ]7 Z; g0 ~; F
    if (!kobj)
$ `# u6 q8 e  F' j        return;
0 M* q% `, z2 I* L6 W    kref_init(&kobj->kref);           /*初始化引用基计数*/
. ^) R/ ^) y! m& _" V/ g8 R% A4 U    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/" [3 ]& r: V+ ~* A4 p( n/ i& U% j$ C
    kobj->state_in_sysfs = 0;
# C0 h) ~! ?5 O' ^    kobj->state_add_uevent_sent = 0;. v( Y5 J4 A- t; V4 f2 I! V# ~
    kobj->state_remove_uevent_sent = 0;
) U# ?! v3 V% o' D/ @    kobj->state_initialized = 1;
$ l! n6 ?* ]4 R}
& A8 z+ ^1 o+ `" x; \3.2.2 kobject_add_internal
- @7 x' x& P# p- M! v$ m) @  该函数将在sysfs中建立目录。
& m5 n& N& L& \
, q2 {. _( h& y; w1 K& y! X: p: u9 w 下面代码位于drivers/base/kobject.c。
' o& Q4 W2 ^% q  Hstatic int kobject_add_internal(struct kobject *kobj)
8 d8 J5 Y$ M$ q. S: D{
) @+ e# r$ u% H: D( @        int error = 0;
2 X/ Z) K$ C* A# Q- T7 A; E        struct kobject *parent;: P$ _# U, v2 n5 _! s$ _4 [

5 f" A$ ]# I' f$ x% B  J        if (!kobj)  m' w4 }! I8 X( f  e
                return -ENOENT;
0 C+ F: z2 A/ l        /*检查name字段是否存在*/3 |# c) i4 a2 [  V
        if (!kobj->name || !kobj->name[0]) {
! L7 K9 X, s+ P8 M1 {  L                WARN(1, "kobject: (%p): attempted to be registered with empty "+ }7 J8 H7 i0 _7 |
                         "name!\n", kobj);/ D$ S) j5 g: V$ l9 J9 S
                return -EINVAL;! L1 p2 b/ {! C7 O) F1 f
        }
, A4 B9 X9 L; S' I& P% `& \5 q
" Q/ k* k/ H3 h6 ?        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/5 z& [1 x" m) u2 n
5 I6 {7 g2 g0 r- O! {: X: w
        /* join kset if set, use it as parent if we do not already have one */
% E/ h# Z1 }+ `' V4 P" G        if (kobj->kset) {        ) ]/ t$ z9 q5 m& U
                if (!parent)
  {8 ?- [) G. q" z. o  y                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
! v9 g9 C% f( q                        parent = kobject_get(&kobj->kset->kobj);2 j7 i: x9 {4 y( v+ `/ c4 l) h
                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/& `! x! c4 U" k; T
                kobj->parent = parent;* C0 `6 ?9 u/ ~! i
        }
7 j/ \# r1 N9 F2 `' _; ~0 S
3 S4 Y$ x( P9 f+ a        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
9 N, O+ }' t5 ^, p* g                 kobject_name(kobj), kobj, __func__,. X6 F& ^1 `7 J+ j2 }
                 parent ? kobject_name(parent) : "<NULL>",9 |: c3 j- c# |
                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");0 u/ M; y2 f3 Z: U6 ]' J

. r6 _: q. k: Z) p" S6 N5 d        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/. l, w& o+ Z, U2 }) `- T" M5 u
        if (error) {1 f1 B! r8 ?: u* p3 x0 B
                kobj_kset_leave(kobj);        /*删除链表项*/
( e# f. C- F: {2 }( |                kobject_put(parent);        /*减少引用计数*/7 c) ^' U5 U" q' E3 ~; I- c, W
                kobj->parent = NULL;
8 G& G7 A; w/ ]4 o! U+ H1 H. P/ q& |" T) K
                /* be noisy on error issues */0 r0 T4 G* |  l0 \+ a  s5 T
                if (error == -EEXIST)  J" W# y0 x6 A1 i0 X
                        printk(KERN_ERR "%s failed for %s with "+ R* B8 s7 |; C8 ^7 G8 `
                               "-EEXIST, don't try to register things with "# f1 [1 T$ A, I' d( d% `
                               "the same name in the same directory.\n",+ A7 q% p; a+ c# A. j
                               __func__, kobject_name(kobj));  A5 y; D  N8 {% f4 r
                else
/ k: l) s: x! @% e. h                        printk(KERN_ERR "%s failed for %s (%d)\n",9 k5 a2 t8 R! k* a$ j" n: R
                               __func__, kobject_name(kobj), error);
) J, z8 J# E5 d! y4 h8 s                dump_stack();
4 R6 ?' X( A' M* ?2 X        } else+ ^4 E/ }( T) R$ w9 `0 q
                kobj->state_in_sysfs = 1;: @0 z9 K7 U/ v
) V1 V+ V6 G3 R3 {1 i4 t+ [) ^% Q* w
        return error;4 _; g& t9 K' U  ~6 {' B
}, X) C; i- b/ Y
% s3 p: p3 d( t8 b! Q' C
在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。: ~( g* }, F; q+ H4 A- P. {+ ^

5 I+ x, ?. F! }  h8 ^/ ~. Q+ d在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。3 b: v& m3 T1 S: P9 |- T

$ N$ v2 z2 J" L5 M7 a至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。
) B- k+ g& q+ V5 o' n0 [
* |( }' V- B8 B1 R5 y4. driver model
. U, t1 P4 n& u! E第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。
1 b. M# u8 r$ |
6 c) [! @( X1 R! U4 xLinux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。8 M* D, N" I, q

. ?- [" O2 s. u2 h这个属于分离的思想,将设备和驱动分开管理。# f' ^# m+ B& W3 K

. }* I9 L4 R  l3 N. y# n+ R4 m1 k同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。4 ^- L, _8 |' X$ D/ c# \+ k
6 y' P, w3 ?8 F& k$ M
4.1 bus
3 b7 M5 Q; {+ n! C总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。
0 g' O/ j. t" a6 ^" C) G6 F  [0 H) @; A8 l$ |( A$ H
下列代码位于include/linux/device.h。
+ f" P& W. ~+ |( D- V
, n. U* T1 H0 J9 l3 a
. G# ?( Q% J7 A" ~- f4 H4 `struct bus_type {
. h9 Y# S! v" D0 A* L# o3 I1 w; |5 q    const char        *name;  o5 }; g0 W+ i9 U
    struct bus_attribute    *bus_attrs;
) T9 O) q6 K0 a) T& s! ~    struct device_attribute    *dev_attrs;4 g: R) |9 @" F( B$ n
    struct driver_attribute    *drv_attrs;
* @8 _8 c) l# P* [
/ j" h5 b. b& H+ V2 W    int (*match)(struct device *dev, struct device_driver *drv);
+ z/ N( C1 V) o' V# C* X    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);% V2 i4 w# X' ?( n6 S7 P/ H0 M4 H
    int (*probe)(struct device *dev);
- v; L8 U, C* |* F5 K0 y    int (*remove)(struct device *dev);
  h# p( c3 t2 e$ J    void (*shutdown)(struct device *dev);
! S6 w7 D5 N) x6 _- i
* @0 H7 v5 r1 r& ?+ X: b1 x& s7 a    int (*suspend)(struct device *dev, pm_message_t state);  _; [3 f2 d/ M0 y. Q) b, C! H! h
    int (*suspend_late)(struct device *dev, pm_message_t state);5 z' M7 P# c9 y. x! L1 M6 i6 k
    int (*resume_early)(struct device *dev);
, `' [- v' E- c    int (*resume)(struct device *dev);' L7 u4 }2 p  G9 c( R2 J

8 i9 G4 m, x; T% r* A: i! X# H    struct dev_pm_ops *pm;
$ O/ O) [1 d1 j# `1 g) Y0 n) m' _- h7 A2 y; f8 S
    struct bus_type_private *p;- Y/ I* `( U* m1 W5 J0 w$ H
};
0 @2 E( Q6 n2 ~
" L1 T' o0 V, W- ^. B' x/**
* g- B" C! p' i- i * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.0 W* }! x- y8 F9 a% Q3 n
*$ |4 h( e% X% D; [
* @subsys - the struct kset that defines this bus.  This is the main kobject2 W2 B9 ?9 @5 i" k& d1 \' ^
* @drivers_kset - the list of drivers associated with this bus
2 J, r6 [4 o6 M5 `8 | * @devices_kset - the list of devices associated with this bus8 l7 c, B; [" c( n  a
* @klist_devices - the klist to iterate over the @devices_kset
) e# _( n, p& T& _+ f, [( Z0 } * @klist_drivers - the klist to iterate over the @drivers_kset/ I  c/ @4 _8 c- J& X
* @bus_notifier - the bus notifier list for anything that cares about things( X& ~6 F4 y6 s5 Y% Z0 f' s$ Z
* on this bus.
0 q7 {7 \9 w7 u3 ~, f5 ?) i * @bus - pointer back to the struct bus_type that this structure is associated
, v7 U: E1 Q1 c: b, E * with.
6 x+ R4 p6 d( j6 ~ *) \. y+ u- w& d
* This structure is the one that is the actual kobject allowing struct3 d. N/ l8 a6 I6 D! X7 {! R0 d
* bus_type to be statically allocated safely.  Nothing outside of the driver
0 b, D5 T: p, K1 v( I. x. N * core should ever touch these fields.
6 ?8 h' Q- D' t */
) M. @/ r, |1 p1 ystruct bus_type_private {' `7 T. O& O) V* ~" i, E* {7 b
    struct kset subsys;' [- T. _  t; e$ V; L$ H/ \
    struct kset *drivers_kset;! O" R* z2 c+ @7 G2 B5 {. Z7 R
    struct kset *devices_kset;
0 k2 k. J' L  w  a& u1 U$ Y    struct klist klist_devices;; }. f1 h+ ~- Y; b7 T9 T
    struct klist klist_drivers;- }& F. c; \# `' e# j6 T
    struct blocking_notifier_head bus_notifier;
* K4 e& O1 X  O9 J    unsigned int drivers_autoprobe:1;& e& y5 O; h8 o! n" Y
    struct bus_type *bus;
0 G2 K: ?) B8 v/ s9 u( u};
7 A8 }# h, z# V0 U/ }我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。  S' c" j. W- d) l1 D7 q
drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。) B. ^0 ^; l8 N- \; o

# B9 t2 O  }( N8 o7 i; N同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。' E* s2 L6 m1 R6 o
1 v, D9 Q% P* E3 Q1 k4 F
4.2 device
7 i& j& z% u" ]' T( X8 U2 d( i设备对象在driver-model中使用struct device来表示。
) `5 j/ r6 J, w6 [9 u( W! C( K) C. d1 _2 v. p5 v+ d- M# d
下列代码位于include/linux/device.h。' L0 H6 {' @; n
struct device {& U+ l, j1 ^4 \0 B1 V
        struct device                *parent;
( J7 {2 i* Z3 v. W# h% [1 w* p! j7 h
        struct device_private        *p;
6 D4 J+ N! R+ G! b* X9 |- Q1 P) @2 I+ u3 {, j/ b
        struct kobject kobj;
5 v$ h/ I% }) Y. T' N1 z7 {        const char                *init_name; /* initial name of the device */. ^7 j& d' U1 ?1 f- ^+ V! |
        struct device_type        *type;( L* _6 }) u' ]; m
4 n9 x0 L0 G* J" S$ X
        struct semaphore        sem;        /* semaphore to synchronize calls to
/ n1 ~  q4 Q# X: V( x                                         * its driver.9 w2 r, F( ?1 M/ J1 \. T8 ^
                                         */
; t+ N/ s- p& b* }
0 d$ K6 ^8 i7 Y7 Y! G# M7 p& Z        struct bus_type        *bus;                /* type of bus device is on */+ X" q$ ~# C: w) M
        struct device_driver *driver;        /* which driver has allocated this
- b2 D, S: @5 }; b* H; H                                           device */! i6 v$ r5 {1 {% |- w
        void                *driver_data;        /* data private to the driver */
6 j7 ~+ @$ G5 ^4 k% w        void                *platform_data;        /* Platform specific data, device
, c/ d; U9 `! |' C) ?% X, G                                           core doesn't touch it */  x/ \$ C  ?8 z& Q+ \$ |* p. q
        struct dev_pm_info        power;, d# A2 x: g+ f+ l" n7 D8 e

2 u. M( c+ U0 J/ G1 s0 P#ifdef CONFIG_NUMA* v& s: ]. b  t% }
        int                numa_node;        /* NUMA node this device is close to */% H# E2 _# W/ Z0 f! ]' k+ R, _
#endif
. g1 p; I: h% _2 H% o  ]        u64                *dma_mask;        /* dma mask (if dma'able device) */7 v; W% K9 j1 F' G7 f, |+ n
        u64                coherent_dma_mask;/* Like dma_mask, but for; A5 l( n% }% U2 p8 F6 v9 H+ ~
                                             alloc_coherent mappings as5 i/ p0 c1 n9 \3 P" `4 t
                                             not all hardware supports: C8 [2 `' F  K
                                             64 bit addresses for consistent! C0 A- A9 I- \: X# d
                                             allocations such descriptors. */
/ {6 d7 P. N* M, l5 ~! @5 B% P( W4 g+ b+ ]  n
        struct device_dma_parameters *dma_pARMs;; j0 g4 O& |: N. a

& Y$ d* f, m3 V        struct list_head        dma_pools;        /* dma pools (if dma'ble) */
, q% s9 d$ b" i- u( R
3 s' r- b! i6 d8 P4 k7 x        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem; N% [7 E* y* c
                                             override */
9 @" A) k* m! `9 I5 O; b        /* arch specific additions */9 n9 ?8 F6 v! U9 F$ a! B- C
        struct dev_archdata        archdata;5 i5 ?7 Z0 U9 b# M) z5 y+ A) Z# f, A

, f8 R5 Q: [5 ^5 J2 t& F$ s        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */  e/ k/ Z( J. F' r( ^

7 Y& r7 O' e$ y7 z/ _) }7 r        spinlock_t                devres_lock;1 i! ]& G4 k0 l
        struct list_head        devres_head;
. V0 O3 C# }' W
! z, U" U' J  P6 K        struct klist_node        knode_class;
! A2 m( g# m9 I1 W        struct class                *class;
% E5 S& }4 q. t6 ]        struct attribute_group        **groups;        /* optional groups */
  r1 ~' k& ]2 ?* x" E
6 j& C5 W5 M3 G4 W! x        void        (*release)(struct device *dev);2 P1 ?  v( K/ r  C5 ?
};; V- [, d9 Z0 a6 ~
2 v! x( V2 {6 U( l
/**
9 l6 o5 \6 i. ~0 ~" q% I! M * struct device_private - structure to hold the private to the driver core portions of the device structure./ @6 Z% x+ n  y# z4 o. l# E
*
5 B3 \! Q, i* v# L0 q8 C9 _0 C9 A * @klist_children - klist containing all children of this device, X& o" I5 t0 [4 N  m2 j( U2 U
* @knode_parent - node in sibling list4 ^9 _8 B7 R* C" _6 R; j0 d* F! ^
* @knode_driver - node in driver list, F. w) |2 S8 R" r" J
* @knode_bus - node in bus list; [- L- g( {  W' e6 m; D
* @device - pointer back to the struct class that this structure is9 G" _; z3 U% V2 a$ }: X$ w% _  D
* associated with.
! o) c8 ]& l0 S4 p *
. O$ F* y6 \9 \7 ~3 Z5 p! p! l * Nothing outside of the driver core should ever touch these fields.
9 ^; M- c$ {/ h! L* V0 M) @ */
# g6 ?/ S2 ^6 X6 o: Dstruct device_private {
3 Z5 `/ `: M+ L# \    struct klist klist_children;  n. p* L9 P5 ?2 W* V0 I
    struct klist_node knode_parent;; N3 N0 x+ X. H! k+ ~! v
    struct klist_node knode_driver;
6 @- D3 t' a8 u* u    struct klist_node knode_bus;1 O; E1 b3 Q( g% a
    struct device *device;
" M1 v6 a+ [' T3 x5 X};1 B* v4 k! o5 A; j
device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。% z- ^% ?* z" ?1 M+ L

6 e( r7 j. M8 v: a& ?1 x7 Z9 `; l该device所挂载的bus由knode_bus指定。
& Z% W$ A; [2 c8 U* Q7 }& i4 D
; b9 ]. w$ K# y# N* V' }该device所对应的设备驱动由knode_driver指定。
( I; I6 d1 y/ ?+ h) L; w+ o7 i" j% _- [4 N
4.3 driver
: |& [3 j" e7 V$ `设备设备对象在driver-model中使用struct device_driver来表示。
3 }# M* T: R# u. M4 w) _& R% B& Q" K
下列代码位于include/linux/device.h。
8 G1 X3 r8 _8 y* ~2 q  L4 Ystruct device_driver {6 _0 j2 J6 J3 m( i3 I) [. g
        const char                *name;
/ C$ _+ o( [3 R        struct bus_type                *bus;
0 ?2 e, u1 q% e: T: k! Z" P4 P) V0 M2 H2 u
        struct module                *owner;" X0 X; p8 ^+ [" T( H
        const char                 *mod_name;        /* used for built-in modules */0 V. c0 S, ?7 [" N% j4 h  X6 G% p
7 P5 v; l8 Z5 |& v0 s! [1 {
        int (*probe) (struct device *dev);9 H+ A+ |1 T+ z, Z% \
        int (*remove) (struct device *dev);
. h3 E6 _1 h2 W9 v- b5 B        void (*shutdown) (struct device *dev);
6 \" S$ K9 q3 a2 t% \% A5 Z        int (*suspend) (struct device *dev, pm_message_t state);
; p0 O% w8 K& B/ a( o        int (*resume) (struct device *dev);5 K% g5 G1 E& D. V+ }9 D9 J
        struct attribute_group **groups;+ S4 P! d: [0 B  M

5 y- g. E4 p; b: f0 h: s0 s        struct dev_pm_ops *pm;2 `' \, [0 `8 G! T' N. E( S* |8 \6 a

* {" T1 T1 P! B        struct driver_private *p;6 n( k8 Q+ S. i
};
7 t' m9 |# M! V! w, r- U% G1 A9 ~: i3 n( ]2 L. T9 B1 u, o
struct driver_private {
5 _( }% e" X- |" O2 N4 q% z& a    struct kobject kobj;& d7 X% B  R* c* O9 y, x! I. t
    struct klist klist_devices;% t# P# `3 [9 U1 q- H' D! m
    struct klist_node knode_bus;9 K3 n* |7 ^( U3 M; z4 h5 j; O: {
    struct module_kobject *mkobj;
/ q" E) C8 x) u5 x& `. k    struct device_driver *driver;
$ z; M4 _0 Z; t1 M1 Q  _1 i9 N};
5 ]' V" u$ N/ h& M3 K1 ddevice_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。2 b4 [' g: K4 y& o
该设备驱动所支持的设备由klist_devices指定。
+ g* P8 X* ~( V. b" h, ^; u, n% ]. F
该设备驱动所挂载的总线由knode_bus制定。8 t) F! {& L* F+ e8 u
% A5 L6 v4 ^8 ~9 N, y: y  g
5. Bus举例
+ n9 ~4 T5 c1 M1 \本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。/ r$ r$ o4 B# P/ I" r3 [$ ~3 Y

! W$ j# k; ~( |2 V6 ?- mplatform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:
  X( F2 i8 N- j  d) x: ?0 O  |
' Q3 v4 w7 ~+ T5 n) [start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。& J. g6 Z7 Z! o+ R
- S9 \+ C# ^& ^
注:kernel_init()是在rest_init函数中创建内核线程来执行的。
" {' {8 E* ^; |$ t* j
3 v) x2 ^) R6 u$ [* X- u
2 F8 V4 A+ [1 J8 F5 j
) X# C" y" U  y1 w) {! z; T- }int __init platform_bus_init(void)
* g5 K. A2 Y( b  Q& f% P{
7 s: _& a# g" W- r% X    int error;/ p1 Y5 C8 s" T' n& j: B
5 `  @: X3 b$ \& O
    early_platform_cleanup();5 e7 i" v; G0 R. b
' h+ t) C- {7 {" p
    error = device_register(&platform_bus);
  A) E  W) g; s4 F9 l: g3 y    if (error)
4 ?3 [/ q. Y! m- R        return error;
7 x% {+ q4 L1 C# S  q5 |4 A    error =  bus_register(&platform_bus_type);
3 A& S' W  J  v' m1 V: |9 W    if (error)
& z. t7 N& E  |! A9 f/ U: V; p        device_unregister(&platform_bus);
- j0 w, F# _7 Z2 O1 D    return error;
0 B7 r! T7 r( b6 s# w}
! z$ }5 `8 _! ^- mstruct bus_type platform_bus_type = {
$ I8 t8 Z3 ~/ X9 k1 E- I; R5 M        .name                = "platform",' g9 C$ N4 X4 F2 w" r( L
        .dev_attrs        = platform_dev_attrs,( Q3 @# S7 l- Y9 i; s4 t+ I0 T
        .match                = platform_match,, E* T4 S0 r4 ]" w! K  [2 j/ K
        .uevent                = platform_uevent,9 ?% @" R( G( |, k6 q5 |
        .pm                = PLATFORM_PM_OPS_PTR,9 L) h  B9 i6 f* M
};; N% E2 t5 @5 W
EXPORT_SYMBOL_GPL(platform_bus_type);
% F6 H4 B3 U* x. {从bus_type,我们看到该总线的名字为platform。, N  Y" [7 f: r. ~$ |3 ~
调用了两个函数,我们只关注bus_register函数。6 [/ U* w$ X6 m5 y
( f6 p0 j4 F  t: s2 S) M8 T
+ K. D5 h- j* m* |1 c
/**$ J6 v& P& f+ \  b8 U: B
* bus_register - register a bus with the system.
6 \3 I( s. w" G2 q * @bus: bus.
( C  B) n" T5 _$ }5 \1 d9 u" Q+ N ** k. h2 S: n, O: B
* Once we have that, we registered the bus with the kobject
# B+ R' |% f' {- r( T/ ~- N' \. b * infrastructure, then register the children subsystems it has:
' {, Z/ \0 ]5 Y  o$ w1 l& c6 x * the devices and drivers that belong to the bus.* T$ I$ j0 I1 u. t- Q7 P
*/& R- f& v4 b, @* j
int bus_register(struct bus_type *bus)' u. g- `5 N" N; G4 N# C+ J
{( X! y2 R% o& l$ m0 u
        int retval;; A+ q1 S4 u. C$ O
        struct bus_type_private *priv;7 j: @( T+ F- _% J2 P

' ^# `) i( H2 c: T- a        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
. Q: A  l% x+ F9 r2 F        if (!priv)
- m/ G" W% M+ Q' C6 z' o* J                return -ENOMEM;
5 k# N4 H$ x2 z  Q        /*互相保存*/, M( F$ n, }7 N5 o$ ?
        priv->bus = bus;: B" `( N0 ^$ j: w  b
        bus->p = priv;
* W* z& ?/ K) Y; v+ d2 q. f- y4 `1 _7 e1 D  ^0 I1 I" ~
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
, k6 w4 x& e) u) w) t        /*设定kobject->name*/7 T8 Q- L3 Z/ c2 T& X
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);+ [6 \2 a( m; z' @0 l3 q! D. P+ p& k) U
        if (retval): b2 J) v# T9 k7 P6 t; ~
                goto out;- G5 {5 I3 ~# K- I, K

- F$ l& L" I. |        priv->subsys.kobj.kset = bus_kset;
. M6 L9 T( d% m9 w( ^        priv->subsys.kobj.ktype = &bus_ktype;
8 j$ T1 w* h0 w, m+ e        priv->drivers_autoprobe = 1;
+ P3 K; H* d4 R; n6 J% g% e
: s  K& M, r% F0 [/ M        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/
: V+ k9 X+ K5 s  n/ g1 s        retval = kset_register(&priv->subsys);       
2 ~' W1 g) c2 U        if (retval)5 P  }; P% x7 ?
                goto out;/ A( P. F$ W) ~

) j: r9 v* u3 K1 A6 n        /*创建属性,在bus/XXX/建立文件uevent*/. @- \! z9 n3 q- B! k, h9 _4 l- K
        retval = bus_create_file(bus, &bus_attr_uevent);
& [% A0 }# O! }5 g1 A- T/ y3 g* y        if (retval)2 ~6 H9 M9 [; O% m2 S1 ~
                goto bus_uevent_fail;* F. v9 @: M9 Q# N- I& E9 G1 L

3 Y$ M' n4 l/ X" k        /*创建kset,在bus/XXX/建立目录devices*/
0 l7 V+ {) z3 D2 I* d; |        priv->devices_kset = kset_create_and_add("devices", NULL,
' w7 ]9 V! L: _& |                                                 &priv->subsys.kobj);5 U/ A1 I4 s% K2 V6 G
        if (!priv->devices_kset) {
) ^) I/ N  a9 V9 Y) Q# p                retval = -ENOMEM;/ s7 K7 `  M9 ?8 ]
                goto bus_devices_fail;' ?, q4 r: ^% P2 {5 [5 G5 H* Z
        }
/ G! i) J1 F  S
0 j  h1 J& {& R1 C0 w3 @        /*创建kset,在bus/XXX/建立目录drivers*/
0 v/ R9 x& f1 o        priv->drivers_kset = kset_create_and_add("drivers", NULL,2 _9 A+ ^2 |7 X5 k5 b
                                                 &priv->subsys.kobj);6 C/ q- `& C1 P6 e: ^
        if (!priv->drivers_kset) {
' a& T% g% z- `) }                retval = -ENOMEM;, d2 j: t, z, K% J
                goto bus_drivers_fail;
( o. r' x: }- @% x* @        }- n  d2 P% p/ \0 w( W2 w) w
        /*初始化2个内核链表,*// j+ m- X, u* _2 u
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
, f/ K" E( g$ f2 H5 _        klist_init(&priv->klist_drivers, NULL, NULL);# y9 j7 z) ?2 _) B3 D2 v1 @+ q
/ Y+ [4 E+ H9 T( h6 M6 J
        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/
5 u& P3 E& b8 `) H  Q6 g8 a        retval = add_probe_files(bus);8 {7 \/ a% i6 u' s6 |. Y
        if (retval)
) [: W; m; f1 B: E                goto bus_probe_files_fail;! f" ~* k' E0 k5 b) Q) s
        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
- j  p) q# u; x        retval = bus_add_attrs(bus);
+ G! J, c" J) Z        if (retval)
% R- t) y: h/ O! |# X# N. ^, J                goto bus_attrs_fail;+ B- j8 H1 o& B# [$ Y# i
- T. h6 r/ E( S- X3 Q5 r
        pr_debug("bus: '%s': registered\n", bus->name);
" F! W  l- A6 K! p3 [' Q        return 0;- C, `) v) ]  E- ^4 H/ K# g3 i: }

& P2 i# t8 y9 Q3 xbus_attrs_fail:% q3 R% x1 j/ o/ T
        remove_probe_files(bus);* ]% W  A/ A# O; R0 J
bus_probe_files_fail:$ w; K$ U) C) C- q
        kset_unregister(bus->p->drivers_kset);
* Y+ d9 [& j$ z, L- qbus_drivers_fail:
" X+ ~2 _6 ?+ C* d7 e        kset_unregister(bus->p->devices_kset);
4 B0 k% W7 R' G# t1 Y. Tbus_devices_fail:
) `0 n/ e& z0 j8 f* H; u$ }/ q3 Z        bus_remove_file(bus, &bus_attr_uevent);3 G7 t# ]6 B% w7 D5 H
bus_uevent_fail:
4 P) S: ~; G- Y; K9 x        kset_unregister(&bus->p->subsys);
/ h4 t3 W1 [$ j% ^        kfree(bus->p);
. Y2 T3 P. @, U& jout:' j  l. t1 @- l8 a4 G
        bus->p = NULL;3 x5 m! w, |# g$ T; J* M/ m8 s
        return retval;4 X+ E1 }0 x! d/ H  ~* w
}( S1 ?* r+ V# o
EXPORT_SYMBOL_GPL(bus_register);
+ i/ Z) W( E* ]: O, y+ L8 @
, _& a/ R- U1 F5 l; i8 c  s函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。$ `4 C$ h& o! E* u" M  Q! L6 V, ~$ {
在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。
5 v5 Q$ V, p" P7 M
. T0 r% a; _% x" O5 F接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。
) b) r7 I3 b# O! R
  m1 {; E9 n( o( x! [8 P7 Y8 C紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。7 ?3 T9 t% Y' a, @
9 ^2 x6 Y" c( K4 A

: r) L' _0 ]# x( B: p/* add the kobject to its kset's list */
1 ], _) K6 M6 N2 G1 n  U/ Bstatic void kobj_kset_join(struct kobject *kobj)/ V, Y) j) e5 o5 ?( P
{% D( [' z) u6 d5 P9 X1 }
        if (!kobj->kset)
: k  Z7 R. v+ G1 s                return;
( e0 ^! T  W  R2 r# n
. C) q4 t2 ]+ |- f1 {0 D8 S% e        kset_get(kobj->kset);        /*增加kset引用计数*/2 P6 A+ n+ s7 R1 c8 y$ `& u
        spin_lock(&kobj->kset->list_lock);; P6 y* i' w; g: [
        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/: e$ Z5 T6 }! R/ X* l: u) E5 ?% D
        spin_unlock(&kobj->kset->list_lock);
( I& o* }) z9 N: Z7 Y! o: v- G}
# J" i9 x' n# x2 }- w* E+ Xkset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。$ |" K7 Z/ |9 F' D9 t- W

$ v1 z1 s4 t- C2 s+ a 1 g0 ]5 T6 X. o# M7 y5 [" I% P5 Y$ s
1 X, N: ^* E! [8 O; H
然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。
7 u' z! H  m( t% H- f$ Z. Q
8 d4 g) [3 ]5 P/ Y% Rint bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
7 h, C2 ]& D) d! W, j{
* Z9 h0 A) f8 V4 g7 Q% n& N        int error;0 A4 ?0 m, g8 P- W
        if (bus_get(bus)) {
& T. s) D$ H9 b                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);( x2 X; k3 H5 U
                bus_put(bus);
4 P* D! \# z. Z5 n3 G- X: ^) _        } else
% ?, }; E6 O8 \# e1 C$ @3 k7 `                error = -EINVAL;. |2 v9 A" d* Y9 n3 @& f
        return error;' R7 D! Q3 g4 Z" _) y
}
4 O6 Z) y: N3 _# L5 vEXPORT_SYMBOL_GPL(bus_create_file);9 |) ?/ V& M" G' o$ g
有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
& J+ Z, m' y+ y6 m/ N8 @接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。
% T7 G7 o: g; a' g* P& n  \9 y3 J) t# h2 z! @% B
这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。5 R, P3 @0 i5 Z4 G. \% R

4 z. w5 L# B  k3 \- K0 i( [1 k# T( j也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。) F2 e/ i7 ~% \
1 b# E+ }& ]; ?
我们来看下关系图:
% f7 [3 t( A  c2 r+ n0 k+ r. k4 }5 ^
% I8 P8 [7 S: }2 p( r  Q. w

: \/ U7 Z- M0 ^! ]$ W随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
  h9 s/ t* }- ?, N' ^1 Q& Z3 s
: \5 ]4 `' L3 y9 W9 M3 Q/ Y+ H  f" ^static int add_probe_files(struct bus_type *bus)
: c) W8 m' c: b+ ?! r3 t{
" v& P% H5 O" D3 u8 W        int retval;
  X0 `; M8 h4 b# a  U) Q
& ~% P; I  x: H6 F        retval = bus_create_file(bus, &bus_attr_drivers_probe);
! D! K. n5 Z7 [! [$ e& Q* \        if (retval)# j! A6 u* {- Q' T
                goto out;* A" n9 j( g% T
, f3 ^  @' e4 ~
        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);' x9 {: K) |! n- {
        if (retval)/ w* e4 K/ R. Z+ D; s+ k8 X7 G2 H1 M
                bus_remove_file(bus, &bus_attr_drivers_probe);. }+ V1 H( S* b* M6 H) H2 `
out:  j6 q1 w/ J; E% V
        return retval;# y1 n9 [& f6 J, w" w7 h' D$ Z
}
! c# ^- h2 s+ \1 \该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。; O7 K8 y! C1 J
最后调用bus_add_attrs创建总线相关的属性文件。
( k4 y) \1 J( x6 H% J1 c! g4 C) U/ H8 M3 D2 D
/**
7 h8 B  X0 K  C# n7 ?: s * bus_add_attrs - Add default attributes for this bus.
- p) E1 C7 ?& M1 R! w * @bus: Bus that has just been registered.
. W) n0 k# j0 e+ q0 C5 i7 H  O: f' C */
$ r/ g4 L2 w7 g# k! O/ V/ a7 \$ ]5 a
static int bus_add_attrs(struct bus_type *bus). i5 A& p: V4 a" W
{3 x8 w. a% ~0 D2 J' u5 @' i
        int error = 0;: C4 X$ m5 g" P
        int i;' Q% V9 L/ t# P2 z/ L9 c9 ~
3 T6 F+ ^0 E: R% E
        if (bus->bus_attrs) {
2 L6 V0 n8 {- V" _4 m7 \                for (i = 0; attr_name(bus->bus_attrs); i++) {
; `; y/ C& _( o; Z4 G0 A                        error = bus_create_file(bus, &bus->bus_attrs);
; w  w7 j+ W, G- R) V3 M# D. W                        if (error); ^; _) |1 R: q) c
                                goto err;
* \5 _  S2 }* F  S3 I4 @# S' o                }& b8 K* w8 u$ @3 p- @! Y
        }! W- \% D9 U+ b. d* X5 f9 Q
done:
# ?7 y( I: ~$ K! a        return error;0 H7 W8 H3 q% m! X
err:
9 R  [; a8 H: ]" R        while (--i >= 0)
- n; N5 K( }9 I9 z) J4 n                bus_remove_file(bus, &bus->bus_attrs);
+ @; N& Z5 E& B4 r2 L: B        goto done;4 B9 {  b5 S7 w2 p3 [, p2 l( K
}" G2 G7 H& ?  t" z- T! e
我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。* e- s0 B- x2 |4 ]
好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。% P+ X9 ~/ k/ M; c3 y8 ?

% ]1 t" N  V2 o# k) G1 @[root@yj423 platform]#pwd3 v: r2 w( q- e( P, H9 C
/sys/bus/platform3 F0 A0 R4 P& @1 V& [, I
[root@yj423 platform]#ls4 Y% N- S! E( i  W, X
devices            drivers            drivers_autoprobe  drivers_probe      uevent/ |# S" A" }9 w/ G1 Q/ ^  ~
最后,我们对整个bus_register的过程进行一个小结。
1 P# B/ W6 S( q  z" J- ^. d* q$ F! \) C

% i4 M2 ^1 Y2 F) w# |
  l/ A1 N9 C& [- R$ o+ l6. device举例
: ~9 B! K6 b& N: B$ j本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。1 y5 y4 s& n* f* d. n' K

8 S9 O( m+ ]2 }0 e4 K' o7 I' n6.1 虚拟的platform设备) Y: s  D1 W, l3 r
之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。" S% ^/ P8 |' {6 x

6 E9 a: Y; y1 N6 s3 E0 q在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。4 L/ K0 M0 K: L( j: M9 r

, H9 V/ h( }# C- d* K) Jint __init platform_bus_init(void): ?  E0 f+ E' M2 N# N& x
{
. u4 G# S: K0 v: a# e8 b+ d3 X        int error;) x6 u" p8 q4 O. U
/ t% S* Q2 t+ b
        early_platform_cleanup();" I% P! S4 q- x1 @/ j" `. v# R" e" K
7 b0 x8 D9 Q$ O$ e
        error = device_register(&platform_bus);
7 f: n; L. Y% e        if (error)& u7 O+ G4 d) i; N
                return error;
9 w. V" |: w  D7 e: B3 }/ Q3 A        error =  bus_register(&platform_bus_type);
0 i+ P. S0 W- o& S- d9 h3 E: v        if (error)0 d5 [- a! r# x
                device_unregister(&platform_bus);2 |1 F) {' K! c$ O  c
        return error;" L- \9 r% u& d# F' h! T/ M2 n
}
1 I7 {* X1 I5 t+ W! j; l- I( z6 K& O0 e
struct device platform_bus = {7 e& ?2 ?1 y8 [2 b7 d
    .init_name    = "platform",
) B$ O* f* u' j  L, j};
1 d/ q1 F6 L& _8 n: d( r4 d  v/ mEXPORT_SYMBOL_GPL(platform_bus): z% z+ ~/ w5 c
下列函数位于drivers/base/core.c。
  |" c2 H  t9 s2 O/**' s5 Y" L, }* L
* device_register - register a device with the system.
& e/ e; o& g% C& W * @dev: pointer to the device structure
" q' `' q' ?( t9 U7 A4 K *
: K5 F3 l1 O0 P4 F% s * This happens in two clean steps - initialize the device$ D* B* t. V$ w6 ^, }$ U( R4 o" L  F
* and add it to the system. The two steps can be called
" s' v+ K9 f4 |: e$ v7 U) m3 @# t5 n * separately, but this is the easiest and most common.; h5 y* `8 v8 C8 a
* I.e. you should only call the two helpers separately if* d6 @/ h" B8 @# t$ T
* have a clearly defined need to use and refcount the device
  `& X& k( k, E3 N: n/ ~1 {. M * before it is added to the hierarchy.& _# c# n9 h/ m
*$ V' f0 Z* J& {5 c0 x9 m
* NOTE: _Never_ directly free @dev after calling this function, even- w0 i* e2 _* U
* if it returned an error! Always use put_device() to give up the
. m; d' r% [6 ?2 i* z& R8 R * reference initialized in this function instead.' _/ e3 o4 ?3 G
*/
: D. }$ C: q  S) qint device_register(struct device *dev)4 W' |7 T$ d0 H1 K$ U. K0 t; U; o6 d
{6 Y) ^( _3 C4 p/ g' o/ Z1 |
        device_initialize(dev);        /*初始化dev的某些字段*/
. b! _$ A  ~2 J& f+ y* A4 T        return device_add(dev); /*将设备添加到系统中*/1 F& I3 E9 q. F& b- x  T
}' {3 f0 R3 i1 h* N1 F

6 l6 [" z, u* q一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:% L3 l: l( L' s7 u
7 O. V# e/ |  B( M5 o' d9 u
下列函数位于drivers/base/core.c。
# M, a9 _2 E# B2 r/**+ d# r- R1 F. o2 P
* device_initialize - init device structure.; M/ B% v$ I, v
* @dev: device.
6 k% u# x4 m% S# ^ *
9 {, w! S+ s: x$ c * This prepares the device for use by other layers by initializing8 E5 Y  J5 N8 O
* its fields.
9 T/ r' X/ f$ [- b$ ? * It is the first half of device_register(), if called by6 y3 E. e; M4 a+ m& o9 B
* that function, though it can also be called separately, so one9 |1 [9 C- p: ~4 \( F
* may use @dev's fields. In particular, get_device()/put_device()0 {+ I; {: c( f( L
* may be used for reference counting of @dev after calling this! A- D- b( n+ i* Q
* function.( M9 G( h+ F! _
*
6 G4 {/ N& H  L$ f0 {9 h4 [ * NOTE: Use put_device() to give up your reference instead of freeing( g# a% Y- {) M4 v
* @dev directly once you have called this function.! ^  [0 F" h) ~% j9 M* C
*/
- h# j. b. S, Tvoid device_initialize(struct device *dev)* \! u4 X. x' K. b$ P
{  |- Z9 t, `6 S2 [
    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/
4 ^: b& A# [+ B/ n    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/
; n! d; ~$ l1 Z  c( u    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
# K3 ]2 q& K0 u& j' M  L    init_MUTEX(&dev->sem);                /*初始化互斥体*/
; q* m0 E/ h- j0 K+ y3 N& i1 p    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
' l; s& O4 p( b    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
8 l0 T0 q  {$ ~    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/9 H! S  a! u  n
    device_pm_init(dev);                /*设置该device可操作*/
8 t- L/ k( G% N8 Z* R3 g    set_dev_node(dev, -1);                /*设置NUMA节点*/( V) ?1 M' \3 n# V- g2 e, M
}
: n: }: h. y% W: n8 V1 F' X6.1.1 有关devices_kset9 q/ s# ?( v; i, ^. `2 D! ^! b! m
首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。1 F: e) @1 k7 B% e
* }) W( l& }! v) Z; v& u
该对象的建立是在devices_init函数中完成的。) G) o' r' k/ I1 i4 o
int __init devices_init(void)% w7 b& Q) e1 `" g
{% P" l5 u# k7 x! C
        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);/ D- p8 Y1 H) Y8 y- f7 ~4 H
        if (!devices_kset)
. @7 C4 `) U5 F5 l  Y) |- k                return -ENOMEM;; e5 r! i( N- o1 x" L2 p$ J* K
        dev_kobj = kobject_create_and_add("dev", NULL);- |# r% A8 ?( b" P/ y. M0 H% Z6 K
        if (!dev_kobj)
- m5 L  }0 u0 E' |) ?8 `                goto dev_kobj_err;
2 k. e% f+ n! K" V5 x        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);' S2 ~( E6 i* A9 e% ~, A! K) K
        if (!sysfs_dev_block_kobj)
/ r( i% p/ r6 R                goto block_kobj_err;
3 L! `. k! s, G9 g7 O% j6 e. m7 j        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);. d- B6 i( W9 i: a( @( N+ _
        if (!sysfs_dev_char_kobj)
$ J- p2 [$ B) A% g8 @# L                goto char_kobj_err;
" V$ ?8 s0 H* i+ n: X# W7 B/ `1 ?' M' B4 R
        return 0;4 @! Z6 O7 g- `# B! F. {

; n! h! L5 {; h9 h: x char_kobj_err:- K0 `( ~( }# j2 r  ?' j
        kobject_put(sysfs_dev_block_kobj);/ H$ S! |+ f' O$ S+ N+ b+ G
block_kobj_err:
4 a6 r/ P9 c" m$ [6 E) T        kobject_put(dev_kobj);
: U9 }2 C+ {1 `- s" T1 V7 _; a: f dev_kobj_err:
; v; m& l4 t4 g3 w1 S1 l$ V2 `        kset_unregister(devices_kset);) ]! b6 D. x, ^
        return -ENOMEM;
1 T0 F" K9 M) c}7 l  b' W9 d2 e& T0 F/ T) Q
由此可见,devices_kset对象表示的目录为/sys下的devices目录。
# U/ \7 w( w" k6.1.2 kobject_init& r) o" \! z3 e2 I, @" m: b! a+ n7 Y
下列函数位于lib/kojbect.c。
" k+ @% K' D8 b; w5 F/**
' A  ^* y# |+ @, F0 g * kobject_init - initialize a kobject structure
4 O1 o4 N6 I; ^5 | * @kobj: pointer to the kobject to initialize
2 h1 U& f( W' }$ u! S * @ktype: pointer to the ktype for this kobject.! @) f3 Q0 K5 X6 C; D. m
*
: ~% Z- e6 P4 T: B * This function will properly initialize a kobject such that it can then
! p$ l) Z6 u  O& w- s& O * be passed to the kobject_add() call.6 p, s# u6 X$ {+ Q' e( k
*7 i2 F2 p& [* F/ g! W% V! `; U: @
* After this function is called, the kobject MUST be cleaned up by a call2 r% q- y0 g0 j- J0 o+ n
* to kobject_put(), not by a call to kfree directly to ensure that all of8 \2 p, b* I) L9 J) G: Z9 Z3 A, u
* the memory is cleaned up properly.
) n$ q! s7 J5 h */
' |- _7 ^9 X# n$ L/ B. wvoid kobject_init(struct kobject *kobj, struct kobj_type *ktype)
, \* k1 L7 M* \5 h{6 J3 v6 @( M2 y+ W/ [
        char *err_str;
( `% v" F* z* H, l( a2 B+ Q2 d5 a6 g/ b6 L% ^8 y
        if (!kobj) {: o9 b. |! V$ `( t! v. s
                err_str = "invalid kobject pointer!";; a9 p9 B5 G8 S" |
                goto error;) A- i1 h& K. e  @4 h) e& ^
        }
# ?0 a2 `$ D' g1 L; ]        if (!ktype) {/ k: A* r1 M. j7 S9 F, s- i0 y
                err_str = "must have a ktype to be initialized properly!\n";) D2 w4 a0 e3 O( J
                goto error;& B& C& \& q! @9 t
        }5 Q3 L1 l# \, f& s- s  t
        if (kobj->state_initialized) {
4 \+ l/ b2 \* O; l5 }6 W                /* do not error out as sometimes we can recover */
0 w" q+ f2 P* }$ K                printk(KERN_ERR "kobject (%p): tried to init an initialized "- E3 K+ }5 e/ ~
                       "object, something is seriously wrong.\n", kobj);
8 w, k1 ]0 S8 Y/ z                dump_stack();
6 _/ b7 M) _! Z3 i: W6 }9 [; {. v( v0 r0 S        }
* W0 a+ d2 h; y. w
) V: x, c& g3 E0 U% k$ B# _" @9 ]        kobject_init_internal(kobj);
" ^& e) ?" J0 I        kobj->ktype = ktype;
6 h  m: G- z  m& k7 G$ g        return;
! V, E7 n7 o# m9 P. d8 D1 f; E1 N3 S7 G1 F  E1 z0 L( p0 n
error:, l% F% s2 {5 V' Z
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
/ w( g1 A3 ?+ z) [8 Y* w8 H        dump_stack();" K4 n( A) J- n6 |
}
) ?' L& e  i5 W1 C( y, z- w& ~EXPORT_SYMBOL(kobject_init);
, }/ [0 X# l  f: H
$ R; G& {3 z; t% g) A: U# qstatic void kobject_init_internal(struct kobject *kobj)3 h% x! q; Z; a0 y( `; }: F
{
2 P% X+ t' u$ n6 c7 `( N# z    if (!kobj). c! Q' y1 x) D# `" y8 b
        return;
3 M8 g8 H& @! N# S    kref_init(&kobj->kref);            /*初始化引用基计数*/
/ L  d3 M% _: D1 W, w    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
) `# f7 z, `5 o* U    kobj->state_in_sysfs = 0;' m; r' y9 x' y$ y8 }& K
    kobj->state_add_uevent_sent = 0;
* h3 [: `8 |$ A% b- |    kobj->state_remove_uevent_sent = 0;
5 C" ~. \6 r# d' q+ U3 x7 `. C    kobj->state_initialized = 1;) k. V3 J$ x& X  f/ g, J" d' H% \
}
/ W# F# N, `+ r% H: J' k! i该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。$ @. [- k: T/ L' [3 R+ D
6.1.3 device_init_wakeup
4 c4 N* X3 K; Z2 a, ^参数val为0,设置该device不能够唤醒。
4 J2 s  x, Q! O$ X* p+ ?#ifdef CONFIG_PM
* \+ {0 R) U% B5 p3 K0 i5 b
9 ~, \# I; W% j6 }/ F. c/* changes to device_may_wakeup take effect on the next pm state change.
5 E) t3 Q2 A  s; g6 Y: | * by default, devices should wakeup if they can.
" L' Q  H  N, g9 H6 H */  \) v& a3 u0 }, _3 ~
static inline void device_init_wakeup(struct device *dev, int val)7 h' c" R! P; u4 q* K6 l5 J
{
6 Z) U% N  D$ L) w% F, j. T        dev->power.can_wakeup = dev->power.should_wakeup = !!val;/ `( a3 j+ K( z; b3 p- G
}* u8 {% T$ X" S# t+ v8 H0 R6 e; A
。。。。。。
& F4 h. S0 M1 L7 s/ {  {+ n#else /* !CONFIG_PM */- C/ w) h3 G$ z  \" I
2 b" n  x, ]7 K: k- s" H
/* For some reason the next two routines work even without CONFIG_PM */' J# j- {6 K  w- T$ v, S
static inline void device_init_wakeup(struct device *dev, int val); x& R1 b' o6 ~3 J$ Z: p+ [
{
5 b6 V2 v. K- j% x: t0 Z+ k/ {/ w    dev->power.can_wakeup = !!val;0 s% p# u& B' _! b8 _
}) z1 M. V( Y. v0 `; |9 `
。。。。。。
% S; ~' Z: [( q. B8 E5 D  z3 ?#endif2 |0 Z4 O1 U. g. I
* s5 b) z5 P) R* I; l$ r7 o* F
" {9 @5 M0 E7 R8 G! N. |
6.1.4 device_pm_init
% x* j7 p+ B1 I+ f2 E设置电源的状态。7 ]" _2 p5 d3 m4 s/ `4 h
static inline void device_pm_init(struct device *dev)
( b4 S! H) J9 w0 p& J3 e  n' m" M{
7 ^& {% @7 ~( V        dev->power.status = DPM_ON;    /*该device被认为可操作*/  n9 v; d( T1 S: D
}
& c& ?; `. `3 m- N. M6.1.5 set_dev_node/ R1 S, L4 b7 i* z3 a$ N$ Y0 r# K
如果使用NUMA,则设置NUMA节点。, L/ U/ p% O2 T. q( B- E, a4 O
#ifdef CONFIG_NUMA
7 X0 \" A" k' s) e4 S8 G1 T) Y。。。。。。+ E7 `/ @  E" A( v6 r8 |8 {: {
static inline void set_dev_node(struct device *dev, int node)
7 H) Y! S+ c- D& Q/ Y. D4 G' o{
& H; D6 {2 e4 x' ^# W5 {        dev->numa_node = node;4 w8 j! k1 K; ]4 C0 f
}
4 T& Y9 `6 s( x, {3 E# C#else
+ k  F+ N6 I( p+ d* `。。。。。。
! T  [5 O' r2 s7 Q* Nstatic inline void set_dev_node(struct device *dev, int node)
) j% D# ?# L# ?+ ~) A$ ?{6 c/ _8 f) q2 e: g) `* t
}
$ u9 X2 O+ H. C- I  s2 b0 {- S#endif
' r' G+ N  F% W- W% k% M& F6 ?5 \) h  D
6.2 device_add
- z9 ?3 H% Y5 C% s' ]接下来是注册的第二步:调用device_add。7 F) V7 S' {1 f  x( e
4 u" y* t/ C% |7 e: A2 c
/**
2 O4 ]# B& ?& H/ B" c0 u * device_add - add device to device hierarchy.
9 b. q/ _7 ~) u9 O$ q+ B0 ` * @dev: device.$ K# W) w; }8 z) |" ?' S
*7 B& t$ N5 y9 P& J% C  T7 k
* This is part 2 of device_register(), though may be called
& C/ k/ U4 H  Z& q+ b7 i* B( H2 f * separately _iff_ device_initialize() has been called separately." U1 ?# t+ o& e, Y0 Q9 p
** }- d# P8 k' ?3 c3 M! V9 `2 h. L! q
* This adds @dev to the kobject hierarchy via kobject_add(), adds it
% F9 N3 `( T! B  l+ Z3 _ * to the global and sibling lists for the device, then
0 \7 j) }1 ^: W5 t  D8 T4 S* s * adds it to the other relevant subsystems of the driver model.0 V& G2 W' |/ Z
*. k4 `0 r0 h8 t
* NOTE: _Never_ directly free @dev after calling this function, even
/ [- D1 e& Z1 P5 i$ `/ `2 `5 F * if it returned an error! Always use put_device() to give up your
4 Z# w2 U+ `. T * reference instead.
2 {: L% i  d. ^5 z, m4 V* P  F */
1 g7 i, b. ^6 Q4 q, ]int device_add(struct device *dev)
  b% ], U/ |, v% |6 C" K{, E5 P0 m2 j4 m+ o
        struct device *parent = NULL;% X2 B% f$ B/ o  z+ s5 r
        struct class_inteRFace *class_intf;8 S& L8 j6 @" P+ x) {
        int error = -EINVAL;; h5 X5 P+ a4 G4 Q/ C

1 P# I9 I; I# U8 b0 }2 [' P- D- z        dev = get_device(dev);        /*增加引用计数*/) G! B/ k& G0 p4 f! M
        if (!dev)7 K7 t8 s% x1 e5 E& N" k. ?  s
                goto done;; D& M; x% C: l( r9 l1 n, h  i# Z

( p' R4 r- J5 @" A; J1 L        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/
, [5 k  X/ C9 P0 T) L# j        if (!dev->p) {( S) \6 J3 Z" x! x1 |: l8 [
                error = -ENOMEM;1 F2 U$ b$ G& P; I# P
                goto done;
5 `  R& l# d) p$ c! }        }) |, L5 `, h5 W4 h+ h5 i
        dev->p->device = dev;        /*保存dev*/2 s5 i. |! L& n  h
        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/
  n: c( o: Y; @3 `' k                   klist_children_put);
, r8 L4 D; `: k% q# W5 Q) L( ^4 t1 |" z
        /*# C) x( K# h* F
         * for statically allocated devices, which should all be converted
) J: |8 P0 G& n8 c/ }/ r: Y         * some day, we need to initialize the name. We prevent reading back
, I2 Q$ v: u: N  G* q$ a) M         * the name, and force the use of dev_name()
( S8 }) A9 V/ a7 }: T3 L         */5 z9 N) E: w8 W+ ^
        if (dev->init_name) {( s7 q, N4 F" e& r1 k! ]5 i* F
                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/2 t8 o/ ^" b1 [1 U* _
                dev->init_name = NULL;
* G+ G) s! j4 E# J% V- \) n! [        }' X) M% M$ T6 {' U; q

/ v, ?6 g. o% B9 J0 K        if (!dev_name(dev))        /*检查dev->kobject->name*/
* l# B8 H7 X  `/ z                goto name_error;
  a3 h$ g$ z5 |; d; m8 a" C3 Q3 {  H( F9 G* M0 p
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);  X: e  \6 v2 i6 b1 [$ A

# r; p6 Q# M( V; y! k        parent = get_device(dev->parent);        /*增加父设备引用计数*/, f" V% U  n  U
        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/" h6 O  h( _* r" o. A: U5 i& p1 r- {

5 k& w' C" [6 v2 Z5 r* t! n        /* use parent numa_node */6 H, h2 b+ l/ |: n. e! m
        if (parent)
/ i1 K7 r9 ^: d9 ~                set_dev_node(dev, dev_to_node(parent));, r7 M9 ~2 @/ ^2 M! K0 S+ ?9 N  q

$ c: _/ ?/ k' s* y8 c        /* first, register with generic layer. */
0 H) n: \- u  d+ q7 s8 p) G1 k        /* we require the name to be set before, and pass NULL */2 S" J, l/ L- I2 K- {; i, g
        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
2 [" p5 M0 @% M, a        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);       
  i4 m2 }; y* |) D6 |. s        if (error)1 p9 L% P% Y/ m6 \# }
                goto Error;
5 m0 G+ a" c3 h  ]- u4 X$ a! Y5 _4 i" f4 n8 w" H
        /* notify platform of device entry */6 j+ d4 I- W0 j3 W: Q$ n7 C
        if (platform_notify)
8 S0 m; _* {- _5 @                platform_notify(dev);5 [0 b/ ~$ m# N1 G* w3 G
+ ?5 z3 t3 a  o3 I
        /*在XXX下建立文件uevent*/
0 x/ N# s. x3 T# Q# ]        error = device_create_file(dev, &uevent_attr);1 y5 B# K) n( V9 n% D8 f2 w4 o$ {4 ]
        if (error)7 d; d, v; |, g: W
                goto attrError;: j) O- c7 n! e" m! E# ~) U
4 z' r6 D" p" q" x, K( {- D3 e
        if (MAJOR(dev->devt)) {/*主设备号不为0*/5 d( L% \& f4 C' J' v
                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/5 E! [0 O% B) B4 u. S
                if (error)
) {& v- o# P" y) r                        goto ueventattrError;
1 Q3 U9 |. ?7 b) B  y+ H; _. v% ~9 X# r' {5 W" m
                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */& j* e! K- |7 B3 Q1 p1 h
                error = device_create_sys_dev_entry(dev);
, g3 A8 Z: @. }5 j& [7 M5 i                if (error)
- ?& Y4 ]' K, A# \1 ~                        goto devtattrError;
3 H: m$ F: d4 _' b+ ^9 t        }9 E. H2 ~9 c( v* h4 n- Z
$ N- `7 A  A/ R( C# U
        error = device_add_class_symlinks(dev);( A6 ~- u5 B/ d
        if (error)2 D* k' X, J( m3 u
                goto SymlinkError;6 \' h! c+ [7 Z* D! V5 F2 h2 S) m
        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/
* Z6 @# _8 u, L& @        if (error)7 f( Y) b. r3 {! ^8 ]
                goto AttrsError;
+ c+ k# }! Q  i9 P+ o- s        error = bus_add_device(dev);        /*添加3个symlink*/
% H+ B$ Q9 {$ ]/ m/ P& |+ g5 m        if (error), y0 W6 {! D8 l% n
                goto BusError;
- F7 e, R& Q2 r3 o" S$ z; }5 j" a+ [2 j7 r        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/: t7 o5 i4 r! J  h1 n" v
        if (error)$ B$ X6 X8 K! m2 K& o! e6 ^4 Y
                goto DPMError;
9 n% m; t3 b3 _8 a7 G        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/
; o5 `. J; L# O) R# g
+ N5 m7 a# @' z3 @6 _. c        /* Notify clients of device addition.  This call must come+ k8 @7 e+ h0 A) X! r, `8 u
         * after dpm_sysf_add() and before kobject_uevent().. r6 G* q7 u: X7 v. x9 B$ F
         */
1 _) V* T  X5 P: y, }        if (dev->bus)
$ d3 A! Q" O$ V! s2 O                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
: O$ y1 ^9 c( r9 z& w3 E1 M( f                                             BUS_NOTIFY_ADD_DEVICE, dev);- U: r9 h% K4 r: V  c% x- Y

$ [$ v, H: E9 O3 ^0 d; D  J% ]        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/
. q5 B. J3 J) M# X' ?        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/
$ k- z8 d$ h) h" x  F9 @. p        if (parent)3 K& k1 `) T: h. O+ i
                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/1 X4 b6 ~2 Z# l' F2 V- q: }$ L( Y
                               &parent->p->klist_children);
+ b+ x  b6 L( S. h* E, r3 a: r
        if (dev->class) {                                                /*该设备属于某个设备类*/; [( W$ e6 d. W! C- j: f; C0 A
                mutex_lock(&dev->class->p->class_mutex);& j; k! h0 T( ?! _3 j
                /* tie the class to the device */
& |; q# [/ `( L                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/
  W# m* y" l- g1 z5 u; o                               &dev->class->p->class_devices);
1 ?8 _' Q$ I; m2 n1 c4 ~# K) b  N9 S4 \8 D: O- ?8 V
                /* notify any interfaces that the device is here */$ P' L( T  b7 J( |: O! V8 F, `* T
                list_for_each_entry(class_intf,4 p$ g3 w3 ^: S) d
                                    &dev->class->p->class_interfaces, node)
; G( D, @/ I6 s. O                        if (class_intf->add_dev)
, E5 i% `; v' m6 J" g                                class_intf->add_dev(dev, class_intf);  ?6 g1 |0 \+ D: C
                mutex_unlock(&dev->class->p->class_mutex);
" R0 g3 h. u0 K7 k        }2 A1 A+ N; @* G+ c
done:% `0 b3 K: j6 r0 R: p5 G; x8 z
        put_device(dev);
7 F9 Z; P, J5 Z        return error;
- r4 W7 r( m# w% j; B5 u0 W DPMError:
0 @. d# I; b0 H% N        bus_remove_device(dev);
& y* }1 S! @- ^% y1 K$ | BusError:
! ^$ C# n  R* n        device_remove_attrs(dev);
( t/ E& j) e' l6 `* ] AttrsError:
7 f  I! g/ L' g        device_remove_class_symlinks(dev);1 |8 d; u7 u6 ?" _* p
SymlinkError:
4 W9 F- P8 D6 m" ?2 ]! A/ _: K6 {4 f# d        if (MAJOR(dev->devt))
. N. i5 M$ Z% y$ a3 [0 u                device_remove_sys_dev_entry(dev);; P% I1 I8 _: e& T1 K' C
devtattrError:' a8 W: P( I; g* V. Z9 ]
        if (MAJOR(dev->devt))
& A+ P4 `# s7 m  b$ n                device_remove_file(dev, &devt_attr);( b- N& v6 O3 k0 t( X
ueventattrError:, E6 l' s8 n9 a/ |! |& a4 ^
        device_remove_file(dev, &uevent_attr);
. ^& n9 W1 H" L attrError:
* Z. D+ H  h8 ^        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
( k& n. u/ f: K7 O( u        kobject_del(&dev->kobj);
0 Z9 F; }" f3 I4 {  n7 e; Z/ } Error:  g8 N/ M7 s) i/ O, I, ^& C  U
        cleanup_device_parent(dev);
+ o2 r) C! \' U2 m1 W6 W        if (parent); H) l6 V- `3 Y
                put_device(parent);  J5 s) }6 H& }7 U+ @
name_error:7 U, s4 y  ]/ E: P7 k; e/ P6 f
        kfree(dev->p);+ G1 h/ b4 L, s
        dev->p = NULL;; Y9 w* U* O' U- t+ P. q4 T
        goto done;0 h. r% J0 h" Z7 A0 t. \5 p
}4 D4 C5 v% ]2 q( f2 _# R7 H3 g

0 |/ I2 J# v0 _' z$ N该函数调用了非常多的其他函数,接下来对主要的函数做出分析。6 `7 J4 X& R' f3 H# z
6.2.1 setup_parent函数6 R4 y& M! p- R/ J) {- X
下列代码位于drivers/base/core.c。! B4 m( L3 q4 B' W" n. e0 _
static void setup_parent(struct device *dev, struct device *parent)
: R5 r) l* r1 ]1 A2 n8 U5 U{/ u7 w0 s3 A0 F6 A5 g5 E
        struct kobject *kobj;
! {. K8 z. m. k# q. Z        kobj = get_device_parent(dev, parent);3 @5 t0 I6 B+ A+ A/ d5 R
        if (kobj)* m3 a3 J" b, I
                dev->kobj.parent = kobj;
  U; E4 i/ C8 h4 c7 {}
% o. C" S, w: z. `. L$ t
3 T. v; N+ g8 `0 B: E" b! rstatic struct kobject *get_device_parent(struct device *dev,
, E7 w7 w: X& r% }+ }2 D- d                     struct device *parent)
8 \% W( a- V8 z. e# Q- G{8 W3 t6 K' p" t9 U1 C& W% r
    /* class devices without a parent live in /sys/class/<classname>/ */
! e8 k' G9 q& P* r) O9 ~  P- M    if (dev->class && (!parent || parent->class != dev->class))
. H) s( I& W  B" N$ u6 ?9 B0 }! t        return &dev->class->p->class_subsys.kobj;, g) @5 m* ^- v% g
    /* all other devices keep their parent */2 b! L- I8 ?2 L7 D, u/ t# x6 b
    else if (parent)! P  ]7 H  G! x
        return &parent->kobj;
' o  g- z$ p# `, \" P+ d! T1 I! b1 x
    return NULL;
7 S" x- V& `5 B1 X* o. n6 x}# X) r# p0 `2 K0 `3 e" M
该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。
* [2 R* |7 u3 h: g; Q- b- E6.2.2 kobject_add函数
/ G* ?6 \7 D* m下列代码位于lib/kobject.c。" L& z1 F5 c5 w/ T$ a2 U% S
/**# R7 P: o7 O6 z0 i% H: \
* kobject_add - the main kobject add function6 a# B7 \7 W- p1 _( p
* @kobj: the kobject to add
, P9 W! ]9 O1 ]: @ * @parent: pointer to the parent of the kobject.
! P. n2 v0 D' A( [3 a * @fmt: format to name the kobject with.0 _' _$ Z/ ^9 ^/ B5 U% ^4 j4 J5 \
*
  J' o& S" _* Z6 m; q$ { * The kobject name is set and added to the kobject hierarchy in this
7 K4 ?- n7 E8 X7 s& y. ^' A* r5 b * function.
. k' h, i" p; W& f, d; e *
  ~4 W# f, C& O$ A# L8 f * If @parent is set, then the parent of the @kobj will be set to it.
" w7 R; V2 `2 Y4 R * If @parent is NULL, then the parent of the @kobj will be set to the
: `' B; |3 f1 j! Y8 c3 k$ U * kobject associted with the kset assigned to this kobject.  If no kset* h/ W+ L7 L3 Q% Y3 b
* is assigned to the kobject, then the kobject will be located in the$ E/ B5 V* N" Q7 c# f1 H
* root of the sysfs tree.
* R8 m/ @; ]  a *
* A4 v7 q( x5 o8 W( M * If this function returns an error, kobject_put() must be called to
1 B% T' |. N) P3 |" B * properly clean up the memory associated with the object.
2 ^9 j# Z2 s( F" R: U * Under no instance should the kobject that is passed to this function
) Z  _) l7 S+ A9 w: u% Q/ S' ? * be directly freed with a call to kfree(), that can leak memory.: `' k4 m* n/ a; X7 c6 p/ B
*
$ V: c: Q& E) J" y3 s * Note, no "add" uevent will be created with this call, the caller should set
' `( N. O" S/ [  b. N, u; l- q5 p * up all of the necessary sysfs files for the object and then call6 i, k: s( R2 G( y1 k; i) p( u
* kobject_uevent() with the UEVENT_ADD parameter to ensure that8 }# w( p  W: \' D
* userspace is properly notified of this kobject's creation.: n- i$ M7 D3 ?# q) `7 n* _: d  [
*/
6 n/ r) Y# v! V2 a3 E! c  Q$ \int kobject_add(struct kobject *kobj, struct kobject *parent,; G! m( e4 ?0 m+ Y
                const char *fmt, ...)) f8 C2 a5 p, y% ~7 P
{' `% Y: d! J& I& `# S
        va_list args;. x5 M. C6 w/ M* o8 O, S$ ?
        int retval;
, C! \1 U+ J2 R1 F% C) W6 x3 n
$ H, Y5 i7 n! B# A        if (!kobj)
. o, x; i1 X( b5 d0 U                return -EINVAL;6 F* _4 T- u3 ~; S; X4 b
6 [5 T; ]" d: k/ {
        if (!kobj->state_initialized) {# H( Q. z- _% P3 D' }3 @
                printk(KERN_ERR "kobject '%s' (%p): tried to add an "( m6 L! v2 o" H
                       "uninitialized object, something is seriously wrong.\n",
3 v4 v" z7 v. W' P5 p, k. ^                       kobject_name(kobj), kobj);' I' d. u, g5 f; T" c# {* t  J
                dump_stack();
: i5 O9 d. X  |; h8 ?" ]                return -EINVAL;
7 E# h1 r1 L) y2 \/ |4 z        }
& I& N0 d( A& {* c* j        va_start(args, fmt);
- Q% F$ r8 L7 C' u/ b: l: m" A        retval = kobject_add_varg(kobj, parent, fmt, args);8 |; k; e, d  e7 W( d+ |
        va_end(args);
; `6 _" d9 ~  M3 V) G( H3 `8 w+ m8 }1 \1 F" H( T; D
        return retval;
  Z" g" B; f9 P  _7 z- ?% k}
4 x( f# c& t" i; H- OEXPORT_SYMBOL(kobject_add);
. {  o' s- a" J; l! n7 }0 v% u% w1 i+ @, y% B% j7 n2 P3 O
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,+ Q' J; l% d% d; B4 O
                const char *fmt, va_list vargs)
3 T5 _8 {8 ]& {! _1 g7 k{
# n1 ?* \3 X4 X: f) o    int retval;+ w7 }* ?( Q, E  `. \1 C2 O( g3 y2 x
! k& c, h5 a# Z
    retval = kobject_set_name_vargs(kobj, fmt, vargs);
5 T1 ~; W+ Q5 c: r    if (retval) {% a9 r/ F1 ^& a
        printk(KERN_ERR "kobject: can not set name properly!\n");
+ |3 d& H! G/ R) a# l2 Q" L; r        return retval;
) e; X# @* Y- \8 I9 b: q    }  r. x: E" p7 b; b- ]- b: y, c
    kobj->parent = parent;* c+ \0 ~2 V: W
    return kobject_add_internal(kobj);
' r' g# I* q0 M& l6 x}
7 D# N0 Y4 W$ @0 S% g; C
. R0 x: r5 b0 |/ b- F& Fstatic int kobject_add_internal(struct kobject *kobj)
- i8 i% I3 c( k2 b# I, i1 A{
$ \* R  p) W% x    int error = 0;
: b- k! r% [' [# W    struct kobject *parent;$ A' P+ T/ B: x1 D# V: t# U7 o7 V
" W$ g+ D( r0 W2 U9 e
    if (!kobj), g8 ?2 D1 C. a" V$ Z) h( l
        return -ENOENT;4 B- D% d1 l, t* U
    /*检查name字段是否存在*/8 H$ o1 N* S5 ^( Q% M
    if (!kobj->name || !kobj->name[0]) {( K$ ~9 T% X1 \
        WARN(1, "kobject: (%p): attempted to be registered with empty ": B! L. s  k5 O4 K  A* I0 I
             "name!\n", kobj);/ h! r9 b6 w4 {- }; H+ Z5 C
        return -EINVAL;, J# _: _9 P/ z6 a
    }% d* Q" A6 d7 h+ w3 M9 f  }3 f

* n+ H5 K, L! c# f  A9 p    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
8 ~/ `$ ]4 p1 T8 U% O" v' H5 o$ e( R* a3 d! o8 @- {
    /* join kset if set, use it as parent if we do not already have one */6 ~9 d, }) x) n+ ~2 Y+ W& z! N/ ^$ K
    if (kobj->kset) {   
9 p+ Q& V3 Y- x6 L3 K        if (!parent)
5 {+ Q9 g) x4 g% ]0 K8 [# M            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
; l0 q" c( H8 b5 \( a            parent = kobject_get(&kobj->kset->kobj);
% p0 j5 D/ z7 S$ |% M9 o& j( W: F        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/3 u5 c+ n2 x: W& m8 ]- [- ^
        kobj->parent = parent;- m# v4 z; g  |2 V$ ~
    }
2 q% q5 J0 ]1 e, u: E4 x
% B. z0 T3 x+ k( \1 g' \7 J    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",, q0 W" i$ f2 [2 T- D" i( h; |
         kobject_name(kobj), kobj, __func__,8 Z2 c/ X6 g3 ]7 M
         parent ? kobject_name(parent) : "<NULL>",
: K- Q( n9 x/ E7 F         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");5 b( n& ^0 H. G$ E* [9 C& v

7 F5 C! h" y: i2 b    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/" ]9 u0 t6 ^2 h( W
    if (error) {
3 b9 a1 V# `5 v0 g  p  Z        kobj_kset_leave(kobj);    /*删除链表项*/& V" ]0 O5 w; \
        kobject_put(parent);    /*减少引用计数*/9 }* Q. I4 s5 I4 |
        kobj->parent = NULL;
. b6 A/ ]# S; c; m; r: \/ |$ c# V* x# s: @3 q
        /* be noisy on error issues */
9 o* {1 S) J7 u8 }2 ~# k( K        if (error == -EEXIST)* U) j; v( M$ m2 }
            printk(KERN_ERR "%s failed for %s with "
2 t9 f# o  l& T* A4 ]% p                   "-EEXIST, don't try to register things with "
% I6 Q8 i% @1 v                   "the same name in the same directory.\n",
1 F# J4 z2 Z3 C+ ~% W( A7 b3 u3 [  h; @; O                   __func__, kobject_name(kobj));& g  A+ t' N* c3 J! M
        else
& U. U% F7 v% f! d" x- c) ^- [            printk(KERN_ERR "%s failed for %s (%d)\n",9 @* \5 q  k- [0 ^* D# h4 o
                   __func__, kobject_name(kobj), error);
, i3 p$ b* X2 S( y& e, E        dump_stack();
% v9 ]; Z$ M5 h6 r! V, Q, g) B    } else* I9 j- B% S8 _, Q& k
        kobj->state_in_sysfs = 1;
1 p* B7 p, U; {
" p9 |& p9 k7 C1 q: \0 w- I- O: J; c% J    return error;- D' c& ^2 f+ ?1 a. a7 O5 m5 o2 c
}
; p# M, K6 s& R5 [! s在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。
7 @* d. W0 i% b2 [而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。7 Q- e/ t& \# i2 I

" G: O/ w# ]. h2 U2 Z% @. D& A但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???
2 |+ i  g0 r' U4 ]6 {7 d9 @
0 K1 M# P5 C7 n/ E8 |0 {* p6.2.3 device_create_sys_dev_entry函数
6 y8 D0 g4 m. o/ \. c在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。4 G; [1 [0 n- \& {
但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。7 C9 a8 W+ w. @7 {9 j5 Q5 q! o6 u
. \# A& G- ~9 C( {/ V, Z
下列代码位于drivers/base/core.c。/ _! U7 Q$ \# ?! h
static int device_create_sys_dev_entry(struct device *dev)- ]  ~' U: l5 O6 X! \, W. ^2 n
{& H4 i3 p, ^1 W4 O5 h+ i
        struct kobject *kobj = device_to_dev_kobj(dev);5 o! T# Q. Q3 N- B& w$ Y* w& @
        int error = 0;( d, F! H+ l: I2 r. f4 y
        char devt_str[15];
7 o8 s1 B) k* i( o' ^9 W
" G3 V6 H) L& e- D% ]5 {2 J        if (kobj) {9 m' B" p- z! p" x
                format_dev_t(devt_str, dev->devt);
" _7 H: }+ [9 q" @                error = sysfs_create_link(kobj, &dev->kobj, devt_str);
* R* ~2 Z! D* t- E0 z; \        }1 e4 \) a  J% E6 E

3 {/ ]+ O0 O, ?        return error;) [% r" d+ d& W* D
}% W/ X- ~. Q5 @8 s2 {/ O; s" l
/**/ A0 k* B, i  N7 f/ V
* device_to_dev_kobj - select a /sys/dev/ directory for the device
2 M8 K: n# G$ H/ R6 {( T& G) r * @dev: device
0 D" k% M" B& y2 y- A *
8 E# G' }' \5 t( Z4 d. S5 ^7 U4 \6 M * By default we select char/ for new entries.  Setting class->dev_obj& V* H* N" E/ a. R) P7 k, J7 K
* to NULL prevents an entry from being created.  class->dev_kobj must' p+ v% s- u- m+ g- B
* be set (or cleared) before any devices are registered to the class! o- }) J3 `1 |$ o$ ~% M7 U
* otherwise device_create_sys_dev_entry() and5 _2 L3 ]5 u+ p) J/ o& f( d) F& P
* device_remove_sys_dev_entry() will disagree about the the presence
8 S7 u" D* i7 p * of the link.
# d: n4 a4 w, ]  k0 M* r */2 M: b- G7 H6 X" E2 F1 _! k
static struct kobject *device_to_dev_kobj(struct device *dev)
+ n8 J. i+ {2 v. k{
4 F6 R, C) f/ J: Q( o' T    struct kobject *kobj;: a) _6 g2 i/ @5 G( \9 m1 A
/ |# B9 D! T' o
    if (dev->class)3 h0 ~( o2 I8 V: l9 q6 S
        kobj = dev->class->dev_kobj;; o7 `7 L* S# O+ B
    else
  N8 _6 T. E. [4 v        kobj = sysfs_dev_char_kobj;
, g0 q7 f$ T7 Z+ ~1 p7 O/ {* A) i! h7 j/ K
    return kobj;
. Y% M( o! y6 b& D& O8 b}
! W  l4 c1 r0 X; z9 y' Q0 z7 u; x2 }% @6 P( w$ o- m
6.2.4 device_add_class_symlinks函数
/ j7 z1 ^/ z% m! d由于dev->class为NULL,本函数其实没做任何工作。5 Q. i* w5 N* \9 x+ b3 w( U+ N
0 U+ ]% _) S! t, S( |$ [  |  s( y
下列代码位于drivers/base/core.c。
1 t' C0 [% E; g! a& O0 ]static int device_add_class_symlinks(struct device *dev)
2 V' n$ ?, d( b: W{
% t, J9 b, g. T        int error;
/ }2 l; S. S: K* F0 n; Q
# [( q/ W2 d# L9 U/ W4 A        if (!dev->class)
' h; {+ b0 l7 H                return 0;
2 ~) W6 z) N  a+ i. e0 [  R! u* p+ u2 f
        error = sysfs_create_link(&dev->kobj,0 |; Y3 p# X4 ?& ~/ E( E  l2 N  A' I
                                  &dev->class->p->class_subsys.kobj,- E6 Z8 D$ s. S6 c4 h2 }6 S
                                  "subsystem");9 t% j) `. N- n  X; h7 N. d
        if (error)1 j* A* S% N- u: D' a8 p
                goto out;
: X: r7 o# Y( U: k' D) l7 j$ N: q: p5 [8 R0 b0 f
#ifdef CONFIG_SYSFS_DEPRECATED5 C7 q  ]) z3 m0 b0 j1 V+ w, w6 Y
        /* stacked class devices need a symlink in the class directory */: n# w7 Z2 A( @4 ^
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&/ J1 E9 H, B, V8 Q
            device_is_not_partition(dev)) {
" q7 w* X. E% F$ J0 R- w- @                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
) k% X) `- f" X* F! H9 C                                          &dev->kobj, dev_name(dev));# m$ @" B# ^: E* |9 W
                if (error)( M  ~: |8 K! g8 P: [& J
                        goto out_subsys;0 \0 B3 R$ W/ n  y8 e/ K
        }5 P4 q9 n& W/ C* t( U
& o3 W% ]8 s) C
        if (dev->parent && device_is_not_partition(dev)) {: o1 O% Z$ c: O; r
                struct device *parent = dev->parent;
5 W: x% o3 ?$ D$ \# a                char *class_name;
- z' _4 e1 s: C  n) R& _7 O
, R% z2 P4 C7 U  i                /*! b3 J9 _# B  h$ Q" z2 T& }+ V  H# J
                 * stacked class devices have the 'device' link
2 f/ \, v/ k8 Z  [: C                 * pointing to the bus device instead of the parent' O( j2 S$ I/ `# p6 U6 u- A- A4 o
                 */( s. X8 E3 ?" |4 `) ~
                while (parent->class && !parent->bus && parent->parent)$ H3 {  ~) g, T
                        parent = parent->parent;  ?6 G  n, c1 O7 i% z! \

7 Z9 a7 B1 \: o1 ?1 T9 m+ U: g. I                error = sysfs_create_link(&dev->kobj,
  P; [' }9 S9 i2 W: f: u                                          &parent->kobj,5 m8 S- @+ k' i' x) d; G" d/ [
                                          "device");
" C; o/ {( I2 s; m* z                if (error)/ c2 T/ _5 U& f7 @
                        goto out_busid;7 J, L" X# q0 G; _  R4 ?

4 x! E3 K. F5 X0 s                class_name = make_class_name(dev->class->name,
4 ~  w7 p, U' i1 S* O0 S                                                &dev->kobj);
( [, g% z; U# P( ~                if (class_name)" s8 r3 W4 ], J! N2 f$ @
                        error = sysfs_create_link(&dev->parent->kobj,+ W- w& T7 b3 L: x, b4 c$ U
                                                &dev->kobj, class_name);
7 a0 T) [* R# V  y4 r! |1 `                kfree(class_name);/ M" s* Y- I* J" Q: l
                if (error)+ i! e4 Y' L3 N' E) i- D- O$ a8 U
                        goto out_device;
1 ?5 R9 g4 u$ {# _( \2 H0 W        }* N( o9 r  x3 @/ o
        return 0;' M" q0 s. T. e4 ]
: x8 c; Z& z% w# v9 ]/ r% b
out_device:
9 ]( U! Z; T) i4 _. V        if (dev->parent && device_is_not_partition(dev))
$ @* Q& U! i3 F6 _- m                sysfs_remove_link(&dev->kobj, "device");
! n# @9 D/ M' [5 @; oout_busid:" }  v1 ]. V* Z
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&, p3 k+ [$ j; k6 W  l
            device_is_not_partition(dev))* W. j. F5 t5 ?; M# n7 Z/ R
                sysfs_remove_link(&dev->class->p->class_subsys.kobj,4 E; i3 P' _7 I- E# S4 X
                                  dev_name(dev));" r% A* y3 C+ d  c# g8 @
#else0 D# s9 E7 @! J+ h+ [( r9 N0 _
        /* link in the class directory pointing to the device */
! k( H& U, V  x) H; n2 D2 ~: D        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
  J5 S; G; J2 F                                  &dev->kobj, dev_name(dev));' p9 ~* h" [1 @- a; D
        if (error)
3 w7 d) @  R  x& R3 {! P. S0 x                goto out_subsys;+ B4 H) m0 `& d% x
( j0 v: @' _8 b) o& q
        if (dev->parent && device_is_not_partition(dev)) {
4 s7 _7 x, y$ R1 H7 k/ x. o                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
; I# `, T" W: Z8 z, C                                          "device");7 E' r% ?' C, t) x. P) m; X
                if (error)
* n+ F' |+ [" k. c; L9 z                        goto out_busid;
5 p$ w4 t8 J: }2 v        }
* t2 f3 ?+ A- Q        return 0;1 m( n  t: N/ X7 |! P

1 V( ^3 G  f% x' o# rout_busid:
1 Z. T! H* d5 A4 H        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
' V/ K8 g+ `8 |0 n#endif, t$ c7 Q4 X; R0 L

8 F) T8 A& Q5 |out_subsys:" G4 A3 r" ^0 p0 M, u
        sysfs_remove_link(&dev->kobj, "subsystem");
# n5 R0 U, q  m. @- tout:0 o9 x7 l# X4 }
        return error;
8 ?2 q! X+ \6 S% l; s; l}
4 S" f; V1 G' I9 j6 N6.2.5 device_add_attrs函数: a" }4 X* y" x
同样dev->class为空,什么都没干。, R/ O4 _2 K6 j$ w) K# P, ]% ^2 e6 n
下列代码位于drivers/base/core.c。
/ D, o5 B. {+ m5 |" gstatic int device_add_attrs(struct device *dev)* f6 }7 t; D, S) C" w/ n  t) ~
{- o( ^9 Q1 m, t) x# t6 L% Q
        struct class *class = dev->class;3 }/ w, {6 B" K- S
        struct device_type *type = dev->type;
# l0 u# `8 A8 d/ A, H        int error;
0 J! i  d' \: v2 v' V
! ^- o8 R; @' |. Q8 w        if (class) {
; V0 F+ ^0 ?9 y- F& L- f9 ~                error = device_add_attributes(dev, class->dev_attrs);' L6 ^+ }7 M% V* W: W% ~* I
                if (error). h/ c9 w: y% N* g
                        return error;
7 b1 [1 y6 c9 _        }
* T% z2 P6 V9 M! z% K
9 u. Y; m. o0 e7 f0 r        if (type) {
6 K1 \- l5 J, f+ M( I  w1 v                error = device_add_groups(dev, type->groups);  C( C" [1 D( ^6 E% I# K- [
                if (error)2 r: z& F- r6 ]* u& M. P7 p
                        goto err_remove_class_attrs;
, Z% m3 v3 A3 M! T. ?4 m        }
; n8 m4 I  R+ E( j0 E$ z! {$ y7 X# T
        error = device_add_groups(dev, dev->groups);9 a& h7 t2 o( |$ t  w* P
        if (error)
3 T' f8 O9 {  Q- l0 j$ s4 Q  b  E                goto err_remove_type_groups;' M+ A6 b* [2 h8 r8 u  `2 J2 ~4 C: K

$ J5 H' |. w8 V! Z" N6 v  l( W        return 0;
4 v  @( {; C$ J- P' z0 h. b( A& X2 C- g- [/ c
err_remove_type_groups:
( J2 P# h+ f$ \7 n; t. o        if (type)
( ~& |7 F* q" f) e                device_remove_groups(dev, type->groups);
% X" Q0 j* T8 ^! ?: ]3 |2 i err_remove_class_attrs:
' W% E. L+ E$ j% M) t        if (class)- F4 w% n" R1 {. l
                device_remove_attributes(dev, class->dev_attrs);8 q7 K, e* R! Y: u7 m# F- l

5 L) E! c% ?6 r: q# o        return error;
- w8 i! M0 i3 I3 z4 W! Z}8 j+ @9 a/ @% i4 A' l
6.2.6 bus_add_device函数0 f3 n% J% [! m4 @4 U
由于dev->bus未指定,因此这个函数什么都没干。8 k9 K+ R$ q7 q1 s

5 v7 l; o  Q) R: _% d. d+ I该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。: F  i/ G! n/ D! n' x: P) R, g* T  H

4 e) O' J- A! c' |* E下列代码位于drivers/base/bus.c。
( t# t% o- @. ?9 _/**
0 H+ ~) ]5 O: V% P) o# R * bus_add_device - add device to bus
$ y* n7 ^) j3 @ * @dev: device being added( k2 [; N- M  W$ b
*
; v7 l" E: @9 M4 W/ E- k6 } * - Add the device to its bus's list of devices.
* g* g) j1 a2 G% `* H * - Create link to device's bus.- ]; r3 X4 Q1 E* M4 |
*/* i1 Q; V1 G* t, M& S& z
int bus_add_device(struct device *dev)
( i$ b+ u; R' p{
5 d+ V3 P1 L+ T, S/ B        struct bus_type *bus = bus_get(dev->bus);( y, m% o  ?. l- H6 o5 Q3 U& i
        int error = 0;
1 s0 }, S/ D3 m5 P2 o- K2 n. E) R) w$ D: F3 J% W
        if (bus) {5 G# H* N3 q" ?; q- Q
                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));1 X9 L% q, Q9 o- W! O1 A0 n; J
                error = device_add_attrs(bus, dev);  V3 r  N0 Q" y0 P+ B( e/ R
                if (error)0 o+ k& P& R8 M7 I0 c
                        goto out_put;
, X3 M7 U7 c- N: Q                # O# B4 S' E' m
                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/7 ~! X1 X1 N; @% n
                error = sysfs_create_link(&bus->p->devices_kset->kobj,
9 c: A4 e" v! N8 s" E3 ^: S) Y* e                                                &dev->kobj, dev_name(dev));( E+ {& e4 L- y2 y# n8 K
                if (error)
' U. C6 n' K* M* `4 ]) [, r                        goto out_id;4 R  Z; @3 L; A$ {) g/ o' N3 H  \
                / ~) {: [2 n8 l' N  R, v
                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
* C: \( S) P% n' s5 O- X+ `0 d, K: i                error = sysfs_create_link(&dev->kobj,5 Y  M: i- b3 i* o1 F. L! K
                                &dev->bus->p->subsys.kobj, "subsystem");* P1 o! C4 U. K. E" X' k- F3 P8 F' ^
                if (error)
8 E4 P  C2 m7 v4 U$ Z% u                        goto out_subsys;; ?5 Y8 y! M7 d8 I/ J
               
7 J6 l, i3 R; ?2 N" `) p' h                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/% d" M" g' [' k5 A
                error = make_deprecated_bus_links(dev);) R' Z% }" H; P# Q# h( K
                if (error)
/ _: D7 u. S9 ~+ X! c6 }0 c                        goto out_deprecated;
# I' r* s. g+ T4 u        }# t1 {6 }. c+ K: U; h. y
        return 0;( z' [# c1 _( v, ]/ e1 K5 Z
3 w6 R% s& A5 ?
out_deprecated:
) N& d$ r4 I, g3 W5 K: y        sysfs_remove_link(&dev->kobj, "subsystem");& K+ o3 z' G. Q3 g7 C
out_subsys:
" @/ f6 D8 j1 R( {1 J, R        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
8 [" \7 s% B+ B  ~' j0 M/ X1 P& ~out_id:
1 K# p& e- o5 e! N! g. P/ b9 H3 v" K        device_remove_attrs(bus, dev);' w6 F3 O5 c8 r& _& J/ m
out_put:0 I& `* a) W0 \' ]8 H  d
        bus_put(dev->bus);( I# O* _) m! c& @) R) O
        return error;
/ o! m" @; t. r: [+ Z}
  i2 }+ r. ~  D0 l$ v. \/ e" R! g- N! L1 h% Z
6.2.7 dpm_sysfs_add函数
/ }+ O' X3 q) \5 d, `* ^下列代码位于drivers/base/power/sysfs.c。1 _- Q, q( R1 O( T9 w; Q" E+ C
int dpm_sysfs_add(struct device * dev)
' \1 m; T. R" _7 i" p{2 C4 V7 r9 ~2 I
        return sysfs_create_group(&dev->kobj, &pm_attr_group);
9 V6 o+ J# K1 `4 t2 e}
, r) P* B! r+ z* [1 B& o' U& z( L
2 E1 o, O' E- G( T" C) [0 ^, Ustatic DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);0 A% o' l  N/ ]7 N6 C4 h8 O9 r; I

9 a( V, A9 q9 k8 z! F5 {
# A; |& x2 l6 L; n. O8 y/ ^static struct attribute * power_attrs[] = {
- m5 y/ ^' |7 I* J# k, R    &dev_attr_wakeup.attr,$ p, o: b& ]3 d& S
    NULL,
* }' A4 d6 r2 @% H};
# k4 s; v8 P/ M% ~/ bstatic struct attribute_group pm_attr_group = {
( Q+ I. n) y0 C, w4 P* j    .name    = "power",5 S9 n3 ^4 }: T5 K3 p  D2 ]
    .attrs    = power_attrs,
, \) r- q: p$ q! y; F  F};
% Y& _+ m0 E  a
+ S. l  W$ E# Y该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。
4 p, C; Y+ c* ]9 F2 _. w% i# }7 K& D% ~+ P: E# S
在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。
, p# T) ]: v! d+ B1 y1 F% f) n6.2.8 device_pm_add函数! n- Q$ `1 O, z% T
下列代码位于drivers/base/power/main.c。9 I; {1 n# R0 Z& S
/**
- D* l, @$ J1 ^/ i7 M; X *        device_pm_add - add a device to the list of active devices) D# T9 {8 B( P2 h3 s
*        @dev:        Device to be added to the list
% n9 _( {4 H4 x# J2 T */  q$ x6 d, Q: _4 U- W+ ^
void device_pm_add(struct device *dev)
4 D8 Z# p0 |0 i0 U$ `! j( S{; ^: |5 X/ J! c- S1 [1 N
        pr_debug("PM: Adding info for %s:%s\n",7 h/ a, z9 Y* ^
                 dev->bus ? dev->bus->name : "No Bus",# S5 m* e" G2 u& S  ^. O, g( v
                 kobject_name(&dev->kobj));
* x7 R8 A, `- U+ S1 Y# l        mutex_lock(&dpm_list_mtx);4 y9 X8 R# Q7 C& d8 ], t
        if (dev->parent) {9 m8 w. e8 [- I' F: y- H
                if (dev->parent->power.status >= DPM_SUSPENDING)9 e! ], @- {$ u" {
                        dev_warn(dev, "parent %s should not be sleeping\n",
% p% S" Y; `$ z. o) Q                                 dev_name(dev->parent));
5 F+ e' }0 N6 r. d0 q        } else if (transition_started) {
' |- f* E% O: e- _* o( S                /*
2 I, i' z- S- e- @                 * We refuse to register parentless devices while a PM) N; e" J2 h$ V6 O( L$ f
                 * transition is in progress in order to avoid leaving them/ {+ N# y5 t! q( c8 ?" q0 ?
                 * unhandled down the road
) R; h& h# r! d$ H/ X0 H                 */& `6 z% Z1 [# `: t& E1 |
                dev_WARN(dev, "Parentless device registered during a PM transaction\n");4 I; I# T3 A, z% l
        }
& C8 v4 \) ~$ A4 X5 F. a% d9 c' O7 W  k4 _0 `3 H
        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/
& k" ^  m/ o/ _/ ^; b        mutex_unlock(&dpm_list_mtx);6 |2 K+ ^. l6 I+ w  m
}, M9 i: P  c( e2 _; V3 V" j% }, i
/ e) d( v$ x" R  s* {
该函数只是将设备添加到电源管理链表中。
( M5 ^5 t* _# g( y) n  P6 K6.2.9 bus_attach_device函数5 z* }8 l* W$ Y% E% I4 M) J9 N
在本例中,由于bus未指定,该函数实际不做任何工作。
% l& ]; \4 I: ^6 h  ^" v* o下列代码位于drivers/base/bus.c。
  S' Q# ^' m0 ?7 S; p* ^: X# f
8 M1 s/ Q4 c* y% F9 M6 O/**( {% j- g# d4 @$ t% ]( e
* bus_attach_device - add device to bus
- a  ]6 C; Z9 y' A  o. K; B * @dev: device tried to attach to a driver* U/ T8 }# ~- P+ n
*
7 P+ x9 O; F( Z' ~/ w0 C * - Add device to bus's list of devices.
) C% c+ R0 i# \+ n+ z% d * - Try to attach to driver.& A, u; O: t2 l  N, G8 Q
*/
0 j( t. i0 w; r- {) t- O  Gvoid bus_attach_device(struct device *dev)  V7 D4 ]8 n4 t0 o: H
{
3 t* g- {& T' s1 w! ]( C        struct bus_type *bus = dev->bus;
1 k- A3 G+ m4 m- H5 K        int ret = 0;& B& Z& T/ h( O$ ?' K; W4 ~
7 d, G( D8 B* u0 t5 Q+ R5 B. ^
        if (bus) {& a# p% W! E2 @; l
                if (bus->p->drivers_autoprobe)
- i* @+ F" }( g3 L- m1 v, v) _4 t                        ret = device_attach(dev);        /*尝试获取驱动*/8 H& X' s" J1 _- ?/ U
                WARN_ON(ret < 0);
* c8 R' ~# F, `                if (ret >= 0)                /*将设备挂在到总线中*/: G, x% i; V- J9 D3 x
                        klist_add_tail(&dev->p->knode_bus,* [" E' c2 o1 h3 F+ J
                                       &bus->p->klist_devices);2 L, s4 |9 b$ m3 x
        }
( A  [6 A, z. n+ F& M( w% Z}
. X2 e" {4 ?- k. o& Z+ T$ L( B$ a
/**
/ o9 q4 k8 ]4 h  | * device_attach - try to attach device to a driver., m: R$ P* m, Z9 j" w
* @dev: device.3 }! N- `- v! @$ I3 e" X
*" Z! c7 O$ z( o7 v) P  J* f5 e
* Walk the list of drivers that the bus has and call1 G7 ]7 q  n! C+ B) p: c, J; a
* driver_probe_device() for each pair. If a compatible7 N& M6 T! \% ~* n) O* t
* pair is found, break out and return.! c9 j3 f& D2 N' E5 R+ K" O  _
*
9 Q0 F  V- d  ~& w2 | * Returns 1 if the device was bound to a driver;  J& N' u2 @4 Z' ~$ N3 M3 O, Y
* 0 if no matching device was found;
' N+ P+ O. X6 A: h6 m * -ENODEV if the device is not registered.: {) L1 h4 L- K) E
*
  y: r6 [; |  J2 l7 J; B * When called for a USB interface, @dev->parent->sem must be held.
0 D: I$ p# J/ c3 k */
0 e7 \8 h  g3 R3 n* Wint device_attach(struct device *dev)* f" i: a4 w- D  K
{
( q( i( J* _9 f: o# B" R    int ret = 0;
4 {5 B/ l2 v3 M% |  o& q
  ~6 l* a. ~/ m7 v9 w% k    down(&dev->sem);: g  v/ K, M/ }# z0 i! l$ S: ~7 _. I
    if (dev->driver) {    /*如果已指定驱动,即已绑定*/) S/ h7 V$ x, E) t
        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
* L# x2 a8 h, W7 b* Z% y        if (ret == 0)4 g" h6 U* t+ ~6 l% @2 Z2 b( C" Q1 v
            ret = 1;# I- p% }4 w$ {9 g. S
        else {
) _! C( T8 v1 ?7 y5 Q            dev->driver = NULL;6 {$ N# @4 w4 R- l% h! E2 D4 v
            ret = 0;% z( K4 s4 t+ Q: M& D' x8 \9 \2 h
        }! U  U7 c" {- D  ~8 y3 g+ j( f
    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/, E8 ], B. `+ H9 d  v6 R6 M
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);  b0 H8 f/ M: M9 n; E
    }
( t% V. R/ Y* W, e0 b+ U! G    up(&dev->sem);1 D3 V; H8 W5 e/ v- ^
    return ret;
! o, l+ c0 b+ G/ m* @}! {4 Y0 S7 z5 q% i* h; D
EXPORT_SYMBOL_GPL(device_attach);
: b8 X( p, |& c  V+ \5 p/ H, x) O
如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。
4 j: k* m, d; x; C
2 p5 d* n. R- V; z3 J7 S为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。9 l/ a4 ?- _( D1 k5 {! R: |
2 R% m# _+ ~4 C" ]* s
我们来看下bus_for_each_drv:& I8 ^+ x( C: H/ o4 p3 V" a7 u
, K! {2 x# P% L+ [# L2 ?9 x
/**7 h: w9 c+ r8 E* g$ a5 }
* bus_for_each_drv - driver iterator
' |( n2 o$ S  r0 ?( e * @bus: bus we're dealing with.
$ X& {6 t/ a  X+ K * @start: driver to start iterating on.
8 q4 ~' y# R( P7 v; X1 L * @data: data to pass to the callback.: S- e  i' ^4 g, K% X
* @fn: function to call for each driver.
3 D+ v+ `& F' v# L% K2 q2 @: ] *
, b  W: M, B# ? * This is nearly identical to the device iterator above.: G/ p: {" O+ E' k- ?- h8 u
* We iterate over each driver that belongs to @bus, and call9 W8 Q4 Y5 T& M# n' y& ^
* @fn for each. If @fn returns anything but 0, we break out
- H# d/ O& S6 L. z- t- d- H$ h * and return it. If @start is not NULL, we use it as the head1 O! N- G$ U" D) B5 L. a
* of the list.& t, c% Z0 w; f. {% X8 @
*
. k& q# {- H0 @- a8 P9 ? * NOTE: we don't return the driver that returns a non-zero
$ n+ J' R7 H+ r% K# H( j! z * value, nor do we leave the reference count incremented for that& l1 ^3 Q  B4 B  a( E" Y
* driver. If the caller needs to know that info, it must set it  O  {% C6 E8 n) m* `
* in the callback. It must also be sure to increment the refcount% g5 q8 G4 j0 `, p2 b+ I$ E+ A$ i: g" g
* so it doesn't disappear before returning to the caller.9 S, V0 K3 |0 P/ {* Y9 W7 C
*/# w, E/ a1 \  H4 W7 S% G
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,! G3 P4 \5 L9 ?& X
             void *data, int (*fn)(struct device_driver *, void *))
7 O5 I# \5 l" d$ D  v- w{
# X. y/ ?0 T1 r. h. f  A    struct klist_iter i;5 ?2 Z+ e3 b' T5 i3 H5 D
    struct device_driver *drv;
+ x+ F4 e1 S( s* w( I5 z4 r    int error = 0;! `# Z# I0 I. [* n7 `0 Q

+ @% `6 T3 O7 H' `4 B    if (!bus)
, i. y- b/ G- i% A8 O+ h        return -EINVAL;* g2 |2 Z$ D7 H0 t) ^, C5 [
, t; J0 f) D6 S- E4 ?3 s
    klist_iter_init_node(&bus->p->klist_drivers, &i,  u1 [  x5 |- l& q: M
                 start ? &start->p->knode_bus : NULL);6 }; R/ P2 @: x  J! E/ m
    while ((drv = next_driver(&i)) && !error)
' F: X; ~9 R5 V$ y( o( B2 b0 y        error = fn(drv, data);7 u4 k$ Q7 I: G# r+ G6 V$ h0 e
    klist_iter_exit(&i);7 U* d& V$ u% Y4 k4 o0 c
    return error;
8 L2 f. S: P. [}+ p* Y3 P4 j- t9 k6 L1 @- }
EXPORT_SYMBOL_GPL(bus_for_each_drv);* s; |6 j: B% l' `( \
该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:# t, b5 j; K0 L) i* ]. J9 h

* X* h' M1 [$ n" S) l. P' ~) _  o7 Y4 Dstatic int __device_attach(struct device_driver *drv, void *data)
# @& i& v) }- m5 ~8 O{
( u# B. Z! [) F9 U; Q' h! z1 @        struct device *dev = data;) z6 v& t- |. T

  _1 v5 p* ]" K        if (!driver_match_device(drv, dev))   /*进行匹配工作*/" G3 Z2 V! [, t" B& [! ?
                return 0;
# I: u5 r! G) j$ O2 M$ }" M' C* |" _9 b: R. _2 G
        return driver_probe_device(drv, dev);
! f3 d' n; g) S" n! }/ p% X}2 V4 I6 o% N0 M" X, o# w( c# m/ a

+ J) L3 G, M+ istatic inline int driver_match_device(struct device_driver *drv,; n0 ~/ W* T8 C4 x& B0 g
                      struct device *dev)* b& s1 k2 G8 u
{4 ^/ [# k+ M$ M4 y0 R9 x
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
- Q. H5 P; Z4 V} 7 ]3 V( r3 Q, X3 \

% F' T" @3 ?' n/**. P# ^+ }, S8 D4 e4 _# A
* driver_probe_device - attempt to bind device & driver together
- T. k, X6 ?: p0 X9 a) r * @drv: driver to bind a device to# N. f) c  T* H/ M, `7 `
* @dev: device to try to bind to the driver2 I  M5 _$ x2 e' F% t9 N! @* X
*
5 W- G4 E2 _! z2 q% K' k * This function returns -ENODEV if the device is not registered,
; g; x( `8 I& c+ T  H0 P * 1 if the device is bound sucessfully and 0 otherwise.; P1 y% {% E1 F# e( i4 L* v
*
$ I! Y) h+ O" F7 ^5 @2 ? * This function must be called with @dev->sem held.  When called for a
1 W( y* Q) m  ^ * USB interface, @dev->parent->sem must be held as well.
: o- M5 L9 U' J. m */, ^1 \" {; y2 T4 b5 I
int driver_probe_device(struct device_driver *drv, struct device *dev)
3 g: E' {9 i7 K( u5 K{
! q; R* p8 f6 x( ~  Z! [: K4 i    int ret = 0;5 i3 D9 o  ?) U! m

4 J* L8 O' o9 I( H9 o+ @: Z    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/. q% {) h6 ]/ L2 I
        return -ENODEV;" z( r3 _+ K5 \* c, M

% k3 J8 [6 k+ v# g    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
# n  ^& y' u0 G3 f0 ~) k! A& a         drv->bus->name, __func__, dev_name(dev), drv->name);
7 n- ^! z* Q. q- B, A  h+ j5 t6 W# v( {/ I' t' M  {4 T0 K
    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/   
: b' `( s  U* g* F: |! V+ v
* h5 o3 i) T% y2 s5 f    return ret;, t8 g8 ?+ R" K5 p
}1 q* j- b; S- Z. u: N
$ ]$ T4 Q( {7 ^
该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。* ^) p% v2 t3 S: k6 \# A) O
我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。
- q& V9 P$ w" I  ?1 ]. T& q
. c6 D9 k. |; h5 Y) H4 a& K% _+ u随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。
2 |" Y, n8 A7 W) q) D) h4 W+ ~5 `* i( {5 {  x7 ^! |4 T
really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。: o. u4 V. b" m
6.2.10 小结
$ m+ \( A4 C! B1 O8 P7 Y在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。
% ~* p" F2 q; Z$ d! b+ s- I% O( G1 f* z. Z- X/ E0 [( Q
最后以函数调用过程的总结来结束第6.2小结。
; k3 d& Q) m% R7 X6 T6 R+ O! L5 F( E6 Q

4 _5 N$ n4 J1 l
+ \2 [! O# \0 C' J: i/ X' v/ k- K% T9 ~  ?
6.3 spi主控制器的平台设备
. h' E" J/ Z! r4 U本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。
& V; r' v" G  f. \( T6 ~3 x
) h; t& U! j' N4 m" p$ v+ f在内核的启动阶段,platform设备将被注册进内核。我们来看下。- r0 b- X% S' q" Y; I+ K" d+ E
  J9 t/ P4 e# o9 E, v+ D/ c4 q
下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c
8 v& ~6 [% K1 |% z  x. S& [
  R  Y; d8 D! m8 p# `9 Q4 p$ ystatic struct resource s3c_spi0_resource[] = {
. {7 e& k( v  ^, c  A4 g    [0] = {
! r( _  e: G; v& k% R        .start = S3C24XX_PA_SPI,
" K8 {, C% L$ E& k' R        .end   = S3C24XX_PA_SPI + 0x1f,
& t4 n' L  O  |$ F        .flags = IORESOURCE_MEM,
2 [3 j% c9 H; w) L  A! y1 F0 M    },) N1 T1 o6 ^, f6 a% u
    [1] = {3 C! c2 Y5 W- U; f% O" \
        .start = IRQ_SPI0,
2 Z) {4 R! W5 g- S/ c        .end   = IRQ_SPI0,7 w2 z0 x2 G4 ~7 ~' }5 z- y
        .flags = IORESOURCE_IRQ,: {% K, K6 \  P; w: U
    }
* W# d9 y1 |4 P" ^7 N6 ^/ j
  |7 \3 n, q5 Y: }- R& s};% ~0 T% x0 X% s% d8 M. \
$ Z, z9 x9 f; ~9 i
static u64 s3c_device_spi0_dmamask = 0xffffffffUL;7 b$ I& z. Z7 i1 _
$ o5 `% b' J0 y
struct platform_device s3c_device_spi0 = {3 y: i' y. a0 a3 F/ X+ c& E# T. @
    .name          = "s3c2410-spi",1 N* O8 Z3 Z) N
    .id          = 0,
) ]# B' Q6 K8 t, k2 N3 b    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
; t0 U/ J/ O) F5 P. y! x    .resource      = s3c_spi0_resource,
, h9 l, ]  q  f9 k6 N: V6 M( s; [- M        .dev              = {! F' j, o+ o8 D  q! N) Z8 h
                .dma_mask = &s3c_device_spi0_dmamask,
* @/ Z* |; ^7 Q. h                .coherent_dma_mask = 0xffffffffUL
/ c5 l9 H4 |1 Y6 H6 d  |( v6 f        }
# H3 p! T7 {/ m# G};
0 h1 A. M  ^6 K! m$ W$ u) S2 h# }! C4 m4 S
: B; s- E+ ^2 H: q1 Qstatic struct platform_device *smdk2440_devices[] __initdata = {( |: T- m" ]" j7 N
    &s3c_device_usb,$ V1 B4 m& y  ?, ~+ l! ^
    &s3c_device_lcd,4 U2 P' m/ ]& T# p$ v( B
    &s3c_device_wdt,' o+ ^" K/ ]) ]; z/ k) H
    &s3c_device_i2c0,
0 O* p- l% V9 u3 o; r    &s3c_device_iis,- P2 T4 e1 q7 s, O+ H3 u. U
    &s3c_device_spi0,
9 a, i3 v8 J/ w. c( k5 Y};3 ^6 j4 h) f; m' e1 Y( {2 x$ Y, @
, D  e7 c1 Q7 }* q
+ s# k3 Y% f  S  q6 y; d6 U3 d

" ]' u5 i9 k# Q0 Lstatic void __init smdk2440_machine_init(void)
' x9 ?/ j. [1 c+ h8 ^% F! q{
# e7 I5 E( r8 X! {* f        s3c24xx_fb_set_platdata(&smdk2440_fb_info);" Q0 p2 r  s1 A$ ]% r; j% p* O
        s3c_i2c0_set_platdata(NULL);
, }- B5 d- u+ B# E/ R; d+ d- [, Y& K" S1 F9 E5 E/ s. Q
        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));5 g7 E8 t9 e. A! t, F* s
        smdk_machine_init();+ m* M+ q) q/ f1 t  j4 X* C2 G( B
}' t: J, i4 V" U/ a4 b; o
' [  l3 D6 E6 F- L/ J- C
在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。( P  {" S  M2 I9 G% a# x
6.3.1 platform_add_devices
; D+ a6 W. _1 c5 u, i/*** D/ V4 n' U1 r# h  ^
* platform_add_devices - add a numbers of platform devices$ I6 S' }+ X$ W: J
* @devs: array of platform devices to add0 O! @. w; `+ ?6 Q  s6 {
* @num: number of platform devices in array
2 f. N' E0 [6 N4 G6 e  l9 f */9 v- \6 l7 o6 W! ^# F
int platform_add_devices(struct platform_device **devs, int num)
4 e5 |7 m1 W% }, Y{
. X- D& h5 ^) \* Z% M        int i, ret = 0;" k; x8 }3 b% v* o% M8 J& M

3 G9 s+ e! T$ F7 ?& F        for (i = 0; i < num; i++) {
& I9 r2 J4 Z0 A7 u7 C4 F; n: s                ret = platform_device_register(devs);' T: Q6 e+ ]* O
                if (ret) {/ a, ~2 g- x1 A) u$ @. Z
                        while (--i >= 0)
- t% z  g% P' d                                platform_device_unregister(devs);
$ x1 I% {$ B! Y" e1 T0 W/ W                        break;" F+ A2 v9 b$ H  _, c% o/ F1 \
                }" x* i+ v9 Y7 e
        }7 Z! Y2 ]! q) x* u! E
! L+ i, G3 ^' {3 F1 |8 Z( x
        return ret;
, c0 ]. X2 Q& Z6 `}1 U! l6 T8 Y. n6 ^6 s( ]
EXPORT_SYMBOL_GPL(platform_add_devices);0 o; a0 @; C8 K
& I# X- a, M3 e# `1 u8 M/ s
该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。
( ?9 R3 x1 H7 |8 v' o& V6.3.2  platform_device_register
, a  F/ s8 w' k. f/**4 l, R: f+ I7 _$ n- z
* platform_device_register - add a platform-level device
- R  s% W  U+ F3 U * @pdev: platform device we're adding
; U& b2 v! E/ W. A, M1 R */
9 ~6 r$ W, J' Q' q' Q+ Gint platform_device_register(struct platform_device *pdev)
+ _' i4 X& K3 R/ a/ f9 K# m6 J) S{
, a$ L2 s! |, [, j$ S5 X1 i/ J: |        device_initialize(&pdev->dev);' f' b! V' F. ]2 F/ x8 L
        return platform_device_add(pdev);
( R4 i7 q1 e+ W4 b0 b6 g4 C}0 V2 k7 o: z9 {6 s
EXPORT_SYMBOL_GPL(platform_device_register);3 T: d& D" z2 \/ g
; p2 z) b/ v* o/ T3 x4 R
调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。9 p) O7 @1 U% V4 I+ D' U
6.3.2  platform_device_register
/ S' q  }0 j8 Z; `6 z/ u9 i  ^/**! b* ?8 K6 O# p0 p4 j
* platform_device_add - add a platform device to device hierarchy
0 m/ g5 {' N  N/ M2 j7 a& G * @pdev: platform device we're adding4 t) m6 M: Q! {, P& K1 w
*
' m" i* n, M4 s2 O * This is part 2 of platform_device_register(), though may be called) b; q# t9 _  t2 Y+ |
* separately _iff_ pdev was allocated by platform_device_alloc().
% i1 e, ^7 L% {( w */
& h0 V! W9 x; n% jint platform_device_add(struct platform_device *pdev)( P% u% Y3 [% B& L: a
{
1 d6 S3 x) ?* r& J& n2 {  Z4 a        int i, ret = 0;2 I% h6 `9 d0 g' t. S$ o& H

/ M6 ~9 O; s/ R. s5 W4 o        if (!pdev)5 s) p6 K6 Y6 q' _+ ~4 M- q) E0 q
                return -EINVAL;
. {: T$ L1 w4 m6 H# N+ [9 P* e. H) y! y/ e. u" i$ d
        if (!pdev->dev.parent); c6 R7 l: P2 s9 f
                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/
! u- f" j! X) b9 E0 O7 C
+ i' Z' W8 ?& s+ x        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/
. W% S# _8 R6 S% B( s0 c, W  p5 @- M5 O) ]- H3 {& h
        if (pdev->id != -1)9 Z& U! q% D. e2 e
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
) S4 ^  r5 ~: u$ z0 O9 C3 k  |        else
4 I  Q2 a, p; Z, J6 [' w9 q                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/* ?* {9 x1 X- @9 [

& P2 y. {& ~$ A4 i/ S- ^' I2 C6 {        /*遍历平台设备的资源,并将资源添加到资源树中*/) l% X1 u3 r, n, B
        for (i = 0; i < pdev->num_resources; i++) {, ]- ~/ W- Q! K
                struct resource *p, *r = &pdev->resource;5 b0 t& B8 O3 z$ |
' b: N' ]" B0 o  [$ k0 u
                if (r->name == NULL): W4 l) Q9 n* a: N6 @3 d
                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/
7 Z# f2 L8 i6 [
" w# m# A& T* K! d$ h. N                p = r->parent;
( L+ R3 Z8 l* `                if (!p) {        /*p空*/
) a) z9 `7 C, y" u9 v                        if (resource_type(r) == IORESOURCE_MEM)# b0 K: C, F9 O) b' ^& p
                                p = &iomem_resource;' p1 c0 d0 c( b) o% |# F
                        else if (resource_type(r) == IORESOURCE_IO)
+ |: Z& _: \/ y5 {) L                                p = &ioport_resource;
# r0 ]+ T2 L( J8 X- z- `                }- W  B% l) z7 |; I  N  e

6 S0 l( K- p2 W* q) C6 r/ a) ^                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/; O6 Z# z$ \' r; A/ n
                        printk(KERN_ERR
( x# Z: L* q2 ?1 W2 r                               "%s: failed to claim resource %d\n",% s. d+ F+ G9 m2 z6 K2 ]
                               dev_name(&pdev->dev), i);
8 Z! E9 b1 G7 j1 ^2 g( R9 ?& X                        ret = -EBUSY;
6 D$ N! A6 I8 I7 m: r                        goto failed;
% W1 X; n$ H5 k" r: ]                }, N; i9 P. z. c. W9 C5 ~! u
        }$ o7 f! t. m* P5 Y; M" Z

  _5 d' f) K" s' S* H: d        pr_debug("Registering platform device '%s'. Parent at %s\n",
3 ?9 \8 n+ J/ L5 A                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
, r0 @8 Y* P7 `3 Q, A+ w1 U6 N* l; z/ H- a4 I
        ret = device_add(&pdev->dev);        /*添加设备*/8 }+ x+ F' M- @. U& q2 ?# |
        if (ret == 0)
& A6 [, Z5 f7 H& |) K                return ret;* u5 w0 w3 E: d8 A3 h7 s1 X& d

( W0 m" U& n8 b& g& e- q1 y failed:
) S+ O& O4 _( b* o        while (--i >= 0) {
! \! Z2 f/ ?; ]1 C6 Q0 q                struct resource *r = &pdev->resource;
, |! P9 V' F0 Q) n6 W0 g                unsigned long type = resource_type(r);
) k3 f# p0 j- V4 [/ y
  w; c. U- M+ h! ^5 ]( W0 l6 }                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
3 d. }2 G$ F% y' y$ {( B1 N                        release_resource(r);6 v( g: y5 p" S/ N: m
        }$ ^% C1 L. x% Z3 D

( [2 M- G) N. A1 M0 k        return ret;  ^9 F# Y: C' _6 w
}9 M0 A; n, R3 v% ~
EXPORT_SYMBOL_GPL(platform_device_add);
! z5 D9 z6 a. S7 }8 T3 ?! a
( r5 p' Y5 J* F$ d! M) R3 r在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
5 c2 H  N8 f2 v' ]0 s  o* z本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。
( y0 p; k! g- g: }3 }- U$ Q% ^0 }( r9 y/ o
那么这个"其他的工作"干了些什么呢?
1 ~' Z' d" Z6 m8 s5 L3 S
1 m. N, G9 p- r4 {# p6 ^9 `首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。5 [. o/ }7 P7 ~4 H3 P* a
然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。  d6 _* v: l  ^  o+ T8 q2 r

" A5 j+ G+ S4 q( }, |; j# L最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。1 p  J' S( D" z* c( z, H
: _# f! o/ H- d6 k5 o& _
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。* t, |- D  J9 `) l) t* E
# X  I& G5 B+ F, b6 c4 i4 r: z2 S
由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。- ]. f8 A# {: B& V
- N% \% |/ N9 ]7 W  d% n
6.3.3 不一样device_add调用结果. {$ G+ g) N7 G4 @+ f1 l8 {
首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:
; b' F5 v2 F: A" ]- |' B0 k% E6 T
pdev->dev->kobj.kset = devices_kset
7 {( {) p8 ^: q5 o# M4 K/ b/ b+ o/ d) ]! ~& {2 P% z
pdev->dev-.parent = &platform_bus
4 c$ t" g8 k. |6 y8 B8 i" }, r  S. Y7 L; @; J4 a8 R
pdev->dev.bus = &platform_bus_type
1 J" u' g% S6 k
0 N/ @- S! C. K: V1 ~set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。
% x/ G  d- z; T: m! W( C/ v8 f0 R- u' m( T6 I
kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。! C6 u$ B1 M% z" ?( Q$ `8 X9 |  Z, @' }

9 {- E7 c7 P1 a6 w4 Q$ idevice_create_file建立属性文件uevent。
1 Y- F' K  ?5 V5 F3 x0 K' Rbus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。, }. }8 ~" i$ y$ f4 \  @

! [3 H' x1 f* V4 q2 A# G            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。+ j6 _3 r, H/ K  Y4 M, g4 c

$ p- m% e/ k- [. J; a8 c           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。
  a1 _3 v- g! j! |$ P% C. A  `( G
2 [+ B* h1 @- d2 idpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。+ ?/ B( L) ?1 Z! u" H

% i, q4 h* B; {* `执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。- e: M" V: L' z( T/ P% k
  S0 X# d! Y9 i3 }
[root@yj423 s3c2410-spi.0]#pwd
9 i6 k, N( M, i/sys/devices/platform/s3c2410-spi.0
# r! f5 l% o0 }% M3 r6 |[root@yj423 s3c2410-spi.0]#ll" S6 q# M+ T- O$ u  o' v; U
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform( q; L2 P7 V$ g6 A; O
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
2 S" A# D$ ]# T, c' R  i+ G-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias: F- Q, W* Z" n9 M
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power8 ?- A4 [% K# F/ e$ ], L) }+ Q9 }
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
) f2 S1 c- ?& C3 Z, @$ u7 S4 xdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1
. P7 N8 a; ~& |) y! P2 Y( hlrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
3 r( H) }6 K9 l# `# w1 clrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
2 z$ K2 H, H, l$ d0 Z-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent
: ~' o. O4 I2 W. j5 D! N: l2 O  M, v. Q3 R* ?
[root@yj423 devices]#pwd
. R& }' o" a7 y! k/ e8 W8 {/sys/bus/platform/devices: L4 _3 o8 C: g
[root@yj423 devices]#ll s3c2410-spi.0
; F/ W5 e# [2 L) i; u# r8 Alrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0
6 O1 @/ f+ k3 U通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。
* x! Q8 J) A5 I' h2 r. h) ^
+ X! j3 {/ o8 v$ o+ U+ ~bus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。% c. e5 z8 B  e3 [6 j% ]; r- B
5 p, R" S) X3 ~, J+ P  n( ~0 c
接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。
: S% V5 |& C$ r
. ]0 W4 Z% _+ n, a5 Q7. driver举例8 @; |0 n) p' o7 X1 l" r% n$ P
我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。
- Z# @7 t! |9 \& P" ?$ ?& `
% P* E, U9 c) l0 x( H& t" |/ c7.1 s3c24xx_spi_init
* b2 L& u5 @- X2 D  Y, E下列代码位于drivers/spi/spi_s3c24xx.c。
4 n; p' f% {( \9 e2 A# AMODULE_ALIAS("platform:s3c2410-spi");, F# M. Q% m! ^' ]+ M, ?
static struct platform_driver s3c24xx_spi_driver = {9 p. K) @  C( M- e) `2 c/ I
    .remove        = __exit_p(s3c24xx_spi_remove),
* d/ Y+ k- t+ f$ Y    .suspend    = s3c24xx_spi_suspend,8 t. R$ @4 H$ I3 |, }% c1 I
    .resume        = s3c24xx_spi_resume,
  U- ]4 I; N8 V    .driver        = {
/ g6 t; x+ R7 f1 E: p# o0 ^        .name    = "s3c2410-spi",& K, {% s2 g& o; ^3 h- E, s% L
        .owner    = THIS_MODULE,
9 s2 i7 O- P& ^1 ]* O    },
- _$ W6 B2 N/ t7 ?};
* z* P" u" ^. v/ T& ^4 ^" W7 m# j
/ a  p% w& M2 H/ J( }+ z( ostatic int __init s3c24xx_spi_init(void)
6 a! {+ H. z% U! U{9 }# F3 B% f. e/ h
        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register2 ?8 m, S: H$ B& X  e( V* ^0 \
}9 `1 q4 ^0 g3 R, a+ Q/ t% B
驱动注册通过调用platform_driver_probe来完成。
9 o  E# j$ H  g: l4 P! m! Q1 Q1 o注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。
- l, M* Z: P0 H9 ]0 }7.2  platform_driver_probe7 q' C/ o7 S4 Y  M) P! r" J
下列代码位于drivers/base/platform.c。$ e3 I8 d! M1 P) ^( W% L3 h+ G, i1 G/ E
/**& L, M0 ^; R% v7 v
* platform_driver_probe - register driver for non-hotpluggable device
9 e" Q. T, L: M  H0 s4 k * @drv: platform driver structure
6 [1 g6 Y( r; N# c% W4 H3 R$ V * @probe: the driver probe routine, probably from an __init section2 ~: F6 C4 d- ~8 V9 |" \: p) p8 I: b# V, j
*# f1 i) @& q! @. F, j9 _
* Use this instead of platform_driver_register() when you know the device: E# K9 n9 p* b, i
* is not hotpluggable and has already been registered, and you want to# @3 I2 y4 `, m; Z  o3 U7 ?
* remove its run-once probe() infrastructure from memory after the driver+ }) p: I& o2 t+ c% T$ ]
* has bound to the device.' t' O' q, Z4 ^5 F$ O" C
*) T6 k7 s/ P. ^
* One typical use for this would be with drivers for controllers integrated
' m. W6 B+ s' G/ y  i, ~% I: k: \ * into system-on-chip processors, where the controller devices have been
3 X& k# N  ~: ?, k9 c$ a1 [ * configured as part of board setup.
1 ?% C; h) y5 }/ Z8 V2 X- R *
: }4 P# _5 T8 C* d: q8 H$ W * Returns zero if the driver registered and bound to a device, else returns5 c* k% }" }) ~, p% r2 D
* a negative error code and with the driver not registered.
0 [* @" Q6 t' A6 t) H0 @ */) `6 q/ P: N* h0 y
int __init_or_module platform_driver_probe(struct platform_driver *drv,4 Z# B! `3 a" O' u
                int (*probe)(struct platform_device *))
3 `0 H9 t% l1 y' Q9 D$ @& }{7 b  \5 h4 |7 W: V: `
        int retval, code;" b0 v: G, h; A$ R
' U/ f' T% v7 [, J
        /* temporary section violation during probe() */3 P/ f, V1 Y0 y& ~* R% o
        drv->probe = probe;
  r5 \& v2 j  {, ~' a. h3 t9 v        retval = code = platform_driver_register(drv); /*注册platform驱动*/
& ?- ]3 I: W5 c) `0 h& y% m3 n
. O8 b" E& t8 g6 c2 u$ L% c        /* Fixup that section violation, being paranoid about code scanning
; w% y- ^' k4 e; J! R5 N" p         * the list of drivers in order to probe new devices.  Check to see9 q9 C3 t1 m. W1 D$ ^3 O  t2 S
         * if the probe was successful, and make sure any forced probes of
' q# A/ m- g% @- @         * new devices fail.
* g# z, [! e# }; _         */& U' p8 t2 \" \, ]
        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);2 L- O: [( L/ A" R2 i* ?0 t
        drv->probe = NULL;
; J) P) G+ s  w  [+ M6 V" A, d! z& Y        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
/ R. _1 `. z9 B                retval = -ENODEV;( @+ h% `5 b1 y- e3 }, V
        drv->driver.probe = platform_drv_probe_fail;0 H+ `% L/ \. e1 `
        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
  l) W- ?7 W) S! v+ d
3 a4 N7 |) L( o2 g        if (code != retval)
2 n% H6 o5 F$ ?) q' r8 p                platform_driver_unregister(drv);! ?# Z/ m3 e# w6 K: t' h- L# r
        return retval;
! e; r6 z9 j: p. q5 K6 C% U}
6 l) i; F1 O1 `+ E: e7 p" b( I4 KEXPORT_SYMBOL_GPL(platform_driver_probe);
3 p+ I- O, v/ o+ t- R3 O& H这里的重点是platform_driver_register,由它来完成了platform驱动的注册。: j* K& x2 c% G9 M" u
7.3 platform_driver_register
, ^" C- {  c5 i* S8 E/**; a4 J/ f2 R: T; Y. c
* platform_driver_register+ O1 i, C# s  s7 O! F+ N
* @drv: platform driver structure) M7 W* y% M. H4 Z
*/3 P7 |- A7 o# H, r. e
int platform_driver_register(struct platform_driver *drv)
, P9 y2 u. H5 N{" r; e5 S1 b$ R) f1 u
        drv->driver.bus = &platform_bus_type;
* B& o7 d& A7 a3 U* e        if (drv->probe)
3 l$ F0 k2 F$ l3 K- H                drv->driver.probe = platform_drv_probe;
2 ^, b: g( X& M1 c1 ^4 q        if (drv->remove)( d- p' b; J9 s
                drv->driver.remove = platform_drv_remove;
' ]4 q, k- P$ h# h0 V        if (drv->shutdown)
4 u, y: A$ A2 C, O0 Q                drv->driver.shutdown = platform_drv_shutdown;
7 s* w7 r2 W  _3 p# f; @) _! x        if (drv->suspend): J" Q; J3 s0 y9 x
                drv->driver.suspend = platform_drv_suspend;
+ L& c  f) C/ Z$ ~# q1 c- b' B        if (drv->resume)7 H# c/ R0 ]  X1 y- q
                drv->driver.resume = platform_drv_resume;" K7 {" b1 V  c1 r2 g5 d( e
        return driver_register(&drv->driver); /*驱动注册*/
0 T  x4 D& g) L: X/ e}
! q0 h' N1 d6 Q" m- u0 K  WEXPORT_SYMBOL_GPL(platform_driver_register);# O4 X$ z0 T' ^, |4 D9 z- v/ Y
, z3 {3 b. Q1 U" Y' c2 g- H
driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。4 @" K+ J( f- I* L7 M  w
7.4 driver_register! _4 M7 x* |4 G% _4 r
下列代码位于drivers/base/driver.c。8 h* j4 B! T1 V& v
/**8 e; r: n3 G- ]3 Y+ ^
* driver_register - register driver with bus
4 T  n7 h( |  R0 g * @drv: driver to register: Q$ |9 d# R# b8 T5 X. R6 ]
*
0 \( p; K. K0 r! X! ~' ~- }9 N8 Z * We pass off most of the work to the bus_add_driver() call,1 m! k& z; {8 a2 [; |9 H5 _
* since most of the things we have to do deal with the bus$ w& J8 P0 \, C# t8 C2 {
* structures.' u0 ], j6 s7 I
*/
( A: x. x; y4 r7 H  i  Yint driver_register(struct device_driver *drv)
+ ]1 y0 t: I( u7 q2 b{% F# \# s7 F6 C! n7 V
        int ret;
5 P  K# Y) f- Q# Y- x        struct device_driver *other;
+ W' a8 k& N, @. L: C& m
7 O! i0 H9 ]' d1 p  H9 R+ v        BUG_ON(!drv->bus->p);
& y0 \( Y% ~" z- S
" R' P$ F  r7 t# C3 h, j        if ((drv->bus->probe && drv->probe) ||7 E+ D: `/ u6 E, i
            (drv->bus->remove && drv->remove) ||  r: w% O! G5 }0 W
            (drv->bus->shutdown && drv->shutdown))
. w! [. W0 }: P$ I                printk(KERN_WARNING "Driver '%s' needs updating - please use "
% p/ F2 V. {9 h- L  }                        "bus_type methods\n", drv->name);
+ V9 O& r* A0 g
! B+ N/ w( i, t2 X6 f9 ]        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/
1 h, n6 N, f+ m) C3 h: {        if (other) {        /*存在则报错*// R* b: L1 r2 a1 K3 ^/ }/ h
                put_driver(other);
# w& m- n1 @. J, ^- n                printk(KERN_ERR "Error: Driver '%s' is already registered, "
: H3 J. e# o# C" u" w2 R                        "aborting...\n", drv->name);
8 ]7 k( \3 n0 U+ a. K, J8 T6 D# `                return -EEXIST;8 {0 _) X- a# G& |( i" d
        }
5 P0 J6 m' ^4 k$ R' n. M
/ P, N3 R7 _2 @, w* g" {        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/& B/ y. i) |* `) Q
        if (ret); E. s$ n# \& Y9 s
                return ret;
- |# ~2 N# s+ u        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/
9 t) B( q- `) Y        if (ret)
$ p) |- j$ f3 k; x% _                bus_remove_driver(drv);
& n3 W6 t/ F7 H4 H0 n" n* V$ G. Z6 ]        return ret;  l" m9 z/ f2 `1 y8 F
}
8 V$ J9 z- `2 b; i) sEXPORT_SYMBOL_GPL(driver_register);; A- F1 c" S8 n& }$ A' @3 k* Q7 n
这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。
0 }- g9 x! n% H: p% s, Y9 f5 w接下来就分析这两个函数。6 Q% v9 f# k8 p- z+ r# l+ ^
7.5 driver_find
6 S2 s1 }) d/ T' H0 i下列代码位于drivers/base/driver.c。
" B4 y4 x0 @! }/ ~7 k2 |1 K" x! @/**! t0 E) F) e) [' V2 e8 Q1 {9 U
* driver_find - locate driver on a bus by its name.7 O7 O  ?: M3 y8 ~9 p4 O" T# q2 N& b
* @name: name of the driver.0 h/ ?3 m4 q* P. [" O/ o. e# Y
* @bus: bus to scan for the driver.4 @% c, w  w# R+ b1 S  H6 ?
*
/ C8 }. [7 Q* L- C7 D) k6 K * Call kset_find_obj() to iterate over list of drivers on0 W' ~/ `! @+ S
* a bus to find driver by name. Return driver if found.
3 L3 `1 G. T3 _3 I& q+ _% Y *, l# F" K7 R  n+ }# V4 ^
* Note that kset_find_obj increments driver's reference count.  ]# H# f( Q- D: y. u7 K5 H8 V
*/
! \9 i1 N' Q: ?struct device_driver *driver_find(const char *name, struct bus_type *bus)8 p# n7 d" h& ~
{
- R8 }3 H: z3 x/ g$ ~        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
/ e8 u1 ~5 `) V3 z: _* `        struct driver_private *priv;" v' c/ N0 `+ w/ ~' Y

7 }$ k1 T9 [# V/ v5 N        if (k) {! b; G3 h3 _$ G4 Z3 w4 h/ |
                priv = to_driver(k);
' p3 u# V: y( `1 i                return priv->driver;" y4 _) R1 B0 k5 v4 d  _
        }# p+ a* e5 m, N7 v2 {7 c5 N4 ?9 e
        return NULL;6 w+ y( _9 ?( e4 t6 U2 |3 U. `
}
% U9 m" P  L6 E# j# JEXPORT_SYMBOL_GPL(driver_find);
1 n, y1 A, a* A0 n
  L1 W+ K# _+ S' ?/ [- _6 v% t/**
, v& O; X/ C( P) L1 p' J0 ~ * kset_find_obj - search for object in kset.4 Z, _# c+ |  |* p% P
* @kset: kset we're looking in., F* x* k" N$ ^$ J: q6 l, i
* @name: object's name.7 D3 `3 f$ n  r% C9 M- D3 W
*: o0 @+ y) O0 \4 C% _- X; O
* Lock kset via @kset->subsys, and iterate over @kset->list,
" N/ M1 y! s' t * looking for a matching kobject. If matching object is found
2 C' O4 C2 b. x! J8 a * take a reference and return the object.1 W9 d6 i3 z4 m1 u8 s- u5 i
*/7 Y; O) ]5 c. k: O
struct kobject *kset_find_obj(struct kset *kset, const char *name)
+ M. A- G- l1 b{
6 n0 x' G8 z  Z' P' e* v        struct kobject *k;
3 S# S) D% a4 B        struct kobject *ret = NULL;7 o) {6 A( f- s  d& Q( g
4 g9 b6 ]2 ~% }& H+ J$ W1 ~
        spin_lock(&kset->list_lock);! |6 G4 Y3 H9 I! H
        list_for_each_entry(k, &kset->list, entry) {' m5 ^, R- p) P$ J: a* _
                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
6 |2 J3 q# D! p. i" `                        ret = kobject_get(k);$ [( u! S2 Z5 j! N
                        break;
2 ?4 ~, |) t* N                }
: d/ k3 A4 Y3 ~+ `% n        }4 Z# O! ~0 m! i7 a
        spin_unlock(&kset->list_lock);! V7 a  q9 w+ z! C; P
        return ret;
# r- X5 _+ U, n& P+ ]6 Z& M* U8 X}% |2 o9 C+ S" A% h$ o# ^5 U) \7 O" ]: C
这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。9 ^6 K2 ?: r$ m1 u- E. m: ?
7.6 bus_add_driver2 R0 c; ^4 S5 K; ]
下列代码位于drivers/base/bus.c
$ V: T% [) T: G" I2 W' d$ j3 o. d0 E. t
/**
/ G8 T5 e. A; t' E * bus_add_driver - Add a driver to the bus.
1 `+ M. K  N8 C6 v  X * @drv: driver.- W% I! r+ Y+ L# {, ~; l5 r# A! c
*/( V- v4 q5 D& d, ?
int bus_add_driver(struct device_driver *drv)
9 N' u7 e$ v( F5 T+ o9 R0 }* Y{5 P5 ~1 P( v7 P/ r
        struct bus_type *bus;- `: d& R# I: e5 q1 D, y  x
        struct driver_private *priv;
2 z) [* W. F- e; J, `        int error = 0;
# {8 `6 n, C5 I  x' z! `3 V
4 d/ L  ]. q* }2 }        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/
' B7 }- a# l; d1 f3 P        if (!bus)* Y3 g' K0 H4 T; e8 h% f' p
                return -EINVAL;
. d+ J3 I; W, A9 ]4 X* ~# ]& {2 o8 m8 @0 N+ T1 A$ A7 F' J
        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
$ H" H7 S7 E! K) j/ i$ j' _% U* z, ]: y6 G8 h. ]% q$ G. w0 g
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/
' @0 B; ^- k8 z  c/ [        if (!priv) {
) F- t$ x" j1 }/ L1 ^- J5 R                error = -ENOMEM;3 P5 K9 ?9 Q" l2 e* i
                goto out_put_bus;' z: }9 }# E& h
        }
( }# N! r' q4 u8 x8 Q  y8 C" e        /*初始化内核链表*/" |* l4 [3 S& y- ~) p( S
        klist_init(&priv->klist_devices, NULL, NULL);
$ ^" }9 j) T2 z        /*相互保存*/0 w0 j& Z% H, }# E
        priv->driver = drv;
, K- y& t/ e1 X- f        drv->p = priv;- K9 Q; m  ~! T2 M
        /*设置该kobj属于那个kset*// I8 v" o+ z! f& Z, u( j  y
        priv->kobj.kset = bus->p->drivers_kset;- O+ i% b8 r  L$ a
        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/0 X  }- d# X! z. t) t
                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
, ]' O/ [: q) B        if (error)( ^' t9 b3 O/ v( Q1 l
                goto out_unregister;
3 B! |, S2 F6 W% e" v% j1 C6 _  @* o0 l* Z
        if (drv->bus->p->drivers_autoprobe) {3 i+ }7 a; b. Z
                error = driver_attach(drv);        /*尝试绑定驱动和设备*/0 U3 a; w! A$ z) B, s. @* Z
                if (error); R* t- F% r& H  \
                        goto out_unregister;
! i1 _6 O) T% `2 ~, V: A+ W        }
* E+ X: N" ?% O: G& E        /*添加该驱动到bus的内核链表中*/
! T9 x9 c! L( }) h: i        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);3 l% C* E/ V3 B! _
        module_add_driver(drv->owner, drv);/*?????????*/
& w# C( o1 T; D1 T' W( K8 W
% Q! u* c/ A: \7 F        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/+ @! ?# K" ^- I8 X
        error = driver_create_file(drv, &driver_attr_uevent);
3 N1 Z8 _: G5 u( L% Q        if (error) {) U' G# J1 }. F1 B4 B
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",1 q) E5 p9 E' e2 s1 A
                        __func__, drv->name);9 y0 w+ G0 N9 ?3 L5 I
        }  n: m( H6 k2 M7 ^
        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/0 X2 ?* U. c* A5 n- y
        error = driver_add_attrs(bus, drv);
. h) i3 s* @' N  Y        if (error) {1 `4 }: Z2 X' V6 i6 O
                /* How the hell do we get out of this pickle? Give up */
/ m6 @1 ~" u1 g                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",/ e4 C9 s" w/ W9 X
                        __func__, drv->name);
4 z* c2 f$ a. l0 s        }3 \$ i% }2 o- t
        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/9 Q" e' V+ a, l( y3 l# y; s
        error = add_bind_files(drv);
0 P3 V( p; C/ B6 n- K7 A* ^7 i" V+ k        if (error) {
$ A! G- k) B4 G: _                /* Ditto */  Y/ P6 p. Z/ ^% o: P% `$ I2 {
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",: B1 E+ e3 F/ T4 \. F
                        __func__, drv->name);
4 a- Y" n4 P/ [+ a! Y        }
% D! V  Z2 c3 h( V1 I( n8 S        /*通知用户空间???*/
( J1 L1 M  A# V% p        kobject_uevent(&priv->kobj, KOBJ_ADD);
. \& O/ Y* P$ r7 F6 P' J8 Y        return 0;
% n! A2 l% O  J$ ^+ nout_unregister:# ?+ u- `7 v4 W8 k, i5 L
        kfree(drv->p);
! P+ K; ^! }( |5 i: @        drv->p = NULL;/ n3 {( G3 S2 P' f7 Q9 m/ n6 X
        kobject_put(&priv->kobj);2 m2 H. u5 F+ [9 ?+ d
out_put_bus:
1 [- X5 _' m& p' M* y        bus_put(bus);
/ S3 c$ S" K9 U        return error;
, {. @. q/ p% K$ x}( S8 q6 }% O4 N8 U. g0 X
在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。
: E6 ~! d$ Q* o2 E7 P, c7.6.1 kobject_init_and_add% ?* t- n9 Y; X4 D0 H& W
下列代码位于lib/kobject.c。9 G6 f3 K. }- Q4 v4 e3 K! d
/**2 ^1 x) L% G3 r9 j4 T+ e9 j
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy* C+ g- k0 A0 d% i$ v% L) r# D- {
* @kobj: pointer to the kobject to initialize; z' Z* S* V8 l8 Q( K4 A
* @ktype: pointer to the ktype for this kobject.& c7 V& }+ J; ?# V
* @parent: pointer to the parent of this kobject.
- _7 g' z0 e2 l. d) J1 n8 P * @fmt: the name of the kobject.
+ [; ]! @8 T2 P *0 R2 d- }+ s: j8 _' ]5 n3 u  \" I+ b
* This function combines the call to kobject_init() and
# ?1 ^5 r8 J6 Q( y1 M# ]) X * kobject_add().  The same type of error handling after a call to! K% z" D; P1 B7 v. X
* kobject_add() and kobject lifetime rules are the same here.& Z: `) @4 ]0 D
*/, }+ B/ T9 a2 N2 ^
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
1 q: `" m2 T0 E3 T+ [7 W$ Y, o                         struct kobject *parent, const char *fmt, ...)7 u/ O. G7 ~: i3 Y
{
2 t6 l3 S* G, b$ g. S5 u7 r- s        va_list args;1 w/ [! D. b  j1 u* C* a# |& _
        int retval;
9 O8 E4 g" d& [# g+ G" v& \  \
9 h) }0 ?# X9 @4 A% n* \  D0 B        kobject_init(kobj, ktype);
0 X; u8 V8 u- N8 t4 m* {- G2 q$ K& ~; A" C$ a7 g7 L$ L$ @' d
        va_start(args, fmt);! Q- x: J; h% I( a
        retval = kobject_add_varg(kobj, parent, fmt, args);4 e! c) z/ i6 M+ t# g+ I9 |/ y
        va_end(args);% X4 W3 A( Q  k) b0 Z/ `0 |

$ q3 V& C- _1 `6 y, z' p        return retval;
& k+ e. D1 a# Y1 d+ P3 T}
8 M4 h" o" W5 o2 _* w/ H8 QEXPORT_SYMBOL_GPL(kobject_init_and_add);" K) M: u4 F: L# r7 ?$ T
该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。
7 ~0 V% u: i) e" q调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。' r+ G: l* S5 I
! X/ K; e, |" u9 h( f
我们来验证下:/ Q$ R/ k+ S7 ~) R/ N. Z
4 q, c0 g7 _! q" t
[root@yj423 s3c2410-spi]#pwd
( g9 V6 e# v) Q% c6 w/ B/sys/bus/platform/drivers/s3c2410-spi1 }) h3 Z- \1 |  [. X
接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。9 [4 ^; U; D) N4 R2 p4 V

* K6 [- o% v+ E4 |8 K* Y. E9 A7.6.2 driver_attach
- F- ?# T; G/ ^下列代码位于drivers/base/dd.c。" s) h6 \9 a& }+ ]
/**5 H& T) z5 I% E2 P  W9 j6 B
* driver_attach - try to bind driver to devices.
2 a8 D0 t2 l0 Z5 y1 R* {, L" f * @drv: driver.% n4 Z! Z; n" A4 }
*# v% ]8 ]9 U6 j
* Walk the list of devices that the bus has on it and try to* ]0 o- @5 ]- [% T
* match the driver with each one.  If driver_probe_device()) a& e8 @/ r4 ?* v
* returns 0 and the @dev->driver is set, we've found a
0 I9 [4 ?: I1 k+ y * compatible pair." i5 c$ Q3 a. `. c% V
*/+ c, c0 c. T# Z) X% C$ v3 m# N
int driver_attach(struct device_driver *drv)
- C+ E8 A; f' E) V{
2 ]. T0 E* N  ]8 s; ~7 T+ H0 ^        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);9 K7 `6 _& }8 ?
}
' ]  p9 S$ o+ L! z- NEXPORT_SYMBOL_GPL(driver_attach);5 o6 |4 F" c9 x5 r2 d' o: V: j
该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。  X  S0 E% E$ c, Z8 _
这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。
! D$ z2 W* ^9 b& z  Q
8 M+ n* w" j# a7 G/**
" M8 s+ c; [  L0 ~$ U * bus_for_each_dev - device iterator.+ w* t5 t( g2 \4 ^1 X
* @bus: bus type.
/ P  I$ v7 C8 g7 I% W$ h * @start: device to start iterating from.: M9 ?! v: i+ o* B
* @data: data for the callback.
8 ?, N. L) a! k2 B * @fn: function to be called for each device.
/ p1 _  `3 F( |1 ]7 _# z; G; u) u/ { *
' v. a, C* A0 U  b% t1 Z * Iterate over @bus's list of devices, and call @fn for each,: x; y+ q) C5 c( x
* passing it @data. If @start is not NULL, we use that device to
% Q2 s6 _9 T! n, Q * begin iterating from.# F9 V5 Q4 C; R% q2 `: I
*
, X* j. T& ?9 q3 ^ * We check the return of @fn each time. If it returns anything) s! [/ V. @1 Y5 }! Z# t4 T$ I
* other than 0, we break out and return that value.; o8 \" D; }- n# y; G
*
5 Z9 o& i' E, @4 C$ B5 s * NOTE: The device that returns a non-zero value is not retained
  H. }+ h# b* ~# \- m * in any way, nor is its refcount incremented. If the caller needs
* U% m: K# ]5 h * to retain this data, it should do, and increment the reference0 x1 f: u) e: [+ K: {8 ]
* count in the supplied callback.
! j2 g* Y9 ?  t */
3 B, R/ ?) d  K* \int bus_for_each_dev(struct bus_type *bus, struct device *start,: G8 q' j6 [0 V$ l, l2 f9 j
                     void *data, int (*fn)(struct device *, void *)): M( i/ ?0 ^/ ~) t
{+ J% W: O, }3 N
        struct klist_iter i;
' A& l7 ^7 @$ G* V& F; l7 J        struct device *dev;3 a$ s! i$ A  t) G
        int error = 0;
( y- Z$ ^+ ?1 K8 }4 y0 s
1 ?  m( R5 l4 u- n/ r        if (!bus)% j4 i7 _) v$ m% k6 g' S
                return -EINVAL;* a" n* b  w3 x; ^4 w; D1 {
* g$ \- E( {( w% b0 ~) \
        klist_iter_init_node(&bus->p->klist_devices, &i,' Z7 Y* j4 V% r  x6 ]& n
                             (start ? &start->p->knode_bus : NULL));2 n' e( x/ s5 X. D+ n# G
        while ((dev = next_device(&i)) && !error)
  ^- |2 c3 P' r. R4 k" @# o- }, Y                error = fn(dev, data);- Y% [; {! i$ E
        klist_iter_exit(&i);
& L' n9 U, U+ \  k4 B        return error;5 q3 \. h$ s7 [' X, ^) N% G
}
; t% B- k# k$ N# G, g0 O7 F, IEXPORT_SYMBOL_GPL(bus_for_each_dev);6 c4 y' Q/ I* J. Q* U
通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。6 C! h0 r3 ]; ^* \& s  e$ F
static int __driver_attach(struct device *dev, void *data)
3 [. ]: \/ Q7 R2 F$ r, |{( w( S* S9 s, Y' L! e) A7 ^
        struct device_driver *drv = data;* _, l; F7 `$ n& V1 p# \% o& [

0 y1 s+ D! j" d; W1 X# a- e% d        /*  C, s6 W$ o! O. U
         * Lock device and try to bind to it. We drop the error
1 J( c+ e% ?: C3 _! z         * here and always return 0, because we need to keep trying
9 S* j% o; ]+ L7 a( U8 Z" P' B         * to bind to devices and some drivers will return an error
( w1 P; L6 p' N$ X% U0 Z& h         * simply if it didn't support the device.# m9 z5 f  j4 s8 m
         *
8 u+ A6 g& K* e: v+ [5 S         * driver_probe_device() will spit a warning if there
7 {) e. [1 M1 }         * is an error.
& S# {6 i+ ]" X6 @: F         */5 H5 C( U/ N" H$ O+ ~  B$ \, P

- ~7 n2 }2 q5 A" N# a/ T& S        if (!driver_match_device(drv, dev))
# H5 {$ ?' F# ?* X& m- u3 j" |                return 0;
1 k5 n' ?" y5 ?: ]* ?
9 ]1 \$ C8 |& n- e8 l3 H8 ~        if (dev->parent)        /* Needed for USB */3 t8 N8 b& M; L7 G; V3 a1 j
                down(&dev->parent->sem);+ w" `2 c4 U8 j# Y) l7 X3 V* `
        down(&dev->sem);
+ b; k+ s0 ]1 G: P& h6 P8 K        if (!dev->driver)
7 ?8 j4 G  a' [, Y9 c( J* y9 U/ t                driver_probe_device(drv, dev);% {9 i4 U0 r  n6 z0 ]; X4 {; p
        up(&dev->sem);
7 P3 L( L7 Q# e# y1 T3 C        if (dev->parent)
8 f+ H$ c  b8 T' M( F  P: y! K                up(&dev->parent->sem);3 r0 z% E+ i( o  ~/ D9 ~* \
# V9 F1 [' _" u# {
        return 0;. ~% U) ?1 }- ^: u
}2 |; |& f  E# R
首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:
, [* m7 F" R0 e2 Cstatic inline int driver_match_device(struct device_driver *drv,6 V' H( F1 G' c% r5 @! Q+ u
                                      struct device *dev)1 y& X; K6 |/ o
{
* F6 d7 T  N2 l        return drv->bus->match ? drv->bus->match(dev, drv) : 1;# K  L! `# ]" u7 P) q
}6 k# }8 H3 Q: w7 _6 Z3 {7 b0 u
" k- C$ @5 R& @/ A8 R! X4 y
这里直接调用了platform总线的match方法,我们来看下这个方法。5 f0 [, H( z" |: D+ W
/**
$ _- C6 H. R: J- I2 h * platform_match - bind platform device to platform driver.% z. ^% W& S/ N) t" R9 B
* @dev: device.. Z; p0 @0 X" Q* y0 g
* @drv: driver.. L' H9 C+ V( q1 y" W# c0 K
*2 W( |2 F6 N! d. i' K/ H
* Platform device IDs are assumed to be encoded like this:/ c3 y$ M" y) m
* "<name><instance>", where <name> is a short description of the type of5 f. Y' M$ X0 v
* device, like "pci" or "floppy", and <instance> is the enumerated
( R! B  l7 x7 J; w+ x6 _2 k: { * instance of the device, like '0' or '42'.  Driver IDs are simply% B; T& y/ X. w) g9 K, u
* "<name>".  So, extract the <name> from the platform_device structure,) H, I# D. K- B9 L! U
* and compare it against the name of the driver. Return whether they match
  {! X3 |5 \4 { * or not.3 h+ c8 {4 z3 {% Z8 A
*/
( q( P' }9 o* |( z9 [static int platform_match(struct device *dev, struct device_driver *drv)
$ _: u- ?/ ~/ P+ r  @{8 H, U! }# l7 J* c- `. [# v0 n, r
        struct platform_device *pdev = to_platform_device(dev);
5 }" n/ y, v# B3 G- A/ ?        struct platform_driver *pdrv = to_platform_driver(drv);& D- N! X: m: J- E7 U2 j3 `& K- }
; _- x% D" g, @$ x6 s& B3 o+ x
        /* match against the id table first */
7 c1 D* v& R; l( i        if (pdrv->id_table)
9 L* n$ D2 l/ P9 [) {                return platform_match_id(pdrv->id_table, pdev) != NULL;. N' ]7 O% d  `) q3 @
, l9 E; N# q3 b6 P* Y: M1 G
        /* fall-back to driver name match */
6 |; W* N$ a2 b# \- h  r; a; h( {        return (strcmp(pdev->name, drv->name) == 0);0 ?) `* a% `' r6 w& U! `7 Q2 `; R
}
& n1 y  d5 X& j+ g: G- G该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。
! M" _) A& `3 F6 V; w6 A8 L/ i在本例中两者同为s3c2410-spi。因此匹配完成,返回1。* j5 a; ]# `" k5 G1 E, q

  y, c' I$ u  c返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:6 t# C' L% ^& ]$ Q1 A

& y( o% e+ U' Z/**" R; t% l" |. U6 h" z( b0 H
* driver_probe_device - attempt to bind device & driver together- {  q: E7 \  f9 z& p
* @drv: driver to bind a device to9 M% h( f" l/ x$ V
* @dev: device to try to bind to the driver
& [/ g8 q% r+ V( R *
) Z$ Q# C  _5 a3 u5 ~% N" G, P' N9 @ * This function returns -ENODEV if the device is not registered,
( I  `; \( {  o4 G * 1 if the device is bound sucessfully and 0 otherwise.
) h6 u" A: w, V, x8 Q7 b% { *
% }* D% E% L9 M+ d5 L) }/ T * This function must be called with @dev->sem held.  When called for a7 f& q7 J# W" M
* USB interface, @dev->parent->sem must be held as well.
, [  g9 |9 m$ T, W/ v: k */
0 j4 V8 l) L0 E4 oint driver_probe_device(struct device_driver *drv, struct device *dev)! j# q+ }; s% M* ]% Z, e
{
" E, [' m1 q& m$ I        int ret = 0;
* G/ N5 ~4 i4 s- B% {6 f# n: y' \: V/ Q) C& ^* u
        if (!device_is_registered(dev))2 Y; P7 e- v, R
                return -ENODEV;
/ A' Q! G8 n; C) Q! M
2 O7 ?9 K5 e/ A/ O' W        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",  l: R- o# e; s5 K
                 drv->bus->name, __func__, dev_name(dev), drv->name);
& f! c+ Z2 C& P! U- n# D
8 i6 ~- d2 r9 E: e        ret = really_probe(dev, drv);
' Q; W+ X# V! h& ~3 U% ?$ N/ i4 K. y) e" l5 A1 X
        return ret;
0 j$ H. T: P& k, j. K) p9 b7 q$ @}
1 n6 W; D" F+ T& h( B& m+ S3 k  Xstatic inline int device_is_registered(struct device *dev)
# \3 B" ^7 `) R; Q2 A{, e$ T6 Z6 G" y6 ^1 {0 h. m  u! x) p
    return dev->kobj.state_in_sysfs;
' A2 X$ |4 Y7 e3 h" e# k: a, w}8 `0 R- i) A. Z, T( b( }
该函数将调用really_probe来绑定设备和它的驱动。% f- t9 G# O% ?' \; w, y
static int really_probe(struct device *dev, struct device_driver *drv)) `( E7 X* j3 m" T+ L( o9 Y
{
  W, A, D/ k6 E* k! n0 a        int ret = 0;+ z" K6 F$ j7 L% Z/ K! U2 S4 x! W
7 i; s) S3 L! r9 e' T9 N
        atomic_inc(&probe_count);
9 n! h: ]4 H+ N9 J; |# T$ _        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
$ d2 J. E1 r6 o/ [; W2 r                 drv->bus->name, __func__, drv->name, dev_name(dev));
, t& L% L" t8 Q) H        WARN_ON(!list_empty(&dev->devres_head));0 ?! t( p( k# S$ k

$ J7 h' |" C% x2 @7 _( f4 R( j        dev->driver = drv;2 r2 D7 W- @3 A, c% X7 n
        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/7 F; j- ]' e$ n: h6 ^
                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
% ~0 L( G( W: l+ T                        __func__, dev_name(dev));
8 g0 T) Z* [* |  t& _                goto probe_failed;
, V9 d8 X3 C: Y4 K" E  p% d        }) M3 K& \, r* D' i& x( q& }& D

3 W' I4 r' I1 v; C3 S        if (dev->bus->probe) {
6 a- w  k9 C  a7 q5 D: q; [                ret = dev->bus->probe(dev);/*调用总线的probe方法*/
: g7 {' A9 b# D- V2 u2 {( T                if (ret)& N" m. d9 @- g1 P( n4 a
                        goto probe_failed;# w9 W" W4 C  V0 z
        } else if (drv->probe) {
  f2 ]+ z1 E! w; g                ret = drv->probe(dev);        /*调用驱动的probe方法*/
. ~( K2 I! q. v! }# t                if (ret)" i' F) B; @/ S
                        goto probe_failed;
( A' y/ P: {9 U4 D% W& |2 }        }: ~$ u+ e; o' ~2 S
2 I4 C! q, y; G
        driver_bound(dev);              /*绑定设备和驱动*/: T' }7 G$ Q) [1 S( p2 e) h; l
        ret = 1;
9 t6 l4 `5 j, P5 I, {' F2 Q        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
; N3 H$ h5 ]4 a: c# [5 e9 u                 drv->bus->name, __func__, dev_name(dev), drv->name);
) p$ v  L4 P" P7 l" M        goto done;; c& e9 }7 P) U' G# x* b; \9 V3 P
' E5 C3 |: H! {- c; y  }
probe_failed:
! L( i* d; \  T! q+ P        devres_release_all(dev);
8 i3 q& {8 Y9 r( M( B        driver_sysfs_remove(dev);
3 @/ @1 ?! p- ?: X7 I        dev->driver = NULL;2 X0 O, \5 S( K# f

  y- }1 r: ?# @& Z1 t        if (ret != -ENODEV && ret != -ENXIO) {
, [  B; p1 C% e% f7 s                /* driver matched but the probe failed */
, M& e, u5 a8 j$ @                printk(KERN_WARNING! ^/ z& c0 Z3 _- L$ H
                       "%s: probe of %s failed with error %d\n",
, \/ P0 W/ ]( a' x                       drv->name, dev_name(dev), ret);# P. C; A& Z1 a( B, o! O: [
        }6 F4 |9 Z, a1 o* ]7 t' |: J+ z
        /*" {) g7 K& I" b7 U
         * Ignore errors returned by ->probe so that the next driver can try; Y# B& }. |" x7 @8 v
         * its luck.
, G4 I9 u. D6 v3 x9 a1 w         */! ^8 a9 [. r8 {/ |
        ret = 0;
8 R# K9 f$ @: w; ^" R# a) H$ Tdone:2 J: a( p% F8 }/ x  g/ C
        atomic_dec(&probe_count);; f/ f2 p0 }/ R6 z* x9 g+ S
        wake_up(&probe_waitqueue);
6 G- i2 o) r& U1 \; h# m9 j        return ret;6 N, M* G6 ?4 V! g1 ?9 V
}$ t+ S4 `( T( q! y
: R/ L0 p. C( t1 n, |
在这个函数中调用4个函数。
: h2 e  U1 k3 b8 ~6 O; o
- k# d& C, k4 O2 h, w第一个函数driver_sysfs_add将更新sysfs。+ g. l) s9 ?8 E+ n

; {1 g% O* Y6 l6 R: p& H2 `" |static int driver_sysfs_add(struct device *dev)
. s4 J8 m4 z) u{( u, U4 o3 @5 [2 e; ?! l; B
        int ret;- O) P8 V( S/ e% g. e
        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,: h; E' f' z' t
           链接指向/sys/devices/platform/XXX */  h' D1 F5 `8 J( B: L
        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,# H- w/ j' _1 Y5 ~+ g0 r2 R
                          kobject_name(&dev->kobj));
2 Z, f1 J. w3 f6 u        if (ret == 0) {! |4 ]$ D% p' p- E3 _7 J5 E
                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,
4 D3 W; S) O8 g1 j) K0 Z5 B$ L                  指向/sys/bus/xxx/drivers目录下的某个目录*/
# z/ h! u  P5 q! L                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,# k4 {- E- w8 f. r7 g+ ?* j1 x' |
                                        "driver");
( W* I) A$ Y3 _2 L: _( N% q                if (ret)  _+ |  A/ l) s1 }3 f" ^* J
                        sysfs_remove_link(&dev->driver->p->kobj,- b! ]" n3 C. {; ]) s4 J
                                        kobject_name(&dev->kobj));, I4 v& ]+ y8 w. s+ T: r
        }
$ u9 Y; n) |8 O/ P        return ret;
, x8 S' p- V  j$ H}
% y: ]- W: E' v$ ?- ]1 S; k% o! u  j, v7 l
执行完以后,建立了两个链接。% Z$ [' H0 u7 p1 o$ W2 K' l8 x& X
在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.02 H& @9 ?9 h: B/ O  B3 _
在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。
/ d/ U: U3 t1 Z: y6 K这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。
" x4 I9 C6 V$ L: e6 a1 B; q; ?
$ f% }' F) H" K2 ^5 T[root@yj423 s3c2410-spi]#pwd1 o% T/ V- f# }) V% H9 n, v5 q% [
/sys/bus/platform/drivers/s3c2410-spi
1 u% K5 Z: k% K; T, u$ i  S[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 / K5 h  @! g8 T
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
1 O' h( B( q1 Q[root@yj423 s3c2410-spi.0]#pwd1 N$ _/ S# r) b$ k
/sys/devices/platform/s3c2410-spi.07 c7 W+ M( o7 n" t5 P9 t' [
[root@yj423 s3c2410-spi.0]#ll driver; Q0 J/ `7 ]7 F
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi4 C- ^. H6 ?  }0 m

8 X' t/ }0 _0 ?' T- b- l. b( ~第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。
/ [( a2 L7 D$ T1 l  A8 q
8 v3 x$ i1 K) n8 m* h# ]7 \第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。
2 c  H* X0 z' p4 J1 j' p$ m+ j
3 N# I& ^7 F0 x* I第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。. x. U  m  {& e

* b& ]& L" I  d# U. C, f. xstatic void driver_bound(struct device *dev)
- D: U; ^0 \& ]6 Y; D0 G- H4 v{
/ B: @% s1 r; U0 t        if (klist_node_attached(&dev->p->knode_driver)) {
" B! ~5 L% R; Q% [9 b                printk(KERN_WARNING "%s: device %s already bound\n",
- A! s5 o  X/ B; i- u. v                        __func__, kobject_name(&dev->kobj));) i" h' a8 t" `4 U7 x4 Y, W& Z+ K
                return;
4 `5 N! Q3 E0 E5 q3 e3 K# [9 W- F5 K        }
2 f' k& v: j- h5 _
! J& [4 u9 [0 H4 Q1 S        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
6 R3 j* b2 `3 y0 |0 W3 D5 t& i                 __func__, dev->driver->name);
; C; N) `/ `1 O+ T) V& |. G: T* L3 d2 p
        if (dev->bus)
2 u1 e& S: M( w1 |% p. i- d% {                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
' `3 `: ?' T: q                                             BUS_NOTIFY_BOUND_DRIVER, dev);, O7 ]; [5 }) M8 i4 Q
# s$ D  m5 E2 G6 Y6 r. m
        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);$ m- [8 s7 _: Y& ~
}
' P! v7 l3 V$ f6 v7 W9 |其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。
; L% z5 K; `/ M) V, O, ]+ I至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。5 }7 r/ h5 L) I
% e5 s- S9 q: E2 I* j4 c1 J
在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。
) N. L7 p/ w# Q0 h
; c* D, L# O" Z3 \3 V: g: y' g4 ~首先,将驱动添加到总线的驱动列表中。; N- F% S. R% x6 Q, Q! l
接着,如果定义了驱动属性文件,则创建。- Z' p: i3 B0 H2 s! r. Q
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。8 x6 W9 W/ `; j8 f" |4 Y$ s1 i
0 g' [. Q3 |# |3 [- a8 ?" u* V
我们来验证下:# P' t: G& s5 r9 w% `( n

/ [- ?4 o' c. }4 D4 V1 _: V  s- |[root@yj423 s3c2410-spi]#pwd2 Z* [, @& ~( V# H1 I8 |
/sys/bus/platform/drivers/s3c2410-spi
, _- {" i0 ]' J: X! _[root@yj423 s3c2410-spi]#ls
  ?) w: b4 ~9 d& Y& N  Zbind           s3c2410-spi.0  uevent         unbind
& a% U2 G; e6 L5 \+ J0 d7.7 小结
1 ]3 H3 G4 O; R# H% H在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。4 E/ [- v6 @+ x( L- N; ~

& [! u$ k$ o  J: K8 r& x同时,还更新了链表的指向,在内核中体现了同样的关系。$ D7 M2 Z' N- I( F- E

  E: p. ?) v) h* V5 D) L最后以platform driver的注册过程结束本章。
: ?) ~  D3 Z' j* l: V, [) G0 {2 r& S/ I' Z

* A. K2 O, I! u: Q3 b1 V1 U+ D+ ?: o, a- r
8. sysfs底层函数
1 K+ ]' m. D3 V6 K3 G, {# q6 G下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。
, [/ P  `. H' M7 M% ]6 i在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。
4 t  ^6 e1 K) W1 v+ e
( N9 m2 ?# @3 i/ H+ u; F8.1 注册sysfs文件系统
% J5 v( t# }- p" k6 H4 I9 J2 psysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。
2 F! }7 [8 m5 ]. H% S: _' j8 s: Rstart_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。. |' g& W6 t2 c5 f& K
  G: S1 B2 c- C; g
int __init sysfs_init(void)
$ {! C" b# K' _* V) W$ ]* }{; t4 a7 t& m$ p' K6 _5 I. {
        int err = -ENOMEM;
& u$ i$ o) s  w4 A        /*建立cache,名字为sysfs_dir_cache*/+ m8 p* w6 F* e( `3 S! Z
        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",% q) f4 E6 a6 [$ ^1 `8 u, D
                                              sizeof(struct sysfs_dirent),
& s, ?! W5 M: @                                              0, 0, NULL);
2 i; C4 [8 Q' n% n: \& i        if (!sysfs_dir_cachep)
0 `9 [# X7 D* A$ S0 \& \* r/ k1 }9 r                goto out;
! h8 ~. ?- C2 K) l3 T  U; }: u2 ^  N9 |; @! ]' i
        err = sysfs_inode_init();
( M& a5 e; F5 R8 K* _2 j) E5 P8 h2 |$ z        if (err)* z, b+ g$ p& c9 c
                goto out_err;
: _! q  w7 G  e6 ]- o) N        /*注册文件系统*/
" R' b. P+ ~* m' |        err = register_filesystem(&sysfs_fs_type);  c$ F4 l$ Q4 p" {0 B" I
        if (!err) {* M% d: B( p  t4 G- P' v/ t: W
                /*注册成功,加载文件系统*/9 `% o+ S* x  Y. U/ f4 s4 [6 F( q
                sysfs_mount = kern_mount(&sysfs_fs_type);9 P( U0 [9 X& d, i- f8 _
                if (IS_ERR(sysfs_mount)) {9 ~0 ^# ]6 X" _+ r
                        printk(KERN_ERR "sysfs: could not mount!\n");7 ^7 S. o# T5 g$ p; n
                        err = PTR_ERR(sysfs_mount);+ s! r" ~: b6 ^9 o
                        sysfs_mount = NULL;
+ [! ]6 t* J5 b& W8 u! B                        unregister_filesystem(&sysfs_fs_type);
: i1 T3 l8 ~6 i( Z                        goto out_err;
# S1 b/ x* z( Y% p                }
4 |+ w% h" @2 `9 e1 h; }0 T        } else
1 C6 }$ ]2 I$ k+ N! N5 S5 g$ T                goto out_err;
! b, R( v, [3 D3 G5 M. i/ B7 ~out:' B- k9 H+ ]! l: Q
        return err;) z* q1 e+ Q# h* a; Q
out_err:/ L2 \) h0 `0 q% F
        kmem_cache_destroy(sysfs_dir_cachep);* ~" O+ h, ?+ C2 U  s5 D+ T
        sysfs_dir_cachep = NULL;9 A+ Y/ @! F- I* k% ?
        goto out;2 Z6 w  r7 e/ L7 r4 w, y% F
}
% ~) \) |- e8 @; k5 c; f1 G5 d
static struct file_system_type sysfs_fs_type = {
) |! V2 g3 K3 \9 \. C; y& k8 v8 y* A( G5 n    .name        = "sysfs",
/ p1 ]3 H2 r' |- S8 d& w    .get_sb        = sysfs_get_sb,
, l! f7 I6 d7 b1 u9 g7 a! N( H    .kill_sb    = kill_anon_super,
( P8 e+ u! k) M. M+ K};
# w2 l- B+ B) @7 k& P6 U( T$ @' D( M5 n; z
8.1.1 register_filesystem
, z2 w' N1 o7 T& m下列代码位于fs/filesystems.c。8 d+ V8 d! E' y0 |
/**. j) I& }3 q' T* q6 B6 Y4 Y9 j
*        register_filesystem - register a new filesystem8 Y% L7 ]) p; x  P! k! V
*        @fs: the file system structure; C5 G1 }) s( H0 `9 K
*: B% m& \- U+ u, w" O" ~! x
*        Adds the file system passed to the list of file systems the kernel
! L, o5 Y$ S! m- U3 M9 @ *        is aware of for mount and other syscalls. Returns 0 on success,  ~$ A5 G7 C8 _8 W: P* Y/ i
*        or a negative errno code on an error.5 ~. ?/ m4 U: y. b5 o9 ~
*; r/ t5 H5 z/ F2 q3 C# `
*        The &struct file_system_type that is passed is linked into the kernel 2 G& f9 f2 E& s7 c$ Z4 v
*        structures and must not be freed until the file system has been
! m5 {2 B* l9 N *        unregistered.
. u( n0 x- e8 d' E */% W! p9 n& ]* O9 l3 a
. ~% l# H7 @/ [
int register_filesystem(struct file_system_type * fs)9 }6 Y6 Z3 P+ r
{& c+ N4 X& T& ^$ r
        int res = 0;
* s% }. _( _3 h1 J& ^        struct file_system_type ** p;
' z! c, n. p( R  \$ P
$ M3 r1 k) L3 [6 k' d$ g0 |: a" I$ M. M        BUG_ON(strchr(fs->name, '.'));# x( {- j1 D7 K- W* i0 c
        if (fs->next)
, n# b) ~9 b* d- A                return -EBUSY;3 B. ~/ O2 v% g: U
        INIT_LIST_HEAD(&fs->fs_supers);3 h$ k; C; y$ T& `$ _
        write_lock(&file_systems_lock);' F* f! k/ k! \% M4 M2 U
        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/
$ R! U! n7 f( i, g9 `: |: i& ^6 R2 L        if (*p)7 A- h+ ?1 R3 q
                res = -EBUSY;        /*该文件系统已存在,返回error*/3 W1 g7 x, T. C6 l
        else
7 w( a: I" j7 a* _6 Y4 b# _/ k; E                *p = fs;                /*将新的文件系统加入到链表中*/+ x$ m6 [! v. o2 o1 r9 u& T9 j
        write_unlock(&file_systems_lock);
" p9 ]5 ]% d7 s1 h        return res;, V! ^+ H/ [2 l; h
}
- C' R# y! E( e9 P7 lstatic struct file_system_type **find_filesystem(const char *name, unsigned len)
. _& N3 ^8 a0 z{9 ^, ~0 q5 E* _, R
        struct file_system_type **p;
1 b* {7 [6 A9 p( l8 F        for (p=&file_systems; *p; p=&(*p)->next). H$ l/ v; }5 a' `! Q
                if (strlen((*p)->name) == len &&/ y2 R+ ?0 b1 Q  x
                    strncmp((*p)->name, name, len) == 0): H4 \5 \' i- j0 c. m
                        break;& a, ^5 V( B) q% p
        return p;, T9 s0 _$ [6 `# @& \. d
}
" r7 J' S3 L: W2 K0 M该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。1 a& x% b6 ]- M* b
如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
% t- v4 E* L3 F5 G2 v
- U0 R8 D' m  D: c$ D: k该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。
1 h1 V( O# y2 y% t7 i: M; D2 L
. A& X2 n. \: K8.1.2 kern_mount函数. i& Z/ `" u: E% O7 s
下列代码位于include/linux/fs.h
, v# a( Y+ c) e; @. G
  f+ s  F2 S/ Z5 v; L7 ?#define kern_mount(type) kern_mount_data(type, NULL)
0 N/ H. M0 t! S5 B2 }下列代码位于fs/sysfs/mount.c
, j4 d: H& M6 u3 Nstruct vfsmount *kern_mount_data(struct file_system_type *type, void *data)2 X/ X( z; e: a7 v7 [$ ^
{. e0 s' d3 D1 C, p; ]# O
    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);- r  {2 w* [! J9 o
}
1 e0 f$ y2 X# F8 M6 K( l2 ~
3 G  i( ^& M' {* |  v7 {+ hEXPORT_SYMBOL_GPL(kern_mount_data);2 ?" I$ v2 t' k+ s0 a6 X
kern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:
1 D, j$ M, M. ]. ^  I$ U
+ d4 N0 b( L4 z2 fstruct vfsmount *; y1 o3 e. W: U9 r4 l8 s
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)9 G4 T! l/ d" O, _% t
{9 v' l5 {' z! [  \+ G& N+ u
        struct vfsmount *mnt;# ?* [. k/ w" ^
        char *secdata = NULL;) P6 d( C. I7 Q7 e+ N# r# ^1 C
        int error;4 p, F4 F# {, x. N' z
" _( U+ _7 Y. z2 d
        if (!type)
$ q# Z. k% f2 y                return ERR_PTR(-ENODEV);
9 I( ?$ h6 ^3 p  n3 o5 L2 Y3 }0 [- Q, w/ ~# u1 W- R
        error = -ENOMEM;
* x! T) q% q  b6 i, t        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/& k" Z0 R2 a; b  K3 P
        if (!mnt)
, J' P1 F; O- B: ~                goto out;8 j5 L' ]8 L7 T8 ~3 w

, b2 ?( ?) ^7 |% R+ l        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
. k/ K4 J6 V# F, h, x8 N                secdata = alloc_secdata();
2 h; a+ W# R1 H; }/ v' D                if (!secdata)
) Q' s7 |5 e5 H: \                        goto out_mnt;, ^0 b$ R' t. Q

' _7 l9 L. O+ y! g3 V                error = security_sb_copy_data(data, secdata);
5 S2 f5 Z* Q. C( o. V! s( g                if (error)9 m9 [( V. c+ z: U+ y, L
                        goto out_free_secdata;5 t2 Z2 \. ?/ E7 z, A7 J" s
        }6 j4 ~# a9 v9 }9 ]1 O1 g
        /*get_sb方法,分配superblock对象,并初始化*/
' ^& b1 }( P4 }% _4 b6 q6 ^        error = type->get_sb(type, flags, name, data, mnt);
# s% n1 Z0 s5 s- T8 S        if (error < 0)
& _& M! k. U, g& S$ R2 z                goto out_free_secdata;  ~5 G: F$ Q/ j$ ~1 }8 F
        BUG_ON(!mnt->mnt_sb);) a6 U/ z9 z  B" u9 p' Q- j2 X
+ D. t" R" m( ^4 A
        error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
& ^# z! A( [/ Z2 I         if (error)
  Z4 h2 o7 `: m( P' f9 z                 goto out_sb;
# v2 d. u4 ?' Z  J  n8 f
* P4 _/ C3 J0 q8 M) B        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/0 _6 G, T* {3 R7 r% }0 H" K
        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/
0 M' D+ ?6 a, O8 [2 b, N8 v  @7 l3 \1 o        up_write(&mnt->mnt_sb->s_umount);+ M- b: \- ~4 o$ ?1 a3 O% U
        free_secdata(secdata);7 f7 `# ?2 Q- \
        return mnt;
6 ]5 U9 n3 F3 u. J0 rout_sb:: m6 G7 f; v5 d. @5 b- X
        dput(mnt->mnt_root);/ V& @/ }( Z6 \# |9 v8 d% Z
        deactivate_locked_super(mnt->mnt_sb);. M' D: N# _! k5 H+ W5 @
out_free_secdata:3 @- h0 I) T5 A- m, S& _; u, [
        free_secdata(secdata);
" j# S' R5 W$ gout_mnt:
: d/ X) |# y5 x0 y2 f& F        free_vfsmnt(mnt);. x2 q3 M, b! H0 ]/ S/ O; m
out:' Z8 i. j  Y' H8 d. P, C5 j
        return ERR_PTR(error);
) [, N# b+ p: t9 \" k" J}
4 B: S7 z" s0 e% l" z2 T
" a; w6 I, N+ n( L该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。
7 K/ v, B3 B/ T5 n6 A- Q* }下列函数位于fs/super.c
1 `8 w& a. ^/ v1 e" F: I  astruct vfsmount *alloc_vfsmnt(const char *name)' }& x) }2 _2 l
{
2 s) F9 H' ^+ F. s" P# W! E& l, v        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);; |- @. c; i0 O8 Z
        if (mnt) {' E! U1 a) U4 {) v- y
                int err;
6 t* z, }0 n$ R5 f, B
' @8 l7 y( n# |- R+ G- {                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/7 y. K. e0 z% _4 o- R* D
                if (err)
' o9 q0 |& x+ V2 B2 |                        goto out_free_cache;
3 r. z& ~9 x/ ~; I1 x
- ^- G7 V8 {$ ~5 m" w                if (name) {% _' U) C: \+ J4 ~& c7 S2 e
                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
. \% s' p( t4 ^( Q. ~$ R; _( @                        if (!mnt->mnt_devname)
7 Z4 \. O" B8 Z% p                                goto out_free_id;
; E' n  P3 i+ `# s0 J) {                }
$ P- n) b* E; H% b# Q! y+ B% q, n) y$ ~! S6 ^8 Z( R: S" z
                atomic_set(&mnt->mnt_count, 1);
' Q2 A( R  W! \. I' V1 Q                INIT_LIST_HEAD(&mnt->mnt_hash);! |4 f3 {: Y' _# a7 ]
                INIT_LIST_HEAD(&mnt->mnt_child);
7 |$ y& C3 }7 O9 o                INIT_LIST_HEAD(&mnt->mnt_mounts);. N) y7 r) w+ `
                INIT_LIST_HEAD(&mnt->mnt_list);  R" i9 r! f! k9 G! x
                INIT_LIST_HEAD(&mnt->mnt_expire);+ X, F, a' R- Z% J9 A
                INIT_LIST_HEAD(&mnt->mnt_share);
, ^+ D$ e2 {; x& E; e& a. ^! Q                INIT_LIST_HEAD(&mnt->mnt_slave_list);9 I2 ?) p0 J* R* P/ Q- n4 S
                INIT_LIST_HEAD(&mnt->mnt_slave);
; P3 u/ Q$ ^% T1 H                atomic_set(&mnt->__mnt_writers, 0);. s: q+ ]: S3 e9 Y
        }
. t1 i9 R) F  p7 `1 \  `/ U) W# y5 r        return mnt;
( r  Y1 s- O- ]# ^8 I: q, {2 ~9 M, a' T% B
out_free_id:' M3 _# P8 O6 ]1 E+ F9 d: \* v
        mnt_free_id(mnt);5 \: b6 b% \3 M9 M7 ?# Z
out_free_cache:
4 \+ A0 P( L- U/ \) |( t        kmem_cache_free(mnt_cache, mnt);
$ r: w) _: G9 w% w! y/ t# n% y7 A        return NULL;
. |  y; Y& Y1 ?: a5 J# L}
. _$ E+ d3 i& h8 g% l$ L" V) \分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:5 c) Z; n! y1 ?
下列函数位于fs/sysfs/mount.c。
3 _6 [" ?9 g# K$ F: k% Fstatic int sysfs_get_sb(struct file_system_type *fs_type,
! n6 @0 S* `5 R5 ]* D" k, e% ~        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
- I  o/ K; W# E2 i& g{
, f1 O  ~6 m4 i        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);* @5 t1 L5 m( P) ~  L8 Y
}
* B9 o1 i. Q6 h# W2 j这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。9 a- {& s, D5 J& {' W( u
该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。
0 D" i# m: L( \# {* V0 a% p1 Q, N
该函数的执行过程相当复杂,在下一节单独讲述。- M% d" j. r) w: R. [6 R! n
8 [& u+ \0 X( n
8.2 get_sb_single函数3 w7 {* w# l/ T' y5 I& c& p
下列函数位于fs/sysfs/mount.c。( |5 ~# L6 r5 Q8 L( k5 T. U* ]

; H5 p0 b/ W' R# d0 e* |& fint get_sb_single(struct file_system_type *fs_type,- u& x* O, a. M: Z& V- q
        int flags, void *data,
, Y! g+ J" Z/ Z! b        int (*fill_super)(struct super_block *, void *, int),/ }3 ^8 `0 s& g1 H9 ^
        struct vfsmount *mnt)
9 ]( S7 ~. Z0 M' _6 E7 S1 \' Y{
2 `* D/ L% g& j# K        struct super_block *s;, n( o8 g& ~9 ^7 ?6 [/ K, S/ f, P
        int error;5 O3 b$ @8 w1 T/ {
        /*查找或者创建super_block*/
/ J% q* z. S* k6 X  |        s = sget(fs_type, compare_single, set_anon_super, NULL);
- M. u4 Q  ~1 I, {        if (IS_ERR(s))
' [1 H. c1 r: x! D) }. r                return PTR_ERR(s);
, _- m# O; {, p        if (!s->s_root) {                /*没有根目录dentry*/$ o0 C1 Q0 c  L% e# R) d; ]
                s->s_flags = flags;3 k, m2 k5 _0 A6 S, ]
                /*获取root( / )的 inode和dentry*/
$ V9 N* z2 y) K! f( b2 h$ u                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);. l3 F7 N+ y9 u
                if (error) {
! m+ e" l$ I' A1 m$ G                        deactivate_locked_super(s);
1 ~' w/ Q0 w: h# I' V                        return error;" |9 b" p1 g) w
                }
2 \* l( w7 _0 q) r* J& W1 z                s->s_flags |= MS_ACTIVE;
) ~& `4 Y1 x7 O( y        }
2 W& D/ r/ f4 A% g  D        do_remount_sb(s, flags, data, 0);/ @/ r  l0 N0 e
        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/8 j/ ~( [- h- h0 o
        return 0;
, h2 ]- m$ u0 c3 ?+ s5 L4 ]) ^+ O}
* e1 V0 ~% s4 Z6 s
  {  Y' {% u/ Q' }& QEXPORT_SYMBOL(get_sb_single);
& D) E$ z( z! F1 e# O: G8.2.1 sget函数
! |* A/ U& F/ W" p# N* x! }首先调用了sget函数来查找是否7 m6 I5 T$ \, m. D) X' a
下列函数位于fs/super.c。8 ~+ b: S7 v! v
/**
/ {  ?1 J2 g  G) X+ J- }: f8 |% W0 I/ U: y *        sget        -        find or create a superblock
& P8 ?5 h6 g) U0 m; A1 K# K *        @type:        filesystem type superblock should belong to
' J1 \1 ^4 b8 k6 J* J *        @test:        comparison callback
8 b- V9 e/ i6 p$ I0 v& O( g' z! T *        @set:        setup callback/ f' B9 F$ \- _. Y% L- O
*        @data:        argument to each of them" W5 ~/ h( O( {3 j1 ~
*/' i* q7 O9 ^, x
struct super_block *sget(struct file_system_type *type,' u1 W) M/ f  T' k
                        int (*test)(struct super_block *,void *),
/ H" \' j6 t0 R; ]; ]: M% a                        int (*set)(struct super_block *,void *),
/ |" n6 S- L5 W1 s( C5 g5 f* z                        void *data)
# i3 [8 Z/ g3 O{
7 a; y  y' |* t! r$ e        struct super_block *s = NULL;
, a1 I# d+ [( z, I" k        struct super_block *old;
+ F# t# q# N) L        int err;
% M4 T! P2 m2 H
. q, l; A& m5 n  Dretry:
8 A$ p- E6 {4 X  X4 J        spin_lock(&sb_lock);
! v1 d' L% U" c- P5 ~0 U% ~        if (test) {                       
) s$ Q6 T5 ?/ }" R9 G+ k                /*遍历所有属于该文件系统的super_block*/6 R# r# ^( |$ `1 r) m
                list_for_each_entry(old, &type->fs_supers, s_instances) {
: b6 G) S- r4 N# E# n                        if (!test(old, data))
% |- I6 K- N9 H6 @                                continue;
8 m) w+ x1 }1 ?4 T1 \                        if (!grab_super(old))
6 h5 S- k. r/ K+ U& D3 m7 ~                                goto retry;" k* \3 y, @# L% @
                        if (s) {5 r& i2 n; w2 I: w% `2 f, {
                                up_write(&s->s_umount);0 k; u8 J; B; y, [7 v+ P1 m
                                destroy_super(s);* Y9 Y; P; x0 q8 j
                        }  g: C2 W" x! `& m
                        return old;
7 Y8 N8 Y9 |: H, v5 q! R2 h9 B! ~                }
! V* y' K$ |/ {& O( r& J        }1 V0 t4 A; z9 U' y. l" n- r
        if (!s) {$ j7 |' S! Q8 A) y! j' {' Z) a% c
                spin_unlock(&sb_lock);
2 O, h' ~1 |4 |" w# N7 O) A                s = alloc_super(type);        /*创建新的super_block并初始化*/+ h" ]$ A3 \, y4 ]: a% B: B
                if (!s)3 G; F: f1 A/ }
                        return ERR_PTR(-ENOMEM);
( C& T/ }2 W9 C7 @8 B; M% s                goto retry;
! @: Y# L. k+ k" f* C        }
7 R! [! f5 k7 E* v: d               
& g) K% X/ f# z" a9 r+ L6 V) g        err = set(s, data);                /*设置s->s_dev */
( Z' J$ h& P* j        if (err) {
; b8 g* x! G4 S9 e' x/ W2 }                spin_unlock(&sb_lock);) y9 w/ p2 U( s6 k, z  l3 H: N# A
                up_write(&s->s_umount);- z2 A. Q7 k  w) L6 d
                destroy_super(s);  |5 p6 S0 O4 a9 [0 P' R
                return ERR_PTR(err);  \; [( s3 J4 |
        }; g/ |+ K0 U( O2 q6 }4 B
        s->s_type = type;
2 {& }, q1 {1 G! p5 H; {        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/
: m. V. e4 n; b        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/0 C" G" e& R- B3 w4 J9 `- J! @1 P
        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/$ }9 B, R; s* w4 c; W
        spin_unlock(&sb_lock);
& q! s: J  G! u) k& F: n, j        get_filesystem(type);" E6 l8 o/ |3 s
        return s;! ^% Q- g5 ?! ~% q, t+ Y
}* H8 _  k; L6 O4 s& [6 a5 U
" Q3 d4 v" b3 C$ w! }% U/ `
EXPORT_SYMBOL(sget);8 ?: {$ K1 Z/ }: i% f
该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。
! z. }3 h0 ]! m/ ]然后调用alloc_super函数来创建新的struct super_block。
. M: O8 W- `: z1 [% y" `& b  P
! s! S* Z( t' ~% b9 z! O, J4 N1 t下列函数位于fs/super.c。
4 V0 c, ?. C9 Q9 @" _& O' K6 C. C/**
2 ]6 h6 F* h4 ~0 e; P( V! J8 F" b *        alloc_super        -        create new superblock
" O) W6 G8 B: w; ?2 O5 ]" A/ x *        @type:        filesystem type superblock should belong to
; }: l" k" {) z; x! ~0 b' }3 ?5 y *
+ m& j4 t  u* F2 P *        Allocates and initializes a new &struct super_block.  alloc_super()
9 v& y9 c  o& j& i *        returns a pointer new superblock or %NULL if allocation had failed.
8 f- y$ @) Y  G9 U3 o  E: ^+ ]$ g */
" y+ F0 m+ ]% a2 M5 }  Mstatic struct super_block *alloc_super(struct file_system_type *type)! {/ {! C3 M3 I' P$ M5 m
{
7 p6 S& h4 F  e& G3 N# Z- P        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/* P0 ^2 i- q. i1 D: n* J8 L" \
        static struct super_operations default_op;0 j$ p0 G* B& ?6 ?
7 f' ~3 }6 d* j. R% X( j4 v, o
        if (s) {' \' f9 K2 V* D7 x
                if (security_sb_alloc(s)) {9 W" B3 |" S3 W/ B6 F3 _+ E! \2 y
                        kfree(s);
1 ?; L' _/ x& p8 a                        s = NULL;2 d; @: u& e1 W1 G. q
                        goto out;/ E; C, P7 V) E; U1 A. X  M8 x
                }
6 A) u. z! Q/ _1 t% t/ x                INIT_LIST_HEAD(&s->s_dirty);2 F  B- D4 U- J7 \0 {6 t) m+ h
                INIT_LIST_HEAD(&s->s_io);
8 {) @1 [. ]: Y* U                INIT_LIST_HEAD(&s->s_more_io);2 T$ i8 ?3 u6 k3 l
                INIT_LIST_HEAD(&s->s_files);, x7 R: ?7 W  Z9 X/ f# [0 W
                INIT_LIST_HEAD(&s->s_instances);* l- R* ~: s$ h* [
                INIT_HLIST_HEAD(&s->s_anon);
  D" \& [# I: O# ^! s0 V$ ]                INIT_LIST_HEAD(&s->s_inodes);
$ P1 i' b8 ?; {3 A) Q2 S$ X4 F( t8 n                INIT_LIST_HEAD(&s->s_dentry_lru);
! e3 r6 J( {, P# R                INIT_LIST_HEAD(&s->s_async_list);
; n. q8 M' d3 Z$ o. D0 |2 T2 Y                init_rwsem(&s->s_umount);$ k, B3 x% K) K* Q. f3 k8 v. r1 {
                mutex_init(&s->s_lock);
9 x* Y; }: p6 n, O                lockdep_set_class(&s->s_umount, &type->s_umount_key);
+ B* {+ s2 \, C6 P( _                /*
5 B9 U2 U. O# r. I                 * The locking rules for s_lock are up to the
7 O  N: o# H0 P+ y- _$ L# y6 M; z                 * filesystem. For example ext3fs has different6 z+ x3 ~- D, L: {8 `
                 * lock ordering than usbfs:
0 j# M$ G1 D( k# D( b' c# E                 *// I0 H- D/ Y# ?: Z
                lockdep_set_class(&s->s_lock, &type->s_lock_key);
+ R! B' _; T( G& o' }                /*
+ s3 v: {) e, d5 I2 Z* `                 * sget() can have s_umount recursion.
3 ~  |$ o! K) U                 */ i( U! |1 z, @1 @1 @2 D
                 * When it cannot find a suitable sb, it allocates a new) G1 W, ^0 A! p
                 * one (this one), and tries again to find a suitable old+ p2 E, m' K/ ~% _) W5 P
                 * one.
& ^- o# B5 Z, T, r7 \                 *2 @3 p  C- c" w1 l  }
                 * In case that succeeds, it will acquire the s_umount1 v8 k. z+ l" M" x( e- Q
                 * lock of the old one. Since these are clearly distrinct
: |' r' P9 K, J# i- s& b5 ~' y                 * locks, and this object isn't exposed yet, there's no3 T7 }5 V7 N0 j
                 * risk of deadlocks.) N( u5 X6 R5 P5 t8 [
                 *9 }" |' w! V, z! t
                 * Annotate this by putting this lock in a different- \2 `! H9 z1 Q% c
                 * subclass.6 O: h2 X$ r. S4 x5 l. ~% i
                 */
) H+ {0 X. W  w                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
+ F+ C4 x, I: e                s->s_count = S_BIAS;7 m* J- O( ~5 p6 Z( Z
                atomic_set(&s->s_active, 1);
- k6 Z% ?/ g( @( f  I- d                mutex_init(&s->s_vfs_rename_mutex);
+ W$ ^1 \. d  l% [9 A6 V! O- `7 N# I                mutex_init(&s->s_dquot.dqio_mutex);4 }( A5 [/ V2 |/ y3 {
                mutex_init(&s->s_dquot.dqonoff_mutex);  q% B, i5 G$ j- T$ p) R
                init_rwsem(&s->s_dquot.dqptr_sem);
  j* G9 B1 l0 j9 P2 r                init_waitqueue_head(&s->s_wait_unfrozen);
0 _' ]0 _2 t. r                s->s_maxbytes = MAX_NON_LFS;2 p, _* x7 ~4 \0 z% u( L3 A/ p2 K
                s->dq_op = sb_dquot_ops;
* b8 y/ ~2 Z/ `2 |: _! \3 _                s->s_qcop = sb_quotactl_ops;% K; O2 M8 l5 f0 Z" Z' @3 d0 d
                s->s_op = &default_op;# P, A6 p3 ^+ i7 H3 B# m
                s->s_time_gran = 1000000000;
4 b, `/ t* r4 d" Y# D1 d8 ]9 G        }
8 s3 T! U8 s* [  kout:* B% D* `9 _$ K: y' E- ~
        return s;7 }0 H$ Y8 v: M! [. J" A2 F
}5 S3 u$ P& \$ r. k+ p+ F8 w! y
分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。7 \5 x* d5 L* [* M
下列函数位于fs/super.c。
: v7 z$ V- p! b: n+ ]int set_anon_super(struct super_block *s, void *data)
0 d* H) E. Y# t% q( e, k# Z{' F$ G! M  s- g+ f/ Y: q
        int dev;7 E) f3 Q8 f, P" `
        int error;
( A/ u+ A4 q2 |2 m+ Z8 v5 h+ t3 h* u
retry:
. C" I; R3 H. g8 X2 Q        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/. [9 H' o8 t; k4 v! }' J
                return -ENOMEM;: o. `, Q8 C: \5 b6 F  d
        spin_lock(&unnamed_dev_lock);
( E* z( B1 T8 Q- H        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/- c5 ^( F5 y" t' u0 {
        spin_unlock(&unnamed_dev_lock);: u8 {# m8 |5 U  j' s' o. D0 t
        if (error == -EAGAIN)
" b9 n6 ~* E# }% |8 x- ]                /* We raced and lost with another CPU. */3 }/ b! b' W1 w! d/ M
                goto retry;
- L* @0 e; t5 R4 f6 }3 {: E( F        else if (error)
# [) B* ^6 X' X9 z- n  ^                return -EAGAIN;3 `$ `1 J6 [# j
7 v5 \( {7 `+ C& U& z
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {: U7 {. x6 s# S. g
                spin_lock(&unnamed_dev_lock);
1 i7 E! @9 b" P' [' R                ida_remove(&unnamed_dev_ida, dev);
0 n6 }" H1 R4 Q! @                spin_unlock(&unnamed_dev_lock);
( Z- T/ H8 N. I                return -EMFILE;- {% W2 h" c$ f# k
        }
& ?5 m" h- B1 B. h        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/
4 v6 X* {, m1 K3 F        return 0;% `! J) A4 n7 u' \. u. ^
}4 B/ w2 F3 n  F- u6 f+ U
8.2.2  sysfs_fill_super函数
* `) R$ R- k. l' j, I1 g分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。
  ]4 f0 ~6 _. x- p) X1 o; Q3 X: b  Y, V. E
下列函数位于fs/sysfs/mount.c。
: {6 R" x, _1 l+ J- S; ]- x' e2 rstruct super_block * sysfs_sb = NULL;; t: _% v: p9 B' M- U# p6 `- b
1 J# N& E  r6 Z2 c% V
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
* l5 {  T+ c  o# J: }5 T; ]& M{4 H. H" }' ]- |! o2 d+ I6 @
        struct inode *inode;
$ P# P" ?8 q+ I8 Z  z& ~4 `. E( C4 B        struct dentry *root;
6 O+ y( S2 S$ h
; B( ?0 j, W1 ?" P) M5 X4 d; E        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/
/ Z( Z$ i5 f8 o8 U0 D) k6 w2 {        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/+ m' U6 K, c  @+ a
        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/
  s# c' W) H  c4 M4 l% P; K5 O        sb->s_op = &sysfs_ops;
0 C6 D6 g+ V/ M: P& I/ V8 G! ^  u        sb->s_time_gran = 1;
' N- n: |2 B' l$ n  n& @        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/( J/ T& c* ~0 W: p8 C; y+ @

2 I4 L- J5 B0 V1 w        /* get root inode, initialize and unlock it */& r1 c7 }2 {7 C6 C- }/ ^5 m3 ~' i" N+ ^
        mutex_lock(&sysfs_mutex);
, f3 H  R( w: t6 a* K) I9 N) d* m        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/               
% q" D3 R$ d! l& [" g        mutex_unlock(&sysfs_mutex);
' l* o, D, l5 C/ }9 J0 S; `& t) o        if (!inode) {
6 ?& L& X" N) w( z1 q- \7 r                pr_debug("sysfs: could not get root inode\n");$ w6 m( o# q4 ^: V
                return -ENOMEM;
5 K: s' D/ r7 Y        }4 t$ F8 D- e( h8 ~/ s; b3 O' L7 s
, ~1 P7 @- `. ^# L( y
        /* instantiate and link root dentry */& n/ B1 ~! k- i
        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/
- a! U5 D/ D2 C        if (!root) {" K& Y6 }( I9 ?  i
                pr_debug("%s: could not get root dentry!\n",__func__);1 P* V/ X0 {& c/ @9 O; U& D
                iput(inode);
: E  y) z" x/ p/ ~                return -ENOMEM;
. j/ X  n0 L* s6 [" [        }+ y2 ]. I; W) X. r1 o
        root->d_fsdata = &sysfs_root;. q" k# d! v0 e& h2 E
        sb->s_root = root;   /*保存superblock的根dentry*/1 [# \8 V7 T) W1 A4 E% B0 W
        return 0;/ |8 U2 W( V3 G- L8 t4 {, m
}4 w3 X" @) c* O) T" h

5 }* @$ c/ r! a  C  X0 gstruct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/
) F% F: P  O9 G8 e: r- S    .s_name        = "",
* m6 C6 ]$ v1 D7 h" h6 |( k    .s_count    = ATOMIC_INIT(1),
; g9 A0 h" C6 M0 J    .s_flags    = SYSFS_DIR,4 t+ p5 f6 _+ S" ]1 a5 v- C- N1 \
    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,. t8 L2 ?: i; j
    .s_ino        = 1,
7 m: \" ~1 n; r5 u0 Z0 W};" o; m/ Z1 S- w. d" f0 x3 K' a
7 [" s: m. k% R2 l0 U; C
在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。
, B8 u: [9 o2 K0 y0 O随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。: Q# O2 n( @& l2 Z

3 ~6 ^0 I# F6 e5 G+ \我们看些这个sysfs_dirent数据结构:; G, p% M+ S# R2 F- r
/*
8 @4 i2 `' t3 Z* N* C * sysfs_dirent - the building block of sysfs hierarchy.  Each and+ a7 p$ g4 b% _+ B+ X
* every sysfs node is represented by single sysfs_dirent.% G8 _7 h- }/ h& J  N  u
*$ O! E" d4 [/ T* ^
* As long as s_count reference is held, the sysfs_dirent itself is8 E2 t1 o9 v# F3 q7 T! i. C/ _
* accessible.  Dereferencing s_elem or any other outer entity! S; s; z# a- s, }9 m; |
* requires s_active reference.
( \# E# s( K  h; I */
$ |* c( w7 \) \struct sysfs_dirent {
) g* B) Y& b7 L* h        atomic_t                s_count;+ v6 {3 f( }; c3 K; {
        atomic_t                s_active;
' w8 b! N" k% {  j2 h        struct sysfs_dirent        *s_parent;7 T4 T$ ]9 ?7 L4 ?. @4 @
        struct sysfs_dirent        *s_sibling;) v8 [' b0 p0 L9 d* z) h8 u5 z
        const char                *s_name;& m- M# |  Q: u. S" P5 Y

6 s" ^% c8 R% C( k. Q        union {
) d1 y8 x  G  G/ L8 u2 [                struct sysfs_elem_dir                s_dir;
% u) o' ]6 X( q4 p7 w                struct sysfs_elem_symlink        s_symlink;) w0 v* p  F' @3 X% l/ \
                struct sysfs_elem_attr                s_attr;
2 r% [5 X* I. \9 m                struct sysfs_elem_bin_attr        s_bin_attr;& m' Q' x4 a* e% M! Z# {
        };
" o* x! ]" U. }3 \$ ]  W
- @, e; J6 S' O+ E0 w5 Z        unsigned int                s_flags;1 d- N: V9 m! y% p
        ino_t                        s_ino;
( U7 c8 J9 L+ }: ?        umode_t                        s_mode;1 P* r! n$ @( E. V6 R
        struct iattr                *s_iattr;
) `( @( B! P7 k% l; x0 t. M# Z. ~) |};
8 D0 P' w' O5 D& X' u8 V其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。
3 A! X3 ?0 N+ r& R) z另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。' w# T+ T$ o3 }1 H5 b9 H% M" ]$ x* w
接着,在来看下sysfs_get_inode函数:
- s. J( y+ m  k3 p$ z下列函数位于fs/sysfs/inode.c。) q; @5 Z1 n% a8 J6 g1 u2 T4 }1 R8 `
/**
8 _5 s3 a8 D  B  ?% Q4 ] *        sysfs_get_inode - get inode for sysfs_dirent* e4 ^$ |0 Q; f( j. w
*        @sd: sysfs_dirent to allocate inode for) }( [5 |( D9 ~) G2 v- X; r
*
# \, Q! ^- A+ o& z' q3 x *        Get inode for @sd.  If such inode doesn't exist, a new inode1 T/ v/ F' n6 F, L
*        is allocated and basics are initialized.  New inode is% ]6 i" E* ^6 R' n% _5 z4 a3 ?
*        returned locked.
$ a- f2 Y) R( s7 B6 [ *( L9 k5 |; T, Y" q: Z  w+ h1 X0 M
*        LOCKING:( F- I9 l3 r4 c8 w9 v
*        Kernel thread context (may sleep).
, h" P" e7 A1 o8 k4 d *4 s9 |$ \1 `% Y
*        RETURNS:# W: O! B. L8 T7 |( U
*        Pointer to allocated inode on success, NULL on failure.4 H& z. j* P5 ^' u
*/. p$ G0 u, x: P: ~
struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
: B% t  I& {  N{7 e% P9 _: p2 D1 c$ V7 e- P! L
        struct inode *inode;
2 L9 g" U1 \7 g" M4 Y
1 t3 ~  ?8 c/ c4 G        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/5 n' _; k! E" o
        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/& W2 ?6 Z! S/ |+ x
                sysfs_init_inode(sd, inode);
, R4 j2 T% J! r' D+ I) L4 J& k8 I8 W" z$ a4 b) P
        return inode;
9 }* }$ j( x& \4 Y}! G7 W* F8 B# H

% ]6 r5 y, t0 K% `$ ~- q5 i$ r/**
2 {( s) \, c  g: l2 I * iget_locked - obtain an inode from a mounted file system
1 T4 b* }! c* W * @sb:        super block of file system5 W# v% [$ ?2 ]
* @ino:    inode number to get
: a; s, `2 I3 U: b2 {( c8 s3 a *
) `' w) ]5 j' \2 n* P) e( k- Q' v * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
# [) E1 n0 e/ f8 \4 {0 E * the inode cache and if present it is returned with an increased reference5 _" }4 s4 h+ z& M8 ^
* count. This is for file systems where the inode number is sufficient for
. f! O+ {1 R( Y2 z * unique identification of an inode.: h9 Z/ T6 {: J$ t% H# L
*
' X) O6 x! b$ Q7 j* r) _/ ~3 o! U * If the inode is not in cache, get_new_inode_fast() is called to allocate a1 H! T8 G2 d1 K# ~0 L
* new inode and this is returned locked, hashed, and with the I_NEW flag set.2 B+ T$ M" H# J+ j* |- A
* The file system gets to fill it in before unlocking it via( h' E5 X, M; m# P5 Y9 E4 M2 n
* unlock_new_inode().5 P0 V  g. F" b: \
*/5 z: K- P' ?8 U0 u  d
struct inode *iget_locked(struct super_block *sb, unsigned long ino)
% V3 Z/ }4 ]: t) b+ k) z3 u6 M{: d$ o7 s( b' Y# p- L: c
    struct hlist_head *head = inode_hashtable + hash(sb, ino);
6 }5 H7 D& z5 q- q1 X) k4 m7 A6 H    struct inode *inode;
" e4 [& w5 m% H% p- H; t
: T0 c, q/ m, u. r5 x) j) u    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
! b( e1 l" O. |7 g/ P. S    if (inode). w' J  w& p8 C  l; I* s7 A+ l
        return inode;         /*找到了该inode*/
- w1 Y: b7 k4 t- p/ a    /*# D4 E( |9 J% p0 h' U9 j
     * get_new_inode_fast() will do the right thing, re-trying the search
- F2 i! B, C0 o+ q0 }     * in case it had to block at any point.
' o: w" z% F, q1 @     */. X0 O7 q0 u& C- x6 i0 H, v
    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/, l; }6 \: M$ {7 F) J  J$ t
}
( |, Z1 ?7 f3 FEXPORT_SYMBOL(iget_locked);, J6 [- v: Y& I% T1 t8 T

, ?. y$ y8 ~9 m; ~/ D' ?( Qstatic void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)" ]2 D; s$ q4 `1 z. l! _, c
{
, ^% u7 X0 w' G# u% n4 N  p    struct bin_attribute *bin_attr;1 }' [5 U  s5 M/ R1 e* k1 D
  c8 g7 E* M$ T& y  E) Y
    inode->i_private = sysfs_get(sd);4 ]) A$ B0 `5 e  M8 S$ L5 W
    inode->i_mapping->a_ops = &sysfs_aops;- o* [, {) S4 V
    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;( g  _* y- K7 j7 G* Y* H
    inode->i_op = &sysfs_inode_operations;4 ?8 [) g! O9 V9 K  v
    inode->i_ino = sd->s_ino;
5 P; `* N/ {& P  _9 h6 P0 p0 |4 R    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);: D  s5 |9 C8 _" e

- r7 e0 G7 K' u& y, N4 B    if (sd->s_iattr) {
; m: H" S4 N5 ]. s        /* sysfs_dirent has non-default attributes' h% k2 f" N* m3 J9 d' ~
         * get them for the new inode from persistent copy6 D* S9 T  z) Q! e( d% R# _
         * in sysfs_dirent
: u  T- p! w0 T4 U; c         */: @' j" s& @7 T4 z+ J
        set_inode_attr(inode, sd->s_iattr);; i& T5 _% C  H& s0 N9 w  E( L
    } else
1 q5 f4 x' J6 q9 t- z; i        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/3 _! `! {2 a8 E5 ~0 m7 y" Z
; V" D0 o; E8 h2 o* r2 E. c% N: j
  k8 e1 G  ]/ [6 z' r
    /* initialize inode according to type */3 V# c  w. D% E+ X5 |$ G3 b, V7 ~
    switch (sysfs_type(sd)) {
3 f3 d3 k9 U0 N$ a    case SYSFS_DIR:
! z+ P( ]8 L, `  U9 [/ V        inode->i_op = &sysfs_dir_inode_operations;1 J0 Z0 D8 b* R* q( Q, s* x9 A
        inode->i_fop = &sysfs_dir_operations;
! [: b& a  `& W; [/ M        inode->i_nlink = sysfs_count_nlink(sd);
5 ]- K; k! n4 F- V2 ^        break;  E" o" K- J+ C  C
    case SYSFS_KOBJ_ATTR:0 Z$ l! @/ u2 r& t7 I6 @1 {; q
        inode->i_size = PAGE_SIZE;4 F7 a+ V/ w) c7 W3 |/ g
        inode->i_fop = &sysfs_file_operations;" }' a6 `: J5 V! j. A5 I& l
        break;) s& v- m! Y" E7 ?: W6 |
    case SYSFS_KOBJ_BIN_ATTR:5 e$ f- r/ T! o% C5 W
        bin_attr = sd->s_bin_attr.bin_attr;( i2 N- j9 O0 e) C( Z; J
        inode->i_size = bin_attr->size;
) n- \8 o* d- e+ g! I        inode->i_fop = &bin_fops;
: D. X! `' J* s# m# T4 p        break;
8 K! z' c8 L5 P7 E    case SYSFS_KOBJ_LINK:
9 k. I% y/ x6 p$ q/ T7 e        inode->i_op = &sysfs_symlink_inode_operations;
4 N3 _. ^. V% ~& ^7 o        break;. _3 z. t3 _/ v: ~
    default:3 ^) q7 i6 `. J7 F) [- d% n' X
        BUG();& U$ N% {9 s: N; g* w
    }
3 {# g+ r3 H" p( s
' C; ~4 P: ?) B  t7 G% C    unlock_new_inode(inode);
$ U# ^. m* J8 |3 j" T}$ O' o2 D) A4 f
该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。; c9 B/ e$ c& b
再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。
! i% }$ ?7 w% L( M, W' U# N8 W/**
4 p% K2 X9 r2 w6 G: o8 E, p * d_alloc_root - allocate root dentry
# [. s$ _1 f! ~  S. t * @root_inode: inode to allocate the root for
# I; L  G) F+ g+ E *5 _0 b* z( G# l+ o2 K% U9 E
* Allocate a root ("/") dentry for the inode given. The inode is2 x( `, f* N) H. S+ t+ G- `
* instantiated and returned. %NULL is returned if there is insufficient/ x  h# m2 B2 D% H( X. M0 C; X% j0 c/ ]
* memory or the inode passed is %NULL., U. M5 o1 \& e
*/* o, r: ?( ~+ s2 ~  i/ L; z+ J8 o

! Y: i* B$ g) J" D  L1 Estruct dentry * d_alloc_root(struct inode * root_inode). q8 x) m1 S. Q
{
. t. o; C9 M+ }# e* F5 K        struct dentry *res = NULL;' o- R8 j, B2 p$ H

' q# i) s$ Y: o+ _        if (root_inode) {- ?9 F, `3 @. j
                static const struct qstr name = { .name = "/", .len = 1 };
1 T0 g# V6 f/ u5 t& G6 R: K$ [
                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/
* H1 Q$ n! Q6 H0 ]                if (res) {+ e. P" m, A, r
                        res->d_sb = root_inode->i_sb;
$ f( r; k( H7 s6 r& [: r& Z                        res->d_parent = res;       
& g, X* P" [. B2 u2 G                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/: O3 Q8 C* S2 x$ S
                }
) r4 W  G* B" Q: V* p5 K        }
3 ?- @! l" W- A* F% F        return res;
% k. @' b0 i: @) x' b7 Z; t' O" N- x}- M" s* T. C9 x
7 [" t' H3 p- a1 l* C
/**
2 l) t7 ?7 f' T' l, P& Z" w * d_alloc    -    allocate a dcache entry9 }2 h7 y8 @% z, c" t5 n: m( |
* @parent: parent of entry to allocate5 G& R8 o$ z$ `8 z- D. g
* @name: qstr of the name4 u0 u: r+ ^1 [; @/ `$ q$ ^
*9 V' i! u4 E1 r' H  a. B: N" F  x9 O
* Allocates a dentry. It returns %NULL if there is insufficient memory- Y/ t9 ^4 c. ^4 L$ @) X
* available. On a success the dentry is returned. The name passed in is+ S- l* M# X+ I: X) I
* copied and the copy passed in may be reused after this call.
, C, U1 l$ b, J7 F */
5 _+ h% J+ e6 m  P7 \$ [
. l2 J6 `8 `6 {- `/ C7 cstruct dentry *d_alloc(struct dentry * parent, const struct qstr *name)2 u9 ?1 z& m. K$ w: F" u
{2 i% U* [# H2 e& |
    struct dentry *dentry;
+ C1 _! N& L: Z' X: O! n    char *dname;
9 z9 h. T8 t( W5 b2 `" g9 w& G" M
& r) n- @9 S8 n1 q: E8 I    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/
' Q4 N) ]. h( P5 I( {& d- A* o    if (!dentry)6 w: |4 A" s) D9 n4 ^: {
        return NULL;3 i) P6 X/ ~1 W/ D% Z# L

3 E4 g9 i% `$ ^) b# }3 l8 p    if (name->len > DNAME_INLINE_LEN-1) {1 ^- u! ^: y* J, H
        dname = kmalloc(name->len + 1, GFP_KERNEL);
: l3 [2 F5 g' H. `& g1 B0 }        if (!dname) {
5 g* H0 h+ A2 I" r: _2 Q7 l            kmem_cache_free(dentry_cache, dentry);
  V& [0 V8 N$ {* X* ]            return NULL;
! R2 L, ~' j6 a- f( p) H        }
. i8 ^' A8 w' N# X    } else  {+ x9 Q* |, b8 ~% V& ]
        dname = dentry->d_iname;' V2 \1 c  l$ U
    }    2 f: `' N* Q1 e. N! @* D( Z! k
    dentry->d_name.name = dname;& a) M% Y& ~- |( m+ |/ Y/ J5 k
. j% X" i# H6 {- I! F7 X" Q, Q( T
    dentry->d_name.len = name->len;+ F# x) Z: @8 K+ i. C
    dentry->d_name.hash = name->hash;: x3 V+ h7 t; L" Z6 L  m
    mEMCpy(dname, name->name, name->len);) i: q8 g" @7 d! O" q; N; E$ ?
    dname[name->len] = 0;7 Y& z' K, r& e

! O% B2 Z7 k5 L& A8 V- K5 g    atomic_set(&dentry->d_count, 1);
3 k5 @( W7 r' x+ R    dentry->d_flags = DCACHE_UNHASHED;2 L. r& C& _# ^1 `' f
    spin_lock_init(&dentry->d_lock);
" F6 |" L0 A( V& u+ t* h  W; J    dentry->d_inode = NULL;
2 c+ T' c% q% Y) u    dentry->d_parent = NULL;
8 h( n$ A7 R' }    dentry->d_sb = NULL;
/ l; a) A2 Q2 b    dentry->d_op = NULL;9 `) _: R# s& h1 g( l7 b6 ~
    dentry->d_fsdata = NULL;
7 y2 a9 s% l; h4 ]    dentry->d_mounted = 0;# E$ ^5 K6 W* Q: ~* z
    INIT_HLIST_NODE(&dentry->d_hash);
( z* q; H4 ^# E% k7 j" N  K    INIT_LIST_HEAD(&dentry->d_lru);
, k  F: N. y# f; w0 ~4 Z    INIT_LIST_HEAD(&dentry->d_subdirs);2 ?5 u0 O$ ?( \
    INIT_LIST_HEAD(&dentry->d_alias);6 g' c. b' R2 Z$ ~
2 C- r, X8 _  q- O$ M8 M: h/ |
    if (parent) {    /*有父目录,则设置指针来表示关系*/
6 ?) I$ P' k5 Y% O        dentry->d_parent = dget(parent);
1 {% P. L4 ?5 \# m        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/
6 ^% R, \! N, K& K    } else {  S, U& Z9 y& b- A; w
        INIT_LIST_HEAD(&dentry->d_u.d_child);
( r/ s; v6 [5 F, j4 U1 M: c! E    }$ K/ k$ k, \9 I8 A
: T/ a! H; V& R
    spin_lock(&dcache_lock);
/ H# m6 ]! T9 s# @    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/
0 C: G0 u& n2 x        list_add(&dentry->d_u.d_child, &parent->d_subdirs);. D8 u! d: P0 R' h$ L& K
    dentry_stat.nr_dentry++;
3 a( F# [: {! D1 B    spin_unlock(&dcache_lock);
9 L) a9 z$ H- v# _1 W
/ z# n1 P1 w/ w    return dentry;9 n$ P0 t: L' g# g
}
! \' N, x0 e8 g$ |" Q; {& @4 H5 w" Z
  p) K- O) `5 \/ \/**
" M" s+ h3 h' D! D * d_instantiate - fill in inode information for a dentry* Y2 w" ]1 f/ W6 @- T
* @entry: dentry to complete. O7 x1 r9 m- T5 y4 x& p$ v
* @inode: inode to attach to this dentry& `) f$ R+ L2 Z: ~( r' B
*
# ~& k# ~* H) e2 `3 X( E- X * Fill in inode information in the entry.. }5 f. W& K  n$ Y* t) k! S
*) V4 v$ J% Q0 j; A' n0 E  D+ [3 @  F
* This turns negative dentries into productive full members4 \2 J9 ?7 z9 A4 C
* of society.* N. b6 x# H5 @, f/ Z
*) N  b% T9 g' e* [' S0 g# e
* NOTE! This assumes that the inode count has been incremented3 X' O- _/ w/ F* Z! p% a& X
* (or otherwise set) by the caller to indicate that it is now: q( h% b' t) h8 Z' q
* in use by the dcache.7 J5 z2 m+ H1 ?* u) T
*/
* ~6 p  g1 {2 m, y3 h
; y# ?$ ~5 W3 ]+ Xvoid d_instantiate(struct dentry *entry, struct inode * inode)
  D2 U; M. o( H. V) }+ B& r, u, g{  y5 v/ T+ u0 d3 p$ h, w: Z
    BUG_ON(!list_empty(&entry->d_alias));( W" B. {; I6 O
    spin_lock(&dcache_lock);, Q4 f8 k- H; D* F5 ]2 ^
    __d_instantiate(entry, inode);8 v, z3 M* k( g, {# Z  y' h( ?
    spin_unlock(&dcache_lock);
+ _3 H' g+ a$ E  P    security_d_instantiate(entry, inode);( D$ s5 a6 ]" }7 C# ^/ w6 y# X
}/ ?, X7 {! y' G7 b  G- w% A6 X) m

; N4 }. {$ h1 L2 v- }8 W6 Y! l- e/* the caller must hold dcache_lock */3 I; c$ r$ ^& N# m. b7 \" N% {
static void __d_instantiate(struct dentry *dentry, struct inode *inode)# a! `; H7 V$ i
{
& C% U* O. H. P( x- ]/ `0 ]    if (inode)4 A5 H" |9 c; G" y- l( |8 |0 G8 y5 s
        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/( h2 W; `/ R+ _& ]' ~& m' @% Q
    dentry->d_inode = inode;        /*保存dentry对应的inode*/7 E, D4 M) M0 g+ d. J, g2 K, }' Z
    fsnotify_d_instantiate(dentry, inode);, Q! I, K0 N5 q% o! Y" H& x0 M: q4 L: U
}
; x) x* S: b1 A, l5 I' ?" h, S/ i7 u, D
该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
  K4 x- Y5 J$ k! J0 X/ z# `2 d接着调用d_instantiate来绑定inode和dentry之间的关系。
8 m3 ~8 f' w+ i! g# L; E- i
/ e# g$ H/ K1 X( j' Q
; l  E! t0 x8 P1 H9 t' w  K在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。3 B! g* U2 M: J2 ^

) C, f0 d/ L6 X) g) f- _可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。
- w, H, q4 D! O$ J2 b' ~' Z3 |  u  w9 i! T; W$ }
8.2.3  do_remount_sb
- |1 G. r4 k% e1 i; G; B  ?& }下列代码位于fs/super.c。
1 b% j2 d7 Q3 D+ ^* m! y: @, s$ }1 e% Q" d/**
- G6 H7 C! m" \5 I6 t$ K( W  x *        do_remount_sb - asks filesystem to change mount options.* ^* \$ c8 _" \2 ]- h
*        @sb:        superblock in question
, M+ l4 @, a9 S *        @flags:        numeric part of options
) f& ?( j( P  N9 F2 u' a, l *        @data:        the rest of options9 l! v! Y+ \1 r6 R" r
*      @force: whether or not to force the change
2 |9 {% X& {3 h *. a( H& u: _, C" v
*        Alters the mount options of a mounted file system.
; r7 {5 ^, v0 O- ^ */# r/ l8 L. k' W% j5 r& Q
int do_remount_sb(struct super_block *sb, int flags, void *data, int force)9 u/ I! V' W- @0 F
{
  l/ }8 `% o+ Z3 {% A        int retval;
# J6 Q6 ~- N/ t* a  m6 Q1 ^  o        int remount_rw;
3 i: K' b! M, A) R" j        # B, y# t1 W! d7 V, q
#ifdef CONFIG_BLOCK$ v' M  _4 I0 o; ]- w" {* g" Q
        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))" f3 P/ {4 |8 }. q; D
                return -EACCES;
5 p9 _0 l( d. N" p* U#endif6 r3 V# G* J; ]
        if (flags & MS_RDONLY)
: M$ r+ t) a) I9 x) [                acct_auto_close(sb);
$ e# ^# K) `$ ~' L* I/ R        shrink_dcache_sb(sb);% ~; i# g7 x6 h, u! L6 N
        fsync_super(sb);
& j1 o$ g" v. P- M+ I9 V+ Q4 k  [' ~4 y- x
        /* If we are remounting RDONLY and current sb is read/write,6 w" t" q! Z8 S% \2 A$ M- {
           make sure there are no rw files opened */
- [7 e5 V; c1 \& Z        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
* C+ K/ x7 @- m3 ^, J                if (force)* X2 w4 c1 ?; O6 o% Y" W! r
                        mark_files_ro(sb);
7 \/ d2 H: t0 N+ N" w( u% A) C                else if (!fs_may_remount_ro(sb))3 E8 d/ b# [6 @& M- G% K
                        return -EBUSY;* d3 Z* X; V$ z, e0 d' o0 v8 C
                retval = vfs_dq_off(sb, 1);
8 s1 d, m2 t# q                if (retval < 0 && retval != -ENOSYS)
; d9 e) f' ?* F                        return -EBUSY;
% |3 q* v; U- s1 N. o7 x, q        }' E; o$ f! L. x) T1 d) m/ l
        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);. U: N8 M6 m9 G, R# ^5 e' W
2 |# g  d& d- \" s" r- |
        if (sb->s_op->remount_fs) {
! m. `0 a/ s' f. ?8 X  {                lock_super(sb);! K4 {' `+ b% Q  T
                retval = sb->s_op->remount_fs(sb, &flags, data);. i0 W6 P. ~  v% R+ A' x2 `  C; S
                unlock_super(sb);
5 x) C- S9 F9 o' |* p$ N1 u                if (retval)
' N0 c2 W- h% ]: V/ j& }                        return retval;
5 d0 _" ~; W/ v  u        }
! `. K2 p; w$ l4 u        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
2 `, i: I/ G; F; h+ w        if (remount_rw)
+ m9 o/ u' a1 h7 {1 E                vfs_dq_quota_on_remount(sb);
( n6 U; k. x6 O# \        return 0;
, f8 r7 J& }+ F! B. {. J1 Y' c}; b2 @* h. W3 W* H/ w

) X6 V1 Y; e; z/ Y/ g9 e, d  y这个函数用来修改挂在选项,这个函数就不分析了,不是重点。& ^0 o; B& s' {+ t- }$ }0 r
8.2.4simple_set_mnt3 }4 f% g# ~: J5 Y0 t# z6 {' ^- V
下列函数位于fs/namespace.c。; P3 v  ?& x" `  _: s: K
void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)8 Q7 U/ y% ?! t1 p
{
* B% o3 h$ \! Z# t$ y1 ^        mnt->mnt_sb = sb;* O( E7 w, U4 X8 r% x! U2 z
        mnt->mnt_root = dget(sb->s_root);
1 ~" h' ]8 a' C- s}
9 H  @/ n% ?$ Z+ K! a' g8 E该函数设置了vfsmount的superblock和根dentry。
+ H4 i4 @) q4 Y" t! j  Y* f2 L' V6 Z! w: I- q% F( v
8.2.5 小结; u8 m/ e: h/ h4 j& R/ w5 m2 y
这里,对sysfs的注册过程做一个总结。0 J  |' R2 `- d+ R7 L/ L0 o! r" ~: r
4 `+ B' K( d1 U6 e6 n; @( E1 f0 ?
sysfs_init函数调用过程示意图如下:& w2 Y8 Z# j! L; U, }) y
' h: a# n2 ?/ ~& q

" ]; Y- {& m0 M$ x
6 D! x+ U1 f, e0 D  {* Z在整个过程中,先后使用和创建了许多struct
9 n) k# b0 X5 U' t7 e
% ~4 A( {6 [( ~2 D: ^- Z第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。
, }4 c% j2 z  `8 r& j) Z" @& F4 D2 U2 y0 \- ?6 k- t
第二,建立了vfsmount。- f0 t' t. S6 q# c1 D. @0 N

- y. ~7 ?  N1 K3 U6 f  U第三,创建了超级块super_block。5 C' Y( L5 @) I/ U% w, ]
, }: Y/ |0 b( u
第四,根据sysfs_dirent表示的根目录,建立了inode。
% [/ y3 B" ?/ Y9 K
9 R! R& ]+ {% h* u, S最后,根据刚才建立的inode创建了dentry。; I7 t! }8 G2 X7 l2 T: q
. D; V0 Y9 J% p# _% @; j1 n
除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
/ O8 ]4 X6 M* R( A8 o5 Z, D
' b* V: u: p, {! E8 _8.3 创建目录
; u& @- g/ T, n* S4 O" |9 S在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。
5 r6 m4 {% ^! q$ q' x# L6 O) s* d$ _3 m) Q
下列代码位于fs/sysfs/dir.c。; T+ P/ \; y% G: P8 Q6 j& r/ E
/**) W. j; O/ D3 x; ]
*        sysfs_create_dir - create a directory for an object.
/ X  g8 g8 q$ `7 F/ }* p; { *        @kobj:                object we're creating directory for. 7 r! Y& x  j& C6 f/ h/ d( [7 p* W
*/
2 Q& L' ?& d$ I! R' Yint sysfs_create_dir(struct kobject * kobj)7 t8 N/ M9 A$ x* [5 p
{
( F/ q0 A# ~1 b        struct sysfs_dirent *parent_sd, *sd;" \9 t8 w- _3 h: r. O9 \
        int error = 0;
5 z! d. P- I5 v, U2 S" j* h
* p' c' z0 S; S7 C4 `        BUG_ON(!kobj);
- p2 _% U  K/ V% H! p7 O$ Q" K8 W: l& L4 c
        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/$ J" n. q+ e- q
                parent_sd = kobj->parent->sd;: X7 H; L, a- g5 B
        else                                /*没有则是在sys根目录*/
$ V) @! O3 i: ^0 a+ K                parent_sd = &sysfs_root;
* z" n1 G0 W3 W+ T; Z
4 r0 G$ T) j. d) ^) ]2 `. ]0 i        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
5 P  y9 l+ t: ^/ t0 `6 c$ z. d        if (!error)" Y. {7 a, T9 Y! B# y; R$ T# a! @
                kobj->sd = sd;; Y; c! g+ d( I% l: q2 }  ?* a
        return error;. u- U7 P6 Y5 S' T
}
! J( L) p) e1 M) }/ t6 ~6 X- E1 Y5 T$ z: c2 [: Q7 S
函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。. Q* w. F  h0 e4 o) A* R
很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。" Y! L  l9 |9 Z  S  }# w' P9 _
. m7 |- R! w6 ?: t% ~; h( S- |( F  p
下列代码位于fs/sysfs/dir.c。
8 A. g8 R% y4 z+ L. J. O& @9 wstatic int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,7 l8 b) |8 t$ u' G, X
                      const char *name, struct sysfs_dirent **p_sd)5 `2 f  B1 A3 K; w! i4 Q" F
{
) E" a0 f1 ]2 P- U: r) m+ T- G& ^        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
& h6 k2 A4 X, d* H" ~        struct sysfs_addrm_cxt acxt;
# E: [3 W8 J1 W  q. z* x5 v        struct sysfs_dirent *sd;
. u4 g* I2 c$ h) \# E, Q        int rc;+ y- J7 _( _5 R1 k1 o6 y# v3 I: e

2 s3 Z( X6 S, L8 g' s7 {4 b' I        /* allocate */        /*分配sysfs_dirent并初始化*/& [5 V& O$ [/ e$ z
        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);0 E5 c) b8 D/ I6 Y6 }& m
        if (!sd)
; ^) b% V  |  Z4 ]" N                return -ENOMEM;8 O7 \: _5 y: `0 ?' [; D0 {1 D3 C
        sd->s_dir.kobj = kobj;         /*保存kobject对象*/
, h9 m! C0 h$ u% R7 J- m
4 ^8 n& f" j8 @& b' \: T- i5 v        /* link in */
1 o, x! ?' g1 \) E* F  Q* w        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/' s* m' C# c& Y+ u
        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/, v' n% O: |' b# q2 M% n' h
        sysfs_addrm_finish(&acxt);                /*收尾工作*/
. X; v8 g$ \, f" u- R
- r: X9 A% y! T        if (rc == 0)                /*rc为0表示创建成功*/# G; ~/ Y. a. F
                *p_sd = sd;
9 ^! W/ V: b( J; W+ D3 _0 q+ K0 h        else
! O2 N$ [% J' M" l                sysfs_put(sd);        /*增加引用计数*/
$ C( i0 Q3 O2 c' Y
" j% `1 y, q$ h1 W4 x$ b; D        return rc;" L( B, V5 X' i% V# L6 j
}6 v+ a4 Y8 Q# {- \+ U$ ^
这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。+ E( P' _( k2 `& I2 L

8 }* v- _0 c) v( Y; z0 Wmode还有几个宏定义可以使用,如下:0 }; A/ C" o: U, g4 u& Y$ x4 Z- ~
#define SYSFS_KOBJ_ATTR                        0x0002: f& W% Y% N; B2 Y' l8 P2 E
#define SYSFS_KOBJ_BIN_ATTR                0x0004
/ D: h( V' G7 d1 _: N2 U& Z: \#define SYSFS_KOBJ_LINK                        0x00081 a" Z: G) k5 F- S. D/ z  l
#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK); V0 v) A- D* o; T; A) Y4 H5 m
8.3.1 sysfs_new_dirent
: R  {4 c& X& \2 g) C8 {5 g8 L  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。- Z' k, O$ C0 c3 Z: m4 h

) x- ?/ v& M6 K6 k下列代码位于fs/sysfs/dir.c。
' D) B$ J' s: ~struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)! ?. S+ @) m% z7 h! H% C
{
8 r: B" g2 b5 T4 ?" H6 Q        char *dup_name = NULL;. x$ I2 e# D3 T9 A4 ~
        struct sysfs_dirent *sd;* O1 L0 s6 _2 g' L: [4 H* b9 P6 f

  Z& o5 [, K0 e. j6 G  q( o1 e1 ?        if (type & SYSFS_COPY_NAME) {6 n: V! B) \) {( J+ ]
                name = dup_name = kstrdup(name, GFP_KERNEL);
. [6 S$ f: `; o; x: }' v. T                if (!name)
( U' H' P, H; v; Y                        return NULL;
3 M. _" Y: m* ?+ m        }5 f2 S4 L) k; d
        /*分配sysfs_dirent并清0*/" \% O- I0 H- }
        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);4 I% c% M9 B+ A5 T9 {; ?8 G7 k6 w
        if (!sd)
( S% w  x# |+ D2 s; E( Q4 w0 g                goto err_out1;( m. E, w# i2 c' O( f  Y6 ]

$ c% B1 M6 Y, f4 u) a: q        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/
. q0 {* b" Q  j, R                goto err_out2;
$ x0 P& J- ^" V# S; |5 m
* X, m. _- }/ I) g7 [        atomic_set(&sd->s_count, 1);
( x) F6 T4 @/ `! g8 G        atomic_set(&sd->s_active, 0);
4 A0 i% M( Q  K& h: {6 r
, H2 K/ k5 r2 w/ g( e& v7 q        sd->s_name = name;# [  q5 q  e- a0 I5 @
        sd->s_mode = mode;
2 d, D% @* [) p* z. a        sd->s_flags = type;0 c8 ^1 T0 B+ S/ M
9 T1 B: {) t: e4 V
        return sd;: N, ?& b1 U. h  h, F8 A% v, b

& a, o9 ~! K# B err_out2:' j- Z1 f+ [8 M, t, q
        kmem_cache_free(sysfs_dir_cachep, sd);
5 Z- e; P5 M" n err_out1:
' f* r% D) U- G! P        kfree(dup_name);9 ^( v9 C% s- t5 W! A& E
        return NULL;) R+ k, r) {1 _7 b# ^% l, N9 o
}
' r. I0 C' H: i% x: M) A8.3.2 有关sysfs_dirent中的联合体
- j- }9 `) d4 r$ J分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。" d, _: J8 p: _
. @* w- q& r8 _4 z+ }- ^( }
/* type-specific structures for sysfs_dirent->s_* union members */
5 N! v" R5 ^. ]# ?, Xstruct sysfs_elem_dir {; u0 P( e; [& j- u% a
        struct kobject                *kobj;
& ~" u! {: J' h3 z        /* children list starts here and goes through sd->s_sibling */
  d9 j" a0 C2 X& [- y% B        struct sysfs_dirent        *children;
% g2 M7 x% I& p) X};  `) ]! a* V& ?% P( k
5 b  c6 e1 b0 ~/ i. q  H
struct sysfs_elem_symlink {  x0 g9 f  Z7 I) m- H9 z) l# S7 t
    struct sysfs_dirent    *target_sd;
* W" p! J5 r% `3 L: s0 C. h};
* A& @- J3 n$ I) p$ }7 o! P, y5 i4 |$ u$ t8 B" b$ t9 n
struct sysfs_elem_attr {
4 F& p- \% R) r4 C- e    struct attribute    *attr;
( g8 s# {1 q9 O2 o' C- W9 Y    struct sysfs_open_dirent *open;1 a% \: W' Z0 X0 _4 w7 B1 T
};/ u: |; y! O2 j; X5 M% [1 \" l- \

$ f0 L2 W# F+ S7 _struct sysfs_elem_bin_attr {! L! K* Z- h: o+ L& J% S" z
    struct bin_attribute    *bin_attr;
- a# U0 x+ k; i: A    struct hlist_head    buffers;
. ?( K$ c" [/ M3 _};0 d+ s" m6 V0 @8 ^- X) O
根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。( S% r5 D. M/ a
在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。/ _3 Z! ^' Z% ]: Y
" s* z; C2 T1 m1 z
在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。1 j* G4 W& I% E9 h; J+ w% \

2 Y! o5 M0 G/ ?& o8.3.3 sysfs_addrm_start3 q2 ?! i4 ?3 u/ u
在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。
2 f4 @% ~, P( T9 X' c; O
: k# O. W" k  @下列代码位于fs/sysfs/dir.c。) ^+ m) G7 e' ?
/**
# }/ P0 Q3 T5 l$ p3 w2 i. Y6 q *        sysfs_addrm_start - prepare for sysfs_dirent add/remove7 O: K5 @! m* x( s' M3 W  e8 {
*        @acxt: pointer to sysfs_addrm_cxt to be used
* L8 w# x4 {! k+ u' t *        @parent_sd: parent sysfs_dirent' I% n  b9 t& F/ B0 d
*
, D. ^' D5 K( |  c2 K' } *        This function is called when the caller is about to add or- O$ Q( V$ y- B3 c
*        remove sysfs_dirent under @parent_sd.  This function acquires: S! Y( x# u% N# `
*        sysfs_mutex, grabs inode for @parent_sd if available and lock+ m- s+ ?/ V! e9 a
*        i_mutex of it.  @acxt is used to keep and pass context to
* y8 c8 Y0 m& T9 k8 f9 K( ` *        other addrm functions.2 {7 c: I8 Y1 U3 M8 x
*
9 i4 ~7 R' J# J9 }9 b *        LOCKING:, U( d, \6 e* P9 @1 g
*        Kernel thread context (may sleep).  sysfs_mutex is locked on$ [# H% O' d6 H8 ]
*        return.  i_mutex of parent inode is locked on return if
0 }1 ^4 D  r- |0 Q *        available.6 S. _$ X5 @% ?: U
*/
% r0 F% N/ {: N! n' D+ k7 }void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,# T  E8 z; R: h
                       struct sysfs_dirent *parent_sd): O: V5 S8 K3 F# s' H8 I, `' E
{
* Q9 O' ~) w- w% j/ x- R        struct inode *inode;/ V, K  U3 U3 Y3 ?# h# G

4 ?( N# b( F7 ]% A* s        memset(acxt, 0, sizeof(*acxt));0 G, h( H; y: G6 c  B1 G
        acxt->parent_sd = parent_sd;, Y0 G7 B& v2 s: u; Y! }1 R7 m

( \" O+ l! D5 i2 i        /* Lookup parent inode.  inode initialization is protected by+ C. C7 b; r0 d
         * sysfs_mutex, so inode existence can be determined by9 H* l! N7 \9 {1 _/ q/ p" k
         * looking up inode while holding sysfs_mutex.
! R4 w$ n! J. C! C5 F4 W0 L# q2 b         */
" t& P8 I0 f- V+ g" M& ~        mutex_lock(&sysfs_mutex);
2 l1 z& k8 p( R4 H, {        /*根据parent_sd来寻找父inode*/9 W9 O5 s8 m' T+ f/ K9 z
        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,/ e* t/ V4 C( V, u2 I
                         parent_sd);$ e0 f8 U2 j/ v7 Z4 z( W7 ~3 y
        if (inode) {2 W- m& h, Y( L  T! \( I. S6 z" B; t
                WARN_ON(inode->i_state & I_NEW);1 o( A  o3 G* g
- _/ q' k  f6 M  P! }
                /* parent inode available */  C+ D& X8 |8 p4 P& x0 k3 L
                acxt->parent_inode = inode;                /*保存找到的父inode*/! O0 ]: z  ?: T3 ^, I0 Y

  [. l* |7 t2 B9 i! D                /* sysfs_mutex is below i_mutex in lock hierarchy.
$ I# ?1 t' |5 D; d                 * First, trylock i_mutex.  If fails, unlock
) k1 o; ~, q# p4 J                 * sysfs_mutex and lock them in order." [. v  s% t$ Z; z, l
                 */
- S6 F3 ]# ~6 B8 i& H1 b                if (!mutex_trylock(&inode->i_mutex)) {
6 w1 a9 S, f- I2 Y& c6 }4 ^4 ~3 i                        mutex_unlock(&sysfs_mutex);
7 r# W+ P( d1 ?                        mutex_lock(&inode->i_mutex);& {; [7 A8 r/ H: _- V' e% ^4 N2 n
                        mutex_lock(&sysfs_mutex);
4 ~' o! e' j# Q8 L9 o  Z                }
# s- [  w( M% u/ [5 S( g        }
' }6 V5 \8 E4 _0 t2 G}
+ [. `1 M, ^4 W$ L: p
8 g; w; |( P0 ]; Q. {0 P/*
" y6 a5 d' H# q6 O+ {3 \- N * Context structure to be used while adding/removing nodes.: Y; N7 }1 Q5 l! o
*// P9 c! ?6 n$ r8 R- D. t- L
struct sysfs_addrm_cxt {1 O/ F+ \! V& m) k2 c( m
    struct sysfs_dirent    *parent_sd;$ f: k' J6 z9 s6 X) m
    struct inode        *parent_inode;
9 h  j6 E, r" }" ^' b9 c    struct sysfs_dirent    *removed;; U3 N4 D) v. ?) m: k
    int            cnt;# d' c6 ?  e. H7 x
};+ j" H; I# N6 Z0 D, e
注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。
. j! L# f, k! d: T# |8.3.4 sysfs_add_one
9 R8 V" z% T/ J下列代码位于fs/sysfs/dir.c。4 A2 {! j0 ^" ]$ m, c
/**2 F2 C5 c+ c) p6 k$ S9 s
*        sysfs_add_one - add sysfs_dirent to parent1 M. K6 Y& U* C0 X* }! E- l
*        @acxt: addrm context to use
# E( I' }: C/ M; a. J0 [# R *        @sd: sysfs_dirent to be added9 \# p" K/ W7 h
*( p1 t! E) d+ O% Y. Y
*        Get @acxt->parent_sd and set sd->s_parent to it and increment
- U  O" W: m/ Y2 K' B *        nlink of parent inode if @sd is a directory and link into the
& }5 e' E( h: Y. S *        children list of the parent.2 S! V+ T4 A# ~; w1 f
*. s3 w$ k+ f- O5 m+ S* j( J
*        This function should be called between calls to
! A/ O+ M% C5 h. Q0 {4 ^7 j4 j% ?  G *        sysfs_addrm_start() and sysfs_addrm_finish() and should be! Y. @( U- f, g# Y9 @* X! H
*        passed the same @acxt as passed to sysfs_addrm_start().# ~8 Q8 B5 N7 c& C5 o) N
*$ s" \- k2 E& k! z! T3 X- f
*        LOCKING:
) e0 K3 D6 u1 A6 A8 ]$ F3 E *        Determined by sysfs_addrm_start().
" d' b) g7 u* L *
8 r8 Y7 @; \  t$ f3 i2 F *        RETURNS:( J: a& p" z/ b2 |  [9 [5 A
*        0 on success, -EEXIST if entry with the given name already
  `+ O" s: E& m *        exists.
- G* \& R2 k/ M7 V( l: i: D. a( K; q */
1 R" ~- I2 z) u5 Jint sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
) E; m; @8 V1 \{
6 q8 G& I' V2 B! p; G# Y+ x4 n- s0 R        int ret;
9 O6 ~. P! Q, v6 G. J4 s2 B- E; z# `
        ret = __sysfs_add_one(acxt, sd);- [7 u+ L% ^9 A1 J
        if (ret == -EEXIST) {
! ]& j; w, {& V) V" v5 b                char *path = kzalloc(PATH_MAX, GFP_KERNEL);9 a+ a$ O& z) T1 }1 u5 x- R/ o
                WARN(1, KERN_WARNING1 e% t# `& ^1 t2 O) c3 v' A
                     "sysfs: cannot create duplicate filename '%s'\n",
/ m( L( j3 ?- e                     (path == NULL) ? sd->s_name :
2 b2 u8 c; G% R8 s$ M                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),* u9 t9 M6 W* S) o
                            sd->s_name));) t* `! f) u* ~$ ^3 N3 o
                kfree(path);  }4 d6 a7 D. E+ X3 Q, _% f
        }/ g: W# T$ E+ F! H) V$ T

$ B$ n+ o  x; K# \! A% d+ Z        return ret;2 i6 o8 F' n3 z5 q) Z. D4 A0 r
}
; C4 X" E0 i6 D: z: D
# t- `. Y1 H' v6 j$ m; J3 L/**. t) `+ t* K/ C& y; j0 z
*    __sysfs_add_one - add sysfs_dirent to parent without warning
: r# d0 A3 V) X! ?( y+ l7 L/ p, p, V *    @acxt: addrm context to use3 f! V, a, S8 f# c
*    @sd: sysfs_dirent to be added3 B# K' I6 o: x5 B$ t% q0 A4 |
*
( u) l3 Z% `4 G7 l* M! c  G6 U *    Get @acxt->parent_sd and set sd->s_parent to it and increment9 l1 T! s5 N; G6 k; Q5 D
*    nlink of parent inode if @sd is a directory and link into the" v3 t: n% m) T9 |
*    children list of the parent.  G2 L9 H7 \( z0 t+ `) M0 O
*; e0 d/ c6 T6 p; j, U; _' J3 k7 i
*    This function should be called between calls to# r% }7 Z4 u7 _) N+ n
*    sysfs_addrm_start() and sysfs_addrm_finish() and should be
) R# g. x/ [8 A8 b5 i *    passed the same @acxt as passed to sysfs_addrm_start().- D" c% c4 T' q0 ?+ s- P
*
9 S" f9 [5 e  S* I! K% c% S; D *    LOCKING:6 T6 t0 x; T6 P+ C( P0 E0 S, H. d
*    Determined by sysfs_addrm_start().8 ]0 ]% {5 ]1 W' S! W! ~; h/ s
*
( `$ w. i1 u& x *    RETURNS:
+ t, Z8 O% l3 d* C( |7 }0 X; V& a *    0 on success, -EEXIST if entry with the given name already: b3 Q1 w; ?4 ^" H  D5 [& d/ i" k
*    exists.7 C3 `' P1 Z' V. A
*/9 E* D# y: c/ M" y  G- E
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
; G( l# v2 U. i8 i1 Y: m6 W# x" P  w{" o- c1 Q, ]& S% H
    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
, Z' k: O& s: y; x( t9 r# A; K    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
. |1 O7 _3 r' P; \2 n! [        return -EEXIST;
% W) p& @( n; e6 O
  W2 I+ W' E5 n/ O$ i: I    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
3 y8 R$ q1 m! s! ?& K
: J0 Y3 D8 u5 D: ^+ }. J    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/: G' r# n0 c3 P
        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/
0 C% a3 z7 B9 w( m/ g; ]0 x. @6 ^8 z
    acxt->cnt++;
4 w: A7 p: e* `6 b( h; h5 ^4 {6 \$ S$ Y- Y" a# i
    sysfs_link_sibling(sd);
  t' B. q) K0 s. t! h7 }4 i
1 g' y  ]. ^1 o4 o    return 0;2 b3 \0 Z2 n3 k, d7 D- r* S
}! X( g& Z5 B/ i2 `
4 Q/ k- S% E, Z' v7 W' ~
/**" u& w5 {# D: v- e
*    sysfs_find_dirent - find sysfs_dirent with the given name
: G! i2 G. F0 s  j *    @parent_sd: sysfs_dirent to search under& ~/ N* H$ r! q4 u" h$ S
*    @name: name to look for: {$ t& a( v$ d/ ^
*
# N( ]. ^6 N1 a7 w8 o% W. p5 ^  k" H& s *    Look for sysfs_dirent with name @name under @parent_sd.
0 t7 ~, O8 B1 I *
$ x* z" A7 G' _" t- a *    LOCKING:0 Z9 e3 Q6 M2 r: ^- I
*    mutex_lock(sysfs_mutex)4 F3 R: w/ w5 h5 m& V' i
*' f, u1 }+ H: D2 D6 t1 H) J
*    RETURNS:
! x) L5 r/ `% X *    Pointer to sysfs_dirent if found, NULL if not.
2 P/ b9 C1 V/ F* Q3 t& O- [' a6 Y- [ */
' M( d7 |6 r+ _& u9 j2 }# Pstruct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
, I# ^+ p, ~5 ^) h0 g8 q                       const unsigned char *name)
  r+ A; ], r5 ~4 T' T{  }; x! G* n- {! S- |1 r& d
    struct sysfs_dirent *sd;
* c1 {) B7 i& K  [: Y6 z5 N3 @* }+ R' r3 y: F. {9 B. `
    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)6 M! N3 k# b. h- O
        if (!strcmp(sd->s_name, name))
7 V3 e& N( l# B. D& G! J            return sd;
# K- c) H1 m7 \. u    return NULL;
$ x! |/ s2 w' Q% R! c9 r% ?} 5 b2 j. V0 y0 \+ g% ^" i
3 H8 X3 d# p: q  ]
/**
; a0 B/ J) U5 r: ^ *    sysfs_link_sibling - link sysfs_dirent into sibling list
" K4 ^7 L5 b5 p1 Z *    @sd: sysfs_dirent of interest
- M- j! \' \; S# t3 H$ _1 N *5 \0 s% m; W: ?: \6 L
*    Link @sd into its sibling list which starts from
3 x, A* a2 i& ~9 h/ P* ] *    sd->s_parent->s_dir.children.( y! d3 e6 L1 \! ]# m5 D2 K
*
4 _9 `8 m4 [# h: E( X/ O *    Locking:1 c# M5 _( G/ \2 v( F( s/ c
*    mutex_lock(sysfs_mutex)
1 H/ X& H$ J1 [3 C3 m */
& a( u+ X1 c. k" b8 V$ r  [7 tstatic void sysfs_link_sibling(struct sysfs_dirent *sd)! e1 @0 d2 x" s+ V, Y
{9 O8 w4 L3 E! g/ ~5 W* z
    struct sysfs_dirent *parent_sd = sd->s_parent;
) B3 K" S; f! X4 |, S! |. v( @    struct sysfs_dirent **pos;2 e+ E3 G( l- I
0 r: a$ n; y5 G8 S. W/ R
    BUG_ON(sd->s_sibling);) d4 q/ t. j& I
/ e2 |- c% ~! D* D& `' q
    /* Store directory entries in order by ino.  This allows4 [! Y9 @+ U3 W" `- d
     * readdir to properly restart without having to add a) P" C( R) _9 _9 \( U
     * cursor into the s_dir.children list.
5 G  a7 y: |3 o( v* [9 ^6 I     */
, m8 A3 M) G# A( O5 j9 j     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/
, m* ]! B3 d* ^2 u4 @5 J0 I    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
3 b5 H5 e, l& R7 I1 c        if (sd->s_ino < (*pos)->s_ino)/ P7 ?4 e) J2 V+ j/ }6 c
            break;
' E% Q# O9 p/ X: t& @$ P    }# E6 Y* t* {( ~# p$ x% U  w* ]
    /*插入链表*/9 `+ T* \; y; z  i4 T' ?
    sd->s_sibling = *pos;/ a5 U: q% S' M. n
    *pos = sd; 7 N; E# n( A$ ]) E9 k( H
}) w. G' K5 x4 S& @7 {' S
该函数直接调用了__sysfs_add_one,后者先调用sysfs_find_dirent来查找该parent_sd下有无该的sysfs_dirent,如果没有,则设置创建好的新的sysfs_dirent的s_parent字段。也就是将新的sysfs_dirent添加到父sys_dirent中。接着调用sysfs_link_sibling函数,将新建的sysfs_dirent添加到sd->s_parent->s_dir.children链表中。0 @& S# w3 a1 ]. j1 N
8.3.5 sysfs_addrm_finish
+ b: N1 K& N4 o! f* p1 M下列代码位于fs/sysfs/dir.c。4 [: p9 t! c, f
) R2 x; |, r; r+ ^$ b
/**" v  s6 T4 u( b- x; o7 N+ ^7 R
*        sysfs_addrm_finish - finish up sysfs_dirent add/remove
& J' ^2 _- V0 Z6 D, R' d+ w- W *        @acxt: addrm context to finish up( {; I% t+ X/ a
*
% ~0 p3 F5 W; T: E *        Finish up sysfs_dirent add/remove.  Resources acquired by
8 r- b. |$ y) j$ I  D *        sysfs_addrm_start() are released and removed sysfs_dirents are* s3 w1 k: l3 L( `: M
*        cleaned up.  Timestamps on the parent inode are updated.$ n/ M5 B0 s/ I
*
" Z& u, U1 q  k *        LOCKING:8 y$ J7 U2 i9 B- V5 S1 f- V- G$ p/ M
*        All mutexes acquired by sysfs_addrm_start() are released.
3 g4 @- ^7 w' s# M. P */( @/ E/ M! q# P& e% h9 G% @0 Z6 i
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)# j1 T1 g* N- O9 A! l+ \7 Q
{
$ O8 T( l- L6 E7 q4 G+ Z: [        /* release resources acquired by sysfs_addrm_start() */
8 j4 [# ]/ Q  F$ A        mutex_unlock(&sysfs_mutex);
- _/ b# c/ j+ @8 ^: P        if (acxt->parent_inode) {  A; n$ R' A) c+ s" T( _( |
                struct inode *inode = acxt->parent_inode;4 i; w& V" ]" A

/ z+ e/ ?0 l" o9 |; g                /* if added/removed, update timestamps on the parent */
( u# M) ]0 V! T6 e; g: |/ @% c* f8 k                if (acxt->cnt)! |. n* u8 v( v+ f5 C8 h
                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*// s0 A, I4 z% k0 c0 ]7 P8 e# b

0 u" \8 J7 @: U6 P+ _. F  j( `                mutex_unlock(&inode->i_mutex);
3 n0 r9 E; b$ D/ d8 A0 R                iput(inode);
& [& w8 E) A7 E& g, p        }9 L8 O3 Z' V7 K5 S3 R9 A1 a5 p

4 g9 `3 R, A/ m( u+ }0 G        /* kill removed sysfs_dirents */
1 I0 I; I: _3 Z. k3 j        while (acxt->removed) {  p* {6 P* n% z$ D$ Q- h: S
                struct sysfs_dirent *sd = acxt->removed;9 J$ U7 Z. M2 O5 j- J
+ m8 G. V& s1 s
                acxt->removed = sd->s_sibling;
6 I+ p, J- l, d  o( J                sd->s_sibling = NULL;
( u* y9 L! F5 V! d/ M: p, H  y# {' i& w
                sysfs_drop_dentry(sd);
. H6 j( j2 o/ A% S' a                sysfs_deactivate(sd);- T1 D2 A3 D; P3 t# M; o3 {
                unmap_bin_file(sd);# @/ a  I& W; ?) R  v
                sysfs_put(sd);1 R. ^2 e- a2 _' w, {
        }
8 E: V9 j1 K* p: q+ |% c$ p}9 s7 l; e$ G" m% y6 S$ ?
  X- ~; y8 z& Q8 ?2 X0 A3 k, Y
该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。
1 }" y: z% Z5 o% l' a/ I
! f% g. a: O# r  J% h0 G, }至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。2 ^' p( C4 t) ^, W6 b" E

( A0 J) ^+ m" [1 f9 m下面我们看下如何添加属性文件。2 ?- O" p* b' I, C# v+ @
8.4 创建属性文件4 O( x, ?: g# ~/ f
添加属性文件使用sysfs_create_file函数。
; i) d0 ?4 U- M+ q: r! V
7 w/ a8 W$ q. D* k+ R# D下列函数位于fs/sysfs/file.c。
' `( _* E4 l$ {$ U( [# v6 Z/**
: P4 Z$ v- b% m+ U *        sysfs_create_file - create an attribute file for an object.
3 X2 T4 n0 K9 Q/ K% T: e* c *        @kobj:        object we're creating for. : j' E  ]  j6 f0 l8 H
*        @attr:        attribute descriptor.
- V6 r: k& V8 p3 Z- {7 E */' O4 T! V" ~3 n
' j( Y# m# K( T1 ^7 ~  [
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)) u7 s0 O0 C$ k5 F( \6 q& N' q
{
9 x4 d* T" P# Q" U        BUG_ON(!kobj || !kobj->sd || !attr);% \; _7 I: B% l8 }1 C+ n& z' w0 F; C

. A. e$ B3 j* u" o# M* D+ S. ~2 j( p        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);9 P& Z1 O6 Q4 e9 x

( j9 x& I( C, p: G% V* U7 C. ~}, q* ]# ]6 ?6 U8 U' f
8 n8 F& s' T' F) w  d
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,9 L9 J: W0 P9 n# N% x4 F
           int type)
% r$ |1 N2 U: L3 t6 U. d{
7 o1 t, S) k% g: N! ?( Q; _    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);9 ?! [+ U1 f) G9 \4 h. H+ p, h* B* t
}
* ]" X5 d( k: n9 t
/ Q6 O+ B2 ~. ]. i+ \int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
- }" w8 S6 h7 L% S6 {' w3 {8 `            const struct attribute *attr, int type, mode_t amode)2 p3 V0 `* ~1 x: ~. F' c( @
{
, I/ D* Q) M3 X    umode_t mode = (amode & S_IALLUGO) | S_IFREG;
3 w# X! ?+ b8 j8 U    struct sysfs_addrm_cxt acxt;
: X, g' V" G3 y6 H1 F0 S: F- [5 `# k    struct sysfs_dirent *sd;* R9 d" X2 h% W1 V) M" P
    int rc;
* ~/ x: A5 I$ k/ r4 g    /*分配sysfs_dirent并初始化*/( L0 F& F8 m2 L( V. q+ C
    sd = sysfs_new_dirent(attr->name, mode, type);
) ]7 q, {- j, g0 I, g5 ]5 t    if (!sd)
$ D: ^" l/ ^/ W- W6 Y. }( o        return -ENOMEM;# ~9 a+ f$ t* g* ^9 D4 j
    sd->s_attr.attr = (void *)attr;& t" o8 i- w+ Q
# G( Q3 Y( P5 {$ d' n
    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/
1 L" g  o: x5 G" P9 Z4 R( S    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
" j7 |  p# q/ E    sysfs_addrm_finish(&acxt);            /*收尾工作*/9 y- Y/ L; l9 S* m6 i$ z1 g+ U

$ `/ \# f$ o6 g6 v: s' w    if (rc)            /*0表示创建成功*/
& O8 _8 k2 z7 H& `" W9 s        sysfs_put(sd);
; @' z$ O* I% N2 j. s, g$ ~: u' I$ g* M6 p+ j
    return rc;
+ [8 X  {- N2 L( ~4 r0 d}
1 M2 M$ {$ K5 {0 h; L; |5 ^0 X* J3 r! }) {* V3 M& ]( y* H
sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。# m- [' x$ B7 _
sysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。
7 D- v: Q0 `7 X  I+ ?2 g4 f" P. N" L; M5 }  j+ y
需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。
6 |6 x0 {; h. D$ M: e8.5 创建symlink. X0 }: k4 e. P8 [* |
最后,来看下symlink的建立。" d) y% P4 U# k7 J0 F4 p0 `
/**2 C- ^/ V/ B8 y, ?. U
*        sysfs_create_link - create symlink between two objects.
0 P8 }' w+ y2 J$ L *        @kobj:        object whose directory we're creating the link in.! D0 H8 z/ r. r; R" u8 D! c# G! a. g
*        @target:        object we're pointing to.
6 t5 H6 w* }: p; a' X2 M *        @name:                name of the symlink.
/ n4 p# n4 {3 L# k1 T; i: B */
% ]5 I9 n7 Y0 `- Eint sysfs_create_link(struct kobject *kobj, struct kobject *target,
  ?( X' g1 w' c* a                      const char *name)
8 i. ~! N( u: s! x{
2 J' q- c# C. Y0 q/ w' V$ B) V        return sysfs_do_create_link(kobj, target, name, 1);, L; S# ]' x0 M! t! [2 O3 e2 ?
}2 S. m. f" V4 f4 h

0 }$ n$ \: P' w% A, tstatic int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
8 ^2 x7 U$ R" a& ?2 i* p3 Z4 W. w                const char *name, int warn)9 l  W/ d8 x' U+ {" {
{2 d# y3 i, Y" p, Y( V  I. J
    struct sysfs_dirent *parent_sd = NULL;
  p" G- O/ o" T4 @& P) S    struct sysfs_dirent *target_sd = NULL;
; i2 \: S' E; F: c; f    struct sysfs_dirent *sd = NULL;& J( e0 h+ g+ A# J6 c* S" T2 _$ b
    struct sysfs_addrm_cxt acxt;
9 U# R' D9 j% k2 C; {4 A    int error;9 M; s3 N3 F, X# d
; f& c0 y, H+ @3 g, N, |3 q
    BUG_ON(!name);
/ k+ Z4 M. F4 _; [5 R& v2 [6 ]
' [- r' K& E1 u3 s& J    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/9 @* T9 z  T& x, ]6 d' ^3 Z
        parent_sd = &sysfs_root;
; H: B* W: p) Y7 f$ F( ]5 j    else        /*有父sysfs_dirent*/
1 s# K- m, |1 _3 A$ ?0 ?        parent_sd = kobj->sd;/ {1 {6 J1 ~* l
4 |3 [' L0 _; A( q4 R
    error = -EFAULT;
2 h, l0 ^: P7 @/ C4 I$ s    if (!parent_sd)
, t7 H+ F" Z; ^# F6 f0 ?5 n        goto out_put;
8 E5 G2 [- d) g, `5 c7 m- t) I. K' i  I. L+ p
    /* target->sd can go away beneath us but is protected with
1 F5 D0 z/ ?( B1 `9 H3 b     * sysfs_assoc_lock.  Fetch target_sd from it.
% f: U% v% T/ {     */1 b) s& n5 V) X3 _+ o/ P4 [
    spin_lock(&sysfs_assoc_lock);
# H9 A" l% x9 r    if (target->sd)8 l( I! r2 i4 T3 Y; I  }
        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/3 H' ]3 P, s- K1 L
    spin_unlock(&sysfs_assoc_lock);
0 \. O" o6 x% C
" Q4 W; r: L& o7 @    error = -ENOENT;
' q; V; g+ a. \( b  ~. j    if (!target_sd)
. s- m- q4 F7 W3 o6 @! [- }& }% l        goto out_put;
: P, z- o7 n6 H7 T9 |6 \( U# D$ T& O/ X# S& v
    error = -ENOMEM;- d; }, C+ P; \) P, v
    /*分配sysfs_dirent并初始化*/# t, i) @- P) M
    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
3 Y. T  N9 p7 ^. Q8 ?    if (!sd)) o% s9 F' r: H6 [( R1 ~
        goto out_put;
8 ^/ S7 C# z4 [. t0 W3 m8 q$ j1 v
5 R' z% [) Z( _* \. E    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/& y3 N6 [1 N. |/ I- p
    target_sd = NULL;    /* reference is now owned by the symlink */
' ]# n" `  I8 c/ |+ b1 V/ P5 N8 ^6 i+ I+ u3 ~! Y( D
    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/* P; W3 ?1 {% V+ M6 Y3 {/ R: W* P
    if (warn)
. g2 h. n0 ^6 q! t4 j, m( Z5 c        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
1 O# F3 v$ I1 b" T2 ?$ s7 j    else  r& |0 [3 r9 A
        error = __sysfs_add_one(&acxt, sd);% h. E4 v$ }1 c) s" [! w
    sysfs_addrm_finish(&acxt);            /*收尾工作*/
3 H- }9 M4 L8 k9 k+ s# ]& W0 f- R* D* N( ]2 u
    if (error)
/ w' R% c7 ^5 F% B' {        goto out_put;. }$ R1 ^% |' n8 e9 `3 t1 a

) i3 G4 P1 N! \& }    return 0;
" }5 w' P" e9 K( C: s) M) O) @
0 _! F' j* G# T- k9 g: ]; x/ m out_put:) O- ~( Q* F" r
    sysfs_put(target_sd);: V7 B& _" A2 l* P2 a! E
    sysfs_put(sd);
+ \/ V* {/ {7 c$ u4 D    return error;6 R4 v# q/ |" J( e/ P
}# G6 |- @* n4 G! l9 J

. h7 f- f- Y/ T; B  ~( `5 R1 A这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。/ I" d4 r( [& |; q
因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。' E  f; I+ G  S# a3 J* t: j, t8 R

6 t# \) K1 L# n, _8.6 小结
# c3 |0 L0 G( ?& ^. }本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录
3 d' L+ s$ v2 h8 {# n- w. K: ~2 _
0 q* J( V2 F  J有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。
% {; Z! Z/ ]/ N' U4 `% H4 W# j* {% X: V$ r
9 总结* z) B: A# A  Z3 D& n4 G
本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。
& l- r+ d8 [+ Y0 Z. |
; t% V. }! m  \7 i接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。
; \2 L0 G: M4 x9 J6 m* _: ~% c
- H. E- D9 L; {3 l6 _, G随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。% U4 b4 u7 r( |6 Y' Y7 K
% V. C- Z& N9 D& j0 G
然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。
+ P& Z! F& _0 Q* w% \+ B
0 L, z; [; m; C2 L: v& r/ R7 t之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。
& D( P8 N$ o0 ^& a# L
3 r) z& b8 ~$ _+ G最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。+ b0 F: h4 i" W6 ^1 t) v# c+ y& Z
- l5 J1 W8 [  z+ p/ J: K2 S

, `+ ?- m: P; ]* F# @

该用户从未签到

2#
发表于 2020-6-17 17:22 | 只看该作者
设备驱动模型和sysfs文件系统解读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-25 19:49 , Processed in 0.437500 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表