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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。$ U6 u: C9 u) C* g# f1 W0 x8 C
) V' H# ]3 K$ T( |
内核版本:2.6.30/ B5 D7 ]2 r3 m5 U2 `* E1 j
* O# Y7 d* B& l% T. l
1. What is sysfs?
% a6 _, |1 t# R0 i9 F) a% L- R  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。
3 \+ n: F9 n/ x
; {. C# [3 s  L  我们来看看sysfs的文件结构:3 c) j* I# }  a8 z+ Z+ Y1 G1 t
1 F  g0 @! V: W0 r9 h1 V
[root@yj423 /sys]#ls5 @0 {; R1 c! j0 ]- a- Y3 ]' S
block     class     devices   fs        module: \  p  y; Q( D
bus       dev       firmware  kernel    power
7 D# o& n6 u# L$ ~& E* P3 U0 z) E$ T1 {& a8 K( \1 r+ o. [
block:块设备0 s' ?+ z/ H1 Y4 V" R) g5 f6 m
' ^: |0 `1 L8 X% u+ u
bus:系统中的总线
5 C  i4 d6 Y* U% q$ }: R  W' d2 l, U8 P* v0 l
class: 设备类型,比如输入设备$ ?8 t" Y3 ?$ s5 p( F% ]; \. u
( b% f% e4 K7 p
dev:系统中已注册的设备节点的视图,有两个子目录char和block。
1 J9 G/ \* ?6 F/ E9 S8 A/ `! ]& R1 q2 T
devices:系统中所有设备拓扑结构视图$ D6 h( I5 Z7 k* e
+ L* W. o" u9 t7 ]* u! J5 ?5 _; `# H
fireware:固件
5 F$ ?$ X& j9 I( k3 Z3 z  w
  {3 @" ]+ V* U7 {9 \fs:文件系统
+ B; Z8 Q8 u) I4 s7 ^# p7 b
! T/ E2 s& g& g0 R: ?! Ekernel:内核配置选项和状态信息
) w* n7 F8 g4 h6 H$ x( Q/ Z3 ?( K( b. @
% c& E! Y6 o  umodule:模块+ S6 B, W3 `/ q' o$ {

. U5 K( |3 X% y4 w! N4 e, [power:系统的电源管理数据3 R( ~3 ~& i3 Z4 j$ k+ k0 }
5 H# X) I% v# k
2. kobject ,kset和ktype
; ^. y% K& r: o2 F3 b1 j  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。* L# |5 J, Y6 V& U

: D7 v1 Y( \8 t' t% s6 I2.1 kobject
' J; w' D" G' @: z  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。* e: C: p0 t: i7 z4 J
; e' s3 q- O) q4 t4 W' P: [
  kobject用struct kobject来描述。
5 v4 d0 i# X( v; `; ?; j- }; {! [' O
struct kobject {: t7 X* z  C. a3 d
    const char        *name;            /*在sysfs建立目录的名字*/  q8 O6 u. A5 F9 z
    struct list_head    entry;        /*用于连接到所属kset的链表中*/+ Y, F4 t$ ^. \8 ]; s) d- |" F
    struct kobject        *parent;    /*父对象*/
6 k: M# i* P7 x1 F" ^# n0 ^" x    struct kset        *kset;            /*属于哪个kset*/
2 L6 {% i& e9 K  \    struct kobj_type    *ktype;        /*类型*/
7 d3 D4 j* V! \" E9 ~& m    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
5 R: [, L  l: a9 j1 w    struct kref        kref;            /*对象的应用计数*/- S1 e# a. e! H. S, z
    unsigned int state_initialized:1;
+ @9 Z- {1 ?2 \  ?5 y    unsigned int state_in_sysfs:1;: T3 l7 ?: _5 L( S
    unsigned int state_add_uevent_sent:1;
. G& R3 V8 C$ V1 ~2 `4 d3 y    unsigned int state_remove_uevent_sent:1;! N7 j2 @5 v* B6 z0 G# i! h9 t
    unsigned int uevent_suppress:1;5 E. [$ C/ _% y3 r. B7 @$ S. m: i8 z
};
' i- ~, }( m* Z$ T2 o! D2.2 kset
' f' C# e$ @9 t! F4 W  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。0 R& o+ ~. @) W  N! i1 x1 a
5 }/ ^+ A% P5 l$ C7 h
  kset使用struct kset来描述。
* S  Z* K* F( ?  ^( I% u
- K& D% g/ @* R+ d0 R; Z$ ~/**
2 L* S/ L3 m- G- C8 ] * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
4 N- ^4 s  g6 o" u7 B& l *% E8 c* u0 z7 G- h( c
* A kset defines a group of kobjects.  They can be individually
8 J2 ?) b& `; N* P) X/ U6 o" P * different "types" but overall these kobjects all want to be grouped
  }# Z& s, ^6 O' j3 b: @# N * together and operated on in the same manner.  ksets are used to( _, I9 @. x8 D) @( `# s
* define the attribute callbacks and other common events that happen to
" ~$ l+ \: c6 W * a kobject.& |6 w8 `0 p4 y3 }- w% `% o# O
*
3 O" x; q  C2 X  E$ N  m7 D9 I6 D * @list: the list of all kobjects for this kset
; a( D% \. B5 b' ? * @list_lock: a lock for iterating over the kobjects: M# z. v9 O2 N7 z" s; ^
* @kobj: the embedded kobject for this kset (recursion, isn't it fun...)/ k0 S8 O) T; }) x  D& ]4 w* L# @
* @uevent_ops: the set of uevent operations for this kset.  These are
; f& {" i# ]' r2 k" u6 y8 ?% L * called whenever a kobject has something happen to it so that the kset
: Q: t: C/ B$ k! j+ p0 y7 n * can add new environment variables, or filter out the uevents if so
8 L4 g0 }% d; A+ Y" T  r) j * desired.4 o+ ~& j$ ~9 v2 n% p( C
*/' ?0 d& e( q' C1 S
struct kset {
: ]1 E! M" R2 B1 b        struct list_head list;                /*属于该kset的kobject链表*/) V3 m$ A& K& [% z6 s; [5 z2 W
        spinlock_t list_lock;        9 h* r- ?6 M9 n- l" M
        struct kobject kobj;        /*该kset内嵌的kobj*/
8 Q* Y. a- j% W7 W& x3 o, s: b* ?8 l3 i8 B+ g3 n" ~6 }4 V3 v
        struct kset_uevent_ops *uevent_ops;
+ r$ q7 t, ~* b/ N1 q6 p};- Y: \& w1 X2 T; b# g

$ T5 `1 @& Y0 A9 P$ \6 t2.3 ktype, W# S. ~# X3 e2 p0 R5 n
每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。4 K: f$ G: S$ N* E2 O2 B8 i
, {; t0 n# P3 e4 }# U/ ~
struct kobj_type {
2 F2 \% v1 Q1 ^# @& @8 m0 u    void (*release)(struct kobject *kobj);
; |8 T* {, J" W; _2 L- J' y    struct sysfs_ops *sysfs_ops;
' I% Z1 Z3 @) H    struct attribute **default_attrs;+ x" Y# ~8 }# R: a7 f
};  ]% I' I0 D0 \" |" g1 P7 Q
; a9 p  O' f* I
struct sysfs_ops {
, V$ c* \$ P& c; T2 t  B" `: ~    ssize_t    (*show)(struct kobject *, struct attribute *,char *);
5 X3 }9 B7 S- S% ]. e) ~    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);6 b  ]( \2 ?  j& s, _
};
) [; l3 ?6 e0 L- B- l: m  O
; S; N5 m, c1 `0 `. k/* FIXME
' \8 L6 `( \' _ * The *owner field is no longer used.: S0 s% _: f5 o# S
* x86 tree has been cleaned up. The owner; Y" k, }  ~) e- ?/ e- M
* attribute is still left for other arches.8 W4 N  C" Q1 C& L- G
*/
  g0 {! W% t+ o+ n: }- Bstruct attribute {/ k- F( L# V) Q
    const char        *name;
/ _' _; e" y% y1 m' G7 O7 h  M    struct module        *owner;: _$ @0 H7 a& l8 c; K& S
    mode_t            mode;
& u$ q& K0 E1 Y};
% O1 I, I/ R( H5 [7 I) X
, i8 `  m& b3 S7 v( _5 G6 |! w
. I8 Y" `: \" ?4 E; ~& @. d当kobject的引用计数为0时,通过release方法来释放相关的资源。
" X* r! x& N6 t  _& n/ D( Iattribute为属性,每个属性在sysfs中都有对应的属性文件。4 K0 M, A# u. I3 ~1 ~& v2 b7 j7 W, O1 d

# W9 [/ E5 F9 rsysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。$ e! a" y! t/ Y# q5 m6 n
* {7 e5 }$ ]$ T/ \+ c
2.4 kobject与kset的关系  ]- R* L5 ?) r6 P# {2 Q5 g& O& H6 L
  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。
% b" x9 d8 f/ C4 r( S! f  u' R! N; Q3 r  A0 |0 Y
   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。
( P2 j3 p, h/ Q6 m0 j  z- D4 o8 t( f! l7 S( a# \$ N7 B8 |& v
; X3 D1 Z4 c2 p. P. r

3 Z% D: U- ^( Q' ^3.举例8 M1 t3 R8 s: P6 N4 G8 H  A
在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。. Q2 k; i+ D7 T( X, D" U

+ m* P  N- D% a; n- ]下面代码位于drivers/base/bus.c
( ^, k8 v$ A4 M( Aint __init buses_init(void)
4 l6 f  t2 n' F1 q/ O{! X7 w8 s/ w9 r, z3 a
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
+ c1 e  K  E4 G2 _        if (!bus_kset)
# e: ?1 b$ }$ b3 {5 i% d, g+ O" }% t                return -ENOMEM;) F5 M' j  |) t* J
        return 0;
( ?/ q4 Y8 h' Y; ~# X6 T; E}/ r) f# A6 C. J

, V0 f8 m3 @* N! g  zstatic struct kset_uevent_ops bus_uevent_ops = {
# l0 y+ ?6 H& g& t( J& z) @    .filter = bus_uevent_filter,6 f8 z1 L$ v4 z/ s" [0 t! P& N
};
* y* H9 V( w' \% Y0 P  U5 o; D6 u) S# m7 r/ g: I  M
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
3 Q( d) N4 R- L( H/ `3 [{. p* o! P% I0 b& \# O! j$ n: E+ L
    struct kobj_type *ktype = get_ktype(kobj);
5 P' l/ c, F; V+ \& _
6 A* Y) d" S. L0 e/ K$ Z8 e    if (ktype == &bus_ktype)) U7 S$ [5 w% O7 r2 f& B
        return 1;% c" w7 i4 R* A" p+ d8 J0 L
    return 0;  s0 G  ]9 W# a7 H4 \
}
" K  u" p' I1 F5 e4 E0 X这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。
' v. j  L0 c& L; `下面代码位于drivers/base/kobject.c9 `; _6 x; H1 |
/**
3 o. Z: k9 i! x( {6 ] * kset_create_and_add - create a struct kset dynamically and add it to sysfs0 |$ @1 O, c  m: e7 M0 q
*6 k: p1 N9 b* B/ p: V) v
* @name: the name for the kset5 D; O# o$ y9 N$ b
* @uevent_ops: a struct kset_uevent_ops for the kset
& a, [  J" d  K* E- c& g' q8 K9 Z * @parent_kobj: the parent kobject of this kset, if any.
2 V# n, u" G6 B) A) }( v *. ]# P0 y+ J- l
* This function creates a kset structure dynamically and registers it
% E/ j9 W8 E9 ]5 D& t7 R0 Y2 d * with sysfs.  When you are finished with this structure, call& ?- I) w# b3 z( P3 @4 Q
* kset_unregister() and the structure will be dynamically freed when it
# D* l6 k. W7 y0 T  s. F) w * is no longer being used.- S  s/ \: k  a* z( T: [/ T. b
*; `% U+ G( s' |2 h# h% Z7 ?3 O, g7 Z! G
* If the kset was not able to be created, NULL will be returned.
8 H- D& h6 J, D0 I5 Z */
3 [8 D( r- Z. Y/ e, V' O+ jstruct kset *kset_create_and_add(const char *name,3 c4 o7 H! t9 V0 |
                                 struct kset_uevent_ops *uevent_ops,
; y; d" k+ Q! e6 ]. k1 J                                 struct kobject *parent_kobj)
3 `+ d# B1 D! E# o: S+ \, j8 N{' q4 b. R% X0 j$ f) u) T
        struct kset *kset;- D4 J" ^- z+ {; c) Q) ~  T6 B( i7 [2 H
        int error;
/ N  T4 @' Q" O4 A! {/ a: r$ @  Z  G5 S
        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/
9 z! w9 j7 K+ M4 e5 w        if (!kset)
( F4 A5 E3 ^5 q6 S% i% y                return NULL;) G7 ]/ R, F' M
        error = kset_register(kset);        /*添加kset到sysfs*/
% b3 S  @& Z+ t+ t' P+ a7 P        if (error) {
; S1 a. T- R, ]6 E8 d) m                kfree(kset);
/ U; W  O1 x6 H7 ~) q# h                return NULL;
$ H; v" g8 B1 F. Q2 X8 o+ `        }
7 {9 i) U; e( O5 p. ^& w        return kset;( l+ f, d$ j3 L
}
+ P7 D: G. q4 x/ i$ w6 Q这里主要调用了两个函数,接下分别来看下。# T9 b5 l* h  |1 S8 c$ F, Z
" F7 [# l" i4 {! X% b$ _
3.1 kset_create函数
% V/ p1 b. o; c* P) |8 w5 D下面代码位于drivers/base/kobject.c
2 B, P" j$ }5 X: {# E: |* M3 b$ R; {4 h0 r; {6 s
/**1 p( f8 }8 a4 H( _+ J: b% a
* kset_create - create a struct kset dynamically/ w( c6 i$ z" P' A7 Q; n9 Q
*
+ _& e# B4 i* n( o. u' } * @name: the name for the kset- G4 a) d# ]9 W; L( O* N4 U
* @uevent_ops: a struct kset_uevent_ops for the kset
( Z# |  E+ B; q; K * @parent_kobj: the parent kobject of this kset, if any.4 |; _. _7 W0 }% R
*
- V  @) M( p! B+ s; m * This function creates a kset structure dynamically.  This structure can3 B: ]2 i, {# k- w
* then be registered with the system and show up in sysfs with a call to
) {' p0 Y! T. u' i; ?# X' g2 N4 v * kset_register().  When you are finished with this structure, if: |" Q& ~/ t0 U) X6 L; N, @4 y( r
* kset_register() has been called, call kset_unregister() and the; n9 Q1 J" T1 M% Q; @
* structure will be dynamically freed when it is no longer being used.
4 u4 `  V/ Y0 G! @7 L! E2 U% \9 ^# w *9 i) i2 G' f3 y
* If the kset was not able to be created, NULL will be returned.$ h  y  ], T# K
*/
- k! L* n! A6 q3 d( ostatic struct kset *kset_create(const char *name,) p7 b4 A' I% g, u: q2 ~, O5 H
                                struct kset_uevent_ops *uevent_ops,
/ h2 n* w- K3 r  J2 K0 G                                struct kobject *parent_kobj)
0 G7 z$ i' B- s5 _& u: W{7 y; O4 e. V( Y& {8 j' r
        struct kset *kset;
& e& z5 E% g, v1 I4 }. M1 M/ M# j  v- c( l: o7 W
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/
* _' B0 _# d  j  Z8 e! i+ y        if (!kset)$ V# j" b6 n" N& Q- l
                return NULL;& B5 j0 ?# u/ |" T) `! u
        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/
- }7 T) b: ?/ M& I        kset->uevent_ops = uevent_ops;
, }: \# S. e. n0 R2 w0 j        kset->kobj.parent = parent_kobj;        /*设置父对象*/
" x: L* G" a  k$ h0 l8 v) ]( C; J# `; }, E  Z" [
        /*
, k; Y4 c8 l. P& o" R/ b( s, R/ |2 }* S         * The kobject of this kset will have a type of kset_ktype and belong to
; W$ ?, p  P* a) \" j% W- V1 K         * no kset itself.  That way we can properly free it when it is4 _8 w7 U- ^; E! F, x
         * finished being used.
1 f& v, B+ S: a8 _! E         */$ |+ E! D' P! B. E
        kset->kobj.ktype = &kset_ktype;
4 C; s$ }' L0 ~* U4 J# y% V. p7 r        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/6 x0 t, {7 C: H  i9 Q) S
# C  ?" X/ x- Q2 H3 }
        return kset;* P1 o0 A' i& s9 b% j
}
- |. x. f0 r" j4 P& F
: E* U* d& K- e8 z这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,$ ^, M( s$ B5 k0 ?' D
* k4 m; r7 g3 G# E$ M$ U, o
也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。
# k: s% c! F4 Y' W& c/ ~& d
$ w7 f2 k: q+ E随后简要看下由kobject_set_name函数调用引发的一系列调用。
4 {- M8 j* K5 Z! H' n
' C6 @6 D1 l( `( g) d/**2 S% F2 P3 |! j7 j
* kobject_set_name - Set the name of a kobject
/ P$ L( P* J6 e * @kobj: struct kobject to set the name of) K; l' d8 M2 |: b9 Z
* @fmt: format string used to build the name
2 D9 w  q7 {) ] *7 l: Q5 W1 L8 I/ B1 l+ _( x
* This sets the name of the kobject.  If you have already added the- [: k' `, V3 z% S* S
* kobject to the system, you must call kobject_rename() in order to
& t2 D2 ]8 N" a * change the name of the kobject.
' x: m% X& y% \. a */
) Q& _5 s. ^- o1 \3 a7 Y. Iint kobject_set_name(struct kobject *kobj, const char *fmt, ...)
& q( [. D! G9 `, ]7 l& s: e{9 F4 k8 Q# ~- f1 V
        va_list vargs;. M6 q* K6 A/ K8 [# B
        int retval;
. g* Q& s  S5 |  o1 j2 \& z
/ i- n1 f- t/ @4 @  ^* A1 X! r3 ]        va_start(vargs, fmt);( B: c' z* s: T  m1 A6 ]+ N) E7 a
        retval = kobject_set_name_vargs(kobj, fmt, vargs);9 S; H8 K' K8 E: _- p) K6 W$ q
        va_end(vargs);: u$ _6 `! Z- ~& z  o3 H

) K- C3 a* j5 v' W) Y        return retval;: E. P3 s0 D$ w( O  Z
}
/ e4 R1 c" \% p4 \' v! m0 Z% W3 e9 Q7 H' h0 u" y% P; a
/*** {" w' O* {( X+ A7 \: X+ v
* kobject_set_name_vargs - Set the name of an kobject
% X8 R! f7 y( O- R4 k/ h5 A * @kobj: struct kobject to set the name of
: {5 x' ?3 x: m, v0 Q& @! l * @fmt: format string used to build the name5 k/ L# W" u' i/ c7 M$ G
* @vargs: vargs to format the string.: `; m9 r4 L: R" G. V
*/
% b$ d8 n" Z0 l2 v. Cint kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
4 T/ ]7 a' |4 d- O+ O& J' Z                  va_list vargs)- e, y% y# C! s# s- w; c0 z
{* Z5 w2 ]7 |: S& G( r  A2 _. \+ L
    const char *old_name = kobj->name;) H4 K, C: S/ J
    char *s;. t+ j6 n9 h5 o3 }
3 z. f7 i# [% m
    if (kobj->name && !fmt)
0 y! t$ o* K, ]        return 0;
* f: Y6 @) ]4 G# G+ g
: q" k5 ^7 J; k& G+ w" W    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
9 i9 |5 o2 y+ ^" i  i& Q    if (!kobj->name)
2 K$ f0 S$ E3 r: o4 ~        return -ENOMEM;
) f6 E* E* A- W( r; W. b% K  F& o3 u4 d. d# q  b* ?  @
    /* ewww... some of these buggers have '/' in the name ... */
! d5 F* l. ~5 ~( t0 g& K    while ((s = strchr(kobj->name, '/'))); }- {7 G! U) {* u% ?; e1 c* g
        s[0] = '!';
. F; T2 @6 k* f# `" Z* I- @' d6 N9 o2 P4 t& ?* I, r3 F. g" p
    kfree(old_name);
' T0 o# x+ l9 S9 w7 q    return 0;' H" ]* M% Q/ ?* ^3 U' {2 c0 s: I
}6 ^3 U3 g1 L: F( L
8 @0 S$ ~( d# \% g
/* Simplified asprintf. */
2 m/ M# m5 j. B$ s0 [char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)8 e9 K" N9 `: o( I2 X& x; l
{& B& U5 Y9 {$ u) i
    unsigned int len;
; V* R5 _; [. W* L' S+ C8 q    char *p;$ i  Y6 e' Z1 c0 N, R
    va_list aq;
" b9 E2 w6 B, q% z: k5 u6 z4 `% }- e1 n( B: I2 N4 R
    va_copy(aq, ap);
+ `) s- J+ ?; x    len = vsnprintf(NULL, 0, fmt, aq);% \$ b, I4 O$ U" I6 x; F
    va_end(aq);2 N7 ~* }9 T( `* ]

- ^2 e( t: C/ f0 O: W* V* y* G9 ^$ E    p = kmalloc(len+1, gfp);
: @9 ]1 q; f2 A/ k    if (!p)
9 r9 J( N. G3 G5 a        return NULL;- j, J+ p' P" Z
0 |; y9 G* r( C1 L/ g/ a
    vsnprintf(p, len+1, fmt, ap);
8 _9 s3 ]9 a$ k1 u
! Q0 P+ O0 s& ~# ?# S    return p;7 {9 ^# B# K- o9 l- e6 D
}1 s# [( P; G4 }( `! F8 ~
3.2 kset_register+ U- c9 n8 K+ m- B( u% U& U
下面代码位于drivers/base/kobject.c。
3 b/ d8 q9 Y8 w; g! Z8 H/**
& t6 G  `% [- x * kset_register - initialize and add a kset., A# I# S, c. G  K
* @k: kset.
$ g. k' m' K, X" D */
$ P( `' ]( L" }- P; R) t, Fint kset_register(struct kset *k)
! n- T, a# [* U" O+ ?{' Q! S$ Q6 y6 Q3 G! M
        int err;
9 F% x, ~8 I' u3 V/ R' k9 Y8 M; P1 s8 f9 w0 A7 h+ I
        if (!k)
- q$ w& x" w$ S) m                return -EINVAL;9 Y2 E. q* [6 G9 \
; n, O8 o; j/ ^8 `0 u3 n
        kset_init(k);           /*初始化kset*/
. |( \5 X/ m4 E# S( T; E) G, W        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/0 c2 ?( r/ j: M7 n
        if (err)! W9 M# j. _$ w4 t! n  ~! P5 H7 @: G
                return err;1 d( |) n8 _5 e: U) a, {
        kobject_uevent(&k->kobj, KOBJ_ADD);4 N: Q3 L# z/ y0 s: F; q
        return 0;
) t: K6 r. p! e% M4 b6 w: ]+ H}+ [: x) y$ h8 S
这里面调用了3个函数。这里先介绍前两个函数。$ @3 V% b7 e+ b9 R7 O5 \
) ?; i# g5 B: \: H6 z
3.2.1 kset_init
% E' X6 j/ c, _( A1 x  该函数用于初始化kset。
0 _; m5 q7 \: n
8 q3 K) U& T7 ~0 f8 w. `  下面代码位于drivers/base/kobject.c。
' o+ O' f& R% O. L1 c$ B* e
: I4 E& E2 s. q; F2 e3 k7 B# `/*** j2 F# V+ L0 F8 Y2 P
* kset_init - initialize a kset for use2 T4 ]" R' g4 o' G  n
* @k: kset
9 b; M9 S( ?, Y& M */6 z# s* k; q; D" I! N2 N7 b9 G6 z2 `
void kset_init(struct kset *k)2 q. b) \9 B" h+ A) r! v
{
/ n6 |# a1 \& s, C. e3 s0 X' S        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
- k+ `+ r) ]% y  ^4 O+ ?0 ?        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/
( {* S+ H- z/ K: A- H        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/+ y0 h- V- N! @# _+ t( a# e% t
}
; T. n+ o: \( G& n" V* R' {$ f) a4 w8 `- {4 D
static void kobject_init_internal(struct kobject *kobj)
; x" Z) f5 l( }{% u; @& o' n& }% I4 p7 o9 f; t
    if (!kobj)
/ z1 R# V8 f7 F4 _- g! Z5 q; l( T        return;; V1 S, M0 L* I, z" o( I5 [
    kref_init(&kobj->kref);           /*初始化引用基计数*/
3 R4 h* ^% t% A- X    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/- Q: H( A" U9 h$ J  ^
    kobj->state_in_sysfs = 0;
# T  S- P0 o, u0 A7 r    kobj->state_add_uevent_sent = 0;
5 R7 O" |  x  q7 W) \) C5 |* n    kobj->state_remove_uevent_sent = 0;7 E' e# c+ H; \: t
    kobj->state_initialized = 1;( Z4 P& Y2 ]' J
}
+ K$ Z  Z8 Z8 R6 h( A6 g3.2.2 kobject_add_internal
' {' {& U) D: r+ ]7 t: |  该函数将在sysfs中建立目录。
- J' Z  b* a* {& K* U$ I. `( C
( a) G4 W# R; r5 q  x( N) T4 d 下面代码位于drivers/base/kobject.c。
! B( G/ ^, d' r. B$ }) @static int kobject_add_internal(struct kobject *kobj)
  A  |2 G# ?# c7 }4 F{
8 B/ U0 Z; u* K( X5 c        int error = 0;# U# H  S0 n5 T. K. C; `3 [
        struct kobject *parent;2 E6 l/ [7 Y$ {7 e, z  Y3 m
; P8 M* v9 s6 F; r4 h6 e
        if (!kobj)
# k2 C# Z/ J$ k& W& o                return -ENOENT;
7 u* B% I. B) A% E' ]        /*检查name字段是否存在*// n0 Z0 r* K. m1 |
        if (!kobj->name || !kobj->name[0]) {
/ `% y& r( k# V- F' p3 B                WARN(1, "kobject: (%p): attempted to be registered with empty "
1 a. b- {( T3 b3 n& g                         "name!\n", kobj);
# k: A8 I- g; P# o! D                return -EINVAL;
* t; \6 C) X* O/ [7 {  U- J0 t7 z6 B* x5 L        }1 `1 Z; [2 f0 g: |
3 y+ _7 `  [) N
        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/4 ~; Z. \0 B0 s. R* V

8 p. U  f! A& q* H% K3 k        /* join kset if set, use it as parent if we do not already have one */5 z" [: i/ U9 F7 v# C$ {% u
        if (kobj->kset) {        ' W' k) m6 I1 M9 G
                if (!parent)
! k( s* n: Q, E5 a" A) U' D                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
2 n: J+ |. r8 _# O  p: ^                        parent = kobject_get(&kobj->kset->kobj);
. B% l1 U7 z/ [( c  W& v, z                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/
6 x5 Q+ Y# D1 h: ^: l: F                kobj->parent = parent;
6 H+ R  G; i( @        }
& e3 d0 N7 F. Q+ o
! b" K5 s5 B, D6 n- c, d: C$ v        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",7 f7 r' Q+ Y* c+ W
                 kobject_name(kobj), kobj, __func__,& x( I, C- ~9 a5 F0 D
                 parent ? kobject_name(parent) : "<NULL>",
( z$ F% s- H2 r$ |5 o- s0 x* `                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");$ O& Y9 Y" t. Z: k* q( @" [5 c
/ X: j/ V2 O, W) X: G" \1 o+ }
        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/
% ?! [  o8 i* s) |8 x; k) V        if (error) {6 h# Z0 N3 W, ^' j' Y- z, J9 o
                kobj_kset_leave(kobj);        /*删除链表项*/
* u2 y& Z$ O5 z  y2 Z! r0 @                kobject_put(parent);        /*减少引用计数*/# Q: ~8 N( K7 M
                kobj->parent = NULL;
% `& f9 h$ p; [) g7 G/ t
2 o& ^0 W" f  e0 w# t/ Z1 M- D                /* be noisy on error issues */- d, J7 o! E& K6 z2 Y
                if (error == -EEXIST)
  \9 T) W/ z6 b; _; b                        printk(KERN_ERR "%s failed for %s with "# Y7 G# ]9 m3 {2 I3 t- A
                               "-EEXIST, don't try to register things with "
% a7 P$ H9 S$ K4 C& v  @& V                               "the same name in the same directory.\n",. r8 n7 O  h4 A& n$ ?
                               __func__, kobject_name(kobj));
$ X) v( b: b  U4 m                else* C& r8 A  J+ W9 d
                        printk(KERN_ERR "%s failed for %s (%d)\n",
& i4 |: W: V3 P! e7 O4 w$ l                               __func__, kobject_name(kobj), error);
6 F7 a5 K& o$ Z+ M; i4 C5 {                dump_stack();- ]& E6 v# {3 T7 l
        } else
  W4 P( w1 ^4 h% l5 ?! l$ C# r                kobj->state_in_sysfs = 1;
" d# G: t% f9 N% ^: d& S3 [% {
+ f. r/ h" S5 z4 q4 o1 \9 S        return error;
. ^7 B  X- E7 D. H}$ {5 m% n! b3 U/ t/ T
8 E$ Y; L4 G4 |: u$ J$ d% _
在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。
# [0 s7 @4 Y$ \$ @8 V; M5 q0 n( _! h" A& R1 ^
在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。, U; H6 }' t5 Z: L

2 d" R. a1 O9 N% F# N* \  V2 p至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。6 N8 t; J: Z; k4 z
1 R  N) N1 E0 u
4. driver model( ^- ~% y. R2 V3 n* w
第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。& {" }- Q+ P" Z1 U1 ]+ ~; @4 `1 ~  h

' |$ Y, o4 M8 ?Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。6 k+ M1 x# `: r
3 K' L5 S9 Y: v/ N
这个属于分离的思想,将设备和驱动分开管理。
+ Q. _8 w6 H/ z# ^
& L# m$ V2 A: N: v0 |# u同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。
/ f2 w" @! b: h: i5 q1 [' u9 b/ `) }. h+ n# V
4.1 bus
7 Q, c* ^6 [) D- A2 k8 A  X  t4 I总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。2 x, ?. y  n2 \3 I
0 L( q* l% Y# N& V, A
下列代码位于include/linux/device.h。
  N: s7 v# W2 w2 E3 `' w6 Q& w0 K* I  j6 A8 F

) x+ b1 x. j; u* Mstruct bus_type {
6 T1 J# Y- B% `5 M+ ?    const char        *name;! u" f. \% M  Y
    struct bus_attribute    *bus_attrs;" _/ ]4 A& N+ }4 p
    struct device_attribute    *dev_attrs;9 M8 F7 i( a6 O8 D' P9 }
    struct driver_attribute    *drv_attrs;5 W% y) A9 b$ p' L( A2 }

. x2 k! I* T# F. V3 u+ P: C    int (*match)(struct device *dev, struct device_driver *drv);3 m) R5 C, j7 E
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
" I* L0 }) I0 @3 V; t    int (*probe)(struct device *dev);, s0 p( ~8 o) \) s: j3 z
    int (*remove)(struct device *dev);
1 y4 G" q  e. T& y8 i" T0 W    void (*shutdown)(struct device *dev);$ G0 o4 Z; b9 M3 f
  F" ^1 k% [' U0 }% F3 k
    int (*suspend)(struct device *dev, pm_message_t state);
( p3 k: _; z/ @. e! g' D- @9 k    int (*suspend_late)(struct device *dev, pm_message_t state);
! Z: X, R4 r  `  N    int (*resume_early)(struct device *dev);
* n& n! G3 V% q    int (*resume)(struct device *dev);2 e, \( M3 E: \3 ^" w7 y  i

9 x( a1 G2 i5 s# m% I+ {, i& {    struct dev_pm_ops *pm;% g8 G* g) R# M8 O7 k2 x

9 s7 I, {: {% x    struct bus_type_private *p;
$ g: j' ^) ?) {2 T( R( d4 d" u};2 a9 d- w( R: t. N  U9 [/ [6 a

9 @! P5 X5 b6 x+ c5 o/**
# w+ I+ F8 R; ^5 E& X. h. q- R5 { * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
) X+ W& f" ?. g3 d5 j- a *
! d4 y" s4 f, R5 ^- Z' S * @subsys - the struct kset that defines this bus.  This is the main kobject# H0 B6 M& U4 X2 [3 ^
* @drivers_kset - the list of drivers associated with this bus
0 o- P3 W  x. f4 f * @devices_kset - the list of devices associated with this bus
; S4 c2 ?! t- y# C* | * @klist_devices - the klist to iterate over the @devices_kset
) T+ G6 u: Q% B6 \/ {6 H9 f * @klist_drivers - the klist to iterate over the @drivers_kset9 L$ M' j5 H: b3 |
* @bus_notifier - the bus notifier list for anything that cares about things# P, C; U! p/ m! s
* on this bus.$ D# I6 C  n. s# i2 A0 x
* @bus - pointer back to the struct bus_type that this structure is associated
  J6 ?/ |5 h' N  ^8 `+ ~  b. ? * with.
' x' F" x; R3 T" r, J2 b. j, i *6 o! `; a! a9 K+ A2 {! w8 w
* This structure is the one that is the actual kobject allowing struct
* ?: ]( L0 Z' X5 L1 T. s! Z" x0 o * bus_type to be statically allocated safely.  Nothing outside of the driver# B9 g% A( C, Y  K1 K
* core should ever touch these fields.  |7 C) G- {+ T" L9 X  C
*/
, e* Z/ u' m9 x' `7 g- i0 xstruct bus_type_private {
8 f# t+ G) n% m2 D( i$ m    struct kset subsys;
$ s& O8 t$ ?! [8 d6 V" J2 S    struct kset *drivers_kset;" ?" H9 {. p  x$ b  a# T/ a
    struct kset *devices_kset;
. T& d) m4 k1 J0 ]# R    struct klist klist_devices;
9 N( U1 ]2 k7 v3 i" ~    struct klist klist_drivers;
! \3 y- ?7 d7 h5 M/ P% v  @    struct blocking_notifier_head bus_notifier;8 ?/ m9 L' I: p! I$ x
    unsigned int drivers_autoprobe:1;
5 k" w8 `9 U2 O! H- ~5 O  v7 d; Q) a    struct bus_type *bus;& c+ G$ W" x! R  z+ {7 V
};9 @# b( U, s/ s" ?0 j3 _/ w6 h
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。
! [0 G9 J: w7 w0 O2 c" S% Vdrivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。; ?3 d' v! Q- x* ^+ @
8 _0 R! W* H& a) {% h% G: x
同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。2 \  u" J! m. V( x. v6 J" O5 z5 E. j
) X, i* S4 [) [4 ~! y+ r
4.2 device5 ?0 k( R# p+ K
设备对象在driver-model中使用struct device来表示。
) C, W1 c+ m1 C; N- d, p) Y8 _% i. a& ]8 C$ x8 m7 W
下列代码位于include/linux/device.h。
, p1 f% K% i1 o+ w* Z9 Ustruct device {
4 ^# a* ~8 ~& ]( q: I' ]( `        struct device                *parent;$ D6 p* G8 S& X

' n6 C' \" `1 i1 J        struct device_private        *p;
% V) B% N* a0 a3 `7 f/ _8 T  P
" O0 X. s% ?+ V+ l" r& n4 \        struct kobject kobj;( H7 |2 |' z# B0 }! h- }
        const char                *init_name; /* initial name of the device */6 h& V' d8 d8 I7 J2 j: q
        struct device_type        *type;
- M$ q, i3 p$ U# U
. o9 m# v3 Q' v+ ]" v/ W        struct semaphore        sem;        /* semaphore to synchronize calls to- d" g2 G% r" n! `" a
                                         * its driver.; f. V: Q* f1 t$ }
                                         */7 I- q( z2 Z8 `, Y1 N

. m3 L$ x+ A8 c8 l! |7 z1 S        struct bus_type        *bus;                /* type of bus device is on */
. j+ r2 p6 \4 Z3 f; l8 |7 B        struct device_driver *driver;        /* which driver has allocated this
6 O5 c" a- g+ {( Q9 W& c                                           device */
8 \4 p# l, H! [' G8 ^$ ~7 ]        void                *driver_data;        /* data private to the driver */1 {# {# H; v$ G) N! K5 d
        void                *platform_data;        /* Platform specific data, device
: |, Q1 x' m  f( T                                           core doesn't touch it */. B' J- n# E4 r2 p1 R4 b
        struct dev_pm_info        power;
! Z; s' _, H# ~* w/ u
, B9 h. S* M* h+ {; [+ q#ifdef CONFIG_NUMA) j( a1 {! E* o' \! {. _$ }0 \( a) E
        int                numa_node;        /* NUMA node this device is close to */
7 Y7 H4 t  j, C+ O+ O#endif- M/ F, Q) G4 o& O
        u64                *dma_mask;        /* dma mask (if dma'able device) */& L3 K$ J! l4 V) h3 [+ Q
        u64                coherent_dma_mask;/* Like dma_mask, but for
( E# k) @1 l& h$ B7 s- U" U4 t2 \+ k: Q                                             alloc_coherent mappings as) R9 p. B' g+ H- i
                                             not all hardware supports
$ j/ R/ I& v, S. |) Y" l                                             64 bit addresses for consistent
, p6 P/ E* J$ ]/ F                                             allocations such descriptors. */
7 W& y6 V2 p( x
* P8 z+ m1 ]+ B( D3 B9 j" @" E        struct device_dma_parameters *dma_pARMs;
1 ^' |' @$ k! I1 g- U! m
" S! t2 K* H+ K$ u        struct list_head        dma_pools;        /* dma pools (if dma'ble) */: o- O$ C! T' G8 Y: X* n- _, ^% R
' E0 q3 w& ^* Z: X5 L# b, f- x
        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem
" q5 R- K0 L7 ^  Y                                             override */
2 b4 m; F+ o# g7 b. d- f        /* arch specific additions */
. Q; E( B, p' \- U! g        struct dev_archdata        archdata;
& y0 b. g) G2 Q6 |" a9 a# b2 p! Q0 G+ ^1 B2 p+ K3 p) Y7 m' w! C
        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */: z# a5 D* h0 Z2 {" a1 c
8 f! _. [4 k# m6 }# R: k" ]1 D
        spinlock_t                devres_lock;# e4 @! I6 j" E( h8 g' v
        struct list_head        devres_head;
3 |- Q: h0 A9 e) s# y- P8 _5 s) ?' J9 U- K! z* c0 y& G4 j
        struct klist_node        knode_class;8 y$ b" ?- q7 {, @0 H
        struct class                *class;
6 ]& y. P- y9 N4 i, u2 Z, N        struct attribute_group        **groups;        /* optional groups */$ J9 v" A  U% }6 _# D
( Z2 z3 s3 ^+ s! H6 I  J, v4 V
        void        (*release)(struct device *dev);# J8 }% Z$ \# {- x8 q7 _) w) I
};  r% l5 h& _7 s
( t  E1 G9 h8 p) x3 G& D9 K
/**# o! ]' ]# o5 T3 E) R& p- k  F) \
* struct device_private - structure to hold the private to the driver core portions of the device structure.
3 I7 L( F' E/ C  j *9 q1 q! @+ [4 I( f+ g, S! O4 r" ~
* @klist_children - klist containing all children of this device
1 \* _0 q: Z! T * @knode_parent - node in sibling list$ k) k9 R+ c( P* A/ i
* @knode_driver - node in driver list
+ ?7 ~4 R2 M& [' U * @knode_bus - node in bus list0 U3 T' u% m" p9 a/ r; w
* @device - pointer back to the struct class that this structure is+ n6 L3 n! a$ s$ j  n' X6 b
* associated with.
! r1 e  n; u: {- Z, c8 E *
3 q9 V( g5 N" g, \# i8 B- N5 p * Nothing outside of the driver core should ever touch these fields.
6 B" k8 @: P# W1 Z7 E3 H' w */
% W0 _  u9 I0 n% d8 Kstruct device_private {9 E# H5 t3 h$ W8 V2 h
    struct klist klist_children;+ q; g) i3 ~/ e/ O) o; a
    struct klist_node knode_parent;' P0 v# ]6 k% M0 ^' i
    struct klist_node knode_driver;
1 ]4 G- U# S0 C6 F    struct klist_node knode_bus;+ P4 A& \  J' S$ B
    struct device *device;" K* H% x0 ~; l0 K4 P
};! p- j& v* J  ~( T; t& f
device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。
* E/ M% k3 n* c' r" N% M9 y2 }' E$ @: L+ r$ t) H- {/ c8 M
该device所挂载的bus由knode_bus指定。
/ k3 h2 K. x5 D1 [7 D5 ]) P. F/ O0 Y  g! r' s: k+ c
该device所对应的设备驱动由knode_driver指定。% c' [4 o0 @7 e1 H' T
2 n1 D" x: k. j0 D' t7 j- o
4.3 driver0 W+ w* |! A  L- [
设备设备对象在driver-model中使用struct device_driver来表示。9 e# f1 n! @  Y/ z
, `: U3 d/ X4 _. k  s- v
下列代码位于include/linux/device.h。& K. J+ {- Q$ y: J7 }& t
struct device_driver {  S- ^0 z8 G2 z- c- B' u) U
        const char                *name;
! _* b& _, a  p- W! {$ e        struct bus_type                *bus;1 e$ T+ E: l" P  X5 M

0 |# w/ C; q# s        struct module                *owner;
) G6 r- h" M4 u0 E& d        const char                 *mod_name;        /* used for built-in modules */; k9 |# u8 R/ d+ n) e
  e) d/ r: v: `5 P3 F
        int (*probe) (struct device *dev);
- ^- E8 A* \0 {7 D$ D        int (*remove) (struct device *dev);# e" j- j( i; j( o. K9 L. @7 F$ k
        void (*shutdown) (struct device *dev);
  U6 r7 y7 e; c% E" x% n        int (*suspend) (struct device *dev, pm_message_t state);& _2 H+ L1 z' w0 V4 e
        int (*resume) (struct device *dev);1 y; S( i: ?# u
        struct attribute_group **groups;, ^9 p: S* C' ?8 R' q) c, H
2 u' g  I$ G1 C8 {, d" U4 M# {
        struct dev_pm_ops *pm;2 [. `" f8 R# P; y, \0 g

. _- _3 H) Q$ P) _; m        struct driver_private *p;8 j' V2 o: y7 C9 B/ L0 ]
};
# W" z: u, u  K: ~
) a+ ~4 t- G2 G5 p9 v3 Rstruct driver_private {
$ I/ k7 p4 ^, Q, m/ S2 y1 e; g" G    struct kobject kobj;  q1 N- }9 q  E
    struct klist klist_devices;+ d& V' e' }( A5 Q( Z
    struct klist_node knode_bus;/ D& n; a4 }. l7 `/ |  S4 D) u) ~
    struct module_kobject *mkobj;
. l8 ]/ L: e# t/ t    struct device_driver *driver;
( `8 o) I% _, l) I}; + f; |* \6 C7 H4 I+ `
device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。. @/ J7 y' ~* G; ]- M
该设备驱动所支持的设备由klist_devices指定。
/ P1 m$ B" L( N: K( P. H4 l
7 {9 `0 I1 }: i3 C该设备驱动所挂载的总线由knode_bus制定。1 r: f; J+ d+ N3 k
% U+ t+ ?; \* F
5. Bus举例
1 Q9 Y# n. y8 ]& J本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。5 M, }! P- `1 H* e2 ~- y8 K

, f5 B6 ~. f# R7 B( N$ j2 }platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:. I3 j& t4 i5 J: b, {; w  B+ J) v
3 g. b3 n4 N0 U' z
start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。- g2 m1 v2 R% w$ t
& n4 U0 O' q- v
注:kernel_init()是在rest_init函数中创建内核线程来执行的。5 J+ `4 U( T: C9 j4 |8 \3 ^5 s; m
: v6 p6 ^6 Z: O7 X- O- M
8 L7 q9 V1 b/ Y

/ Q& b: ?0 p: A" ~; F  Z6 f) u. nint __init platform_bus_init(void)
1 q* Z" N; h6 U7 g: D6 d* k. `{9 h: p7 M8 i0 T4 Y
    int error;
4 O( s  c3 r+ S) I0 W; _5 R" M# W6 `- Z# i7 |
    early_platform_cleanup();1 C3 [+ U) v6 k
6 T6 b/ _% W4 d& m; s, p5 R# t$ u
    error = device_register(&platform_bus);/ k" i% ]. A4 L) f# y7 Y+ o
    if (error)) Q8 S  y8 b" c% ]" v/ n7 E3 T
        return error;3 c  |/ I! F6 K# O0 f
    error =  bus_register(&platform_bus_type);
, K3 W- F2 o9 b    if (error)
- p1 _2 {5 L5 \/ k' L* h$ t; Y        device_unregister(&platform_bus);$ S1 n' m; h: ~1 t7 Y6 O! Q. \4 o
    return error;, Q( Y( @9 I- Q
}% K$ z# K4 K8 J+ X% v' p
struct bus_type platform_bus_type = {
! ^- P9 \! l0 }) r- x/ Q& L7 H4 g0 a        .name                = "platform",
' R9 g- I* C' _0 }+ j        .dev_attrs        = platform_dev_attrs,
* E, ~6 ^$ e; {- t" h2 x# C        .match                = platform_match,
7 ]$ m0 f/ u: l! Z0 f* @. |        .uevent                = platform_uevent,' t( T4 G. }1 g6 J/ _- A) e& G
        .pm                = PLATFORM_PM_OPS_PTR,
. W3 m& a0 N) `9 K};
" ?. H5 `, _; YEXPORT_SYMBOL_GPL(platform_bus_type);) V( ~- T8 T" h$ d/ a
从bus_type,我们看到该总线的名字为platform。
# D- s2 `3 z7 J" S  N7 ~! u9 F6 p调用了两个函数,我们只关注bus_register函数。+ Y' o8 g. o# x' v- Q& b+ p9 h

$ z8 W- Z& W. I( D5 P# m: o% j- c0 m& D
/*** t* M& q+ s: \; h
* bus_register - register a bus with the system.' d$ `7 ~' Q: L, @
* @bus: bus.
: e4 {; o7 c) [  x! q; l! v ** e6 T" n9 t2 ?- O4 z/ T
* Once we have that, we registered the bus with the kobject
: X3 w2 C0 w7 R! E * infrastructure, then register the children subsystems it has:4 j3 z7 c# \' V8 A
* the devices and drivers that belong to the bus.
  {+ l7 |& e1 t: f6 U; ?# a */+ T1 L9 Y/ }" W3 Y: _# F+ H
int bus_register(struct bus_type *bus)
; q. Y2 c; G; S- d2 B{
& \+ f, |0 |# j$ o7 s$ q0 p8 u8 _        int retval;
: g1 o/ g+ e  J% f- S4 ]" ?' D' k        struct bus_type_private *priv;
: M! y3 D/ g0 S
/ r4 a3 ?6 @, B* F: M        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
4 D4 G/ X8 s) m$ f8 k* S        if (!priv)
4 z% O# Q4 @' B8 G1 O                return -ENOMEM;! ~; G6 c. U7 z. W6 \0 d& E3 |
        /*互相保存*/
