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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。
  j- `, |7 m, ~  C, E+ q
" D+ S- [/ ]( h! k9 o内核版本:2.6.307 R: Y( |! K9 N! o1 j

% }* Z$ O$ y/ e6 K1. What is sysfs?0 e* Q$ n; y, Q
  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。# c; Z9 g5 ^( b# [; N& Q# w1 q

* n6 F" y  U( i  我们来看看sysfs的文件结构:, O4 U# R' M- F5 g! o: G' N8 f

. ~% k" z4 Z9 d7 L3 E2 l[root@yj423 /sys]#ls
0 Q8 y& z% [0 Gblock     class     devices   fs        module1 @' g/ V/ p/ ~
bus       dev       firmware  kernel    power
1 m" D: e/ @* @/ ?; a0 x0 ]/ G5 Q4 F3 S$ O
block:块设备
7 ^8 w5 U4 m& s
" d. }3 f7 T  h" _7 _( Xbus:系统中的总线  t) d% U+ q% b/ h# B" g

8 U! Z2 J* h  gclass: 设备类型,比如输入设备' F* T; A  z' D- _0 M! B- y  v
& x2 C8 U$ `* M; d7 P) H# Q
dev:系统中已注册的设备节点的视图,有两个子目录char和block。
0 ?6 T/ C# C) n1 b# k
+ u5 _0 s( W( [5 w5 p) J* \/ Y7 `devices:系统中所有设备拓扑结构视图
7 f* `9 L; |" N1 c& C0 T  A+ J8 z3 o/ m- q4 o  ^: G
fireware:固件3 a8 }0 ~7 y% I0 W0 b8 R) ?

7 Y8 z4 \8 p3 K4 _! Vfs:文件系统( a+ p3 y$ [7 e6 {% y
3 V* g1 f& \4 [0 Y. G6 J4 U0 ~
kernel:内核配置选项和状态信息
9 n; B* l3 O5 h1 L8 y' \0 L) o3 B2 h* Q; e& @
module:模块: Z  N7 e3 X6 v
2 `- x/ [* k* K9 ^
power:系统的电源管理数据
) a% S  n$ @6 ?6 t
: z7 C7 F; A: n; S2. kobject ,kset和ktype2 m. l8 A- k# J- C* T
  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。3 v" q- s  D3 ~8 Q& L6 S

1 D/ n2 W. g- u8 T% ?( b3 f2.1 kobject) x' v) K  Q% Q3 ^1 k+ B7 n
  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。0 L2 {$ O# U" M* y; D
4 U* f0 i) F. l! o
  kobject用struct kobject来描述。
( ?6 c6 U! l4 `9 z6 [8 ^/ m2 i! ~' ]- T2 T6 ~: j
struct kobject {
& Q6 n& U; @% e/ k3 q! {$ }    const char        *name;            /*在sysfs建立目录的名字*/
; y- p4 ?4 f, o+ O: e    struct list_head    entry;        /*用于连接到所属kset的链表中*/5 @1 J1 v8 l) w7 P! U
    struct kobject        *parent;    /*父对象*/
# R- V& p: v- t# |    struct kset        *kset;            /*属于哪个kset*/
. y+ {+ C$ X+ d# E    struct kobj_type    *ktype;        /*类型*/9 I- s% J  E+ F# q
    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
% n2 O6 W! i. t4 z& H# e" e    struct kref        kref;            /*对象的应用计数*/+ _0 d( R0 H( D( G% b# U
    unsigned int state_initialized:1;$ f- M! J0 Q8 ^! m, M" J+ i# X
    unsigned int state_in_sysfs:1;, d: n* A' l* N* \7 M
    unsigned int state_add_uevent_sent:1;) \" o9 I: P, T
    unsigned int state_remove_uevent_sent:1;
7 `1 L$ n, ?9 U! R# x. y& ?    unsigned int uevent_suppress:1;
& g" R/ P! |1 D3 j" @, H};
& P( Q# R  q, G+ q3 ~, d2 E7 u* Y2.2 kset: Q2 H$ p, D  o. `8 t1 o% y) A0 @
  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。
9 H; N& z; k& u- c0 p: }) u
' L) {( r6 W) E  p0 m+ I  kset使用struct kset来描述。
* e) D' E& {  N" P
" ^- O1 |9 S- c8 L+ C/**; D$ |: w5 J* ^8 e# ?  M0 v6 o
* struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
4 [) x) m* w* ^/ k *4 K- Z  E% j4 C4 K3 [! b! M
* A kset defines a group of kobjects.  They can be individually
4 d1 p8 i* @: W. \ * different "types" but overall these kobjects all want to be grouped9 b6 q& B; U/ ?3 p$ p
* together and operated on in the same manner.  ksets are used to5 r; S. n4 n  `+ E  v
* define the attribute callbacks and other common events that happen to8 _' }# p' A5 T' V) ?$ s
* a kobject.- R% Y2 q. n+ ]' d
*: I4 E3 `) ~7 {0 J+ B
* @list: the list of all kobjects for this kset$ t. i* ~# G, ]8 ]6 P# s1 E
* @list_lock: a lock for iterating over the kobjects: r2 r# i3 h# ~: Y, M9 ^. M4 d
* @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
4 Z, ^1 m4 K1 d" j * @uevent_ops: the set of uevent operations for this kset.  These are: k4 t& ]' Z/ [, v# O! F; ^
* called whenever a kobject has something happen to it so that the kset6 c7 l6 H6 Z: o9 U' D+ o9 k+ i2 p
* can add new environment variables, or filter out the uevents if so
3 m( j! H0 g: |5 B2 L1 I4 U * desired.2 H$ s/ C2 B% n" |
*/! o+ F+ H/ I7 _0 A% n2 R* L
struct kset {
2 B1 O# ^( f5 J. L/ T# ?( p        struct list_head list;                /*属于该kset的kobject链表*/( T! m5 l- G( s5 J3 B
        spinlock_t list_lock;        ( a' q  j  Y2 m3 c8 K* C4 w  Q4 b
        struct kobject kobj;        /*该kset内嵌的kobj*/( }2 U; P" O  {7 k/ Z8 Z! |
  _7 T$ T2 ~* u* d& g4 N
        struct kset_uevent_ops *uevent_ops;& `- T( P- N) L$ A
};
& Q# Y1 f( Z# f" K7 k( M* |1 B2 l+ B1 j3 ?+ j' i3 \  ]4 i! E/ U
2.3 ktype
$ X7 o/ m& p4 w8 q% {9 L$ C每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。
6 b7 h9 _1 W2 |6 A3 G$ q" R  g/ y9 i
& D- C6 _$ v* N- U9 Sstruct kobj_type {
3 ^* z1 o8 j% I& u    void (*release)(struct kobject *kobj);
- j/ K* z/ G/ l/ j3 p    struct sysfs_ops *sysfs_ops;' w+ u: S2 N, V
    struct attribute **default_attrs;: r  E' k# x0 S
};
9 ]+ P$ r$ ~: w! W7 F+ p6 N& @6 x3 n! G
struct sysfs_ops {
# K2 n2 \0 M- M    ssize_t    (*show)(struct kobject *, struct attribute *,char *);
6 H! b( N# W. [$ u4 [    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);
; b+ x, ], T6 v$ i6 @};9 j: Y: W4 w* z* K" A3 ~
0 U) ?8 ]* v4 O7 F
/* FIXME) j* h) ~( x' ^# N8 E( ~; F2 X
* The *owner field is no longer used.6 y) ?" H- `/ V8 E' I6 A  M# {8 @
* x86 tree has been cleaned up. The owner
, S3 v( H1 x! n/ ^ * attribute is still left for other arches., x) Y# T/ u$ P
*/, m( n) q& R) J5 x  A
struct attribute {0 [" l! u, }- h
    const char        *name;% Y! b' U" t% Q
    struct module        *owner;& d. _; x8 `2 Y, p+ z4 z" v$ l
    mode_t            mode;! Y0 b. A* }3 |' g8 A* I
};
0 x7 a* m/ z3 G4 R" T
, `) B2 ~. D4 v( `3 U# s; j3 p
% N9 W/ s0 Z0 \/ [# r' ?! u当kobject的引用计数为0时,通过release方法来释放相关的资源。6 t& V& f8 e/ U# z4 N, D
attribute为属性,每个属性在sysfs中都有对应的属性文件。
3 [8 n, `, s) G5 d( R" J% r: V3 z0 x7 K! c# I1 g9 s
sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。
2 `* X% D( z5 E" b) `# s; F! z, \+ Q- L" x
2.4 kobject与kset的关系, K  V; ~; [7 d
  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。. @+ ?# E* m1 `& y" J& U( D

0 O! T# K0 u. v8 F; g   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。
+ n+ z* W+ y9 J1 t
: x# b; R7 N: G! Y3 X2 z8 [- Y% \ ; j9 n! Y" @. X3 b4 Y% c4 ?  g
- r: ^5 @% F+ r# d6 ~8 j& C  B
3.举例" r* t' t5 [; F- ]# `) w
在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。& V2 g* ^  B6 x, X& k/ G
  N( K3 s% e# P3 C' }1 a
下面代码位于drivers/base/bus.c3 I/ d8 ^/ r, T2 A5 W# \
int __init buses_init(void)5 J5 G. N3 C  ^& B
{
# k6 A% H# L: s( }+ N        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
5 q6 D/ Z5 u% `! P$ }. x$ I' K7 N        if (!bus_kset)
1 Y, `2 Q* \; _- q) X                return -ENOMEM;
8 y3 u2 v" A5 @- Z3 u        return 0;. H: v% n* `/ t7 y8 b
}4 x$ K2 a8 @+ K$ K% d" J
4 h* |, i) w" Q5 c  `2 [- a
static struct kset_uevent_ops bus_uevent_ops = {) S5 F) n5 N2 g( |! u
    .filter = bus_uevent_filter,
4 l9 n, X' Y3 o- q1 T4 p. S2 P};- p8 {& @3 f2 @, Y8 l* i- J9 m0 M0 c
: T9 s, d5 f4 J9 o+ c* @" c
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)( Z' ^: U( R* ]
{5 w* T9 j0 E4 r. z+ P9 F; @
    struct kobj_type *ktype = get_ktype(kobj);5 F2 R0 S; T% C2 p' U& w

2 h! y% Y7 `! L. H7 Z! m    if (ktype == &bus_ktype)- S* k$ _4 x, w) {
        return 1;1 X; u, }# G. N- v/ ~# P% ]
    return 0;
; M0 V% \* I" e}5 M$ n: H1 X8 L! e$ P$ s
这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。
- d* \! {7 {; }$ u" @3 g; @& Q( b下面代码位于drivers/base/kobject.c
; c7 j* G5 H7 W9 m! F% F  [/**- ]0 ^6 H2 R7 r
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
$ D+ \9 B  z  {' N *
3 H8 o1 s4 d1 Y* R( r * @name: the name for the kset
7 W' N7 l) t+ U" ~6 T! }3 _ * @uevent_ops: a struct kset_uevent_ops for the kset0 f  \0 v; y/ o
* @parent_kobj: the parent kobject of this kset, if any.& n/ W1 Q' r+ C4 i2 u5 N  u
*2 D+ {2 x% M3 [1 h% @2 L0 U
* This function creates a kset structure dynamically and registers it0 Y9 j5 v) i; h: Z- ?; h
* with sysfs.  When you are finished with this structure, call6 u- n' L+ D/ R' i. b* c5 T
* kset_unregister() and the structure will be dynamically freed when it& l. k5 ]/ x- {. `$ \
* is no longer being used.
( g7 V6 j- s+ `: R *2 d. j- M  O0 X6 l
* If the kset was not able to be created, NULL will be returned.0 ^# o) t  d+ m1 i& x4 p4 h
*/6 [# l7 Y2 R* D
struct kset *kset_create_and_add(const char *name,
7 u' P6 G6 h1 T1 L0 ?* K                                 struct kset_uevent_ops *uevent_ops,
/ P+ S/ s$ N; p4 z$ e# ^                                 struct kobject *parent_kobj)
6 X: O% H6 T% V+ N) S{
! V9 N) O7 h* p, W7 k        struct kset *kset;- C5 R  v$ U$ z( j  Z
        int error;
+ T8 D9 j! T) A! g# P* ]# Q. ]) |+ I
        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/
7 ?7 ^5 n& h% S# G        if (!kset)) t  ~, n1 @5 q7 k
                return NULL;  H% |1 c- ]# R( l+ A( ^' E* M8 K& B
        error = kset_register(kset);        /*添加kset到sysfs*/+ A. N% X4 U# `0 y0 q
        if (error) {' d" W( d. E0 g- C" f5 u4 y0 W
                kfree(kset);
, P4 F  i5 |& E8 q                return NULL;% Y- V0 U3 r3 ]" R) l4 e9 S* k
        }3 U- Q" D: E8 z5 y& D0 I
        return kset;
+ D7 i5 z5 u6 r}  L5 S5 a+ w9 `- `) q( j
这里主要调用了两个函数,接下分别来看下。
- p0 h  G* _) e# j# b3 g
4 G- r, z$ w2 I0 Z4 }3 |3.1 kset_create函数
4 o0 I3 }! m: A1 M7 J下面代码位于drivers/base/kobject.c- A; o% Y0 `" z# m# b( Z1 e

! z# ]3 ~0 ^' X: g: f6 {; D/**% n7 v$ s, B9 }4 X% \
* kset_create - create a struct kset dynamically/ R' d0 l3 O5 v( i: b
*
7 e. T( ?( c" J. | * @name: the name for the kset( Q8 n) \+ _$ m$ A, ~
* @uevent_ops: a struct kset_uevent_ops for the kset
. p+ j  O! d/ v5 ^1 \. c( N- q * @parent_kobj: the parent kobject of this kset, if any.! o6 F& ~' x) }: M- @% P( S5 a
*
) d9 K5 h; D; Q% z) U * This function creates a kset structure dynamically.  This structure can
6 j! `. |# x  [ * then be registered with the system and show up in sysfs with a call to1 p( J+ b9 M3 O2 n9 l
* kset_register().  When you are finished with this structure, if& [- e% Q( U) e4 @; J
* kset_register() has been called, call kset_unregister() and the
$ k* h) P) ?2 k/ d& j * structure will be dynamically freed when it is no longer being used., t, b3 B( D2 A. W, d+ g; J: y
*
7 ^% u1 [+ H! w0 u6 j, V1 a7 K * If the kset was not able to be created, NULL will be returned.
; }  d5 W1 F  I$ r4 e9 X */
( U; W, o$ R# Q8 c4 Y1 ^# pstatic struct kset *kset_create(const char *name,
+ h& N% K; F5 w1 a% B                                struct kset_uevent_ops *uevent_ops,
! `8 h+ ~4 _2 A: m* n) O                                struct kobject *parent_kobj)
: n' K; r5 @0 r0 B  l! J7 @' f{- D5 I) ]& s; h! X  t
        struct kset *kset;
6 I5 o8 L' y1 }  S7 g* ~4 T( a+ ]8 }2 Y
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/" K* b/ a# m1 o6 z" I
        if (!kset)9 {- O: n; N( v2 e5 r  |+ K' e
                return NULL;
, x" B6 A+ x4 V9 E% A! N- s5 g0 s        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/* |, @% l  S6 ^
        kset->uevent_ops = uevent_ops;
+ E+ X& I/ S# m& M        kset->kobj.parent = parent_kobj;        /*设置父对象*/
4 _/ c! F" Y: T6 O! G( n; f# w* P6 M  e- W; j
        /*
( R6 {$ g; `6 n         * The kobject of this kset will have a type of kset_ktype and belong to
# n( m3 N' Q' g. d' D: D         * no kset itself.  That way we can properly free it when it is
1 H* X0 @- y- Q         * finished being used.
1 q; w1 x# J# l  }% D9 I8 ]         */4 n$ g! L& @) s( K( R" m6 ]. j" F
        kset->kobj.ktype = &kset_ktype;, c+ f3 W, ~/ S; N1 N! I
        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/
( F% \6 B! P! C9 h' Y+ y. k' j4 c# R" |4 z4 H. V
        return kset;
* |+ `$ p- Q* Y: V}
2 T9 j; |- Q$ z- A
7 r5 ~% `* A+ J1 ^这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,
  k0 B$ b5 s' [) r
: r' ], d* {; h. a也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。$ j2 O5 A( G; L; ]; [
% l3 W/ N& a0 l
随后简要看下由kobject_set_name函数调用引发的一系列调用。
+ Z! D3 V5 b& r: C, d( l- h/ u
; Z6 [: `1 w1 n/**
, h" a% Z3 j+ C* Z) p) D * kobject_set_name - Set the name of a kobject
' v5 k4 z: l" r" e1 c * @kobj: struct kobject to set the name of
2 A& \, K! u# e+ B1 B" F7 } * @fmt: format string used to build the name: L. V: w  I$ q2 q# I9 d
*
; P3 ?& g1 {+ O& t" D3 w * This sets the name of the kobject.  If you have already added the
+ T* f7 T0 a8 ~, O2 w * kobject to the system, you must call kobject_rename() in order to" [' {8 N% ]. J6 @' b$ L1 S
* change the name of the kobject.
4 J# y- A% L! v0 G8 J */& w, {1 h3 N- U5 s- u, k& B. k
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
+ O: F, D1 P) a{. `/ W' @4 K' g) M( {5 V8 j
        va_list vargs;5 x. {1 k4 v+ `( l1 _% _
        int retval;
$ c2 C3 Q# l! b: G( }6 S* ]* B; G! F; {9 n  j! a
        va_start(vargs, fmt);
2 F) K* [+ @0 W# _, V9 e7 ?        retval = kobject_set_name_vargs(kobj, fmt, vargs);3 \/ a& v; h3 X5 g9 P+ u
        va_end(vargs);, W9 n+ U! E( V0 g: e$ b+ O. i

9 q- g& i  N3 N2 p        return retval;" W0 V5 D7 s4 T" j
}
5 m, E/ G/ H- h( ^9 y2 W; N& [1 T+ p& c( [: m7 }
/**& t# u5 I9 R7 Q: e) {
* kobject_set_name_vargs - Set the name of an kobject
1 z' m6 u, B  x * @kobj: struct kobject to set the name of; s  j! |9 L2 `2 ~, {
* @fmt: format string used to build the name
" i2 q2 U" O* z * @vargs: vargs to format the string.
) b6 G; z; A7 }- ^1 @  z; S8 A */4 {0 z6 K: t. `4 z  U2 y
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
- x  q1 A% O# t6 p6 v                  va_list vargs)+ [' a% m3 P/ o3 ?! t' u5 L' {8 r
{/ B0 }, ?. a$ F6 P: ?+ \: v9 K
    const char *old_name = kobj->name;0 J: c% L; z+ l, D% P& f* ~0 Q& H
    char *s;1 v3 a, F( \, x; y
0 ~3 m/ |: S( x3 a: n
    if (kobj->name && !fmt)( }1 b; o- ^9 ?7 e
        return 0;) p, z& e5 r4 z  L

. f+ N3 o* O3 Y! ~4 o    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
# z! S& j2 |+ V7 y    if (!kobj->name)
% }) @: \. K5 D        return -ENOMEM;# h* b7 F4 D, S1 z6 w- N4 `
+ A4 T0 h+ c. E
    /* ewww... some of these buggers have '/' in the name ... */
! ?/ S$ y& h8 V. h& g    while ((s = strchr(kobj->name, '/')))5 ^8 n* ^1 U- l  p; y) B# I3 {
        s[0] = '!';
. j2 R4 w( {: h# c5 @/ j* Z; J4 v# A9 P3 T
    kfree(old_name);* m' m+ T8 x8 j$ C% m3 A
    return 0;3 @$ f  X: D6 \) A6 h+ ~/ C
}
0 X1 s7 g# h7 N3 D6 C3 w! h; f" ^+ A; o, _
/* Simplified asprintf. */
2 N; ~/ i0 A/ \/ x5 m+ ], j2 E- Y7 Tchar *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
2 ^" e; Y. f  t% s{( k% s* f% i' ^) e. V/ d
    unsigned int len;: _3 Z! R8 O) s0 X
    char *p;& |( v# e% e  B
    va_list aq;. W9 y/ V6 ]- ^3 l* s# V
0 ^+ l6 _, X. T
    va_copy(aq, ap);
8 M3 I$ A0 Q. B; f# c5 t- F: t    len = vsnprintf(NULL, 0, fmt, aq);9 C: }* H" S/ d  M
    va_end(aq);, w4 G7 Q# P# U  T' j6 p

) ]- F8 [* Y8 X9 F4 O4 V    p = kmalloc(len+1, gfp);
/ M+ O- b+ a8 `+ r! c9 K- D5 P  b4 w    if (!p)
  }/ C$ m9 o0 i9 X" A: g        return NULL;8 |: A8 Y8 W* e  Y. B+ A* Z
$ Y. c# i" M7 L1 \
    vsnprintf(p, len+1, fmt, ap);& o# z, D! U# N  x: \

) W+ e0 ?0 `/ Z( {' V2 }' g    return p;! u3 F; {. g- s
}" {$ j, O9 x" X0 y5 w( O
3.2 kset_register
- \7 @3 w$ r: f5 m$ k' W, f下面代码位于drivers/base/kobject.c。6 y+ |( l4 D3 j, u6 q. I: ]
/**) i6 k+ z5 F7 a3 E0 x1 s$ J
* kset_register - initialize and add a kset.
, A. g. _# H- q0 Z' \# i * @k: kset." r1 \1 H% _! \! P
*/- x' C  i6 {, ]$ |6 c
int kset_register(struct kset *k)
. U: Q; c& q2 y/ `( @{
! q" x, [3 E- U4 q4 R        int err;2 T, I/ \8 _5 R
7 P' y  v- W' s( \1 T
        if (!k)1 }$ \- y3 M. a: a$ {4 R6 G! y( C
                return -EINVAL;
; k* W6 M, o7 u. b4 }- G+ d$ D; S$ ^, B8 z
        kset_init(k);           /*初始化kset*/
& @/ c0 G8 K& Z) Q8 H. k        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/+ ]! M4 z* P, F  p. m5 u( d
        if (err)
" z: `8 {  W, A; I. U1 P* [                return err;6 x1 O) W/ @; ~# F$ S' o
        kobject_uevent(&k->kobj, KOBJ_ADD);
! ~* D7 G1 o$ c/ z) r( q* d        return 0;9 v1 b+ q2 t6 v! O
}
; U' ?( H0 V7 c1 |, {这里面调用了3个函数。这里先介绍前两个函数。6 o& @$ D/ F% ]" F3 F3 t' Z( |

0 x- i. Q1 o6 C5 ~; L5 i$ L8 S! b3.2.1 kset_init
) g8 r' h0 k) R& I. H8 m2 r  该函数用于初始化kset。
4 t% V- h+ m, ^8 I4 h, c, O
" C6 U9 L( @" D8 O7 h# |  下面代码位于drivers/base/kobject.c。) ~0 ]/ O# H; h1 b! y

- t! \) }6 _# k. y0 Q' B, E. x5 b2 m/**  o) P6 y1 u- F; d
* kset_init - initialize a kset for use! ^' P! _$ T# c1 n, k9 L
* @k: kset
4 N) q4 C3 T% u! K2 Y4 P5 } */
% J, D: u6 `# M5 n$ T  X/ wvoid kset_init(struct kset *k)
" b1 g+ u8 D  d* w  t{
; a  E& E6 O, I# Q        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/! G% y1 h! W5 a
        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/! }! ~/ p" R  j6 V6 g0 X
        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/
! I! h1 @, H$ O' O8 Z4 |}
% N0 g+ j- k3 ?) q# l$ K7 ]* ^2 U" N3 G% N+ |
static void kobject_init_internal(struct kobject *kobj)4 u. a3 y% K4 F0 G" s
{: ]- _* g) q' F( Q/ ~& U
    if (!kobj)
$ E2 l  f# M# \- j$ Q+ O: c        return;& s1 O, C. |7 n, ~8 H
    kref_init(&kobj->kref);           /*初始化引用基计数*/" F5 E) u& H/ H, H1 ~
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
- }0 d! e8 T4 k$ G6 ?- K    kobj->state_in_sysfs = 0;
9 Y' {! S( N! \# E. }    kobj->state_add_uevent_sent = 0;4 D6 ?9 X6 T( m( j) L
    kobj->state_remove_uevent_sent = 0;
  Q0 S7 `8 b8 \    kobj->state_initialized = 1;
4 g4 K$ C0 b) k" s0 i( m3 _}
, d2 G' G4 p, `7 g( i2 z& }/ O3.2.2 kobject_add_internal
+ y& Z: P3 u! Y& @& t  该函数将在sysfs中建立目录。7 c! U! l3 X! ]: ~* `3 n8 ^; ~* }
; P& @- R1 v; e7 o2 E  _
下面代码位于drivers/base/kobject.c。1 c: Y8 T. a2 {4 k
static int kobject_add_internal(struct kobject *kobj)8 u5 g6 J# [. B
{
; B0 n0 \- x9 a% [        int error = 0;
% O4 B: u, c1 J0 ?1 E4 `2 e& m        struct kobject *parent;
; }+ w4 Z6 o5 Y) r
% g8 J( o4 Z% g5 I2 p        if (!kobj)  n- v( l) S: g& @5 |
                return -ENOENT;
' L/ S6 D/ M: F2 f$ t) L1 S4 ?        /*检查name字段是否存在*/1 U6 W! t2 ?- ?6 a7 E
        if (!kobj->name || !kobj->name[0]) {$ Z" N6 i: e. |9 p
                WARN(1, "kobject: (%p): attempted to be registered with empty "
9 d/ j) z. v0 ^                         "name!\n", kobj);
' t- A" l% r. F" s* z                return -EINVAL;
: i9 ~+ V7 x& \$ S        }2 [/ |0 |0 C; r- _* v, S' d

- o: v" v1 s% a3 c' Z        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/4 Z  @, K7 x1 t: y! t

2 A, f. X  X% y2 s2 ~9 c, R, h. j        /* join kset if set, use it as parent if we do not already have one */# ^# f- F2 u- k' Y  L5 U
        if (kobj->kset) {       
0 i' C" w- P. R/ p3 `& M' i                if (!parent)
! r, x, S* O8 b* X                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
7 B/ f2 o0 x' R0 S# l& g+ ^9 v                        parent = kobject_get(&kobj->kset->kobj);
8 G5 [0 e7 i( r  y& t) Q                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/9 D$ J* _% l9 A3 |" J+ ^7 `) F
                kobj->parent = parent;& T( B9 {) m, |0 i# e2 C  V
        }, W( u4 }* W+ F! o3 T% ?
6 p  b1 V" J* w+ r* S
        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
- n8 J, G$ K3 z                 kobject_name(kobj), kobj, __func__,  s. H5 z9 f* i. p  V. e# e, t
                 parent ? kobject_name(parent) : "<NULL>",2 C( k( y4 M! o% p$ I6 U6 e; P
                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
! a- z( d( _+ M3 }9 ~
" }" F5 d" B2 P4 E3 H) H        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/
5 a$ H# B9 o) {2 P0 \( s        if (error) {
1 i4 v7 H' n1 b  c& X! d) G& d! B- Q                kobj_kset_leave(kobj);        /*删除链表项*/* k- k) k, T. N+ i
                kobject_put(parent);        /*减少引用计数*/
7 s# f( y7 @- Y# `/ g- s9 ~4 Q                kobj->parent = NULL;
# r3 m' Y. [7 E
; M: ]- Q9 Y  @; M! K$ Q                /* be noisy on error issues */. W& @+ c  `3 i/ Z3 q1 Q" v6 P
                if (error == -EEXIST)
8 J  M( ?4 B7 J$ }% _                        printk(KERN_ERR "%s failed for %s with "
( {5 @+ q1 o2 T* M                               "-EEXIST, don't try to register things with "
+ z: X, q5 x) \, Z3 t                               "the same name in the same directory.\n",5 S1 `8 Y. h/ |
                               __func__, kobject_name(kobj));' E2 A; U* l& h) n# b. B2 J( ^
                else
4 d- \+ f( S% ~* ^                        printk(KERN_ERR "%s failed for %s (%d)\n",
2 l# N+ [5 i4 v, b7 S                               __func__, kobject_name(kobj), error);( P' ^- m2 N- i" i& r% \
                dump_stack();* E) k% |- L7 ]2 x' N5 U( t* r
        } else
+ q( G8 S* Z* b6 }( _# B                kobj->state_in_sysfs = 1;) {. R9 V- T) s  m

) U. I' m: F! _/ b        return error;
" ?4 a* c; |4 ]6 A  w}% T. w& [+ l0 y3 m) D

& w, k( T0 y) q, r; ~/ _/ J, [在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。
; n5 L7 S: ^( v; X# `, X& ]( F- Z2 v# P3 h8 Y  A
在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。
7 R' e5 q9 y$ ^5 m# K- R! d- h2 a' }( R
至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。6 _# W8 f& O0 [

* b9 j# S( Q6 J4. driver model
% t1 M" d. r0 E! H2 `4 n1 ?0 z+ j" j第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。( h9 k; C4 b5 X: r% G6 c4 P3 W

% o: [) B5 M+ c+ V. b8 t( hLinux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。" F2 g# h4 d# r8 `0 h! s
7 y' d( B2 r, O
这个属于分离的思想,将设备和驱动分开管理。7 o9 _0 l) s. M3 p/ t$ S% l

& C3 s' z& F( Q# }同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。
' R* F" X3 f) e6 F' H, J5 r
8 C$ E5 _2 f# [  o4.1 bus3 _9 f/ |0 I- C7 D9 z
总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。
& Y9 h6 W! S$ B! B0 g) R+ p" y9 q3 `, i, w1 Y5 m, t
下列代码位于include/linux/device.h。
& J- N$ B: ^9 z% z! _/ E# T: |% a) \. }

5 i% Z2 b! K3 A  U: }struct bus_type {
3 r; k! t  [' G& P0 f! u    const char        *name;# q: u* P0 @3 {9 A: p$ S1 Y1 a$ J
    struct bus_attribute    *bus_attrs;
/ v2 |8 g+ D# f; C    struct device_attribute    *dev_attrs;7 D7 d' n( g) h( ^( a  W( ?
    struct driver_attribute    *drv_attrs;
3 j6 u& u: C& F2 j( [& ~$ }" B$ N6 s1 J5 g. V
    int (*match)(struct device *dev, struct device_driver *drv);  I. y) O3 x- m+ S2 X; S$ H
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);4 q# j  U& a1 z: u& _, ]
    int (*probe)(struct device *dev);5 q# e; j# {* I2 o: k
    int (*remove)(struct device *dev);& e; U  B: W/ V' D, }6 ^7 Q
    void (*shutdown)(struct device *dev);
1 E9 u* L2 [& V, o/ f
: I# v0 D/ |9 `8 X9 G    int (*suspend)(struct device *dev, pm_message_t state);
: a1 P& ^' i# R# j4 i( P! B& s# [6 Z    int (*suspend_late)(struct device *dev, pm_message_t state);
6 r5 m. a8 B; C( I( W, C: k    int (*resume_early)(struct device *dev);
8 R8 ]; }7 r) N% j% `    int (*resume)(struct device *dev);
) t- `2 P* V6 N- a# k  b) J2 x6 v3 a5 E& P4 F# |! a- b7 A
    struct dev_pm_ops *pm;! J2 B5 @- c4 R2 q5 B$ f" r
/ c$ ^5 B- l# g( g
    struct bus_type_private *p;
/ J* R8 ~( `/ b$ O8 M$ i};1 M4 O, a4 |  K

' j8 @5 o9 B. e/ l/**. Q5 V3 e1 H! f
* struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.3 B/ D) J  y; ]( ~' B8 D+ I. d9 |' e
*+ j6 E) A& [. z$ m
* @subsys - the struct kset that defines this bus.  This is the main kobject
, n5 t6 X* U/ Q) Z3 p * @drivers_kset - the list of drivers associated with this bus
, y2 |- I) I2 b1 T' O' _ * @devices_kset - the list of devices associated with this bus
$ G) Y) A1 K8 d4 W6 p5 b3 Q, { * @klist_devices - the klist to iterate over the @devices_kset
! V$ }; i8 _7 P4 m5 j * @klist_drivers - the klist to iterate over the @drivers_kset, q( C5 e& D# f
* @bus_notifier - the bus notifier list for anything that cares about things/ g" M8 N, n+ o/ U4 M& D
* on this bus.  b3 x. [4 g3 R4 v+ M3 K+ L" U
* @bus - pointer back to the struct bus_type that this structure is associated
( J# _7 i6 ^7 b2 Y) u  g * with.! i5 N; {2 d( l8 b' R
*/ f  X  g/ D6 C3 X* @/ J
* This structure is the one that is the actual kobject allowing struct& ]. t% }8 U. b$ c
* bus_type to be statically allocated safely.  Nothing outside of the driver* d$ {2 `' i- F" z2 F; I2 Q5 B
* core should ever touch these fields.+ E7 N1 a; X. N3 t/ F
*/
4 R- g7 z/ f3 Z! ?struct bus_type_private {
# P* N7 {7 U- `6 M    struct kset subsys;
1 V0 @; I# ?+ }9 o8 g    struct kset *drivers_kset;. D, d1 M! Y! w
    struct kset *devices_kset;- k0 P1 z- U; u
    struct klist klist_devices;. k1 B, h! ~+ G
    struct klist klist_drivers;
8 Q) n* L) @  p0 L    struct blocking_notifier_head bus_notifier;
0 E2 N+ K: W; q    unsigned int drivers_autoprobe:1;
# `# N, P( o) \' f    struct bus_type *bus;
4 i4 u7 p8 p, p# {4 l};) B5 _3 Y& _/ w( r+ V
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。
$ T3 _. S7 O( gdrivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。
" i* A  J0 ^0 T! }5 ^* Q6 i' Z0 v: X8 t1 M- n
同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。
7 H+ ]3 z) D- k+ s" L+ S- T
0 e. d  e: @3 I$ }- `3 q4.2 device
9 _9 ]9 [/ x% n* g5 P) {6 T设备对象在driver-model中使用struct device来表示。1 Q- F, d1 G/ Y8 ]" y; Y6 W4 o6 ^( q

" x# r* X' @* u% |下列代码位于include/linux/device.h。& [4 i4 q5 X* @  X% p4 \
struct device {
* e! Y9 @/ U) ~$ y/ K# e% v. q        struct device                *parent;
* J  G0 Q7 x6 |+ T6 y
) X/ N* L! f4 n5 R        struct device_private        *p;' m% W8 m* f% C5 X; e
# {' D( Y7 \$ s
        struct kobject kobj;
! L/ f! U: r0 G  O* J' h        const char                *init_name; /* initial name of the device */
& {4 ]- {: X+ p- P" C7 h        struct device_type        *type;! O  x, A0 F' s  q
1 ^0 F& Z1 M, N% O& |4 X) C& p
        struct semaphore        sem;        /* semaphore to synchronize calls to
( `3 s. N  |- |3 h                                         * its driver.
$ P, g' {; y! B6 m3 w                                         */
# L3 k: |$ c5 f1 }0 t+ B* {1 Y8 Q. L
. b. l1 \' H; N6 n# ]) g        struct bus_type        *bus;                /* type of bus device is on */
* `2 F6 H3 _- C" y4 N6 [        struct device_driver *driver;        /* which driver has allocated this
( R* Z' L5 ~% O. [0 d                                           device */
3 b4 d% T# J* W+ f        void                *driver_data;        /* data private to the driver */
  t) ?, X% z! @" x" l3 }4 `        void                *platform_data;        /* Platform specific data, device$ {# \6 o% r  n- t  i* l
                                           core doesn't touch it */6 @: @+ |/ m1 L/ F* i5 R
        struct dev_pm_info        power;
4 H& V; T/ M( _7 n3 r3 k  L. k% |9 |
#ifdef CONFIG_NUMA
$ ]7 Q, K& R  Q) t% S- n, ]        int                numa_node;        /* NUMA node this device is close to */
+ S) n, k" G  C$ ~6 u#endif
  ?" h' \6 A/ H, M( y        u64                *dma_mask;        /* dma mask (if dma'able device) */% x" u/ z8 c" Q3 o% ^
        u64                coherent_dma_mask;/* Like dma_mask, but for
4 g, t. w) I2 A% f7 r                                             alloc_coherent mappings as2 I. ?- A) I3 ~3 f7 `* Q+ D
                                             not all hardware supports
$ E6 f) r1 H( _# T                                             64 bit addresses for consistent
: {3 I' c! C  l: @                                             allocations such descriptors. */
7 g; y8 s- e3 U6 h" k4 ^" u6 p+ o5 K1 K4 X: m4 D; C- |
        struct device_dma_parameters *dma_pARMs;
