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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。
- w/ I& R8 t8 d9 k9 k3 F3 w1 L5 n3 r$ p2 R8 ?; w
内核版本:2.6.30
2 N3 F; g5 j: @* v8 s7 ?. U8 d: t! c7 Z0 a: H
1. What is sysfs?0 g2 k1 y* f) v
  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。
. r& o3 Q+ S3 X! i8 d# Y: [: I& G+ j  ]! l
  我们来看看sysfs的文件结构:
8 u& ^+ U- d; b0 E( X% X2 G. Z
% {1 K. K! I: c/ ]$ U1 E  _! p[root@yj423 /sys]#ls
- n4 ^5 _" q( A; [( Q4 nblock     class     devices   fs        module7 O* Y: @# }9 v# ]: y; m
bus       dev       firmware  kernel    power. J& M, m9 G; C6 ]
- W2 |9 b1 V# v% N
block:块设备2 n" e. V1 k7 `" }1 c- U

: u" Y3 x; I5 i9 n6 n1 I$ Lbus:系统中的总线
% ^( ^7 N8 f# g7 [, n  u: |5 w$ t9 B. ~
class: 设备类型,比如输入设备& c) L  F; i! E( E( w
& ]5 f3 \9 B1 }
dev:系统中已注册的设备节点的视图,有两个子目录char和block。
1 X- P0 G8 b( U7 L& J2 E* k
! d2 z4 y0 y/ ?devices:系统中所有设备拓扑结构视图6 ?) x1 n; \+ j$ x* n

1 G1 j& F6 u# {. |fireware:固件
# j% z' ]# |4 ~9 V, k$ D: ~) ~
  u! m& A2 L* k  k# mfs:文件系统$ n) f3 B2 y5 }
& G6 ]) @+ t) H2 E' W; c
kernel:内核配置选项和状态信息
+ R* }6 z1 T$ K4 S; s  t( |5 M9 |' }+ k& W3 ]  {4 {6 s
module:模块  p, `0 s, F  I4 x& a. r! ~
; e( \2 I0 z' W
power:系统的电源管理数据
& P( G: o0 A& `) g1 R1 ?) f, G4 N& u( R$ a. D
2. kobject ,kset和ktype
- o5 w. q- W: K; A' r5 {  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。- S& Z& D! C7 ^/ j1 c  h; J+ V
9 \. w* i( J2 _8 B
2.1 kobject8 n& z( j8 R6 s8 B3 d
  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。9 B+ p' \+ X4 {  N

4 L8 Z) ]$ l5 D* X  kobject用struct kobject来描述。' A% A- e! g. Y' _2 k( q' o
3 w3 V, h+ m. V* {  K0 ]+ \& p" v. K
struct kobject {
- Y2 ^" g  {( x% b& t# j    const char        *name;            /*在sysfs建立目录的名字*/
$ s% }5 O: D  \7 E3 n- |9 j    struct list_head    entry;        /*用于连接到所属kset的链表中*/
) x+ X3 d3 [- ]6 `! e- ~) u% m. y# O    struct kobject        *parent;    /*父对象*/
. r" `. Q$ T+ t7 |, N4 S5 H    struct kset        *kset;            /*属于哪个kset*/
7 T% m9 F: A6 B! E0 @2 O) l: Q    struct kobj_type    *ktype;        /*类型*/
+ p& t( m2 E8 o    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/- d2 n( A& W2 g' H6 Y
    struct kref        kref;            /*对象的应用计数*/) m6 ^! i* f/ @8 p1 U6 W
    unsigned int state_initialized:1;: r1 G& p! @4 u, l; [( {! ]
    unsigned int state_in_sysfs:1;/ x' v. ]+ Z: i3 I
    unsigned int state_add_uevent_sent:1;
/ L+ X: v6 h* Z: F    unsigned int state_remove_uevent_sent:1;
& w; F( K- M: Y4 [$ h    unsigned int uevent_suppress:1;
1 ^1 u3 p" s7 J! ]6 k};1 J  a1 o* q% A- N$ \% y
2.2 kset
- q# x$ ~: Q" N- n  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。) e2 k3 R, g2 L% z5 A4 l) X
4 Y  v# U% g- b- k6 n2 Z- D
  kset使用struct kset来描述。6 i3 y/ x1 W6 O4 T& W* Q1 _
+ I% x/ f% W* ~! F
/**
, `) _/ K; a. c$ G, b * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.$ X% y4 z" `9 n: i
*
; v9 I+ G$ {9 S. t * A kset defines a group of kobjects.  They can be individually7 ?. r' g% p+ V+ j4 p! B
* different "types" but overall these kobjects all want to be grouped8 Z* I/ p; S) n% }1 V. G9 F( f. Q
* together and operated on in the same manner.  ksets are used to
" t  `2 {1 {8 H% ], M- H" K$ L * define the attribute callbacks and other common events that happen to
8 w3 R6 Z2 |) d) i1 F; \' [ * a kobject.
; S, R7 C2 D0 e9 g *, q$ Z- ?5 n# T6 @6 B8 |& b
* @list: the list of all kobjects for this kset0 p' J  a9 ?& `2 j, N3 s- P
* @list_lock: a lock for iterating over the kobjects; T( w8 o, H/ Y- t
* @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
+ N5 s- Z# T# K8 v( a1 F * @uevent_ops: the set of uevent operations for this kset.  These are
) g7 [7 T' I( I+ G * called whenever a kobject has something happen to it so that the kset
2 L! ?+ C' V# l6 \6 g4 u, r$ _ * can add new environment variables, or filter out the uevents if so
& |) R& x+ q/ e) Q6 B/ Z4 E& D0 v * desired.- _" H$ T3 S6 a/ I: g, N
*/% @  ]# P7 |0 O# }: S
struct kset {
  p- ^2 ?# D" z/ x) t% I& m6 |" ~' x! G        struct list_head list;                /*属于该kset的kobject链表*/
8 R4 T0 w, s  `( O$ \        spinlock_t list_lock;       
1 R1 l5 V: l- \( l4 {        struct kobject kobj;        /*该kset内嵌的kobj*/
" X( ]% I0 l5 A2 C5 U! C: F
  S# ?4 x2 M- D9 j1 o        struct kset_uevent_ops *uevent_ops;/ k. B/ B3 c  \: y, n( ]& d
};
7 t) k0 ]. M; {8 e. l
$ N/ x: y% e+ i4 m  e0 L8 I2.3 ktype# t$ v5 ^: G$ t7 d3 X# v1 W
每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。
' K4 G+ I/ H2 N5 i$ D' F& ~- z5 D
struct kobj_type {
" @6 i) @: N/ S: n    void (*release)(struct kobject *kobj);; m/ i: i, D+ w8 N
    struct sysfs_ops *sysfs_ops;
  g7 `, F# |4 v; j    struct attribute **default_attrs;
( y9 \6 y) W/ o3 ]/ T};
' g/ B- @) ~& V7 O  N/ k/ q8 ]+ L5 x. B7 X, w- q: V8 p' @
struct sysfs_ops {( \- ?; r. _9 K: s. W! P2 D
    ssize_t    (*show)(struct kobject *, struct attribute *,char *);, M/ I9 |9 r5 J; c
    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);9 n6 y, r( K3 X, S' x
};
5 l% _0 s- A& m. B1 q9 g/ |$ l
' r9 f# j" G: |7 D/* FIXME1 M. N9 S# O+ l3 \% {7 v
* The *owner field is no longer used.
4 A. P7 @1 |, A5 s1 ]+ l& _ * x86 tree has been cleaned up. The owner& I) H+ J, u+ F/ a. S
* attribute is still left for other arches.. q! e4 E( f- |$ u, n5 O! u
*/* t" D8 B" Y( V4 `0 {' P
struct attribute {
% e+ q# d! a/ N    const char        *name;& K# q& r  O9 R$ t& a
    struct module        *owner;" G/ w7 c& }7 o, q% ], M% O
    mode_t            mode;
8 F; b2 |7 @6 v- |  k/ c};
+ T8 _7 i* f" \4 h" w9 d6 s6 V+ \
% _% x3 S  s0 A0 u: V6 {* [$ Z9 e0 P: J4 R" ^0 Q
当kobject的引用计数为0时,通过release方法来释放相关的资源。
2 S7 t6 A2 I' ?. pattribute为属性,每个属性在sysfs中都有对应的属性文件。7 N! l+ n- I% H' }  a4 h' F! |

! h1 s* i( ~) @sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。& `: }" ^% N% \# W+ ~; L

4 D  g" }& u# s% j$ Q2.4 kobject与kset的关系
( s. L" f$ p# J4 q2 K, g  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。+ i* I% [: O$ O% Z) U  R
& [5 z; [7 x4 w8 p  d
   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。
: O- ^7 C  h2 P% f$ _. h
, c5 E* c. C% r, @' r 3 C2 q0 m/ ~' s! F5 }
2 e4 s1 ]& P9 a# o
3.举例
$ N+ p- T3 P, U. T8 n3 e7 l在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。# B4 y3 f: A& T4 a1 J

3 Q: u. I/ l2 h2 c5 T下面代码位于drivers/base/bus.c
+ ^1 g( [9 a7 k7 c' b2 Y5 Y* f( Eint __init buses_init(void)" R7 x3 p5 z3 I, O
{! P8 J; J0 g" y' g3 w
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);7 l) h$ P$ _* p, u! W
        if (!bus_kset). X: Q$ o4 q, d6 x
                return -ENOMEM;
& r2 [( N1 \. N) c# s* u        return 0;
' g) K, d' x# c9 r& r}
% V8 i) L& c7 X6 e  n$ E8 U0 y& J  g. Y7 y8 j: y5 Q  [( m
static struct kset_uevent_ops bus_uevent_ops = {
$ B: o( B% ]" Y. W    .filter = bus_uevent_filter,
! T1 z. C( Q2 C4 `};  \  }( [& K# B$ K! D
% X* ?. Y) D, i4 `! t
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
8 O& ?' o1 S& r& {! Y! E3 B! i{
0 ]* J2 q+ b7 l' q; y- e    struct kobj_type *ktype = get_ktype(kobj);% r. z4 Q1 B) l. z
# A! Z0 v, g" a; \0 w
    if (ktype == &bus_ktype)$ l! p7 _, o$ [0 o4 ^7 ~
        return 1;5 t& Q3 M& m% m3 f+ x
    return 0;
2 ?6 o+ c% j6 q4 t& f}
  o( L9 Z! T" S! h) {; t5 w这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。7 S* Y$ i+ `: x$ e9 i
下面代码位于drivers/base/kobject.c7 b1 W/ |2 k- e! j# K2 \4 Y1 z
/**6 H" w+ F  N, y9 X2 y. D9 _; s
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
5 Z( z' q# J0 ]8 v; X0 A+ T *
7 V+ T* J7 p1 C* p/ v5 p2 ?% V * @name: the name for the kset
9 p0 s! R% g- E* a* v * @uevent_ops: a struct kset_uevent_ops for the kset
5 M+ t" K7 q7 s$ b8 l# k- o9 g * @parent_kobj: the parent kobject of this kset, if any.4 i3 }1 x8 O2 v
*
8 B1 l6 e* O# P * This function creates a kset structure dynamically and registers it' }. z( h# s7 {: N8 U; ^
* with sysfs.  When you are finished with this structure, call
) r3 E' R' h7 F0 M* \$ H * kset_unregister() and the structure will be dynamically freed when it
( B0 I; F: O: M/ l# `- u * is no longer being used.! Y  \4 K( z7 k. f# y; c  d4 k; ]
*
2 y4 A" K/ s! d$ Z2 F; X0 n * If the kset was not able to be created, NULL will be returned.
( B3 K& W2 r2 C. C$ V: J */* u* L, S0 H+ j4 U, [
struct kset *kset_create_and_add(const char *name,
& p! H  k) T) c) d5 z; G" x                                 struct kset_uevent_ops *uevent_ops,& U% M3 K0 R' |8 _  |: b& f
                                 struct kobject *parent_kobj)
) U: V9 ]+ X# I' W1 x{" m; D# ^# T* t: d1 N1 K
        struct kset *kset;
5 @2 K7 V' m. p3 ]# Y0 u5 k        int error;9 j( u: b) d0 q1 `- y9 @  w6 _' u

8 ]0 t  H9 f, @' q        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/
# f/ O( L. H( f! ]; X( ^        if (!kset)6 P! H/ m5 ~% r. g# W
                return NULL;
9 p$ ~( p9 n0 x" @        error = kset_register(kset);        /*添加kset到sysfs*/
: V' V# N2 K/ W4 T& b0 A        if (error) {
/ \5 H1 o" t5 |! V" ?; ^                kfree(kset);
3 |2 D2 q8 `" ^8 D8 F" m$ n! p# R* @                return NULL;
, A( M$ V) L: V# z0 G) D        }
' @+ T5 p, d4 V. _0 a6 b3 j        return kset;: K4 A; \: f* B$ Z' T
}
- _2 @: I0 ]% N  {3 `这里主要调用了两个函数,接下分别来看下。
/ E3 L2 m9 q8 F- ?0 k& m
8 M! S# s' d; G  z+ P! |3.1 kset_create函数
( d0 i, i6 M) t" ^* R) ?% t7 s下面代码位于drivers/base/kobject.c
! M  ~! s  x$ e  ?5 C) p7 m
7 U' ?1 [2 H. m7 b2 E/ S/**
  _# p5 e6 R& j9 j- L) V * kset_create - create a struct kset dynamically
- ?4 N! e/ Z3 w$ r$ M5 C1 q *" x) H. G, H: }. Q/ P( x
* @name: the name for the kset
2 w6 I" r/ H5 B * @uevent_ops: a struct kset_uevent_ops for the kset
1 p& ^2 N/ {1 I6 t* y$ P  u3 J: a * @parent_kobj: the parent kobject of this kset, if any.2 g( A3 u5 x4 F" X+ X
** Y& s7 w" ]- t# @( a! _6 A) A
* This function creates a kset structure dynamically.  This structure can" Z2 I" [/ B( |$ s2 |& x
* then be registered with the system and show up in sysfs with a call to) I6 k2 V( u6 q3 z2 @( ~$ H
* kset_register().  When you are finished with this structure, if
/ V4 A3 v' j4 s6 g4 W( r * kset_register() has been called, call kset_unregister() and the
$ v  I6 k$ |. L# I- f- ? * structure will be dynamically freed when it is no longer being used.7 Q& B; I+ @4 u9 t5 b+ `7 P
*4 d: h' @1 H$ ]5 l6 Q( o
* If the kset was not able to be created, NULL will be returned.- O; z$ L9 ], R4 m( T5 P6 F
*/" b# f/ {7 x6 j6 F. d
static struct kset *kset_create(const char *name,
, o3 U2 F4 Z3 o, `. Y                                struct kset_uevent_ops *uevent_ops,
6 \0 a/ K" F! C& v! w' l. m( C                                struct kobject *parent_kobj)
2 }' A+ {4 a2 V$ ^+ i& d{
$ B( N+ s9 |1 @) z, p) e& {        struct kset *kset;1 b0 g. _. X& ~1 i0 u+ @* M
. g* ]- k+ K# R- J
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/' \$ z; l: b# F4 Z0 B' G
        if (!kset)
4 q. ^3 u. F4 H4 c  W% x6 j! @                return NULL;/ B& ?  d$ W* z' J# b+ U
        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/
3 W$ V+ n9 q3 }* s( M5 `2 E        kset->uevent_ops = uevent_ops;2 @8 y% E% ~5 p5 v8 _3 H  l
        kset->kobj.parent = parent_kobj;        /*设置父对象*/
! e2 }; Z& Z$ c$ e% @9 Q7 Z
% u: ]" K% {1 q) S5 R& K0 C5 _        /*
2 g4 a  m; u* Q# J9 M% Q         * The kobject of this kset will have a type of kset_ktype and belong to
4 c$ d" }' J, |. n         * no kset itself.  That way we can properly free it when it is* u5 ?/ P7 c" l5 |( g
         * finished being used.. U5 }- P$ e& h) u; U4 n
         */
" W3 X% b& z* T0 ?; i8 x7 x* h        kset->kobj.ktype = &kset_ktype;6 \  }# m% ~) ^! b
        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/5 c4 Q3 n  J# a/ R/ D
. y  A4 q, ~5 m2 c" w+ L8 R2 ^' u6 V
        return kset;0 c/ o; |) n" w' u" s
}
2 I# A- _4 G( P8 v5 Y; a1 u# V/ n
0 u9 p3 Z3 a3 P; S这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,
2 g/ k4 {6 S$ V3 o4 s
) [( s: _0 j9 w; V" V% T% Q也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。
7 Q3 ?7 K0 c6 }! J! z2 v# [# a) c9 x' {% h6 C$ J
随后简要看下由kobject_set_name函数调用引发的一系列调用。: ?9 Q- O8 [0 O

: p7 ]$ T' O& i$ }/**
# {8 @9 L7 S- b7 g# i( ` * kobject_set_name - Set the name of a kobject, |# |3 P& v" \& Z
* @kobj: struct kobject to set the name of# `% j( T; s% @/ u: Y
* @fmt: format string used to build the name+ ?3 \) j+ D" e3 n" e
*! ?: A9 Z( A/ I. ]4 c& o
* This sets the name of the kobject.  If you have already added the# c- W  A; z' Y+ I) W
* kobject to the system, you must call kobject_rename() in order to. L$ s$ v3 f2 i* J# l' S7 Y! @0 Y
* change the name of the kobject.* [0 _! @0 Q" ?4 w- z( ^
*/
* ?6 H. c% N7 H) Oint kobject_set_name(struct kobject *kobj, const char *fmt, ...)3 ]: Q5 d  B( r" R4 o+ d$ a
{
# t, y  b  ^0 g" b  B- [        va_list vargs;5 w& a1 U; O; p& t& }0 N# e
        int retval;  Y( ^9 E) p6 a, F9 h2 Z, G& m6 {

3 V7 V0 K& l& f) {        va_start(vargs, fmt);! Y9 F4 d; A8 u; S: O: {6 P
        retval = kobject_set_name_vargs(kobj, fmt, vargs);- p/ L3 a1 b- y( L/ _
        va_end(vargs);, L8 U0 O1 o  U
0 u9 T4 N/ R- k
        return retval;  a  }) @/ q) j# A3 C
}
' H4 C% T. m1 n5 j4 M
- L# p0 O& ?* k6 D1 s7 M) {/**3 i$ M8 ^& q* B. |  m- ^& o8 b3 j
* kobject_set_name_vargs - Set the name of an kobject
, N4 r8 ~1 ?4 I9 G' ?5 l * @kobj: struct kobject to set the name of
. o, c% P. J/ \% c8 i* G * @fmt: format string used to build the name
- j" X4 O/ J) F0 h" U8 w8 j * @vargs: vargs to format the string.
6 ?- ~5 m* d/ W8 ?5 m; b* G */
" d& X' ]( b3 f: J: t. L+ uint kobject_set_name_vargs(struct kobject *kobj, const char *fmt,% ?2 G7 A4 P  L  b
                  va_list vargs)
( `2 f9 u7 w6 e. H{/ m. u* c; Z, U: y9 o8 q' k
    const char *old_name = kobj->name;
- I/ Q6 G3 h4 U4 \( E! l+ L    char *s;4 k3 j! \1 Z7 H
! `/ S' c( _. T$ F
    if (kobj->name && !fmt)' W, h" k5 ?( u
        return 0;
9 `; Y& @9 M2 ]" M; U6 I) X* y$ x4 ]6 s
    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
" Q- X3 s4 q! }6 E    if (!kobj->name)
3 |8 K1 l0 ]- \        return -ENOMEM;# [/ k$ f0 f1 [
4 b( L; @" l, u) w$ L- Q9 n
    /* ewww... some of these buggers have '/' in the name ... */
+ ^' X. C1 U2 p6 \3 l    while ((s = strchr(kobj->name, '/')))
/ p) I- \9 A/ {( Q) r' I# Q; |& @  v        s[0] = '!';/ ?: k( h6 C  l1 I% O7 O

' L# o1 @4 L. D7 v    kfree(old_name);
' c8 M& T1 s- U, R1 f  q  B7 Q1 M    return 0;3 W9 p$ ?  C) W5 v% H+ ^# t
}& t# c: X! X: g4 a0 b* z
/ D# w# G0 @8 v4 ^
/* Simplified asprintf. */
& x) Y6 ]! M* o( X( M- Hchar *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)' V5 }. w: Q; Y! G! [8 ~
{2 u3 C; |; r' e6 \$ N' G4 C+ D! J
    unsigned int len;
2 i3 R- \7 j+ m( ~3 N: p3 `    char *p;
) c9 q- J* Q5 K% l( _' ~7 b6 k    va_list aq;& v( r1 K9 m  @& s

7 @- W' A3 H# ^% @: Z3 d- w    va_copy(aq, ap);
6 M% M% T* J3 x4 X( l; u9 @  q) t# \    len = vsnprintf(NULL, 0, fmt, aq);
' N3 P. r4 N& |    va_end(aq);
5 x) I( Y! E9 C* e  N& K) K3 f' _2 ]7 @
    p = kmalloc(len+1, gfp);
) j( i+ L! O  ~( Y# F    if (!p)
8 X8 e* G2 J9 g2 f% l        return NULL;
/ x& W2 m. d# _0 D
8 a2 D" r4 H  K  u! x    vsnprintf(p, len+1, fmt, ap);
4 k: y1 \5 j7 i, N" n4 [
5 X7 v9 F& U; r' S$ l$ F    return p;
0 [: I) l2 `; w}! P) R4 x' S8 s4 d; ~
3.2 kset_register
( C: q+ E7 L! Q1 T: n下面代码位于drivers/base/kobject.c。
+ I' x' o7 j/ z) j' i* @1 R( O& E5 E/**+ c: o6 i& l5 V: b: V
* kset_register - initialize and add a kset.
8 c' {6 b$ d* y: N, ?4 h7 C * @k: kset.8 {) [( R1 n% e: x! Q
*/
9 o$ g$ z7 {, Xint kset_register(struct kset *k)& E7 l8 g1 C, W0 B! _
{
4 M! h6 ^+ M& z        int err;
  t# F) w9 H- |3 F' x# g. N6 k& {3 `) a+ H+ j% }; R
        if (!k)+ ^# d8 \( K2 `
                return -EINVAL;
* V! B+ J; [3 e7 v# b0 a, w' y. K0 d. k. g
        kset_init(k);           /*初始化kset*/: T6 r" {, i% i/ T2 N  `" \7 o
        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*// c3 f5 O$ ]) E8 F- ]: L, \; u
        if (err)
, G& D! y+ }  i: R8 |7 _                return err;/ G: g* J4 i' `3 y6 g2 q& n! c
        kobject_uevent(&k->kobj, KOBJ_ADD);3 i2 Y. Z% a0 \/ t3 v
        return 0;- L5 _8 w0 T0 K5 n
}
5 r- a; ]6 ^% o& p6 @) w这里面调用了3个函数。这里先介绍前两个函数。0 j: @3 o4 ?4 i/ w: H$ c

( c$ N) |+ f+ N7 X: o3.2.1 kset_init
. P* y5 R0 A( i) O  该函数用于初始化kset。& ?% F6 q5 [3 W$ X" f2 H9 w

' G6 V5 q; z' C  下面代码位于drivers/base/kobject.c。6 `& \. K% B- G3 ]& m! t

% f  e7 S+ t7 x$ f* Z/**& m9 `! r2 m) V; k$ M
* kset_init - initialize a kset for use6 k8 o9 G7 b5 a0 k4 R
* @k: kset+ I# I4 V7 O* H7 C* w
*/$ T7 ^. A6 [  _* j
void kset_init(struct kset *k)  P5 L) E% x' A/ R6 u
{: l) W% M: U# x% ^; D3 X
        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/( m& K. R6 K, f& o/ c( ]
        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/5 d) b" m4 _2 T% g9 d, K( h0 x8 v
        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/
( }! r: o3 D$ x  S9 P- j2 |}6 v2 e! }' z6 |; x