+ r7 w; ?, ~, i4 C3 ]& E/ V1 v        priv->bus = bus;# o& }* x% K) d& o
        bus->p = priv;" h; R9 C, T9 Y* n
! w8 K" k  ^" [/ o/ j
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
" Y' n# E3 i) s" h, d+ c        /*设定kobject->name*/
! s4 T# y. P5 A6 d- a2 u        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);" @5 F) R' m  A# j  F/ `0 Y/ O
        if (retval)9 z9 m, g, n& c0 I0 j
                goto out;
, V3 b8 E* _6 e3 ^' Z% k+ ]7 S! \
7 l$ f9 d* s5 d, o+ @" n2 u; c        priv->subsys.kobj.kset = bus_kset;
7 [) A/ @7 j$ I0 S        priv->subsys.kobj.ktype = &bus_ktype;8 z( W9 Z5 ?! Q4 I
        priv->drivers_autoprobe = 1;
) x) \3 g" l% X7 s2 V. x& J; B
        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/( \- o9 g/ n  b: e0 u
        retval = kset_register(&priv->subsys);       
! h; O4 h$ ?# a  y4 R' v        if (retval)- t% P& [- ?1 _6 t
                goto out;
' U+ W% {! ~9 Y- L( g5 a' _" d" }* M( L: L. x- X
        /*创建属性,在bus/XXX/建立文件uevent*/. l8 T6 O. `2 i: W. R& l. Q) H
        retval = bus_create_file(bus, &bus_attr_uevent);
. P/ X& v/ G: K: s+ N9 e        if (retval)+ g; |% V) u, V
                goto bus_uevent_fail;
4 S' }+ D; t( P' R& G1 L  e9 d/ d" @+ y
        /*创建kset,在bus/XXX/建立目录devices*/
! ?3 a7 F8 ?" k+ e        priv->devices_kset = kset_create_and_add("devices", NULL,5 e  M* z& E! n' ~  _7 G$ o+ r
                                                 &priv->subsys.kobj);! X' @8 x" r( x/ J5 Q6 ~
        if (!priv->devices_kset) {7 F6 i& a! z0 {1 x4 {
                retval = -ENOMEM;
; y: j" D6 A1 \) g' p; }' `                goto bus_devices_fail;
2 p0 x. o1 f7 \8 m( F+ c1 }  q        }
& H" h9 e$ W, h% K; I8 l
, Q$ L4 W- B0 j) _$ Q( K0 X        /*创建kset,在bus/XXX/建立目录drivers*/
& ~' K% M# Z0 u' L4 X        priv->drivers_kset = kset_create_and_add("drivers", NULL,
5 D$ Q& A8 z) ], ?( m4 m& Z. _* x# `                                                 &priv->subsys.kobj);
5 Z5 E* y# V; S6 C9 S4 ]( t        if (!priv->drivers_kset) {
! [0 q8 w& g' H$ M( |                retval = -ENOMEM;
2 |2 {; }+ N1 W5 O# m1 n8 t                goto bus_drivers_fail;
7 W  s) P( i0 ~1 Y# M        }/ S- i5 H- s( o& q# Y  x  m
        /*初始化2个内核链表,*/9 a  I' K+ K; M- M8 V; q7 ~
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
' M$ X2 R3 }, R8 t& `+ t" p0 w        klist_init(&priv->klist_drivers, NULL, NULL);
* i7 H9 ^( P! E& D) b; w
' m4 m; |' U5 f$ n/ M        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/
% J" n" Z1 g* _" e1 v1 p9 \0 p        retval = add_probe_files(bus);
9 c& b* S, g+ @% H' n* P: n        if (retval)5 O" c- Z7 k/ B8 C' |
                goto bus_probe_files_fail;
0 M. h9 a" t2 p4 P6 N( v        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/4 _  b" S+ E4 R2 T$ U7 P7 I
        retval = bus_add_attrs(bus);6 j" v; M: W! `; j$ n
        if (retval)& f- i0 p5 _5 s! G- G3 B2 u
                goto bus_attrs_fail;6 C5 ^- }- V* k% A0 e3 s# e
+ @/ z: @2 R& p! @5 ~
        pr_debug("bus: '%s': registered\n", bus->name);
+ l( @6 }! N/ _3 s; n: g3 C        return 0;
8 o' b1 R0 x& B: b' n
& s% `4 R. @6 K  ?: n! I! F0 Lbus_attrs_fail:
8 A$ A8 g) _; @( l& o$ j        remove_probe_files(bus);6 K: J5 L8 l6 q2 u
bus_probe_files_fail:
0 A' w: [$ S' z+ [. Z* x        kset_unregister(bus->p->drivers_kset);
; \0 F& O2 o/ T/ bbus_drivers_fail:
8 q% J5 h( [0 J* Y        kset_unregister(bus->p->devices_kset);$ R. [4 `& B1 U
bus_devices_fail:
& w+ f- e" R2 f: {        bus_remove_file(bus, &bus_attr_uevent);
; x" O; N1 h- p  L4 Qbus_uevent_fail:3 I( j7 p- j$ v! y5 k
        kset_unregister(&bus->p->subsys);
! g' e) V- P  x" S        kfree(bus->p);
0 N- d: ], G! D9 W  Nout:; B9 ]( }  ]5 F, b& y
        bus->p = NULL;) Z- G) v% ^' q3 r* @5 F" T0 Y
        return retval;
* @) z; F( u: ?7 [! a5 ]}
; z0 n/ z# p+ q' B3 eEXPORT_SYMBOL_GPL(bus_register);
+ ^, v/ o- Z1 W0 ?* u
$ N; r$ a( ]8 h' ^函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。
9 u3 E- l. }4 Z% c3 \, z在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。) j- t+ H9 i) z: Y
9 ?% s% l6 s1 S9 u
接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。
  Y4 l: u; z. K( T
4 k, y5 O3 w8 [$ o* e+ @$ c8 {紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。
  _2 x9 C  q0 q) @: W- A$ {2 A' g# C2 D' _
' \% k0 q: `/ _# R
/* add the kobject to its kset's list */% q2 p+ w4 C$ T* w( l. L
static void kobj_kset_join(struct kobject *kobj)
5 M: i, F* X4 z1 J+ O4 u( K* c: s{
4 X, H. D# [* P8 C* f7 y        if (!kobj->kset)
: _! i, [6 z* U) I& P                return;
% W6 N# _/ I, C5 R* g# i
% d; U8 a6 }  z; R, M/ L7 B, h        kset_get(kobj->kset);        /*增加kset引用计数*/3 q2 S5 M8 s1 W  D" W+ e9 }& }9 J" j
        spin_lock(&kobj->kset->list_lock);3 o9 T! D3 @* d$ y% h1 j6 G
        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/4 c0 n3 f0 A2 Q, `7 B; [& T7 b
        spin_unlock(&kobj->kset->list_lock);5 F6 O4 t2 W) I6 S" ]
}
9 A9 d& N2 [! a- w: e! c( ]! bkset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。
. Q+ T  @5 l9 V! P1 Z" a! x
7 B- w. N6 s  g, Z9 b- @- }
# O* T1 `! S( i$ E& ]9 k5 n% E/ n  X3 `$ F* b/ a& w( |: q! a
然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。" `. G" A' }6 G" x: c$ ]

; a1 V/ v7 ?! V4 ?' e/ v$ {int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
  x6 Y& H- Z0 y- v{% Y, p& @+ b5 X& G! {* z1 g. M
        int error;
" l1 Z. r3 f9 g) f* i3 [% t        if (bus_get(bus)) {* ^/ K3 H: b) W. M  |9 l+ J
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
, i4 K8 w& c0 N  \' V$ R                bus_put(bus);  u8 r/ _1 w( h4 E# a  B  _; v) D
        } else; S1 S2 |. U7 }# p# A8 b
                error = -EINVAL;  h' _; K9 ]; Z  B' `! X" @
        return error;
$ D& g) B! t9 E+ a9 u4 F}. B0 _+ B( U, s$ K- c
EXPORT_SYMBOL_GPL(bus_create_file);; I' L% C% O0 n0 j2 @) W$ c
有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
# P5 D; F9 x  ]6 v1 D6 q+ b接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。3 b0 L% v0 P4 e- w) d0 l
3 B1 E7 Y$ v# M6 r/ A" w: b+ T
这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。$ V4 o. `6 h, W/ D( G" N
% R! s* o8 V1 C+ ^# {! D
也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。) V. |0 @7 u! ^8 O. e8 m
# A' @9 f# C/ {) p9 v
我们来看下关系图:
5 \4 B) u9 p9 f4 ]0 e+ t
) `4 k) P" v% _4 I* _8 { ; s1 q4 \4 B7 U/ {
7 j; D* N! J9 K0 j: B/ |
随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
5 U$ H, T# ]: s3 q( ~+ L
- G! e! Z! e" S( A: gstatic int add_probe_files(struct bus_type *bus)
$ t4 W2 @, b2 U: s{0 h+ |4 `% h$ y4 W$ m
        int retval;3 C' U6 E8 Z4 g

( E, o( L4 Z1 e0 O% o! j        retval = bus_create_file(bus, &bus_attr_drivers_probe);: }+ Z6 [9 W3 ^. [7 I6 H$ L' j
        if (retval)
* g- `) ]2 |" |) P% N8 Z                goto out;9 L; Z2 ]6 z) R- O

4 o, E4 I" H, I- }% f2 E        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
$ O' a6 M: g& k# j+ \5 ^        if (retval)
0 t7 e4 @6 |' R4 S1 [3 f                bus_remove_file(bus, &bus_attr_drivers_probe);
$ c) m; \* i! k( w5 }out:
9 G& u, p2 W) \; t( T: f        return retval;  A6 D7 @+ m# }- W( {* P6 H
}
% a+ z* \1 A/ v; h该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。+ {& |$ w9 I, d* [9 q3 Y0 S+ D
最后调用bus_add_attrs创建总线相关的属性文件。
$ _& f  u8 P$ `8 G! }8 B# t% ~1 l. r4 _
/**
4 X4 U: ~+ ?9 E; l+ a( z4 i * bus_add_attrs - Add default attributes for this bus.
& A4 {9 D/ {6 |( a2 K * @bus: Bus that has just been registered.
& J1 J8 ?' D  S1 ?) {) x */
% t: n( e- [% U$ u* ~# u% o8 |* K' _( w4 L1 H9 E. E
static int bus_add_attrs(struct bus_type *bus)
" o' b3 l" R% K$ L& Z/ V1 _/ h  ?{
* L: x; B' C/ v* D* o4 d- T% v        int error = 0;
1 r; x5 j$ `  L' n2 }4 G8 _6 c$ V        int i;
* X+ Q, L+ y8 n8 ?1 u; Z. c$ J; i% a3 ~9 \2 M. G* \# \0 r2 Z" e
        if (bus->bus_attrs) {
" F: r1 z6 M' V" m                for (i = 0; attr_name(bus->bus_attrs); i++) {- X% R7 A2 |% d3 ^
                        error = bus_create_file(bus, &bus->bus_attrs);
9 H( L& i" T1 l                        if (error)9 Y1 z9 ?5 Q3 f8 u* K) |4 p
                                goto err;, ]; n3 H# g( [) y9 n" m
                }
5 N! q8 n4 t- A7 l        }* ]( T; L. G+ c
done:/ }: K% h; y6 L% A+ x7 y" |& `
        return error;
# J. {$ {% `7 e- g1 h- [1 K5 kerr:
/ S% U# I& a! ~" @        while (--i >= 0)6 F0 q  Z/ l3 F2 v0 B' b
                bus_remove_file(bus, &bus->bus_attrs);5 V3 y8 w. B& |9 f/ [
        goto done;
" Y( M+ ^+ U" b* y: }) ~}0 t8 m0 j* \8 O- n6 I: x8 c& @9 B  M
我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。
! Z: @+ p$ g, ?8 a好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。8 U" Z- l! g. }% r5 r. v. B
  X* A/ [" Z0 t, ^" |
[root@yj423 platform]#pwd( C: z% K! l$ v+ b0 W: _
/sys/bus/platform, v$ ?% w# k5 S4 D1 h/ r5 [' c
[root@yj423 platform]#ls& D8 s& _6 [" `' S; Q! W
devices            drivers            drivers_autoprobe  drivers_probe      uevent; i  S# L9 g$ V% L
最后,我们对整个bus_register的过程进行一个小结。
# U# o( w9 p( C2 V
1 ~; S7 B* Z6 T 5 ]/ q8 Z. ]7 O3 ]6 N' q& v0 @

% Y* p6 B/ c% c, P' z+ Q! O4 X6. device举例6 D( s' Q# y6 ]# n/ V& p
本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。
$ _, W$ D- u5 C+ H7 @& Q$ R: [$ `3 j/ G& X% u" J
6.1 虚拟的platform设备
0 A; D+ s/ ^0 l之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。6 o+ V; b9 [8 o! q
4 t( e2 y" ~$ I( r3 J7 A/ ^0 M5 I
在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。- u7 ~7 i3 Q7 @9 g6 \3 o5 ~
7 ~! j4 K7 M5 W5 M( T% K
int __init platform_bus_init(void)+ U! R: J( U0 a7 g$ z3 o; G
{  x- z% `$ x" s# S$ t
        int error;% u/ J" t1 z1 z4 q3 V

" `0 z5 C# w, d& e9 n        early_platform_cleanup();
. Z/ V7 v. O' W1 I( {. V* g  e" C4 R' z9 o: q: I5 v1 |
        error = device_register(&platform_bus);9 d( X/ l) M1 f" s/ B* [
        if (error)5 n; V8 }/ {3 f) b" I) `* P
                return error;' [! P1 U! T% O3 T! h( @- a7 s& U) G* ^) A
        error =  bus_register(&platform_bus_type);( |  N! S% F; w0 g8 F- T
        if (error)
& N+ E( \+ \/ E) W" v                device_unregister(&platform_bus);8 k1 U: g' `. d0 u, o
        return error;' P" @1 I) V; D8 _& b3 x0 h, |+ Q
}& c/ C' B5 [  R. ?
8 w1 A8 m' w5 I7 V2 \
struct device platform_bus = {
7 h) i" K  k5 K1 l, F* E- H    .init_name    = "platform",9 ~7 W6 O8 ~8 Q) y( p" D9 {
};0 L0 t! ?% V2 j$ c+ X
EXPORT_SYMBOL_GPL(platform_bus)3 [% P6 u! F, a# A4 n
下列函数位于drivers/base/core.c。  |# ^& [1 ]4 g
/**2 M0 L2 o6 c. E5 [0 x
* device_register - register a device with the system.' Z- F- J6 `5 V1 @5 o. F% Y" q4 X
* @dev: pointer to the device structure7 l4 [5 h# w4 {3 C
*! D4 w/ e: S6 k
* This happens in two clean steps - initialize the device9 z' q: i+ B5 j
* and add it to the system. The two steps can be called
  {* W0 |) V9 r' h& T * separately, but this is the easiest and most common.5 [) O, |6 l  Z8 l% _3 ^
* I.e. you should only call the two helpers separately if2 o8 }5 }: \% D; A. W
* have a clearly defined need to use and refcount the device
: n! M' t& K7 t- H6 u * before it is added to the hierarchy.4 t9 O/ x( I# f6 G6 a
*" w9 i: m5 e2 \6 r
* NOTE: _Never_ directly free @dev after calling this function, even' R* a8 K0 s* L5 o: Q) ~
* if it returned an error! Always use put_device() to give up the$ |2 U* m' O6 ?7 A
* reference initialized in this function instead.) C1 z/ `6 a( K; w2 a* }
*/+ C& K4 D6 p7 [1 Z# s# A
int device_register(struct device *dev)/ ]9 i1 h5 r) q
{
! ~) R! V+ m9 e: ~0 J1 z        device_initialize(dev);        /*初始化dev的某些字段*/
6 W' G- N! T0 m6 H7 ?  T- `+ e        return device_add(dev); /*将设备添加到系统中*/
& R7 o' S, i( n' z5 }' @" A$ ~1 W}2 r0 I! x7 t! M( Z2 y

: d3 E6 a& u5 u  q; b1 f一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:
* b) J. ^1 T4 C" `3 W0 c
6 [5 X# S* B( G, e' U. o; I2 \下列函数位于drivers/base/core.c。
% R7 E7 X+ w" d0 P; C/**! g4 [, G4 r: ^' }; b
* device_initialize - init device structure.7 `' S+ q5 ?/ [. Y
* @dev: device." `) K" d5 l( r# k' G
*
0 `/ K& G& T" T) g, Y( P! x4 I% q * This prepares the device for use by other layers by initializing5 a* L0 T9 \2 n, y, p+ d  G
* its fields.
- a7 N* ]5 l4 [) s * It is the first half of device_register(), if called by0 O4 e% T$ T- x" J6 P
* that function, though it can also be called separately, so one
3 v8 D& V) f0 f9 i8 K8 ~% O * may use @dev's fields. In particular, get_device()/put_device()
2 {4 q1 y9 z7 X2 S) D3 L * may be used for reference counting of @dev after calling this8 K0 V6 P3 S) @
* function.! [; k4 n) Z- I* H# Z* q5 V( h
*
" F9 [) x( @. I( `* U * NOTE: Use put_device() to give up your reference instead of freeing9 L" ~& T* J  I5 t0 U
* @dev directly once you have called this function.  N! ~# I% [, a8 c0 o+ Y* v4 k
*/9 I! N9 o' U! X, @; x" X
void device_initialize(struct device *dev)
. j/ u8 a6 h* M% t) C{4 T5 S9 C$ u% ~* e7 e3 n) P$ G. `  Q
    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/( m; \% b. g" o1 s
    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/9 Z- J8 f% v" w6 K5 \6 f' f3 ?
    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
* ?0 y% J  H; i" T! x' D' t" r* I    init_MUTEX(&dev->sem);                /*初始化互斥体*/
3 z* h) d! S3 T- I: A    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
0 A! s; q4 |; z" Q, o, I    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
7 m! g9 F: q! w6 h    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/7 N8 ?) o, @/ [- h7 Y
    device_pm_init(dev);                /*设置该device可操作*/
  h/ k* h$ ?8 {& d- a' {0 u    set_dev_node(dev, -1);                /*设置NUMA节点*/
+ q6 y( a7 K3 f# ~}- x/ J1 d, D! n
6.1.1 有关devices_kset" m0 r4 z6 x; s2 ^. z  F9 h( A& ]
首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。6 G# K3 u2 \0 s7 N
0 Z7 m' u$ |- w! z3 H9 {6 _
该对象的建立是在devices_init函数中完成的。; y& d/ D$ g. n; O! q
int __init devices_init(void)7 ]; W+ x' o- x6 _* V
{1 h+ i. ^# E$ ^. ]% n
        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);! Y8 G$ j6 R$ K7 Y' T" O
        if (!devices_kset)# z, _& M, c8 M. X
                return -ENOMEM;
; i) M, R: c1 {  e        dev_kobj = kobject_create_and_add("dev", NULL);) J3 U6 P: g1 m# ~" f8 Y
        if (!dev_kobj)) I+ a# b2 E( ]6 t  E" N4 M
                goto dev_kobj_err;* n1 B% I: a8 Q/ V  X6 J
        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);( m* i8 g8 x" d+ b4 T
        if (!sysfs_dev_block_kobj)7 @, d1 ?; I% J# U# U& A
                goto block_kobj_err;$ Z1 D/ T- g, l; D
        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
+ F3 x9 v. f2 n+ }8 n* l        if (!sysfs_dev_char_kobj)
- d' w  R2 Q  @3 t/ \                goto char_kobj_err;) y* w9 c+ M/ s8 L/ p! Q# P
1 l% Z: v. N" t1 O7 C" y# g* W
        return 0;% [5 ]1 Q9 z7 D

$ l. I' T# e2 H) I) v0 z; | char_kobj_err:
3 P0 ^) t, _+ S5 g( J7 [! b        kobject_put(sysfs_dev_block_kobj);
$ H/ j3 T8 r2 e. x1 d block_kobj_err:
; E% I. n5 e7 j, ]# J        kobject_put(dev_kobj);6 G3 k. g  E0 T8 I" X  [) E
dev_kobj_err:" a+ l% R6 [2 `. J+ C3 H3 ]
        kset_unregister(devices_kset);