. r4 f. ^# e8 o/ n, K7 x, E8 ]. H" _" V! k! Z4 p
        struct list_head        dma_pools;        /* dma pools (if dma'ble) */
/ G. @4 Y; e' ~& X( ]' h; d1 _  c( p% T8 \3 p
        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem; O+ _/ }( @- l! E6 p+ V0 @  |
                                             override */* U- ~7 ~( S4 R/ D; ?# S$ a
        /* arch specific additions */
8 G% V( p. n% N$ P$ ]        struct dev_archdata        archdata;7 ~) x9 R& P. h

3 K( a! a- ]0 [4 w1 B" ~7 ^        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */4 r6 G9 o; c1 Y8 T' ]1 n* U
/ g9 j- u* A/ b# \( I% M; B  T
        spinlock_t                devres_lock;6 N4 j& `( c. j; K1 `; B
        struct list_head        devres_head;
8 M$ `$ l) z* O- d# |3 T9 d: F( x6 B7 I0 p3 s
        struct klist_node        knode_class;7 z* c8 b) z7 q6 _( F6 S
        struct class                *class;  h9 f( W( [$ _  o8 ?
        struct attribute_group        **groups;        /* optional groups */
9 r4 Q0 V/ o( }+ ]4 O/ i6 Y
& ]5 B; L9 g9 g7 R8 G8 U4 @        void        (*release)(struct device *dev);9 B. t1 \3 |5 X
};# n' l" E2 c. o# _1 q4 D+ D% V
* I+ y" `: ^- |) @- ]7 \
/**# }! B! n& q/ h5 X5 K
* struct device_private - structure to hold the private to the driver core portions of the device structure.
# M& ^2 r+ c2 m: l+ r/ [" f *
- N) L5 [0 i* c& C9 m * @klist_children - klist containing all children of this device0 V$ _0 l2 \$ B  G  x9 Z
* @knode_parent - node in sibling list
4 ?) D9 v, u& L9 ?3 R9 J9 Y. F * @knode_driver - node in driver list
! @) k  s  Z- O  X4 y. x9 d * @knode_bus - node in bus list
7 b: y; O) @5 g& T * @device - pointer back to the struct class that this structure is
1 c7 d* ~3 S, N$ B5 M( ] * associated with.7 d) L8 x  q; M9 ?* j, e
*
, {. w) {' d8 K/ T% x, g * Nothing outside of the driver core should ever touch these fields.
( F0 R8 j8 {3 }! I- {/ C */
$ R% D, }6 e5 E, j6 d. Bstruct device_private {
" N* n: A, U4 p: \    struct klist klist_children;+ d3 Q! |: `1 H% ?
    struct klist_node knode_parent;
% S; n$ y3 L9 k4 ^) @3 n5 }    struct klist_node knode_driver;
- i% M+ m0 w/ S8 I. g    struct klist_node knode_bus;$ j( O0 z8 A% Z: a" S
    struct device *device;
$ b9 ^5 T. }. Z( t: C4 l. R};6 x+ j! Y! d4 @* V
device本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。. y% ]+ l: o  ~* V1 l: ?( h

+ T* ?$ C5 r$ E5 m: G该device所挂载的bus由knode_bus指定。) d# n# F/ n3 p1 O
% j" \" b* ]# D
该device所对应的设备驱动由knode_driver指定。
8 p5 P, H( o  ^( j- A; ^! W+ o; G: O( h) f
4.3 driver
0 d7 \  c- B% a8 h9 f5 k) R0 N设备设备对象在driver-model中使用struct device_driver来表示。# D0 L3 z' W$ H( d9 W

% t% r0 g/ y5 @: z; ?6 ~下列代码位于include/linux/device.h。5 M$ d+ }6 n; s9 i
struct device_driver {0 e7 f1 L1 e! b
        const char                *name;$ L/ D8 n* U$ C
        struct bus_type                *bus;' j. E9 N' _3 \( s
6 N! p) G0 b  w3 c1 S) l
        struct module                *owner;& Y7 _) g, k: L# o
        const char                 *mod_name;        /* used for built-in modules */$ d6 ^9 j2 j2 V& x
& k( C0 E3 t/ q
        int (*probe) (struct device *dev);
! z; N7 k. T, p9 Y5 b        int (*remove) (struct device *dev);" O. r4 ^$ _- L# y$ q& j
        void (*shutdown) (struct device *dev);) h$ ^8 k$ g+ u
        int (*suspend) (struct device *dev, pm_message_t state);
  T' Q" }( R4 _! Y. }7 f" i        int (*resume) (struct device *dev);- s; {! c/ J, Y" a
        struct attribute_group **groups;- G: e9 N( h! Q7 S4 P; C

% F& C  y5 t8 i) t7 V        struct dev_pm_ops *pm;: E0 @. Z; @) J. k9 `

8 _' T/ n& b! I8 V        struct driver_private *p;2 v. z0 O7 @* u; L5 W& K9 f) J
};
& c4 F' ]1 N1 G# W! c4 I! a  P" Z
2 Q# ~/ k$ m: ]3 }, ystruct driver_private {: ]4 W9 U. A; A7 c
    struct kobject kobj;
3 R0 i% x3 N, d    struct klist klist_devices;
2 J% F6 A/ A, V7 m; S6 b    struct klist_node knode_bus;/ F+ B5 O0 b/ d& _
    struct module_kobject *mkobj;
6 Q2 ?9 X9 E- f: U& z    struct device_driver *driver;& p. P- |  N( r
};
. B' z- d$ I$ \! g9 L) M2 ?device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。
+ h4 F9 t3 ?3 D2 L5 v) |) Q4 o该设备驱动所支持的设备由klist_devices指定。7 I7 L  G  d4 @% `6 H$ Z' W
& [) U! ~) G3 O$ D) j% \" r  F. Z
该设备驱动所挂载的总线由knode_bus制定。( C( E8 v0 j6 Z) u8 @! z
9 K8 @5 ?" M& P* i% Y
5. Bus举例
% R  B! A0 T% P3 l: |4 D本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。" }4 R; B8 V1 k7 J

2 W5 z/ u. y! \2 Zplatform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:4 f8 h: l" g# e
2 ^' {' E% a+ m1 [8 `/ y8 U
start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。4 x: \" e, L. H1 \/ j

8 E- w9 {: {- v) C注:kernel_init()是在rest_init函数中创建内核线程来执行的。
, {5 i0 Q$ y2 K- B5 A+ x2 u; \  _* |  F5 T7 y

6 ]( l% e5 g- Q- h5 V& F4 t9 k; U. I+ {& I
int __init platform_bus_init(void)# h  \9 {. S3 t5 X
{+ V0 y! E* A; }5 A, q. c, p4 I
    int error;( M% o( ^  }9 P1 b$ s# X

/ S) P7 ]4 j! M1 W) ^    early_platform_cleanup();0 X# L/ o! ^( r0 C4 ]
8 L0 ?8 s3 i9 v5 ]! O# [$ W! y
    error = device_register(&platform_bus);
2 u& t9 I  w) X* c; k1 {    if (error)
% P& ~1 j4 R8 g' m) D" {        return error;
$ e  S7 n, A* A. m- w6 b8 I    error =  bus_register(&platform_bus_type);$ P  I1 T6 z1 l$ A4 F: S9 o
    if (error)! N4 ^; l9 F& ^. \& D; i
        device_unregister(&platform_bus);0 I2 f0 ]& l7 _* t+ ]) k2 r
    return error;4 ]9 l* @3 m4 H1 M9 j
}
! _' u8 g) r( W" [" s' Nstruct bus_type platform_bus_type = {* o1 }0 a& ^2 N/ F+ j6 U4 h9 j) g
        .name                = "platform",/ y! s6 `6 `: a* Z
        .dev_attrs        = platform_dev_attrs,
- r  W% k) G! Y        .match                = platform_match,% d9 q, E% J7 R7 u' C4 N
        .uevent                = platform_uevent,$ c9 U2 ?# O. p) \# W' l. y
        .pm                = PLATFORM_PM_OPS_PTR,
" u) l& F6 |+ J# t  L6 R};
+ j4 W" f  [( H4 i! q0 [) TEXPORT_SYMBOL_GPL(platform_bus_type);
/ z2 X4 |0 L. `  `, x9 J1 X$ b从bus_type,我们看到该总线的名字为platform。8 U$ h' n  ?* T) s2 A& ~5 \
调用了两个函数,我们只关注bus_register函数。
8 l( q) [% g3 H" n) l0 C6 A
8 i* ?# e% [: p" Y9 U; ~- j4 X# m5 P% R
/**% ?( ]' @! T) b# B" l4 o& c4 G
* bus_register - register a bus with the system.0 s7 g2 E6 l+ M0 ]- h
* @bus: bus.
% L+ X  Z; G0 E+ B8 f" b) t  G *
5 R$ q5 P0 X- L9 E * Once we have that, we registered the bus with the kobject% w  l/ U6 L( e+ D1 W3 P  G
* infrastructure, then register the children subsystems it has:' J- H  @. {9 U7 E3 B
* the devices and drivers that belong to the bus.7 `9 L) h9 t6 \) V7 h
*/
/ A/ |, ?9 i. J$ T  G" f6 h7 Qint bus_register(struct bus_type *bus)
( Q( o8 M5 E9 y# w, v) C7 j; G{
! O: ]4 W; s! V        int retval;' p& _6 B  U* j" I) s5 j/ Z$ E( l
        struct bus_type_private *priv;8 T+ I2 o& O, y, R( m( v$ W
& {% ?( ?7 D2 s
        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);8 }" ~, Z2 c/ [9 ^+ O0 @
        if (!priv)
# R0 u6 W8 K" x- ^) p/ L9 p                return -ENOMEM;6 Z% ?( `' {% L9 E. t) D" J/ d
        /*互相保存*// X" Z) i# P! J. [# o9 Y7 i
        priv->bus = bus;
7 a% Z5 W& M$ q4 r0 Q" Z1 q$ g        bus->p = priv;
: _( n; l' j1 {3 P* Q3 d! q$ B" [
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
1 g! D* q9 W% i$ P# n' f        /*设定kobject->name*/- _3 t8 G% V- i$ W1 W
        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);$ k. D2 q# O$ n
        if (retval)& f6 N8 R" q* s! L, t. B
                goto out;/ J3 H# O6 @+ Q: d

' l0 a1 F* q& y, U        priv->subsys.kobj.kset = bus_kset;1 S. [7 v/ V" S$ p
        priv->subsys.kobj.ktype = &bus_ktype;
3 f8 ~# D9 n. T0 \; @        priv->drivers_autoprobe = 1;& o8 W) x) r) [

/ }! r% \# h/ I! ]# K        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/
+ f* U6 _% {1 D1 i' P        retval = kset_register(&priv->subsys);       
8 ~0 I! x9 l1 K% V6 n+ _* W        if (retval)6 q, P$ V8 W; Y% h  a, X' f5 V
                goto out;" M5 A3 x+ L* i
  _$ J, t3 U) O$ P
        /*创建属性,在bus/XXX/建立文件uevent*/
, X; W* f) R6 q8 J! v# _        retval = bus_create_file(bus, &bus_attr_uevent);4 ?/ n. ^) e5 H1 Q
        if (retval)% \, Y6 Q7 B* Z: _! X- N! A2 i# k& C3 @
                goto bus_uevent_fail;+ y! k# c4 t+ c7 a
7 e+ j% |+ I9 p
        /*创建kset,在bus/XXX/建立目录devices*/4 |) X, y  A* T0 L# u4 d
        priv->devices_kset = kset_create_and_add("devices", NULL,& S9 o; z: ^& v! C6 m7 V3 K
                                                 &priv->subsys.kobj);' C5 w; a% v( Z% W+ E
        if (!priv->devices_kset) {; W' \0 K5 r  ?7 r2 s" F) p
                retval = -ENOMEM;; u$ S8 x; o0 Y$ a, c+ n  Y
                goto bus_devices_fail;' L& ^4 S0 V! Q7 U2 f9 Q% z( e* D
        }
. }% T$ P+ l! M' K
2 e7 _& ?) D7 d" x1 N/ P        /*创建kset,在bus/XXX/建立目录drivers*/, _" c7 f+ q, S5 U' _+ H- N
        priv->drivers_kset = kset_create_and_add("drivers", NULL,
8 `5 s3 r5 d% m9 u. r                                                 &priv->subsys.kobj);
) M& L' A. g% r6 o' p        if (!priv->drivers_kset) {, G' t! D- s3 h% |" A
                retval = -ENOMEM;
! t3 L2 r5 Z* W                goto bus_drivers_fail;
) S- J  v* Z( `6 H1 @8 A        }9 p9 V  A) @' P# \9 k
        /*初始化2个内核链表,*/* V0 Y/ P; U# ^, K# F  C
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
0 ^" ^$ f/ ]) F5 ~7 t, o" t        klist_init(&priv->klist_drivers, NULL, NULL);8 o5 c% M6 y8 m  T4 {* d7 M

2 m* r/ }) }3 f+ ]5 \        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/% Z! O. A( L- w8 Y! u4 L
        retval = add_probe_files(bus);
7 Y) S' |( s4 F9 w$ B        if (retval)
* o$ H; i$ |9 |/ k9 C+ d                goto bus_probe_files_fail;, q0 K) D: b0 {
        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
. Q3 z6 M' c& U4 |; j! r: M        retval = bus_add_attrs(bus);% {. ]8 T! k' W
        if (retval)
8 o" l9 g- y8 ]' T. {0 U                goto bus_attrs_fail;, o0 }3 V1 ^8 U& V8 G1 \" ?

6 \+ V5 j0 R% U* ~% w- D* ]: O        pr_debug("bus: '%s': registered\n", bus->name);
4 v$ J) @9 {9 b+ Z  l& h        return 0;
; w* P, l; g7 }. j% Z
4 X+ K6 A; Y9 I/ L/ {1 Bbus_attrs_fail:9 B6 H; n. R+ E" X; p  G& V# W/ V
        remove_probe_files(bus);) ]" X4 F( |0 w0 L3 N* t* e. K7 v
bus_probe_files_fail:8 |! @' @" b  o' F
        kset_unregister(bus->p->drivers_kset);7 m0 u" S4 {* J+ ^9 Y
bus_drivers_fail:) M/ U" v# o/ k- p, _" j$ B
        kset_unregister(bus->p->devices_kset);
6 i1 G" D1 @  u8 S3 l4 F$ Ybus_devices_fail:" ^" L* m5 ~* ^, M2 o
        bus_remove_file(bus, &bus_attr_uevent);
( X3 j/ e5 W. T* z1 sbus_uevent_fail:! }; X1 o6 J* B) c
        kset_unregister(&bus->p->subsys);
! O) f4 s4 A1 a+ `' {) I        kfree(bus->p);
% W& S3 ?' E& ?4 A6 {5 _( u% {  k6 ~out:1 N8 r+ v. @: |/ X7 Y  d
        bus->p = NULL;
4 e) ^. v% M  i* v  U; Q' ?( z        return retval;+ k9 s1 S9 z' W
}; K- V/ B$ x, [0 k9 k
EXPORT_SYMBOL_GPL(bus_register);
2 B0 C! L4 f$ i2 p+ K: t" r* R% F1 p" r% u. O/ |% a7 C
函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。/ C  M( J, O: ]& b) i1 o4 O
在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。, J( U- Q2 M8 R/ s0 Z
4 b8 {1 u* D6 C0 P
接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。- Y( I# {0 d) I3 _/ c$ _

5 F1 Q" l4 H; n' }: V紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。
8 K  U! g6 I+ Y- ^6 |+ ]$ |; |4 T6 a, V

0 X  k5 T% E* _) K/ O( Y/* add the kobject to its kset's list */: e0 R. Q4 h+ q+ E2 z
static void kobj_kset_join(struct kobject *kobj)
. ]8 ]  I% j& y! I) B- ?' b{& Y5 A# W. ?( C$ ]  o, a5 f
        if (!kobj->kset)/ D: r: {' R4 b! A) k! `
                return;: u! V4 {% ]2 \  L' L

8 p9 ~2 u+ T4 a) U* a0 U* f        kset_get(kobj->kset);        /*增加kset引用计数*/
  Y; y% b% E5 Q, a5 g( B        spin_lock(&kobj->kset->list_lock);0 Z3 o+ y- ^& C4 t, [
        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/. P- k  ^" C, {' }5 a, a
        spin_unlock(&kobj->kset->list_lock);
! a. y5 W& ]( Q}
! ^: z+ J" d2 }( b* h3 Mkset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。
- i* Q( n, ]: v6 D8 O8 K5 N3 K( F9 B& E1 U" d

4 Y! T5 q" d% G; `
5 t2 ?) K3 J1 I3 J+ p$ y/ X然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。
4 }/ K  Z) a. p9 Y" E! [' q0 ]: n; U- x' v0 I* ?
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)( Z' @4 ?" F' O
{) `* g5 l6 h8 b7 D( K
        int error;8 x4 p& I4 o9 ~0 B
        if (bus_get(bus)) {  p; _; R4 F" U! [% s; O, e
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
. G$ h0 L8 \* y& y' }5 r3 O                bus_put(bus);
" ]0 D5 Y# }# g1 C2 S        } else  {: Y, y' _% d3 Y6 e0 p
                error = -EINVAL;
# Z/ ~  E2 h* m3 W* r" Z6 A+ _        return error;
& R' k' H/ w  R3 S) Z}
7 [8 G4 C0 d: }6 X9 m; t. Y) ^EXPORT_SYMBOL_GPL(bus_create_file);
# U: S# T) z3 }5 j有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
# t; H' h6 D8 m" W; w# Y接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。
  e: M, Q9 @* Y3 T) b1 \, f2 q4 ^% n# ^
这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。
7 A. |) S2 X: z0 U
% C2 d: L0 j  F; N4 ]也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。% n  u$ e  q* }: [) t6 u8 ]5 T
$ l3 l+ E, K' c1 C( O9 m6 L9 R
我们来看下关系图:
$ Q2 g$ ?  z4 l7 Z7 K) @9 }4 {- P! ^7 O8 k  Q, B
- x, \2 ]0 g. C: S! {2 F0 F$ Y2 @
9 V) W# V/ X1 w7 H
随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
8 v, n( B( B- n% \0 \4 O6 Y( s; V: b9 [: u+ y3 F5 k, m
static int add_probe_files(struct bus_type *bus)
# t: p2 c- y5 l7 B{* h# F$ B" q" {
        int retval;
- U% y/ B' J: S4 @. L, j5 J1 M4 c- w: |, c5 g
        retval = bus_create_file(bus, &bus_attr_drivers_probe);$ b% ^9 {" ~4 y  q% i
        if (retval)
( n! P! V" a5 W8 `6 v                goto out;. R4 i9 i# M: h8 t1 ?9 [+ M" e

; y5 w2 v* }  Q! r5 Q7 m  x. }+ g        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
- ]6 y3 A+ p' S9 n  R, {* A        if (retval)
" V( \& u- }+ T& V9 v4 }6 f. B/ X* i3 [                bus_remove_file(bus, &bus_attr_drivers_probe);
  z% I! c& V5 @5 W5 ^4 P% Wout:  \! l1 R8 Y" |7 ]1 a; z* V9 }( I
        return retval;
4 i% _% M' Y9 I* u" s$ F) w}
3 q+ ~. C3 D0 h8 i$ l该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。
! z" N3 D5 @0 b  M7 l; @% T最后调用bus_add_attrs创建总线相关的属性文件。
3 @1 }  X$ q; }% O3 k  {5 B
. ?7 Y; t+ x) Y) d3 y! Y/**
' k1 |! I3 S9 D; D% {2 @ * bus_add_attrs - Add default attributes for this bus.
1 ]  f/ T+ p& F1 O2 L4 ?# \' Z * @bus: Bus that has just been registered.8 T+ G) F3 I* v0 I  G1 P
*/  Y9 y7 R! I0 x" t$ l

5 V* K" ^- u+ e7 Nstatic int bus_add_attrs(struct bus_type *bus)
% m2 h2 W* ~6 Q{
6 o2 X& j$ \8 k        int error = 0;
4 {8 s5 @7 G' n8 C; z  j. i        int i;
( R9 k; W6 l2 H) P5 Y" b& D0 C# _2 R9 d- @( o0 Y; `9 @* ?0 c; V
        if (bus->bus_attrs) {, n' l9 a1 F' [7 \- G
                for (i = 0; attr_name(bus->bus_attrs); i++) {
/ G, k. k8 U8 ^* _" {$ Q: {0 e% @                        error = bus_create_file(bus, &bus->bus_attrs);
* x$ ?6 u3 T% l' H% f                        if (error)
; ?& y& `4 Q: [; [                                goto err;) R5 k( C& R, Y; Z" U4 `% {
                }
8 V1 B! z5 r. g        }! z: j1 a* F& y
done:
3 q* ]4 q7 Y% m8 u5 }  E        return error;) D) C6 g4 |4 o$ G* l2 d# E/ _
err:
0 C3 X' p, \' v" u- o7 l8 ]        while (--i >= 0)
( X$ `) `% f1 ]9 r+ L% ^                bus_remove_file(bus, &bus->bus_attrs);
) F6 A; d; s: q3 }6 {1 C        goto done;
4 S5 d- J/ D! t% r}
  L2 S2 d7 W, l$ e我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。
3 a# X" H+ n- s' L0 i8 _, u好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。
" t$ A6 n8 g2 h  C* I- j8 u2 N
/ m/ z7 ~1 P0 j7 v[root@yj423 platform]#pwd+ [: n9 w! Q6 P* m
/sys/bus/platform% M; x7 z; ^* l' u( E
[root@yj423 platform]#ls
: B1 I9 n/ x/ [2 \devices            drivers            drivers_autoprobe  drivers_probe      uevent
& m, G2 Y0 h2 w! p最后,我们对整个bus_register的过程进行一个小结。* R% U0 Z) b& ^' O8 z

- y% u4 Y' @: U" t$ v" { ' u. a8 h6 h8 L5 b6 z
0 b) ^* b2 x! ?+ W9 _& [) B4 p4 g
6. device举例
, k* F4 T- h# E- d# i8 E! G本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。
: `) [, m) }  x" _3 {: f( U% y; F8 v3 |( K9 p
6.1 虚拟的platform设备
( k0 s7 p( R5 C之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。
; E! [+ l. {+ X& e
+ Q$ o( i& ?3 e  S( W+ [( C在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。1 f3 O  a/ B# T) R0 H. N

# |3 J; t  D% k0 G% [- v: Aint __init platform_bus_init(void)1 l/ m( S- ^' X2 q( b$ z$ h$ s
{& S$ g7 P' A, g* @/ ]% Z+ h/ `: {
        int error;
& I* f5 O4 l3 i* V
4 X' P' J) K5 g+ g; @, ~' K3 Y- ?        early_platform_cleanup();- }- Z5 C) o/ q# q6 {  P0 w

8 ~. D. i" \* h/ Z3 Y- i        error = device_register(&platform_bus);6 u" C# m$ O0 `0 d. }% `
        if (error)
