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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。, Y( K; C1 q( D

1 c8 c& g$ S: z内核版本:2.6.30" ^4 A/ `" O) n3 C
" P% x6 O! P$ Y/ R2 z9 D0 J( M
1. What is sysfs?
9 \3 B3 P/ [1 l( p1 [  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。
& \$ x  r( R7 e- j- ^7 h; o. l4 H& u7 s( {3 ]8 z' z
  我们来看看sysfs的文件结构:
2 L6 @8 s4 O. c8 }7 ~$ J
& J! M. T) w0 ?" n[root@yj423 /sys]#ls# b$ d4 z. p' v& \! V3 O# Q; w; y
block     class     devices   fs        module
! |; b3 a7 c+ ~- R  G, H- n1 rbus       dev       firmware  kernel    power
1 |; c9 \6 J/ f4 ]% h# q( N: Z. V" l
block:块设备
& w% K5 k' o1 B* i8 g! r. W- }. U' G; C7 P" z7 C$ Z& ~
bus:系统中的总线! f) V& r3 m4 R+ f

: @2 _- Y' l* @3 f6 Vclass: 设备类型,比如输入设备1 s+ H- i  |. n! d$ l

( U1 R. Z2 E7 g0 Y  Idev:系统中已注册的设备节点的视图,有两个子目录char和block。
: ~9 F. L1 _' P* c6 i1 A4 i" h; x+ m7 ]& w
devices:系统中所有设备拓扑结构视图
+ W' g; a8 J$ g4 Y& k2 ?
; a6 z0 o3 ]7 E8 O% W  }fireware:固件2 Z5 O  x6 ]' w5 e7 M; l1 V: N
% i+ t% K( a, W; i# ]( r3 d
fs:文件系统
$ a: r$ s, W3 f" e- r
4 O0 A0 e& r! v1 v" _kernel:内核配置选项和状态信息
, d) m3 S4 Y0 b$ ]8 S) U3 p3 H* s
( W4 |& Q: z( ]- O; |$ imodule:模块; u% S) P5 f3 i$ |" B  B2 F* `  }

( _4 H- x7 D; t1 Y! `1 W6 C0 }power:系统的电源管理数据
3 h6 p: A" G2 z, H; S* n" h" z  W, {( U/ ^+ x& F; n
2. kobject ,kset和ktype- _/ @. K" {7 H5 t! D  U
  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。& |, i+ O9 V; d1 i: a& A& Q( C

7 g5 j+ H9 t' {! {" o7 Y$ u2.1 kobject* j# s% S1 Z, X  \3 \; W9 p9 i
  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。2 R' K  h% Y4 }
4 q( r0 Q+ A+ h" m: g2 E$ k9 s7 y
  kobject用struct kobject来描述。+ e2 ]  S* Z' z' B; z+ t; `1 ?

# S4 U, h- L1 x. P) y; T- s6 |struct kobject {
& u: l, [0 R% A. K- A" s$ m5 L    const char        *name;            /*在sysfs建立目录的名字*/
; W! ?* b  D/ D/ m, X    struct list_head    entry;        /*用于连接到所属kset的链表中*/' C/ w7 ~$ l0 Q+ R. L% @- M$ v7 q* T% z
    struct kobject        *parent;    /*父对象*/
5 I3 `# [/ u0 j5 [, q    struct kset        *kset;            /*属于哪个kset*/' k+ ~- S4 k! i9 j
    struct kobj_type    *ktype;        /*类型*/
( |( T) \9 _' d8 C    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/
# b+ V! p, b8 t& x! w8 J" n    struct kref        kref;            /*对象的应用计数*/
* \) t+ b1 x# ]4 w% ]6 ^7 y    unsigned int state_initialized:1;
6 h, h. Y3 w0 \  I' t    unsigned int state_in_sysfs:1;( k# Q" Z0 t2 b
    unsigned int state_add_uevent_sent:1;, R5 I# F/ t- M  [! N$ X
    unsigned int state_remove_uevent_sent:1;
- ]  N' A) W; t    unsigned int uevent_suppress:1;# I) @3 |5 x* a# D
};
1 d; c. g, L: h' ^0 s6 l$ R$ h- [2.2 kset
( e/ ~. A6 D2 R0 D  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。) W* l8 T$ @: O% y& g( n) y

6 {0 \( g3 |- w  kset使用struct kset来描述。4 K% O( _0 l8 d0 J

+ M9 o5 k( C+ U( m/**
0 v# x$ X6 o# U' _; }2 d; A * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
, y* G4 m6 s7 i1 U- ^. [  k: D *1 g* s4 `- p( C3 ]5 K, {2 d
* A kset defines a group of kobjects.  They can be individually
6 I  j% k  g9 n; E- Z, y+ D * different "types" but overall these kobjects all want to be grouped' J( S+ \& N3 v+ O- ]! X8 K0 o
* together and operated on in the same manner.  ksets are used to
3 Q  t5 Z5 ?0 G4 i * define the attribute callbacks and other common events that happen to  r. h5 d; Q3 H- @, m: f
* a kobject.2 Z# E# r0 m  y# u/ j0 T) G( ?
*
# U/ I8 ]/ |1 H * @list: the list of all kobjects for this kset
/ h1 F- |% R# A. b9 |8 C. }# ? * @list_lock: a lock for iterating over the kobjects
8 U$ G, n2 Z. l6 K; L * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
+ {$ z, x! i" z( c* r7 | * @uevent_ops: the set of uevent operations for this kset.  These are
- [, Y, r0 h  `; y * called whenever a kobject has something happen to it so that the kset
  ]7 D# h: i9 N- ~  ` * can add new environment variables, or filter out the uevents if so4 D+ h9 Y8 I( t% V
* desired.
7 @( f$ M, L2 S9 ` */$ S# x+ R! F; K: y
struct kset {9 l7 Q0 q2 h) ^% A3 p/ R. u8 e, Q- R4 k
        struct list_head list;                /*属于该kset的kobject链表*/
. |3 s' P' K$ n: M        spinlock_t list_lock;        * L4 x. }- P% P1 s, \" V8 f5 j& Y! o# {. ?
        struct kobject kobj;        /*该kset内嵌的kobj*/+ [% r6 e# B3 `+ S
( _- K! N. ?' p/ R- C- I; h
        struct kset_uevent_ops *uevent_ops;
" M& q; [- a2 @8 d( S% F};. x9 s" i7 l$ Y/ g: v6 z

5 Z" {: x5 y& f4 E7 D* H2.3 ktype8 b; |9 d4 ^& k! ^1 V2 ~+ Y- T
每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。
6 M: o* b' y+ O9 L1 d( ?5 I7 }3 K1 l. Z
struct kobj_type {7 I9 @' r6 x2 c# R- g2 I& e3 w
    void (*release)(struct kobject *kobj);2 V5 V2 M9 u* X% d+ Y
    struct sysfs_ops *sysfs_ops;- E' |, i# a7 c. V
    struct attribute **default_attrs;. L3 a/ `' |* Q" J- R( O/ h
};
2 z" J3 c! X& j* G5 [
" I, Z: U, _% Estruct sysfs_ops {# [) W6 L1 T- C$ t9 {
    ssize_t    (*show)(struct kobject *, struct attribute *,char *);
# M, n8 Y% n! R$ [    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);7 g' A4 k9 K8 B2 \
};2 t/ l( z1 ], c" E

- _0 t) n: y2 \$ `' ]2 Z/* FIXME
3 u6 U( Z# U4 e; M9 Z * The *owner field is no longer used.
0 s6 K! n2 h6 K2 b& Y3 c' v * x86 tree has been cleaned up. The owner
' j" [& o# ^/ m+ ~8 r * attribute is still left for other arches.
6 H& Q& J# {) c" M# n" ^ */
& c# W& a- t# u( G) y. _& |struct attribute {
6 z0 S* G, O' ^! P    const char        *name;$ _, x, j$ p# R4 d. I
    struct module        *owner;
/ C, b; [8 _1 R4 Q' g- r7 C/ Z( l: \& M    mode_t            mode;
- A; [# D9 r$ K! l6 A! P; b};' h' M/ C* H' i" s

8 U6 V" p9 s  x: t/ C" X/ f# C2 Q" \; e3 M! \4 ~
当kobject的引用计数为0时,通过release方法来释放相关的资源。- @7 M3 I+ Z' O* i9 ]1 u
attribute为属性,每个属性在sysfs中都有对应的属性文件。. ?' E8 Q) |* Q# C! e6 L4 G
; z4 Y  S) k5 `
sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。
5 T6 I2 U' \7 v) F7 O. t$ J, S0 v/ B+ L2 T
2.4 kobject与kset的关系: ]3 k% B8 j9 V: w8 z
  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。- @3 H# R& T0 d& h
' X0 U/ K  \, s; z( f4 G# P. q
   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。
6 s5 X! {# ^, E; r" h% F9 Z; K: d1 e' Y; u

4 l: |3 L$ ^8 Y5 \( k- ]5 W$ X7 T& k6 v
3.举例
( U9 T. H9 f* u在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。) K7 z# T( v6 b# U  o' W  F9 q2 M
, h' I5 U1 a& M7 O/ ~7 b" \
下面代码位于drivers/base/bus.c# m7 U" ]4 A- j; o5 t* g" C+ N
int __init buses_init(void)
- x$ o6 q6 u) `. V3 V{5 Q7 J" I1 J' i" U, n, V- A
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
0 Q9 c5 S/ i$ k0 X        if (!bus_kset)
- P# T3 g8 |8 J( S  @( E                return -ENOMEM;( R2 T% S: A9 X' _  Y
        return 0;: e* P& Q0 c3 i4 M
}) [7 L7 t/ Y3 \. B% z  n8 J# ~
' P3 c, P4 L+ ?+ a# Q
static struct kset_uevent_ops bus_uevent_ops = {7 W/ D- N, b) n+ H+ s6 _& d* F
    .filter = bus_uevent_filter,
% i/ P: N1 X6 V/ [};7 D* A7 t0 J1 [

  u/ u6 K1 ?! h% B6 o) p. qstatic int bus_uevent_filter(struct kset *kset, struct kobject *kobj)( [( e0 {1 M) R1 `
{
/ S) w+ h7 ^% ~0 f! J' g: _) U( U    struct kobj_type *ktype = get_ktype(kobj);
9 y& b' g. s% J% u) S, c8 w  v4 e% Z( G2 U" P# V! c! A$ {
    if (ktype == &bus_ktype); A! a( h. W* P2 f+ @5 k8 _
        return 1;
) x7 n- {! \  f6 j# I4 ^- l    return 0;% J0 S; q7 N, N5 V( l- @4 _( z
}$ f) h+ n9 m( |/ s9 C9 p/ ~" x
这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。, w5 N9 h' Z% k8 V% ]) L
下面代码位于drivers/base/kobject.c. e3 q! h0 X  Q7 t8 I% p9 N/ D
/**6 v; }& |. h9 j
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
3 w* `( j  ?" j' E *
3 |) h  e/ ~2 w) N * @name: the name for the kset
! J6 }2 z* z) J8 t6 I+ Q * @uevent_ops: a struct kset_uevent_ops for the kset
: O) e1 V3 i) y$ j/ t- z3 Z * @parent_kobj: the parent kobject of this kset, if any.; Q& U' ]2 h* s7 X; }
*
% S7 C. e9 X! X- c; q* a * This function creates a kset structure dynamically and registers it
; k) T6 r2 j1 |- h* k6 E  h9 @ * with sysfs.  When you are finished with this structure, call! M) K5 s0 h% u! C  H
* kset_unregister() and the structure will be dynamically freed when it# |! k8 J8 k  n7 p% B0 y$ E# }
* is no longer being used.2 q* a, L: S+ H9 C" X
*4 h; J5 [, s' R! U. O
* If the kset was not able to be created, NULL will be returned.
- l$ ^/ o$ k4 A! P' O$ R */
/ x  R5 c/ T* _struct kset *kset_create_and_add(const char *name,
2 [3 H8 I; R8 `# @* g+ T                                 struct kset_uevent_ops *uevent_ops,
& w' w: |9 ~  ]- _3 F                                 struct kobject *parent_kobj)# |, ~: w& F9 x
{0 ]! f8 S. h' t
        struct kset *kset;
" x0 G- h" b+ i$ A4 ?: a        int error;- j2 N: g- X7 E& e  H6 _" ]
1 p" }8 Q* @1 K( G( v' U" m
        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/* w2 d; @- t# s5 I+ R: B% f
        if (!kset), Q$ n6 f- X0 `2 ^  [0 Y
                return NULL;# ?3 U, N# @2 \8 E% o4 y1 e1 |
        error = kset_register(kset);        /*添加kset到sysfs*/$ i% U) `9 ~& ]7 `/ \' \9 m% k
        if (error) {
6 [5 ?7 p/ k6 T, |1 S# n                kfree(kset);* t* W8 Y) n: V2 _1 F2 S6 o
                return NULL;
! a! {! Y( a6 v5 b- s% B        }
; p) i$ |; N  ?6 I+ z) h- U' |        return kset;, c! k. C% W9 W' [: f! r4 ~
}- @( ^( Z" V! Z2 \% Q/ r* t/ Q% z" K
这里主要调用了两个函数,接下分别来看下。/ C/ v3 x% t/ v; `

# i5 d8 D# d& H" T, I" B9 t3.1 kset_create函数* g( U4 x) p; q( B
下面代码位于drivers/base/kobject.c
6 J6 w, h& F6 j- r; L
) T3 l. R& V5 d$ Y6 s' w' L/**
6 o! b6 l: H; a* _6 C# D * kset_create - create a struct kset dynamically
+ S, Z# z6 {5 i7 u8 W* I *
  V( @1 g" a' }1 o * @name: the name for the kset
# T% U; p$ Z  X* P4 b5 b9 ?/ B * @uevent_ops: a struct kset_uevent_ops for the kset
5 a8 o0 I) L+ f( P * @parent_kobj: the parent kobject of this kset, if any.$ `4 f0 e, c  [3 L" `/ G
*; N( D1 Q+ e0 T9 ~( {4 }7 F
* This function creates a kset structure dynamically.  This structure can5 E8 S+ s, c  f# [7 c
* then be registered with the system and show up in sysfs with a call to
3 G$ n/ [* y- K2 P& w * kset_register().  When you are finished with this structure, if0 L% V8 @" A. W( V+ z5 N7 ]. z% |
* kset_register() has been called, call kset_unregister() and the1 L6 v& X! t# q3 [) z
* structure will be dynamically freed when it is no longer being used.8 r, V  G- D* }3 q5 P/ p% y
*" u( f8 @& |+ h) w5 H
* If the kset was not able to be created, NULL will be returned.% S& }- ~, [- T; ?& e7 J! N) Z6 ]
*/
0 @' `5 k- s4 ~( S2 H# Mstatic struct kset *kset_create(const char *name,
: w( n! \- y  y                                struct kset_uevent_ops *uevent_ops,, ?5 y1 c/ T6 e
                                struct kobject *parent_kobj)
2 g. |# W; i3 E8 B. c9 f$ V# B- r{2 g: {- B7 I6 W6 b, b0 }& Y" R$ r
        struct kset *kset;4 j/ e* E3 X6 @8 D; @

: z$ J3 `  B; E3 h% t, h7 J; j        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/2 o4 D6 g3 ?3 [+ }% @- X; e
        if (!kset)) t) ~0 d9 }+ h8 K
                return NULL;4 {5 D. F3 I  t, }
        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/
: E7 I" ~. Z, u' s0 @" i        kset->uevent_ops = uevent_ops;' V! \' _# X' e& z1 |
        kset->kobj.parent = parent_kobj;        /*设置父对象*/3 U. E. V7 p: ]0 O6 {2 T
4 K! R3 r. n* \8 v! C& Q
        /*. n- F! G& j: q* \, [8 m0 J
         * The kobject of this kset will have a type of kset_ktype and belong to
5 O2 ]9 t) F; \! `         * no kset itself.  That way we can properly free it when it is' L8 I8 Q* j: Z- h6 f$ ]
         * finished being used.
# F: c* I1 w: z" n         */
1 Y5 `; t: K+ y; I: v. b; ?* E) Q        kset->kobj.ktype = &kset_ktype;( A# C8 G' i/ B9 }
        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/
, J9 Q4 g, U9 T: C
  z9 i! ^& E+ h6 |  V$ A( H        return kset;: a7 e4 Y! S8 l" I
}
* a+ Y& S0 |+ ?' _& o6 |0 K" H) u4 o
这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,
0 a" E6 O9 R9 L& r) D% N. X
0 O3 z2 A! p4 L也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。7 h( F2 a- G1 @% X- m( K* Z1 y
& f2 \/ m( w& O, t
随后简要看下由kobject_set_name函数调用引发的一系列调用。
+ ^: p& T6 g8 A# x! y$ C# ?5 l2 J- ?$ x5 t
/**
/ \: Q: w, F; G: Y" \ * kobject_set_name - Set the name of a kobject2 K' s9 d6 P( d3 J+ G
* @kobj: struct kobject to set the name of
/ M; c9 `! Z$ x  t1 b * @fmt: format string used to build the name5 K3 a" g" x3 ^
*
* @3 v, x! S  s  Y5 r' E * This sets the name of the kobject.  If you have already added the! L2 X8 R" P6 ]. B# k$ w
* kobject to the system, you must call kobject_rename() in order to
7 G/ x  V2 \! Z * change the name of the kobject.
/ [# M6 i3 g& E1 V/ P */
$ g7 f+ M2 F" y. A9 u0 z% P- \int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
: `; j' @/ |) p7 ?{* J6 J: T6 l$ J
        va_list vargs;5 M9 W  U( ?- B" i9 Z
        int retval;
7 M! d7 \; H- z7 h% R% S- G3 h
( q4 n+ V$ l+ C# s        va_start(vargs, fmt);; y& a# m9 K  q8 X  g& s
        retval = kobject_set_name_vargs(kobj, fmt, vargs);  P/ e! W& q1 `2 p! [& ]
        va_end(vargs);" J  U! |# t- |* p9 `: S- ~
: F  Z/ L/ r$ f7 x
        return retval;- m0 Z' E( D4 k. n0 w4 x! D8 N
}1 ]7 ~% H: g- H- p* V+ J

$ z3 \4 j% r; N( M* u+ ]' D; L/**4 a8 v- e# A) f  I0 Y0 E
* kobject_set_name_vargs - Set the name of an kobject
: l( G& H4 X5 q& j* ] * @kobj: struct kobject to set the name of
0 n, v4 @# X& y% \5 e * @fmt: format string used to build the name
( S' Q/ z# ~" V2 M; G * @vargs: vargs to format the string.$ y: B1 C7 L4 c& k5 o5 a
*/, f' i3 T" ^+ V$ J# D% ]2 U
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,6 T+ I! ^; ^/ @  w5 v; p
                  va_list vargs)
. i, F% t' U# b. k7 ]{6 T4 T% ~1 n/ Q: h: D) w. y; q& @  l) I
    const char *old_name = kobj->name;0 d" b& d0 b" o
    char *s;
( m, }0 T3 y( }4 W! F, U
; k2 l2 [8 n0 v( k    if (kobj->name && !fmt)
' _& @: B, R1 ?3 P! F) t        return 0;
$ W) {7 [% w, v# V* o1 p, i, H8 P* z# ?6 @, l% e
    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
9 X" U0 q  j6 L' h  P  R& v    if (!kobj->name)+ w* C! @' x) y: [. S( B0 u! }! ]2 v
        return -ENOMEM;
# F7 ?8 W) Y! P# Q$ a" {, i! C. j6 Z. I; h7 o
    /* ewww... some of these buggers have '/' in the name ... */! v5 b+ c) B5 X# V6 q* d7 d7 X
    while ((s = strchr(kobj->name, '/'))); M! d. I$ I+ n- |
        s[0] = '!';
* `' O4 z. r- D8 P- t1 g; r. N' P
    kfree(old_name);
- [' k3 K4 N2 M( V: u    return 0;, o7 X. A# \  @# b7 q' z. S/ r
}
' `: W. R) A. r2 R7 U% u$ {8 c6 T: K* O; p% c/ u
/* Simplified asprintf. */
8 v1 j  d) Y4 p+ G; T' L- @7 Rchar *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)- r, T4 \7 y% W3 n* L
{
. n8 g9 ^; l; h$ v3 |    unsigned int len;1 R% y1 L6 g! F7 n
    char *p;
# e7 Q1 ?# r. O    va_list aq;$ ]) U: F* c5 W9 n, e
+ j! u: U# o2 h0 D* u# D9 w6 P
    va_copy(aq, ap);) r9 U: h: s, _3 [- Y$ K5 m0 [
    len = vsnprintf(NULL, 0, fmt, aq);
  P0 w8 b% D" u9 g% o9 E3 ]    va_end(aq);
7 o7 q. r+ l, J9 g8 l) y$ f# ^8 z) w) w# n
    p = kmalloc(len+1, gfp);) m: h1 N. ]" i
    if (!p)9 ]: M' z. I6 E. m1 f" `1 r# c
        return NULL;
6 D( T8 e( l% r3 E" f; w& U. D" @# e; T1 S8 c
    vsnprintf(p, len+1, fmt, ap);
0 c- y% ^; J5 _  R' d2 T9 w$ s5 M' Q) G4 y
    return p;
9 ?- L% I9 ~- }/ V}
( z3 w/ I. |6 f- n3.2 kset_register
1 k' p9 q% e1 N下面代码位于drivers/base/kobject.c。
" d# k, s. O& ~+ e5 F/**
/ t$ F$ G# W& U * kset_register - initialize and add a kset.
/ F' N2 \+ m8 w# B! J * @k: kset.
% @% R. q+ c! s! d7 F */
5 Z# m3 s$ g( P' L( B; j7 Wint kset_register(struct kset *k)
0 s) O% |9 O4 Y& s" u: u{2 q- C4 M& S0 {8 a: M0 e
        int err;
  G& e& C. m1 N6 t. r) Y' f
7 C; T2 Z. J  \3 k/ ?  `% O        if (!k)
4 A& a% A8 |: t                return -EINVAL;% a6 E8 J: Q, J0 {8 K/ {# C( ~

, [. m. s7 ?# c7 z( K# [% \0 l        kset_init(k);           /*初始化kset*/
$ x8 M% M) k* K8 N% L4 Z4 p        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/
# p8 v2 G2 M5 j5 _        if (err)/ ^) R4 z( }& r$ _
                return err;
& `3 f9 _' r/ D( L        kobject_uevent(&k->kobj, KOBJ_ADD);+ P) J8 r: V" ?6 Y- C/ |% P+ k
        return 0;
8 R: D5 B! d; Z, N. d}# K6 {2 n9 o9 ^( r; [+ w
这里面调用了3个函数。这里先介绍前两个函数。
* O) ?. ~$ ]) i
' e1 |+ ~: q8 W5 f, G$ v7 h3.2.1 kset_init) d# k# Y! j0 z9 z( ~6 Q* o/ C* I
  该函数用于初始化kset。
' ]4 ?3 f" m6 ?7 v
  ^) ^' }- `% v- n  下面代码位于drivers/base/kobject.c。
  {& R3 r4 V. I, ~% H6 m: d
- c5 a- T7 {& A8 j5 S. z/**% D5 g* H: U1 A0 \
* kset_init - initialize a kset for use
) N, p) U# t& V7 X * @k: kset
' D9 K4 A/ g( _+ B" h2 L% v */
. V1 d8 H- ]: |2 Z! X. L! j2 ^void kset_init(struct kset *k)
) k+ ]2 ^; X- x5 C4 f6 H. r  X3 r{2 H) u0 z0 ^1 E/ G) F8 X
        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
" }, }/ e# M: A        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/0 d3 C. Z8 T2 a& Q5 X/ {! f
        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/
3 T) ~& y% g& R. ^; w# H* ^}% \. T+ x4 F8 D8 m# B
0 \& _3 e, K6 ?2 j
static void kobject_init_internal(struct kobject *kobj)
  K% ?3 H& o0 v  U, Z{
, l- L( s  e" H% A    if (!kobj)
8 i1 F: P0 ~" K2 n$ u& {        return;) m; z8 q- g0 G
    kref_init(&kobj->kref);           /*初始化引用基计数*/% v5 r1 m1 m8 N$ m. O4 o; O) F& }
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
7 R7 ?6 L7 S5 q8 V0 ~& _    kobj->state_in_sysfs = 0;
9 r6 F, S' N) a# A* o    kobj->state_add_uevent_sent = 0;3 l7 e# g; o# v3 ]8 H* I0 e
    kobj->state_remove_uevent_sent = 0;
* r9 z% ?: P  w7 [& L    kobj->state_initialized = 1;
7 |0 |+ {5 F; m: _# W}
4 b, W9 \# n/ z7 G9 o3 P. R3.2.2 kobject_add_internal# Y/ `$ J: ^8 N$ H+ U# T2 B
  该函数将在sysfs中建立目录。, m4 I0 ^/ O8 V) ]( [& e/ b

3 i+ d/ f6 v; j- N" o9 }! q 下面代码位于drivers/base/kobject.c。
9 ?, ~; n* e  j+ Z  i- [; O" ^static int kobject_add_internal(struct kobject *kobj)& g6 T& f6 J8 y, a. P3 d
{
: o4 R1 G9 u9 C3 g8 A; `# G4 ]        int error = 0;
% O5 V6 U! V7 Q3 B. G        struct kobject *parent;
, y, \0 M5 l* b  O9 `
2 F/ j4 a" u  w6 G6 ~% `! L        if (!kobj)) d( y& s; I4 u9 L: D3 b9 W+ R$ g
                return -ENOENT;. U+ P2 ?% ~3 x; R& t
        /*检查name字段是否存在*/5 c# @+ `: q, I, ?! |% T
        if (!kobj->name || !kobj->name[0]) {! d& R4 x' `# l1 c: `3 y  M2 q) w
                WARN(1, "kobject: (%p): attempted to be registered with empty ") B: j$ A. ^! f
                         "name!\n", kobj);
6 u) Y. K& R8 t                return -EINVAL;1 e6 o. L- r* q  I1 I& _$ a9 A1 q
        }3 \% ^) l. I4 D5 A4 T/ s9 e5 p$ H

2 w2 O; v- L( f$ \        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/
7 O) A$ ?8 G. m7 c% @4 Z
, g8 E/ P" ^  j) ^1 f        /* join kset if set, use it as parent if we do not already have one */+ `5 n# g& C, P2 I2 Z
        if (kobj->kset) {       
- R9 E/ f# [/ r, j! m                if (!parent)
* Y3 X+ f+ l+ H3 P% r! l9 ]                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/- A9 U$ ~$ v2 [3 t
                        parent = kobject_get(&kobj->kset->kobj);3 i+ n9 T: O0 h
                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/
% a" g: ?7 j9 p- _4 B                kobj->parent = parent;, o1 @7 E! |7 S6 O
        }
) r, f3 x) Q* C5 ^/ f8 X' b! C: k; U4 O6 u, B- D' `* J: p3 g
        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",+ O* m$ T* Z1 A7 h
                 kobject_name(kobj), kobj, __func__,/ R3 l1 m6 H! q, F
                 parent ? kobject_name(parent) : "<NULL>",
+ c* O& ?$ C$ E4 e3 V( [/ l5 ]4 j% ]! a                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
% n& S- n3 q; I# O0 ~, ?, g/ n5 u! B, s5 W9 C2 v6 W
        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/- h  x4 Z; w+ _5 G- d  P5 \
        if (error) {0 C; s9 V$ F& |5 D1 J0 g; W
                kobj_kset_leave(kobj);        /*删除链表项*/6 J$ Z' `: }4 I/ l5 v
                kobject_put(parent);        /*减少引用计数*/
# [" m* s2 X2 y0 o                kobj->parent = NULL;
+ V- G# S  y2 D! X" i- w6 m1 A3 C! a& M8 ?% j( @' p" n
                /* be noisy on error issues */
+ f. `  R; j2 n" B  k) _                if (error == -EEXIST)
4 L' i- h4 Q2 p  N9 Y                        printk(KERN_ERR "%s failed for %s with "" F( a. d6 T; m/ e. n
                               "-EEXIST, don't try to register things with "
9 \$ \' }( L& T0 E. N! i                               "the same name in the same directory.\n",
! K+ T3 x3 y% e; a# J: q2 _                               __func__, kobject_name(kobj));
1 d0 `* m" }+ `0 f8 U                else8 a2 t# p+ Q) Z: j
                        printk(KERN_ERR "%s failed for %s (%d)\n",
2 [$ f$ D5 w" [" A                               __func__, kobject_name(kobj), error);5 P& N) Z+ x8 r- c
                dump_stack();