* u+ R' q6 A2 M/ W  `" Gstatic void kobject_init_internal(struct kobject *kobj)
2 M: n$ r: y7 L6 @+ T* t$ z{
* ~9 M1 W' }) A/ H' s; j7 V& }    if (!kobj)0 y3 l4 b9 I2 Z
        return;' T" X' m* l, [9 N& G3 `
    kref_init(&kobj->kref);           /*初始化引用基计数*/1 Z( a3 @; {& n' v. S$ x6 F
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
1 A0 f7 Z8 `  l0 C3 ^0 g    kobj->state_in_sysfs = 0;. {+ L  V) w2 z7 P- N! }6 N
    kobj->state_add_uevent_sent = 0;+ m4 G* {  U2 f( m( w! [
    kobj->state_remove_uevent_sent = 0;
) c" \% T; T9 y    kobj->state_initialized = 1;' @+ a; i' a7 x; K. B5 U0 y* h
}7 ~+ a- K/ T& J: c
3.2.2 kobject_add_internal1 h( J# A5 m2 |
  该函数将在sysfs中建立目录。
5 t8 L" ~7 c( W  L+ C8 Z9 a1 \0 L
& G1 o6 Z0 L& S0 S! T# [ 下面代码位于drivers/base/kobject.c。  ?+ n7 G* ]+ e+ [# `/ i
static int kobject_add_internal(struct kobject *kobj)
5 z* U/ s. U7 J4 r, g{
  ~9 D& y: |' b0 _1 k0 R& B        int error = 0;. t! a; A& k1 i9 f- M
        struct kobject *parent;
- e( ^# {% V/ i9 ?1 a! I/ p( k. ~, }7 b# O) h7 k* A1 O
        if (!kobj)+ J  e5 C! Y  ]3 v6 h: p  s, `
                return -ENOENT;0 _9 \$ ]0 O1 N4 t( d
        /*检查name字段是否存在*/' F5 D" Y% r& V: e# h8 O3 C9 t# r
        if (!kobj->name || !kobj->name[0]) {3 F! V! j6 f. @8 C
                WARN(1, "kobject: (%p): attempted to be registered with empty ": N, ~% y% b' b$ N
                         "name!\n", kobj);. I3 s  l$ i  j& w
                return -EINVAL;
8 u0 y/ o0 }7 M+ _; C. Q  A        }
& i1 R4 T' C' n2 L( j
0 p& d: _+ b. S; D; G        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/
% G: X8 Q7 ^' h* p9 [. I/ @9 e4 a  g$ Z
        /* join kset if set, use it as parent if we do not already have one *// r' T; Y% c, A) l& }% o0 c
        if (kobj->kset) {        " D2 W4 i* B0 R( r6 ]
                if (!parent)
- C) M& A6 ?/ ~, x6 q+ B                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/; ?9 M% M3 c1 D
                        parent = kobject_get(&kobj->kset->kobj);  T. h& o% h1 D; Y1 ]$ T% v6 Z
                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/
+ b% q" i0 X7 S                kobj->parent = parent;
7 \+ r% J8 P- a; X& a8 ]0 Q& h2 b+ Z        }
, m, [3 t# X- j( {. K" t+ W3 a3 L! x! p. }9 b5 W% z& s! c
        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",. m# O# g) I& b% l
                 kobject_name(kobj), kobj, __func__,8 z2 ^+ [% j$ O
                 parent ? kobject_name(parent) : "<NULL>",
+ @2 K3 s* F6 p9 {                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");' r5 p" A+ h- Z: l/ u$ b0 E
& G4 n% z+ v9 X' ?' o
        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/
- a; J5 C; A/ f5 Y        if (error) {0 u$ C% Y/ V+ ]9 Y) h* |
                kobj_kset_leave(kobj);        /*删除链表项*/
0 ~6 @+ _9 V. _1 }1 y                kobject_put(parent);        /*减少引用计数*/6 {" [! D+ J7 J9 l- I8 t
                kobj->parent = NULL;- a  V, f( A) O% d; n( z, \

6 X- c8 \7 G4 _8 `) m                /* be noisy on error issues */5 R4 v; x6 r/ I" m# q
                if (error == -EEXIST)
6 R8 E0 k+ x8 v0 l/ d' b( N                        printk(KERN_ERR "%s failed for %s with "" k( h4 F" W) ~6 a* L! H
                               "-EEXIST, don't try to register things with "9 ^! R/ y( v- O5 M
                               "the same name in the same directory.\n",
2 ]( F- x0 E6 `* d                               __func__, kobject_name(kobj));
0 H# o) V- l6 `: b& h) S# o                else
! a" W( J$ V0 s' D: h                        printk(KERN_ERR "%s failed for %s (%d)\n",
) {5 O8 L$ j. m- [3 J                               __func__, kobject_name(kobj), error);0 }7 d* h, ], b  t1 k- h8 g- o
                dump_stack();( \0 F7 h3 l$ L: e  H
        } else
2 v: `( G: \1 L9 a2 ~  e6 Z                kobj->state_in_sysfs = 1;8 L7 L+ `6 ~3 I, D6 {

) V) p9 u5 X% L: e        return error;
) D2 c$ h7 v8 E& M}
5 @3 D- R0 u0 h/ m( t( o) W- {4 W
4 u* s# I9 q/ g5 V+ I在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。
, A: q/ m5 L$ ^4 @0 f& |" R  v9 o$ H" K" ?" F
在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。
/ a! U3 ]: N8 O& l: A
! i' p0 l0 f  I7 v: ]至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。4 V. I7 y9 Y) u/ Y" u
4 q/ y$ \9 G- G* i- A7 f
4. driver model
; p% v9 H6 `6 v4 R, y第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。! F" R+ G1 n5 E0 X: s: @
# f5 [' ]" {( A. f9 e
Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。! G* a1 v( d8 `" K

" R1 Q- A2 i: h这个属于分离的思想,将设备和驱动分开管理。% ~5 i' L/ k1 b: ]  I7 \
7 q; S* [' @! V3 N  B! f* l
同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。$ f. Z4 o2 a: L8 ]3 u
$ Y& Z3 Z) c, }( I! \7 v
4.1 bus
( S' z$ Z( O; _* I总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。2 N2 s- I& Z/ C- h% G
8 D7 |3 J: X* L8 s& X
下列代码位于include/linux/device.h。
7 W8 k& }$ p$ D; R$ s5 f5 a2 X# M( B1 r5 |
2 I0 n; @: W0 L* j% B4 ~
struct bus_type {
" t" x" s+ I' N; G6 U    const char        *name;
# P" Y& ~7 j# [  H: }$ q4 x    struct bus_attribute    *bus_attrs;
/ w! u1 O0 k* W1 H  G' a    struct device_attribute    *dev_attrs;) F' v. E* ~& r% ^( B$ P8 M
    struct driver_attribute    *drv_attrs;: R/ S+ }, s2 _( b

) t9 a$ d2 N2 |* _* c, s, w& g    int (*match)(struct device *dev, struct device_driver *drv);
3 `# y- r! V2 a. e  V) T) A( g6 x    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
4 F' O0 ^9 g) r5 {! F3 S    int (*probe)(struct device *dev);
' ^3 D$ }  F1 f1 R9 f+ p2 g, [/ P    int (*remove)(struct device *dev);
9 C/ X$ s( ]* Y    void (*shutdown)(struct device *dev);
3 H1 f2 l0 L, n" @; ]5 M2 ]3 Q! U9 {2 x7 n# @$ [4 ?
    int (*suspend)(struct device *dev, pm_message_t state);& Q5 Q5 n7 h( n7 ^8 `
    int (*suspend_late)(struct device *dev, pm_message_t state);
  \/ l# ~& w8 N/ G9 K! }( A2 \    int (*resume_early)(struct device *dev);4 Y1 ]1 \* Q3 V. p/ u/ I
    int (*resume)(struct device *dev);* }" r5 e9 ?- X3 E
, u+ @2 t: v2 G7 B" ~
    struct dev_pm_ops *pm;
- G0 p2 `' M3 k; Y+ S7 r5 \* h5 R  J
    struct bus_type_private *p;
7 a- v. I3 [; z. G, E};
  v' X2 S5 B: x4 K: U9 j7 l* j" [8 b, N$ c
/**
+ }# ?: I. _" w* N3 U, H * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.$ A/ c7 ~6 C, n& ?
*) i0 k/ h# U% O
* @subsys - the struct kset that defines this bus.  This is the main kobject
6 h2 l8 {- h7 a5 l% h: k) Z; u9 ? * @drivers_kset - the list of drivers associated with this bus
; L9 J9 j. G5 V0 q * @devices_kset - the list of devices associated with this bus. S1 \+ T: Y  L! d" {  P
* @klist_devices - the klist to iterate over the @devices_kset% O2 E7 ^4 {: G4 I, R* W3 w
* @klist_drivers - the klist to iterate over the @drivers_kset
2 Y3 w7 j: U2 J( c6 l * @bus_notifier - the bus notifier list for anything that cares about things' ~/ H* e" n6 F- g9 z) ?  B# A
* on this bus.
8 ~# t$ ?, d! f! K* G * @bus - pointer back to the struct bus_type that this structure is associated
+ n- N1 \1 B& w. l * with.
: P+ D* y) x4 f8 v *
" o/ Y0 C( `( `4 X: ^* _' I) y7 I/ D * This structure is the one that is the actual kobject allowing struct
6 o2 v; ~4 b/ P2 `9 a5 a * bus_type to be statically allocated safely.  Nothing outside of the driver6 a) Z# ]" U. @8 W6 ^8 B7 P/ k4 b1 j
* core should ever touch these fields.( {+ J" k( D, t% @0 J5 J
*/
6 n# e, M! i$ n$ U# }struct bus_type_private {
( a1 p( G/ Z5 b1 @: H% `    struct kset subsys;& Z# D( U* \4 l+ P$ J) ?$ d
    struct kset *drivers_kset;
- |/ v+ X, n! j; n1 h. U    struct kset *devices_kset;
+ M: A; ?& G  F    struct klist klist_devices;4 {$ w/ h) O, n
    struct klist klist_drivers;
: p! G" k; g/ e    struct blocking_notifier_head bus_notifier;
; ^; _+ X7 c- H/ a/ m$ [! |    unsigned int drivers_autoprobe:1;- k+ G$ A& a5 y, C5 \" w$ x. }$ p( p
    struct bus_type *bus;1 Q& z! y3 {# O: K5 d4 \+ E" E& Q0 i
};3 }# q) a# F7 V, V$ M! C* B8 X
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。& V8 r2 G- c9 V* y
drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。
4 N$ b- {1 B8 G) O7 F9 W2 ^% k4 d/ s
同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。. B/ J6 t7 d6 c
5 i, t9 p0 u' K& E
4.2 device# @" l! {* H9 Y" q% h4 w$ K
设备对象在driver-model中使用struct device来表示。
3 s9 @+ X; a9 T, @1 ~
6 y/ b2 B" p0 p- P+ l6 t$ k下列代码位于include/linux/device.h。
4 A! T+ q2 N, n8 Y2 ~struct device {- }2 ]" }8 d. u+ l" H- |
        struct device                *parent;
: h. i; V* f8 R$ d
* L$ T, P0 l; L7 H6 E6 n        struct device_private        *p;
9 U: a' M3 h0 A0 Q8 f
3 L! F% M5 l5 ~        struct kobject kobj;
4 v4 G- o& p9 |7 I9 {        const char                *init_name; /* initial name of the device */
2 K/ N) a9 h4 t" s  [        struct device_type        *type;
' P  i1 |: x; ?. q! d6 M
5 M# V$ F1 D& q) f* @        struct semaphore        sem;        /* semaphore to synchronize calls to( K% k0 W3 j+ g7 V8 `
                                         * its driver.  f6 N4 N8 e2 _7 V7 F3 |5 D
                                         */
+ E; B1 M! l. m/ \# d' B3 }8 q7 e4 S. C  c) N. X1 ~
        struct bus_type        *bus;                /* type of bus device is on */5 X2 b; C" i; E& X3 S
        struct device_driver *driver;        /* which driver has allocated this
( Q! o0 Z( S; }1 b* `" b                                           device */
% v8 ~. a/ i5 N- ^, W        void                *driver_data;        /* data private to the driver */, t% X; _6 [/ ]6 k
        void                *platform_data;        /* Platform specific data, device+ l) ^" `2 j: t; h) d. F. O- J
                                           core doesn't touch it */7 E$ T) S- ^# i6 `2 G: R4 b: c
        struct dev_pm_info        power;* W& R1 u* s* U. ^& V# G
0 B6 d) ~7 g# f2 E: x/ Q+ L
#ifdef CONFIG_NUMA; G, T8 q, H5 ]5 H
        int                numa_node;        /* NUMA node this device is close to */
" M. S) b9 ~. p#endif
) M$ ?- X" ^2 B. o- D. T        u64                *dma_mask;        /* dma mask (if dma'able device) */
6 H% T9 W# `: p& ]" U6 M$ x1 A        u64                coherent_dma_mask;/* Like dma_mask, but for  c8 ~* G  n# p& ?
                                             alloc_coherent mappings as/ `# r5 Q# T& K0 l
                                             not all hardware supports! [' y. B, K3 w* w2 P- a( H/ d
                                             64 bit addresses for consistent
  y% @8 K4 M: ~% U                                             allocations such descriptors. */
1 p  k6 |8 ?# e- O" r9 {
; W  I* c+ v1 T1 B( F- e        struct device_dma_parameters *dma_pARMs;
1 Y) _% }5 r3 v' ~& G0 N: ~, |+ U( [( m) U( |
        struct list_head        dma_pools;        /* dma pools (if dma'ble) */0 [4 \$ Z" q  d# u9 i& i0 s% D
- N+ N" q8 W' }9 Q6 ?$ p7 s& ^
        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem
4 ]' y# T1 z0 u0 W! o                                             override */
1 c  O3 M1 V6 }- Q        /* arch specific additions */. i! W) f1 z: a1 Z, j$ [
        struct dev_archdata        archdata;# ]6 a2 l9 f, j, Q

$ w. O% }" w5 ?% X) o0 [        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */5 N, P1 C# X7 n! S/ w
- N3 O8 `9 I: {# C3 A  o: z
        spinlock_t                devres_lock;
' p' s6 i' _- h! ]; I        struct list_head        devres_head;
- W: [' r, j, q9 f6 I7 q
& B6 _! ~! B) F# s1 ?  F- ?        struct klist_node        knode_class;; h# @6 b' y4 h
        struct class                *class;+ |& l; ^, j" j6 t8 k" n
        struct attribute_group        **groups;        /* optional groups */* K6 Y1 C+ Z+ u+ g) `2 P

# K& W& f' ]% C# w1 @# v        void        (*release)(struct device *dev);  q9 N6 }; Q3 d, V- d- {
};
2 y4 J7 m8 o2 h; i# b1 }
7 }$ U* t, [( [/ r/**
6 l2 k2 r1 v+ T( M * struct device_private - structure to hold the private to the driver core portions of the device structure.
2 j: f1 h# l- k' J *1 I. X. H3 V- Q. H
* @klist_children - klist containing all children of this device
6 k+ z$ P8 E% E1 e" W * @knode_parent - node in sibling list) J% B8 @: e" s. Z
* @knode_driver - node in driver list
6 `2 \4 K# V) E' y * @knode_bus - node in bus list/ f, G3 u' \' A3 h* J( r
* @device - pointer back to the struct class that this structure is
  d- L& y% U3 x( L * associated with.6 g% D, H- z0 E* r
*
( ~# v5 y' b6 V8 Q" D * Nothing outside of the driver core should ever touch these fields.
% j* ~: R* T' {1 [' ~% F* q$ q' Q */3 h4 U2 n2 W) m* _5 g4 q/ c
struct device_private {
! {1 n- T3 \) L* c- Y/ b    struct klist klist_children;
3 _& u" l7 G- u" `  [6 ^  c5 e7 @    struct klist_node knode_parent;6 H% a( B/ G. s" Q, z5 y& C
    struct klist_node knode_driver;
+ i7 z  A( a6 X' Y    struct klist_node knode_bus;
  P! T6 o$ u  `3 U. r/ ~* i6 _0 c    struct device *device;) I# q: [' ^4 R7 }" D& B  i% l
};# G- v! k  S/ o0 o" _. g; a: Q
device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。9 D2 t2 E+ H6 Z" n

" \5 n0 q8 Q. l( A/ |8 \7 J该device所挂载的bus由knode_bus指定。
/ ?/ V" J3 e6 z9 |) H( ?* B
: @0 i! U/ D; X) h* U该device所对应的设备驱动由knode_driver指定。
' H& {2 @0 E1 C  p) @; R3 L1 H( _1 r' S9 F* ^+ H
4.3 driver
+ f6 x+ E& O  ^设备设备对象在driver-model中使用struct device_driver来表示。
' ]; _" m0 ~2 C( w0 a9 N2 j) s/ D* I7 n' `6 B* ?" {! n
下列代码位于include/linux/device.h。+ N' U4 r, M% k6 J. r
struct device_driver {
- F0 b. o: D. Y" u0 u( m) J        const char                *name;
# T: Y9 C0 C3 G; f, I- c- \5 p; I        struct bus_type                *bus;/ [- J: H& d7 Z1 y7 @
3 ^7 z" C8 K4 q  A
        struct module                *owner;
, }# L: p% o# w, j8 N# F. o" ~        const char                 *mod_name;        /* used for built-in modules */
  F  y: Y* T% |) S0 ?/ i$ F0 h: \1 v9 z! i$ s% {2 d1 h& Y$ P
        int (*probe) (struct device *dev);; ^$ n) H1 {+ M* o3 B* _
        int (*remove) (struct device *dev);
$ {3 j& d% o9 m$ l        void (*shutdown) (struct device *dev);
  n% j" P9 A) }! V" I6 f7 s        int (*suspend) (struct device *dev, pm_message_t state);
5 {+ w, r# _  {, E0 p        int (*resume) (struct device *dev);
6 D: j5 `" p( @7 }, `& U. u        struct attribute_group **groups;: ?. [/ ]' U6 e0 Q0 i
( J+ i% e$ {$ B9 E$ K4 i7 b
        struct dev_pm_ops *pm;
& V5 e  Z( c" W  D- n2 {; R& i  k
# w2 R' F$ K3 |- p1 r        struct driver_private *p;/ p1 y% n& V: x8 p- f
};0 `! D! _0 s! u
; g; C; T/ @, f$ `8 N! \& c* w
struct driver_private {
+ B, X; F8 k5 X+ `. K+ x    struct kobject kobj;5 \" m( p6 Q% f5 `" W3 i
    struct klist klist_devices;$ W3 w# [& c* y% D3 ~
    struct klist_node knode_bus;
! ?1 E1 K$ ]; b    struct module_kobject *mkobj;
# c* J: Y9 k* R; p& D    struct device_driver *driver;
! k5 A9 ~, {; F; p9 k};
$ d% b1 {. U/ s! X4 q9 ldevice_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。( t' v% r4 D- [4 e% ]3 F
该设备驱动所支持的设备由klist_devices指定。
! L* \% d( S9 p5 ^4 j+ ]: Y/ z5 ^4 k3 `+ f" w5 g  [
该设备驱动所挂载的总线由knode_bus制定。
( b+ a! w# x& a% n: V- L$ V1 e) Y/ ]* J6 w0 C- y8 b9 a- Y
5. Bus举例: c5 T; Q# U! D* g
本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。
' [$ b+ F& t5 B/ E! B: D4 o
) M' e4 l" r! ]6 g: m. _platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:
# n/ f6 Q6 S1 {+ s2 k# m/ {3 o, U
( b) |6 |/ V2 j3 ?! c6 ~start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。/ |6 u  i0 b6 o0 I. f& X

* J& l, h2 G" ~. s+ \注:kernel_init()是在rest_init函数中创建内核线程来执行的。' H; h# L; K' ^' E: e2 ?
( Y# F: {! U: b2 o4 O6 }  O, N

' d3 e+ Z) K# ?3 c3 V# M7 o, o% J. M, K) M
int __init platform_bus_init(void)
5 ]- Q' G8 x7 |; t4 T2 |7 X& [{& G; g* |$ L6 r% j  b8 i( m* g( _: D
    int error;
  {; t. S  P) `* J* ~6 g
& i& F: ]3 R3 T4 e+ E    early_platform_cleanup();
% L( D8 W0 a8 [' k, c( ^, ~! v; i+ T! t. h
    error = device_register(&platform_bus);
8 M& D8 A4 `/ g/ Q/ _' j    if (error)
% D* S8 y$ M  h6 @8 h1 P/ E        return error;
) w' Y0 ]6 u. k* o1 y5 Q# D7 Y' l    error =  bus_register(&platform_bus_type);+ ?* o1 ~/ t9 B
    if (error)
* R1 ^2 E4 i8 ]$ @, J" U2 B/ P        device_unregister(&platform_bus);
: e8 p; @4 V- g& R    return error;! |. b- O: \! g+ U9 l- g- b7 @
}
# h# A/ O9 O5 H% x/ g( i& {% B7 {struct bus_type platform_bus_type = {, Y: L4 h# @4 i3 a2 u, L
        .name                = "platform",4 F$ v; I: o8 C: U* c
        .dev_attrs        = platform_dev_attrs,. M+ c. d+ m& V* r) ^3 _! L5 ]
        .match                = platform_match,
) }/ b. F, Z' `) X6 p        .uevent                = platform_uevent,
3 c4 D2 ]9 L, B# u- R        .pm                = PLATFORM_PM_OPS_PTR,
; B) p% u1 B5 @2 @. A( w" Y};
+ @0 Q" g, v/ G3 B* X5 lEXPORT_SYMBOL_GPL(platform_bus_type);
6 B7 A" }8 S# F1 C从bus_type,我们看到该总线的名字为platform。
& h. H  w* h' t3 @1 d7 S调用了两个函数,我们只关注bus_register函数。
1 o/ I5 S7 g9 \2 m- w9 l* ^- i0 t% z. M
$ i( j2 b( Y) t9 Z
6 O% T9 \; W. y5 Z5 ?' z5 B5 g/**
/ G( I8 X, |- L2 f% o4 p * bus_register - register a bus with the system.9 O0 O& g4 Z& M$ p$ y! b
* @bus: bus.
- \. [, p$ M$ N7 Q- c/ t *4 ~+ [2 x# f$ O2 p5 C
* Once we have that, we registered the bus with the kobject8 m0 Q% I. C9 E2 F* [6 ?
* infrastructure, then register the children subsystems it has:
7 a. x- i& B2 T3 \* ]0 C) B1 \ * the devices and drivers that belong to the bus.
* V) o8 U/ ]7 C& S# W */
; L- O( b0 W1 u! H. i7 Xint bus_register(struct bus_type *bus)
) j3 r. `  T* {$ S- R/ ~5 N5 |{$ c3 g' ]5 U# E: ^& Q
        int retval;6 f# W. q1 H& Z. t8 f9 t/ [  x
        struct bus_type_private *priv;
7 C& j: O2 q8 i9 _( |5 n% D4 n* l( [4 Q! j. g5 k5 I' P# }* j
        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
4 i; w2 H" b) K: w" P        if (!priv)/ b/ t; V3 Q  r& E' }( h
                return -ENOMEM;
! T4 c6 ~$ @* B1 G0 g0 t/ \; }        /*互相保存*/
1 X- i- K" G) x3 F% s* A! A        priv->bus = bus;0 |- ?; p$ x2 M$ N4 ]
        bus->p = priv;
( V2 O9 G) X' U  I- A# Z& T0 j; {' n3 F$ M* Y( {4 E- C3 S8 A
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);& F- W. o' ^- {6 F  O) p
        /*设定kobject->name*/
7 C# h7 |6 F) y1 R  a. o" y! x5 Z; _        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
: l2 h7 ]+ Z5 V+ Z% L! b9 g% I        if (retval)
8 E8 x1 U7 V4 K: j" Y                goto out;
0 H. S3 C/ R8 L5 h' P: N
% t5 b3 |7 v7 {: c        priv->subsys.kobj.kset = bus_kset;1 e. W5 c2 D& F
        priv->subsys.kobj.ktype = &bus_ktype;
1 a/ O0 A0 Y2 v  s        priv->drivers_autoprobe = 1;
8 ]& N+ _- f4 g" i8 g1 \, S1 a
% q: ]: G- J5 x. ?( P( p. \        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/
0 @5 v. D( X: u" N3 h& p        retval = kset_register(&priv->subsys);       
8 K9 w+ f& s( D# q2 \3 M( }* G! t: F        if (retval)
2 J! Z: T# T7 E$ j* ?                goto out;; p( _' `* n0 `/ R
1 {4 @7 ^* F6 l$ {6 U2 c" ^
        /*创建属性,在bus/XXX/建立文件uevent*/2 Q) o4 C, B2 ]: v
        retval = bus_create_file(bus, &bus_attr_uevent);- }& s% {0 T" ]: j, G6 U
        if (retval)5 V2 t! w: V6 @) d8 b% q
                goto bus_uevent_fail;
6 [! a' y) y- J: b3 m$ o0 i" F2 B0 ?9 X. h4 I$ u
        /*创建kset,在bus/XXX/建立目录devices*/. O9 R" n+ _+ T) O( s5 Q
        priv->devices_kset = kset_create_and_add("devices", NULL,* E) g/ A- k/ ]' B
                                                 &priv->subsys.kobj);& ^/ A- K% O& F3 u, b
        if (!priv->devices_kset) {
( ^; z) h$ \! G- C                retval = -ENOMEM;) q9 H+ [- d6 `4 y9 }3 F3 u3 _, w
                goto bus_devices_fail;
. L- g9 q! U1 h7 x. q6 j        }. L! Z( r4 v, V( V. Y6 s  s8 v- d8 i, _

6 v/ q6 @$ D) y( D8 I1 A        /*创建kset,在bus/XXX/建立目录drivers*/0 g" [: y5 T4 P. j7 ]
        priv->drivers_kset = kset_create_and_add("drivers", NULL,
- @$ S4 [! }% m! |                                                 &priv->subsys.kobj);
( z% t2 v0 a- O# r, _) G$ k' C        if (!priv->drivers_kset) {9 I% t& K# M1 P9 n+ G7 s9 e
                retval = -ENOMEM;
& f8 `& R; S5 D, I) t: O% b0 e                goto bus_drivers_fail;
5 }5 z; j5 t; z5 z9 S4 `        }* b: E* P* u0 E- ^; P1 T# X
        /*初始化2个内核链表,*/
7 T9 M8 O& ^" Y# ]" J. A( E        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);& d1 Y, J  S* j: w# y3 S
        klist_init(&priv->klist_drivers, NULL, NULL);
- L' [# K( p" {; ], }5 C2 G9 Y; a4 B/ A# f4 c; f
        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/+ k+ r9 E# K9 K& ~3 F8 z
        retval = add_probe_files(bus);$ X5 v7 c" u8 a8 S
        if (retval); u  q( ]' z2 M  h8 S6 l' c* y
                goto bus_probe_files_fail;0 A! W' ?$ o+ f3 [
        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
  I! a- s2 |5 A. j+ T- H        retval = bus_add_attrs(bus);
% ~0 P9 F" M* K4 ~3 v9 _) g, y        if (retval): U) |% c; G0 C
                goto bus_attrs_fail;
* M0 y5 s8 H$ v2 h4 v( }7 w
: v6 `& ^' x( v! }: s( r  ]        pr_debug("bus: '%s': registered\n", bus->name);7 Q. P+ ?% x/ O' Y3 }
        return 0;
2 d5 c' M" ^" h  P/ U9 U# F1 {: c* i: L7 A
bus_attrs_fail:, g2 l$ f* F+ S
        remove_probe_files(bus);
( t8 h9 l' @: z9 a& Kbus_probe_files_fail:
- ?2 n4 A& L' Y9 x! L- [        kset_unregister(bus->p->drivers_kset);
% p4 q. u! M1 T6 T+ rbus_drivers_fail:
. S% v! l7 S3 H& H$ l: ?$ q        kset_unregister(bus->p->devices_kset);+ z+ r& J: M7 Y2 {9 A/ a0 F& v
bus_devices_fail:( p! a7 H. ?6 \
        bus_remove_file(bus, &bus_attr_uevent);3 W# [9 \  _$ I4 S
bus_uevent_fail:5 v7 j" O1 d7 D3 \# k) j+ ?
        kset_unregister(&bus->p->subsys);, f" D% ~7 h$ C( c2 U( ~" Y
        kfree(bus->p);
) |5 J; a# ]1 ]2 c4 B% ~out:
4 M* f+ R; ]% m  ?& D7 t+ f        bus->p = NULL;
+ {. j( }9 E# K; q1 S% L* b# K        return retval;" m4 L5 j2 B  R; c$ u. H$ K
}9 e& c0 R) u, l) |" v' A
EXPORT_SYMBOL_GPL(bus_register);% Q* n! |* j2 M

! ]! R% s+ ^2 V9 m* s函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。) V5 [. ~- ^" r( R6 e7 ]
在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。
. F9 e) _2 e0 A. [1 Z# S0 F1 g2 d% i( K
接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。
4 p5 C' G. S7 F. g  p% n7 {4 F
% T' G8 O  K" v6 S紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。7 A1 S% ?1 J# g: @; `3 `

8 R( I# n! c6 C9 u7 `3 H* {  H6 u8 p; \
/* add the kobject to its kset's list */
4 U0 w: [! M/ G: A  T* X; o7 ~: [static void kobj_kset_join(struct kobject *kobj)6 y  V! t3 K% g# k) |: c* r  y
{, H6 O$ W/ V! c; K" }" ^" `
        if (!kobj->kset). M) D/ w  k! u0 R$ q( C( C
                return;
" V# q; P" ]; }5 R6 ~3 ~
8 E3 q- i4 k! D, r) N5 i$ {        kset_get(kobj->kset);        /*增加kset引用计数*/
: i/ D7 w# g7 i" _        spin_lock(&kobj->kset->list_lock);
3 X( v; }) ]* ^( Y        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/
0 ~1 H( ^4 [5 f' b9 Q; @3 z8 \        spin_unlock(&kobj->kset->list_lock);8 M9 ?, p$ f, A: i, `
}" s7 T9 j; O  U
kset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。
' B" m( b, ]% V1 s* u$ [" z! t4 K: ]+ [1 f# k
/ a, o- H9 s& |  V

) ?0 w- y3 T2 O2 U然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。
/ I! Y6 A. o! ?4 W2 f  v. H/ q: s+ O) \7 q# U" U" U
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
* j' f4 T$ s! r" I{2 [, `0 {) R! W6 ~6 U' f1 ?
        int error;
# p, T. i" A: J- D        if (bus_get(bus)) {8 M8 p; F7 f: z
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);  f( }+ [+ a. @
                bus_put(bus);
  W8 i- |. I- H+ d" x! f        } else
, j. M6 c) Y" z$ M4 E                error = -EINVAL;
' |2 Z+ Q( I' L, C. U- x, d        return error;
8 y" R7 H8 M" d: r, d  q0 k7 x}( w4 Q3 W8 p9 R$ V% V  Z8 s! Y
EXPORT_SYMBOL_GPL(bus_create_file);) p" Y7 o$ L6 S$ M
有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
" |+ ^$ c/ Y$ o, R5 d. }( M% w接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。
. t1 H9 p, e& s0 V( |# P, s+ _; C8 u# p
/ T* c/ |5 q& O这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。
/ S& D4 z3 a4 D  m7 k8 ^
9 E2 D' i4 T& C2 j& u, [3 _$ j% Z3 o也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。* W. z3 K" Q/ i- x) G- W
) ~  M7 @/ }" g: L8 n
我们来看下关系图:
% M  k. O- z; ^1 S; ?) b% C6 l
4 }. P8 f8 m4 V, \% M9 Y5 k7 v
; ^# K! Q0 Y# ^, h+ \/ M: i
% e( n. z' z* k- ]5 v" I随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
! l# |+ q8 L/ ]& @, @  B* _9 B" w2 o
static int add_probe_files(struct bus_type *bus)
6 e' E. D& P" n{
  o, _& U! b2 S8 o. b4 q6 J        int retval;
. G  Y% N5 @3 r. q3 h9 R$ O: y; e
, O* J! t6 O4 c        retval = bus_create_file(bus, &bus_attr_drivers_probe);
+ E+ S) a( a1 b2 a( \3 I8 _- y        if (retval)
/ e5 V( O4 J+ g                goto out;
. d2 J: D0 C0 n) O( z" C2 O+ o
        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);2 }% e! y* q* w! b, E3 p. K" D
        if (retval): k0 I) M) s' {4 V& [
                bus_remove_file(bus, &bus_attr_drivers_probe);
. w* _3 g3 g, z: n% iout:( j! r6 ^1 X* z1 j3 s$ u
        return retval;
7 V) ?' t) x+ `. _}
# W3 C$ ~" P* D1 b  V该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。
; f6 w) y8 r0 w+ [( e* F( C最后调用bus_add_attrs创建总线相关的属性文件。
( e1 {& Z3 r4 M, I2 w8 j; d3 Q! c+ }. T1 x) i: Y( d0 _% M
/**/ j. `( J- v+ Y/ {) D
* bus_add_attrs - Add default attributes for this bus.( Y( v/ ~# q3 Y) @
* @bus: Bus that has just been registered.
  ^. w* }$ S2 s# A9 v& L7 ] */
0 e  V' J) M: W- M0 U
9 f8 e# u5 Y4 T* L4 A* hstatic int bus_add_attrs(struct bus_type *bus)* I, ^( d- k, A6 ]$ D. v. e
{/ y. W7 x/ u2 V3 J4 y
        int error = 0;
! z$ e' A" t& `" W% F        int i;: I3 y8 p7 |" |. D: d4 _" Y
* J' S0 o$ t" o$ }% V% c
        if (bus->bus_attrs) {' f- J: y. E/ }4 b
                for (i = 0; attr_name(bus->bus_attrs); i++) {
' H) ]6 b* ~5 D. E' P) u& A                        error = bus_create_file(bus, &bus->bus_attrs);( E4 q. q% ]  Q/ `! M  I4 \
                        if (error)
. g. L9 i4 F$ ~6 o# K2 M1 R                                goto err;5 z. Q( Y% I8 Z* ^5 e2 b
                }
" m& p& }6 V& B% t        }
9 k3 m* K$ s$ b, G, bdone:% c- K. S. C& \# @( N$ S) X
        return error;
; n% o, L1 w! \7 ?! lerr:
+ n! \% e& l: ?& Z" L: g$ T# z        while (--i >= 0)
" g% L) w; {3 d! Q, i8 v1 g                bus_remove_file(bus, &bus->bus_attrs);
" D6 {) R# N/ g        goto done;
' m- w) e0 Z  N4 y# T; f}1 [% Q4 C7 |- c6 W
我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。$ G" N9 ^; P  V" f
好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。
. w8 I- V, s; Q" c( w$ u& v
8 g( h, z+ l+ b" T" G6 p2 c& a' o[root@yj423 platform]#pwd
3 S6 ^; r* t; i. b/sys/bus/platform0 K  v5 m) h8 k: y& m
[root@yj423 platform]#ls
  |  B/ ]1 c7 L3 v3 d  fdevices            drivers            drivers_autoprobe  drivers_probe      uevent/ ~% E  `; O! K( ?, `  \
最后,我们对整个bus_register的过程进行一个小结。  K# E) t7 U# z. l6 h" T; S
# d0 \( C- N+ U' n

# H  M1 p0 L2 a& [5 R# ^4 A" p/ b9 w( P* l
6. device举例: H! m- K/ j$ z7 Y$ c# I
本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。: U& B1 {; w- _5 s6 _
+ G6 x9 r* k& J6 b0 o  h2 [
6.1 虚拟的platform设备8 Z; T  z" p2 F4 ^6 H/ u' c
之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。
. j& ^( B" ?# K$ r" ]' i" p! p$ P; Z1 Z& q2 H; m
在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。+ z  B- Q4 A% e7 {6 g
, Z# S+ J) O; ^
int __init platform_bus_init(void)
4 }; N" ^2 A" w% c9 G{
. E6 a6 b7 z5 `6 i        int error;
& R6 I. p. h  N7 h: f) y3 \/ p5 |5 _+ w
        early_platform_cleanup();
/ n; d) n9 a: F8 Z+ [8 k$ H2 X' U( h
        error = device_register(&platform_bus);3 c2 o  g& Z5 @1 T$ F
        if (error)7 @3 a  G7 B$ _% y* W
                return error;
, \; H. }' _+ N        error =  bus_register(&platform_bus_type);
0 `/ B0 u# @# D# K4 v        if (error)1 E' ]3 U: }1 n1 ?
                device_unregister(&platform_bus);5 r. V4 V) J& @4 u, v, Y* g
        return error;
; v* Q) n* O2 n4 g6 ~}$ c7 h0 L% a! X8 M2 m4 F
( F9 q2 P! K* m. K
struct device platform_bus = {
# q7 n1 J6 ?0 B- p: i% o! W    .init_name    = "platform",& F) P! T" N% y/ ?% h
};7 \; d1 J( U9 g0 p3 F
EXPORT_SYMBOL_GPL(platform_bus)
5 u! p$ g. F6 L3 s: }' p0 j, X0 W" q9 x下列函数位于drivers/base/core.c。5 f: s  O, Y2 r1 H& O
/**9 u( Q+ l( x% H' I
* device_register - register a device with the system.! M8 @- W6 l, u: h8 Q7 X
* @dev: pointer to the device structure
& L  i& t& t1 m! W9 B *
+ V# f9 k7 Q! E3 b  L& S * This happens in two clean steps - initialize the device
1 v4 J4 u4 s0 ^6 Y' M * and add it to the system. The two steps can be called
: h6 F, l% ]% \ * separately, but this is the easiest and most common.
" q6 B, k( K: W& |$ K * I.e. you should only call the two helpers separately if) c1 u/ A7 g; K! ^
* have a clearly defined need to use and refcount the device
! b. J; N) i; B: k0 t * before it is added to the hierarchy.
9 |0 B" ?) y2 B3 G% D *
1 T% ^+ G! m+ f! H5 B3 p1 U+ V * NOTE: _Never_ directly free @dev after calling this function, even
. r5 i5 m  C# v; ^ * if it returned an error! Always use put_device() to give up the, f6 n( ?* J  [9 g( Z: X! c6 F
* reference initialized in this function instead.6 Z: _8 Q; L) o. b3 o) S
*/
+ ?, I: s0 h3 b7 M1 n% Iint device_register(struct device *dev)9 d0 Q; P, K2 E+ H
{' Q) K) P( |! U5 _$ j& C" D/ Q
        device_initialize(dev);        /*初始化dev的某些字段*/
, D+ O6 k. t6 C& T/ _        return device_add(dev); /*将设备添加到系统中*/
. e. u3 {* U2 C, w" l0 U# A. S}
+ ~# c! m( e1 ^1 W- Q0 h
( }; [* A$ o9 l1 ]3 g一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:: o. @6 w4 @6 `# H5 Q
# ^% h* P$ U& ?. u6 O" V' E  ]8 R
下列函数位于drivers/base/core.c。( Q' y6 s& {7 t2 D, i! I: V9 ^9 k
/**
" y7 j( [/ s* p! ^. ] * device_initialize - init device structure.  k# \1 W! K( f8 o* `% u) s
* @dev: device.
- n$ r. c$ \% ^ ** J" ?" u7 a/ b* n, k* o6 c
* This prepares the device for use by other layers by initializing
: F- K, I9 Y. P% G" w * its fields.
% b$ _( \( c$ M6 x: D# | * It is the first half of device_register(), if called by- b, p) y, K0 X: J; W5 l( j3 H3 D! `
* that function, though it can also be called separately, so one
( a* Y. u5 {3 I! `+ ]3 ]- ?6 v5 B * may use @dev's fields. In particular, get_device()/put_device()
# {8 ?6 f9 t0 v" S8 l( U * may be used for reference counting of @dev after calling this5 X* ^, ~# o5 ?9 \5 H! Y# \/ H
* function.
$ x* A: }8 M8 A( K8 j1 F *" x: A; Z, S) T% e, n
* NOTE: Use put_device() to give up your reference instead of freeing; y9 o+ ~' |* K' c6 P+ q
* @dev directly once you have called this function.
2 o+ L5 k& P) o# _6 C3 l */, s) ~; R3 }5 ?) ~$ U" H
void device_initialize(struct device *dev)! F+ ~6 g) w' i
{
+ k! B) k; ^7 A. N. ~    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/
& j# B& K, `' f    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/
, O# {5 b. u4 W- ?- u5 Y    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/7 ^* T- P% D0 V0 @# T. o$ b  @7 K! D; ^
    init_MUTEX(&dev->sem);                /*初始化互斥体*/
" f  m! R, B; k5 e* L  O2 ]( Q. s    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
! p% e9 }* x  l$ G( c    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
9 D7 b& y5 ~: k' P$ {4 f    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/3 ~! }2 {/ b6 B5 M
    device_pm_init(dev);                /*设置该device可操作*/
' @" P! `2 x( L( y" W    set_dev_node(dev, -1);                /*设置NUMA节点*/4 S, e. w) N8 `7 Q$ X2 @
}8 a& b0 W- w/ h; k* y( b
6.1.1 有关devices_kset9 W9 V. u' ^5 H7 N
首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。
2 g, ^. L  f- L2 Y$ p& P1 F4 _& n
该对象的建立是在devices_init函数中完成的。4 b2 c0 I& Y; @2 }. Z" v
int __init devices_init(void)0 {1 Q+ O& |/ N4 L
{
! t# K4 U5 O+ `0 a1 }  g9 N% R        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);# R5 y2 i7 O0 Q: p& O
        if (!devices_kset)
. O3 \/ z% n8 ^, E/ E* F                return -ENOMEM;) ~7 \/ w0 V) M# L, Q, ~, H
        dev_kobj = kobject_create_and_add("dev", NULL);
& E# A/ H! t7 L        if (!dev_kobj); }" H& a7 r" g/ @* T. C$ c( n8 l
                goto dev_kobj_err;3 b0 X+ j$ _+ n5 k" P
        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