# I8 j  N" a3 w% ?7 Q/ u  N                return error;' `: r' Q& i5 r) Q2 @
        error =  bus_register(&platform_bus_type);! m3 e( K& ^: p( Z  \7 H$ i2 Q: p
        if (error)
/ h# K9 [& v, U                device_unregister(&platform_bus);7 i8 t& g9 `% z% N
        return error;/ j. L- {, q, K% W& h: n& O: T
}& P" w1 l! q4 e( g7 d$ t0 Y( k4 D1 h
! N7 \8 P9 }: v1 M1 X
struct device platform_bus = {3 U1 P; y2 |3 f! J, d5 b  X
    .init_name    = "platform",+ K5 i8 P, ]& B0 u
};
& e/ Z2 l2 K9 N, tEXPORT_SYMBOL_GPL(platform_bus)
6 p& j3 X9 i4 h5 N下列函数位于drivers/base/core.c。. h2 E" A) C; Y& p: ?
/**# |/ y! U! K9 G! S% f
* device_register - register a device with the system.9 g( N  o3 _$ Z! S% e& {, r
* @dev: pointer to the device structure
6 ~1 r0 [/ C" ?! f9 t0 i *
- Z0 z8 [7 F, A% g& y * This happens in two clean steps - initialize the device/ ^& }3 f6 h- T
* and add it to the system. The two steps can be called
1 Q+ [8 M( C7 `. X' X% f  g( Z1 y * separately, but this is the easiest and most common.
# B* s& }1 q4 r" r% C * I.e. you should only call the two helpers separately if1 r; U$ ~/ U3 B. K! r
* have a clearly defined need to use and refcount the device
( F0 y- g) ?$ v' J * before it is added to the hierarchy.
5 m$ t* `2 d6 C) c+ p( n ** _, m, z- s5 s8 a/ ?# @; v
* NOTE: _Never_ directly free @dev after calling this function, even
2 S9 a9 M" V) u& t. h. c2 z, f3 ? * if it returned an error! Always use put_device() to give up the
" W& K* c/ b# [0 k2 h$ |% n5 L; c * reference initialized in this function instead.
2 F8 s4 r+ i0 N' W */" D6 [8 B" \$ B) s
int device_register(struct device *dev)
, B. P3 u2 j$ ~8 x{
1 l8 p3 _, v" l; B5 @$ |        device_initialize(dev);        /*初始化dev的某些字段*/* w4 O% b3 ~+ o) P
        return device_add(dev); /*将设备添加到系统中*/" S. a# V2 \+ h& V0 S8 U3 ?- z: ?
}
! d7 L0 _- y2 J0 D% y' U' N3 `1 \$ [* p3 g" n
一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:
* A: e& }0 R) t0 P8 d0 p9 B5 Q' c9 e2 j4 w5 R
下列函数位于drivers/base/core.c。' i/ P8 I0 [: u% p" [
/**+ n; a' \! D6 A+ {& V5 T# p
* device_initialize - init device structure.
' r; p! u4 ~7 Q; ]+ K* l3 P * @dev: device.; b0 d. v& T- I6 p1 |
*% p3 x8 l# a, o, ?3 G$ j$ i
* This prepares the device for use by other layers by initializing" a$ G8 ?  i5 e9 ]2 P6 j( _. W
* its fields.
- x& t9 r; d  M; H7 w) l& w * It is the first half of device_register(), if called by9 W" z+ w0 R! |6 y; x! A
* that function, though it can also be called separately, so one
2 K( @" R+ ?- Z% x* f; C& \( A: [! V * may use @dev's fields. In particular, get_device()/put_device()
# J) f1 k/ J$ m; U7 ^1 l * may be used for reference counting of @dev after calling this
" S/ c- H, g$ m * function.
  M* N) u3 x/ _4 } *
5 K; E; o" C; u* x7 j; T * NOTE: Use put_device() to give up your reference instead of freeing- N; t( L+ C& ~! E7 C- r
* @dev directly once you have called this function.7 C. ?. {" n' C# s! ?& A3 r
*/. t* W7 R  W" R  `( ?/ |$ ^$ ^
void device_initialize(struct device *dev)5 A, N5 j  g- H1 k0 `. X. q
{
% G1 J' c$ _6 W! [    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/* E6 v+ _- U. S0 `
    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/
" }- J0 \& o7 D. `" {3 d% H% g# k    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/& J; N% @2 N( o$ ^9 [1 c- S
    init_MUTEX(&dev->sem);                /*初始化互斥体*/5 |; s8 b! \, Z
    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
* ^! t( ^8 V/ t+ Y0 x5 v; [. @2 K    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/: j1 b9 S+ H! a( T3 x
    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/
" D  k9 p) n6 n* u- m6 i- ]    device_pm_init(dev);                /*设置该device可操作*/
; c7 ^+ L0 I" I7 W2 f0 j    set_dev_node(dev, -1);                /*设置NUMA节点*/, d& }7 L5 {2 K1 m
}; b* b/ R- A1 Y+ d( R5 H
6.1.1 有关devices_kset0 n# r1 c# ~/ }5 v# m) K* C
首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。' G( o6 y  a! a' L$ h
$ Q" o0 ^' _0 c; z
该对象的建立是在devices_init函数中完成的。2 b& u1 j7 ^1 _" l/ y+ ]
int __init devices_init(void)
# x# `  k* f9 [* {{
% a5 |5 s: O% i( ^; f0 j, s        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);: k* c) g( N7 r% x* b
        if (!devices_kset)
" W5 D; a) |& u. C                return -ENOMEM;. S# \, K. |+ f8 @  A1 K
        dev_kobj = kobject_create_and_add("dev", NULL);
! o5 d7 ?3 E+ ~; U        if (!dev_kobj)
7 L" ~, n' ~3 q9 W0 D9 s                goto dev_kobj_err;; `- U# A( u; X
        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);. T2 D; J! W1 t* v' C
        if (!sysfs_dev_block_kobj); q) i2 D5 s! i& Z* J
                goto block_kobj_err;* i0 `8 J& C9 a% b6 H( Y! |
        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
: u+ p2 [3 a% U% o        if (!sysfs_dev_char_kobj)0 s3 E  e9 r& p5 N  s. |) b
                goto char_kobj_err;! g* L2 _& b- S! q
  f; g: {, V. ?1 H# @$ d  t0 R$ g
        return 0;% {0 b+ P8 ]7 y
( L2 g4 k9 r" @3 n0 S' H3 ?! d( I
char_kobj_err:0 v& e) G6 Q8 Y) K" n7 j) Z
        kobject_put(sysfs_dev_block_kobj);4 y+ u. s% _; @: p- F
block_kobj_err:
$ r9 a" H: c4 Y: ~) Q( x        kobject_put(dev_kobj);0 W- C9 d! F* I+ u# c+ q0 I
dev_kobj_err:
3 d4 ~& H+ j- w3 f        kset_unregister(devices_kset);
- G% j$ z7 ^% E0 A; V/ m/ M        return -ENOMEM;
0 x' B( B# S9 m5 j3 _& F; s}; l: f- b5 z* U7 l% D
由此可见,devices_kset对象表示的目录为/sys下的devices目录。
  j  V$ F$ t/ s6 W6.1.2 kobject_init. ]. |* p% Y( Z) b! p
下列函数位于lib/kojbect.c。
7 [  ?; P3 o2 ^1 X* @/**
; }7 _, o' I/ M( B& E* V * kobject_init - initialize a kobject structure7 d% @/ k0 Q* O) g
* @kobj: pointer to the kobject to initialize
, F2 v9 f: I) x8 n; y! ` * @ktype: pointer to the ktype for this kobject.. p- y! i0 z3 `0 J8 j
*
" ^' P8 w3 G5 S7 e# M' E * This function will properly initialize a kobject such that it can then  E5 L  X* H# y
* be passed to the kobject_add() call.
! i! {. C5 C3 @: W *
, Z; G4 Q: [( S, x% b * After this function is called, the kobject MUST be cleaned up by a call
; T  F  a2 @0 W: z( S8 Q2 _6 v$ | * to kobject_put(), not by a call to kfree directly to ensure that all of
, p" u+ i; f9 [8 o * the memory is cleaned up properly.
6 `1 j  @$ K! R3 p  O1 t */- E2 t0 S: T8 e0 p1 B# H9 i9 L( u
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)/ k1 Q" _* }0 r
{7 [0 f3 _$ P( _3 Q! N. P6 U- i7 |
        char *err_str;4 u0 u9 \. f! K; `$ J/ A' h2 e& T; `
/ U# ?% D2 a4 ~3 k5 v/ Z8 I
        if (!kobj) {: p7 R" G4 O4 U; ?+ M
                err_str = "invalid kobject pointer!";
' Y, |7 c, l, d                goto error;$ {2 w4 u$ d9 U0 o4 U. c0 q0 f2 z6 Z
        }
/ q2 b9 {7 k3 f0 |' G5 @2 d        if (!ktype) {
' s6 [8 Z. Q0 @, y) p                err_str = "must have a ktype to be initialized properly!\n";
* M9 f6 b$ E5 l* ]                goto error;- l4 G) e% H$ J( g3 o4 l
        }
; V& w/ ]0 M, L- x8 {! T        if (kobj->state_initialized) {
" m1 \7 j6 M0 N8 i$ ^$ M  k5 p# u9 _                /* do not error out as sometimes we can recover */" m* n+ a% S, B
                printk(KERN_ERR "kobject (%p): tried to init an initialized "
# O; A: F# T+ J; R9 r) s$ S                       "object, something is seriously wrong.\n", kobj);% c* h. B1 v7 ]* A  \
                dump_stack();
# |7 W  o) ^5 F9 R% y2 {2 O        }
7 i# A1 m1 w+ H9 p
7 i5 U0 M0 C# J/ r$ g# a( p        kobject_init_internal(kobj);
* ~. X3 g5 A0 s5 B: Q        kobj->ktype = ktype;
' a8 R9 P$ g9 |6 _/ {        return;$ }9 ~4 R8 Y3 u( @; A

7 o! Z5 h: L$ {- g6 j) k  b) jerror:7 [4 e3 A, T; y
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
* w! X1 W9 C" ?; g1 E. V% x        dump_stack();
9 i3 q. [4 ]) |! v4 ^}# L- G7 R: m6 A; v9 X3 F
EXPORT_SYMBOL(kobject_init);( A! W" F3 s1 @1 K
! X% \1 \# U" t- T7 H7 G: G
static void kobject_init_internal(struct kobject *kobj)
1 A( V$ F+ J* V. T0 {5 _{
' `! E8 r; _- F9 w4 X5 P    if (!kobj)
2 Z5 Y" J  a2 \! z& v" Q        return;- r5 p$ `$ Z2 @
    kref_init(&kobj->kref);            /*初始化引用基计数*/+ r  m  {0 \3 g
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
! _4 i( W* |* e& _5 A    kobj->state_in_sysfs = 0;9 v( Y( D8 E' @+ G5 Y( j
    kobj->state_add_uevent_sent = 0;9 c1 B. n, Y: b. m
    kobj->state_remove_uevent_sent = 0;
+ ]4 D4 b+ o' E  n" \/ ^    kobj->state_initialized = 1;
2 V2 m$ B" |+ P4 Y! ~}% W9 O1 v% S2 J
该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。5 c: g: b+ ~' d( C) h5 M
6.1.3 device_init_wakeup8 _! o, |) `- t: `9 a
参数val为0,设置该device不能够唤醒。
- f: Q3 p% m6 ~: R#ifdef CONFIG_PM& F6 z# [  Y- \7 l0 `# S
# A8 ?$ i4 G/ t3 L  i( |
/* changes to device_may_wakeup take effect on the next pm state change.! h9 e+ v  i) E4 N0 c) }
* by default, devices should wakeup if they can.
/ G8 e' g. a$ J7 D: q! ~. a3 U */
" h! u3 w# K$ ?/ S" O4 y/ Astatic inline void device_init_wakeup(struct device *dev, int val)$ ?5 `9 l0 S3 F4 Q: N
{5 M. T0 y$ O/ D( L3 h: |
        dev->power.can_wakeup = dev->power.should_wakeup = !!val;4 n( b9 K8 f+ o8 q
}
8 {: r9 G7 Y& J3 }) k。。。。。。
0 T1 Y4 I! b* e5 O) M* B6 o4 p1 ^$ z#else /* !CONFIG_PM */
% p+ A8 ~; q  m; l7 C
7 g0 ^- L6 x4 S4 z0 n0 i5 \/ n/* For some reason the next two routines work even without CONFIG_PM */
: v5 k& K5 h0 Hstatic inline void device_init_wakeup(struct device *dev, int val)$ ?& ]7 P+ G# T4 a6 l+ q6 f2 [. W3 z
{/ ?) u/ B3 C; K% x2 U+ d2 g$ l% r
    dev->power.can_wakeup = !!val;* z9 h- h% R5 d% }
}" c: A. G' G, I3 R- j8 p7 Q$ x
。。。。。。
6 v/ p1 _0 ?) \( V4 l#endif
+ S# Z! J5 ]( d
. s2 K( V$ f" C- D, p( ^: Z
6 @* N# L9 C. b, j) o# E6.1.4 device_pm_init
2 m; S$ S7 u. ]9 Y; O3 ^7 d设置电源的状态。# e  h6 e* C4 V: k; n, ?
static inline void device_pm_init(struct device *dev)
* j6 f4 A$ Q% E" I" C) b{4 m* R: E: R  i0 x/ @6 e7 r
        dev->power.status = DPM_ON;    /*该device被认为可操作*/
$ h. F) j# f) r- r4 z}( ^3 w, l4 \0 B" y1 A9 c5 t4 ~
6.1.5 set_dev_node4 |8 G/ ^9 ]6 y2 `
如果使用NUMA,则设置NUMA节点。
4 b* M. p- b& q! [- y7 S/ Q; {#ifdef CONFIG_NUMA
  ]% f) t9 O0 @+ k。。。。。。1 i$ y- s4 I- ~: N  N
static inline void set_dev_node(struct device *dev, int node)
3 b( X' Q8 u0 {: U6 a' P( J{
9 {1 g  f4 t8 s$ {' c5 W1 d        dev->numa_node = node;
/ D% f# E, k4 j; [" b5 D  v}( P! V/ o( a$ x
#else
. z5 X5 @' }/ A; O。。。。。。
0 Z2 M, F8 w$ T/ y5 w; n' `' {6 tstatic inline void set_dev_node(struct device *dev, int node)
3 m& W. A; t) {6 |; e0 h6 v{* E' I& I( M; B2 g; n" o
}5 c" |* f4 R# J
#endif
' G/ Q# C7 R  d9 N+ X2 S" e  ?
( V3 h5 v; M2 E* J* S% [/ S6.2 device_add( r. J! e6 b/ Z& x
接下来是注册的第二步:调用device_add。: R# K1 n# [6 ]4 e

/ K9 I3 S- L  a5 U& L/**1 c- K: v" e5 o( _
* device_add - add device to device hierarchy.
+ ~9 [% y0 v2 T7 F! ]5 `2 k% Y * @dev: device.( x0 i: C! i- h. y/ |' ~6 a9 ?& d/ B
*) G' ~2 L2 u! J  g7 {/ y8 m, n
* This is part 2 of device_register(), though may be called
% z" ]' U9 R  G * separately _iff_ device_initialize() has been called separately.) ^5 x6 Z: {& n
*
' \5 ?' w6 V* u# l- T5 l! D3 l8 G * This adds @dev to the kobject hierarchy via kobject_add(), adds it. \6 f6 z" X: L; O. w% c8 }9 G* @
* to the global and sibling lists for the device, then
4 V: G8 _  C4 A" b; n4 a * adds it to the other relevant subsystems of the driver model.* y' N$ N) I  }1 f
*7 Q# U5 q! W1 R8 ?" X& M
* NOTE: _Never_ directly free @dev after calling this function, even
: e/ N4 m4 {+ a4 f * if it returned an error! Always use put_device() to give up your" k5 n7 M0 P* m% m, A( P" }
* reference instead.
  a# P4 C  R8 w( b7 v */, ?/ F# [) h$ B" S8 \
int device_add(struct device *dev)2 n( b1 W, k$ |$ X6 u. H1 T
{: ]$ s, A- F: _! t
        struct device *parent = NULL;8 V, N& V) @7 x/ q5 T
        struct class_inteRFace *class_intf;
" _2 u: j! n; `# @        int error = -EINVAL;) Z  w* U# D: ^% o+ W7 ?8 o

# U( u# ~1 Z: O! @2 C8 Q& _, `* g' y8 n        dev = get_device(dev);        /*增加引用计数*/
, V/ G+ T+ U8 N        if (!dev)
% p2 m& z* d! B* x" y, \0 ~1 f) n                goto done;
, J' B4 s* J& t7 _0 Q! e
9 s: X% A& U8 A' a8 E9 K6 s5 v! l        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/' R  S0 N8 I( i! L
        if (!dev->p) {
2 j, L! s' S6 S                error = -ENOMEM;
% q0 e: _2 P/ {. S) ^                goto done;
; ^& H2 |' \( P5 q1 I$ o        }
) j+ H5 z5 U% Y3 v6 g        dev->p->device = dev;        /*保存dev*/9 U9 ?1 |; H" a
        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/
$ M- ~: @+ P+ {. _- c0 V                   klist_children_put);9 m- k, s* @) v6 k5 m- U! h
- h) R0 X8 q$ a- {" D: h( s* j4 L1 ~
        /*! ?, y, G& e) f: H# o$ ]
         * for statically allocated devices, which should all be converted
# _* W- G  D2 l6 m+ a" @$ K         * some day, we need to initialize the name. We prevent reading back
. j" C( h* ?4 k8 Q% f0 r* @# B  Z         * the name, and force the use of dev_name()
/ S$ H0 r& |  [! W         */1 ]( O( t  A7 D
        if (dev->init_name) {
; v9 Y! a* r2 R0 O                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/6 R5 E1 r4 F5 O7 L! |  w% {# M
                dev->init_name = NULL;
0 R5 k8 R/ P0 I% L2 W  o        }
3 y& l( ^5 }+ C, ]5 D& y7 }8 w* T) F8 f0 {; M# h/ x  D
        if (!dev_name(dev))        /*检查dev->kobject->name*/
+ p+ d9 J/ {# u. b2 U& U, V                goto name_error;
2 T4 u! V& a/ B& T, A/ E- Z9 ?4 x! @
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
9 U( V7 e' J2 Q9 X
/ i6 g/ S- T5 c. n/ ?6 S        parent = get_device(dev->parent);        /*增加父设备引用计数*/
3 X/ F. c6 P, j8 e6 U. ^9 d, p0 c        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/# Y' ^8 X! @- A

# Z& }) {* ^6 D! X; y% B        /* use parent numa_node */2 h  {! P; a7 \: x; T& \3 w
        if (parent)
- v0 u& P$ T7 D5 X# w                set_dev_node(dev, dev_to_node(parent));
5 ?& G1 J6 ^: z* F1 m& v0 G, ~6 }
) C+ ~6 w" l1 d% s* Z7 C2 v        /* first, register with generic layer. */* j& G7 K" K6 x5 `: o- B# i. s
        /* we require the name to be set before, and pass NULL */& z' R* d( E' Q- P- a
        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
" s" e; J+ ^; j2 _        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);       
: ]; d6 S2 @4 U        if (error)1 [% l6 F/ t4 I  g, k
                goto Error;  |2 m6 F. v% b/ Z, q% z- x7 L2 U

* \! ^' ^& X: j8 O        /* notify platform of device entry */
6 t5 {, J+ x" C0 I* u5 F        if (platform_notify)
. J* F& v( S4 a* Q                platform_notify(dev);. ]& c- p0 `% z" @
$ p+ _  U! K% }
        /*在XXX下建立文件uevent*/
8 b. r) C( A6 h' ^5 [/ L9 m        error = device_create_file(dev, &uevent_attr);  s- a. W6 z, B; J6 r
        if (error). q- g3 X7 W4 I0 |4 m: L
                goto attrError;
% N; {( F' e; b4 ~5 F1 f! p0 E* h8 l
        if (MAJOR(dev->devt)) {/*主设备号不为0*/
0 b. u( c# Y8 C1 o- e' g& [. I                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/
) P0 u$ P, a$ N1 H                if (error), i% v5 ]( r2 c6 h* d2 m
                        goto ueventattrError;+ w& Q1 F6 f/ D9 D9 P
7 U: D$ t' n7 [1 p  T5 K
                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */3 k7 Y# @* g. ]: p8 \
                error = device_create_sys_dev_entry(dev); 9 ]1 u3 U# N0 x0 `9 A7 o6 P
                if (error)
: L' z$ D3 a! P) F                        goto devtattrError;7 E1 W. Y& g, b+ K4 H1 ?* g5 ?
        }
( B7 t: f& {8 j# e  d) ?, G/ E$ @. l
+ H: {7 I, W6 F' r* |) B/ d' t1 W        error = device_add_class_symlinks(dev);
& i- F. u) m: x5 E( k2 S4 x! ]% P8 V        if (error)0 m: B1 q  r  O
                goto SymlinkError;
& Q; |& s" E; |        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/* i5 M. }, \( ~1 U. S1 L
        if (error)" K8 W4 A# ]. j1 l+ t1 B
                goto AttrsError;
% ?9 l( |! t8 p+ y  M        error = bus_add_device(dev);        /*添加3个symlink*/5 |5 ?* Y- C: `, m+ H
        if (error)
+ m! I6 l9 y. r6 r) q                goto BusError;
( b1 z  i* w: B) _' h        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/. h  W# l% W9 U' ~/ z/ _- G
        if (error)+ g9 x4 g' ?" f/ ]
                goto DPMError;
. ~+ J: t7 v. f# e        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/2 u1 E) h" L1 J  H
* ]+ F3 D2 _# D' I: h
        /* Notify clients of device addition.  This call must come+ @% ]4 L: R$ }( B
         * after dpm_sysf_add() and before kobject_uevent().% ]# |, d# t# k2 f; Q
         */
3 m) K9 x5 p9 X0 _, I) D! d        if (dev->bus)
2 t; H/ g, @; o$ b: X5 Q                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,9 D0 r0 o) S- X( N
                                             BUS_NOTIFY_ADD_DEVICE, dev);
2 c# U4 Q3 ]2 @* s# i& _2 G9 O& O4 O- n9 A* U
        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/# \# ?7 i4 u# I- O2 |
        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/7 ^9 P, K! I; L' X. i9 M3 L
        if (parent)
# j; |4 p3 h5 `! R* B                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/
# x6 g  K/ L( O$ k# S+ M; }( |, r1 O                               &parent->p->klist_children);
/ d- N" p' Z+ _2 w0 c: e0 R/ [  K: j/ i- a- E& \% Q$ Z* Y$ S/ v3 W
        if (dev->class) {                                                /*该设备属于某个设备类*/
  c' q# x* `( e" N& S3 T                mutex_lock(&dev->class->p->class_mutex);! c9 `9 k$ Y4 e- g5 s
                /* tie the class to the device */( w1 q2 q* n9 o8 u. z
                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/
4 n% c* c  K3 q/ Y                               &dev->class->p->class_devices);' o: D9 `0 i4 ]; \0 L/ s# X

9 n* F+ z$ w5 A* |, L/ y% S4 [                /* notify any interfaces that the device is here */
6 b( O- e, Y& t2 ~$ C, X                list_for_each_entry(class_intf,
/ e' A7 m! m5 o! V+ \+ _9 j: F                                    &dev->class->p->class_interfaces, node)8 M/ i9 e( b5 b2 f% C8 _7 _
                        if (class_intf->add_dev); K8 S% s" X% f! k1 \; X
                                class_intf->add_dev(dev, class_intf);; o2 _; B: o0 h. {6 P5 [
                mutex_unlock(&dev->class->p->class_mutex);
0 c$ o, C; v8 S/ l        }2 D; `' w: P, Z0 ~5 g& u) ~6 _" f
done:
  p2 [( y, E/ Q# o! e: W% N* s        put_device(dev);1 U* _8 Z8 K# x9 x
        return error;! f# C, R3 q7 E: S( k" i8 x& }
DPMError:
$ m' ], U1 E2 e1 z  R- q9 u/ U        bus_remove_device(dev);' s* d3 X' ?( a! d
BusError:/ {% U8 R8 O2 f' X6 _
        device_remove_attrs(dev);
4 G" Y: `7 _0 Q& D/ k5 O: r4 J AttrsError:
. |8 \* F! H) o( w* I& s: d        device_remove_class_symlinks(dev);
' O: Z" v8 O+ Q SymlinkError:
; U; c2 n2 @+ x7 ?- i        if (MAJOR(dev->devt))0 X0 {/ b1 F- g& L
                device_remove_sys_dev_entry(dev);
# _4 a5 B) p8 T8 a" o5 I devtattrError:
6 U$ B& w' {# e9 j! p        if (MAJOR(dev->devt))
# y% l' r6 y+ e( v6 Q* u% R                device_remove_file(dev, &devt_attr);; z& t; i/ h3 \& O
ueventattrError:
& q# J- Y6 v. a2 C9 ]5 H6 p! I        device_remove_file(dev, &uevent_attr);* g( n' l4 g, h6 E; S; V/ f
attrError:# J* s; A& G  [2 Q/ n9 ], N9 A* Q
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);' C7 T9 H! m  R
        kobject_del(&dev->kobj);2 l! ~2 ~5 ~; k0 r" k  F% s
Error:$ S4 o& i5 Y' k1 P( h
        cleanup_device_parent(dev);8 x0 p) j6 H2 S9 b1 t
        if (parent)
# F. G1 r* I# Y2 h5 [1 Q                put_device(parent);
" [' b# T- w# h/ E9 z7 L) {* ]& Vname_error:, N9 n4 W* ?% X7 G
        kfree(dev->p);7 W, B0 C) k8 ]1 v8 t8 t6 i" Z
        dev->p = NULL;
( M/ R) K1 d& `* }% h        goto done;
" c. l" e7 Q# }' I8 }}
8 p7 `2 u8 @' w( C- X' M. r! @1 E) [/ H8 g( u
该函数调用了非常多的其他函数,接下来对主要的函数做出分析。
: o, a4 s+ ]/ H6.2.1 setup_parent函数
) A; j, y' ~+ J( n- \, J下列代码位于drivers/base/core.c。! m/ C( z% T+ f$ v/ N
static void setup_parent(struct device *dev, struct device *parent)6 i( i4 o3 A$ Y" f! L. i
{
# a  o6 @; B* _3 a- K9 k        struct kobject *kobj;8 Y4 h9 M( K" X; v+ }8 f5 U2 b
        kobj = get_device_parent(dev, parent);
' {( s- `( }  c+ J5 h5 B* S! ?5 b        if (kobj), z- @% j5 C9 b
                dev->kobj.parent = kobj;
5 I  t+ E  n1 D* Z' U- u}
5 e! E, ~; ?* x8 h2 {! g) K* ?2 r- S* D5 j
static struct kobject *get_device_parent(struct device *dev,
7 n: z% }, M. k4 Z* j6 i                     struct device *parent)
2 w, J4 r( y0 E- K& x8 c% D" j{
# D( l0 P( h  s8 [; x1 z2 ]    /* class devices without a parent live in /sys/class/<classname>/ */( r9 R0 ], k: a, o5 k
    if (dev->class && (!parent || parent->class != dev->class))
6 `) P# H' a/ Z2 k7 @        return &dev->class->p->class_subsys.kobj;& n, F+ m3 a# ]6 @# `$ M
    /* all other devices keep their parent */6 n# L- I- Q0 _7 W5 l, @
    else if (parent)2 F% T( ~7 Y! K* Y& A6 }0 |
        return &parent->kobj;7 L, W& p& a- M

& b; f! z3 M. i) \" }( k8 ~7 k    return NULL;6 x3 O  d& u( z$ |" H
}
3 m# C  r: B5 n该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。
5 K# |8 D# ^1 D8 S$ r$ w5 V6.2.2 kobject_add函数
6 a# I9 m' c: C5 d/ ~; _  T: r下列代码位于lib/kobject.c。
* z' I- ?* A% b8 O% y, k" d/**; z; w9 T" Q/ t- l" N
* kobject_add - the main kobject add function, G3 f$ g" y! g5 _4 E
* @kobj: the kobject to add
- k! P: w: X+ q* P * @parent: pointer to the parent of the kobject./ d' R# y) F: C/ S, n' Y
* @fmt: format to name the kobject with.8 j  w9 X  U5 S. C
*6 ]/ q5 s! ~  N( B
* The kobject name is set and added to the kobject hierarchy in this
' [% H) d1 W% u * function.6 y) Z+ P& Y$ X* |( q( i5 S/ S( l
*+ {  C+ S. R6 _- n
* If @parent is set, then the parent of the @kobj will be set to it.
; {$ |7 B" }; ~8 m5 |: y6 b0 @, P * If @parent is NULL, then the parent of the @kobj will be set to the
/ |' u& Y3 l/ V- Y+ R  w$ t- \$ W9 M * kobject associted with the kset assigned to this kobject.  If no kset
1 @- o& P1 F! h: Q * is assigned to the kobject, then the kobject will be located in the* x: L5 ]; ]- F9 G3 r/ F! R7 }
* root of the sysfs tree.0 E/ D5 c* C# e; K
*
: O7 d8 n. _, {- E; G1 k- W+ O) P * If this function returns an error, kobject_put() must be called to$ c$ ]) r4 B5 e4 d& E
* properly clean up the memory associated with the object.
$ ^- B5 c2 J$ k/ Q; @$ y* t6 _" } * Under no instance should the kobject that is passed to this function
2 u# F2 {+ A, }* S+ E# F' N  f * be directly freed with a call to kfree(), that can leak memory.
+ ~& T9 n9 H2 p *# E- V2 }( j- ^
* Note, no "add" uevent will be created with this call, the caller should set
9 e1 `! l0 x3 @& O$ l * up all of the necessary sysfs files for the object and then call
- K1 e' N+ H; g. i7 |0 _ * kobject_uevent() with the UEVENT_ADD parameter to ensure that
6 X  t" n) I" n, @/ ?6 J * userspace is properly notified of this kobject's creation.
% z# z. q- [% s8 p: ^! I. Z' i */+ Q$ L7 k+ |& l8 w2 Y
int kobject_add(struct kobject *kobj, struct kobject *parent,
# }* m5 t# r8 E0 G, P' u2 L# ]                const char *fmt, ...)3 r. k( s! [' `: d! V
{
. G8 ]. |# h/ J        va_list args;) T# s4 v! \6 W: L' I- L  X/ Z
        int retval;2 z9 w3 R/ E- M- C

* V! P: o( u4 \/ Y0 E! C! J3 r% u        if (!kobj)
" d4 t3 Z% U1 a' H                return -EINVAL;
# x+ v" r3 }0 t; D$ ]# \2 m/ d
# z, g7 i9 O3 {        if (!kobj->state_initialized) {
1 g% N# C8 U8 W$ @% y& f+ X/ V                printk(KERN_ERR "kobject '%s' (%p): tried to add an "
" s, d5 I. W, W9 b% e2 G                       "uninitialized object, something is seriously wrong.\n",
8 Q& {7 W) m& n                       kobject_name(kobj), kobj);2 P' B0 Q" F& h
                dump_stack();
# c) G& _, I; ^% Z                return -EINVAL;1 \0 T" W7 X  O
        }
: t- T$ f, m  {1 P- Q$ J        va_start(args, fmt);2 o, K0 A& c: {# Z. |. X& s
        retval = kobject_add_varg(kobj, parent, fmt, args);
8 k; O/ d: ~, o: L! Z        va_end(args);
0 o/ A/ |" _& z( Z* f
; \: q2 x3 S' D  _+ E( f        return retval;3 l# {/ p& i& o
}: }- Q3 ^) L/ R! j7 D
EXPORT_SYMBOL(kobject_add);8 W4 T! x4 P% H- f$ f' U0 s' F
  a" ~) c1 X# E9 i5 P2 u- v
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
. H! F( h: R+ |) }                const char *fmt, va_list vargs)/ ^# r1 O1 a+ w, b  a4 C7 g+ R
{
- Q2 N% i0 d- W4 \% d    int retval;0 C- F5 |# |+ k; s8 [5 I) l
# n) j  o! |6 ]% n- x9 X) o
    retval = kobject_set_name_vargs(kobj, fmt, vargs);
+ l% _- `$ A9 ?! x% m    if (retval) {
0 B; M) i% L) \; Z; I1 I5 Y        printk(KERN_ERR "kobject: can not set name properly!\n");
; ~( A0 ^* Q- [& d        return retval;6 x) @8 j4 e$ n, ~% V
    }, t+ |2 y6 }5 I
    kobj->parent = parent;
2 J2 b8 d8 I( t0 H. I, M, q    return kobject_add_internal(kobj);
7 d5 |5 b5 \% |8 Q: N}0 E3 a3 C; F+ h% G/ Q5 Z# B
, v- C4 I& U6 l' y8 D+ M" B
static int kobject_add_internal(struct kobject *kobj)
# o- A3 I4 m% J9 Y# u{1 W4 ]. d8 Q3 N+ z2 Z9 s0 n( A
    int error = 0;' a/ X, V* k' D. f5 @
    struct kobject *parent;9 X0 h7 j" |/ d$ {  Q
2 o; ?$ J8 c3 g1 c
    if (!kobj)/ \6 |. t) T; p! N3 I2 ]
        return -ENOENT;) P1 W! ]9 G% i: _* [6 a% F
    /*检查name字段是否存在*/
$ s6 q' X# y% f/ H7 l5 [    if (!kobj->name || !kobj->name[0]) {0 R" I( y0 l$ o0 S4 u
        WARN(1, "kobject: (%p): attempted to be registered with empty "
% B7 B& y1 I4 B4 J             "name!\n", kobj);
& \9 }1 k7 d: I1 [        return -EINVAL;- k+ q& W6 W( G& ^5 W- s0 g8 L1 I
    }9 L2 h7 Z% B# ~0 n& U
% O# b) T  h8 l6 E$ o5 E8 E
    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
& d: f. P6 k" h' j4 I. r2 q" {- @- I  A$ N9 o  q& i; S
    /* join kset if set, use it as parent if we do not already have one */
9 \/ E& q6 a4 B3 q' M    if (kobj->kset) {    4 A4 ~3 ^3 r" x1 t) W- M
        if (!parent)" _( j" z) e, q
            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/  b. W4 T! P) Y7 n7 [
            parent = kobject_get(&kobj->kset->kobj);
: p) d7 V0 q4 t; x! R1 h( L        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
5 ~$ Q6 u0 f+ j6 I( ^7 {6 _        kobj->parent = parent;2 S! }( A. J' v# e
    }2 _8 ?1 [4 Y, @" f1 S* g3 @

; \* m! m$ G( g( K' U4 _* X    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",. O4 D& g# _% W# |$ W5 _
         kobject_name(kobj), kobj, __func__,- G  J+ N8 S4 d
         parent ? kobject_name(parent) : "<NULL>",
0 P5 C- i( Y; _& u* C         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
# `7 ~' |7 B5 m( ^6 b; X
* L) f; u' p: R    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
& e8 @3 I) f2 n9 P: I    if (error) {! B) k( q- }; V+ p* w
        kobj_kset_leave(kobj);    /*删除链表项*/: D$ W, T$ x& G% S$ W$ g
        kobject_put(parent);    /*减少引用计数*/. T! ^3 {! M+ x# L% @7 @/ }- B
        kobj->parent = NULL;
! }* G0 M9 t% K
4 Y2 O# P3 z% A* d. D# \        /* be noisy on error issues */
) W4 T$ t  ]" b- ^9 _        if (error == -EEXIST)! ?/ H5 }1 O0 Q1 O" y9 p  S
            printk(KERN_ERR "%s failed for %s with "
, C  w2 q: z& c# L5 r# P                   "-EEXIST, don't try to register things with "
0 w9 g% r) A3 f                   "the same name in the same directory.\n",. _$ }" r/ @" [# r
                   __func__, kobject_name(kobj));
9 x3 R' E" d- Z$ k- m        else' u' m" S. i0 g% \& D
            printk(KERN_ERR "%s failed for %s (%d)\n",. W- P+ p8 B/ {
                   __func__, kobject_name(kobj), error);% s) l7 r: D# T# q$ z1 U$ B
        dump_stack();
" l8 T; O/ l& P  x/ e- S  I2 ^2 n    } else
+ n1 o! C5 Q* q8 {& F        kobj->state_in_sysfs = 1;3 y  G: K2 Q; k9 r2 C0 z

( N2 J2 H3 U& s! L) P8 y    return error;
5 ^  W* r$ v& O3 q! P}
. L3 X4 d3 o. t$ _2 {, Q在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。
( C9 D  R3 N  K: r而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。8 v5 D; M' d7 N3 }  k. r% s. x

& ~, X8 [1 ^) s# @但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???
2 E$ Y6 E0 ~& L- g5 w: q9 z) ?: n* A9 Z: b+ K. |- w
6.2.3 device_create_sys_dev_entry函数4 j7 `4 x2 R/ f( h$ x" c+ u
在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。7 O, w  e! X2 B1 u- }+ X2 r
但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。* ]  y' u% V0 U& r  t1 {

/ Q4 R% K5 z8 f& B) M7 n' G下列代码位于drivers/base/core.c。( j# s3 s% _0 c# C" B. r+ \  m
static int device_create_sys_dev_entry(struct device *dev)
6 }$ N+ U- z2 F( p1 O1 ?: V( A4 l{  [; H  Z: Z6 O5 Q
        struct kobject *kobj = device_to_dev_kobj(dev);! ~5 U0 d3 ^7 g7 V
        int error = 0;
3 A  g+ X' f: A2 f2 p. x+ o        char devt_str[15];
, U# M# Q; G* F+ a& f" U! @2 l9 |- e' R, u, P2 C' J
        if (kobj) {* k1 f9 O6 y/ D0 a$ R+ V+ l1 a
                format_dev_t(devt_str, dev->devt);
0 `+ s3 d, N& R- Z' z                error = sysfs_create_link(kobj, &dev->kobj, devt_str);4 o  ]0 j' r6 O' C% U7 G* z% d
        }
- T) }4 f. k4 {% h. |/ s( s' u# C
+ H  P; d! U& t8 \, h  H* h  r        return error;: E' |1 u- P. _6 C7 E2 Y. G
}
% `7 H" S* b  `/**: n5 Y+ y6 o1 ?
* device_to_dev_kobj - select a /sys/dev/ directory for the device' I- M( l3 E0 ]; J3 k, L
* @dev: device
% M5 E. n  E6 p6 a& C *
& L, L# `9 t3 m# z0 V! k * By default we select char/ for new entries.  Setting class->dev_obj( C" e6 b2 A0 ~  r2 y/ h1 _. J
* to NULL prevents an entry from being created.  class->dev_kobj must
; @; @' c! N8 O! _2 B6 j# e$ d * be set (or cleared) before any devices are registered to the class# X3 I3 m* m6 P
* otherwise device_create_sys_dev_entry() and* w. ^# u9 Z5 q, Y
* device_remove_sys_dev_entry() will disagree about the the presence
8 |- t2 F5 j3 s  Q * of the link.8 n! ?+ A+ S1 J1 F& v4 ?% b
*/5 O+ i& x0 `% `# p
static struct kobject *device_to_dev_kobj(struct device *dev)
1 m/ T0 c0 N$ R  q7 s* P( C/ q{+ H3 k- M" b$ a9 ~$ C
    struct kobject *kobj;# o  F" {" k, z/ {& F
* ~2 f$ t7 b+ v- A# E! k8 G0 e5 {# ~
    if (dev->class)
0 p! Q( Z! D8 O/ O        kobj = dev->class->dev_kobj;( }% e7 _  z, j. F
    else
9 M' r8 K* A; Q: \7 a& j        kobj = sysfs_dev_char_kobj;( _& B1 R& D. C3 a1 h# n" u

. [/ g  N' }0 B6 b    return kobj;2 [" j  V* O  G; j% B
}5 x5 G$ b* ~, w1 ~3 s& r5 C8 D

, E1 L. P$ h- S3 D1 q, j6.2.4 device_add_class_symlinks函数: B: ]% h# E5 K# p
由于dev->class为NULL,本函数其实没做任何工作。
9 ~  g" F  U+ Y$ y$ B' j. t# h; E# n: C5 {. Y" t
下列代码位于drivers/base/core.c。, w$ C' C* s# \  o! u: t- u
static int device_add_class_symlinks(struct device *dev)8 F+ D9 |& e: |- }9 ~
{
4 H) d& E" h4 _# b; S6 J        int error;0 n$ h2 p, A9 K# d
0 p7 a  U& b( e5 k
        if (!dev->class)4 ~0 _( x% v- e& v2 g
                return 0;4 p; B  _7 A4 X1 c

2 X) M% _9 r& J1 q        error = sysfs_create_link(&dev->kobj,
: w8 V4 C% F, C! Y$ n$ O% k                                  &dev->class->p->class_subsys.kobj,
6 z5 z, a, g8 k0 x9 z6 G                                  "subsystem");
( e+ W$ V, X: b+ i- [/ W        if (error)
8 X6 J* B9 z0 l: r                goto out;! s4 g* I9 _5 m, j

* J* }; f" m  }#ifdef CONFIG_SYSFS_DEPRECATED/ R4 Q5 v2 G9 d3 t) [. x6 r. [4 s
        /* stacked class devices need a symlink in the class directory */& @. r. a6 {7 i) ~% [) P; X/ k
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
; V/ _( |) H! N            device_is_not_partition(dev)) {
  l1 i0 C) f1 R4 R: E* \                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,$ |: |% [+ B/ f+ ~' [- h2 }8 Y
                                          &dev->kobj, dev_name(dev));, Q# `0 x$ [3 X* C
                if (error)
9 F- h7 q3 ~  l' V& [                        goto out_subsys;
) \7 B( r- O" ?( U        }
  S' C" m8 G# C) E( d8 f0 m: L0 r; }3 t
        if (dev->parent && device_is_not_partition(dev)) {( S7 t, p7 j* c5 d2 `
                struct device *parent = dev->parent;+ l, V# V6 o4 R/ x
                char *class_name;
1 p0 r! R3 H# h( q
  D) I  v1 S9 d$ G                /*
- o' I; ]& @$ e! p' D) W9 ~                 * stacked class devices have the 'device' link; d# @; p3 a- }. F
                 * pointing to the bus device instead of the parent
# p; h' ~. [1 m5 ~                 */! I" m2 L0 h! k" s$ p# w" G
                while (parent->class && !parent->bus && parent->parent). W2 C, w5 C* w4 q0 Y* ~& m
                        parent = parent->parent;. W$ |! I9 [3 i3 M

7 \3 l, q1 ^8 s6 L5 d; g% b0 E. p                error = sysfs_create_link(&dev->kobj,+ h0 a; J( A8 J% C! p( X
                                          &parent->kobj,3 Y" O8 }6 b" ?& f) n' ?
                                          "device");( R2 ^, }4 a- l) n. _
                if (error)# R# Z' \8 v- q- X$ d- ]5 H" W9 g
                        goto out_busid;
5 W1 [: H4 M2 s
; N% r0 S9 l8 F' {! ?                class_name = make_class_name(dev->class->name,3 D1 M; w1 D. ?+ ~% ~3 K
                                                &dev->kobj);
. P6 U+ v; Q9 ~                if (class_name)
8 t3 f+ e" r6 a" [( N4 W  e1 }" n                        error = sysfs_create_link(&dev->parent->kobj,2 J$ q* w/ F5 q
                                                &dev->kobj, class_name);- }3 g) j/ U& |, S% \; ?
                kfree(class_name);" w) F9 O" |! W7 W1 V
                if (error)
0 [# @; T, i5 x% u) \# ?                        goto out_device;
3 q# h9 m: {& y6 Q( R0 ~! V        }
4 e# l& P4 J+ @8 C, r: v        return 0;
, Q. h0 d' A- D  S" m
, i7 `. A: o) V" qout_device:
# h, ^  s1 Q* w! T" D        if (dev->parent && device_is_not_partition(dev))/ ?( @( e! m. ]. ]4 |6 T8 `
                sysfs_remove_link(&dev->kobj, "device");; [: E* {5 p) Z! L" P5 e
out_busid:
8 ~9 D0 c' z& D# q# B; G        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
% |5 e+ `% p* ]( U5 b            device_is_not_partition(dev))
" V0 p* j# g$ g( _9 S* n                sysfs_remove_link(&dev->class->p->class_subsys.kobj,; ~+ ]9 ~4 A- u8 n7 j; [
                                  dev_name(dev));
+ C2 J1 P% H0 u% q#else3 R0 y) r$ X- G9 E1 c% G5 C# J1 w
        /* link in the class directory pointing to the device */
4 F. `  a7 M/ e, u        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,8 R1 E" S; O0 v& @5 M
                                  &dev->kobj, dev_name(dev));
) G/ D5 f# V% l" t        if (error)
' t1 C3 i9 g; v8 F3 V; p' N/ b                goto out_subsys;" h8 R' ^$ c, d' `! O* F% ]# n

3 _- R; g2 R2 A        if (dev->parent && device_is_not_partition(dev)) {( X4 K: y! Q. m1 d& E! s
                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
6 ^6 i1 I1 H+ t9 ]( _  m& B  Q                                          "device");. K+ J/ k. f/ d+ D5 H/ J
                if (error). f- C( z  M& m: v
                        goto out_busid;! P  _; U6 L7 [: J
        }
3 N! |' b" F3 s( C' G2 v1 w        return 0;
' x, a2 x: i/ O5 f- V" W; q- y' T3 `1 y, w
out_busid:
8 f, F3 M2 [5 X1 S- C        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
/ M8 C3 ]- X% w1 \" o" a+ z) `* Y#endif3 }$ S* n' S4 b3 r% m- y$ X, }

/ |$ \7 _( D$ e1 M# {$ u/ Vout_subsys:
% y$ w5 O' ]2 p" w3 g) o        sysfs_remove_link(&dev->kobj, "subsystem");  P+ C. D2 H$ }& s& [
out:$ X& q& L" X* ~) b
        return error;
0 b, P' q" P7 u' {}; F/ Y9 V0 I, t: L. ?
6.2.5 device_add_attrs函数
4 }' U9 j5 x# P" {  P9 X% c同样dev->class为空,什么都没干。
  c# H; V1 `  w6 ?0 E- @2 ~下列代码位于drivers/base/core.c。: T/ R, ~2 l: @' b  u* Q
static int device_add_attrs(struct device *dev)  d6 B- Y$ E0 q) u5 [1 _! s
{
8 ~8 b" x- M8 Q        struct class *class = dev->class;
8 K7 O; }- O( C! \9 L% p        struct device_type *type = dev->type;- R5 W( P- t, @& f) O
        int error;9 Y! ~0 b% U4 {) h

" H" v1 r6 H% a5 D) Z        if (class) {& I- w1 @+ u' a6 m: ~
                error = device_add_attributes(dev, class->dev_attrs);
5 g4 T  `& ?- _5 A; ]$ o3 v                if (error)+ M8 P2 P: N, r1 O6 p4 V
                        return error;3 ~# m/ ]5 I- g  Z- ]
        }% k8 L" b2 @! {- Y1 C2 }
% }2 F% O" D+ S) A
        if (type) {
8 X. p7 I2 M  a4 U- z+ L; L$ V/ H+ [; ^                error = device_add_groups(dev, type->groups);
' n- q1 g* }) w3 c                if (error)
4 R" @9 V- D1 [  \% ?% h) c2 V6 A                        goto err_remove_class_attrs;8 E% Z5 Z# w6 l7 L4 e
        }
1 i& U7 K$ {1 d
: |& z) B5 y$ S# Z9 c% }        error = device_add_groups(dev, dev->groups);* {( ~3 Y7 k( v/ M* x( r+ f8 c
        if (error)) q  \$ U* p. l0 y
                goto err_remove_type_groups;
9 x/ y* ~1 }. K7 a
$ H4 j- W9 {' T, K" x/ f6 E, }& k' z6 G        return 0;9 z9 a0 s' d2 v9 L/ F2 h( ]: g4 [
4 [* V3 c- G/ G" A+ ^
err_remove_type_groups:
3 Y! ~2 [# Q7 U: j* C+ p        if (type)
, u- i0 U9 `/ {$ s9 K# X                device_remove_groups(dev, type->groups);2 `% Y2 H/ u, h; l% |
err_remove_class_attrs:
. j$ Q& _4 k& U' M$ s+ j        if (class)8 @* c1 Q# S" e( N
                device_remove_attributes(dev, class->dev_attrs);
: v& B" D4 m" j7 s
. n3 U% d' B* t6 M+ d        return error;- m' Y6 q" @: X, k
}
  [7 H+ G$ _5 v+ ^  n4 {6.2.6 bus_add_device函数1 k; k0 m  `* y2 I$ x! |
由于dev->bus未指定,因此这个函数什么都没干。
! C! }+ q3 U: S- ~% P0 N% O% D9 R% t: q. e" U
该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。9 ?1 Q& y# |4 }# ~8 K5 l: J

% G! }/ Y2 H5 l& c: O下列代码位于drivers/base/bus.c。9 [) Q7 i5 l# h  f3 O& Q
/**
& {& k; E* g9 |1 d5 S1 R. @ * bus_add_device - add device to bus
- w- v- r0 a! r5 V * @dev: device being added+ H" E7 j6 y' g8 F
*
# N8 C7 g9 ~" ?& f * - Add the device to its bus's list of devices.
8 t. ~4 i: {6 B4 @' s3 |- C * - Create link to device's bus.
7 S" B$ m. @& W: F" k5 w3 `* a */
2 W% E$ T* m2 y, D1 {& r6 Wint bus_add_device(struct device *dev)
3 d7 w6 m5 Q( v{
: t8 m+ b" w$ y! j% {/ j# y- t2 P        struct bus_type *bus = bus_get(dev->bus);  a1 I) U3 |5 ]+ _: Q3 ~0 z; a3 L
        int error = 0;
8 j& f" z$ J% [3 V- P
' y& J) Z* _! S$ R0 Q        if (bus) {
3 V2 \  Z/ K1 b, w                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));- H: R# Q( f% o8 [& C/ a( N
                error = device_add_attrs(bus, dev);
9 Q/ a7 `' v8 F- ]& B7 O4 Z                if (error)" Z3 V. {! C% L* e' R) O& i
                        goto out_put;
  I& Y9 r# x3 H$ u                $ r+ p7 [$ q5 J  S
                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/
3 q0 w& H& O8 _: Q4 c3 |                error = sysfs_create_link(&bus->p->devices_kset->kobj,
9 W* W. {+ g/ R5 ^                                                &dev->kobj, dev_name(dev));
$ `6 ~0 N, w( Z- `2 ]% a6 T" Y                if (error)
# r# A3 P7 S  g* ^3 w. `/ Q                        goto out_id;
$ y3 h/ |' y2 g+ I, J( q                $ k- X; O, t6 W2 E6 D8 b+ f7 R* _
                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
$ A* Z7 ^/ K3 K9 k* T8 p' q- ~4 l                error = sysfs_create_link(&dev->kobj,( \( S5 t/ M& ~6 z( y, ?2 [
                                &dev->bus->p->subsys.kobj, "subsystem");0 N5 t0 q/ U. k& y
                if (error)
5 ?. W. `+ [; w4 f# s. \* ]  b                        goto out_subsys;+ K6 r6 Y5 y2 N3 X9 {9 W
                ) [0 a3 H) L, P, ]' R9 e
                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/
  E. J8 X- B- S' T$ f                error = make_deprecated_bus_links(dev);6 O" g5 K+ }; E1 J
                if (error)
9 x, I% ^. |$ R; P$ M                        goto out_deprecated;
+ f; e) H8 e, b8 i7 U$ f9 [        }
+ @6 y. k: b9 C9 C1 X3 B+ ~; B        return 0;
, X: C( X6 C; ]. Q( ~- y1 m
5 D& t4 q3 Y5 O6 I" Cout_deprecated:
) h- f/ g4 `, p+ U- X  J: w# ^1 x& {        sysfs_remove_link(&dev->kobj, "subsystem");
- o+ B, E# \! [" U) _out_subsys:
; _/ g  X9 @- L$ @! K        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));% Z. P( l; q# u2 o/ f$ u
out_id:
) E  j6 d0 Z& K$ \* E- o/ P        device_remove_attrs(bus, dev);, c( Y  I; a+ o1 I
out_put:
  w3 Z: J5 R6 e5 V! D        bus_put(dev->bus);
6 U4 F& T+ s" M6 z$ N        return error;. R6 t, \  W5 e1 Y; W
}2 u6 @8 Y; c  r) v1 |

+ H  r" c! M# ]$ p! j! C6.2.7 dpm_sysfs_add函数8 M. K: V$ @, \) n. e2 w( R, d
下列代码位于drivers/base/power/sysfs.c。2 D' }# F- V; O$ Q
int dpm_sysfs_add(struct device * dev)
2 d* p- o5 b' ~7 ^7 Q& n3 C{
1 a+ r9 g3 @3 k/ [& ~# x% d        return sysfs_create_group(&dev->kobj, &pm_attr_group);
% H  I3 o# Q0 }! [7 Q2 _}8 F  D/ Y; p% y* R3 \

& K, @7 t/ r8 E8 q' v5 ]% kstatic DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
; D  {0 Q3 h) f4 k9 n5 s9 q  ]/ E/ y& z2 `; C9 D: E+ k2 n2 A) ]' Z3 _  R

5 Z' Q! o" ?5 ostatic struct attribute * power_attrs[] = {
" G3 D7 z0 v# E$ l    &dev_attr_wakeup.attr,
. D8 b; H, |4 {2 D# ^. X9 u) [    NULL,
% _5 ^4 N1 ~4 {+ h6 f& x  ]- @9 D- o};
, f0 l' B2 V, ~$ X# J/ Jstatic struct attribute_group pm_attr_group = {
' M$ N- H( O6 T  s" s    .name    = "power",
) ]- l: V0 h! m  U& k& u- Y+ z    .attrs    = power_attrs,' N" u7 r8 Y+ b$ Y
};
5 v( d4 r7 J7 A" C
  Y2 q) k* ?( Y  o' A: m该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。
& b3 s. S( ]- |+ F  [, j  g$ m8 d9 o- K+ i% J, k) W2 l
在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。0 Q( M) v3 ?( t( Z9 |
6.2.8 device_pm_add函数
0 x: C/ ^% j0 {' M% o7 T% V下列代码位于drivers/base/power/main.c。
/ q0 J3 Z. K" z  j& L4 u, f) d/**$ e- y5 {1 k2 U  Z6 K, f
*        device_pm_add - add a device to the list of active devices2 a* X, R; b! I  o) {) e1 d
*        @dev:        Device to be added to the list+ q: q  F9 i% s3 \
*/2 `- W* w/ ^8 j" r& ~  e% B! l
void device_pm_add(struct device *dev)4 b$ g- n: j+ u
{- S" f! a7 u- a; B
        pr_debug("PM: Adding info for %s:%s\n",; p! N! U- G  U: s; S7 A
                 dev->bus ? dev->bus->name : "No Bus",& Q6 m6 }# ?2 ^! @
                 kobject_name(&dev->kobj));
/ v5 G: T% b* X  r! n- Q0 E, H/ m6 n0 g        mutex_lock(&dpm_list_mtx);
/ k  X" ^' s2 J        if (dev->parent) {
  j! a9 P5 q' c" U4 [. b2 Z+ S7 F                if (dev->parent->power.status >= DPM_SUSPENDING)
0 X# G  A& E$ T1 X# g, c$ B4 l                        dev_warn(dev, "parent %s should not be sleeping\n",
! s" E0 H( V5 a  Q0 O                                 dev_name(dev->parent));
# ?4 v+ @; k2 v% @0 H$ z' w. s1 D        } else if (transition_started) {: m% _4 I  J" Y  F% }( y& `3 l
                /*
2 W) U; o8 D$ z* G7 Z                 * We refuse to register parentless devices while a PM) r9 X+ \  e( A1 q$ Y
                 * transition is in progress in order to avoid leaving them
  m& ?( F$ O+ R9 k                 * unhandled down the road8 V# i2 e) F# J. u- n3 s, v
                 */$ a- ^. I8 p  N$ C; A
                dev_WARN(dev, "Parentless device registered during a PM transaction\n");# L7 c2 L, w  w# c* n* a
        }
3 T* i! F0 h, a; c( C! N6 D  l) D- @- E: H; e- ^2 x
        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/  A. b7 |! D- d8 K! U
        mutex_unlock(&dpm_list_mtx);
7 Y& g7 x5 a) s$ c5 a  M0 {}2 {# \& H/ E$ a; z: R+ |2 O
# [8 h! X% o# y6 U/ j
该函数只是将设备添加到电源管理链表中。
2 R7 R3 a, P6 n! A; K/ C2 S8 R6.2.9 bus_attach_device函数' n" v- d0 N$ a" k! }  |
在本例中,由于bus未指定,该函数实际不做任何工作。- }! f! B7 h2 v+ b) Z" E
下列代码位于drivers/base/bus.c。! ?2 R; X7 S" f) F% e

$ ?; N0 s( y* ^$ w8 H/**
2 d5 q5 W# y# Q1 l7 k+ u7 e' u! D& H * bus_attach_device - add device to bus
7 o9 J5 \: }4 a) o6 \ * @dev: device tried to attach to a driver  T3 U; u5 J# w! R$ r' c3 b
*
! c$ t  v6 A7 R6 h% K * - Add device to bus's list of devices.
8 _4 r& k8 L8 Y4 [ * - Try to attach to driver.9 C2 o5 C. {# g
*/9 S  j7 S) F" X# V, y8 g2 P
void bus_attach_device(struct device *dev)0 c  F& g& m8 ?% \
{0 P$ J$ ~+ L" v' O$ p4 w2 x
        struct bus_type *bus = dev->bus;
) ]5 t7 q4 p) k4 @" \7 b& R$ Q        int ret = 0;' G3 o. f5 v: ~. \3 v: o
( K+ c, k2 `8 q, F7 i
        if (bus) {* z. s0 R7 @+ a/ B
                if (bus->p->drivers_autoprobe), A+ ^) ]2 I# e5 T: J9 x. d5 Q
                        ret = device_attach(dev);        /*尝试获取驱动*/+ J2 `+ Y" i% [, g0 G: I2 O; Y
                WARN_ON(ret < 0);* T1 [. \. ?# F( z: L; o9 d
                if (ret >= 0)                /*将设备挂在到总线中*/* u( k3 |/ L" S$ T
                        klist_add_tail(&dev->p->knode_bus,# ~7 H  A* x4 d- s4 u; |# H" O) t
                                       &bus->p->klist_devices);3 V" r( Z  e  B4 j9 L
        }
) b) d; K) E: S}% A6 y/ H7 g9 ^9 |

' x; L% l0 @) L* W: j# J/**
! [8 c& g( o" c" V1 ^+ T2 e * device_attach - try to attach device to a driver.
2 ]/ x7 M: n$ v/ \. N/ ~ * @dev: device.
; N# G. `$ V( z7 D *
" ^* m) B$ F2 }0 h8 d * Walk the list of drivers that the bus has and call) B! l7 N# ^; k, k. Z- s
* driver_probe_device() for each pair. If a compatible  z& }. Y3 j4 H( V5 v
* pair is found, break out and return.
% R: l! F, ~5 y *
! v( P, Q, a- S( M& W * Returns 1 if the device was bound to a driver;, o' A4 a. \+ P6 k
* 0 if no matching device was found;
6 O: m1 h7 O3 U * -ENODEV if the device is not registered.
% S) E  f: `. H- `* G0 g6 H- z *; I, Y4 o/ D6 y7 P' d
* When called for a USB interface, @dev->parent->sem must be held.2 T. \5 i% n: x5 ?) i$ ~
*// W' H6 P- Z. M5 O+ s  k. g' C
int device_attach(struct device *dev)0 G# a! Z) l2 C7 x1 S( @
{+ k# q9 D2 I9 j
    int ret = 0;% C9 s$ c% r+ J3 h; m# v4 E

: c5 j/ H, j+ f9 G" w. y/ b    down(&dev->sem);, B3 Z0 o* @2 {0 x; H
    if (dev->driver) {    /*如果已指定驱动,即已绑定*/
, R$ s9 n  t5 Y0 k2 ]        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
$ M5 R  A6 o% A        if (ret == 0)+ h( z, P5 q* i. N
            ret = 1;
1 A# |2 g  U+ c* Y5 m# D        else {
3 C; f) l6 j" o, H: i* n- R% U$ M" n            dev->driver = NULL;5 Z$ h+ y0 O7 q4 M( F
            ret = 0;
. _4 Q& |. P' e* q0 N% J7 ]        }
) G3 r3 N# n/ m8 a    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/
2 j. n8 |1 }8 A7 p; n9 V* y! W        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);) _" \6 g5 u  M  {' P  ?) p! m
    }; j* `$ {' g% K' c8 `
    up(&dev->sem);7 Q5 n! y5 N2 f( P
    return ret;
  y4 Z/ }6 c0 \}
& O3 Q. }* o3 _8 b; A1 TEXPORT_SYMBOL_GPL(device_attach);
# B" N; O: A: V9 A9 B, \; M0 T. R5 }2 f( Q
如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。( \# T5 ?5 g6 h
0 y% d; V* j( P- s* J
为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。
: F5 n  Z! P5 @
2 D$ \! E" a- o2 m. c. |我们来看下bus_for_each_drv:6 A3 E2 Q$ H1 F; `+ j" r
2 r) Y5 C1 E4 I4 R4 L( C6 c! O
/**8 d. m$ Z' C  k- \, C
* bus_for_each_drv - driver iterator: Z% U" D, s: e8 c$ V" s$ e! ?3 Q' L
* @bus: bus we're dealing with.
) m% R" q4 \0 v0 x * @start: driver to start iterating on.
6 l4 L; b3 r* `) N * @data: data to pass to the callback." r- [& L) L4 g3 `
* @fn: function to call for each driver.
7 T7 F! d, R* W *
) U  t! {$ P# F. p% ? * This is nearly identical to the device iterator above.
0 T0 \& Q+ e7 f: V, @* ?, D- V * We iterate over each driver that belongs to @bus, and call
. ^& O/ ~# M/ J$ @ * @fn for each. If @fn returns anything but 0, we break out
1 x6 e% @. r4 j% W2 O* c * and return it. If @start is not NULL, we use it as the head
6 H. o! z/ H% c& u' n+ @1 @ * of the list.
$ Z5 R0 u, w. U! C& @6 ? *
) U3 e& J3 J, X- @1 }" ~- R * NOTE: we don't return the driver that returns a non-zero
) P7 ?1 p( \9 m! P * value, nor do we leave the reference count incremented for that
6 U) h4 |+ }$ B7 Q3 C0 x * driver. If the caller needs to know that info, it must set it
6 H! G3 p9 F9 k! k. S- u# v6 M * in the callback. It must also be sure to increment the refcount* A2 i" R# L- I4 h
* so it doesn't disappear before returning to the caller.
4 }1 {  P# X) L */# V" s# G# ~, L8 r
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
  z, E; ?' L2 Z             void *data, int (*fn)(struct device_driver *, void *))
3 c5 l8 f! U  H( F0 d! S' z{9 b& n5 V1 ~. {  y; _: u( e
    struct klist_iter i;
1 D9 Q4 |) |% ^( |; g/ A" U    struct device_driver *drv;
" d! [* |) M# S. ^/ Q0 Z    int error = 0;2 y3 J7 I4 l' S1 z1 D% N5 n$ b
  ?% W0 Z' W0 q; ?# W
    if (!bus)
# B+ \. a% S) i: F        return -EINVAL;$ R9 U) m2 e  N8 [. M- r% R# z

5 q+ ]3 P% Z1 q5 f- p    klist_iter_init_node(&bus->p->klist_drivers, &i,6 m- b, H8 o) G
                 start ? &start->p->knode_bus : NULL);$ n3 B6 ], T" {/ P8 Z
    while ((drv = next_driver(&i)) && !error)
& m( [3 t% o  j& ~' l2 i        error = fn(drv, data);
! W$ q3 O. H# s  v0 D    klist_iter_exit(&i);
% {9 r: M1 y$ G) L    return error;
& p: V: y, Q7 T! G  t6 O* {5 I}: a, t/ I9 k2 W4 p6 o9 r: e
EXPORT_SYMBOL_GPL(bus_for_each_drv);* r/ }' r0 n( l
该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:
' X: M/ J# k/ h! G1 I& R; r$ @5 d) X4 U* ^, e1 T
static int __device_attach(struct device_driver *drv, void *data)
, w- ]. i' M6 q1 [{: h* m: A5 G/ L  h
        struct device *dev = data;) h: V2 I% i+ D
% k2 i6 p# @/ W
        if (!driver_match_device(drv, dev))   /*进行匹配工作*/0 q9 R; i) v3 J6 C, p5 _) G
                return 0;