# Z5 b" Y; ^2 s+ Y$ i        } else
3 h9 h5 i5 }5 ~* }                kobj->state_in_sysfs = 1;/ h( f4 W2 ?8 G8 V& E3 W; q' x

" M# N! U5 l: ?$ E* j' w        return error;
! a: G9 W+ r+ [' R* ]) r: }}
' s( b8 a0 S& H0 _9 y
$ U# F$ W3 b* _* J在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。' Q* Q) @9 Y% V8 c& P2 a* b
( H$ h: ^$ T* U, O
在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。3 g" [4 D! w$ K' y
2 p& U0 r2 l7 M# |, K$ f8 R- e0 l: C+ K/ j
至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。
+ h0 q  ]( ?' I+ k3 D% |! ^" C1 V5 n1 s0 t, u$ s
4. driver model# w# f6 a7 {: D$ n
第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。
/ u8 b* A. Q9 p0 }4 d. y; P: v2 `# M2 ]" ?
Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。  w6 C) f/ b# s( I' L8 Q" p

; g, ]" {. v3 }( q, j9 D这个属于分离的思想,将设备和驱动分开管理。2 p: p: R5 c5 M) A, }% g
/ }$ n2 S, ~# K3 I
同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。6 A+ I: i7 ?9 |0 N6 W
; x0 P) F7 q; K9 X) _. D  W8 v  W
4.1 bus
; ]6 M5 b/ L- ^2 d0 K  x总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。4 @, D. ^3 @- X" V* T; j. X

- c# V  M0 y; H下列代码位于include/linux/device.h。8 n8 ~# U/ F5 z1 E3 t4 h  X. |2 G/ C
0 \/ c8 N5 B6 J' C3 W

) d( x5 n0 h6 l! a2 q" n- u- Jstruct bus_type {8 }- c% I, Z* y9 A- j) {& _1 Y
    const char        *name;
- R& \9 _/ V5 g5 \: P/ E    struct bus_attribute    *bus_attrs;' {' h& i3 a3 X! w6 v* m/ D  m
    struct device_attribute    *dev_attrs;$ ^: D1 G* l0 u9 l
    struct driver_attribute    *drv_attrs;( D2 T# c; }* \' q$ ?
" P6 D* L& g5 H! C5 }
    int (*match)(struct device *dev, struct device_driver *drv);2 B% A+ M- @/ X$ V* G6 ]' f) j
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);1 H+ Q8 C3 z7 {, t2 B- ]* N
    int (*probe)(struct device *dev);% f& ~5 ~$ [3 O8 }/ i( V
    int (*remove)(struct device *dev);: t6 [* _7 h+ U( k& v% k4 C) O3 H
    void (*shutdown)(struct device *dev);+ u# J2 t  c/ P( \3 A5 R& e# T
7 `  @5 Q( v7 L
    int (*suspend)(struct device *dev, pm_message_t state);
2 C5 Q) I" M! b- M5 l- M    int (*suspend_late)(struct device *dev, pm_message_t state);
+ Z( l  i8 q. `" h$ s, w    int (*resume_early)(struct device *dev);9 P. I, u" G: r2 V4 R9 G" P
    int (*resume)(struct device *dev);
3 P- p- g( ~' G5 N
" _* C1 c, |3 C5 A    struct dev_pm_ops *pm;
# i  t2 `; ~( ?3 M! Y! `4 c
1 M0 {; o$ X' d+ C& `) s( A6 N    struct bus_type_private *p;5 V! T% b. c  i3 K6 a+ B2 C# W  f
};
; w! [) d* V2 n/ R5 P# j- Q2 |$ D$ r. ^; R
/**4 S( V- w- M/ J0 c% G: k7 x! g
* struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
& s( g2 l8 b* r; y5 j' q% w3 `  k& z *8 y2 ]- t7 N! ]  C# j2 m
* @subsys - the struct kset that defines this bus.  This is the main kobject
( P$ N, c9 Z5 m  c( Z& `0 O * @drivers_kset - the list of drivers associated with this bus2 p$ ?' b8 P' h. v, D* r
* @devices_kset - the list of devices associated with this bus
4 x0 J# D  n0 Z * @klist_devices - the klist to iterate over the @devices_kset
: F8 S8 H! q5 \% y8 [ * @klist_drivers - the klist to iterate over the @drivers_kset
2 i* l: L, B; H$ Y) s: y# Q1 U * @bus_notifier - the bus notifier list for anything that cares about things' x! l3 w( o$ p0 y- W/ r+ F
* on this bus.) L- W0 ~1 u5 d% y. |
* @bus - pointer back to the struct bus_type that this structure is associated
: q: C2 s  [7 T * with.2 f1 I/ `( s; Q$ [: r: N
*. X( b# P4 l! U) c
* This structure is the one that is the actual kobject allowing struct/ i7 R2 u) R9 y( Q2 I  |" d1 I
* bus_type to be statically allocated safely.  Nothing outside of the driver
3 u! ~, v$ h8 ~1 S0 U1 d * core should ever touch these fields.
  o6 s. l& U! @5 `# J, Q. u */4 q: [2 p$ D) `( m6 o0 b, i& ^' B
struct bus_type_private {
5 y) Y: Q7 t* t6 C% z$ m    struct kset subsys;
  X- t6 z6 c) @4 l2 e9 o    struct kset *drivers_kset;
; P* m! q9 Y+ r* c- O1 ?5 l8 M    struct kset *devices_kset;
' _' h1 k) s9 h    struct klist klist_devices;
, [  u1 O/ d# f# i: W    struct klist klist_drivers;* L5 s  O( y& d, V
    struct blocking_notifier_head bus_notifier;
/ Z7 D% P- A) n+ C; o" ~/ l    unsigned int drivers_autoprobe:1;" s. E3 \) x) c
    struct bus_type *bus;  d: j. V4 K& U9 D. U
};3 _; b0 e  ]  }3 z( V& [
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。
4 [# [0 \$ K' N* d! S7 Ydrivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。
8 y% M/ K1 e7 [1 |
& L% M  n/ B+ c/ t! X9 ?同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。4 o. n/ Z9 b  n! J
+ d) t0 j0 m' I( ]
4.2 device* _) T8 L+ p- ]& r% @) @
设备对象在driver-model中使用struct device来表示。
- i) A+ y: S0 U( [$ M9 Z; y* J% c! G8 o; O# f: {  H- @
下列代码位于include/linux/device.h。
! |. Z7 [( r/ q5 k8 kstruct device {
0 R' f5 @) @- |# ]( d        struct device                *parent;+ e+ `* J+ x  i+ N6 G
$ g5 V( {7 y0 \. r3 Z( |" t& x' s
        struct device_private        *p;
6 Z* b* E, {7 c2 N* E% B
; X% e- M$ @5 H, @2 a; o        struct kobject kobj;
, _8 {, D7 U) S" U. P/ p: A        const char                *init_name; /* initial name of the device */
5 g# q9 r& z' G7 w! B        struct device_type        *type;
1 l9 S5 q* {- f4 M6 m' `8 q5 J- P, l* ~3 o! P2 O. J
        struct semaphore        sem;        /* semaphore to synchronize calls to) C, g8 K* J4 e# d5 Z
                                         * its driver.) t7 ]: `, \" ?; x+ L3 h
                                         */
( I' U* \' X3 ~; X' g; ~' p) C2 Q
2 B/ I9 h, w$ S* d9 U7 ]6 s        struct bus_type        *bus;                /* type of bus device is on */: `- O, V% F. ]- _/ x
        struct device_driver *driver;        /* which driver has allocated this
" F: {% r6 E0 ?9 W  x                                           device */& B2 S5 y3 r! V1 P8 Q  @. f8 B1 c) B
        void                *driver_data;        /* data private to the driver */
+ t' r; r  D4 m9 `        void                *platform_data;        /* Platform specific data, device
& n# R$ Z6 _) _$ q                                           core doesn't touch it */5 o) Z/ e5 T4 N( _6 ?0 b/ d7 I* f4 f9 o
        struct dev_pm_info        power;
0 Q& Q! c9 {+ m( l1 Q. A; Z. g0 |' W5 x( ~+ g# z  P8 y7 \
#ifdef CONFIG_NUMA
8 h  s) X% ^: w; p3 |6 `" C        int                numa_node;        /* NUMA node this device is close to */
0 T: f4 n6 x$ Z: e) S  ]% _#endif. I/ q9 M3 N4 p. F
        u64                *dma_mask;        /* dma mask (if dma'able device) */# m, J, A4 B, H6 Y+ o% X; K9 e' o8 d
        u64                coherent_dma_mask;/* Like dma_mask, but for
  |- O8 i7 F* K                                             alloc_coherent mappings as
4 W  A" p/ J1 u9 h2 p5 @  O/ f( D                                             not all hardware supports
# N% Z  w! B7 x4 d; i+ K                                             64 bit addresses for consistent
8 u; x% i3 y3 Y                                             allocations such descriptors. */
/ m4 Z% c- E. j' v9 _- x4 t0 @6 w; \( _4 v
        struct device_dma_parameters *dma_pARMs;( [$ @/ I9 T7 ~4 r+ R7 m
+ v- v& S5 q8 @* D
        struct list_head        dma_pools;        /* dma pools (if dma'ble) */
; Z) f# `/ X* o5 T& B3 I4 W5 O. j6 H5 f- `2 v$ u' z3 h
        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem+ m9 e, I* J2 V" }3 A
                                             override */
. u. h& e" j6 J2 P, `! d1 H9 |# B        /* arch specific additions */
5 @1 F+ |( [7 E        struct dev_archdata        archdata;
: E+ B9 ]! N$ n' a/ O3 \( b9 ^& Q& o( z& b: F( U
        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */
$ F8 l* C- @- e6 P# p
% P: ~' X" c2 k  }0 G# F        spinlock_t                devres_lock;- }4 s9 p2 p4 g/ R  B+ R
        struct list_head        devres_head;. ]. `. C$ w) i

' A- C6 E  G: i* Y        struct klist_node        knode_class;
; C! S; F. }. r) _2 X0 n* `        struct class                *class;
) k/ Y2 A, I( z: ?2 r% z        struct attribute_group        **groups;        /* optional groups */
: B! }6 I" [  e4 v4 M' R- w6 R; u! a$ n! C
        void        (*release)(struct device *dev);
1 Q  c  x% p+ F& W};) O. a3 p5 u* ^( k
3 p) s' p& E' F( ^/ C! k
/**$ f2 [( E7 J; V( w6 j
* struct device_private - structure to hold the private to the driver core portions of the device structure.9 F$ H7 p5 u- u' i! g3 K
*
4 y4 Y# H2 v; E% u! _: A* j * @klist_children - klist containing all children of this device* |6 H' t/ m  I) ?
* @knode_parent - node in sibling list
" n# y' B1 I$ ` * @knode_driver - node in driver list: t2 Z' I! t0 l/ O; {
* @knode_bus - node in bus list
7 y. a7 l4 @, ^4 k! r: D' ^8 o4 E * @device - pointer back to the struct class that this structure is: Z' l' S- i6 M0 |) {( ?
* associated with.
4 m0 w  ^/ Y5 V: a *& T, e2 M' {+ `! o9 Y: v) |
* Nothing outside of the driver core should ever touch these fields.- ^/ _) f& h4 r2 q# w! @
*/% q2 Y* G8 F, N( j
struct device_private {
5 e9 E' J8 ?- o! c' d4 K# f) i( V    struct klist klist_children;
% a& V" w- Q; c  ~; `: h: K    struct klist_node knode_parent;7 Z9 {/ m/ t# o
    struct klist_node knode_driver;
" {! G8 ^$ N/ N8 X4 y2 H6 j; c    struct klist_node knode_bus;
- W* _7 O& l# j# W6 z$ r    struct device *device;. Q! M4 T5 R( K, h
};
7 F* m6 |9 @4 T$ n1 s# ~! E3 U/ O1 idevice本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。
0 e; f/ _2 n7 u4 j0 h: D9 H  h/ b( E& a8 u! l* w- Y# `# e
该device所挂载的bus由knode_bus指定。
) Y; F. @% B9 s$ h* G# _4 X
2 g! N0 S5 T" D# C0 S该device所对应的设备驱动由knode_driver指定。. _4 `8 M) d7 l" g" y

# D) V3 d! i' F, C! I2 i6 p4.3 driver# y! n6 j0 y/ l0 H
设备设备对象在driver-model中使用struct device_driver来表示。- K8 ~: t1 }% |4 e# v0 L

3 `7 @# m5 G- i, }6 {下列代码位于include/linux/device.h。
8 o& H9 K: k& v! r7 [" A& J4 Bstruct device_driver {
% h9 u1 H! X* G* S        const char                *name;
( n; w2 d; [  x! X6 P+ H% v2 x" u        struct bus_type                *bus;/ E1 P, @& i* F  b/ t1 U+ Z6 V

; g9 q9 x# _! S. v7 u" D/ b% s( @( O        struct module                *owner;. O0 r4 I; C& S  S$ f
        const char                 *mod_name;        /* used for built-in modules */7 o: S0 s$ t2 w4 o
* p! x) R' }: {( {) [" ~
        int (*probe) (struct device *dev);
/ {( _. V3 b& |* R8 s        int (*remove) (struct device *dev);
. I; x6 w' Z$ w& U5 \        void (*shutdown) (struct device *dev);5 @: S/ r( p" s8 x" e
        int (*suspend) (struct device *dev, pm_message_t state);
8 l( }8 `$ i9 ^' Q2 [        int (*resume) (struct device *dev);" i- B' u; d0 ?7 Q& T& `% H; p
        struct attribute_group **groups;
- w1 K7 j# C$ J0 c# R# H$ [2 z' S! ~
% W% \0 T) p9 n/ ^: r) c        struct dev_pm_ops *pm;
" J9 q5 i, Y- E! p3 a
/ y7 m" `7 W' N: A* O" a% }        struct driver_private *p;
. |( {- Z* g2 d; o" h" R};, q% \0 H4 z6 m4 R. r1 }+ l
1 Q- H2 b9 x" N
struct driver_private {+ u. d: R3 M2 D, p
    struct kobject kobj;, x4 ?8 U: F6 j
    struct klist klist_devices;# t9 {+ |/ _, I: r2 X
    struct klist_node knode_bus;
; s2 ^; ~9 p' U# U; I- A5 [    struct module_kobject *mkobj;4 q# O4 g$ p, }$ g1 @# }
    struct device_driver *driver;1 ~; Q1 z5 ?& D5 j7 D( N& M9 E
};
! S; `- e0 W1 d6 |1 pdevice_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。
$ |; j8 H1 L5 w* v该设备驱动所支持的设备由klist_devices指定。6 H8 K, S% z% O6 A5 F
9 T( }6 [7 u- q6 j! j/ w" U
该设备驱动所挂载的总线由knode_bus制定。% ~1 \: `1 p% a9 l/ b- {( D3 c5 p% f
) ?- H) O% ]5 q
5. Bus举例: I3 l+ s, h! D7 B6 S
本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。
; m" c: k$ A" B/ \8 E/ j$ p2 N$ E* |/ {
platform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:6 U0 s; u/ ^+ c3 t- M+ h
1 F# ^: h6 s( W& e5 S( [& n
start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。
. V2 j  E0 a% m) z& E/ `1 b& r3 C* i& L& G5 X8 O/ k$ l- ~
注:kernel_init()是在rest_init函数中创建内核线程来执行的。
0 G* f9 A+ z: x0 }# C& ]
* R" y, D! a) N
5 \5 v0 q' x5 I& n% p; J
, {+ i! W+ I9 M  F7 Aint __init platform_bus_init(void)8 @: ]7 n+ r) Q- K# ~2 ~7 b
{: z5 Z# ]. ^& L9 q
    int error;
8 b" d4 S) z9 A, d. t4 l5 o& x% K6 Q9 t
    early_platform_cleanup();
2 s& b3 n8 v8 L/ M4 M* P) T
3 ]8 r% _7 z" \* p0 O+ g    error = device_register(&platform_bus);# M) K1 t+ @" \$ L
    if (error)
( O+ r$ m" Q$ C/ A! G# e        return error;
. r0 Q  r( K' G. S8 w    error =  bus_register(&platform_bus_type);( y- o# D+ R# k! u. v/ p* o
    if (error)
4 P: L1 h+ w: w* Z        device_unregister(&platform_bus);9 Q" N/ _$ H0 R+ h. X5 S
    return error;
3 {; R6 d, r. X}
, V" K* s9 W; h) vstruct bus_type platform_bus_type = {% j- E, u2 K' x, [  K6 `5 J- {
        .name                = "platform",9 A# d5 |$ T( t$ M
        .dev_attrs        = platform_dev_attrs,
2 e) F8 ]. D6 p' A        .match                = platform_match,
) C# D4 _3 _, F: n, h& V  t! T        .uevent                = platform_uevent,0 D/ e# ^" \! |/ }+ D' L
        .pm                = PLATFORM_PM_OPS_PTR,# {0 F; o9 H+ f
};
- P/ ]  O7 F( e) x9 `5 LEXPORT_SYMBOL_GPL(platform_bus_type);2 ~" {6 h8 j4 Y1 S, N+ s8 q/ @
从bus_type,我们看到该总线的名字为platform。
* U8 B& X: y1 X2 J调用了两个函数,我们只关注bus_register函数。' m/ R8 K- t) u' k0 b

+ W  }0 ~4 L% q
0 O3 A- `+ z$ ~. A, p4 K/**' K6 l# \9 G4 M( \* ]5 I- E
* bus_register - register a bus with the system.
2 Z+ x& d7 x$ x! S* k* g( ?: ]0 i * @bus: bus.$ d% F3 `& }' z
*
& A; ~% l& F- I * Once we have that, we registered the bus with the kobject
2 O+ B4 S& J1 E, } * infrastructure, then register the children subsystems it has:
$ _; l2 y" s1 w8 [5 j8 } * the devices and drivers that belong to the bus.0 k2 S; I4 R0 Z8 b/ @" A" R. e
*/
9 _1 v9 B2 t, rint bus_register(struct bus_type *bus)- f. g% Z5 |$ t0 n# u& a
{* u  K7 Z1 I4 J) n( ~3 B) E
        int retval;
$ H( t' t! t6 n4 R% e2 r8 e0 ~/ o4 T        struct bus_type_private *priv;
0 r( o4 Z: G# p
" s$ t" }7 p& y6 l        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);) t! h) p' Q/ G2 A
        if (!priv)) E8 A# b7 T0 A
                return -ENOMEM;7 N; {4 e% C4 n/ t1 D
        /*互相保存*/0 |8 k& W& p0 H4 `) Q1 b( B: `- s0 A
        priv->bus = bus;
- e3 h+ s% v, k1 H3 @        bus->p = priv;
6 v2 j2 E+ u* i! Z9 z5 R( ~* N/ b& a/ o
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);2 u& z3 @+ Z- a9 f6 ?' s/ z" i
        /*设定kobject->name*/
$ P2 N, f) g7 |1 }, M        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
9 R9 Q7 J% E' |        if (retval); K  [8 N* T7 a$ O9 F
                goto out;( M2 B- _1 R8 F5 K* R

: F& Y% [+ m& z# L! g% c" }        priv->subsys.kobj.kset = bus_kset;: u/ F; v0 j. g# z. U6 |
        priv->subsys.kobj.ktype = &bus_ktype;
' {8 M( b' r" ]% s' T        priv->drivers_autoprobe = 1;
7 i$ l  K- G7 {  h4 g1 @. x2 M; ~
. i, ]- x, T: k3 v4 Z        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/8 [  t* {% L* o, M; I# J
        retval = kset_register(&priv->subsys);          e- ^7 o+ m- R* k
        if (retval)
; \$ I+ |! D  c3 {                goto out;3 _3 [. V5 F- I, Z8 }: R
/ i; {! H( \( }5 l7 l
        /*创建属性,在bus/XXX/建立文件uevent*/
4 `% d$ M- n2 C% j; t  H. Z        retval = bus_create_file(bus, &bus_attr_uevent);' S7 p! R& q; [: m0 o& m
        if (retval)6 a7 p: o5 V) Z2 r( R5 j, T
                goto bus_uevent_fail;
2 t& ~8 K2 ?# V- Z: M3 I5 v6 v
  c7 L. w# T. K        /*创建kset,在bus/XXX/建立目录devices*/
8 g. ^  s- [. N        priv->devices_kset = kset_create_and_add("devices", NULL,
6 N1 a4 U  ^0 v% o' a$ o) D                                                 &priv->subsys.kobj);/ ~0 q# t' k# ~3 f; |8 R
        if (!priv->devices_kset) {4 F$ b1 y! B# F# |* c
                retval = -ENOMEM;6 P' `1 C3 `& y, U. F
                goto bus_devices_fail;) D; O0 V8 _' a- L1 I' R6 ~
        }
) X. ]$ T, f, k2 W
; |) N+ `1 J  x% {# f9 w        /*创建kset,在bus/XXX/建立目录drivers*/
; @2 p3 ~( S; B' V5 t7 k9 F        priv->drivers_kset = kset_create_and_add("drivers", NULL,' }' w. l/ k- t& `3 |8 ?' L
                                                 &priv->subsys.kobj);
% I7 Y+ U- @) L        if (!priv->drivers_kset) {* O. g3 \7 ]' Z# y% z  \$ I
                retval = -ENOMEM;
7 I! n( z! B+ L                goto bus_drivers_fail;
, y0 _4 O) Z/ W# j+ K5 l        }
$ Q! z/ |9 D$ ^+ H( C* \        /*初始化2个内核链表,*/2 ^- D/ I4 ^8 i$ H
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);# z1 Q- e8 K2 D5 @: a
        klist_init(&priv->klist_drivers, NULL, NULL);
; |: ^' }5 O# f# z0 R! Y, ]/ ~+ w8 P, w
        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/
9 L" q% D# S; e3 d  B) A/ r        retval = add_probe_files(bus);
* Q; N4 Z& K# L( L0 _* f* y+ O        if (retval)
6 t5 ^4 F& R' z. U9 X) H- w                goto bus_probe_files_fail;
& M4 W/ v8 |) Y        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/
9 s1 P2 s' F8 D% }. k( O        retval = bus_add_attrs(bus);+ k4 D& P; x- M. U
        if (retval)
7 m  ]" o+ E( _( d& Y& [2 t* _                goto bus_attrs_fail;3 _! l1 N7 b4 d$ |3 {7 I* t
) ]/ W. F6 e- a( d3 T
        pr_debug("bus: '%s': registered\n", bus->name);3 j1 I$ G! c; ?3 F
        return 0;9 f& u$ M1 E8 P4 k4 B

3 A4 {% @4 B+ N' X2 k1 fbus_attrs_fail:+ ^8 ~* j; _1 {: v4 ]8 `
        remove_probe_files(bus);
# w: @6 P/ q3 J( |6 P1 U8 ~bus_probe_files_fail:5 z& s5 ^' v( o" Z  g0 F
        kset_unregister(bus->p->drivers_kset);
1 p- s- X" u4 L6 `: zbus_drivers_fail:' k! a  t* t; I
        kset_unregister(bus->p->devices_kset);
5 Y- i9 `- `; o! bbus_devices_fail:
& _7 G- d, j9 U- E4 G" [% j% f        bus_remove_file(bus, &bus_attr_uevent);
. J9 N' G$ C* X& z* qbus_uevent_fail:
/ y/ \& E  B9 y6 Z        kset_unregister(&bus->p->subsys);2 j* w) j- h/ h; A% ?
        kfree(bus->p);' Z7 \6 r. R% S1 c6 |
out:/ d2 ~8 E, _- A4 y
        bus->p = NULL;2 t% K% f, ^4 s  O1 z/ i+ p+ @2 O. |) E
        return retval;, y# f; c0 l2 S0 W/ F  A% H. R
}2 D$ K1 A* R- t/ ~
EXPORT_SYMBOL_GPL(bus_register);
* t1 ^5 j: \& p8 S, e) o4 H; r! @3 H4 \) Z' e- ~" M0 g
函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。
5 W6 R4 g6 H0 G: C在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。- y6 `8 b. @( D$ f6 J1 f8 D' E' v$ X
% I6 ]7 d& V: m
接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。
' h( i$ }8 f& C# l0 z
3 D; ~) l& m4 }6 l紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。$ F1 G# q1 _0 s) G1 r# K

3 T8 l, m2 H6 I( h8 q+ [4 O, ?9 T
4 ]! K  n+ }" ~/* add the kobject to its kset's list */
: E# u, S4 ?9 e5 q  ~static void kobj_kset_join(struct kobject *kobj)
" v" O" X+ l9 X{
3 c6 ?1 {& z) I& v9 S        if (!kobj->kset)
" B$ C* B: v) q) ^) o& T                return;# `: m( j2 ]6 k
- f9 \) O5 p/ O& m8 z0 q
        kset_get(kobj->kset);        /*增加kset引用计数*/2 n2 Y: C' m/ C6 s% ?
        spin_lock(&kobj->kset->list_lock);0 C2 ~3 c- p( p& X
        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/
% J: ^5 b9 D) I# V$ K- |) \  K        spin_unlock(&kobj->kset->list_lock);% l& J3 j, d6 I- i$ c
}' M$ t5 c3 o" ~
kset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。( P6 {" ]0 [0 O5 b
& h  I; w5 w4 U/ B+ v( R! [

: P+ A8 `5 ^9 k$ }0 Y
; Z) X& j% Z* s) U( A然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。
0 o; e0 Y5 Z& a6 n% y
6 k1 b! y% ~, h) aint bus_create_file(struct bus_type *bus, struct bus_attribute *attr): a9 H; J; D; E, `
{" R; Y$ P  B1 N, \
        int error;4 {; G$ d3 c/ {, Q# [. t' |
        if (bus_get(bus)) {: f, o: w- q# p2 C' p
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
$ W- M' G- u* j0 U) x                bus_put(bus);/ E$ r8 p  Y& K
        } else
; L3 I/ H* X$ }+ Y                error = -EINVAL;/ Q; ~0 J% ]3 O( _- W! L  [# [
        return error;
8 L" ]* o; B- u. X8 \; a$ O}, _& w) L+ m6 ]( j0 q' t  f
EXPORT_SYMBOL_GPL(bus_create_file);* w$ [% F7 {2 f% T2 ~
有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。2 T6 W, E& s! E  ?# v/ B4 O4 n
接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。
4 L" {5 f; e- b+ N5 |1 I' s* N/ n. F
这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。- h/ r5 w: j; P6 J: A) {6 h) m

7 U; X8 U  r& a2 J6 a也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。
# Z8 O7 U4 J  o% i* \. k& e7 }  d, G1 K- K: h& B% s8 G* w6 P
我们来看下关系图:& w# C1 T. {8 L$ G5 I
* O# a$ X& L  {

! S) n6 q6 c5 L! F/ d1 \# x
- E+ t6 W: @' d5 v- e& b$ ]随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
& i7 u. ?& G* D
" s7 J/ a2 C2 R# U/ q" X. Estatic int add_probe_files(struct bus_type *bus)" p" a& `0 u" I% |' D
{
1 [% ?: `) J% d+ U4 A        int retval;$ k7 R, r9 d; |) }* u, Q
& L8 Z3 N) I9 E' s. y3 k! f% r
        retval = bus_create_file(bus, &bus_attr_drivers_probe);  e) q5 c' c: }% k; V) J  M
        if (retval)
0 u1 i/ }: y9 d* h                goto out;. }& w4 S7 @3 Y

$ V# B0 K. h3 |/ }" o+ l0 V        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);! D% A7 E3 R# N8 J6 S$ Z7 Z# }
        if (retval)
& y) C7 z4 Z* ]9 Z                bus_remove_file(bus, &bus_attr_drivers_probe);4 A* [$ {6 j8 k9 s# ?7 q4 I& l; }5 i
out:
1 K# e# Q% H% p) a        return retval;; \6 r! b9 L7 S) {) N. I
}
& j. @; @3 r. S& z: z该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。
2 n& I8 |7 g! W0 m' \, N: A最后调用bus_add_attrs创建总线相关的属性文件。9 m- A) R0 r  K' C2 B( g% ]
+ [8 ]) u- @" B$ d' \% L
/**! ]" S0 E2 E$ n
* bus_add_attrs - Add default attributes for this bus.
; b8 p( ?$ ]( p/ {* J1 |6 s * @bus: Bus that has just been registered.( F9 k( E1 U- {/ I5 Y, a& o6 s
*/
- z. \/ ^, G- k7 T- l" \/ T
$ z) n" m! x) mstatic int bus_add_attrs(struct bus_type *bus): C5 l* V5 X. E: C; h% S
{, c  V+ n* Y: d' B1 T
        int error = 0;' l2 i% e% o1 z
        int i;) W  J/ g6 C' {6 {, \6 S0 y0 n6 }
$ }& n+ |: J$ P+ g2 w
        if (bus->bus_attrs) {
6 O& B+ t+ g8 C" z, h                for (i = 0; attr_name(bus->bus_attrs); i++) {
  v; w( ]; W  }# P  d. H2 e                        error = bus_create_file(bus, &bus->bus_attrs);$ Y- \8 [; q% T
                        if (error)
: P5 b) Y( Q0 l  ~( c$ |7 o5 {                                goto err;
8 I4 V7 G% _. x% m; l                }( A' s7 N) ]% P% P4 N9 h
        }
* W# `3 [3 e" |* K# L3 _2 Sdone:7 n0 k  |- B1 o  |
        return error;
; `8 W$ v3 R7 `" g1 z1 k) g0 Kerr:
. A) ~  n+ T3 `* ~        while (--i >= 0)- P5 z1 a) P: U0 |' ^3 ^
                bus_remove_file(bus, &bus->bus_attrs);
# x9 ]# C2 `* m! A        goto done;$ p, A, O& g3 G
}
: v; [. j8 a9 w4 L2 |. W# [我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。" U/ g* l5 y4 f1 q7 k$ j
好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。" f4 a& i2 H/ f3 t/ E6 d. _

, D: O% ?. M9 O/ E& x[root@yj423 platform]#pwd
3 x" }) H0 z0 v9 k: s9 I$ P. }/sys/bus/platform* w5 o9 ^# V5 T
[root@yj423 platform]#ls2 @% t' B* Y0 U2 O  J. Y9 o% V' g
devices            drivers            drivers_autoprobe  drivers_probe      uevent: F9 P8 g3 n1 K5 P
最后,我们对整个bus_register的过程进行一个小结。
3 W3 q* A/ {7 r4 v( N. b8 E' K
6 _5 d- ^: A6 z$ o3 w ( d$ e; M6 f) J/ A- T8 o$ ?4 q
7 `3 W8 ^, ?, J  F0 D! ^
6. device举例$ `9 q( ]# Q( Q+ e
本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。
5 P$ z  K  K' M- N$ m  k; j+ g7 I6 d* f( k' x+ e- H
6.1 虚拟的platform设备, b9 i# ]0 ?+ x0 I4 |" q
之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。1 _! e+ I7 m3 ]7 z( q4 U% Y  |
: @( i5 G# K9 y* X6 l7 E  I6 d  w
在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。
" T& W* |4 e, o, S4 U) W
  h  v. M3 m  Z* @/ f& }int __init platform_bus_init(void)
9 R6 |, d* p2 ]5 H7 a9 ^{
9 M/ `: N+ M8 o& o' `! v* k        int error;
( q+ Q: z$ m" I, L% }, d  q0 e( A% |( [2 u. N* o5 L0 i4 T- x" M
        early_platform_cleanup();
8 \; D# ]2 t4 v9 [# r9 f2 n% U- F$ ^
        error = device_register(&platform_bus);" q6 \2 O# j5 U. v0 G3 o; B
        if (error)3 P' W. t9 O! S* `4 N7 y  y
                return error;; P% I( J- P1 k* {, C) \
        error =  bus_register(&platform_bus_type);+ ?# H, b0 _5 n1 [: F% M5 x4 P
        if (error)
0 K1 w$ a" C5 e  H& f! l7 b( U" O: y                device_unregister(&platform_bus);7 T1 \" k$ C/ {" f# B
        return error;
8 m3 U8 T/ U% i: G# O$ a, x* |  g* b}
# p! p+ Z; o# [* Q7 s: k
6 i) H- b* e/ n) t8 X( ostruct device platform_bus = {: P9 X6 J) `! A! B+ h# P
    .init_name    = "platform",
4 l: M4 C/ v' v6 ]. i1 c5 E};
1 ?! A# c! U6 {+ [$ NEXPORT_SYMBOL_GPL(platform_bus)7 ]9 F3 o( M2 @* q- J
下列函数位于drivers/base/core.c。1 e, S# F$ q6 a) B8 a
/**
$ J3 s; r& V- B( K7 D( o- B6 f * device_register - register a device with the system.
. c, X9 g+ P+ J$ Z * @dev: pointer to the device structure& y( P  z! b+ r% ]
*
( U1 R0 E! Y8 [1 G2 d4 K * This happens in two clean steps - initialize the device
% c9 D* Y' e9 H; ]5 s. \& ^* z * and add it to the system. The two steps can be called; o6 L+ X) q/ t- r9 ]
* separately, but this is the easiest and most common.. l- B" B/ M9 R+ m1 ]" i$ D
* I.e. you should only call the two helpers separately if
( f- a( k1 \! N: m; C * have a clearly defined need to use and refcount the device/ ~, u( M7 i6 _
* before it is added to the hierarchy.
0 Y" H" C  }0 o+ B( N. d *
" V; R/ O, r1 P# S9 R6 j * NOTE: _Never_ directly free @dev after calling this function, even
7 Y3 J0 G8 I7 @ * if it returned an error! Always use put_device() to give up the4 w: `. r' y. [! c0 b
* reference initialized in this function instead.% f! S! w. w8 T9 E9 D' B
*/
. z" x1 z+ v3 @1 iint device_register(struct device *dev)4 E8 m( C* f* b, G# c1 d; ~" \5 V5 C
{- E8 m' _' f0 p
        device_initialize(dev);        /*初始化dev的某些字段*/
2 y+ X0 ^! n! t# X5 I        return device_add(dev); /*将设备添加到系统中*/! u+ o4 j- j: B4 _2 j: |% m$ t$ C
}# [$ t/ ]# I4 Y! h, h# T+ \
* Y8 s- ]* @4 E- o: H2 B1 z  F+ |
一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:
9 f6 d9 X6 u5 C: B" I  H
1 H* I5 c! }9 D& g1 z下列函数位于drivers/base/core.c。
* a* y4 d9 V& B6 j9 m( `: z/**
) \/ I5 y! d2 k1 L7 |" C- R * device_initialize - init device structure.
) R5 ^4 j6 q) R$ `: X * @dev: device.
. y. C% Y9 c: W! N2 E0 d *
4 I8 a- Y7 K4 { * This prepares the device for use by other layers by initializing* V: t& G6 k4 f* Q
* its fields.
) ^- H1 F" C4 ~2 f0 P  t * It is the first half of device_register(), if called by2 _2 N6 Q8 v7 W" r( X* E
* that function, though it can also be called separately, so one
0 B( d; {$ v- D8 i7 K2 H9 E * may use @dev's fields. In particular, get_device()/put_device()
2 `1 r  F$ b1 ]- q7 k * may be used for reference counting of @dev after calling this# ^: K  e+ j/ w- }# q
* function.0 D7 V" a6 ~6 p+ l  {# l
*
5 a& o( @1 R; l0 _& h; m" _$ e * NOTE: Use put_device() to give up your reference instead of freeing
5 _7 F" y$ e7 N' m$ w& J& C2 ] * @dev directly once you have called this function.
$ R/ X- \3 N6 K0 F3 t! Y. @' N: t */% l( f; l4 q( q
void device_initialize(struct device *dev)+ `, q2 K6 v' G' |* L' s! S
{$ ~$ S$ u1 O5 z, @. s3 v
    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/. q. e( i- X2 y, i% F) d2 ]( X
    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/  a- J0 r' X) `3 U" o" N# D; O
    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
' t5 @# N" `! r1 q9 K    init_MUTEX(&dev->sem);                /*初始化互斥体*/  [9 }2 j, D5 V. H7 f# |0 h$ [& A
    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/
: C0 M" j( q1 d" |9 [! m    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/
) o# `1 T8 r+ u6 `, J3 M    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/
) k( {3 t' H3 R" f    device_pm_init(dev);                /*设置该device可操作*/
0 a. f0 F6 J$ ?6 G    set_dev_node(dev, -1);                /*设置NUMA节点*/' N* h. i% |3 R* C. L
}
- m7 Z) s# S% v% Q" o6.1.1 有关devices_kset/ |* H6 W7 `# a& {' I5 H
首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。
" Q5 Z' S- C/ T5 j  C2 k6 ~! i3 n$ n# b5 `2 d& o, `+ f
该对象的建立是在devices_init函数中完成的。
* X; p- J9 i" E; m+ uint __init devices_init(void): M2 Q2 n' t! u/ X, n7 C
{- {. _5 d9 Q# S
        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
$ H& ?. i% c5 ]        if (!devices_kset)' |! |' i, ~7 e% ^9 R
                return -ENOMEM;* h9 }+ I5 j; ]+ l% u. J
        dev_kobj = kobject_create_and_add("dev", NULL);/ |* E( D/ v, I& n* e. Y: P
        if (!dev_kobj)
8 v* r  }/ O; w8 a                goto dev_kobj_err;
% H/ z+ K( X4 G+ e7 W9 X/ _9 x* X9 I        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
  ?. R* u7 t: L. S3 Z' }        if (!sysfs_dev_block_kobj)
2 b% s; H: h- }                goto block_kobj_err;. _. P8 a; i% i5 D, x! w) a2 Z
        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);4 s$ N9 W- e: p+ V% U# O
        if (!sysfs_dev_char_kobj)
: K/ Y# W0 j# d4 x1 S                goto char_kobj_err;' u: P6 R  V8 Q3 v& z1 T
( R) Z$ J! `2 t9 y6 _+ N
        return 0;
$ @* S6 c4 }1 {5 [; B/ X" c3 r5 Z3 [
char_kobj_err:' e1 M) J& B, X6 x5 Y: Z3 N
        kobject_put(sysfs_dev_block_kobj);
% J* q+ |2 u  m# o1 T7 B block_kobj_err:
' l, p& n; `- j1 `        kobject_put(dev_kobj);
& t) E! S5 c" [4 L/ A* o dev_kobj_err:
4 y8 o6 l4 D* a- u' d        kset_unregister(devices_kset);
( V& Y. J) T* s1 z        return -ENOMEM;' `7 R" c+ L# I. d7 A
}3 g7 z  b- `* \  E& ^# A6 Y/ b
由此可见,devices_kset对象表示的目录为/sys下的devices目录。
  {. h+ T% x8 [- P6.1.2 kobject_init
2 |6 a  ]! Z* |. A6 u# H0 r下列函数位于lib/kojbect.c。
* D2 ]- y- s5 |- l; w/**# V5 M# f7 L- e8 Q$ b, V
* kobject_init - initialize a kobject structure* a/ i0 Y$ x  |/ s  ^
* @kobj: pointer to the kobject to initialize: p4 j7 \# j8 u9 [9 q
* @ktype: pointer to the ktype for this kobject.
2 g3 s+ K' a- t2 E- f *2 m7 j; j$ n: q2 _
* This function will properly initialize a kobject such that it can then
+ x% H; r/ @, p5 y, N! | * be passed to the kobject_add() call.
' o- u4 a6 Z. I# g& p  ^ *6 l- K7 g( ?6 A0 o3 i/ w; `: G1 U) {
* After this function is called, the kobject MUST be cleaned up by a call
7 V6 ^2 N/ T  E+ c; T' n" l * to kobject_put(), not by a call to kfree directly to ensure that all of8 ^1 ?0 X. P# \( _0 M% I
* the memory is cleaned up properly.
3 p3 W8 `% M; n */
+ J% K5 }% Y# x. ^1 bvoid kobject_init(struct kobject *kobj, struct kobj_type *ktype)
' ?( ~# w( _- z& U9 H{) w2 d# `2 _; T" ]9 E3 E6 \& [4 ?
        char *err_str;
2 b- Z5 [, K" Q* c  r, T4 U8 s. j0 Q  J- |
        if (!kobj) {
! F" N! s% c8 y                err_str = "invalid kobject pointer!";
0 n7 @: y" D! K& r  }* M                goto error;
7 M- t" q/ S3 s1 o        }" G5 b9 c4 C8 `. B2 M
        if (!ktype) {
% ~6 l: A  q0 @& s* c                err_str = "must have a ktype to be initialized properly!\n";( s: I: W' |4 k
                goto error;% R; ]8 X. R* }. i
        }
& }/ e5 [! E7 z8 x2 R; k% U        if (kobj->state_initialized) {
5 _3 I: k  q  [/ U& G: t6 N- t+ l" F                /* do not error out as sometimes we can recover */
0 ~, Z% l2 U0 Q, j& G                printk(KERN_ERR "kobject (%p): tried to init an initialized ", u/ P) i4 G9 D3 ^: Y: c. M
                       "object, something is seriously wrong.\n", kobj);9 ]2 r# p& q6 W# `' h1 G3 n
                dump_stack();8 ?( |$ _! p8 E5 {, @$ c
        }2 P3 k' ^3 S8 g: E9 _

4 H/ V, E4 Z4 @8 l% O        kobject_init_internal(kobj);6 u# j' c3 N0 T; T% T6 S1 W* ^
        kobj->ktype = ktype;$ G: l# y: P9 c6 L+ R/ N
        return;! N( z9 P8 V0 i- {+ X
; \! C$ v; d. s' M7 k$ Q
error:; }% ]8 G+ N& L" ~
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
. L" l8 ?7 n% k) g5 F# t( f        dump_stack();( a4 R* f8 x5 C( _# @
}# E% ]& b0 L# c( _# Y9 c5 @
EXPORT_SYMBOL(kobject_init);
: E% |& P% m6 z) f" V5 k  r* A5 [6 F) N5 x
static void kobject_init_internal(struct kobject *kobj)6 P3 ]: d# r/ m) Q5 ^6 v1 b; h
{& N/ ~1 f% }9 R6 Y( c
    if (!kobj)
: [+ }' c; u% ^4 h  r        return;# c" x6 n* m7 z5 j0 j1 U
    kref_init(&kobj->kref);            /*初始化引用基计数*/
8 ?. a( P, g5 p" T    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
7 g6 a8 M* l* M+ H8 v    kobj->state_in_sysfs = 0;" M0 }- T/ R% q# ]% B
    kobj->state_add_uevent_sent = 0;# b9 i; H6 \* `  A" e0 v! ]
    kobj->state_remove_uevent_sent = 0;; V; M3 W( s' S  T- ^0 P5 i
    kobj->state_initialized = 1;
5 f7 L- \* C$ s5 t}
! g; T+ J+ B: [+ ?7 P9 _* q该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。; c3 k0 Y5 E% o4 l# M
6.1.3 device_init_wakeup8 a5 _% D; v* c2 ]! r. L$ X* t
参数val为0,设置该device不能够唤醒。
# n' r7 u4 F2 \2 ?: q#ifdef CONFIG_PM
8 C7 B9 l8 }# [& y+ S: n! B7 B3 O% N4 N
/* changes to device_may_wakeup take effect on the next pm state change.; p! x8 I3 i. f0 q3 q$ q% I
* by default, devices should wakeup if they can.
  ^4 @$ y( w# K+ a */4 U& J3 B, u! T% w, e9 I% q
static inline void device_init_wakeup(struct device *dev, int val)
8 q* D" j2 X' V8 i- `$ C{
' s. q9 M5 y& q) A1 F+ D: e        dev->power.can_wakeup = dev->power.should_wakeup = !!val;# h) i1 E+ \2 V
}# c. U/ [) Y( N! ]
。。。。。。8 J7 K. y2 G* \  p/ w
#else /* !CONFIG_PM */: Y8 x: c1 z) T9 `  n3 S/ V

+ B, E" M4 N+ ?( F2 C- E! B$ W- K/* For some reason the next two routines work even without CONFIG_PM */: Z2 w$ L7 ?+ Q3 l  K
static inline void device_init_wakeup(struct device *dev, int val)2 K) ~- n" ~1 r1 O: d8 b6 @
{
6 l, ]* ]) c( y7 c  U+ s) `    dev->power.can_wakeup = !!val;# m( E& m- F0 a8 ^
}% ~  H# V1 C" m0 x4 u
。。。。。。; s/ n- F7 G" }. P
#endif7 v$ w3 X5 [: b+ {, G

! v4 A# Z5 n. q- H! F* K8 i( B; H* r" f+ J
6.1.4 device_pm_init) v7 a! b4 M1 r) ?  L( W
设置电源的状态。! a0 j" _! w" K1 x  c7 A2 |
static inline void device_pm_init(struct device *dev)
( N% e9 y3 x& }$ Z! a1 }7 M7 V0 V{
; F" u# F( G% P% a) R        dev->power.status = DPM_ON;    /*该device被认为可操作*/% w. h: v! Y6 w) n1 d
}
& j& _' E  q( s" H1 m/ P) ~8 k6.1.5 set_dev_node
" r0 U7 r" E2 G" q7 H; }如果使用NUMA,则设置NUMA节点。
+ V; w( a# R6 N% B* j3 q9 b#ifdef CONFIG_NUMA
1 g1 m+ n* f1 D% f。。。。。。  n& b; B# |7 o
static inline void set_dev_node(struct device *dev, int node)
7 y$ _5 Y% `+ ~{
' Y2 }7 s4 P/ W0 ~5 S0 {( M        dev->numa_node = node;
! v7 Y# A6 b$ b$ T6 a# J: y, I( m# E& a}
$ C0 p; w$ ~9 k% ^+ U+ s#else
3 D  J' m7 y0 i。。。。。。1 J- \/ ]# |+ P/ q/ r
static inline void set_dev_node(struct device *dev, int node)
. H. c  h& r8 n4 H8 [- J{# P$ w1 y3 h# b1 @
}6 w3 L$ K+ ?( G: j0 t; ?
#endif% L8 f" R; D$ O/ S! ^
: R/ d! N2 `  k) D2 ]
6.2 device_add3 M/ k! j- U8 w# t, T8 k5 R- K
接下来是注册的第二步:调用device_add。
4 D+ G  w0 A$ o& F" v; g) M, x0 s* r+ n2 a* t
/**' ]( b- v. K* Y9 {, {+ l1 M6 O+ k
* device_add - add device to device hierarchy.
0 q: d5 q! l. \$ ~+ D$ q * @dev: device.
$ g' F  b# F5 N% u$ y *
! E, _6 `7 i6 z * This is part 2 of device_register(), though may be called
* l! U4 ^# H- i* { * separately _iff_ device_initialize() has been called separately.' `8 h4 D9 c  g& `5 t: r/ A" }3 ]  Z
*2 n0 O- B, h4 ~+ h
* This adds @dev to the kobject hierarchy via kobject_add(), adds it
/ Y2 y$ T+ N) n3 f$ Y * to the global and sibling lists for the device, then
3 c, d2 j2 @5 y# X8 E8 ~7 o$ m * adds it to the other relevant subsystems of the driver model.
9 r* ^) e$ d4 ~* \  z/ H *
; O: h* {9 N# w) R! c * NOTE: _Never_ directly free @dev after calling this function, even
1 _# b, }' K1 ^* ^& _* N * if it returned an error! Always use put_device() to give up your3 e; i  K8 {6 L0 S
* reference instead.) h6 T% U& y3 x' |+ \
*/+ [: k+ ~- a5 I4 c
int device_add(struct device *dev)9 }& Z9 |( ~0 N. w$ C
{. d" o. h+ q( o4 I' m3 u* a" c
        struct device *parent = NULL;6 s8 }( j: V8 E; w+ f8 i' t( `, m
        struct class_inteRFace *class_intf;
6 `# M+ U9 k* i. C6 `! n5 R+ b        int error = -EINVAL;
/ [1 U0 q$ _8 i3 ^3 c' y6 h8 n9 z1 t0 Q
        dev = get_device(dev);        /*增加引用计数*/
9 U5 C" {0 u% w, W        if (!dev)
( G5 \+ ^+ w: b2 w                goto done;
' I# T3 n  M3 a  @, H' t
% U: @5 @+ |( S# e4 t4 ]1 o$ P0 N4 ]7 Y        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/
3 \# ^9 p( c" `        if (!dev->p) {
8 r1 x7 S: m; `! ~: G6 S+ ~4 s, D                error = -ENOMEM;
. @  j5 W- d0 y- N                goto done;3 q) G& I: H; w9 S( _' t1 a
        }
  Y8 ~& I+ X# w        dev->p->device = dev;        /*保存dev*/
- M4 v( ]7 ]" _5 X3 G        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/* U) f/ `% E0 b% M/ F: E/ H
                   klist_children_put);  }& C, Q9 h  l  O: w

$ U5 Q3 K9 u/ |6 S) r( H: d        /*  n" p9 v$ A$ P! y1 \! p
         * for statically allocated devices, which should all be converted
9 c0 h, q; n! R( w0 H, c9 w         * some day, we need to initialize the name. We prevent reading back
- d3 v. P. L) U2 v2 _) x2 C% W  Z         * the name, and force the use of dev_name(), _5 [6 K- ?9 L; I3 A" F! M9 J
         */
! \! R' A) p8 V0 N" r6 v% T5 `6 V        if (dev->init_name) {0 g% A5 p6 v4 M4 V  i# D' c
                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/
9 `% ?( H# h* U( B5 I6 x                dev->init_name = NULL;) F- p6 Q1 n" B# Z
        }
! b+ Q% H( {- }2 n6 i8 [2 k! U1 ?) m) K8 ]8 Q
        if (!dev_name(dev))        /*检查dev->kobject->name*/
1 z6 f2 A& }* y' E                goto name_error;0 h, ^/ G+ B- N* c7 f& U$ T

9 U1 S; F  c" L/ p" f; r4 l: e* J9 z: g        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);+ i% H& V$ `* V
! J& d6 j4 F& {, z; E# g3 V5 M
        parent = get_device(dev->parent);        /*增加父设备引用计数*/
" ^3 c' {5 o  Z" m        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/
# O( x1 E# P( _6 Z6 l+ c* s; B6 m  ]& e) P. C
        /* use parent numa_node */
+ A0 v9 E& V7 v0 C6 }4 e( R        if (parent)% u# e8 o: m. c# I% W3 S9 g
                set_dev_node(dev, dev_to_node(parent));1 w+ Y  U& }, {5 U& y
8 O0 q$ ?, [4 ~0 ]$ o& c7 u+ s
        /* first, register with generic layer. */+ L  d1 c1 v* P' G- R8 R& R
        /* we require the name to be set before, and pass NULL */
/ W6 _% x, c& W: Z        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/
" \# N3 G) k7 a        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);       
2 K' v: F7 q; w7 O, ~6 ?# `4 o  y        if (error)
) z" W" m8 @7 O" B) y% Q$ ]1 Q1 a                goto Error;
, G9 b$ I) K+ p$ v5 r) I- |% ]1 {+ h
        /* notify platform of device entry */: j. Y! Z( R; ]: d9 ^- J; z
        if (platform_notify)( _; N  D  ~- `7 Z7 E! }/ k
                platform_notify(dev);
9 S# r" c6 j: U/ `
: M+ t# o5 M/ e8 s8 w8 b        /*在XXX下建立文件uevent*/
. A& F- ~9 a  y0 g- d/ j: Q) h9 E        error = device_create_file(dev, &uevent_attr);$ Y% v0 o# Z/ \( {1 Y* q
        if (error)
- j( S4 L! [' P7 ?2 B, q                goto attrError;
7 w. c" A  [+ Y+ r- b2 }: T4 y& y4 M; @
        if (MAJOR(dev->devt)) {/*主设备号不为0*/' y/ j6 r0 t7 s& u8 Y
                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/
( A' E& v' N' ]: C/ J5 f9 i                if (error)
& x1 N  M" o5 u2 K1 c' G                        goto ueventattrError;' f" s, ~' _. R4 x8 l

4 g/ {3 Y5 ]8 z3 H' @3 D                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */' k% Z+ K& u3 M4 d% ?6 l3 [
                error = device_create_sys_dev_entry(dev);
' @+ b" `* \6 ?! I) \( T2 ]                if (error)
9 y, {9 |. \! W7 b, S% C                        goto devtattrError;' S; n, V0 N2 l! e% x  H
        }- {! D9 G! q9 H$ Q

% @9 `2 Q1 F1 D& O8 x1 |0 G        error = device_add_class_symlinks(dev);. ?% H2 k: W2 e- p
        if (error)' ?. {! M0 m3 ?2 b# u
                goto SymlinkError;3 Y/ c: d" h' d3 \& ]* G
        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/
2 t# p( ]5 Q! l% I! e# [        if (error)1 R& g0 Z- |, x% }5 c% m7 o9 u5 a) B
                goto AttrsError;
# w/ C( M! T; X$ ~4 ?        error = bus_add_device(dev);        /*添加3个symlink*/
8 t. w  B8 m& t& k4 N        if (error)
( a) `& j) L2 p: p  k$ ?                goto BusError;3 ~7 g1 ]* d5 o) h2 V! Y# \$ ^. ]
        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/
; B  C1 ]0 b: l7 x+ ^$ _, r) N' F        if (error)
9 k$ {1 O4 a, o3 [6 ?9 K                goto DPMError;
) s, B! B) p' }; T; ?0 T" j" Y        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/2 A, r7 x. |' ]9 x6 U

' V5 v2 n) C8 C# f# s        /* Notify clients of device addition.  This call must come. _% _; f/ Q# f  [3 t/ ]8 _4 O
         * after dpm_sysf_add() and before kobject_uevent().% z) I4 U4 v) o
         */! [) L/ E2 m6 C# ~
        if (dev->bus)# L! V! U1 ?' x5 _+ }( O
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
" J% G3 X7 }+ Q# o, q7 D                                             BUS_NOTIFY_ADD_DEVICE, dev);
% C. X* v/ x& O8 W2 m6 l3 v1 W1 x8 m0 l! x, V" X
        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/6 B  {+ I0 N5 I4 Z; s4 ]) C* n# f
        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/7 D  f$ f" m, T+ q( w! T
        if (parent)# b+ _0 @- E" I6 b. o2 j. [
                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/7 ~7 F; L0 ]% H& C( z: @
                               &parent->p->klist_children);# V6 A8 G) _4 ~1 A/ S% t9 q  ]# B