& {, K- F6 {( g$ @6 D) `        if (!sysfs_dev_block_kobj), v7 _8 p4 l( Q7 P1 |
                goto block_kobj_err;
) r. }) e5 \) y& E" K# i        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
9 |: j1 V2 V" M) }( G9 ~5 ^* R8 c7 {        if (!sysfs_dev_char_kobj)
$ n/ X3 |+ l0 b: t& m: Q# R9 y                goto char_kobj_err;
( [9 ^5 h( Y* x, A. P" a- |, \( o" b; N- w9 W/ p- }; w+ b  U
        return 0;
! g6 I% L- B4 u* O9 m; N% x% k7 {7 e& k* x# O1 r0 ?4 ]& _
char_kobj_err:- L1 \! D3 x1 ]( l" _% u
        kobject_put(sysfs_dev_block_kobj);! w' l2 E6 _# Y. z2 `
block_kobj_err:
. Z. [4 ~* @% H2 C! ?& _4 D" J& M        kobject_put(dev_kobj);) [) z. p* H8 @7 {5 t* _# O
dev_kobj_err:( B* Y( R4 j  [$ f* E- k0 f9 q; M
        kset_unregister(devices_kset);: p" O+ {3 a! W
        return -ENOMEM;( `$ G+ J6 l2 C3 ^, S. u! n7 x
}
0 |2 q$ S6 e( t6 D" C' W由此可见,devices_kset对象表示的目录为/sys下的devices目录。1 P, w/ C( P' h  F) ^9 M5 y6 k; {1 o
6.1.2 kobject_init
' E8 y0 j7 b3 }6 w下列函数位于lib/kojbect.c。
5 b$ @+ y0 a7 w& T/**
( I* Q' G' }) q3 ]3 I* C * kobject_init - initialize a kobject structure; z+ Q0 }1 I) J; D( U
* @kobj: pointer to the kobject to initialize
, m7 u# U7 ]" _/ v  t * @ktype: pointer to the ktype for this kobject.
8 q9 z2 ]. a& ?: F, i *2 A6 R# m, ?. X$ u4 w+ R. ?9 g
* This function will properly initialize a kobject such that it can then% i3 z( C# z& u# n+ ?1 u3 ~
* be passed to the kobject_add() call.$ l9 b2 V# j+ d% @
*
8 y  ?* C# g2 t- q! b! g2 q * After this function is called, the kobject MUST be cleaned up by a call  s# U8 a0 k2 ^1 c; K; v$ Y" y4 K+ z& K
* to kobject_put(), not by a call to kfree directly to ensure that all of
% k: F# a1 b4 B+ z) m& J# i! ~3 z * the memory is cleaned up properly.
; J$ ?) p$ ]1 K6 L) p. Y */
; `- S; R6 y" ]8 f  {* x( jvoid kobject_init(struct kobject *kobj, struct kobj_type *ktype)
* i+ H: w+ `% j3 g# W3 [! X7 M{
% A5 s. j0 |! l' S9 [8 }( `        char *err_str;/ E" `# a/ \+ E  W+ C
  ~8 C: M; `$ i1 d8 Q5 M
        if (!kobj) {2 T2 s4 r7 t* _/ X3 x
                err_str = "invalid kobject pointer!";9 X- B) Q3 `9 s, U4 j
                goto error;
, k1 ]& d4 q  G" W. m% T" \+ `% K        }
( v) O5 Z+ X1 ]( y1 U6 v        if (!ktype) {6 j; i' n+ Y* K+ Z. }
                err_str = "must have a ktype to be initialized properly!\n";
3 h( c4 ^$ [7 C+ M* @, {" O2 x( b                goto error;2 d( N" A3 S# i7 H
        }
) x) j4 {7 A' G+ B0 D4 y  I        if (kobj->state_initialized) {) B( T) J# {( L6 \
                /* do not error out as sometimes we can recover */
; k9 A4 c5 D. C0 e' v* }  y                printk(KERN_ERR "kobject (%p): tried to init an initialized "1 E/ a& ]4 Z/ D9 ~0 x1 P
                       "object, something is seriously wrong.\n", kobj);& |2 e; x8 H' V: r
                dump_stack();
- ]4 Y( w6 a& F$ K8 |# u# V        }. V3 R! w( R. e
8 j2 d+ x+ b# K( B4 R  l
        kobject_init_internal(kobj);  W& J2 o% ^# h, x3 j; }- v% R
        kobj->ktype = ktype;0 Z% c& m- `  Q, u7 p
        return;  @- T$ S: u' e/ n8 S5 [

. B; K, R3 X; e2 F% ?5 e0 v2 |error:$ A1 c4 A1 q! V
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
& z/ ?3 D/ m5 `5 V0 ]0 _        dump_stack();' w  k; y8 d  L) l' J
}
- _5 m$ r. m* @9 S& cEXPORT_SYMBOL(kobject_init);
8 p6 E7 x) G/ j
% E! c+ d5 [/ L) b. y1 Cstatic void kobject_init_internal(struct kobject *kobj)
. F, I; V; _# H9 w{/ D5 y$ j4 F9 G
    if (!kobj)
' w7 w9 C! Q$ h        return;6 ~0 j. Q) I( Q6 i* a/ k! j
    kref_init(&kobj->kref);            /*初始化引用基计数*/2 V/ U- U5 y- g4 H: B! p5 e- `
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
9 r, B& X4 L1 a: z, k" |0 C    kobj->state_in_sysfs = 0;
5 K: J4 I. R0 }5 C4 W* |2 j    kobj->state_add_uevent_sent = 0;
. C" h' T7 U" t8 d: G5 z! L8 h    kobj->state_remove_uevent_sent = 0;5 R& G% H3 r% i! O' [, j
    kobj->state_initialized = 1;
) b5 R' W. a, N}
+ p# q/ |; z3 i, |: o1 @" x该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。/ s* ~& Z+ S$ ?- N0 U/ z
6.1.3 device_init_wakeup
) d' c  X4 p5 O, j, H0 ^参数val为0,设置该device不能够唤醒。3 j$ d: P* d9 b- `/ T% V4 s
#ifdef CONFIG_PM# R4 P( S+ u) o# G% f4 Y# X* O* ^  j

% i6 n' K- x* p, T- ~/ |/* changes to device_may_wakeup take effect on the next pm state change.8 N& V- C# N" t
* by default, devices should wakeup if they can.. q+ f! h4 j( L4 |
*/1 E" N6 o1 E1 D$ P6 i0 I( ?/ P* L1 i4 ]
static inline void device_init_wakeup(struct device *dev, int val)! i2 o# i6 E( e$ u$ r( A5 i
{6 C3 e# l6 h6 ?$ X6 u$ r
        dev->power.can_wakeup = dev->power.should_wakeup = !!val;
2 x. E$ k. o) f  e: m}3 g0 z$ |2 r2 d+ @9 @- k$ f4 [
。。。。。。
' V% @6 d4 m+ K" v#else /* !CONFIG_PM */$ q+ K) b! Y& B) V5 ?
8 N# K9 v8 H) o1 n% n7 e- N! o
/* For some reason the next two routines work even without CONFIG_PM */( e% C4 |$ U- J2 N! p/ Y0 L
static inline void device_init_wakeup(struct device *dev, int val)6 p0 R" \" p# q- ]
{
$ b( Y" O) @0 s1 ~+ g    dev->power.can_wakeup = !!val;
& W) O3 Y0 V7 G}' Z- Q9 }! V4 D
。。。。。。7 I% r8 w" |( P) E9 {. ]
#endif
" M- ^- n( U- r& M% h0 J# s' x, k" `1 b. d) u

  X$ }7 x, D) g3 L* d6 I( H- ~6.1.4 device_pm_init
- I2 k% K% q1 H' F设置电源的状态。  X3 [* r( y$ ]) U& F/ @4 E, _2 F
static inline void device_pm_init(struct device *dev)
$ p7 Y9 c+ t4 o{, p$ P$ X3 j8 n; U5 \
        dev->power.status = DPM_ON;    /*该device被认为可操作*/
5 s- z" K/ W! n, x% x8 J}
3 w, ~9 u" @+ C: V# F6.1.5 set_dev_node7 G% ]. H  C3 ~  l2 c
如果使用NUMA,则设置NUMA节点。
; Q0 M# [' R: Q) a0 `! u. i#ifdef CONFIG_NUMA
0 x# R8 u- f4 M。。。。。。
% h) G) M( f/ Q+ d( qstatic inline void set_dev_node(struct device *dev, int node)
& s7 p! m) H% B. h* _1 G* `9 K{
3 L- E7 I4 U8 \8 o, R        dev->numa_node = node;8 S6 k, l+ x, r5 F2 B- b
}
: I, [# k/ ~% H( t; X; Y2 E#else; R! X+ N8 O* e" T
。。。。。。
0 E9 T- F) g3 S: Mstatic inline void set_dev_node(struct device *dev, int node)
1 l: v; G. k' G{
4 d5 A1 ^5 p& e) M5 U) T}
9 U& z, w- Z" J- @$ C  x#endif& v' x# G! F; ~! z
! M) n2 T- e9 f$ A( P/ r7 F  }. ?, O
6.2 device_add
: ^! g5 P# g8 ^% M接下来是注册的第二步:调用device_add。' B. L- K' y/ E: ~+ a
% W3 A' y8 c3 @- g* m* W5 x
/**6 p, O" k! d* `7 |, H+ H: H
* device_add - add device to device hierarchy.8 r+ N$ C. h' o, S$ ^. n% B# G
* @dev: device.7 l$ s' ]5 `5 `
*
. m5 @; G& V% N: d/ N * This is part 2 of device_register(), though may be called" w0 P5 d" s1 w: w8 O
* separately _iff_ device_initialize() has been called separately.' J3 w; T; L( n: E
*; s+ {  z. @) T5 k" Q5 a. f3 R+ I
* This adds @dev to the kobject hierarchy via kobject_add(), adds it( o0 [. b2 F- U3 A2 ]
* to the global and sibling lists for the device, then# A! w9 u  y- {3 S2 o& L5 h8 y5 Q( Q
* adds it to the other relevant subsystems of the driver model.
6 i" w' @0 I/ j3 s *. r  T& O  c2 e2 b9 D- @
* NOTE: _Never_ directly free @dev after calling this function, even
3 O. [! i$ L  }$ w0 @ * if it returned an error! Always use put_device() to give up your
1 ~: |- P7 c( d& i; Y) X+ M# l * reference instead./ e' @# _) m5 N/ z
*/
$ |0 A' M9 g6 W  S9 t5 N6 @1 F! rint device_add(struct device *dev)
9 }9 o- T, b' j9 V{9 y8 z+ \8 X# b7 ]
        struct device *parent = NULL;
, ?- J& B. r9 l7 j  x8 f8 h        struct class_inteRFace *class_intf;
* h" m2 T* }( T1 Z! q        int error = -EINVAL;6 X$ L/ E$ z4 T$ ^: g( Q! t

; }2 ]5 [- Q7 n  J- K2 ~( |8 }- ]+ h        dev = get_device(dev);        /*增加引用计数*/
- y$ T1 y. w9 ]3 R: ~        if (!dev)$ F1 P$ N8 R. O; T
                goto done;( Z: C0 ]0 W# {4 M8 S2 x( E5 Y0 Y; U
; i2 [, D5 z/ M2 P8 b
        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/
9 a$ K, h5 s$ K: C! @2 \, h6 Q        if (!dev->p) {: `9 R( t0 g0 a4 p
                error = -ENOMEM;& n' l) w. O8 x( f7 a
                goto done;
: Q8 g( y6 ^7 z" ~9 J        }
0 P2 l7 {' e* I, i& _) y        dev->p->device = dev;        /*保存dev*/* a$ u7 u3 w* A1 A4 V$ G3 A3 O
        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/
: i5 q0 v8 c2 R, b8 F8 x                   klist_children_put);
; `5 j( I- @1 G' O
) q- D# [: A. {( `        /*
6 }. n: d( U' J& \9 V2 V         * for statically allocated devices, which should all be converted
" ^% ]6 X4 a0 a; G& _8 X         * some day, we need to initialize the name. We prevent reading back7 Q$ G) K6 |+ q5 B, a; O$ H1 y
         * the name, and force the use of dev_name()
& q# r! q* A9 }, t; f$ e         */0 y% k) k8 r( Y; e. j- U' q
        if (dev->init_name) {
& R1 Z% _5 i0 L; _( H                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/
1 _  P2 j( Y# u8 G3 v, b3 j7 V                dev->init_name = NULL;
9 t, z9 {" f. r        }
6 T; t. X- N- h# F3 J
# C) Q1 a4 g0 s- c        if (!dev_name(dev))        /*检查dev->kobject->name*/
% H+ g" Z4 w3 B5 L. d4 g% S                goto name_error;8 R& S- z7 Q: [) @, q

: J) g- ?2 b( g; i: S        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);( N; S" t7 |1 j7 h1 k

1 b- d8 f: k& m8 Y* ?6 d; R        parent = get_device(dev->parent);        /*增加父设备引用计数*/8 \! c; R6 f% B# b, s6 e! {' Z
        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/7 y% [4 L; J, n3 d1 }

- s. N# K* w, q- p        /* use parent numa_node */
1 V* g/ m  k- L4 }6 j* W        if (parent)
7 V5 z- U/ D6 V6 s                set_dev_node(dev, dev_to_node(parent));, a' @' W+ a* K: \! h
5 A# b' s9 y4 ^! a- K% M7 \
        /* first, register with generic layer. */* S! e/ H, m- Y& ?2 {6 j& ?, t
        /* we require the name to be set before, and pass NULL */* h; O7 p  e; y  X; x/ U4 r
        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
/ i3 z0 b. ~, l* \6 O) \        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);        6 F% ~6 O5 R8 N/ I& V5 Q5 |
        if (error)3 {/ m, d* u7 S# w' @
                goto Error;# I- O. g" B" h2 |/ c9 a* H! R

. n$ Y* M2 j, P        /* notify platform of device entry */
2 c1 z4 S* a+ q        if (platform_notify)
8 Q7 S7 t! j0 `! d                platform_notify(dev);, U& s2 f$ z* J  E8 k, r

+ |; _6 A+ Y; b+ P$ F        /*在XXX下建立文件uevent*/
% e+ r. y0 n! ]5 \, h9 f        error = device_create_file(dev, &uevent_attr);
+ S5 A( S$ R, z8 l" W        if (error)
. O) ~+ v# ]" X9 y) G                goto attrError;# b3 @( S  k8 e! J: N5 `

! @& F% V9 r  R        if (MAJOR(dev->devt)) {/*主设备号不为0*/
9 a4 Z$ `2 E& e5 m; V% ?# W                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/
3 {% I) ]- w  ^1 W                if (error)$ O8 _' s4 H; P7 `
                        goto ueventattrError;
3 }2 V0 t$ ~4 }6 q4 `( e- z1 [+ r2 T) ?" ~4 \* |6 @4 B& V
                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */
4 u; R  u8 J" U: h# _1 [& h                error = device_create_sys_dev_entry(dev);
# s2 ]- |" g- L# v) i8 ]' P                if (error)8 c7 ^8 F- @7 i9 [% Q: Q
                        goto devtattrError;2 I$ y/ B7 {+ Y
        }
, R7 m$ B. j2 n0 o3 X, o
8 S- u5 x2 x. s: F  j        error = device_add_class_symlinks(dev);
$ \) o) J( F# A* }' @) s        if (error)
4 ~1 ^( `" \+ N0 o2 N                goto SymlinkError;# q: u  u2 a. O; D% d! R" @
        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/
. |3 V5 E" H# W/ B; R% c        if (error)
* U, Y, b2 M$ c9 T+ q( w                goto AttrsError;. T9 S  |: N1 j
        error = bus_add_device(dev);        /*添加3个symlink*/
& P) ^  n8 L4 `- O  p9 u        if (error)
0 n. {3 I8 u6 q: i7 I                goto BusError;
4 ~* ~# L9 F' y2 ^        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/
% d0 T! `4 e* C( F        if (error)
# ~- }- i# o: _: A5 _/ t7 F# @                goto DPMError;5 \. N2 u, j, g8 X
        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/
; j& B" C' M7 l4 i
( w& K2 c8 J* U# t. p# f        /* Notify clients of device addition.  This call must come
& i- s4 m$ m6 i$ b% g! P, a; g4 l4 j% [         * after dpm_sysf_add() and before kobject_uevent().$ Y( L" N9 x( f: t( u; k# h
         */& X! S' w1 a5 X3 y: o+ X
        if (dev->bus); t$ l+ b6 j# w, w
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
% T# L& [- O; B5 l" E" A1 P/ y& ?& `                                             BUS_NOTIFY_ADD_DEVICE, dev);% E" q0 ?" y; \- p+ F- W
7 |; N/ }( K+ H! Y
        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/
0 Z: b! f8 d% x8 `/ A8 I6 M        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/, D1 Q/ q  `  T' V; J( |6 r
        if (parent)
$ y" q: }" Q8 t0 @$ Y( m3 k0 ?                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/
& a& |: P- E6 y8 z) P6 ~8 _                               &parent->p->klist_children);
4 x: E1 a/ ~, N1 e1 P2 R9 ]' j" S; C! F
        if (dev->class) {                                                /*该设备属于某个设备类*/
# M% e; X+ U' ~! u. Z                mutex_lock(&dev->class->p->class_mutex);
1 L  k3 v, |) H, P                /* tie the class to the device */
  ?7 n% w' Z" q3 {                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/
5 a8 R: ]8 v6 H                               &dev->class->p->class_devices);
3 @4 |( w. g. I2 I! ?0 M( V* z4 \6 l/ Z0 g, W/ g
                /* notify any interfaces that the device is here */+ [! R  o$ V1 ^7 I" F
                list_for_each_entry(class_intf,' \2 {' |9 j+ i7 s9 x
                                    &dev->class->p->class_interfaces, node)
" F5 V" O8 j- D                        if (class_intf->add_dev)
8 g/ P8 U6 t7 b' q3 B                                class_intf->add_dev(dev, class_intf);
7 f; i) S- h# d1 x/ r                mutex_unlock(&dev->class->p->class_mutex);
7 \  \( r4 j( V5 g$ v! D& b        }
8 A8 g" g, {: K3 G& z1 pdone:
6 Y$ i" U, o; m7 r, L% l        put_device(dev);
  T' r3 m9 ^( e        return error;
2 m. S: ?" S9 m  O4 Q DPMError:6 |/ j  u  b, i# b2 ]) r
        bus_remove_device(dev);
& {6 t9 Q$ v4 J BusError:) {% ?+ D2 r) U) ?' G: r5 W
        device_remove_attrs(dev);
  v' N; J( D8 j AttrsError:
; o/ T* b1 @: @7 b; O        device_remove_class_symlinks(dev);
/ S/ V& a$ B' N SymlinkError:& r: `. s: w" ?$ s' E# f# b
        if (MAJOR(dev->devt))) m$ t8 m/ @  \; P' O
                device_remove_sys_dev_entry(dev);
5 X7 ]/ K3 q& @5 F" g& \. n6 Z* y& E devtattrError:4 t' V2 ~; [& i+ c0 A  y! V1 O
        if (MAJOR(dev->devt))
% f: U, d1 ~- G+ M* Y$ x8 _                device_remove_file(dev, &devt_attr);
# H( @; w- [3 Z ueventattrError:; U# y+ F* @! V
        device_remove_file(dev, &uevent_attr);
4 D  j5 G2 e6 i/ n, j- Q8 G4 J attrError:/ G$ q0 r: W  S% K$ C( V" t
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
4 c0 H* k/ D; O/ ~- h( }: X        kobject_del(&dev->kobj);! e8 B+ z* O2 b
Error:
4 q; W; D1 y! H        cleanup_device_parent(dev);' J, ?& \5 Y4 T* f! t5 z9 `
        if (parent)+ b3 N$ o. d9 `  {
                put_device(parent);
, w! y" }3 G- r" \6 Q7 S, pname_error:
0 q( _/ ~; q5 e8 F& X* f1 r( I* X        kfree(dev->p);$ N3 K0 j4 c0 z. m( h  r
        dev->p = NULL;- M8 }6 w# v! d2 F4 t
        goto done;
5 h6 s/ C# J' k2 F& F/ g! t}
8 `! T0 b% h7 Y7 x9 @
" Q* t( V& }1 }  }; E该函数调用了非常多的其他函数,接下来对主要的函数做出分析。
' S& x+ h8 p  G1 b6 C6.2.1 setup_parent函数! i* g% k% o8 z
下列代码位于drivers/base/core.c。! k+ v/ o  |! ?
static void setup_parent(struct device *dev, struct device *parent)5 i  b8 z0 }; C# R
{* V/ v1 |$ o+ X4 q  p/ Z. U+ F% @
        struct kobject *kobj;
/ X+ Y$ w% c, |$ d/ ]        kobj = get_device_parent(dev, parent);, r3 C: S* j: w; y+ c4 s' g
        if (kobj)$ o; A5 w3 Y2 g# z! L7 y
                dev->kobj.parent = kobj;
% A, G! ]0 q: Q/ L( S}
: B1 v! a: F; T4 Z! M1 R% L5 u0 M- U; r
static struct kobject *get_device_parent(struct device *dev,
' x; G+ j( Q/ T9 f& U  D+ {2 H9 S                     struct device *parent)
  i+ ]/ r1 s9 t6 N{7 P" N# G6 `0 k* f0 c
    /* class devices without a parent live in /sys/class/<classname>/ */' S) o, k' y% d% b  n( O& P
    if (dev->class && (!parent || parent->class != dev->class))
& j* E2 E( g5 q# K' P4 E        return &dev->class->p->class_subsys.kobj;
7 t  v9 X- O1 I, P: J    /* all other devices keep their parent */
; o) y' M. o. v' p    else if (parent)6 n( d' Q/ |, i% G
        return &parent->kobj;# e. z: b' r4 E. n0 C3 s* r
- C  l) t  s2 G9 R
    return NULL;
; N+ \# E2 O% S9 x+ j2 C  G8 Q}6 W/ J# y( d' O' P' C' q- a
该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。, J/ r* v( |/ k4 i) n
6.2.2 kobject_add函数
: T" h4 z7 H1 v$ t' n: r+ B  f下列代码位于lib/kobject.c。% u* b7 E8 y/ I0 x- C
/**8 f3 |7 g- T9 U8 X7 e
* kobject_add - the main kobject add function
! Q0 d2 V' Q' b2 [( q * @kobj: the kobject to add
. d- T4 x7 w4 @  Z! U: o! W * @parent: pointer to the parent of the kobject.
6 j8 S8 F. B9 n( |3 Q7 z * @fmt: format to name the kobject with./ T9 e3 \2 _2 P0 o& L4 q
*+ s/ D9 e3 u& d! J* U3 `
* The kobject name is set and added to the kobject hierarchy in this/ B! W4 Q1 q  {6 |" R: e
* function.
# K2 M3 L% f/ r/ Y6 I; ^ *
; ?' R0 V) {. k% n3 ]! ` * If @parent is set, then the parent of the @kobj will be set to it.
' P4 _5 i, O7 M8 R1 n * If @parent is NULL, then the parent of the @kobj will be set to the
$ p3 c. J# G  a4 X * kobject associted with the kset assigned to this kobject.  If no kset3 C% A" n# n, ?$ A: h0 c9 j
* is assigned to the kobject, then the kobject will be located in the
0 g0 \6 \  R7 j" V- U9 z8 V * root of the sysfs tree.8 W$ ^; f- Q1 ?- R, `- m1 P: a5 m% m
*& [1 {1 s! b9 _; }9 v! w% O
* If this function returns an error, kobject_put() must be called to  E, u3 o* B( j8 h, I
* properly clean up the memory associated with the object.
1 E9 M0 h& i& V * Under no instance should the kobject that is passed to this function; B3 [3 B! H+ b" J1 p$ u2 D
* be directly freed with a call to kfree(), that can leak memory.
% e; w: g6 A  u4 }, ~% r$ d$ k *
/ A, V6 e3 L" a% x * Note, no "add" uevent will be created with this call, the caller should set8 J; o* c' j/ Y& ]- x! N
* up all of the necessary sysfs files for the object and then call
  d8 d" Q, C& J3 I% _ * kobject_uevent() with the UEVENT_ADD parameter to ensure that( b& r9 U% V6 U  l# l4 d
* userspace is properly notified of this kobject's creation.
! D1 P. S+ L8 h" p# Z6 f */# a, Z: d, d) @& x6 f
int kobject_add(struct kobject *kobj, struct kobject *parent,
$ m9 w: g# D" F                const char *fmt, ...)% t9 k* a4 l: B
{
; \7 K0 g4 f* C. }9 Y% @2 i( A7 _        va_list args;
( [' u! \7 ]- M% {5 R- q) s0 z        int retval;
8 \% B- \1 _0 C/ ~/ I  [. M6 @  Z+ }  x) v% z- H  m' g
        if (!kobj). I! I6 e! y- v# T) @& [. V  o2 m
                return -EINVAL;
7 Q$ c& r$ Y+ `0 R
9 K4 I2 Q2 @3 P8 G9 W  ?9 H        if (!kobj->state_initialized) {
% h% T7 |! F9 O( Z                printk(KERN_ERR "kobject '%s' (%p): tried to add an "2 ^4 i5 J4 @0 ^9 d1 b" q" n
                       "uninitialized object, something is seriously wrong.\n",
+ W6 s0 r. P( ~: d                       kobject_name(kobj), kobj);
4 \- V( J1 X" h1 D# _; Z                dump_stack();9 A8 n7 h/ Z* r( Z! D2 S. ^2 Q+ U
                return -EINVAL;
; d; H! M: F" q8 z7 _& j9 w+ F) y0 d        }
. k  A! H' w0 \8 t% d        va_start(args, fmt);
& k  W  A% q5 K6 t. b. o. y        retval = kobject_add_varg(kobj, parent, fmt, args);
) i5 ~, r' d2 G$ z  }4 o# H        va_end(args);
, C( N* E2 r7 F
5 m7 J; Z8 }# \. Q        return retval;( j" c1 _  S3 l# [* J/ c
}. s/ E% ?: e: E
EXPORT_SYMBOL(kobject_add);
/ I% C3 ?6 o8 D5 ~9 I+ {5 e5 K# D, m9 @8 o0 i: Y# r
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
8 S$ B5 J4 a/ E/ U& Z                const char *fmt, va_list vargs)
( X* ~$ D& N# }  D3 V! }# X2 e{
8 b: U" @- A# E1 h6 G    int retval;  Z; }+ X$ t0 S3 S' |3 ?3 d
! R& \4 ]' ^: U5 u; H
    retval = kobject_set_name_vargs(kobj, fmt, vargs);: e5 `9 G% w8 E$ {" l. Z  I$ s. v# i
    if (retval) {
/ h# x3 p9 Y9 X; _' x        printk(KERN_ERR "kobject: can not set name properly!\n");+ [9 W* S: z1 s  h* ]# {% n
        return retval;
' _. |: J/ R7 J: T8 E8 ~/ ]9 E    }+ u5 o3 S3 u- i; y
    kobj->parent = parent;# O+ @- {; N; r. _
    return kobject_add_internal(kobj);
. Z- K9 q! x$ O: ]' d/ D1 |}$ o' r1 D4 D. K2 e" o' [5 p6 L
* ?* b3 ~+ I8 }/ t. o! ?6 z
static int kobject_add_internal(struct kobject *kobj)
3 R. r7 \& x) X% j9 o9 i& A{; Z4 u9 P, T$ Q  g3 }# T6 b) {
    int error = 0;0 Y. \2 R) s6 r: V' N
    struct kobject *parent;% f2 Y5 l) S, ^6 J; N: A

" O+ c  q* ^6 b    if (!kobj)2 R0 ~2 F0 {$ P& d$ D6 C0 F
        return -ENOENT;
" t5 f2 K7 X8 N3 y; r  s# |1 r& M    /*检查name字段是否存在*/- a3 i2 i" D9 t/ g( R+ o7 }' m
    if (!kobj->name || !kobj->name[0]) {1 ^4 \. _; a$ h' v/ g! u
        WARN(1, "kobject: (%p): attempted to be registered with empty "6 P9 }! i* _3 |) k. w
             "name!\n", kobj);+ a3 b7 p# l) U$ v" t
        return -EINVAL;
; z2 C7 Z' |. P& |& J' ^7 W    }
$ ~8 v: ^1 t% X, S& c' w# L' I4 q8 @2 m! E8 r( r( F: A
    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
# }, _6 J$ ]) ?4 C9 m6 j9 k; M# e7 T/ ]
    /* join kset if set, use it as parent if we do not already have one */
% ~5 Q7 y4 g% s5 l    if (kobj->kset) {   
' m# J' m% G9 N5 G5 q# G6 ~        if (!parent)
6 B8 b7 k/ i: g) d, o4 }6 z/ v            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/$ s& [3 s% l0 r( k: u# ]2 f
            parent = kobject_get(&kobj->kset->kobj);7 p7 q5 h: j" B, [0 m
        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/" L) h$ i5 ^/ E0 `& _
        kobj->parent = parent;0 N# i' q0 B/ b+ }
    }0 a: U, y6 B- h. b2 j

: s: i! g3 U2 o$ h! U" H8 O    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",+ c7 n: x' ^  \  W# S, \
         kobject_name(kobj), kobj, __func__,  Z; Q6 C3 {, u6 ?# Y
         parent ? kobject_name(parent) : "<NULL>",% P4 w& m5 M+ t  Y  N
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");# s4 q* E& B6 f5 `( z! P1 K9 N
4 f8 X) {& @2 b3 Q
    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/+ [0 A" t% u) I* F* l2 W+ x  J; k
    if (error) {
6 P9 O; T6 s0 J. x7 J        kobj_kset_leave(kobj);    /*删除链表项*/+ W8 o2 b# V' g. f) f
        kobject_put(parent);    /*减少引用计数*/( V! H+ n/ k" R3 L8 a  I
        kobj->parent = NULL;5 N- K5 u$ L( e

* z( H! E; L4 x* B- w; v# O: s        /* be noisy on error issues */
0 A9 {  X1 ]5 ?  u" a2 y+ K        if (error == -EEXIST)/ B% z; M7 {8 m$ ]2 ?
            printk(KERN_ERR "%s failed for %s with "
5 m5 Z, u$ p1 ?7 z- T% i6 ^                   "-EEXIST, don't try to register things with "
. e* L( m: y8 V( @9 d5 W                   "the same name in the same directory.\n",- O1 o& R+ T: @: A; i4 q& T/ }
                   __func__, kobject_name(kobj));
+ [6 ^( j& {8 r( u* w) S6 m* R* Z$ X        else  J, \6 r( A) y+ F7 H# [
            printk(KERN_ERR "%s failed for %s (%d)\n",
/ d; g: `! m, W, i4 x: d2 ^  b                   __func__, kobject_name(kobj), error);
; G9 g1 ]8 ~* E2 H( u$ i        dump_stack();/ Z* m6 K! {5 K3 V3 T) l: E: B
    } else
* T- w2 N4 Z6 I( x+ g8 U. I        kobj->state_in_sysfs = 1;3 I+ z6 W. u( _0 P( T4 o* j( j+ k

/ [. L7 o4 |# |+ U; Z8 L    return error;2 ~9 J2 B2 K3 T! N4 T
}+ W! |/ d5 ?+ g/ }( T* D9 O; @
在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。- B. ^6 D) g, p) X
而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。
! _+ J. K! C% h$ d/ B
* E  r. [7 K0 G3 n2 V但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???, n" K6 q% c& P

. Z0 k, h, C0 p0 U4 G6.2.3 device_create_sys_dev_entry函数
4 _" u) P! j5 I: N$ i+ d在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。
9 j2 B+ J" Q3 v' E但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。9 `+ N* N4 K+ S1 o( d) {

& F& A2 c% F' K3 R下列代码位于drivers/base/core.c。
- g2 T. {" J' s- K7 Hstatic int device_create_sys_dev_entry(struct device *dev)# I" o' Q9 W* J# Y( a
{
1 X0 j( W" b5 g, \$ q        struct kobject *kobj = device_to_dev_kobj(dev);
8 E3 |1 @% }  f- x0 Q7 y9 X/ z        int error = 0;
3 I: b* @! S. L* m! V% L9 F! U) W        char devt_str[15];
" ^, f1 S1 _( Q- [3 j$ O, q7 v2 y4 F* w  d: d
        if (kobj) {
4 F. y" j$ q0 E3 w9 Q, H                format_dev_t(devt_str, dev->devt);
2 m" m# i5 }& s4 s. K3 K3 v* g6 E                error = sysfs_create_link(kobj, &dev->kobj, devt_str);+ n- r- {: Q# ?; P2 n  w
        }
+ |  Y# _: T0 H) k3 j
5 k, ]& E! m/ D# E6 b9 Y+ L* [        return error;
# h2 [$ m! t6 Y% m: ^}5 i$ @& Q: X: }, g: x  w- X
/**! \8 O: y% Q! T; u& j) y1 y
* device_to_dev_kobj - select a /sys/dev/ directory for the device1 M; X5 C5 n5 d, l& }4 F
* @dev: device+ i5 T* u, n+ [+ T4 l6 O
*
: z- n2 c9 _. i$ g( \1 I  o5 ^0 C * By default we select char/ for new entries.  Setting class->dev_obj, U, d$ E8 h" A" O8 l" A
* to NULL prevents an entry from being created.  class->dev_kobj must: q! K9 d: f  H% F
* be set (or cleared) before any devices are registered to the class1 s/ A6 |1 h% Y# o" O* R% ^
* otherwise device_create_sys_dev_entry() and" x, D+ B9 f& o3 t  G$ ^
* device_remove_sys_dev_entry() will disagree about the the presence/ T7 n% s5 |% K) S& s0 o/ @
* of the link.6 V4 ~5 s3 B. p7 M; E/ [
*/! q6 q# E! o5 W- [9 Y" b! S
static struct kobject *device_to_dev_kobj(struct device *dev)# R2 ^% x8 G4 P5 t" T
{
8 z. ~$ V7 C+ _$ p1 y    struct kobject *kobj;
0 b2 `7 P+ g, r1 N* V4 C) o5 `' D' w: a5 ]; a2 W' @
    if (dev->class)
8 H' t! r8 I7 y+ S# N        kobj = dev->class->dev_kobj;' w7 H" D$ O& `2 M
    else# t- }0 N; _! \4 U9 E8 v
        kobj = sysfs_dev_char_kobj;- x" W, h. ], @+ k

* k0 _7 E! m+ Q; w2 S    return kobj;
( l& C* f7 y  Y0 c; R' J( @% h}
  f% P+ t% w! ]& i- L& S
6 F1 \$ n$ u% J$ @6.2.4 device_add_class_symlinks函数& k* _  L# M8 e3 R) B" B
由于dev->class为NULL,本函数其实没做任何工作。; R0 w4 y6 ^: g4 k4 o' M
6 l) l- {; ~3 n, g+ Z+ O
下列代码位于drivers/base/core.c。
4 [; x" ^* w; ustatic int device_add_class_symlinks(struct device *dev)6 f/ k5 m9 u* ?& K
{( y. `! \8 u# k! @6 s) V
        int error;
/ j+ L4 Q' U& y' K* N! p$ x% ~; |( o# `4 h; o3 e/ B, I
        if (!dev->class)5 W5 n/ G7 X! E) d% P7 o' v
                return 0;
9 T3 z3 S0 [, Z( n1 G5 U5 X
# r: c0 |5 I5 E7 D* ?        error = sysfs_create_link(&dev->kobj,8 B. o: L( ^( w* X
                                  &dev->class->p->class_subsys.kobj,  ^# W2 y. h& S1 b
                                  "subsystem");
* H- ]; A7 G3 B% o* V        if (error)0 _# t( L$ A1 M6 _$ r% f0 X# ^
                goto out;1 w8 J& T9 I3 P6 G" e8 F9 E
. X/ z6 q5 P  S" `9 v
#ifdef CONFIG_SYSFS_DEPRECATED
$ M# T: G, e% G        /* stacked class devices need a symlink in the class directory */
, `9 F! N, C3 [5 Q) B        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
; u. I$ X  t( m; a            device_is_not_partition(dev)) {
& i3 l: Q! D3 W: ]( G, v                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
4 G/ c/ n5 N6 e( O0 x9 Z! p                                          &dev->kobj, dev_name(dev));. v+ k3 I, E% T6 F& I
                if (error)
: p: K. i( Q$ i; Z8 |$ l6 t4 i+ h) W                        goto out_subsys;
( L$ f0 `( I7 Y  @        }; v  u6 g( f/ f. }" {: C

% c6 j1 O. y" C2 ]        if (dev->parent && device_is_not_partition(dev)) {
9 x$ m" O7 i# C" l. F; O' p" v                struct device *parent = dev->parent;
  b& T$ ]2 S1 X9 J% u                char *class_name;) }% I0 c* Z& @* |* G$ x" t
7 }9 Z% B0 p+ {3 t" B; }
                /*
/ D9 S7 Z1 ~- O7 M                 * stacked class devices have the 'device' link+ j! i- B. W8 k$ T' N8 m
                 * pointing to the bus device instead of the parent6 v# j- d: E$ N; {5 B# P
                 */' V7 O) k# [( f) E: v5 M  n
                while (parent->class && !parent->bus && parent->parent)) ^2 w, _: Y! j& N* A
                        parent = parent->parent;1 w% q( H7 J; f5 X# [
. h/ D) ^% \+ z4 G% L/ J; E
                error = sysfs_create_link(&dev->kobj,
! Q4 o$ H  f8 Z' C1 |                                          &parent->kobj,
( k- s- `" s4 v8 f- Y$ d- f7 S# @                                          "device");) Z; U  k) l& D
                if (error)) f" d' t5 R: W  H, J5 q
                        goto out_busid;+ `+ J! C' K1 D" \

+ p# }3 ?; Q- x/ ^0 [                class_name = make_class_name(dev->class->name,
7 O; D! r7 O8 a3 Q                                                &dev->kobj);
/ W+ U! W2 M' }                if (class_name)
# M6 m7 A4 M! f. G7 N% m  H9 j                        error = sysfs_create_link(&dev->parent->kobj,( }" a) Y* D  T( Q7 ~3 ]# e/ x
                                                &dev->kobj, class_name);
' i7 S: m7 @$ _, J* @                kfree(class_name);/ Z( g. l% j" C. W
                if (error)
. Y' i( D, N* ?5 M6 S+ e                        goto out_device;
  b3 `# E& S" e        }- g/ t* W; M7 i2 j, U
        return 0;
6 D: W* K0 t& e/ c( b+ ]% y; P' D6 k% P' x' O
out_device:1 o7 O6 Z- I; A' g
        if (dev->parent && device_is_not_partition(dev))
2 ~) |. ]& i( L# [2 R# o                sysfs_remove_link(&dev->kobj, "device");
( N4 j# a( `* N8 aout_busid:( J8 e: n2 w. A/ A
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
5 h  M  R. i' N/ n4 J$ Q9 N            device_is_not_partition(dev))
0 P, S# A4 j" U. _( s0 Q8 `6 W                sysfs_remove_link(&dev->class->p->class_subsys.kobj,
5 H- N- u4 A$ L  }$ b                                  dev_name(dev));
6 p! ^) y' c% v5 s8 E#else
# F* q  R& A8 P' c5 B$ Q9 n% w        /* link in the class directory pointing to the device */5 F8 ]% _$ D/ G6 f( D! Z! I
        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
% g8 p, R/ H9 s0 Q' N& P0 n4 H                                  &dev->kobj, dev_name(dev));
: U& c  p- U' P        if (error)$ b, @* f5 {8 a/ i) }. Q  `
                goto out_subsys;
7 R0 J% X6 B( E/ F$ ?% l$ x5 f  c/ g, {: y: ~5 C
        if (dev->parent && device_is_not_partition(dev)) {
; N) Z! ?9 t7 A5 K. ^4 V5 A                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
* p) T. _9 N2 H% f+ Y- g                                          "device");0 T6 f1 {" M, [- j  j+ @, I3 ?5 ]: t
                if (error)5 a4 h8 g4 J7 ?% N* D
                        goto out_busid;
4 F" ]! X! D: F& |* J3 _        }7 U; i( B2 S+ [8 K/ ?
        return 0;7 E) Z: a! I& I, T, ]5 p% R1 J: s/ R
4 B) J4 o( B, d3 R4 t
out_busid:5 w# Q0 R' N' x, q' T) q
        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
5 L) X+ U! m! a4 s* c. R' o#endif; Q$ ?7 L2 T9 g

* z3 z' I& w4 I, g; H* n( \/ Tout_subsys:
3 X! Q( X- b. P1 _4 Z0 I        sysfs_remove_link(&dev->kobj, "subsystem");
* r2 R- t) r8 @# W/ s8 X9 q6 Wout:
$ M7 Q/ h! s. c6 m& K        return error;
6 G+ Y, }) V) I}
( r6 c1 m6 W2 Z% J, j0 A6.2.5 device_add_attrs函数6 S5 C) P; C8 \5 A) @* ~! S2 p* d
同样dev->class为空,什么都没干。' m9 V- p+ `" u" y' \4 x
下列代码位于drivers/base/core.c。
# Q! H# t$ b  Y, h! w& \5 u. ?static int device_add_attrs(struct device *dev)0 K4 k1 L2 X8 J! L" \; i3 z
{: z$ B* D, E( f1 ?/ [  p. U' v
        struct class *class = dev->class;& i1 f1 \: F# D
        struct device_type *type = dev->type;
. r4 Z, Z) `# _: T7 H# N: d        int error;
, O  Q" k* }& }5 {/ W' F& F5 `- u! r! y$ ~3 T5 m% R$ D6 n
        if (class) {+ n0 d. X0 q: r; i
                error = device_add_attributes(dev, class->dev_attrs);
0 m; H2 {0 J' r4 X; `2 j                if (error): x. @. a# @) p- S8 P5 b6 f
                        return error;
2 o1 w9 v' }+ y% y! t4 t        }
6 [& S8 p5 {5 f0 P5 b; D* H( f% V4 A' z2 F* Q- `/ e) _
        if (type) {/ E2 g% x% f; Y; \9 _9 f+ y
                error = device_add_groups(dev, type->groups);/ D) l* E" U3 H
                if (error)+ D( ~/ z  O: s/ w' _# P+ k' _
                        goto err_remove_class_attrs;
, {6 s3 H5 U5 o' H) ]        }$ |* A) _' }  y9 ]
5 l  P) ]3 d2 }
        error = device_add_groups(dev, dev->groups);, u* {* @  H( n8 X( d
        if (error)
6 i' k  m2 ]2 g8 n+ ]                goto err_remove_type_groups;3 W4 x& K. U9 s$ ^* `4 i$ G* I
' u$ O# M" G7 A3 g6 z4 n& m
        return 0;
1 b" Y' o% F- T* r+ ~, ^1 Y5 T! f7 [$ y$ P& `$ ?
err_remove_type_groups:
7 s' U( W" }1 c7 ~        if (type)& K; B7 P$ U8 H& l. R8 Y* J, b
                device_remove_groups(dev, type->groups);  v$ l8 B  K# Z- I
err_remove_class_attrs:9 `$ ]$ W- O4 W- M4 g* O
        if (class)- L, W6 |: Z9 j( j
                device_remove_attributes(dev, class->dev_attrs);% O6 }# n( u* p

- a8 E* }! _; T, f6 C$ N        return error;
3 J1 z' _% h! o) w9 ~. @}
7 f' q: @) c% U5 |6.2.6 bus_add_device函数" [5 L' l* p, i& o" I; S0 V: F5 ]
由于dev->bus未指定,因此这个函数什么都没干。8 L" l) O( ]: ^$ r' v6 p& a) D
9 Q: T  C* J! t6 t; X. l/ y
该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。2 r+ l/ H2 a+ f2 D4 h

2 c8 {- G; X& ?/ ]( \% d1 A4 Z下列代码位于drivers/base/bus.c。$ E) \; u1 M- k" F4 [2 K
/**/ m) W; B' D5 g
* bus_add_device - add device to bus
# I' L9 `" Y7 L; C0 g4 f * @dev: device being added! C/ Y7 {! l4 E# x( ^  @; f
*3 Y4 U) k) p3 K8 m2 |- }6 ^- J
* - Add the device to its bus's list of devices.
# M  w( c8 ]6 N; U, t) H6 A * - Create link to device's bus.
, i$ H7 B9 ?& s/ k3 R) }& \  F */
/ S% T# V$ k& Yint bus_add_device(struct device *dev): @9 x) v" N. w8 R4 K/ i
{) j/ h+ W0 Z% F9 H. h: z7 E
        struct bus_type *bus = bus_get(dev->bus);
( C  D% k  N2 ?        int error = 0;
) v7 i* Y3 H& f1 b2 V4 W* @9 O* Z4 s1 Z" b# J
        if (bus) {4 C$ h9 P6 M- G; N, B
                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));- C+ Q' o: d& [+ x: E" }
                error = device_add_attrs(bus, dev);
/ w+ o+ ^. U* R2 ^* \0 u                if (error)
5 v; {* w3 t% F/ `! v                        goto out_put;
- R7 @- G* D! `6 n+ _5 j& w               
* p6 p7 b/ D$ o                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/  |% o5 ]' {' _# D' Y
                error = sysfs_create_link(&bus->p->devices_kset->kobj,- h& f8 ?( e1 p- G1 \
                                                &dev->kobj, dev_name(dev));6 D; q9 m2 @( P3 z2 h* t4 z+ Z
                if (error)
  @) ~# Z- R+ `0 C8 }5 h8 `3 J* ?8 s$ u                        goto out_id;- `* x, A9 Q# {# A0 N
               
+ m! o. B! R$ x' A. V, U: ?3 X( k                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
' b$ T) l! _% o1 k1 }                error = sysfs_create_link(&dev->kobj,
5 Q' K3 M; H6 L, F7 f                                &dev->bus->p->subsys.kobj, "subsystem");! |2 F5 J  v- q; ~, {
                if (error)
$ x1 C, L, s+ i2 A; B3 u                        goto out_subsys;
6 a5 J& C) w/ t+ q' @2 x: t               
+ @7 A. u3 R2 r& _" Q1 @                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/
) B9 R. b8 s+ U+ @$ w% o                error = make_deprecated_bus_links(dev);
% ~- A; d6 b6 A# q% N  z2 i                if (error)' t$ ]1 `5 V4 l4 W, f
                        goto out_deprecated;
$ d- D7 U2 v5 c& g1 ]% d        }
+ N$ z9 B( x/ a        return 0;" I' }5 x& i* k4 |9 N. t7 q
$ c7 I7 S/ h0 q# x
out_deprecated:6 v  {( W# I# [# Z
        sysfs_remove_link(&dev->kobj, "subsystem");
  V$ S' h  u4 x9 R" f/ y8 Vout_subsys:
; T; J8 v3 ?; j' H$ w0 K( N        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
3 s6 J2 ?  z. d9 b; p# S1 Tout_id:/ L1 v0 M# E8 e9 Y6 \- L+ w
        device_remove_attrs(bus, dev);
9 |* q' U9 |4 E9 F, `out_put:
" N/ A, Q& y% m2 M9 l        bus_put(dev->bus);
& f4 q( H8 Y, A2 o        return error;: a  ^1 F' j; k+ R1 q3 T6 U% Q
}
9 j' ]+ a8 I4 Q* w# |( A9 [& |% y9 G3 Y  C; K+ l
6.2.7 dpm_sysfs_add函数+ L0 j: j+ G4 N9 ]* ?3 p- G
下列代码位于drivers/base/power/sysfs.c。' v1 I' d5 J% \5 ^; |
int dpm_sysfs_add(struct device * dev)  ~  [+ D: a; `8 d/ t& z/ A' n1 B- Y1 G
{* \+ u' A8 A, x0 w* C9 @, L: V# X$ ^
        return sysfs_create_group(&dev->kobj, &pm_attr_group);$ e( D4 m: D$ \. F3 E
}
8 G+ Q$ T" F- Y. Y: j! v# k  A/ h; k+ ~
. r* @4 m! o0 a8 R$ hstatic DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);* y' B, F; o6 r# c- C0 e  t# q* p# t  F

2 c9 A5 ~( d$ H% w8 m4 ]1 S: y: c, i( r1 ]. Q: A: D
static struct attribute * power_attrs[] = {' P& X! j2 F, b* G$ ^+ w8 |4 B
    &dev_attr_wakeup.attr,) q4 d+ k8 f+ g6 \$ D
    NULL,: Y  ?) B) Z& M6 Q! S
};) K% h; G( h0 A8 k: s! v/ N5 h
static struct attribute_group pm_attr_group = {' G' r  W' h3 W- H
    .name    = "power",$ Q$ t0 E2 s9 C) l" T
    .attrs    = power_attrs,
/ ]6 M1 l' `2 D' b};- c3 t: Z4 U) T/ j

% T) B; D) B" Z5 g. i9 a该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。8 L  r8 a+ C* t, g! g

- ]) J# ~: G" n' Q( k/ z在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。7 e5 B& o0 P, k0 [
6.2.8 device_pm_add函数
/ y: j3 g5 L( ]" q. g下列代码位于drivers/base/power/main.c。% S; W# ?: d" m7 s1 @
/**
. @3 L% }+ }6 T' v  m1 S( }3 n *        device_pm_add - add a device to the list of active devices. d: }( R) }0 g  m: S: `; T! c
*        @dev:        Device to be added to the list2 V- I  g) Q- R
*/
1 m5 {* K% t: Y: Y, L9 [' ]( ^void device_pm_add(struct device *dev)9 W9 S% D' p( l$ ~+ E4 `9 F
{
# V$ x+ Q) J7 }  B; k        pr_debug("PM: Adding info for %s:%s\n",8 l- C5 m4 k, h3 X8 ?4 u
                 dev->bus ? dev->bus->name : "No Bus",( \3 y& W6 Y8 ], J
                 kobject_name(&dev->kobj));
+ X% `: t7 h0 ^" q        mutex_lock(&dpm_list_mtx);# s0 ?* K, P/ R6 K& O3 {) F
        if (dev->parent) {8 ]) \( r. F4 }/ [0 d! B, R
                if (dev->parent->power.status >= DPM_SUSPENDING)& N" a8 _' u4 B
                        dev_warn(dev, "parent %s should not be sleeping\n",. A8 p2 F& H( \! L8 j
                                 dev_name(dev->parent));
$ q$ R9 U3 S+ O        } else if (transition_started) {
* \6 K2 E' m1 J& Z# u                /*) K( _5 D7 y! @9 y' s
                 * We refuse to register parentless devices while a PM! y1 e0 H5 U0 I5 c5 p
                 * transition is in progress in order to avoid leaving them
0 ~6 G; y! U) B2 g* z; {                 * unhandled down the road+ p" |) o: g& W; F3 a& \/ H
                 */% j9 s* m8 g- `4 z- Y
                dev_WARN(dev, "Parentless device registered during a PM transaction\n");# t+ l6 d3 q4 ]
        }1 {2 k: S& |+ G. A" K9 M
6 N8 Q3 j1 S7 I- k  C
        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/
$ S  Q$ m/ A( g2 k5 |        mutex_unlock(&dpm_list_mtx);
& }, u3 A3 N  @, W. F6 ~7 \6 Q- N}
, Z! t2 c2 _5 y9 ~% C" @5 k3 P, |6 N" A
该函数只是将设备添加到电源管理链表中。
! f# n3 r, W- }: M! w! b0 C) {6.2.9 bus_attach_device函数9 b6 M2 [7 i3 ?5 O) z5 t
在本例中,由于bus未指定,该函数实际不做任何工作。/ e2 ]6 h2 g8 s. i/ i3 B% c
下列代码位于drivers/base/bus.c。
  ?9 @6 [: a+ A7 _- C* [
6 G; W! Q' V! [* K3 |/**. }- I, ], @) X7 i0 j6 q& o
* bus_attach_device - add device to bus0 |! v& }' E9 ]) C5 [: k. j. H4 G, f
* @dev: device tried to attach to a driver
! A+ `4 s% F' T* _ *) Z- ]* ^7 Z6 Z6 a7 [
* - Add device to bus's list of devices.
! z1 ~/ G# I- A. q9 ~! g/ q * - Try to attach to driver.0 B) Q) u  q1 t9 P
*/0 D4 _$ e: {% k1 c6 i  Q/ p
void bus_attach_device(struct device *dev)
& I8 q8 ^* G3 \/ E. v) H{+ B) a2 H' @+ F* x- N+ J
        struct bus_type *bus = dev->bus;: V5 K, [/ Q6 j
        int ret = 0;
7 i: K! V: g3 t" [) q) m" q, f/ Y8 b0 |
        if (bus) {/ \' W7 g- j  y7 r- ]- b
                if (bus->p->drivers_autoprobe)
' r, U7 H3 Y9 W) a                        ret = device_attach(dev);        /*尝试获取驱动*/
' }. e% |6 H: B# U4 ?0 w0 w& V                WARN_ON(ret < 0);- w) I1 d( D6 z/ t
                if (ret >= 0)                /*将设备挂在到总线中*/
2 M! a" l) G  M                        klist_add_tail(&dev->p->knode_bus,
0 U  d$ k' L0 |" a) |$ Z' U                                       &bus->p->klist_devices);
2 n3 t7 b8 D- d1 `6 p6 ~4 _        }
& A( a4 g) o4 ]}2 B6 g7 z4 O& O
+ Q+ H5 B/ g) P9 S" F& D; [4 I
/**- h& A6 v6 [$ m% y6 ~) Y+ y
* device_attach - try to attach device to a driver.
6 y$ y) B( \! D" j * @dev: device.3 B% A/ |% o6 F7 \" F6 ]' Y
*4 E; ]' u# t; N# [1 k7 o
* Walk the list of drivers that the bus has and call
% W8 v3 M; x  P/ m( R7 o4 E7 B0 ~ * driver_probe_device() for each pair. If a compatible
5 L+ H* A" s9 g6 v  ? * pair is found, break out and return.
8 Q3 ]( ~# \2 y0 _: L5 y1 k *( n3 {! `* X7 O! g
* Returns 1 if the device was bound to a driver;
6 C, G+ x* }8 I* X/ c3 e * 0 if no matching device was found;
: M# T, E( f& w: \! l' S3 [/ i * -ENODEV if the device is not registered.
" c0 g! w: c! D# C' ?6 H *
! P9 n0 B  y; P: r/ T. c * When called for a USB interface, @dev->parent->sem must be held.
8 w( I) J: ?6 @& S. s( d1 K2 G$ S */
! j' C8 i( t: V2 q) Jint device_attach(struct device *dev); K0 J5 L7 P0 b( C0 T( D9 b
{; y. g* P2 P- t  c- ^+ y
    int ret = 0;* o( Q  \1 ^6 [( q  @- w
* }" x# k: j& E) w. ]# `
    down(&dev->sem);
2 R& Z6 {/ h5 d3 G; t4 ^    if (dev->driver) {    /*如果已指定驱动,即已绑定*/, X# n8 h  I6 M% j5 Z& i
        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/1 G; q! j4 f6 o/ j( w* N# E
        if (ret == 0)
/ `/ Z- s/ e+ u6 m: [4 f  ?            ret = 1;8 d: P/ j1 K) k8 M5 k( Z8 t1 B
        else {% q9 R, L7 a; s
            dev->driver = NULL;. m- C3 C5 X! b' P
            ret = 0;
, C% |" C2 p% `8 b        }
$ N* I- [4 {0 _  G1 V& m    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/) }! C( j! k: E  X! P+ ]* W
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);: U7 b/ e& d# `/ v: D
    }
7 i  j- g0 Q8 F    up(&dev->sem);" o) L# F1 O( c
    return ret;
) a: V* I+ y' `+ \. C3 B}
+ M- f# o' J* h+ [; F+ UEXPORT_SYMBOL_GPL(device_attach);, H% j: R& Z! J/ o/ t
( K: Y  I& ?" ^: T3 c
如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。  Z+ ?1 @4 x7 z, u6 M1 b1 c( D: Z9 ~

( [. I0 i/ B9 G6 J5 H为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。
+ s8 o6 \) t$ q$ X: v5 r) x8 C9 n+ q( Q, F( p
我们来看下bus_for_each_drv:/ w6 ?7 |/ A! {% G  o, ?- Z
3 }) @4 O' ?2 e; ^+ O; x
/**2 {6 @2 r  F. F: a  p
* bus_for_each_drv - driver iterator
2 U; y, ~5 f% A( J2 ?" _ * @bus: bus we're dealing with.
( ~2 v: o- ^1 x. P/ [ * @start: driver to start iterating on.' c* c- p4 ~! c# s' B$ t
* @data: data to pass to the callback.- j) [# u! q6 V+ Q& f
* @fn: function to call for each driver.7 C" ~, v5 ~) {7 F
*5 ~" `& Q. L) g0 B
* This is nearly identical to the device iterator above.
' |0 R3 C# J7 V$ _! t * We iterate over each driver that belongs to @bus, and call  n( Z. C' ?  k+ Y' R& r% u
* @fn for each. If @fn returns anything but 0, we break out. W! b; m2 H. y. L5 k
* and return it. If @start is not NULL, we use it as the head2 [$ ^7 j% n( N, u
* of the list.+ p) m( }$ ~) ]  d# r5 X
*( T4 J8 b3 Y& u2 Q) V
* NOTE: we don't return the driver that returns a non-zero
$ K3 U/ ?, i; [, \; Z# B1 k4 B * value, nor do we leave the reference count incremented for that  g1 J: y: E8 A& c
* driver. If the caller needs to know that info, it must set it
& h% u& ^% j! ?" ^9 k* _ * in the callback. It must also be sure to increment the refcount
: x, s" I0 w! l+ n  B$ k5 d! {$ @ * so it doesn't disappear before returning to the caller.
5 o& H- ^, G% v# R */3 I6 Z; w* S$ M6 P
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,- d; H+ N. J+ ?* v* o) k) I
             void *data, int (*fn)(struct device_driver *, void *))
0 }) w! p. c" e( Y{# c& Z8 y' S4 X( z$ N4 X6 p; s
    struct klist_iter i;6 }0 G5 g0 N9 d% X/ }
    struct device_driver *drv;
0 \9 V" y' C! V! h    int error = 0;
8 L2 U8 @/ Z( C& L% F; k3 d. |, G4 E* R3 K& y% C! X
    if (!bus)
- t  u( _0 m& r4 e* m' _        return -EINVAL;* K* J! m" c9 E8 _+ A
* d3 g' \3 K1 ?
    klist_iter_init_node(&bus->p->klist_drivers, &i,1 O. _% F7 T" v
                 start ? &start->p->knode_bus : NULL);
) c7 D: C) |; v  C' e- t    while ((drv = next_driver(&i)) && !error)
; U1 p5 J4 ?3 A# }- _        error = fn(drv, data);
& Y- O! W# Y) t: T+ |* ]6 X8 e    klist_iter_exit(&i);
% p# z9 g: ^& J1 d& `. K    return error;
0 M0 r: v/ q, i5 ?! ]% c! J6 Q}1 W7 L: i$ Y4 \9 S
EXPORT_SYMBOL_GPL(bus_for_each_drv);
! r, d3 e( i- ^; Z6 O3 g6 w该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:
0 i6 R, y- q; j& [/ [4 o+ T( u, x3 F4 H* a
static int __device_attach(struct device_driver *drv, void *data)
7 n$ {, ]' v' v{! j- E8 [  @- Y2 N$ A
        struct device *dev = data;
, l: A9 v! u$ e; E6 H' r. e# P& B7 |4 _+ W3 S4 i1 W
        if (!driver_match_device(drv, dev))   /*进行匹配工作*/
7 @. n7 F9 z8 e: \( T                return 0;
3 N" @- t7 T/ B* P* X0 p# v9 u# Q8 S. c( y, W. f% _
        return driver_probe_device(drv, dev);5 v8 W, M( Z" E5 K' `4 a) a
}
- V! O( |  r) K1 T$ C. V+ O) ]: Y+ q% ~1 F$ X( l
static inline int driver_match_device(struct device_driver *drv,
: Z: |0 Q( Y3 d( g! J' C                      struct device *dev)9 I2 w! V0 W4 R) x
{
8 P) G9 O; s. o% P8 v    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
" y, j+ I7 i3 b) e- _$ ^}
9 A$ ]7 i$ ^4 \% u- e+ [6 V+ o) A( S. f1 W
/**7 o% `+ K* V/ y% m2 g9 k
* driver_probe_device - attempt to bind device & driver together
. F/ _  }6 \4 r- u! _4 M( `  A * @drv: driver to bind a device to
& g, V1 J3 ~( t9 c1 J * @dev: device to try to bind to the driver
5 Q+ o9 f9 U8 W$ V4 U: `" O5 D) h *; I! I; [& x; w+ j
* This function returns -ENODEV if the device is not registered,
! ^  V" N) A% k  T8 U6 \7 o * 1 if the device is bound sucessfully and 0 otherwise.
, H  ]- o4 F" P *
  j8 c+ H* {) k * This function must be called with @dev->sem held.  When called for a. |# [- R4 c2 Q5 T1 \
* USB interface, @dev->parent->sem must be held as well.
" `2 m; v5 g! V4 S */, |; i8 n' v+ g  F
int driver_probe_device(struct device_driver *drv, struct device *dev)
* n( f- U' y" i  J; P4 k{
. R1 C0 ^5 v) e/ C& X5 e    int ret = 0;
2 z* Y2 ^; W4 c7 ^! @3 B! b1 f1 s
    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/
9 h9 g- |2 v( q: }9 X. p# o        return -ENODEV;1 a( r9 |) |) T' \% b
+ w$ q, d& E6 q. r0 G& \
    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",) V3 F6 g; C* ~6 p' C* }- x# }
         drv->bus->name, __func__, dev_name(dev), drv->name);3 P: J- f# e& S- e6 i) X

+ K* w8 @1 F( [% O+ m3 @; y, m    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/   
. o/ [! T' x1 ^
3 G" @5 k: E1 M0 w# x& M# M' S    return ret;  ^; X4 [: T0 R
}
8 B/ o* N( X0 ^6 L: ~6 Y5 ]$ G8 x6 W. ?8 z
该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。
0 t. I. Y8 {& C8 `2 C7 K0 N1 G我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。
! Q: g9 h4 }9 h: Q* c- Z. D$ M5 ?" r% ?+ G, |
随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。
; W$ b9 b4 T$ ~7 b1 J
% b6 T' ?) I: W9 B, areally_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。) D3 S, T9 {8 Z3 g0 \& i1 X
6.2.10 小结
8 S- Z& o0 c1 G1 x在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。
0 L( Y4 q! i. c+ z: c6 W
$ u. X  |) B) d2 x' g% N9 y最后以函数调用过程的总结来结束第6.2小结。+ s7 X* |% t) T7 c, O& G
4 _( b- m: i! x' [; H* C3 G
0 C" `" P8 O: D; |8 w/ U' V

' f/ [0 ^/ W, g; L
, `0 J0 N' n$ M7 O+ x' Y0 V6.3 spi主控制器的平台设备* x; n& D" U3 [. @9 j" Y  m
本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。
7 U: u$ `; m" f5 k2 A* j4 p3 K% r% ], z
在内核的启动阶段,platform设备将被注册进内核。我们来看下。
! `2 a1 p; }) A+ e) I6 A% l1 L! M: ~* o+ t
下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c
7 ~- z/ ?& Y! D3 B  _# [$ d' b& j: O- F8 q* ]! N$ E8 H4 k9 Y5 h
static struct resource s3c_spi0_resource[] = {
/ ?2 b. G. s7 M0 k' ?7 D. Q6 K    [0] = {
$ ^# m0 \% Y8 O# K        .start = S3C24XX_PA_SPI,  X9 `: i- n9 V/ |8 u. c% G1 D
        .end   = S3C24XX_PA_SPI + 0x1f,9 U+ u: x9 S, b$ D% v! {
        .flags = IORESOURCE_MEM,
  G* K+ M0 }3 y" B! [  s    },
7 W' C4 ]! O; n3 \: J- c    [1] = {
8 F7 A4 W3 K7 i8 D# X        .start = IRQ_SPI0,
; G3 Y3 J) L4 x        .end   = IRQ_SPI0,5 j. k7 M8 a; d* t4 Q
        .flags = IORESOURCE_IRQ,' X& j4 _* y  ?: U
    }: l5 m5 T: O, |7 X* b* r" D

3 ?5 N/ g9 [! `6 E0 z% v% a1 C};  }( m; b( f" ~
. O# [% X$ Q; F3 d% ~+ C( }' z
static u64 s3c_device_spi0_dmamask = 0xffffffffUL;' X% z4 Y+ k$ u) n0 {6 w
3 D' o. J% P& T3 ?4 v7 Q
struct platform_device s3c_device_spi0 = {
1 C* a  \% o5 ?    .name          = "s3c2410-spi"," |+ G5 p* x, J; o# J
    .id          = 0,3 p, x5 _' s- \4 I4 n
    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),, q% u$ a5 G3 i* y
    .resource      = s3c_spi0_resource,
# K% v! Z+ A  _8 v; n5 r        .dev              = {
& j5 C/ p5 A( w, [3 K8 ?                .dma_mask = &s3c_device_spi0_dmamask,0 H0 E! E- L# W, m8 Q
                .coherent_dma_mask = 0xffffffffUL$ p) U2 t( r3 s1 L0 O* p7 E( |  l
        }" f5 v3 Y7 A! _
};- A5 {0 Y" K7 m6 t5 B2 T3 r( _

/ K1 K& E& t( t  p2 {$ @7 J' Jstatic struct platform_device *smdk2440_devices[] __initdata = {
! F7 [. b( v: m+ r2 Z% e    &s3c_device_usb,
; p2 H/ y4 M3 v    &s3c_device_lcd,  B" E: o) f" G" d
    &s3c_device_wdt,
9 i* u5 n3 X5 |; F* ]: W    &s3c_device_i2c0,- T8 i2 U+ G) q. |
    &s3c_device_iis,! e* p* E  f, N: T: W% w5 n
    &s3c_device_spi0,8 f0 F5 D: e# m6 O  B$ ^
};
; }9 [7 v; o! s2 B- T7 X
" x4 r% i) `; i. c) v  ^# F: n* w# X

4 Z- H! v7 q5 l2 \: x6 [static void __init smdk2440_machine_init(void)* S0 `4 p6 u0 H* j
{
# _3 e" p7 N, ~7 S* N/ z* o/ `7 i        s3c24xx_fb_set_platdata(&smdk2440_fb_info);$ B( j4 u* V; D* o( \! {: _
        s3c_i2c0_set_platdata(NULL);7 ]6 L7 A3 K) M! ~6 p. {6 c3 \

: B- v& B1 _) }' O) ^- A/ }        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));2 O$ v4 u; t- G( G  j2 k
        smdk_machine_init();
) n$ ^/ y8 Z( p6 h- i}3 M5 j  B( G5 L& M+ D* _8 g

5 ^% G/ T$ ]$ {4 v6 K( P在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。* q6 C0 s" M, A* y
6.3.1 platform_add_devices
9 u+ o) I, R. `0 T/**
  Q* z7 a0 o- G9 p) Z# P * platform_add_devices - add a numbers of platform devices: x% M# A: c$ \/ \1 c9 L
* @devs: array of platform devices to add
* B6 X. o" K( f( m' V) _4 Z * @num: number of platform devices in array
9 b( W6 b! q9 l7 w2 | */
! ^  {6 {/ U6 {5 @1 ?int platform_add_devices(struct platform_device **devs, int num)/ z9 Y, n" p3 Q4 t3 ^
{# {8 d& F4 ~! @3 k
        int i, ret = 0;. T0 ~' V( @2 E" a% b

  F8 @8 Z' m2 O1 B( g# I& [        for (i = 0; i < num; i++) {
7 S) t" B$ T1 p" v/ X7 s) D                ret = platform_device_register(devs);
# O0 W  O- a$ K- u. c                if (ret) {
3 O2 q) |8 t  `' o" a# k                        while (--i >= 0)1 L& w5 Y0 I% v' G* W+ i# H+ X& @" S
                                platform_device_unregister(devs);
! X) l4 h% ]$ @- e                        break;
7 n. \% N. {$ W                }
4 t  ~, \& i1 W        }
( R+ t9 _1 O! B+ X# @% `! i
  B6 s' @1 L5 C# d3 E: d        return ret;. B) E* `7 p2 B9 j
}
; p( `7 a- t3 K7 D% V, gEXPORT_SYMBOL_GPL(platform_add_devices);
. |# W6 Q% M* j) z
3 X4 T/ c' b( R1 N& x. E( H该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。- V+ j$ g. x7 b+ C0 i
6.3.2  platform_device_register
  Q- F. O/ M8 D8 U6 m% ]/ v/**
* [8 t8 i2 Z1 c6 t6 r9 v * platform_device_register - add a platform-level device
4 p- T- Y  p7 v * @pdev: platform device we're adding
+ W) \% h% u/ j! M5 f0 p8 g */
3 M0 g4 z4 ^9 d* v7 B4 e' A: A& Oint platform_device_register(struct platform_device *pdev). b6 X0 P9 Y! {' r
{
$ D# v. @9 f5 X* C2 d: l        device_initialize(&pdev->dev);; u3 x2 ]7 B3 P9 X
        return platform_device_add(pdev);: _5 \$ Q& V/ z/ d
}
6 N6 X3 P9 \" I3 QEXPORT_SYMBOL_GPL(platform_device_register);, n5 w$ m! _* I. \# x! i5 d
# ?; f( p7 S2 A0 ?" E2 f. v
调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。2 Y+ h' e" y  T, K$ ?3 n' P/ I
6.3.2  platform_device_register4 R3 Q  V$ ]/ k. v1 V4 Z* J
/**
! h( N9 c5 ^9 Y# v1 c * platform_device_add - add a platform device to device hierarchy3 V& o3 u7 `5 K. k9 p
* @pdev: platform device we're adding! |8 P' g! {7 r8 |
*
7 o% q, L) q$ d$ @$ n * This is part 2 of platform_device_register(), though may be called# P% w: m6 t0 T7 S
* separately _iff_ pdev was allocated by platform_device_alloc().
" x3 {1 n2 _; \" |) F* [1 Z */
4 f* ]+ e* x" u9 j. cint platform_device_add(struct platform_device *pdev)+ K+ ^  o& y0 L) K4 m; y( l
{
1 P6 I& z' c/ I6 x+ t/ ~5 l        int i, ret = 0;# V1 I( G: t' O! J* ^6 _4 R
; V; ]: }. }3 }0 a8 q4 v8 S
        if (!pdev)
6 y( B3 q5 g* \8 d                return -EINVAL;
0 _* T3 E; f/ e' p6 H6 j9 @2 _/ t5 B; ~) h7 k& `' ^( E
        if (!pdev->dev.parent)
5 r0 Q: Y% C, m' j+ c. J                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/
% O$ u; B6 E% ?9 _5 S- `9 ~, L8 `, v4 |
        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/& i1 G: P3 P& U5 z3 R2 v- q# @3 s

) }9 P. c0 ~/ Y) ~        if (pdev->id != -1)
4 s7 G% x6 P6 C( Z                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
+ y7 ?8 J6 z, C7 u# ]9 S        else3 y: e) m5 W4 x$ q1 V  s
                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/  j( o; B5 x# ^5 n* o

' Z% P8 Q5 l$ r0 }, I, H        /*遍历平台设备的资源,并将资源添加到资源树中*/2 T3 Q( ], K4 t1 a
        for (i = 0; i < pdev->num_resources; i++) {
$ P4 S* j( C: r2 G8 d% H                struct resource *p, *r = &pdev->resource;: M" w6 u# x. L( ]

# O" k) z! d1 ?                if (r->name == NULL)4 Z6 }5 M* `5 ~. M2 C; S9 r" u0 z! ]7 D9 \4 B
                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/
. w  B, P4 r* ~* j/ s& `: ]( o% ~0 ~" \; u+ ^. t, h- Z) Y5 l
                p = r->parent;0 X# k) g8 M# t0 ?/ Y+ q( M0 ]
                if (!p) {        /*p空*/' J; k4 E0 f) y# O% `' ]( Q1 B
                        if (resource_type(r) == IORESOURCE_MEM)/ F9 Y9 G) N# s
                                p = &iomem_resource;
8 f( }# _2 _; O# Y. R9 W                        else if (resource_type(r) == IORESOURCE_IO)$ l+ b# l3 j6 f+ V! |) t5 k* A0 C
                                p = &ioport_resource;4 V7 o7 U. j* y
                }4 R* \1 Y6 y5 ~: d8 W$ \" G

/ t' z/ t. N3 o6 `* _) S" m                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/
7 Q5 ~% I/ Z! q                        printk(KERN_ERR
" p2 \& k0 x+ i4 J7 ?% N                               "%s: failed to claim resource %d\n",( t/ x3 T; K5 U7 g- _6 s
                               dev_name(&pdev->dev), i);2 H0 i& u% j. q5 T' C
                        ret = -EBUSY;0 A: P0 K8 `0 f, H2 I# `
                        goto failed;
9 s# Z; r0 I( B- e5 \5 b                }
* n" v, F( O1 M7 Z3 T& y        }2 u3 p/ X9 u! F4 k( m

6 g' y# c, \8 k0 ?: N7 M) ~& d8 _        pr_debug("Registering platform device '%s'. Parent at %s\n",7 X% G) @8 Z1 F) {0 q0 p
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
* k6 M$ P' U1 s6 Z
, W3 x6 M2 S* g/ Q6 @4 m        ret = device_add(&pdev->dev);        /*添加设备*/
/ u9 e: G$ R( R1 C, G        if (ret == 0)& N9 ?; T; J" M# k$ Y
                return ret;
) b% M" I" D2 f5 }) a- \! l' M1 [& [2 ~
failed:& o8 t! I4 x- f$ `) T* r
        while (--i >= 0) {
* l, i; s( @+ X5 l0 h                struct resource *r = &pdev->resource;
" w# G8 N/ \) N6 t' ]                unsigned long type = resource_type(r);
. L. \/ l3 T5 _9 f4 W' l+ F, u+ P" p' z, @9 T, Q
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)7 q5 u, |1 m$ r7 L0 P7 f2 ^
                        release_resource(r);1 Z. w. {' X" I0 H
        }) U; h9 O# D+ h0 U# F
1 o9 Y& @( h! `% b
        return ret;
: `" G; @- f7 a6 v- I$ B6 D}
& C+ M+ |5 D8 ~8 M' G4 dEXPORT_SYMBOL_GPL(platform_device_add);
. g$ R/ k& x. H+ _1 q
9 r+ Q* f  B. {) g在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
  n1 Q( `5 G/ i9 }8 B$ Z/ D本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。
1 g# k+ j2 B3 e( ]  T  `
5 F! B) V& K  Z3 O& n, `+ {那么这个"其他的工作"干了些什么呢?: J9 e7 ^" |- }. N3 V5 f/ y; N/ g. g
4 h1 x# H2 i, ~* i
首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。
/ S: ~) E" z, G- o3 o然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。
0 P3 _# A& a% |  W* Y" b. |8 Z
* g* u. b6 ^# Z  ~- T. F最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。4 u1 t, H" Z* P' z( o% C' c2 s
% h" y, Y( o* g& ~: N  x2 \2 G
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。
8 R7 S8 W$ |& ?7 T
) t$ m( O2 E% \2 S% C0 c由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。
1 K: [! F, ~4 `: U% R9 o. F1 ~4 {3 h; s' o
6.3.3 不一样device_add调用结果
: S& ]5 Y+ G1 O1 t8 d首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:
+ A+ |# E- g+ f- R4 x% }4 P* R! D
9 @3 }( |$ ~. ~# H' p- `0 [3 qpdev->dev->kobj.kset = devices_kset
4 K/ F0 f0 R  y$ T% x. \- h! Y3 ?3 |" A! E0 E: `! r
pdev->dev-.parent = &platform_bus
" Y" R* J7 B3 m9 |7 p- C
5 ]" s6 }) \: o5 [- Lpdev->dev.bus = &platform_bus_type$ y% ]! n" A6 x! O$ M8 B7 M% M
& {- A: f% l! f1 c6 f- P* x9 y
set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。4 A% x; x, }9 d* H' |2 q" i$ R

6 r! Z, O; _: K# G& vkobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。
6 ]; Y  A, W) D8 i8 u: ]8 F) d' [2 k$ }* b- a
device_create_file建立属性文件uevent。
  p2 n& C4 E! m5 m. S# m& ?- k$ s1 }bus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。