$ q- n- H! j6 H) c
! v5 V, R  x' X        return driver_probe_device(drv, dev);
% x/ a, O- O" w+ y}
, g: X: s1 |- O( ~: E1 j7 T- t5 q
2 F6 U# t6 S# y- E2 Cstatic inline int driver_match_device(struct device_driver *drv,
8 I2 ^; J. l" U" a& r# ^1 r7 ^# O                      struct device *dev)1 J/ s1 \3 ?9 \: v- Z
{
: q2 y- D: F0 k5 ?    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
8 ?3 w4 y% t4 G- _5 v}
2 i7 l* Q1 Y. \& ]( e* A( x. p5 \" A* I( c4 \% u& Z! F
/**
6 _7 l6 w" q% y' H * driver_probe_device - attempt to bind device & driver together$ X+ f* _/ I1 M' |) }  ~7 D
* @drv: driver to bind a device to9 ?( G5 R; v% n
* @dev: device to try to bind to the driver
+ k' h* W8 ]& D *
- ]/ L6 Z6 Q7 U3 Q  d+ U * This function returns -ENODEV if the device is not registered,9 @& g8 a: i$ ~; Y  Z
* 1 if the device is bound sucessfully and 0 otherwise.
0 |5 ~5 d2 b  }! M/ V+ d *+ r0 g% n+ S' T$ x
* This function must be called with @dev->sem held.  When called for a5 R5 p* b7 A2 z7 a  ^1 @
* USB interface, @dev->parent->sem must be held as well.7 K  J% a% y+ v$ b. R( _4 x0 [
*/% g; d/ m' O0 q/ Y/ v
int driver_probe_device(struct device_driver *drv, struct device *dev)
0 K$ c, c) I7 D' s$ ^{% ^* c& Y  I6 {: s% Y
    int ret = 0;
& ~- u7 \  Q1 b* g$ ?/ U7 y6 p" J! A' |1 o
    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/
  v; k7 U/ h* V; x+ j# ]% {        return -ENODEV;
8 o& I7 ^6 H2 v5 B
2 k* ?* i9 C9 O! B# p- r( a    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",1 O! q' K2 J4 d6 j
         drv->bus->name, __func__, dev_name(dev), drv->name);
& p1 E& u% ^& f5 e$ t; ~& S1 E! D8 t! c' a5 {
    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/   