: {) K; E/ |) T' s" \$ u5 e/ F6 Z$ s8 F
        if (dev->class) {                                                /*该设备属于某个设备类*/7 [' Y* h) w; f
                mutex_lock(&dev->class->p->class_mutex);
3 E( k7 c/ B- e* H  `                /* tie the class to the device */
' P1 d- i2 u7 l: G5 t9 t" }3 E                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/
/ m' B/ D, ]9 ?. _                               &dev->class->p->class_devices);
$ h& o' M& P" {7 n$ g, F9 i7 {- g: k
                /* notify any interfaces that the device is here */) Q5 A$ F  ^( `/ H/ ~" r
                list_for_each_entry(class_intf,+ c( M0 C3 `! V8 V6 c
                                    &dev->class->p->class_interfaces, node). Z9 j, G( [. K, w2 u
                        if (class_intf->add_dev)0 H$ C% q5 i: y& a
                                class_intf->add_dev(dev, class_intf);
- t" i2 D, U" i1 h7 @0 E, p" e                mutex_unlock(&dev->class->p->class_mutex);
  f0 K0 k- i$ P" h3 ?! `        }5 m: W+ ?; g' X& y+ G& H
done:" j; L) Q/ S" b5 i# }- |8 V
        put_device(dev);' [1 b3 |  S4 t/ @4 [
        return error;
' ^; J( S  G! u3 x' O6 o DPMError:! C9 C/ }# a8 z! d0 A9 R, ]4 a
        bus_remove_device(dev);1 ?6 U% r- M1 E  y) I
BusError:! N, j# v( Z6 }
        device_remove_attrs(dev);
8 S5 h; Q$ W7 x% ?7 k AttrsError:
+ v: m+ u; H7 m        device_remove_class_symlinks(dev);* P6 q! n# p9 F5 H7 s% {
SymlinkError:
* n0 h: y) J8 m8 Q        if (MAJOR(dev->devt))1 c0 Z/ q& g* }" M) ^  Y
                device_remove_sys_dev_entry(dev);
; ~' A1 X7 W$ ?: d) d devtattrError:. w2 s2 r( t5 F2 n( Y
        if (MAJOR(dev->devt))7 d: S: T; O* K) N
                device_remove_file(dev, &devt_attr);
# o  F4 D: f6 ^0 Y4 _ ueventattrError:  S4 o" n+ ?& h4 u5 q# j) z
        device_remove_file(dev, &uevent_attr);
9 a# }1 U$ i4 I" i+ t% t: s attrError:
  V6 b  z, L1 N6 p        kobject_uevent(&dev->kobj, KOBJ_REMOVE);: z$ g, s) P3 w+ r- k
        kobject_del(&dev->kobj);
4 b6 X" Q7 u% G2 C3 x# [ Error:
( T2 K* s0 }$ u" c& J' m- v        cleanup_device_parent(dev);. X; L3 Z1 |, g0 A* C  Z' ?" s" q3 {
        if (parent)# B! e; K( f  F) R! V* G
                put_device(parent);
4 ~% m" O' q- q, U/ u8 ~name_error:
3 v0 }, p7 J! X4 M% p        kfree(dev->p);+ e/ Q4 i+ y" {) U- K4 H2 ?" H
        dev->p = NULL;
- ]" U; B5 T/ [' H        goto done;3 X7 f: l1 Q- q6 Z
}* V2 e& t* R% x5 P, p
2 T" w% V6 h) Y* _
该函数调用了非常多的其他函数,接下来对主要的函数做出分析。' h" b! l* }! z4 m- J/ d
6.2.1 setup_parent函数  q4 X3 j% K3 }# N1 X- H
下列代码位于drivers/base/core.c。
. h3 y3 I+ P) g8 x1 f( Astatic void setup_parent(struct device *dev, struct device *parent)
- E# O0 O3 v6 K. [% w8 R( @; p{! d2 z& j8 C$ L
        struct kobject *kobj;3 D/ l+ J4 A0 ~' t% u  e
        kobj = get_device_parent(dev, parent);
$ l3 b- q, v5 R' I        if (kobj)
# j* M$ W# ]# T6 c* Z% J) |. D                dev->kobj.parent = kobj;, R$ O/ Y; }% K- Y
}! A& x  e7 |' M  c) ^
" h6 i) \4 x! ]$ Q2 h1 x
static struct kobject *get_device_parent(struct device *dev,: C! Y/ L* G; K4 y
                     struct device *parent)
, v" Y) a7 A3 k6 P{
* _+ D, {* m" K2 n  u* h5 j    /* class devices without a parent live in /sys/class/<classname>/ */9 a6 A) {! e: X3 m1 g: x5 H; k
    if (dev->class && (!parent || parent->class != dev->class))
% T: a5 t: Y; n. |: b1 G        return &dev->class->p->class_subsys.kobj;
6 r  i0 R' o3 e- y2 d1 [3 m    /* all other devices keep their parent */
8 q! G" S5 A5 t# o% W    else if (parent)
! \' O0 ]3 y4 l2 y) f/ b+ Z, ~        return &parent->kobj;6 a' N+ ^- \+ H8 d2 O; s7 Z* M

+ i  K& }; M) ]  `7 |    return NULL;
: C5 |: G  u8 T  `# O! y6 e}: v% N2 ~0 F+ R" S# m
该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。
2 Q3 c  V3 p6 l( e7 S7 t. n; i/ k6.2.2 kobject_add函数
) z3 I  |# q! @! w下列代码位于lib/kobject.c。  x0 {+ C' n) g. W* j9 _5 t
/**
5 C1 j. n  A$ @6 c3 | * kobject_add - the main kobject add function
# s0 R* s! I- \; N * @kobj: the kobject to add
6 K) `6 J4 x7 a5 g  |* G * @parent: pointer to the parent of the kobject.
1 O# `. k! c4 i. X6 j * @fmt: format to name the kobject with.
9 |* S4 C3 i9 S *
* c0 ~  `. }' ? * The kobject name is set and added to the kobject hierarchy in this3 z  b) e6 g, R/ d# \  Z* D
* function.+ o% U+ B7 a0 m6 Y9 W8 x
*
2 ~' c; `$ ?* \2 u  Y( [ * If @parent is set, then the parent of the @kobj will be set to it.2 R( [: s9 O- ^
* If @parent is NULL, then the parent of the @kobj will be set to the
6 Z! O! S" q6 s * kobject associted with the kset assigned to this kobject.  If no kset
* P6 i9 _- c' u! |0 P * is assigned to the kobject, then the kobject will be located in the! B! X2 R4 H1 z2 G2 E$ y( N
* root of the sysfs tree.
" I6 E7 s3 s9 @! y( F *
0 ]3 S' B; f3 F" C7 S7 G9 z * If this function returns an error, kobject_put() must be called to! u: F& x' M* c- U
* properly clean up the memory associated with the object.1 j& ^% w+ j" P3 [4 C; v# p
* Under no instance should the kobject that is passed to this function4 I% d8 J8 b0 ?5 p* A( k, A
* be directly freed with a call to kfree(), that can leak memory.8 ^2 H' A8 j+ x; p6 b- d
*
/ s+ P" s. y! o! r" g0 F * Note, no "add" uevent will be created with this call, the caller should set
9 p9 |- d/ V1 d * up all of the necessary sysfs files for the object and then call
" U8 s& E6 {! _# t) i( S0 h * kobject_uevent() with the UEVENT_ADD parameter to ensure that
1 X! ]/ w! E: L0 W0 Q( x * userspace is properly notified of this kobject's creation.1 H$ Y" g3 n1 O
*/8 ^% Y3 C+ X! A9 N
int kobject_add(struct kobject *kobj, struct kobject *parent,- N+ G4 G2 x3 s& s
                const char *fmt, ...)8 l: O5 _3 m3 W  q
{
/ w4 ^5 \* r% Y5 Q( K6 _: F2 x% a        va_list args;
; L4 E7 o' k: m; K; ^2 [" {        int retval;' _0 O2 @0 u* }0 {4 e0 E2 m9 t

7 k9 f2 L/ [  O) Q  Y- r        if (!kobj)* ]9 [5 G, G  Q; x
                return -EINVAL;
! R5 o7 z' d1 m" J2 A. u
$ _% k. g3 Y/ y% z- @* D- W        if (!kobj->state_initialized) {% K+ j4 Z9 ~; c/ R3 `9 x. G6 V3 O
                printk(KERN_ERR "kobject '%s' (%p): tried to add an "+ ]$ z: S1 q1 b8 `7 e6 k# A
                       "uninitialized object, something is seriously wrong.\n",; A: N- J1 S! S, g& E8 a/ o# v
                       kobject_name(kobj), kobj);
1 I, p+ c/ A8 E7 H% W                dump_stack();8 e: x/ U; ?. B: f
                return -EINVAL;  k! }% P/ d4 z
        }
, w4 T$ e. r9 D0 p- t  N        va_start(args, fmt);
- O2 X8 \- i0 w2 h0 e7 @  U        retval = kobject_add_varg(kobj, parent, fmt, args);
5 Y8 D2 @. o' E% T$ p+ O* i3 A        va_end(args);
# w' ]1 ~  G1 ^3 I" A, w
0 w( v8 |5 d2 H        return retval;
. X. M8 w9 x( b3 `( d% Z# U/ R8 d. j}
6 o# O& ]  u' j2 g3 X- T' V! SEXPORT_SYMBOL(kobject_add);4 n, g+ y# @+ t

* j: N. b, b  T3 n) Xstatic int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
! u  P6 P6 R) ~! G                const char *fmt, va_list vargs)/ g3 N6 {0 S4 e
{* @% x: m9 G& T
    int retval;5 U! _- V4 z3 v- i3 d

$ i# n# d  f" x$ K; N4 ]    retval = kobject_set_name_vargs(kobj, fmt, vargs);
& h+ e& b  s  D6 q    if (retval) {1 Y) v; n7 P: d7 I
        printk(KERN_ERR "kobject: can not set name properly!\n");
- H+ l( R4 @9 i4 \        return retval;
5 n) @; y0 o. f: z* t9 x( c6 O    }" @0 G7 Q: s$ H: q) E' i8 e
    kobj->parent = parent;- \+ I2 N9 W) G3 D' o2 w' r, o! b: ^
    return kobject_add_internal(kobj);
6 }) t: I. V- v: D. A  L}; n$ [- Z, A6 C- {8 Z
8 Y) ^' h. E, ~- K7 O# t/ n' s. W
static int kobject_add_internal(struct kobject *kobj)
' q' ^9 H0 M+ _+ h" T{
$ @/ |" Z+ P0 ?' a# f& x3 u    int error = 0;6 }* `+ y& f& U. X$ ~; }
    struct kobject *parent;7 o9 ~; J( _! P; [- |  G
  A2 i4 Q- `( w/ V5 {& R- H
    if (!kobj)
% u+ ?4 J; _# r, v  N9 I        return -ENOENT;8 u2 e# D. P& u0 O+ F* I! l
    /*检查name字段是否存在*/
6 q/ D# t+ l9 C2 I) i    if (!kobj->name || !kobj->name[0]) {) m$ [* S% L) |# o' B; \1 [
        WARN(1, "kobject: (%p): attempted to be registered with empty "* }$ q& U" B/ i( m
             "name!\n", kobj);
4 C  g+ x# V% S( P        return -EINVAL;  P5 o0 y, p6 b8 W3 ~
    }
: g$ ^$ |7 y* Z) X; \6 Z$ {: c. M) f9 z& x
    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/# D- @5 [( }/ y, n+ i6 @# G
7 r6 V. F' ^9 n( w
    /* join kset if set, use it as parent if we do not already have one */
& v* \; n2 J3 Z5 a  d% K% Z; J    if (kobj->kset) {    6 r6 {; W- `1 r4 r5 Q* U5 ^6 s
        if (!parent)3 ]$ e, ?# G% J& P2 a
            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/1 v6 s5 r6 {7 u+ D$ t. _! M
            parent = kobject_get(&kobj->kset->kobj);0 y6 @$ n  L; q" l' c
        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/
) o# ^0 {0 c7 i4 t/ B& F, n& S        kobj->parent = parent;
% z. U- X6 c, K2 l3 v' A    }' K0 h# M" ~! m7 [
0 h" G! S( w! z  R
    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",+ v6 L- N7 I! x! _' e6 ~( H
         kobject_name(kobj), kobj, __func__,
3 M8 w; X6 L. z         parent ? kobject_name(parent) : "<NULL>",' X6 A3 B- y, H
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
, `4 ?9 V  S8 P( @- s6 _' Q# w% @/ l3 T& Q! z$ e, o
    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/: S& A. n7 u4 W5 E6 T
    if (error) {
5 \2 n3 Q( h( V% q4 G        kobj_kset_leave(kobj);    /*删除链表项*/+ `' w3 D" v0 m
        kobject_put(parent);    /*减少引用计数*/+ b' E4 Y4 z4 p  J0 ^1 {
        kobj->parent = NULL;
) F* F1 z3 n4 O5 ^
4 D% [: ]7 D; _* ~- U        /* be noisy on error issues */
2 o" \$ Y9 D- y0 h1 F        if (error == -EEXIST)
* B" n3 t. E' y6 q' ~3 ]: C            printk(KERN_ERR "%s failed for %s with "- g! H1 U# K- w- V: t, l, {
                   "-EEXIST, don't try to register things with "
: G/ T. l+ u8 V0 D" y                   "the same name in the same directory.\n",
% R1 C( F5 X, @$ O3 ~$ \# Z" G                   __func__, kobject_name(kobj));
) r5 v! V. ]) K$ h        else
2 H0 j2 b+ R0 ~' b& X            printk(KERN_ERR "%s failed for %s (%d)\n"," M2 M* q; y# E) T
                   __func__, kobject_name(kobj), error);6 G8 |0 e7 V1 Z9 w7 b. c8 Z; k4 ~- Z4 {
        dump_stack();" W) X  X6 {/ _9 h
    } else
8 R4 u$ S: t0 X% K3 ?+ }' t) Q1 U        kobj->state_in_sysfs = 1;) W, M( F& p% H" ~
6 [: y' J7 d8 N7 [# D
    return error;! Y2 o' b8 R3 ^) r  r- ^) b7 u% z
}
5 ?" {% c; H  w6 d6 v在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。& d) I2 J9 j' P& S; f: W5 i
而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。
  E, H; v6 ~5 O* ~* F1 m2 V/ U+ |/ ?
但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???
' o* N& t% ]) U1 C0 n$ p% a
1 y! \4 }3 t1 {% I8 z& K- x) _6.2.3 device_create_sys_dev_entry函数
! C' }+ J# `* X/ l( s) H6 x0 i在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。
" e- i4 k9 x' W% y/ B但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。% ^- T9 x+ _, J  W9 Q6 C; L1 V" A
" }7 I' s$ A. ?. V) `' d* e
下列代码位于drivers/base/core.c。& K! O. G+ D. [4 y' x7 L0 I/ Q
static int device_create_sys_dev_entry(struct device *dev)
+ n& L( O, d3 p4 q' h$ k{
  M$ a6 X; @, F) |6 G# S, O$ f        struct kobject *kobj = device_to_dev_kobj(dev);2 r. Y8 H7 @; O# w3 Q
        int error = 0;* \$ a6 F0 V8 k* v
        char devt_str[15];
% u0 P+ g7 h) T" K; }! v6 K* ]' x
6 n& o! |* w, j* |) Q% F        if (kobj) {# j. s; B; V7 ]- t8 e
                format_dev_t(devt_str, dev->devt);* h/ t+ z+ a8 W1 K  `8 |% Y
                error = sysfs_create_link(kobj, &dev->kobj, devt_str);
$ q; V( L1 m% a* D' y5 @        }, @5 t' K3 X' T

6 E. ~2 D' s5 F! ^# e3 m        return error;" @! i+ t- {0 s! D
}/ ]8 N7 v; z9 e. c: U9 x# o9 B7 N
/**
2 E* E) u! Y. U * device_to_dev_kobj - select a /sys/dev/ directory for the device1 \0 L) h& d; b% q, W, N
* @dev: device
6 L( X8 d, L$ W0 H3 g) G *# w8 c4 D9 C$ F; `
* By default we select char/ for new entries.  Setting class->dev_obj8 {+ b% R0 j6 L) m. X& M! a) a
* to NULL prevents an entry from being created.  class->dev_kobj must
/ Z0 j; ]+ W. M% h * be set (or cleared) before any devices are registered to the class
9 p, W6 [+ A- Q' Q7 x1 d$ \  u+ c * otherwise device_create_sys_dev_entry() and
9 @* i. @" y6 y" v * device_remove_sys_dev_entry() will disagree about the the presence
4 g5 e. n) U4 k) D * of the link.. @/ e7 l5 X5 P. R( R4 @/ P
*/' ^2 I- v. k. i; ~
static struct kobject *device_to_dev_kobj(struct device *dev)# m9 l$ r9 v$ E
{* `# K# ]" @9 g) ~
    struct kobject *kobj;9 {- y. n6 d0 a

& b/ L% \& @+ @) T* f    if (dev->class)4 I6 H1 o) U: O7 y4 R
        kobj = dev->class->dev_kobj;
* n) V% |( m  V% j% X    else6 `; b  U2 \' S4 z- S
        kobj = sysfs_dev_char_kobj;* |) ]% ~2 d- S: g  g: _
# f. g9 i: d) a4 m
    return kobj;( Q4 n+ j% w4 y( e5 n+ @6 [
}
. C. ?8 z& ^: @  G% D4 h: `
- r2 y! `- g1 g6.2.4 device_add_class_symlinks函数
. T, y- v8 P6 {, J' ~3 c. b5 a0 ^由于dev->class为NULL,本函数其实没做任何工作。0 j2 X% L, p0 e% W) {

2 q- L/ c( W; P下列代码位于drivers/base/core.c。" S6 |3 P: `. R6 c. Z! B5 O: p. d5 x$ {& k
static int device_add_class_symlinks(struct device *dev)
$ M0 |- k" ~& R. s3 f' d0 t4 B{: @* V2 w' ~! \! ]! \' x. V6 J; B
        int error;
( N) N) ]: M' x5 q" z4 [9 }
. }% |: H# @* b        if (!dev->class)
/ `# T' I; v5 S                return 0;4 H% c3 F  g5 L, U

# x& G7 e' z) F, a. E' |. ^5 `        error = sysfs_create_link(&dev->kobj,
0 e, j5 d3 S: f) k9 x                                  &dev->class->p->class_subsys.kobj,
, H$ V# x. U% T6 M. T! E                                  "subsystem");
  U  j3 l6 n2 q/ R0 P        if (error)" {. U) R, N# K8 a
                goto out;; I  v0 B3 v  z2 q1 }% j
: S* A3 S. C* k
#ifdef CONFIG_SYSFS_DEPRECATED
' ^0 A8 g& q) H        /* stacked class devices need a symlink in the class directory */
; ]5 \- L! B4 A        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&+ v% I! n; X+ ]) U5 `* \
            device_is_not_partition(dev)) {) _9 ^" J. L1 e
                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
1 l& g1 b5 L, o) N0 q" ~) i                                          &dev->kobj, dev_name(dev));
" Z' z; z5 [) |1 g  L                if (error)
  `6 c8 O/ `2 n" L                        goto out_subsys;
, C" k( d+ A3 t" E& I        }4 ~# |) f, s4 N

5 n' W. v1 `% F        if (dev->parent && device_is_not_partition(dev)) {
( g  V& p' `5 L9 k- x                struct device *parent = dev->parent;& O8 R. C4 I4 s$ W' N9 M
                char *class_name;
- ]3 t; D$ B( y# [, j/ t1 B/ L( q6 s) C+ d
                /*' |6 y2 L2 s# U+ b* I  o* p% _
                 * stacked class devices have the 'device' link  y$ n- V; ^0 q) d) N
                 * pointing to the bus device instead of the parent
' k' |) ]" t& n9 ?/ l                 */
, K, H* N$ r; ^* D; K                while (parent->class && !parent->bus && parent->parent)/ v% E9 W, \: I( K. b
                        parent = parent->parent;& P9 G- G+ D  {) U1 a& v% `
9 m6 a" t/ r. c" k, N; P
                error = sysfs_create_link(&dev->kobj,7 e* x' T8 x( U& O5 W" v
                                          &parent->kobj,& w- g9 a4 t: [! o1 l
                                          "device");
2 ]  Q' G7 ]" m- E' K% @+ ~- f                if (error)
' J* p* K% V  e! |4 M' ^                        goto out_busid;
5 `/ {5 D. R$ h5 J8 S7 p! X
  ]; c, C/ R) t( C                class_name = make_class_name(dev->class->name,; ]# z3 E/ l' S  ~9 c9 k6 f
                                                &dev->kobj);
9 Q0 z# q! U# D# e                if (class_name)
9 J, G. G* C* l: J3 g, O                        error = sysfs_create_link(&dev->parent->kobj,4 u  I) w+ W( ?  H) q+ O9 _
                                                &dev->kobj, class_name);
# m  x- I( o* Y& j                kfree(class_name);4 `% V2 l. ^1 K7 ^) i, ]
                if (error)% c, v) i% q! Q2 t+ ~/ J2 f
                        goto out_device;4 E' d1 I4 l& F3 k: @
        }
7 d  ^+ F7 c. d        return 0;
4 u  R5 c: D1 @3 l' u* j3 @. ]" `) S2 `
out_device:
: H4 R# Z' }7 E* h( z! [        if (dev->parent && device_is_not_partition(dev))% U- f" X; I, G& p
                sysfs_remove_link(&dev->kobj, "device");
# a& z4 R. n" m$ [8 n( Vout_busid:- O. o) }) \0 v) N. ~1 s
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&& A3 c+ y7 q# d" C8 M/ b% j
            device_is_not_partition(dev))' U7 S( v7 k6 ~0 b, |8 b
                sysfs_remove_link(&dev->class->p->class_subsys.kobj,
( t9 d. @. E" H: H0 M) V; s& ?                                  dev_name(dev));
: ]* }( Q8 [! e; h, a+ v#else- A2 A* N: ^$ a: J" C6 |- Q
        /* link in the class directory pointing to the device */; y: E. Y  l; |4 E, y9 B; [
        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
1 L0 j0 I+ ]' h# M" f- ?                                  &dev->kobj, dev_name(dev));% C' b+ T( Z9 ~: G
        if (error)
5 N) y, J2 n7 d4 N                goto out_subsys;1 x$ l9 w. f% @3 t$ j2 J* p
' L2 ~! K0 J9 u# O  g
        if (dev->parent && device_is_not_partition(dev)) {
$ A9 ?& N" h! J6 t+ v& v                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
* P9 R$ s/ u; e* W6 U7 t$ J                                          "device");- e  z6 r7 h& z  a' P
                if (error)7 \/ u7 V( M$ H1 X5 F, m2 V* R
                        goto out_busid;
2 r; G- f" e4 f2 a. M+ h9 `  }. ?% X        }( o0 W0 G5 Q' |$ r% y; }7 l
        return 0;" C+ R# m( G- C* R' J  |5 K

( X( i  p9 Z1 y. ?/ g3 Q4 Aout_busid:
6 M& o: X# K, Q; e3 A        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
' Y8 v; S) S( Y0 k#endif7 @# E0 F% K0 p# X  j( v8 {

$ N# `9 V. w* B; {9 H& lout_subsys:, A4 J1 V  |  p
        sysfs_remove_link(&dev->kobj, "subsystem");
, Z, r# A. }) C9 U7 Vout:: n" D  ]$ f# S& q. d) b. w4 X2 P
        return error;9 w+ w4 V8 V/ ^. d' x
}
, T8 J& {, @* P' }$ _/ w! U8 l6.2.5 device_add_attrs函数# k) o' E' u) V9 b" T" Z$ @9 R
同样dev->class为空,什么都没干。
4 E  I; Q; y/ |下列代码位于drivers/base/core.c。
, [+ E% s- ^* U4 _' h8 [- n+ w7 @static int device_add_attrs(struct device *dev)
, D. @0 @3 d% a" k  x{9 C) b' I5 a0 ]) F( f
        struct class *class = dev->class;
) Q- H! D0 a; f        struct device_type *type = dev->type;
4 H( ^  `7 k! t3 ?& i        int error;
" A8 Q+ Q( n' Y& A$ O" G8 z0 A, I+ v2 M& P9 y4 t/ g
        if (class) {9 }2 ], R  \4 }8 L$ n$ _- _3 r
                error = device_add_attributes(dev, class->dev_attrs);
+ I; b, U8 H0 |' B# }1 D                if (error), _3 P& O+ g" Y
                        return error;
" x& z8 I* d+ R        }
4 M' W) |% N4 |$ M) e7 c
' V8 s/ V5 \0 z& t4 g1 _        if (type) {' D8 @" U0 E# I) T* D: L; i
                error = device_add_groups(dev, type->groups);
: t6 N, f- Z+ V- D$ u                if (error)& R9 G: I/ A8 `: X7 {2 X
                        goto err_remove_class_attrs;
* A4 G3 w; s( a6 r        }( F1 K+ g- Z9 {2 S4 @" l* L

* @6 a) x7 _  y4 Y        error = device_add_groups(dev, dev->groups);
. k- T5 \. \1 k# j+ |* [# z" \        if (error)3 W; j/ i! p. l
                goto err_remove_type_groups;) v9 S9 n2 I9 d" k: s# t
( Q2 ~' x! l2 C
        return 0;0 l5 _" J" Z) `9 P, W8 ?$ ^4 B
# f* F; A( @! `. C. o. u0 Z" N
err_remove_type_groups:
) P$ ]# |) m- i' p        if (type)
! V' m- O6 S" @) X- H  Y                device_remove_groups(dev, type->groups);% o- E1 _: M3 z% k0 Z$ K+ n
err_remove_class_attrs:0 c2 c$ x. B% e' ^! e% [" c
        if (class)
3 U3 i: T1 y+ @0 C, U                device_remove_attributes(dev, class->dev_attrs);; [/ x3 ~) }# n; _- ]5 w" v

, d) s5 s3 v) K) a3 w3 F        return error;
. n+ k4 Z3 y$ t; S}/ A) c! P& H8 d4 B1 H
6.2.6 bus_add_device函数
0 c- v) U( R7 l) g  r0 a由于dev->bus未指定,因此这个函数什么都没干。
5 a4 R! l5 W& A9 M  ~. {) }- T/ x' {/ M5 G3 H- }
该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。* A% M% ], p0 ], j& a* ^! \
% M3 I8 r7 o4 b9 @6 M( u
下列代码位于drivers/base/bus.c。& j& U& t, x) `4 _! J  b; c% E
/**2 v/ H) T7 w2 ~8 |9 a# H
* bus_add_device - add device to bus
$ w7 y; `9 [" K4 {( e * @dev: device being added
( P# U6 N" L6 V( m, h *
2 e7 f# S* Y0 q * - Add the device to its bus's list of devices.
1 D! Z/ x5 D1 K * - Create link to device's bus.
! w7 }5 m  J& w/ I* J$ W */
" ?) @& t4 S8 Jint bus_add_device(struct device *dev); F6 ?+ |, |: W' H/ m, H
{7 V, n  q5 t3 h! ~( F4 b/ M  c2 }' C: B) E
        struct bus_type *bus = bus_get(dev->bus);
) A3 f1 X2 d6 i, i! T5 {: s# ?9 d3 ]        int error = 0;3 ~) H% ]! \8 ~. h
& B+ z7 ~- d8 I# D/ X/ x; p
        if (bus) {" ?1 V( U* N8 W8 O
                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
$ P5 D4 J# _$ ?, C& a9 K' r                error = device_add_attrs(bus, dev);" Q& c3 t! r" \: J/ ?' U2 I
                if (error)
: j! _+ ~/ g: i2 s                        goto out_put;
5 t1 s) a1 G- ~0 z                . @  F% v  L$ M: r9 q& T
                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/
$ ~2 P: Y" y& b6 j                error = sysfs_create_link(&bus->p->devices_kset->kobj,: p* C% P+ {* Q6 A1 w) S
                                                &dev->kobj, dev_name(dev));% F5 [7 x  F6 ]$ }% m) R
                if (error)