, n+ x8 a/ K. V5 X% v8 n. F1 j7 y- E1 d. ]$ f+ m
            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。. H) z9 Q& h( O% @

/ t1 D9 d2 [+ B0 l  _; M           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。
# M0 |' }2 @8 l- S9 n, n" \/ V& X% F2 a/ i1 G
dpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。, D& p0 {/ p2 ^4 A8 g0 o& C% W- E
- Z3 E6 F/ J$ R# _4 l, z
执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。3 S; b: d8 x, m' q7 l
6 m  \4 l3 ]* y  q$ _
[root@yj423 s3c2410-spi.0]#pwd
) k1 U3 _6 ^9 \/sys/devices/platform/s3c2410-spi.0
- w5 ~: j" K9 O; j( ~[root@yj423 s3c2410-spi.0]#ll
. X) M# x" d5 L$ c. \0 I# I- c$ P; ?lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform
; g, y1 ~7 f  v# N7 _2 Z7 `lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi: i& C% A! @* z: [8 b8 z4 F
-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias5 ?" V, H1 R! Y+ Q6 x6 v" Q
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power3 O2 Y+ G( s) k9 G% t2 ^8 y
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0) ^5 N: ?6 X( F# E7 L7 n. e/ }" Y
drwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1! T3 s6 b, F- F  X  M: b7 d
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
1 }7 S" I& A: ?lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform  E$ g. i9 q& Q  d( B" E
-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent* D+ }. c  X+ `' E5 B
2 }; Z# R* E% o- @/ L. P
[root@yj423 devices]#pwd
9 \% r% U( {  E" v  L) O0 c0 \' I; K/sys/bus/platform/devices. }8 G' \2 W* k
[root@yj423 devices]#ll s3c2410-spi.0 8 d4 Q- V6 ^  M4 N  V$ ?
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.04 x+ \5 I# W( W4 C7 c2 N  X
通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。0 B8 ?6 H$ V- u0 c1 W+ i
7 R- b2 u: {2 e6 T& Q; t3 p
bus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。2 |! O, R9 F5 ]8 d5 J, F7 Q
: C. j* h8 m+ w# c) b! [
接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。
% z. s" B4 c, |% l: L% r: X% Q+ T( i' Z* X% a' ^
7. driver举例
0 |& z$ ]  z' \  y: W; M. R我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。  w) X' O) {2 Q3 E) z* q) t

8 E" e, {4 q6 I# z! w2 Q$ \& m7.1 s3c24xx_spi_init
4 U# |. g4 f( B3 T* M! u# M# {下列代码位于drivers/spi/spi_s3c24xx.c。
8 i* i% B& K5 z( l. Q: Q9 ]1 C* }MODULE_ALIAS("platform:s3c2410-spi");" S5 H* K: {  l3 v2 c
static struct platform_driver s3c24xx_spi_driver = {2 F0 _' j0 t$ M9 t
    .remove        = __exit_p(s3c24xx_spi_remove),3 S. m: H7 S3 l; _
    .suspend    = s3c24xx_spi_suspend,( J. l' I& k8 i) H+ N2 [; m
    .resume        = s3c24xx_spi_resume,7 h6 @9 k  X# }* t1 y
    .driver        = {
' k: [- Y+ f$ r+ u+ e, Q7 A        .name    = "s3c2410-spi",
- E( ~& |7 T& Z0 k: u! K1 n8 Q        .owner    = THIS_MODULE,
" Q, W9 D3 G/ _4 p8 t  U0 }    },
# e! {  C7 O5 ~, f3 z& U};* H9 h; p# s5 v' V4 j; Y
, }, p4 [7 c3 m5 P% c2 G' [# z. A
static int __init s3c24xx_spi_init(void)
6 {# r' K% b" a/ c3 {{; A8 F$ }4 t: `- c: n
        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register  m6 Q7 ~! C% H; }& R, p
}
% g! F* a( e8 a: V. }驱动注册通过调用platform_driver_probe来完成。
+ m0 d& M0 x+ j( B* Q注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。" i  D( `( C( S! N) d; l" A
7.2  platform_driver_probe$ F" y( r# J+ v/ f0 g+ @
下列代码位于drivers/base/platform.c。
" ~; R( j( @/ z% z1 Z/**8 _7 b: n3 c0 d8 B' l7 q
* platform_driver_probe - register driver for non-hotpluggable device
& j5 A7 q" M1 k * @drv: platform driver structure& ~: N9 v% E7 ]) V. L7 s
* @probe: the driver probe routine, probably from an __init section6 Y  p4 T+ e: Q' D5 }* m7 m1 a, O! K, E
*# a) K! L! A3 y. }- [5 q/ m
* Use this instead of platform_driver_register() when you know the device! }" X! ^3 A; J( C, }4 O. j
* is not hotpluggable and has already been registered, and you want to* D, X0 \3 O2 J* |7 L* @
* remove its run-once probe() infrastructure from memory after the driver
9 D9 r/ b; W' j * has bound to the device.9 d/ Y$ p) N7 e2 D0 j; O' G
*6 w1 R& y9 B" Y! ~4 ^, U: z% R& }
* One typical use for this would be with drivers for controllers integrated
( B. p& a- q. n * into system-on-chip processors, where the controller devices have been
+ a, W8 A$ l) Y+ [. ~* y * configured as part of board setup.0 f& n8 g1 t3 `4 p* M
*# s5 \, Z8 H' @- ]. D
* Returns zero if the driver registered and bound to a device, else returns+ @& \3 r+ L' a4 ~& q6 ?& I
* a negative error code and with the driver not registered.$ @' z0 B/ X2 w2 W  ~5 g+ h
*/
: z% Y  A3 _: m2 c, ^2 U# X, mint __init_or_module platform_driver_probe(struct platform_driver *drv,, w/ U3 L( y5 ~7 `! i0 j; f
                int (*probe)(struct platform_device *))4 U8 [# w6 n. T5 b$ V. h) s2 u
{
/ A1 z! F, Y: @        int retval, code;# T/ v' N+ z  x4 |+ B3 f

, D9 W2 Q7 C: n! |        /* temporary section violation during probe() */
# S+ E3 K; i, W3 `+ }        drv->probe = probe;8 j0 @+ w; s' l" m3 D
        retval = code = platform_driver_register(drv); /*注册platform驱动*/0 a  R3 q0 t0 Q0 D

5 p- f0 B& \! q( E9 H        /* Fixup that section violation, being paranoid about code scanning
8 q) N* |8 ]; n, u: H2 G         * the list of drivers in order to probe new devices.  Check to see" j8 ^3 N9 G' m/ ~1 g
         * if the probe was successful, and make sure any forced probes of
4 e$ ~& |$ z& M/ }         * new devices fail.' Z' Y: N  C* n: B$ A+ A
         */
: Z! C+ x8 `- t$ n5 T7 d$ W        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);* |7 L( j+ K/ D3 s. F' K% n4 k( q
        drv->probe = NULL;
2 y6 t1 |& w( ]- B# T- K, `+ H' @/ U+ z        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))) `7 U1 z* E. U; o7 O
                retval = -ENODEV;6 L- e8 q7 F) [' |& l3 ]! B
        drv->driver.probe = platform_drv_probe_fail;
4 j: H  z- ^% q8 \5 R        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
+ w3 W" A$ C4 s8 S8 D
) n/ G: Q" m. C3 I/ ]        if (code != retval)4 z4 V( [. _- K& B3 D6 ]
                platform_driver_unregister(drv);
+ r, S8 I" J; K& R& X        return retval;* ^& U/ ?5 D2 v- i; a; b/ r
}3 i  x& c0 ]  ?
EXPORT_SYMBOL_GPL(platform_driver_probe);  A5 w$ [( _9 Y1 O
这里的重点是platform_driver_register,由它来完成了platform驱动的注册。3 ?0 {0 ]8 B) I( h6 X# `1 I
7.3 platform_driver_register
- y; [: o+ ~# E4 Y% I& v  ?  [6 K/**
8 s" Y* J, K) u5 T3 _ * platform_driver_register
1 w9 s  ]  ^+ z" } * @drv: platform driver structure7 h3 ?+ {* K4 l7 j+ k$ a
*/
0 R: w* v' J+ U  y  a( Uint platform_driver_register(struct platform_driver *drv)( Q: E1 c6 {1 `0 N4 h5 q4 K
{# W9 q: c& F/ x/ p* s9 |, C; ~
        drv->driver.bus = &platform_bus_type;
+ N8 r( U( y/ m0 Y        if (drv->probe)
9 x& D( M3 S6 _4 ~7 a# K8 j                drv->driver.probe = platform_drv_probe;+ T1 ?1 f: M4 |' l0 q# `' a  i
        if (drv->remove)! ^5 y7 F+ y  t8 E' r
                drv->driver.remove = platform_drv_remove;
: a0 f7 R2 [- E: i        if (drv->shutdown). }5 q* q+ k* ?2 H0 r  S
                drv->driver.shutdown = platform_drv_shutdown;5 p7 V8 e# Q( X$ U7 I
        if (drv->suspend): G" k: E4 {; ]8 e
                drv->driver.suspend = platform_drv_suspend;
: k& C% E+ ^) W( K8 x  }4 q; a        if (drv->resume)
& `  ^# w. j' R3 u  Y                drv->driver.resume = platform_drv_resume;/ o. E+ v" ?  C' i! p* N) _
        return driver_register(&drv->driver); /*驱动注册*/% U7 A) {7 V* f! D" Y* E; L4 D$ T1 ~
}
7 G  L  e) F" d, d- S7 Q5 S# aEXPORT_SYMBOL_GPL(platform_driver_register);6 Z; {2 O4 M. H. E$ u

8 g; {) Y1 H( }6 [driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。* V! {  N3 ~! p
7.4 driver_register+ x, _! x. w) T, C) l1 A  S! r- n
下列代码位于drivers/base/driver.c。$ ^  d4 h, _% K- T' j
/**6 p; o- R% }% p; q" E/ d
* driver_register - register driver with bus
! Q# w8 x. I* ?; x4 w7 M* R' E * @drv: driver to register5 r: ?9 D. I1 Q/ X
*1 R2 J* ~$ _! k* [
* We pass off most of the work to the bus_add_driver() call,
) o$ I( R- W/ C6 E- V. B* C * since most of the things we have to do deal with the bus
  Q2 [7 X4 |7 Q8 Q9 n& y * structures.! |( i3 J5 d  F8 {5 V
*/  X8 s, L: Y7 a+ _- n
int driver_register(struct device_driver *drv)
) H! B# N8 Z) `( r7 j{
' j! r7 Q5 ^1 w. R. a8 d        int ret;
0 R2 _& w5 x7 ^  v/ i" N6 K+ p# c0 D        struct device_driver *other;8 t2 Q" q: B0 p* W9 Q& Y& e

2 A! {- b# J2 z- z9 e        BUG_ON(!drv->bus->p);
! k* ]! y. m$ d4 z7 d! _# d% i1 c9 j( O8 G* i9 ^) t$ N; i
        if ((drv->bus->probe && drv->probe) ||2 _+ u1 w0 }0 z: y  k
            (drv->bus->remove && drv->remove) ||
9 k7 [: \* V7 x  k            (drv->bus->shutdown && drv->shutdown))7 }" j) h! _, P
                printk(KERN_WARNING "Driver '%s' needs updating - please use "
. g- O! a8 }( Q6 M' z6 @& q+ z                        "bus_type methods\n", drv->name);
  v* b9 Z# L- L9 f4 H2 d
  S; N) E# U, A. ~" C( g8 u        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/! U* n0 Q$ b# H4 ]; ~; G0 C
        if (other) {        /*存在则报错*/9 _$ y4 J( F1 n' A+ Y+ A% n" F
                put_driver(other);
8 _8 D5 e1 z. t5 Q                printk(KERN_ERR "Error: Driver '%s' is already registered, "
) h& u. ?( t, ~$ n8 I7 ]! V( p                        "aborting...\n", drv->name);8 G) ^, `- F" {
                return -EEXIST;0 S* c. p3 o0 k  k
        }
% a9 c! F, @, p0 n1 G" t" K3 C  T4 |8 a" G% [( m
        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/
2 H, r" l2 f2 q4 R" G        if (ret). J. N4 E7 o$ G9 y
                return ret;1 R* V$ N  ]) F0 R2 {0 y, E
        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/% H3 [4 B- t/ d( q' A. @
        if (ret)
0 _* M( I  B4 R% O                bus_remove_driver(drv);
# e, O, W. ~; _0 j6 A: j        return ret;2 N+ T% Z& U. `& Z3 w  H6 ^3 J9 F
}0 ~; ^0 n/ V3 B
EXPORT_SYMBOL_GPL(driver_register);
7 B( E  d/ b; k. z+ R) X这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。+ ~2 O" s7 U, @0 x2 ]1 S
接下来就分析这两个函数。
2 g; H. z. x4 D( K" o& C# F$ I3 t1 S7.5 driver_find
7 t* b6 G  }: \4 Q% T1 }0 L: A下列代码位于drivers/base/driver.c。
0 T0 I4 i+ w' ~! c' P( G/**
% g* i  q+ C% {7 b! I; A$ r) U * driver_find - locate driver on a bus by its name.
% u( ~' A& a3 u, t * @name: name of the driver.
7 M+ _2 l7 S& f0 ?2 l  B" t$ w% ? * @bus: bus to scan for the driver./ V4 n# A/ P5 m
*8 i2 S$ q4 W. E9 {' i
* Call kset_find_obj() to iterate over list of drivers on; z9 }4 ^' x: S8 g& A
* a bus to find driver by name. Return driver if found.
! u( y1 j$ N7 J7 l) H# Z7 s, U$ _( h *+ d! ^; D1 |, u9 g* k
* Note that kset_find_obj increments driver's reference count.) `8 |, x* Y6 u* {
*/
( x7 l# u# q. a% Kstruct device_driver *driver_find(const char *name, struct bus_type *bus)3 ?& G9 o  e8 X# [2 h
{1 x7 n8 u" t- i6 |8 T
        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);; k! [( C3 Z( l0 K% T5 d
        struct driver_private *priv;4 [4 a! j# p1 J+ \! J
% d+ l. v+ \0 z
        if (k) {; t. P+ z: Q+ b) P& ?8 l! _
                priv = to_driver(k);
. ~( S% r+ H4 t' h$ o: F4 `. c                return priv->driver;( h# i% c! d2 z/ J
        }) v) p9 m5 e/ o( O/ ?: O1 ~. l
        return NULL;% C! ~# s( a  A) I
}
' E/ P6 I" [. Q; }* K, fEXPORT_SYMBOL_GPL(driver_find);
" t+ q1 W8 T$ x8 k, ]; q
8 S6 o- E7 N6 [# D" d  y- U/**, V/ K+ c, W- ]# w  |0 _
* kset_find_obj - search for object in kset.6 e; j* e8 a0 P+ B7 }! ~
* @kset: kset we're looking in./ m$ N, ~) y4 p( t: Q
* @name: object's name.
7 e) O0 x+ B  }4 A4 I" v6 N& K) W *
( J. h1 P3 H5 v * Lock kset via @kset->subsys, and iterate over @kset->list,
  w4 R, o8 F' P. N' U( T1 ? * looking for a matching kobject. If matching object is found2 s2 j+ R4 V) q
* take a reference and return the object.8 @3 u  I. y+ J* T, G0 |# B2 o
*/- S% U- x! u% F' q8 b! q0 f
struct kobject *kset_find_obj(struct kset *kset, const char *name)
% M+ y$ y6 r5 _! `7 a2 C{' q4 F, B1 y  u# u
        struct kobject *k;7 m9 ~+ y  [3 _+ o% f0 H9 [" \7 o
        struct kobject *ret = NULL;( R. J1 @7 S" O( L0 x2 n
8 o( c9 R  S! o9 X
        spin_lock(&kset->list_lock);& N2 |! A/ n. ?1 Q! H
        list_for_each_entry(k, &kset->list, entry) {
3 @$ z. l& e5 ?4 J4 x7 Z. q                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
; Q2 c" ?" j5 M; M; s" Z7 e/ t# {                        ret = kobject_get(k);
" E1 a! w2 c' _; d+ ~. _- z* h8 {                        break;
- O, U7 L4 N* h4 A5 A* K                }
) G( j8 N3 q7 U# V3 w2 L6 P# g2 n, Q        }
, h; x1 p9 l1 j+ g        spin_unlock(&kset->list_lock);
+ X; e1 s9 b( |' L1 C$ g        return ret;0 M3 ?1 \* ~$ S6 {& j2 k3 F
}
. q1 W' ~3 ~& Y; T, v* J2 F这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。
2 O7 {2 t3 f' r7.6 bus_add_driver7 o) P) H" n2 u4 z- _) n8 K
下列代码位于drivers/base/bus.c
( P, X8 ^$ T2 S6 W
" |% U9 e8 {! T" x/**% m( I4 y" v+ P3 V* S# g
* bus_add_driver - Add a driver to the bus.) e5 X- c6 X% @3 Y0 [; p
* @drv: driver.$ Y4 f5 n7 L& h7 V8 [) k
*/* N$ l! f+ d$ c/ u* C- n1 ^
int bus_add_driver(struct device_driver *drv)
7 C' W/ [5 e" k) o* ]( G1 A3 b1 }{$ E! {. g( v8 y, d
        struct bus_type *bus;
( d/ Z; L% P% y: `+ i/ p) Q( c        struct driver_private *priv;
9 v* u2 E8 U2 }9 h1 J! D        int error = 0;
8 _' [; Z: N/ [  v# O# e, S; \  w$ u: n+ P# i! O
        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/! j# t8 _  {( T% x( I1 |
        if (!bus)% {; f$ N9 v- Y7 w% |! }) _, I8 i
                return -EINVAL;9 h0 }: L5 T$ E1 p: L" e& q
( Z$ ]! J9 _5 q/ I. [, [+ ?
        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);3 j7 q0 O% R- p
+ c: a5 x# W5 A& g5 R
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/* p) K2 L  ?+ z3 J8 f# _
        if (!priv) {
( [, y: R: n; p5 o8 V9 Q                error = -ENOMEM;* G/ L2 a/ ]$ W) f* q
                goto out_put_bus;
9 p4 P  ?7 A' x, |( @        }9 J9 M! t# M( C  V9 K+ ], y
        /*初始化内核链表*/0 W8 |7 \4 x4 R+ @2 T+ j
        klist_init(&priv->klist_devices, NULL, NULL);2 d3 L, R0 c2 D, A) Q1 `7 ^& \
        /*相互保存*/, `2 O5 G7 z; `5 k, F0 x( K, L
        priv->driver = drv;+ V: G  _8 g+ h: J8 K
        drv->p = priv;* m. c: D. T9 |  j9 z6 l
        /*设置该kobj属于那个kset*/
4 O7 p5 G3 u6 J* v/ l        priv->kobj.kset = bus->p->drivers_kset;
! y7 ^1 p% X( c( N& U9 ?        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/( s1 z( z/ o5 Q1 I# ?
                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
6 U% q. V8 Q* n; A/ `        if (error)1 i7 _2 c, o+ j* M
                goto out_unregister;$ j! S- F4 R7 E  p6 A6 s7 \6 S8 ?
! H" Z- H: d, @# f, B6 k
        if (drv->bus->p->drivers_autoprobe) {
' t, p% N0 _) M* n' l3 b% \                error = driver_attach(drv);        /*尝试绑定驱动和设备*// X/ U5 l" r+ d- Z$ I
                if (error)
  B& _/ J0 @9 x) A$ @                        goto out_unregister;
1 L2 [9 E9 I& r1 m' x* \6 ]        }
# Q# m# F/ d6 [# ]        /*添加该驱动到bus的内核链表中*/
2 N! l3 Q+ w9 }( t" Q% M, e        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);0 K7 G/ T+ N# ]/ \% Q
        module_add_driver(drv->owner, drv);/*?????????*/
/ l# c' J, A! W0 \+ I' ?2 k+ |, p* Y1 g  E8 z
        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
" ], i6 `) c+ N        error = driver_create_file(drv, &driver_attr_uevent);
  I( j, U& r5 f: C9 U0 |        if (error) {
! u, v) K/ C2 V; g) A# Y0 c                printk(KERN_ERR "%s: uevent attr (%s) failed\n",/ h$ i: W2 z$ \
                        __func__, drv->name);* z% k: b- R' e# `+ B9 ^
        }3 g, d9 Q( e% y1 M
        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/
) g0 `5 X4 g! t        error = driver_add_attrs(bus, drv);9 Z8 d" p2 C$ ^7 W9 Z% k- l0 L2 m
        if (error) {# @  ?/ ]3 m, [/ ^- \4 K5 L6 N
                /* How the hell do we get out of this pickle? Give up */
7 Q7 d& ^9 \3 c! }. D; S                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
9 {7 U% H/ P( n- A9 m6 H" I                        __func__, drv->name);
' i4 D2 L. B8 R) t; k7 x  |7 y6 g        }
% Y1 e! V, A7 _, j        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/) o% C) \  X- o$ O9 x5 J
        error = add_bind_files(drv);
+ G& T/ `; Q- o0 d& \        if (error) {- ]0 w* b6 A6 Q' y: b
                /* Ditto */
% o$ a" X  K8 b* Q                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",9 K7 ?7 ?$ U# Q+ Z
                        __func__, drv->name);
& C& @$ n& B; A( N2 k        }
7 F& P6 U" m  }; R; A. {! J4 f        /*通知用户空间???*/
' Z1 |+ z0 U% ]7 ~4 t: v        kobject_uevent(&priv->kobj, KOBJ_ADD);
" T6 y9 G- |8 X' {        return 0;- s: \0 t" W  i; F  L$ R* V
out_unregister:. s5 ]: \, M( U  m
        kfree(drv->p);7 a; F* o6 ~* \. p. k4 y
        drv->p = NULL;; F% ^0 x0 Q+ k; d6 t
        kobject_put(&priv->kobj);
# H1 J6 F1 v( V0 I8 xout_put_bus:
) [5 T0 K: g" k2 y" Z        bus_put(bus);
8 O/ I% T( H8 q$ k2 L, x        return error;
( j5 `# X0 f: C1 f5 D7 L( F" W}3 i! \4 k+ r4 s: s1 [
在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。: }1 e- w4 r3 M' c4 n( L( |) a
7.6.1 kobject_init_and_add
+ A. N/ M0 h( k' }0 \下列代码位于lib/kobject.c。
7 ~( X6 T% d5 Y) M) p- u/**
8 Y. {+ O; Q; I% _2 a: ` * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
& Z$ u& z% @& C5 X * @kobj: pointer to the kobject to initialize! f& j/ g+ R" t; z
* @ktype: pointer to the ktype for this kobject.) f+ ]3 h$ V9 `1 H" A( ~
* @parent: pointer to the parent of this kobject.
; p$ k$ d& ^; N2 d$ V+ l, {6 I; b * @fmt: the name of the kobject.
  \, H% [6 m) ~! M5 @$ x *
" n0 D! k& T2 Z: S. `) R  _% Z# I * This function combines the call to kobject_init() and  w+ ~$ s, d# I: [) N4 _. C
* kobject_add().  The same type of error handling after a call to
0 @$ o  h. a8 L2 b* S6 D+ c  E * kobject_add() and kobject lifetime rules are the same here.( K& k, a4 d* K* R0 `: G& T
*/: D0 b% W$ @; H/ K
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+ D& S- l( p- i                         struct kobject *parent, const char *fmt, ...)
* G4 Y3 v; ]) X( A  t) X6 e{
3 f1 X& v! ?7 x6 u9 N        va_list args;
( J6 F* f! C  k; L. R' B: w% P        int retval;& S. `; o% k& ^6 U0 {

3 a  `) m8 }/ @3 J0 b) o0 N0 Q9 p        kobject_init(kobj, ktype);2 W( ~' ?- W" D# h8 p

0 m9 i, J2 Y; z, N$ u/ k# O& d        va_start(args, fmt);6 G; s2 i! A7 L5 Z1 o) N8 v# L
        retval = kobject_add_varg(kobj, parent, fmt, args);. e3 _  J- ]) f7 j" A$ D% |" _6 g8 x
        va_end(args);
2 h* w* Q1 Q2 y' N! Q1 b$ N" f* @: V; i" M/ F& O
        return retval;
2 q. s  O6 o. K6 e2 H: b0 h}  i; p! P( U6 M+ V1 c! l0 l$ S3 D
EXPORT_SYMBOL_GPL(kobject_init_and_add);2 q4 t% J: n8 O  D
该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。
4 j4 S4 T7 r  U调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。- V! A$ j7 L. @

( n. e' l* Q0 I( i  i我们来验证下:% `7 y% [5 A0 |$ F

" x( J" q1 K9 u4 n+ X/ O+ J[root@yj423 s3c2410-spi]#pwd
' Z# n( ~2 O2 f9 y# c/ H/sys/bus/platform/drivers/s3c2410-spi1 c: E7 B/ O6 D6 Y  h; l8 w
接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。
2 d+ d! k5 {. Z! p( I( U
; A% q+ S7 k; R+ C7.6.2 driver_attach
% Z& X% T* E. F: n, m下列代码位于drivers/base/dd.c。
' Q& e6 y: H% Z& l* `  u' `/**
2 q' c/ M- M3 T/ r * driver_attach - try to bind driver to devices.
% j! z) j4 A- c1 s1 g * @drv: driver.
9 l7 T0 `. g# ?; H$ t1 A *: W0 @5 @& ]+ R2 |( x: W' x
* Walk the list of devices that the bus has on it and try to6 B& v% U2 |( S
* match the driver with each one.  If driver_probe_device()( j; \9 ~  n5 @* U0 ~! i6 N
* returns 0 and the @dev->driver is set, we've found a6 e; c+ m! l0 ~
* compatible pair.- q  p9 C  ~6 p- \' X
*/! t3 Z* M8 {6 e; U/ H$ f
int driver_attach(struct device_driver *drv)$ F8 V3 N1 L* v9 f5 Z3 O. }% P
{
0 W8 p5 R& P6 N; B& q3 i  q) H        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);; e) s/ [( s: v) B) o7 q5 S* S
}
$ N& G& Y# j  f: w. {& {+ NEXPORT_SYMBOL_GPL(driver_attach);7 Y+ n; t) k7 p4 w: D7 O3 u
该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。5 y+ a; w2 L: X- `' h5 d9 j$ J
这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。2 v3 \* C4 ^- n* V1 P  j; J$ L4 |

. _8 A. g4 N- ~! N4 @" O8 c/**
( M8 y2 V( R$ `; S! z# O7 r * bus_for_each_dev - device iterator.
, g! k# P! m: m; [% B4 u * @bus: bus type.
+ G; J/ k1 h' F8 ^* a  j * @start: device to start iterating from.% F9 N1 M  @6 n, ~
* @data: data for the callback.  [% L7 x0 z- G! T( Z2 q/ D. y
* @fn: function to be called for each device.. J& c. u4 y* I) F
*4 h- O; X* |# k2 B, G" |4 u' L" t
* Iterate over @bus's list of devices, and call @fn for each,+ |' y% i9 x4 S" L
* passing it @data. If @start is not NULL, we use that device to
- Q  h+ m7 [7 q. M) i: b" z * begin iterating from.
2 S: E/ G+ g% Y0 Q *6 d# N  C$ l8 ?. {) L5 k
* We check the return of @fn each time. If it returns anything
, b+ r, `" Y: c) }% d9 @0 \ * other than 0, we break out and return that value.
& T! u2 w# I, L0 l9 s; V9 r *
' r$ W1 Y6 R! n. w, m * NOTE: The device that returns a non-zero value is not retained
0 ]" [( |$ b* @9 _4 S * in any way, nor is its refcount incremented. If the caller needs
/ h* }4 {1 s! \; A! @. B * to retain this data, it should do, and increment the reference$ e) s9 O$ w- r0 ^4 A8 R  ^# e& r
* count in the supplied callback.
4 B' @2 h3 K7 b2 K' d */
2 b( Q4 u+ @- R* [2 tint bus_for_each_dev(struct bus_type *bus, struct device *start,# A4 f- ~+ v* y# m, }* i2 a
                     void *data, int (*fn)(struct device *, void *))2 |" ?6 [6 `  J" P5 J( Y
{
- h' R* w6 d% J        struct klist_iter i;
) e% d, f2 T2 g4 g; Z* r- G' F4 e        struct device *dev;# E1 g* p$ |1 K6 ]- t# h0 {
        int error = 0;6 ]+ s. A9 R# S: O4 L; r

, P  L: P+ j& }1 r5 _/ g4 U        if (!bus)
  A3 }( `$ Q8 D# _7 n7 B/ S                return -EINVAL;+ H$ N1 ]6 M3 e# h9 U

+ l4 @8 a- u8 G7 D! O        klist_iter_init_node(&bus->p->klist_devices, &i,( @# n* R9 S2 x
                             (start ? &start->p->knode_bus : NULL));) W) j$ \7 W6 S( j) d* m$ Z6 v9 I8 \
        while ((dev = next_device(&i)) && !error)0 z  Z: C/ f0 J4 R' _
                error = fn(dev, data);
8 }, T" N) i2 ]* N7 j6 i( S        klist_iter_exit(&i);2 [2 l8 n, M$ m8 t3 L! Y( w
        return error;
( C7 t, j' D5 A* |4 M}# f8 J4 H* j+ S  u9 y" P
EXPORT_SYMBOL_GPL(bus_for_each_dev);; Z( y9 U7 ^( t1 M  b# P$ l
通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。7 p. J  |1 r  P) D2 I9 h- K7 n% d
static int __driver_attach(struct device *dev, void *data)# G8 A# K8 g% R( T" w  v# {
{
7 s3 `6 D+ v) d8 |& H! \2 l! Y        struct device_driver *drv = data;
7 I4 i$ D9 |3 v4 n' Q$ X
) z- R$ Y& ~* A, ~1 C# A3 c/ T7 v        /*7 q: V/ F9 X/ t( X
         * Lock device and try to bind to it. We drop the error. J, E. Y' p9 F
         * here and always return 0, because we need to keep trying
  p: M! E- J7 c         * to bind to devices and some drivers will return an error
& i5 `$ t# E- H& z4 T$ i  o/ _% I         * simply if it didn't support the device.4 ^2 J/ Z  e3 t3 D; j
         *
  @9 x4 d6 {: \         * driver_probe_device() will spit a warning if there
+ Y- p6 {: U7 r) [: ]         * is an error.! |, n% h9 I% V( X: O9 t
         */" p( a0 J; x6 S2 Q
+ A( B2 t$ m: t# ^
        if (!driver_match_device(drv, dev))
1 X3 R, Z# z& U                return 0;
5 H/ [7 A! s7 U$ F/ @  W" A7 H- B6 i: p+ Z$ ^3 v7 W& e- s
        if (dev->parent)        /* Needed for USB */
& P! Q( {  v/ @" l                down(&dev->parent->sem);, k# `' c: M6 w+ L$ d
        down(&dev->sem);
2 v" H, R) E2 D/ {9 h) d$ [3 ^        if (!dev->driver)4 N/ Q3 S) }7 @5 B
                driver_probe_device(drv, dev);
8 ]: w; z1 E* o- y/ p2 E# b% v        up(&dev->sem);4 {0 |; L( k! m. ?/ N
        if (dev->parent)4 c+ ~! l0 A# ?2 N, X/ P
                up(&dev->parent->sem);, d1 ^; g& J- x/ z
% Z2 W1 O0 w7 Y; t. a7 N
        return 0;
% n% N7 ~. w" m: M; J}
& T1 b. V8 Y2 v. V6 I9 G首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:
. Z2 ^0 L! ]1 l( N; A  {static inline int driver_match_device(struct device_driver *drv,
* u( T; `2 q% x  }                                      struct device *dev)
8 a/ E3 o2 j2 C- y; e; C{9 \. n# ]- H. e! S( y( \8 o- T7 U4 L
        return drv->bus->match ? drv->bus->match(dev, drv) : 1;+ E6 u* H, @& X# U2 V* T
}
: |) a9 X2 b. r& D  H' z
# S9 J5 @& _0 B/ X这里直接调用了platform总线的match方法,我们来看下这个方法。
' Z3 s! j( R- W/ F/**
3 |% M; u$ `7 c1 }1 g * platform_match - bind platform device to platform driver.3 ]- ^( o: U. r6 s, S
* @dev: device.
3 k! Y" u5 M" w! {. H * @drv: driver.
0 G2 U' ~, c2 J5 g2 e *
4 i" N' @& E2 o; Y1 C" N- q& Z * Platform device IDs are assumed to be encoded like this:
% \# G# p- F8 {* c * "<name><instance>", where <name> is a short description of the type of) M- Q7 M; O% Z
* device, like "pci" or "floppy", and <instance> is the enumerated3 b& m; x- ^6 p8 m! E- ]9 s
* instance of the device, like '0' or '42'.  Driver IDs are simply! t: U6 S3 M. Q7 u7 |6 A
* "<name>".  So, extract the <name> from the platform_device structure,1 d( f% x3 r, p+ e0 [
* and compare it against the name of the driver. Return whether they match& K+ z4 L- z, J( ]& n: K8 B
* or not.
* g) R$ L8 d$ F+ F+ s */1 k$ v8 \8 v! _0 q3 d: ~! G
static int platform_match(struct device *dev, struct device_driver *drv)
9 v# F7 j# ?/ b7 T# \% i{- t" }# _8 F% s0 E/ v
        struct platform_device *pdev = to_platform_device(dev);% ]( r8 f# d( b5 q. a% m- v
        struct platform_driver *pdrv = to_platform_driver(drv);1 n0 J2 ~- H9 Z: q$ l3 q

  t, ^. P- r! g1 z        /* match against the id table first */7 ]  [3 o- ]- A& `, @
        if (pdrv->id_table)& F2 K" D  O/ x% `
                return platform_match_id(pdrv->id_table, pdev) != NULL;+ j' e! q+ v7 [) Z, k1 k- j
7 o% f. s! I9 k3 p: |
        /* fall-back to driver name match */
5 t0 r8 k1 X& K1 G2 f1 n% L        return (strcmp(pdev->name, drv->name) == 0);- |1 X" F' ?0 ]' b! V9 G
}
, w& n2 s7 c7 s4 o& r该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。
9 [3 E! }4 r" R) e在本例中两者同为s3c2410-spi。因此匹配完成,返回1。* ^$ j* b3 \: L$ Y% c% }

4 U4 E8 q  p  V$ T返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:3 f  y5 V( m, i
# ?+ A- X) k7 X5 @
/**) r6 z0 F3 G8 P
* driver_probe_device - attempt to bind device & driver together
  W& D5 c( R+ S$ D) B/ L * @drv: driver to bind a device to' V1 A1 z5 k& u+ n3 o* w
* @dev: device to try to bind to the driver
9 @* W( I+ K# |# t3 C9 C *
5 g  w+ w; _* Y! Y6 q- ~ * This function returns -ENODEV if the device is not registered,+ c( D9 ~5 L% y( Z
* 1 if the device is bound sucessfully and 0 otherwise.
8 B. R2 z! U- Z/ h! R; J) e1 @ *
! e5 @, U; N8 y0 y" S( j * This function must be called with @dev->sem held.  When called for a
  Q3 w0 t1 S0 q+ `8 t * USB interface, @dev->parent->sem must be held as well.
- F' m, y& W3 }; E */; V. Q- ^8 k2 J1 l: Y1 t6 T/ s% Y
int driver_probe_device(struct device_driver *drv, struct device *dev)9 L1 M. D$ {3 w# f% }
{' J, Q/ z2 j# `0 W' A7 `8 a
        int ret = 0;
: A8 t6 w/ H* O6 a
, W# N0 s" F2 O/ ?, @+ }        if (!device_is_registered(dev))$ e! D5 O" _' t* }
                return -ENODEV;
" d: |2 Z+ H; f, E& ]  G# X! E
# p4 S  G, f) w: N- j        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
& H# ?% p6 s1 w" @8 H, _; j) M% Q                 drv->bus->name, __func__, dev_name(dev), drv->name);
- u  x9 n2 U5 n+ ^; ~, m3 v7 T) X/ @0 [# a8 h  t) D
        ret = really_probe(dev, drv);
* X3 Q# m/ f% v( C# }, Z) M+ [' V. ^$ n
        return ret;& |" Z9 t; k5 O- \. O1 N+ X; K
}, _$ M. I( m0 j; l
static inline int device_is_registered(struct device *dev)
$ x8 v% q3 O7 w{
8 z& t$ g6 y" G; }3 N7 p1 K    return dev->kobj.state_in_sysfs;
/ o# G% |* y. Q3 f8 _! B; y}
% u* |  q7 s" @+ v* `8 `0 G该函数将调用really_probe来绑定设备和它的驱动。
: t! `6 p- W, S7 u: E0 C$ Cstatic int really_probe(struct device *dev, struct device_driver *drv)* M) J- s% G2 o1 S" c
{6 D8 M& A) F! ~7 d
        int ret = 0;
5 c6 K9 P& ]5 D0 k* L1 W% m  k) q: g8 r; O9 V
        atomic_inc(&probe_count);
4 X6 Q- `2 {# G) ^, u: C( g        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
' ?' x  z) i1 @8 H5 }! _                 drv->bus->name, __func__, drv->name, dev_name(dev));
. m4 I; F) L  |* L- I6 x6 f        WARN_ON(!list_empty(&dev->devres_head));
. T% a5 P" L: f& E% ]3 `; z; G1 Q9 a) I; b" f
        dev->driver = drv;
$ M8 }4 u2 c7 I  R2 n, M6 J3 a) Y        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/
' ~3 w- M# b" W) Z& M5 l% B' J- L0 e5 V                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
! v- ~$ i& ?# e; l, f                        __func__, dev_name(dev));
% X. J! Q6 f% M  }# l- s5 O& D3 v                goto probe_failed;
, X7 C2 Y, z/ j: A! ]9 k# U: `        }
& e# Q$ _5 r0 i8 Z6 G. H9 b$ D
9 k, A& p. p% c+ ]6 O        if (dev->bus->probe) {/ Z/ x5 j$ F( u
                ret = dev->bus->probe(dev);/*调用总线的probe方法*/
+ F# Z9 ]  z. J. i) U2 _) V9 |, M1 _                if (ret)7 m4 _$ @/ q* z) n1 R1 M5 V
                        goto probe_failed;- s+ b* F* g8 ?) f% y, b1 W
        } else if (drv->probe) {+ z6 ]! I8 y0 j+ v3 T. i4 U/ l
                ret = drv->probe(dev);        /*调用驱动的probe方法*/