' C$ j% o" D3 a4 J4 @        return -ENOMEM;8 f$ y) D) Q  p! P5 |' g$ R0 |/ P
}- ?( m  x- h0 T0 Y: l. l
由此可见,devices_kset对象表示的目录为/sys下的devices目录。" V& r$ m( \) o% \7 _
6.1.2 kobject_init* u' A6 l( Z. q5 G6 C, C
下列函数位于lib/kojbect.c。
6 F  l) Z2 J, @" W! \! Y1 e. T/**6 G; S: I2 j3 z# t
* kobject_init - initialize a kobject structure
. |$ V1 _2 |0 i# }2 F * @kobj: pointer to the kobject to initialize0 d( o$ e0 Q  y. V" b
* @ktype: pointer to the ktype for this kobject., W' G$ Q; ]6 c' f7 a) N
*
! I; D3 z+ v! G * This function will properly initialize a kobject such that it can then; _, S9 Z; |  g7 J, y
* be passed to the kobject_add() call.; P( a, C# g! d9 H0 J8 n
*3 S& `0 O3 h5 u/ ?
* After this function is called, the kobject MUST be cleaned up by a call
! [2 q! b1 W! ], w  a$ ` * to kobject_put(), not by a call to kfree directly to ensure that all of$ ^/ Z& |5 Z& i: E% Q3 Q( l
* the memory is cleaned up properly.+ E* b3 ~2 W; w5 g  Z; ^
*/( Q4 ]1 N+ o# w# ^& ~# m- @3 t
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  x  ~! ]) f3 h" K& p9 }
{
8 `) @2 E+ W- C8 j" {3 [        char *err_str;& {' N9 A  Z0 {
* H5 v8 k4 w, s, y. s7 d" o' k+ |& {
        if (!kobj) {
, j7 j) a5 C' J* i                err_str = "invalid kobject pointer!";
7 Y& d. j( L7 n) L. H& L* W                goto error;
" H" U- _* F- X3 b5 o& Z* Y        }2 V8 `( H  a# m& Z) A% S# i- d  o; O
        if (!ktype) {
$ ^( f5 s( M2 O" ?9 n) D/ g                err_str = "must have a ktype to be initialized properly!\n";
' A  K3 X9 \' s" Z0 k  w                goto error;8 C3 {& p' S: ~" o) L% f% o  S
        }
- b6 X; p; O% S8 O- a% ]        if (kobj->state_initialized) {3 x5 g1 k/ f/ a) o& e4 W
                /* do not error out as sometimes we can recover */
5 ?% Z: x2 K# |; j+ d7 Y) V0 R  [                printk(KERN_ERR "kobject (%p): tried to init an initialized "- e* w7 u6 \  x' Q$ x$ z
                       "object, something is seriously wrong.\n", kobj);
5 I# \5 g" R& @6 ~2 \7 t                dump_stack();+ x  c" l. ~* t& [; Y
        }
: u3 f: i/ X/ }5 T$ d* X& Z% Z7 E9 s. X+ U$ p0 N: O8 l- U( _
        kobject_init_internal(kobj);1 \. y; w6 Y! ^- V3 m- ~* T5 E2 I
        kobj->ktype = ktype;5 I3 @( q+ C" r1 J, L% |( e4 l
        return;
' j% s/ ?0 M% L4 Y+ j6 J, E, v' ~$ O9 |, @9 k' {7 I* \
error:
1 `. M. n* Z6 k' d# r; i; N6 Q: Z        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
0 L/ @& a" |0 j1 y' g- T9 `% N        dump_stack();4 M! g7 S. E3 i: g0 D9 ?( N0 R
}
! V- D9 N) S+ H4 _2 z  ?& TEXPORT_SYMBOL(kobject_init);
. i* d' P3 X1 n' c. ~, j# B5 f/ H! o2 @7 h
static void kobject_init_internal(struct kobject *kobj)
( j" ]) P( K/ f0 u% X{2 {/ A, B& ]3 d: N! @8 [# H
    if (!kobj)7 N* S6 @8 g/ ~# L9 T  O( q
        return;
$ G+ r0 v. r5 C- c0 `5 ]    kref_init(&kobj->kref);            /*初始化引用基计数*/
' m1 Y) x9 r% ]3 c    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/9 _- `& L" X7 H4 z- m4 r
    kobj->state_in_sysfs = 0;8 s1 v+ ?0 T+ W4 d0 [; t5 k
    kobj->state_add_uevent_sent = 0;
' |4 i6 w( x, a; D. h0 N5 V. J+ {/ r    kobj->state_remove_uevent_sent = 0;+ O0 j; ]; B; }4 I
    kobj->state_initialized = 1;1 Y: m- @; n' n% R& i
}
% |" S6 m# e& o该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。6 B) A: B8 |& P/ N0 u
6.1.3 device_init_wakeup0 Z( ^' t0 w% b" [* N5 Q6 K
参数val为0,设置该device不能够唤醒。
; ~% [8 p5 T' g" Y0 M) @. d- b9 G#ifdef CONFIG_PM
% M( r7 y0 g& T2 s, J! K( s: X* f' v: c% z" M
/* changes to device_may_wakeup take effect on the next pm state change.& e- r6 y1 I9 D6 \: ~3 Q7 _; g5 l
* by default, devices should wakeup if they can.% p' {& G* `% B/ E: P
*/
/ s9 A! F+ C: Jstatic inline void device_init_wakeup(struct device *dev, int val)% r, q5 H, }, @2 v: p+ M1 q
{
! L/ G" A9 \: r7 b- Y' `  n+ [        dev->power.can_wakeup = dev->power.should_wakeup = !!val;) f& w# ~( H# P* v+ C
}  e  S6 ]( X. s$ t( m, t
。。。。。。3 N0 l8 a% G, n, F
#else /* !CONFIG_PM */
' J# f4 r3 E, A/ q0 b( A" A5 x4 |; ~: x; A
/* For some reason the next two routines work even without CONFIG_PM */
1 h# |- k8 I2 J6 s8 N% kstatic inline void device_init_wakeup(struct device *dev, int val)) ~1 {7 K/ f( l, y* \: y
{
$ N, [7 P, }" k  s: [2 k, w    dev->power.can_wakeup = !!val;
) Q6 ]" e5 b! G: O3 S}; n7 ^4 e4 E2 P! Y: D
。。。。。。* C5 c  h3 }6 Z" X# U6 d6 `
#endif
( y, E% x  i9 X5 `2 @2 \4 W1 L9 }/ f- V7 l9 a

2 m6 t- Y8 N" E# ?4 a# @6.1.4 device_pm_init& S) Q: h0 i1 `- a. n. W2 y8 Q
设置电源的状态。
4 ~6 ]7 z- L/ {static inline void device_pm_init(struct device *dev)( @) s4 S% T+ a7 B; w* _6 x
{
3 @! y, r0 v& d6 {" E/ Q        dev->power.status = DPM_ON;    /*该device被认为可操作*/( W% d& A3 R# X+ [! R& o  e
}. Z: h$ U* d: `4 }8 I
6.1.5 set_dev_node
$ g/ ?- \# v3 i- Q* ?如果使用NUMA,则设置NUMA节点。
+ t0 r. m! g& J* k2 N  M#ifdef CONFIG_NUMA- a: Q- c( D. e0 ~; w0 ^# _
。。。。。。
# B; z- a& d# ]" m8 bstatic inline void set_dev_node(struct device *dev, int node)% ]5 G; m6 B& B% P
{! c7 ~( p& e- a% x; A7 h/ q% W
        dev->numa_node = node;; ]; Q% a( }! x9 Z9 t0 `
}
" L/ W) a8 V( r" t) g#else6 w1 Q" i0 M  h; t
。。。。。。3 [) X* J! n; v2 ^' e; x; Q( y
static inline void set_dev_node(struct device *dev, int node)
: c, y; |+ i; ~{
, s: C* V; T! h  z}
$ ~- @( k" v) Z* ~% g1 C1 h4 E7 S#endif
0 O# W- s+ x8 K8 Z% m* R0 D
7 l/ Y$ h6 G7 o+ P. Z0 S% U6.2 device_add
$ Z+ w; e; b$ P6 f; q2 T- e  K1 B接下来是注册的第二步:调用device_add。$ ?* F2 |* c. a  I& B& k8 w# c

# r5 j3 b5 A# q  k/**. n. o% `; z9 W8 ?
* device_add - add device to device hierarchy.4 ]3 H4 L7 R0 L! _& t
* @dev: device., ?+ l4 W' k, p3 {2 k
*
6 o2 ^& {/ j* V1 |" f. G * This is part 2 of device_register(), though may be called* S) y* s  G5 p! L: _1 E% X: c0 R
* separately _iff_ device_initialize() has been called separately.( v3 G! c( K' V' }8 I4 y, y# u
*5 Y0 v7 i+ L$ j7 \, U; Q$ C1 z, z
* This adds @dev to the kobject hierarchy via kobject_add(), adds it' ^7 ?9 H  i* X+ S
* to the global and sibling lists for the device, then4 e- u+ F7 {" h
* adds it to the other relevant subsystems of the driver model.2 m( l2 @# x+ u5 N& M5 q: }
*
4 [0 r: t8 h% I9 r  r. J * NOTE: _Never_ directly free @dev after calling this function, even1 V& i, h% C! A" V' E8 r
* if it returned an error! Always use put_device() to give up your
  \* l& e3 O5 {/ k5 O * reference instead.* `3 X9 y6 J7 A
*/
) e& D4 q2 L/ C# T, R8 wint device_add(struct device *dev): h, P$ ~" r3 M: J8 F
{
+ \# S  V% |) R: t        struct device *parent = NULL;2 `) U, v+ ^& \, T6 S# ?; j: r
        struct class_inteRFace *class_intf;$ X3 _/ F. @6 W! C
        int error = -EINVAL;
6 S0 x- W; T; o( [3 x& }
3 w  P6 Z  i" Z" [1 d  X0 U, q        dev = get_device(dev);        /*增加引用计数*/- r+ h9 n) N, ~( O) W9 \; A( ^, q9 K
        if (!dev)- l2 |4 K# m9 {- s* O2 S: F
                goto done;% q2 c  d& x* }6 U; f- y5 `

; m3 P* M! O3 \        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/
# q1 n, t) _* x7 o2 M6 I        if (!dev->p) {$ H6 E$ b1 }6 O- u/ ~8 q0 z/ S
                error = -ENOMEM;
5 r# h5 l$ m' H                goto done;# |: ?4 F2 u  v3 G$ D
        }
( Z7 {6 ^. ], A% g; X        dev->p->device = dev;        /*保存dev*/# P0 T: z, ~. L; O& N" f
        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/
! j  o, D2 _! L6 z                   klist_children_put);
4 V/ I6 P! r/ h  B
4 `6 g" ~) G, M9 O/ B6 }        /*
8 R# z- l& d4 ^5 L7 c         * for statically allocated devices, which should all be converted. r7 p1 A4 v$ J6 J) o4 f) Y
         * some day, we need to initialize the name. We prevent reading back* Y) Q4 ]! b4 a2 z* @5 v9 j
         * the name, and force the use of dev_name()8 x) r9 M/ G1 _7 A
         */7 z, ?" X* s0 z
        if (dev->init_name) {
: [. y  [- K, V7 F- F) T* S                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/
5 [$ T1 r2 q! [) c$ K9 m" n                dev->init_name = NULL;
$ h* K- E* Z+ P3 u- j        }* h4 g" D3 I, c" a0 |1 N9 p2 U
1 c0 x5 S# O! V: w4 e3 Z
        if (!dev_name(dev))        /*检查dev->kobject->name*/
7 ?  B! ^/ \3 K) [- ?1 _. R6 v                goto name_error;/ L  b0 E, }9 E2 W

! w6 l  \" ]8 j8 {; s; q# a        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);& s) R, H) f0 E& E# a8 \! {
* H: @/ A  k/ y: Y- Z, s* D1 v
        parent = get_device(dev->parent);        /*增加父设备引用计数*/
$ h9 v) O0 f8 ]4 E/ c        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/
7 T7 u( G3 O/ h4 |3 L$ _% n8 X% J) A/ I+ ^$ r
        /* use parent numa_node */- z% ?* x& @1 I, n6 S
        if (parent)
  B. e  y% q* d                set_dev_node(dev, dev_to_node(parent));
% t+ M) B! W( o! @; [! y6 ]* V' P) g; a* H% p+ A8 k. G  H
        /* first, register with generic layer. */4 S4 v) f% V2 n% O3 `8 u
        /* we require the name to be set before, and pass NULL */
8 O3 l: [6 _- D+ K1 f; P$ C        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
' d4 A0 c: v( c        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);        4 W6 K- R7 ^3 s, m
        if (error)
7 g! B3 F. a1 d  B                goto Error;
9 |1 T# r; E* q# }3 Q8 \
+ V. m: K2 R. k        /* notify platform of device entry */) ^7 ~# w8 G2 k( S8 Y8 {9 Z6 q
        if (platform_notify)$ c0 u+ O2 j4 b- M$ P$ f% u
                platform_notify(dev);
* i$ G( Z0 U) d  ?7 b% S4 j
5 w- ^/ V$ Q8 y. J0 R        /*在XXX下建立文件uevent*/" u6 ~& r* q2 c  L" R! h
        error = device_create_file(dev, &uevent_attr);
9 p& y7 t, ^0 `& h) g. R6 |        if (error)2 J' j, X" a6 ]- F0 W
                goto attrError;
) t+ K4 f- p( Q
1 u2 s( ]# V  F) S$ k        if (MAJOR(dev->devt)) {/*主设备号不为0*/+ V6 F7 f; T' ?; |3 `7 o
                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*// `! ~" ?- B: Z  B
                if (error)  @0 W! G+ J, H$ K1 z- L, c
                        goto ueventattrError;
  o0 p: [2 Y1 y/ [8 Q" ~3 E. [6 f* Z: t( }
                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */9 E# l' I1 R4 \# }/ I
                error = device_create_sys_dev_entry(dev); $ ?* ]* E& f3 N$ f  L' {3 ?
                if (error)
  ?! z' w. h; _+ ~. o( u" Q                        goto devtattrError;
6 h& x- u) p: |) R0 ]& c7 D        }4 u/ z- A$ e* O. O

1 N! Q1 g1 _$ C3 x6 c; x6 [        error = device_add_class_symlinks(dev);
1 Q4 _4 o/ t; Y! h9 A5 e8 U% H. ~8 f        if (error)  K. T6 L  d7 G5 ?9 Z
                goto SymlinkError;5 x* q* }! F% P4 ]- i
        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/! N) A: ], U8 a: O, d0 p% d
        if (error)5 K9 S. a& h6 i
                goto AttrsError;7 Q0 v! \4 m9 ~0 N$ w7 g
        error = bus_add_device(dev);        /*添加3个symlink*/
. c2 ~& S+ o: x9 ~1 `% d/ K- ?8 \        if (error)
# ?0 T4 O+ a% b; o& {                goto BusError;
: y. u; ~2 b! Y% p6 I+ a  k8 d' }        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/& Y, [1 i7 ~+ K8 B% F( g6 G) x+ Q
        if (error)
) V5 J3 W6 e4 I# T9 G                goto DPMError;
4 ?1 r: u0 e; I        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/
' p7 C4 @8 q  x0 `7 `0 M1 d8 R# g3 x( G: D) U
        /* Notify clients of device addition.  This call must come
- p6 m; E3 o0 Y# Q" n, W         * after dpm_sysf_add() and before kobject_uevent().3 `4 L; I3 _  {* L: E  |
         */
$ B) k8 U4 f8 D4 s' `' c        if (dev->bus)
- N, X4 K& r+ `1 R                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
0 z( O- M( z/ ]  X( i% x3 c- N$ ]                                             BUS_NOTIFY_ADD_DEVICE, dev);2 G- b) z$ f" p2 j0 I4 E; n6 x

: G4 R6 V. k/ I2 o7 [        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/
+ G8 e- _; P4 z" h        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/, t3 G& \7 b+ p! K9 O, B7 n& D8 o
        if (parent)
+ B5 T& a/ z( @                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/: C, I+ W5 f& D6 _- `
                               &parent->p->klist_children);
1 r( {- C) n( g0 _( n# J" `0 h" X, _) O" r+ U
        if (dev->class) {                                                /*该设备属于某个设备类*/
/ |" m+ W, X$ Y8 B1 o6 r                mutex_lock(&dev->class->p->class_mutex);7 x" m$ R0 G6 P4 e# V2 ^# F
                /* tie the class to the device */
8 `$ t. V0 R( o, q' C1 R, n9 Q                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/; _: }$ T# O- u  A6 N
                               &dev->class->p->class_devices);5 _6 L& P2 k5 B; m5 _6 C4 x7 Y
% {1 [0 j' q& P+ U9 H
                /* notify any interfaces that the device is here */' B8 M  u) \( A5 i, e( I, L* r5 _) j
                list_for_each_entry(class_intf,
" W$ e9 i9 `; k; N) B+ {                                    &dev->class->p->class_interfaces, node)
$ ^" L; T6 y) M! T                        if (class_intf->add_dev)
# t  G( F- Y' ~$ r, f: a. ]* i                                class_intf->add_dev(dev, class_intf);
5 T) |' }6 \4 N4 [                mutex_unlock(&dev->class->p->class_mutex);
& v$ u5 J+ c5 Z' O        }$ x; e# h4 U! e. W. V2 x
done:
" A! W  K* |" E        put_device(dev);
. z4 O  V' |. c) R( Z. I  o( a( X) V        return error;1 E0 C1 z8 q0 D! A/ e; S" F* S
DPMError:/ H# g9 J0 Q% T+ k
        bus_remove_device(dev);5 e& H* l8 n9 _- H" E
BusError:; P# m2 i. g: \0 S# h. A
        device_remove_attrs(dev);2 O8 Z1 N( m; i: @4 X. A2 F
AttrsError:
0 d9 ?$ A, e- W: @0 l        device_remove_class_symlinks(dev);; z4 x: R' v/ t
SymlinkError:$ H0 Y2 e' T9 D
        if (MAJOR(dev->devt))
/ q) l/ ^- K8 L$ ]! N                device_remove_sys_dev_entry(dev);
, C, v5 ^7 ~# Z# \& j6 }$ k4 ]1 r devtattrError:
" P! {, Q1 C0 ?6 f( G$ h+ L        if (MAJOR(dev->devt))
: N4 K- [% s, |+ \" x% M2 _  Q9 o: N                device_remove_file(dev, &devt_attr);
5 b0 U5 f, p% p1 k8 O) n( `" _$ K ueventattrError:
' ?' Q& j) d" z! T# B        device_remove_file(dev, &uevent_attr);6 {: W$ Q3 Q8 s+ F, L$ K, ?' n
attrError:
% d' ~# s: |, M+ z. w( z9 E; \5 {' \        kobject_uevent(&dev->kobj, KOBJ_REMOVE);. |& X' D. W! p
        kobject_del(&dev->kobj);4 v( t2 u. b- p' J+ m- I* M& U
Error:0 c9 |9 p) Q) z3 }( X2 r
        cleanup_device_parent(dev);
# P2 |" F, x4 ]* W        if (parent), D1 F: M- U8 n+ q
                put_device(parent);
8 P( g2 p) ], e: t+ U/ vname_error:  {- Q2 i5 i$ T
        kfree(dev->p);
, q9 ^, m9 C, m        dev->p = NULL;
, o- z% X. H" G4 {" E# r0 {        goto done;
4 q9 [. R( X2 w6 i1 V}
) j: W5 k8 U: }6 v( R( k: K0 D
9 ^0 r) a: G6 [& H/ b6 g该函数调用了非常多的其他函数,接下来对主要的函数做出分析。- Q# ]9 M- n; j+ J* G+ K
6.2.1 setup_parent函数
( y5 {! W3 N5 k% N% e& N+ y. y下列代码位于drivers/base/core.c。
$ {3 c# Z2 r( Q1 s. ], ^static void setup_parent(struct device *dev, struct device *parent)1 S8 C6 i' V1 N/ O8 G( B$ l# N5 f
{" n% v; ?+ m' H' R& q
        struct kobject *kobj;
$ ~+ T* S0 L2 G+ r        kobj = get_device_parent(dev, parent);
3 x1 k, e8 }$ [        if (kobj)' [( C8 a; w( H) ]8 F" t
                dev->kobj.parent = kobj;5 o1 O- L/ c8 B* p3 z
}7 g& i# h4 a, k: f4 G
# C# W, b0 g: m, E% X9 Z# \
static struct kobject *get_device_parent(struct device *dev,0 {5 E" i- L( g; b( v
                     struct device *parent)& @) v+ {) e. t: \
{
, r. z# k! L$ p  ?' [. k+ Z4 w( S    /* class devices without a parent live in /sys/class/<classname>/ */
4 k: Z& \7 U' b% A. M1 L    if (dev->class && (!parent || parent->class != dev->class))
' @6 m  ?$ K9 s$ l        return &dev->class->p->class_subsys.kobj;, O# \8 V- }' a- o/ g+ w
    /* all other devices keep their parent */9 H/ I: E$ q5 t% m
    else if (parent)
6 R% E' `( k) _  y0 {        return &parent->kobj;/ `9 @( m' Z& J5 s3 U+ r$ L
1 X) t( b( ~7 B% q
    return NULL;
" G9 _0 X/ `8 H% e}
) y7 m! S  G3 B" L* `该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。& Z' s3 z7 h2 [0 H
6.2.2 kobject_add函数) e2 h; m1 v8 X2 R" I# Z* X
下列代码位于lib/kobject.c。
/ Y& e. @: W% e) w4 o1 j/**
! U7 _" M: G! \" A: D * kobject_add - the main kobject add function
- r) T) j' n, m1 [& I * @kobj: the kobject to add
6 I. k! a$ e6 b( R, @ * @parent: pointer to the parent of the kobject.
8 A) i+ W( o- m- F) T; _, W * @fmt: format to name the kobject with.6 e, w) U- b' _) E+ Q) {
*
2 |6 F+ q0 B. x8 {& `/ ?0 n * The kobject name is set and added to the kobject hierarchy in this3 A3 l: K6 Z; O* F8 G
* function.0 o" l0 c1 S0 I5 S, M( N2 {
*
, l4 i$ I6 F) S$ E2 L- N * If @parent is set, then the parent of the @kobj will be set to it." F6 K# v( g% e, l
* If @parent is NULL, then the parent of the @kobj will be set to the3 u! I7 F. j* `) n$ Y' d5 _. P  q
* kobject associted with the kset assigned to this kobject.  If no kset# j% o! G3 D& P3 G' R$ i
* is assigned to the kobject, then the kobject will be located in the7 g# e0 s5 ?0 i7 z4 A  y3 C( h" j
* root of the sysfs tree.+ U9 s9 v6 _/ K3 `7 V* ^2 h
*' _/ d* _: f' L% ]( S% K
* If this function returns an error, kobject_put() must be called to
: t8 ?  F; d# P * properly clean up the memory associated with the object.) h' |* {+ K4 q/ h% l8 n( X
* Under no instance should the kobject that is passed to this function
  f- {4 w* l. h! k- B * be directly freed with a call to kfree(), that can leak memory.
, h% ?( y5 T, R, H8 } *
- w. x  R9 @: y9 h8 [ * Note, no "add" uevent will be created with this call, the caller should set
7 r  k1 i2 \3 d8 R * up all of the necessary sysfs files for the object and then call% J; q/ R  i- F9 x8 [; d$ h7 C
* kobject_uevent() with the UEVENT_ADD parameter to ensure that3 `. U8 z2 [0 G* ]: r8 P
* userspace is properly notified of this kobject's creation.
( y6 Q3 J$ d! L( d8 L */
& j# n2 W; ?1 x3 g% M' i8 gint kobject_add(struct kobject *kobj, struct kobject *parent,
! n; g0 |6 P% c% H. W) ^7 t6 @                const char *fmt, ...)
7 S2 `: w; h( q  @  M# m{
% X4 ?8 S. T! A. z! E& ?        va_list args;9 N6 B3 f* l1 T# k& s
        int retval;
: l0 E% R' c( Q0 `6 V6 d
$ a$ h( V9 @( U0 `: C        if (!kobj)$ h# m7 |  P# b7 Y6 y4 C( }8 b' D
                return -EINVAL;
4 q& h2 I& ^  @$ l8 o& U- H6 {) A- F$ C9 h) X# s
        if (!kobj->state_initialized) {
. e. y5 Q7 z: z# P0 {! ?+ c# K                printk(KERN_ERR "kobject '%s' (%p): tried to add an "
; I! a( }) r0 N, i* S" t4 i: b9 c                       "uninitialized object, something is seriously wrong.\n",; e5 d) K( J$ F
                       kobject_name(kobj), kobj);5 p& Q- ~$ M# N- R  X. c: x( k
                dump_stack();
/ y' F  G& b/ M! U4 `$ q6 z' S( w                return -EINVAL;8 B. x, e- K; |6 [- r
        }% X3 _6 V1 v5 E4 t
        va_start(args, fmt);4 u* v$ ^0 ?& a& i( `4 t7 q
        retval = kobject_add_varg(kobj, parent, fmt, args);' L  W) D8 }; B- `) z# @
        va_end(args);! R1 b' O1 g1 @2 F6 Q. f

# C  t6 @+ n3 u+ _        return retval;. p( a; Z( C6 v9 M" _
}
! q1 c' Y  [5 \/ V/ L& d/ PEXPORT_SYMBOL(kobject_add);5 y7 q1 w) ~# v6 i) F& o

7 Z7 c* ^; }1 p, X4 Kstatic int kobject_add_varg(struct kobject *kobj, struct kobject *parent,( x5 q8 w# |1 @8 m+ |
                const char *fmt, va_list vargs)
* y) h5 K) o  `& ^. K: A- _9 z0 {{% w3 c3 W% I7 u8 Q* `
    int retval;
# d! b  P5 ]5 Z; @5 E) F- l/ H, y/ n5 N& @7 }
    retval = kobject_set_name_vargs(kobj, fmt, vargs);9 o9 z( a, v) k. L( x
    if (retval) {
% ^9 S5 D/ K7 C; ]        printk(KERN_ERR "kobject: can not set name properly!\n");( H2 q6 c( Y" d
        return retval;8 Y* \2 M* i) K2 b* B
    }9 O7 n, y) V8 l9 m" ?7 g
    kobj->parent = parent;
: V& [( C( N' d6 s( r; s8 |# A    return kobject_add_internal(kobj);
2 y, x0 v, i$ s( r8 o}& }" e3 m4 [, s  ~5 x
  [0 e" H% D/ a$ B5 U
static int kobject_add_internal(struct kobject *kobj)
  r  f  \" C6 ?9 k  d{
1 j. h* F" y- s# ]! U% F    int error = 0;
, }0 W# |; B0 }$ N2 X# b& |    struct kobject *parent;
7 L% ~$ O; @( H" H! K' Y+ c; Z  Z) \3 w5 f& @; r  i2 f
    if (!kobj)
. b' x/ ]3 q& s+ m) J        return -ENOENT;: z5 q; z# h3 K1 n
    /*检查name字段是否存在*/
( ^- U5 }! S; l8 b$ _    if (!kobj->name || !kobj->name[0]) {* i" O5 D9 H' ^8 `- J- G5 D  n
        WARN(1, "kobject: (%p): attempted to be registered with empty "5 q) _# n( n$ m4 W% j. N
             "name!\n", kobj);
6 Y# q4 F5 m) {6 V* Z        return -EINVAL;0 C5 r: A; c0 a- ?
    }
+ z6 [6 y( i6 c. p; }$ g
& L. J. d  N+ _, g* W    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/8 U2 s% N3 @+ [$ @

9 B: R$ s! @* p( V7 ?- C$ M    /* join kset if set, use it as parent if we do not already have one */' u/ ~; ?- ?  u$ N
    if (kobj->kset) {   
% N/ W8 j& b* G# p. \! V        if (!parent)
3 c2 \! ~- Z: n( f: `/ `- P            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/+ ]5 A& O5 V) T
            parent = kobject_get(&kobj->kset->kobj);
' H; N) I2 S  [9 s) t5 u        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
; ~* H& G8 b$ b& ?' Y" k( L, p/ h* O0 l        kobj->parent = parent;5 Y) @0 T/ o0 z0 B( ~) L; R. b
    }
. v* Y- c9 f+ M8 }8 X
" G- `- w1 \6 ~5 g" Z- y    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",( K( C+ S7 Y5 `, a
         kobject_name(kobj), kobj, __func__,
. g4 O- Z) r8 G- J! l" w         parent ? kobject_name(parent) : "<NULL>",
& M9 a% @" u3 |         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");5 G. e- w( P- j( t" a; |8 B# }
) A. r& Z, p* V" l6 d0 d9 q) J, m
    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
1 U4 t3 L. S/ K    if (error) {8 R% m# [" E7 l- \5 e4 q
        kobj_kset_leave(kobj);    /*删除链表项*/6 @, f* K* \% o; E! x5 p
        kobject_put(parent);    /*减少引用计数*/" n1 x2 C; \! r- k- p
        kobj->parent = NULL;
: B% R9 Q$ g2 }: t- J! R, R: i+ F7 {
        /* be noisy on error issues */
$ w8 r6 }, N* X& D1 [7 }. O        if (error == -EEXIST)' N/ N! ]/ v" h) y9 a
            printk(KERN_ERR "%s failed for %s with ". Y: v- s6 P1 e) c
                   "-EEXIST, don't try to register things with "
2 j: O. {( r6 B1 g$ `8 |  S                   "the same name in the same directory.\n",
% c8 e: L4 Q/ l6 |                   __func__, kobject_name(kobj));- W  y, X6 K! W) B1 t
        else/ z; X9 X. Z% _% r2 K# m1 D1 C
            printk(KERN_ERR "%s failed for %s (%d)\n",( r0 Q# C1 D3 O3 y
                   __func__, kobject_name(kobj), error);4 g3 Y# K1 f; ?5 T! H9 @
        dump_stack();# Q. h1 @. ]+ q4 G3 i( L( `
    } else$ e) h1 p3 B  g6 P& r
        kobj->state_in_sysfs = 1;
4 Q1 e, _9 h* g
. m7 c2 m; v+ k7 P0 c, z    return error;$ l; w) R$ l# w# o( o- p0 Y; n
}! Q8 T. S; Q1 B  Q* u( g& u
在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。
0 I3 I. m  F/ V% k5 y而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。
0 K) d! l; V6 v  k
& e1 q% S( x$ h6 b5 {$ _1 K但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???
' J% j* ?8 x. X% p; v- ~1 ^2 X
8 |; M$ n7 A2 u* K+ c6.2.3 device_create_sys_dev_entry函数3 F5 v" ?, Q& n/ t4 k: G/ q/ W6 I( P
在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。
# n6 W0 H  @/ {+ k但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。
/ t0 L2 }3 ~+ {1 x  T. N
7 a1 A" y  ]* f; E2 g8 v0 Y下列代码位于drivers/base/core.c。; @( s/ w. f0 u' Z6 c
static int device_create_sys_dev_entry(struct device *dev)
$ D7 E$ J" m0 R% Y& B1 H{( a+ B+ d+ Z: L
        struct kobject *kobj = device_to_dev_kobj(dev);
4 B0 E+ p. M/ i: Q        int error = 0;
' e7 [  n( [( P        char devt_str[15];8 k. ~4 h8 A2 `" o( p

, O- P) v# }- V0 n        if (kobj) {; B& V; N8 j$ h2 Y
                format_dev_t(devt_str, dev->devt);% Y1 {2 f9 R( A$ \$ z/ w
                error = sysfs_create_link(kobj, &dev->kobj, devt_str);
  ~$ @8 o! `* ?& o7 k* o$ A        }
2 X( `/ D& W1 ?, _1 e, o# _
& d' a9 ?" p6 g( ]4 v        return error;
8 H6 I4 r( c5 X- |% d}1 ?; v( {! t8 U7 Q3 R& L9 {
/**
8 l- ^5 B5 T2 Q% ?4 U7 [4 u * device_to_dev_kobj - select a /sys/dev/ directory for the device0 S3 Y: s1 t  ^" ?5 `: J! Y  }$ m
* @dev: device
4 F$ e7 J5 _0 w *
: w: Y4 j$ S6 s: B" c1 X) Z/ D * By default we select char/ for new entries.  Setting class->dev_obj
) _7 j6 V8 j6 v: V, M+ } * to NULL prevents an entry from being created.  class->dev_kobj must, p  O; ]8 V: Q, x" |
* be set (or cleared) before any devices are registered to the class( x* r+ n' D" u) ^
* otherwise device_create_sys_dev_entry() and2 r, h+ `( l$ J- ?4 s1 I
* device_remove_sys_dev_entry() will disagree about the the presence
0 f* ]: o- V) @* a( P2 p9 R1 M * of the link.
7 U: H' h2 Q3 Z% `9 ?; ]& `; o */
8 }# ]6 _% I) x+ D; Jstatic struct kobject *device_to_dev_kobj(struct device *dev); i& r, p0 T5 n
{
0 Z0 y: J' j+ I3 l: q( a    struct kobject *kobj;; b$ G5 ^2 b; y; R1 A/ m

! H! X) S  q5 v& C  D    if (dev->class)3 Z  C& c# P8 r
        kobj = dev->class->dev_kobj;3 p4 M7 ~: h9 b6 b
    else$ K" T$ x8 m' P! n  ]5 R) o  F
        kobj = sysfs_dev_char_kobj;; r' Y' h. m+ S- ~& A

( `" L9 P7 I6 {- J% S0 }7 d* y    return kobj;
& q0 \  k$ e  Z}* `$ ~5 o% b, q/ E

1 W$ O" R5 t( d7 }, k1 Z( H6.2.4 device_add_class_symlinks函数
# E- S1 t  ]3 L3 |2 x1 m7 B* O由于dev->class为NULL,本函数其实没做任何工作。2 T" x/ s+ t; l6 z1 u  ]' u
5 [1 i: v/ _) F" c" n! a* H; n
下列代码位于drivers/base/core.c。
/ x! B1 R7 o9 g& E: fstatic int device_add_class_symlinks(struct device *dev)# D. n( U9 Y/ D8 F+ E
{
$ X! s+ L& ?, _# a5 i( d8 N1 h8 P        int error;2 ^6 M  i8 J7 A0 y8 {

+ c: E" L3 ~  }: k; h5 z2 a% E        if (!dev->class)
/ {; B4 u/ g9 L) @                return 0;* a2 A: M: e1 B' X9 S

) o& x# d8 x7 h        error = sysfs_create_link(&dev->kobj,
9 I2 W5 v' g+ W$ W                                  &dev->class->p->class_subsys.kobj,6 S2 p+ ?+ {5 Z1 h1 C' _$ u8 b
                                  "subsystem");
" D% |9 H2 L7 M; U7 Q: U9 ^        if (error)! r. \" g  g& ]& c* z
                goto out;. \4 L. J2 G0 B* p% d  {, z9 x

6 ?; F+ o! r$ \# Y* c9 N#ifdef CONFIG_SYSFS_DEPRECATED
/ ^/ F0 F  I! p1 t0 d5 \( M; T        /* stacked class devices need a symlink in the class directory */* @. Q' P$ P7 T; V3 U% u; n+ |+ I: K: N
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
- ~; g4 M/ n$ K# j! N7 g) g0 ^            device_is_not_partition(dev)) {
! Z. `1 A. I3 }                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,; h+ A/ c. G; N* y1 A, ?8 Z$ b
                                          &dev->kobj, dev_name(dev));
, ^( a' E/ b) f3 ?; o                if (error)
% L1 O! t9 _$ }( K; E                        goto out_subsys;
) y/ z8 {: r! p- L1 u( C        }
" L' n" I  r( n4 |3 |1 f- Q) z' y& r  h
        if (dev->parent && device_is_not_partition(dev)) {! @! H/ T( L+ o* b2 j6 L/ M
                struct device *parent = dev->parent;% s: W" A0 h1 f/ v# @
                char *class_name;
. q4 v' l8 k) T7 }+ c4 N9 o: Z) A% H+ I9 `
                /*
. N8 O$ h# i3 C& A1 K( b                 * stacked class devices have the 'device' link
0 o0 E8 B3 M& W& l$ @, P" s                 * pointing to the bus device instead of the parent% l) e$ X9 L! i/ V
                 */% ]# c$ t8 c  x( u
                while (parent->class && !parent->bus && parent->parent)
9 y1 L; ?8 M! ]) k7 f                        parent = parent->parent;
1 B2 E; [$ w5 F# ?7 A5 H: o9 t6 u/ u3 Z
                error = sysfs_create_link(&dev->kobj,- F& ?3 E" Q- y1 }2 ^4 k
                                          &parent->kobj,
- T0 I& ?6 Y* U: U7 q1 y                                          "device");
, P, Q+ D$ ?, @; j$ t                if (error)' B! [% t2 t1 `: [
                        goto out_busid;
/ a4 E9 c1 v* D* u) X
* ]0 Q5 _+ \% q$ n                class_name = make_class_name(dev->class->name,
7 `/ c: w/ W# K5 r" L. v                                                &dev->kobj);; x- B' B9 w6 p
                if (class_name)
- B! |( f# n- e0 v; y2 X                        error = sysfs_create_link(&dev->parent->kobj," [& r- L9 \& [, t, P
                                                &dev->kobj, class_name);
& M, B$ z5 I0 A4 a% y0 ]7 P6 M                kfree(class_name);
9 g) v/ j5 y3 i( O& h                if (error)% K) }$ b; D% O: |# `# J) V
                        goto out_device;( [' t  h3 L5 U
        }) a1 J! y6 q8 w
        return 0;
5 n6 W8 S5 Q# F; q9 t- g- z3 `3 L0 J3 p8 R0 z1 W
out_device:
3 G9 M0 |7 E8 {9 ^1 O* [- V& k        if (dev->parent && device_is_not_partition(dev))
4 G! ^: y- ]0 k                sysfs_remove_link(&dev->kobj, "device");
* j7 i/ a8 v3 ^1 \8 t: d' sout_busid:3 ]" i# a, M0 o8 o9 M- a. U) s
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&0 A# t8 Y' q. }8 e* \' x: ]( f" Y
            device_is_not_partition(dev))$ o+ V+ w3 l( T# _# {
                sysfs_remove_link(&dev->class->p->class_subsys.kobj,+ R: B* p  G; \/ m/ C
                                  dev_name(dev));$ O* _9 T+ ?0 h7 o2 E! p
#else/ y5 l8 h, q+ g
        /* link in the class directory pointing to the device */1 S8 j3 R; R9 t& N
        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,6 g2 `( j; N% P) I+ v$ ?
                                  &dev->kobj, dev_name(dev));% s7 k: p) h; n8 h! T" z/ l
        if (error)( V& d; f. b, `& p" G
                goto out_subsys;. `2 z6 U# D& ~' h1 X3 R5 ?5 Q- i
$ L2 z# n0 [/ _9 E) o' L
        if (dev->parent && device_is_not_partition(dev)) {
% T3 ^  c! `+ f" G& G                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,, X0 K3 o" w: y$ P$ Y
                                          "device");
& \& X8 e% E2 f% A+ o' e/ s2 {' h                if (error), Z, V* C& X4 O# B
                        goto out_busid;) v2 o6 n# j. m$ ^/ t$ f* W5 W! y
        }
/ d; y$ ]- X5 E6 A# ~6 a) ]        return 0;% `# }  l7 A* M0 P

# |2 l) W( n( I4 K' ^3 s. n0 Fout_busid:1 ^. D6 m! S8 j( a& e
        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));9 J2 F& ]8 ]! G9 c
#endif; ^* P' {, r! N& H2 y: \% m

0 U" d" d) m# Y4 ^4 r( J3 Vout_subsys:& v8 m1 k* M; @6 P9 E
        sysfs_remove_link(&dev->kobj, "subsystem");