& B0 |; d! v2 i$ l                        goto out_id;
+ z% X! v6 c: o: v. d                ! f9 V6 t; ]% u- N
                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
" g( n7 O( Z0 K0 @7 y- U                error = sysfs_create_link(&dev->kobj,/ h4 V) i& b1 V6 o$ q* L% z
                                &dev->bus->p->subsys.kobj, "subsystem");- i0 M& B2 S! o# ?
                if (error)
* r) D( n4 G) F* u3 e0 b- F4 {                        goto out_subsys;2 N: r$ l5 V5 {7 @2 A
                ; h9 B! r4 x9 E1 [5 J8 b. B
                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/- m% X9 S* b4 u( n9 ?
                error = make_deprecated_bus_links(dev);" F# M+ p$ i" G7 J
                if (error)
% m' m. q# [+ }5 ]- }# o# j                        goto out_deprecated;
7 {- T  q9 G4 K: H, \2 U        }
" P* S' A  \5 M. e: Q5 D5 k        return 0;
1 u7 h/ e6 S" K5 H9 V: g/ J8 S, Z( B. N
out_deprecated:6 q3 D5 J* X/ r
        sysfs_remove_link(&dev->kobj, "subsystem");1 s. T  N  f) H$ S% U- l
out_subsys:6 ~" g& |& [% l* O* w* ]
        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
) K& _8 O: h1 `& k4 r) K& A+ l1 K' Oout_id:
7 Q4 Y0 v$ \2 F. ]1 M- A; e        device_remove_attrs(bus, dev);' X( h  e3 m2 G! s. ~
out_put:
' f- G" ~5 C" _        bus_put(dev->bus);& Q$ g4 r- Q/ V1 v" _7 l+ O6 M
        return error;
+ Y  {2 W' P; U# u* o7 d}
  \5 b$ e4 O- k. c/ h+ R) ^! v# Q; n, w0 C
6.2.7 dpm_sysfs_add函数
' M7 `' \9 h* i( R4 V下列代码位于drivers/base/power/sysfs.c。
* w9 f5 l0 M& P9 U0 d( N* d' m2 hint dpm_sysfs_add(struct device * dev)6 B5 ]7 R+ S4 ^
{
  v8 k7 M5 x6 X4 w! @, m+ v" G, H        return sysfs_create_group(&dev->kobj, &pm_attr_group);9 ^+ i) Q" I& w" _% v
}( T6 b7 `; w8 X8 ~
( l6 m4 v; ?/ |1 G6 X4 Q8 V! X; Z
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
: p2 g& M$ c' c9 t; ~' {, V) L! X- t
( u) a' g: \6 h5 r1 `
static struct attribute * power_attrs[] = {& p2 X* P0 K2 h6 `) [
    &dev_attr_wakeup.attr,2 t. N. {/ P" K
    NULL,4 k! H; x  {& y+ `2 t3 K9 j
};
& P9 L0 c. B$ j: \: `; X2 Hstatic struct attribute_group pm_attr_group = {
" c* E. ~7 z4 h& D1 O    .name    = "power",8 g; r- _3 w( i( [. Y6 q& W1 J
    .attrs    = power_attrs,, d+ t, y: i! ?1 e) P2 @. A0 y8 q
};
1 T+ F- H7 I* `' ~: }! O$ S( d- B7 D+ l
该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。. p# H; ^; }" {2 k9 s
4 d+ `; p3 j( \% p
在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。
! p$ ]" q+ Q, H2 ?3 z6.2.8 device_pm_add函数
0 y$ }. n5 H. |4 U) C2 O( W下列代码位于drivers/base/power/main.c。7 ~& @" v# e( b+ B/ I  ~+ E, Z
/**- x3 |* k' J+ F6 D2 M1 \( l9 `
*        device_pm_add - add a device to the list of active devices
( u' e5 [2 l" c% b, m *        @dev:        Device to be added to the list$ b# Z! |( a4 x6 {8 O# v
*// B  E: c+ C/ {( y! y. i; i
void device_pm_add(struct device *dev)
5 ~- i4 R1 T+ y$ I+ i{# X% W* f! e! t2 y$ X. M& \
        pr_debug("PM: Adding info for %s:%s\n",
: f' D9 T( g  ?9 Z                 dev->bus ? dev->bus->name : "No Bus",5 I* s* W8 D; O  f
                 kobject_name(&dev->kobj));
3 Q: f- p* [; U9 e' \        mutex_lock(&dpm_list_mtx);, s' ?% T, R  `& w8 U% I
        if (dev->parent) {# D0 E* K$ B# E
                if (dev->parent->power.status >= DPM_SUSPENDING)
3 [( w7 k" }# q3 f                        dev_warn(dev, "parent %s should not be sleeping\n",
8 x2 @! I* O0 g$ _                                 dev_name(dev->parent));0 e( {0 I& t' q" ]
        } else if (transition_started) {
- \) x( S% Z- X, |                /*
# W4 H( E- O6 H' r2 W; J- Y                 * We refuse to register parentless devices while a PM
6 u( b8 |9 ]$ S4 O3 q7 |                 * transition is in progress in order to avoid leaving them: Y$ C0 U: q7 w6 k. R
                 * unhandled down the road1 A2 `  ]& T+ H
                 */
; N- M& v9 v( D' o3 C                dev_WARN(dev, "Parentless device registered during a PM transaction\n");; ~& R2 f% }/ U4 t/ j, @# X5 a9 n
        }6 \% _3 A8 h6 p# i/ h

( i0 j  W+ Y4 Z        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/
& b6 q. {2 q$ X6 y* z0 i1 K8 k        mutex_unlock(&dpm_list_mtx);2 \" G/ w( {0 e) R) }+ O9 a7 B
}
, P4 r" e5 W3 I
$ i" ^. s! |+ G4 e该函数只是将设备添加到电源管理链表中。# H5 Q% x1 ]; k+ l# d  ?( o' L/ U
6.2.9 bus_attach_device函数" j9 _& S( w) Q% H' I
在本例中,由于bus未指定,该函数实际不做任何工作。
; m6 l" g* Z" U4 _/ v* f下列代码位于drivers/base/bus.c。1 R" K* A3 H" B' |) X1 b
  K/ G% d) q% @, P4 V) q
/**
+ r) u; |, t9 t, B * bus_attach_device - add device to bus
4 s8 c1 ]$ M0 U5 e: A- F# w' g3 ? * @dev: device tried to attach to a driver
  R, V5 L, t5 P' \, v+ X/ X! ` *
6 ~' v$ u" O/ [6 G9 G2 G; p * - Add device to bus's list of devices.
( z5 I9 H, _) K: y! k * - Try to attach to driver./ p4 e; O  x, Z0 a% z, h2 a
*/. g7 t$ z- d- Q# ^, x
void bus_attach_device(struct device *dev)- ~9 g  K; ^( w' E7 D- _* Y; h# G
{3 a8 w& N1 c5 K* p+ O' c. w
        struct bus_type *bus = dev->bus;# X! T, I: `- Q+ k' v
        int ret = 0;* T" A) U! ^; r
+ k% z. Q2 |. g: M
        if (bus) {4 I0 `. U( {$ g
                if (bus->p->drivers_autoprobe)
8 Y  n2 a  ]8 U- g% B0 P                        ret = device_attach(dev);        /*尝试获取驱动*/7 t4 @" Q' U6 G+ q2 D- S
                WARN_ON(ret < 0);9 G! r% z! n% s' A8 a. c
                if (ret >= 0)                /*将设备挂在到总线中*/; V! D7 g+ D& F( p. u. c/ K
                        klist_add_tail(&dev->p->knode_bus,
6 @5 Y, q& ]' e  T4 r7 R% O                                       &bus->p->klist_devices);
2 b& m7 i6 M, ^8 E1 u        }+ u- P6 H. e+ ~4 g- M! Z
}: F& B6 [- T& }$ N6 ^8 g

; n7 ?) t* I, E& F7 A% j/**
# P1 o+ H' K7 h, Z3 ]) } * device_attach - try to attach device to a driver.
* N+ c, o+ i7 u4 Q * @dev: device.
+ c* s. Q! Y: q" K *
7 v$ Y% s6 i. {6 ~: V * Walk the list of drivers that the bus has and call
% {. w- t( o/ K1 Y' c8 A3 g5 H * driver_probe_device() for each pair. If a compatible
" A) `9 D1 e/ z* y! C- F$ j * pair is found, break out and return.
  L  G# e8 j3 }4 y *
5 C! T3 z  ~% T2 D. F * Returns 1 if the device was bound to a driver;
+ [" g: x! }1 I0 L * 0 if no matching device was found;
7 r/ l7 U! t9 O( ?1 f: s" i; d * -ENODEV if the device is not registered.
6 y* p' R6 A% J, A *  H) k8 x4 b9 |. @) i
* When called for a USB interface, @dev->parent->sem must be held.
9 A4 h7 Q3 F- w6 W  U& U */' b0 q" ?/ o7 R6 D( N/ y9 g
int device_attach(struct device *dev), @" ~! d5 Q3 M: D4 q( C" [! X! I2 h
{
1 b' W" R/ Y. Y2 v    int ret = 0;
; K6 B, V% c( J( X
6 ^; }3 o7 j: i8 I- I    down(&dev->sem);" u! L" A8 R2 N
    if (dev->driver) {    /*如果已指定驱动,即已绑定*/0 F: j8 v" i5 y9 J+ @. l
        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
/ N3 }  t: a+ Z- v4 P- u5 l        if (ret == 0)
' X! e& U4 p, K) ?" n+ I" A7 z            ret = 1;
$ r. t) K* u, d7 }9 [  ?9 H/ C4 x        else {' I4 s5 V' s1 E7 m& ]2 H* l* F
            dev->driver = NULL;
0 k2 @0 y0 o; {$ g) B            ret = 0;8 o4 J% G' Y( r5 X- f6 f1 o) Q
        }0 R1 K( t8 K& T6 _' D
    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/
) W7 o/ D* [0 ?        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
. @# _% f7 G5 q: S6 l    }
; |' L- ~3 V5 ]' Y2 t+ o    up(&dev->sem);' j% v" L; k: q1 ?
    return ret;
1 U+ d* L; T; x1 _- y2 E; C}
$ t( R- F% l* c- X  u: R! nEXPORT_SYMBOL_GPL(device_attach);
, p) O' t' m5 `2 O: r; r" {" v2 X% |. I' G, I; h
如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。2 v0 d  F$ X5 c/ W
- Z( u6 q1 R/ m9 l9 j5 O4 Y
为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。
0 S% [9 J1 _; M/ r2 q, y) k6 e# o6 D. W1 O( ]( N
我们来看下bus_for_each_drv:9 Q5 n, Y; M' i! p6 k
, \7 o0 [6 K! ~. l/ o- n
/**7 ^2 S6 t6 B  q% d9 `* T. q
* bus_for_each_drv - driver iterator' q+ M% t4 c9 F7 D" v3 ^
* @bus: bus we're dealing with.
$ r8 d; t9 {4 y$ o$ k8 M * @start: driver to start iterating on.% R2 m3 a, |4 V% W
* @data: data to pass to the callback.% l7 A1 C; O/ A) v
* @fn: function to call for each driver.
2 f0 x5 s7 I( }, ]) U" @0 s, h *8 y' f8 X! t) [! X5 H" @) _, v( m; h
* This is nearly identical to the device iterator above.
% |6 g( U1 u- f5 }! ?5 X+ q * We iterate over each driver that belongs to @bus, and call
$ F( b/ e5 E% A9 [ * @fn for each. If @fn returns anything but 0, we break out% i: V* q1 s3 o0 K
* and return it. If @start is not NULL, we use it as the head8 Y6 m& ~$ S# I1 F% u- @
* of the list.% O% q2 l" m4 O" w5 }( ?
*7 i6 s' u" F+ j' K- s& n
* NOTE: we don't return the driver that returns a non-zero
( M% l0 x( X/ d3 W( D: E  d * value, nor do we leave the reference count incremented for that
) R9 q. r* k/ M4 B. J * driver. If the caller needs to know that info, it must set it: w6 k% I7 P& h
* in the callback. It must also be sure to increment the refcount5 `4 ]) [4 {+ x4 F0 x
* so it doesn't disappear before returning to the caller.
3 G& i3 T2 J/ z  T$ U */5 {' t+ w8 W6 c. S! @9 ]
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,# L! i3 ^$ G/ U6 r5 V1 Y# Z' o
             void *data, int (*fn)(struct device_driver *, void *))- I" L1 T4 K- {, ?5 I$ k6 L2 h7 A" c& w
{
0 o" U6 @& M% b    struct klist_iter i;
' h% y0 ?& t. Y4 ^, `7 l  Q    struct device_driver *drv;% p9 r0 r& \4 U' h( e) b
    int error = 0;$ j/ P( ]' Y* z7 }. W4 o" b3 ?

8 \  _( f; x, G- Z, ~$ h  f. H9 [) C7 J    if (!bus)
$ K6 i/ s6 G  `  [( [        return -EINVAL;/ p/ T0 p4 J& k' ?# z# L

2 B- O* o1 H/ C6 Y" U    klist_iter_init_node(&bus->p->klist_drivers, &i,! I  ~% k. w8 X; ]  N) K
                 start ? &start->p->knode_bus : NULL);9 p8 g9 ?5 e' z4 ^' }" ?4 x% a
    while ((drv = next_driver(&i)) && !error)
8 e# m2 O1 f8 `$ d7 s' p4 H        error = fn(drv, data);
/ x; t1 R5 L& a9 t& z& j- v5 J    klist_iter_exit(&i);3 H$ L  q; s1 H9 U% s. m7 A5 B6 I
    return error;) _- `  J2 V  J3 i( S+ h4 k
}
) F1 v) Z* E8 Y- ?EXPORT_SYMBOL_GPL(bus_for_each_drv);
1 u" V) z$ ^: P6 V/ {该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:
9 I* u. W9 M& f2 i% K: D, a7 L- p) N3 `8 `
static int __device_attach(struct device_driver *drv, void *data)
, {" e9 t$ R. p{
& k/ M2 U/ H  `0 a  Q        struct device *dev = data;/ U" b. \% a0 p( h& D7 Y  m2 Z
" J+ z. N8 ]0 |. F
        if (!driver_match_device(drv, dev))   /*进行匹配工作*/$ n$ {, G' e/ s( L! V4 U# C' b; Q
                return 0;
7 h( D0 S3 B; M. D+ d; O+ d' n# j  s
        return driver_probe_device(drv, dev);
5 F% T* R8 ^7 S* A& V}
! r( P+ ~$ }6 N/ X, U
& C8 G! w9 k! h9 u2 P% V8 Mstatic inline int driver_match_device(struct device_driver *drv,
- U* V# x' A, C3 u" ^6 p                      struct device *dev)
0 L7 h, x! M, h: }( c) T+ S{
" F. I% m- r5 T( G    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
* t; R6 l) R% N! x}
0 \  b  }8 y/ r# R# }( ?) A5 |
* t1 I6 u9 U2 M, t$ v/**! |- ^: M: _) H: G7 F5 H
* driver_probe_device - attempt to bind device & driver together6 w# j* b& m7 c! U# I% s
* @drv: driver to bind a device to
. w' c6 {: {+ t& E- R4 c* C * @dev: device to try to bind to the driver5 l$ m, X1 N* @8 C; r& w* g
*3 j, }) Y: k; n, d
* This function returns -ENODEV if the device is not registered,! u/ y7 E( d. u+ Y- f2 Z2 x
* 1 if the device is bound sucessfully and 0 otherwise.( l. ?9 M5 C. [1 I* _7 O
*
9 q( `  a8 p) k+ V1 D; v" H * This function must be called with @dev->sem held.  When called for a6 I0 J- |5 I4 s$ c3 d" Z
* USB interface, @dev->parent->sem must be held as well.& O3 J. i1 F/ I$ o2 K# L+ G/ M
*/
8 V1 p3 R+ X, E: x; Z% f+ `8 Qint driver_probe_device(struct device_driver *drv, struct device *dev)
( Q, y5 M: Y) b0 q{' c4 D  d7 s# `$ W. e
    int ret = 0;
# g1 J+ E9 H3 T( f6 i; l- \0 ^6 S! c, S
    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/1 u2 v% U, I8 R4 ]* Y
        return -ENODEV;) e* d: a9 R" n+ q' s
7 j  r' U7 k+ @; t8 T6 ~
    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
# c6 c! I) }' B! U8 z/ T         drv->bus->name, __func__, dev_name(dev), drv->name);
: r* f* ?/ W! z) v: O# C: w3 W% c2 i4 q: X1 g( P5 w
    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/    & _* ~, r& _0 A* _$ h9 \, O' I

/ W2 L' m6 D3 h3 ~    return ret;
/ ~* c$ i( \/ o  j, A* \4 |}
+ v, @% n6 }( Q6 W
. O& H$ P+ o9 l5 n" I8 a该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。# F  c* N: V, R9 c$ S0 |
我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。
  L: `/ k# {2 ]# D! r' K0 j; h0 \8 `1 W% K6 }+ H
随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。
* K9 N$ O9 f! R* `! s0 X. E. S& V) K& G5 I9 {
really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。5 b# [+ z* {4 B
6.2.10 小结" X3 A: P2 m; M0 q% ?1 |; ]
在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。6 p7 B3 ?- x+ x$ W# ^. _

4 c+ J* |# O- t; ^% N4 z7 E最后以函数调用过程的总结来结束第6.2小结。
) g" i- R" e+ \( r5 s0 Y
/ I/ t- ]$ s  o" }7 U! E6 f( h ' |$ \. z/ V0 N$ Q1 z" W) _4 c

, Y0 H" T* B  l2 E/ z2 |4 O: n
8 I$ l9 p! e9 c6.3 spi主控制器的平台设备
7 o7 g) D) p- F2 M: f# N, c本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。
6 J) _' y. k5 u1 y% Z
: D, D+ l% a1 E, A  c( Q& b在内核的启动阶段,platform设备将被注册进内核。我们来看下。
, M8 N* b" o5 X! g: ?' a8 {+ D, C. v, V- {: f/ N* n
下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c
: j+ v/ v( W0 e+ f3 c4 N
4 p+ O/ g$ W$ \" z  Dstatic struct resource s3c_spi0_resource[] = {
( y$ W% I% c; a7 O0 g    [0] = {
* Z5 S9 S2 p) s( `; x1 d        .start = S3C24XX_PA_SPI,
* X% q! |% Y( R        .end   = S3C24XX_PA_SPI + 0x1f,3 g3 r; p% V& Z, \. a, l8 i
        .flags = IORESOURCE_MEM,* s& P; C: q) [3 f8 K
    },( c  k$ M4 X. {" q$ M$ d: H$ g, I7 N
    [1] = {  h8 O6 u' V& u: t+ D% K/ B# U
        .start = IRQ_SPI0,
5 N6 C6 e: V7 B2 {        .end   = IRQ_SPI0,
- D+ l. u; ]# v8 m) s2 `3 D        .flags = IORESOURCE_IRQ,
* F% v! ?4 c) x& p, [; `* Y    }
! W  z& w6 z1 g2 b! ?1 E$ _, j) {: O, ~9 V! k! f8 g8 `
};
8 f* I9 Y, ]9 `1 H4 }1 o  B
! Y4 i! y: W% j5 Estatic u64 s3c_device_spi0_dmamask = 0xffffffffUL;
8 N; ^2 v$ p/ N$ U1 b1 ?9 ]2 N
9 X1 V1 f! B: S; ^+ N( Qstruct platform_device s3c_device_spi0 = {6 |5 D2 m* X' }' E
    .name          = "s3c2410-spi",
( H$ X/ B5 Q( R) Y; Z    .id          = 0,
5 G' ~6 P: b# [( ?: i    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
' k6 J$ X# {, ~* s    .resource      = s3c_spi0_resource,
7 }7 n3 D$ \; Q& b8 q" e1 o9 c        .dev              = {
% b* n( T) N5 m                .dma_mask = &s3c_device_spi0_dmamask,. K4 g( ], x3 C& u  g* s* c% `
                .coherent_dma_mask = 0xffffffffUL
; I" }5 S- b. K) m2 J1 m4 a        }& @% C7 i# T. n6 `2 V7 t
};
+ z9 `' w  q/ Y7 i& }: Q9 \4 [- i: u. ^- c0 \& l& L
static struct platform_device *smdk2440_devices[] __initdata = {  S( a4 w# @$ E; y: C& _4 U0 p
    &s3c_device_usb,
3 ?% @+ {# v! y; n- o  V    &s3c_device_lcd,
' J9 [8 y' g1 ]) i    &s3c_device_wdt,/ B  b8 r7 U6 N7 _# L0 H4 e
    &s3c_device_i2c0,
) Y- b2 [: m' j2 L9 J    &s3c_device_iis,) q) Y; T$ y8 @# I6 i( w9 ~
    &s3c_device_spi0,
% B5 Q- A1 f9 H/ c};* J% ~, H% J/ U& s# C  @

( w$ z' y3 I' E8 X! B1 `- s
1 X  X6 ]  ^" K+ u( Q* h* S: D6 Q9 _7 y' x: I5 x; Q
static void __init smdk2440_machine_init(void)) C; \2 F1 {/ I2 Q0 q5 h$ Y
{
% C1 y9 X5 C- w( l) z( q        s3c24xx_fb_set_platdata(&smdk2440_fb_info);( E" ^/ E( l; l- b4 L
        s3c_i2c0_set_platdata(NULL);/ f8 }7 r! k1 e0 f& R% l2 \: g( Y0 Z+ ]
& b% S0 L1 K0 I2 S+ J
        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));/ h8 K6 ~  T3 \, m
        smdk_machine_init();0 _% v# Z( x& z  o0 d! S( D
}
3 i" [1 C* }" a
9 w: o0 w% Y; M/ X: n0 O在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。* @  K) p/ D) w( U
6.3.1 platform_add_devices
; G9 a  c  H) S! A, k/**7 a: {. Y; [% j8 l& A; o3 R- H6 D
* platform_add_devices - add a numbers of platform devices
3 c# O. v- ]0 O) F4 }% l * @devs: array of platform devices to add
4 |8 C$ t; `2 m& l3 o; y * @num: number of platform devices in array/ E5 f+ o- u  }8 y5 x6 l0 m: I) P
*/5 o; U" K: O3 w% l) _
int platform_add_devices(struct platform_device **devs, int num)+ l6 l9 T% S9 h
{
  x( @# i0 ~/ y: ~: @; `  b        int i, ret = 0;
- N# Q* y6 P+ g
6 K% F8 T1 V, o% ^5 x        for (i = 0; i < num; i++) {
2 v; V, ~9 d! K7 U2 @: T. x& R# D                ret = platform_device_register(devs);
: J) P: [- S. {/ O- s  O+ h                if (ret) {3 ?1 S' F- V. P% {( U8 F9 N
                        while (--i >= 0). N6 a, c+ e" Y0 O( o: p
                                platform_device_unregister(devs);3 Q/ x1 [( v6 k; s
                        break;
4 N% p" b0 ], P* l5 A- d                }# p% d7 g3 \- ^, `, G
        }  R% ?9 [9 _* g- _& b

) q# ^6 B; A. t- h" W1 v        return ret;
% A* h! p4 u3 h+ O& {' ^6 X. H}; z) Q# I7 ~. S' L; y+ m
EXPORT_SYMBOL_GPL(platform_add_devices);! i9 \6 G9 ^3 W/ b+ ^  \/ j+ u
7 d4 A: Y/ F* o. Z" `* y  L9 H& T
该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。: }! u2 ]$ Q& ]8 J5 x7 {! z
6.3.2  platform_device_register4 ^2 G( z% \2 u4 J  x
/**  R8 [5 R$ p& I" H; A' _% R
* platform_device_register - add a platform-level device' m/ |; B# o* n
* @pdev: platform device we're adding
( N5 ~- x4 ?8 ~. ?2 b */. k) F& G5 P; P  C% q2 I
int platform_device_register(struct platform_device *pdev)4 U9 }! }% t2 ]
{
; e+ L4 h# Y: p2 b        device_initialize(&pdev->dev);5 p* F& U6 z! F/ A8 U3 m6 H% g+ w
        return platform_device_add(pdev);. d2 _2 {% ~" U5 z" P
}
5 c# a/ `2 q7 V# M8 t) c' JEXPORT_SYMBOL_GPL(platform_device_register);: O' `* s1 x7 J* y8 ?/ x
" P: Q; s# d9 Y8 U: d
调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。  o4 p4 _4 l$ Y" \4 i
6.3.2  platform_device_register
6 A' t' q9 y0 j; p5 J/**
. c- R4 w$ g) t * platform_device_add - add a platform device to device hierarchy
: ?# ^- b+ Z9 b( | * @pdev: platform device we're adding+ q; F2 p& p9 d7 {4 e/ r' X- v
*
5 @( I( Z0 v0 Z  ^( T0 D+ \ * This is part 2 of platform_device_register(), though may be called
2 }9 U' i8 Z  ^ * separately _iff_ pdev was allocated by platform_device_alloc().
. }6 A9 b! k) P; g */
. d. i+ b8 S8 [& ~' C( Q; Zint platform_device_add(struct platform_device *pdev)
, a, i: K* q( o7 Q" _2 o) O{7 ~9 V$ P5 M& B1 T$ q
        int i, ret = 0;6 `: r: \% S( b/ k$ y* x* U. i" r

- [3 D1 e1 j$ v# B% F3 W$ m        if (!pdev)
7 _4 \8 c% |+ P2 a) y% W% m                return -EINVAL;
1 c' n+ s# \0 g
" l. Y. m4 O' H        if (!pdev->dev.parent)
0 ]( C( X6 K$ N; F$ |! D0 ?                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/
; q$ }" q: w8 X
& ~$ n0 e0 @- z: B% O+ e' O  m        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/$ a- e/ Y. H$ a
5 i% w2 i, {" m
        if (pdev->id != -1)
/ M& t, k2 @( Z4 D& S4 O                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
. u& b$ p2 w# @        else5 T0 S3 k* G* X2 |8 x. E! U1 R$ M
                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/
3 l$ O- s- f1 o
$ T, J2 @" q2 w# l        /*遍历平台设备的资源,并将资源添加到资源树中*/# H6 \' h1 `: ]# q
        for (i = 0; i < pdev->num_resources; i++) {
1 g0 l, @! b* b. R1 Y                struct resource *p, *r = &pdev->resource;, q' P' t4 R  X
0 T6 Y" ~7 u" j& p& O  l
                if (r->name == NULL)
3 c, i5 V1 }' R                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/
4 U6 c# T# ^7 Q7 Q- r6 f7 \" L
$ @; X. |' n$ o; D- m0 G                p = r->parent;! ]' I4 D4 r: H7 a1 H" ~
                if (!p) {        /*p空*/+ D: U, W9 \: L' H5 T
                        if (resource_type(r) == IORESOURCE_MEM)+ \- C' L- {  U' \2 E/ ]
                                p = &iomem_resource;
5 D% t5 T0 m( ~7 E1 U+ y0 k                        else if (resource_type(r) == IORESOURCE_IO)# T6 p% M6 S( g* C8 O2 ?
                                p = &ioport_resource;
% J# E% R- o/ t2 z& d( X                }
, K) P5 o# q( ?* D/ G, P
: z9 U) p0 K& p                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/6 X/ _( |% T6 @1 _9 ?, r% O- u
                        printk(KERN_ERR3 O# p1 F. e; I" X( p
                               "%s: failed to claim resource %d\n",
# H( e: _, q4 S: }. `! I  e                               dev_name(&pdev->dev), i);
- p( _- G( U, B7 \  i5 S                        ret = -EBUSY;$ s7 A# Q. a+ J. \) |% z
                        goto failed;
- }* k. A, q9 m5 n; v. J+ p* w9 I                }5 ~$ U% D) l' H' g8 O4 h
        }
5 t! T- L& o' |' `/ E) J; y+ F* c4 D; d' _8 N4 C  d) W
        pr_debug("Registering platform device '%s'. Parent at %s\n",8 e7 B" }* w2 F1 i9 i  h2 s1 B
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));. q' [7 z) K5 q5 C% V$ D. V7 O

. d0 K& t; {9 D, w        ret = device_add(&pdev->dev);        /*添加设备*/
# C  q; W1 Y) }% r+ b        if (ret == 0)( M3 z5 [: k' }- |
                return ret;, |5 h6 g$ x; l. K3 P) j1 x

/ ~. P9 H8 k) z' M1 C failed:7 g0 Z/ m3 Q. d4 i
        while (--i >= 0) {6 Z+ P6 k: Y0 @
                struct resource *r = &pdev->resource;0 }% M2 V" ~/ D( {& Y. z: ]
                unsigned long type = resource_type(r);
3 W" s: o, Z3 _+ P7 o/ g& j( z# J; L) ?2 ^; ?- ~
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO). \8 [  o6 X- y  x
                        release_resource(r);" m& z2 M1 P+ g* x) P
        }
2 V' P- U+ B! O) w, k# D' T& X# |. ]; I; b& e
        return ret;
% A( _. ]1 Q$ ?0 S, r! T* m}
: {; X0 h! n/ |% t6 M. L. vEXPORT_SYMBOL_GPL(platform_device_add);. r# D" c: c( y% ~0 W$ f
: l  V1 _* [# ~  H1 P
在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
6 L! D! p9 x6 l本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。
" M# o$ g2 x6 i' [! j7 b3 t+ W( _/ ~' m# U
那么这个"其他的工作"干了些什么呢?0 J+ Z2 V3 Y7 m1 ]

! j. B# V. z# c# k* _首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。
0 Z. l; a8 [9 k8 `+ G: E然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。7 f# d) o. d7 Q! M: W# i5 |

. }3 t6 d+ e! a7 _最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。$ w; f& K" N; O  y6 a8 t) p
1 {( \; i! _% S+ S
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。7 c& }# f% c3 B5 L: g7 V* t8 X

% b: L0 G* H# d由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。
* }& J( p7 w! G" D% [4 W
7 [; {' V4 ^6 \6 S/ Y" X: O& F6.3.3 不一样device_add调用结果8 _- n) A/ ^, K5 ~" K$ s* }- W
首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:9 d; l/ ?8 S- s$ [9 ?6 q

. Y7 h% V8 o4 P6 E9 E7 Npdev->dev->kobj.kset = devices_kset" P* Y! Y. v' ?5 V

( W, q2 H2 t* opdev->dev-.parent = &platform_bus
8 |0 F8 {' Q9 N7 _) M( u
* C% i# T! m- ^( Cpdev->dev.bus = &platform_bus_type& c1 f; K8 p3 h* F! J$ s  d' v6 ]( Q
# i- ]# a5 D1 Z! f# g
set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。% E+ N. g% p' B2 M; s
+ a+ k6 X& S% i
kobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。
9 m+ s7 S- E, C" C9 U% S  t
; d, `' y0 D7 y' Y! xdevice_create_file建立属性文件uevent。
, k4 e9 u2 S; X( \9 A& nbus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。7 @: a' m" h: `$ ]4 Z  r* B

5 I5 ]' @+ b' @) m            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。
+ @0 v  v* g2 |& Z& n- S7 e6 g% E2 B- m  K/ N. h4 O
           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。: Z- y- r- e. T$ K# Q) V; q& U

2 \3 G7 |7 d# N. |dpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。; g( b7 v  M  F% k

( C5 h8 i& a$ J4 A5 Q/ _7 C  Y执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。
( n9 m5 R% d* O; J' g& D) ?
0 ^, T1 G' c+ }2 o5 G7 i[root@yj423 s3c2410-spi.0]#pwd. E4 y/ |5 h5 x* a* P# A
/sys/devices/platform/s3c2410-spi.0
- m- M" Q6 t5 j/ s9 ^[root@yj423 s3c2410-spi.0]#ll; s' S2 T! R8 r  B
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform) Q# N( w6 o* n$ K$ r
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
# w8 p& \1 r: o$ t9 ^* a-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias
9 |3 X8 L. w" g0 q. D, h3 ]drwxr-xr-x    2 root     root             0 Jan  1 00:29 power
" p8 D( _# K5 S+ V; w5 kdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
7 g( K2 l) e, `, U3 y8 Gdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1" k+ o2 K4 w$ e( K; }- j
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi0
7 \+ M  E! p! }( f: L: j2 ilrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
8 x4 q8 f/ n1 ^4 S2 A0 `-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent
$ d" u1 D& e# o# ]% y3 \6 A! \) V& B+ [: Q. b
[root@yj423 devices]#pwd
" U4 `3 b0 W/ V& p8 D3 A/sys/bus/platform/devices" {4 n5 q" N; D" }% ?' n
[root@yj423 devices]#ll s3c2410-spi.0 6 k* f8 E+ n# r; h2 e8 W1 }
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.0
8 i$ v3 h  ?5 _0 q- `! }& ?通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。) D) \7 f! d9 @

3 T6 ~3 i' W: T6 o- U1 ~/ g8 mbus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。
: P5 ~& h8 Y, _  J1 X, |3 G3 Q8 u/ m" o# i. j* Q% U
接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。  \. F# X& J) E$ ^) o. k6 V
2 B* e4 ]; S0 ^
7. driver举例& W6 [3 U1 [9 O
我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。) x8 q- g2 b1 a; v+ p
: V; Y$ A0 ^) z4 D, ?% z: p
7.1 s3c24xx_spi_init
9 F! B* \8 T; Y& l9 w( \# u* E下列代码位于drivers/spi/spi_s3c24xx.c。
4 ~6 d& ~- b4 y3 w. x& Z3 i6 B+ {MODULE_ALIAS("platform:s3c2410-spi");9 R4 [" k; h9 ?9 \6 z2 S
static struct platform_driver s3c24xx_spi_driver = {/ J. y5 f$ W9 L8 K9 w
    .remove        = __exit_p(s3c24xx_spi_remove),
9 N" @$ D4 B$ X# c& b* c    .suspend    = s3c24xx_spi_suspend,
# `( [6 {0 l9 d    .resume        = s3c24xx_spi_resume,
- c" R7 M/ l& {' p5 z" C5 L    .driver        = {) b+ C# |* j* r: }7 E
        .name    = "s3c2410-spi",
0 W- t, ~3 G; D3 \0 f3 U6 t$ n        .owner    = THIS_MODULE,: H  |- x' s& N, n1 |
    },# G" Y9 z8 H! M3 @0 Z
};
- V+ a( u4 P( l- P
5 I0 S5 S, L8 [static int __init s3c24xx_spi_init(void), f# {( X! n  N9 s
{
7 {% n0 L$ n8 L# o7 [  ?! l6 X        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
# _+ K' X4 W: X2 h}) i6 e& t7 G# l9 W5 @) _4 s- P% a- S
驱动注册通过调用platform_driver_probe来完成。
) {) I7 q( P+ K) y* v& O8 H0 H注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。+ e7 d# B' ?% v8 x; R
7.2  platform_driver_probe3 o$ z3 Y6 K& c& ~$ `# M& i
下列代码位于drivers/base/platform.c。1 o8 h- U/ E7 b) q0 m! T( x5 |
/**
, C, {0 q. z' q$ y4 ^ * platform_driver_probe - register driver for non-hotpluggable device' B; ?) E$ a- e/ G$ a7 j
* @drv: platform driver structure
0 W7 j( o) y  \  r4 p * @probe: the driver probe routine, probably from an __init section# D7 |: O' B8 U- d% U, T4 J, e6 b
*
' n2 X; z* V* l" o# {: l  K * Use this instead of platform_driver_register() when you know the device) `7 b* ~5 M( x% O4 O* L  q! m- P" ?
* is not hotpluggable and has already been registered, and you want to
5 {6 h8 k9 K' h) k7 t6 J * remove its run-once probe() infrastructure from memory after the driver# F. R/ ~6 s9 }
* has bound to the device.5 o2 J0 ?* e% Q5 u7 _% J8 |
*
! Y8 x' H) b9 z/ g4 i# G! b- F * One typical use for this would be with drivers for controllers integrated6 B+ ?3 I" e! m. G/ q/ P
* into system-on-chip processors, where the controller devices have been/ Q% Q+ r8 R9 G) d. {
* configured as part of board setup.
" K& W% {/ Q6 B1 |* w8 q *
1 a! r7 ?. n4 a: A0 {) z* x * Returns zero if the driver registered and bound to a device, else returns
" j' G6 m- R% `( t' ?7 F* ]% | * a negative error code and with the driver not registered.
$ \# ?8 B1 I7 [2 P- ^$ ]: m */- H5 h- r, D3 O: c6 ?) `3 h& B
int __init_or_module platform_driver_probe(struct platform_driver *drv,, q8 N5 T1 Z/ i
                int (*probe)(struct platform_device *))
4 n! P2 B! s2 V{
- D) }* K+ U- `  g: U! Q        int retval, code;4 j, D0 u1 e: A$ g7 O: q7 j- Y

( p$ y# p- f1 w8 M9 b- Z6 P# O/ |6 E5 K        /* temporary section violation during probe() */; ~+ x! P3 x3 Z" P! R
        drv->probe = probe;
6 k  h  ]$ G' z        retval = code = platform_driver_register(drv); /*注册platform驱动*/
6 |! i7 J% I5 [& |0 g9 _; P
' U5 T/ W; C( L8 _# `) {        /* Fixup that section violation, being paranoid about code scanning" A, ~9 O7 Y, @7 R& ?
         * the list of drivers in order to probe new devices.  Check to see
, }; \% K9 {. K( |, b+ ], i- |         * if the probe was successful, and make sure any forced probes of
# x" a) V1 z+ f         * new devices fail.' ^1 ^, @  ?! s/ I) Y8 n6 N
         */
% Y3 w/ R. X: z' Z+ S" l        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);$ ?( X9 R) D6 ]! }; r- j
        drv->probe = NULL;
) R7 s+ |0 }5 a4 _) H        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))6 |6 Y, j& w1 A. H1 x2 f1 \: i8 _+ h
                retval = -ENODEV;# L0 x/ o5 f; ^9 R/ p6 b' k
        drv->driver.probe = platform_drv_probe_fail;& T* t% `  m" E+ g( A: A, n
        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);$ G0 ]" Q5 s0 g) ]! g
5 a+ J3 ?) |7 A. O' O& u
        if (code != retval)/ x; ~; ?4 ~7 _* h: H- u
                platform_driver_unregister(drv);% P) f2 @0 E% \! F1 }1 K
        return retval;
  h1 A0 t7 k* c0 R}
4 u; `9 ^8 K0 O, z6 ?EXPORT_SYMBOL_GPL(platform_driver_probe);
! G" k+ D7 X4 A6 u这里的重点是platform_driver_register,由它来完成了platform驱动的注册。8 j) ]4 v' a0 w% E4 O% w/ {, a
7.3 platform_driver_register
( e8 y4 R& x7 M6 A" }9 t0 ^% g/**
" |# X8 _) s& y' m2 a# I2 U * platform_driver_register: s8 ?7 _$ I/ B6 S* B: R
* @drv: platform driver structure
, D0 o) J  \6 |, p' _ */
4 S- S2 Y  ?  G6 bint platform_driver_register(struct platform_driver *drv)
! ]) k& v9 g# q9 A( @# C{6 u4 e5 g' i* b) [& R( K
        drv->driver.bus = &platform_bus_type;8 c9 B' i7 v7 N5 n, ?, q5 R; Q% P: [
        if (drv->probe)# [& R+ E6 S3 P. j, w
                drv->driver.probe = platform_drv_probe;
/ Y* h; _1 x% ]/ E  ?7 `        if (drv->remove)
& a# I* X+ G' f* X/ o- e                drv->driver.remove = platform_drv_remove;
* u" K$ V) G( H; N/ J( D; I        if (drv->shutdown)4 A7 L6 n& o# Y$ {* n" p1 U
                drv->driver.shutdown = platform_drv_shutdown;* P! N, ]) ^0 z4 U" A" r% S
        if (drv->suspend)
! i7 u/ ^! Y, r6 e) V  \9 B                drv->driver.suspend = platform_drv_suspend;
6 f3 ?2 c- [: H7 L4 d        if (drv->resume)! [3 q# B0 a$ c, k9 _: W9 u
                drv->driver.resume = platform_drv_resume;
, |8 K- i3 x& |- ^( ]; `5 l7 K$ u        return driver_register(&drv->driver); /*驱动注册*/
- A, P; ]& m0 t( F6 l0 h}
) {0 ?4 ~8 m2 y1 L3 s4 G) A/ HEXPORT_SYMBOL_GPL(platform_driver_register);% i( a) R4 G, ?! i6 [' P: i
  y, x, V$ c7 S5 @8 `- v7 Z# t$ `
driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。
# z, h/ \) N2 l/ N7 G" Y# g7.4 driver_register' Y5 s) z$ L$ G1 t7 M
下列代码位于drivers/base/driver.c。8 b/ C2 S8 t! Q+ \
/**0 x* B, L. g' w$ Z* r! U
* driver_register - register driver with bus
! E, K2 ?0 x' f2 U( v  s! r: U * @drv: driver to register
) c, S# J( E4 z7 I% C. K' u3 c *, S0 M' X- S5 H0 @/ K
* We pass off most of the work to the bus_add_driver() call,9 ~& @9 j& m( B( G' m* n) \
* since most of the things we have to do deal with the bus7 s9 I# ?0 K) ~7 I3 j0 @8 D$ ^% {
* structures./ c& W# M) a- ~
*/
+ q$ [; t' M! b1 S4 f4 u' Hint driver_register(struct device_driver *drv)
9 E: z: b. u; I& r2 ?{; Z) w2 D$ T* A" [' M: x
        int ret;( V- h2 \% m; o* h7 a
        struct device_driver *other;% }' `& f0 G+ Y# R2 n' U; x

7 `' s' y; J$ H  ?0 O        BUG_ON(!drv->bus->p);
# _$ l* e+ R& |, o. {! c+ G: K
7 }- O) n: y2 K) j4 Y4 n( D  m        if ((drv->bus->probe && drv->probe) ||
+ T, `: |$ j, Z( a5 p            (drv->bus->remove && drv->remove) ||
  R7 y5 c" ^( J            (drv->bus->shutdown && drv->shutdown))
5 ?1 v; K5 T4 q! e$ M& v6 `# [8 `                printk(KERN_WARNING "Driver '%s' needs updating - please use "
$ e* x3 l4 K# X                        "bus_type methods\n", drv->name);! h0 J/ r# |. Q1 m
+ P- ]+ ]: L5 a
        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/
5 k1 L( M& I, _, e9 ?        if (other) {        /*存在则报错*/( B8 h, g8 B* [/ b, k
                put_driver(other);- j5 B" {" y' _) q
                printk(KERN_ERR "Error: Driver '%s' is already registered, "
3 ?% q6 U$ d" C                        "aborting...\n", drv->name);1 c* B# [0 M2 ]/ l$ s1 D
                return -EEXIST;2 b6 \5 r2 Z) z
        }3 x  P/ k4 ?7 K3 e  A& ?

2 V' e) _- U; R' }: M        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/8 e/ K9 N( ]' |: o( _
        if (ret)
0 w" j  c! m9 H                return ret;
2 n" x" G/ Z. c7 l6 \8 M, u- w: c, M        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/
* R8 [. {2 s. V7 s; ?        if (ret)0 i8 Y) X- `8 \7 f( ]* q
                bus_remove_driver(drv);( l* Q& M. R. ~1 `. c
        return ret;& [2 C# T0 M% b: Z3 G9 p) s, g
}3 q' n# A8 g' Q) L* J4 s7 |
EXPORT_SYMBOL_GPL(driver_register);; m" H  P! p$ B
这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。
" I! ~0 u9 k1 `* @! X接下来就分析这两个函数。+ F! d8 a8 H* J& Z2 ~
7.5 driver_find
" ^. D/ e' q  V% V9 n下列代码位于drivers/base/driver.c。
2 r; v0 h- _; v/**1 c" W! ?# e- G' }# l1 a7 \
* driver_find - locate driver on a bus by its name.
6 k3 a) c% _' ]7 q) i * @name: name of the driver.
8 N, e  @" X$ N' C6 ^5 }6 j  x * @bus: bus to scan for the driver.5 x- }4 j' @) T3 q. Z5 o' F
*( d. c. ?% G! s8 Q$ Q1 ?
* Call kset_find_obj() to iterate over list of drivers on* n! v- T- Q6 A' e* q( J
* a bus to find driver by name. Return driver if found.( C+ _: d- E3 M4 f
*
+ Q/ y6 W. u' ]. i! d$ v * Note that kset_find_obj increments driver's reference count.  i5 j% ~0 k+ c5 @5 @( g
*/
& u: {0 [# S; [, r6 h5 A; mstruct device_driver *driver_find(const char *name, struct bus_type *bus)
9 P3 u! |3 r8 u. j) \{
- e, C) e) R) b) w        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
) ]1 s+ i7 T5 a' T0 f/ V. h        struct driver_private *priv;, W# k# G: s* y+ c

' U# \. T, e) K$ ?6 [: I, y        if (k) {
) h0 P3 T5 q9 _& @: C2 s" b6 ]                priv = to_driver(k);# L3 O% S9 M  ~. z. A8 w: _
                return priv->driver;
# s: L* a5 @* {' G# z        }
* {& |+ [1 D6 E8 ~        return NULL;
; u# k' [' y9 j- X# {' y}& a2 H7 L+ L- ~1 h
EXPORT_SYMBOL_GPL(driver_find);
. g. }) W6 q" D$ {) A9 e
0 T: T, v, N" ?5 {/**
; O& }7 e, x$ y4 z7 a: Q * kset_find_obj - search for object in kset.: q) R0 h1 f, u. X9 j/ }
* @kset: kset we're looking in.
; T! U% Z, H: o& ~$ K * @name: object's name.
4 [/ F  e8 H, g: j8 E *
  C: B# n- v. i! q1 B! Y * Lock kset via @kset->subsys, and iterate over @kset->list,
) G  i, E6 i4 N+ b" l * looking for a matching kobject. If matching object is found
7 c$ ~) y. V) X: j$ f/ f * take a reference and return the object.
( [! U' S6 @8 ]3 x- ~ */
4 t' }: i. R4 q: \struct kobject *kset_find_obj(struct kset *kset, const char *name)7 h. {( Y3 {" [0 [+ k7 g; W$ ~- B; D
{
/ a6 t6 r' a1 p        struct kobject *k;
; X6 z. m) g4 u/ Q* ]4 i0 w        struct kobject *ret = NULL;6 m; |0 q) I; v