4 x# t" e$ b" k6 G$ d% `                if (ret)5 d8 U# ?' H+ o
                        goto probe_failed;
5 n0 J, c, `0 G8 y        }$ Y5 U/ \9 p) j+ ~* U& |" x8 K
. U! V. g9 d+ m$ m! \  `% }
        driver_bound(dev);              /*绑定设备和驱动*/4 A2 m6 Q7 B1 I. t. T
        ret = 1;; w3 [7 e5 u0 o0 l
        pr_debug("bus: '%s': %s: bound device %s to driver %s\n"," o$ Q- g" x$ `/ t
                 drv->bus->name, __func__, dev_name(dev), drv->name);
6 Z' a" [: h/ N  V        goto done;1 G, _* @; y/ a8 d( J, K

" Y! D  I, j# P, e! xprobe_failed:
, U: X# L. T6 _5 _$ u: ]        devres_release_all(dev);' D- U1 t+ S) }1 a$ U
        driver_sysfs_remove(dev);7 l0 ?$ w8 ?) a7 s. _5 X: c! o' `9 ]
        dev->driver = NULL;- q  k" l  |) D
  C7 k' S  {2 F7 W/ W& b
        if (ret != -ENODEV && ret != -ENXIO) {
$ a7 }% d, _) ], \6 J# z9 l& r                /* driver matched but the probe failed */. A: ~! F# [- Q1 q
                printk(KERN_WARNING
& U+ P2 T9 @" t: {                       "%s: probe of %s failed with error %d\n",
) h5 o! n: ~; ~- Z. p2 P- [                       drv->name, dev_name(dev), ret);
5 \4 ?1 i. \7 z" Z5 M' Y        }
8 T( d  V& \! e! H        /*6 q2 d" T' g" B4 D/ x2 {
         * Ignore errors returned by ->probe so that the next driver can try% @7 ~+ [* x3 E3 P( x2 x: l
         * its luck.; m1 n7 d9 f1 A# e; L9 ^
         */
  G/ N( r4 s# u0 f9 P( k: ^: M        ret = 0;
- f% h8 b+ A7 A1 bdone:
. `3 }7 M6 T8 ?8 I; A: Z        atomic_dec(&probe_count);. C! b6 b$ b/ S- z; f% U- }
        wake_up(&probe_waitqueue);1 y: S7 j7 w4 K; J7 t( t$ L4 b5 `
        return ret;
( a. f" V+ `3 }# h2 ]}
( y# o. L, I& O1 a3 ]2 f) B* c  a0 d/ Z
在这个函数中调用4个函数。( a8 a: T+ ^; o% v" o- B& ~/ ~
  S4 w7 ^: f+ H" A3 @
第一个函数driver_sysfs_add将更新sysfs。0 C$ B6 A3 Y3 Y5 a. a
( \6 k" b' M4 X
static int driver_sysfs_add(struct device *dev)
5 a6 J8 Y5 ]; P6 }% B+ h8 g{
& G7 K4 k2 ?6 y' o9 L+ L        int ret;
( E, k& a; A* E$ q7 @! |        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
8 x9 P6 ?- ]5 D! ?4 F% Q           链接指向/sys/devices/platform/XXX */
; w) N* a- V/ L, R        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,% q6 Z& J1 T- Z. _! w/ F. C
                          kobject_name(&dev->kobj));5 e* }' m! W- T3 x: U( M
        if (ret == 0) {
; v) F# b. j: L# J- N1 k" n% p8 x                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,4 d5 N/ t* ~8 I9 W) d0 l% ]
                  指向/sys/bus/xxx/drivers目录下的某个目录*/
8 ~) u1 W( [! [8 c' F, L( T                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
: _" E1 d4 A( U                                        "driver");
9 t" o  N$ J5 }                if (ret)0 K: V6 N* u8 m6 |6 M
                        sysfs_remove_link(&dev->driver->p->kobj,* q0 L+ B* W1 `* }6 v- `' v
                                        kobject_name(&dev->kobj));+ h, A0 b* C- d; Q
        }* \! X3 W% Q0 q$ l% C
        return ret;) |; a+ ~  x6 V6 v; U
}: P. A1 f6 }% I. o: K$ m* E2 b