8 \8 S/ {8 r: ?out:
; ^8 Z8 F6 ^9 Z9 V! W  X        return error;
7 a' J* {3 T: V! v) V$ C}
4 Z" m9 l" A' D6.2.5 device_add_attrs函数
* R  O' h% T" l/ K7 g3 ^9 I同样dev->class为空,什么都没干。( A( d) S0 m; L
下列代码位于drivers/base/core.c。# r- D. B! Z$ x" e& R
static int device_add_attrs(struct device *dev)) N( C4 B% |# M3 U- O+ T
{( {) x: q- U+ q  M2 Z3 Z8 [
        struct class *class = dev->class;
5 n+ j0 z* Z' x1 y" k        struct device_type *type = dev->type;
! J5 ]+ ?! R" C9 r! T" L1 P- S* J1 \        int error;
* d  j, }0 b/ J( g, q7 [+ H0 i' ^% u6 v3 Z$ G
        if (class) {! f6 b3 M$ S' F& w% y
                error = device_add_attributes(dev, class->dev_attrs);& [2 C" |) |6 b0 A
                if (error)
6 a/ j: b3 |9 R6 E& I8 X8 ^                        return error;) N8 D, ]0 u+ y1 O
        }  h! ~/ _' K7 U8 J& o6 j
/ z( Q. U, E+ |- k! i7 a/ S& Y4 P6 N/ X2 Z
        if (type) {
0 l3 V! u8 c' V3 I                error = device_add_groups(dev, type->groups);
$ ^2 k9 D# B7 |6 [( J0 D                if (error)
2 [, k; N0 j: J1 C                        goto err_remove_class_attrs;
. A& O! a. W: h* m! K! H        }
$ b4 C9 z$ p2 _: P# \5 x& ^8 n6 T2 O4 Y& k3 d
        error = device_add_groups(dev, dev->groups);3 T0 q0 ], _" s7 [' B
        if (error)
" \9 B: ?- v8 ^0 K6 _- p                goto err_remove_type_groups;
$ U3 M* D9 P6 x
$ L" z  W: v: [% [! u        return 0;
' n% Z8 ]. A2 P5 h  o8 C7 h/ t' i
/ s" }) B3 b' Z' k err_remove_type_groups:
1 M# g, s7 ^: U$ H9 A        if (type): W1 y* C; W* P1 X/ Z
                device_remove_groups(dev, type->groups);
) [$ }+ ^% Q5 F& h5 j err_remove_class_attrs:+ j( {0 B, Q: [/ N) O' Z* o7 T6 c
        if (class)
( I" D. z; o4 {1 U# S, }) `                device_remove_attributes(dev, class->dev_attrs);
# h* y# l( K' _
  K4 L4 k; D3 u6 L& `, n% H3 q        return error;
1 _$ U; j) u2 ], d! f: o- k}6 b3 \3 A4 {6 m* E+ I
6.2.6 bus_add_device函数
$ u& c+ u' V: h3 |由于dev->bus未指定,因此这个函数什么都没干。2 q# E8 g: _* Q5 W; o6 M2 r

& C! ]6 \  V+ b' l( H该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。
# E0 Q  [8 v$ F" X8 z( C5 k4 G
& w3 v+ a( [, s' N# }下列代码位于drivers/base/bus.c。/ Z0 z3 s% C9 ]/ w
/**
6 s& y* m  Q+ y* [5 u" R * bus_add_device - add device to bus) T. R) b6 {" R
* @dev: device being added
. O( G1 d0 l) V/ {" {" I+ [ *
; p0 `8 X' ]' `0 |- F( v' k4 x' Z0 X * - Add the device to its bus's list of devices.3 P' W( Z$ n. r- n
* - Create link to device's bus.
4 W- q8 ?3 v  b8 ]& y! ]5 R */
4 y2 K0 Q8 i/ f% n) W. E7 Lint bus_add_device(struct device *dev)
/ Q  Q* o$ m9 \; y, Z; X{
( ]0 ~( Q  \- A. N) E" X        struct bus_type *bus = bus_get(dev->bus);1 {* [3 q5 o6 e/ z1 D; W) x
        int error = 0;
% w9 V9 v  z& t* H8 C
, l! {# C8 ^9 a" o        if (bus) {
) s) e+ d8 F8 s% L) @* w                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));! E5 L1 P8 [) d3 i' a6 S. Q) q4 x
                error = device_add_attrs(bus, dev);4 Z9 X0 a. W% }3 d) D# P9 A7 B6 {
                if (error)/ U. @) T0 x: Y3 X9 F
                        goto out_put;; n' B5 ~7 A* t7 j% G$ |
               
8 |" w0 N) |6 p4 e                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/
: C" k7 b- K4 z7 X                error = sysfs_create_link(&bus->p->devices_kset->kobj,
: R) G0 Y6 x0 T                                                &dev->kobj, dev_name(dev));
* j- h+ h+ E: {3 i. }+ P. s* n6 B) O                if (error)
5 y9 x7 S: S: A                        goto out_id;
! G+ {$ S6 F( b( z  P* F2 N                # Y/ o& L; S0 t
                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*// W! p( n  z3 `) |+ v8 O5 n; q. u
                error = sysfs_create_link(&dev->kobj,$ s; w' q6 p4 m1 k
                                &dev->bus->p->subsys.kobj, "subsystem");
$ u( e/ u+ ]/ C3 p. p. G: Y, c                if (error)  F! q. C6 {' F3 ?! X9 x
                        goto out_subsys;
! w2 ^. [) Q& I                4 G- d& D" H$ F. v! n! W
                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/! `: g* U1 k9 r( U% u  b" F/ R! I
                error = make_deprecated_bus_links(dev);
& Y* b# b- f$ Q                if (error)
& G! l6 S  g4 Q) j" C, \                        goto out_deprecated;
/ w( j2 W0 c2 I        }
% d3 p$ q* Y7 C2 x' G( i/ k7 Y        return 0;1 ?  g3 E& K- D2 U! Q& V
5 x8 |- K: E; t4 h6 b
out_deprecated:
9 E6 p/ i6 @/ M        sysfs_remove_link(&dev->kobj, "subsystem");
( k: G* }0 o' |out_subsys:# n& w2 |8 ~* _& J; z, `
        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));0 ~0 V9 H! D$ l7 f: O% k
out_id:
3 U; Y# L# Z1 g- t0 R        device_remove_attrs(bus, dev);
9 z  L7 x0 C" {- I1 I: Xout_put:* d8 F$ H, w1 Z2 @
        bus_put(dev->bus);
! m8 i, ?* s  ~0 ]& y1 n5 M8 x        return error;% j1 V  u+ l( k5 a
}. r6 y: n; h0 A. e& A5 c' @

4 U7 }- N: d1 ]! T0 K4 q0 s, f6.2.7 dpm_sysfs_add函数
1 O3 a4 b) Z1 D" e# O6 w  ?下列代码位于drivers/base/power/sysfs.c。- b  I: [: _& V6 ]
int dpm_sysfs_add(struct device * dev)0 k0 H. I1 c  Z5 ^
{
+ v* r3 a4 I: d9 Y  U. O        return sysfs_create_group(&dev->kobj, &pm_attr_group);; t$ X0 E, S% D. Q
}
) y8 r$ F& a) w- |, G+ u
: ?* z% E& i( ^7 }static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
/ k- q1 k% D; f4 K
; @0 x) K0 n# E' k5 c" d) E% @5 L( V& \1 T4 j3 M) W
static struct attribute * power_attrs[] = {( q" F4 L& `+ v2 w# ^8 A
    &dev_attr_wakeup.attr,; R+ b: V1 A" U3 T; w2 s, |' Q
    NULL,
4 K2 B. w3 f+ i) G+ N( f# O};" J- X  m4 b' t' F- _
static struct attribute_group pm_attr_group = {5 t' \% L. G& n0 s& a; D& @
    .name    = "power",) b6 D4 h/ d5 j+ V0 R) Z  m
    .attrs    = power_attrs,: ]8 T" L+ T8 ?. u3 i
};
6 `  l, v* h+ t0 Z" e
) l. y% f* d' \该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。; C. D( j1 E8 [. B# f
* H$ a: W/ E- ~7 _+ ]8 Z% A! M
在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。
& `- C5 W; d" I6.2.8 device_pm_add函数9 W; @$ r# l) n: E# {
下列代码位于drivers/base/power/main.c。5 J/ p2 ]& \  g1 o: q
/**
/ F  x. J7 V3 g" _. y *        device_pm_add - add a device to the list of active devices" s7 j" K- \* d6 e# b
*        @dev:        Device to be added to the list
- y0 F. X3 M8 k! q6 d2 G */: c3 F# h1 s+ E$ e
void device_pm_add(struct device *dev)  ~* q& k5 p) c  i# b- A3 U
{
% _& w! H% c3 b$ O        pr_debug("PM: Adding info for %s:%s\n",
' f; @4 }5 |8 Y5 Y0 C                 dev->bus ? dev->bus->name : "No Bus",
  f1 W+ q) w( `1 V: V  ?7 i- ^5 n                 kobject_name(&dev->kobj));1 G# ]1 f) _2 Z6 U: D: ^0 R2 r9 K
        mutex_lock(&dpm_list_mtx);$ @# o5 u8 p# b6 o$ d7 \3 e
        if (dev->parent) {
  p& a8 v1 u3 W2 h! ?/ b2 H                if (dev->parent->power.status >= DPM_SUSPENDING)# v% a% |0 G( ?% M0 Z: s( X
                        dev_warn(dev, "parent %s should not be sleeping\n",% x  |. q. R' J" h5 p
                                 dev_name(dev->parent));
* H3 M1 q3 q5 L* A        } else if (transition_started) {
- V5 ^7 v7 L) i& e/ Y# u6 C; |6 D% ]                /*
# n1 X! }0 K/ P3 X. R8 k1 t                 * We refuse to register parentless devices while a PM6 q, P4 Y4 O8 C) F3 b
                 * transition is in progress in order to avoid leaving them
4 |2 y2 F  g+ k* Y                 * unhandled down the road% C7 p4 b1 l' a: Y+ o& A
                 */- ^0 g( y  f& o1 E( l6 c4 }
                dev_WARN(dev, "Parentless device registered during a PM transaction\n");3 r# L1 Q) f7 i
        }1 y) ?# N; L% p* I8 f* v
/ ?& {: {. W2 I. N9 Y& T( u4 X
        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/+ B6 q8 h* I1 e7 j3 U+ _0 F9 [
        mutex_unlock(&dpm_list_mtx);0 n/ a' \% v+ C1 a) W
}
% f5 N" B2 [' }; i( ]( a/ j$ E* m6 M/ m
该函数只是将设备添加到电源管理链表中。
$ O7 W0 R( u# F& I- o) g7 _# Q6.2.9 bus_attach_device函数
+ X9 _% f8 u) l: j: C) g在本例中,由于bus未指定,该函数实际不做任何工作。
) K+ K6 U4 j! M2 `6 H! T7 ~下列代码位于drivers/base/bus.c。. k, \2 [' d9 \% W) D5 O% Z

! P$ w; V, m& z" C9 k/**
1 a/ ~7 b& P6 T, T2 F5 Q * bus_attach_device - add device to bus* P; u* E( q* ]& ]/ D+ C0 J0 \6 Z3 [
* @dev: device tried to attach to a driver
- _. a3 M! b' y *
9 T, O* M% O! o( A5 t2 ~ * - Add device to bus's list of devices.
! l" R0 ?# a- I' F6 {9 S * - Try to attach to driver.
' M3 u9 `/ z. F6 w% S5 ? */% G9 G. f0 y9 f& Q' l2 q
void bus_attach_device(struct device *dev)0 |1 d" O* X  Z4 z
{
* Z* o- H; i2 e        struct bus_type *bus = dev->bus;* k" `1 h( o, P0 R% n7 p& p- ~
        int ret = 0;  r3 E% r' }2 o; w8 r) l  l1 ^/ X

/ V0 i3 c# i: R3 Q9 d  _        if (bus) {& @$ L  }, y* _" o8 i8 \2 Y
                if (bus->p->drivers_autoprobe)
% j/ d8 m, k; a/ |/ z  l                        ret = device_attach(dev);        /*尝试获取驱动*/& p3 Z' A! D, Y- _2 B
                WARN_ON(ret < 0);
8 D3 W, w( n! i                if (ret >= 0)                /*将设备挂在到总线中*// t3 ?- y6 j9 p& y3 r
                        klist_add_tail(&dev->p->knode_bus,6 s, H' `+ Y( j# Y% ]5 t
                                       &bus->p->klist_devices);
0 ~- m5 _) Z5 c/ B        }
7 V0 ^' s% {1 t0 U}
- }) f0 K& z8 p  X, I% a3 ?3 |" Q3 P7 n6 m
/**% R1 x: n1 M) D1 T
* device_attach - try to attach device to a driver.
5 k; J, p) S/ j' Y. O7 U * @dev: device.
# e+ j) C! k" _$ F3 M" d7 M# a *. m4 b% M. P6 n0 C' w7 N
* Walk the list of drivers that the bus has and call: U( i/ {+ H5 Q2 `, c. ^( R; w  ^, T' K
* driver_probe_device() for each pair. If a compatible
5 C3 K! y4 ~0 Z* O: j  o7 c: n * pair is found, break out and return.
  u% D$ s* l& p" w, k3 B) B *
. \2 l) R- \' F# i. ~9 x* _ * Returns 1 if the device was bound to a driver;2 M  }/ o; \7 f  s: k# r- Q
* 0 if no matching device was found;8 j. M$ N5 z3 q' k( E! @
* -ENODEV if the device is not registered.8 ^) ?- z/ T& G3 `
*
4 h$ Y7 v/ |" m! {, v * When called for a USB interface, @dev->parent->sem must be held.# }  y  w6 j: p. r$ V. }% j' H8 H
*/
7 U. j3 o4 b# xint device_attach(struct device *dev)9 |/ |- G0 p+ T1 j
{
" O# v* ?2 G; v) Z0 J2 n+ f) N    int ret = 0;
* a. `' b& P& @) Q6 m5 c/ u. [
! D; m$ P; ~6 ]3 E# Q    down(&dev->sem);6 C. E( S8 n" H. c
    if (dev->driver) {    /*如果已指定驱动,即已绑定*/# V8 z5 Q" _9 @4 @
        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/; W: U+ ^% j/ }! ?7 I4 G  f* k
        if (ret == 0)
- l3 m8 r. t- K' X4 t            ret = 1;; I7 ~0 \1 \+ Y3 m1 T
        else {
& U+ l* i+ `8 e1 X% K* {            dev->driver = NULL;' N- g) K) Q& T1 u+ Z" S% [/ g
            ret = 0;
& H5 ~# u3 `8 K        }6 j6 e! P8 {+ p
    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/) l* |1 s  ?' x) D% M! Q
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);( Q! C, y. r. o3 ~- q
    }' u! L% G3 q! a! {- `
    up(&dev->sem);
/ M9 U: q2 D' L: [    return ret;
. s! R1 {+ w3 m0 q6 h! R0 p& a4 G}9 U( p5 b- `( |9 @- Q- W+ h; X6 u
EXPORT_SYMBOL_GPL(device_attach);
, ?. ~- e/ O  i& Y% i; S
' Y* }+ @& w( Y" _; \' D如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。2 x9 }# [8 ~9 ~/ r
% A  v: e0 p. n% {8 ]
为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。
8 R& d0 [+ C0 D* i8 o6 F! ?; d
; c' D: H6 Q2 }: S3 ~- V" Q我们来看下bus_for_each_drv:4 K0 J- q* c5 S- m
! T# g7 V  i' R8 F
/**
0 P9 T! j$ K; }. }' A; L5 {0 ~* ? * bus_for_each_drv - driver iterator9 F+ m6 e3 T* _* g7 U
* @bus: bus we're dealing with.) \: M; X) i) ~. X' S1 c8 t" \: k
* @start: driver to start iterating on.
0 I8 F- h+ k* \$ a. A * @data: data to pass to the callback.
- b; _* |6 n5 Y  v5 D5 m& M * @fn: function to call for each driver.
; U) c- H& o5 S- { *
/ E; C& }, z5 s1 @2 ?& K+ |/ \ * This is nearly identical to the device iterator above.6 T1 y0 m8 w" |* c$ E( D
* We iterate over each driver that belongs to @bus, and call* Q; A' z/ ~, ^* U- k
* @fn for each. If @fn returns anything but 0, we break out
/ x- j( I; J' T* h$ S7 M2 b * and return it. If @start is not NULL, we use it as the head7 z3 n/ l3 v6 e% F' O$ e8 e9 u4 `
* of the list.; e. F0 p  h) s
*
6 i) D/ `! [& v; O * NOTE: we don't return the driver that returns a non-zero6 V& N- F, \" w
* value, nor do we leave the reference count incremented for that9 c" w: U* g% L, Q% Q5 g
* driver. If the caller needs to know that info, it must set it$ p9 Z- {: v5 f( u
* in the callback. It must also be sure to increment the refcount: A9 O2 @1 [2 Y/ {% i1 h
* so it doesn't disappear before returning to the caller.- L( v) I* D- h6 R. v' P
*/
# i0 }$ X( d2 X0 e# [5 X0 ]2 aint bus_for_each_drv(struct bus_type *bus, struct device_driver *start,+ F; @$ G( S8 O
             void *data, int (*fn)(struct device_driver *, void *))
% ^/ h6 r2 T% _9 P% z0 X{* T+ y# ~/ @8 H" J( U* E8 }/ ^
    struct klist_iter i;
0 j& P% g5 V; w    struct device_driver *drv;
0 x# B% E/ m: T# M) F* l7 X) o    int error = 0;3 O' s7 k! L! Z# m4 B4 z3 j

, _7 L, S9 B: _# ^    if (!bus)
5 Z4 s; P9 t3 a& a5 _; {! ]4 G        return -EINVAL;& _3 M: B2 G% P0 `; L; ~! F

7 l' }9 @  g5 @$ W    klist_iter_init_node(&bus->p->klist_drivers, &i,
  E+ |% [; y+ w2 }- x$ B                 start ? &start->p->knode_bus : NULL);+ c# F2 }" E) o# c  S- \
    while ((drv = next_driver(&i)) && !error)
0 z, y8 g  q" z$ Y' j        error = fn(drv, data);- j- {  i: l4 q' ?+ Q
    klist_iter_exit(&i);
  _' ?' r: O1 W! C' h    return error;( @; S, u" P0 {# X) `$ W# H
}
8 M' q9 V/ K2 n* G% vEXPORT_SYMBOL_GPL(bus_for_each_drv);
8 P; c0 p- b: Q6 I) b该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:
/ Q" X: \; _: o, t' x; o/ |* C2 V  }7 _5 _6 N
static int __device_attach(struct device_driver *drv, void *data)
1 f& Y5 Q/ k8 n: Y{  `+ t2 X" d; K2 W4 p! v
        struct device *dev = data;
; L2 K8 ]: h. @% ~9 @8 g5 v- _& f- O4 p% g2 y; E# V3 o
        if (!driver_match_device(drv, dev))   /*进行匹配工作*/
8 |' M2 x7 F/ H( Z0 J5 }' r) o                return 0;
- k/ @0 Q# v& `8 l! K: I; W9 a+ Z. Z5 u/ V
        return driver_probe_device(drv, dev);! }6 ]" T) B9 z1 \
}
( ?8 x& E; H$ [
4 H5 Z; ]4 a  G" I8 Z7 {static inline int driver_match_device(struct device_driver *drv,9 E$ C+ H- R# h
                      struct device *dev)9 @# m) D6 |. V& O
{
- X" K4 K5 }  u. K: W  Q    return drv->bus->match ? drv->bus->match(dev, drv) : 1;7 Y: @! T8 d) I
} 0 u+ u! t, c, I& O
3 y" f1 z+ q2 [& s5 N) E
/**( r0 K6 E! K# K1 B0 X
* driver_probe_device - attempt to bind device & driver together
/ P' j% V5 O1 ]7 n6 ] * @drv: driver to bind a device to
8 ?2 D; ]! _0 G5 ]2 ~% O4 L+ v5 a * @dev: device to try to bind to the driver* e4 R/ T0 w; E: X5 a9 X
*/ B! F% G- O- _$ S" `2 I
* This function returns -ENODEV if the device is not registered,
; F* I1 G) f% s0 r, W  N( i * 1 if the device is bound sucessfully and 0 otherwise.8 V0 L2 R/ O1 U% ]7 e2 R5 j% X
*# p- z6 g& `# k: e9 D) Z2 `; @
* This function must be called with @dev->sem held.  When called for a7 ~2 E. N0 \, C& ?! T6 S# L
* USB interface, @dev->parent->sem must be held as well.4 r; L& e$ d# H/ {" Z
*/
, Q+ `* q8 q! T: M; q; o3 Rint driver_probe_device(struct device_driver *drv, struct device *dev)$ g% c4 \$ e/ C
{
6 B( K( q' j' v( [( Y    int ret = 0;
& T5 d/ a# C3 b, \5 V9 M# g# m/ j! f# J* @# z
    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/2 ?, C% m) p! c$ }& \( o
        return -ENODEV;
4 M0 C" N# k" U& C& Q) X0 a3 p  w2 D; ^3 |" i$ f9 t% O
    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",% R( [+ M1 t  |- n& M
         drv->bus->name, __func__, dev_name(dev), drv->name);
; i' v& b1 J; l% D1 o( M4 P) t, S* \4 g8 X8 n/ ~/ q" f1 F
    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/    ) q+ }4 ]# ]8 k5 J8 |% ^) Q
$ @: l$ ]' }' p1 ]  L2 R
    return ret;0 x  Z& B  x+ w1 q5 f+ c$ }* c
}* i$ c, u8 s0 X  d5 m' t3 {

5 ]/ N8 z4 [" h1 ^+ `' w! t: ]& x4 D该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。( ?# I8 q7 c) ^3 }/ K6 Q
我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。0 K2 D  F9 C; I: Y
: J8 l7 d) f& S; P7 T, ~
随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。
% F2 t. H+ l# A3 D% F% W
) W. q$ a  |3 Q  l/ Hreally_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。
# A5 a( ~- k4 t- T. i( `6.2.10 小结, I7 t' Z' `$ b) h  z, e4 m% h
在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。/ t! |6 M6 O  M) ?; g& k. Q

8 s# c. ]/ K' G) u0 u最后以函数调用过程的总结来结束第6.2小结。
* k; w3 V: I1 `$ j" T0 H
* Q- t$ C. n  s1 x) B ' d2 G( t- ^3 l+ r& R5 E) X/ ?1 h

0 \( y$ B" \' Q7 Z0 }$ a
* U* l, s: O0 [1 e& k3 d6.3 spi主控制器的平台设备
3 f5 Z: r; H* e  n5 [0 R本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。
) T. F& D& ~) {! X& G3 ]7 E
4 [; Z2 O- l2 o0 A在内核的启动阶段,platform设备将被注册进内核。我们来看下。- y+ j, [+ f* P! D( J3 K6 g

5 @: @  ?: X) Y9 D/ ^0 ?下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c9 T' o3 c9 C2 d$ O6 u/ m1 [1 e
/ a: I/ W, ^% i2 t/ ^. T% I3 ]
static struct resource s3c_spi0_resource[] = {
# F3 \! |6 |: F2 |% B    [0] = {
* f2 [- Y) i+ D$ O+ I( j/ Y        .start = S3C24XX_PA_SPI,6 g5 a# ~- m9 w( X' J3 v
        .end   = S3C24XX_PA_SPI + 0x1f,* _( j9 f- C" g' @1 y' y! Y( G
        .flags = IORESOURCE_MEM,! V  Q: e( ~( }# n' q3 U. v
    },/ J/ r4 D  O* B1 U; l3 ]" [
    [1] = {/ J9 \/ p6 g/ d
        .start = IRQ_SPI0,
1 R+ N$ W7 ~7 Q: i% W  R1 [        .end   = IRQ_SPI0,7 A7 V0 k& C( f
        .flags = IORESOURCE_IRQ,
: i1 t: D7 l) Q& j7 }: r    }2 J" E7 E4 }6 A" J$ Y( {
0 ^( W9 D9 ]* ~/ I+ c& U+ ?0 F
};; M, `* c1 h8 m7 o1 t4 m
- U  Y) y: R$ q) Y- V; \# ^
static u64 s3c_device_spi0_dmamask = 0xffffffffUL;0 w4 E3 u' w9 t1 p

: T0 B7 E" R' \struct platform_device s3c_device_spi0 = {# b: [! q- m% Z* {% ]4 ^9 o
    .name          = "s3c2410-spi",
9 q& e+ q: a, Y8 y; F6 _    .id          = 0,% K" I* A* v* Z) d4 X1 Z
    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
$ B& Q' ?+ P9 w5 U: ]. Y8 O. C. I    .resource      = s3c_spi0_resource,
  @. C* z1 ?9 k& a+ j        .dev              = {
1 n) F. u1 l* R+ E. @  c$ r5 s1 f                .dma_mask = &s3c_device_spi0_dmamask,7 a) W  ^8 ^1 Y' M) z
                .coherent_dma_mask = 0xffffffffUL8 z9 a) E5 E7 l/ P
        }
3 J# I* s2 G7 K% F6 S* k};
* N9 o  {( a" J( |
: S% A/ W3 P9 B; g: mstatic struct platform_device *smdk2440_devices[] __initdata = {
# g8 [, v$ l% y! Q    &s3c_device_usb,
3 q6 J3 k. r8 W1 P  b" d" z    &s3c_device_lcd,( M: H7 S4 A6 Y' v  ?& p7 V
    &s3c_device_wdt,# ^* a- ?8 q* h1 J
    &s3c_device_i2c0,
) _3 \4 ^# L4 t( b: I; `8 Q* {    &s3c_device_iis,4 K: r" D: A4 a( d5 b
    &s3c_device_spi0,& m( Y) f# A; r" X' Q$ O, W% T
};
" O8 P$ ^' ?" j- _
- J4 _& {: \2 F2 E, v, V2 f3 Y! c" u6 m3 t6 w. G$ Q) i6 j6 P- R' C
- M2 q9 v' M. r+ ~2 `& c0 h& Y, @
static void __init smdk2440_machine_init(void)
; h+ P9 f6 t, [! x{' f0 W( C  g' d% B- ~' P! W
        s3c24xx_fb_set_platdata(&smdk2440_fb_info);
/ w+ z1 F% N3 Q+ W& c" }        s3c_i2c0_set_platdata(NULL);( J# x" c. i- o. x3 H- a4 V& D

6 r  P6 v5 y1 G        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
, s& G0 u) |* _( z; l        smdk_machine_init();8 c& l( e( V: K7 Z3 k4 R: a
}
3 j) W9 u3 }  q: r3 Q! a! N
6 O& I8 M  a/ Q  ^6 X在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。
  ^$ o0 j; P3 `4 F: V9 X- s5 K6.3.1 platform_add_devices/ |- q3 y6 m1 Y4 H  ^
/**
2 k) q' b) u; j/ [* U7 j7 b6 J * platform_add_devices - add a numbers of platform devices: W# C$ K4 P& K3 |- g% R
* @devs: array of platform devices to add
& X6 e5 V5 O! }+ W& T * @num: number of platform devices in array; c2 ~. q# a9 }8 \, o: F) Y
*/) l+ t! f" V3 h! n5 n
int platform_add_devices(struct platform_device **devs, int num); l9 n( [; r+ U" s
{' c( z# y9 q/ R" C" O: \
        int i, ret = 0;
4 W9 g' {% d+ @9 a2 C7 }3 g/ _& J! A7 z) k! q( i& M
        for (i = 0; i < num; i++) {, P- \. X1 T) ]) ]
                ret = platform_device_register(devs);
' ^: N2 s3 c( Q$ p                if (ret) {4 f6 K0 z$ F; |! b1 @6 y9 b4 {8 m
                        while (--i >= 0)
; @6 t( C6 }7 q' k                                platform_device_unregister(devs);5 x# J6 S) a, B5 e
                        break;
0 n+ r& R( K  U1 c; j$ d                }
6 W' H2 ^+ [% p7 w        }3 x0 w4 @5 ?7 k1 q8 B- j0 k

8 ?! M8 U; ]( A. C! ?' d        return ret;
3 ?2 @. U8 `$ z6 B8 G" j/ a, |}# D. }; ?; p( V: v
EXPORT_SYMBOL_GPL(platform_add_devices);
: t7 c% Y! T- j5 c( \; S6 Z" {0 Q# e5 @
! N9 W) |" Q1 o6 w8 D! e该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。# `" w' W: z( X8 L$ \/ s  a
6.3.2  platform_device_register
! q, m6 R/ J$ g' c& C/**8 i0 x) G4 `, h% E0 i
* platform_device_register - add a platform-level device
/ F, s/ q: |2 y; r, S- y5 O  l * @pdev: platform device we're adding5 A' r. Z) O2 `6 t. q" g. G( ?
*/
6 P: }/ L$ z! Y4 y6 ]! {4 H& H" dint platform_device_register(struct platform_device *pdev)
' Z2 u# I! d5 e- w{- l  g1 j. @5 f3 O* n- w* K
        device_initialize(&pdev->dev);6 k1 m1 J. b# W7 `
        return platform_device_add(pdev);9 @( o% E: w1 j  I
}; G4 D6 M6 {+ y8 l% ~
EXPORT_SYMBOL_GPL(platform_device_register);7 y3 j, o, m, r1 M

* m' p: a/ W* C: p2 S8 t5 J0 R/ T1 D5 c调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。
* M0 q! X* s' x6 c; {- K  Q6.3.2  platform_device_register
& w8 C! I/ s+ X& w1 j/ w# E5 s6 \5 R/**/ t& ^* K. r) Z# D- n3 `5 I
* platform_device_add - add a platform device to device hierarchy
* w* [* ^# U  j * @pdev: platform device we're adding
! }2 K6 K5 U+ z8 C# C *
- f; r- d8 S, C: A. c3 e+ W* ~ * This is part 2 of platform_device_register(), though may be called
( i7 B# G1 G) @* U * separately _iff_ pdev was allocated by platform_device_alloc()." F5 N" {, s' z- `; m- k% T
*/9 @+ |2 t4 K  N4 C% c
int platform_device_add(struct platform_device *pdev); S4 K8 c; C' a. W) o% |/ s
{
3 F8 G7 q; S. ^) I; f6 Q/ I& I        int i, ret = 0;
- u# Z! w" x: L: X3 q( k8 N" y2 m* r
% G% l% u7 z% V8 @0 o- U        if (!pdev)
- t1 R4 L6 E) L' x, n- I# f/ k                return -EINVAL;% w3 R9 E; M* M8 q

! b! x. b, v7 H! n. m7 W4 m4 F5 ?        if (!pdev->dev.parent)
, L! ]' G: r$ @" D$ M                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/
  a3 a, a! o8 w+ j: p/ k+ s. W7 U+ E3 ^' `
        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/
" Q- U# y- k- m2 u" K/ ^, h+ D" u& p2 _% D( _
        if (pdev->id != -1)2 x0 \. K, O9 V! p6 G) `/ x$ E
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);7 t/ N) `2 Z) m6 O
        else6 r& o5 T5 n" Y) O( N5 @4 |/ `
                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/
1 f2 y& \# e. _" ^$ r, t8 Z, ]) r& T
        /*遍历平台设备的资源,并将资源添加到资源树中*// A* j2 c, j5 C; k' D3 ?
        for (i = 0; i < pdev->num_resources; i++) {
# Y) I7 Z- R+ R4 C: F& n) @# i                struct resource *p, *r = &pdev->resource;
. U$ }- ?% |  e3 e4 g7 k
2 G# f0 d7 c& _- W                if (r->name == NULL)
3 ^  ^/ D9 _, n# F( c! x                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/( {+ Y* i' [7 B+ |  n+ s' G

( K$ q2 k( N) \% l0 R; |) d                p = r->parent;, p, n2 A$ ~3 @( o5 U, ?
                if (!p) {        /*p空*/
- m( \4 ~; V" P: N7 w& r0 u* q                        if (resource_type(r) == IORESOURCE_MEM)
3 m4 {, n, s3 m* t  l5 }' u                                p = &iomem_resource;  u# t2 P# _) p
                        else if (resource_type(r) == IORESOURCE_IO)7 q9 U0 `* M  [8 _% X
                                p = &ioport_resource;+ Q0 I& }4 @% d# H
                }/ {6 f( h) }& n- R6 {
* O( B2 n1 r7 g& b2 [7 i& i  E
                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/9 O( z3 I0 C1 K6 c( m8 f9 ^
                        printk(KERN_ERR' j3 J1 T# C! B* ?( A& A$ Q
                               "%s: failed to claim resource %d\n",
2 L% n  j; f) ~$ ^& o* A' O                               dev_name(&pdev->dev), i);1 l9 ~& k( P! v+ H+ R/ Y- G
                        ret = -EBUSY;, y" f% i+ H0 w4 R# y7 P3 @; D
                        goto failed;9 l4 s  W  o: S: w% n1 h1 O
                }
! }1 {4 w6 \* j  M! s- R8 G+ N7 z        }0 k( N* v5 U4 A; P# T4 ?
$ e& _9 I$ f! j. _+ S* l; D
        pr_debug("Registering platform device '%s'. Parent at %s\n",
4 P; v0 I6 t3 E( z1 ^1 Z                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
0 Q( ]; \4 K5 J( w
1 o+ Q- v& S- X# u        ret = device_add(&pdev->dev);        /*添加设备*/
' K9 S2 x4 [7 t( J0 v1 ?0 G        if (ret == 0)
; t" P" i# P6 [. }4 D                return ret;
1 R7 D2 n. _' I
, k/ ^% Y& W+ U  T failed:2 b2 T  g4 o$ s  t% D
        while (--i >= 0) {! C  ]) a9 A5 l% u. l1 f" @
                struct resource *r = &pdev->resource;
+ S" l! {2 {7 ?& \, |8 }' B9 K                unsigned long type = resource_type(r);3 h4 ]! V; X( v, v7 q& D$ T5 ]
8 k6 A; y! J2 T1 x( e
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)$ I) A8 V3 h. _2 o7 i8 s
                        release_resource(r);5 _" U+ d8 I' J
        }
$ p4 d2 ?' x" Q3 P, E* n9 A# k4 N7 u7 `3 ]3 k# a6 e* s( l* c
        return ret;( o1 T7 ^% R2 j% A8 o. [
}
7 w5 t6 w; Z: ~4 @EXPORT_SYMBOL_GPL(platform_device_add);( f- H$ V# q* D  a- O0 O) _0 h1 u
5 u# B; g3 E4 X
在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
/ w6 Q# l! d9 z本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。1 _' O# h+ \: S

. f# Y* l( S1 C那么这个"其他的工作"干了些什么呢?
, ^, ?$ W/ M1 a
9 Y; D" O) `: Q首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。$ p  `; D* o: ~0 `# C& C" x
然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。' `/ W  W/ C/ L$ X, m4 y

0 `' H, N0 T" `, \& Z$ u最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。% k6 R. w6 s# I! O8 J: f
  i) s3 q, B  }4 [
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。4 b5 e6 k* ?1 j3 Q$ T" N

! @% g  U) I4 g' h) B$ Q* u由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。
! c' u# H7 w/ B, @9 ^) @# P; I7 u+ _$ `0 _
6.3.3 不一样device_add调用结果
2 b5 F4 [' v% d$ o5 e首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:) W5 ^" t, X! ~4 |" Y1 i3 p4 e4 G

8 a+ R% J% b. V9 `3 b2 wpdev->dev->kobj.kset = devices_kset
9 _4 v4 R3 T0 s7 g. n; L  i" x5 X; ^5 V$ v: M, B2 F0 Q
pdev->dev-.parent = &platform_bus. w& `3 y: P, T0 j

/ u  a# b4 F" K+ _/ d. [pdev->dev.bus = &platform_bus_type! n  T+ _1 N. C
1 u) B' M* a" E$ g
set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。" B& n' M) _- n* N# u
, K3 B% \1 W# {6 f0 N
kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。
9 _7 p9 M; W3 l! }# N* N  x/ g/ l6 t7 F2 u0 x2 L; U7 L! D- K0 i1 P
device_create_file建立属性文件uevent。
; l; o- X0 f- T, k  `, i% ?bus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。
5 \3 m! T! F- N3 m
9 x  i2 H# ]) g            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。. h: p& |% M2 X
  U% \; d$ [' z+ T5 n. I
           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。& y1 @. ^  j1 p6 [

# N6 g7 w% q: |, s( w0 Kdpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。) Z6 g8 x; ]7 A- I% b
$ S0 \8 @) M  j( O3 c# ~, h2 n
执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。
+ ?- c) l5 F3 Y' x5 \
9 q; H3 O1 _2 y; v! s' r, U[root@yj423 s3c2410-spi.0]#pwd% f/ [( F& Y3 T% O' b8 D+ x
/sys/devices/platform/s3c2410-spi.0
( C/ D' d" L% A/ J% ~- p# \$ H- H3 h[root@yj423 s3c2410-spi.0]#ll$ U. L' Q+ k: t5 ^$ J; ~
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform
2 }5 i5 Y- U2 ~6 Clrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
/ p! ?9 e! t9 ^) }* I( _-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias
3 P) }4 C/ Z0 ~" w) tdrwxr-xr-x    2 root     root             0 Jan  1 00:29 power! P3 H3 K" f/ i0 ~% v" T) o
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
6 J; H9 p: @$ c  w" @, Hdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1) m0 F5 x9 c0 z; i) D$ ~& n, E1 G
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
4 c. I* a$ b% R/ S! ~lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform7 p  M$ m2 w4 T6 s- r( f
-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent
) w* E* s; D6 X+ i$ B, i; O' @' A4 @/ K4 b  O" H- ?
[root@yj423 devices]#pwd
4 V& D; o5 M# I; P/sys/bus/platform/devices
5 u) k* E9 a2 o, b' e4 F' m2 w: d2 r[root@yj423 devices]#ll s3c2410-spi.0 6 c+ A' p& e) O
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0
9 }+ S/ M1 @6 U1 c8 B8 W1 X5 j8 \通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。9 m/ S9 r" P9 ?8 r6 I- C6 \

- {1 `( u# L+ D3 Xbus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。$ h# h! h# a+ @" A: z, h7 N

! }5 E, A6 F+ P& ]6 e$ ]接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。
3 q! d1 z2 o6 b" J9 b6 ]% C  O' L2 n# X9 n
7. driver举例0 h! \" f) a8 ]2 W% k1 b6 T: r. K
我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。, L3 V. P5 B( F+ o6 \

0 k+ N- J( }- \- Q  `4 f7.1 s3c24xx_spi_init4 q; C: v7 {: T6 f
下列代码位于drivers/spi/spi_s3c24xx.c。
- @) m8 L5 V0 ^& X+ x0 [( M7 XMODULE_ALIAS("platform:s3c2410-spi");4 J* @6 S; P. N3 Z: g1 H6 d8 U  f
static struct platform_driver s3c24xx_spi_driver = {1 T) ?- W9 D* w
    .remove        = __exit_p(s3c24xx_spi_remove),3 }3 W+ W+ L3 ^$ s) g
    .suspend    = s3c24xx_spi_suspend,
. `# X9 _- ]* n$ w; M3 u6 Q    .resume        = s3c24xx_spi_resume,
% h2 T. g% [' O- Q3 Q1 T    .driver        = {
: `; m. C/ c8 X6 }        .name    = "s3c2410-spi",# x0 R6 [2 @4 H+ C$ S  \$ L
        .owner    = THIS_MODULE,
( E7 A+ M( u- |( P5 t    },
% ?$ C5 x: g) K$ s; X. @};5 w) F, [0 W9 V
* w: F# T% v4 ?, S
static int __init s3c24xx_spi_init(void)
. M. U  K% {1 Z. q{% [4 B% G1 `3 m+ p8 ~
        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register7 Q4 b7 ]* R2 E1 L
}
8 u6 l" x! G6 t+ X/ {" V6 S: [" @驱动注册通过调用platform_driver_probe来完成。
  \3 }3 U$ x; M. A! k3 i1 N注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。0 e& m- T8 Z" V7 j8 N+ m