3 K1 Q6 H+ P7 j% m; {- k6 j        spin_lock(&kset->list_lock);7 }3 y. X' K5 X% X/ w! m7 N! E
        list_for_each_entry(k, &kset->list, entry) {
: G$ o" {% w2 N2 ~% [( r( y                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
, x+ b# g" A% a- }3 k3 X# ?                        ret = kobject_get(k);
# \/ z, M  |7 F. ~& ^5 o5 ?                        break;* E5 W0 c: b- Y
                }2 J& Z# X+ p3 @. x( L5 R$ P
        }
( |6 V' R$ n, l0 @7 i5 i        spin_unlock(&kset->list_lock);
9 r; q8 d3 z' y( j& K        return ret;3 u& I" G) P9 a: B5 X0 F* ]
}
* ?- s0 I' k, m) d0 J6 e2 ]这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。
; t3 Q& p: P+ ]$ l7.6 bus_add_driver# Z' z6 y  X6 a4 A0 ?8 I6 I& Z# ?
下列代码位于drivers/base/bus.c6 Z2 ?1 D5 y" ]# F! c0 _% c7 [

" ~; Z, y! p$ P% L2 q3 R/**
3 N. I8 d: U% P5 J( L * bus_add_driver - Add a driver to the bus.& P# C# ~5 N  n( [: T( L5 L
* @drv: driver.: ~' |: U9 ~5 n5 A- f% m& V7 U
*/7 h8 o3 r  C8 R! h% D
int bus_add_driver(struct device_driver *drv)- P! t4 R8 z5 ?. C7 C) `2 e
{
: U3 L. v5 e9 p7 \$ ~! ]* t# J8 N        struct bus_type *bus;
- S% J& u! O4 U( j, T; v6 e! e        struct driver_private *priv;
# P$ y: L  H5 H% r1 ?        int error = 0;
& H- L# E8 ^; a; L* X
. `9 f5 j3 _+ P; x4 t        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/
2 ]& d) }" B& Q8 ^) @& c        if (!bus)
1 r& Q0 C. V( k2 \$ l                return -EINVAL;
0 d) I! f* `$ V7 G- W: V" c5 N" {2 X' S( c
        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);1 N0 J  e# {' V2 @0 x5 l5 G) d, ?
2 K0 e" n" j+ H$ d1 w8 E
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/+ V  J6 J: Z; j2 {) `4 }- D
        if (!priv) {
6 C0 F. a$ \: r* w: `                error = -ENOMEM;
. \5 o1 T8 x, m% h                goto out_put_bus;0 T4 y* h( B% X! p# y2 g1 h( O
        }
/ P# g/ }5 y2 n+ M4 R- d- P' a        /*初始化内核链表*/
5 q  b+ |* U; P/ U0 ?  d& M/ B/ F) H        klist_init(&priv->klist_devices, NULL, NULL);
0 w" d' Q+ I% W8 Y9 V        /*相互保存*/
9 c. V  H2 Q- r/ i9 y$ x        priv->driver = drv;! f: k, b$ Z8 P. V% x! a8 y
        drv->p = priv;; `- ~* d0 X' }/ x$ p2 ]8 u
        /*设置该kobj属于那个kset*/
; ]3 w9 q6 `4 O        priv->kobj.kset = bus->p->drivers_kset;
* J1 u; E6 b0 s3 g3 [  D, r        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/8 G* z% E4 k. d% c
                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/- k( x2 {$ W1 X% i) @8 o
        if (error)
$ t4 H, x! L( o3 J                goto out_unregister;
2 v, y' _8 q  p1 Z9 V+ G7 L: ^9 D) I5 A4 A( ?+ x& M9 B( B# \
        if (drv->bus->p->drivers_autoprobe) {* U/ D1 t6 G0 Y- N7 B
                error = driver_attach(drv);        /*尝试绑定驱动和设备*/6 }/ z3 z$ O" r. i" R
                if (error)1 p0 j1 h' H8 I7 j
                        goto out_unregister;
; g$ ?8 {8 M! [. u; U% }, r        }; m' {# _2 Z0 o. o
        /*添加该驱动到bus的内核链表中*/; Q& w. u1 a6 \4 O( }4 `$ N, x
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
# n$ G' r+ e; \6 k9 G( c        module_add_driver(drv->owner, drv);/*?????????*/
( ~2 C6 ~; {( Y' K" _( X& T6 }, p
  e3 c; [9 o& c% N1 d        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/
7 l0 J* ?  U9 z2 M) e        error = driver_create_file(drv, &driver_attr_uevent);! a9 t4 Z, _( Y/ C, V/ }( \1 P8 M
        if (error) {" g* J; ^/ a* S& W2 L# c
                printk(KERN_ERR "%s: uevent attr (%s) failed\n",2 G8 s7 F- t- @' T( R
                        __func__, drv->name);
/ _2 ~$ ~$ {, H& e0 ~/ K; B+ W) i        }! n) Y5 O/ k  A: j% @5 y1 B
        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/* C# u# d4 [& [! U1 U) J; y" ^* D: i
        error = driver_add_attrs(bus, drv);* z- N, M6 x' F! u5 |# N& r" A
        if (error) {& D1 R3 w3 V1 W+ m+ |6 T: l# P
                /* How the hell do we get out of this pickle? Give up */
" j+ _9 m; S, C: P+ T                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",# S) v- [( ^( Z+ W
                        __func__, drv->name);
0 ?  y- H* D* ]# L6 P        }
8 N8 ?8 a) h: L. ?* B* m        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/) \9 S) P* ]; E
        error = add_bind_files(drv);
$ j5 t' }' L6 o! J. K1 T% G  i" y        if (error) {6 p0 Z5 t5 U5 M( N' c4 ~
                /* Ditto */
( ~, _6 \6 p; U                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",/ f, @- H/ o6 b5 D" W- [
                        __func__, drv->name);
# ~- I: [, C( F# T( R0 v3 U) ]( J        }
1 Z% ^2 D5 t# Z2 h+ l  e  m        /*通知用户空间???*/
" S2 `7 o* L; L  O3 u        kobject_uevent(&priv->kobj, KOBJ_ADD);  N1 z5 A- j3 @2 a% ]
        return 0;* K9 h" m3 W* B$ J$ r! z3 j
out_unregister:
" P6 h0 C/ d! U) J8 }- z4 }7 f" i        kfree(drv->p);
: _( [  a3 S/ I* i        drv->p = NULL;+ V: ^* v; c6 g; d7 r- c
        kobject_put(&priv->kobj);
; `2 C# N8 ]4 f. v  x! W& ~out_put_bus:
! y* i- P) V) `# p        bus_put(bus);" ^, ^3 ^6 Y4 K( J; v
        return error;
: Z# P: A; g, g9 c( F}
3 x8 Z) P/ n! O在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。
8 O0 H, q0 x' U$ \  d8 c" ?5 M# B7.6.1 kobject_init_and_add7 w; M- ?. F6 F) ~. |
下列代码位于lib/kobject.c。
8 ~5 H! g! c7 C! R/**3 w0 M- c) L" N' q: i
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy% m1 O5 u2 |6 O: K; V, ?0 R( u
* @kobj: pointer to the kobject to initialize" r( h2 T" d  x: Y6 y
* @ktype: pointer to the ktype for this kobject.6 n( @- R2 h# p. C* Z; _! {9 o
* @parent: pointer to the parent of this kobject./ F! d+ s9 e' H$ ]
* @fmt: the name of the kobject.! l( i: p) P& m+ n* z# P
*
  c, j# C. \: N" _ * This function combines the call to kobject_init() and
, Y& }2 c- v! E6 X * kobject_add().  The same type of error handling after a call to9 M1 ~+ T6 C4 {: H: [
* kobject_add() and kobject lifetime rules are the same here.! k3 T+ B) B; g8 H. e# \
*/
8 ^0 a7 P! o* o+ yint kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
2 m& ?. `6 q# C9 g$ @9 U                         struct kobject *parent, const char *fmt, ...)
- `. |' d, k7 A2 _! T{9 d1 w& b8 T* Q" r- D% b+ T: {
        va_list args;
2 a/ _7 b) v  a$ U# I        int retval;: n0 O' O$ ~, s) G! x+ v3 o6 ]

. z0 Q7 K; d" A3 R) p% E' Q9 P* X        kobject_init(kobj, ktype);" o) v7 l- p' u4 b

& W/ B" H5 o4 ^# I( R& _        va_start(args, fmt);
& c9 ~: [- v1 ], N6 n* c- s0 J        retval = kobject_add_varg(kobj, parent, fmt, args);1 L" N- B" `/ ^: t8 F" {
        va_end(args);
# p8 x/ ~$ @) Z- k. g, }3 {4 L
  a) I% }* g! m" k        return retval;
" n" \$ \: J. H! p7 a7 ^& a8 @* l}9 h' M9 L4 Y$ [$ H, y
EXPORT_SYMBOL_GPL(kobject_init_and_add);: i9 p$ B& O, ]  N6 U+ d
该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。5 h, C1 W/ t8 ^$ ?
调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。
$ T" D: ^0 i& {3 Y; O4 {
* k' J# b8 g; m& J, B我们来验证下:
$ r) v$ c. }9 o- w! }
+ p- B5 c8 W# k- L8 I) S- V6 C. y+ a[root@yj423 s3c2410-spi]#pwd+ C2 q$ l6 R- N7 P4 b
/sys/bus/platform/drivers/s3c2410-spi+ _9 d/ u. Q3 Z* g; h
接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。
/ y( K2 {* w1 F5 e+ C' q3 Y; o6 d7 l$ x! c
7.6.2 driver_attach
7 x! A/ Q( J; p6 x下列代码位于drivers/base/dd.c。
! C( ]* j! s9 _6 {* {& b6 Q/**9 ~+ R' Q; \- W' `+ f1 K5 A
* driver_attach - try to bind driver to devices." y+ \: N5 B& I2 B$ w
* @drv: driver.
% ^7 w7 A8 S5 {/ P% \5 J) A$ c( n' D *+ G8 w- ?, X& f1 j3 s0 v4 y& n+ {7 y+ i
* Walk the list of devices that the bus has on it and try to
5 S: I$ O# a5 c' O * match the driver with each one.  If driver_probe_device()
& Z# e* n# s% B- c8 t8 W0 Y8 D4 r% Y: B * returns 0 and the @dev->driver is set, we've found a
# R; d. E4 u! O+ w- X; s * compatible pair.& Q) |0 O  X6 ~
*/
, H0 `! O3 y/ S, c" kint driver_attach(struct device_driver *drv)$ s) g0 p# D: g: O$ M9 Y. T& d
{
) D, H: ?+ F5 N        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);  j% q3 l/ y4 M3 f8 n
}; O; g  j* [* p( X/ f/ S4 B& m) O0 s3 ?
EXPORT_SYMBOL_GPL(driver_attach);( P& ]- P5 ~$ S3 o, V) \% x% b
该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。
3 \0 I- p, A' N, r1 N& W这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。, u! |$ K3 V4 v' @

, a  C! [* {/ n  B. E" p7 m/**
9 ~7 c0 c- s8 f7 z5 c+ R * bus_for_each_dev - device iterator.
3 c9 o9 A" I# [1 @ * @bus: bus type.
2 @' ^; q8 n1 q * @start: device to start iterating from.- c, ?' L; k) q4 x
* @data: data for the callback.* Y. C  p5 X5 N; w$ x, a
* @fn: function to be called for each device.: n  I  ~& B3 [" x, f" [
*! n4 U1 ~0 M) w; x, N
* Iterate over @bus's list of devices, and call @fn for each,
3 |6 ~& ?8 u: G: ]1 d- {  Y * passing it @data. If @start is not NULL, we use that device to" i- f- @; x6 v1 `5 P) _) C1 `
* begin iterating from.2 V$ i2 x6 F+ }
*
/ N( l. R' h& J6 Y, k- a; o * We check the return of @fn each time. If it returns anything
& Q0 L+ [. l2 e. t- ~7 V * other than 0, we break out and return that value.
3 [! a, N" ~( E  O5 I *- O6 \( p8 r, |7 r/ I4 k
* NOTE: The device that returns a non-zero value is not retained
/ }" q. M% j: i) ^* i * in any way, nor is its refcount incremented. If the caller needs
3 v- j/ [! q9 P# N/ n * to retain this data, it should do, and increment the reference6 m+ o" n3 Y( W1 W: z* V4 H9 |
* count in the supplied callback.- ~. C6 t; Q0 z- Z/ V. s: }
*/
0 A8 [" q" p3 c# V, rint bus_for_each_dev(struct bus_type *bus, struct device *start,
$ {4 \1 j6 W/ @7 n9 b8 \                     void *data, int (*fn)(struct device *, void *))  {* X# r8 ]% E# }. a
{& P* b) M0 T3 ]; n+ Y7 X- L. L2 l! k$ Q
        struct klist_iter i;7 O# ~  H9 ]- o4 D  V9 E
        struct device *dev;
1 @: e0 U4 {, C% J( p        int error = 0;
# `7 p5 D8 Y6 S; P3 v( S! J$ L) J) H
        if (!bus)# f, G; @- S3 c7 t# q% K
                return -EINVAL;
5 Y8 n* h1 z# j( J) v' m- V- Z% ?# X* k9 M# v, }9 h( t$ Y5 E% m
        klist_iter_init_node(&bus->p->klist_devices, &i,
! o3 a# V5 b  S; l1 {                             (start ? &start->p->knode_bus : NULL));
; b; Y; j+ S6 k/ H, r        while ((dev = next_device(&i)) && !error)
4 Z2 j7 L( l; W, ?                error = fn(dev, data);& O  W0 f& l, Y! x7 J, R3 Z1 ?0 S
        klist_iter_exit(&i);
+ }. a$ N5 E2 x" u        return error;6 E. o. y0 S! w9 O% t0 _5 [" C
}
. {1 w  L# |: pEXPORT_SYMBOL_GPL(bus_for_each_dev);9 \& n6 R9 Q5 R* p
通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。5 X( q& {7 U+ y: m: t9 U; F
static int __driver_attach(struct device *dev, void *data)! |' x  T5 V, g) z
{
3 |1 H- i% d) Y2 h& y7 u        struct device_driver *drv = data;
+ k% W7 C6 E5 O, l: v9 P0 ^' b7 p3 N0 J' H9 P7 k1 `
        /*
; A5 h2 ?$ z6 r" _2 l9 f         * Lock device and try to bind to it. We drop the error! `! ]/ y5 [* a! s
         * here and always return 0, because we need to keep trying; Q2 o2 p7 c2 z/ I5 C, c$ M: D6 D
         * to bind to devices and some drivers will return an error+ P4 ?  l- X9 d) V9 p' H
         * simply if it didn't support the device.  N( s& y8 @1 I- E  d
         *! `. S* r" s# T: ]: x
         * driver_probe_device() will spit a warning if there1 ^$ J4 y! u- g/ O* C
         * is an error.
: n/ K; {' s& }         */
, d& l7 z) v0 B9 Y* i% N. ?
3 ]0 F4 k2 x( D( ^& ~- w3 \  n7 S        if (!driver_match_device(drv, dev)): c  k4 z3 N1 J% l7 Q7 L! y
                return 0;' _' E9 B$ P# k, I

) R) K$ @, s" v6 @2 N        if (dev->parent)        /* Needed for USB */, R6 h8 v3 R0 ]  R
                down(&dev->parent->sem);
5 Q$ W+ \& ]4 f! m2 }        down(&dev->sem);
; L, v; W5 v  T9 v$ ?1 x( O        if (!dev->driver)
! u' m9 ?; p4 T1 Q                driver_probe_device(drv, dev);
1 P% B6 ]$ p4 x0 m' {/ ~) o        up(&dev->sem);
+ }$ n+ `2 d# H- P5 n        if (dev->parent)
! D$ t3 U& G3 Q, }7 j/ N: O, b1 z                up(&dev->parent->sem);
( x9 |) V# B  f. c$ s
7 ], U% f- N& U* i        return 0;; I# x6 o9 |+ e) U' Q& d3 k
}
! b. v" F' v$ T6 I. O% |6 C% ?首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:( I' q" ~7 Y# J: H4 T  V
static inline int driver_match_device(struct device_driver *drv,
+ O; L, F' u% S# S1 C$ {# j                                      struct device *dev)( g" ?- e# ~# e/ ?: V
{
* Q5 g- s+ F# m: i$ Z  h        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
% |9 F4 ?8 V# T6 F) g' u) k}
: S& U+ ?& B+ I: l6 E: ^2 Y- S% T+ y% P
' y/ g# A* Z% T* x* ~$ [- Y这里直接调用了platform总线的match方法,我们来看下这个方法。
; W# \" O- D2 h/**
7 F- J5 I+ k0 ^- w- H, o1 Z1 z4 J, l * platform_match - bind platform device to platform driver.
% H! T% ~6 m# x9 a* x" o: B * @dev: device.4 U" ~1 u/ p$ j: D
* @drv: driver.
  ^1 i+ _. m+ ?9 Y! B! N" { *
) a0 \& v2 ^5 ?: g5 Q* o; G, R * Platform device IDs are assumed to be encoded like this:8 {. [# R4 ^! L
* "<name><instance>", where <name> is a short description of the type of
$ u! P7 z  f+ c% G$ a4 ?% ^. C3 D * device, like "pci" or "floppy", and <instance> is the enumerated; R" k" {9 G* n
* instance of the device, like '0' or '42'.  Driver IDs are simply
2 a# j5 m  l. I" u3 t * "<name>".  So, extract the <name> from the platform_device structure,
0 X8 l8 I8 Z' ^: w* P) Z * and compare it against the name of the driver. Return whether they match, E5 a1 B# F* s
* or not.
! H/ T6 B6 m; Y3 u6 u */  K1 A. }0 c; o1 R, E( P
static int platform_match(struct device *dev, struct device_driver *drv)
' N/ w# {4 y7 P) _8 i* k{
# K" m( K4 a; |8 ]  g# v        struct platform_device *pdev = to_platform_device(dev);
; p- I, T+ ~, @% I        struct platform_driver *pdrv = to_platform_driver(drv);2 R9 F* L, F* g: h

* `& R; k1 H' r9 g3 F$ m        /* match against the id table first */
* V2 s' }+ J) D/ P0 H; g; j$ k        if (pdrv->id_table): |) s/ T- Y5 |4 E( O, m
                return platform_match_id(pdrv->id_table, pdev) != NULL;
4 D. y1 x$ N" D# w  x  p$ d" @$ G# p
        /* fall-back to driver name match */
$ M# X- l/ y( e: c/ u) T        return (strcmp(pdev->name, drv->name) == 0);8 L* O& H3 J. Q* C  j# u3 r
}3 J. O/ h' t7 u7 i8 |
该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。  R  X: c$ c7 j$ x8 J8 }! S# ?3 e
在本例中两者同为s3c2410-spi。因此匹配完成,返回1。
" `* p  Q! j) B- ^; Q& Q5 u, C1 e4 w2 m8 u
返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:
6 d4 n2 @) b) E4 V  t
* d0 l$ C. a# I# ?5 A3 c/**7 ]5 U& V  C6 K0 t6 ?2 N
* driver_probe_device - attempt to bind device & driver together* I& ~. r* C. m0 |5 l
* @drv: driver to bind a device to
5 ^( @8 _4 N* K8 B7 Y4 J& O * @dev: device to try to bind to the driver
2 {7 X  r, Y5 I9 u6 u( ] *
6 n2 W+ e4 E) ?. X * This function returns -ENODEV if the device is not registered,3 K' I4 `! E* O2 N8 ?8 S& I
* 1 if the device is bound sucessfully and 0 otherwise.
! g" Y5 S& m- t1 B; ?9 e1 e */ b5 r$ o6 ?) i$ A8 E& e) {/ K
* This function must be called with @dev->sem held.  When called for a" H5 P, C* e, a
* USB interface, @dev->parent->sem must be held as well./ y' y6 h$ F1 G
*/- X' A. C0 Z. h3 m8 V
int driver_probe_device(struct device_driver *drv, struct device *dev)
8 A+ v) _( v3 c+ b5 O{0 l# S4 _/ p9 e( g; w$ R' l
        int ret = 0;9 @/ e, h  u' B+ r5 ?3 k6 }: S

. R& W9 A* M. }9 F        if (!device_is_registered(dev)): {8 {4 Q  i/ j/ M. S3 o0 m
                return -ENODEV;2 s0 ^4 t5 o2 k
/ z+ a" x0 k+ G0 [
        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",7 s. k  H, {* s4 T* U4 ?' @, U7 W
                 drv->bus->name, __func__, dev_name(dev), drv->name);
1 F+ g( q1 g# n! N' K) R
0 V9 h$ K0 Q0 c& w9 p        ret = really_probe(dev, drv);, A( F6 {; t$ V1 b; I
  e- r" z9 B  \( G
        return ret;
# U: ]4 I5 \) t9 M1 K}& z  y2 `4 J$ g- Z, C
static inline int device_is_registered(struct device *dev)
" j7 a; z2 c8 p" u( i{+ {, q5 d0 s$ i. p' V, w$ Z3 M
    return dev->kobj.state_in_sysfs;( ^) x1 X# v7 ^5 Z* v
}
* L' I5 B: K. v该函数将调用really_probe来绑定设备和它的驱动。
( k2 u  ^* ?( m/ _; G& x- ]static int really_probe(struct device *dev, struct device_driver *drv)
1 v  u! B. |" C2 A" `4 g1 F{3 l' X$ F% o9 l" Q; M: a. O
        int ret = 0;3 I/ j: I$ A1 |: @0 k
( G& d# X9 v  D0 t3 c
        atomic_inc(&probe_count);
/ R9 |6 Q& E  S- \' l        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
- s* ?9 p- H2 a9 `/ ?! `                 drv->bus->name, __func__, drv->name, dev_name(dev));
( p# ]# h5 i9 c        WARN_ON(!list_empty(&dev->devres_head));  s' M3 V6 S! e) y; H
: B/ ^; b0 |6 u
        dev->driver = drv;( T  D  b+ `/ H7 A) \  W8 W
        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/
4 m" P$ g4 f2 L+ y  e1 d                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",! y" N0 t. t1 s9 \) B
                        __func__, dev_name(dev));1 E6 }% K" N  X. Y
                goto probe_failed;
; T4 z0 j4 T" ~0 p8 c" Q  A( Y9 N. F        }
& Z6 C1 W. |4 ?+ y# y- [. P2 S
+ d9 L6 D$ [- p, P! u        if (dev->bus->probe) {( Q- k1 I% s7 M# n( b
                ret = dev->bus->probe(dev);/*调用总线的probe方法*/( @2 R( j6 S, L# F) Z
                if (ret)5 K" v  l( i! p- I6 p
                        goto probe_failed;
3 S% s2 Z* j4 ]% N! ~        } else if (drv->probe) {$ \* V0 G* n) [% y
                ret = drv->probe(dev);        /*调用驱动的probe方法*/9 j' v. m+ }/ t0 N7 J' U5 I
                if (ret)
" r8 w; a# b. E& d  ?2 J  u5 `' x                        goto probe_failed;, ]* T+ @. F/ }8 X8 h5 L7 _
        }( K) P% l+ w7 n1 m6 M, Y

& K- ^/ u2 |. s7 e        driver_bound(dev);              /*绑定设备和驱动*/
* o+ G- m, n) w1 D        ret = 1;
, r- _" h( b; s! w3 t, g2 H0 C        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",8 P) _" J) W+ \5 Z
                 drv->bus->name, __func__, dev_name(dev), drv->name);* o- D$ j: d) T4 ?  h, O% J' A6 V
        goto done;
) `" G, W& M' m8 }( ?
2 c8 E5 ^" ?% L6 w/ Wprobe_failed:) G- w( S4 ?/ \5 v, v
        devres_release_all(dev);
9 r" c# N" q$ o6 d  n2 c0 S        driver_sysfs_remove(dev);
! f* c) q1 O. ?9 A/ d' D: l) t        dev->driver = NULL;
" W, p* x) y0 p. j+ k! P9 ~+ w
7 O0 A+ R+ T  e: k4 I- _4 m        if (ret != -ENODEV && ret != -ENXIO) {4 B! d2 s" c- r- t: s
                /* driver matched but the probe failed */
* l0 x8 G& {- z6 |: m7 s1 t                printk(KERN_WARNING
3 x1 q- u, z  s5 h) |8 s                       "%s: probe of %s failed with error %d\n",1 W4 j1 E+ d# H9 y6 ?  F
                       drv->name, dev_name(dev), ret);
5 f! U; ?" H9 l. K) R: {        }
3 T. V' A$ H. A5 v9 R  c. X        /*0 ^0 E. z3 R0 {" H
         * Ignore errors returned by ->probe so that the next driver can try. o0 }( p. z5 k3 J
         * its luck.
) G4 C: E# C8 t/ ^  }7 l         */, {7 V5 a* d" X9 |9 v
        ret = 0;
( U: S7 H" ?6 rdone:  Y7 s2 F% V- y  X
        atomic_dec(&probe_count);
5 l8 W7 Y4 v! a; J; s        wake_up(&probe_waitqueue);
" f. U; ?, F0 Q" J) x        return ret;; g6 p6 K; M1 g- y
}9 C8 [8 m9 @; P

/ E7 d) y4 Q- F  a在这个函数中调用4个函数。
2 e) p9 ~& k0 N# h7 G8 f
: Y, n) @* U$ w) R第一个函数driver_sysfs_add将更新sysfs。
8 g8 d6 r$ @5 b; {( a- `6 b' U0 D: z
static int driver_sysfs_add(struct device *dev)
* b# Y% Y/ d  J{' M8 n0 f% \3 ?
        int ret;
) C' l- h) w7 y        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
- O, k" e+ n6 I* L/ m' R) E% [) v- e           链接指向/sys/devices/platform/XXX */
/ G4 S0 j0 n" A9 p& t6 j        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
& u' R! u1 U* x% W7 d                          kobject_name(&dev->kobj));
' {; }8 S) H  y6 b% P        if (ret == 0) {
8 n" B- H3 v* z4 A                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,) T2 @* v  a* P. E2 a
                  指向/sys/bus/xxx/drivers目录下的某个目录*/0 }5 _1 r' t- F
                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
. k/ `" W4 w0 b1 C6 ~                                        "driver");# n) W2 ]) G: G3 v3 y8 N' [7 b+ l
                if (ret)) ]: T% c6 M, ~/ c" U( j
                        sysfs_remove_link(&dev->driver->p->kobj,+ L0 }7 h! b8 }3 s' M! j1 f
                                        kobject_name(&dev->kobj));
; J2 ^- h+ I( p& W        }6 P2 ~/ E# J4 b
        return ret;
3 }$ Q/ [4 Z! R1 v9 F. D}
* @0 x; m, I9 y6 u9 I) {" u5 P5 M: ]( d$ }7 R# m1 A# d" h
执行完以后,建立了两个链接。
- n. y0 ^" ]% ^$ E0 _在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0$ o7 h7 V& l) k$ i; ?, U& v
在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。
( ?$ {7 s6 w& i# H9 T( v% C/ h5 e( m' U这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。
( a+ N6 K6 G  N" }, E3 T! D6 {' b; F  S' k/ `% Q! e4 I( t
[root@yj423 s3c2410-spi]#pwd9 I3 @/ B! ?# [
/sys/bus/platform/drivers/s3c2410-spi: T. t1 R* ?- i( e1 M3 Y% \
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0
' X6 I$ p2 f  D- |3 g1 j9 ^lrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.0
  b9 ?7 F0 V8 ~5 A6 [* `9 {! D[root@yj423 s3c2410-spi.0]#pwd
/ {6 s, C. j  g( ?# O; m( `5 u- j/sys/devices/platform/s3c2410-spi.02 e  ?3 ~9 n: v" {8 `
[root@yj423 s3c2410-spi.0]#ll driver: i7 e4 Y/ d" O
lrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi
+ y- G  ^( R8 e- V, z5 ?, I
2 ^4 [. ]7 S; k; X1 \3 }第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。
- Q* H0 |5 N# s3 S; C# A9 i9 ?) o0 {9 J
第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。
4 ~4 `+ o$ d' I- g9 w& k7 d' o
  `" W; o: L  ], `" [5 e5 k第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。
' K5 c* O$ `+ Q, t% C$ O& i
, }, ^; e3 p$ l! H# ]% l& estatic void driver_bound(struct device *dev)1 V8 K' G7 F6 M2 b
{: J: D  L5 A1 F/ R
        if (klist_node_attached(&dev->p->knode_driver)) {
( W. j; [; \5 E' x# L                printk(KERN_WARNING "%s: device %s already bound\n",
6 h) h* P; v7 R' Z6 a                        __func__, kobject_name(&dev->kobj));2 I( H7 \: v# s0 }8 M
                return;
4 u) S' d8 r2 Y        }
) e; c  N; `0 }( P
' x+ o% c0 i: Y# ]        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),0 E3 A1 m5 i4 H; @
                 __func__, dev->driver->name);
4 f' d! m9 c% @; Z% A" x; [" c5 C: Q* \9 ~
        if (dev->bus)
" k4 [$ q* k! O9 `                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
, i# @) y4 K6 Y' ^/ o8 @8 h                                             BUS_NOTIFY_BOUND_DRIVER, dev);. V) R  h3 |/ D9 U4 v/ m

% K- Z' l& O' x* {5 ~7 j3 R        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);0 Y. e2 v& F7 U
}
" f, c0 K; q  O5 L6 |8 O/ A其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。2 D8 O1 W  N5 i9 M; i
至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。
" k, }0 Q9 u& p0 C! A2 A0 C0 b
1 P( d* u  t+ l! U在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。# h2 `; D' t: `5 r' M/ P
4 l" Y" C9 f) Y1 B$ b/ q2 X
首先,将驱动添加到总线的驱动列表中。4 _: \+ ^; L0 v, z) e) m# L8 T
接着,如果定义了驱动属性文件,则创建。# x. z( r$ C/ s  o
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。: E( b9 k9 I: J) r
, ]! Q$ s$ S; f6 n  Z
我们来验证下:" k) t- n' b1 R

/ q5 A) _) [# p6 D0 j2 ]1 J4 L[root@yj423 s3c2410-spi]#pwd
5 l) Q4 _( H% o/sys/bus/platform/drivers/s3c2410-spi2 e) E( i$ u3 c5 v5 `
[root@yj423 s3c2410-spi]#ls! O( ?( o* _6 w6 _+ @9 S7 r
bind           s3c2410-spi.0  uevent         unbind
' D$ h9 q2 P7 r: W+ I8 K7.7 小结
5 }' }2 n, b9 a6 W( [6 E在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。  X- _" v: ^, L9 T" K! Y* D6 F
3 s! q6 D8 u  k' k8 E
同时,还更新了链表的指向,在内核中体现了同样的关系。
8 C( ]' N, g2 h! |# r- B( L$ ?7 p( I8 _+ n* t8 e
最后以platform driver的注册过程结束本章。, V' c3 W- C5 R8 U8 Q
! `0 G2 ]* C: R* Z4 I: ]$ z& T* G4 F