- c. r& O& Z, y' x0 `执行完以后,建立了两个链接。: T3 O; _, ^) K0 v
在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0
0 u/ s+ w) ~3 R# D在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。! V2 e4 P3 |; j# j! G2 L
这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。
4 t9 }: C3 n/ S9 }
, q: x" e$ ?, X8 x[root@yj423 s3c2410-spi]#pwd
) j, l& m2 m1 ], C/sys/bus/platform/drivers/s3c2410-spi
6 M9 `/ v% R9 ~[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 ! `; b, j" R, l' |2 J
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
5 N6 `8 Q( y" U7 a# O8 E1 _[root@yj423 s3c2410-spi.0]#pwd
. F+ A. J$ }: x* n6 [. o9 z/sys/devices/platform/s3c2410-spi.09 Q) m8 d: c. T, u7 `9 B( L
[root@yj423 s3c2410-spi.0]#ll driver4 b9 J/ J  w* j: W3 L* p
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi1 {  Z9 E, Z! C' f& G- C* G9 X
6 F: b! U$ U; R- z7 C
第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。
0 O3 _7 Z' l" o% T4 o/ |* q, X$ _9 r% T) E( A+ a3 H- k
第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。6 ~2 G/ c8 k0 a2 x- k$ y
/ W) R4 @. M8 P3 X* |( Z' @! H
第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。4 R$ x# e$ z6 N$ y- R+ ]* |( @

3 V  i. L" x# O: i! I3 X4 u: lstatic void driver_bound(struct device *dev)
. _& N4 z7 @) o) [+ z/ H{
8 ]0 n3 ~- d* a4 P, t! u        if (klist_node_attached(&dev->p->knode_driver)) {
3 W6 \- O0 P- |2 }# F                printk(KERN_WARNING "%s: device %s already bound\n",
0 [, z" k$ F8 Q; u. v                        __func__, kobject_name(&dev->kobj));( u5 ^: l- {  N& ^
                return;
, G4 {! @% C4 |1 _' Z2 t        }
: ]: _/ z" o$ e! S
  e! g2 Z- |0 K+ y! n; Y, ]        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
6 I, T* |! M. p3 {                 __func__, dev->driver->name);
* Z' _2 y' |0 y: {) `8 z  X  f+ v% Y
        if (dev->bus)
) i8 u) R$ Q9 S3 E' p- ?1 n1 K4 W                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
- s6 u! N) O/ W4 i$ B$ @- a% e                                             BUS_NOTIFY_BOUND_DRIVER, dev);
' m" R" ~' A% B% y$ @
) Q* o# G" a0 |        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);8 O0 y1 A1 U8 n  D; C5 O
}
, n! S, p* u! {5 f. Y# @: k其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。. u; j7 S: a3 D" X7 |
至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。
' R- m% ~2 J8 g  ?4 F% |- U3 \$ K; u7 X# `
在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。# c9 U( W1 R- Q
7 T6 F+ G# X; V% N! o
首先,将驱动添加到总线的驱动列表中。
+ W! O2 g3 f! \# P, C9 m接着,如果定义了驱动属性文件,则创建。
# }- L, h9 l) D1 Y1 n& V最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。
0 m& y" P+ k5 u, S# T. x) x  T7 k$ p" p5 ?4 ]' O9 K  t' P6 q0 o
我们来验证下:
" u3 E7 m: G* i7 T) |! }2 E$ C1 ^" m0 _3 I
[root@yj423 s3c2410-spi]#pwd
* d4 I6 y" Q3 U8 i! S/sys/bus/platform/drivers/s3c2410-spi, ?) P# w( [7 [0 [. J% s+ j
[root@yj423 s3c2410-spi]#ls0 j! T2 H7 I! k" m! B
bind           s3c2410-spi.0  uevent         unbind  P* Z1 m" n3 \$ Y9 H, B( L- W
7.7 小结
# e# i' W' K, a9 y# i在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。
2 v9 c* z# k3 C
$ F2 n- b. I# T2 U5 h2 }/ }同时,还更新了链表的指向,在内核中体现了同样的关系。
! z7 F1 C& L/ c( r
$ ~  C1 V7 \( g6 V. E$ D9 _最后以platform driver的注册过程结束本章。) B/ ]) E1 ?5 ]6 k! `

. i# K: C1 {5 y$ _
. r# R. ~! W. n' w# U. p9 a0 G* X. O1 O) m' j4 O( X. ?3 N/ `! K
8. sysfs底层函数% F( m  N1 T0 @: w
下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。/ @4 y: X) Y' Z6 T. g  _. w) Q
在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。
: l2 f, U( [' s$ P3 |& n1 O# J0 B4 T
8.1 注册sysfs文件系统
& M8 d" s5 @! C; gsysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。) G$ D: f+ |+ ^7 e% e% G
start_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。8 v6 Z3 n1 q, f, h. [
1 o9 w" r- @( x7 u
int __init sysfs_init(void)
; |4 N* j( \% n' i$ J6 @2 e6 D{$ O  {: S7 T7 C5 C2 w; s
        int err = -ENOMEM;
5 g, C# b& G. d9 I: ~        /*建立cache,名字为sysfs_dir_cache*/
1 D( B  N5 V4 [        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",$ k3 C0 z7 A, G+ }& ]2 X& y
                                              sizeof(struct sysfs_dirent),3 T; I; }4 O7 @' ^# M5 B1 U
                                              0, 0, NULL);, ~! U' E0 T' l. e5 _; @3 `9 d
        if (!sysfs_dir_cachep)2 T$ N7 U' p( F/ D, O: T, ^/ v" K
                goto out;7 F7 R1 T( e3 W% c* W$ c/ h
2 \& a/ X+ @- A! r% O) M) V
        err = sysfs_inode_init();
2 J2 b4 f9 e) [4 L8 z' q8 W        if (err)
8 b0 T8 ?! \" p: t6 Q                goto out_err;, h( u1 C# T( c5 Z
        /*注册文件系统*/
" p+ T$ n3 `# g1 |8 e" C        err = register_filesystem(&sysfs_fs_type);$ y* v( i  d+ w% ?3 I' \
        if (!err) {* i: R. e3 u: ?& Z+ t1 }2 t# b
                /*注册成功,加载文件系统*// D, c) W# N' `3 c% P! b
                sysfs_mount = kern_mount(&sysfs_fs_type);
' }$ E& a* l" v$ P, K; l                if (IS_ERR(sysfs_mount)) {% y1 ?- T* u' W: d1 s% ^3 Q* n9 y
                        printk(KERN_ERR "sysfs: could not mount!\n");& p! i2 u2 Z! Q- C; }$ m. m
                        err = PTR_ERR(sysfs_mount);& N) t7 P9 N# m. u4 Q0 k
                        sysfs_mount = NULL;6 h- E: U  Y8 w( o& O
                        unregister_filesystem(&sysfs_fs_type);
7 `# s& j9 Q! N% p                        goto out_err;) m+ @) o! i% V4 h: h
                }0 o$ A$ C( o; _
        } else
8 D% U3 H5 h6 q: Y( P0 F1 h                goto out_err;' o1 o4 Q. o  m$ D. X! G8 w
out:
/ }7 @( N' u1 v3 w+ ], }, I        return err;: Q& _8 p6 m) V! K$ n
out_err:
! t  i0 H9 ]2 t7 U4 e& H, L1 I, R        kmem_cache_destroy(sysfs_dir_cachep);' ?+ W1 K3 w" j# p4 y% j$ P% y
        sysfs_dir_cachep = NULL;
0 Z" ~. r8 V2 Z2 K9 e) _+ a/ X% p( |0 v        goto out;
; b2 Z! H3 m7 O# i4 b}" {1 A7 Y- ?; T' V8 v  K
# n8 {$ @  s, I
static struct file_system_type sysfs_fs_type = {  b1 v5 D6 s' P$ |( O
    .name        = "sysfs",
* d/ V' t5 W0 e( `" n    .get_sb        = sysfs_get_sb,6 M, M- ?" |9 f' D* Y  D7 r; ~6 a$ V5 q
    .kill_sb    = kill_anon_super,
% \$ i! y, S- e' L6 q0 ?9 D};
( ], j, N* e7 `3 O: ^4 _& F1 w% F& u9 V5 d
8.1.1 register_filesystem
$ L0 |! x1 T1 p2 W# C* {# A2 m下列代码位于fs/filesystems.c。
: R* s) `7 F  z7 f/**
+ j* I) o3 {; H4 O. s0 e0 x+ S *        register_filesystem - register a new filesystem
% n! K% ?9 p1 l* _; F7 g/ a *        @fs: the file system structure/ Z5 a' ?1 q2 s6 W% l! [
*2 n# L6 n* u, k' }" {0 j
*        Adds the file system passed to the list of file systems the kernel, T& M4 w9 H) g+ y4 _! A" y
*        is aware of for mount and other syscalls. Returns 0 on success,
' g! M8 k( z$ U+ }1 r *        or a negative errno code on an error.
. v9 P9 ?5 D; p; o *
% E: f3 ^- z) [2 y% J* c: L) Q" i- Q1 ] *        The &struct file_system_type that is passed is linked into the kernel 4 Z$ n  }( b2 ?- D
*        structures and must not be freed until the file system has been. S5 F) ^' Z6 w, T6 a/ Q; V
*        unregistered.
2 c% O9 x  N# a */
7 d& \3 d$ a: _# }; E& e+ x% g- p
! \, X+ w" s0 I4 W3 |int register_filesystem(struct file_system_type * fs)
- L3 c$ H4 _$ A" D. T9 R{: h7 x6 z# @% B& G( F0 q
        int res = 0;
: Y5 ~& v* b6 g3 |  H        struct file_system_type ** p;
% K" C' S# Q: \( q* b7 h0 F
5 s/ G" P% @' d4 j, T  ?        BUG_ON(strchr(fs->name, '.'));2 ~% B: A* G& r4 [, C
        if (fs->next)
+ s9 O" h, g  d& y4 I7 @% ?                return -EBUSY;
- L, e7 w) g+ i' J8 T. e        INIT_LIST_HEAD(&fs->fs_supers);, B% d' X/ p3 V& j
        write_lock(&file_systems_lock);
+ X" Z5 A$ z+ k  v8 L; m        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/7 o5 R( M2 F, K* y2 n* U2 b
        if (*p)4 |3 T7 X& \8 b) ~" }
                res = -EBUSY;        /*该文件系统已存在,返回error*/
1 ^  q, ?0 `& E: e9 O# [        else
+ o/ a" u, ]' V' G% ?( ]6 w0 N3 M                *p = fs;                /*将新的文件系统加入到链表中*/9 K1 Y6 [$ B% [0 ~! P' |
        write_unlock(&file_systems_lock);
' e0 R& V8 }; {8 W! i0 |! b        return res;* K1 w8 d, b. Q& e
}
# O5 A0 g- P6 _: H) F' o$ b# d% Xstatic struct file_system_type **find_filesystem(const char *name, unsigned len)  z% W1 e9 ~2 x6 g8 s5 N
{' M. ?0 Z! ?  D% V, h: J# k* _" Q
        struct file_system_type **p;
1 q9 v' p8 t+ u  y4 ^7 h        for (p=&file_systems; *p; p=&(*p)->next)( l4 L* ^& ]9 Z) c: Y
                if (strlen((*p)->name) == len &&
1 W2 U5 [9 p5 W* D& h2 r                    strncmp((*p)->name, name, len) == 0)
4 v, ~& t" Y: ?! Z4 ~9 @* E                        break;
# ?- I* L; m  Y9 q0 P' d! o        return p;
6 x- r8 x, y2 i  X2 G3 k8 {5 O- ~" }}
/ U7 t/ }: k6 K8 Y' J+ V该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。
+ c4 @" U1 p) N3 i如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
+ x1 R* a$ E  g* V% Q, p. t6 O  N+ Y8 u7 T1 U' p  @! j2 P
该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。! S9 `0 p( p5 u; O- g3 T1 J
7 d/ O. }; o0 z9 |
8.1.2 kern_mount函数* X: x' t' i/ x& h+ r" i7 e
下列代码位于include/linux/fs.h( _+ z, ^6 N! ]: i4 ]( f$ s" M
) U2 C/ x% Z( ^  ]- z
#define kern_mount(type) kern_mount_data(type, NULL)+ [" k4 Q: g2 w- v( Y2 b
下列代码位于fs/sysfs/mount.c8 x% O. S$ q  I- B! Y
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)( i2 i+ h6 u/ Y/ h% S1 }- t
{; Q9 ]% w$ Q* J; ~7 [& B
    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);8 N4 }7 }* d# Y7 \- E0 [
}& T( E6 \, O7 ~: c

- J, T7 |$ {( L% \2 c; t6 ~* u1 ]EXPORT_SYMBOL_GPL(kern_mount_data);
. _7 F2 j  z2 akern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:
8 g. |, C) l0 c
, `9 n* g& v, a4 a7 F$ c+ fstruct vfsmount *: e+ x, d+ _7 G
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)5 K! n$ o8 s% B: d/ z4 b( x* M
{) V( W9 _: w6 ~8 ^0 x( k' h
        struct vfsmount *mnt;
4 [/ f# i& ?6 C. d        char *secdata = NULL;9 f6 b2 k: j7 F; K% z" h. v
        int error;5 _3 |: m7 }& P  c7 j1 Y
  P/ b& F" B" t8 R" D$ _# |
        if (!type)
4 B7 U; w* v8 O                return ERR_PTR(-ENODEV);& N& Y6 S7 F* l" B& ]

) v- k7 ~5 b: ?' A$ B        error = -ENOMEM;% C, M! u; M; ~) t9 `5 s
        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/
) E& }" c6 G$ R# x% M8 V" d        if (!mnt)
. b7 c( k9 o+ P7 ^/ ~% Q6 ~3 ^                goto out;; k0 {9 D! j( e7 \; {( D
5 l6 ^* z( X. k7 Q4 J/ z
        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {7 O  D2 {! u5 T! P% c$ {9 I
                secdata = alloc_secdata();- {3 I( s* Z. g3 ]8 p/ x
                if (!secdata)7 f' o1 v3 J3 n, V
                        goto out_mnt;5 E9 X# W  v( o- i0 L5 k

' H+ O& Z6 t6 j                error = security_sb_copy_data(data, secdata);
3 U- m: l; k0 ?" |9 L- e& H                if (error)
% y; P$ {: a4 a: p& f9 Y0 F                        goto out_free_secdata;
  H0 L$ G, G, w        }3 U' J" E: |( m2 w7 E, S  L4 [
        /*get_sb方法,分配superblock对象,并初始化*/$ s/ [: h3 p+ u0 r+ U( w# B
        error = type->get_sb(type, flags, name, data, mnt);
* V  S) K, W9 {' R  Q4 L        if (error < 0), p9 s$ w8 }" n& R
                goto out_free_secdata;4 |3 E. v& K6 L
        BUG_ON(!mnt->mnt_sb);: Q7 ~  J8 |5 L) U2 O5 W3 v. }6 I

) v% i/ u3 d7 Y5 z3 J3 `% c         error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);% e2 @( R, U$ [# H% I" i! k# l8 b$ w; d
        if (error)
/ U- H2 y6 C2 z8 b5 d  R5 A- Q5 m                 goto out_sb;
! t  p8 b9 e3 [8 a
) g! z) q$ [  {8 P        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/
7 W% d+ `* }! X7 _0 ^        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/- Q. L# B) F2 {  }4 m3 d( n; C! a$ X
        up_write(&mnt->mnt_sb->s_umount);
) \8 a0 ^* L2 ~6 X6 N" B# ^        free_secdata(secdata);/ c7 d) G3 I  K6 e! d
        return mnt;  K1 r7 Y% o; ?  V  U: f
out_sb:" k2 `0 W5 b) x. w2 m: Q
        dput(mnt->mnt_root);0 S$ a. `) V2 h/ _; T$ P0 I
        deactivate_locked_super(mnt->mnt_sb);
3 Y7 r5 D' i3 J, Bout_free_secdata:
3 {' k+ T5 u- w# |# n9 `: m2 {        free_secdata(secdata);% K6 Z8 @' p5 G: Z$ ^. m
out_mnt:
. m. X/ o3 A2 [. O3 t" X        free_vfsmnt(mnt);
& q& |- q6 @7 Iout:; X3 q; I- I6 X$ N) q, ]
        return ERR_PTR(error);! n  I, }& Z& R5 q* s/ _
}) a. E$ U+ O, L( y; S1 G
! F7 v. l: a# C" ^
该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。' R" F. r' q% r, ?
下列函数位于fs/super.c) Q* d8 x+ v& A  y. {0 r
struct vfsmount *alloc_vfsmnt(const char *name). V; Q! S9 C' O; z
{
/ t# O! q0 Z7 k' T        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);1 V7 k. ^- P; A, P# {+ D% H: R
        if (mnt) {% T6 u6 i  ]) n
                int err;
4 B6 \* h8 M( r% f+ C4 Z
3 C4 L, X6 G) A$ n; L                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/0 m1 @% V- @; }# g$ x
                if (err)+ i1 ]* d/ J" D9 x$ n3 R5 u. m2 ^
                        goto out_free_cache;7 V# V! {0 C+ k( A( v$ ^# p
' H2 `" t& Q  N/ f
                if (name) {
& Q: [% K+ J9 W) ^8 F! T3 E7 @                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
, @; {2 C' [2 P$ d2 v                        if (!mnt->mnt_devname)- b8 j' ]9 k6 d- I) j: B
                                goto out_free_id;) f: w1 u1 N) C! z+ l) T
                }
; r- s! V5 w1 e' \. [: j+ X4 B* G6 H5 k# y2 Q1 Z
                atomic_set(&mnt->mnt_count, 1);
, j/ r) N& `; K8 D8 f9 r$ n' G                INIT_LIST_HEAD(&mnt->mnt_hash);
. L3 W0 c/ P( O3 Q0 j                INIT_LIST_HEAD(&mnt->mnt_child);* ]& G2 H+ K) R# c. }. @
                INIT_LIST_HEAD(&mnt->mnt_mounts);7 C' l+ A  K! P1 b
                INIT_LIST_HEAD(&mnt->mnt_list);
3 y7 E# k$ M8 n8 {. J9 X                INIT_LIST_HEAD(&mnt->mnt_expire);! V+ C2 D0 r1 b. T4 }
                INIT_LIST_HEAD(&mnt->mnt_share);4 ?6 ^3 V3 C8 S$ R  G( g5 K# H
                INIT_LIST_HEAD(&mnt->mnt_slave_list);
! }. f7 P( e1 K6 G; V                INIT_LIST_HEAD(&mnt->mnt_slave);8 `: Z  M. G+ f* q1 M# Y* {/ M
                atomic_set(&mnt->__mnt_writers, 0);
: W3 h; M' d3 w/ Z* A4 @        }3 Z$ a4 N& w. l* y
        return mnt;
% }3 `8 x: S& d$ E3 |* D
  q: f. C( _4 g3 m5 v3 @8 ^out_free_id:
, e! f! ~5 }, r' Q7 ~' e        mnt_free_id(mnt);2 {6 ~$ `4 T: {1 M( m$ D
out_free_cache:! O* _/ T. w1 r& G
        kmem_cache_free(mnt_cache, mnt);' u# l0 n; ~2 j6 @
        return NULL;. z+ S" T3 U) z4 X; K9 X
}2 M5 r& j' h$ P1 e' R" v
分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:2 V" @9 y0 l4 `1 `' F& f8 N
下列函数位于fs/sysfs/mount.c。
' H: b! m: f2 i4 O+ [static int sysfs_get_sb(struct file_system_type *fs_type,5 C& E; l7 f: }) T( F% q/ O: ?* w
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)$ r2 ~- J, {% }6 T
{
  s4 G  `" Y; _# q        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);/ b+ B0 B/ F, V: ?) ?
}. r& ?. ?! o8 N% _) k; n
这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。
# n2 b( Y0 b' J; U* g- J该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。
" X9 R& T$ V# L1 d9 W, [9 d% S4 M* V; ]8 N3 r0 r
该函数的执行过程相当复杂,在下一节单独讲述。
. {3 l& r2 l4 s+ T% J; p0 l8 q' u7 G) X4 E" y9 f
8.2 get_sb_single函数
. _9 L1 {: X7 o: ^3 [4 W下列函数位于fs/sysfs/mount.c。, e+ [; t6 M$ L! `

* R* r3 B) _0 p0 qint get_sb_single(struct file_system_type *fs_type,- l# ~  `' m' H* K7 u, z" B
        int flags, void *data,! w4 _- K; A) d1 Y# r
        int (*fill_super)(struct super_block *, void *, int),
3 Q" V: J3 i+ o1 ?* p2 X        struct vfsmount *mnt)
! j8 W+ c; a' V  s! h/ U{+ f0 @) a  B7 e9 K5 k1 u  w' ]6 o
        struct super_block *s;
8 O" c9 z+ @' a( ?2 B9 l% N, y        int error;$ \5 w! Z) i- a* ]0 |* C9 u; T
        /*查找或者创建super_block*/! y( P* H& e% ?
        s = sget(fs_type, compare_single, set_anon_super, NULL);  t% h: d. b, q- s1 v/ @
        if (IS_ERR(s)): K  ?$ w, j% E% L# W
                return PTR_ERR(s);
1 n% Z2 k. W1 S2 r( e$ c6 I- h+ K        if (!s->s_root) {                /*没有根目录dentry*/
. ^% w% e8 G$ O                s->s_flags = flags;
# e. b1 ~5 f0 C% g                /*获取root( / )的 inode和dentry*/- g' X$ E" [" [- H$ e3 ]
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);0 z! F, M2 b9 {$ O7 z! G
                if (error) {' ]5 C6 Z' M+ S( r
                        deactivate_locked_super(s);/ y/ F& e/ y8 @
                        return error;
6 \  T9 V5 b6 L: E: G1 b                }
" Y- K( F+ `) |! b3 n$ V                s->s_flags |= MS_ACTIVE;
2 C/ M: e3 z9 Z2 p" ~+ `. h, q( D        }+ R  ?1 N! s8 k4 J' v
        do_remount_sb(s, flags, data, 0);& o$ K2 d7 H" d" H' V) c
        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/4 y* I+ \( B7 i/ J
        return 0;
4 v. m$ i* @+ b. M}
$ c! o# b+ s% D1 j% B3 o/ _7 F
$ c8 a2 ^. D7 c( d3 ~% HEXPORT_SYMBOL(get_sb_single);
# [7 c6 n8 x3 W- y& x8.2.1 sget函数
% s: f9 `3 \; R首先调用了sget函数来查找是否
5 G1 z3 Y& R  `" E5 b下列函数位于fs/super.c。1 x1 V' ~' g% d6 I2 {3 [
/**2 b: l/ b' M& `* f1 h
*        sget        -        find or create a superblock4 J; Z( I8 w7 w* X! Q' B; o* ^
*        @type:        filesystem type superblock should belong to
! Q0 J/ V* B% F4 D' G1 B *        @test:        comparison callback
. ^* o0 C5 g! y8 k4 P *        @set:        setup callback
0 X! L4 n4 L; @/ D' F' Q$ {% _ *        @data:        argument to each of them
8 [* a0 c6 I3 b5 q2 F */
+ W. d5 N) z/ Pstruct super_block *sget(struct file_system_type *type,. m; w, g5 ~/ T7 r9 p- t/ ?
                        int (*test)(struct super_block *,void *),7 u( n+ W) R; G3 p. y
                        int (*set)(struct super_block *,void *),
/ C4 W# r( d* D) D/ Y( l' a                        void *data)' q0 Y( V& Z( `+ J8 s
{
" U8 @6 j3 s, ?- V        struct super_block *s = NULL;
3 a% E8 I) U( D1 V        struct super_block *old;; _! a2 b/ v0 s6 ]. l. y; Y7 P
        int err;( j# y% ], t/ n8 C

6 W1 ?( P& Q( ?7 }' Hretry:
" F( A9 g) S' @3 B$ L( [6 L  \( o6 h        spin_lock(&sb_lock);
8 G+ _0 h- f! @        if (test) {                       
3 n, V1 A3 M" W* J  [# b; J                /*遍历所有属于该文件系统的super_block*/) v0 j% Q/ `* {
                list_for_each_entry(old, &type->fs_supers, s_instances) {8 Z% i# l2 c7 U1 y; y/ Y9 J
                        if (!test(old, data))
# a9 `, u& C, U& h$ w                                continue;
8 @+ n& i7 l7 I/ i                        if (!grab_super(old))' i/ [5 D4 d8 u. L- h
                                goto retry;
) o# `$ I* }4 `7 d2 V9 L                        if (s) {
; g8 f9 N- }! E3 o! P                                up_write(&s->s_umount);
$ l4 H- ~, i) }5 P& S" b; p                                destroy_super(s);- r5 i9 Q# ^. D2 C  D. o& y4 L
                        }# B3 c+ ~. @% g: b% u) W
                        return old;
9 k3 _, W6 d5 i, _                }
, T4 }9 F4 i+ Q# U* }$ [        }) T& ~! B+ B: h. k
        if (!s) {
3 b+ W# b$ a- C, f" D! e9 [7 @                spin_unlock(&sb_lock);0 U. S( D- P3 H4 U
                s = alloc_super(type);        /*创建新的super_block并初始化*/& D* R0 J3 z9 P9 X# w
                if (!s)
7 w* N  o9 u% F* E; O                        return ERR_PTR(-ENOMEM);  k) ~# r( M8 ?4 _- {
                goto retry;, b( M- t+ t+ q7 x, b( a' U. g
        }" h0 u1 ^& l9 M) K/ l8 `  p# ^6 _
                $ R+ E% @& a0 F" |
        err = set(s, data);                /*设置s->s_dev */
# @/ |9 J6 Q, N8 t/ g. P4 p& K        if (err) {1 A4 v% v+ K% f' w' U
                spin_unlock(&sb_lock);
7 g  s* I, B  R: q                up_write(&s->s_umount);
% q1 Y' N9 |/ `4 `! D/ ?1 b                destroy_super(s);
- ^4 q4 F% l# ~                return ERR_PTR(err);
/ ^: R4 Y$ M) f        }" p+ Q: P; {  }& I3 s; Y  X6 s
        s->s_type = type;
: m/ |! r% g* A        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/
9 `' J+ @# `4 Y  j# F        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/' O3 M) \( i# Z1 \) `
        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/
8 ]2 i- z! f/ _9 v8 t/ X! E1 Q        spin_unlock(&sb_lock);
2 @1 }( l. @9 n3 ?" }' s4 ]        get_filesystem(type);6 e% [0 d2 {5 y/ ~4 ?$ G0 ^0 B( g
        return s;
5 C1 c3 J/ o" d}3 d0 o( H. U: [) N! R: R
% h5 R5 z2 }% w! S
EXPORT_SYMBOL(sget);
# _8 T: ~# ]0 S- p) ~& g该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。* `0 c6 t+ s/ @$ x- O/ d
然后调用alloc_super函数来创建新的struct super_block。: ~  V  |& w& Z9 w
+ O3 |. b0 I5 i, [
下列函数位于fs/super.c。7 R# I$ A6 Y7 u" ?, n* j  E
/**
6 z# i7 [: O! ?; Y5 h *        alloc_super        -        create new superblock" i7 t' }4 t# H* C6 {% o) ]
*        @type:        filesystem type superblock should belong to# D# r* ^1 g  e' h% [3 g
** i" x2 g. N( a
*        Allocates and initializes a new &struct super_block.  alloc_super()3 s- v, F: n7 v$ p+ z% q! L
*        returns a pointer new superblock or %NULL if allocation had failed.3 P4 f( e* k! i1 E
*/
# A( f. ]) B7 _, [' j7 Astatic struct super_block *alloc_super(struct file_system_type *type)3 q, v  c" |  I
{+ e, o6 ?4 h* b! W7 O% c) H
        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/0 U  O0 \4 _# P* f
        static struct super_operations default_op;9 u, q; G0 m( y: X4 w( Z

, S, G4 F8 J$ @        if (s) {
  _2 V' j  D) ]                if (security_sb_alloc(s)) {
7 i1 |9 a7 \6 p                        kfree(s);. X8 ^3 Q2 f) m8 I# Z3 M
                        s = NULL;
7 r. n& x" \  j3 o                        goto out;
6 r8 I0 S2 k$ {* }                }% t; ~9 e- b1 X4 K$ w+ A# ?" W
                INIT_LIST_HEAD(&s->s_dirty);. [! F6 M+ ?6 [5 V
                INIT_LIST_HEAD(&s->s_io);8 e: E5 B* e9 F- I
                INIT_LIST_HEAD(&s->s_more_io);
9 P  m' |) V! o                INIT_LIST_HEAD(&s->s_files);+ J4 x* Y" e, ]4 O% v
                INIT_LIST_HEAD(&s->s_instances);" E1 X  F% l3 n
                INIT_HLIST_HEAD(&s->s_anon);
9 v% z6 L; D7 [* H) p9 v& \$ J+ k, F                INIT_LIST_HEAD(&s->s_inodes);+ h7 S* O8 ]+ ]3 [, ]
                INIT_LIST_HEAD(&s->s_dentry_lru);. U3 C& N& o$ m2 a$ ?/ L2 u
                INIT_LIST_HEAD(&s->s_async_list);4 v8 E- k" I3 K# G' V
                init_rwsem(&s->s_umount);
% X' W/ G1 O. p9 Z                mutex_init(&s->s_lock);
5 i) w7 r' }' ?  w8 L                lockdep_set_class(&s->s_umount, &type->s_umount_key);
! o! o. E* q3 |9 n/ {$ s                /*
. b2 k# @' |9 E0 L3 n5 k) `8 e' ]7 g                 * The locking rules for s_lock are up to the7 f3 b; [6 b4 b
                 * filesystem. For example ext3fs has different
6 r0 I9 a# C2 Y4 C) a3 H9 e0 Q                 * lock ordering than usbfs:; r1 e: |4 h4 U1 \  |/ i; `0 q
                 */$ ^1 o/ z) J! o2 z# }% [, o
                lockdep_set_class(&s->s_lock, &type->s_lock_key);  Y9 P! s5 J" [% L+ W$ ^
                /*% N+ `0 k1 _+ g) J: r0 f- K4 [: R
                 * sget() can have s_umount recursion.( D( _6 P" u3 u5 q) D3 a
                 *
# C3 A. V) e, d7 E% [. @                 * When it cannot find a suitable sb, it allocates a new
. Z' a8 j  Q. U9 _. f                 * one (this one), and tries again to find a suitable old
4 {: k- G  c: n                 * one.  O6 ~. N, X7 Q
                 *
4 i/ k# k0 m/ R& h. |  O, ^                 * In case that succeeds, it will acquire the s_umount
/ n$ o( J: ?# O" y$ ^4 U                 * lock of the old one. Since these are clearly distrinct5 S" K  y- n2 b* T- I
                 * locks, and this object isn't exposed yet, there's no" M& u2 q, g$ u, i
                 * risk of deadlocks.: c% m6 A9 ]# q
                 *
: K! L' v( Q! K8 A                 * Annotate this by putting this lock in a different
1 h) W; N" t0 F, f  y                 * subclass.0 I+ }2 r2 D3 L( w
                 */8 l& R# G, k- d. Z& n9 _6 p# L
                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);# p  ~8 ?! o5 d3 i  i. A
                s->s_count = S_BIAS;1 T& H9 t: X4 B8 Z5 W% M4 z7 w
                atomic_set(&s->s_active, 1);
  [' H" O9 T. j1 a- b9 e" S3 D                mutex_init(&s->s_vfs_rename_mutex);
. N! W' B! m( m5 m0 N                mutex_init(&s->s_dquot.dqio_mutex);
8 _" V6 Q( G2 z9 p2 a                mutex_init(&s->s_dquot.dqonoff_mutex);3 w3 @, ^/ c8 K
                init_rwsem(&s->s_dquot.dqptr_sem);+ R* i# l5 Z9 b" Z. h
                init_waitqueue_head(&s->s_wait_unfrozen);
! |8 s% D0 R+ k6 K% y9 ]                s->s_maxbytes = MAX_NON_LFS;
1 d' ^4 X" f6 M+ w+ g8 a                s->dq_op = sb_dquot_ops;
' Z3 H5 U1 y* P/ V# f$ F4 J4 W% G4 [. g                s->s_qcop = sb_quotactl_ops;  ], l. _5 V+ w6 T
                s->s_op = &default_op;4 g3 O" B/ ?& H, \- z* |
                s->s_time_gran = 1000000000;