% y2 `5 O% E0 U; Q* o" z  x: Z- o: e" Y9 F) F
    return ret;
( R# n" h3 j& U! t* v$ `( y- X}
/ V% F! ^1 A4 d1 J2 f9 c# o3 z: g4 m+ q2 w# Z6 x1 Z, m; s# e
该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。
- F5 y; q2 g4 g% B我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。# J: d' J3 [, [- p, `0 W
1 `# ^2 L, p' Q. C# G  t
随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。
  \- E3 K4 l" ^: i9 I  B# Z, |7 S% B% X  u2 t' f7 j5 ~* b
really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。8 A4 N  Z0 E! N2 T% E
6.2.10 小结- U" W6 o6 x! u: h, P7 X
在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。
) K5 L5 r& u! C2 S2 ]: d: y3 C; Q
7 V& j- a2 c2 J) _/ f" p5 T最后以函数调用过程的总结来结束第6.2小结。
9 ?; e* N# u4 ^" k- B
6 }+ t2 B. f$ |; n9 x
6 K! q" F" g; }+ x
2 w2 h$ f# g$ }( J5 S7 a0 r4 D2 [4 g# e8 O! t/ R7 e
6.3 spi主控制器的平台设备
5 O0 c/ B8 j! C" J本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。/ G$ M% H9 T: s8 c" h1 b7 V
) v* g; e/ u+ ]+ S$ P. x
在内核的启动阶段,platform设备将被注册进内核。我们来看下。
/ b7 g! G6 A2 g( J0 J2 e& |
! z, W& a+ [! o! Y下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c
+ N- p+ s5 H$ \/ G8 X* J/ ]4 R4 X& |* D
, i8 F4 P  h. y# K, [static struct resource s3c_spi0_resource[] = {, ~1 o8 N  R' Z) v2 M- v
    [0] = {
  q# }4 b6 U8 M4 {2 ]        .start = S3C24XX_PA_SPI,8 k. G8 x) [- W# E( H* ^
        .end   = S3C24XX_PA_SPI + 0x1f,
2 V; ?% q% z' @' ~0 U+ _        .flags = IORESOURCE_MEM,
" n, a& \$ j( ]. H. t3 t    },
! v0 j7 ~  Y% t; V) U  w    [1] = {3 F  J8 E2 h! O# x. K3 ^
        .start = IRQ_SPI0,9 \# Q6 b+ y5 P1 n
        .end   = IRQ_SPI0,
7 h4 t: X) o9 ~' _! ]8 W        .flags = IORESOURCE_IRQ,
6 V* F. l" L, T    }2 x( P) p; U' ~! w8 j
* ^1 C  ~" s! v- D9 I% |
};- [3 }! R: I+ V: k+ G
2 O$ u) k! B2 S: L, W4 |( G9 x
static u64 s3c_device_spi0_dmamask = 0xffffffffUL;$ Q3 C4 A) _) e/ N& B1 f

& ^; R& |' l- \8 {5 O  m; P% \struct platform_device s3c_device_spi0 = {
1 E! M1 d/ e9 @- O9 v    .name          = "s3c2410-spi",6 b! [' e$ ^8 n1 R* F6 I% i* l' Q
    .id          = 0,4 b, L7 B6 r* r( w# c/ Q
    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),0 f5 Q: H- J2 X7 w: ]& D
    .resource      = s3c_spi0_resource,
7 e2 _8 ]: ]* W+ B* T        .dev              = {
9 _2 i- p( _# M) R" n                .dma_mask = &s3c_device_spi0_dmamask,
: ]8 M3 b3 L3 u                .coherent_dma_mask = 0xffffffffUL$ E' Z- ]; V6 f# Y& B
        }0 P0 K# ^- D% |. \+ I+ H
};8 f; y. d2 L3 V
; U) v( P! o) C  W4 S% E
static struct platform_device *smdk2440_devices[] __initdata = {
7 Q" x1 _, B. {8 X! _    &s3c_device_usb,
3 r4 e# m+ e' g5 M3 u$ q    &s3c_device_lcd,, l& d+ \$ J9 P& k1 F
    &s3c_device_wdt,
$ ~4 r& d; M3 N9 ]* v  i( u6 h    &s3c_device_i2c0,- ]# {/ r/ q2 E9 e' h9 {+ A! v. W
    &s3c_device_iis,
" Y% b1 V9 S; A, ]    &s3c_device_spi0,
8 v4 m! \7 R& H! H};
; G) q7 a9 ^7 G8 a0 M) y/ z
# J. x# @) n& ]1 `; G4 N
+ `) @; C0 l, l" I: D5 ^8 P, Q& ?0 p7 ?$ x3 i) a( L; |
static void __init smdk2440_machine_init(void)- Z6 E9 w! `' b' `9 U* C: P2 D9 Z
{
* n6 O/ B/ E' N0 P- r        s3c24xx_fb_set_platdata(&smdk2440_fb_info);+ v& J+ K* ~9 B1 q
        s3c_i2c0_set_platdata(NULL);
. k" y( j- L' Q. s4 _* m' C9 w" O) }3 T8 T8 u' Z) K
        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
2 E/ r5 J' V- C* A' o8 l        smdk_machine_init();2 `* c  e9 X: j( d: ?4 {
}0 N! S4 y- _- b' f7 R( `, @
0 X6 x- o) i- m: K9 d1 S; P  z
在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。3 y; ?" n& @- {. w
6.3.1 platform_add_devices# U( ?: [5 n) n8 N4 S( c
/**
2 ]$ j/ p9 E3 Z8 b * platform_add_devices - add a numbers of platform devices6 L. q8 W0 y1 k8 z
* @devs: array of platform devices to add
# N' u1 L# Q+ J8 h * @num: number of platform devices in array
0 Z1 r9 F# U! H9 } */
+ v4 E" D! |2 Q) z& Z, G2 Fint platform_add_devices(struct platform_device **devs, int num)/ {, v% u% Z1 A9 C2 i
{
7 ~8 c! d2 g2 @3 e& W        int i, ret = 0;
* C& j6 W* _# y* U0 D; O: }
- K+ R8 t" q" P0 U4 B        for (i = 0; i < num; i++) {4 v. R0 `: A" v  m
                ret = platform_device_register(devs);
: Z, l2 f  h. m' [" u                if (ret) {3 s% ^) f. f4 F/ x0 b
                        while (--i >= 0)7 w$ a! P. H3 k8 E
                                platform_device_unregister(devs);9 Q7 P: d+ B2 ?1 M
                        break;+ F" w; q- a- Z  ~
                }! ^8 T0 o5 D3 @& q1 l% a
        }. S7 r- Z5 q' h9 Z  {+ i) `
4 z( x' a% G8 Q9 {; u5 q) c
        return ret;) q: P6 a! V3 a( Q# @: d& Q4 R
}7 R, n, {/ |+ Y0 i# y/ s
EXPORT_SYMBOL_GPL(platform_add_devices);
+ ?  v  |) u2 R( q1 Y: }" ^5 E. e5 o: i+ @7 s
该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。
) j8 t. Y" c$ L7 H# ~6.3.2  platform_device_register3 J* _3 |# I" s7 F! J) a
/**) N. Z' c$ R' v8 @% A' H/ H2 `6 U7 |
* platform_device_register - add a platform-level device4 b- y) b% }% T5 b( N# k+ t, |
* @pdev: platform device we're adding
4 q0 t% i* e! b3 ? */  ~& y9 w" P: B* c4 }
int platform_device_register(struct platform_device *pdev)$ }  v8 `1 {4 a  v
{
: I' v8 u& m$ ?) @* m        device_initialize(&pdev->dev);1 s) S$ c$ }. d1 E4 _; m& |% F. U
        return platform_device_add(pdev);4 t# i  o- ^3 n! f3 n
}
( @5 i! F: q6 X: _3 T( V" rEXPORT_SYMBOL_GPL(platform_device_register);- S* R  `! i5 f% e4 K5 P
0 ?+ m. S2 l; ^5 J- p# w
调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。( c) W' o! p: G% B
6.3.2  platform_device_register, ^/ ?% v5 E1 s1 l$ |+ k
/**; I+ B% R: ^- l
* platform_device_add - add a platform device to device hierarchy
) a: W5 a/ w! b * @pdev: platform device we're adding9 B0 D, G1 Z5 j( X
*3 @0 z2 d  N6 F% |" L$ ]4 q- b/ b
* This is part 2 of platform_device_register(), though may be called! }1 w. f+ M; T+ {- ]
* separately _iff_ pdev was allocated by platform_device_alloc().
/ e! [" m( U8 J" ~- Q3 E */1 I- e9 `8 a+ n9 X2 G
int platform_device_add(struct platform_device *pdev)
" G. H' D7 `) h% v* w! l0 p{
& S4 _! t8 ~) R, K; s4 V, s        int i, ret = 0;
8 M+ n) _4 e- f" K# I8 w
$ r! m* x) M0 [+ z- ^% v3 [8 P* t9 d        if (!pdev)- {7 o. b/ }' j. u. b
                return -EINVAL;8 N3 i5 Z1 g6 b5 i6 m
6 D3 ~* P5 n) y8 I! x" _) U
        if (!pdev->dev.parent)
1 k1 v6 D0 ?; b5 _. j' V# \9 m& t6 M                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/* }" D3 I7 `, A* F) _& c$ z1 C! v
+ {2 T7 L! H9 b$ l  i- ^$ _) t% t" w2 \
        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/
& F% H8 h  ]* y4 j
6 b1 e- ~+ O" _  p) }        if (pdev->id != -1)) p* ]1 p* W% O. B1 h& Z1 g; }
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
5 ~4 t; E1 |4 L( l        else  N8 d" [, A" t4 G' U3 H
                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/. Y& Y4 b# e6 M" {& Q: p3 W, @" N

3 Z, |1 L8 D) _  F! M6 f0 \        /*遍历平台设备的资源,并将资源添加到资源树中*/
( S8 R6 N: H) P. z        for (i = 0; i < pdev->num_resources; i++) {
! J& f6 M) L$ _, ?5 t/ p                struct resource *p, *r = &pdev->resource;
" ~# C+ e; _  I0 T- x; i2 p6 {/ \8 e( K( c7 ~& f, w: y6 x
                if (r->name == NULL)1 T. U( Z9 j( m+ d, c
                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/, M& ~  |5 c) m- K  [. b$ K' q

( n" M& T$ W5 o( B                p = r->parent;: v  z1 Q4 N' F4 A4 I* L- p
                if (!p) {        /*p空*/
, W* K* U/ P, }/ L2 L/ @5 B  q# B                        if (resource_type(r) == IORESOURCE_MEM)
) |* s# V0 y: C3 d2 p  e3 Z                                p = &iomem_resource;1 `2 p7 C. }; \1 I- d" T
                        else if (resource_type(r) == IORESOURCE_IO)! u) v8 f9 o+ D; y5 F+ o" |
                                p = &ioport_resource;
; T/ B0 Z2 w  j3 t                }
6 T$ D# a7 x6 Y1 W! E+ N  i
- l0 o7 V$ n0 r6 G# n1 S  K* K                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/. p8 ~7 n. e3 Y4 ~1 h
                        printk(KERN_ERR
( n. F* {! U& P/ f0 O                               "%s: failed to claim resource %d\n",
" h' d7 M' N8 }8 f                               dev_name(&pdev->dev), i);9 F2 K* Y9 Y# b" h& I7 U. K
                        ret = -EBUSY;
+ l, M! ], j; \2 \: K3 X                        goto failed;
0 \' z9 p% b$ |8 y1 g  S$ l) _                }
/ w' K% U1 \( `        }
% W4 L8 m: T  r) |5 W4 Y+ d  m- i1 w0 B! d4 s
        pr_debug("Registering platform device '%s'. Parent at %s\n",
7 N* }& g& ~7 k7 |& D9 b                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));2 R: o* h% X3 f9 a5 {4 g

- f: M  y3 }8 _4 A        ret = device_add(&pdev->dev);        /*添加设备*/
7 [9 a6 z# y+ Z& Y' R' Q        if (ret == 0)# V" \/ Q: U, ]  t$ y' m+ u
                return ret;
1 _4 z6 D( Y; h' U2 A8 C
' f% s2 V" z5 ^. q5 h failed:
( i% W! s% i/ K( r1 w        while (--i >= 0) {
4 t" Q2 M7 j! D3 P4 z. Q                struct resource *r = &pdev->resource;
3 m2 `* y  C- P+ M4 e( `7 r3 e: B                unsigned long type = resource_type(r);
! Y8 j  |% q  E3 p5 x/ t: B
% y! q" F# n2 \                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)5 q3 ]/ X; ]. \% d3 |
                        release_resource(r);
1 z; @9 D2 X  t/ H, ~1 G        }
; [7 [' h: [9 r* H- F/ \: {  J' [0 a3 c  c; W
        return ret;$ X# `* G! M$ D6 N' ?0 o
}5 r1 s7 S9 Q) Y
EXPORT_SYMBOL_GPL(platform_device_add);) }8 L; G; J  l# b, l
' A! v& b+ J, K
在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
' n9 S1 k1 Y; x; t本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。7 }9 I  `8 B) G& Y! b( k" `4 p8 H3 V

: L8 s; y7 P5 G) q) ]4 d  w9 |; |$ ~那么这个"其他的工作"干了些什么呢?+ x8 s) g( O/ g, c
: y! w- f- W/ f4 _
首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。% r( r, g* z% a8 ^( J
然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。0 B3 u, _, V. u/ F5 Z6 F
9 R9 ^8 g; \" W, m
最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。
( n1 v. Z/ C: A7 F  @2 i# y! r" w5 y
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。  h8 `' ^  g/ z) _  K/ V* X

- d( G. W: j2 H) d- F% \' r) ?由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。  g/ ~# V" L& G" h$ E' w& j# n
2 v5 p: t6 j6 s' R
6.3.3 不一样device_add调用结果" K8 M! m1 J9 E; k9 T5 S7 J
首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:* ?! Q5 S; w( w* Y

' b' G3 i$ \9 V' c) jpdev->dev->kobj.kset = devices_kset9 F' d& `# T1 G  r6 M; F
0 [! e8 d  i. t6 l' I/ @9 W
pdev->dev-.parent = &platform_bus, |- p: Z% B3 j1 E9 L1 N, C' w

3 v' f. ?) {, w) s6 qpdev->dev.bus = &platform_bus_type
0 K( C+ {7 C5 o5 F, Y8 i" W
1 I/ K- G( C; @' P" Y: Hset_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。4 |- X/ U% R* A# d" A
3 B: M2 m& Z# u+ r; ~- k
kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。
# Z& S& T4 i* f9 i1 B
8 p6 B. u+ f  V( R% D# [# p( rdevice_create_file建立属性文件uevent。
4 L/ B0 K( n5 s( Wbus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。; p+ B7 i9 [$ U
# F6 ~8 Z0 T+ e4 [" H, T
            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。
4 b  q. r3 k* d( S" {# Y( I8 E. {8 Q, Y  K; e5 d
           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。. @' h! Y2 ~/ ~- Q
# G/ |) M7 L# [5 t/ w% y7 u9 K! c
dpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。
( F$ J9 Y/ V  Z- y: i& B" x+ e1 p
' M; g# u; Q, _1 X- ~0 K/ O& y! L执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。
3 G- ^* [0 e: x: |( \) G( O9 r) \3 C% @9 \. t  g+ \* V
[root@yj423 s3c2410-spi.0]#pwd
# u9 W: w) Z3 q/sys/devices/platform/s3c2410-spi.0( J! E+ |, }" ^  v' @9 z
[root@yj423 s3c2410-spi.0]#ll
, {1 X1 i  K5 @, ~7 v: v9 \lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform4 a: S2 J$ l" N3 O. j$ W8 m
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
- o- i' I( ^6 Q- b+ @-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias4 L, r4 P, h# `/ E2 ]
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power
+ G& x7 b, ?& p  S0 F8 qdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
+ q8 A" n. |* s" S' \( Jdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1
2 G) l% X% p) E- n$ r) e" H5 ylrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
% R& e! F9 {" Nlrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
0 E- ]7 y3 R7 o$ t, W5 w1 d/ @: B-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent
0 N" p" b$ N8 N+ I( P! O! B+ A$ N4 g1 h7 P
[root@yj423 devices]#pwd* b1 L/ A5 E/ \; h
/sys/bus/platform/devices7 p0 @# b* y3 I
[root@yj423 devices]#ll s3c2410-spi.0 - V$ O) B0 h. N/ N1 T. H* B: O
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0: p# I0 S" y4 ]: Y
通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。/ u1 G! P  l5 |

+ m# V/ w9 }! `  s2 {, j' gbus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。( f4 s" ?; |6 `' ?% O) Z* o
/ m$ E: g8 ^5 e6 l  [% g- S0 [
接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。
' w* ^# j- H( m3 v
& v/ s: C- q4 _. |$ b" @6 P/ U2 A7. driver举例
/ T% l" ~3 t' F* n$ o5 T& U我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。, a! `+ Y* C0 n

9 [- V9 Z: a4 u% O* X5 w; V3 N7.1 s3c24xx_spi_init
, u: i' u' X  o6 C7 _2 L) R. @- `下列代码位于drivers/spi/spi_s3c24xx.c。
/ m( }: F' B" u5 ?; X$ e; M5 ?MODULE_ALIAS("platform:s3c2410-spi");1 l8 ]. C' T( E' w, }& f
static struct platform_driver s3c24xx_spi_driver = {
8 h* x& Y- e  k; p/ G" P& v$ i# l    .remove        = __exit_p(s3c24xx_spi_remove),1 w% T' Z& _. Z9 o8 Q0 o+ x: O
    .suspend    = s3c24xx_spi_suspend,
7 M2 h. ]: {1 U- Z, D    .resume        = s3c24xx_spi_resume,
; o, t" E  K9 a( ?9 H  ]    .driver        = {
$ d% P/ D& D" G+ r5 D        .name    = "s3c2410-spi",
, k9 ^/ r; m3 o6 c5 R        .owner    = THIS_MODULE,) F0 e. d* R& z- m
    },
4 u4 X4 S" ^3 y: ]3 u8 O8 w2 l};
5 e) n3 h. V  g2 G" j
: t6 F' l, _7 `3 e% }: ostatic int __init s3c24xx_spi_init(void)
3 O" r& Y( T  i- O& X2 {{* j1 f2 r2 v( |/ E8 o
        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
/ P2 ]9 H9 X. [2 C% C/ H}, {% i  [/ {( i) u( d2 D/ k* }
驱动注册通过调用platform_driver_probe来完成。( R1 q" y( W; z: O, L8 L( N/ U
注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。- m3 w: }. D1 C  O0 N( j
7.2  platform_driver_probe
7 l8 R6 ?7 `" f' ^! w5 w下列代码位于drivers/base/platform.c。! O' {1 p9 M+ D& I: c( I  K, h1 a+ ]
/**
" H; H& \) t- T! k4 \+ F * platform_driver_probe - register driver for non-hotpluggable device9 {5 |+ e8 M7 k2 X/ d
* @drv: platform driver structure
' F+ p5 D  f" z* D, j4 ] * @probe: the driver probe routine, probably from an __init section
4 [* q# P9 \. E) F( a *
7 w1 [& I' [  R% b/ j. t0 z% E * Use this instead of platform_driver_register() when you know the device4 r$ v3 z9 \. o: |* B
* is not hotpluggable and has already been registered, and you want to+ w' e) ?+ d. Q- _, h
* remove its run-once probe() infrastructure from memory after the driver- X# V2 K  R& k0 |3 v
* has bound to the device.9 c/ d& G5 E0 P1 _* K2 A/ r
*5 E. k& |3 M! n0 P
* One typical use for this would be with drivers for controllers integrated  C- |1 {- a3 m! f8 `; q$ M
* into system-on-chip processors, where the controller devices have been( b% ?/ d9 G+ y5 }5 S, B$ ?
* configured as part of board setup.' y# j2 V! r( q) o
*
4 D( F' Z: O; ~ * Returns zero if the driver registered and bound to a device, else returns# Z1 C, L4 J" C: a( E" R( u0 G
* a negative error code and with the driver not registered.8 j3 \% M7 `( S% r$ `& i
*/
4 G& l& [# f+ g9 u/ ^int __init_or_module platform_driver_probe(struct platform_driver *drv,
. {! H5 Z% }+ c% v6 e                int (*probe)(struct platform_device *))3 C2 c8 t" U: I" t7 u+ V: P
{  B% {9 h% n& V# _6 E; z1 J5 i
        int retval, code;
4 ]$ T  @2 |# |; F9 ]! U0 u
8 d2 n9 e$ v! x! j, s" q1 S: `8 J        /* temporary section violation during probe() */
1 y3 l" b( q6 C- K8 s  v$ t        drv->probe = probe;( a" p0 k: q; I# m; J! E
        retval = code = platform_driver_register(drv); /*注册platform驱动*/
; {& d- l( E8 `5 w! [8 M7 M/ E
  b1 Y( ]; q6 x1 m: d        /* Fixup that section violation, being paranoid about code scanning
( j4 o: J, p/ o/ @* Q) Z+ ^& x         * the list of drivers in order to probe new devices.  Check to see
7 `+ k4 u6 H+ o) a         * if the probe was successful, and make sure any forced probes of0 M1 n, e  k1 [% s0 v" [
         * new devices fail.2 `# y+ u& e3 N+ U, a: D
         */1 C7 X. _/ S" D7 r, @
        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
: h/ z7 r# N) a' N! d        drv->probe = NULL;! e6 \' U7 B' N$ I" H' z) @8 \; Z
        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)). ]5 j* q2 Y' h* \. ^
                retval = -ENODEV;
# a8 G) Q8 d/ O: [# n& Z        drv->driver.probe = platform_drv_probe_fail;
7 J9 C$ x+ ?! Z3 S) y3 n        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
1 H! R4 d- _3 h+ J* X8 c/ _; s; r7 x, V. F  d4 x% o9 h
        if (code != retval)) N5 r: R  r* \
                platform_driver_unregister(drv);7 h; O3 a: [8 u" O1 \' b* J2 p
        return retval;
" L% U4 u  @# M6 i; R( Y# l}6 f" L! R% |* C/ Z( I  X
EXPORT_SYMBOL_GPL(platform_driver_probe);- {, S6 X1 t/ Y- m
这里的重点是platform_driver_register,由它来完成了platform驱动的注册。
/ T. E9 ^' B! F0 F+ O! x7.3 platform_driver_register
0 q# q7 T) [$ O9 u/ H" z( B/**
+ x; L, r& y+ P * platform_driver_register
8 u% D# O  `' a" c7 x! j1 x$ z) P * @drv: platform driver structure
4 U; t( ?% v( {7 c$ } */
$ y  y; ?+ W2 q# v* w, B+ p8 S( l( Dint platform_driver_register(struct platform_driver *drv)0 {+ l" z' P4 w1 r& @& q* G" a
{8 a* c3 W& w- q' B$ L' C
        drv->driver.bus = &platform_bus_type;
) `  ?: B& y% o8 k: S6 {5 ?, |        if (drv->probe)$ Z2 q; g1 E, v1 i% j
                drv->driver.probe = platform_drv_probe;
0 A9 {3 b6 G$ T& V& t        if (drv->remove)
! ?. w9 u9 w- C9 v2 H5 `0 U                drv->driver.remove = platform_drv_remove;
3 x* u7 R: a5 Z. }, z1 N; E( q* i        if (drv->shutdown)  t4 @" f1 M# `3 Q
                drv->driver.shutdown = platform_drv_shutdown;/ b) }' @; f2 @0 d
        if (drv->suspend)
2 f* h/ ^9 i: {8 i% w2 w                drv->driver.suspend = platform_drv_suspend;9 s+ u% t% R9 o  {# K: @
        if (drv->resume)$ O6 T# E& n5 Z4 O% u
                drv->driver.resume = platform_drv_resume;9 u) C' I$ }# A) }5 d4 O; N
        return driver_register(&drv->driver); /*驱动注册*/
9 @3 h+ K+ a1 f) |1 H9 c}
$ V; [0 }/ H& i% n5 e& o" w; mEXPORT_SYMBOL_GPL(platform_driver_register);
( Z- e# Y: C- e, H6 I" d5 I8 _; y% u/ Y8 i
driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。
* U9 p& ~2 u$ u% y! X7.4 driver_register" s, |% s$ ~% g- v  D8 A
下列代码位于drivers/base/driver.c。0 M& p) m9 m- i$ [* e: A% L, A
/**
9 f& S( b9 a4 t$ k. ]* R% x" \ * driver_register - register driver with bus
. U8 ^" G5 ?/ s; ~( A: p7 k3 A/ F * @drv: driver to register
8 a0 R" O% f% z( _4 P, s+ m *
( b2 V9 c( X) S8 P% E * We pass off most of the work to the bus_add_driver() call,0 f  z4 Z: L) {% p( {& M  B
* since most of the things we have to do deal with the bus
* ^# w1 d7 o8 n9 q) T: C& I0 K * structures.
6 e. l2 \+ H! w7 |9 |' Y5 A */7 z2 n1 |+ z  ^
int driver_register(struct device_driver *drv)% u7 z! v+ n# N
{
# \! x0 |* Q9 e( F# ^4 v6 f1 H        int ret;9 }5 f6 y$ w* f& W9 V
        struct device_driver *other;/ N' E, I! w! s) f" i

9 u! C/ @7 m  }. M# h& F" j# n: @        BUG_ON(!drv->bus->p);
( V8 U6 x* c5 L/ T0 _( ^# [
% _% d& t: C# H, }        if ((drv->bus->probe && drv->probe) ||8 L! [* t$ T5 C! m' p( X- {9 B7 h
            (drv->bus->remove && drv->remove) ||
8 o$ e2 ]5 e) ?/ N! \            (drv->bus->shutdown && drv->shutdown)). Q0 h' ?# w& x5 R- {& i
                printk(KERN_WARNING "Driver '%s' needs updating - please use "7 |+ w; a$ T+ q- }6 I# y& g1 ?
                        "bus_type methods\n", drv->name);2 v' y" q1 d7 I6 F  ~7 T

# e% d6 ^& ^7 y  T. o/ ]$ _* p        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/7 i" J! a" J; v1 l
        if (other) {        /*存在则报错*/
9 s/ w5 M, @8 T                put_driver(other);4 }9 H+ K5 Y$ I7 K! x2 E
                printk(KERN_ERR "Error: Driver '%s' is already registered, ". Q" [: p7 J  i$ V4 x/ ~
                        "aborting...\n", drv->name);
4 d( |) V2 _  i* `6 D' L                return -EEXIST;! T" G) q3 M) @! Q3 \
        }3 j% @+ c* O- g, }" c
$ L5 s% A2 L% m6 n9 S5 Y
        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/
7 N9 q  K7 [, X& B- }        if (ret)
' p* b( k8 L9 R/ A9 o4 C% }4 {                return ret;5 i' `! ?# A% u* Q* u8 ~
        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/
; t( p$ f; V& f        if (ret)
9 E; N+ v0 a, G0 ^' X) c* }                bus_remove_driver(drv);
+ a1 G% S* H1 ~, s  h7 c        return ret;
# s, C* ]1 p, S: E4 B}
9 u1 K& J% M3 s$ f2 k% fEXPORT_SYMBOL_GPL(driver_register);
$ G: t4 [" Y5 a1 b这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。* W! z3 F4 ~& u/ w5 U- b! o. A
接下来就分析这两个函数。1 s/ L8 l3 \- R3 C: ^& h  V
7.5 driver_find
5 h$ V  Q" |- B9 i; F下列代码位于drivers/base/driver.c。1 I$ l7 F5 F% c0 g, t% {) w3 N
/**. J3 A  P  S4 {4 `# g7 D5 I
* driver_find - locate driver on a bus by its name./ x# Z" `: |+ w7 q0 m
* @name: name of the driver.
5 g) c4 q7 c; I; [: ~8 G/ O * @bus: bus to scan for the driver.
+ p7 e; k: l; ]) u: V# v; }8 o0 w *
& H# A  G2 H! d% e3 m * Call kset_find_obj() to iterate over list of drivers on5 ?( Z# P& t1 A0 C: {; ?
* a bus to find driver by name. Return driver if found.& T' _7 Y. y8 v3 ]; W! q1 H  p
*  k! m8 K/ b" ^3 G
* Note that kset_find_obj increments driver's reference count.0 S3 ]; `8 I  X% `4 }; `
*/
$ m  o) J! Q. [& G0 Fstruct device_driver *driver_find(const char *name, struct bus_type *bus)5 w8 ?9 {8 W9 Y3 |' H8 H
{! r! G, Q6 A, |( \" y  A' i+ ?& A
        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
, Q. @2 |% u( P6 T/ X7 }/ h        struct driver_private *priv;  C. C! b' i# V  S8 l% ^2 k. X8 r

5 w6 o$ a0 `6 p4 s: ~$ V' b: k' D        if (k) {& }. m* @' Q" }
                priv = to_driver(k);
' G/ h' o& b7 p% Y; B6 f: w; X                return priv->driver;
3 Y! @- F5 z, d        }' \- u: ?* F1 x$ v9 O
        return NULL;
2 j+ N( T* A# a/ z1 p' @}
  \% U4 {0 I- Q6 G6 REXPORT_SYMBOL_GPL(driver_find);0 ^5 }7 {  e% {! x; q) Z

9 u3 w, t3 s6 w/**4 U+ k* M# ?. \  P
* kset_find_obj - search for object in kset.6 L  k# _, _; q$ l% E  S+ c# G
* @kset: kset we're looking in.
$ t, L# i) u9 m9 X. |% v$ b * @name: object's name.
- _2 [- w0 N5 {- O! ?: t- i  [ *& _0 s. L$ u# }/ s, N4 c
* Lock kset via @kset->subsys, and iterate over @kset->list,( y) i; _. v& \4 J  {! R" `' b
* looking for a matching kobject. If matching object is found! @* X0 q4 ~3 m( I; o
* take a reference and return the object.
/ J: }7 P. E! H4 M. X */) [* j4 S" z6 N- v  M; G
struct kobject *kset_find_obj(struct kset *kset, const char *name)
8 D8 N- C! I; Y! x- a' n: g2 g{
; W2 [* z5 e4 J# `0 O. x        struct kobject *k;  U8 I' w" R4 k2 r8 L# r: J
        struct kobject *ret = NULL;1 f- D) F% a3 i

% R* H" G4 a  a+ f0 r3 P8 b        spin_lock(&kset->list_lock);
* ~# g# R. U9 [+ q! g6 c. N        list_for_each_entry(k, &kset->list, entry) {+ Y4 p1 }$ H, L( H2 K
                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
& d- j) A! [; [* s& }                        ret = kobject_get(k);
) t# U# ~' n6 T0 v9 I: H                        break;# B7 Z4 w2 y7 K- N( n' ^
                }1 I$ D# N/ n4 m3 M
        }3 z9 d' {1 t: z$ q! o5 t* F
        spin_unlock(&kset->list_lock);
& m5 \7 I) q- j( Q7 G1 @; S+ j        return ret;
* v: M+ B0 G/ P$ G8 c}4 l) c: _! |+ o/ G3 l; L
这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。
3 {! E4 p% _2 Z0 ~! f/ |( W3 e. c7.6 bus_add_driver, H5 I# v! {0 y9 s' I5 }/ u
下列代码位于drivers/base/bus.c
$ Z& v" p1 V- H) x. s. u3 I1 b
% A3 X; s  A6 T& E- j/**
9 H/ O( b2 a* f4 t3 a, { * bus_add_driver - Add a driver to the bus.( w, p, |1 Q: v: M, W
* @drv: driver.
& B3 k# e/ J* O/ h& ] */, b' a9 S  f% D8 L9 n7 T" r; Q, L
int bus_add_driver(struct device_driver *drv)1 J8 |& M4 c3 z: K8 b
{
+ |+ v3 ]( P( m& K4 e! z        struct bus_type *bus;
( c. T$ k+ N# N, w' d; l        struct driver_private *priv;( @" M/ P# e2 p9 _( s* v8 ?
        int error = 0;
. c) O) \) K1 R, K' o+ V5 T  f' L- n- Q0 ], X9 S
        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/3 N+ Y5 F( E* {6 Z% p3 I
        if (!bus)
: k" E6 n' l- [! O- G/ Z& Y                return -EINVAL;
: F! B' t, u5 c! _1 _2 h
( |( J# {% U5 |# ~" y        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
# ^& X, W+ U7 q* ?( M: J, g7 V& x6 Z6 y* {1 a. n
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/
7 u& m0 |! n* V. ]! X  U        if (!priv) {" H. R5 `$ m" }9 n" N  n
                error = -ENOMEM;) W9 G" d4 y4 \6 L* ]' E
                goto out_put_bus;" b, U& L5 Z" w! V: D% R
        }0 a# x9 I# C- }( B4 @
        /*初始化内核链表*/- B; s: l: b. u7 B
        klist_init(&priv->klist_devices, NULL, NULL);! a2 ?; ]1 @, n5 b) J# @0 t2 \0 t
        /*相互保存*/
: v1 Z( J5 s9 Z% Q  c        priv->driver = drv;
' x# J% p' e. @1 Y        drv->p = priv;
; e# h8 s6 g: l+ I        /*设置该kobj属于那个kset*/
7 Y8 s0 c. B) n: i  J  z) u        priv->kobj.kset = bus->p->drivers_kset;
0 v- z, K& `1 E( b        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/
5 L& h1 \# D/ q8 X- `1 K                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/
& s! h1 G0 v4 ?" |( p0 r/ q        if (error)) e2 ?2 s/ N# }4 x# k
                goto out_unregister;3 t% D% q/ j8 ^4 I
# _( W$ k/ ~" u; x$ Z% _
        if (drv->bus->p->drivers_autoprobe) {' t( t" l3 I9 {: f  r1 \, N: s
                error = driver_attach(drv);        /*尝试绑定驱动和设备*/. f6 b0 A, J( ]- G/ i
                if (error)* q, H, W* d+ u# |1 I+ w8 b% k
                        goto out_unregister;
+ C: o" d: w* v: t2 ]/ g) R8 w. K        }
4 d' G1 f- w/ G' c        /*添加该驱动到bus的内核链表中*/
' `2 M6 _8 z( ?2 i        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
; P* z: u8 J4 v9 [        module_add_driver(drv->owner, drv);/*?????????*/- }# `) j+ H# y

" m  I) C; @7 p3 q9 c        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
8 k2 w! k6 C) ?, v5 U; t$ g        error = driver_create_file(drv, &driver_attr_uevent);
# Y, n# E. p! o* B& @* b        if (error) {4 k6 c3 @1 @+ X1 F) H0 Y4 W
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
5 p6 [7 c. S; _, Z* n                        __func__, drv->name);
" n$ m0 U  C' J; U        }" p9 W! ~. M+ ?; N
        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/# m' E; ~! D$ Q- z1 R
        error = driver_add_attrs(bus, drv);) v+ L/ Z3 i, O' J6 x, c( @6 ]
        if (error) {9 u! \( ~* z* c% \& }
                /* How the hell do we get out of this pickle? Give up */
3 M) X/ [- `8 e; G3 n2 Z  v                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
; D( D/ a& P3 j# }* K& z! H1 y                        __func__, drv->name);3 s0 ]6 V3 m5 l
        }+ M; l! N; W& Z
        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/
( M& ^/ o3 [% @- Y) m8 L        error = add_bind_files(drv);
0 R# g: Y0 @$ M3 ^/ h# {        if (error) {
/ @2 U6 u# x; ^, R$ [                /* Ditto */
  W) j$ m- K+ v( D2 B* H. S                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",/ v* w6 Q8 G' f! Z' h, W
                        __func__, drv->name);
& F, J  M! v; f; W        }
1 M* T* i( @8 i, U! F+ P        /*通知用户空间???*/
% N1 @4 ]+ n+ N% ?) k4 ]/ U        kobject_uevent(&priv->kobj, KOBJ_ADD);- m6 V1 O# g9 H$ n& X
        return 0;
" O3 [" _. A: iout_unregister:0 |( ~8 P: A: S8 x# k, l2 M; j
        kfree(drv->p);
6 V3 \; U7 h0 P        drv->p = NULL;
3 v. ?6 s  j3 B) h        kobject_put(&priv->kobj);" ~; s3 L, V/ q$ O
out_put_bus:* \# r7 s* a$ J' n
        bus_put(bus);
+ z9 E6 o( J, e* c        return error;
( [. o7 V0 {4 V& k}( _* g. e, B& i: _" h+ r- F
在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。6 {' @; q" Z" N5 Z7 x6 E
7.6.1 kobject_init_and_add8 M: `5 J  B+ I' Q' X' V
下列代码位于lib/kobject.c。0 Y8 T; w" F. g% _# |% M. g( {! s
/**
0 F$ r+ c% l3 D) R0 S; p7 C * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
1 c  T9 q8 I2 a/ @ * @kobj: pointer to the kobject to initialize
  n4 d( d7 S2 P! ]) C6 T/ \0 V6 g * @ktype: pointer to the ktype for this kobject.+ h- ]; Y; A- {, U5 N# d7 `
* @parent: pointer to the parent of this kobject.) g' W! X% Z4 w* a( o
* @fmt: the name of the kobject.0 c% e2 t( J( Q) T% `, T2 @) r: O
*3 X9 ]8 H+ E0 J7 d5 _+ l9 Z
* This function combines the call to kobject_init() and
* h4 x. z3 C' y' C7 K * kobject_add().  The same type of error handling after a call to" W( e! @& D8 w$ m, A7 p
* kobject_add() and kobject lifetime rules are the same here.3 Q0 v4 P; j: r% j; K0 r7 }/ t! D
*/  f7 {- b8 ]9 U% j) h6 v
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,; R( q4 }- z6 p, r
                         struct kobject *parent, const char *fmt, ...)! f5 Q8 t& U$ \- ~( P
{
' i" P, e4 [, u4 T% E: @" @        va_list args;
6 |# s6 D6 u8 Z- _4 A, y+ {4 C        int retval;/ P( G% v0 o6 w( C8 l
" Z; s+ M( q/ Y* a
        kobject_init(kobj, ktype);
+ }& e: o$ Y" T" s5 ~. J1 Z: q2 u5 R; A& o* u# J' c3 \
        va_start(args, fmt);
' x* ?& ]7 Y3 e0 W0 u        retval = kobject_add_varg(kobj, parent, fmt, args);  e5 n. R4 |0 ~$ z
        va_end(args);! v( }6 h7 W5 L) c3 k4 F1 @+ r
& u. C/ L; A! x. p# ]5 X
        return retval;
* V' `8 m: W1 |7 h1 U, x}
' o9 c  A& ^; z2 b, [EXPORT_SYMBOL_GPL(kobject_init_and_add);+ t# [. L$ H) [, g7 j, r$ u- X0 w7 j
该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。, F8 z4 |  I1 s# X1 L4 w' d
调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。0 Q. _- H% W: `1 P
5 M& ]( {' c5 c7 o3 c
我们来验证下:3 P& o4 }: W+ P
2 W# o- X# u: I0 Z
[root@yj423 s3c2410-spi]#pwd( h8 |5 _) @: @1 ]- F
/sys/bus/platform/drivers/s3c2410-spi+ A6 M$ a# X, x5 Q
接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。
2 C$ U8 M4 v# y7 T" Q7 ~7 ~" a; V& ]4 Q& K
7.6.2 driver_attach
  C# m) e% \5 k2 j* U+ a! G+ z下列代码位于drivers/base/dd.c。
- |% U5 O/ e. A5 K8 S9 [/**
3 J: y6 s- A" _9 {% g/ C( }) N * driver_attach - try to bind driver to devices.1 Y4 p6 Z7 X; R" O
* @drv: driver.) L6 @/ H8 `) ?4 F9 S9 I: u
*# y2 F6 |4 g; F9 M2 [
* Walk the list of devices that the bus has on it and try to' `9 v# l5 J" P; w- h
* match the driver with each one.  If driver_probe_device(), y; p7 @2 H/ |) z: k
* returns 0 and the @dev->driver is set, we've found a
( y( Y/ m. }" Z# V5 g' \* @ * compatible pair.
8 N+ r4 _( P$ i! v$ L */% t: X6 O" k" _5 n
int driver_attach(struct device_driver *drv)
0 k* ]. z( z; s3 B0 F{1 I7 V) g4 z: s, `* J; d
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);7 \8 Q. X, A. ^; \) r
}. K+ t4 m4 i! u- l  K! B
EXPORT_SYMBOL_GPL(driver_attach);
2 {5 O1 c) w: P, K" M' ^该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。- q: y* r( I' l0 }% U. S. g* `, b; j3 D
这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。
+ P' ?% M# F- Z# i2 ~6 i7 i2 u
/**' b3 b6 `/ q$ A2 o  x9 f$ X: v
* bus_for_each_dev - device iterator.$ k; z5 {# \+ j0 ^9 e6 ]8 B+ A
* @bus: bus type.9 }6 C, C8 U4 `. M' k
* @start: device to start iterating from.
. |9 I8 C& m! N; E  O" v * @data: data for the callback.
0 |' {6 j+ K! ]  V2 p * @fn: function to be called for each device.
& ]; H  b3 r8 V/ C# i5 V *6 i0 l( I+ U. `! M* a3 u/ Q' b
* Iterate over @bus's list of devices, and call @fn for each,
; V+ _3 N6 p5 G" F& H+ j* b * passing it @data. If @start is not NULL, we use that device to1 ]# p; `  _; G& V" ]0 h2 k  B
* begin iterating from.- }7 G# q1 `. t; U1 G" J+ T( |0 n
*9 M7 p: @& w# I- V+ q1 B2 J+ q
* We check the return of @fn each time. If it returns anything8 V' F  z1 H0 N4 G: [- D
* other than 0, we break out and return that value.
3 [$ k2 H8 ?! l1 |9 k% X9 g *
' }  X2 e( Z2 Z8 X" x, V  K * NOTE: The device that returns a non-zero value is not retained( t' W- R( y' x; X( c1 [
* in any way, nor is its refcount incremented. If the caller needs
- H) [+ L/ u& M+ Y0 J$ A, U0 F * to retain this data, it should do, and increment the reference" y8 p8 Y- `* d1 R  _+ _" I
* count in the supplied callback., r2 e2 v1 G0 i- `" c) ]
*/
1 Y+ a( g2 ~8 [3 r. r$ x# o! rint bus_for_each_dev(struct bus_type *bus, struct device *start,( ?/ u$ [" G0 D! ?# A
                     void *data, int (*fn)(struct device *, void *)), b9 I( ^. C7 I0 t
{1 r  c2 N( S# W8 A+ h
        struct klist_iter i;
$ b* t. s; T% |" s/ v6 ^2 E6 r        struct device *dev;! U5 \- U1 l) K7 k4 k; d' @2 Q
        int error = 0;
, F# {3 o' f* ?4 H
$ F1 s1 y% c5 A3 ^        if (!bus)  l: z5 x' N" |9 Z  [( V% _: I
                return -EINVAL;
( `; _3 A- k9 ~2 n# }4 s! i
8 B1 M5 k$ Z. a        klist_iter_init_node(&bus->p->klist_devices, &i,
6 Z& H5 R! K  L/ |+ \                             (start ? &start->p->knode_bus : NULL));
: H- p! M" ?0 l( l' P        while ((dev = next_device(&i)) && !error)3 b- H8 g  N: @$ v$ n# e
                error = fn(dev, data);, `2 D5 U  \# k
        klist_iter_exit(&i);. T! A/ `1 X6 ^( T. [3 l! d- S
        return error;" a2 ^# M2 U7 e! k# I/ q
}$ \% ^) g5 V2 y+ e3 _* P
EXPORT_SYMBOL_GPL(bus_for_each_dev);
/ ^& p, i& W8 R  W8 l' R通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。5 [( N' J; b" _1 a
static int __driver_attach(struct device *dev, void *data)
. D  M) M; r0 N% e{
4 T+ x$ T8 ~) X        struct device_driver *drv = data;
3 E; \- r# e$ e; F& q6 \. k) P) n, o+ j- q) ^5 Y! X5 p# B% L
        /*
* l8 H4 \7 {# c  U. ]         * Lock device and try to bind to it. We drop the error
  _9 N; u- z5 C4 a8 H         * here and always return 0, because we need to keep trying+ _. |) T0 K2 N3 U) ]
         * to bind to devices and some drivers will return an error
" e2 g8 e* I4 r9 \         * simply if it didn't support the device.
* {: g1 V6 N8 r8 ?  Y7 v4 ^         *
  @4 o5 u6 f, Y" f" ]         * driver_probe_device() will spit a warning if there5 |! @1 R( m0 F& c- I% A4 P6 l; P
         * is an error.9 W6 Q0 @6 H& T3 N3 e
         */  _, I' y6 |$ G" E' i$ d( t
( `( P$ d% M/ k( M1 `  m
        if (!driver_match_device(drv, dev))1 z- O9 g7 D; b. K- @
                return 0;: Y  k/ {" d( I" n( \, K( r$ F# e- x
/ i( i# ]& ~5 g; r7 w; H2 Q
        if (dev->parent)        /* Needed for USB */4 q' Z+ V  M" X; ^% S
                down(&dev->parent->sem);7 [9 y( b$ F+ M0 U' k) y
        down(&dev->sem);% @* Z) ]5 a/ X5 ^
        if (!dev->driver); ^% T; j. }( C
                driver_probe_device(drv, dev);# K5 X8 S- _$ _2 x/ {( O2 s
        up(&dev->sem);
2 B2 v* Q* a! V! J: Y! J        if (dev->parent)! C' M4 I* a7 G# P
                up(&dev->parent->sem);+ c. w0 j; s- G
& ?) I9 J. V1 }7 i7 a0 @7 W: V9 d
        return 0;
0 a% N1 b- U( q}
9 H5 j( @$ R9 k4 ?8 r% [, c首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:
+ f  W4 j8 X3 W( R$ m2 f5 w, F4 pstatic inline int driver_match_device(struct device_driver *drv,
9 ]8 K; c! y6 W) I0 [( r                                      struct device *dev)/ t# n$ F" Y/ r3 N
{
( L( M! j" a3 ?0 `7 c: b2 J$ i        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
$ D) J! P+ [+ Z}+ v+ n/ f* c8 f/ s3 }( E% d

! V3 K2 K$ N+ J, }: u) B2 T这里直接调用了platform总线的match方法,我们来看下这个方法。
3 s  g9 }/ B/ ^) J/**! h0 ^8 w* E$ P1 C8 Z6 Z% q
* platform_match - bind platform device to platform driver.' V+ f; u- w$ m% M) Q# a) \% w3 f$ s6 U
* @dev: device.
5 I* }# U7 j* H * @drv: driver./ {, Q% ]6 l: k: l. N& l- b! s+ u
*$ H/ K9 H; p, y" q2 l# {8 |3 M
* Platform device IDs are assumed to be encoded like this:
! V, n9 _9 i# I% l * "<name><instance>", where <name> is a short description of the type of) H: P. U% Y: d
* device, like "pci" or "floppy", and <instance> is the enumerated' z: U/ c1 i5 y9 t8 X2 k
* instance of the device, like '0' or '42'.  Driver IDs are simply; W. M* |- b/ r1 I
* "<name>".  So, extract the <name> from the platform_device structure,
+ @& S/ \' S# l$ n" D3 i * and compare it against the name of the driver. Return whether they match
' }) Y( P6 e9 B9 t * or not.
3 j: A) ?5 _+ h; w4 M$ k0 n */7 _( {5 [/ l4 f% i3 m7 F+ t
static int platform_match(struct device *dev, struct device_driver *drv)
; D, }9 x5 q2 U1 L" c5 ^* c' ]  j{
3 P) i/ V3 g3 K# Z3 C- P+ ^0 b( j& y        struct platform_device *pdev = to_platform_device(dev);! x/ I9 F$ `" ?  c# Y2 W2 c
        struct platform_driver *pdrv = to_platform_driver(drv);) r% F. P8 p# E) s

( d: a) k  }5 p        /* match against the id table first */
6 ?7 x. p9 K- D  f/ v2 E0 i6 R        if (pdrv->id_table)
/ U$ y. w& K% E" T                return platform_match_id(pdrv->id_table, pdev) != NULL;
+ o& F9 ^' d1 D  C4 t8 H0 v0 p4 |% I9 _' Y
        /* fall-back to driver name match */& X. ^# ~3 v6 d  N1 p
        return (strcmp(pdev->name, drv->name) == 0);
, r; Q7 a( E+ L+ Z! O# q}
! G' O% X3 X1 e( ~- Q该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。
) f& ?) H6 z! l% j/ @. l2 q9 ~在本例中两者同为s3c2410-spi。因此匹配完成,返回1。5 }% z0 f! {) L( @& S* M
1 A* H: ], v7 e" g
返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:
9 H7 R( o) g/ c" s" Q1 n3 J7 Y1 h
/**
6 V2 ]2 x4 N; V3 p * driver_probe_device - attempt to bind device & driver together; o4 {6 W! f. G  t+ G* t
* @drv: driver to bind a device to
0 \+ N' t# {( a% E1 X * @dev: device to try to bind to the driver
3 a% S* n/ s8 }# B *' ?. `' x1 t1 k6 X' D: P
* This function returns -ENODEV if the device is not registered,; u& o- G6 K! p/ B1 A
* 1 if the device is bound sucessfully and 0 otherwise.2 r- E& D. u, g, K
*
* u+ G" |. C* l+ |, V* | * This function must be called with @dev->sem held.  When called for a" X; L- o' q) o/ y& w  [6 D( S. P8 R
* USB interface, @dev->parent->sem must be held as well.1 j  a& T/ v! `( D
*/4 `" |7 F3 d% E7 u
int driver_probe_device(struct device_driver *drv, struct device *dev)
, t# H3 c7 v  c. N{
( ^- E  {! s- p9 @( R+ G( Y0 Q, y        int ret = 0;
2 \  F. g/ h7 x! y3 G* `6 a! d3 ^9 C! u7 p: H9 g- V
        if (!device_is_registered(dev))
8 h$ U& ~1 K6 Y8 o$ c, l- P                return -ENODEV;
' J  }/ {' L' q; a8 U8 X9 V& a. i
" C0 T% b) ^7 L7 f  x  N) L; g        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
9 M& U" y3 C6 L                 drv->bus->name, __func__, dev_name(dev), drv->name);
5 X5 P9 _7 N! H; V5 \0 S3 I
( q/ x& [8 c' w8 @7 q        ret = really_probe(dev, drv);
3 q; m! ?) s5 `) `! Z0 ^* Z# G* n8 S6 |4 C
        return ret;3 I% C( s1 Z1 @% h8 g+ v" G
}
$ m1 ?' q" @0 A5 v" H* Q. @static inline int device_is_registered(struct device *dev)/ T' c) w5 R- @: B
{1 w5 s* r3 }$ M1 G5 }. p6 G
    return dev->kobj.state_in_sysfs;- }; N* T" \! ^0 e& H
}5 k6 E; |9 e" I; b5 L% v
该函数将调用really_probe来绑定设备和它的驱动。
5 k, v# h2 E7 v. F& Fstatic int really_probe(struct device *dev, struct device_driver *drv)
. q2 n0 {( ^6 U& [+ E{
' u7 T4 c: J" S2 j; {        int ret = 0;
' [! ^5 O/ G' n/ d  ]0 A. _! V# Q* \; U: n  [. M
        atomic_inc(&probe_count);% i$ C8 R4 Y, z9 w
        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",. X6 v5 Z3 q2 j* |0 t& L, q
                 drv->bus->name, __func__, drv->name, dev_name(dev));- c. Y6 I" u+ f; X! v
        WARN_ON(!list_empty(&dev->devres_head));! z  Z1 \/ |/ }8 ]( O( h

. y- d$ f: `! f+ q9 p1 R        dev->driver = drv;
* \- N% V9 F& o2 P! z        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/
, U; j0 @3 }% G1 K% p7 C4 [' y1 ^                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",1 Z" B& C/ t9 R3 B
                        __func__, dev_name(dev));
* m( l* h2 b, c! h                goto probe_failed;
  i, q! T/ n: `& a$ O% r6 r        }: Q  t1 p( R" F. K- i
6 S9 Q3 ?/ `' [1 K+ z  `7 ^0 t
        if (dev->bus->probe) {
4 c1 O6 X, [: c8 N1 O                ret = dev->bus->probe(dev);/*调用总线的probe方法*/2 e- X1 V6 W! r) s) c* ?! j2 o+ s
                if (ret)' ~! ]  J0 M3 M+ q$ f; Y8 |3 F
                        goto probe_failed;; T0 i7 x, \4 R( G4 m
        } else if (drv->probe) {
0 a3 W4 H# k2 S- `3 D. x                ret = drv->probe(dev);        /*调用驱动的probe方法*/* X" [$ R* u: i) J% e
                if (ret)
/ ~3 F0 @/ R. M6 F7 L1 Z; a( p                        goto probe_failed;# G$ s7 ^/ |8 ?- @4 g7 v6 D
        }
: F8 w+ x0 J3 o; i1 G: Y
9 N3 I4 L1 S1 G% G* I        driver_bound(dev);              /*绑定设备和驱动*/% o! {0 h- A# N6 n
        ret = 1;
  ]1 W2 ?7 G7 ]8 x8 R9 P        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",5 Z2 A! k' K  b+ r
                 drv->bus->name, __func__, dev_name(dev), drv->name);
2 Q. m% X# m4 u, u        goto done;
2 J% _  W6 D7 V- k% J5 b$ \. n1 E' C; U9 }
probe_failed:4 C) g8 \) g# [. p' K) r4 Z# E
        devres_release_all(dev);
3 s8 Y, K: p% }8 x        driver_sysfs_remove(dev);
* d9 i/ b! Z  f6 E/ D        dev->driver = NULL;. w% |- X4 @# z0 l; ]
+ E1 K# ~, \  H6 T5 {9 I
        if (ret != -ENODEV && ret != -ENXIO) {* n+ w) ~! \$ p$ r1 G0 k7 \; [  k
                /* driver matched but the probe failed */' {& X' c$ ~% X% k
                printk(KERN_WARNING
9 ~1 X7 X3 V. O( y4 p                       "%s: probe of %s failed with error %d\n",
6 H* F) b" N+ `% }# w# ]                       drv->name, dev_name(dev), ret);/ X2 K; T5 m: H  G4 ~( A8 `4 P
        }
$ @) x5 \. G$ t# H        /*
- ?4 O" Y) P7 M6 `5 q) H& m7 L         * Ignore errors returned by ->probe so that the next driver can try
( \: ^  V' h$ z" I, u0 @- e         * its luck.
2 n- D" V+ [8 _# I3 D         */; \7 Z& Y3 F9 [
        ret = 0;
+ L7 N( A: Q" F9 n. Fdone:7 z! a  _4 z, M, a$ c
        atomic_dec(&probe_count);
6 [8 T6 r" n1 _9 [        wake_up(&probe_waitqueue);$ _4 u+ A& p, [. q
        return ret;
, u5 d# e( c; w+ ?+ g0 q/ M- O}+ ^7 k$ B8 _  p7 L- L

1 R% e  Z* V9 L$ t; f在这个函数中调用4个函数。! N& G" j& q6 K

1 P, j" T: @- ]第一个函数driver_sysfs_add将更新sysfs。
0 S( q9 H  w0 n& N3 R
. @7 m, e; Y, x' U6 J" tstatic int driver_sysfs_add(struct device *dev)
6 w! C, t# k' ~$ G* T) F{, ?  {+ A0 R3 {) T- L( ?; f
        int ret;( B5 S1 q" n8 |( P
        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,' s) x' y9 b& ]  Z; j/ t
           链接指向/sys/devices/platform/XXX */
: Q7 d5 @# \) `        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,7 w1 t' W& `+ M, y7 w" n4 I  ~7 Q5 U
                          kobject_name(&dev->kobj));
* Y2 W3 N' ?% l6 Y2 ]* R1 k        if (ret == 0) {
3 a) E1 Y' v* e" X; ~. |% P: Y                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,
' R0 K  k5 c: }- }6 i                  指向/sys/bus/xxx/drivers目录下的某个目录*/# Y- g" b# Y, v# Z- G
                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,9 Y, f) F1 ^$ c4 t7 L: d# H: l& w& U
                                        "driver");3 [0 u$ I( D" O1 b
                if (ret)
3 y  T: u) g7 o4 O7 n9 Q1 X5 y; F                        sysfs_remove_link(&dev->driver->p->kobj,
& A/ r! U; u, X) y                                        kobject_name(&dev->kobj));
9 n# c& G+ _5 C" c! P4 ?        }
+ w1 V6 P+ ]; m: o9 S        return ret;
, P' d- k0 F; k7 X2 E% P}8 D3 C5 R' z+ `, q) c$ ?/ m

& m+ g  F4 W" L% I3 `3 i执行完以后,建立了两个链接。
6 v* u2 S" F8 ^, B在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.07 e/ l9 h4 W2 m8 E8 q9 {# L
在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。1 @* j7 M7 F4 b! k3 @) e
这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。
& {! E, W, s& ]- J3 J8 Z! Q1 G; h8 ]8 z7 D
[root@yj423 s3c2410-spi]#pwd
& i& J* p& e5 J/ }+ d5 ^) Z- K/sys/bus/platform/drivers/s3c2410-spi
3 c* U1 R9 L! I$ l[root@yj423 s3c2410-spi]#ll s3c2410-spi.0 ( X4 {/ K; }) L. G' r2 s5 K; h
lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
* v+ q- w, [8 g6 o' u$ o4 \% Y% i7 ^[root@yj423 s3c2410-spi.0]#pwd
6 n# n+ i0 N6 k9 V( i/sys/devices/platform/s3c2410-spi.0
6 i6 A: @% w' F/ u9 r8 D; x[root@yj423 s3c2410-spi.0]#ll driver5 L  r% s( M  h' C! e' H
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi
0 Y. h+ M9 X7 M' x; N5 ?! \0 m
第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。4 y+ Y' X" }, @7 ~2 d
- a1 f6 Q8 o& i" J6 j7 \1 g, R, C
第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。
, n1 e# A" P1 B3 c* |
6 d2 K3 Z) a. Y- V  f* ^第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。' J, O/ r0 M/ u6 A; n
5 R( T8 `$ Y( h
static void driver_bound(struct device *dev)
2 K! [+ n# \  M9 a{9 ]6 X) O( m; @& P- u0 a) a2 X$ N
        if (klist_node_attached(&dev->p->knode_driver)) {
$ J  q, H7 h0 a, w- o  d                printk(KERN_WARNING "%s: device %s already bound\n",* [$ B' B) F: r- V. F
                        __func__, kobject_name(&dev->kobj));! E* ?1 D; k1 i! G2 G; j& c  u7 Q& b
                return;( Y5 V6 L- q* P
        }% j3 g% I1 i+ ^2 ?/ E- b7 ~) z
; f  W6 K" Q, f! E) s
        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
% d7 _0 m% j. q8 Y, |                 __func__, dev->driver->name);: m" U6 s% k9 F+ R- y6 t1 q, n# l
% F3 g2 t( v4 M4 r  F
        if (dev->bus)7 g4 M" W+ E- f( t1 F! }5 J
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,9 B+ u, p2 {. H" J5 ?
                                             BUS_NOTIFY_BOUND_DRIVER, dev);
  p- e. Q% |( n" c6 y8 X
+ Q: k/ @6 R) |  C        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
/ D$ e6 h6 k  X7 I& c% v. g}% p4 |: T" r4 `
其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。
9 f- a) s* `' E9 k  R至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。! h* w& D) K. C

0 K9 ?) Y$ f, P5 x在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。
4 q7 M+ q& b6 x' v! i3 _4 L2 S5 Y
, Z- h3 z9 h. c3 M' R- K) B( x3 J4 U3 }首先,将驱动添加到总线的驱动列表中。
( G+ q. {. i( B+ G: ~- K接着,如果定义了驱动属性文件,则创建。9 U% j# X$ J3 J1 \6 w
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。" `  f. ^; g- k
& U. E& R& j" Q  _9 g$ b4 N$ M4 l
我们来验证下:
/ B% \. `" m* N4 }5 G" c# c
) A! B" ]& T7 d3 R; X* F6 Z+ H[root@yj423 s3c2410-spi]#pwd
3 R% L6 C& \- G8 i6 {) ?  @/sys/bus/platform/drivers/s3c2410-spi7 d& o+ V) P3 Q8 j9 C# W) c
[root@yj423 s3c2410-spi]#ls
# B) l8 ?' G! Y! @- Pbind           s3c2410-spi.0  uevent         unbind1 D8 c: X& m1 l% V# B2 t
7.7 小结
& k" }/ r$ b2 p8 g* x在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。& w; i$ e7 o9 ^3 A6 L4 W& ^( H
9 Y4 u" D: c1 @
同时,还更新了链表的指向,在内核中体现了同样的关系。
0 D- F1 K' {! u* F6 S" h; y7 J0 v
$ N4 ~% S+ Z' n& p8 t- ~最后以platform driver的注册过程结束本章。
1 n' {* z) C- V4 @# ?3 l" ?) G) ~- d: Y' i+ g8 j

; H9 j( q6 l, O" R1 j; K
7 b: R  B9 n' q) J9 z/ U8. sysfs底层函数" |& e( |) t5 v- G
下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。
2 b7 B' Q2 T0 v$ k9 h$ a+ `在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。" S0 ~7 D# D+ B1 {) O% |2 S
4 Q! w# w( f8 q
8.1 注册sysfs文件系统" j, G1 T& Z8 A/ f
sysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。
9 U# L  D- `7 {9 nstart_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。
# }- G; Y. k& _2 \
  G+ S/ z: d, G% F' [4 Lint __init sysfs_init(void)
/ Z# W" z& A1 N; L, E{  d: U3 ]0 v  L- a3 R
        int err = -ENOMEM;( Q6 E& v5 n9 r
        /*建立cache,名字为sysfs_dir_cache*/
" s( u* W& v  m6 F# ?+ |% ?& b0 z        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
0 M4 _5 `3 P- I# y5 K5 C                                              sizeof(struct sysfs_dirent),6 _+ k) S/ H2 D3 Y5 i0 Z% c( E
                                              0, 0, NULL);  L0 y2 }2 P! [8 m; i6 h
        if (!sysfs_dir_cachep)
7 @& f! U' I  e. L                goto out;- R' X- Y+ I0 G! D; A/ j
$ `5 c+ ^. E7 X0 m$ K; Q
        err = sysfs_inode_init();9 L7 }% i' C$ @4 J
        if (err)
& d* I, X2 K* |                goto out_err;
/ a: j. l9 y% C+ j# q4 ?        /*注册文件系统*/
* n9 h3 N( v! _" f% P' L$ ?* S        err = register_filesystem(&sysfs_fs_type);$ T# o- b; B0 K
        if (!err) {
) O! D$ h, F3 V- _8 z                /*注册成功,加载文件系统*/
7 K1 u* ^+ z* D3 E8 d9 X. f; i                sysfs_mount = kern_mount(&sysfs_fs_type);1 C. {( N% `2 E' a1 S
                if (IS_ERR(sysfs_mount)) {0 e" P" b# q0 j9 E5 p& G
                        printk(KERN_ERR "sysfs: could not mount!\n");
! Q6 k8 T4 G" V3 i2 U% F                        err = PTR_ERR(sysfs_mount);
2 j$ Q$ X6 A8 |8 T" q                        sysfs_mount = NULL;
+ u4 S) Y+ A* s& l2 a+ Z$ H4 h1 J( o' \                        unregister_filesystem(&sysfs_fs_type);( A; P" X/ I! `9 B. ~9 ]
                        goto out_err;
$ ~; J: x6 n9 F) H0 r                }" ?' Q+ |4 ]) A( r) p# L6 U' z
        } else
2 Z) e" ~$ v- U                goto out_err;
. I' ~0 _7 b9 z/ Q# g- Wout:
8 r. B' f# V" z        return err;
: q' L* q, j. [0 D# }out_err:) z% [" }9 y5 g: Y4 h/ J: e
        kmem_cache_destroy(sysfs_dir_cachep);
  }4 v- ?7 S# x, O1 J' h" t% o        sysfs_dir_cachep = NULL;! o( d& }9 X+ p, I$ B. [
        goto out;
, u& q2 I! ~* @9 t2 g}9 ]' K) Y* H4 j: Z8 X/ F+ M# D

  v& i; j: N7 V- Gstatic struct file_system_type sysfs_fs_type = {
7 c) q/ Y' p: F% Q  |, G: r    .name        = "sysfs",
& @) q# v: Z7 {. x, T1 L    .get_sb        = sysfs_get_sb,1 [) r# r( J. T" b
    .kill_sb    = kill_anon_super,5 i! c$ c+ Z9 T9 V* y" j
};
3 ~  f* |: B0 o* x
3 }% J: }5 F8 ?8.1.1 register_filesystem) E5 n: z' x8 c7 u% J" q5 v
下列代码位于fs/filesystems.c。# A& L: [9 {$ p6 n5 h  ]. m
/**% q* s( F* H' m- }5 m# M0 ^, B, l) }
*        register_filesystem - register a new filesystem
$ h% @  r4 `- a. j& j  P *        @fs: the file system structure! S( k/ u: Q3 X: Q9 `
*9 z2 A$ X* P8 y6 x3 R2 L" d
*        Adds the file system passed to the list of file systems the kernel7 ^6 z% c8 ]( O3 g
*        is aware of for mount and other syscalls. Returns 0 on success,3 f$ H$ {3 C. |# r# }; r' _
*        or a negative errno code on an error.
5 l+ q5 ?6 c7 z( U2 P" m; R2 W *
* }" T+ K) M. M- G& _" _3 G *        The &struct file_system_type that is passed is linked into the kernel ; g, I7 u& h7 Y) ^2 Y0 q
*        structures and must not be freed until the file system has been
* X% T/ z) W0 a *        unregistered.5 O0 h* k! O5 T( V
*/
6 X- v1 M& u- ]1 g+ d7 q- o- r0 Y% X" ?' ~. L
int register_filesystem(struct file_system_type * fs)
* J8 c" t6 l% |{
: }/ y- _& [, y& h5 B4 \$ z3 D) x        int res = 0;2 D; Z0 r% K# ]$ ]3 i
        struct file_system_type ** p;, J/ G3 e8 R: }2 B- J