* j, }8 x& j" {$ ?4 \, o  B; w( M6 r; U4 ^' ], z
8. sysfs底层函数# j1 Y2 q, H; Z/ J' g
下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。
3 [) I, p+ q6 U) N+ J; x" L5 v5 F在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。1 E* {* m) C! \9 G$ h4 ^
& W' S3 P! R. w+ R
8.1 注册sysfs文件系统
3 y3 G8 y" |1 r& n& bsysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。
( j7 @% D6 G1 @" Fstart_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。$ @0 w$ ?! _: q4 J$ p. O

# i9 m! J; ]& f+ [) L9 g3 Q2 ?( ^* g. ~. `int __init sysfs_init(void)7 ^4 x+ s* d$ E6 S2 o: x' ]
{
1 p0 I) G7 f( D9 B  Z+ a1 o        int err = -ENOMEM;
4 L1 \0 {3 Y3 v7 B$ \" ?  ~        /*建立cache,名字为sysfs_dir_cache*/
# W& R7 V  u4 t% K0 t" g        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
/ @$ |6 s8 J" _2 l) v9 W* t  X5 C                                              sizeof(struct sysfs_dirent),
5 }+ ~" Q; {  T' S                                              0, 0, NULL);; Y/ l$ B8 V- f& K2 b0 L  D- j- F
        if (!sysfs_dir_cachep)
/ G/ M) u( ?- p" V; X1 m8 l                goto out;
) O( ~4 }# r9 C( C! f- D
9 A0 \+ ?; [4 D8 N- Z  j        err = sysfs_inode_init();& f4 M$ p8 h9 ?) K) a; a7 f' y
        if (err)
3 O3 I4 j  y! Y                goto out_err;
: x% j; B3 R. [0 l( X- x/ I        /*注册文件系统*/) s/ t0 M. r/ l% R
        err = register_filesystem(&sysfs_fs_type);
; j2 n% y5 {) f# e+ F        if (!err) {
0 z3 B9 G2 c. {) j0 x1 M) l( h- ?                /*注册成功,加载文件系统*/0 Z  ]# g# Q3 ^+ M3 z, r6 o
                sysfs_mount = kern_mount(&sysfs_fs_type);# V5 i% \- K  o, w) h
                if (IS_ERR(sysfs_mount)) {
/ j$ [; A6 k) e* Y! V) I  l  U                        printk(KERN_ERR "sysfs: could not mount!\n");4 y# [* G/ r3 r5 i
                        err = PTR_ERR(sysfs_mount);
7 k& l% K5 O0 x, ^5 M& H- h; G                        sysfs_mount = NULL;
$ g, I; P( R  N                        unregister_filesystem(&sysfs_fs_type);
; X4 C8 |- E# f( g, X                        goto out_err;
7 A. `% ^0 _* P6 k$ \                }/ X: C) x8 T7 O
        } else
4 V6 S* J0 s( {                goto out_err;4 x; M" S) O( K$ _
out:  t; }, v3 T1 K, q  Q/ s
        return err;
' b6 r, j+ _) E- d% E" b6 Eout_err:7 c$ Q+ y! J2 Y1 L
        kmem_cache_destroy(sysfs_dir_cachep);6 I( w! o8 @8 I  f  |" Q' d4 h4 L  Z" V
        sysfs_dir_cachep = NULL;6 k3 X4 j/ I  G; q
        goto out;$ a* `% @* t+ A* n7 @6 a- w
}
( R% u+ \& }" l5 @4 u% \* t  Y- [! V1 y8 O
static struct file_system_type sysfs_fs_type = {
' Q4 H* ~9 _3 i  ^  J    .name        = "sysfs",
7 w: @9 ~2 ~# {+ o    .get_sb        = sysfs_get_sb,) L: l5 ~9 m* w1 {
    .kill_sb    = kill_anon_super,5 }% k8 i0 K# ~
};
3 \$ t- Z. Q; P7 q6 O- D3 D1 X% Q. L5 B5 b) R  g( @8 e- N
8.1.1 register_filesystem7 a: I( a3 I  l
下列代码位于fs/filesystems.c。. y' C: d" f- a% {# Z1 m8 N) E
/**7 u7 O  j8 v  d, j- Z4 S5 x
*        register_filesystem - register a new filesystem) o7 @- u- f1 h
*        @fs: the file system structure
: R! o+ R* v0 z( S7 b, X7 \2 n. e *
$ Z  Z) @+ b- t& r0 A9 l *        Adds the file system passed to the list of file systems the kernel' t1 i% j+ z/ u3 t
*        is aware of for mount and other syscalls. Returns 0 on success," |1 D0 n( R0 [$ ?7 \; j
*        or a negative errno code on an error.$ E, l3 G" n7 Q+ a9 M" I
*: ~* E: Z: h2 ?* H9 m5 W) n
*        The &struct file_system_type that is passed is linked into the kernel 2 ?6 B( |7 N* H  X
*        structures and must not be freed until the file system has been
: q) n1 |% D: @$ _: i+ h; D *        unregistered.
0 c) y3 R; a; V; H2 q' S; q5 S */
9 I$ f7 l/ A: \+ A6 L% _0 p9 y/ {$ ]3 z. I
int register_filesystem(struct file_system_type * fs)
* Q, K6 }) t+ k. j% h2 q{! ^. ]6 p; o" S. U+ A
        int res = 0;
$ O' o) W+ m( [" |7 C6 x- x$ j  {        struct file_system_type ** p;7 Y. u3 A2 ^- a& Q  d3 A

4 K  F7 _# v: z$ t' R        BUG_ON(strchr(fs->name, '.'));
" \$ T* _4 B( @8 |        if (fs->next); c1 l6 z9 L+ i- ]5 Q" A1 F
                return -EBUSY;
0 D% M+ v4 \' @' O        INIT_LIST_HEAD(&fs->fs_supers);/ l  t6 }' u" H
        write_lock(&file_systems_lock);