, k/ _$ h$ V* F3 h& D        }
* g9 x6 m+ f1 ?( w1 v; Zout:
4 t& v" X, A! d( k# d. n* O5 A        return s;
8 y6 l# ]# B. H}! r4 Z; i3 H' A. l8 W. [/ D" j: r* e
分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。, A/ V+ f  T, l
下列函数位于fs/super.c。
0 ?' b* R4 a* B  \& f6 M( e5 j7 Iint set_anon_super(struct super_block *s, void *data)9 ?. y+ D' |3 n( n9 t
{
- E1 [# k3 D1 }5 }, _$ \+ ~7 f        int dev;
# p4 }1 y' K% `2 {7 P9 J+ ~7 z        int error;
: [' \& B6 y: B; p& h& f1 l) ~: B. \2 b
retry:: @6 [- H; |* t1 _7 v) K/ I( q
        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/
/ c. c2 B0 D7 n0 G9 R                return -ENOMEM;
( k4 R$ K' ~- q) |- K        spin_lock(&unnamed_dev_lock);
! D7 q* l6 R: e, w! q        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/7 V. c1 P/ Q) @7 y7 `' b
        spin_unlock(&unnamed_dev_lock);
* \( \( M/ n: V        if (error == -EAGAIN)
& j1 n0 M; i: H, G* z" F                /* We raced and lost with another CPU. */4 D3 C* x: g! \
                goto retry;2 C* S/ O; [: B% m
        else if (error)/ D" f" z; O3 e& x' J' F; k& Z  F
                return -EAGAIN;
0 Q7 y4 j+ Z! `( l# Z* x
) S" I( ^  d0 y" G3 H( I+ Y2 D        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {$ _' d3 U3 T8 M, W2 o
                spin_lock(&unnamed_dev_lock);: K4 E  g& |% p8 l
                ida_remove(&unnamed_dev_ida, dev);
& F: B' C! A! C( k: \# ~9 g                spin_unlock(&unnamed_dev_lock);$ Z4 ?* ^4 Z$ I$ e+ |$ B/ `& }
                return -EMFILE;
5 M8 N- O) G5 l8 H8 ^        }9 g! D$ V0 ^1 i
        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/9 H( D7 @3 Y, h! @2 r* M7 p
        return 0;  s. V, u3 y" I- y* j( I; R; D0 u
}
) ]) o6 Z' A1 P" r- B+ }8 v0 c  N8.2.2  sysfs_fill_super函数
8 m0 t1 k! E8 f/ h, q: N9 S分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。
( j& v& H' r/ I
5 ~7 w0 R" P4 }" Y) S0 E  x下列函数位于fs/sysfs/mount.c。
5 h! x2 W( o/ L( }( cstruct super_block * sysfs_sb = NULL;- B& [$ x) z* {

  ]; }! |! D) _2 @static int sysfs_fill_super(struct super_block *sb, void *data, int silent)( S0 P; M  T9 v
{
8 I2 Q# W  j0 s, W; v        struct inode *inode;& K5 ?8 v" E; S5 G$ Q
        struct dentry *root;
: z+ q9 s; C9 L( |! S' |( d
# q2 q, o  k$ l        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/
4 c. Q% J! N7 k3 f* l4 \6 J$ t        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
9 k$ h0 I0 Y$ B. w* G2 p) }; I        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/
* C( P0 r) W, t6 P        sb->s_op = &sysfs_ops;
& ?0 T: ~' L* R1 R+ {9 M& H        sb->s_time_gran = 1;7 n8 Z, o. ^6 E' d( U
        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/
! s* v. c: Z: d/ @. L; n- P: N, p
        /* get root inode, initialize and unlock it */
6 t  C. i6 `- r! ?; R4 Q4 m        mutex_lock(&sysfs_mutex);
, K' Z: |, |  y4 [: K        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/                " c& \6 g0 \1 ]! S7 d
        mutex_unlock(&sysfs_mutex);$ Z  J( o% t  N  [  Z3 X
        if (!inode) {: f0 I: {* Q; }/ @2 s
                pr_debug("sysfs: could not get root inode\n");
8 P% `/ @1 y5 T7 V3 A9 y2 y                return -ENOMEM;
2 k4 l) V5 L5 d% O: l7 M        }
+ j' l% x" ^) C' i1 y
* G) X! A  F1 \3 {2 y        /* instantiate and link root dentry */9 _+ c$ G+ f2 t" y
        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/# m7 q& k- i6 m# G
        if (!root) {
" U& K8 [, y- C. W& L                pr_debug("%s: could not get root dentry!\n",__func__);
, X9 F) P/ I; L5 r/ [: e                iput(inode);* ^- T6 `0 p. I
                return -ENOMEM;) l. x2 D  g( X" J
        }
( S: J; j2 @  {. d8 m        root->d_fsdata = &sysfs_root;/ [! u+ @" O( n- c0 V$ F  O. u. A
        sb->s_root = root;   /*保存superblock的根dentry*/
! ?4 F; ^0 x! w+ u        return 0;
( s$ S+ v) u* E  \}7 q  P/ k+ {  G' ~: N4 [( B" ^. [/ Z
! ^% F# P/ e6 U, v7 J
struct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/
8 |; ~* u  w( W. R9 }    .s_name        = "",* z2 j! T5 y, B1 m$ h
    .s_count    = ATOMIC_INIT(1),
: p; W' u% C  \" P/ H    .s_flags    = SYSFS_DIR,4 k% Q# k; G: h, `
    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,: M/ E3 V( Q) f  ~
    .s_ino        = 1,9 C5 ~( G- m# _
};
: v3 k! d7 \5 ~( }# R7 I3 f/ C! O. _4 l8 c) a
在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。0 D: k' j4 M# ]) n' P
随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。. U1 U( ~7 s0 `7 r3 i6 t
- K6 L* Q( x+ D( g& j9 d
我们看些这个sysfs_dirent数据结构:
1 B1 G5 W& }& m/*5 I* n9 v: P# x8 j$ w4 I  k. g
* sysfs_dirent - the building block of sysfs hierarchy.  Each and
; g9 Z2 g6 v6 m: u# s * every sysfs node is represented by single sysfs_dirent.
  a6 C/ H" W5 r4 }$ t( @5 k4 v *
. D2 l7 z) i7 V * As long as s_count reference is held, the sysfs_dirent itself is
" D! _1 f0 {4 p0 K7 H  |3 s9 Z  Z * accessible.  Dereferencing s_elem or any other outer entity; p  _3 H& S1 g! {6 B3 `
* requires s_active reference.& @, B& Q0 }9 x% P, G) X" x; j, ~
*/
5 K$ Q' I: P& J3 c0 |struct sysfs_dirent {
' [& z$ H9 h/ X" F        atomic_t                s_count;5 r/ r. Y- X1 M- a4 K1 h% B$ Y" s0 ~
        atomic_t                s_active;# v6 c7 a, B' {$ v8 Z! x7 C
        struct sysfs_dirent        *s_parent;
5 ~1 n2 `! V2 ~& B" l3 J) I        struct sysfs_dirent        *s_sibling;
& q' ?$ I* n; X- P7 L; ?        const char                *s_name;9 B6 _7 A; Y# D! N- H5 g; H
: J) F7 {; \2 n( \" ]7 j) s) s" [
        union {
# \4 q5 X0 R' I5 S+ r                struct sysfs_elem_dir                s_dir;
$ T5 }$ L( v5 J                struct sysfs_elem_symlink        s_symlink;
% n9 L( R6 j2 t/ ]) M                struct sysfs_elem_attr                s_attr;
1 }6 A9 `3 n; L$ s5 k                struct sysfs_elem_bin_attr        s_bin_attr;
( |9 X5 [" h8 O0 `        };
0 X: X1 Y: s( i- l9 _. ~4 O0 _% k/ {: D  R
        unsigned int                s_flags;' r3 A1 d& T7 ~% C
        ino_t                        s_ino;
$ {( r9 v' k: u1 ^$ R        umode_t                        s_mode;
: O7 C& a1 z  ^* \' ]        struct iattr                *s_iattr;
2 d. l# l" a6 K( ^* Z  y0 U};% ^  T! S2 j: ]$ F1 }7 |
其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。
# u0 ~2 q, h$ B4 S$ l另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。
: `0 s  X' Q) F  J5 x$ ?接着,在来看下sysfs_get_inode函数:9 C" h' \7 H/ [( |
下列函数位于fs/sysfs/inode.c。
) [' y( f  E2 S' k4 g- V5 ?3 ?/**
" `/ J# S3 b  s  I5 C) | *        sysfs_get_inode - get inode for sysfs_dirent
! G3 k3 ]/ P; ~4 I0 U$ M *        @sd: sysfs_dirent to allocate inode for$ `/ v  U5 E' M# ^" |
*
+ c# c# H- _4 h5 G3 n  v *        Get inode for @sd.  If such inode doesn't exist, a new inode- {% K2 V& C; o, L
*        is allocated and basics are initialized.  New inode is
! V: o2 z' I0 O0 h; Y *        returned locked.- A0 V& p0 v( x1 ?4 [2 P
*
8 N, k) O) U: b *        LOCKING:
7 e* {8 \3 n. G! ]: R" x2 T! N" H *        Kernel thread context (may sleep).3 u9 A# k% |! X# @# F4 `! F+ ]
*
5 s$ p! i& D* C! @+ s, b *        RETURNS:$ W- {9 n+ K2 P5 A  W# C4 M
*        Pointer to allocated inode on success, NULL on failure.
6 k/ ~. U0 O5 d: I8 r */
2 P/ }( a, [0 F. q. @2 ~struct inode * sysfs_get_inode(struct sysfs_dirent *sd)8 t  U) ^, B8 @2 v: q" I: e2 n
{
  D6 a9 n- O+ ?7 [, [/ I' x/ w        struct inode *inode;" V( p( a4 L6 {& K( n9 q

$ p( v& ^0 q) v1 w5 p. U8 j1 o        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/1 |( @1 [' ]: b$ d/ \  M* K6 k% z
        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/; d3 D5 ^$ W9 F3 g% P0 @9 O+ I
                sysfs_init_inode(sd, inode);
- v6 J( N/ a- U% U( p- ]4 z3 T6 ]" {6 k$ P& W! g& [
        return inode;
6 A! n  z2 m( H- S' v: x' X- K}
! N" F4 l8 L+ P
! t  e, [4 j8 D! s1 F& ?  d) k/**
2 K9 X: I. ?1 X! o. _ * iget_locked - obtain an inode from a mounted file system
8 Q- T; O! k; |* R1 `8 p$ y * @sb:        super block of file system
+ v+ ]) i' V' C4 }  F; y/ ^( S+ } * @ino:    inode number to get3 S1 y6 p: h- f- m
*
# t6 z6 B& q% C) i8 V * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
' B5 `5 q. H$ c * the inode cache and if present it is returned with an increased reference# [+ ~$ ]# x  f! I7 E/ j& b5 O, {
* count. This is for file systems where the inode number is sufficient for( n+ x2 B2 _# H7 J0 S# D
* unique identification of an inode.$ o* e& |8 `/ O7 w! b4 B
** q+ i% e3 `" {* K
* If the inode is not in cache, get_new_inode_fast() is called to allocate a$ j# ?0 e2 R- L6 ?# Z; r
* new inode and this is returned locked, hashed, and with the I_NEW flag set.
4 D4 A: f( d: ~6 K * The file system gets to fill it in before unlocking it via
8 z$ ^+ {, i! H$ G$ M" B * unlock_new_inode().* H0 J; ]. B9 V4 o5 l5 J. e
*/
2 G( y' O9 E# T" C6 n+ Sstruct inode *iget_locked(struct super_block *sb, unsigned long ino)
2 C0 M8 |/ u% A4 I! `, ^/ x{1 b/ {% r5 h+ w3 j0 F8 t
    struct hlist_head *head = inode_hashtable + hash(sb, ino);
) Z0 v9 r+ Y  u! z) U  k0 I7 @    struct inode *inode;
! Z% ^6 Y( y( B# J! Y$ @
9 l/ L  s- x+ u6 o2 m: S    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
4 `$ H% p& w9 y( _2 d* L7 l& C    if (inode)5 o/ ^3 O8 R% `% r: t/ R
        return inode;         /*找到了该inode*/
% H( \' z+ n- V! @3 o' t0 n9 R" _    /*
. b' \3 M5 |5 \4 u, M* P. F; d" k     * get_new_inode_fast() will do the right thing, re-trying the search. i5 D+ M% }2 f9 }7 m0 z
     * in case it had to block at any point.
' i4 A2 G  X5 q! T" p% Q, h8 ]/ I- M     */
8 \- v+ W+ r( E( ^/ j0 F    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/! G9 T% y4 d9 O( N, V+ `
}
3 e; |1 ^8 g& A- ~% I# w& u6 o# CEXPORT_SYMBOL(iget_locked);; F4 A& b2 j0 b( S8 G" _: ]

" \+ p: {& I, w, k# }, u1 h  h$ A6 sstatic void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
/ }* r! ~3 ], r5 w# {1 a! c{$ I' J) d  T0 G6 j: b
    struct bin_attribute *bin_attr;
# S9 E: q5 H: B8 T: [
7 k1 |4 S4 \4 X    inode->i_private = sysfs_get(sd);
- [' A$ n# H7 e4 \9 `    inode->i_mapping->a_ops = &sysfs_aops;
$ R" V/ ^1 |$ C2 H( ^3 f    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
5 M+ ?) P; k/ X1 F1 b( {" T    inode->i_op = &sysfs_inode_operations;
) P  c4 B8 j' a( R7 Q: P- L7 O    inode->i_ino = sd->s_ino;6 e+ ^) K# `1 C! P0 v  b+ Q
    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
# P, L, X( M4 L, @3 {7 ^- b
7 a: D2 ^, l+ L6 \- g# X3 O( G2 A% D: h    if (sd->s_iattr) {; d; ~; V# T+ U
        /* sysfs_dirent has non-default attributes
  K3 D% g7 Y+ d+ ~) X         * get them for the new inode from persistent copy  o5 b9 B4 C' k/ i5 h% ^5 k
         * in sysfs_dirent
! I' Z" P. O/ X         */
6 K) d5 x- d% n        set_inode_attr(inode, sd->s_iattr);
- f' G2 z5 o! b9 ]5 M4 }    } else
# f  z/ r! r* k# B4 `3 Y  A        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/
6 h) N0 ~+ \. |7 z3 I3 i3 N+ q- f1 S0 D' _8 Z

* y  b1 d9 A2 F( @( O" e/ b    /* initialize inode according to type *// \: h7 r; d& w4 O  r' d. H, ]
    switch (sysfs_type(sd)) {. C* L( G' k3 x8 [! \9 b
    case SYSFS_DIR:
: V# \+ S( n7 i& j        inode->i_op = &sysfs_dir_inode_operations;" W7 x3 F5 o' H. N4 C
        inode->i_fop = &sysfs_dir_operations;; b+ h6 w4 G  J7 O8 A# {
        inode->i_nlink = sysfs_count_nlink(sd);
" \# _: C. k% h# D# C) z        break;6 h# K" A" o4 T# Q9 X) x
    case SYSFS_KOBJ_ATTR:; R/ l7 A" D1 m% t7 t% O8 u& b
        inode->i_size = PAGE_SIZE;. U6 v9 m& M  S5 Y# f) @! A
        inode->i_fop = &sysfs_file_operations;
" S: N' g, }2 K        break;
3 K/ t% A: Q* @+ N% e% T8 B4 P+ a: H4 }    case SYSFS_KOBJ_BIN_ATTR:& q& h5 _! W! U) I& K  Y* W
        bin_attr = sd->s_bin_attr.bin_attr;* Z4 t7 r% I% G$ ^
        inode->i_size = bin_attr->size;6 [! N( }* a! o  @
        inode->i_fop = &bin_fops;6 V: o( G- I& X: @
        break;
& C& }8 @, i/ ^) [: L* w    case SYSFS_KOBJ_LINK:/ A) G) B4 A" |  c% S) j% b4 E
        inode->i_op = &sysfs_symlink_inode_operations;
2 f2 w- D) x6 a8 U        break;" u; `9 ^# ~, C
    default:
# C; o2 T- |1 k" }4 \% i        BUG();2 ~9 H% z/ G5 w: b+ A; L2 x
    }" ~" Y- u0 [  z) W* Z8 J( X

' v  i; y5 n1 R    unlock_new_inode(inode);
9 S- v+ q9 n  H. ^5 P; T4 c: x}
0 n+ w" T8 U! d该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。; a1 t/ T  Z/ j9 Q& ?, G! \7 a
再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。* b8 ^0 M, _8 [  Z
/**
2 s8 E! Q- G" g# c$ N * d_alloc_root - allocate root dentry' h! ?6 k8 r5 S1 ^
* @root_inode: inode to allocate the root for
) [& x$ T! @6 o *% n% c' L9 i  f& K- C
* Allocate a root ("/") dentry for the inode given. The inode is
3 @* G# P( |/ h * instantiated and returned. %NULL is returned if there is insufficient8 q9 R4 A! \' }
* memory or the inode passed is %NULL.( _$ D* b: q$ o6 _
*/: s7 }1 U7 @  S

3 ]% e7 M3 J# J( C2 e  ustruct dentry * d_alloc_root(struct inode * root_inode)
9 \& B( i0 k3 ]* |: f- |# ]6 i. C/ Y{3 i! o! [+ y& y6 a) e
        struct dentry *res = NULL;
% {9 Y/ _% y  n6 b: J. r$ G6 _3 l1 L
        if (root_inode) {+ Y. K5 E4 h( W5 b( I5 ?
                static const struct qstr name = { .name = "/", .len = 1 };0 Y4 B/ Z/ C( s: L; d

6 h$ L  L& X( V/ @& d: ]                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/; Y) W6 J' Z0 q" e
                if (res) {" n# w+ B9 w  ^* @" ~# v. Y
                        res->d_sb = root_inode->i_sb;
# @  F4 n  ?* R; I" W5 i                        res->d_parent = res;       
& h) \' _( |8 l3 t6 G+ a" @                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/
9 }* P: I( @( Y  F" y* t                }
. N7 \9 n) A: A  b( u  ]        }8 B( n9 E# |& f, h9 X* S( B3 Y
        return res;
5 @6 G. F, `4 [- M  z}
/ [6 X* ~+ J% K, N
/ B  n% K5 Z0 b* G/*** }0 q7 T8 [  \
* d_alloc    -    allocate a dcache entry
6 J- C/ f' u3 F# H4 @ * @parent: parent of entry to allocate
" N/ w( f4 `' A) B- }5 B/ h, s * @name: qstr of the name2 j, F; ]5 `6 ?% D: z9 _! F& A9 D
*
- h2 h( Z0 o9 o, ` * Allocates a dentry. It returns %NULL if there is insufficient memory* ~4 w" M9 P3 _: t$ x) Y8 ]
* available. On a success the dentry is returned. The name passed in is( l8 u& g' P, B* o8 E, G( x% _: d
* copied and the copy passed in may be reused after this call.; w5 h+ i: C3 t: H
*/
; c9 _2 l" u, `0 V7 u2 R
7 O) S( t0 V; X; xstruct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
  p4 J5 V! u9 g: p* k. B{
# L  T, A& x5 g* ^4 s9 z    struct dentry *dentry;
4 Z2 ~$ J" _  A7 p    char *dname;
2 N& B' I% A. w
* y- ]+ \0 l6 ?/ k: U    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/% F5 d3 F0 W% [- H! n
    if (!dentry)/ z  F# A# W) y8 l7 ?4 R
        return NULL;5 c2 K( M& l! A

1 V* G8 ?4 [- S2 _* H    if (name->len > DNAME_INLINE_LEN-1) {
# r) R. h, u& P* }        dname = kmalloc(name->len + 1, GFP_KERNEL);
0 L7 J! m1 |; I' [2 d6 z        if (!dname) {
8 n5 R( T, y  j# P2 R& w) ^            kmem_cache_free(dentry_cache, dentry);
% R* k6 E; B# a) @3 f            return NULL;& ~1 n. f; w$ v" v% N; O: }5 |
        }8 [; I1 S  `& H, H+ D, _, f2 H
    } else  {# u9 s5 H$ G9 W
        dname = dentry->d_iname;
" s6 \/ G; I4 Y    }    $ P! D- O- {' y$ Q8 s( M
    dentry->d_name.name = dname;2 a2 x2 i# S0 l$ W; |

; ~8 a1 V( B7 R' U2 v8 A+ `5 B    dentry->d_name.len = name->len;
" |( p1 C" B4 f( f' L    dentry->d_name.hash = name->hash;
9 V+ }% b- S" [* @. I; y; e# n    mEMCpy(dname, name->name, name->len);
; m, e' A' E% t1 k. `: q$ t    dname[name->len] = 0;
+ e4 o6 O- M! O; d/ ^& x" P9 q1 w6 M- p! I" w# T- i4 X
    atomic_set(&dentry->d_count, 1);
& y1 h$ P2 h: ^% |. a    dentry->d_flags = DCACHE_UNHASHED;
+ V5 \& t7 Y3 H    spin_lock_init(&dentry->d_lock);: Y; }" l0 c/ T5 W  A
    dentry->d_inode = NULL;
0 _& V  K* A* a! H0 |    dentry->d_parent = NULL;
3 Q! I" F/ I) ]5 a0 a    dentry->d_sb = NULL;) V. @/ g+ E! {8 E3 _( o
    dentry->d_op = NULL;. V1 @/ R, F" S3 {
    dentry->d_fsdata = NULL;
* x5 Q7 L. k% e( Z1 k5 I* y    dentry->d_mounted = 0;  }0 l: ^- ], |
    INIT_HLIST_NODE(&dentry->d_hash);
& n2 p1 j; F  V' y    INIT_LIST_HEAD(&dentry->d_lru);+ y; R. @7 ]& B0 w
    INIT_LIST_HEAD(&dentry->d_subdirs);
# ^4 ^, D% f% f- Y6 A    INIT_LIST_HEAD(&dentry->d_alias);
+ z) y- L. f+ N, ]& v
6 \  S- B2 ]+ r$ ~; }    if (parent) {    /*有父目录,则设置指针来表示关系*/
% T$ a0 x  ]& \2 o1 d' v! Z0 Q        dentry->d_parent = dget(parent);2 X- S) q4 x1 B0 d) T5 H- T1 J0 z
        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/
7 d: P2 }5 _3 S/ S  O    } else {. E# t; [! ~4 _9 K
        INIT_LIST_HEAD(&dentry->d_u.d_child);
" |2 s0 j- F7 C# \$ U* Z    }
' `  T2 G. G! \+ u; k) f. E& K( |
& Y7 d: \9 Z) l8 ]    spin_lock(&dcache_lock);
( I) w4 ]7 m% y    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/0 L. q* ?- A4 Z8 ^- h
        list_add(&dentry->d_u.d_child, &parent->d_subdirs);' W9 e8 V4 Q( F0 J3 ^
    dentry_stat.nr_dentry++;
7 l* U& ~9 i" P7 C% a9 O4 @* v    spin_unlock(&dcache_lock);+ q+ O+ I) T  G# Q: Z% m

( P, t) l* b% F0 |6 {# i) k$ z    return dentry;9 k! Z1 ^5 ^* [4 W5 r, q
} & h  J3 m% |3 ?! v

( O7 W8 M' [0 V8 z/**
0 x6 c) B, s$ I4 u+ u) J" l * d_instantiate - fill in inode information for a dentry
' C; D8 B# u0 a2 O- H" J * @entry: dentry to complete4 F0 y$ O$ A$ @$ U; B
* @inode: inode to attach to this dentry7 p8 f$ X, j1 G- S3 r. m  Y
*
( }, |2 W3 Q- k- [ * Fill in inode information in the entry.) A; w$ ?9 P2 R. B1 N
*3 l4 m, F* Z: l' P% I* Q$ ~% e& c0 g
* This turns negative dentries into productive full members- \% E( C, }2 x8 |! p. X
* of society.
7 g6 ]1 z% Y$ N, |+ q$ o *8 P! l) e9 M7 T3 D6 ~; S! k
* NOTE! This assumes that the inode count has been incremented6 M( h5 I3 e4 ~* i
* (or otherwise set) by the caller to indicate that it is now% P6 m% a4 L1 A3 s7 m
* in use by the dcache.
) _% C0 }6 I8 N9 X' v) R */: x4 P) s* y- _7 B) ~/ l; S3 T
( ^' B; }* \9 X5 U4 a8 q
void d_instantiate(struct dentry *entry, struct inode * inode)
9 ]5 Z9 e2 `1 @( i( S{
) l; v& \- ]. ?$ r; @& l1 T    BUG_ON(!list_empty(&entry->d_alias));* @0 y2 h8 s) e; G) A# E
    spin_lock(&dcache_lock);/ ?- K7 K! _0 X$ ~, B& g' k4 [
    __d_instantiate(entry, inode);5 {8 ?- y4 h1 V1 Z( Q) i" q
    spin_unlock(&dcache_lock);
5 d0 E$ v9 Q4 \! c    security_d_instantiate(entry, inode);
  `1 J' p7 k4 a}3 l8 J6 Z3 G+ ~# G+ E8 _

& E2 z2 _9 k; q% S* j8 _9 `8 f$ f/* the caller must hold dcache_lock */- O" N9 i$ W$ ^1 g$ S
static void __d_instantiate(struct dentry *dentry, struct inode *inode): p# v2 m+ U/ U- D- g( O3 h# t. k
{$ C! q- \" Z: S  V4 J5 Q
    if (inode)
8 D# _$ e( b2 G8 K$ g! o; k2 ]        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/: }% i. d; r+ k' V
    dentry->d_inode = inode;        /*保存dentry对应的inode*/
$ }/ B, s3 I+ k. k$ E    fsnotify_d_instantiate(dentry, inode);- u  Q# ?( y6 E1 d
}
( h' \! N/ y1 V: ~% X" c* X& \
+ O* u5 @2 |# L8 I9 w7 n该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
, c& x) V, z: n7 a8 p5 h接着调用d_instantiate来绑定inode和dentry之间的关系。
' ^5 w$ @) D, f# c7 n
" b; ~8 v: R$ d, Q4 O* d
, Z" K' V' B. h8 \# t. Q( ?在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。$ _4 r1 T, B1 ]

+ u4 }# r2 B! N9 z2 B可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。
& _8 }9 E0 d& t! ?3 {" D) t% I* B, X; ~( A! [
8.2.3  do_remount_sb+ C5 M# i2 g9 R9 h4 V
下列代码位于fs/super.c。# c" e8 S! [  P, _8 o
/**: f8 d/ z! {. _+ H" C8 A3 x1 D
*        do_remount_sb - asks filesystem to change mount options.
8 m, L9 b2 n' W; p/ k. ?' c# `' b) Q *        @sb:        superblock in question) u6 |( u& ]" b% D1 T9 Q/ \, L
*        @flags:        numeric part of options
  t, F7 D( D) d  F5 i *        @data:        the rest of options& z5 r. B" }' C1 c9 _
*      @force: whether or not to force the change
8 z, u+ C4 }( m' ?; y1 g& v+ o$ I *2 A, E" K( m! ^/ _9 {7 f8 e
*        Alters the mount options of a mounted file system.8 [, H  H% q7 P4 y( X& Z
*/' V) I3 O9 s7 _' @* @( d
int do_remount_sb(struct super_block *sb, int flags, void *data, int force)" ~, |- I. e4 ?  P- O1 c
{
! Y: `0 H4 q3 M- {) U        int retval;; r$ B  q" u, L
        int remount_rw;
- d- A1 j: h/ H+ |6 W, C        3 _) I5 X2 w/ f7 e
#ifdef CONFIG_BLOCK% g: K* B; i. A& Z7 q. a, v" F1 T9 F
        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))# M+ @- ^& m4 [% w9 c
                return -EACCES;
4 E+ h8 d, z7 _/ m) q' g#endif
, Q( A& G8 d9 \. ~+ I        if (flags & MS_RDONLY)
# h  ]% F9 |6 @) M% O; T                acct_auto_close(sb);. _" ~5 D% ^) p9 D' Q8 _
        shrink_dcache_sb(sb);: c& A7 T0 l4 B
        fsync_super(sb);9 ^1 n3 e7 M1 Z+ Q( x- o
/ M- Z$ a8 [8 o: G" U/ ^/ C/ M
        /* If we are remounting RDONLY and current sb is read/write,% d5 S  A0 z2 l: ?4 i6 P3 V
           make sure there are no rw files opened */( ?! d; }6 g$ Q/ I' A3 y
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {8 n) D! D6 x. b2 C1 g: `4 D  c
                if (force)% ]6 ^+ N2 N5 A( B! Z' @; I' A) l
                        mark_files_ro(sb);
( G3 Y" [: C' N: Q                else if (!fs_may_remount_ro(sb))
$ P, h7 O0 a5 f- s+ ~8 K                        return -EBUSY;* f9 `4 R( e+ L: S+ a; Z* P. U
                retval = vfs_dq_off(sb, 1);4 T5 B( l" k( a: H5 O7 B# G0 M
                if (retval < 0 && retval != -ENOSYS)
- J4 J1 W$ s  g5 P( c                        return -EBUSY;$ n# L* t9 l! ^$ T
        }/ ]3 E& s. p7 y) C7 g& z5 U
        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);9 U6 x- Q. v% c3 x

9 A& K# I2 P' W4 C$ d0 \/ Z        if (sb->s_op->remount_fs) {+ H" S1 O* H8 R8 m6 B% u: ]" N
                lock_super(sb);
' s7 j0 @( e: I" @; K                retval = sb->s_op->remount_fs(sb, &flags, data);
( ~; K+ G2 ]$ f* ~6 H5 \' l* G' z3 V                unlock_super(sb);
2 l3 M9 j, E+ `1 j6 M8 ]5 B6 L5 p+ m                if (retval)
" t. Z- J! A9 v4 Z" k6 ^                        return retval;9 S( p' `# u" E0 U' @
        }* ^9 e5 b" }- w- |5 b) m# S
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
8 D7 n- H( j9 I1 X( A# Y        if (remount_rw)0 d# Q  S  y; I2 O1 B
                vfs_dq_quota_on_remount(sb);1 P3 e* [1 G, r. Q& t* U( ^% q8 b
        return 0;
0 l. M$ a5 J9 u$ k  z- |9 ]}
' Z5 t' \$ o( k" w5 c. @/ l* g0 c; t4 `7 y# u
这个函数用来修改挂在选项,这个函数就不分析了,不是重点。
8 x5 p- v. C, X* b8.2.4simple_set_mnt, N9 Z# K# d0 u+ a
下列函数位于fs/namespace.c。
! X& t4 R, Q& q8 x9 P0 J0 @" dvoid simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
6 v6 a) [0 f4 l: q3 K+ y" r{
- U, |9 h; `9 I! n% Y        mnt->mnt_sb = sb;
# L+ y0 u1 O. D! s        mnt->mnt_root = dget(sb->s_root);# @- H# E* Z8 i: y" e
}
+ m' f+ [, a6 O, L& x该函数设置了vfsmount的superblock和根dentry。" g* R5 g7 m5 b# \+ a' _1 _

9 O5 C; f* k3 P8.2.5 小结6 l0 n+ k. a8 C8 H
这里,对sysfs的注册过程做一个总结。
6 l7 `0 Q( ~( t! p" n- t0 V1 \: V/ p, _5 m& ^6 z& X
sysfs_init函数调用过程示意图如下:6 [0 `" p8 h, B+ ^

" C# M' X7 T" ?: t6 v  n& I: U2 W 2 R# Z' q/ d# P1 B  K* _

5 |! Y. l: a2 K  p在整个过程中,先后使用和创建了许多struct
5 e8 y- p/ z: y* ~6 i" W1 U! F9 d7 \* a2 Z4 i$ _9 Z, V3 X
第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。: A, J8 u! _. O

0 a+ `7 C# x1 C3 s( ~$ J+ ?' U第二,建立了vfsmount。9 @# L, d6 P( y4 h
! ^9 N( i" ~! [8 w& N
第三,创建了超级块super_block。7 s8 n* ]3 g3 L( f# W" ^

8 y6 C% I, d2 c2 Y2 q, p; B) U0 M第四,根据sysfs_dirent表示的根目录,建立了inode。% C0 e' H( l) f& B3 _9 P& n

. X. H* F0 r- k, u& d* q最后,根据刚才建立的inode创建了dentry。2 d/ z  H) O" E

: j+ n, |  n$ U$ R6 l4 O8 z% t# D除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
$ w$ e3 l  v2 P. H' B/ i- @, c+ }$ C' h6 `* g7 z0 O! R
8.3 创建目录
) \" k" k6 C: H5 e1 D; c在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。; ~0 G# U9 P) R) B. _

) `: `5 j1 B1 a, _/ B4 {下列代码位于fs/sysfs/dir.c。
: H  e' |9 u+ g/ _# {4 t( ^) U/**3 v3 Y. x; o% t1 h7 k
*        sysfs_create_dir - create a directory for an object.! [+ e3 @1 b) \7 Y
*        @kobj:                object we're creating directory for.
* J0 W+ g* ~9 a3 E4 p. i* ^ */
0 [0 D/ I: R! S4 q, Gint sysfs_create_dir(struct kobject * kobj)) U6 I# {3 }1 V$ X" S
{( t3 l" q# T1 |4 N3 `
        struct sysfs_dirent *parent_sd, *sd;
, |# ~$ @5 e+ t+ ~9 d& i        int error = 0;
5 e! E) p7 r* _( M- n$ |5 @- \, f
+ {' d. H/ q  f2 x3 g7 j        BUG_ON(!kobj);7 a2 y8 U, p& X: a' ?) B
5 S/ d7 W: c' t3 h9 p
        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/
. A- {8 c) J. H* g6 x) F                parent_sd = kobj->parent->sd;
7 s. U, E! r* u; }& Q        else                                /*没有则是在sys根目录*/
% ~! [4 Z1 D- `. H                parent_sd = &sysfs_root;
: w: H1 J1 w% z& \" u- m2 O
/ a) M7 ]' K5 `: m! G7 q/ ~        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);) C) A6 s. f1 r5 y; q
        if (!error)
  V; z% o' [' W: t; Y                kobj->sd = sd;1 v, Q$ v0 P' q" x4 \
        return error;3 ]/ k% _( x5 g% O. m  s
}* C5 Z) `% P. X

5 e: t/ y2 n) B% V! I$ T函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。' u6 a7 z* Q% V8 {
很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。
4 U1 C0 H& F( c7 i( C- c# N8 a2 E4 o& T; h9 t# M" K$ a8 G2 n- }
下列代码位于fs/sysfs/dir.c。
; y+ I4 ^8 e7 k0 X# [static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
0 [; j0 y8 X1 O0 c2 `& `                      const char *name, struct sysfs_dirent **p_sd)
9 x1 q  V( U0 j3 j1 u( o. z2 V{
) C  `1 `$ K9 \% f  W        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
8 C; ~7 V' p3 m9 s        struct sysfs_addrm_cxt acxt;
3 X$ Q- y& _0 E' I        struct sysfs_dirent *sd;
+ Z1 f# I# r* Y- Z* ?        int rc;9 N& A% h2 k' x3 S2 ]4 ^
4 \' V1 X: E$ ?/ H" P5 X
        /* allocate */        /*分配sysfs_dirent并初始化*/) Y, w5 n6 s. I$ E- L
        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);( b! D* {" c+ D& x8 C
        if (!sd)1 i9 Q- @- u& D% I* y
                return -ENOMEM;# C9 x* q$ V+ S9 a: W
        sd->s_dir.kobj = kobj;         /*保存kobject对象*/
0 m6 |! N$ c) w! E% m$ M6 s# e& J) ^# j! O& B% t: \* B. W( W
        /* link in */
9 |9 B2 m0 H2 m$ L        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
4 d& t& b% E( M& e  i        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/9 h1 L1 O" g' ]1 |
        sysfs_addrm_finish(&acxt);                /*收尾工作*/& H" e$ K7 A& Z: s4 h

- G" n* J; o% U$ [+ T  |        if (rc == 0)                /*rc为0表示创建成功*/) ]6 K# k6 E6 B
                *p_sd = sd;# F! {$ p* j; A
        else
, r! @7 {! o, c  N% Z# Q1 N0 Y0 x                sysfs_put(sd);        /*增加引用计数*/$ G" `; O" t- u- f6 @) n- O+ s

4 a! y( t* {/ V7 I        return rc;
# o- b. m- }' a) ?) c+ q' m8 N}, j3 R8 {. ^" a/ }0 s$ ]7 Z
这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。) e4 e/ g$ s: Q' i/ D( G1 Z
% d3 |9 n& a! R! k- q) b
mode还有几个宏定义可以使用,如下:4 s, ^. T# R) {
#define SYSFS_KOBJ_ATTR                        0x0002
9 ^* K/ a- Z/ d#define SYSFS_KOBJ_BIN_ATTR                0x0004
& F: q# Z1 W7 m' i0 B! a#define SYSFS_KOBJ_LINK                        0x0008
3 O  u  z0 j0 p- ]0 a#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)1 }9 U; [. L8 I5 a& V
8.3.1 sysfs_new_dirent
3 j) D. t5 |) ^9 _. B  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。
+ X. l( ]8 ^  |9 Z# m  v/ p1 M# m6 p
7 [* c9 W5 d) l+ E8 X2 B下列代码位于fs/sysfs/dir.c。
; F* x/ T- a3 Estruct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
! _0 E" C- [( S' G9 P$ q{$ k6 m" j4 O6 b( l/ j2 h% Z6 _
        char *dup_name = NULL;, |, f' ], q* ~
        struct sysfs_dirent *sd;* P7 R' u) j' N+ w/ H3 u

8 M' p* t. k( a2 l/ r        if (type & SYSFS_COPY_NAME) {' p, k8 w. B# r- T* q
                name = dup_name = kstrdup(name, GFP_KERNEL);
+ K1 L$ `% I# S3 \                if (!name)1 c2 ~6 s3 V- J" b
                        return NULL;. [/ y7 ?8 Y2 V* }4 {% J
        }1 r, E0 N& J# m$ k, Q6 V) u
        /*分配sysfs_dirent并清0*/5 n4 D) k; O3 Y
        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
' L, G( q" |0 `7 Z) t( e        if (!sd)
8 \% X/ D" V* V6 m- g9 A                goto err_out1;& t+ ?$ f5 W1 ]; X7 i" M+ p

7 X+ P9 Z6 U! g" N. Y$ n/ R% Y        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/7 o) d- R" _& Q( Y9 @
                goto err_out2;
) v( o* F+ q: E1 P' u: h4 X) W9 {1 y' h8 I
        atomic_set(&sd->s_count, 1);0 |' {/ [+ c+ o) m+ F1 w( |
        atomic_set(&sd->s_active, 0);/ _9 C+ ^6 w. v& \% U
7 i" I' t1 z8 P( D& Z
        sd->s_name = name;' p4 e4 I; s; c" L
        sd->s_mode = mode;. a- W! G* C" ?! j
        sd->s_flags = type;
3 S# u" _# H5 ^* |- P7 f2 K% y% y# A$ q' O. C1 R, E7 i
        return sd;) `; }( [: g6 }2 P1 C# N; \

) o* G5 H' y3 Y! C$ {: |+ Z err_out2:. ]0 V7 r/ s5 S- m% G: o' R
        kmem_cache_free(sysfs_dir_cachep, sd);
% v7 h5 t) K- }: \" z9 _9 [0 Q err_out1:1 }/ i% ~' ~# b/ C% b+ Z
        kfree(dup_name);
' C' s: A, g, I% Y% A        return NULL;
" ~5 z# o7 H8 C% V- @}
2 t' ]$ E) t3 f- f" o0 Y8.3.2 有关sysfs_dirent中的联合体- R2 D6 I/ q9 i
分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。
- u3 ^% {: g  t8 U8 E4 q. P/ r! d) j
/* type-specific structures for sysfs_dirent->s_* union members */
) i" Q. V- V% F. x) f0 rstruct sysfs_elem_dir {' l3 u9 l6 q2 ?1 Z1 d% B- u
        struct kobject                *kobj;
/ t: k, @" @  G0 M; h        /* children list starts here and goes through sd->s_sibling */
8 W# `: n) y1 c* {+ t( h        struct sysfs_dirent        *children;# ]$ D( L4 |  Z! s
};  ~; r+ q# M) i* s+ L1 c& b
# C: O  f( B* G* G- F. y
struct sysfs_elem_symlink {. p7 k) p! u6 Z  p: F
    struct sysfs_dirent    *target_sd;
$ ~' V/ R# `9 W9 ?! A- U# J};$ z* I1 R' W+ V' \, K" B* F
$ f* Q7 A6 Q: S
struct sysfs_elem_attr {: B, g  ?% L( C7 V" \0 m' K; x
    struct attribute    *attr;- q8 b/ g  T4 d1 B9 d8 N0 _* W
    struct sysfs_open_dirent *open;
, P& S6 D/ X( p- m1 {, ~5 w0 u) C};7 {3 H7 A( _) K+ l3 t) F
2 Z* J! a) k, y6 Z* p3 u
struct sysfs_elem_bin_attr {
+ Q) `5 r- a! e    struct bin_attribute    *bin_attr;
0 f$ p! ?+ y6 t7 q, L3 M0 a    struct hlist_head    buffers;
$ c, |. d$ Q: N+ c4 ?};9 Q3 |7 x3 W, |- I
根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。
/ u8 G5 X( w' |: \* w3 W$ P在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。6 M/ o" Y: ~' @, i
1 k( f7 k9 L5 G8 o7 A
在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。- S6 g2 M8 E# d$ s2 X# O
7 K; x8 N# b# q/ ~& t4 l8 b" m
8.3.3 sysfs_addrm_start& O% o2 R: L( ^# f) C
在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。4 v" h: ^( D$ B; N# e- N6 [

" z" y6 L& E/ Q/ D- q下列代码位于fs/sysfs/dir.c。* q1 |" w8 W: c" @) r9 f
/**
. Y* E" k% u, ?, G# T" n *        sysfs_addrm_start - prepare for sysfs_dirent add/remove2 W+ k4 ?% l6 R( y5 q6 L9 ]
*        @acxt: pointer to sysfs_addrm_cxt to be used# B( r  z) A. p$ b  `
*        @parent_sd: parent sysfs_dirent
8 I; f1 l% E: \+ e0 Q *
# A7 Y* ]0 g8 T( D, M *        This function is called when the caller is about to add or, x  L- h; n* s7 E# o8 V" v
*        remove sysfs_dirent under @parent_sd.  This function acquires2 A1 g6 i4 ?  V4 y3 r0 l& J
*        sysfs_mutex, grabs inode for @parent_sd if available and lock" A/ a3 A* j* d. u7 R$ I6 |
*        i_mutex of it.  @acxt is used to keep and pass context to! V* c+ D' F6 @$ r2 y. F
*        other addrm functions.
# Y& B: ~2 z- E *
+ a: K5 v) b0 {! {  ?, k; C3 i *        LOCKING:/ ^7 q/ O5 e8 _( C5 [
*        Kernel thread context (may sleep).  sysfs_mutex is locked on9 o" u9 A" h4 q. I) m: q
*        return.  i_mutex of parent inode is locked on return if
2 M# N# Q( m! s. W  m% q0 \% k+ e# Y *        available.
- T$ J0 I( s- ~) w5 M/ g: O */
/ J9 ]# {4 `! [: ]void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,$ E" \; g& r$ v% n( B0 N
                       struct sysfs_dirent *parent_sd)  D$ o9 n2 K% m7 k/ z
{
& J) m: i# E5 j        struct inode *inode;
; O% i* U; j  h0 D! j) \2 O4 R! d4 ~, @4 [$ Z4 o$ h- |0 E
        memset(acxt, 0, sizeof(*acxt));
; b0 p! g" Z  J+ W        acxt->parent_sd = parent_sd;
8 s* G( ]6 E( |1 s6 D. c# A5 s% h5 t' a7 h5 [: C# c
        /* Lookup parent inode.  inode initialization is protected by
. }. E& d9 {% O: `! z2 o" H         * sysfs_mutex, so inode existence can be determined by- Z2 H) Q, m* L; q
         * looking up inode while holding sysfs_mutex.
& U4 A: L7 @* [( ^2 X" o2 k4 Y         */) x+ h) x$ p3 a. k  _; n5 {$ |5 |
        mutex_lock(&sysfs_mutex);
5 I* h$ _; A9 F% V; y        /*根据parent_sd来寻找父inode*/
/ w8 u; S% h  i7 ~4 z  F3 |4 B1 O        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,0 M6 u+ G- C1 F
                         parent_sd);
0 G* E& y) b' W  d        if (inode) {
+ [- S$ l' o6 ^5 z4 Y                WARN_ON(inode->i_state & I_NEW);
( l9 l: p" u( d9 h3 l5 L3 m8 k6 ]. R$ d) ]6 _4 s. L
                /* parent inode available */
, C) {- t7 W: u1 l                acxt->parent_inode = inode;                /*保存找到的父inode*/7 H3 z. ]: v2 [

4 ]; N' H, ^/ `                /* sysfs_mutex is below i_mutex in lock hierarchy.
. R) H0 ~6 |* c, Z6 X                 * First, trylock i_mutex.  If fails, unlock; O$ O3 @! K& h, ?% B& [% x" _
                 * sysfs_mutex and lock them in order.
1 [6 G* u1 u9 u                 */# V* j( w5 k5 G: @* g% n7 }; M1 ?
                if (!mutex_trylock(&inode->i_mutex)) {  I$ n( v" |- E
                        mutex_unlock(&sysfs_mutex);. V6 m# V; T  _! V; M
                        mutex_lock(&inode->i_mutex);
/ V  R4 U# {% j% v: S  ]- Z                        mutex_lock(&sysfs_mutex);4 G) t  u9 D2 X# A+ I
                }
7 y( ], Q6 y7 [+ r, \        }
8 |6 t* Z5 p9 i" N" b6 U( p7 d}
0 `! [- S. D- n+ ~; v" y( L  \& D( v% |, P
/*: R5 N3 F( q$ }) @1 `; V3 n+ q3 U
* Context structure to be used while adding/removing nodes.
* [; }/ B6 ^5 B4 u7 s */
( {+ m+ Q7 I; T  _  {struct sysfs_addrm_cxt {
4 d* [) [- f3 v6 d9 h9 K) d* _    struct sysfs_dirent    *parent_sd;
2 b* E1 S1 F0 c- S% m3 F    struct inode        *parent_inode;5 J% n& w" T8 D
    struct sysfs_dirent    *removed;& g' x, C, {5 r; h- `& P
    int            cnt;: ?' s  s) z% t, a1 a2 W# j- s1 f
};
! _2 S' {! K0 E- \' b注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。. C5 W' `5 D! o! ]! O: v% A
8.3.4 sysfs_add_one" d) A( [" i, W  a2 P, [
下列代码位于fs/sysfs/dir.c。
5 S4 _5 W# s" o! L/**! C$ Q0 _$ x4 j+ ^% I( ~
*        sysfs_add_one - add sysfs_dirent to parent: d3 `4 D3 i9 Q( X, i
*        @acxt: addrm context to use
4 ~7 Q+ k4 s6 S *        @sd: sysfs_dirent to be added
* Y4 W' U0 b! D2 d# i4 e3 d *6 Z8 j  B7 W% t' `
*        Get @acxt->parent_sd and set sd->s_parent to it and increment6 i& Z8 i0 I) X' k
*        nlink of parent inode if @sd is a directory and link into the
) }% N3 N0 U2 R- M# |& q- a *        children list of the parent.: u+ ^6 v6 Y8 {9 k3 W$ a* _
*4 J$ a/ P# h) _
*        This function should be called between calls to6 b5 Z- o8 D6 c5 K
*        sysfs_addrm_start() and sysfs_addrm_finish() and should be2 A# E$ G' v7 K* w
*        passed the same @acxt as passed to sysfs_addrm_start().
% }6 [! C/ U' ^1 b0 T5 D *! S: B5 l; O5 E( T1 C6 f9 [- V
*        LOCKING:
5 r$ l1 t, L! X3 A' J *        Determined by sysfs_addrm_start().+ r& y6 e2 F3 a7 q6 B, q) H) S
*
. S5 l# j+ p; z) R9 h# p *        RETURNS:
- {9 a. \- |; [. T *        0 on success, -EEXIST if entry with the given name already1 K; N, |& ~0 L! n! G
*        exists.. W( [$ V6 z" S  T
*/# r# C, ]  L/ A6 r( L# w2 e
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
* a8 G6 p6 x7 o+ U% d$ t. V- c4 }{
- q; u" S7 w; U' r: O        int ret;5 `& c7 j9 Q$ z
; |# }$ c1 F5 \4 |. E8 b* u
        ret = __sysfs_add_one(acxt, sd);( x3 z4 }' O$ L4 x$ p9 Y
        if (ret == -EEXIST) {8 Y+ [% `3 B6 s. o( K1 n
                char *path = kzalloc(PATH_MAX, GFP_KERNEL);
( Y  I' ?) Z" |/ F. z- @* `                WARN(1, KERN_WARNING5 m( S) t; N3 P
                     "sysfs: cannot create duplicate filename '%s'\n",
8 X$ F4 L& q4 D$ K6 _7 K7 k                     (path == NULL) ? sd->s_name :
' f+ U+ E1 Z' X8 }/ o# |                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),- l- A7 ]  x( _) X
                            sd->s_name));
4 V7 V- Z8 x& F  ?$ @. E                kfree(path);
3 j9 q# P: Y4 _4 A        }
( J$ F9 h2 H* K) Q0 S6 s4 a! {2 s; {6 A: j, A
        return ret;: c6 N0 U9 k  H
}3 Z0 @0 A' j3 x$ ]4 J9 Q

5 e5 S. d: V; W- _. H; i/**
6 `, _2 N) I5 K' s/ X5 Y/ } *    __sysfs_add_one - add sysfs_dirent to parent without warning
. t% p$ W# w2 t) L6 H- k *    @acxt: addrm context to use" Q1 ?. n% X, q) }8 \' K  h
*    @sd: sysfs_dirent to be added4 j1 v3 ^, |) c/ W
*
/ P9 S) P- x+ r- a *    Get @acxt->parent_sd and set sd->s_parent to it and increment
3 `# P' s0 Q0 d) y# L *    nlink of parent inode if @sd is a directory and link into the
# Q- o- e& h9 c1 O *    children list of the parent.
1 m1 {2 ]- {& P *
0 v& T7 J/ R& {# R *    This function should be called between calls to
* l8 v" Q$ q3 p *    sysfs_addrm_start() and sysfs_addrm_finish() and should be. }% W, e1 O- O+ E) y5 _9 m
*    passed the same @acxt as passed to sysfs_addrm_start().$ X  i& u; c8 M5 `3 F
*- @0 M/ `" q- ]* ~
*    LOCKING:& |- }" O$ M) L3 n  J% I
*    Determined by sysfs_addrm_start().* P7 Q$ H5 W0 \3 p1 b3 o
*
# J- w1 i* y  o+ B0 L *    RETURNS:( t2 H) O, Q8 m* x+ @' D
*    0 on success, -EEXIST if entry with the given name already
9 {$ S$ Y5 l# g; i *    exists.' n4 A  [% n+ N0 O- q1 L9 v# d# |4 o8 E
*/4 T7 {0 i, z/ b. L; `
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)4 P8 _' R1 K: u# b
{. J* U6 Z' d8 _/ e2 W
    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
2 v9 Y% `/ _9 ^+ G5 i    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))5 w( M! A/ @- @# I2 u
        return -EEXIST;* A% C* j9 `, A4 q9 A
4 ^, _) Z( {& D* U
    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
' c% c7 y( S7 ]1 h6 {9 O. j1 ]0 m$ G4 B" N9 F8 E
    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/! ^% K1 a& T( N8 t+ c) H
        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/  G/ f; `' e  N# {+ V, Z+ T. W4 ~
& w$ I" U' [1 `8 o  Y5 B3 y" I
    acxt->cnt++;$ y0 c- v3 M& m2 D; C: E( _

2 z  s1 F" ?5 p: c, b5 x  }    sysfs_link_sibling(sd);
" B3 ^# P6 m7 P
' o/ n" H  t+ y* L/ P& h    return 0;1 U) o" g. c. u7 `
}
# r- @0 n  S  l, Q/ F
- R/ l; V# {- }2 A+ L/**" l9 ?& W$ }3 u' y
*    sysfs_find_dirent - find sysfs_dirent with the given name
3 r/ ~& K3 B) M& c) X *    @parent_sd: sysfs_dirent to search under
; |: n0 U/ i' Z. r& X* A) i *    @name: name to look for. t% J2 t* G) X0 I
*
% d& N, s$ F5 H3 {! A8 J *    Look for sysfs_dirent with name @name under @parent_sd.
; W, X5 h) y. V3 |+ y4 r4 u" h *! G5 T" u% T" R* z
*    LOCKING:; K, D; F- ]0 w) _) P% g% x6 i
*    mutex_lock(sysfs_mutex)
  r8 ^, W" d- L6 P$ [, G$ x" S *- X' G  X5 t9 Y! y, q& ~3 e1 o& \  O
*    RETURNS:, R+ Q5 T0 S9 D7 X
*    Pointer to sysfs_dirent if found, NULL if not.) i) c* S2 e  P$ S) f) `
*/6 m* G0 b6 U  _! o4 c
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
( u7 Y( @5 M: a' D: R                       const unsigned char *name)
) |  q5 E, U- Z. D4 e# r# j{
$ B/ w) h+ R, _' {. \" W    struct sysfs_dirent *sd;
# G' o* _' h, Y4 k# x5 \. F1 L8 {
3 P$ r+ d. a4 Z" D8 R" w    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
2 w3 c6 [( t9 Z  W0 U        if (!strcmp(sd->s_name, name))
, K* Z; c$ G4 n" {5 S! J1 x) I            return sd;( @( G$ v  t/ K& i+ F+ y
    return NULL;) h% Y6 x, T8 V) N1 E
} # h, \) n. ~% A  n) J1 ~! S& j

4 L4 \' M% U! g4 W: j; d7 i/**4 \+ A4 O- q, O
*    sysfs_link_sibling - link sysfs_dirent into sibling list; k. Y1 @+ s6 \1 p0 z- {& p
*    @sd: sysfs_dirent of interest& I7 d( X3 V/ {$ z9 H9 n
*0 ^5 |: q2 z5 I  P
*    Link @sd into its sibling list which starts from1 c5 Z$ _% C& _
*    sd->s_parent->s_dir.children.3 r1 o) X$ G* ^. P3 X0 t$ |' A
*% U" o6 x% p2 w2 k" m) T% i  P, G. E
*    Locking:9 f& w2 {) G7 g2 A2 f
*    mutex_lock(sysfs_mutex)
+ V9 g" `# H% \( M  {0 f */- H0 u1 d' v0 F- `/ K- c  \' }
static void sysfs_link_sibling(struct sysfs_dirent *sd)6 J7 C- v& a1 Q. j6 W, [2 U2 _
{9 i0 c. J1 e8 h* U; |9 ~2 t
    struct sysfs_dirent *parent_sd = sd->s_parent;
" b9 M4 Z. o5 u' |! n    struct sysfs_dirent **pos;
2 Y2 B( F0 a, z" _6 ]7 e
3 {0 u/ H* i( L. y7 ^    BUG_ON(sd->s_sibling);: e5 o) U) F  _) G9 q5 F9 [
  `' A8 N5 N1 d2 o# a% T  T" M
    /* Store directory entries in order by ino.  This allows
/ d* u6 P& E& q* r7 S0 Y     * readdir to properly restart without having to add a4 z6 X5 Z8 p+ a% |. ~/ d
     * cursor into the s_dir.children list.* H6 p' f% ~# W4 g! C
     */# o, F2 p# A+ T6 n; z: [9 L
     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/! ?0 @+ [& k3 J5 Z* \# {  W
    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
& g9 x% `8 Y! w" ]  B" {        if (sd->s_ino < (*pos)->s_ino)7 z# t7 }9 h0 Z9 ~% }9 S4 \& o
            break;) d4 z- l) Z7 j& A, f4 L
    }
5 h& [  V* V+ P' s" C    /*插入链表*/3 h) }+ x! H2 b# b
    sd->s_sibling = *pos;; U: A8 v  c, o6 L. f# |* ^
    *pos = sd;
1 E5 \" n- f6 H/ x, ?4 c! c}
# p- d0 o! j1 `, G3 R: ?- S) p" H该函数直接调用了__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链表中。
+ v2 K, U3 @6 s" [, p5 Z% ^8.3.5 sysfs_addrm_finish
/ X% A1 Q8 a/ V- d; D+ C5 a下列代码位于fs/sysfs/dir.c。" |9 K2 c' f) b8 \/ @2 z6 x
7 O% w5 G* ]  j5 x" P
/**
, S9 A4 X; O8 e" C6 Z+ F" x  f *        sysfs_addrm_finish - finish up sysfs_dirent add/remove
* t7 D% n8 d- @" {& _4 I  P4 l *        @acxt: addrm context to finish up5 V3 \0 @* U0 [0 A/ ^4 P
*
4 K8 ]3 Y' t5 G7 v *        Finish up sysfs_dirent add/remove.  Resources acquired by5 k6 E' L+ C# J
*        sysfs_addrm_start() are released and removed sysfs_dirents are
% J0 f2 v9 T2 r: Y *        cleaned up.  Timestamps on the parent inode are updated.
# r( ]$ Q- X! a% P% C* T9 v9 o4 U *
! P) @8 D, W1 f *        LOCKING:
' H8 N: U6 w: q# T& B *        All mutexes acquired by sysfs_addrm_start() are released.
0 N# _  a! ~( G: w8 B+ @$ N# j, y */
) u! x9 x: z  n. x9 Z- z; Avoid sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)% w2 ]+ g9 _7 a% T7 M! j
{! `9 H3 X; {% O) S( g5 z! c
        /* release resources acquired by sysfs_addrm_start() */+ H* U1 [6 ^0 |# f- A: |; W% k
        mutex_unlock(&sysfs_mutex);
1 L' m5 ]* a" J$ l- k& V6 P0 \        if (acxt->parent_inode) {' n8 ^+ L+ T" F# U$ j' h3 m
                struct inode *inode = acxt->parent_inode;
, k/ ?' }" }  |5 x% D
1 k0 |9 ~6 m" T% L* J8 E% ]                /* if added/removed, update timestamps on the parent */& Q0 A; h1 ~. L; w5 s, _: F
                if (acxt->cnt)/ h9 Q& c) Y  \
                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/0 L! R0 a3 R* t! C+ A' x
1 F4 V  h- c/ {( X* @" _+ U, I; L
                mutex_unlock(&inode->i_mutex);
" V6 X4 [! f6 D$ }                iput(inode);6 I1 x; \, T7 ~" ?
        }; x, X& ~1 ]5 n4 I

2 a; m# v  `; g9 ]/ o4 Z+ q        /* kill removed sysfs_dirents */
5 ~7 v& f: [, Y3 J; ?; s0 S6 k        while (acxt->removed) {
9 R7 s7 e4 T5 P1 J# _4 q* r                struct sysfs_dirent *sd = acxt->removed;
' f  ]. f8 q% h1 Z6 g
5 o7 R0 N& O  _, g1 J                acxt->removed = sd->s_sibling;
. k2 I0 c% ~& ~                sd->s_sibling = NULL;
. q2 p9 V& F! S* `" Y, s/ ~
2 Y5 O6 A) M7 H/ ]2 G' F  ~                sysfs_drop_dentry(sd);
. m! x9 r( m; T* p2 q' b                sysfs_deactivate(sd);$ D' ?, W0 L( E$ K9 e
                unmap_bin_file(sd);7 C8 l; p2 M0 E* }
                sysfs_put(sd);
. H; R" X( q& E        }
/ N; |1 B- V. h}
! _) b( `  `5 a4 T0 E
# J$ {/ T9 \; l; w5 `; O" s该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。9 }& h9 U/ q" ^" P

# y1 C4 ?. d  h至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。2 I8 S  e. F2 m, ?& g/ ]  Z# k. }% D

( u& S6 A' r" ]0 b下面我们看下如何添加属性文件。6 b$ t! V" w+ a0 f
8.4 创建属性文件
" P0 A5 m; q1 g" a. F/ j# ], q1 T添加属性文件使用sysfs_create_file函数。6 X7 C0 Q: O8 @$ p' Y- o+ B6 \4 ?

9 M1 m; _2 \' k  q# c9 N0 W7 `/ B下列函数位于fs/sysfs/file.c。- \7 D; x: H/ p' S5 @! J9 [4 m
/**  C- q5 z0 b2 i, S
*        sysfs_create_file - create an attribute file for an object.  F3 m7 ~1 R, c2 f6 B
*        @kobj:        object we're creating for. + c: f0 ^0 \. `0 |5 T
*        @attr:        attribute descriptor.2 x. Q& ~+ P4 B6 Y0 C! z
*/1 G9 @  _# a9 z2 x
( S& K& i1 F$ b3 h* p  n
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
( `- N' |- K5 u2 o, I{
: i" i( M: T1 X0 m        BUG_ON(!kobj || !kobj->sd || !attr);
* F' b, j. u! u$ l2 {+ y. {0 r" f* }' [
        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
# y, D: N5 l" }; ~
: `& @+ ?  t$ p! }0 @}" u& Q* g* b. j, N

- M; O( r  }# H; {int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
9 `2 k* ]/ g& K/ y           int type)3 t( V7 Y' z6 Y; i& X
{8 r. n# j8 o4 K
    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
, N% G" _) ^1 K/ Q}
" ~2 a/ V7 j' s$ ?
* d5 Z5 l3 f! h  Qint sysfs_add_file_mode(struct sysfs_dirent *dir_sd,& {. [. x% U+ a; @
            const struct attribute *attr, int type, mode_t amode); W4 l; u2 F; Y0 D7 j0 S0 q& o
{' E* E/ |8 ?5 b( ?( i$ @9 u
    umode_t mode = (amode & S_IALLUGO) | S_IFREG;
6 X5 F" p4 ?5 q( r" G( y- f- ^    struct sysfs_addrm_cxt acxt;
3 T, h" P1 n* x0 q    struct sysfs_dirent *sd;7 g( p% h7 H: U. K3 m
    int rc;3 W# y1 n5 h# ^7 S
    /*分配sysfs_dirent并初始化*/6 a) |+ |$ Q/ F0 j
    sd = sysfs_new_dirent(attr->name, mode, type);
2 s4 X' @9 f, x1 l. t  p    if (!sd)2 q: _- P* h9 v
        return -ENOMEM;. y: L) R) E+ t2 |1 e7 G
    sd->s_attr.attr = (void *)attr;
1 k1 m: Z- d; I. R! _/ _7 n4 o' v
    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/! o- p; _' f( q2 U8 Y
    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/: A& c" j0 j& k
    sysfs_addrm_finish(&acxt);            /*收尾工作*/
$ g; G% j0 {% m; z; k
3 r. n8 m4 b( k, p! {    if (rc)            /*0表示创建成功*/
% Z4 X- U7 E& c9 ^        sysfs_put(sd);1 {' Q+ V$ c+ F/ w4 v) d5 v

9 T. u/ \% P% u+ [# u1 C  T/ |, ?2 F    return rc;8 s4 p( I* g4 p1 F: n# G% r
}3 K3 j2 Y9 V: W* q; }8 x
5 c" ]- ]+ o1 d! T* m
sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。
# R; _# l" I2 S5 P5 C' T9 D* Fsysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。
) D0 I) o$ w' K4 v9 A, ?! O  ~
3 ~7 R) r# n+ i9 m需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。% {8 G; m6 |( S# T) h, s6 E/ P* f# d
8.5 创建symlink& L2 b' {+ N4 E: {& r2 b+ O0 T
最后,来看下symlink的建立。+ u- k5 b* ]% }+ ^0 U: N
/**
: `+ C; N7 J. o/ j) Z7 A *        sysfs_create_link - create symlink between two objects.- S4 P" |& P& P# R
*        @kobj:        object whose directory we're creating the link in.9 A1 o. L! T/ }, r8 |( V9 `9 a. |
*        @target:        object we're pointing to.
" G/ F" x( }' d5 f: s *        @name:                name of the symlink.3 B6 M# C4 Z6 A$ ?6 C
*/( \# \$ X$ B8 h
int sysfs_create_link(struct kobject *kobj, struct kobject *target,
! b) J) f- B1 M  N( @9 H4 N& q                      const char *name)- g' y0 G! ~; r* G0 D9 w
{
5 I, X& H+ m8 d- R4 X! {        return sysfs_do_create_link(kobj, target, name, 1);+ O6 f  a+ {: N. T5 `- n
}0 ]) [& d1 |$ d. ]& R. ]5 c

5 A0 v6 u& p% Y/ G, bstatic int sysfs_do_create_link(struct kobject *kobj, struct kobject *target," n' _; c: _7 w0 h0 R5 u/ b  H
                const char *name, int warn)+ \8 U% h- i! @# |
{3 L, g4 ~$ U9 O  s6 ~8 ?) _1 ^& N! W+ O  R
    struct sysfs_dirent *parent_sd = NULL;! l, b: |" B6 y5 I: O1 F' q
    struct sysfs_dirent *target_sd = NULL;
8 u# ?' l4 k5 z1 M) W) u    struct sysfs_dirent *sd = NULL;
: Z4 j9 R) v$ k7 L# i: Z) w    struct sysfs_addrm_cxt acxt;1 k0 e8 x, g. ^& w
    int error;. A4 |- W; [: s" t4 O

+ Y6 m' b& B5 T5 W    BUG_ON(!name);
  f. z; G% `4 u: m5 b/ i8 z
$ o" @2 `, p5 H8 p$ o; A' ?$ w    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/
3 a" ?$ H0 G2 z( _2 _3 c9 {        parent_sd = &sysfs_root;
0 @) g7 L! z9 J0 ]    else        /*有父sysfs_dirent*/1 a& N+ S: t1 H" U( R( l% Z
        parent_sd = kobj->sd;
; R& C6 J' v+ J5 U$ K8 R+ p
: y( S: E# q3 Q    error = -EFAULT;# ~& j# x$ c/ B. E# \: v
    if (!parent_sd)
6 O4 P2 }+ ~- E        goto out_put;
) D5 t3 r9 R0 }/ F  D  v, R& c( C' |; _* C# {" ^, X
    /* target->sd can go away beneath us but is protected with
1 D( H+ X# m) J* B     * sysfs_assoc_lock.  Fetch target_sd from it.
# W/ K) A3 R* F5 j! k     */
* U# u! S. S$ M' @2 D0 Q    spin_lock(&sysfs_assoc_lock);
: I) g6 G% e/ i/ a- T3 g    if (target->sd)
/ t- @! F+ h/ c- M, V# S        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
# e( h3 D3 q" t& B9 k1 i. T# ^( U. H    spin_unlock(&sysfs_assoc_lock);
# `% r( m- O: R5 J. v& C
5 m3 T& r" q7 W" R    error = -ENOENT;( p0 M. ^+ T6 G# G2 J9 F9 j
    if (!target_sd)
+ G- R: b: g, d% H  ]4 B        goto out_put;
9 z- S. v4 f- v( O
$ B. @" T# O5 r2 ^) o( X; I    error = -ENOMEM;
  }9 N) N+ Z1 U, r    /*分配sysfs_dirent并初始化*/
7 e# U$ v& C/ g) T! W7 m    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
9 w% A% g% C# l& J& L1 e    if (!sd)
% b/ I3 X" `2 X1 z" [0 x  c        goto out_put;
9 z5 G( C% W  y4 U# j, l+ Q
7 T$ Z! e1 o3 s7 D8 m) ^+ L' t" `8 [    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
4 Y! g* {* w1 M- e    target_sd = NULL;    /* reference is now owned by the symlink */3 _* [2 w3 N8 \' e

( ^& R/ x7 Y) s( A8 Q, |    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
# [% K7 u$ r- d* w9 x    if (warn)
4 v2 i; ~+ k6 ~- i2 t        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
" E( w: V9 [5 @    else
; j/ C+ X4 x2 ~5 e  ~        error = __sysfs_add_one(&acxt, sd);
* t" Q: t5 u) y( M5 d  b    sysfs_addrm_finish(&acxt);            /*收尾工作*/
5 b/ q! Z7 T$ F! H! O9 s3 J% p2 V& e8 i8 _5 w. G/ B
    if (error)
0 X) D( w2 Y. h* R, W# z' N        goto out_put;7 d6 k6 `1 w, |! F; D
$ z( E& U* \$ R) p/ u
    return 0;* |, J7 }, [' N

# ]- G9 D8 m; |& R out_put:1 I7 p& u% n( M9 o6 t# E; ~/ ]
    sysfs_put(target_sd);- m. t% Y0 Q. l% e( ^! F) x* e2 G
    sysfs_put(sd);
# E8 t6 o1 ~' x5 q$ Q. [    return error;, ?" Q  J  k3 Y
}+ Y8 f/ W+ |- s9 J/ _- p. Z
; R; W2 r4 ]" h6 ?
这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。8 f6 ~- Y: G( t$ [; Q/ H
因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。
  A* J! N, v" ~; h/ d3 m
; d. U* N  A1 w! g3 y8.6 小结  p9 U3 h; V2 `& `
本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录
# Z! @+ |4 g4 T
) Z0 H+ C# Z" o. m! z$ m5 z有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。
& }" A1 c$ Q2 p6 A2 k2 C" A$ s' }' a8 Y: q% m# W3 h5 `  I8 l3 f
9 总结
6 z4 i$ t* [+ [* J9 Q. ]本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。
5 ^+ M5 k$ T% e. N' T5 U2 s! Q5 {/ B6 T  T0 N( h
接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。! C, o2 R" W1 n! s, ?& Z

5 A( b1 b- d3 _+ t随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。7 N% s/ Q6 }( o( o

. ~3 u5 e* ?; [, C# v% M7 n然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。( A0 K6 V$ q3 s  Q1 Q0 i# m7 f
1 _& ^4 l- R- f0 F( k5 R/ A
之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。! k* _2 e) E9 e

! B9 ?7 n$ E0 Z9 G" k; M0 I+ A最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。0 D+ u$ A3 Z& i* v" T

8 c% `7 I( c2 E0 Y' Q) X1 U5 p( Y8 e
6 }0 i; B3 E3 J' U1 n9 C: x

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 22:18 , Processed in 0.390625 second(s), 26 queries , Gzip On.

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

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

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