7 e# s  u9 g% E" W4 N0 t+ y7 C        BUG_ON(strchr(fs->name, '.'));# G: G7 {# n2 {. Z& K9 P, A
        if (fs->next)
# F3 [& }" E, W. J# O                return -EBUSY;
8 R6 @" X9 q- \' Q  K0 J        INIT_LIST_HEAD(&fs->fs_supers);+ Z0 I- r2 E: w; k
        write_lock(&file_systems_lock);
2 y( F% \* F& O+ b( b  u# q) _        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/
+ n% v3 H" }8 Y! b# ?- |        if (*p). I) \4 M1 D# W0 Z3 U5 j
                res = -EBUSY;        /*该文件系统已存在,返回error*/
6 z$ R; N  `$ m        else) R+ Z+ {; g/ ~5 t
                *p = fs;                /*将新的文件系统加入到链表中*/
! A& u: I% E7 z        write_unlock(&file_systems_lock);
- A8 Y- i  ~, E& E2 F% e, J  V        return res;  {1 |  _3 `5 u  g
}
9 R5 C& s7 c+ \) i3 B# {5 g0 Nstatic struct file_system_type **find_filesystem(const char *name, unsigned len)2 \0 `+ m, K$ F  ]! m& s
{( N8 \8 ]3 ~, M" \2 Y# z0 k
        struct file_system_type **p;
' y* G3 y" I0 P9 C7 T" e        for (p=&file_systems; *p; p=&(*p)->next)
: R0 X7 Z0 }  W                if (strlen((*p)->name) == len &&
+ t7 n1 Y5 x! A$ z, z# m                    strncmp((*p)->name, name, len) == 0)
+ c+ a: x* D( F4 B                        break;
: \+ t3 U$ z) h3 ^) F+ ^0 M  F' G        return p;' k6 L$ }! G. R9 y7 R! X
}# _2 F  L  i+ }; T# b
该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。
$ ~4 p: I: r3 |0 a) J$ S" V如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
8 {. a; M2 t# k0 z5 l7 K& p' l3 q$ Z/ a% r
该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。3 l8 e& e" j- h, L7 B2 Q( e

$ v: l9 P, {& w: j9 i6 V) }8 ^8.1.2 kern_mount函数9 r5 J: X( z4 J" {& F
下列代码位于include/linux/fs.h
8 }; |, J* \5 L4 m# M
. b0 W% h4 f# @# A/ c#define kern_mount(type) kern_mount_data(type, NULL)0 {$ M+ E  B2 n: _6 R! h/ p
下列代码位于fs/sysfs/mount.c, k. `/ u' L1 x8 Z
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+ T4 S7 B" Z; n, u+ _{. a) ]" G8 F$ v: s/ G5 w3 _0 K
    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);" p8 Q  C, m# x; f
}
  M* A! P1 j0 k# j- |3 U" O, S/ W0 c7 S- I# V2 i3 w5 e, }. l: O
EXPORT_SYMBOL_GPL(kern_mount_data);
/ x7 Z% b, ^/ z) k" [. kkern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:- I) O! l* B+ s) u1 _; M4 P

; O7 b3 q- O5 ?9 Gstruct vfsmount *
- W" ^) a5 Y% V0 j$ B7 o# lvfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)& R$ m( r2 F: A( I9 K
{
) e1 }1 b1 ?- g2 F; e% h3 P! R        struct vfsmount *mnt;
$ A/ r0 d$ c0 P1 \        char *secdata = NULL;" `" q. j: _; E, _% U! r2 a
        int error;
+ t# ^( q6 \6 F9 ?. R( ~- v# ~8 K7 F& r& a% g8 e" J
        if (!type). p; F: B1 b) u4 A
                return ERR_PTR(-ENODEV);
, n$ r4 [: T( c! P+ H0 N/ C4 e" j9 C- j7 x0 E8 j+ z8 Y
        error = -ENOMEM;
! x2 B/ ~/ u. Y1 Q' }7 T1 O& F        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/
9 d9 J/ ]' i; c& r        if (!mnt)
; K) ~  ^* ?8 R' g/ J3 G/ `                goto out;
7 ~$ |$ y# g2 i5 m4 y6 y/ B
; c9 }* \' ~) F        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
7 ^/ @& `- C$ `  T5 Y                secdata = alloc_secdata();7 m' u4 F* Z9 e/ Y# B) a' P
                if (!secdata)  y  [: m5 V( I6 ]2 j7 V: ^
                        goto out_mnt;: L; k: [0 g: b: c: X

- ~% i8 }( }7 X2 J9 G                error = security_sb_copy_data(data, secdata);( Z7 z$ m1 e$ k/ V
                if (error)
) D# `; s% Z' V: M7 P# @2 z                        goto out_free_secdata;
, B( `" _; g5 V6 u) @        }. n# W# }6 T) p: {: I" x# r
        /*get_sb方法,分配superblock对象,并初始化*/: {2 b. J. p1 B3 v% i1 B7 g" }- i+ X2 T
        error = type->get_sb(type, flags, name, data, mnt);
% w( P& m3 U# N8 x        if (error < 0)3 `0 u3 ?2 j% S* e
                goto out_free_secdata;( S2 w0 t7 w  v
        BUG_ON(!mnt->mnt_sb);2 m$ I$ `7 J7 v. P3 n% t% \
7 a! Y* W' @# d
        error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);% `5 R8 w5 @6 Y" N6 Z3 |3 z& N9 U5 o
        if (error)
0 s  ~4 A& q* t9 e4 Y+ w                 goto out_sb;7 r9 x: O. ?$ _  @8 o# p

. S. T/ I" I- x1 l3 S7 ]        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/' g3 O- Z7 G6 j9 I, _
        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/
3 k& T+ Y+ G6 f; C( c3 h/ T$ r; V# g& x$ A        up_write(&mnt->mnt_sb->s_umount);- @3 ?4 p7 k- r! q
        free_secdata(secdata);
7 K+ v6 Q2 i7 E; V        return mnt;
5 v. @; ^# s8 Xout_sb:* g9 S4 k4 B6 G; I
        dput(mnt->mnt_root);
4 ^1 F) G9 G5 P8 F        deactivate_locked_super(mnt->mnt_sb);
+ N, S% C- P1 v& S0 N/ S4 ^out_free_secdata:: A6 }! x1 k7 j
        free_secdata(secdata);. C% H6 u  S5 s4 h4 N
out_mnt:% e# i7 W+ O8 D1 n3 M8 Z, R/ ^
        free_vfsmnt(mnt);
. d0 `; T6 A% W/ `: qout:2 Z; b3 ?  _. Z+ b) }  V
        return ERR_PTR(error);
  z; f9 E) S$ D* L. F0 w}- _% \8 o: u  o" A+ H. A