7.2  platform_driver_probe8 V" i& t6 b1 ~, X$ f
下列代码位于drivers/base/platform.c。6 ^( E7 a2 n3 [
/**
. _# ?7 |. ?) D/ S7 }. S/ N& O* | * platform_driver_probe - register driver for non-hotpluggable device
4 t4 D- C! l& m; @4 Q2 a5 L * @drv: platform driver structure
; G1 Z* B- T% z3 S * @probe: the driver probe routine, probably from an __init section
& [0 `, P2 C- Q9 L3 h* d- t# K& { *5 P5 W: w& x* ]8 g  c
* Use this instead of platform_driver_register() when you know the device
' a8 X$ J$ B2 N3 C; w% E6 Q * is not hotpluggable and has already been registered, and you want to
3 s7 ]0 o6 C9 j * remove its run-once probe() infrastructure from memory after the driver$ Z1 H0 s. J. h" [( n$ t' L& |5 C5 y
* has bound to the device.
, V' @, _$ ~# ~6 u' y *
( J# E1 t+ Q0 K. Y * One typical use for this would be with drivers for controllers integrated
8 q% g; }5 d1 k1 p6 J7 Y * into system-on-chip processors, where the controller devices have been1 h) X; N' c, o; X8 V
* configured as part of board setup.
4 y" \4 w- U: T: i* Q( H *6 v6 ~8 ?8 O9 p4 @" B
* Returns zero if the driver registered and bound to a device, else returns8 p1 {! X+ m! m9 s) J
* a negative error code and with the driver not registered.5 Y* D7 O- V+ b
*/& e8 b, i$ I7 K
int __init_or_module platform_driver_probe(struct platform_driver *drv,! g/ [+ K; O& j% f
                int (*probe)(struct platform_device *))
& A: Q/ X4 d* S9 P. k$ [3 s7 W- k2 ~{
  V7 m0 O+ l% p7 Q" ]' d0 p        int retval, code;1 a3 e9 P2 q0 ^4 {

& o" V) |3 C; k3 Z4 f        /* temporary section violation during probe() */
$ N4 _: ^, G) O. u        drv->probe = probe;
. j/ i1 k; d8 a- R) w( t: w        retval = code = platform_driver_register(drv); /*注册platform驱动*/
7 y4 S( a9 j2 P) M/ c2 ?( g3 r* y0 c( a" Y- U# W" L& H
        /* Fixup that section violation, being paranoid about code scanning# [* v! Z0 N- S7 F2 I' N
         * the list of drivers in order to probe new devices.  Check to see+ S$ }( A$ R6 n6 d- i
         * if the probe was successful, and make sure any forced probes of$ Z) u5 E4 }& T, g  @2 `) S. \
         * new devices fail.) c+ ]- c3 ^3 b9 T7 p
         */
4 F' U& y2 b8 C2 n        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);: r" S% p  B8 e. ?# i6 F* s
        drv->probe = NULL;% ?, X; ?" O) h
        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
, [/ [+ q0 x  p0 u6 b% u+ @$ l# |                retval = -ENODEV;7 }/ s+ A/ `2 q6 q* Q3 N: z
        drv->driver.probe = platform_drv_probe_fail;
' d5 Y" s0 c6 N( ]8 x1 d% {; A        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);/ c3 ]$ U3 F' B8 O, P4 e: w
7 V  E/ x# |; Z; m% v% a$ o* t& y
        if (code != retval)$ `  O) F5 Z, _. [4 x6 J
                platform_driver_unregister(drv);
# P# v, \. i; x9 G) Y) e/ Q! h3 C        return retval;
9 O( E. l) j: \4 K8 E% C}
2 l# C) b  _: o- s- y1 [EXPORT_SYMBOL_GPL(platform_driver_probe);
" ^  m; Z- k+ P$ `2 Z这里的重点是platform_driver_register,由它来完成了platform驱动的注册。
% ~3 r% l; h! B! B3 K; C+ [/ w0 B% l7.3 platform_driver_register
3 K* O$ O2 e$ p' R0 U* [/**- v* ]6 u1 n* g: D5 a1 L
* platform_driver_register! ^' O# v- o5 g0 A
* @drv: platform driver structure6 `6 o6 s; Z# N9 V# ~$ g0 q$ G
*/4 m1 }( y1 \' n3 ^+ R
int platform_driver_register(struct platform_driver *drv)* s' ?( i" Z( x! B( g) y& t0 ]
{
  N4 z0 J7 F% r  `        drv->driver.bus = &platform_bus_type;
" U# L9 F8 P& a$ Y; L/ @        if (drv->probe)9 D% o+ o. r9 R4 [( @6 S
                drv->driver.probe = platform_drv_probe;$ l6 E5 e  V" b# y* l
        if (drv->remove)2 Z0 Y9 j$ S8 J& k* F0 b% d
                drv->driver.remove = platform_drv_remove;/ ~5 B/ p) P5 W* E2 V
        if (drv->shutdown)
; v: r' T8 Q7 {                drv->driver.shutdown = platform_drv_shutdown;
  C5 |; I( V: C* }1 i: X) D        if (drv->suspend)
% p9 x' z1 h5 K                drv->driver.suspend = platform_drv_suspend;
. |: R9 K% |/ E! P. d/ A5 A" c- m        if (drv->resume)8 ]2 b9 o. r: x0 m6 ?5 p2 Q
                drv->driver.resume = platform_drv_resume;
- n* y5 s$ d" k, D; z* S        return driver_register(&drv->driver); /*驱动注册*/
% T# I2 ^# B3 [# [; k}
( u% Y/ A/ K# a6 f) m& |' V+ KEXPORT_SYMBOL_GPL(platform_driver_register);
: B5 c7 R! G0 _- f: b  Q, F9 L* _6 _$ [
/ G; N& M5 z5 b# u! ydriver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。3 d! E9 [: k. U2 v
7.4 driver_register* c( X4 r; U% ]1 e; C# C6 Y( {
下列代码位于drivers/base/driver.c。
" ?5 E1 q( e1 m9 ]; D2 T% Y/**
. w$ i1 a/ H6 r/ X * driver_register - register driver with bus# {2 K, I, K5 M6 p- \9 ~" P" B* x+ D
* @drv: driver to register0 i* m2 x% o6 M6 s; ~
*
7 Q( W% |; ], t; Z/ F* { * We pass off most of the work to the bus_add_driver() call,$ A) ~- ]+ S# w6 X0 w
* since most of the things we have to do deal with the bus
2 g. [  o) s0 T * structures.
8 d9 F1 C' d+ W */
/ Y5 \1 t3 l, \) p1 s$ _8 mint driver_register(struct device_driver *drv)* C3 \1 o; ~7 B: Q. }& I  ^
{
1 D4 Z$ S) v  O4 ]* b        int ret;
" D, s8 }/ j2 C7 ~, g        struct device_driver *other;
$ D. q8 Z& r7 z$ O4 n! M
9 d! L3 v6 @' @* t        BUG_ON(!drv->bus->p);
# }' L! `, H7 Q8 P- K1 ~% R  h7 Z: J
        if ((drv->bus->probe && drv->probe) ||9 L- S/ c- N) m) P9 B3 ^% h- d
            (drv->bus->remove && drv->remove) ||! e' U4 L* }8 p+ b
            (drv->bus->shutdown && drv->shutdown))
# Z+ U6 h1 ~" H" T0 k. Q& k                printk(KERN_WARNING "Driver '%s' needs updating - please use "
5 k: o* O" w* e6 V                        "bus_type methods\n", drv->name);
" _5 H/ E: g6 ^1 o6 w
2 G8 m) N1 N/ r' R2 @0 `3 ?# s  a4 o: \        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/- k' e" p# n* s
        if (other) {        /*存在则报错*/
  j4 L8 t0 j* a* F  Z7 v$ |                put_driver(other);
/ H7 _" _. f9 e% x/ e# y0 B: D                printk(KERN_ERR "Error: Driver '%s' is already registered, "
9 G  H1 H' W8 W0 l                        "aborting...\n", drv->name);
& @- e4 J. F2 Q8 A0 L7 z+ x                return -EEXIST;7 @+ T1 r+ p' K% a4 S
        }
  z( A" `" R% n% ?4 I1 \0 ~5 d1 p0 n; A* a" I- K. H
        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/1 {0 [1 Y1 ~( O2 c$ @
        if (ret)2 _' `7 z! a' Y7 C1 x1 w
                return ret;
3 \. k( g: I2 @* q) _# [        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/( r. o5 F) E% F% E# i
        if (ret)
, r' H3 @1 G  L1 x9 c' x                bus_remove_driver(drv);/ n  Q" {8 d+ E+ M7 A
        return ret;
* C, O2 q3 S$ m$ V& W: t& H7 ^: L}
& m1 Z& ~, u- h3 X2 z1 d. \EXPORT_SYMBOL_GPL(driver_register);
5 K( J$ }+ I3 Z( o) m这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。  C$ e- ?0 {9 ~8 T8 g! d' t9 }6 g7 ^$ ~
接下来就分析这两个函数。
& E0 ]8 _$ y8 j5 n2 e4 U3 ?% ?3 ?7.5 driver_find1 u- N0 Q' T& \1 z' `
下列代码位于drivers/base/driver.c。' ^) ?* [' ?) f8 J1 X8 B& t
/**
9 `3 x9 J! V7 E2 |6 c$ J * driver_find - locate driver on a bus by its name." m5 P  [" P# c1 H
* @name: name of the driver.
" c* b6 ~" `/ ^7 l: c * @bus: bus to scan for the driver.
" }- i+ M  @4 R' n *7 r' d, x; i) F% j; S# {4 ^
* Call kset_find_obj() to iterate over list of drivers on
5 n& O* p3 a& G: w' ]  t9 ?3 @ * a bus to find driver by name. Return driver if found.
+ I8 H  i; f" z *4 m0 A: _9 l  J" y/ L5 s/ L0 K4 k9 _# [
* Note that kset_find_obj increments driver's reference count.5 n) V! f) Q/ \& W2 a( C% J
*/
) L1 {4 @" E$ astruct device_driver *driver_find(const char *name, struct bus_type *bus); l9 s( }4 b5 Q0 v6 R( c/ \; v8 t
{
: [% `% H  Y- q2 ~+ `7 y0 n, p        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);  U1 N7 B& `* }2 i# j
        struct driver_private *priv;% o2 [5 \' S" u; Q& T1 G
9 e, W1 F2 x+ J$ x, D+ Y( t
        if (k) {+ s. c' _! B! s& n9 ]5 O8 y3 Z
                priv = to_driver(k);
& _8 o8 \' T( e$ ]                return priv->driver;
, t- E' e8 z" j        }
0 b/ Y+ K. _- H) Z( L# Y        return NULL;) n7 B; W" P, L& j. z
}
+ F! N4 v3 t7 a3 Z+ _% WEXPORT_SYMBOL_GPL(driver_find);: W- S6 N" R3 h4 b7 k; y
1 f$ t$ w, }$ ]$ i
/**& l) Z9 X  w* F/ |) S4 p" c* b
* kset_find_obj - search for object in kset.
5 p. i3 j4 ^( x3 J( s3 ~  m: @- a * @kset: kset we're looking in.
6 C5 C. d5 y* m, e# G. b) N * @name: object's name.& L$ ]# |& }& B3 q! O' k
*
  a. K' z& w! T9 J2 \ * Lock kset via @kset->subsys, and iterate over @kset->list,+ I/ c# _. X2 D
* looking for a matching kobject. If matching object is found
5 p. c3 ]8 E& s" l0 G3 k * take a reference and return the object.
% R+ E' F* h( T6 t% r. ~: O */) N; V# d  G0 D7 q
struct kobject *kset_find_obj(struct kset *kset, const char *name)+ e9 b8 u3 I% j2 ]7 k/ b5 K7 w* s
{) X; ~$ _6 Z3 b# w5 _
        struct kobject *k;
3 `7 C6 ^" {& [# h* h6 e        struct kobject *ret = NULL;
% L( K# \( t$ h' w
* H! {4 Y4 ]* C5 s$ {        spin_lock(&kset->list_lock);
0 o/ a' `  E8 M3 N8 |        list_for_each_entry(k, &kset->list, entry) {- h5 Q+ S, f. z2 U+ {( |
                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
- _! ], N. Q! ~  a# Z. E                        ret = kobject_get(k);
- G6 U' q7 ^  b% N                        break;
+ l6 G4 N/ I- l, O                }
. [! T0 L$ I. w- [; S        }" @& V1 S! Q  J% q/ K0 ]% B
        spin_unlock(&kset->list_lock);
% L8 f/ b! T6 y! o4 }$ v9 n5 j7 W        return ret;
, N/ `. E. y$ c4 v; i}
' k$ L* V+ m' {4 d% n# x1 a这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。7 f  U) L7 W) \* H* c) v/ m
7.6 bus_add_driver# X* l# z5 z+ L; p6 |
下列代码位于drivers/base/bus.c
# r! O+ e: `5 D9 r9 r8 i! \+ k3 m* [' c# _- s+ c
/**
- Y# [9 Y) b) X * bus_add_driver - Add a driver to the bus./ U9 w' t$ I# O# q/ y4 W$ ^2 ~
* @drv: driver.
8 O0 \( V. H! _2 B- A */
+ ^/ A, e3 L  f9 V+ {int bus_add_driver(struct device_driver *drv)( |/ B$ i- N" [" x$ Q  m- U
{
8 V3 p6 N, y$ M$ E5 @+ [        struct bus_type *bus;7 `* h9 ?. b5 r% l# h
        struct driver_private *priv;9 [2 ]7 {7 S8 ~" W' }3 t2 ]2 {5 N
        int error = 0;
) h9 O" a4 w& Q. _7 g
* J" n& Q  q+ h8 W        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/
; _) ?/ b5 b* w- N8 P2 }8 |0 C1 `        if (!bus)3 K5 U2 a( i! j0 P6 d; {. O# j6 u
                return -EINVAL;
1 ~" z0 Y* d. C( t2 W  B* x6 d" y
/ P2 V1 n! ]3 d, y/ q        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);7 G# _) M$ _8 ]) Z
" b( Q8 X  G! M" s% C/ u
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/5 V( [$ S# C( l5 Y
        if (!priv) {
# X3 [" W7 t6 T/ k' u3 Z                error = -ENOMEM;# v; ]! C7 n7 j* G. ?, `
                goto out_put_bus;0 W2 `! A: h6 k6 I* n( R$ F3 X
        }
# s! ~% [$ K8 n$ u3 g        /*初始化内核链表*/
" t) l, ~4 r% H3 o        klist_init(&priv->klist_devices, NULL, NULL);
0 S2 J5 [  v3 K        /*相互保存*/
& }9 K/ K% z7 Z3 g1 R# r2 q        priv->driver = drv;8 Y& n8 e9 I5 ]/ F3 E8 U+ b# Q
        drv->p = priv;& U* y7 W' M5 |+ q6 K
        /*设置该kobj属于那个kset*/& S% u& P# ~% I8 C: Z% r8 H
        priv->kobj.kset = bus->p->drivers_kset;
* `' W) D$ J7 \4 w+ D9 E        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/+ k# ~* b# a* h6 m* i8 I& L( L
                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/, A2 D, o1 N" X
        if (error)
) \8 ]4 V5 B0 n  ]8 g1 t6 K                goto out_unregister;
, g+ s# o" C# }# i, Y6 j5 g/ p8 Q" o8 b& O$ B) c9 I
        if (drv->bus->p->drivers_autoprobe) {
. E9 E7 r  Z9 d2 Q# H                error = driver_attach(drv);        /*尝试绑定驱动和设备*/  ?. e* }- _: {4 f$ v+ s
                if (error)
/ e: l) \: \5 J' ~  [/ V/ r                        goto out_unregister;4 K$ d4 q; m5 H( i
        }
+ \* q7 @& h$ V/ b        /*添加该驱动到bus的内核链表中*/
7 E$ `1 e: |  Y% m3 \" o' x        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
, s4 M& J! h. B$ B( k% i' ^        module_add_driver(drv->owner, drv);/*?????????*/
9 l: ~9 K1 @& L7 ~% [% L+ J7 @: u* C9 _
        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
9 b2 n1 d" x6 l$ p        error = driver_create_file(drv, &driver_attr_uevent);
2 O7 [% c6 S  j( T: Q        if (error) {4 D& S* a) |( o; l
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",8 |3 c; x/ `0 R0 U  E
                        __func__, drv->name);
" m+ y5 m7 o. K1 N! k/ ^; k        }
. `+ w% U  t6 a/ G: G& o. n/ n        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/
) h3 x% ^# C5 h' J+ @+ V        error = driver_add_attrs(bus, drv);
! b2 n3 n- M7 {7 K6 J$ x        if (error) {- h- x3 ?. \; s
                /* How the hell do we get out of this pickle? Give up */
# q1 M  z: E7 J+ ]  @# a                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
3 U# V3 c0 I2 S2 n5 W! Z2 F; t                        __func__, drv->name);! M2 G* ]. @  z* f% \( k7 ~
        }2 o+ c5 ^( ]' H* J) b
        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/* H9 j# r8 F- x) _/ m5 i, @( l+ j
        error = add_bind_files(drv);/ U  e/ p5 m3 f1 Q
        if (error) {# l3 E  ^* ]2 N( k
                /* Ditto */
* w6 t2 Q8 A) r. B) d& l3 \                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",8 j1 {) Y' a  G7 g: p
                        __func__, drv->name);; k; \$ m- ?. e
        }% z3 J( M2 b+ d5 N& s
        /*通知用户空间???*/$ P3 L9 g! B5 ~% G2 j
        kobject_uevent(&priv->kobj, KOBJ_ADD);
' r9 _0 v( w- {& Z: u        return 0;
7 f4 H% L& P/ D' w5 b8 }- e5 Fout_unregister:
' e: E1 ^4 n# G/ j5 K" J        kfree(drv->p);
+ }7 g$ Z8 o; r# o        drv->p = NULL;9 z  Q* b0 i, q8 }6 a: K
        kobject_put(&priv->kobj);3 Y2 \/ j( p/ V
out_put_bus:
; I: [! D. {' w7 k" ?! H" ]* f; p        bus_put(bus);
0 `  [$ ]3 J7 i* j9 o( ?* n        return error;0 m2 N7 W; a/ ~+ t& |
}+ p9 i8 ]2 l( A! S+ ]. H
在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。
7 r% z% J* W* L6 |( h4 D2 D7.6.1 kobject_init_and_add
9 f7 ]& Y1 \7 k( _7 W( J6 g5 D下列代码位于lib/kobject.c。
% J# R# Y- |& I" x+ o/**
4 |+ |9 m; o. E* L4 z* V * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
- Z, _$ j3 M- X/ t, c * @kobj: pointer to the kobject to initialize) d6 v2 W$ Q: H( A4 Z0 Y
* @ktype: pointer to the ktype for this kobject.  u- Y' R) k9 T9 L* |6 r
* @parent: pointer to the parent of this kobject.
7 ^' h1 Y8 \  J4 r * @fmt: the name of the kobject.& Y5 s% |. \2 R
*
8 N2 m' u' ?' k/ I' j * This function combines the call to kobject_init() and# [( a' z. t1 {' b
* kobject_add().  The same type of error handling after a call to
9 F& e! x& c' c" D; A! ] * kobject_add() and kobject lifetime rules are the same here.
9 C4 n! l" q; \! S! u */
. I; q2 S" X5 m9 Z; Mint kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
1 F4 \7 N- j% o; x                         struct kobject *parent, const char *fmt, ...)
0 U; C8 h  @1 x  g$ V! C{$ P' E" h) [) a- c0 ^5 Q
        va_list args;# V" F8 Z; `) f7 ]* R% ?/ s& h$ ^
        int retval;2 k3 l' H0 c& Q. Z% N1 P

' q/ L$ ]3 h* J3 }/ |        kobject_init(kobj, ktype);
+ q# b% V0 t) _9 k3 U) N' ], ?& p+ s0 G  \0 C+ k& d, r
        va_start(args, fmt);
+ [6 b) _: S+ B, X# A5 A        retval = kobject_add_varg(kobj, parent, fmt, args);. K! z: }  X1 C
        va_end(args);$ W$ J2 `' c! n: J

; J% n. a: ?% E        return retval;
- ~. P$ F& e" E: C}
% e" H, }7 Q+ Z8 Z! z, nEXPORT_SYMBOL_GPL(kobject_init_and_add);
( r: N4 X; [, b; J$ X) K$ ~该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。- s' m9 F) Y/ X6 _
调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。
; E0 x0 F( ]' b& ~* H( Z! a" M2 u
7 ?: S2 Y, X" }我们来验证下:' K( x9 i8 e  M7 }

4 t- ]5 B: m2 {6 {( a# c2 `[root@yj423 s3c2410-spi]#pwd. Y: K3 _+ I% R- Z; b  ?$ m" n
/sys/bus/platform/drivers/s3c2410-spi$ S0 k0 m" T# f3 t+ V
接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。
1 E' f- N/ R+ a) `3 n% u! T8 V: }' Z, S( t9 B2 |8 w
7.6.2 driver_attach
! l5 \9 S+ {4 [7 ]- a1 S下列代码位于drivers/base/dd.c。
2 Q5 R7 |4 }! n+ @/**% k$ @) ^$ X5 H8 |& H
* driver_attach - try to bind driver to devices.
% i# x/ O  E0 ]9 L7 v% \; _8 K * @drv: driver.3 O# g7 L' i( F/ \$ n2 k
*
. Z0 D$ z8 `. K/ g  P* W * Walk the list of devices that the bus has on it and try to
8 r8 e& I8 O6 C: K; L * match the driver with each one.  If driver_probe_device()
$ a+ @% Z  B) W, N6 Y: v" s * returns 0 and the @dev->driver is set, we've found a
% [$ e# T6 r% h- t( E * compatible pair.
9 r7 s( V1 |  W/ T: V */0 x7 Y' f/ J- |
int driver_attach(struct device_driver *drv)3 m9 w/ x% G. g5 Y  B2 X
{: R% |5 x0 S1 O, s7 k5 V/ G
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);6 x6 e: G: D' D7 e% q: [
}
% D; D/ Z. D9 h+ I+ i3 X5 v+ G& AEXPORT_SYMBOL_GPL(driver_attach);5 P7 z9 c9 e- B8 s* y4 m& v
该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。
% g) [1 R" N7 n# t+ c( \, E这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。
+ j# U$ L  g0 G1 K0 Y5 |
) ?0 @% X1 x# z# Q( ~( z. n2 E/**
9 R& ~  d% T- f  t * bus_for_each_dev - device iterator.
( j. |" V6 G+ [1 x * @bus: bus type.$ @) l4 O' r! Y1 v3 t
* @start: device to start iterating from.
2 t0 Q0 M2 o0 w# \ * @data: data for the callback.
1 }  K2 {: ^. M+ E8 [. j: T * @fn: function to be called for each device.
% t! m3 r" e7 x2 [$ n4 h7 _ *1 u- [% K" A( }- S4 e8 V( f/ d8 x& H
* Iterate over @bus's list of devices, and call @fn for each,
  r7 X7 x1 c( ]" M * passing it @data. If @start is not NULL, we use that device to
# U9 n& {4 T( m7 } * begin iterating from.
1 `4 F8 a4 @5 F" Q8 d$ U. j *
# w: U9 A: g: b0 U. F2 [* Z * We check the return of @fn each time. If it returns anything0 k+ o+ N. e  d- v# e4 L
* other than 0, we break out and return that value." V3 B7 @& q" f6 m; [
*
3 O; B/ c" ]4 Z * NOTE: The device that returns a non-zero value is not retained, i2 p2 G5 J$ C! w* M' k. L, X
* in any way, nor is its refcount incremented. If the caller needs
8 m5 v5 g2 g& U4 ]) q * to retain this data, it should do, and increment the reference3 I8 d* @$ |! O- G- t% M" t/ V' s8 z
* count in the supplied callback.
6 d4 P' f& _/ D# ]' R5 b9 c */+ j, g& Z5 y7 w4 P# M) D
int bus_for_each_dev(struct bus_type *bus, struct device *start,
0 V% p- K3 H  N2 [: k" ?. f) b                     void *data, int (*fn)(struct device *, void *))( d7 `, q9 y1 |3 G5 ~& C, y( v
{3 g' |5 P) k$ U  b8 ?; }
        struct klist_iter i;+ w4 K* C  F, z4 Y
        struct device *dev;8 q  W- O; J! p/ n0 q1 Z
        int error = 0;
4 w9 f5 v% z' {4 F. `* [$ J" V5 C4 c" N; A# a5 C
        if (!bus)+ i% P9 N9 Z- v% S1 ?
                return -EINVAL;
7 j6 l/ @3 Y. T' }* N+ O. x
, @0 I  x  r3 O0 N        klist_iter_init_node(&bus->p->klist_devices, &i,* U# c8 Q5 _% v
                             (start ? &start->p->knode_bus : NULL));
. U$ R: ~, J3 @  R* F7 l        while ((dev = next_device(&i)) && !error)
. n' z+ a' n! E5 |                error = fn(dev, data);
& u- ?! e. R" H; n        klist_iter_exit(&i);& b0 B4 k' L+ z. K" D- ~/ G
        return error;
+ t, b# \' e" }% W" b$ K}$ U, R/ P9 ^2 S2 C) H4 D
EXPORT_SYMBOL_GPL(bus_for_each_dev);3 v+ Z* _+ K% M$ c, O
通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。4 }7 n+ P' m: j4 A2 t" [
static int __driver_attach(struct device *dev, void *data)2 s( e$ W* r+ y: j6 \
{
, N3 U  ^% t2 _! D4 k; \1 G        struct device_driver *drv = data;
  |5 \, n# s1 M6 S9 ^7 `5 F  `
4 \0 d6 ]* F/ G- ~! q        /*
9 {0 j, {+ `7 q- ]: Z" c# ~         * Lock device and try to bind to it. We drop the error
2 ^; O( l  g/ D+ h$ a5 W( A8 a. S         * here and always return 0, because we need to keep trying
, B( C! k; u. Z9 S! K         * to bind to devices and some drivers will return an error9 C5 J* x' n. p6 p# \, y1 l
         * simply if it didn't support the device.% y5 S# N8 R' x+ w
         *
- X, ]2 h5 w0 x0 X. t' i) }         * driver_probe_device() will spit a warning if there" }# `8 q8 F- P1 W/ f7 N3 h
         * is an error.# l6 w! C5 ?8 J4 ^& u% c# L1 u& q
         */2 _' u. c( M+ [
. x! \( O, s4 @" C( f$ A3 R. a
        if (!driver_match_device(drv, dev))- `) F3 e! A/ c4 y
                return 0;
1 r$ L" q% B+ {# M
4 c( u( t2 j: u6 F1 f        if (dev->parent)        /* Needed for USB */
2 s( ^# W0 t) m' R# o                down(&dev->parent->sem);
& E8 y; C& J5 N% ~; s% ]% U) u        down(&dev->sem);
- L) a4 J- R  i  }6 h        if (!dev->driver)
5 }0 _$ S1 h# z6 S& l5 E( H                driver_probe_device(drv, dev);9 X/ V0 L) O! P: Q) h: y. z- \2 X, ^
        up(&dev->sem);
! {, i( ^5 k1 r: R! j4 o) ]" _2 `        if (dev->parent)
4 t: S2 D; |/ j# R                up(&dev->parent->sem);5 T, \# G1 u! N7 j; c6 \( p

# q6 I. S. _, ^* J, ^' g- v7 Z1 |        return 0;
7 {( D  e( C- g3 `. a8 h1 X4 b4 u}
' m# r( v- ^3 Y0 i3 |# U# m首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:
& ^. X" n! v1 D: X( r9 |static inline int driver_match_device(struct device_driver *drv,
" B; h' s3 ^: Q, G$ ?/ m3 f7 K                                      struct device *dev)* }( ~3 z1 ~) g& F7 U
{
6 d& I# m7 {4 j8 P, i) h4 [        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
# ~9 @, _5 W0 `$ \7 C}( }; ?1 A' ]1 S! w
# {$ a( D6 h: P0 a4 U. Z0 s% ~
这里直接调用了platform总线的match方法,我们来看下这个方法。
/ f% }+ G. R0 X/**
9 }, s! \! F, O * platform_match - bind platform device to platform driver.+ F5 X- O( a7 z" X& @" x9 E
* @dev: device.
- e1 n9 f# V+ h * @drv: driver.
3 O+ V; l. I, h) g% x1 N- C *
; z( T) m" T' i * Platform device IDs are assumed to be encoded like this:
1 ^- ~8 u9 y3 q6 `8 P1 N * "<name><instance>", where <name> is a short description of the type of) L3 d' {5 Y0 p4 R5 k( V$ K& e! w* l% H
* device, like "pci" or "floppy", and <instance> is the enumerated
& k) a% }5 E- M! l: A  B * instance of the device, like '0' or '42'.  Driver IDs are simply
: i' I5 q: {) M( p- E/ E * "<name>".  So, extract the <name> from the platform_device structure,+ W" W3 a5 Q  u' M6 D% u
* and compare it against the name of the driver. Return whether they match8 e: J# }$ U1 l" G9 Y( E; l1 _
* or not.
) Q: M" o" Q+ W( W0 E) i */) Z; k" r' v7 w' M! \6 f
static int platform_match(struct device *dev, struct device_driver *drv)
: J! o& }' o. e2 q) U{; o/ J- G; Z9 L. P: D0 x
        struct platform_device *pdev = to_platform_device(dev);) G. [' N6 R$ @) o2 @; [7 t
        struct platform_driver *pdrv = to_platform_driver(drv);4 x/ Q5 l& u2 f( F% I

( C6 {0 H8 d% x  M        /* match against the id table first */$ u- n; L, q/ S# R4 x1 p
        if (pdrv->id_table)" e6 M( W+ b2 u- Q& ]; e' F
                return platform_match_id(pdrv->id_table, pdev) != NULL;; v( n/ O6 k4 t8 [& \1 F
3 V8 N% q  s6 G7 w
        /* fall-back to driver name match */7 ~$ t& b4 B% T- ?
        return (strcmp(pdev->name, drv->name) == 0);
* F2 F4 s9 |3 H5 q}! F: c) O' `# v0 i$ v
该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。
- A' T9 s9 n: N4 G8 C在本例中两者同为s3c2410-spi。因此匹配完成,返回1。7 z# c: A  e- U

( r) T, y: w; n( e' H' x& l) Z; X返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:
8 g, W1 J3 \& j6 ^
. C9 y# H' V4 `" |( {. Q% o3 Y, ^$ e/**! W6 d; [- _2 u+ s
* driver_probe_device - attempt to bind device & driver together9 ~* r6 W, B1 B* H$ a! C* ?( W- q
* @drv: driver to bind a device to( f" |) r% Z  I" W% X7 D! K
* @dev: device to try to bind to the driver; y- }) m& N  f  Q
*
( U2 M3 `  b! I3 ], A+ D * This function returns -ENODEV if the device is not registered,
. [' x5 v3 @; I, [$ b" o * 1 if the device is bound sucessfully and 0 otherwise.& C$ X9 n! @7 T3 Q+ J# O' l
*
5 q" m( `1 @7 V( s8 `' L6 i * This function must be called with @dev->sem held.  When called for a/ @' V2 G/ Z' \/ c" H$ N# G
* USB interface, @dev->parent->sem must be held as well.
% G7 ^  u$ q0 n6 U4 P. a7 N */5 w- _4 u1 t5 u- j9 F; ]
int driver_probe_device(struct device_driver *drv, struct device *dev)3 `; f( z! F. D4 q+ q
{
9 c: u) Y+ [6 m3 `        int ret = 0;4 F7 q- E. X) J6 S5 d
% b* J- V8 @3 c9 R5 m
        if (!device_is_registered(dev))
7 O9 B; t7 _. }4 N                return -ENODEV;
  O+ v' _# i7 P1 R1 Z
1 J7 t' P# T, \0 ?        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",: C. ]+ L' d5 u, q
                 drv->bus->name, __func__, dev_name(dev), drv->name);' z( q/ ]& e* O
; P, L$ X7 ?5 c
        ret = really_probe(dev, drv);; i2 k  ^3 ?3 o0 U

2 i3 \0 I" i# C" P) s2 r+ r/ b        return ret;
4 Y, h& ?% y% |6 q7 K  z2 H6 f}4 {' @- e' f5 F4 R  h1 F' K
static inline int device_is_registered(struct device *dev)
! Z' y+ v- K# M{
# b3 V/ |# C' X3 Q7 z    return dev->kobj.state_in_sysfs;
! Q/ g2 E6 E, \0 F, J}7 V$ ^+ Y" A+ p: Q
该函数将调用really_probe来绑定设备和它的驱动。! x# ?5 B4 _: \1 s1 t5 i7 \
static int really_probe(struct device *dev, struct device_driver *drv)% {1 P9 y% a1 u, I, q
{
- y8 G9 P, \! U8 }0 {        int ret = 0;
3 o* [) _( R6 x) I
1 p+ U# r% H# f& Q; Q        atomic_inc(&probe_count);
& C" L( N3 K  R" X        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
; S: c" |5 y$ P6 @2 o* h$ H                 drv->bus->name, __func__, drv->name, dev_name(dev));$ `  ]3 W: H- D9 Q3 K' Q7 f
        WARN_ON(!list_empty(&dev->devres_head));" i0 o' ^, y' ~' n& Y

6 S2 b, W1 M$ ]1 w, b% v        dev->driver = drv;
2 t4 D. }0 j5 r( J        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/9 O, Y. @# v4 F9 x+ L
                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",9 ~: v9 A: b4 j* i& U0 J& \0 f) Z( j) M
                        __func__, dev_name(dev));
& h" ], ^6 C+ M. }  U$ Q                goto probe_failed;
  L2 }# s6 D; ]7 ^# j! \# r( X        }
/ S; W$ |! v6 ^( s
- r& y' q2 \% a1 A  q6 s) g        if (dev->bus->probe) {& i9 @1 g$ q+ D: ^( W
                ret = dev->bus->probe(dev);/*调用总线的probe方法*/
  D- l; h3 X3 L: k* ^3 E/ _                if (ret)3 n- n  g' V! W2 t/ N9 N; {
                        goto probe_failed;5 O7 u5 O" ^1 R0 V
        } else if (drv->probe) {
+ C  j3 ?- I4 \" H5 k( o& c7 l                ret = drv->probe(dev);        /*调用驱动的probe方法*/
- V. P2 q; V1 T                if (ret)
8 j3 I  j( ?# `) f0 Q8 {" R# i                        goto probe_failed;5 K# Z( ^1 ^! J: x/ p  Y
        }8 K( p) _7 e) J
+ Q) A; _& c0 x6 s9 D- ?) F' q
        driver_bound(dev);              /*绑定设备和驱动*/+ I- T  X9 N2 `- c- h( q/ G
        ret = 1;
9 w! n- K# K, U' `+ W5 M0 e        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
0 l9 C$ E( X$ H9 Y9 Z6 a) B/ H6 p4 ^                 drv->bus->name, __func__, dev_name(dev), drv->name);
3 ]4 }5 r  I% U        goto done;4 e% B8 Z% Z! d2 X2 H$ Z
: U5 q5 u/ K( r0 E$ y
probe_failed:& g7 e9 L7 n3 [8 I4 a* [% @+ [
        devres_release_all(dev);& s6 |7 r% J1 k% J
        driver_sysfs_remove(dev);
* V2 Q% ^. f0 u2 m* X) e        dev->driver = NULL;- T* m) o# V+ }1 f) b
: I1 U; }2 b5 H
        if (ret != -ENODEV && ret != -ENXIO) {; ]/ x3 X9 e# I& w! k
                /* driver matched but the probe failed */
- w' b2 t/ C) Z- T' M! s                printk(KERN_WARNING6 B' M: c; l% u2 [5 I8 k' r5 D
                       "%s: probe of %s failed with error %d\n",, m% m# _& L4 _) n8 K" d* c* k
                       drv->name, dev_name(dev), ret);, w: z# K4 z) P5 p
        }; z5 j8 y, Y  |" [% p! m; y
        /*
' K8 P* `6 b& Q1 X         * Ignore errors returned by ->probe so that the next driver can try
5 h+ F. b, c- |4 Z# F0 j3 l- t+ H5 Y         * its luck.
0 L$ ]: K$ z; l2 _" Y         */
1 p3 u" g; N( g/ \# `$ G; o7 Q6 Y        ret = 0;
' a4 s9 z9 _$ N6 \& Cdone:
" V0 C( T7 ]0 t        atomic_dec(&probe_count);
5 l9 q  E+ J7 {% U! x0 L/ U1 C# {        wake_up(&probe_waitqueue);8 c/ n3 _. [6 K7 [% y8 `/ U% E
        return ret;. k# m3 x# o3 {/ w, {
}; k9 P: Y; y' m. d3 {1 M1 P/ e  c4 j

7 T# u$ q% ?: _" V在这个函数中调用4个函数。
  F$ W2 ^/ o8 \* J
  {  G+ U4 o- q* [% k2 ]/ c! X3 ?第一个函数driver_sysfs_add将更新sysfs。
" H$ G4 ^0 I1 `4 E% U+ U9 Z( A: q: h$ |: y
static int driver_sysfs_add(struct device *dev)
! \/ U( S# }" p" v* ]7 Z$ C{
+ |8 x; x0 n/ \) ]        int ret;
) L( E  j$ C; ^6 U+ O- \        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
2 @/ C* u/ J6 y4 L' l0 J           链接指向/sys/devices/platform/XXX */
. |& i+ k. G- b: E8 {        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
- X  M( F& Q7 T+ [5 g                          kobject_name(&dev->kobj));
3 C% m2 e2 j- p2 s        if (ret == 0) {. Z# O8 L) T; W; o
                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,% m* Q+ C, Y. I7 w/ x4 ?6 ~& i3 X* k
                  指向/sys/bus/xxx/drivers目录下的某个目录*/+ J1 _3 B* `, x# {0 m
                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,5 x7 t- m) U4 g" F" Z
                                        "driver");
) o" F! I8 n3 r) X4 p6 ]( @                if (ret)
4 t# }- O7 {8 u5 i# L                        sysfs_remove_link(&dev->driver->p->kobj,0 f/ D  o. p8 u& v- {# a5 y$ F- f
                                        kobject_name(&dev->kobj));
% C- M& D* x2 Z' V' z- ]        }' o' |$ p' D. Y; M" M) H
        return ret;/ _2 t; |3 ^4 W4 P2 I/ u+ f3 O% y4 @
}$ A- [2 D" g/ _$ a& T- U
* x3 `8 G4 [( a# Q  w9 C% E
执行完以后,建立了两个链接。
/ O9 b8 f# Q6 ^  a在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0
  }) r7 y. O) v' d1 v在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。
7 c" ^* ~  C8 m这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。6 L7 [( n+ ]. V' |, \% ]% g, V( N% `$ E
" A) N# |: q% R& N! Y" u3 Q2 i
[root@yj423 s3c2410-spi]#pwd# ?9 A4 _/ ]% }( k
/sys/bus/platform/drivers/s3c2410-spi; E* C8 w# u. O( [4 x
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 + A' o7 [, b) E* U" l$ y
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
1 w  B* w; C% N2 G/ C( k+ ]; I5 i[root@yj423 s3c2410-spi.0]#pwd
+ R/ X: S! `5 Y/sys/devices/platform/s3c2410-spi.0
* z. D7 h1 z8 f$ S+ Y) Y0 X+ |[root@yj423 s3c2410-spi.0]#ll driver
) e/ h* m' {2 D; X; D% e6 Y1 glrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi0 W, Z3 N1 y6 P0 H1 Z
# H4 N) E( z0 C6 h/ e
第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。) Y( U& F( E; [- J) ~

/ ]0 [' |9 k( J$ e第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。+ R, Q/ \* h9 m; N( Z. |0 X9 ?
3 ?! h) t) Z, z8 Q  U. I% g
第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。
# B% S: D- a+ g- b" X. z& Y1 e4 f: d
static void driver_bound(struct device *dev)
( }, g0 v- ~/ v* G6 t- S& ]  d+ l8 H{
& o* _" f6 D/ d6 V        if (klist_node_attached(&dev->p->knode_driver)) {
" w+ ?- M2 ?2 ?+ i                printk(KERN_WARNING "%s: device %s already bound\n",+ F/ f1 t. S' I) T, Z- ?
                        __func__, kobject_name(&dev->kobj));, ?! [" N4 ^% n* g2 J" j7 n: h
                return;# F. D4 p: ?0 r8 e+ u9 D
        }
. Y0 u1 Z* S6 ~+ [' J  J
8 _& x: v$ q- I4 K+ G8 K) J* G        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),. `' `: M) ^5 B
                 __func__, dev->driver->name);
4 ^  w% T9 H' z' j# S! `$ ^& n+ b3 s) G
        if (dev->bus)# A5 R* [6 v; `1 y/ I4 S
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,9 n' p5 x- _8 W+ q1 R: C5 a
                                             BUS_NOTIFY_BOUND_DRIVER, dev);
8 N) A! w( B2 W9 L$ L3 Z% f/ R( m: d3 [- o+ q9 M* j
        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
7 I! u+ [7 E0 ~$ A9 R" a}0 W; e: A  ~1 F& D. h* q+ j+ J9 F; V
其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。1 T1 h1 ^% U) ?$ ~
至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。
, }0 M; X  F) V2 |4 \' Z0 _+ o' E6 J+ O' Y( T
在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。
+ O" j% J) E& O1 c( t  i6 Q. N1 B0 r. \: ~1 V, o
首先,将驱动添加到总线的驱动列表中。
% a5 p: y0 [9 ~" K% W- @接着,如果定义了驱动属性文件,则创建。/ b# H) H* [# `( _/ ?' ?! p& I
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。
& ?( O; C0 |3 j& Z: y0 x$ j
+ q1 \0 L5 d8 U& h. c: `我们来验证下:5 _6 |4 T7 x3 g" W( Q

% Y% |# i: w1 J/ h6 u[root@yj423 s3c2410-spi]#pwd
, S: k; ~3 {7 k/sys/bus/platform/drivers/s3c2410-spi# t) Z; g4 o5 @& |
[root@yj423 s3c2410-spi]#ls
! e  q$ _1 P3 r8 I+ I* \bind           s3c2410-spi.0  uevent         unbind/ e$ A& l6 s0 D5 S. o
7.7 小结8 r- N3 G4 T) t4 {) m4 @
在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。: \- m( @) a; v% \
# @- o2 d8 S; S$ @0 U2 M
同时,还更新了链表的指向,在内核中体现了同样的关系。) Z4 y2 N5 c: e! w
) ^+ r, r, X1 H4 q/ G' {
最后以platform driver的注册过程结束本章。! |% B# d) {7 o& e
, t: b! d6 u1 c4 c

" U0 y# u1 K& j. a# o$ Q0 R4 u+ w: m9 M, H9 _# D. D: Y0 N
8. sysfs底层函数
: [' j2 d4 K" U( C# |0 g下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。) u" m6 o0 r3 \8 b3 \$ U: I7 M4 e
在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。
# H5 M! `5 w/ I: l4 ~3 c
1 \5 s) d% B9 {% D8.1 注册sysfs文件系统: g0 {! X2 l8 v/ x
sysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。' ?$ B/ @5 z& [. B: w0 @% x
start_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。
! `. U7 Z5 `$ X9 {; B
" y! S! @/ \, X7 u' `int __init sysfs_init(void)
, L0 O' \' e7 D0 R4 V; v+ [{3 I4 a$ o) D3 E0 R$ m- r' ^
        int err = -ENOMEM;
" V" F  [- g, n" Z        /*建立cache,名字为sysfs_dir_cache*/& n8 f4 w& L* _: k5 S
        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
' p' w  ?9 P8 F! o( F# ]                                              sizeof(struct sysfs_dirent),
; P0 w* k4 S* a# J$ ~                                              0, 0, NULL);
) t: c8 @! h2 U* S        if (!sysfs_dir_cachep)
8 k3 a% q* N6 P  |                goto out;* F8 s8 [% G; ~
# ^& O. X. I) y+ X. i0 a* H
        err = sysfs_inode_init();
0 @' o) T4 l3 _+ u* _6 W' N        if (err)0 G) f5 z$ [- w2 s* U6 y
                goto out_err;
" e: N% }' N2 V& ~1 _& y6 I6 `9 I        /*注册文件系统*/( |1 M0 {; E9 H: O5 B5 L2 x; s# h' d
        err = register_filesystem(&sysfs_fs_type);( K. T, X* x* t- D2 P0 A& v: K
        if (!err) {
6 v/ {2 w, s8 l0 o* l9 p/ q, P                /*注册成功,加载文件系统*/
$ t0 O. e! F: Y+ A8 d0 r                sysfs_mount = kern_mount(&sysfs_fs_type);
2 W0 H4 z6 L3 f0 K( [' s                if (IS_ERR(sysfs_mount)) {$ y& g6 @# ~' c5 d, z
                        printk(KERN_ERR "sysfs: could not mount!\n");9 G+ r0 I" A- A0 i2 h) ]% ^
                        err = PTR_ERR(sysfs_mount);
5 O1 E% g8 a. r& X* l4 j                        sysfs_mount = NULL;
" D2 r( s& Y6 H' ]5 ?: `5 d                        unregister_filesystem(&sysfs_fs_type);
7 d6 W% `) O( R' u% J8 k6 }/ u                        goto out_err;# f. W7 t1 f/ e4 G
                }+ y, e5 v7 J, f- L" C
        } else
* n) W# o; Y9 g1 b4 ?0 C& v$ Y4 G                goto out_err;
+ k# @, W# T6 i" c( Gout:7 s' L" ]/ u% }) A% F- z3 Y
        return err;
' _3 S0 N- b- dout_err:+ U% f) j" g: f: S8 P: N
        kmem_cache_destroy(sysfs_dir_cachep);
# Y- @% L, ?/ b' E5 O: k        sysfs_dir_cachep = NULL;
, V8 ]! A9 s" z: Y        goto out;
  Z9 S7 ~1 ^, Q' Z% b}9 v* d* `" `- Z
- t$ ^$ e9 ]. t" q
static struct file_system_type sysfs_fs_type = {' j: f* `; g& v3 y- _7 m
    .name        = "sysfs",5 z$ z& r6 N$ u& w4 V
    .get_sb        = sysfs_get_sb,0 e  ?, F* O, U, P
    .kill_sb    = kill_anon_super,& {/ o, _3 z' Y
};: {% \0 y8 ~8 Z5 C  k2 Z
/ B# Z8 U$ X+ r, F$ N, j. L- d
8.1.1 register_filesystem
9 b, H# K, {- V/ ]. h下列代码位于fs/filesystems.c。: ?' b, A( P4 Y( V( `9 A( N# E0 d) [. P
/**
! L0 q/ N( q' q! ^: c *        register_filesystem - register a new filesystem
& v: w1 Z$ A" T+ d% h/ |1 \5 n *        @fs: the file system structure
5 Z1 B  A8 ]2 d" @3 h *
' e  m/ |. K9 O: W *        Adds the file system passed to the list of file systems the kernel
/ ^% L/ D  m7 r+ ~1 M9 Y2 }# l *        is aware of for mount and other syscalls. Returns 0 on success,' k, Y9 f- R: Y+ a1 F0 ?
*        or a negative errno code on an error.
% r9 Z' b) H! A8 n4 Q6 p *( U% g5 r% ]) N: n6 J3 ?3 Q$ U
*        The &struct file_system_type that is passed is linked into the kernel ' L( Z; n% @7 l' f
*        structures and must not be freed until the file system has been3 r* x5 o9 A! o
*        unregistered.4 `- H/ v  E* V7 }" X1 g8 ?6 ^
*/
% E; H9 J/ W/ `: ~  i3 _  g. o* @9 _. ^  T0 N  \! e
int register_filesystem(struct file_system_type * fs)
) j4 ~, K3 Z# V( r{9 O, p0 ?; Q9 c9 H
        int res = 0;
. z. T* T: ^8 F" l        struct file_system_type ** p;4 A: D, c9 z  o" @" U) j& m

( _, x% W" N) Y6 Y$ v        BUG_ON(strchr(fs->name, '.'));6 c& P/ ~* F; L2 ?! T) K
        if (fs->next)6 v5 O. W0 N5 K. H
                return -EBUSY;
- T$ C- ^" z; m6 X& a        INIT_LIST_HEAD(&fs->fs_supers);7 b' m) f: N1 j- \5 a$ Y
        write_lock(&file_systems_lock);
+ O$ t) K( b$ `$ u        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/, Z+ W4 ]: Z5 p3 A6 w
        if (*p)
* o$ G2 _2 H! d8 [9 X, r                res = -EBUSY;        /*该文件系统已存在,返回error*/5 o! P' ?  g1 }8 o$ U
        else
( [7 n9 e! s: A: |                *p = fs;                /*将新的文件系统加入到链表中*/
! J/ `' e; w6 }; s$ H2 W; F" P/ R        write_unlock(&file_systems_lock);# ^: w; }: Q4 w. m( y+ L8 k
        return res;1 |7 g8 Y3 R6 o+ P
}
" J2 t& R. d1 {9 |! M2 |& Zstatic struct file_system_type **find_filesystem(const char *name, unsigned len): K: q) b" c! B2 S0 U. z8 n6 j& X
{6 X. g& l+ m- g% A2 V. g* {
        struct file_system_type **p;& S  F/ V" q; P$ Q2 ^
        for (p=&file_systems; *p; p=&(*p)->next)
- H9 N( w) G2 b0 }                if (strlen((*p)->name) == len &&5 j0 `& C0 G$ b% A
                    strncmp((*p)->name, name, len) == 0)& D, P  w  d% O% G1 ^( X
                        break;$ P7 R& W6 Y* ~( ]) r' A
        return p;. p/ z- d6 C1 t' D" d8 t2 B5 _
}
, c/ J1 I% w# w  v该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。
) [3 P" Q& |. X  N) z7 O3 H" _如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
2 L* m2 f( N0 c- i, w! \& R; ]
; J( s4 j. b( H该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。  G+ n* }! b; p+ a9 i3 A, e
% n0 p- @  X: ?6 `: b, @7 i; l7 ^
8.1.2 kern_mount函数1 u) U6 f9 ?, E- _0 P
下列代码位于include/linux/fs.h. S' Q9 }: `7 @0 ~, b; \4 q  l) p
- y% z3 s+ R! J& e% I. K
#define kern_mount(type) kern_mount_data(type, NULL)
2 s' v9 B( N: C2 P) T, W下列代码位于fs/sysfs/mount.c  \# i4 Y/ @  \/ c5 {- a9 u
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
; c0 X/ |3 S% v0 @( K{
1 g. v8 @8 N7 f5 B    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);2 M& {1 r5 m9 O, j% Q
}
+ a  K9 z" r1 X& m/ D* R! W) |9 G2 X6 D; k) b
EXPORT_SYMBOL_GPL(kern_mount_data);# L* U9 `5 u0 r' D+ ^- T" [
kern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:2 B% O: P" M% D; V4 [( K+ Y

+ b) A1 ]* t* V5 ?% @3 u: K* Nstruct vfsmount *
6 n/ u( t* g( C* @( C* Dvfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
  m1 |9 f" Y4 b1 D; v8 q{* w! ^$ N" n* k# N! z3 ~
        struct vfsmount *mnt;( q' m) z: d6 X" m+ ~. M7 G7 j! p$ K
        char *secdata = NULL;
" a7 J2 {9 b! n" R! f$ i9 ^: H/ M        int error;
3 O# R8 N' _3 u2 w' j% }$ v' ~( r' m
        if (!type)# N/ u; K2 _1 {2 L0 m& N( z2 N
                return ERR_PTR(-ENODEV);8 s/ p; _5 w2 z

1 o/ j+ \4 f: g9 m" Z& n, E" x' U        error = -ENOMEM;% g+ ~, D& L* @; V9 K# u
        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/4 L3 s1 e8 ?+ R) l( I! y- L3 B
        if (!mnt)
2 U, D/ q9 o$ L4 {                goto out;
: |3 W6 F( q; U. ]1 v# U" O% l
8 O! j/ d% i- V' G        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
) V7 ~) H8 g8 b, d                secdata = alloc_secdata();5 z7 |" O' K( }. c2 O* J+ T
                if (!secdata)0 c  k" Y2 _) B6 o* O
                        goto out_mnt;+ a  i6 G9 i( Q
1 D2 [5 x& o( V( k) z
                error = security_sb_copy_data(data, secdata);) @1 D( t0 e0 C' T+ D, A) i
                if (error)
7 a' Y  J! \8 r                        goto out_free_secdata;/ |  V4 F8 m) Q6 a2 J1 }
        }8 L  b: Q. c( h# ?  L5 N
        /*get_sb方法,分配superblock对象,并初始化*/- X/ Q* B# I1 F( N+ u7 E! @* H& f* c
        error = type->get_sb(type, flags, name, data, mnt);; h/ L( G; l1 v- _2 b
        if (error < 0)% W. A$ \+ i$ w1 }; `' Q* t; O, z( m
                goto out_free_secdata;% c# G9 \& u- W+ n) z
        BUG_ON(!mnt->mnt_sb);
: D1 H/ D. K% T2 \4 _, s; d
2 B3 Y5 W1 `! F2 J         error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
) C3 x; G, G* c" ?5 C7 \         if (error)( z6 W  a* z' ^6 p6 a8 |3 U) X3 w
                goto out_sb;0 K* a6 \7 x# U8 d4 m6 j

4 W2 H7 ?: n4 W: ?        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/
( s" f6 T/ F: \3 q- g        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/
9 |& x+ A6 s0 Y- j' U8 ^        up_write(&mnt->mnt_sb->s_umount);
/ I7 m( u" h' K4 e/ T        free_secdata(secdata);
+ H5 n) _/ F* L( F6 p  |" F- d        return mnt;+ O7 C) M4 B9 `
out_sb:+ i5 a  \6 q, e0 c1 P; `
        dput(mnt->mnt_root);
2 ]) c: ?4 s8 ?- {, G2 H        deactivate_locked_super(mnt->mnt_sb);. ?+ l5 |" W1 m* F$ v% A" m2 l
out_free_secdata:3 L3 i1 O4 J9 l7 u1 F
        free_secdata(secdata);
  r& h$ I/ t- uout_mnt:! A" ~& k) I9 @5 W
        free_vfsmnt(mnt);
2 D, h* H" y6 `8 t% Y9 O# e5 E' bout:4 ]6 l) V, B, _; P
        return ERR_PTR(error);6 r( R  z2 v: f$ ^! n% B% f' C1 U( d8 a
}, R6 S, _# z5 }8 K3 z; k

# a: o6 \8 K+ l% [0 n, m. w该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。  p9 N* \! @; n4 T, x
下列函数位于fs/super.c
/ M. z5 J6 b% k* k, c9 jstruct vfsmount *alloc_vfsmnt(const char *name)+ x0 B) b+ S& C
{
" x1 d8 N% H/ |' d4 c& ]  i        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);: x9 q! I( l- @1 a5 u, a
        if (mnt) {6 ?5 H! j  d7 b- Q) e7 |
                int err;! Z% d; q" n( G6 J! ?
4 f4 `/ G2 u# p6 S% P
                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/$ Q1 A+ U* c0 Y* K
                if (err)
. i9 T' d3 R' d                        goto out_free_cache;
9 U- N* F$ j! T9 \0 I' o4 Z6 @# d  N* h4 B
                if (name) {: X+ K# }- F8 q! A0 a; i
                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/, L! @4 O' k% Q. A& I( E
                        if (!mnt->mnt_devname)3 z$ z/ ]2 n/ F; ~: [) l6 [& F
                                goto out_free_id;
4 J8 V: {* \7 ~' _" ^1 [+ _9 U. t                }
( X% g, H( i0 p# l
: {7 E" Q/ n( N* A- F5 Q                atomic_set(&mnt->mnt_count, 1);
* H# ~, ]6 [+ \6 N                INIT_LIST_HEAD(&mnt->mnt_hash);: d& s6 W' D9 c, p$ e
                INIT_LIST_HEAD(&mnt->mnt_child);# D$ |4 t5 ^. u/ O, a( U) Q
                INIT_LIST_HEAD(&mnt->mnt_mounts);
1 h$ R) X2 O, F8 d8 O; m, g5 Y                INIT_LIST_HEAD(&mnt->mnt_list);
* Q, }5 f7 v5 B9 c                INIT_LIST_HEAD(&mnt->mnt_expire);
! H' y! u8 g9 O( U, b0 @                INIT_LIST_HEAD(&mnt->mnt_share);- ~0 C9 \! Q4 D2 a
                INIT_LIST_HEAD(&mnt->mnt_slave_list);/ r8 u+ W: l1 v9 g' s5 x
                INIT_LIST_HEAD(&mnt->mnt_slave);
& G* D- H  i( _# d& a/ p9 Z                atomic_set(&mnt->__mnt_writers, 0);9 y' o. C8 ~' Y# |9 ?
        }" i, u* ~4 I' [% ~! ^
        return mnt;6 n5 e% M! L. @( r, L! c2 s9 R) L

$ m3 j3 G9 l+ K; ^" Q5 `2 R  Yout_free_id:
0 {1 l  E5 C- v; x$ x" }& Y        mnt_free_id(mnt);' ?" d6 k' U" x7 |* D
out_free_cache:
% q+ ^+ I1 }/ H, l6 |' C* M. {- {        kmem_cache_free(mnt_cache, mnt);
6 }& J4 F9 u6 i8 I( ^0 p        return NULL;, p# d& x! o7 u. e$ K3 x1 {
}
" Q7 ^( p# A7 W( ~分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:+ ~* U/ g* s) G( u
下列函数位于fs/sysfs/mount.c。
; q- F3 h. \7 D4 E% _) l% ~static int sysfs_get_sb(struct file_system_type *fs_type,& z$ `5 K" x* t
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
- U2 d( T* A9 Y3 S{
  m! R0 V/ [4 X: a) G2 V        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
& M7 P& M6 ^; B7 a6 q# N}
+ d& a. c8 ^, ^! m* ]这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。2 q( x6 d+ Y) k# Y
该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。* v5 \5 v9 c3 d. t) t" x# A& V9 S
) L7 W* X7 F: H' ^
该函数的执行过程相当复杂,在下一节单独讲述。! _3 D) I8 n# l2 l) c! Y

/ o  e. f- }8 v; u& t8.2 get_sb_single函数
: f4 `/ R7 ~- s2 ]9 K7 a2 Q下列函数位于fs/sysfs/mount.c。. g- D0 m. q( u. x4 K7 }; I. t

  K9 ?9 K7 s; O, yint get_sb_single(struct file_system_type *fs_type,
* W/ f9 n) j2 v7 p4 D- r        int flags, void *data,
, u% f& W. i! p2 _$ i- |        int (*fill_super)(struct super_block *, void *, int),
; s9 L3 p" ~  U+ Z        struct vfsmount *mnt)
! n3 J, I) w5 D6 b! G1 }( z# {{
7 A/ Z& w& n* n  M* a        struct super_block *s;; \; m3 l* F- |! p1 v
        int error;
7 J' P4 z' d8 j6 Z2 A; j        /*查找或者创建super_block*/& u9 G. i; k+ g( y
        s = sget(fs_type, compare_single, set_anon_super, NULL);& C9 D2 ?$ _/ q) u. j! f- Q
        if (IS_ERR(s))
6 \5 u5 T9 b. o; E$ Q( l, w                return PTR_ERR(s);2 B3 F+ P$ \, Y* T
        if (!s->s_root) {                /*没有根目录dentry*/+ ]& B  u& L) R$ Z
                s->s_flags = flags;
' n. W/ K" h& T  C& \8 `                /*获取root( / )的 inode和dentry*/
" G4 `! e8 @1 F8 o. `, V                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
& A# W. \7 p( O  H/ `+ c0 F                if (error) {" w8 n( _: i1 |# }; n
                        deactivate_locked_super(s);0 }6 R  s  u4 B1 H! V  L% z2 B
                        return error;
: Q8 x1 u) a- g* P                }8 [) c% r7 ?9 x; E
                s->s_flags |= MS_ACTIVE;% x, }; r! q1 G/ o$ N$ q
        }
1 ?+ o2 t! N4 K* r) i3 D  d        do_remount_sb(s, flags, data, 0);  `" W1 R# B/ \0 A5 w4 U! O
        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/
2 R1 U5 M# W2 o8 z        return 0;
; i4 J5 U/ Y* b# Y' D7 k7 D}
) \6 w' S) y* Y' t# \* ?( x
/ j" L/ o9 T$ G1 X: Q* ]3 K/ HEXPORT_SYMBOL(get_sb_single);' u$ ^' v( j* ]- c6 Z
8.2.1 sget函数- i+ y0 h$ y. W5 ~8 x) w
首先调用了sget函数来查找是否* E; l& L: L! {5 w8 e
下列函数位于fs/super.c。5 j* B! f, T6 c" l
/**9 k; P) V6 H& b7 f
*        sget        -        find or create a superblock
( n2 Y8 Z6 D* r4 e) Y- i) u' _ *        @type:        filesystem type superblock should belong to5 \- E1 e: c* r, s8 p7 G
*        @test:        comparison callback: C/ _! y6 z3 q0 }
*        @set:        setup callback
5 X6 _4 o, J. d  |. T8 }4 ~6 b *        @data:        argument to each of them
7 p& ?+ h) e* [" i9 e */- m0 g4 _6 c8 C' j8 o$ U
struct super_block *sget(struct file_system_type *type,
5 n: I6 X, ?; F5 y+ B9 U2 }                        int (*test)(struct super_block *,void *),
3 W' ~2 }# h$ i                        int (*set)(struct super_block *,void *),) c# @7 x+ q, a; b$ @
                        void *data)
7 E( y8 x3 _/ x) v) m{) }$ N1 c( C( v2 @
        struct super_block *s = NULL;1 z3 Y& l" c7 r7 G
        struct super_block *old;
7 L' y# t0 `+ h+ N% }0 t        int err;
+ D  d) L' o7 [2 f  a: O% F/ H2 _3 L. L1 x) Z' s" {
retry:
( s, _" E- b$ I% d1 `8 f        spin_lock(&sb_lock);+ `3 Z. x# d0 b8 g
        if (test) {                       
  f% G2 G$ X( W0 D" U                /*遍历所有属于该文件系统的super_block*/8 h$ R( r% A4 U0 b9 \" s
                list_for_each_entry(old, &type->fs_supers, s_instances) {
  X: R& _' X. W6 K                        if (!test(old, data))
0 M0 l; O; M# e; J+ l4 I                                continue;
, `' R6 Y1 r4 r9 M                        if (!grab_super(old))
% ]2 P! H, n- d                                goto retry;) k, _8 \+ t  J; {4 Z' Z
                        if (s) {
( X; f8 ?" s5 e                                up_write(&s->s_umount);
) y% f( A% [6 v8 E) J( Z" W5 w4 r                                destroy_super(s);" |5 `4 T" s8 n
                        }- s# I! [2 t6 }! ^* w. y
                        return old;0 w" M* a) }/ u0 I! V% D
                }
' T* n/ l* G9 J+ a        }
0 l0 B9 z$ ]) A9 S6 j' b2 ?        if (!s) {) n$ k; m& |  Q
                spin_unlock(&sb_lock);
4 j% j7 C! y1 K7 z                s = alloc_super(type);        /*创建新的super_block并初始化*/
+ J% Z& D7 Q, N7 ^                if (!s)- o+ f. S; e2 x4 j
                        return ERR_PTR(-ENOMEM);. R% f9 ?2 J/ C$ ?/ s  r
                goto retry;
" {/ c  n7 ?. [/ v$ N: n' i4 ^        }
( d+ _/ T3 M; J, f. i                . e: r' v6 o# h
        err = set(s, data);                /*设置s->s_dev */
- O; N7 w: \5 _% w: b! s2 D, o( U        if (err) {% M/ s' x" p8 q& |* M. C
                spin_unlock(&sb_lock);5 b( N- ?% B2 k! ~: a; C  I  m
                up_write(&s->s_umount);
% C! ^! g8 U, r1 K                destroy_super(s);: |( [, i( h7 I
                return ERR_PTR(err);
, u3 W$ E  v: @9 Y' L0 P5 A$ V        }# q: F* |5 Y* d$ E" k# h) E
        s->s_type = type;9 k1 [8 ]) C/ A' Z
        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/
6 M2 x' ~0 H$ m' g1 w- |        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/, w2 ?+ ]; d" d6 {6 `+ j% G. H5 e
        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/
. y# m# W- n2 l5 ?        spin_unlock(&sb_lock);. J) H! ]7 R, u# q. o# ~
        get_filesystem(type);
  U. z% ^# ?& o3 Q: N# ^9 y        return s;
& Q# E% y3 `8 h+ F& M}  `2 c+ V' m1 F6 `4 I/ F

3 h8 D" x: R% t, b2 M4 h( M2 }EXPORT_SYMBOL(sget);, p" Y0 C- [4 S# c3 _3 ]
该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。% T* U) z* e" Q/ |) F4 {
然后调用alloc_super函数来创建新的struct super_block。" }5 p, E6 L; K& E6 k! S) F' E

) @# [. X7 Y& T# a2 m/ ~; {下列函数位于fs/super.c。
( R; L) K4 Z) f% R" f! N' w/**6 ^4 q& M( K2 I) z- @. I
*        alloc_super        -        create new superblock  |  q. O( c/ l: R
*        @type:        filesystem type superblock should belong to
1 K, T6 R0 o0 a4 K$ H3 i *
6 y  x4 A9 x* }' q *        Allocates and initializes a new &struct super_block.  alloc_super()
2 E. T1 `/ {6 { *        returns a pointer new superblock or %NULL if allocation had failed.
; I$ O7 r6 C  K1 |! ^ */
+ J& [, z: t- o, a! T- rstatic struct super_block *alloc_super(struct file_system_type *type)
1 g9 ~) i; u9 ?0 {# O{
! N  U) U* Q& o8 _* T4 ?        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/
" B; j- F9 D2 |        static struct super_operations default_op;
+ F2 m9 H! Y. K9 y8 Q
. y+ A) @; C  [        if (s) {
/ S0 U" Z& L: ?1 j                if (security_sb_alloc(s)) {# k6 E+ ~$ Y, k7 T4 C; G) z
                        kfree(s);
' l  f0 \' [+ s" F                        s = NULL;
- q8 B5 D. z$ u5 E0 ?4 [# u                        goto out;
. D$ V. V7 O: }+ E; K6 F                }" f" E5 ]! W9 i( s' S
                INIT_LIST_HEAD(&s->s_dirty);0 G' ^: T9 a6 T5 ^9 }. c
                INIT_LIST_HEAD(&s->s_io);$ q) e) f8 r; e" m, Q1 r; c" ]
                INIT_LIST_HEAD(&s->s_more_io);
- y& N8 m- k" |8 E6 W                INIT_LIST_HEAD(&s->s_files);( X& K8 C8 s) O0 @8 a. W% B9 |$ |
                INIT_LIST_HEAD(&s->s_instances);
/ s% j  |, ?; l, U3 R0 N                INIT_HLIST_HEAD(&s->s_anon);
* ^" d' W3 k2 j& L$ Y( T. l" Z                INIT_LIST_HEAD(&s->s_inodes);# H/ u$ T4 e, [- k8 h! P
                INIT_LIST_HEAD(&s->s_dentry_lru);# b! S( u: k0 B# e3 t6 l
                INIT_LIST_HEAD(&s->s_async_list);0 @* D% M$ j9 c9 z5 z( U
                init_rwsem(&s->s_umount);
' b9 }( V  m2 v6 _                mutex_init(&s->s_lock);
1 b7 H  m6 V% l' n* V                lockdep_set_class(&s->s_umount, &type->s_umount_key);4 k9 s2 V) a8 ^: a* A# C' J, Q  f9 I
                /*$ [2 k8 h. t+ g
                 * The locking rules for s_lock are up to the% G; h( k9 Z5 K5 \
                 * filesystem. For example ext3fs has different) D4 V+ L# e" F& ?7 G& T. c$ Z
                 * lock ordering than usbfs:- n2 A8 c1 |+ N+ O3 i3 V
                 */1 L# z* |0 Q0 w( ~* C; H) ^7 V6 [
                lockdep_set_class(&s->s_lock, &type->s_lock_key);
) }' D0 b" o7 p: @2 }                /*
& v* x6 S6 m" L$ p( E0 H# W- S' A" m                 * sget() can have s_umount recursion.
& D* n6 S  k1 R! h                 *
7 Z! h8 n1 F% }) t( q% s- Y0 d# n                 * When it cannot find a suitable sb, it allocates a new4 _& i% M2 g3 j+ H! \  t
                 * one (this one), and tries again to find a suitable old
. a; |7 [& x: H7 K. ]2 ?                 * one.
( Q# n; _; B" ]5 u: w                 *! W! Y  K3 K" g) \9 H) L* E
                 * In case that succeeds, it will acquire the s_umount
4 J% x7 \# `2 _' v                 * lock of the old one. Since these are clearly distrinct2 c, C, {4 N4 f5 S) {
                 * locks, and this object isn't exposed yet, there's no
) T. o+ M5 Z5 ]6 N' o" i                 * risk of deadlocks.
; V* I: r$ X3 S6 }* u, k2 Y                 *
  ~+ P) V1 W3 n* E8 {/ I$ N                 * Annotate this by putting this lock in a different) {* _$ H- R6 @7 x1 ~# a. V
                 * subclass.
9 l8 v3 U: f/ g& |4 h$ v/ o$ @                 */
7 d7 K% R+ `# Y" o6 ]                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
0 E1 L5 D" T( @% t# O: ?                s->s_count = S_BIAS;
, S  D0 Z! |$ d4 O% J  a+ o. o                atomic_set(&s->s_active, 1);7 N: H7 n. g4 `2 b' s" l
                mutex_init(&s->s_vfs_rename_mutex);/ I- V3 {( ?0 [9 a" |5 x% c4 f
                mutex_init(&s->s_dquot.dqio_mutex);
: U) s: _/ k; h4 Y2 p5 O5 i                mutex_init(&s->s_dquot.dqonoff_mutex);4 Z4 o# v3 P1 y* o# T
                init_rwsem(&s->s_dquot.dqptr_sem);+ d# C7 I! X  Z
                init_waitqueue_head(&s->s_wait_unfrozen);
! L. K' ]+ A# l6 M! J- q, v                s->s_maxbytes = MAX_NON_LFS;
5 F. _0 m4 N; Z; c2 S/ g& S* y                s->dq_op = sb_dquot_ops;
. [" i3 ~& l$ Q0 r: U/ F& ~1 C! ]                s->s_qcop = sb_quotactl_ops;
( w6 h* A! i% E                s->s_op = &default_op;5 \/ ^7 F5 R: {+ M& }/ }" N( h
                s->s_time_gran = 1000000000;
; a2 b2 O2 P( i' V        }1 r% A& J/ M9 M  O) K* b
out:9 M# f+ |3 o6 N* w2 Y! L6 v
        return s;! p1 D8 W& i0 R7 [2 u6 `( M4 }! a
}
' F* P; }. U0 ^, \8 n1 A7 \分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。
- o% u; }; Z1 H4 H* H- L3 K下列函数位于fs/super.c。4 J# I% I5 O. ^) T
int set_anon_super(struct super_block *s, void *data)
0 L0 {6 E8 N3 p0 T{7 C3 v1 N" L7 U
        int dev;
9 y8 j( c' ]" {3 \) W! |1 A        int error;$ d: G% V- h* y

  q" u- U9 I- a* b; Z( P! L retry:! e! D4 I: `" v: x1 j
        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/: T* i7 A+ H( @- B6 }0 n8 z
                return -ENOMEM;
9 E# P- J1 d3 u/ ]7 p0 |5 w' E        spin_lock(&unnamed_dev_lock);0 K' V- D6 B1 s  f- i
        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/
* n& u" {- k4 r; a9 d# o8 \3 t% L2 e. j9 e$ Z        spin_unlock(&unnamed_dev_lock);
! A; x, }. O% C        if (error == -EAGAIN)
! b3 I( G9 t& ?* x                /* We raced and lost with another CPU. */
' J: ]$ k  F. S" w                goto retry;
0 A9 Q" Q" k6 p. P* z/ n6 D. U% ^        else if (error)" Y4 t$ n% c$ Y: R
                return -EAGAIN;
1 ^, z' C9 ~! b3 p  j" ?+ d6 @4 K3 {4 |: Q- O
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
8 B3 C% Z. i/ q0 F5 F; G                spin_lock(&unnamed_dev_lock);
: |) c* {1 j# v$ [/ h- E( R% K                ida_remove(&unnamed_dev_ida, dev);
/ H; ]: |) G+ }( r3 a$ K                spin_unlock(&unnamed_dev_lock);
5 z( W: g# K4 p, S* R                return -EMFILE;
) g( A! o& s4 X$ f* S        }
: L7 r6 I4 W# @' X) Q5 v        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/7 H  Q0 P; n8 a
        return 0;
$ ^. Z$ R5 A+ R}* F$ t) f# y8 y5 F/ F0 a
8.2.2  sysfs_fill_super函数
$ w! P3 L& Z& t3 g: D( a; t分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。% f1 E4 ^8 |5 C( k
2 v7 Y, b/ R2 L1 L2 z2 ]
下列函数位于fs/sysfs/mount.c。' x: x, \8 N2 `, h; i
struct super_block * sysfs_sb = NULL;
7 V/ u  g* h' E5 @; g2 f. i* O
  ]% C8 g; J8 ]# L1 K$ S( fstatic int sysfs_fill_super(struct super_block *sb, void *data, int silent)
2 }8 G! x1 l4 m4 q' j  F/ i0 g8 d: v{3 U2 G: F5 }& t# Y' K1 ?3 d6 p
        struct inode *inode;5 [4 g# R/ H' c4 n1 l+ ?  ^" W6 U
        struct dentry *root;  Z/ [; j' E' r

' d% l3 X+ ?8 m1 L$ X: l        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/
# c0 h' u) \, k* I        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
7 h* q$ D/ q- b3 D  }' W" L        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/, b0 t9 J8 n  m" a
        sb->s_op = &sysfs_ops;9 a( [; f0 T! E# E) _! W
        sb->s_time_gran = 1;
) P' z0 ?7 `+ X5 a. Y' M        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/
+ T/ [% F6 ?7 N, q; w; U
2 v9 s  D8 X  T' r6 X/ V& O, E) t* K( E        /* get root inode, initialize and unlock it */
- X4 j; F; ^5 `5 J& ~        mutex_lock(&sysfs_mutex);7 X8 x5 j% n$ D" S
        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/                0 ?: S/ F3 M8 v. |, f) Q
        mutex_unlock(&sysfs_mutex);
+ D2 Q7 c4 O6 G$ D9 a        if (!inode) {
" e" q( U- h( l2 ^  q) V# |1 A                pr_debug("sysfs: could not get root inode\n");
4 ~5 Z9 k% y4 a                return -ENOMEM;
% y, m$ w, ~, v2 X# L        }
6 s0 \+ P6 A9 m/ Y$ J! N* i/ T5 `% y1 w* v
        /* instantiate and link root dentry */* n, `0 v& `: I6 H) |' F; y
        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/
6 n$ k1 g6 ^0 e7 E. L) k$ |+ Q- t, t        if (!root) {
9 ]# Q" i0 r5 M) o  y& ~' _                pr_debug("%s: could not get root dentry!\n",__func__);
5 T7 Z+ N! H6 }3 x1 _                iput(inode);
: o& n% Q9 ~9 M6 \9 F# J                return -ENOMEM;$ _- R6 [& M, P! K5 e
        }/ y; x/ E/ A6 W$ l2 Y4 U: S
        root->d_fsdata = &sysfs_root;6 J# l8 f1 s" @3 D; X
        sb->s_root = root;   /*保存superblock的根dentry*/# H$ g( H9 N2 V; a7 s: U
        return 0;0 w# K0 }+ M& Y0 Z" E- N. T" f
}3 a" ^) \. x9 h( S$ p3 B5 U8 |
  F3 _2 p  t9 e+ e2 y- L' d
struct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/: Z" t/ r; Z0 b- t9 I
    .s_name        = "",
( t- W) a+ j, m    .s_count    = ATOMIC_INIT(1),2 Y& c& k3 r& n3 K4 i$ F
    .s_flags    = SYSFS_DIR,3 u& P4 @( `" z9 g* O
    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
$ T9 P' z9 Z" V, {- o, D* |    .s_ino        = 1," ^- t5 L7 w( h4 t
};
. p5 g6 x1 w# J" Q
; d+ U1 V" m& H在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。
: [% o3 |8 F4 n# ]( t/ g随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。$ K- z" d* k$ x! C
; x1 u1 \! f  q  o; J6 k4 f& z' |
我们看些这个sysfs_dirent数据结构:
. o, d% E& p( k: c# \* t+ ~/*
) G* i# D8 V6 g; `4 i# s+ { * sysfs_dirent - the building block of sysfs hierarchy.  Each and# Q3 I, F# a* O) B6 @( v# V
* every sysfs node is represented by single sysfs_dirent.5 E, ]- D# U' p4 ]7 U/ Z- e& O
*
" M" \1 w: z. @ * As long as s_count reference is held, the sysfs_dirent itself is/ b* c- L& }: [6 ?0 u9 Q; h' w
* accessible.  Dereferencing s_elem or any other outer entity
6 }2 v% x7 P* S' N$ F& K. T * requires s_active reference.- \. g3 a; i5 s- W) K$ [( L
*/; W' h" ~* q8 \% q9 Z
struct sysfs_dirent {  e3 A! u( A2 O( ~
        atomic_t                s_count;  c) |( r  v: x3 b$ T
        atomic_t                s_active;
, o5 N, `0 K) |) M2 f        struct sysfs_dirent        *s_parent;
3 G4 @# ^( {+ R        struct sysfs_dirent        *s_sibling;
0 O4 e: `" m, e7 D5 `! K4 J        const char                *s_name;
+ P; _8 M/ g  a5 u- y  f) d5 V
" J9 f* J1 X. y4 D        union {
! T& n8 a+ Q+ D+ u0 P( `                struct sysfs_elem_dir                s_dir;
7 t4 F8 i8 A( X2 e. ]6 a+ n& ]                struct sysfs_elem_symlink        s_symlink;4 J* C, P- G2 v4 o) B% J$ e6 L( b& c
                struct sysfs_elem_attr                s_attr;5 q: w- D3 ~$ @2 [3 z
                struct sysfs_elem_bin_attr        s_bin_attr;
/ o) {0 j8 e) a4 h4 b        };
& N& |6 K( J. C. C$ i5 U4 `4 y
2 a3 o1 z5 ]( b4 y1 C% Q4 ^. Q        unsigned int                s_flags;
6 X: b4 m5 j; _# |/ g        ino_t                        s_ino;
% n5 b$ v8 x0 Y* {* N$ D        umode_t                        s_mode;9 B3 Z$ ]8 S* I
        struct iattr                *s_iattr;
! i) P: P8 E+ I; q8 S& N};
3 B$ r! B1 N7 S. f% v/ _0 r其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。
6 U3 X5 }. X, V# j- D另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。6 @. c! n0 o- ^- x
接着,在来看下sysfs_get_inode函数:
. Y, v7 {, t% u" ~5 c) r( g下列函数位于fs/sysfs/inode.c。( K6 M, O5 ?* o: e$ c8 J5 i& K
/**
! r9 P3 \# X' m, C) T *        sysfs_get_inode - get inode for sysfs_dirent/ Q7 ?) B2 Y. U7 u
*        @sd: sysfs_dirent to allocate inode for, ^! }: G4 A" U; ?7 j
*
8 e& n' I1 s/ Y2 L' ?2 d *        Get inode for @sd.  If such inode doesn't exist, a new inode
$ k; C$ C+ ~- f$ \2 m8 ?  u1 ^ *        is allocated and basics are initialized.  New inode is
% Y$ S  L3 {$ Z *        returned locked.1 v; H# u6 W! h. C3 W* P' [& ?
*
: m! |( s$ T: n% T% P *        LOCKING:
$ d! [7 i0 O# R3 n! ?9 U3 t0 r *        Kernel thread context (may sleep).5 k/ q- E9 d2 ]* [0 w
*
% h/ D  B/ W) n$ U* u3 ] *        RETURNS:
9 |% H! ~& M" l" g. j *        Pointer to allocated inode on success, NULL on failure.3 P4 A* A% B5 j0 G( E" |
*/
1 k6 \5 t, T: Xstruct inode * sysfs_get_inode(struct sysfs_dirent *sd); A8 u; m8 D* L5 h1 w- t
{
+ E0 G3 \) N/ I4 t7 E5 A+ ^        struct inode *inode;+ g0 D+ `9 r# C% P* i" c! q# E/ E
1 I! {/ B* {/ S8 A  {- W( `! ^
        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/
$ a9 ?4 v* e1 u# r        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/
; m: v% [* b  R, I3 q/ s                sysfs_init_inode(sd, inode);3 X( ^* F" P8 i+ F
$ B) z; H3 y: c! ^' I
        return inode;, j& {3 b4 R. N% k0 {/ T3 x  Q
}* C9 a& C; t: J1 @# l- r

! S8 {8 }2 s! y, X) {% J! P/**
- D" L  `  F: I * iget_locked - obtain an inode from a mounted file system
$ L& A$ e5 k& S4 K8 f) N, r0 b * @sb:        super block of file system
+ @8 S8 z  J& z. }5 `2 D* m * @ino:    inode number to get
$ O: ~2 L$ y2 D: Z. \0 }) @* w *. e$ ^2 J! r. M  N
* iget_locked() uses ifind_fast() to search for the inode specified by @ino in
% p. w$ m! c2 u- R  y * the inode cache and if present it is returned with an increased reference1 p0 |0 _# m& C0 F  [  @0 K3 }
* count. This is for file systems where the inode number is sufficient for. c  Z& L  B* Z* S; B; W3 n4 V
* unique identification of an inode./ Q/ O( V' b" L, p5 y- {
*
$ `/ u. R8 {8 {# f' R, {$ R/ W * If the inode is not in cache, get_new_inode_fast() is called to allocate a
$ K5 x! ~: f7 E, p! s * new inode and this is returned locked, hashed, and with the I_NEW flag set.
- w3 \4 h+ C. t: q. o& y * The file system gets to fill it in before unlocking it via
' B8 O) z, `' r9 t* m" y& \5 P * unlock_new_inode()., R7 j6 b% C. l5 Z& Z
*/
1 u/ b: U, L" g; D% ystruct inode *iget_locked(struct super_block *sb, unsigned long ino)
1 c4 d7 N5 V, C, C0 D{
' L  i) {. }* A5 j    struct hlist_head *head = inode_hashtable + hash(sb, ino);
7 k8 m% h2 a9 X5 s' R1 M, G: x    struct inode *inode;0 \2 n; s3 Y+ S' d0 H
1 Y  T* l' I* P5 j
    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/4 I9 v6 B* A" f$ \/ G
    if (inode)
  \, j+ _! _( F9 t0 s% D' [. \        return inode;         /*找到了该inode*/
1 \* y7 [6 \" _0 Y# W    /*
. ~* e- y; M: @     * get_new_inode_fast() will do the right thing, re-trying the search( Y7 n9 T4 P; b7 l' m6 _9 l
     * in case it had to block at any point.
& o0 S$ k5 B3 f# W8 m     */
4 h9 ?* ?! m6 w& o! Y9 D    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/
9 B. H9 X/ u/ l. F! ^}
6 X3 ~9 z9 m3 {# CEXPORT_SYMBOL(iget_locked);: y: ?/ [, B4 _1 Y. w

) ]5 v- p. y3 K: S) S! h) p3 k  r  L* Estatic void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
3 Z, W  p5 ^6 L5 _+ S{0 s) z! x4 G( p( e* N5 @$ k
    struct bin_attribute *bin_attr;
; q' T4 {6 }2 [" Z. E# w
# Q! S4 m0 ^& [! x  T4 w# L7 ^    inode->i_private = sysfs_get(sd);
8 I8 `( ?+ H1 w& N. u    inode->i_mapping->a_ops = &sysfs_aops;+ w0 N6 x: H1 A  k
    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;5 x) e3 h: B- a$ X4 ~
    inode->i_op = &sysfs_inode_operations;
/ o/ u$ }7 i, x8 ?+ r5 I) _: B, B    inode->i_ino = sd->s_ino;
& n" d' E2 v0 i    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);, a. @0 W! ]0 b& y
! z9 e. o. z" R& ]' x3 F) G
    if (sd->s_iattr) {
& q# K* n/ T0 n% ]0 b        /* sysfs_dirent has non-default attributes+ h4 y" w  @% j7 J3 U/ ^  V0 h
         * get them for the new inode from persistent copy3 q: i4 b4 P$ g' w- V
         * in sysfs_dirent. k. y5 {: @3 o5 F$ D! P
         */
/ c( P/ v$ @4 G& L$ y        set_inode_attr(inode, sd->s_iattr);$ e& O1 x& E9 E5 k! b
    } else; a' x5 H5 A; E5 d- }/ Z- t- r7 g
        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/
: e& B( w+ [" P) {9 P) L/ t8 H  r) i8 v7 l9 \
4 b* J0 s; L: y$ Q% C9 L# Y* w, ^
    /* initialize inode according to type */7 K9 X+ S, ?7 B. g. R" f
    switch (sysfs_type(sd)) {
! r6 _: y6 W$ @# y8 [    case SYSFS_DIR:8 D& e: J. {; A
        inode->i_op = &sysfs_dir_inode_operations;) h$ w: F1 ?- J9 T3 V( o
        inode->i_fop = &sysfs_dir_operations;
: q1 G* }* L! V  M. h, }        inode->i_nlink = sysfs_count_nlink(sd);
$ m2 s+ m4 v$ M* h+ W: p        break;
# Z, ]$ F# W5 f  G+ C% y    case SYSFS_KOBJ_ATTR:  H( A; d/ O! F6 `/ K% h" {
        inode->i_size = PAGE_SIZE;
' N3 E! J* e; b5 h7 I' D1 r. ]0 _( \        inode->i_fop = &sysfs_file_operations;) _) Q5 ~. e6 E6 k% i  W* O
        break;
. K7 h. I- m* ?- s    case SYSFS_KOBJ_BIN_ATTR:
: N6 _& A- d( P1 A        bin_attr = sd->s_bin_attr.bin_attr;
' J( k! m' @1 x) b: v; n        inode->i_size = bin_attr->size;3 T8 G! R7 B" Y. f, n2 g
        inode->i_fop = &bin_fops;, a9 w6 n1 }( ]7 Z& c  p2 ]
        break;0 t, r, n; B2 v
    case SYSFS_KOBJ_LINK:
- b( |! r# r! b0 w" R        inode->i_op = &sysfs_symlink_inode_operations;
- H/ j, E* n  \( b: X' W        break;
& w7 T* G5 g# F    default:
( F' [0 M6 P# p# [* M        BUG();  E' {6 P3 V+ V
    }
9 M# V' ~7 R$ ?  ?
5 D! L  C3 R+ V9 v5 e) S    unlock_new_inode(inode);
; p7 V/ D# f1 h, n" M! f}
- ?+ m/ n: w' U该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。
% e; |* t( W$ v; y; K0 r再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。
) L! B* ~0 G) d' o0 q4 o+ G+ Z7 @/**. l; G& V  q1 p
* d_alloc_root - allocate root dentry! m" c( x, |! V+ p
* @root_inode: inode to allocate the root for  R7 z( h$ i% Z: z# B5 d8 r! e
*
! G! {# [2 v& G/ V) B$ U; c * Allocate a root ("/") dentry for the inode given. The inode is
9 f) v$ v% A1 T- @7 h5 o7 b * instantiated and returned. %NULL is returned if there is insufficient. m- `) @$ g' n4 f" A
* memory or the inode passed is %NULL.
' W' W% J9 z# s9 l( F6 u$ B */0 L+ C% s2 s+ a* [  y7 Q* p/ Y; [8 A
4 N! J  F( Q: h8 s$ s' ]/ r, D; F
struct dentry * d_alloc_root(struct inode * root_inode)8 M. e  _0 ~% R% q5 Q  R
{* a, I& G! K; o8 G
        struct dentry *res = NULL;
% t3 E- P0 W& }1 n) {" A$ r; R9 `9 b  M6 }  y
        if (root_inode) {9 f6 z4 s7 _$ h6 V1 P
                static const struct qstr name = { .name = "/", .len = 1 };5 g. k. }& c/ C8 p! W
; e8 y. }% b6 `3 A& p
                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/
) S+ X* ?2 m' C- k7 A4 J4 a                if (res) {/ L9 n( A2 v! T5 `9 r
                        res->d_sb = root_inode->i_sb;
* S6 H+ D8 k# i% q                        res->d_parent = res;        ( ^, X$ |0 T8 b! X/ Y3 U. s% s" k
                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/
  V# h7 R: X  ^9 k. g" c                }' F6 T) H8 t6 ~; N6 {/ g
        }# u5 o: n6 k7 P! a5 N
        return res;4 A( \6 L! A3 Z4 J+ o
}- N& Y7 Z: c  P6 o% s

+ V& r4 \: J, ~* M* Q* m- S( i' f/**! V, y. s3 f6 J+ X* y7 }, n( z
* d_alloc    -    allocate a dcache entry
+ a9 h, {+ I2 M+ m  i; E* d* J. W * @parent: parent of entry to allocate2 o0 I( C; w) V" t( k3 }4 R
* @name: qstr of the name$ d+ S3 W# R) ~% I! q, x7 J! M
*
. Y9 B  {" Z8 l3 z5 o  k& H/ R * Allocates a dentry. It returns %NULL if there is insufficient memory% L0 P  e% v! r' g7 G
* available. On a success the dentry is returned. The name passed in is; o' G) h& w( B$ H2 b
* copied and the copy passed in may be reused after this call.8 h' {" P1 s$ C) g
*/# k! z/ O' N- x

( Y0 G$ \: X7 d( \struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
  W/ I* v, s( T! e' b{
7 P2 d% |6 E' o/ O  {: f0 S% L    struct dentry *dentry;$ x: [0 d5 u) _" ]6 n* j
    char *dname;
9 r/ i; O9 N1 ?. p2 [2 w
  a( ^9 ]/ ^1 }$ V. N& C    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/7 G- j4 Y  Y9 k: X) |2 Z
    if (!dentry)1 V  C+ _% F: [+ K3 w1 b7 \4 P+ _7 D4 V
        return NULL;
! y( W5 X7 T! s) ^, J) n0 ^  s0 X0 }) }- m9 z. M0 V
    if (name->len > DNAME_INLINE_LEN-1) {, a" Q6 R/ Q/ Q$ n' S4 ?3 l
        dname = kmalloc(name->len + 1, GFP_KERNEL);
# _4 l6 T- j1 K2 s        if (!dname) {$ O  L5 |3 h2 D3 m+ n1 J7 ]5 C0 |
            kmem_cache_free(dentry_cache, dentry);
6 z1 e7 l7 Y9 R# V            return NULL;
: J7 D- z- g$ ?0 r% T7 W        }
& z1 y6 [- `" B- G+ U    } else  {& f( w6 f5 ~; ^+ T" y: O$ U
        dname = dentry->d_iname;+ o) @1 M+ A# e& j4 H' V7 ]
    }   
: y$ v% G8 y/ C    dentry->d_name.name = dname;
5 @+ [/ U- P8 c8 z$ ?5 Y# k& W. h2 V
9 G. z- U) D6 I) `# ?    dentry->d_name.len = name->len;
5 \2 k- U& m5 c) A    dentry->d_name.hash = name->hash;- z, J) V9 ~3 F+ ^9 t
    mEMCpy(dname, name->name, name->len);
+ J6 X) f. g7 H: C! q+ Z) {) s9 B1 t    dname[name->len] = 0;
5 b! e5 x" F% Z1 D
. h- R) w: a+ Q    atomic_set(&dentry->d_count, 1);
, N; K8 U; b* W7 k) T0 u- P( a* H    dentry->d_flags = DCACHE_UNHASHED;" r* ~, e' C; L3 O: o2 h
    spin_lock_init(&dentry->d_lock);
3 {+ [! t8 o% ?$ |7 e% E  y- J    dentry->d_inode = NULL;1 U/ K" A( c5 x0 t& a
    dentry->d_parent = NULL;# s5 K& i2 M0 _% S+ W) b% C  N
    dentry->d_sb = NULL;
; x! o# B0 K! _7 u: F    dentry->d_op = NULL;' q0 ]9 S2 E5 s8 H; Y5 u
    dentry->d_fsdata = NULL;& J2 F: q- E2 W8 t* m# {* n. U, j
    dentry->d_mounted = 0;
. g& C9 `$ q# _: G3 L& y6 {: E    INIT_HLIST_NODE(&dentry->d_hash);
1 \/ _0 S$ I) [/ y5 @/ F    INIT_LIST_HEAD(&dentry->d_lru);
( x* |. Q( i, w: N( y8 x5 G    INIT_LIST_HEAD(&dentry->d_subdirs);2 G/ N: b; d) X2 t% t
    INIT_LIST_HEAD(&dentry->d_alias);
% F" n  J' S$ K2 C, r% x  ~% ~
: w2 u. A- \/ h) \# ^! x6 \    if (parent) {    /*有父目录,则设置指针来表示关系*/% @& q5 u, D7 k& U& l, L4 r1 Z
        dentry->d_parent = dget(parent);
: e0 j" \' ]3 G8 I8 \4 y& \) c        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/& Y) j6 a" k% d+ I5 E
    } else {$ g7 r" ]( N& `. m2 h. W/ M0 O; J+ b
        INIT_LIST_HEAD(&dentry->d_u.d_child);9 L: f+ K+ P$ R- J/ Y1 G
    }
# J2 J; D9 A4 _: K4 b) K, h7 k% s
# @6 t+ W8 p# }    spin_lock(&dcache_lock);: _) B( d% [& n0 S% W+ l
    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/
' @3 G  a6 z$ U5 A# o" s9 Z+ v        list_add(&dentry->d_u.d_child, &parent->d_subdirs);
5 k9 N, d3 W+ v" M    dentry_stat.nr_dentry++;6 w, L; U- Z. @9 B! n
    spin_unlock(&dcache_lock);
7 x' Q5 ~% Z# v7 O: I0 z
8 j/ |  l/ f  S    return dentry;
8 p3 w) l! j7 i# P$ _} * Z* o) V( N* W. |1 e6 T

- ?, x( [+ H9 n! {. J2 o" |( d# S/**; A# k5 {6 V) F& y
* d_instantiate - fill in inode information for a dentry
- b8 E7 U2 _( F0 j$ E8 Y  c+ q! ]# p * @entry: dentry to complete( I: ^( m+ _$ s8 |4 v
* @inode: inode to attach to this dentry) i' P% k& \: `1 g
*
$ N9 w7 ~* `6 c' X  |' u * Fill in inode information in the entry.. f9 L4 \3 [! ]. \' r. `
*
) T/ n' U6 Z+ t( Q1 A3 d6 E( x& p * This turns negative dentries into productive full members- u9 ?9 q1 L0 s% G. [
* of society.
) |8 l1 y) X3 C$ y; w *" a  Z6 Z  ?5 k# U9 w7 _
* NOTE! This assumes that the inode count has been incremented
* {- o0 y/ |, L3 s4 z( q3 t * (or otherwise set) by the caller to indicate that it is now7 V7 ?* ]0 ~8 _9 s
* in use by the dcache.
$ V& E* W8 F& H! N/ w+ S */8 C2 D/ e, A2 l5 R7 a6 n: J

7 Y4 e6 I1 f% F3 D8 Evoid d_instantiate(struct dentry *entry, struct inode * inode)
6 E/ a3 ]& B+ J0 k# ], G# q5 @{- F% z) J: Z2 O( M0 T: y
    BUG_ON(!list_empty(&entry->d_alias));
  I  D# ~) v. ^" v    spin_lock(&dcache_lock);
3 v& n8 y& e. _8 g    __d_instantiate(entry, inode);, W+ c  @+ u+ e
    spin_unlock(&dcache_lock);
( @  m6 t3 l& j% V0 V    security_d_instantiate(entry, inode);
* X8 U, [8 A. S; Z" D- q}
5 ^( J7 o3 K" @- X# U& H, j8 J/ b! [# q& j% S; x6 L1 b
/* the caller must hold dcache_lock */; o( N9 C) _" L& [7 }
static void __d_instantiate(struct dentry *dentry, struct inode *inode)7 o7 J* @2 ^. {
{
8 G% _. W- \& o! b/ `8 ^& `    if (inode)
0 A! a8 T% M9 U        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/
+ n; Y3 c' c0 r+ y7 e& ]    dentry->d_inode = inode;        /*保存dentry对应的inode*/9 L) }% a" h" E0 ]( x3 I' C
    fsnotify_d_instantiate(dentry, inode);
6 d/ {* ^& S3 f5 ^+ K% Y7 K( J}
& t7 f* ^6 y# g5 ]. S! v: k1 z
$ c( w5 S/ F, Y, M7 M% B: q3 o7 D该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。, T% R8 a& v/ V, f4 O, _6 B3 H
接着调用d_instantiate来绑定inode和dentry之间的关系。
6 ], t( \( z0 }# E5 q6 [1 v& @( i1 U( a1 R$ E5 _
) f# G% O' j. Z$ A$ m3 ?! L
在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。
- w5 ?2 b. m2 r7 [
$ u- P6 E# _. E( b( u/ g可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。
  f, L! u4 n. O) y, k0 [
% H2 R1 @: x9 c8 Q, t$ l- D5 {8.2.3  do_remount_sb
2 e! v! ~& M5 ?, F1 C, \下列代码位于fs/super.c。$ @' v  B: k( x* D7 L' X
/**
5 B$ ?5 i' K5 E) g *        do_remount_sb - asks filesystem to change mount options.
0 Q0 R1 M3 o' n, P& H: ^ *        @sb:        superblock in question
( {  C7 w* L, u0 K% Z2 ^ *        @flags:        numeric part of options
' |$ n2 o( T* i; G# I9 ~- k *        @data:        the rest of options( {4 _$ k8 s% h8 H% h! x* w
*      @force: whether or not to force the change- K( C; V- \6 b% S6 H2 F7 n- \. s5 t
*
4 U9 s" K" e4 s% o) p: _( x *        Alters the mount options of a mounted file system.
( G" K! ~8 l/ F7 y' z1 q" [8 S */. O0 b, R+ P7 u
int do_remount_sb(struct super_block *sb, int flags, void *data, int force): [4 `, I& E8 j% A9 }. P+ Z" T
{, ~8 i  r/ y; v2 d  l6 Q4 x
        int retval;
% ]8 u+ v; l3 `! Q        int remount_rw;
5 C0 H0 _; O1 q          B0 J# w4 C& q. x0 T. q/ M9 |: i# `
#ifdef CONFIG_BLOCK1 D0 ?9 F  z* U& N* F4 L
        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
) ~6 |/ Z3 a2 S7 z5 w6 g                return -EACCES;
& n# r* L0 V5 O: _1 V#endif* J7 F) V- X4 l. k9 K/ J  Z; n; @
        if (flags & MS_RDONLY)
, c9 y3 S- C+ ]4 E2 J0 S0 c$ z" d0 H                acct_auto_close(sb);; c, `9 ^# l* v  }
        shrink_dcache_sb(sb);+ c$ E' w0 N) b9 K* e3 V6 @) m
        fsync_super(sb);" x' {, a  i  z% N7 T4 [+ A
1 W8 u7 }3 o: j1 g
        /* If we are remounting RDONLY and current sb is read/write,* H2 m, ^4 z) s9 G2 M$ D" R
           make sure there are no rw files opened */
6 {- {7 t4 {3 w& z0 O( x; }  ]/ n        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {. X6 R3 ]# k6 R( `' Z  {
                if (force)+ `- s/ l" `8 P% p" m3 J) q
                        mark_files_ro(sb);( I, i, D$ r1 J1 V/ U$ N
                else if (!fs_may_remount_ro(sb))% h# _/ t$ X4 _/ Y$ z5 ]
                        return -EBUSY;3 T6 x. O5 j' ?
                retval = vfs_dq_off(sb, 1);! S% d: E% ]' \: _
                if (retval < 0 && retval != -ENOSYS)
8 u' j: O8 s  D, _4 C$ u9 Z                        return -EBUSY;/ r& q( |* {; \9 {: V" l
        }6 f0 n' K7 p, q
        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
( Y( w+ u& x  H9 E  L; s$ E1 S* [" j1 ?' w8 J3 \
        if (sb->s_op->remount_fs) {1 q! c' c- X2 L
                lock_super(sb);8 t; v6 N/ E: S6 B7 ?) }
                retval = sb->s_op->remount_fs(sb, &flags, data);
4 S; I7 o6 L( n                unlock_super(sb);
# B" [9 T* V3 v7 f% S9 i                if (retval)! P7 C3 w5 M% n  l9 w% I% d$ T) ~
                        return retval;
) Q$ q( Z. P. W2 P4 ]" m        }6 Y1 W, j2 h! S4 ^5 F0 N$ o
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
9 p' H0 n# |; e* X        if (remount_rw)$ A( I2 b3 D+ a" O& ~. b
                vfs_dq_quota_on_remount(sb);+ l# t0 }7 O7 ~4 L& d
        return 0;
! m( s$ h- S; J  r/ U! \}
; R5 B' T$ B0 s
4 V9 C* ~3 U3 g/ t6 h这个函数用来修改挂在选项,这个函数就不分析了,不是重点。; L5 N% g; H* y1 H
8.2.4simple_set_mnt
' B6 k2 d/ \# V/ O1 R下列函数位于fs/namespace.c。0 ^  ?; E: y* h" J+ E
void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)- ~1 `; S8 H( e: n$ w! z
{
+ A, I* h/ e# J6 v) [        mnt->mnt_sb = sb;. e  @& ]; W$ l9 ?
        mnt->mnt_root = dget(sb->s_root);9 h: u/ ]3 y) ~7 D7 P/ F' D
}( I3 Y4 O8 Q1 o) V5 i! w6 x# M
该函数设置了vfsmount的superblock和根dentry。
% A1 f1 P, x2 Y/ x/ M2 q. a7 [* A, |% r
8.2.5 小结! |, f8 k) M4 h( {3 `: J
这里,对sysfs的注册过程做一个总结。
8 t2 t& _1 u5 @# Z  W
! V% q0 a: K: `0 e: x/ H+ b7 gsysfs_init函数调用过程示意图如下:
/ a" Y6 l% |% `( l2 c# d
  |6 X% C7 a& P' ?) `
5 n: [' P" m0 j/ z4 x7 }# u1 f1 x
2 R5 M  c8 h/ i1 \/ V. Y在整个过程中,先后使用和创建了许多struct* d: r* }$ Q! p& Q# x1 b

3 @6 ]' A0 G7 K$ Q' I第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。$ z5 v% i. \: `$ L, ^
8 H% h2 F* j( F8 m
第二,建立了vfsmount。5 `) w4 r4 c$ t/ m9 T
9 t5 R' Z8 ~  W' [3 Y
第三,创建了超级块super_block。
5 K* C% m! t4 E; `/ L. j7 O; h* V7 q9 K
第四,根据sysfs_dirent表示的根目录,建立了inode。
; {% h' M( y: Y
6 \, }2 A7 T; i7 q! E最后,根据刚才建立的inode创建了dentry。
+ ^" M0 T( l' y5 S! Z0 }  y# E" w* C
7 v( A7 h9 i8 o$ t" w除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
$ q9 a* a& b( m- L3 Z0 x9 g6 C/ O
+ H$ G8 p3 J/ p" l& m; `, J8.3 创建目录
/ [. L# R6 L' t在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。
+ p) R7 m% ~8 z3 j: b4 z1 U
# i0 j4 q5 O, A" v下列代码位于fs/sysfs/dir.c。
9 q. z3 w2 H" C! w' o/**
1 g1 B3 z& d6 W/ X0 R: I: u *        sysfs_create_dir - create a directory for an object.; }. u8 U7 |6 `: U
*        @kobj:                object we're creating directory for.
3 J# E( p; p6 e9 u) N: o- u */- ]7 g' z' W! l5 y1 ^. X
int sysfs_create_dir(struct kobject * kobj)6 A/ i3 t: c+ `8 t1 v! A2 r0 J
{
& ~3 H3 n9 |4 k( f5 p3 P        struct sysfs_dirent *parent_sd, *sd;5 V. c  k, ?9 k" m3 {8 I0 _
        int error = 0;2 d4 m% d7 U( o$ @. y5 p* \
% X7 P4 `, e& ~% p% O! B  a
        BUG_ON(!kobj);% I" c* Z: f, I$ K' V$ Y

: L1 k' \) v, u1 v1 A# H: v        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/8 l% i2 n  F$ L9 w+ q% E
                parent_sd = kobj->parent->sd;
+ }$ R! r0 S- \: D% i4 i        else                                /*没有则是在sys根目录*/4 }: u4 l. z% c; S" K; x
                parent_sd = &sysfs_root;
, R- }2 n$ x! [7 ^" h
/ [- Y' ], j  u! }3 _) g        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);2 [  t$ H1 j3 e8 G
        if (!error)* R5 D$ l1 @- \$ q( O
                kobj->sd = sd;2 p1 z8 Q; R6 }( A
        return error;, [% d& N3 v- F* z
}
5 f5 X( w2 [. {4 \2 q' H3 g$ T$ j' ^1 U" M; `3 Q
函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。
1 B) o9 `9 E; @& l3 V4 O+ L+ f很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。
: ^! q4 k8 p  g: K
# F' \  g! P; r5 ?! _下列代码位于fs/sysfs/dir.c。3 ~- X9 Q- {% C7 j1 y+ r
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
, S  N9 a* i  H$ D& m6 y8 A4 }) h                      const char *name, struct sysfs_dirent **p_sd), \% a7 g; z& e/ o' c4 Z
{
7 B+ k. I# l, S' X: C& S: Q        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;0 r6 h1 I4 @- N! F- J2 J* i0 N
        struct sysfs_addrm_cxt acxt;
4 A+ B- Z& ^9 c% v8 r        struct sysfs_dirent *sd;
( W% U. C9 B) F. F2 c4 P7 O        int rc;
/ b4 O( m1 h- Q. r
+ t- c* v) V) b0 H* }# Y        /* allocate */        /*分配sysfs_dirent并初始化*/
5 d) [! s# m8 z* D8 v        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);+ Q# e; _9 `& p( K- O6 A
        if (!sd)
# n" n$ p+ ?- c- s5 Y/ C7 W                return -ENOMEM;5 G6 M, |5 \0 _( m( g
        sd->s_dir.kobj = kobj;         /*保存kobject对象*/! o* N" K! y7 {, X. P

0 a- r/ Q" P" m2 a) J( m' l2 o+ O/ f        /* link in */, C' _3 o$ w# j
        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/9 Z0 h% u0 t( }4 p! s$ V
        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/( V( q2 U" K  {( X# V4 b% M0 H- G
        sysfs_addrm_finish(&acxt);                /*收尾工作*/
2 F6 L% N9 m  p4 |# w! A2 U4 I7 _/ x1 C7 t
        if (rc == 0)                /*rc为0表示创建成功*/
* a: N8 G/ i6 g5 o                *p_sd = sd;
( d4 K- Q5 @6 |2 @        else8 L& F- Z4 ~; N+ m/ @* f- y4 Z6 D" e
                sysfs_put(sd);        /*增加引用计数*/
; ?1 C4 A+ }4 c9 X, T0 k4 k4 O
: A2 L. Y/ q4 `- _8 f        return rc;9 |9 a1 x0 z3 P% s" l
}
9 ~* t0 Z; c6 l9 E; j& X这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。: k! l: ~  y4 {; z! u: Z8 K
7 _8 {% W" Y1 ?1 z/ R7 G% ?7 Q) @
mode还有几个宏定义可以使用,如下:, U' [# C2 H/ I' G: A4 q
#define SYSFS_KOBJ_ATTR                        0x0002
: s  X# t, g0 ~* U- E3 I) O#define SYSFS_KOBJ_BIN_ATTR                0x0004
: g8 b  V8 t  O+ b, v$ d#define SYSFS_KOBJ_LINK                        0x0008: r+ J5 k0 }* b- [* I
#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)! y# t, o) A8 `5 z- V
8.3.1 sysfs_new_dirent ' r% \$ g# K/ }3 r8 E( A' @( `
  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。
$ a( h; O6 p# Y7 A6 o( z7 H1 |4 ]- C8 x. H1 g' T! q1 K
下列代码位于fs/sysfs/dir.c。+ R4 _1 h2 {6 q) X( }2 e* p8 [
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)( ]  t$ F; a+ P0 b% I& R4 `+ Y; y
{* R! \! j; {' @/ E4 G; w* e& j( v
        char *dup_name = NULL;
& G1 ~# _2 f8 V' V$ b        struct sysfs_dirent *sd;) _  k. H5 s5 y3 r
* m0 ?0 N' r9 D( L& K$ n. g
        if (type & SYSFS_COPY_NAME) {6 |% [+ r+ I  w% Q1 A2 K
                name = dup_name = kstrdup(name, GFP_KERNEL);3 d3 N! O3 c1 _) Q4 D- |8 p
                if (!name)
# Y1 {+ g5 t6 f- _6 d4 r+ p3 o                        return NULL;
* l& Q, N( X& Z: R( v* K9 o        }3 ?, ^' B& o$ Y: l! g. K' g
        /*分配sysfs_dirent并清0*/
5 l3 c' {5 ?$ z' P5 Y        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
2 d! C1 R, O% v! ]; N3 b1 g        if (!sd)- i1 u/ T4 `$ S  S) D
                goto err_out1;
' A# t2 n* @: l0 b: Q* x% F, ?$ p4 E1 ]" J$ k5 O0 F5 g% X* F
        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/
  ~+ z6 x  V; ~, g                goto err_out2;# ?1 D) r2 w4 s

2 c' U/ B: ^# W6 s% o, c2 D( K        atomic_set(&sd->s_count, 1);! T- k/ Z$ x$ l5 J) ]  P
        atomic_set(&sd->s_active, 0);
% ^$ E, W- Y& x( G' t# ]: D& y6 [' `' B/ V6 I
        sd->s_name = name;
; n; Y% W! r1 t! t* `5 C2 D        sd->s_mode = mode;
& V& h7 m8 G5 X6 C4 p" n        sd->s_flags = type;
6 u- E$ q9 I" D5 ]2 n# p% J. I' z2 e
        return sd;
* _! [8 C+ ^8 v7 g/ P7 |/ B
( l# K1 n( q$ f err_out2:! S$ v0 M4 F  c6 x3 b
        kmem_cache_free(sysfs_dir_cachep, sd);
( h9 {2 |8 ~5 B) P; Q( L err_out1:
$ V% R( c0 Q& M3 ^. K        kfree(dup_name);7 p# {+ A) |  f1 l& L+ \) W
        return NULL;  i  b/ u8 V& N0 j) g8 K4 t1 a6 h
}' ~3 T, x1 a6 e$ r# b+ Z! Z0 }: a
8.3.2 有关sysfs_dirent中的联合体+ S' T$ E, q; q) \' c) h4 {
分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。3 {& o8 C/ g% n5 I3 K7 {" Y# x4 D
- T: J' x2 Z; n4 R
/* type-specific structures for sysfs_dirent->s_* union members */
. ^+ E( e) Y  @0 Y, Lstruct sysfs_elem_dir {1 ?, |: }- x( [) E5 Q4 V
        struct kobject                *kobj;
9 U  l9 ~( e/ {+ {( b        /* children list starts here and goes through sd->s_sibling */
" v+ l. o* H  c+ m" J* z        struct sysfs_dirent        *children;- T$ J1 P: Z8 l8 n; @& T; V& l" ]' R# Y
};& {9 ]4 ]& J" I

  t, T1 j8 l' n7 U- Astruct sysfs_elem_symlink {
5 h- [/ y" ]; \/ D# B7 T    struct sysfs_dirent    *target_sd;
  `) ~  X8 b) [9 o};/ T4 E. ^0 }) v3 O
0 P8 O8 N$ M% F( z! B
struct sysfs_elem_attr {! N) J& L% k3 H1 _/ v3 N( F6 h
    struct attribute    *attr;+ Q3 Z$ j% n5 ?# P
    struct sysfs_open_dirent *open;
+ [2 v; T) e) [1 x& T};% z( A4 c6 H2 t$ N' {
9 ]" J1 N) R* t3 q7 R1 x& d
struct sysfs_elem_bin_attr {
$ B4 A! G" ~+ z, j+ H/ B4 {    struct bin_attribute    *bin_attr;- T! {( o) S6 K7 h( G
    struct hlist_head    buffers;" @9 p9 M4 Y- i
};0 p& }6 Y. M1 c+ T4 g
根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。; h2 x; l4 p6 h( B  w9 r6 e
在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。
3 ]# _: `. \5 c( ^( j9 R$ L3 s% A
在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。
! F& C7 |* `0 m. j' ~5 N7 n# n3 t4 ~8 o: b7 N
8.3.3 sysfs_addrm_start
8 t+ Q$ V4 X6 u' }7 g1 c- A- Z; a3 i在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。/ G" l2 [5 k  ^7 |, W5 J
. r% V1 @, |. ?6 C
下列代码位于fs/sysfs/dir.c。
4 P% j! m1 z- w1 y/**
0 [+ Q, `2 J8 S1 G. g3 [# L *        sysfs_addrm_start - prepare for sysfs_dirent add/remove- S7 H1 O; l8 t3 c( V, P# _
*        @acxt: pointer to sysfs_addrm_cxt to be used4 X( C1 b' C8 |- u+ t% `
*        @parent_sd: parent sysfs_dirent$ ?4 }6 k- k( x' [" I1 V- o3 a% ?
*
/ P& C% ?) u9 \* L3 e- a7 k *        This function is called when the caller is about to add or) I+ w* s6 w3 H* ~0 ^
*        remove sysfs_dirent under @parent_sd.  This function acquires
2 u) R! X7 b0 n% x *        sysfs_mutex, grabs inode for @parent_sd if available and lock' M, [9 Z) }6 N) k! J( {1 H
*        i_mutex of it.  @acxt is used to keep and pass context to4 j0 m; K7 i  n9 w& }- U
*        other addrm functions.9 L) c" G. }1 y: h; `0 X+ o4 I
*
' E0 Y; A; E# |8 B/ `7 q *        LOCKING:4 t; b. Y7 E1 }% R
*        Kernel thread context (may sleep).  sysfs_mutex is locked on
$ `* `: T% s( f# G3 D0 y+ t: | *        return.  i_mutex of parent inode is locked on return if
; ?$ P0 B* F4 `% V: K *        available.
, Q0 Y# {0 t2 \ */
- i1 e8 ~/ E4 \( q6 mvoid sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
. w* v2 c7 R% k/ x. }8 f9 Q                       struct sysfs_dirent *parent_sd)
' A( x: F+ G6 @) F{
7 \  s/ k) F4 A, [! o        struct inode *inode;
9 {) P- }& o- I. o/ h, s; [3 R! N! k
        memset(acxt, 0, sizeof(*acxt));
/ A- k/ z  N8 p        acxt->parent_sd = parent_sd;% _- ~0 P7 I; v. X" K+ U2 S% \

) U: ]' M& ^3 v9 K3 E        /* Lookup parent inode.  inode initialization is protected by2 u2 q6 x# t/ D! B# x/ }
         * sysfs_mutex, so inode existence can be determined by9 q7 Z4 i4 _/ F  A, N/ B: z
         * looking up inode while holding sysfs_mutex.
! z$ I' l  g7 }8 ^5 G         */3 y4 U; w8 P5 N& ~
        mutex_lock(&sysfs_mutex);# f9 i+ r: G" A8 N0 E
        /*根据parent_sd来寻找父inode*/, T5 Y  |& j# c* E% y8 ?
        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
. Q7 L: U. R& M                         parent_sd);& Z' V, S8 c/ w( r
        if (inode) {
8 U4 u3 A8 k5 e* C                WARN_ON(inode->i_state & I_NEW);
- z5 t$ t) G! F  L/ P
, d6 e# u, A+ h8 b; J2 i                /* parent inode available */% S7 q8 d; X4 E0 u7 ?; l/ U$ x; q
                acxt->parent_inode = inode;                /*保存找到的父inode*/
  s" Q9 d- W' d7 q2 P6 j& [( |
- h( H% t0 {1 ~1 Z                /* sysfs_mutex is below i_mutex in lock hierarchy.
$ A  d1 J* N- R' A$ f5 v3 T                 * First, trylock i_mutex.  If fails, unlock# I9 e: {& d$ L. n( Z4 }$ a
                 * sysfs_mutex and lock them in order.
* q$ i% @6 V5 `7 v" V+ s4 G4 E+ M                 */
8 F% ]) Q: b! _7 g                if (!mutex_trylock(&inode->i_mutex)) {  T3 E! j' ~+ t, F1 D
                        mutex_unlock(&sysfs_mutex);# x( O1 i6 K/ u% H; e8 P
                        mutex_lock(&inode->i_mutex);
; r0 \6 v2 D, F" z! }  e3 ~                        mutex_lock(&sysfs_mutex);
  m4 f9 g& ~1 Q; r! S                }
/ R/ E$ d  T) Y+ I        }& X; j7 x& Y* |  q- _8 j! G
}6 G. g# A! a3 n. D1 ^) \: X
1 e. z( l; M( R6 Q/ ]2 G9 Z( ?) S
/*( l; m) W8 @6 Z3 C
* Context structure to be used while adding/removing nodes.1 M6 w5 J/ D. R' P  t9 V* ~
*/
5 [# a' ?' d4 v* [2 b- lstruct sysfs_addrm_cxt {
7 g' _# q& k: K+ h    struct sysfs_dirent    *parent_sd;
5 l# w1 \$ E" }$ i    struct inode        *parent_inode;
# R  L! C* k9 A" o! L3 s0 X- p    struct sysfs_dirent    *removed;
2 U1 Y9 ?* M5 b! Y, c8 v# c    int            cnt;
7 d8 D/ {" L9 |( ?1 d2 f};1 I- S- D1 L% k$ o6 m! a5 @$ l: n
注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。) Q! Z  Z" o8 ?7 h* T; v5 m
8.3.4 sysfs_add_one. w; t- j, n( p
下列代码位于fs/sysfs/dir.c。
+ [) Y% `" g+ H/**
: w: P! N. e9 | *        sysfs_add_one - add sysfs_dirent to parent
; r/ @5 E$ ~, W* }! Z *        @acxt: addrm context to use% Z" O3 A8 `' y" m' B1 V& }
*        @sd: sysfs_dirent to be added# Q$ F' R  h& q7 s* M( @
*) C# W1 b7 q8 u% L& L
*        Get @acxt->parent_sd and set sd->s_parent to it and increment$ z3 y. U5 U+ F1 S' w2 _' T
*        nlink of parent inode if @sd is a directory and link into the
+ s! z) ]1 a/ ?+ D# ^7 L *        children list of the parent.
# R1 T- _7 D' K/ U *# R, A! X+ K" R; P4 C6 _0 k8 ?  t
*        This function should be called between calls to( x0 T6 K7 b2 K+ `' n  q9 ~
*        sysfs_addrm_start() and sysfs_addrm_finish() and should be: W4 z7 {* a% W0 }
*        passed the same @acxt as passed to sysfs_addrm_start().# b& G7 z, \4 i, ^5 u" g( F
*
; u& q$ C" T) X+ R4 Z& W, A *        LOCKING:; Y5 \4 }# c9 f2 Y- @5 e
*        Determined by sysfs_addrm_start().5 W+ t- A$ c$ t# x- K
*
4 T2 h- V6 K( v8 B& M: y% T, b *        RETURNS:5 ~  u! @! @* r: A' M; g$ w/ [
*        0 on success, -EEXIST if entry with the given name already0 U' R" W- i4 A& `% g; |) T& w
*        exists.+ t! _; x! v% s- Z+ E& E
*/, W: B2 Z+ S4 x
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
1 A6 u, \- s- ]# S{
( A# E4 E7 B! T, N        int ret;
$ {4 j* }! H7 o$ ?% A+ \+ P$ X  L! V$ u0 T( A7 X" _2 B% i
        ret = __sysfs_add_one(acxt, sd);
3 N1 F$ L3 b" q$ q  d7 U" U4 W        if (ret == -EEXIST) {* e% S7 |7 W2 e
                char *path = kzalloc(PATH_MAX, GFP_KERNEL);1 }" |0 n; `% \% Q, Q, N
                WARN(1, KERN_WARNING
0 K: ^2 h/ H* g( o                     "sysfs: cannot create duplicate filename '%s'\n",
: C/ D6 m3 f- e* |+ `                     (path == NULL) ? sd->s_name :
6 Y* o+ P( h+ f( Q9 k* ]                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),
' c9 c1 h: J5 I1 s! e2 n                            sd->s_name));
. ^! ?8 m5 o& [4 s' ^                kfree(path);# G3 C% c. _- l. q. P
        }
( K  |6 g% K' n1 M+ i3 d  v4 Y7 @. s. h: j6 V2 X
        return ret;
4 d+ Z/ {% w4 L5 ?}; b0 [' w/ r& |$ c' B  a

( J* w' |3 Z6 B3 P/**3 g  n5 m8 s/ F4 E" H
*    __sysfs_add_one - add sysfs_dirent to parent without warning! k! E* I$ ]8 Z4 o1 z8 P4 D
*    @acxt: addrm context to use! c- L$ U' a7 W
*    @sd: sysfs_dirent to be added  j* ?0 h! u" i
*) o: u  g2 w/ l" H; d  P) v
*    Get @acxt->parent_sd and set sd->s_parent to it and increment6 }+ A4 c: Y3 C3 |4 _2 l: P4 ~
*    nlink of parent inode if @sd is a directory and link into the
. x! m! R1 j$ t3 S *    children list of the parent.
8 B8 a- j5 z2 T+ t, x *( ~8 X# Q* g8 }: `( E
*    This function should be called between calls to
1 z3 X8 T% r+ x$ H) f *    sysfs_addrm_start() and sysfs_addrm_finish() and should be9 u% v% E8 ?' V+ d* }
*    passed the same @acxt as passed to sysfs_addrm_start().
- m# u$ h& D( Y" [7 Z3 @$ H, F8 I/ T0 c *8 ^9 ]# p0 R4 h2 W  Z0 L( F; T" v
*    LOCKING:8 X! ^; ]8 \/ e& }, k
*    Determined by sysfs_addrm_start().
4 A9 r, V+ c. w6 X *
) b8 n4 U% J; `7 G  B, ` *    RETURNS:
: G/ s: @; A5 a7 T. g, G *    0 on success, -EEXIST if entry with the given name already/ J! X2 I4 K/ E; a/ C# _' V5 [
*    exists.9 t7 [" Z0 W% \5 b
*/
7 M4 g, V- m; D; \" F- c( U/ ^int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
; D% a- ?1 S2 B# A* @5 |{
; f: s# S, {. M$ e  h; V; E+ C3 C    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
: j$ u- i- T0 h! S) |- j    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))1 `7 o) k7 V: F$ ~4 g& J) ]; e
        return -EEXIST;7 a! l  |( O, V" T: ?0 v1 p+ \
1 [. Y5 X: `5 D( G' F( Q: \
    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
) d0 }: P3 W! n0 Z3 Z5 f
, l7 u( }1 a; o5 m" o! K    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/. C- |/ L; O0 |+ o
        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/
3 V( |- Y' J: w" U5 n: R
4 y/ P5 {) x7 D2 m& d- H' B    acxt->cnt++;
# o" P1 F( v! ?2 q+ y. k8 U& _( }1 ^' ?% W/ c
    sysfs_link_sibling(sd);# L- I9 ~# A1 H$ F; K4 ^

& d. S3 N* C: f% `0 `$ z    return 0;
, Y, E* l2 _# b0 {2 s8 ^}/ `3 b. B7 Z" R9 D& r" z

& H2 i! S' h) n3 C2 V  ]3 ^. S% [/**& G4 m7 @0 `2 G) F
*    sysfs_find_dirent - find sysfs_dirent with the given name
: ?  L0 R$ m) x *    @parent_sd: sysfs_dirent to search under% f( S2 m& ~; U& ]# ]9 m- B) }# _
*    @name: name to look for# f( e% d" k; C% @9 U
*7 F+ {" |& T5 ^1 {" D/ }6 T# w
*    Look for sysfs_dirent with name @name under @parent_sd.
$ F- g; S0 F8 }0 p *; C+ H1 f! B+ V9 _
*    LOCKING:! k, }& [* y. i
*    mutex_lock(sysfs_mutex)$ S5 J2 v3 H3 m. Y# s  l
*+ V+ z# v0 u! T. q' ]7 D( E
*    RETURNS:
8 m3 n/ j/ `8 }# ^- F1 L! L *    Pointer to sysfs_dirent if found, NULL if not.3 U: f  X- n' k5 P
*/! D# r" `5 V' z: m; u( g- v2 }/ e
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,/ G' P) ]1 I4 Z+ e8 q: y* d1 j4 v
                       const unsigned char *name)) s$ x& q; d# \" b( ]) d
{
8 p# ~. p7 s5 w    struct sysfs_dirent *sd;8 z5 [0 o2 G' J3 Z# X9 `1 @) O, Z! o$ N
- D+ m, d. {2 j& G" a/ [5 B( a: ^
    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
8 g7 S( A+ L; X        if (!strcmp(sd->s_name, name))
6 |6 b4 V0 j6 r7 ]% S7 ~            return sd;( u9 W# T! f% i8 W
    return NULL;
7 l7 S6 a% O  {} 0 _! [3 e  }: S5 D% m; t

* l$ \! c( j% C; [2 T: U( P/**9 Q1 b2 d# d- y( ?: }
*    sysfs_link_sibling - link sysfs_dirent into sibling list# B9 ]4 d. n' P! |( t
*    @sd: sysfs_dirent of interest. A  K" R, w* U5 A# H3 K
*
3 D, o. {: I- t  ?( {7 ? *    Link @sd into its sibling list which starts from
6 `; Z! i' C3 W *    sd->s_parent->s_dir.children.4 X4 j/ e# O3 U% H3 F
*
3 K. _3 e6 @8 t# ~8 p8 X; M *    Locking:+ p- x; W7 @  X7 t
*    mutex_lock(sysfs_mutex)* L! v6 b) [7 _6 P5 f  M
*/# |, R2 S8 e, X6 Y
static void sysfs_link_sibling(struct sysfs_dirent *sd)2 O4 @. D, p" B6 r9 b
{
/ s: X: O& G2 G% r% @, E( m- D    struct sysfs_dirent *parent_sd = sd->s_parent;' o8 K2 I, Z9 K- e- E
    struct sysfs_dirent **pos;2 o4 X- E2 f. C" R5 j5 y

; d; v/ |! }  k6 n( C' I' l& R    BUG_ON(sd->s_sibling);6 Z9 U4 j$ {- j- X) ?0 h( f1 t
) p9 C/ }0 {7 @1 f9 [# \' A7 P
    /* Store directory entries in order by ino.  This allows  K; d5 u+ v6 y# n& t& C4 V
     * readdir to properly restart without having to add a. F  u3 a& k' [. D  N
     * cursor into the s_dir.children list.; E' k8 ^% S$ m! X- _
     */7 [+ G. c9 o+ D6 F
     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/
4 h9 [1 n' p" x0 {; |, [1 L$ I3 v" G    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {% Y% |" u& Y- E* V" ?0 Z1 B
        if (sd->s_ino < (*pos)->s_ino)4 J4 r$ e! q1 \
            break;3 c% x1 l( h9 r  b% S/ S( m
    }
3 m. F$ Y% L* d: ~+ {$ ~( a) B; r    /*插入链表*/
8 Z5 `/ u) ]3 u9 _" g& ?  _    sd->s_sibling = *pos;, _" Z, L  R0 V4 L, p3 ^% E4 r- \$ u
    *pos = sd;
& T0 r2 [3 [) Y}
* X  a  c! i) m" o* _5 D6 N7 @该函数直接调用了__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链表中。4 A5 w. V* h8 Y( s5 a9 j" M
8.3.5 sysfs_addrm_finish6 L  `6 B% D1 n  ]7 C4 k# `- G$ B0 M3 b
下列代码位于fs/sysfs/dir.c。1 Z/ Q+ @& ?) {' ^" Q, J3 ?
! c' `& y9 W- g6 a. S
/**
) k9 H" g/ J& w( z6 I *        sysfs_addrm_finish - finish up sysfs_dirent add/remove1 U: y# i" r! C; @5 e+ b
*        @acxt: addrm context to finish up0 d- M" n' z2 G
*
8 f4 w" ]' p6 r( ~' l" K *        Finish up sysfs_dirent add/remove.  Resources acquired by1 x" L1 L: }  v! J0 S
*        sysfs_addrm_start() are released and removed sysfs_dirents are
. H4 R2 N3 C0 [, ]9 y+ H/ w *        cleaned up.  Timestamps on the parent inode are updated.
5 I: ?& p$ n8 s( C *
: i, {; Q) N. o( U *        LOCKING:% a7 m3 Z7 {) v2 B4 V6 p
*        All mutexes acquired by sysfs_addrm_start() are released.
* Y' Y2 U% H3 D: z5 v1 d+ | */% B" J* J' ^. E4 k8 r8 {8 T
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)' k7 m8 |4 _0 N9 Q( o+ Y& b3 E
{% U, U/ i* {( _* ?, g3 S8 T4 N6 l
        /* release resources acquired by sysfs_addrm_start() */% I- m( x7 j- s3 D, K: W  c
        mutex_unlock(&sysfs_mutex);
$ {2 K+ R) }4 N" Z- y* B        if (acxt->parent_inode) {6 C' V& }1 Y1 Z
                struct inode *inode = acxt->parent_inode;9 I3 w# S+ L: `$ X* x$ q% ?6 F. Q

2 w- c! B% M/ |+ r3 }( P& L9 J* _                /* if added/removed, update timestamps on the parent *// m% w3 g9 @9 r; W8 a- O; v
                if (acxt->cnt)
2 m* O' ]4 Q' Q! n  L4 Q% H! ]( `                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/
7 o3 ?! b" a4 ~8 B: G5 z3 z( y% r  ?4 l, Z' }& l4 Z
                mutex_unlock(&inode->i_mutex);! @2 F+ {6 r1 M, e# \( I; ?
                iput(inode);
" r7 G; n/ ]7 j        }" }8 k9 _, q# |3 G% j' C- G
8 Q. \; h8 |+ n- _5 z5 G: ]; n
        /* kill removed sysfs_dirents */
# b( a2 ~+ C1 q, ]* p+ ~        while (acxt->removed) {
6 E5 e7 p4 A2 d0 Q. X* r! X                struct sysfs_dirent *sd = acxt->removed;' m. o# `3 U  [. h0 f! s
" m0 ~! e8 P  H% H* Z; |- W
                acxt->removed = sd->s_sibling;
( S1 u0 I" n; f! `                sd->s_sibling = NULL;
. R6 R$ o# D+ }+ w; v% g1 g5 D* r* x7 U5 P4 R. Q+ }
                sysfs_drop_dentry(sd);" d- i. D5 G$ ^- e
                sysfs_deactivate(sd);! e; w. q; [/ G0 b. }
                unmap_bin_file(sd);
9 e5 _! f- m: q6 J8 s6 I7 h. J* ~                sysfs_put(sd);
1 S; T! _; b( R/ \3 D7 n* [) L        }8 |1 d# ]( N" r+ O7 D
}
: x1 _% v" L, M( Y6 F+ c" ~* e: Q
该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。8 c% y: [; {: l4 w" k( E
$ c) \6 H/ [+ z
至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。
* T3 T5 [  Y+ u( i2 M7 h! \6 b6 h
下面我们看下如何添加属性文件。% t; \" ?+ z/ A; K3 |0 C3 ]8 m+ W
8.4 创建属性文件
! x/ r5 P: ?% p3 T添加属性文件使用sysfs_create_file函数。
* ]8 G6 H  T/ w0 e" [+ O+ D; R9 f) a* S) R
下列函数位于fs/sysfs/file.c。* H. ]  c# r. ?9 _* _( p5 o
/**
( N! B% `- ?" [9 ~ *        sysfs_create_file - create an attribute file for an object.3 ]& I! a, Y6 ]5 E/ R: O
*        @kobj:        object we're creating for. ( z* L: S; b( b/ q0 ~
*        @attr:        attribute descriptor.
# d4 t3 d) p) ~6 w */
) S6 P+ i6 R2 r: f& _3 t% K9 ]1 F1 O4 b8 O
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
9 P5 d2 C2 `- s- r% m{, r# R4 [$ R- \9 a) ~% D
        BUG_ON(!kobj || !kobj->sd || !attr);
# _' \: ]) a9 G3 m6 O! k3 _/ T& v# l# R+ B( A0 o, u  i/ I
        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
. `0 \( M5 x% X  Q* l
) D; A7 P4 n5 }4 ^- O}
: @& Y2 U" u# G
7 r5 r5 d9 b# v) |int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
9 p( ]9 z/ ?+ Y! |3 w7 h* o- a           int type)
: A6 s( @/ `+ }2 p9 P7 ^4 a" k7 U{1 |' i1 m# J, ?) ?
    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
/ j& U6 t; L" c' q5 u$ @% {( l}) v7 B1 f/ i% M. I0 R! D+ Y
; F- @# k, a" E8 c; K
int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,7 ~7 a6 L/ a1 Z) c# h
            const struct attribute *attr, int type, mode_t amode)
3 n) k9 T' o" w{
$ X6 e+ A( L; L    umode_t mode = (amode & S_IALLUGO) | S_IFREG;* ?% c1 ^3 F, t) B0 I
    struct sysfs_addrm_cxt acxt;  B4 X' c" E; t
    struct sysfs_dirent *sd;
/ y) r. c# S2 u9 S    int rc;
  `- l, G; p, ~' H/ {    /*分配sysfs_dirent并初始化*/
' k! O4 i" F5 p' m5 O    sd = sysfs_new_dirent(attr->name, mode, type);
8 g# N& N8 T- o/ E2 q' l    if (!sd)+ `' G$ Q3 K, \) L0 S6 O) d
        return -ENOMEM;' O7 Y( P' T/ o. P4 o# f
    sd->s_attr.attr = (void *)attr;
7 Z6 r4 j) ^& p: p; E6 L1 a- w
& g( P/ |  @. f+ @; a; @% o    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/
8 t0 Y6 n2 B9 Q. P    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/; [6 O7 d8 I- w% v, O3 \% {# q# I0 G
    sysfs_addrm_finish(&acxt);            /*收尾工作*/
" V1 s4 R" b% K- Z. U0 H. o* c6 o% z; A2 G. {
    if (rc)            /*0表示创建成功*/
$ y% g' Z: b+ \        sysfs_put(sd);: T) N2 i, ^$ r% X5 n5 n1 U# O! U; [
4 _/ L; P; v, m. F( a. m% t6 }$ r) S
    return rc;+ P) P3 q! k: X/ q* }3 w
}
5 _  j) J8 k$ d. z1 I. O& C0 s) E( a$ j1 ~& k$ s
sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。, H. \4 k' w- x  Q8 A: P$ w4 o
sysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。
* a' l* Y9 k7 J2 \1 T# J1 O# E
' k  C( D2 m. I2 @* b- A/ Z3 P需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。
& y7 e$ D+ a8 Z) f6 K8.5 创建symlink
( B) n7 w; \/ T/ C最后,来看下symlink的建立。3 B+ f5 v5 ^: I
/**
3 z9 N# C# N* u *        sysfs_create_link - create symlink between two objects.# s8 F$ x& J6 v: \( I% |7 C9 ~; O
*        @kobj:        object whose directory we're creating the link in.
/ B$ @7 y  Y* }2 ]. Y *        @target:        object we're pointing to.
5 d; O" q7 L9 Z$ [- a  s) c *        @name:                name of the symlink.
# }) M, G. V3 f5 Q */3 q6 u& g5 R# r$ H: k* r
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ d. R3 T2 j; |0 E0 y2 k( Q! T                      const char *name)' ?* ~& U! @; }, v
{4 w4 @1 U( I+ f$ p) @& S0 o
        return sysfs_do_create_link(kobj, target, name, 1);
; `# e+ O0 e, @4 V. R( p; `) n}- F4 A; M; T4 D0 J" G

$ Z5 `) x. G- v& G) m8 L- @static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target," X# h) U& \, m$ t/ o
                const char *name, int warn), _2 R/ v* j3 t0 `3 _* Z+ H
{* N1 H  ?3 t7 z7 ?( q
    struct sysfs_dirent *parent_sd = NULL;& Q( w) F) G7 ^/ Q
    struct sysfs_dirent *target_sd = NULL;; Y7 m" s+ F- k0 E: p
    struct sysfs_dirent *sd = NULL;
  I/ I: M) I3 G# f7 U3 M, _2 X    struct sysfs_addrm_cxt acxt;) i7 G$ g7 t/ U. q2 L. A# [/ B
    int error;
& [" H7 S' J5 \& k, J0 ]: |
* x9 Q- M& z( l/ n: o$ G& ?    BUG_ON(!name);
1 ~+ J5 s0 O% p7 ~) N3 C. f
% O0 O( M0 z% U% x    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/4 }" ~% M& v! \$ @
        parent_sd = &sysfs_root;, X9 I1 A( f. e) \6 r) Z
    else        /*有父sysfs_dirent*/
- ^1 S3 s9 v+ W1 F& @. J. f        parent_sd = kobj->sd;
8 H  X- N. h' @& h8 j( [( B7 m) E; o& u, p* @# K) d$ {
    error = -EFAULT;" |. d9 t6 E. z: L* W
    if (!parent_sd)
- b) k! r1 D7 k& S7 }- J        goto out_put;
  }% G) F. w7 w. |% B1 F6 Y8 I0 R$ O7 O% q5 t- U, W3 N
    /* target->sd can go away beneath us but is protected with9 Y) }# `# L& s4 }' v% Y
     * sysfs_assoc_lock.  Fetch target_sd from it.
( G7 v0 x5 Z2 n/ N- k4 @9 L4 q, v6 T     */
3 d: q7 D# _4 b% h    spin_lock(&sysfs_assoc_lock);* Z5 Z# D5 D3 I- I  o7 b8 d
    if (target->sd)/ q) `% }; D0 K0 f# p
        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
9 L% f) m# J1 u& Q! J- Z( a4 Q    spin_unlock(&sysfs_assoc_lock);
& i' B' b2 q* \/ n! {, r/ h( f# D0 o
    error = -ENOENT;( k0 u; ]' U' V8 B. i
    if (!target_sd). Y1 [) `: M; k" ~3 C4 u
        goto out_put;, P3 W1 R1 w) T. Y% |4 x
; d! s6 n% e, V; S9 O& m4 `& ]. x7 O
    error = -ENOMEM;: M: c! i9 T4 L7 B! ~
    /*分配sysfs_dirent并初始化*// M$ K+ [$ H% i9 N. U- y0 J; ?
    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
7 l5 g4 I  Q, E+ ^    if (!sd)# g8 n* R  y6 {4 s+ t
        goto out_put;. A# [9 x* j2 G" ]9 T- ^- k) M# H
# B( ~* Z6 C0 l6 u- x, ]* o7 s
    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
0 h! C& `6 h; N7 U5 W( ]    target_sd = NULL;    /* reference is now owned by the symlink */
  c) O( d4 `3 r: g0 ^4 E) b+ L/ t" ]! B. ~, I* X* c1 I' ^& r
    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/8 U4 C4 c9 o/ p  c- m( t# X, @4 k
    if (warn)
) B  s1 u( a( x" O. L        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
3 [& `8 b2 x% l3 A3 C) q) y    else
% l' H' {  _# _. `2 z        error = __sysfs_add_one(&acxt, sd);, n' L2 W5 Y, X* B+ u
    sysfs_addrm_finish(&acxt);            /*收尾工作*/; S& `8 k) w3 k% g4 k" [

2 o" z5 y$ W3 s  ~/ \    if (error)
! R6 |5 q, Q: K        goto out_put;
* F5 j; T: R+ M1 `' J
) C" y% O% G2 C& `( u2 R    return 0;
) x# d& ^" x/ Q) l9 f6 M; N
1 Q% p: ~) p% b* A& @$ o out_put:4 c7 G- B9 c5 a
    sysfs_put(target_sd);' v9 o: ~9 T: d8 M
    sysfs_put(sd);
/ l6 Z0 i% R  {) C    return error;- b3 C% Q2 s! k8 R2 o* {7 E# k. K
}
( X, A8 G0 T0 x* q
; n- e: q& G! v8 ?# P这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。
3 c9 @0 F, P. x6 y3 l9 t因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。' {. H  w. h, M

8 \+ U$ Y6 E) V! T% ]- v8.6 小结* M1 F! d: {6 f$ O# M' Y7 Z0 D
本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录
  [3 G4 Z7 l2 v4 z; @: j
; \3 Q1 Q1 \% z0 ?+ y1 I7 k有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。* `) x; e) a/ v# w
0 ^0 X; v7 `! i( J3 x5 o
9 总结# z5 h9 W; Y( A# g4 x& }
本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。7 H. V( R7 @  A( m- p
6 H+ M0 G- ]9 S# P  B  l0 n
接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。
- S2 r$ o4 b1 n9 L* y0 k9 E1 r$ {! _9 k1 k( U3 ~
随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。6 e# i2 S$ L9 t9 r0 D: m0 X% Z$ `
& {: l  t0 f$ z6 r5 K, R$ d8 S
然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。
% W/ S7 f6 Z: k
0 T: G/ Q8 A* Z: Y" x3 O4 K! @之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。
& u; J" c$ k4 @+ Z5 g0 Q$ z
) h) e. x' D7 v$ X2 h. T最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。2 O2 w) I5 x  J) O5 v, k. D& w
# X# A  X& P5 D) B; T3 m

- B9 h5 m+ s* K

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 17:54 , Processed in 0.468750 second(s), 26 queries , Gzip On.

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

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

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