( Q7 x6 K) Q+ f4 {        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/
5 Z; h' L; H/ q9 _8 U5 X( M        if (*p)
9 E6 z: S/ Q5 w( h5 i5 b                res = -EBUSY;        /*该文件系统已存在,返回error*/
( `5 N* |/ T" U  Q' b        else5 b( i' \" ~* ]9 d$ Q$ M
                *p = fs;                /*将新的文件系统加入到链表中*/
+ y: h$ Z4 S$ j) t        write_unlock(&file_systems_lock);
. [& y8 {7 P7 y" q  b9 K$ z3 `        return res;. Q& C; T' a& z, V( f( n- S, D
}% L* x0 e. }  t, l- C) D0 C0 S
static struct file_system_type **find_filesystem(const char *name, unsigned len)1 A/ F* L: U% R6 G
{
  t& ~' _9 n- p' I        struct file_system_type **p;1 @  @7 n/ P, m, n+ ]
        for (p=&file_systems; *p; p=&(*p)->next). M" T% r6 `5 ~$ z; _% E, R8 b
                if (strlen((*p)->name) == len &&
* E( I, J  P% y4 m                    strncmp((*p)->name, name, len) == 0)  b, d  w  K. B3 F( S' J) n
                        break;
+ {( ?0 E8 K! _$ f- s! N1 i        return p;
; ^* ^! G: I9 y2 P6 F, {5 u}  g( \  s% M' Q5 u  t' q: @# i' ?! d! o
该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。
' n+ `  m$ J" |! v如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
8 b+ J% n( k1 y$ C. U3 W
% d3 o6 z. C( i7 N; d该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。
- K7 B0 u3 O3 N+ g
) }  Y; m; |1 c. @" M- u8.1.2 kern_mount函数; t) ^. S. v3 ]( _  a4 l9 G
下列代码位于include/linux/fs.h
2 d; `6 t, X, @7 G# @- B7 e# F; B0 L( \0 e1 n
#define kern_mount(type) kern_mount_data(type, NULL)2 }) k7 s# A! H2 ~8 v; v! ?
下列代码位于fs/sysfs/mount.c9 Q8 V1 d0 R$ R0 T8 B* ?
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)6 W  P! X) D9 D4 P7 v) Z$ N/ e: L
{
3 T* O; j; {1 M, y  m    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
9 F# {+ z5 E: M) L- H1 y! Y0 u}4 b9 R; e' F! c( @! }. m% P6 ~- ~
) |. v( J3 P# p1 q6 Y5 P. T, f
EXPORT_SYMBOL_GPL(kern_mount_data);
5 M9 P( w6 ^. ]- B# i) L* bkern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:
0 u8 J8 M6 i( H9 _6 o3 [$ j, U8 N$ Q5 K* \
struct vfsmount *
7 w6 Y, h. n  Wvfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
& r2 R# U# `' D5 y{
) b* V6 V, w+ f! X( s3 O        struct vfsmount *mnt;7 ]' z6 {- x6 Y3 W
        char *secdata = NULL;, b  I# m' ^6 d) H8 ]; O
        int error;' k( S5 L" O0 R6 w
* m1 p5 H* m7 m# j* V
        if (!type)( y5 F/ r% Q# f7 L/ x
                return ERR_PTR(-ENODEV);8 C1 x* D; c& \9 r

  L+ f) o* p, j; |8 ^        error = -ENOMEM;$ J8 C2 h! D% a- e8 B4 U
        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/! N$ a6 O% w3 n2 B
        if (!mnt)9 m! y% ^7 ]+ y% v
                goto out;; T& j7 J/ b( g

) W: }" |  x; v$ }# n        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
6 Q; p2 C6 I' h& s# w" Y                secdata = alloc_secdata();/ g, ~' D4 d0 G& X* Y
                if (!secdata)
0 i# g  z  ~1 h+ r' ]$ S                        goto out_mnt;
/ |( ~4 R" a9 A, Z+ M! h( }' f+ Y6 {5 i) W- e
                error = security_sb_copy_data(data, secdata);( z0 x! b0 N: y
                if (error)
3 c* L1 w" n3 G: F' y+ z' d) ~2 @: |8 X                        goto out_free_secdata;
9 E/ \- X' @/ x% e; z        }9 S4 W& R2 t4 n# l: P' k: E- X. I
        /*get_sb方法,分配superblock对象,并初始化*/
8 @4 {. S: `8 P2 ]9 e, [* }8 w. V* ?        error = type->get_sb(type, flags, name, data, mnt);4 V6 f$ \8 ^! p8 S9 u5 A& \
        if (error < 0)3 c# |' ?$ p8 E" @$ _
                goto out_free_secdata;& ?$ n; S9 j# [6 \/ H5 ?
        BUG_ON(!mnt->mnt_sb);, F" K6 _+ f2 W3 H
, e8 a6 Y1 H/ Q
        error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
* V* H, s5 @: {6 n- W  {) A         if (error): P+ e" a* G+ M" V; o' V( w3 R
                goto out_sb;# Z# N( y- f7 v) ]/ J* F/ u
! f1 K. z- o" u: C5 P
        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/) ^- ?! y/ w: c- O
        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/
6 a9 E8 h0 y$ Q. ?  A        up_write(&mnt->mnt_sb->s_umount);/ Y( C. t, a" A* n& d/ c  p& p1 @3 _
        free_secdata(secdata);, A* _: s; B# q7 `8 L
        return mnt;
( O# p! p7 \/ U( ?- tout_sb:8 W) h  B1 Q+ l. p# j7 c# E
        dput(mnt->mnt_root);$ F1 Z% J- k  w. O
        deactivate_locked_super(mnt->mnt_sb);
+ I2 G; j# k" C% B! C* T8 oout_free_secdata:
) B$ R* F3 ^7 T+ c8 o        free_secdata(secdata);
3 L# ~3 }3 Z& v  ^8 rout_mnt:
( m* B6 H, R" I$ o/ ?1 }        free_vfsmnt(mnt);
3 u2 h/ }6 `& i5 `7 Z% y2 r$ k# j" Dout:( P- L0 w0 X6 i2 R
        return ERR_PTR(error);- L7 Y& }7 M0 z3 y* A( k
}
$ z: j8 ^$ L4 Y. X' r( b4 u6 q* |, h  A
该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。8 O3 D7 v- e- {3 [+ }2 \1 U
下列函数位于fs/super.c
8 U9 D- R" a: I1 }struct vfsmount *alloc_vfsmnt(const char *name), _- X1 o8 ~  G$ {8 C6 V, u; [: w
{
  s  H% }: }  G0 Z: E7 X        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
; R9 E. t. }9 `& \        if (mnt) {
1 J6 H* i+ d* F  w5 B; `2 Y                int err;9 Y1 e2 L+ O5 I# Q2 `8 K
1 e  n5 K. [8 N
                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/8 Z) k+ R2 k, S
                if (err)
0 \7 P+ ?8 b% [/ S( b7 H( O* ~( e9 l2 m                        goto out_free_cache;8 p5 }* J/ n# w* D

2 J5 L' w1 P$ Y/ j% H' y4 P                if (name) {: n% h* i+ W3 f7 P
                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
3 Y: g' z' ^* {                        if (!mnt->mnt_devname)' Q/ |8 P2 Z/ m$ Z0 \; i. X
                                goto out_free_id;9 g5 b$ F$ C( t' T5 G9 ^. q% R! u" O
                }* t* I; ?& S2 ]! Z2 c

/ V( ^6 {  F, g1 u7 T                atomic_set(&mnt->mnt_count, 1);+ O+ ]: A9 Q& W) v
                INIT_LIST_HEAD(&mnt->mnt_hash);
$ [# ?. Q9 Z" i7 F! J% [& o                INIT_LIST_HEAD(&mnt->mnt_child);: K; j0 R: g0 H
                INIT_LIST_HEAD(&mnt->mnt_mounts);! [& `, I1 k4 w( F' n! y
                INIT_LIST_HEAD(&mnt->mnt_list);! i' L" x' h0 X* p
                INIT_LIST_HEAD(&mnt->mnt_expire);8 k! t) R  E  ~) K$ ?! f, d
                INIT_LIST_HEAD(&mnt->mnt_share);1 z, P" q7 N- A0 R( `! ?7 w4 i
                INIT_LIST_HEAD(&mnt->mnt_slave_list);
7 @) M0 p( L- {+ w7 X; j7 t+ Q8 e                INIT_LIST_HEAD(&mnt->mnt_slave);9 D* G9 t2 l4 a8 p' I, n
                atomic_set(&mnt->__mnt_writers, 0);% p8 Z: h% p5 ^  T- @  [4 h. U
        }
5 f$ ?2 r! y' L# H        return mnt;& a/ d2 z7 _: C) Y* g. M
6 ~& U3 w+ A& s$ s& D; `
out_free_id:
7 T( ^9 `3 ], q8 z$ _5 t        mnt_free_id(mnt);
% E2 U4 B+ K& `out_free_cache:
% \2 i9 s; U0 x3 H1 S        kmem_cache_free(mnt_cache, mnt);) h/ f$ o1 _% C. ]) ~! K
        return NULL;' Y$ N! n5 l7 {
}1 o1 U2 L% R1 w' t6 Z0 Z
分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:- i0 W* Y4 X) J8 W
下列函数位于fs/sysfs/mount.c。" q' W+ G$ @; _* C2 x% U2 `
static int sysfs_get_sb(struct file_system_type *fs_type,, M7 w) d* C. Y. x2 S8 `  q
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)) E5 Z) o7 N4 ?; u
{* F* ]8 Y: ^( X. V, U2 ~% \. X
        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);+ q" ]- c( V7 D2 E& J1 e: q, W- F3 \
}% f! ~5 A2 S$ q# i; y* b
这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。
" b! j1 f" P1 V. l该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。
" C  W9 [4 _- q) e# T
( o7 F4 n9 E* Y7 D1 Z2 i- T  ^& D该函数的执行过程相当复杂,在下一节单独讲述。
& x0 q; T  _$ \# O
: i, A0 `0 w: }8.2 get_sb_single函数8 M& l4 b/ ]6 O, B' `! `4 |# k4 @
下列函数位于fs/sysfs/mount.c。: K. w* ?* Z9 g; Q

* Y& }8 g- W# _% K" x, gint get_sb_single(struct file_system_type *fs_type,
% T) X% `" f/ U" ^6 t; Z+ o        int flags, void *data,
) S; j6 V8 |; z$ q3 p        int (*fill_super)(struct super_block *, void *, int),$ j# O5 m9 {6 @- J  L
        struct vfsmount *mnt)
) g. d1 f) S+ M{+ Q" ^9 G: |# ~# O
        struct super_block *s;
" R/ s$ @. w+ x) B2 W6 s: ~, C        int error;
6 G; ~6 a5 y. }9 C& N& V/ _        /*查找或者创建super_block*/
3 y( Q; G8 L" \4 \' d        s = sget(fs_type, compare_single, set_anon_super, NULL);5 R% S  M( i4 Q& R0 a
        if (IS_ERR(s))) G  F% B" N3 f2 c6 R
                return PTR_ERR(s);
& V& E! j& P( r: \) s8 \# y        if (!s->s_root) {                /*没有根目录dentry*/
( O- p( r; k( H# k; I                s->s_flags = flags;8 D: w/ P, e* L: R, I# K- C
                /*获取root( / )的 inode和dentry*/
, o$ d) w4 X/ o! Q1 i                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
! A2 O2 T2 w- F4 N  u1 }4 ?                if (error) {
& _+ S  Q/ ^4 S* n) W( p9 Q                        deactivate_locked_super(s);
8 N) A9 j8 E# K% f' u                        return error;
) Y9 }6 D$ g$ h+ X% g8 o' i  N$ p                }
2 v2 P  T* g2 m5 h- L                s->s_flags |= MS_ACTIVE;
  J8 T% z; V" v- \        }
1 _* K  e9 B5 q        do_remount_sb(s, flags, data, 0);
7 o) W3 V  Z; e# Z: }( c* f8 Q# `: q        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/9 |) a6 b/ G; H
        return 0;
) c1 h; _+ Q- ~4 c! Q# V}9 C5 Y- m0 k" J; }1 w
% q9 }! t; i: N, n% e* T- Y: O$ H
EXPORT_SYMBOL(get_sb_single);* C7 J' f( ^; j9 w! t' U: f
8.2.1 sget函数
& V. J& l( q( _" f. W1 I首先调用了sget函数来查找是否
7 x" ?6 x7 P% q- C/ R2 J; D下列函数位于fs/super.c。4 K! l# K$ e. w* u! U
/**
+ x( W; x) M% N/ Y* \' v/ m *        sget        -        find or create a superblock9 g" d+ s7 T. d" {+ j% G: C9 x
*        @type:        filesystem type superblock should belong to
: @: d& w% p8 p% K5 m# a! X, m *        @test:        comparison callback1 Y  o' f9 o. B- ~. Z
*        @set:        setup callback7 J4 ?2 K0 U  V, p* V. l, Q
*        @data:        argument to each of them3 U5 c8 V  y/ n9 U
*/
" s/ }/ a2 k  pstruct super_block *sget(struct file_system_type *type,+ s6 z3 V" w, s
                        int (*test)(struct super_block *,void *),, N4 s3 H* I  r+ D7 }' `0 e
                        int (*set)(struct super_block *,void *),
, i9 o% r4 ?  \! ?) p" _4 p! y                        void *data)
1 J; @& Y) L, ^1 j3 W{
& Z' \6 ~% b! L8 b4 d0 c        struct super_block *s = NULL;
/ N+ V: Z8 t. l3 t* U4 I8 Z# O) U) Z/ w        struct super_block *old;
0 P% B6 Y- C( U+ {        int err;
  i6 w  K6 M! P- p- K  P; ?/ v2 Z* \; c1 p/ G
retry:2 F& E) @4 R6 e. O- S$ A9 j
        spin_lock(&sb_lock);
& p! y& w$ t3 T, D        if (test) {                        + v* t3 G& F* G( }" O9 v0 y8 t, O0 d
                /*遍历所有属于该文件系统的super_block*/
6 N. h2 }- l7 G8 Y+ ]3 U                list_for_each_entry(old, &type->fs_supers, s_instances) {0 s2 h7 [! d, X& C5 g/ [6 ^
                        if (!test(old, data))
0 S6 ?3 p. r5 _                                continue;) [# F. M5 u( z9 O* L+ T6 r6 }
                        if (!grab_super(old))
  \# I7 X; X6 P9 y+ l                                goto retry;
. y2 r- `- {, O1 l9 _5 H                        if (s) {
6 X  m5 f0 X; |& {2 o* ^! G! f7 C3 l                                up_write(&s->s_umount);
. I0 L( ^: R: E' M4 ^                                destroy_super(s);( r& F3 Y( G/ M9 W* Q6 L2 w
                        }* J& A/ ^3 z  E2 z3 ^7 y: ]
                        return old;
  q9 U# u) U* I                }
) b/ N- J) S* z( N! n  B$ n        }7 w) [; a& K8 c* `" s
        if (!s) {7 u; d( ?. H& m$ [4 ]( }
                spin_unlock(&sb_lock);; E( i6 X# z9 s0 u, u( V
                s = alloc_super(type);        /*创建新的super_block并初始化*// R6 y1 f$ u& R2 w
                if (!s), v9 e: @7 |+ B# ?
                        return ERR_PTR(-ENOMEM);, ]2 n* k' W3 P7 f  A, z
                goto retry;% T$ l1 j: E5 W- l. c
        }
  K, ?0 y9 s, N, T8 q" q( y6 p               
3 A- a4 G* |, }        err = set(s, data);                /*设置s->s_dev */5 m4 {- R/ A* p: I) d: t# W3 T
        if (err) {
' r1 K3 x  r  A0 M0 g/ X                spin_unlock(&sb_lock);1 h1 |$ q0 g: k. f
                up_write(&s->s_umount);! i: v& o3 r1 t0 B* J2 u
                destroy_super(s);
8 t0 \4 v5 d' b1 X4 \' B" Y$ @" |                return ERR_PTR(err);
# d; F9 S4 W7 ~# r2 e        }
# a: C4 @. s. T1 G* k1 y        s->s_type = type;
* @; b; N% s( K  i/ ]+ S        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/! Q# U( M  N5 }6 q4 R3 U$ v+ n
        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/
0 b$ k! e! w8 w# N6 w) @        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/
& e0 L; _" L* n- @+ J4 w        spin_unlock(&sb_lock);; N! N; ^+ u6 L- q/ j0 v1 j# A3 |
        get_filesystem(type);
8 T6 j1 O. ~1 l+ z0 A: g6 j        return s;9 X( |5 b( a) l
}
; Z; h  P% k: d2 \
% p) x7 N0 I+ h- G1 kEXPORT_SYMBOL(sget);
/ C' h$ g/ y6 f& e1 X& Q该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。& t1 K1 s$ ]- S- \9 d# l/ v
然后调用alloc_super函数来创建新的struct super_block。* ]" d- U& C/ g7 P" M4 f8 ~: V
0 f* ?& }; q' \: T
下列函数位于fs/super.c。) Y/ {- n% J. Y$ M' ?  S
/**
' S5 Q! F: }# h2 y: O6 B *        alloc_super        -        create new superblock5 R* U- b' H- p. W
*        @type:        filesystem type superblock should belong to
1 l3 i6 `$ a* M* \ *# o7 E- ~" c' r3 i: \! l
*        Allocates and initializes a new &struct super_block.  alloc_super()
0 F' m) `9 a- F) q) L6 q; Z. N *        returns a pointer new superblock or %NULL if allocation had failed.; m( A8 u$ ~, a) J
*/* W1 ~' e. I! d4 J
static struct super_block *alloc_super(struct file_system_type *type)' \2 G! z. r, a+ i) q
{; q0 T% t2 L  Q# r4 J
        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/
0 }$ |- Q& q1 Z/ H# m- ?        static struct super_operations default_op;
- C* E8 w# i) S+ n5 |' X) z2 X" X" e: W' X: f
        if (s) {6 M% D/ N& Y; G" Q% A- q; l/ K% x) v: M
                if (security_sb_alloc(s)) {/ o  H3 U1 t+ @4 D2 P1 ~+ r
                        kfree(s);; E- _6 r7 E6 E$ W
                        s = NULL;
- U* L7 d% R3 N  Q: a                        goto out;
& t, z0 A! |9 f/ j7 e! j" S                }5 Q$ k2 K) P) k$ L4 q3 p
                INIT_LIST_HEAD(&s->s_dirty);% O& Z+ ]# g# L: X( j
                INIT_LIST_HEAD(&s->s_io);' I  M, Q' a7 t2 e6 O6 ~0 I: [
                INIT_LIST_HEAD(&s->s_more_io);
) N$ t0 x3 D4 I: a1 N& ], e                INIT_LIST_HEAD(&s->s_files);
$ p: M% I$ O" Q0 D/ p                INIT_LIST_HEAD(&s->s_instances);
+ r: }- r: n7 W$ W- L( h  n                INIT_HLIST_HEAD(&s->s_anon);( q4 g; {& \% [0 g& G
                INIT_LIST_HEAD(&s->s_inodes);. _' s" g$ s9 Q9 L4 M. }
                INIT_LIST_HEAD(&s->s_dentry_lru);
- V2 f( D  g! l. {8 f4 P) Q6 ~. }                INIT_LIST_HEAD(&s->s_async_list);5 p' }1 v) [6 b% O
                init_rwsem(&s->s_umount);6 \. X; v" Y$ j' A/ D; N
                mutex_init(&s->s_lock);
; \$ ?* E% x( t3 f( [; b3 d3 m                lockdep_set_class(&s->s_umount, &type->s_umount_key);
7 f- V# w! h: z' ]9 F. F                /*1 V* C; G$ V& Y. Y" Y2 b
                 * The locking rules for s_lock are up to the2 l) y, u* m+ [: W; L% d
                 * filesystem. For example ext3fs has different& U8 V: ^6 X( o7 C) [
                 * lock ordering than usbfs:
; ]; X) u! [' N4 B5 J2 O' i* I2 _8 q                 */2 {6 G4 F5 U! j+ G* |: W) {
                lockdep_set_class(&s->s_lock, &type->s_lock_key);
4 d6 C1 r2 H5 X6 X+ g                /*
$ |: b4 W3 ^# z                 * sget() can have s_umount recursion.% y; s* L( M" g% I9 Z# X8 t/ }
                 *
' a, q5 X; ]" M/ k- @" l! T/ D                 * When it cannot find a suitable sb, it allocates a new
/ s4 |4 U3 y7 d- K5 I                 * one (this one), and tries again to find a suitable old
8 P7 X  c; x8 P7 u; {                 * one.
" F' X% a8 Q8 G                 *
# C8 }/ c8 W2 N                 * In case that succeeds, it will acquire the s_umount
. _- ^1 }4 V" ~& m8 @                 * lock of the old one. Since these are clearly distrinct
& W! Z6 W% _1 f! F5 e  O                 * locks, and this object isn't exposed yet, there's no
4 G, J. M5 {( Z$ w5 y( D" |                 * risk of deadlocks.
: W3 {3 g; d2 c1 Y  a) }; Z                 */ Q* o+ F5 v5 \( m$ W
                 * Annotate this by putting this lock in a different
4 J" U# a6 j- l# R                 * subclass.6 s7 o" z7 P4 P2 H& E5 c! b
                 */  i: q! f* W, ]/ b) X) Z  a1 H
                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
' ?% m# _3 M2 T9 W, q: q9 d                s->s_count = S_BIAS;1 O/ \2 I5 I" W% u, P# ^
                atomic_set(&s->s_active, 1);3 a% `$ m$ F8 o" C- _+ x
                mutex_init(&s->s_vfs_rename_mutex);5 C& a  J' d" F- {5 u/ E
                mutex_init(&s->s_dquot.dqio_mutex);) C' ^& ]; @6 V. M1 ~8 ~* o
                mutex_init(&s->s_dquot.dqonoff_mutex);
; Q) `# [1 I) h% J4 I                init_rwsem(&s->s_dquot.dqptr_sem);+ w7 f0 s+ }$ l; d
                init_waitqueue_head(&s->s_wait_unfrozen);/ c2 @- n4 X0 P7 }9 c- k1 h
                s->s_maxbytes = MAX_NON_LFS;
8 r; m; r% [+ l% ]- ^0 u2 {3 W- @                s->dq_op = sb_dquot_ops;. k3 J/ u8 [% S4 D
                s->s_qcop = sb_quotactl_ops;: Q9 o: y( `) W; G
                s->s_op = &default_op;
3 |6 v8 f0 C: O1 `) ^3 C                s->s_time_gran = 1000000000;  D- @/ K6 Z/ V5 {3 e" [" z# `
        }9 q3 f6 v" [# H7 @. G2 W
out:" t' @5 M$ `; c3 P& V
        return s;
- F) q1 O( V/ D& j7 |}
% R/ a9 d+ e4 F分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。
4 z" ?8 a) I' K/ Z! |下列函数位于fs/super.c。
7 S+ _* l! B/ j; q3 Q0 w, mint set_anon_super(struct super_block *s, void *data)+ `8 C6 t8 Y( N. H; c* \5 h
{
1 Z; ^( X# c+ o; B# v& z        int dev;  e* E  p% _' z5 V8 s
        int error;
# v/ Y" d. k& K5 l  l. c3 ^# o7 h
retry:& N# ?- _9 f9 a+ N# p
        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/
5 i+ F8 l, T( W% }                return -ENOMEM;- D3 ]9 s6 h0 Z8 a
        spin_lock(&unnamed_dev_lock);
  c# }$ d8 v$ p5 y        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/% u0 S) N( O5 L! r
        spin_unlock(&unnamed_dev_lock);
9 x; }$ ~: V( n5 X# H) h. \, p        if (error == -EAGAIN)
6 T2 l8 w7 E% [1 L/ {                /* We raced and lost with another CPU. */! s$ e+ M5 d; I. H
                goto retry;
# T  ?% E5 s9 ^' f        else if (error)8 n/ J0 f1 f& r4 x. H% r; g
                return -EAGAIN;3 z5 [: _0 k3 X9 L' z+ F0 V' O
# c4 H) z7 m/ X) ]
        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
; I+ r& B$ N( c$ ?' E" c; s                spin_lock(&unnamed_dev_lock);
$ b/ o) k; j$ a9 j                ida_remove(&unnamed_dev_ida, dev);; O1 H( v: w' I* o1 x
                spin_unlock(&unnamed_dev_lock);5 A. w; ], o& ^8 Q5 K, t& ^
                return -EMFILE;
. I- _9 g5 |. q1 k; n/ ?% ^: T        }
+ R6 o6 b4 V" ]! u9 m" q# n        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/
* G  H$ A7 I+ c: U- z! |7 f5 F        return 0;
0 w9 k/ q; [9 _/ i}/ q0 [8 P5 Y/ l: S) C5 s, B$ u
8.2.2  sysfs_fill_super函数
/ R4 R2 z, c! i! ]/ g# V1 m- w分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。6 ]0 \. S" C# t9 U* t, T4 c
1 x7 y4 p1 F( E( C5 z, P3 t9 @
下列函数位于fs/sysfs/mount.c。+ V$ O2 j" a5 Q, ]6 x
struct super_block * sysfs_sb = NULL;# f# @! B* V( Q& c7 L  G& u  w5 S

, x# e$ a% I$ n) `static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
8 f9 T8 ^6 B1 h: A% d{
: |8 k$ N0 e; i* N        struct inode *inode;
6 V; [$ d# `1 y- T3 w" t2 _2 u% n4 a' z        struct dentry *root;- a: ]7 f3 P; l4 p

/ e9 W% j# k# W/ d        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/
" D# M# l( j8 F8 Y, ]6 x4 [9 ?        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
( e* t; p5 @, M7 B( Q        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/
0 v" x. Y- X% [1 B        sb->s_op = &sysfs_ops;) F. R) G3 P; \; s6 G
        sb->s_time_gran = 1;4 I9 Q; u* N7 m# I
        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/
5 q/ F. a$ t, Y% ~( e+ g7 }: K2 O" W# u. K) A
        /* get root inode, initialize and unlock it */* ^' x, U7 @4 Y7 ]$ v6 x# K
        mutex_lock(&sysfs_mutex);+ J( A; k! [9 R3 A' b4 O9 h. _& j
        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/                . E4 X" E' `1 I- N
        mutex_unlock(&sysfs_mutex);
4 c! p) c; V1 A8 l  D6 l        if (!inode) {1 g8 B7 [0 X7 |5 k
                pr_debug("sysfs: could not get root inode\n");
/ `# e$ K* ~+ L( P! n& Y3 `                return -ENOMEM;
* f6 }% W+ ]* F' I' y3 }        }
/ ~8 o9 f+ J" T/ r# e, x# w2 J
, {+ |6 h7 \- B6 h! r  L        /* instantiate and link root dentry */
7 ^% M1 i( v5 m3 j5 @, b        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/
/ o7 Y9 @1 T* x- w) h7 O0 \        if (!root) {
0 L& e2 E( f. m  V) p$ N                pr_debug("%s: could not get root dentry!\n",__func__);. Y" P" Z, Y3 p. K# B' ]
                iput(inode);  c# S5 B. O2 Q- M% X7 @' I
                return -ENOMEM;
, C) d1 b4 U- i        }) |+ z6 I* @& _+ @
        root->d_fsdata = &sysfs_root;$ ?8 p* Q2 }! B; |
        sb->s_root = root;   /*保存superblock的根dentry*/
( k! c/ j. z7 j0 E        return 0;9 w4 T& a% ]; `  W' ?) {: Q+ \- v6 g
}5 G- k, w0 F$ M6 _2 ^5 C# B2 y. l' s$ C
- ?$ m$ W; R9 r6 B! u7 w
struct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/# U/ v% c- _7 L4 t' S7 \+ B; H
    .s_name        = "",* l$ s* H; q- |$ ^
    .s_count    = ATOMIC_INIT(1),  r8 t( V( o0 T" z# g
    .s_flags    = SYSFS_DIR,
4 O( f4 ]# m% E& S, i" d3 U) p    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,* _$ B9 _: C& C
    .s_ino        = 1,2 _% s" r9 b6 l9 K
};
# Y3 e- l% n  R( [3 e1 s! ]( P
6 z3 n* i( {: j  ^. S  U在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。
. f: s7 a4 Z* D$ P( u/ A随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。: b  B. V' k, L4 o

0 A+ K0 }/ G; @$ J: C我们看些这个sysfs_dirent数据结构:9 P( \; u0 m8 b1 _2 m% E0 i
/*+ ^" j  w3 P3 k! D; Y! x
* sysfs_dirent - the building block of sysfs hierarchy.  Each and
& O& X4 o2 D: h0 m9 u * every sysfs node is represented by single sysfs_dirent.
' F' E) B1 q* a1 y7 s: ^1 a *7 J  v; o4 }8 n( Z" g
* As long as s_count reference is held, the sysfs_dirent itself is
8 j6 |7 h. `7 M3 z* L * accessible.  Dereferencing s_elem or any other outer entity6 M5 J9 Q8 f% ^% v
* requires s_active reference.
+ v, p& X4 X% i1 T8 v# R */. r7 x& l9 B8 v7 y* {5 C
struct sysfs_dirent {6 j9 W+ L4 X$ |9 x: E
        atomic_t                s_count;# v) f* G2 H* @6 Q! q8 S  L
        atomic_t                s_active;
6 O) ]+ ~: f3 L5 @) v        struct sysfs_dirent        *s_parent;
2 z2 b- o: b& G+ O( H$ o6 Z        struct sysfs_dirent        *s_sibling;
. `- c0 ]" ]0 k$ y% Y# P' Z        const char                *s_name;
+ |; q- z; F3 G5 R; _& Y/ \2 ~2 O" x
; r9 ]/ W/ D( L        union {& b7 o6 D( c& B5 u2 H" U, k, K
                struct sysfs_elem_dir                s_dir;1 Y6 D+ w* F" _' n% F9 y% c' B
                struct sysfs_elem_symlink        s_symlink;
6 U. z/ E* Z0 C0 U+ [5 d9 _                struct sysfs_elem_attr                s_attr;
0 J5 s0 y1 K2 K' Y7 Z& E                struct sysfs_elem_bin_attr        s_bin_attr;5 [8 P6 H  Q4 P. n8 {
        };1 E+ D  P7 x& t/ v

# A1 V; Z/ v( P' E5 k- Z$ H        unsigned int                s_flags;& B$ Y6 v9 C5 P" Q
        ino_t                        s_ino;
  w. |1 a/ S  R' _/ u8 f" _$ a# z        umode_t                        s_mode;- f. \/ q  g" G1 Q0 J# z
        struct iattr                *s_iattr;- S. C6 Z+ \& ?- J) M3 a
};/ J1 _; d0 Z9 e: ^; ~- p% I
其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。
" o( ~8 e1 i7 ^8 d另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。
3 X5 S" j* q' H; U# Y, B# B/ ?接着,在来看下sysfs_get_inode函数:
; C( J+ E& Z- P下列函数位于fs/sysfs/inode.c。
8 b# _+ y$ P# M0 `; t2 [/**
4 l" v! }4 D: Q+ [ *        sysfs_get_inode - get inode for sysfs_dirent4 z' ]0 P) M6 `4 w- z& [
*        @sd: sysfs_dirent to allocate inode for1 p: F% S3 x' \2 K( o: N2 g2 Q1 M
*
( ?7 k: z' u( e% v1 q *        Get inode for @sd.  If such inode doesn't exist, a new inode
3 _* l) Z7 g+ x5 m! V) n; l# U- \ *        is allocated and basics are initialized.  New inode is
. [" Z# w4 I0 K" F) u3 g *        returned locked.' p1 X+ q0 y, h& |
*) ^$ ^$ _* Y6 o% r) e8 q1 B$ B
*        LOCKING:- [/ p# K! L; V3 x/ N
*        Kernel thread context (may sleep)." r5 Y9 ^5 \; g4 E4 ?
*# c6 U: D9 j* g  p' l
*        RETURNS:- k7 b9 m( c5 A, c' M
*        Pointer to allocated inode on success, NULL on failure.
) z1 C: R$ N  y3 W6 N */
0 i& ]9 Z, Y; T$ l8 q4 {. Gstruct inode * sysfs_get_inode(struct sysfs_dirent *sd)
5 e0 q' k3 s! P( ~# r) z1 d{/ s& ?( S1 Y. V! k7 h! a
        struct inode *inode;
- b5 B9 U3 P: u6 r0 ~
0 |2 E5 V3 o4 L0 R7 }$ x& L        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/! y2 ~* b6 _" s& V& g
        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/
) |5 W7 v. T% `' ?+ M                sysfs_init_inode(sd, inode);
5 O; m; m- r( K  j; N
+ a% [$ Z) T! f; h% j        return inode;; {, r, S/ t/ C4 {" S, R' L" j  X
}  [7 C: @/ }1 r) P9 k1 u
& r  C! \- t7 |) }# A
/**! s. h9 C! e4 L- l# y# E* a
* iget_locked - obtain an inode from a mounted file system  Q* O* A* A3 [
* @sb:        super block of file system
  \  m# N* w  C$ |. k5 L8 [ * @ino:    inode number to get
- _: `/ o2 R* l1 V; c2 K1 t *( D; W& f/ i6 Q; u& g  ^9 S
* iget_locked() uses ifind_fast() to search for the inode specified by @ino in+ P6 Z. w+ W1 _3 E( h
* the inode cache and if present it is returned with an increased reference
$ J4 @. q2 U+ K" u * count. This is for file systems where the inode number is sufficient for
8 i0 @  L+ |: j* A$ M+ v. Z * unique identification of an inode.
( N  v( {) N- h' I, n2 S* g *
9 P( [( U, E0 a/ k * If the inode is not in cache, get_new_inode_fast() is called to allocate a6 z, T# `( m1 \" O- D
* new inode and this is returned locked, hashed, and with the I_NEW flag set.7 {" w$ x0 ~, p
* The file system gets to fill it in before unlocking it via' [( ~7 M; ^3 l4 e  t; d( J# o4 f* `
* unlock_new_inode().
6 t2 H$ l$ [: d; U3 O/ J8 Z */
. A, l' y! Q/ l- W6 jstruct inode *iget_locked(struct super_block *sb, unsigned long ino)5 e% [! c  M0 z3 P  E
{) S7 _+ e& J. I7 y
    struct hlist_head *head = inode_hashtable + hash(sb, ino);
2 c$ J: F6 z5 J, t    struct inode *inode;( s$ `$ u3 R5 O

3 i# I( _2 j1 `6 q    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
- y3 g! w3 p- e2 T' x1 {6 S+ F0 V    if (inode)- L4 ]! }, b1 U$ k3 G
        return inode;         /*找到了该inode*/
4 v  x* K7 \1 V    /*) ^' `; g' p, a" \5 Z) O' r7 s
     * get_new_inode_fast() will do the right thing, re-trying the search/ l  A7 ~  N8 x
     * in case it had to block at any point.; s8 {( o% r) a8 x% R
     */  _% p0 C! D- N1 h
    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/$ h" v4 m/ x# k: V9 n; c. K% u
}9 ^5 V6 ~2 ?% B
EXPORT_SYMBOL(iget_locked);" V$ X8 N/ G: ?9 Z3 Z( N0 ^, w
' s& l) ~1 R2 p3 F$ W8 Y. ?
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)) S7 Q+ {6 k# r1 l- L6 K# ]
{
# M, _, h; ^3 \' }9 H    struct bin_attribute *bin_attr;* w3 j+ ~' |0 M" v1 l2 i8 A
& w! B% n) Z: F; d1 G* Q# y
    inode->i_private = sysfs_get(sd);/ U; ^+ s7 Y* S/ w3 E% E. i8 ]4 w; @
    inode->i_mapping->a_ops = &sysfs_aops;7 q# s( _  b. {
    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;) B) y, \$ k* N; k4 _/ G
    inode->i_op = &sysfs_inode_operations;
0 o2 A/ D8 B$ \% ?    inode->i_ino = sd->s_ino;1 L5 ?# ]$ H, I3 h
    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);7 G+ n7 c: w! g2 V" P* L/ T/ i
! u# ~" u: t+ `4 ^8 X. ?! B
    if (sd->s_iattr) {+ j# K1 T( {5 j' m# y% B) m6 v
        /* sysfs_dirent has non-default attributes# V* s( V  F* q  s
         * get them for the new inode from persistent copy3 t- B# l& f. Z0 B
         * in sysfs_dirent
* J- H+ P" Z" V2 Y7 @" \+ d         */8 C, j; x6 u* J9 N1 `
        set_inode_attr(inode, sd->s_iattr);& G  p5 l& G; H% L8 p( `2 m" Q
    } else/ i: B0 J; y) x1 w/ ~* Y8 \, P
        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/; n* P$ c& p$ d* A3 a% B, ?# @3 |8 W

8 y( w3 ]$ H- N% t" Q! C0 I, V0 @$ Z; H, m. w
    /* initialize inode according to type */$ n9 F" Q: _2 y$ m
    switch (sysfs_type(sd)) {) Q. ~7 a/ k( K' b& n
    case SYSFS_DIR:1 H/ d& D# p( P- g7 \# a  B
        inode->i_op = &sysfs_dir_inode_operations;: [; C6 E" R$ C9 {8 V8 g+ _
        inode->i_fop = &sysfs_dir_operations;( N/ V' h4 Q/ Y$ A( Z( y
        inode->i_nlink = sysfs_count_nlink(sd);1 P2 i: d9 E' b8 A* O1 k1 m
        break;7 d, F& W- h+ o4 v3 k' ?
    case SYSFS_KOBJ_ATTR:
: P, b$ d% l" J4 n        inode->i_size = PAGE_SIZE;; F. F, t8 b- T1 w2 n. H7 S) y+ s1 U, q
        inode->i_fop = &sysfs_file_operations;
* f# a5 q0 A0 ^2 ]: g5 Z        break;
7 z( Y3 }4 _: [) ]9 s$ d    case SYSFS_KOBJ_BIN_ATTR:
, f7 K% `; z* h* {, U        bin_attr = sd->s_bin_attr.bin_attr;/ t3 |6 M. }+ L$ e+ m" v
        inode->i_size = bin_attr->size;  y: F+ ]( `" ]  {2 A3 ]
        inode->i_fop = &bin_fops;) h  k5 B) c0 A9 K5 x$ T
        break;
: Y# A7 _9 S/ Q; c* n4 y7 ^    case SYSFS_KOBJ_LINK:
' R! l" ~5 j5 Q0 W9 R" j) g) P' c        inode->i_op = &sysfs_symlink_inode_operations;
3 H. G& i9 T; w8 U: p        break;0 \2 p" u/ }& Y1 V% m8 i( I, C5 ~
    default:) |  P% i6 D* y0 V3 [4 z3 d
        BUG();! f8 i1 ?! J+ X) F9 P, |' v- x9 M' N! }
    }. _. b% @: o* A
' C0 D1 g: P8 C8 A/ z3 F
    unlock_new_inode(inode);
: e$ r  o  x: D: W7 S}
1 P; c3 `7 Y) |" P该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。
+ g  w( ~+ i- x再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。0 ~7 ]6 r  s0 i2 ^6 _- X
/**
) A7 U& Y" f4 @ * d_alloc_root - allocate root dentry
, }, J0 X- f# }) O/ i) _0 o+ R: x' p- h * @root_inode: inode to allocate the root for
# M) h: b9 }& l6 r* \1 ^. ?+ k$ f *
/ Q8 F6 g, I* E+ T1 E * Allocate a root ("/") dentry for the inode given. The inode is
* q5 v: N# u; {8 r+ P/ M * instantiated and returned. %NULL is returned if there is insufficient
9 r+ ]- p; K5 e# F9 Q) S * memory or the inode passed is %NULL.
( f1 j  w# W% l+ y0 _5 p */. h7 |! X- z0 P

- `7 l, H( r- jstruct dentry * d_alloc_root(struct inode * root_inode)
; B  H2 N; y; P$ q; `  G{; v* ~  U6 y$ w" ]' V0 W! ?, g2 q
        struct dentry *res = NULL;9 B+ p. m5 w- i# w* ]  r; h) {* d7 d
$ @9 t' C9 z+ [2 |. O
        if (root_inode) {% Y% H& |0 ^, }4 v! l5 k
                static const struct qstr name = { .name = "/", .len = 1 };
- C2 ]# I. n! Y$ y5 v/ c0 j2 a2 c7 q; t
                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/
' S  j- M+ Q: I* C                if (res) {
; M" v) C& ?" l: n" _7 ^6 {1 g                        res->d_sb = root_inode->i_sb;) F& \" E/ u3 u3 O5 A$ {
                        res->d_parent = res;        5 S* {, A8 A. {  t/ v: \/ C: T9 k, G
                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/' U) y& {4 T; p
                }8 q; D9 `* T6 E: r) j+ u( X
        }; Z. c& K9 g  S( h( k! p
        return res;
! r; z4 M- N9 T- }9 ~}: X  i$ r6 Q' q: f

! f0 _2 }0 T4 h4 L/**
) B! |% P0 k0 }" g * d_alloc    -    allocate a dcache entry  q4 j# W+ F: n
* @parent: parent of entry to allocate
) o# a8 T' s% A. ? * @name: qstr of the name8 I7 c% b& _7 a; U! p8 x7 A
*
$ O5 @. B# p* _) o# w: H. y, V * Allocates a dentry. It returns %NULL if there is insufficient memory
( c# W' H" d0 ]$ I* Q8 u  D  \ * available. On a success the dentry is returned. The name passed in is) R- b) B( n0 W7 \/ {5 M( x' r
* copied and the copy passed in may be reused after this call.
4 z* T, B9 _5 D2 S: G& P */  _2 g% z0 G& p' N; N- b

  D' W4 |3 O4 ~6 d: v: xstruct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
) o5 F  X% M! I3 Q{
: y% Q: t/ z7 C- e    struct dentry *dentry;
: W8 _( h2 z6 H$ Y. E6 j    char *dname;! ?* F6 v$ u8 f0 |+ j
9 l( g: A7 X2 }
    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/
4 p# b9 W! U5 Y& B( G: g" r6 z+ p    if (!dentry)( h$ S- m. O8 B& m. Y5 T. h) A* I
        return NULL;0 F+ u8 n& \2 l; |
- D% J3 m% `1 c! ^3 f! l
    if (name->len > DNAME_INLINE_LEN-1) {
4 O' F' z2 v8 s# ?! P9 |) S        dname = kmalloc(name->len + 1, GFP_KERNEL);
; m% a& O+ a4 J  @" I% G        if (!dname) {
: N/ w! i' g- K0 s            kmem_cache_free(dentry_cache, dentry); ( y% b+ ]0 K- l: V, b1 Y
            return NULL;9 J+ V* a2 T$ V7 D  B* G8 C6 ^3 S- p6 V
        }) Z' m. v: j- S  w0 M2 A0 O
    } else  {
. Y/ w4 u5 N$ Q  @! O        dname = dentry->d_iname;
1 u9 `) C# j. T& M    }    8 `7 a0 }1 D. [) P5 Y9 U
    dentry->d_name.name = dname;
  x7 P0 r4 H$ Z, N+ S1 w, x5 W& o. R) r, ^. t9 N7 ^' X
    dentry->d_name.len = name->len;0 d  S7 A$ U5 Z0 ?8 H  v* T
    dentry->d_name.hash = name->hash;" r5 D$ |9 r, _- ^
    mEMCpy(dname, name->name, name->len);& @% v* H) c# ]) r6 O: V# t
    dname[name->len] = 0;" I: H: @3 o% i
# b; q" V% D% c" g& C, t6 R9 c
    atomic_set(&dentry->d_count, 1);
  G5 ~7 F; b, R' J" w+ b    dentry->d_flags = DCACHE_UNHASHED;
0 D+ h& d, I; z, [6 y    spin_lock_init(&dentry->d_lock);& T( [1 k) ~3 [
    dentry->d_inode = NULL;
7 X$ b% e) Y' s    dentry->d_parent = NULL;
, @- B9 d9 Q0 ~" N8 ?( V    dentry->d_sb = NULL;
6 a0 X2 x& ?: l% n1 g/ l+ L    dentry->d_op = NULL;
4 d, [* w5 \+ Z( q0 A, y    dentry->d_fsdata = NULL;5 j. q. S) R2 J, z
    dentry->d_mounted = 0;
1 n: W- T4 H2 ], _    INIT_HLIST_NODE(&dentry->d_hash);- E# _# j1 C& x/ x7 A
    INIT_LIST_HEAD(&dentry->d_lru);
/ s4 _* Z2 i7 v$ B$ Q8 h' Y- Z    INIT_LIST_HEAD(&dentry->d_subdirs);! P! [& M( C, j; V8 m0 Y# O
    INIT_LIST_HEAD(&dentry->d_alias);
6 O4 H/ ^$ L) _/ @
' `- w/ _6 R, R    if (parent) {    /*有父目录,则设置指针来表示关系*/  v9 o0 m' W" e" W+ N1 A
        dentry->d_parent = dget(parent);
3 k( H& {5 l  r  }# l9 E8 O9 Z2 j+ T% d        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/
4 X7 _) @/ |5 c% R( [' I8 j    } else {
3 g4 I  d2 K9 g        INIT_LIST_HEAD(&dentry->d_u.d_child);
+ I# j; J# T* j8 x9 \: P. ?    }# I' q% n' u* h4 O* P

0 u- ~1 O6 s6 e) C  O. f1 S    spin_lock(&dcache_lock);+ S4 i! j9 E9 _, \& L) c
    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/: B4 W. E0 D" I: u
        list_add(&dentry->d_u.d_child, &parent->d_subdirs);( s$ o9 n& h% ?7 @8 P
    dentry_stat.nr_dentry++;
) N, a3 }1 B- [/ I3 d+ o    spin_unlock(&dcache_lock);8 k! _  t3 x( f6 }8 ]

. B9 W, g- D/ {( ?    return dentry;
9 |$ _' _: x0 }' d2 I+ m- \}
4 _. g* u- j3 b5 c0 ^
$ Y& q- W* j  e- d$ j/**
, q# F( \, K8 u4 n" B8 B/ E * d_instantiate - fill in inode information for a dentry8 z4 k& x; [- p! B
* @entry: dentry to complete
2 @  I0 K" E3 F# X1 H * @inode: inode to attach to this dentry
$ Q; a% r! h' f' ] *. j% K8 x1 ]+ E6 G8 O
* Fill in inode information in the entry.
$ C  N, W- S, b *0 l% y4 B- {7 e8 d: i1 y
* This turns negative dentries into productive full members
2 V9 Z1 [2 _" R1 T+ ?/ w, H0 X * of society.0 I4 |0 s( [4 `' i: K8 ~" i  ]8 M
*! L+ M/ ^. V  T
* NOTE! This assumes that the inode count has been incremented
* J! n2 Q: P  d" m- l& k; W& P * (or otherwise set) by the caller to indicate that it is now( b' L; f% q' ]8 C4 v
* in use by the dcache.
% Y; E; z3 [; J" T+ [8 }* M! [ */" ~  i6 r. L% B) d" V( c

9 n; \. w0 `) ~* \0 [& R& Rvoid d_instantiate(struct dentry *entry, struct inode * inode). J( j* \4 m) {- k1 G0 ~4 Q, I9 ]
{- @$ `$ l' }# M/ N9 z$ {& \
    BUG_ON(!list_empty(&entry->d_alias));
% u& |0 K0 X- Q$ e" t2 e    spin_lock(&dcache_lock);9 P' F- L4 J0 O3 e4 Z/ z
    __d_instantiate(entry, inode);3 ~* ^5 C) I) f9 L1 h
    spin_unlock(&dcache_lock);/ o" I! v+ j/ d+ m$ G& n- m
    security_d_instantiate(entry, inode);
( U9 i) k5 @  ^5 [: K  S}
. j  q8 M' _* t' b5 g0 T0 k
1 c5 K  x$ B. I0 J/* the caller must hold dcache_lock */$ ~0 h0 ]0 Z  N) i
static void __d_instantiate(struct dentry *dentry, struct inode *inode)! V- u7 z; R' j+ K# C1 v
{( E, p' a* J6 Y) v3 J9 R3 Z
    if (inode)- @# g& B" c; z* G& j, m  ^" j
        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/1 t* c- d% k* c! O) w7 n
    dentry->d_inode = inode;        /*保存dentry对应的inode*/' p% H: @0 x# K+ K
    fsnotify_d_instantiate(dentry, inode);
; J4 `4 O! x' x& f}
& b; v  C8 m; }& x! C* @: I( f) o
9 t! W$ b5 }/ Z该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
9 L5 [8 [/ F  {, c7 Z9 V7 _* I; W接着调用d_instantiate来绑定inode和dentry之间的关系。
! _! L. E" _9 t! C1 m8 R( A- l
: }2 D1 N; E9 g  e) u8 k; L8 J5 K" C, \  h! A
在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。9 e9 e) ?4 N. [6 Q& N. j5 m/ l; L
  z+ n" X0 L6 I3 l
可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。$ U' d6 R9 V3 l
  u: W; u7 E+ K/ I: n9 g  y, h, o
8.2.3  do_remount_sb* U$ u3 N- o, R9 H+ k5 X
下列代码位于fs/super.c。
" U* }0 S" I! J) H/**% e+ N: ~2 ?8 o  L  x  g' n
*        do_remount_sb - asks filesystem to change mount options.
& k; Y! o7 O: L7 ?; e) f/ z *        @sb:        superblock in question  h  R- J6 V" u) o
*        @flags:        numeric part of options# o! M9 r- Q4 g2 _. B
*        @data:        the rest of options
& R  P2 Z/ y* x- U; L! c *      @force: whether or not to force the change
! C( c" M$ Q  L7 { *+ g: k( P& ?( p
*        Alters the mount options of a mounted file system.
' b! f0 E$ U- O */
& q# V% m2 b0 W0 ~5 ^. Mint do_remount_sb(struct super_block *sb, int flags, void *data, int force)
8 Z+ e( k/ Y* j- O{
, D/ Z0 p% b6 z        int retval;
$ g0 I& S3 ^  a- Y        int remount_rw;
; z) w! d  Q# R% _# {4 P. y        - o' f% }% M: M; f
#ifdef CONFIG_BLOCK
6 ?6 c4 E9 U* z- n4 H# d        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))( u) P9 g, C; U
                return -EACCES;  Q/ W) I0 V9 b$ x# I8 ^+ `
#endif1 Z% e% Z+ ?  o" P% M0 O; y
        if (flags & MS_RDONLY)
/ Q+ o; K8 H( s                acct_auto_close(sb);! y% \2 q/ e) A$ k* |
        shrink_dcache_sb(sb);
* `" y/ ]8 F$ [% w* O        fsync_super(sb);
4 k# h' T3 x- T' Y: H, J+ b4 ~
# p1 s) I" }1 D* s        /* If we are remounting RDONLY and current sb is read/write,
+ g) u& i, J' m4 ^3 S/ [           make sure there are no rw files opened */2 M: y+ @8 |- m9 B/ Y0 E" K0 O
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {; i2 K. j: d! m; {5 W$ D) `3 \5 y
                if (force)0 N. }& Z+ A% ?  f
                        mark_files_ro(sb);0 U( L% r* L8 y! v$ F6 P) e
                else if (!fs_may_remount_ro(sb))
1 o7 {9 L2 r: p. o+ G4 T: E, z                        return -EBUSY;
9 U6 ?. e: v9 j" h1 {                retval = vfs_dq_off(sb, 1);
# \* Y, A  e$ v+ d                if (retval < 0 && retval != -ENOSYS)( @1 T" v9 h' {, y/ i
                        return -EBUSY;
* |+ ~  m5 o( P1 A. s" s9 z        }
6 Q3 L" F& {$ y" p        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
' \8 P# z( F: i  O! C! G8 l2 Y7 s0 P& k( V' j
        if (sb->s_op->remount_fs) {- ^" \9 b2 x  c4 _4 H3 A
                lock_super(sb);$ x0 b& P& B  |2 j1 B- a* N( R
                retval = sb->s_op->remount_fs(sb, &flags, data);
1 q9 j4 s& S' _' U                unlock_super(sb);
# i# [0 p0 S9 h$ z2 K                if (retval)  N; E4 v/ ]! |- N/ t/ |
                        return retval;
3 {, F4 g9 {" Y$ a' |        }: }+ l5 k8 ?  _! d% S' a6 s+ ^
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);7 I+ u5 h$ z  v& d4 [/ j( h0 b. A. h
        if (remount_rw)
, r( X( ^9 O5 n                vfs_dq_quota_on_remount(sb);2 s) Z! B: X2 e" p
        return 0;/ J4 L1 q, ?) C
}, z* c1 ?& U! g+ v! r9 G

& q$ `. g$ w% P4 s这个函数用来修改挂在选项,这个函数就不分析了,不是重点。0 @5 I/ T3 D- g: A+ P3 o% X
8.2.4simple_set_mnt, _, M6 [" d( Q0 ^8 v- N( s7 ~
下列函数位于fs/namespace.c。
. O. B  O$ ?" {7 rvoid simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)9 N- L! P9 R9 b1 F% Y( z9 N" f! \
{
! L6 a. m$ Y9 y        mnt->mnt_sb = sb;1 |/ n" M- W- f
        mnt->mnt_root = dget(sb->s_root);0 u2 o$ S: v7 v+ b9 _4 \+ ^8 }6 l' T
}
* p0 ]- I3 U; Q$ s3 M该函数设置了vfsmount的superblock和根dentry。
. A2 p' K! Q& o- \  a, u2 s' Z0 i& O8 ^. k. G- i9 [; M
8.2.5 小结
/ h  b+ M7 ?8 r  H这里,对sysfs的注册过程做一个总结。+ m/ ^# E/ O1 p

/ `$ D' J! j) I! S9 `. U: D; \! U' v5 Bsysfs_init函数调用过程示意图如下:7 v& [: _4 _, J* c* _

% u8 S; D* C, \. S( z1 [+ C6 g
0 E( h: u0 J2 e
1 q: Y% F- I. F" c; {在整个过程中,先后使用和创建了许多struct+ d2 f  j0 R( T6 ?9 b
5 ?' l  B) L0 E% K  `
第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。5 f" v5 ~& g1 t9 T

" T7 c: N3 d  e7 v第二,建立了vfsmount。8 l1 H( H1 q( F

: F% F9 U  L2 ~9 `第三,创建了超级块super_block。
4 j/ Q8 h0 J" r* Z2 b4 w
. m3 d4 V. @9 F; A4 e+ B第四,根据sysfs_dirent表示的根目录,建立了inode。! @6 ?7 `" r% m$ E8 ~
6 ]7 z9 G4 j4 G" B* o" t, V
最后,根据刚才建立的inode创建了dentry。
! l; k$ U4 n! x$ K
5 M2 J& w( w8 p! Z2 o2 h$ b: J% O除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
( C  @5 Y% z5 R6 @& i
6 Y7 ~( X) F" m$ k; A8.3 创建目录8 N* ?9 E0 h8 o: Q5 \/ r$ J
在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。9 R) ~. E/ i! b/ {
6 V" _" ?6 E6 z; c; L
下列代码位于fs/sysfs/dir.c。
. W) {# [& E( b- q5 \/**
5 e8 @% I6 B, `3 H' k9 a *        sysfs_create_dir - create a directory for an object.+ L3 P' d9 g+ U* o8 `; J
*        @kobj:                object we're creating directory for. , g6 L  ]4 K9 g: k8 P4 t; I
*/+ @8 v, q4 ~$ X2 }" q2 v; G2 k
int sysfs_create_dir(struct kobject * kobj): P7 U3 h  @8 ^3 e5 H1 O  f, m  G
{
( a; J3 A% r6 T9 Y( l        struct sysfs_dirent *parent_sd, *sd;0 s0 m3 V( p4 y3 P$ w3 D" d
        int error = 0;
9 M% ^" W% v: h$ U% M) T+ z# G2 J* m2 G5 o$ p
        BUG_ON(!kobj);" }& j; |, ~9 C  h0 D
) W9 N1 O  a  n' U
        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/" o) T3 ^1 Y" Y0 x& ?( ~
                parent_sd = kobj->parent->sd;
2 P$ j" \$ z( R( n+ ~" N        else                                /*没有则是在sys根目录*/4 z: T5 W! y' k; E% x/ s
                parent_sd = &sysfs_root;% b4 n$ `" i( u9 m
5 r$ i, U* b3 o$ |
        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
9 r" T; z, p; K1 }( P        if (!error)
/ u6 \7 O; P" \. s& g9 A' l4 S. M) F5 i                kobj->sd = sd;
: c/ ]/ d( H* Z        return error;
8 C& A# V3 I' X; Z* y- M}
  Q8 w9 T) `8 i1 V- J9 t  r
7 w$ {" e0 j! W2 ]1 ?4 `函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。
) {) T8 R# ^1 R+ A很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。7 p+ L1 b1 B% m, L# U; ~1 e

' A0 _5 q2 K' H: J  w, d) m下列代码位于fs/sysfs/dir.c。; P* a9 [" a% a
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,/ d+ b3 k) \, w/ \' y
                      const char *name, struct sysfs_dirent **p_sd)6 M4 ^+ A4 n) s/ J/ b
{6 r; @1 y; k- h' e1 M
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;& Y. A6 \; J) j# p
        struct sysfs_addrm_cxt acxt;- a0 Y( `( b  z1 S) x* W
        struct sysfs_dirent *sd;& a4 R3 w: i" x* |4 r' G
        int rc;0 c* R! C: N. \8 P6 z
$ o/ g; i5 w; V" A
        /* allocate */        /*分配sysfs_dirent并初始化*/
- h  E/ |) G, D        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);& x$ G. h# N7 Z
        if (!sd)
0 b3 e! Q) u2 v2 E                return -ENOMEM;
& _2 `$ I$ ^: a/ w1 D        sd->s_dir.kobj = kobj;         /*保存kobject对象*/; D1 n7 W3 S+ W

2 `6 S! Q# g" Y, K        /* link in */
2 m3 m9 `1 i0 m2 A# m, r        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
3 U" i. {; ?* D; z! k7 e! C! c        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/
" |% B# E: i' X: k" b3 o        sysfs_addrm_finish(&acxt);                /*收尾工作*/
0 g% Z4 z, z) A, ^
* }8 F/ k) B2 t$ B9 g        if (rc == 0)                /*rc为0表示创建成功*/
( \4 \' I) G  n. t( B( g/ _  \* w                *p_sd = sd;
: Y- v6 f6 X1 n5 n        else
+ s& R9 Y! Q# i, m, M; R: y                sysfs_put(sd);        /*增加引用计数*/9 o/ N$ X3 q  u0 H3 {

4 K) ], e* `- G        return rc;8 m8 ^, b6 |* y( S
}
4 ?8 [& p7 ]$ p这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。, e5 B$ `7 P) z! ]7 ~* E1 e) o- {

7 z7 N: s& L  s( O- v9 emode还有几个宏定义可以使用,如下:
2 ]0 \* ]+ Q/ Q( ~/ {. w#define SYSFS_KOBJ_ATTR                        0x0002  c1 s, m) {# d' f# x1 S
#define SYSFS_KOBJ_BIN_ATTR                0x0004% w" y3 U7 R* L; o% u
#define SYSFS_KOBJ_LINK                        0x0008: d, ~, V% Y* Q, s0 e4 Y7 D5 A. W
#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)+ u4 z/ V; i' }% @
8.3.1 sysfs_new_dirent
8 P- b4 A# z* D6 |8 T/ X% K  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。  s. ]0 O3 M. r" g- J: j

' D8 i/ ^9 B- H1 V2 k下列代码位于fs/sysfs/dir.c。
4 j$ |# m+ g' ]0 h3 U8 wstruct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
8 v' L% l" R$ Y{
' x8 Q0 u+ B. C# t7 a        char *dup_name = NULL;8 t  O8 c4 a5 R5 R* U, |
        struct sysfs_dirent *sd;
* y& B$ e2 Z8 H5 L, X3 }6 C3 y# [; |: P$ N1 X. }
        if (type & SYSFS_COPY_NAME) {) B8 @" g. h# a. B; z. a
                name = dup_name = kstrdup(name, GFP_KERNEL);$ m' J7 H) E3 `/ h2 e1 m8 X# I! N
                if (!name)
8 `5 y: ?2 \4 v* K( p                        return NULL;0 j; ]1 M: t5 d
        }
0 d4 t" {9 y& U5 z        /*分配sysfs_dirent并清0*/) W3 m9 y+ j  b; A
        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);; h7 l# y+ a4 ]! f
        if (!sd)
7 R+ j3 z1 Z% o2 K- D* y; h! @                goto err_out1;+ H4 r" K2 e' U9 ?- K2 Z

0 j2 n, ]/ C) l, _+ N        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/
5 ~( _  P. x; B                goto err_out2;' `3 I+ _* q  Y
% l- c$ b4 l# h. ?/ B  S
        atomic_set(&sd->s_count, 1);
3 X+ J5 R9 a" x" L; x) M        atomic_set(&sd->s_active, 0);
$ k8 G" @, ^- `# U/ j9 I4 }# y1 @
$ j3 U6 @/ y: X# g* s0 x        sd->s_name = name;( s2 m) \6 K2 X2 \
        sd->s_mode = mode;
6 h" A. r% C: x. g* k- J+ b1 n4 p1 Y        sd->s_flags = type;
' j% k: U( q: y/ r& V2 d. i/ h' b6 l. q! g: l6 @8 ]) K  e
        return sd;
/ T4 K9 a; O4 u+ t" Q/ p! w
, h+ J9 W+ w6 C, T err_out2:
" t8 \( j) ^8 v" T  B: O8 f        kmem_cache_free(sysfs_dir_cachep, sd);
: U2 b# C, ~, S; F* B; V err_out1:
# K& O  S0 Q# _' H  z        kfree(dup_name);
' z% T9 D. ]5 r/ j6 r- v        return NULL;
" r9 s( o) X8 x' \" j}
8 {9 h$ O2 v1 y3 k# g8.3.2 有关sysfs_dirent中的联合体0 P# `% C5 c9 [& [( L7 T
分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。
$ X! E& C& n# H
9 y( u2 ?5 i4 s7 [. _8 U7 c" [2 a! c/* type-specific structures for sysfs_dirent->s_* union members */
, t' Y7 l4 m" c+ n1 ]1 Pstruct sysfs_elem_dir {" a& D" S* {( R# A, o* {
        struct kobject                *kobj;
4 Q7 Q8 Q* k+ d" e& l0 L        /* children list starts here and goes through sd->s_sibling */
1 K6 {8 A, ~; t8 h0 |% i) x        struct sysfs_dirent        *children;" c' ]9 k8 ]9 X1 Z' m) C8 |
};0 ?, H+ }/ e- P5 s
- |9 G+ |! P" d0 W! a0 W
struct sysfs_elem_symlink {. j5 p7 r- ~- D6 y
    struct sysfs_dirent    *target_sd;
; w6 Y' ~% V  J1 r: Q% B+ Z, m4 v};
' X5 t# b5 E% R/ r) M3 J% r4 z) L# ~
struct sysfs_elem_attr {* ]2 C, n3 I& z- Z) Y* A
    struct attribute    *attr;
  g5 A) c3 W& x) e9 C    struct sysfs_open_dirent *open;
$ j2 j) Y1 t- m};& X5 s3 L* w( W- [' G! Z( x

* C( Z' @1 z+ y8 qstruct sysfs_elem_bin_attr {- m2 t8 Y" ?, X  a+ o* l
    struct bin_attribute    *bin_attr;& U2 O" \0 u  T. B
    struct hlist_head    buffers;2 ^2 i9 m- I. s5 F2 ]
};% F* O# K3 U- R. ]; y4 P
根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。! }4 _# Z& J3 N
在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。
) q% K* H6 w; F8 \  @8 V
9 B6 \& d, K6 V$ o* }- c( S: c在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。
" I( ?( y: X, [; r4 R$ X: R" u9 v6 O8 V; m. N
8.3.3 sysfs_addrm_start, z/ n" N* B2 L+ s$ \% ]* O
在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。
' ^& V6 w& q+ k9 |- D) W& n% |$ h/ Q" j+ q6 E+ R3 [. y
下列代码位于fs/sysfs/dir.c。! X, V% a* Z) ?4 U$ [
/**
4 M0 J& g4 S+ R0 t# q: t" a9 p *        sysfs_addrm_start - prepare for sysfs_dirent add/remove! p8 s2 A; g. d
*        @acxt: pointer to sysfs_addrm_cxt to be used
4 i+ C* l8 @- t) T *        @parent_sd: parent sysfs_dirent
; [2 K$ b' W* T! r7 t *5 N0 i0 Y7 q) c7 h. B$ W
*        This function is called when the caller is about to add or" }' |% l+ C6 q: b- a7 |
*        remove sysfs_dirent under @parent_sd.  This function acquires* v* W9 W3 W% Q7 z; x4 D3 |
*        sysfs_mutex, grabs inode for @parent_sd if available and lock
' M" g6 i7 l. ?2 Y+ V *        i_mutex of it.  @acxt is used to keep and pass context to
4 \' k8 r2 s- r$ c, D3 ~: i3 U+ u. z, ] *        other addrm functions.  A5 J7 q, E& v6 D+ M' n: B) a: e
*
6 o8 c. P. W/ E *        LOCKING:) w8 l4 x' I5 z
*        Kernel thread context (may sleep).  sysfs_mutex is locked on" p$ r  C( R% ?0 ]7 u0 o9 Q
*        return.  i_mutex of parent inode is locked on return if
# B$ v2 O+ J5 Z; w( ?- L5 k *        available.
  Y9 c& N* X  w8 l: Y& A" i! Z0 ?( y */7 \) q8 g1 N5 b5 Y! ?# d
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,+ ?2 d6 t- g7 M( H
                       struct sysfs_dirent *parent_sd)! V- J  N  {0 V- T; t% l
{" a9 E+ Z. [9 ?8 K
        struct inode *inode;1 W% R0 a5 p5 ^

4 \. z8 m' m( A3 ~' a( {        memset(acxt, 0, sizeof(*acxt));
; P$ g6 }0 _; b/ D1 z  ?        acxt->parent_sd = parent_sd;
/ @9 ]1 X2 M1 M" e4 t& {8 m- C3 V- M% R' u9 I# F! z
        /* Lookup parent inode.  inode initialization is protected by
, \; U9 V* ?% a2 T$ o( A, Y         * sysfs_mutex, so inode existence can be determined by" V3 i% t$ W4 Z4 W5 V  h1 l
         * looking up inode while holding sysfs_mutex.2 O6 y4 ?$ K& F. X; M+ B8 \: G
         */
  e* j/ o* L1 D5 r( Z        mutex_lock(&sysfs_mutex);
% `+ W7 e# V" A, n        /*根据parent_sd来寻找父inode*/
# T  D  [# w6 R: \        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,( E: a# L$ r% H2 }3 ~& m
                         parent_sd);
" K5 U$ h) D+ T( D        if (inode) {
7 t8 ]9 U0 [7 ~& G                WARN_ON(inode->i_state & I_NEW);9 e! x# F$ A+ Q, H% o
2 `4 c, Y+ z4 N& F5 j$ v& v
                /* parent inode available */
2 i" @( ?% O+ [9 v" L                acxt->parent_inode = inode;                /*保存找到的父inode*/+ n2 f  l9 Y' m# d# L$ ?8 A6 M
9 _7 C: B- r+ O  q( y
                /* sysfs_mutex is below i_mutex in lock hierarchy.0 G, ]! Y6 [7 B% L- h& ]( g
                 * First, trylock i_mutex.  If fails, unlock
, S9 O4 [" `$ V* w/ R3 e                 * sysfs_mutex and lock them in order.
. Y/ B7 l/ V5 i  x0 M; A( G# U                 */
5 F+ q0 L# j% w$ Q# R" m& v$ j                if (!mutex_trylock(&inode->i_mutex)) {7 R6 j% }9 \; H& t" X
                        mutex_unlock(&sysfs_mutex);
% N: V# v4 z# X! J+ N                        mutex_lock(&inode->i_mutex);" j; x4 \) ~! x* l: w: }( r
                        mutex_lock(&sysfs_mutex);
/ [& ^6 R5 b" G& p4 W2 i* b$ a                }
% ]6 a6 T: V! _) z- u4 A  i; @        }
# H# e# U3 w+ v* ]8 j}
( T- c* @) g$ s0 ]5 U7 [! Z5 A/ D! s! ?# _  I3 D# q; Z! d
/*& \% }  g  T1 t. ~; z2 B3 g8 N
* Context structure to be used while adding/removing nodes.1 ]- o% o. A& N! [
*/
, @- V( a' @% A9 sstruct sysfs_addrm_cxt {
5 U3 o5 t- X5 {1 S7 ]5 x    struct sysfs_dirent    *parent_sd;6 S3 F- M# t) Q% ^: f# T
    struct inode        *parent_inode;
1 W0 i" n& W+ G6 P. l( `; U    struct sysfs_dirent    *removed;
8 U# l, w, C2 l) H2 }    int            cnt;
+ N" S" L6 \0 A. q, p4 f6 k};. Y5 M/ I1 ]$ D5 W
注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。
4 ]/ X; \) d! G8.3.4 sysfs_add_one
0 f9 C6 G. T- a下列代码位于fs/sysfs/dir.c。: V* w* J  O0 W! K4 i* ]6 k- T, G7 Q; [$ I
/**
1 z3 \: \1 F: t6 P) n5 H. e' \ *        sysfs_add_one - add sysfs_dirent to parent! _" f  P( u, {
*        @acxt: addrm context to use0 [4 K( E& J! w4 E; k- b
*        @sd: sysfs_dirent to be added4 {3 n0 y/ n$ D  k! i  b
*0 y8 g5 E6 h' w1 V! O. G
*        Get @acxt->parent_sd and set sd->s_parent to it and increment
$ J( b3 U4 |9 [$ T7 i# S& o$ ] *        nlink of parent inode if @sd is a directory and link into the
4 k; t1 Z5 ]2 B) Q4 L. P7 A *        children list of the parent.
7 }$ J, h4 @6 Z* r' A* W# S' b *- l# v7 S. t& _' ^
*        This function should be called between calls to; v& w" e% z0 a& p6 R0 @+ d
*        sysfs_addrm_start() and sysfs_addrm_finish() and should be
7 V3 ~% _. r& d *        passed the same @acxt as passed to sysfs_addrm_start().
& f  ^4 x8 N1 m$ i  |- e4 [% @ *
: |# I( f5 B. i( H- { *        LOCKING:7 x) t& y$ D6 E* b7 r0 c  U
*        Determined by sysfs_addrm_start().
, F+ _0 |- t, ?# u *
5 G; [- ]5 n6 ~7 p3 ? *        RETURNS:& K, \. J) F7 D
*        0 on success, -EEXIST if entry with the given name already# Q5 T3 Q$ H. F3 J1 s/ C3 x# j' d
*        exists.
# N# K0 E! \. O. S4 j$ C3 J+ \ */
2 @2 Z5 G+ @( I1 Sint sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
' x! h- z1 g) ]6 e+ j* X% t{5 H3 L4 p/ E3 U! x/ c
        int ret;
/ C3 P& I% B1 t1 |" V+ O4 w- y; K0 z; {1 U2 m6 }# J- U
        ret = __sysfs_add_one(acxt, sd);8 D4 m9 a  U# K$ h
        if (ret == -EEXIST) {4 v7 u! Y: ]6 ]4 R
                char *path = kzalloc(PATH_MAX, GFP_KERNEL);
1 l2 E: c) b+ D2 u" K% [8 k0 c                WARN(1, KERN_WARNING
0 N0 N3 `0 y  l$ e9 y" F0 t% e                     "sysfs: cannot create duplicate filename '%s'\n",
7 h, s4 @2 z1 M% ]  Q  k( @6 X                     (path == NULL) ? sd->s_name :
3 W" H9 B9 j# O' M; e# K& m  e                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/"),+ r( w, a) R) G2 q
                            sd->s_name));
, D' w& S5 C' x' {; n                kfree(path);9 m; C6 Z. y. c5 I$ h7 f
        }
+ V7 V& g- O: K! u/ ^7 Y8 Y
. V9 h  G* ]# J6 W3 r0 d        return ret;5 N% a- E3 y1 d
}
% W2 U8 j8 }0 G
+ F! s7 i9 J" {4 k' ]: _/**8 O0 F0 }, X7 n$ V) U6 ^5 Q# A. E
*    __sysfs_add_one - add sysfs_dirent to parent without warning
0 h0 {. `$ }' d7 [2 X1 p! q* P *    @acxt: addrm context to use  h: p! H# E6 B8 j
*    @sd: sysfs_dirent to be added
# d' P7 p( k0 {1 S* c# L8 f4 c  ]; O$ O ** P( z* }6 V7 L/ n) n4 m! S  ?. C
*    Get @acxt->parent_sd and set sd->s_parent to it and increment; G- i2 y6 K' ]& C
*    nlink of parent inode if @sd is a directory and link into the
# Q& y& p! m2 S& b *    children list of the parent.
7 y0 f' b* `" p' _: X, D *
4 E  I5 {5 O, \  p" b. I *    This function should be called between calls to
, @% N3 P: v" k *    sysfs_addrm_start() and sysfs_addrm_finish() and should be
' |2 g# I  h% g7 P9 B5 x *    passed the same @acxt as passed to sysfs_addrm_start().2 O/ _+ @& s" O. m# h& F! d
*
" c) P) I) W4 m$ k) n' y *    LOCKING:( y0 ~/ r5 X. f
*    Determined by sysfs_addrm_start().3 H# e! d, e: o
*: w2 j5 h5 a+ U7 v; j8 x; b: }
*    RETURNS:( ^# X/ U; Z: r
*    0 on success, -EEXIST if entry with the given name already
, q" |$ p3 s4 r  t$ g *    exists.
1 \+ Z. n6 g; X3 P  ] */4 r7 u8 \4 B# l: a( r
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)8 D2 O9 o5 u3 k+ J3 I4 t8 n
{
$ C6 C3 o+ u9 `0 @" a, [    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/6 X5 r. O! ]0 j2 W. X. j
    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))3 B1 b5 O  u% N& e
        return -EEXIST;4 w1 [( n# i7 L! Y
% w* S! i- L6 \* x9 Y8 a3 @! h
    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
2 u% j+ z- |& a. o% y" U3 R1 ~0 t6 \
    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/) B  q- U3 r' U" G
        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/: M- I6 ]; M/ i- z

0 A4 C+ o3 {6 @1 `8 |, u    acxt->cnt++;+ {( ^& \8 y6 H) M: K: @

! L1 J' u1 L0 D# A4 F4 E' u    sysfs_link_sibling(sd);
' j5 x+ G: }3 \/ J9 o8 a) i# G% i7 i; v. ?8 o  z1 E
    return 0;
1 }# W' Y# P6 Z; o}
: o6 A2 i4 z6 T6 T* j1 {" X; `) X! o* a/ r/ x4 a% k
/**
! J( W9 d$ C6 J9 ~& g, O! ` *    sysfs_find_dirent - find sysfs_dirent with the given name
( M1 B( P3 E# j# ] *    @parent_sd: sysfs_dirent to search under- }1 c8 K0 v, A0 v& |) _
*    @name: name to look for% R8 t6 k$ t( \
*2 E% @& A6 m9 \6 _9 w% e
*    Look for sysfs_dirent with name @name under @parent_sd.
# a2 M) l8 s; Z" T2 M. i, q *
% S( d0 M& X1 E0 N. C *    LOCKING:9 y3 q4 n& G$ \1 `" ^% c5 I
*    mutex_lock(sysfs_mutex)
1 H% T) a9 O: |9 T9 y) K *4 G$ x# G- Q1 e! j! T; \4 d& ~$ L! {3 \
*    RETURNS:
" s; d! d( _$ n0 B *    Pointer to sysfs_dirent if found, NULL if not.
( U+ z* ?; c% t2 N7 p; \' A */% R0 K+ ]/ b8 I4 y4 m
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,8 D$ e6 b& [7 w5 z0 n$ `% [5 E
                       const unsigned char *name)9 M+ G1 c4 K/ ?8 U8 S' ?) P
{
; }8 C" C. V( Q+ T4 u    struct sysfs_dirent *sd;! G. _# U/ u* n; Y! t

# ?# {8 s+ J- ?% H: O; V6 \    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)- ?5 p6 G" R8 y8 t) f
        if (!strcmp(sd->s_name, name))
( k& n* v: i1 {. U- G  v            return sd;# F8 Z0 X$ X' ]4 Z% O
    return NULL;
* x; i+ T! \. P5 F) S7 T; K! ^- M}
. [: l( z; g5 i1 b$ J1 E
8 k+ q5 Y; p: C- w5 Y0 u/**
9 ]& J  R8 Q- P* _: T4 N *    sysfs_link_sibling - link sysfs_dirent into sibling list
8 r3 J) ?" H$ T! i% M: ?0 } *    @sd: sysfs_dirent of interest
% ^( Z4 ~( b: \* s. P$ f9 m- F5 x *
6 q2 ?, I# A* h8 k *    Link @sd into its sibling list which starts from2 A& R) s* G: L: C0 F3 z
*    sd->s_parent->s_dir.children., P. _6 ], ~  k8 v7 s- c/ e3 |
*! }2 Y; y, @* w2 k  E
*    Locking:
! x/ Y1 U& K) F: e6 b *    mutex_lock(sysfs_mutex)
* |) C! P# |, X  _# ~ */
* I3 W1 c/ P( R5 T$ C- Lstatic void sysfs_link_sibling(struct sysfs_dirent *sd)
9 B) V0 N' L' g+ j$ x{
7 D( q- F; A. M    struct sysfs_dirent *parent_sd = sd->s_parent;0 X4 U  ~  e; v) s6 ?. C
    struct sysfs_dirent **pos;
! y" [( E# `7 T) N' P$ n; h8 u% K2 y' k3 c
    BUG_ON(sd->s_sibling);5 w% m3 t% S1 x; \

* n$ j% |0 i6 x1 Y4 q    /* Store directory entries in order by ino.  This allows' u; q0 G/ A4 }
     * readdir to properly restart without having to add a4 s9 k$ ~* |5 A+ d+ v; i
     * cursor into the s_dir.children list.
  `  _! W! C% q- K- n3 B! g7 v     */1 Q$ d* e7 Z' B8 [: Q8 ^
     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/
1 S1 z' A( {- i* y    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {; b3 V1 b; }0 P9 O0 F
        if (sd->s_ino < (*pos)->s_ino)* F* j* J# h' P& H# C
            break;8 n, T4 R0 i+ H+ Z: H
    }