& n8 c' Q1 W. i
该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。4 |( H0 k/ T/ w8 _, O/ v
下列函数位于fs/super.c
( r( E4 t( e' F+ Bstruct vfsmount *alloc_vfsmnt(const char *name)
& Y' \' h# M1 Y{
$ G2 W5 @, J4 }9 d- q7 k% i& q9 n- s        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);/ z1 H1 T6 }9 C# B8 C; ?7 G
        if (mnt) {) A" h5 V- i4 a
                int err;0 o0 i( G( |, u; E+ F; |

' T$ n6 d- \- ~( b                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/# L# T1 [, ?) ~* r0 G4 }
                if (err): A2 P. [# U; D' i! s1 M
                        goto out_free_cache;
( f! t( r" q% I) k5 W- }3 {( g7 [/ T+ q. x- t7 ~; I
                if (name) {5 I: X' ]3 n% i# A5 o& L
                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
) N4 F, O! D' R  S6 c# ]                        if (!mnt->mnt_devname)
, s& _3 ^2 g8 [6 p, \+ J9 s                                goto out_free_id;
- a7 o% r5 m1 x+ ?                }
8 H; R! _; z3 N8 @8 C2 z3 o% n3 @5 d: c0 ~
                atomic_set(&mnt->mnt_count, 1);; }" X  T( u- `7 `# D
                INIT_LIST_HEAD(&mnt->mnt_hash);4 M/ U* D! T; m- X+ w3 \& y1 i& h
                INIT_LIST_HEAD(&mnt->mnt_child);! S7 L% k4 N3 E. v, `
                INIT_LIST_HEAD(&mnt->mnt_mounts);
2 x2 w9 l2 l; c9 O) x+ @6 e                INIT_LIST_HEAD(&mnt->mnt_list);
7 k0 L" Q; A8 c. U                INIT_LIST_HEAD(&mnt->mnt_expire);
% o7 p+ u9 y0 M0 S1 S$ o8 I                INIT_LIST_HEAD(&mnt->mnt_share);6 ^6 k. D" z8 o" W1 }! y9 v- X
                INIT_LIST_HEAD(&mnt->mnt_slave_list);
  {: d' N; i. |3 \4 W                INIT_LIST_HEAD(&mnt->mnt_slave);) d3 S4 S5 M3 g" u* g8 d7 [* R
                atomic_set(&mnt->__mnt_writers, 0);. b. ]3 l# f% |7 [8 A4 n
        }, U8 m( H0 b( m. F2 u2 @4 ^
        return mnt;. B  E- b4 N) t2 A7 v6 [& W

, J1 T' ]9 `9 h; ]/ {5 Iout_free_id:& X+ i5 l, j! z+ S8 D) Q2 z/ [: }
        mnt_free_id(mnt);4 ]" h9 q! F" {- Q" D- b6 Q
out_free_cache:
' T" W4 @) ?# Z- q" z& i$ d$ S+ |5 A        kmem_cache_free(mnt_cache, mnt);# R3 k, l, h3 e3 D+ o( m' O  F
        return NULL;, V% }8 R" T0 T/ X
}: G+ l  A7 s. \; p
分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:2 o  f  g/ E8 [( @& O' s
下列函数位于fs/sysfs/mount.c。
- s5 v1 Z6 f) Qstatic int sysfs_get_sb(struct file_system_type *fs_type,# |  @( J$ m+ `+ l# D( q
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+ n8 \. C2 H& @" x  m( J" Q{
/ G; T- d4 z7 ^: u) X( W% E2 u9 g: K5 _        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
+ e: I1 }6 X0 {9 O}
4 i$ T1 ]7 k9 e; a4 t. s这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。
9 {0 s% B* U. _+ y+ F% h该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。& y- ]. e3 r/ z8 Z5 s: A: o- d

5 P9 D2 W, y4 L1 y$ U* _% j该函数的执行过程相当复杂,在下一节单独讲述。
* i. ^9 `- t* v6 T/ u+ A3 X2 U* u# {* M1 L
8.2 get_sb_single函数
& P( ]$ b4 R* r7 g4 p下列函数位于fs/sysfs/mount.c。: ~# s. m( S7 y! A& o. F) J

8 R4 j2 ^& Q; b) K  Yint get_sb_single(struct file_system_type *fs_type,* O& K; \0 T( p! m
        int flags, void *data,) r+ s1 S# i  g! I; [& e, V! q
        int (*fill_super)(struct super_block *, void *, int),
. O+ D, H( X, W        struct vfsmount *mnt)
' Z8 z1 N2 x. i{: n/ y4 r  m5 K" p, z& m" r. ?5 F  q
        struct super_block *s;
4 U  ^7 s" i6 H$ n1 n4 q. T        int error;
& R' p3 ^3 ?8 |% e" E        /*查找或者创建super_block*/9 l" Y* k# T' p$ k- F* S0 b
        s = sget(fs_type, compare_single, set_anon_super, NULL);
' |4 |2 j& c" O        if (IS_ERR(s))
/ @) N2 T& ]9 A0 m                return PTR_ERR(s);+ T/ _/ o* b+ H9 ?
        if (!s->s_root) {                /*没有根目录dentry*/
. c. \4 i- N, P* u0 f' i8 S+ q; Y                s->s_flags = flags;/ Q" y7 D( J2 `6 _. g
                /*获取root( / )的 inode和dentry*/* K! C5 a- N! x: Z' ~( g
                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);1 K, L5 U4 H& G- f9 W- f
                if (error) {
. h9 O# G6 N: t( N7 {3 d* W8 T0 l                        deactivate_locked_super(s);
8 b* `4 L( E, m' t                        return error;' S1 f& w+ y- q% u5 [
                }7 W0 Q- F8 C* ^) \+ f* {
                s->s_flags |= MS_ACTIVE;
% ~$ o! a) u' ^' ?2 u        }
4 _9 I" |% K2 J* M# h* K0 E1 \        do_remount_sb(s, flags, data, 0);7 E1 b/ {) n" z3 f- Q  U' u
        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/
' f, i# m: ]5 C/ w" ]% G4 k        return 0;$ x1 w& ~9 _- v% z
}
6 y) U3 ~% X& ^0 t4 S" G# W( N! K
- [" M; l( g! bEXPORT_SYMBOL(get_sb_single);
4 R* k7 O% J2 Y% W0 M; ^. c3 Z8.2.1 sget函数, M6 v$ p/ s) L/ y: b5 \8 A
首先调用了sget函数来查找是否9 A: Y$ C8 q5 s* Z7 Y
下列函数位于fs/super.c。
, x$ A* v0 J( U; q1 n5 f" g7 q/**
! C- V3 s  d' C4 U *        sget        -        find or create a superblock
. h8 l  r# c/ h6 H7 A% S *        @type:        filesystem type superblock should belong to
" o6 h; v$ D% q  S *        @test:        comparison callback- {( r8 e6 v0 \7 F
*        @set:        setup callback1 a  Z7 D  Y" K* M; u3 P0 x$ Z
*        @data:        argument to each of them
3 y/ h2 ^* j8 `$ M) u! M */7 ~; p0 [+ x! k, ^
struct super_block *sget(struct file_system_type *type,' x. c- o0 t7 ~1 Z: G+ i
                        int (*test)(struct super_block *,void *),* B8 H6 _& w" p0 R" k% @( p
                        int (*set)(struct super_block *,void *),
9 h& \4 O# ]& _; t" B, V                        void *data)9 e+ `: x1 W0 Z0 j# J0 A3 v: f4 c
{
( J+ @$ P) {" l+ h! L7 _( C        struct super_block *s = NULL;
; E' I: M% x, @! M        struct super_block *old;# R' [9 N7 z( t
        int err;
4 e5 ?; {3 Z, F( ~
5 a+ Y9 x4 a$ b! b4 Q0 C6 p, ]retry:5 I7 p" A( d, g2 c* S" l
        spin_lock(&sb_lock);+ F" w8 S: {) ~  N3 V  o1 b( @9 k. M
        if (test) {                        + b. T4 i% b6 H2 v) F) O
                /*遍历所有属于该文件系统的super_block*/% u/ {" A: F5 e& C, d
                list_for_each_entry(old, &type->fs_supers, s_instances) {
/ |4 J* |1 D& G: w1 q" D$ y) m) i                        if (!test(old, data))/ ]' }5 N3 |+ f5 X' T
                                continue;
: r; a; `9 j0 Y# K                        if (!grab_super(old))/ n$ C) [7 X' W1 N# M
                                goto retry;  r; ?" z9 T2 u% G/ b2 @
                        if (s) {
6 S" t0 B& ~7 ?% h2 L! f                                up_write(&s->s_umount);
0 D! u; p1 O+ X" M% Z                                destroy_super(s);/ N# D* B$ Y* E; N" A8 U. |* Q
                        }
  J8 A$ q4 z0 \& b. A                        return old;% r: b, D1 U7 l+ }
                }
- E1 g1 i1 D' O        }) N7 [7 ~7 z9 j% |% K4 n: ^- q
        if (!s) {
3 Z6 ]! f: X, A: C! b- c$ F" F                spin_unlock(&sb_lock);) g2 P5 [+ e- |; |( V
                s = alloc_super(type);        /*创建新的super_block并初始化*/
6 t% J0 r$ N7 ^, W+ l" F                if (!s)
( n* l1 r3 f0 V' Y9 r                        return ERR_PTR(-ENOMEM);* A" W, Q5 c! E
                goto retry;
' t5 ]9 i' y  e4 d: m4 L9 H        }2 m6 L+ }4 C) _" H" d8 v2 p7 h$ ]
                8 \( Q2 `: M; T3 j6 E( x5 i
        err = set(s, data);                /*设置s->s_dev */. U  d0 N6 m( C$ U. c% X
        if (err) {
  _: R* Y9 D. L( U& l' ^                spin_unlock(&sb_lock);' k4 W' R0 N  [* G& {
                up_write(&s->s_umount);& X3 a4 f$ O* n1 ~! Y( p1 H
                destroy_super(s);
$ s( ~0 j. E# e                return ERR_PTR(err);
  r" C& j7 }# a        }7 P, ~% S! x4 N) J
        s->s_type = type;
" l5 W# {( o" e& n6 K: [4 j9 |- @        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/' e  g% ], T# e# i$ x
        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/2 r+ j) }, b0 P# A0 p
        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/
' T( X+ t3 a, H) p" j        spin_unlock(&sb_lock);
0 ~2 i  Y0 A3 @0 x7 }% z        get_filesystem(type);
( W$ U- s' D% C' h6 ~8 w        return s;& l8 Q, O  g% z9 b
}
4 q" f: g. ^# k1 Z; r
5 U7 b" c* Y, k9 \1 _; d' ~EXPORT_SYMBOL(sget);
- K  o* u4 g7 C: H4 \  R/ N5 g& c& u该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。! F2 l6 s! a$ |& Y& H! d: Q7 C
然后调用alloc_super函数来创建新的struct super_block。
3 `. x; A& L* v8 T( b$ n( d5 _5 n% b: r+ u7 W
下列函数位于fs/super.c。
4 D5 C* _7 h: ~/**
" ~' s3 {! P1 Y  W* B1 G& T; o *        alloc_super        -        create new superblock6 Q; x& J5 q- e. i
*        @type:        filesystem type superblock should belong to
5 p- F0 A: M8 J* U% A; z *
7 L" N5 @8 O- E6 O" { *        Allocates and initializes a new &struct super_block.  alloc_super()
% J& n/ V8 u. C" ^* e8 A *        returns a pointer new superblock or %NULL if allocation had failed.) M( f6 Y' p- s  _/ I9 j( [
*// O( W" V* j' G9 s
static struct super_block *alloc_super(struct file_system_type *type)- M" a. M- D% }4 }% Z# R  V- m
{; B+ x: t9 n( K$ |: k' ]
        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/
8 m8 N- J( i6 M        static struct super_operations default_op;+ u4 Y- @6 L. E+ O
$ S+ j3 K5 F) M3 U+ F# h; P
        if (s) {1 v6 C! ]# t$ c5 j7 y3 r
                if (security_sb_alloc(s)) {! w/ j$ v; y3 l! S
                        kfree(s);
  S# F( l% z0 A" `( b! Q* w" Z, W                        s = NULL;5 I. j# f) u( Z- ?
                        goto out;" I! l  H9 i5 A
                }
1 a6 g- Y9 Q4 ]6 ^* F- y                INIT_LIST_HEAD(&s->s_dirty);
9 k  J# w2 Y7 g3 D                INIT_LIST_HEAD(&s->s_io);* x& ~+ p" i+ x) G
                INIT_LIST_HEAD(&s->s_more_io);
6 F5 @6 Y/ }8 z$ }6 b% H, i* l                INIT_LIST_HEAD(&s->s_files);0 ^5 a. r' ~+ F6 p8 E, \
                INIT_LIST_HEAD(&s->s_instances);
! R1 u" O" Y8 B; n6 J                INIT_HLIST_HEAD(&s->s_anon);3 Y3 i) U* s  G( J1 Y
                INIT_LIST_HEAD(&s->s_inodes);0 P7 D0 f# l, a0 o' D: f+ X3 z$ F$ g
                INIT_LIST_HEAD(&s->s_dentry_lru);7 _! Q# D& ~+ i6 v9 a% ~* B5 t
                INIT_LIST_HEAD(&s->s_async_list);
0 K$ k4 I1 Q: t4 W6 {5 {" B                init_rwsem(&s->s_umount);; [# P0 N6 K4 H$ q5 C* }* g& ?
                mutex_init(&s->s_lock);7 S; {6 K. E. B" W( }$ k* [" g& i* Y
                lockdep_set_class(&s->s_umount, &type->s_umount_key);
% q4 p  d7 h% x/ ]: ~                /*
! A$ n2 }, y8 y. ^6 L# s                 * The locking rules for s_lock are up to the
3 n% c) e" X- U7 B2 ?, t! i4 k$ s# F                 * filesystem. For example ext3fs has different; h3 u, `& q' q( H( E- t  b' x7 k
                 * lock ordering than usbfs:4 U$ c; U5 ?$ Z+ b/ v( p3 T
                 */
! d  _/ G' t+ ]/ h( [9 D                lockdep_set_class(&s->s_lock, &type->s_lock_key);
: l, }. O& [$ j4 k                /*
! x% q5 J# v  c  b$ g7 \                 * sget() can have s_umount recursion.
, k/ [+ K" k4 i( R; D" h# O                 *& W5 D- J* y  s1 [! C
                 * When it cannot find a suitable sb, it allocates a new$ V% Y$ M4 C; J9 v9 S+ V/ b
                 * one (this one), and tries again to find a suitable old
* V. w! w1 P* f  `# i$ f                 * one.
3 g1 m" q6 b) W; w3 C& N                 *
- \3 x$ ?( ]; e( W4 z* e6 ]                 * In case that succeeds, it will acquire the s_umount$ z* n) o$ d6 g7 i% z$ s
                 * lock of the old one. Since these are clearly distrinct  L/ R1 Z& {8 E& ~/ a% g! _
                 * locks, and this object isn't exposed yet, there's no
& b8 w% s' G9 C, Z+ k                 * risk of deadlocks.# \( M- v' \6 C2 r
                 *4 e* q0 c! l. q
                 * Annotate this by putting this lock in a different
# B4 M6 D# k- L6 }$ c                 * subclass., I3 g/ O" |0 ^/ `9 E6 q* j+ w& j
                 */
  f3 `. y, L! Y' f" K% e# r9 v                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);# A3 D, t  N: b. J- D
                s->s_count = S_BIAS;4 \' K) R; X2 {
                atomic_set(&s->s_active, 1);
, G2 f. r& {$ [* i- @* N                mutex_init(&s->s_vfs_rename_mutex);
: Z! x/ C. x; K$ B' Q  h8 W, P1 b. l                mutex_init(&s->s_dquot.dqio_mutex);' j  n. R* l* A2 }9 T6 p' ~
                mutex_init(&s->s_dquot.dqonoff_mutex);! F# l, {% R5 V6 }( T& M, _. l9 x* [
                init_rwsem(&s->s_dquot.dqptr_sem);
3 c: y2 Y1 ^  q  s, I$ X- d! F                init_waitqueue_head(&s->s_wait_unfrozen);
( Y- p+ R: O- d1 X* y" d. Q                s->s_maxbytes = MAX_NON_LFS;
# M3 V  @/ j% x2 V$ k( t                s->dq_op = sb_dquot_ops;
- N$ B( ^! g$ C! [                s->s_qcop = sb_quotactl_ops;
. V! z5 h+ D' @6 o                s->s_op = &default_op;
- J6 o; O$ W3 F2 z7 g                s->s_time_gran = 1000000000;
& c. ?0 N6 T0 e7 Y! s+ _" K        }
0 w7 w' J7 K, ^- J  pout:
- ~/ ^. M) Z  {, T2 s- ]# ~        return s;
8 K4 f5 s: a4 h4 I) L}, D5 E# R0 [) }, N, _3 e
分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。
2 N  _( J5 l! ]$ g# r下列函数位于fs/super.c。: V0 n' ]4 \2 K* h# L2 c
int set_anon_super(struct super_block *s, void *data)+ J# K- j6 D# m5 q. ]: G2 P
{% z1 z" L1 B* ~5 v" Q
        int dev;
  L8 k* }& L9 b        int error;8 h; l, A4 Z+ k0 I9 X
! y% I$ X8 G6 A# _: O
retry:
) f- a, p2 }  a        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/( G* n+ J9 i# p7 S
                return -ENOMEM;
9 g% e' f9 X) d* Z: r# @9 V8 M* a        spin_lock(&unnamed_dev_lock);' M6 Z$ }  w* j! X: R" M" Q
        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/  |9 \% o( l( @9 M7 v
        spin_unlock(&unnamed_dev_lock);
: [$ n! R& h: e% P! s* {: {  V        if (error == -EAGAIN)) u2 Z  I# {' ~; N0 L1 }8 S7 H
                /* We raced and lost with another CPU. */# c4 I5 X- ^$ k2 F8 Z$ J4 x' b
                goto retry;" _: e5 j& g, M: v
        else if (error)! Q6 |& m  |2 _( y; V4 z1 w
                return -EAGAIN;
* k6 ?7 M5 K, P" {% v( y% {+ e" |2 a- _6 s
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {  {' v6 g- W% K* Z8 ~7 l7 Y! y
                spin_lock(&unnamed_dev_lock);* U% `) U& G2 ^0 X4 U. }
                ida_remove(&unnamed_dev_ida, dev);! q8 \; k0 @* D0 k6 h9 B0 x
                spin_unlock(&unnamed_dev_lock);8 {3 @3 d* N& g
                return -EMFILE;
0 w- U3 n) w* O/ V0 W        }
* a) E/ K; ~- r2 |4 {        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/
9 r+ J6 q; {# L' ]9 G        return 0;
  H' M& `; s+ I+ Z}
* S* X6 o* @& K5 q* w: w4 y& Z8.2.2  sysfs_fill_super函数2 C: ]- c0 @" ~; |. |9 y! o/ M
分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。5 t6 _( u( Z# H

. |1 U. I: P) ?# t下列函数位于fs/sysfs/mount.c。
8 Z2 K: D: L2 D1 D* {struct super_block * sysfs_sb = NULL;0 b5 `7 s5 R; Q& W
' B* }# B" t8 h1 O+ x  I
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
# Y' x# D( c) N{
' `* k& f& W7 `7 {2 V        struct inode *inode;* L' v; Y' r6 I- s7 }
        struct dentry *root;! B: A  D4 H% p- v* A: M0 w
8 H  ^! C8 @3 o$ E3 R1 h
        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/
9 G! X( A0 W3 f7 }2 P% [- |, b3 Q        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
$ ]2 s4 e8 [$ d! R, T$ t        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/
1 C  J9 O( T) v        sb->s_op = &sysfs_ops;
6 ?  n$ W3 n" p+ `& O        sb->s_time_gran = 1;+ [+ p; H4 W3 e6 Z7 \7 N# d# I
        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/
+ E- p4 V1 a& W, ], d7 Q- P8 U; M6 d/ ~0 F
        /* get root inode, initialize and unlock it */  p* o) W7 ~; c; Z) ~1 i
        mutex_lock(&sysfs_mutex);# ^- c" O! o1 ]7 R* Z& v
        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/               
/ e4 A3 u9 x) x- h9 Q& j        mutex_unlock(&sysfs_mutex);
5 `6 z$ p: y) d  b) ?5 Z: ^        if (!inode) {; a: I) r6 e) m- n, Z
                pr_debug("sysfs: could not get root inode\n");0 D! p' j; `3 q( h% b
                return -ENOMEM;' J, I. ]3 O, ~) w+ `
        }% c$ T6 C+ C1 {- L  z" d

: v& D3 l5 o" ~/ V3 q* X        /* instantiate and link root dentry */2 y. ]& i5 T7 ?; b9 I" M
        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/% G/ x% i( P0 V. h
        if (!root) {
* b) |( F2 s) e* |: J, x                pr_debug("%s: could not get root dentry!\n",__func__);6 U5 B$ n& s5 n5 b+ e' w
                iput(inode);9 j3 p$ ^7 B6 U( w* F& r9 ^  G4 s0 n9 X
                return -ENOMEM;9 s$ i: z) L  G% a, E
        }0 [. S. Z. Z9 x' k3 y
        root->d_fsdata = &sysfs_root;( L8 \, M+ ^/ }8 D4 H4 ]8 |/ G
        sb->s_root = root;   /*保存superblock的根dentry*/
& B% A  w2 z7 K& A1 s) \        return 0;6 c$ _( t' q* V, G' U. E4 n5 ~
}' f2 A4 W2 o* V& h9 c4 G

! g6 O( `" u; t$ s  ?( Astruct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/
+ f+ I/ V0 ]  \, O& e2 q    .s_name        = "",( H  L7 J7 s  Q5 l& D+ B$ [! f4 V
    .s_count    = ATOMIC_INIT(1),
* L3 C8 M& o8 k9 y0 i( n2 r    .s_flags    = SYSFS_DIR,
6 D- O" {$ S) M. }4 |: X! [    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
( X0 {7 R; P! b. \* A* }4 z) B1 ]    .s_ino        = 1,+ r+ u1 G# U* V/ g% P
};" r' B. r" Y+ C" C* ?
1 b$ R3 k/ g8 j. T4 W
在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。
! G' t5 B8 |% x9 z# z随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。
/ {: w$ o9 c  {+ C0 R  q
! ]8 i; h8 F) \8 Z- f* r' e) k. G我们看些这个sysfs_dirent数据结构:" |# i( S% w9 c  j3 V
/*, W* d. O" [: X# o% u: E0 g
* sysfs_dirent - the building block of sysfs hierarchy.  Each and
/ L' ~  g7 J- u  a * every sysfs node is represented by single sysfs_dirent.* F* s- E4 x& s- |9 z
*
# @7 R7 |+ `8 J* Q * As long as s_count reference is held, the sysfs_dirent itself is' k6 N2 k: k0 a8 c: V: d
* accessible.  Dereferencing s_elem or any other outer entity
4 w: b7 i! O' h# H( b * requires s_active reference.
6 Y1 h( \; ]2 p' e' n) s4 Q( F% t */
0 H: a9 \" U' Q+ w6 Z/ Y/ ^, Zstruct sysfs_dirent {- a0 ]3 Y( Y. T) L9 t
        atomic_t                s_count;
1 _1 r/ D. m3 z: C: v        atomic_t                s_active;
- {- u# D% F. A0 f/ M        struct sysfs_dirent        *s_parent;, V7 S5 E2 R6 E& ?
        struct sysfs_dirent        *s_sibling;
9 X+ ]' ~( L+ y6 @        const char                *s_name;+ R8 r( c6 n2 Y

9 [9 }: M; a/ l, ^8 `$ Y7 a        union {3 P/ F$ f5 c5 _- W1 U; v. H
                struct sysfs_elem_dir                s_dir;
0 W# y! T1 O# B% ]) D0 F                struct sysfs_elem_symlink        s_symlink;0 s! I# ^6 q  ?! c" R" b4 d
                struct sysfs_elem_attr                s_attr;
7 t2 Q' |- y1 w, c1 I% A* u                struct sysfs_elem_bin_attr        s_bin_attr;( V' I0 |5 ^4 ]/ Z8 Z9 v1 m$ J
        };( u( L' O$ P/ U# r- t7 j3 y/ b6 M
1 `. \) p3 n5 ?
        unsigned int                s_flags;$ l9 u$ G! {* w5 z; a1 Z7 u; B
        ino_t                        s_ino;
! A! f5 l/ H( G( E: }# b6 |8 P2 B        umode_t                        s_mode;- P' O$ n" V8 Q) E. E
        struct iattr                *s_iattr;, w# M  ~3 B% N/ j# y
};/ I0 ?" F6 z/ n) g- ?5 `# R
其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。
4 R& S6 F$ ?6 b/ K/ c3 z另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。! n2 G0 {6 X- b# }1 W
接着,在来看下sysfs_get_inode函数:
8 l2 O" B8 N" `  A5 t5 `( |下列函数位于fs/sysfs/inode.c。
; A  \: g% M3 o/**+ F4 ]  w, y& g9 S: U& {
*        sysfs_get_inode - get inode for sysfs_dirent
  G; j! f5 s8 f& q8 B0 H *        @sd: sysfs_dirent to allocate inode for
' I' G+ B) E" e+ g& u *4 g6 ?: R* [& `) X. Y. k
*        Get inode for @sd.  If such inode doesn't exist, a new inode: Q0 B0 p5 l0 P7 D
*        is allocated and basics are initialized.  New inode is
6 y; z: X/ V8 l; I *        returned locked.% Q  E# K* I- p; [8 }1 i4 M1 \
*
! }8 a% \  [5 d6 K& O *        LOCKING:
2 Y& G3 a( N( q1 R% U' L+ s! }3 g *        Kernel thread context (may sleep).# O: G) b1 F7 _, d; J4 t7 M, Z
*6 n6 I9 I1 \8 j% ?3 C3 m
*        RETURNS:& Y* e' }  ]: c3 V* K4 [" K. o( c
*        Pointer to allocated inode on success, NULL on failure.' {+ W5 e# T: e% Y6 e% j
*/
7 ^( T8 F! v2 a; rstruct inode * sysfs_get_inode(struct sysfs_dirent *sd)# B: e( Q* M0 L' Y
{: o. x' C# P: r9 \- _( F2 M' i# Q* y2 n
        struct inode *inode;
9 v1 v( |) P2 D( N1 E7 {2 q$ ?7 o6 S8 d6 @6 K/ [+ {
        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/
' e% V* E% {  _8 R        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/
/ R4 H0 h8 Z* ]: ~2 U* p, m2 @                sysfs_init_inode(sd, inode);/ @9 A5 u/ O. A- u/ d8 o
; _% Z9 O3 y$ \% i9 Y2 H9 T) X
        return inode;# b* O% f0 j& c* \  c) o
}3 i- t6 ~" G" Z: \  s$ M9 {3 g
! v' M" B' V' A- l* S
/**
8 W$ M( n* x+ g- K" w' h6 z' P9 u * iget_locked - obtain an inode from a mounted file system% W; G6 o# m$ H
* @sb:        super block of file system
5 u! G9 {- S6 \* b3 y( `+ y' s * @ino:    inode number to get
. l3 t/ L9 D! h% |! j4 y2 t *
- C$ H. J- d: p( H5 D% u; r- w * iget_locked() uses ifind_fast() to search for the inode specified by @ino in1 W% R* N% I) l  y7 }/ D
* the inode cache and if present it is returned with an increased reference6 R# t! K7 v$ c- i
* count. This is for file systems where the inode number is sufficient for
: P. p4 [, T7 x2 P! r * unique identification of an inode.( R) ?! W4 J( k. Q
*
- y: ^/ U6 Q- m# d% J * If the inode is not in cache, get_new_inode_fast() is called to allocate a
, P( B" u- K0 m3 `5 [0 F * new inode and this is returned locked, hashed, and with the I_NEW flag set." V+ l; x% ?% d( o
* The file system gets to fill it in before unlocking it via6 z# u" @) `7 t0 N" g
* unlock_new_inode().0 K( C. s: T6 t4 m& f' ~# U, W2 U' y, l
*/
7 V1 }+ k( O% ?2 `8 T. [( Dstruct inode *iget_locked(struct super_block *sb, unsigned long ino)3 O: y' x7 q% \5 E
{
3 X& n& e; D5 }    struct hlist_head *head = inode_hashtable + hash(sb, ino);, d8 \5 {6 s# ?0 z1 \
    struct inode *inode;
' f' S( T  h3 A! p. P, k
1 V. b! x& h/ L- d, ]) J; W6 ^# ^4 U    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
6 `- n" C- n  |1 X2 H    if (inode)
; ~7 i5 U0 Y2 G1 {        return inode;         /*找到了该inode*/: T; R# d* A' O5 c# X" W
    /*% E) d  u; @/ U
     * get_new_inode_fast() will do the right thing, re-trying the search
$ B6 _2 j! r7 [& V     * in case it had to block at any point.% H; ?! A% N6 S' n; u; A1 {" N2 p
     */
) T1 [  R# G" `) G! Y2 V: k1 s, `    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/! N- H( m! X, h5 w7 }
}
. j# e% ^1 k8 BEXPORT_SYMBOL(iget_locked);. G- B2 h  J4 Z' R) w

1 y2 O& T# X8 p6 Rstatic void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
  [* Q2 b, I, M4 P. n+ U. g' N{
+ A" c5 B- c! ?* a    struct bin_attribute *bin_attr;
/ m" {+ ]7 D3 C$ Q
3 @: u. g9 E4 U& R! `* Q% J    inode->i_private = sysfs_get(sd);
9 Q( y/ B1 J" T( c) r. p    inode->i_mapping->a_ops = &sysfs_aops;
6 H  I+ L6 M% p    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;* E$ Q; b3 X, q/ e) i/ P% ]$ [
    inode->i_op = &sysfs_inode_operations;
& w9 D* ~+ S% T7 O' H- k4 u( h+ p( \! G    inode->i_ino = sd->s_ino;. a5 e9 ~! a; r- G% N* J. i$ B
    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
3 i# h8 e8 q7 [2 @* f' [+ w: F* O
    if (sd->s_iattr) {; [/ E7 y0 P4 q0 n2 o7 b1 ?
        /* sysfs_dirent has non-default attributes" Z8 H. I0 |+ o4 p6 C% o1 ^4 i' T. {* \$ ~
         * get them for the new inode from persistent copy
2 X3 l" }* E, o% c/ g         * in sysfs_dirent( c5 O: U# p* U+ k3 [9 u
         */3 }' v' ]9 F% y: ]
        set_inode_attr(inode, sd->s_iattr);
% p2 w" i' k% w, h# A! z    } else
( B! N% D! X' j        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/
/ Z, T( j7 k# P2 B6 Q3 @, h
3 t: ?1 |( M4 i4 ?& W
4 R- u& L3 M! z    /* initialize inode according to type */6 f6 \  g: l* V$ `
    switch (sysfs_type(sd)) {
+ Q# O( Z$ W$ f" V) C1 X" U( x    case SYSFS_DIR:
5 N  m1 m- N% ?        inode->i_op = &sysfs_dir_inode_operations;
, P7 h, `9 d. i) m& J( K2 l        inode->i_fop = &sysfs_dir_operations;1 V" K  H" d3 r2 v  j
        inode->i_nlink = sysfs_count_nlink(sd);
7 h9 n. h0 m. }2 g3 _        break;
6 g6 H1 ]5 y* R) J7 O3 t    case SYSFS_KOBJ_ATTR:
: w1 z5 D$ P1 ?        inode->i_size = PAGE_SIZE;' z0 b+ l1 J1 h8 f! x
        inode->i_fop = &sysfs_file_operations;
$ o, |, c% `8 O/ b4 D        break;8 N  ~: U) b' E7 M+ k
    case SYSFS_KOBJ_BIN_ATTR:
/ U4 P! L- g0 ]! b0 j9 c. h        bin_attr = sd->s_bin_attr.bin_attr;
" \4 p1 l' G' i8 ^: b        inode->i_size = bin_attr->size;3 w5 N4 j* W; ]' L1 R
        inode->i_fop = &bin_fops;8 r  o: r/ o5 s. z' N* X2 |- Y( E
        break;
* C8 ?( i, \* m6 W4 q/ F0 l    case SYSFS_KOBJ_LINK:
5 m& C* m* V0 U+ Y" z$ f2 H        inode->i_op = &sysfs_symlink_inode_operations;& Z9 V% H9 A4 J" L( E, [5 E
        break;
3 O' W5 s' A5 ^+ |; \    default:
3 M% ]: ?- o. Z. t% \        BUG();. Y- Z7 y% _) @: R% ~# i7 p
    }
- r0 Y, G4 D5 o9 t$ `
  M, l+ V9 f/ b/ a9 c& y    unlock_new_inode(inode);
% j2 Z2 z6 v  z}3 p; a) m: F  V! A/ ]
该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。4 |/ h- r- o& L$ M4 w: o6 n
再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。3 z! c, k4 Q3 G1 y% x
/**
2 P) T9 U* G3 e * d_alloc_root - allocate root dentry- {: ^+ M7 F5 H
* @root_inode: inode to allocate the root for
0 F; d! j/ {* P" r7 s, \ *8 R- C' h5 ]3 K$ u. c% Q" D$ D
* Allocate a root ("/") dentry for the inode given. The inode is* y0 q2 o% R7 _
* instantiated and returned. %NULL is returned if there is insufficient
' C" D; f: d0 h * memory or the inode passed is %NULL." g( Y: \  _+ w# `0 ?) u7 K
*/4 _: |2 h0 E* y5 U9 Z

# w1 s. v; {2 M8 f7 P) u" E3 l7 Pstruct dentry * d_alloc_root(struct inode * root_inode)  Z: A( }  o/ \7 I6 \1 }
{: T" |8 e4 D$ [1 W
        struct dentry *res = NULL;) v+ ]1 Z: P5 h9 M, J0 ]; D2 ?9 b

1 Z5 f" h- v2 s7 Y2 R        if (root_inode) {
! }9 m7 j% ]; R* M2 s8 v* m/ R" Z                static const struct qstr name = { .name = "/", .len = 1 };
  B  K5 s& ]' N9 M( c& a+ r, n! |/ ~( U" s1 j
                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/: t; J3 g* \" c: P6 U. L1 l
                if (res) {' K8 x( I  v: k' [8 T" d9 K
                        res->d_sb = root_inode->i_sb;
. E( R: @1 z. t! k. [* V                        res->d_parent = res;       
9 }6 x( h% ]$ q                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/+ N9 p: n% O' e3 d5 _9 [- z
                }! X; p; @9 ]: ^
        }
7 p" I+ r  m, |; g        return res;- K) n8 {8 a) w4 M- x
}
1 K0 K, q% j& i/ L* u) [( c
& b' f( T2 x- k- `& g$ K/**
% y* V- x1 o: `/ D$ b3 x1 k * d_alloc    -    allocate a dcache entry
8 g9 Q6 n+ @& b: l  q * @parent: parent of entry to allocate  |. g$ E3 B, T/ W, N, Q
* @name: qstr of the name
$ W, j/ X5 Q/ ]& k+ a* F *
; ]# M8 n" E/ f* u0 S5 e * Allocates a dentry. It returns %NULL if there is insufficient memory
4 l* G. o( `9 a2 q * available. On a success the dentry is returned. The name passed in is
. v6 N7 U/ f8 {8 A$ M * copied and the copy passed in may be reused after this call.! L0 c; K8 H  j8 q  y
*/
+ V, V- [, r8 A3 A+ z9 l5 N2 I9 y4 J4 j5 a8 O+ B6 P/ p
struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
. m* W$ F/ W1 j) S% K0 M; O* ?{& }6 e. t3 s! T
    struct dentry *dentry;8 M" c: d2 `3 V
    char *dname;: z9 t  f% i! _! @. s" H0 n

) z# s, a/ @1 I1 e; L" q" d. x    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/7 [0 T8 Y& p% ?* Q9 c6 [3 p
    if (!dentry)2 V, [. {8 }8 z4 [* m
        return NULL;
) D  \9 ~  j* n. {- B& Z# U' d* F: U  ]3 d. G) I2 k" S
    if (name->len > DNAME_INLINE_LEN-1) {
' r% G5 ~/ M) e) _* ]) J        dname = kmalloc(name->len + 1, GFP_KERNEL);
' z9 ^( c: D/ F7 c5 Z( i# h        if (!dname) {& S. Z: }& v  B+ L8 `$ b
            kmem_cache_free(dentry_cache, dentry);
0 x" b3 \, N' F            return NULL;! Q, j$ V0 s) t* {$ K1 O+ H& ]% I
        }: f6 r# F# a$ ]1 d; i0 F
    } else  {
! q, v& M$ J1 m5 C  }1 |- F        dname = dentry->d_iname;
2 Z3 L) ?# B: ^    }   
" P! ]+ c' ^0 I2 r+ o0 f8 n- ~    dentry->d_name.name = dname;) ?7 u" h/ r7 @, P& ~# U! Z# E& G
, Y8 a. l# X. b0 V
    dentry->d_name.len = name->len;
/ r: p8 S: w! E# t    dentry->d_name.hash = name->hash;: u/ }- L) A7 ~$ [: o/ k
    mEMCpy(dname, name->name, name->len);
& S/ ]# |5 \8 [5 g% u6 D6 x3 m    dname[name->len] = 0;
5 a' H/ ^2 U# O
5 Y$ |2 N! Y1 f* n( [! w9 b; y1 a    atomic_set(&dentry->d_count, 1);' t- o: D# f, C
    dentry->d_flags = DCACHE_UNHASHED;' X( Q# ]( ~5 l7 p% O
    spin_lock_init(&dentry->d_lock);
7 j+ `2 ^% \1 A; Q$ P    dentry->d_inode = NULL;7 T* t2 {% E  c0 w! S' e0 w1 m0 M3 v
    dentry->d_parent = NULL;2 o8 _' Y7 G8 N4 o6 z3 @
    dentry->d_sb = NULL;  Y# B7 H# r; t$ P6 N3 |
    dentry->d_op = NULL;
$ j0 W5 r& d, W2 }    dentry->d_fsdata = NULL;
: @3 y( T% J# G. t4 P) W4 K    dentry->d_mounted = 0;
: a5 p, S, Z& i4 N7 G    INIT_HLIST_NODE(&dentry->d_hash);0 w/ }% C" a0 E3 N# [1 D
    INIT_LIST_HEAD(&dentry->d_lru);
) c4 |  ]& J. H4 k( h' d7 o* }    INIT_LIST_HEAD(&dentry->d_subdirs);
  m* A! s( i, |, F6 Q    INIT_LIST_HEAD(&dentry->d_alias);
; P- V8 R6 K- Z3 @+ T! @9 C" u& e$ t
    if (parent) {    /*有父目录,则设置指针来表示关系*/
" `& Y6 {6 e5 W7 c' p  a0 i# _        dentry->d_parent = dget(parent);( X5 a7 B3 ~2 l# S8 E1 ?
        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/5 S# R# B: G( ^
    } else {
4 r( N% r7 U( E        INIT_LIST_HEAD(&dentry->d_u.d_child);
$ \; i. ~2 k& g" q9 \. t' H0 b    }6 Z: y4 y1 F' i" f
5 I% M4 D8 M1 o' }) u7 p7 I; k) y
    spin_lock(&dcache_lock);5 r! V& f8 W' z8 G! @+ |6 ~
    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/
& e' u8 o$ T% W* S% Y        list_add(&dentry->d_u.d_child, &parent->d_subdirs);! }" G. t. C( R/ _+ ?
    dentry_stat.nr_dentry++;
  {' u: j7 G  l! k4 K9 x( V    spin_unlock(&dcache_lock);
: t, _4 G) I; g3 O0 `8 C$ r
& c, E3 N  W. a+ ~; p  l    return dentry;  P1 e1 Q& v  g
}
/ x% P: B  z+ r$ W) X! O
8 W$ U2 H; O/ F- g; d2 }/**
6 W3 R9 F% P+ D) R2 r8 u * d_instantiate - fill in inode information for a dentry( f1 X0 s8 ]* O
* @entry: dentry to complete
/ b% X! o/ L8 H7 f( {" o * @inode: inode to attach to this dentry
; C  G9 |& E6 Z( Z" p/ V *
6 j- ?  [1 Q+ x& e' v" {. O- B3 T * Fill in inode information in the entry.
5 o& B1 X! _+ Z# I& {0 p9 S3 F% R *4 M, {  f: ~8 R: m' o
* This turns negative dentries into productive full members) P" [% Q0 y( |
* of society.
( K' t( S& X1 G  _, r' a *# C+ Q4 x9 U9 f- v; ]2 ~  I$ i
* NOTE! This assumes that the inode count has been incremented
: y. k3 E, Q9 D' Q4 W0 K% A7 }& ] * (or otherwise set) by the caller to indicate that it is now
1 H$ |0 I' O; d) z/ M1 [, @6 m * in use by the dcache.
, A6 l- g1 `" M */( m7 S; K" T. E- x. ?$ `5 ~; U
  Y% [* q( Q" u# V$ d0 m" ?7 e, \
void d_instantiate(struct dentry *entry, struct inode * inode)# Y# L- [4 i% [" N! g+ e
{
0 L; x8 N$ k! H/ S5 Q) k    BUG_ON(!list_empty(&entry->d_alias));: l8 Q2 Y; _; G: P
    spin_lock(&dcache_lock);
( z; U! x  }/ s' p: Y6 w9 |    __d_instantiate(entry, inode);
* N: \, ~! p0 K) N" v2 l9 z" e    spin_unlock(&dcache_lock);
$ z8 V/ ~9 w6 H0 ~    security_d_instantiate(entry, inode);0 Y0 ?/ T5 b2 L% F% J" c! }
}" Z0 l. Q9 R0 C& H

! F% m! N# U6 @3 \; c$ h" N% N/* the caller must hold dcache_lock */4 X9 [" t7 O; F9 K( G0 e! X; ]0 d
static void __d_instantiate(struct dentry *dentry, struct inode *inode). V% s! y+ R2 ^) ?+ K& F
{
$ D0 V2 E" w6 s5 n9 C7 N1 e    if (inode)
/ B# I+ l: H9 n( g9 Q. `. _. M        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/
% F8 V& X# u  ~, [5 A: v    dentry->d_inode = inode;        /*保存dentry对应的inode*/
; _& y. }/ ?- u; P0 b' R    fsnotify_d_instantiate(dentry, inode);
+ v3 {1 B* T) B1 t' D2 N. j}& p' X. y9 B3 h* g/ y$ N! D

  o+ q0 ]$ D; L$ Y8 L9 r该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
  q) w9 r! U3 I8 u2 @, I1 d; b接着调用d_instantiate来绑定inode和dentry之间的关系。
" k7 g. A' D4 x# R5 V$ ^) {
$ ]' v; o, j7 o# M! g0 c5 B" B* J2 C: t) Y
在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。( z3 w% z9 X! U/ y( B7 N

% d& n) C6 J6 _# C( h9 }( P9 p可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。; m0 X& m$ L6 |6 H0 C* e
. |, j  X: y3 v' W9 S
8.2.3  do_remount_sb
1 E/ t8 x" H' ~' W! K+ H" S下列代码位于fs/super.c。
4 ~6 z5 A$ @, _; c9 j' V+ j/**
$ C+ u3 l6 T* g6 l% F *        do_remount_sb - asks filesystem to change mount options.
) ^, n: v, u# x- F6 L# x8 h4 Z* G *        @sb:        superblock in question" v% r8 P9 I/ Z" F* i
*        @flags:        numeric part of options& ^" n6 @+ r7 n' c8 K0 D
*        @data:        the rest of options/ p1 c- H0 V4 P) Z3 o$ X
*      @force: whether or not to force the change4 ^( k1 E# x- G. j  U/ r3 k
*
! I9 ^' n% r' J2 b7 O *        Alters the mount options of a mounted file system.2 ]. g) B- N; f9 ]* C6 s
*/, p! W( H, {8 {" A
int do_remount_sb(struct super_block *sb, int flags, void *data, int force). E& p9 K* A, X0 D3 u7 l; f, U, E
{1 l# J9 @& x9 l- L' j; ^' M
        int retval;: f* `% j% V3 _" e
        int remount_rw;) w& H1 \5 @9 t1 ~8 v, s8 G& L) ]' B
        . r6 K3 P' w- d0 u% y! M3 b: ^
#ifdef CONFIG_BLOCK
/ y) H0 d1 {4 N1 h9 Y+ b        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))- a2 l1 r0 X( z# q+ }7 u
                return -EACCES;
7 X# P( D" T- e# Z7 @#endif
( p. Z' _+ X" p/ r        if (flags & MS_RDONLY)/ `4 z7 Z" y5 z; @
                acct_auto_close(sb);
3 \- L" ?4 ?9 G        shrink_dcache_sb(sb);7 C1 O0 D; B. r
        fsync_super(sb);
6 T6 f5 i. i9 E0 z4 q* S6 S  A0 r. @: a6 E- ^% Y! c* P
        /* If we are remounting RDONLY and current sb is read/write,9 i9 U' m6 n. m8 @# v
           make sure there are no rw files opened */
+ |, w7 h9 o! [' s' f- ~' r        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {/ U$ [, \( R* r3 {" r
                if (force)
/ R. L1 M: u6 L                        mark_files_ro(sb);( X2 H) v5 n, D# }9 ]9 ?) f6 d: P
                else if (!fs_may_remount_ro(sb))9 |0 w* @1 `5 B6 D3 t" y/ r& t
                        return -EBUSY;" w# |! ?3 A+ K/ `5 Q& n( S. s
                retval = vfs_dq_off(sb, 1);
" z5 u! v8 |7 _- n+ Y( K                if (retval < 0 && retval != -ENOSYS)! G8 i) x6 n/ q% o: Z. P4 \
                        return -EBUSY;
* n1 q; Z& q) z0 J+ \' N7 D        }4 c$ ]) ~) d" E- l9 l3 V5 R
        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);5 N* C, J8 b! y! t# n
2 f4 A5 \8 _5 S4 ~, H/ ^
        if (sb->s_op->remount_fs) {! M! h4 n& _" p. X+ P
                lock_super(sb);% Z  e7 ~( P- p+ H! t- o. |" L# r
                retval = sb->s_op->remount_fs(sb, &flags, data);% d0 n* G% k+ h# `! S
                unlock_super(sb);+ e/ U% S$ i/ J- g/ x
                if (retval)0 y: ^% k+ A" M  u8 J% m
                        return retval;
- N1 @/ D% e6 ]        }$ x% w# P& i* z9 ^
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);7 z2 L' Z  O7 M# ]
        if (remount_rw)
* J$ |$ Q/ o1 G) H- i                vfs_dq_quota_on_remount(sb);
; G5 M' \( H- ]/ [% p6 j        return 0;" l! ?: g* G, d9 l- L
}
$ ]. Z- o2 [2 e9 I: T& u6 q9 a* b; d; V6 G) I( ~; c$ t
这个函数用来修改挂在选项,这个函数就不分析了,不是重点。8 v" v% q0 [1 F( w
8.2.4simple_set_mnt: m* I  l+ K% ^
下列函数位于fs/namespace.c。4 |0 [7 ^6 M$ N
void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
! r; V. q* y% L# V3 _4 `# ^% t{
, A' l3 ~* v5 J% a0 C( ^; Z        mnt->mnt_sb = sb;
& L! V; `8 s  A3 f/ s        mnt->mnt_root = dget(sb->s_root);
7 A6 M# H' `- p* j. @}
% Q$ n/ s6 w! S5 N4 {该函数设置了vfsmount的superblock和根dentry。
! X& X* |: q; K; x: @" _3 y
# c$ H0 }) G: G# n8.2.5 小结9 r$ x5 ?( B! V: h
这里,对sysfs的注册过程做一个总结。4 U- E5 V9 m9 R- r. \0 t

+ u1 i& H4 P1 {) Osysfs_init函数调用过程示意图如下:
: V" f9 t# z. G7 I' o! y
3 G  x0 |! \; G5 [1 V8 ~ / c* {- G/ L0 x1 l3 k* f4 x# x
: P; e1 h8 X) q8 w" O" h; Y
在整个过程中,先后使用和创建了许多struct
9 R6 _1 H/ N" r3 y8 E+ f" }/ r* ]: P
第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。
3 i4 t( t0 l% x( ?/ i+ m) d, A9 ^; R
% Z+ g1 q% B9 m) e+ ~& C+ N0 D* f) w第二,建立了vfsmount。
# z$ t  b0 W9 b$ k7 I" p# J
. c  z- @( d' w0 @+ @  o第三,创建了超级块super_block。3 j: i* u# i& A+ y# ]3 \$ X
* |% D2 |# Y9 D$ Y1 K3 L9 d8 ^
第四,根据sysfs_dirent表示的根目录,建立了inode。
' F5 g- u  f3 D: S6 p/ G- ~
0 D$ ?7 u( A& Z( m' R' L/ f最后,根据刚才建立的inode创建了dentry。
! N- |2 ~% F- d9 h- w( D4 }" \4 V4 H! N6 x+ f8 Y' j# A1 L
除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
5 u" T0 L' i, ]8 o) E) j6 N9 F! e, y, H8 X( u7 z5 O. ~* U' r' M" R# d2 W
8.3 创建目录& h3 ]9 P- m9 q0 H  h1 [
在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。
/ C, b. y7 O( K& Z8 r: n! F
- H# G+ J+ e% h6 H下列代码位于fs/sysfs/dir.c。
) [5 @6 Z; a: f$ T5 y/**+ Z3 ~# w6 e( N+ ?
*        sysfs_create_dir - create a directory for an object.% i' L/ T& Y6 x0 j2 o
*        @kobj:                object we're creating directory for.
8 r7 h$ n8 U% A8 g& q1 `+ q; p& V0 s */  O4 @: r9 X* [5 ^
int sysfs_create_dir(struct kobject * kobj)
& D" R+ n; H8 D* O, a0 M6 \{
% c$ u' o6 |+ d' A        struct sysfs_dirent *parent_sd, *sd;! d+ w# `' [; W
        int error = 0;2 q9 m! X1 R+ U: D( @

" [  m! P3 O3 ~  f0 R) U        BUG_ON(!kobj);$ A6 ?# L+ [1 s% S/ Q) [, L/ x

9 c+ A+ r9 r: n8 l/ l/ w# ^        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/4 Z4 p, W: i+ w" ]- X
                parent_sd = kobj->parent->sd;! M+ w- ?& V  \4 F; T' y# o
        else                                /*没有则是在sys根目录*// J7 c- g1 W& _. h( v! i
                parent_sd = &sysfs_root;' z* y# `) i' J$ M5 t4 s+ M$ p

2 Z, w7 O; p6 t# n: M" ?        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);$ H" C- T% F2 O5 U3 y5 h
        if (!error)
) Q1 k& W/ |! d                kobj->sd = sd;
5 M2 u' z; }  B% e7 U        return error;
* m! J$ M9 J5 ^}
: X6 k# c' t9 V6 M# e8 S# M. n5 ?
* F; D0 e+ n  h) a/ n函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。) l9 f& N# C7 B' `% A1 Y. g( H
很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。. K1 M& _- M0 s

; C$ f+ X) w# }" Y6 ?. p下列代码位于fs/sysfs/dir.c。
: Z3 N8 ?5 N; [static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
! z0 Y, ?% H+ S! V7 ]                      const char *name, struct sysfs_dirent **p_sd)
1 m" N# n1 }" Q0 H: f" V{  ^9 [! u* W2 V, F  S
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;: `# C7 H  b: z; `; G
        struct sysfs_addrm_cxt acxt;4 i" r: M4 p4 h
        struct sysfs_dirent *sd;* x( v* B2 ^: |" Y; e- C8 ]
        int rc;  }# e# u/ f. \; g4 G

) L# r; `7 w3 c  L& Q        /* allocate */        /*分配sysfs_dirent并初始化*/
3 \! L, _$ O" U8 d; y4 t8 n; D& ~        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
# N3 U: y; U; q        if (!sd)& g- _* @# W! Y2 U7 X
                return -ENOMEM;5 r" U& n2 h1 m* C7 ^% b. N( m
        sd->s_dir.kobj = kobj;         /*保存kobject对象*/9 N7 M5 N8 V, c5 l. ^- e* d+ G
; X( h/ y$ o) c/ D* Z8 n* p
        /* link in */
7 h5 t' c* f3 U8 M  m% G        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/. g* x2 i( ~* T9 ]
        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/% J& \6 k; `( G* T1 Y0 A
        sysfs_addrm_finish(&acxt);                /*收尾工作*/
" N$ Y) m: j( v! Z1 a" F, @
. M% W+ U" l9 R        if (rc == 0)                /*rc为0表示创建成功*/( b" n1 q; R. |4 z; C* I9 i) R" ~
                *p_sd = sd;
9 G, j# Q1 k) b  o        else" ]/ I" g; f  z* o5 \# }+ A
                sysfs_put(sd);        /*增加引用计数*/
# E- f1 l6 N; l* e
4 S4 N' U) |! V5 B3 A7 [) u+ I        return rc;
7 C: g% x8 I! r0 S% [6 ?}
& h/ f- q2 C6 \+ l* h0 q这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。
1 n  a0 V" V+ Y: G/ _8 e9 f
2 t% I3 Y0 \4 b; A+ n2 s& Vmode还有几个宏定义可以使用,如下:
# Q; P+ a" f* R' \6 j. e#define SYSFS_KOBJ_ATTR                        0x0002! a' Z- d2 K- G* ^& x
#define SYSFS_KOBJ_BIN_ATTR                0x0004
; t2 b4 M9 v. p, U" M7 C: D1 A#define SYSFS_KOBJ_LINK                        0x0008  h- L: o% O2 H0 n7 P; A! o
#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)% r4 _* M2 {  x
8.3.1 sysfs_new_dirent $ R/ x) W* A  P5 O# _
  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。
; }! F. \2 T/ \. N0 v/ h- @) \
0 |* p5 g2 ^( `# J( n- N1 J' e; G下列代码位于fs/sysfs/dir.c。
7 }% g- c( Y; Q/ r9 B8 b' k% mstruct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
5 c5 [* E  c6 z. ?4 g% `, i{1 ^5 K% ~) h2 B2 R- n$ p. m
        char *dup_name = NULL;
2 U: M1 n, \. X        struct sysfs_dirent *sd;
0 W3 m; y; M& a" C: b3 Z  Z# l3 y; D# u3 q8 j  }
        if (type & SYSFS_COPY_NAME) {% j1 A# n7 i# V& R5 n
                name = dup_name = kstrdup(name, GFP_KERNEL);
( S" R, E$ `4 D) [( e+ z0 V4 u                if (!name)7 b% |. W4 W& H: P: m7 w
                        return NULL;
. d! Y! Y6 B- V2 B$ r. D; c        }
6 s. X, A! B. c4 i& E7 Y  [& `        /*分配sysfs_dirent并清0*/% o4 ]9 C8 p1 c2 J
        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
8 o. t4 j$ H/ f7 a. h! \' V1 c        if (!sd)
% V2 w8 R5 ^1 m' s2 {1 M' Q                goto err_out1;3 N5 J" Y& M; G1 h- m

& e9 l/ I* n6 x5 l/ O  f( Z0 v+ b, J        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/* ~' Z" J1 j/ U! ~( s
                goto err_out2;5 j6 y3 w# X+ y# i6 w
0 k/ j% d8 j* L
        atomic_set(&sd->s_count, 1);
7 M; e8 A) J7 ~9 H        atomic_set(&sd->s_active, 0);; u& F8 P3 C- V1 y! H
4 P0 G- N" l4 ~: b" D! `
        sd->s_name = name;
: V5 y( ~. }3 v0 d0 u3 \        sd->s_mode = mode;: m# y( x9 j3 t/ g- l5 z4 }
        sd->s_flags = type;& c. ]9 |  u7 W" r! V
4 l- U; G& |/ Z( c3 y6 c9 v' @" K
        return sd;
" }$ e0 a9 j% a. B
6 J# B! @2 K1 `; @; x3 _1 T err_out2:; d( `0 \. P6 J; j. b+ y
        kmem_cache_free(sysfs_dir_cachep, sd);( b3 G' K+ K& n) u) e' Y
err_out1:9 h, d- G  Z5 N! A/ c' M1 ?% z  F6 m
        kfree(dup_name);' P" E) a# w8 c4 R9 A0 C4 S
        return NULL;; R* e' O$ c+ {% e7 z, m" X- X
}
) d* c/ h/ F: m" H4 q8.3.2 有关sysfs_dirent中的联合体2 D* J4 L" E& k" L- Q5 ^$ a
分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。5 l4 \0 S. F/ T+ ~+ q& `. B' C8 s
* H0 ~& Q0 o7 {
/* type-specific structures for sysfs_dirent->s_* union members */
+ g2 {/ b4 t0 ~  H! d  E5 Estruct sysfs_elem_dir {, T! ?/ f" [! u3 O' c2 Q  u& \+ y
        struct kobject                *kobj;* m; d2 {5 i: G' q
        /* children list starts here and goes through sd->s_sibling */2 b3 M$ z( e+ t! n- {
        struct sysfs_dirent        *children;
! h- \2 E/ f7 S9 d0 w$ \, S; J5 B};
% e, J. X9 }0 _/ o" T. I: |5 V- \( M6 D+ z( N5 Y
struct sysfs_elem_symlink {
7 W8 C' \/ \* R0 p3 X1 m    struct sysfs_dirent    *target_sd;6 @: Y# n  y/ \, t# J! Q2 ^/ t
};
" a2 O) P% Z/ W6 I9 |! X" Q* p- t( q: o" S( {' K' E% C& A) I/ W' g
struct sysfs_elem_attr {
4 y+ W9 \( Q% I: h# t: c    struct attribute    *attr;
& t" r( C6 q& ~    struct sysfs_open_dirent *open;
6 o+ V+ |2 w# {  m};
4 J$ U5 b' h( m* g4 [) V2 n/ D& y; z7 V# `
struct sysfs_elem_bin_attr {
4 D1 t. M" P% }. d2 v* K1 h    struct bin_attribute    *bin_attr;
# ^7 p- k0 x, U    struct hlist_head    buffers;2 T3 ?0 h1 S4 p1 f! e! s8 {
};
  B1 i$ q( k8 K9 @, i根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。
* E: s7 g+ S! r在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。
2 F* U/ X* s  Z. J+ @* n3 u
3 P: @" J( I5 M* b: h$ q2 z# i# Y在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。2 g) b3 I# v( z+ B

3 X1 G& N, @" o& W1 ~( E! e8.3.3 sysfs_addrm_start
0 q) T' O1 P$ k! @在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。! g& C8 s7 x9 v+ J' G8 V9 C. A
7 s( h* i: [" V- j" a
下列代码位于fs/sysfs/dir.c。
+ J: A4 k, n* V8 d' D! o/ w/**
  r- C0 t4 D8 |$ h# z7 j *        sysfs_addrm_start - prepare for sysfs_dirent add/remove% p" R5 g2 |& z- r6 u& e9 N
*        @acxt: pointer to sysfs_addrm_cxt to be used) X# _6 t' o& i( B$ S! _7 @+ ^
*        @parent_sd: parent sysfs_dirent
. P* Y$ e8 A8 u* a *
% R  ^' v. _4 {( G *        This function is called when the caller is about to add or: ~0 B( X1 U  j
*        remove sysfs_dirent under @parent_sd.  This function acquires
* N8 M9 U2 Y* ^0 B4 k' ^: Q *        sysfs_mutex, grabs inode for @parent_sd if available and lock
5 P/ Y0 }# @' R& s *        i_mutex of it.  @acxt is used to keep and pass context to
1 X8 Q' T/ s* ?' B *        other addrm functions.
, y: k  l/ k  c/ w3 l *
  T0 i7 Z: r, u9 P4 P* u: \* i *        LOCKING:
% t7 I- r3 X$ q3 h6 l *        Kernel thread context (may sleep).  sysfs_mutex is locked on
/ Q3 H2 s8 U: `+ Q$ l6 H7 o *        return.  i_mutex of parent inode is locked on return if. t1 C" j4 q. Y
*        available.% T1 [1 O5 A$ J
*/% y8 W* @% W' j8 E/ W& A
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,! q/ p8 u! w- \5 b7 e- {. n
                       struct sysfs_dirent *parent_sd)3 D& A: a: v7 c6 d/ t6 m
{/ I3 P% c: }: d& p" v$ I
        struct inode *inode;# V: M5 d1 L( u& _
6 Y4 I. n* v7 h
        memset(acxt, 0, sizeof(*acxt));
( s' N! z; D  Z1 l9 _* m7 h        acxt->parent_sd = parent_sd;0 G) {: E* U) C
: a2 |& R% z! E1 u9 Y* h
        /* Lookup parent inode.  inode initialization is protected by! {: o& u' B3 ^$ }5 m$ j
         * sysfs_mutex, so inode existence can be determined by
& q! q/ T4 F8 b1 m8 \- V         * looking up inode while holding sysfs_mutex.
) {9 w- J( B& ^+ k- X( y         */
3 l# Q5 @, o8 b4 O: Z8 S        mutex_lock(&sysfs_mutex);
" A: \. I6 e- Z1 ~/ }) j1 f        /*根据parent_sd来寻找父inode*/
- Q5 Q7 l3 P, A6 f" M% A' o' L        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
0 u% B- F- t6 j6 Q9 e                         parent_sd);3 t# E" }) G! q6 J* a
        if (inode) {# T6 n7 z6 r" y& x& n8 `9 s7 L
                WARN_ON(inode->i_state & I_NEW);1 k0 E2 H% g, \# z. Y# O( y( [( r

, R6 `% X, W0 G0 M5 B$ z                /* parent inode available */
: W$ X9 \6 b, I+ D" |* ~* p                acxt->parent_inode = inode;                /*保存找到的父inode*/2 B  x1 b* L1 k3 D
2 S6 A! Y5 p& q8 ~; K' m1 ?- j; b9 j
                /* sysfs_mutex is below i_mutex in lock hierarchy.8 I' p* @# j' v6 k/ l
                 * First, trylock i_mutex.  If fails, unlock/ L: q  G: |- L
                 * sysfs_mutex and lock them in order.
; P+ k' x, L0 y2 p7 w- ?6 c) t" u                 */6 z- ~& Y$ |) J+ u( M: @& ]
                if (!mutex_trylock(&inode->i_mutex)) {2 e; O- j& `2 q4 I8 h4 N+ F5 T
                        mutex_unlock(&sysfs_mutex);
$ N2 `! _# ^( P/ L                        mutex_lock(&inode->i_mutex);
9 X! o( ^3 C3 }; g: A$ r                        mutex_lock(&sysfs_mutex);# o# O3 \. ?5 R; L9 X  v2 F
                }
/ Q, {  S) q. k        }# h  r$ V; x& V* D- \. E
}% i6 y! z  V% S% N$ Q0 A
0 j3 {$ ~8 E2 `( ]; j, m! C% P
/*
- I: W9 i% }' x * Context structure to be used while adding/removing nodes.1 ~8 E  q! {6 }- U& i# x9 O
*/
# m) x9 f  E! ], d/ Z/ K5 fstruct sysfs_addrm_cxt {
% u4 u  R+ I8 P$ m3 d0 I    struct sysfs_dirent    *parent_sd;% x$ z1 G2 j8 u0 h& v" q3 M1 m
    struct inode        *parent_inode;
& D1 H- n8 B) x" v    struct sysfs_dirent    *removed;# n% h8 K, i* |1 |
    int            cnt;
* p" M! h& ]* z/ @. X};
# g4 b, o) m5 h; |2 J注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。
* J1 @9 z, f- B8.3.4 sysfs_add_one/ ?6 E- w/ @: z4 L3 Z0 |
下列代码位于fs/sysfs/dir.c。
7 m. r$ }3 o* O& q1 q& W6 z# D$ n0 \/**  d* d8 W, Q6 a' ?" e+ d
*        sysfs_add_one - add sysfs_dirent to parent
6 g" x2 e2 G$ R+ G) N *        @acxt: addrm context to use
6 C" c7 C, T. b *        @sd: sysfs_dirent to be added( b# C0 V4 t" Z. U; D( d( F' ~
*
; Z( R; S  ]0 { *        Get @acxt->parent_sd and set sd->s_parent to it and increment
% A5 E0 F$ l1 O+ i2 t1 K0 d *        nlink of parent inode if @sd is a directory and link into the
. N2 ~" ~( H, N4 r8 e, Q7 _ *        children list of the parent.
; Y1 F* V' U' ^7 ~) D *! I: N, ?1 @7 r$ D' }9 R& S
*        This function should be called between calls to
; \- h: L( w- o *        sysfs_addrm_start() and sysfs_addrm_finish() and should be
0 S- }, L- h+ S/ {6 a *        passed the same @acxt as passed to sysfs_addrm_start()." x) o# m* t+ O; z; a# J" g
*
5 u' h  W7 w) j: b, T6 o *        LOCKING:3 Z7 C5 c: R# @0 J1 I2 m# T
*        Determined by sysfs_addrm_start().2 ]) f4 [2 i* E9 l/ E' V, X7 y
*
' f& ]) L1 X, h  H- {% H7 V5 W' s# a *        RETURNS:* X) o: ?- h) c& |
*        0 on success, -EEXIST if entry with the given name already: {/ ~/ f( J; h" j9 M
*        exists.; a7 [- I* a) T5 R1 P
*/4 W; I7 u8 ~; G( c, G  X; a
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
/ k  w- ^4 ]% F. y% t{
6 c) `" i8 u  M; J1 w6 n7 |        int ret;2 C2 x( c. @# _! y8 M, U

1 h* ?& Z& Q: J$ b9 X  G) A        ret = __sysfs_add_one(acxt, sd);
. D2 |3 N( r+ B* F        if (ret == -EEXIST) {$ d& _5 z, i, Q7 h( V
                char *path = kzalloc(PATH_MAX, GFP_KERNEL);7 f7 U  ~1 `7 x2 i" x) w( T( @1 v2 h
                WARN(1, KERN_WARNING  M; ]: S0 h7 E8 I4 N' L
                     "sysfs: cannot create duplicate filename '%s'\n",
4 @; t- z. Z) M                     (path == NULL) ? sd->s_name :" N: U' U3 K1 E$ I, V
                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),
( j: P: Y  P! |4 k                            sd->s_name));8 z* a2 F# j0 G8 U. S( ~
                kfree(path);
2 R" a  b; O) ]- d& v' _+ v, e        }
5 M9 C) [: j: N$ S) O+ X7 Q3 d( g  p6 i" T0 Z, l$ y- b
        return ret;( R( L  a  i$ T, X, O
}
! a$ u. E  y8 d: V- J- a# C/ C+ l7 k9 h0 P6 y: W. L
/**6 D! p% f# Q7 j) y' c7 N
*    __sysfs_add_one - add sysfs_dirent to parent without warning
, q5 a0 n$ {$ j" S7 v  B# s *    @acxt: addrm context to use
, F. z7 B) R- L  z4 F& w *    @sd: sysfs_dirent to be added
* X: H0 n* X* Y, O; c' D4 e8 Z *
# j( L) J1 x+ Z  p *    Get @acxt->parent_sd and set sd->s_parent to it and increment
5 M. H; x  z" @$ C' T  d! u- l *    nlink of parent inode if @sd is a directory and link into the+ k. _" ]$ R) i, R  k3 S
*    children list of the parent.9 A0 X; L8 j6 u: g: f
*
/ W) \, e. C- {  }# V/ E" b *    This function should be called between calls to
5 m4 D, C. I/ X, f' O( i# p1 D *    sysfs_addrm_start() and sysfs_addrm_finish() and should be
! x  E6 b: Y/ \. q1 l  h *    passed the same @acxt as passed to sysfs_addrm_start().5 c/ b& _1 G9 y) p6 W, n. p
*
* |- x6 W6 A6 M; l( @ *    LOCKING:
5 ~6 }4 p% n8 [ *    Determined by sysfs_addrm_start().
* F- a, J7 ~+ [0 F *
( O9 r6 y! B# ]# B/ M *    RETURNS:! C6 {9 o+ r8 n1 r! |: z
*    0 on success, -EEXIST if entry with the given name already/ I8 l. W9 }8 p
*    exists.
; \9 v  J* u6 e- i+ M */
2 L( K! F- |# {/ h8 hint __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
5 d* `& y4 H: z' }6 M9 ^{
0 i( z: F1 W! L0 D! S% \. h    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
0 b1 {' ?3 p" X6 ?6 S* @    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)). i7 ?" u$ Q9 t- v2 ^9 r
        return -EEXIST;; \9 t0 _$ p' S( K' t7 P" g1 @9 x9 r

/ e2 f4 m0 Y; K0 v: [0 ^5 Z6 r    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
4 Q" m- \3 C& T2 H" L1 y8 ~' _* {* f$ T
    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/6 F% [1 k8 G5 S5 e1 x
        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/
1 ^1 P* s. B+ v( k6 u- b9 X# d$ s) L5 ]: J: C" H) H3 K
    acxt->cnt++;
: F. H5 }* h5 k7 J# [+ E' B. y  z$ S" q. T5 e7 B1 X( l: ~' a' `
    sysfs_link_sibling(sd);
7 k# y0 K$ ?* C1 e& M* j) o9 O& P/ t' u& k. j
    return 0;
- d# V, Q, A; e/ O8 v$ a9 [}
$ ~, b% ^5 F6 I
+ n) z- e* M* X" j5 ]" G! y6 w0 J! i/**
/ ?$ B. d) E+ J( C3 q0 e/ P7 w( @' q9 O *    sysfs_find_dirent - find sysfs_dirent with the given name
5 y3 d3 ~& ~) E4 s1 j  v7 S, [ *    @parent_sd: sysfs_dirent to search under
5 K; v  \9 Z$ x3 j2 t2 S *    @name: name to look for
( _, I3 V; l* r: x) Q *, E# u9 u" `0 O
*    Look for sysfs_dirent with name @name under @parent_sd.; r2 d0 K  @8 W- W) ?2 E' |
*
/ u$ c2 y& K  |5 t' }6 Z  t *    LOCKING:. m, D: p" g6 N' {! {$ {
*    mutex_lock(sysfs_mutex)
7 ?% ]" V' r9 v! M* N# u *
! N( h  k3 S. E+ Z) v, P *    RETURNS:( X. @# O9 l' U4 ?9 V5 M3 f
*    Pointer to sysfs_dirent if found, NULL if not.9 Z" n  ]8 k# |; [4 w$ n4 H$ d, V
*/2 t2 s/ L8 I+ [7 k) x
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd," P4 H1 F0 i, H
                       const unsigned char *name)
" B; _/ D/ T% |/ j8 _- U1 H{
6 h' O" s) n+ {7 _* `    struct sysfs_dirent *sd;
- S+ {# h! i4 a
0 _: G" a  a/ W" ~4 ^- L    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
1 ~; D" w' K0 s& i3 m' O        if (!strcmp(sd->s_name, name))& d/ g  ?. z2 {! d
            return sd;+ w$ ?. F% _5 n! N3 ~! T% d
    return NULL;! R# P$ s" T$ ]0 U" r9 |9 i
}
* P- T8 H, Q, A1 Q0 M
" ?/ b, B5 ^$ A' k/**
+ U. Z9 m/ N$ _4 W; Z *    sysfs_link_sibling - link sysfs_dirent into sibling list' b' v+ H  J7 v' Z* E
*    @sd: sysfs_dirent of interest
: Y; ]9 B! L& L: ~/ ?3 e' ^ *6 m7 g3 m6 E/ W) \% l9 B) ?
*    Link @sd into its sibling list which starts from1 [; v' y4 w' [/ r- ~5 A, _
*    sd->s_parent->s_dir.children.
1 R! t7 x& C5 `0 T *
, d  D* P) m2 w- h *    Locking:; R* y4 w! |6 u/ R/ G
*    mutex_lock(sysfs_mutex)1 U+ I5 \: w4 S6 Y
*/
; z9 c0 ^9 E) K: ]* ]: s* x1 sstatic void sysfs_link_sibling(struct sysfs_dirent *sd)5 P1 S  N- t% A" L5 ]4 x" W' G- C
{! g7 l9 p3 Q& v
    struct sysfs_dirent *parent_sd = sd->s_parent;* F/ P+ r( `& L: c% ~5 _) G
    struct sysfs_dirent **pos;; T+ @) D0 j  ~- o: s

4 n0 O/ d( Q0 @    BUG_ON(sd->s_sibling);6 K$ K% z$ q& l/ E% E: Q

8 Y0 W$ D- f: I6 ~5 f    /* Store directory entries in order by ino.  This allows
# ]  ?/ K3 f' P" t     * readdir to properly restart without having to add a
. p" g+ _! B$ Y8 v     * cursor into the s_dir.children list.- j0 v+ [# p5 A$ u& p
     */
! g6 W( @% ~6 ?- N* y! L     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*// t/ U; B* [1 c2 O( r6 O
    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
8 u$ h; f  m: u6 @; ]# F( `        if (sd->s_ino < (*pos)->s_ino)
( m3 [, ~( E) Y, V8 O3 K            break;, f) Z; f4 F/ \# m/ U9 ~
    }8 D, }, Y" J7 e9 y
    /*插入链表*/
7 ~% w# A5 W+ x. F$ a, ^    sd->s_sibling = *pos;+ s6 o" D  K% R1 A- U7 n
    *pos = sd;
2 N. l+ K1 t5 [7 s}
$ F6 R2 p. x, T) p该函数直接调用了__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链表中。
) E$ e2 R1 ]( j. l$ q8.3.5 sysfs_addrm_finish( w* t& L5 q, S& x4 J0 E2 p
下列代码位于fs/sysfs/dir.c。
: q, N4 B, {( }( R) ?
  s. s2 Z& |7 E) J/ y2 l# Q" q/**' g, _6 G3 ?7 s6 a. f
*        sysfs_addrm_finish - finish up sysfs_dirent add/remove5 _0 j; e: D6 N" ]' T5 x
*        @acxt: addrm context to finish up& D6 t2 o% `* W
*
- R9 h6 s3 S% V% ?/ s *        Finish up sysfs_dirent add/remove.  Resources acquired by
; x6 W  {6 D# X6 t. B$ w *        sysfs_addrm_start() are released and removed sysfs_dirents are
0 v$ j) z' }9 |: l# N) _- q9 C *        cleaned up.  Timestamps on the parent inode are updated.
0 \  z) e" f0 D7 h+ b: X9 e* Z7 x" T* |* D *
/ }" h8 u$ _0 }: B *        LOCKING:/ {- j8 C6 d; n* ~( t0 r
*        All mutexes acquired by sysfs_addrm_start() are released.
, G$ @% X- m6 ?8 w0 Y" H3 I8 g */7 h: X8 F4 v. w: m
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt), B- N4 y0 F' L9 C2 r
{
; }) K" ^2 @  d; G3 V$ h0 i7 ?, Q        /* release resources acquired by sysfs_addrm_start() */
# X/ k# `' e- }6 q7 W5 D8 N        mutex_unlock(&sysfs_mutex);
/ W% r5 g/ j7 p1 r4 e+ L: z        if (acxt->parent_inode) {
$ R. m. A- j/ o9 R2 M4 h                struct inode *inode = acxt->parent_inode;
0 m9 @, k# `" k( I' o4 M$ d* w" P( g) [8 Q4 [2 i5 c
                /* if added/removed, update timestamps on the parent */7 B6 ^* o5 O: A) h' ?! h1 F3 e: Y
                if (acxt->cnt), t0 C7 ]' ]. y) L# e
                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*// R: D3 u0 V: |/ k+ E' Z4 N* t- n
% N8 M# s( S: J; N& i
                mutex_unlock(&inode->i_mutex);
5 ]. H( f: L: K5 z' R7 @                iput(inode);* h! {' o' ^) P9 }: G
        }: O- {5 _- q- q, x
9 }  v% ^, x8 L* z7 D. F
        /* kill removed sysfs_dirents */
" j! c- ?7 v2 Z$ i( p        while (acxt->removed) {. z+ g4 D; m- f; a& x% I
                struct sysfs_dirent *sd = acxt->removed;
2 j" u' ^( ?8 G% o7 K8 Y" I' o
0 r9 E" j$ }& o2 [) U                acxt->removed = sd->s_sibling;
3 \# m& H/ t5 t                sd->s_sibling = NULL;+ q2 q2 M& z8 X8 H
% y# z% }' ]  w' Y/ y
                sysfs_drop_dentry(sd);
* c/ P# b: {3 D                sysfs_deactivate(sd);1 s( F7 D' S" L4 i. Q
                unmap_bin_file(sd);) b$ y% ^5 j+ f4 d6 T
                sysfs_put(sd);
0 o% o9 o1 G$ C  r. U        }! z3 h& u% U% x  B" d, v
}" M" ^" M8 S3 S' C7 l
; [; c8 u5 H% d
该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。
) p9 M5 K1 ?: I' ~' ]6 f7 ]
, `8 ^% ~# E3 a" J  B" |至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。
7 _: g* B2 K! X2 z) Q3 Z7 V0 \. Y. S( {8 B( \
下面我们看下如何添加属性文件。9 ^+ p* v$ j7 x0 h
8.4 创建属性文件
; x7 ^6 a& Y8 O0 a' \/ X' d添加属性文件使用sysfs_create_file函数。  r/ C3 e- m  A

6 S" a" z5 n/ T: p7 X下列函数位于fs/sysfs/file.c。
7 a5 I! ~8 j& |9 z4 T: M5 F; T/**6 T# x, H! d) a& W
*        sysfs_create_file - create an attribute file for an object.
) A, b/ f6 ~: ]# a9 ~! A( i+ O *        @kobj:        object we're creating for.
/ x( [, p8 q3 {- t *        @attr:        attribute descriptor.
. V2 u& c) x& V6 G. x, }& \ */. ~7 Q$ o5 Q0 p3 @

; M. ]( i5 T- V) U1 d7 A$ Eint sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
6 V/ f- `8 `2 E3 I! D9 y5 D# r{
2 Y1 m- l1 S5 u" m$ Q        BUG_ON(!kobj || !kobj->sd || !attr);% D. B  r9 U- e/ c1 I/ l% x

& ^' J' P$ b2 S        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);9 y  u+ V8 S. K. p# M" D

! _3 _) t8 O6 X2 h! Z/ D$ l& c}
& o3 S- y6 Z: A/ |* f
) d/ R* j8 f+ L' ~6 aint sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,  _* X% P3 g- x: f- B
           int type): S+ ]6 k) V9 G4 X; H9 s8 @
{: C0 j, U: d- Y# b- d1 X2 l* e/ R
    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);( Z, C# T( W/ v' W; N- Y
}
( p7 {& s( l: A/ ^4 z' {6 a
1 w7 y# y7 N9 f0 w- ?. M, W8 n8 Jint sysfs_add_file_mode(struct sysfs_dirent *dir_sd,4 x9 e* g" V+ o8 e1 g
            const struct attribute *attr, int type, mode_t amode)
% p* F" F! a8 Q" n0 V. E{" D9 ], R4 h" b# _8 J) \, y
    umode_t mode = (amode & S_IALLUGO) | S_IFREG;8 ~+ e. o- G& x% u% L2 d$ Z8 D4 s
    struct sysfs_addrm_cxt acxt;0 f5 k: a0 R1 ?$ U
    struct sysfs_dirent *sd;2 C' c$ i; q9 R% f
    int rc;
( h/ d4 L( N3 e    /*分配sysfs_dirent并初始化*/
  I0 g( \3 v( i, A$ q# r, u& G    sd = sysfs_new_dirent(attr->name, mode, type);
$ J( p1 h  Z; f% A    if (!sd): a6 o  Y  W* d3 g7 C
        return -ENOMEM;
: q5 w% J3 b6 [% u, J0 B; U4 t    sd->s_attr.attr = (void *)attr;
2 z9 _" r. P( N, P. V4 V* `! U/ Z0 O! E9 O& n2 h" S
    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/2 W+ Q2 i) y" U) C) b
    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/  @7 ~9 |" u, d* h
    sysfs_addrm_finish(&acxt);            /*收尾工作*/. O; {# g' x" v8 Q( u9 E
+ P* j' u9 A# O' `, z& }
    if (rc)            /*0表示创建成功*/
+ l& d9 P' v! T! t        sysfs_put(sd);
$ a; I4 s- Y7 O7 y2 m! c7 A; V  a' x& z6 z0 w) n4 e
    return rc;
( Z( ^  w0 l/ `7 Z" h+ h: o}2 @) D9 [, t' G1 G+ a$ i4 r) Q+ V
' `- x6 W, U* N& M
sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。
0 F' V3 E+ v& P- [7 gsysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。2 p- C* \9 f7 v! g3 U

: j$ K4 e, N/ R需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。0 z. X7 N- f% x
8.5 创建symlink
* a: ^8 i$ ^8 [5 v最后,来看下symlink的建立。1 x! ~* _( @$ ]  [4 U  l6 o4 W
/**
% Z  s* E7 D  b; _) n# G *        sysfs_create_link - create symlink between two objects.
5 L6 ?, @' n4 a1 ` *        @kobj:        object whose directory we're creating the link in.5 }6 b0 e# G. T, ?6 s
*        @target:        object we're pointing to.. A9 T! P: H( ^$ W( M
*        @name:                name of the symlink.
9 j6 a: X; F- {( h  s */
$ h# [/ ]" d0 _7 Kint sysfs_create_link(struct kobject *kobj, struct kobject *target,' z# h% M$ p0 q& t- A$ o8 n0 ~
                      const char *name)
! g3 j5 y7 r0 Z5 J6 z1 P{4 B& c4 V5 L: I' s% `' j  b
        return sysfs_do_create_link(kobj, target, name, 1);
2 _. _5 r3 M- d& K}2 x; H2 Q1 s' ]; _, j, T7 g/ h" g+ D0 G
, U8 `# s- C* h5 `6 L
static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
9 e; a+ C7 l; W' g, `                const char *name, int warn)
' j6 q9 z0 r' B2 m% \! S4 z( t7 O{
( m. Z" ]  Q+ {4 [: z    struct sysfs_dirent *parent_sd = NULL;) \- [/ n( H1 L/ W( o  a  h
    struct sysfs_dirent *target_sd = NULL;
$ N9 d/ ~6 o9 u; |* C+ g    struct sysfs_dirent *sd = NULL;
+ O. k6 w# c' S- ^, U$ `7 F! d    struct sysfs_addrm_cxt acxt;2 T2 H' A) a3 q9 @7 H! R
    int error;
/ B/ k- i5 ~9 _- z: D
0 S9 S$ N* S7 n/ r    BUG_ON(!name);
! k* k1 X4 s9 c9 P9 x& f1 u
# e3 M( U3 f! B% E7 Z& X4 h1 U    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/
* ]1 N3 \" L+ c* A2 i1 d        parent_sd = &sysfs_root;8 h, p. a2 t" @; l# C4 c
    else        /*有父sysfs_dirent*/
, f( i3 i! q' R3 I7 q2 M4 B5 t        parent_sd = kobj->sd;* Y! f9 i; u. N. z  t  g' f7 j2 f& o
4 y, c4 W6 K  {' t
    error = -EFAULT;
2 q" ]7 M1 |5 [/ I# y& N    if (!parent_sd)* [" Y. c1 F3 a3 x( J+ @% u2 n; h
        goto out_put;
" w# m0 C8 p9 a* G( H) C; c, J# o8 A7 C* }" D
    /* target->sd can go away beneath us but is protected with
# |, k) z& l4 n' L0 C4 Q; P     * sysfs_assoc_lock.  Fetch target_sd from it.' V1 v  n9 b* a8 l+ W
     */! }# v# }! v8 D( u+ m
    spin_lock(&sysfs_assoc_lock);
# G$ Y' a6 q8 u# k    if (target->sd)4 Z' r- X; J/ a8 w0 H
        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
2 J8 W* r  B# ]. a, f# F* l    spin_unlock(&sysfs_assoc_lock);
% J/ T, ?. S& ?' ?' N# W. Z) O
; h7 |( j# B3 ?/ ?    error = -ENOENT;
+ @) ?- n2 a6 ~8 e, |2 r    if (!target_sd)$ J) V5 y, R9 J: ^& t
        goto out_put;
9 C' Z0 s) g& m; S, @. G1 l9 G9 Z1 A. ^; n* I5 `) m* c, ?
    error = -ENOMEM;
+ C( k8 D* M* ^) ^: K6 q3 K    /*分配sysfs_dirent并初始化*/& i( {4 M/ P) c# W. [9 x
    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);( v+ X; ~2 m2 F; C+ U
    if (!sd)
9 b# i3 O* X9 R! c$ b$ g        goto out_put;- k1 F) ~3 p# u  @7 j, U4 q9 y  w

; ^4 B+ Z( `1 B' V* t, @( z" v    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/: p' `5 G: k5 Z& O* H0 G
    target_sd = NULL;    /* reference is now owned by the symlink */
; f! K4 P9 i6 c& u& e2 u6 c" h5 X" L6 c/ y2 S# ]2 k. W# l
    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
" T! u  X. T! P  l: E5 Y    if (warn)7 F1 _0 p8 H3 |# i5 z
        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
3 F  I. J/ m1 h/ I) t8 ~    else/ U2 ~; T' A# h( _) _7 e/ Y0 G' {. m
        error = __sysfs_add_one(&acxt, sd);
1 R. q1 ^' |/ g& I    sysfs_addrm_finish(&acxt);            /*收尾工作*/% }) h1 {0 _+ R$ A8 M; g1 Z+ q$ `8 S
0 H' w; Y/ U6 ?- B2 F0 b, D, ?+ e
    if (error)+ Q3 r4 e3 u8 M
        goto out_put;: d! i: O' B4 ?+ o' l
: h2 I, u3 H, x6 V: ?. ~' e. ]. _! W
    return 0;) _# H3 ~0 m7 T4 i7 R+ @
) x4 |7 @* f& o  b  t( j
out_put:1 l* L. c  a/ \: {7 P
    sysfs_put(target_sd);
$ @2 N2 ]" V4 k* M% X    sysfs_put(sd);
/ V2 f0 {( Y* S2 @- w8 t- ^1 X    return error;$ q4 e3 `% G6 R2 f0 T% `
}
; C$ b* k$ P' B' B7 G4 O* j; n
这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。
! _- ~: R4 G- N" }; }2 N因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。
6 W7 F) v" z& h! p/ k; t; u
1 V8 |, k- S) }: V. \2 J6 G: y* ~8.6 小结9 L+ Q+ E# H% m5 k" s
本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录' C( o: z% Z5 |: b) t; P: k' x, r

7 f9 E3 P* G, F- V. ^: ^2 S有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。
4 {0 I6 T5 Q% Q) U" M4 v9 L( C9 P% D  s- L
9 总结
5 g: F. }; \' p本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。! t% F$ B- Q, f; u
# m: d- D+ `- g* ^( X: |# L1 s
接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。4 `- n" @" N7 O( u$ \" k9 t( K
9 r, i5 ~) Z; q6 s' H- I6 Z( z
随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。9 d( W8 O8 _  s0 Y

. n9 e0 z5 u. H. F) V  T然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。
  c9 T' H% l* M* h+ o" Y# U/ E( n, n0 q& p# n
之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。
7 p) w7 b- s& Q2 E5 [% [# o- ]! `
9 V, s; o9 v$ q  z最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。# r& W* \0 v/ n0 l% ]
3 J; ^. c) \6 T. i
# L- ~; D4 S' m

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-27 00:28 , Processed in 0.390625 second(s), 26 queries , Gzip On.

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

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

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