% J4 H, L9 `; G& F7 N+ s    /*插入链表*/
% w# ?* I6 A5 v/ ~    sd->s_sibling = *pos;9 `; c3 J5 f- j& t: V9 K) @/ J5 h6 k
    *pos = sd; 2 ~5 J8 p: d; |4 {  Q+ N% B
}
1 ?2 _0 e  y0 g- V: {& {该函数直接调用了__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链表中。1 ~4 ?4 C3 W( l9 [
8.3.5 sysfs_addrm_finish# e* v9 R. N, u: a
下列代码位于fs/sysfs/dir.c。: @$ }$ c' w4 g+ L$ H' S
+ E( E7 x$ E7 N; `# i
/**- I- P+ q7 z6 ?' }1 ?5 R
*        sysfs_addrm_finish - finish up sysfs_dirent add/remove7 L3 @  K6 e$ w% t4 g
*        @acxt: addrm context to finish up
- n* w, ?$ ?+ E& b% c *; G/ s" K9 {. o9 N+ _& n
*        Finish up sysfs_dirent add/remove.  Resources acquired by
# _- @2 V) Y8 H *        sysfs_addrm_start() are released and removed sysfs_dirents are: m7 |0 h  J) G( d; `+ U# z
*        cleaned up.  Timestamps on the parent inode are updated.1 f# T' ]" o! q
*' s1 Z0 f$ ~! p6 Y: r, A0 }
*        LOCKING:) T' @7 y# K& g# {, U' i' O4 Z
*        All mutexes acquired by sysfs_addrm_start() are released.+ u% u) C+ m* Q
*/' D0 c1 v8 M  r
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
$ W- E, F7 ~8 d, X# c* x{' X0 V8 ]: ~. y& u. j
        /* release resources acquired by sysfs_addrm_start() */1 g' K4 ?% l- A4 ^. |8 o
        mutex_unlock(&sysfs_mutex);
6 B3 m+ k2 }2 }1 a7 x: K% J8 e4 J        if (acxt->parent_inode) {3 r$ g$ s, _8 a6 `
                struct inode *inode = acxt->parent_inode;
  [% O) N0 m, q* U5 \+ M! _  ^6 N( Y  J
                /* if added/removed, update timestamps on the parent */: i. n- w" e0 ?, @
                if (acxt->cnt)
! O/ |2 e7 r2 Q5 l) \: h, _+ t8 i4 b                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/
( {7 K; Q  d0 a, u) A& ^! `$ j& p, s+ I8 u* O% P4 D
                mutex_unlock(&inode->i_mutex);! r+ Y! N& C7 Q
                iput(inode);
6 n8 C; l  a: M* B2 k% h7 F8 x        }
% g  A0 Y& ^7 G1 V/ Q* a! n6 `7 Q; H
1 ~' T! U9 `/ I( D5 k2 a$ x6 B$ j: j: i1 g( j        /* kill removed sysfs_dirents */
! ~" O( X# _0 F$ u! L8 X- v        while (acxt->removed) {
! w1 C2 S! i5 B" n6 K5 h                struct sysfs_dirent *sd = acxt->removed;$ V3 H6 Y4 T$ T5 G% O) q( G3 A

$ f. X' T5 Z) }9 s) K0 u                acxt->removed = sd->s_sibling;  Y7 Z4 i0 S$ `0 P3 K7 M
                sd->s_sibling = NULL;
# m. y* k' g( g" |; q% c+ J
9 y9 D# q% F" {/ r                sysfs_drop_dentry(sd);( h$ G) j6 g% a7 H
                sysfs_deactivate(sd);" E. i% c1 T. x
                unmap_bin_file(sd);4 ?8 V& q* K. \+ P; V' v( i
                sysfs_put(sd);5 S1 Y6 @" O+ H8 L  x
        }
9 v5 m0 N, R1 o) i0 B8 }- L}
4 X7 L$ O% O3 k5 r
+ t- ^/ q( u5 H该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。. `0 F; H- ^+ C- L3 p0 c. k6 y

8 Q! A2 U! C: `, P/ O9 R至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。: O# j) E( J" [( I0 O9 ]

! U/ V: L/ U/ ]5 X下面我们看下如何添加属性文件。$ R5 W& @) k8 @& J& s* A
8.4 创建属性文件$ q: V) ~6 _  w% s$ V! D% \3 Y" g* Z
添加属性文件使用sysfs_create_file函数。
7 k6 i! [+ a* R6 l3 W7 T
/ Z$ H2 J9 X0 c4 q4 S0 i下列函数位于fs/sysfs/file.c。4 C/ Q9 x2 j. ]6 ~
/**- q  N+ k+ Q  h0 ]' M
*        sysfs_create_file - create an attribute file for an object.
9 |7 ?2 f# \& k: [: s- _7 L *        @kobj:        object we're creating for.
$ u' Y9 V+ K7 b1 d+ Q *        @attr:        attribute descriptor.
$ e2 S7 V# M  X/ v5 `& Q */- R* y  w: B- h# H9 Y

9 n6 E! d9 W$ wint sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
- s) r: `3 _. o) }1 H{
/ O1 h- E% l* q0 g8 g/ m! p/ b, }        BUG_ON(!kobj || !kobj->sd || !attr);" @' Z( D, d' V, e4 A) X! Y

- t  X4 i* y/ F/ K        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
: ^; ?8 r# t1 p$ I$ f# }4 W4 c- l; ~; ~
}
, @+ l3 O: A: S* D% P! g9 M
* b9 I5 ?6 K: t. z$ |" m2 R9 M0 Oint sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
2 `% O) ^+ o) M0 E6 Q           int type)
, e' L% }; i% ?5 L) D. _{
$ `5 l2 N% c% t3 m* x* b+ O    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);
, e( d& x) k% |( L8 R}
7 H: V' Z. u" I
* v. c( r, o& ^8 sint sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
4 C3 a, g( Q) _0 U, F2 H            const struct attribute *attr, int type, mode_t amode)9 l0 M2 T8 J1 {# O( p) Y6 U: |
{% H2 r2 A& h: D& L4 w" v' @
    umode_t mode = (amode & S_IALLUGO) | S_IFREG;
/ J) S$ ?; v# J- A. b% U  E: E# C    struct sysfs_addrm_cxt acxt;
7 F$ {. k3 I# t    struct sysfs_dirent *sd;& Y; P" w: a3 [- Z  c
    int rc;3 e: o/ F0 e* D+ D, j4 O* h
    /*分配sysfs_dirent并初始化*/
# R& A+ F/ [  C7 S& y    sd = sysfs_new_dirent(attr->name, mode, type);5 Z7 C$ O- j  L: Q: Y& u
    if (!sd)
' X& [5 I# v2 t, ~. ^& x% Z        return -ENOMEM;$ f6 ]* j! _- w+ I
    sd->s_attr.attr = (void *)attr;
( n; `) O1 F2 N) \, j; N7 {- `7 W9 i  U+ ~
    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/- }! @1 B6 u$ i0 _
    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/% b- Z# h4 N: w. j5 J% K- g1 j
    sysfs_addrm_finish(&acxt);            /*收尾工作*/3 E& g0 s1 Z) ]! P, {9 P+ ~$ E+ Z

: P0 C1 z' j% S9 Q4 J) B1 z( g. o    if (rc)            /*0表示创建成功*/ 2 u% ^* q" ?$ x' L- D9 J5 }
        sysfs_put(sd);7 R9 f9 x9 G, g# P! J4 n+ d

+ @  K4 N' O0 o" S" F) b/ z) e    return rc;+ X; b$ A" r! y$ ?4 d& {2 p) Z
}7 h5 B: K2 W8 T

9 a& T( ^. ~/ I" H- L+ }sysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。
2 P8 `# r. h6 f/ \9 s" O) nsysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。+ @! O$ t9 i3 D) `( ?

* m( m; k0 f  K: {需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。' C! G1 `0 ]  k) }
8.5 创建symlink
) [1 b9 v' M/ a8 a( ^最后,来看下symlink的建立。, |! S+ D# M# G9 J) h# m9 p* n" C
/**
8 @5 }. Z# f: D! Z% r6 ^ *        sysfs_create_link - create symlink between two objects.
3 X* g) J4 c: F' D4 ]* \ *        @kobj:        object whose directory we're creating the link in." k: z/ |0 [* u( Z
*        @target:        object we're pointing to.
/ ^+ h4 y# p: k3 t *        @name:                name of the symlink.0 [9 z- @2 p! b9 `
*/
0 \/ I* i& J/ j- e$ Wint sysfs_create_link(struct kobject *kobj, struct kobject *target,
: t: t+ ?2 _' {7 J. I                      const char *name)
3 p* M3 u( T! ]( J7 J. Z5 V{
+ @$ x  l" ~4 Z1 n& @7 P' z1 `+ q        return sysfs_do_create_link(kobj, target, name, 1);
: k/ a5 a; F; x* j5 j" ~}: r. e+ k6 s* E4 _9 V, P
5 |8 s; A$ f/ |; h
static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,1 b) u8 \* k9 R$ e4 U
                const char *name, int warn)2 D  k: _! Y! e! s; V& F$ ~3 w. D: c
{
+ _- @' T( O) J% l    struct sysfs_dirent *parent_sd = NULL;6 Y) a- I- A- B0 n+ h: t+ r
    struct sysfs_dirent *target_sd = NULL;
9 v  \9 Q2 J# g5 i; L1 O    struct sysfs_dirent *sd = NULL;
, x0 j2 s0 f4 c* q+ j/ c* @/ g    struct sysfs_addrm_cxt acxt;
; ~" w  [- Q" x' y    int error;( d% U7 @. u9 h0 a1 o* N; {( ^: }
( T6 y7 V" x6 T! k7 K  K( G: ]
    BUG_ON(!name);0 w4 E  M% B2 v# B$ f

9 l! r4 g7 P$ W% [. S( P; Y    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/5 B. }$ U, ?/ R2 J4 B) c- C
        parent_sd = &sysfs_root;- ]4 z2 A3 K9 w$ }
    else        /*有父sysfs_dirent*/
. \& Q+ C" T4 X' G& l' m/ U        parent_sd = kobj->sd;
5 r2 O3 g/ E  i6 m* S2 t" J5 b4 B
    error = -EFAULT;% m. t/ c. j" V- D  u
    if (!parent_sd)( i$ t+ ^% r. n3 @0 v- d4 k9 l0 K1 h
        goto out_put;7 |! R5 c. V1 A2 V) F" N! `

2 i4 \% N; A0 j/ a: L$ E' J4 l1 u    /* target->sd can go away beneath us but is protected with, V7 h6 @; v! v$ J: b+ N
     * sysfs_assoc_lock.  Fetch target_sd from it.
6 `' z. y. Y8 ^8 h; c. x0 L4 K$ M% O     */
0 u' z9 a+ V* j" w6 b    spin_lock(&sysfs_assoc_lock);! x; [& L8 l* h& t% z9 u) z
    if (target->sd)
+ t; y$ P) U% Y- Y8 T& o        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*/
( e7 k  i5 ~  f5 d+ S4 w    spin_unlock(&sysfs_assoc_lock);
( t3 w4 f$ l( ~8 @( t6 L+ M0 l, R; o( J( p
    error = -ENOENT;4 h3 M0 U) n* ]) _5 g
    if (!target_sd)
* l' I( T/ M9 b+ v; y        goto out_put;- Y/ i( N. V. x. k" p

2 y/ X7 o: l; G% L    error = -ENOMEM;
  c2 e4 y  R2 N  _7 H3 L# d    /*分配sysfs_dirent并初始化*/
* m$ `- B8 y5 ]4 m    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
5 x$ [' N# B: r5 |$ H( e$ C    if (!sd)
8 S2 ~7 _) z/ H9 k" V        goto out_put;
+ K- T9 q) ^% r7 ?. ~& _+ c
" `3 b- v! d- {' s) t* w    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
; k2 ^) o: O, z% n) B9 B! H- l    target_sd = NULL;    /* reference is now owned by the symlink */  M- ~2 o! j7 d; X( H* y* s
- N$ o  w  K& t  A0 M
    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/
! T: h9 e1 Q+ Q5 q    if (warn)
5 M  `3 v4 s. B, o2 @$ a: n        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
' O" [3 v4 y, O7 _) e3 Q. u    else
) f& y& P5 s9 J# A, w+ `1 u0 g) l3 J        error = __sysfs_add_one(&acxt, sd);% e6 `& i: O. m' p/ E% S6 Y
    sysfs_addrm_finish(&acxt);            /*收尾工作*/$ S4 ^& |3 j5 Z' |% r
2 i5 ?6 V1 h9 j9 |1 ~
    if (error)
/ S0 Q! G& t8 K9 {# ^9 D& ^, d* D1 t        goto out_put;
8 @( ^8 R' h) q8 V" A& ~9 f% K! [) D3 h" X$ R
    return 0;
6 W; E3 {( ?0 U/ g0 F, |9 }! r6 N
& p; ^) L- o6 V! g; U1 d4 z out_put:' `- S4 @" D2 I; u7 c& h, W# ?
    sysfs_put(target_sd);
" C2 [& u" f5 \$ _/ M$ [! k    sysfs_put(sd);
6 y* p. Z. C: |% Z/ O    return error;' b+ E0 g, N! u, R
}
7 ^9 _" ], d7 ]! a  G, x- B( t- I+ i5 d
这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。- h6 j( P1 i7 a/ X& k
因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。
* _' ]8 [$ q# M4 ~
9 g0 u0 _* Y; k3 |$ {- Q7 ~8.6 小结* N' q/ e+ Q% [) \9 A; R
本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录
" E& h3 [  X% v  K) T! b
' K- Y% F4 u2 o% ~6 }1 {/ J7 B/ D有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。* l  h5 ?6 A) J3 N$ U% {3 `
! W1 _2 A! ~- l" A% U
9 总结
5 B  ?0 ^- R8 _# y$ {& a) C4 y本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。
( Z# H- r1 |0 z/ D9 P: l/ n% O6 F0 s$ X! H: u' h4 O! C
接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。+ ?) @! q. W* l, V

6 T& ~( `; A( I, L) M) `- H随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。
1 V" O: S1 v, ~  @% i# h( ]3 B  s# R( t
然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。
8 ?# n/ v- q  y8 x. ?+ Y( |0 \
6 y! \- [/ j5 k3 Z% T. ?  m% ^3 A之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。
1 S, A; l0 `2 Z1 l& `  I% C* l+ S3 [- a
最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。
- e9 u6 v7 _, n4 ^) S8 N( Z2 v2 I- T' u, X) F# i
' j- G. a" }3 e, a* m0 z

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-6-29 15:09 , Processed in 0.281250 second(s), 26 queries , Gzip On.

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

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

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