EDA365电子论坛网

标题: Linux设备模型——设备驱动模型和sysfs文件系统解读 [打印本页]

作者: uperrua    时间: 2020-6-17 16:10
标题: Linux设备模型——设备驱动模型和sysfs文件系统解读
本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的。在分析过程中,本文将以platform总线和spi主控制器的platform驱动为例来进行讲解。其实,platform机制是基于driver-model的,通过本文,也会对platform机制有个简单的了解。
: p1 Y: u+ b! r6 `* ~  D, M. M5 L9 ~5 ~$ y
内核版本:2.6.30
) e4 a8 n* Z; L9 g' R( O! ?+ o( T* Y3 }. P5 ~4 x9 C
1. What is sysfs?2 t, v. f6 `0 o# V  J2 a( L
  个人理解:sysfs向用户空间展示了驱动设备的层次结构。我们都知道设备和对应的驱动都是由内核管理的,这些对于用户空间是不可见的。现在通过sysfs,可以在用户空间直观的了解设备驱动的层次结构。
7 h* y$ `) s+ D3 l$ G0 j6 d! Q6 l1 y) S4 X! y0 {5 f
  我们来看看sysfs的文件结构:! w9 u: `5 t4 W/ b" D) N

/ D. D% g! b$ z5 o- C: `: {: r! ?[root@yj423 /sys]#ls
4 q. r. Q/ q- Z9 h  Q$ }" Wblock     class     devices   fs        module' Z7 _% p; }0 W' b1 U& j2 }$ b
bus       dev       firmware  kernel    power3 K+ _9 P$ U5 n
! ~  }( N( I) n! ?! j
block:块设备
% _9 J8 P5 q! v# l
; V6 M% l( ^" vbus:系统中的总线! G8 H: g6 O# H: d9 V7 [

3 Q3 L9 u4 |: B9 S4 bclass: 设备类型,比如输入设备
' J( B7 P1 }; o+ @# i) q$ c
# R* k1 K" Z1 q; @1 ~dev:系统中已注册的设备节点的视图,有两个子目录char和block。6 q* |/ F: A9 q" }
; O! e; z4 o; }
devices:系统中所有设备拓扑结构视图& B9 x* g' ~& w2 S$ M

9 l# p5 Z' ]+ I- tfireware:固件
9 d1 U5 ^$ \8 m/ u& N7 x
4 O0 B8 S, v6 a9 m1 {8 Qfs:文件系统
$ [" q% E& ~: X  D4 X
/ b; w& n  Y# t' ukernel:内核配置选项和状态信息5 M/ ^4 c2 s# k

* p2 ~; l% g: z4 a  smodule:模块
6 x& C0 B$ ~4 H8 n9 F: n, o; i: i6 l# b, z2 W, C: S2 Z
power:系统的电源管理数据
, r1 S- j' z4 F3 Z' k. [2 z  C0 }6 l/ S2 e# p- J( j- T
2. kobject ,kset和ktype4 d7 P9 o& E" a$ o
  要分析sysfs,首先就要分析kobject和kset,因为驱动设备的层次结构的构成就是由这两个东东来完成的。5 t* N! @# a6 o

6 Z* ^- G) A( c0 h  {6 Z; W9 ]5 @2.1 kobject
3 ^, f9 J/ F- e( C  kobject是一个对象的抽象,它用于管理对象。每个kobject对应着sysfs中的一个目录。
9 D) u; h# Q. Q9 Y' L& w: `& Z
7 ?8 n0 e& L2 u' S* C  kobject用struct kobject来描述。
6 h! t% p' f3 _0 w: v, A6 f6 [+ u& [/ I( U1 T( q. r
struct kobject {
& L0 n1 n# J4 j" ]% {& M8 U    const char        *name;            /*在sysfs建立目录的名字*/
) t* d1 j# X+ G    struct list_head    entry;        /*用于连接到所属kset的链表中*/3 Z  ?- q3 Z% z& R. A. a( P
    struct kobject        *parent;    /*父对象*/
9 o: J, \( l  _+ P    struct kset        *kset;            /*属于哪个kset*/$ x9 q: Y) Z2 d* E9 E
    struct kobj_type    *ktype;        /*类型*/) [/ D. l- v5 k& o, R
    struct sysfs_dirent    *sd;        /*sysfs中与该对象对应的文件节点*/" z* q5 }4 U2 r6 L* Q# {
    struct kref        kref;            /*对象的应用计数*/
: B+ ~/ K, d4 s: U6 Q    unsigned int state_initialized:1;
( `2 d( ?0 L$ ?/ B8 N% U2 e7 p    unsigned int state_in_sysfs:1;
% e- q9 }0 d# r2 F    unsigned int state_add_uevent_sent:1;
: B; ]% @% a9 D' Z, R. o& M    unsigned int state_remove_uevent_sent:1;" H% V( E+ `" a8 ]0 u
    unsigned int uevent_suppress:1;4 |& ?" ~5 ^3 [1 U3 P, k! i
};8 o: m( Z! X9 S, N, w& }
2.2 kset
1 i! k& h+ t1 u+ Z# q' v/ f+ U4 e  kset是一些kobject的集合,这些kobject可以有相同的ktype,也可以不同。同时,kset自己也包含一个kobject。在sysfs中,kset也是对应这一个目录,但是目录下面包含着其他的kojbect。# U0 J% x2 e, T4 e- i/ G0 B$ N
7 \# k7 P  e: {
  kset使用struct kset来描述。# U7 O1 w6 X# j/ f
4 |8 Q- }1 }7 K3 S! g
/**8 x* y) n6 S8 f% Q% h. w* t; Z
* struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.0 P0 f; @( ~6 a* w1 R+ C  s
*
  Z6 @7 `# i* S0 C * A kset defines a group of kobjects.  They can be individually9 {8 l) Q8 Q7 d4 @% K) J
* different "types" but overall these kobjects all want to be grouped# k& p# l6 R5 C5 h+ S  e% r
* together and operated on in the same manner.  ksets are used to$ P- X5 }" n/ f" m9 I* Y
* define the attribute callbacks and other common events that happen to2 d) R* V4 y  c) @. R) i
* a kobject.
3 f7 S& n: |( B& w. G$ |0 s *
2 Z3 k% V% l1 F( E2 ]5 B" u * @list: the list of all kobjects for this kset
7 b- ]+ M: J6 {9 ~" w( U * @list_lock: a lock for iterating over the kobjects
- V* g3 u) T/ b * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
7 k( R; o) U6 }$ h, l5 ^: b( z * @uevent_ops: the set of uevent operations for this kset.  These are
, m, }* D+ B# \) {7 l, I * called whenever a kobject has something happen to it so that the kset& r8 W# K& W1 g1 W- z4 F0 r) _5 Z* y
* can add new environment variables, or filter out the uevents if so
. S! K4 Y" F0 X+ s* @) D( n3 `) Q * desired.
$ L' z9 w( g3 _1 [: D */  l. |! s( K, \
struct kset {8 R/ i7 p: p8 S6 ]; @! D- R+ A
        struct list_head list;                /*属于该kset的kobject链表*/
4 `2 M. [$ m9 |        spinlock_t list_lock;       
0 G& E  l1 B4 {  X        struct kobject kobj;        /*该kset内嵌的kobj*/: ~" d, \4 A3 ]& u! p) c2 U
2 A* W$ j; ^. i
        struct kset_uevent_ops *uevent_ops;$ C5 k0 v. P/ ]
};: v! D+ y* m$ N7 n
  S1 t) r6 \' c& f( A; f& s
2.3 ktype
2 I2 p) b( `* s每个kobject对象都内嵌有一个ktype,该结构定义了kobject在创建和删除时所采取的行为。# [- B; A5 U& F( g* \
" S9 D: T( m( |, o: R
struct kobj_type {
% E4 c" E* B& T* Q    void (*release)(struct kobject *kobj);2 s7 }& o1 J* B" ^' ?3 g
    struct sysfs_ops *sysfs_ops;
- {2 a5 A% r) F( S5 Z  c    struct attribute **default_attrs;7 \! i2 ~/ S% e& `& w; b1 N
};9 x  }* o# D/ r; g- X

* W7 Y( ?; V2 C3 [' z8 R& y! m' Nstruct sysfs_ops {# E6 I& C5 H+ ]. N, k8 i0 [( D6 P- U
    ssize_t    (*show)(struct kobject *, struct attribute *,char *);
) |. w, h0 ^2 n    ssize_t    (*store)(struct kobject *,struct attribute *,const char *, size_t);
. U# {6 {6 i* P& s. B};
( _- W/ S$ g8 x. P& D2 }; [0 V4 V* _* W& B# L$ e$ k! a
/* FIXME! X& ]2 U2 }3 ^* {- D
* The *owner field is no longer used.( t: x% T0 S- K8 K7 y  o
* x86 tree has been cleaned up. The owner! J" D4 o8 d, r% `5 M
* attribute is still left for other arches.
, v2 a1 N! p+ ^2 x */
0 V* f. S; o) ]# B8 Hstruct attribute {
0 a4 Z+ G+ [4 }1 v    const char        *name;* g5 w  k' T, g
    struct module        *owner;
8 y1 x5 s8 h% c7 l* h0 @    mode_t            mode;
% }; d) H! d# W1 S};1 G( ^/ O' e+ v6 i' t. @9 {

, F6 L4 f6 \" S1 }& x1 P) P6 [0 R" m! D
当kobject的引用计数为0时,通过release方法来释放相关的资源。
4 h% y4 K* d% x) ^+ mattribute为属性,每个属性在sysfs中都有对应的属性文件。# |2 H! f. Y0 k) O1 Z+ ^! O
" Y0 ^8 Z, k0 L; n
sysfs_op的两个方法用于实现读取和写入属性文件时应该采取的行为。, \6 g. `6 {( [  z

4 |: R$ s# S  ?6 w2.4 kobject与kset的关系
" ?; L, W' x7 f. O  下面这张图非常经典。最下面的kobj都属于一个kset,同时这些kobj的父对象就是kset内嵌的kobj。通过链表,kset可以获取所有属于它的kobj。. P' o6 [# d- O* g4 a

0 v3 y; V% @1 p2 H* Z- ^   从sysfs角度而言,kset代表一个文件夹,而下面的kobj就是这个文件夹里面的内容,而内容有可能是文件也有可能是文件夹。8 K8 O8 r+ y1 n# y: D4 r; ]/ g$ n" k" |

/ h2 f# v0 o( L$ P8 F! ~+ ]0 t( o: z
) j; i$ [* r" l1 p" w! N+ F' D$ l% N8 c0 H
3.举例
: \( t( O" k" k. w% l: [在上一节中,我们知道sys下有一个bus目录,这一将分析如何通过kobject创建bus目录。
5 {+ U8 j8 U9 @& N& E. t# C
9 w( |5 w/ A& G6 U" f下面代码位于drivers/base/bus.c. I2 c: P* V' _0 F7 H4 _
int __init buses_init(void)' `7 G) r& B3 x( A* g4 b7 `
{9 n5 J$ a; e; E/ l# s( z, a
        bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);7 C  w" g4 y4 j+ h
        if (!bus_kset)8 [( n0 m$ v! i
                return -ENOMEM;
# m4 |: `5 r; F( a- H6 ~, f        return 0;
8 ?9 `0 `' p4 {' P' \/ M/ a7 n}& I" {' k1 G" b# r6 r1 f
  s' [; G0 X. [) ^
static struct kset_uevent_ops bus_uevent_ops = {
' L+ G+ g8 X4 F* i    .filter = bus_uevent_filter,) j7 j. Z8 H% p5 K0 g' Y
};
& n# d: _5 n) ?) P. f% K9 ]5 M' W- b& `
static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)2 |$ z# @3 K! j! s3 p2 v4 n* t6 l
{* R) i. M7 r9 a$ p. q$ [$ X1 C
    struct kobj_type *ktype = get_ktype(kobj);
5 o; b1 h. Q) Y7 ~3 r- o6 _. u! q0 J& M1 C
    if (ktype == &bus_ktype)$ G4 y. B3 k% L0 ^) K& @9 M
        return 1;
4 Q$ B+ ~/ w& t& N. x9 F    return 0;  S# A. t  A( @& H5 J& l: r, e  F
}
. W0 e% a0 H/ Y0 c3 P6 |这里直接调用kset_create_and_add,第一个参数为要创建的目录的名字,而第三个参数表示没有父对象。
- r/ h5 V$ @# v! J- x: ^$ N: O下面代码位于drivers/base/kobject.c" ~( k& C" L- C' k
/**) l' t, H* q1 D6 V
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
8 X7 F- J# `& ~7 O: c *- u: E) X3 C1 u  T1 b! v1 a! ?
* @name: the name for the kset
) ^6 I2 m* [4 o% m8 r& s! t * @uevent_ops: a struct kset_uevent_ops for the kset% F+ Q2 F8 s8 T9 Q/ h  H& L4 S' ?1 w
* @parent_kobj: the parent kobject of this kset, if any.
& W# Z1 Y1 y/ J& c! X, G# u! V *$ k$ l- g/ F+ @; Z7 ]( }
* This function creates a kset structure dynamically and registers it* U; [: J$ w# A( v4 C# j* `: ]8 i
* with sysfs.  When you are finished with this structure, call4 |/ N4 J6 d& v) O0 n* j' X
* kset_unregister() and the structure will be dynamically freed when it) n; g0 h3 B' C* Q$ S0 |
* is no longer being used.
* i5 G+ K7 u& n/ ^/ K6 p1 t *6 r6 e! k+ p& C3 J& Y- C  r
* If the kset was not able to be created, NULL will be returned.6 [: ~  E) {1 n0 A! O
*/; R" _- e4 i' A6 [
struct kset *kset_create_and_add(const char *name,8 `. ?9 U, R$ M) o) P
                                 struct kset_uevent_ops *uevent_ops,$ O" g0 @/ D- a- \$ Z, C
                                 struct kobject *parent_kobj)5 k/ o; Y9 J+ r. N) H
{
* |5 P' m* B( A9 }3 i, O; A  C( \        struct kset *kset;6 T2 K7 a8 i! D! I& r5 C* n5 }& B
        int error;+ `$ D+ E# n8 Y9 t, o8 H, b: C
0 M% z4 r/ \& f
        kset = kset_create(name, uevent_ops, parent_kobj);        /*建立kset,设置某些字段*/- M2 Q& V: ^( b( N1 m
        if (!kset): G' _7 a; d6 k5 w, B+ F! P  \
                return NULL;( j$ w' O# e% b  T. `( q
        error = kset_register(kset);        /*添加kset到sysfs*/
/ J+ }; E1 s9 W# ^        if (error) {6 _" B4 b; _0 O7 B- Z  i4 M
                kfree(kset);+ _* p" N9 f- \# }  X8 E0 S
                return NULL;$ c, s' N# x8 n8 |+ r/ Q  R
        }
1 W* o) Q' A. D# V0 |& j        return kset;8 u3 [9 C. [* Q$ O- o* j  N
}
8 P0 g3 i- B4 b) w& x4 E- d这里主要调用了两个函数,接下分别来看下。
, n- I: J7 J- X7 f% x7 ]
* M- I! f5 @: Y  R/ E: v3.1 kset_create函数  t# @/ Q6 i0 l* f4 H% D* d- [! M
下面代码位于drivers/base/kobject.c/ Z% e! p/ X; M8 C
5 J$ b6 C0 E( S5 X
/**
2 V8 ~- Z. _3 t. o2 G * kset_create - create a struct kset dynamically
- c' R, v$ w& R9 Z( F! I *
3 ^( {# G3 Y6 i * @name: the name for the kset& h' N) u+ U" O9 K8 R# |# t/ ^1 R1 }& A
* @uevent_ops: a struct kset_uevent_ops for the kset
/ s1 G& ~' ]! ~$ k  y * @parent_kobj: the parent kobject of this kset, if any.. d/ H( a$ a; o  T
*
: \6 I2 b1 F3 n0 s0 a * This function creates a kset structure dynamically.  This structure can
# N! g4 T1 X6 ?- _0 y+ C* ]8 ` * then be registered with the system and show up in sysfs with a call to/ e' Q) E4 R) s% e. B# W
* kset_register().  When you are finished with this structure, if
( n  ]+ N; n3 i$ [0 i3 L6 ] * kset_register() has been called, call kset_unregister() and the
) {9 [* }5 D8 e, f * structure will be dynamically freed when it is no longer being used.. E3 g5 V1 W2 |# [: p% a+ X
*
& p$ R2 n/ |. B- Z& Y * If the kset was not able to be created, NULL will be returned.
7 {4 U0 k  R& T' Z6 Z */
0 ?% U, f! W, i; m% |% Q1 M4 H9 Qstatic struct kset *kset_create(const char *name,
, c6 [, j! u; O, ]& X" E) Z                                struct kset_uevent_ops *uevent_ops,
6 o; L0 D9 j5 y. g' r& d) a                                struct kobject *parent_kobj)) I' X0 T$ O8 [# P4 Q" m+ C: Q
{
1 R+ M+ `' a- B! ]        struct kset *kset;
: @8 y/ ~9 R8 M# b8 d% `& Z; ~3 n
7 A. y. O$ X. Q4 v% l9 Y        kset = kzalloc(sizeof(*kset), GFP_KERNEL);/*分配kset*/
' s( T+ k. O# B' ~( O: P        if (!kset)8 D! A' C$ w1 j, ~
                return NULL;7 q: V2 L+ m# U* y/ g1 s
        kobject_set_name(&kset->kobj, name);/*设置kobj->name*/1 v, I; _/ V9 Q+ `4 J
        kset->uevent_ops = uevent_ops;
* ^+ e+ E, Q( d( j        kset->kobj.parent = parent_kobj;        /*设置父对象*/$ D& n, c6 i* ?! t: L/ H4 I

9 t: z5 z4 m4 c3 U" V        /*
- ]6 \- ~5 P3 `9 T% `- C& c" F         * The kobject of this kset will have a type of kset_ktype and belong to
! q0 M8 B: d4 r# R, S5 m         * no kset itself.  That way we can properly free it when it is
1 ^8 W3 v+ M" ^  W5 k9 K         * finished being used.
5 ~/ p, n$ _: Y         */
+ X# P9 `7 i9 L5 J" T# G        kset->kobj.ktype = &kset_ktype;; ]+ ~" a, j: U5 n7 q/ x
        kset->kobj.kset = NULL;                        /*本keset不属于任何kset*/
! e/ z2 Z0 q' B0 m. h
/ ?% p3 S+ d4 [& j        return kset;
8 V0 @& a8 I9 ]2 }}) p- Y8 u. X& c/ r: I
* F( N1 \7 e. f% H: r; p, p
这个函数中,动态分配了kset结构,调用kobject_set_name设置kset->kobj->name为bus,也就是我们要创建的目录bus。同时这里kset->kobj.parent为NULL,9 U6 {4 q/ c$ d( c) w! @( |# V( X
, ?: R( C6 M  ?$ H5 [
也就是没有父对象。因为要创建的bus目录是在sysfs所在的根目录创建的,自然没有父对象。4 o  x" \' L+ E* {+ f

- y, d* v) n5 ~( J随后简要看下由kobject_set_name函数调用引发的一系列调用。8 P$ @2 K7 y3 }0 U1 A3 F
  p: ?* W8 F+ X! X5 E
/**6 Z/ S  q. `! ^0 d" U! e
* kobject_set_name - Set the name of a kobject8 k2 W1 U5 T4 R1 d5 ?7 ~4 |
* @kobj: struct kobject to set the name of9 F, j; L/ g8 c1 C9 q
* @fmt: format string used to build the name
. {- T0 J# J- G *- {+ H$ E6 e" G9 Z. t4 ~5 l
* This sets the name of the kobject.  If you have already added the1 {5 y7 i" G1 ^% L8 f
* kobject to the system, you must call kobject_rename() in order to
1 p3 [5 V- A/ y3 n& d6 k * change the name of the kobject.1 l6 M& P! k/ V8 j, X$ D- P/ G
*/
! B( g& W& C" n. A* Gint kobject_set_name(struct kobject *kobj, const char *fmt, ...)$ v  E0 W8 R! g; i9 P& _, I
{
5 U  P4 \% D4 G! e- c: \% V        va_list vargs;
: J6 ?- Z6 {2 u        int retval;
0 N9 p: n$ |* a9 ~& Z! n7 v, ~/ h
  L* o/ K9 \( l% B" X- h2 m        va_start(vargs, fmt);
! S, C6 ]' U. F$ K        retval = kobject_set_name_vargs(kobj, fmt, vargs);* V6 E- f0 g5 |* [; g& I
        va_end(vargs);
3 `" s0 c! {( I2 [6 {. [9 I( i- N6 O" E6 \
        return retval;
) y, s6 e! h( M, e}  T: T. B! I! ^) \2 U  ~6 S  [

2 ?& x4 K7 r2 V/**& P8 j( X' O# U
* kobject_set_name_vargs - Set the name of an kobject
( u( C( |) [4 s4 x7 o! V * @kobj: struct kobject to set the name of
9 [! c( ?2 m/ s3 H: E' O6 I * @fmt: format string used to build the name  ?( p! V1 m: Y( N5 r* H
* @vargs: vargs to format the string.
: Q3 o4 ~( f2 |! k) k */3 O: v* v* B( ]7 {  P2 Y; l1 N) I1 C
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
& ?/ M' k6 f- ]! }. i$ U# v1 _+ ]                  va_list vargs)$ ]' `7 W/ H3 l# z* e
{
2 t. W7 S7 ~" [5 u, e    const char *old_name = kobj->name;' W3 t0 e) p* M; }% X5 S
    char *s;
  N7 W" U* \! J
- i# U& ]' V6 |) }  ^    if (kobj->name && !fmt)8 m. y% {6 M2 T4 `5 P
        return 0;: p4 B5 Z# X9 ]1 R4 N& F/ r

2 U8 K0 B% C- ?+ O; t/ b1 ?" [    kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
7 `& U# g6 i; h1 v2 |2 u5 g+ L- y' \    if (!kobj->name)
! ]& ^0 q8 \7 K8 j/ n: @5 ]        return -ENOMEM;
8 F$ F7 K# ?' [0 O' y( {
, H9 X* C6 x5 P    /* ewww... some of these buggers have '/' in the name ... */
, S! ~: h8 p* N" O    while ((s = strchr(kobj->name, '/')))
7 C( L( A8 k# h# v! i        s[0] = '!';. h; S$ M6 O2 G# z  g5 E
/ H, T. X, N/ F% ?  S! J9 Y
    kfree(old_name);
# p& k" D# L2 c) T. {  j7 w    return 0;
" G( ]" S5 ^9 u0 b; h}
( Z* f5 C* ]9 N' w% ?5 K2 C  Z9 _+ Y! ^# \. G
/* Simplified asprintf. */
/ E" ^; v4 A$ ~6 Fchar *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)% c0 f# _$ b3 i
{: y- [  u( `, O5 O* \% ]7 g
    unsigned int len;
2 P1 q9 w, c! l+ ]$ n% I* c" k    char *p;
4 c, y9 p0 A6 q9 g! G; U; Y    va_list aq;3 I1 Y: C9 W* s
& y& X( I& X' J2 F6 n2 ^$ Q0 s
    va_copy(aq, ap);
) F7 `1 u+ [/ n  k+ A    len = vsnprintf(NULL, 0, fmt, aq);
0 [1 L, X( H' Z7 l/ ]3 _    va_end(aq);$ H0 q3 Y/ d+ n
/ x7 Z* y8 D- v- C2 H0 x; v
    p = kmalloc(len+1, gfp);7 ~) ^' \' C& T5 A8 N% j; }! R+ N: F
    if (!p)& t, r9 I# w0 B  ?2 Q
        return NULL;
; Y% r( Z) {. A$ G0 k" g3 L3 k& f7 J/ L. B  x# P7 P7 m; t+ ?
    vsnprintf(p, len+1, fmt, ap);
  O1 {+ X5 ~7 [' E. C2 u$ E! ^7 M) B  x3 D* |* ^! p0 S) P
    return p;
0 I. @/ L; Z0 }9 B}
6 Z' s8 X6 b" E/ H  `7 O' h5 z3.2 kset_register' P6 d3 ?) s# O" s/ i, j
下面代码位于drivers/base/kobject.c。" P1 d/ u; L+ w2 @* r2 c5 c" {
/**
0 ~+ {. D9 h, k+ w& \5 K7 j! c * kset_register - initialize and add a kset.
8 b$ [4 {+ ]3 ]  Q* s0 ] * @k: kset.
/ ~: a( C( M9 F1 l  o */
: ^  s0 u3 ?5 X& }+ f1 R3 n- uint kset_register(struct kset *k)
, P6 l# ?+ c1 ]( t{3 T# W$ b' l9 N" }6 Q1 v
        int err;: d  L! H$ E; ]/ f9 x( k
+ _& ]6 R! ]& ^2 E9 b
        if (!k)2 K, `0 l& i; W! s: i' y+ S
                return -EINVAL;* v( @9 T* i' F% r' p5 x
  v. }& C7 ^: |9 @
        kset_init(k);           /*初始化kset*/+ F2 b2 g5 K+ G
        err = kobject_add_internal(&k->kobj);  /*在sysfs中建立目录*/. l# {. s- i5 x' \3 k
        if (err)3 J, ^; ?+ z# D9 Z
                return err;
; k0 H. \4 {4 X        kobject_uevent(&k->kobj, KOBJ_ADD);
; x! v; H& W# p7 ^4 H$ `        return 0;
0 T& i! X& ~: F) u; I}* d$ t% R# P7 N9 G1 `' e: j9 ?
这里面调用了3个函数。这里先介绍前两个函数。
! b$ }* R$ m  `, F. }5 [7 j: A) O3 n" }9 Y( c. `# w  r  n/ H4 q# ^
3.2.1 kset_init
* t4 Z; V) }( B0 M  该函数用于初始化kset。
2 Y: O7 K* ^: w$ X: T& Y$ n5 k8 [/ K+ _6 B
  下面代码位于drivers/base/kobject.c。
$ ?6 y- s$ ?- |
- h0 }7 T, L% ~. f" c/**; J5 S! u; \6 d/ B
* kset_init - initialize a kset for use$ i: }" C+ _3 T, ^7 F! q
* @k: kset
  w) y0 x$ s9 y0 y. x8 N0 N */" W) e$ i, j8 z, K2 N% j
void kset_init(struct kset *k)$ C7 J! U6 t; ^
{
# E7 T) {6 F5 v        kobject_init_internal(&k->kobj);/*初始化kobject的某些字段*/
  Q, F) _- x1 g. Z$ P        INIT_LIST_HEAD(&k->list);        /*初始化链表头*/" @9 Z3 N+ h7 s  U
        spin_lock_init(&k->list_lock);        /*初始化自旋锁*/
' o& U! R$ x7 l- K}9 C: s1 x6 O/ v1 s& v2 N& F5 C" _
& d; F5 M; r4 v6 u* m3 v# o
static void kobject_init_internal(struct kobject *kobj)
" c% d* r9 O( a, B# z{, V, e, ~4 H! h: K- i& M
    if (!kobj)
: w4 y+ w8 `, M1 F3 [+ u        return;
1 G. K# I8 ~" W) J1 E    kref_init(&kobj->kref);           /*初始化引用基计数*/
7 s' R1 {7 x# Z( L6 C; Y    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
8 ?; X* G  R) R" t0 X    kobj->state_in_sysfs = 0;& X, N2 B; K, Z: ?
    kobj->state_add_uevent_sent = 0;+ Q! I; S3 t) I1 N$ K% V
    kobj->state_remove_uevent_sent = 0;3 ]$ r: B) d1 e
    kobj->state_initialized = 1;
: g9 e. Z* c$ B& e. M& B}
7 @  v3 z" ]& w* a3.2.2 kobject_add_internal4 Q- a2 r! P4 B; G" M9 y
  该函数将在sysfs中建立目录。& `. Z9 O4 {) n0 Z2 i" _  t4 M
) c4 @  ]+ h& b4 M1 V  v
下面代码位于drivers/base/kobject.c。& `( s9 [& g4 S4 J- _4 o! Z7 C
static int kobject_add_internal(struct kobject *kobj)% O& k% \  }1 f0 F3 }% D1 ?4 }5 c
{& b7 O$ w* i- G; V
        int error = 0;1 K/ _/ V, T; t
        struct kobject *parent;
; V7 A4 r$ r4 }8 l4 b) e8 Z" t2 x5 F) P7 y6 }$ U
        if (!kobj)6 [9 m6 c' p4 R" Y# i
                return -ENOENT;
5 k/ Q( c. z4 o" n: e5 G& G8 \        /*检查name字段是否存在*/
3 t% l4 H. e0 S$ G; u* \7 G' w        if (!kobj->name || !kobj->name[0]) {
, ^! {2 N: @+ G( ]                WARN(1, "kobject: (%p): attempted to be registered with empty "& d) t$ i$ T0 E3 S% {$ F9 A+ p  P
                         "name!\n", kobj);& i" m! ^* p/ j& p8 B$ u& ?) ~. n
                return -EINVAL;) X* x' @! E. I3 r0 w5 d
        }! L/ z* \4 A5 X2 ?

0 i2 a8 Q7 }. {. d  W        parent = kobject_get(kobj->parent);        /*有父对象则增加父对象引用计数*/' V: |/ z$ \; p

# ~- N* C2 P  q( l/ m3 b9 u% d2 {        /* join kset if set, use it as parent if we do not already have one */
. E" {4 }+ c( S) i: Z" G        if (kobj->kset) {       
' L. a6 W  A$ X% N" K' e8 g  Z                if (!parent)* c' t2 E# n+ {6 m5 |
                        /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/: n7 L9 [! R9 p1 w
                        parent = kobject_get(&kobj->kset->kobj);+ U' ?0 j1 ^; |0 ?4 J3 V, I
                kobj_kset_join(kobj);                /*将kojbect添加到kset结构中的链表当中*/
9 ]6 S$ X) r# V/ o6 [                kobj->parent = parent;; v: t6 ^0 y+ h# ]1 |: u
        }
' f# L: s, ^8 T" y9 _
' `4 \" Z) R# [  @        pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
( ~8 l$ G# B$ T7 |0 R( u                 kobject_name(kobj), kobj, __func__,0 ?% {3 X1 y  C# E/ s
                 parent ? kobject_name(parent) : "<NULL>",
6 B' l% e) R0 |' W. i& l, J                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");7 u6 K/ F" Y% b! U7 y
- Q$ ~% W! u! ?2 E( N, l
        error = create_dir(kobj);        /*根据kobj->name在sys中建立目录*/
! g6 b2 E9 s3 ~, |3 Z( e        if (error) {2 G7 s6 m2 v9 ^: M, ?! \1 X
                kobj_kset_leave(kobj);        /*删除链表项*/
& @& [/ M: C! P& W# {5 }                kobject_put(parent);        /*减少引用计数*/
: _4 x8 o' B& [                kobj->parent = NULL;
) f9 F, P  D, q; U. D& g3 V
% f; z& N7 X2 [1 r6 J1 ^% x. U                /* be noisy on error issues */
' O* r9 j' H) I                if (error == -EEXIST)7 K+ k$ o4 O- g# d  Q
                        printk(KERN_ERR "%s failed for %s with "
. S( {' e0 G& J; K                               "-EEXIST, don't try to register things with "
, [5 @5 b. x2 s& F9 k; C* D                               "the same name in the same directory.\n",
) ^. [$ y6 K* V# {* R# ?  z0 m- i; P% |                               __func__, kobject_name(kobj));
7 ^* p( F! U# @7 _6 I# p2 o# B: y                else
/ L) k8 m( ?9 M4 p* E% ?                        printk(KERN_ERR "%s failed for %s (%d)\n",
! L# V; y* d" d& b8 s  X1 c                               __func__, kobject_name(kobj), error);- D$ h( C. D# C8 }( c
                dump_stack();% d% V1 ?, g) g. J
        } else
0 }' S6 I2 |  S  O$ F: ~  j+ b                kobj->state_in_sysfs = 1;
2 z; _8 J; ^- ~6 C9 U
/ o' B: o3 M  D( M% W7 c  @        return error;& ^+ g; E- ?5 }  @2 E: T
}
. b. w6 r3 V( _% Q; {
) E7 r5 e6 e/ M, t) `0 A在上面的kset_create中有kset->kobj.kset = NULL,因此if (kobj->kset)条件不满足。因此在这个函数中,对name进行了必要的检查之后,调用了create_dir在sysfs中创建目录。4 ~7 k3 o  ~2 W9 c0 Z: g

) R: ?4 ^4 e& D+ [在create_dir执行完成以后会在sysfs的根目录(/sys/)建立文件夹bus。该函数的详细分析将在后面给出。
4 m3 r$ u7 n  `1 k0 Z: T7 m# o& D/ V  ?, N- ?1 J( `3 s$ j
至此,对bus目录的建立有了简单而直观的了解。我们可以看出kset其实就是表示一个文件夹,而kset本身也含有一个kobject,而该kobject的name字段即为该目录的名字,本例中为bus。3 ?& @" T8 e9 r

1 z% t: l- @0 X$ \' |6 O  U4. driver model& n# U# s0 Q$ o! t( ~
第2节所介绍的是最底层,最核心的内容。下面开始将描述较为高层的内容。; r; ]- g1 v# I9 s/ a3 i2 R2 P! F6 B- Q
  y4 X( ~! Z! W$ F
Linux设备模型使用了三个数据结构分别来描述总线、设备和驱动。所有的设备和对应的驱动都必须挂载在某一个总线上,通过总线,可以绑定设备和驱动。
6 H% G- s. S2 I0 v& E
( M3 F3 |' C6 N+ K5 W* {% J这个属于分离的思想,将设备和驱动分开管理。
8 g/ p; ^; l5 Y" F! J3 Z
6 X4 j- U) l* I& W6 P: q3 J同时驱动程序可以了解到所有它所支持的设备,同样的,设备也能知道它对应驱动程序。
  z1 X7 |' w  C0 \! q7 r- C* i/ C/ l4 Y+ L
4.1 bus5 x) Q' T# F/ G0 w
总线是处理器与一个设备或者多个设备之间的通道。在设备模型中,所有的设备都挂载在某一个总线上。总线使用struct bus_type来表述。- n" a8 m+ l. g2 s  [
1 }9 B6 F- E6 c- L9 J! m
下列代码位于include/linux/device.h。1 N( I1 L5 T. Y- R# ]  x6 X/ Z
8 ~0 n: v7 L6 p! m9 S

' ^! e& P1 ]3 c& T- ~+ i6 {( n. _struct bus_type {
' J" U  b. ~: \2 x- a    const char        *name;" h  R- X% x8 y3 l$ H
    struct bus_attribute    *bus_attrs;
# D( l- T3 ?8 N    struct device_attribute    *dev_attrs;2 k* Y4 u& w4 h3 g  w& y
    struct driver_attribute    *drv_attrs;: a% \# w, r# y+ `" K  j! b7 d
5 q7 T( o, a. V' e
    int (*match)(struct device *dev, struct device_driver *drv);+ @% p# D; i: g; V& `0 e3 k, p
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);7 x6 c: N% e9 Y2 [) L% v' Q' h: d
    int (*probe)(struct device *dev);) S1 m, d7 _7 O" [# \
    int (*remove)(struct device *dev);
! ?* X" m# Q) [8 x' p# R    void (*shutdown)(struct device *dev);
' O3 u3 y  B1 I) k
. `3 p6 z7 L5 U    int (*suspend)(struct device *dev, pm_message_t state);
4 s  p8 K$ S/ [0 h3 Y0 m( X    int (*suspend_late)(struct device *dev, pm_message_t state);
  _1 o7 U2 r* b; Y: K    int (*resume_early)(struct device *dev);9 A, F# f' }8 V" i# A
    int (*resume)(struct device *dev);: R7 V& ~) t  u; A( I! S: M
% J$ g2 d; c  k6 S: W
    struct dev_pm_ops *pm;$ L  A6 p- O* \" c. Z8 j) {- g7 @2 J

8 ?. F1 E' V7 e( o9 ]    struct bus_type_private *p;
2 C$ c5 o! t! j( j. [7 `};/ B1 ^6 j* p1 u+ i  b3 t" v
' V$ j% O* v! y* z$ L( W# d, s) L
/**
5 S8 F( l4 S+ S" i) a" V7 N- M * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.
2 e  l7 l7 {' X8 L  t: O *4 a2 d. u6 ?+ L9 B1 p% ?; J
* @subsys - the struct kset that defines this bus.  This is the main kobject+ r- a. ?* w8 X. J
* @drivers_kset - the list of drivers associated with this bus
' I/ u0 M8 o# W) ^- l& [, [# n; T! M * @devices_kset - the list of devices associated with this bus
/ W; x, F% H8 c; r* f4 R * @klist_devices - the klist to iterate over the @devices_kset
1 \  ^0 _& f  S1 X * @klist_drivers - the klist to iterate over the @drivers_kset
9 i  Q0 k5 q" C9 r( \) D- X * @bus_notifier - the bus notifier list for anything that cares about things
: i2 `- s8 s- \5 t; R+ q  g * on this bus.) @- o% `4 y  }5 C; z+ W
* @bus - pointer back to the struct bus_type that this structure is associated
+ o7 s: W8 d9 i" p0 f * with.
: [, T( u, i9 Y* O" M7 f" j *
" ^- |, s& I" ]8 C/ U/ g * This structure is the one that is the actual kobject allowing struct
9 m! F0 o3 ^) G9 Z * bus_type to be statically allocated safely.  Nothing outside of the driver1 w. i# f: v+ n* A0 X& O4 N6 f' L# }5 H
* core should ever touch these fields.
6 t2 J# F) V/ {" o" _ */. T8 h, H9 T8 V6 G6 V
struct bus_type_private {- A; p) b3 d6 w8 ?
    struct kset subsys;* Z6 s- z( }& [1 U. v* r: c1 g0 w
    struct kset *drivers_kset;
- ]! X8 h3 S/ U5 Y0 h( [    struct kset *devices_kset;
+ q* Z  O5 j. p: v3 C    struct klist klist_devices;6 M' s& q' w* I$ e1 K3 \9 c
    struct klist klist_drivers;
$ T. S( \% U& S    struct blocking_notifier_head bus_notifier;4 }: o( r8 B, b+ a# s- J
    unsigned int drivers_autoprobe:1;! w8 P1 x# A, Q  N
    struct bus_type *bus;+ f- S5 c; o. J+ a" Z
};: ]) n3 @; V' u5 \: L
我们看到每个bus_type都包含一个kset对象subsys,该kset在/sys/bus/目录下有着对应的一个目录,目录名即为字段name。后面我们将看到platform总线的建立。, G$ X: w& B, \. |. I* y( @
drivers_kset和devices_kset对应着两个目录,该两个目录下将包含该总线上的设备和相应的驱动程序。
/ S6 I, ]" Z: B. y' F" }
3 C; _; L( N/ O2 s2 H同时总线上的设备和驱动将分别保存在两个链表中:klist_devices和klist_drivers。
8 j# t- f+ i+ ?1 N% E2 p, ]$ B3 }1 G0 q1 s" \6 i5 g; y
4.2 device
6 ~& ], f: b; x" \设备对象在driver-model中使用struct device来表示。& j0 _- @6 [; w# o9 t

2 K; p; U8 Q" z/ a. e  `7 l$ T% e下列代码位于include/linux/device.h。: Z" I; i$ z. z8 g
struct device {
5 Z( t) \$ L/ N2 I) O; [3 e        struct device                *parent;( N) m. s/ ]7 I# ^' O" Y2 d1 r
% A* v7 H+ y+ e! X1 j
        struct device_private        *p;
- L- i) n: k0 p1 h9 e4 i
/ @9 l- L' Y9 r: S' G        struct kobject kobj;
+ p6 U6 D! U) p8 n0 _        const char                *init_name; /* initial name of the device */( S4 {+ t- V' u' j* D7 U. p
        struct device_type        *type;% O6 ~1 K9 x: i- ^) G: i
; o4 M: {& O$ f8 \' Z) f
        struct semaphore        sem;        /* semaphore to synchronize calls to& t/ f3 ?5 @5 ^( z; c
                                         * its driver.* G8 C* U, i3 a: v9 m
                                         */
1 q; [5 q! l' @4 @6 q- l* l
/ ]; Q# ^" A* [4 [4 L% W! u        struct bus_type        *bus;                /* type of bus device is on */
: p: a$ E! \$ c3 X# w        struct device_driver *driver;        /* which driver has allocated this
4 |, g* N% [" f, U1 P8 D% T                                           device */8 o2 |) P: R: V! e' q- c* Q
        void                *driver_data;        /* data private to the driver */6 h3 H- u0 ?- r: @! \
        void                *platform_data;        /* Platform specific data, device
/ k- s& W0 K1 T2 Z                                           core doesn't touch it */
! U" [' i2 _2 r6 d        struct dev_pm_info        power;
/ c8 Q1 o; d! U. _/ i. c" i9 O. P/ g$ m1 \. l
#ifdef CONFIG_NUMA
7 I" ~1 g2 s+ q/ M$ F        int                numa_node;        /* NUMA node this device is close to */
/ c3 }# |& x% s; t+ `#endif! A; S9 m1 ]0 i% r, O  _$ d  m. z4 J
        u64                *dma_mask;        /* dma mask (if dma'able device) */
+ t/ J/ L7 C$ e& x8 N        u64                coherent_dma_mask;/* Like dma_mask, but for2 u% p5 Z/ `% f8 t' D! ?8 t* Z
                                             alloc_coherent mappings as
. s& q; U1 R  P8 ]& P2 V+ m                                             not all hardware supports
( f, ^# s+ {0 r( b1 t1 I; L                                             64 bit addresses for consistent* y9 X1 H2 L& X, M2 L8 ]
                                             allocations such descriptors. */" Z5 f% J' ]) C6 R; G, f& `0 g

/ Y3 O4 w9 i" {' w1 x        struct device_dma_parameters *dma_parms;
! B) \; P# p/ x) g4 P2 X- ^; K3 _+ \9 g" r# n1 V- Z
        struct list_head        dma_pools;        /* dma pools (if dma'ble) */& a; P% _8 X8 r1 y0 o

. Y% J( {( A0 m/ @) c" o        struct dma_coherent_mem        *dma_mem; /* internal for coherent mem
' s- ]3 k/ p& z2 s$ M  @                                             override */
$ s& v3 C1 g* `6 R3 }1 P* M# Q        /* arch specific additions */
2 L+ P$ w5 N! I3 c0 \- X* D        struct dev_archdata        archdata;5 O) A! p; @5 o7 Z% {9 T7 H
$ ~% \0 E/ u! m* w1 q! d; ?
        dev_t                        devt;        /* dev_t, creates the sysfs "dev" */
4 _( a. u/ P# S! }* |. c
9 h, }8 @, r4 Z" U/ u! }        spinlock_t                devres_lock;* g# ~% _, j* z; `) a3 p# y/ m0 v/ |
        struct list_head        devres_head;
3 v8 _: y: n" m) X4 R# t
6 k, r- x2 X/ P8 E" u        struct klist_node        knode_class;) T, K! a1 [$ L( o0 V0 }
        struct class                *class;
5 }8 A9 ~* X4 B6 R9 m        struct attribute_group        **groups;        /* optional groups */
5 \4 m9 {1 J0 {0 L! v' Q8 [6 _  U2 _$ o/ D( P9 h
        void        (*release)(struct device *dev);1 r& ^3 ^8 J0 q; ]  U, m: ?' L; V
};
! w* j8 l4 A1 E: u1 }
# R& w5 a. y5 U7 w% N) s7 C/**9 g2 N7 ?* E4 n  X/ d7 m
* struct device_private - structure to hold the private to the driver core portions of the device structure.. ]/ h8 f  {+ h+ A# \3 [2 P
** x- V. u9 q$ p
* @klist_children - klist containing all children of this device
+ r% P1 Y: x$ P+ @0 Z * @knode_parent - node in sibling list
4 N. x. D! Y8 y  H+ ~2 I" E * @knode_driver - node in driver list
9 {6 I6 k% W8 W/ O- Z3 t1 ` * @knode_bus - node in bus list* H3 Z: R; ^! a
* @device - pointer back to the struct class that this structure is
5 X! ~$ c: J* K* R9 n; \. A5 b  k * associated with.- ^  r  [% e1 u5 c4 J' W. j, S/ c
*
3 T; X1 F/ L/ Q  I' G * Nothing outside of the driver core should ever touch these fields.
" L( W3 u2 j) I" {) _ */
( O, R0 j9 L+ s! C6 kstruct device_private {
/ ~7 \7 c9 \1 k- B" J  h# l    struct klist klist_children;
' a8 l3 J' [# n& s    struct klist_node knode_parent;
6 G% }; A+ m6 r- d    struct klist_node knode_driver;2 ^8 e0 l" e- }; ~, u6 t
    struct klist_node knode_bus;% R6 c& \5 V6 A# q! g5 D" t( W" v
    struct device *device;; u: ^% ^, G# _; b) c4 V
};
2 d" K: _: z9 u& W6 hdevice本身包含一个kobject,也就是说这个device在sysfs的某个地方有着一个对应的目录。1 c+ n8 `' k& i0 h. H; ^" g# L
9 l$ F" c% ^3 _/ C; I+ \
该device所挂载的bus由knode_bus指定。) n, }7 S) ]. Z) r
$ ]6 Y" Q7 ]$ N0 o# G
该device所对应的设备驱动由knode_driver指定。
) Y* t+ i2 V4 p/ x  [% j) d: E( I5 p, ?8 `+ `3 f2 b' _- `$ n9 ^
4.3 driver
$ j  N) t4 D/ N8 \' d设备设备对象在driver-model中使用struct device_driver来表示。
. u/ f# w# {! w; @
! R8 n4 R* c' z5 Z6 S4 g7 N下列代码位于include/linux/device.h。8 _2 S2 B: m1 @" u5 V: c
struct device_driver {
8 F5 j( d" a: S- Z' e  ^" ~& ~3 s        const char                *name;6 n* M7 j- e& q% D
        struct bus_type                *bus;- f- J7 j' @$ m$ G/ z, G

3 {: i+ k' \/ x/ k: h2 Z        struct module                *owner;( S& k& \: F6 y2 h0 c% F
        const char                 *mod_name;        /* used for built-in modules */) {+ J, D3 {$ Q4 ^

0 h- n9 G0 n8 K+ j$ F        int (*probe) (struct device *dev);( K. `) M* O/ g
        int (*remove) (struct device *dev);
2 ?' C6 t& ^$ p" i& H        void (*shutdown) (struct device *dev);
, G" U) m6 K" R0 O3 L4 p        int (*suspend) (struct device *dev, pm_message_t state);
9 s7 V7 T' T4 W" g; c5 e) A        int (*resume) (struct device *dev);
' s9 d7 R) D' E1 l$ w        struct attribute_group **groups;
3 ]) v( B& z" [' x3 G' S6 ?% a
        struct dev_pm_ops *pm;) i" e2 H9 f4 u+ s% s
  p. \" S" c/ q1 i: j3 o% z
        struct driver_private *p;
: B; u/ y% N3 i1 O$ W};
3 c* p9 A( w0 V* X" g) a) l7 o
3 @3 h" ]7 X. i& B8 Ustruct driver_private {
" N8 x! H+ M6 p4 v    struct kobject kobj;
) v9 h* [  Y; v. [5 D9 [7 x+ W    struct klist klist_devices;9 w6 k3 h5 z! t; m0 d* b
    struct klist_node knode_bus;
0 ?2 W2 r$ L. D/ f/ y# a    struct module_kobject *mkobj;
! l* o% ?( L/ l! O- I* _    struct device_driver *driver;
. w; T" j0 [$ T# F}; " I# P6 p3 o. _( {  t; }8 ^0 A
device_driver本身包含一个kobject,也就是说这个device_driver在sysfs的某个地方有着一个对应的目录。% z8 u5 K, q' y# Q
该设备驱动所支持的设备由klist_devices指定。
- t& k7 m- ]: Y9 u
/ b$ P# u6 B' S$ ?! |该设备驱动所挂载的总线由knode_bus制定。) N, h# }8 K3 }9 b. j' ^) d: V
7 S5 X5 E5 j2 m/ f- z
5. Bus举例2 I7 X$ A+ G4 D+ t2 T5 J1 G6 p4 C7 I
本节我们将以platform总线为例,来看看,/sys/bus/platform是如何建立的。( l) X6 q- \; z

- Y1 S5 n; P3 |& yplatform总线的注册是由platform_bus_init函数完成的。该函数在内核启动阶段被调用,我们来简单看下调用过程:7 D7 |) l3 f" h7 Z3 t* q

  s/ c! p( ?- B2 I* G2 [start_kernel() -> rest_init() ->kernel_init() -> do_basic_setup() -> driver_init() -> platform_bus_init()。
; b/ @, \0 E) h& R
; w2 F; u8 @; U: T4 |注:kernel_init()是在rest_init函数中创建内核线程来执行的。
( M# s2 x- w0 n& f8 ^% s: Q9 [: m) y& N

: f6 ^" O4 N- b9 y
( Y# @7 I7 ^$ G; i8 g7 {6 I) ?( {  _9 zint __init platform_bus_init(void)0 d3 m; t9 }. [& e8 ]) f
{
- W6 }5 Q: C2 F' T7 W& s! t    int error;, B# p9 i  m; V

" p& K9 U/ m7 U. e    early_platform_cleanup();
; z# ^8 a) x; U( X& T' C2 c4 x  N+ A! U
2 d) x0 J: J% F; o1 \3 n    error = device_register(&platform_bus);
! ]/ B# I1 C4 X/ q1 n" W    if (error)
$ o% ^* }: m% ~/ D* Z1 a% h$ B        return error;
" t, B  V& B' A6 g, F    error =  bus_register(&platform_bus_type);( M* Y7 j/ X4 v
    if (error)
# p% i7 y+ k0 N) I! W        device_unregister(&platform_bus);1 M2 F% D& R; x/ j% q
    return error;) }2 d  j( [8 W9 ]- u+ P/ L
}! j# z* s3 w( W7 G' B( a
struct bus_type platform_bus_type = {
) Y2 {9 t) t  Y' l& k        .name                = "platform",, }! m: h3 X; c* \9 Y+ _  t
        .dev_attrs        = platform_dev_attrs," u  q* |7 _/ y4 l' x6 G
        .match                = platform_match,; ?( j. {. R- |. c( p- }$ R( G
        .uevent                = platform_uevent,3 a% q! [! q* G0 M% V( O# g2 ~
        .pm                = PLATFORM_PM_OPS_PTR,
! ]$ d7 Y, ?" n) v};2 D2 [! S  T$ D5 l4 Y
EXPORT_SYMBOL_GPL(platform_bus_type);
  B- q  o. ^- V* H  \' b从bus_type,我们看到该总线的名字为platform。! p9 k' ]2 D! A/ ~' v* p
调用了两个函数,我们只关注bus_register函数。, W4 o% E. R- M( o# f8 V

2 X$ Y' p3 h' I1 @! e
9 K  e! F; F4 l8 F+ B/**
* d+ F& Q% W5 h! t9 j  q * bus_register - register a bus with the system.
$ B/ p" L" ?1 s5 o * @bus: bus.
- f( ?; D6 K* i' h8 i- ~ *9 D( D) i, g1 x" {- f
* Once we have that, we registered the bus with the kobject
5 O1 w# w3 f9 u- F' |2 B * infrastructure, then register the children subsystems it has:
6 m% \2 k3 ~8 u7 `- `- H! { * the devices and drivers that belong to the bus.3 T/ r- C! i1 S$ ~: _- i, W. E* J" v
*/2 h8 q0 J0 o" P8 ~+ J
int bus_register(struct bus_type *bus): P4 W5 G& B; \
{
4 M: c0 a7 B$ e5 [        int retval;
# t9 Q9 i; t1 A! a5 D2 d        struct bus_type_private *priv;
2 y& Z% _, O6 i4 k- O0 `
5 O4 P& X1 Z! c: k3 G! [        priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
2 U, A+ B& F1 K  A7 O# H9 v7 C        if (!priv)& n4 Q+ w6 p0 X! a
                return -ENOMEM;
% V5 p% E# F7 M$ O        /*互相保存*/
2 F$ x/ w3 a) B7 J( V        priv->bus = bus;
/ ^2 _: }. F  C        bus->p = priv;1 ~% |4 _, C) c/ f, D9 C; i
# M) r, o: X9 s( M( j3 S% [  c% _
        BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);' M1 ~9 n$ w# G9 N
        /*设定kobject->name*/
$ O8 r2 \# [8 i3 G  j8 N        retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);# l3 }' Y% _7 R4 M% ?, G; T
        if (retval)0 |+ }' }; q5 P/ N1 C' Z' g5 L6 \
                goto out;
4 L+ m; z- }9 v* a9 N7 K; v& |6 e& a4 g/ u# K
        priv->subsys.kobj.kset = bus_kset;4 C: p4 s: O8 c9 ]: V/ F
        priv->subsys.kobj.ktype = &bus_ktype;
/ x/ _& Q) M7 x7 |& n# I        priv->drivers_autoprobe = 1;/ P* ~0 o( v$ E& P( F

3 t/ ~  e. o; M! S        /*注册kset,在bus/建立目录XXX,XXX为bus->name*/. D( [7 j1 S# \; |' k( N4 F
        retval = kset_register(&priv->subsys);       
/ i/ h" h# k5 p4 w3 T        if (retval)
# T; i8 n: y# q5 h6 X                goto out;
( F5 B1 F) P% k- G
+ e, ~5 s+ \' [4 p        /*创建属性,在bus/XXX/建立文件uevent*/% ?' ^/ J; U, r7 b6 f
        retval = bus_create_file(bus, &bus_attr_uevent);% v4 F/ X; Y' g
        if (retval)  T7 {" U& N* I% F6 H5 g
                goto bus_uevent_fail;$ e- a& i: y* v
3 @# x& }% C4 j9 ~/ {
        /*创建kset,在bus/XXX/建立目录devices*/
4 c  {3 V7 n0 E3 M+ C. H        priv->devices_kset = kset_create_and_add("devices", NULL,8 @; Z; X8 E' D7 M. i* _0 K  l- a+ Z
                                                 &priv->subsys.kobj);
4 C* n' B2 C# F: s  h$ r' `        if (!priv->devices_kset) {# c9 T' O0 K7 n# [( Y
                retval = -ENOMEM;$ |7 k$ _5 Q0 o' e7 C
                goto bus_devices_fail;4 Z" @3 t/ H" b+ a' F" l
        }
- P$ i1 F2 `: Z+ F5 Q. C3 G( O' C+ d$ d3 f+ |7 B3 C8 Y
        /*创建kset,在bus/XXX/建立目录drivers*/, a2 V/ g+ v. ]+ x! |
        priv->drivers_kset = kset_create_and_add("drivers", NULL,! p6 s6 _9 m6 R, i8 ?& r
                                                 &priv->subsys.kobj);0 i+ G& e, G+ R- E5 \
        if (!priv->drivers_kset) {4 h& ]6 z( _5 ]# y6 e
                retval = -ENOMEM;) L# ]/ a8 I. r1 j- R7 r- b6 [, p4 B
                goto bus_drivers_fail;0 |$ G7 v8 Z. a9 e
        }4 I: b1 ?) _& f+ ~9 J. t
        /*初始化2个内核链表,*/  m( o, d1 f! s3 H
        klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);+ A" F- Y9 l( z& G" r0 _1 ^5 _4 m# A
        klist_init(&priv->klist_drivers, NULL, NULL);& f3 w( K3 [& H6 F2 Z) B/ c

5 B, A, d( c* |& M6 }2 [        /*创建属性,在bus/XXX/建立文件drivers_autoprobe和drivers_probe*/- _$ b6 G; d( J7 v) D; `
        retval = add_probe_files(bus);( d& C  R9 o) s$ E4 O1 V3 s7 m) Q) c
        if (retval)
) T3 ]% |: x( i7 p                goto bus_probe_files_fail;2 k* _- f9 a4 P7 O! Y, F- _
        /*根据bus->bus_attribute创建属性,在bus/XXX/下建立相应的文件d*/! x1 V5 G+ ~& |& s0 v8 K0 Z3 @
        retval = bus_add_attrs(bus);
% j+ j& g3 d" T6 ~2 D        if (retval)3 ^, E3 @3 Q3 t
                goto bus_attrs_fail;% n$ |* n, j( G) V& W8 s
: L% ~5 W- i0 r. E' j: u, D+ K( M
        pr_debug("bus: '%s': registered\n", bus->name);$ k/ \' J- z: O  K: E
        return 0;5 C/ b8 q* k* i3 X

+ Q/ X; f* ^4 T2 i5 x7 Z% Rbus_attrs_fail:
3 ?$ C) {  \: W1 z        remove_probe_files(bus);$ o; P- R' K: @4 h
bus_probe_files_fail:& T# p0 p; @% U" _
        kset_unregister(bus->p->drivers_kset);
- E8 z, ]/ Y8 @; ?& Cbus_drivers_fail:
, k/ n  Y0 D& I9 J- K3 j4 F        kset_unregister(bus->p->devices_kset);
3 `7 ^( w7 H3 I. h* rbus_devices_fail:2 R! e3 [5 C" B1 E6 }+ y' \* U
        bus_remove_file(bus, &bus_attr_uevent);
) L; ~3 z% C. Q6 c8 Ubus_uevent_fail:
8 e) P) X6 ^/ p( c9 m! n, }" f# A        kset_unregister(&bus->p->subsys);) U& r' U" \. `2 {! h
        kfree(bus->p);( z' E" K  O& i! {" Z) ]8 j# K! g/ n( T
out:
9 j- d: H) C  }7 U        bus->p = NULL;  Q3 ?, |) _" Q1 I  A2 \" f+ w; ^
        return retval;
6 e9 b8 e6 C4 e0 T; _}
% A) y9 F& J0 @/ u' T) i( b- nEXPORT_SYMBOL_GPL(bus_register);
! o0 w4 G: ?; i3 {. c% w# X4 ^+ n2 L1 P3 c
函数中,首先调用kobject_set_name设置了bus对象的subsys.kobject->name 为 platform,也就是说会建立一个名为platform的目录。kobject_set_name函数在3.1小节中已经给出。8 q9 B  ]  l& l( f! l  I2 }' |+ I
在这里还用到了bus_kset这个变量,这个变量就是在第3节buses_init函数中建立bus目录所对应的kset对象。
$ o" z( l( v: W% H' {: j7 g1 z' D& {2 R+ f
接着,priv->subsys.kobj.kset = bus_kset,设置subsys的kobj在bus_kset对象包含的集合中,也就是说bus目录下将包含subsys对象所对应的目录,即platform。  t+ Q) s% S' r" ?# c) }- D  ]

; y. G5 Z* ]/ @& w6 |( i紧接着调用了kset_register,参数为&priv->subsys。该函数在3.2节中以给出。在该函数的调用过程中,将调用kobj_kset_join函数,该函数将kobject添加到kobject->kset的链表中。
0 y5 y( W; ?6 t+ l$ r2 {, \
0 A! D/ N7 _/ b  ]% ?3 M6 ]! w2 F5 S0 I6 t2 b
/* add the kobject to its kset's list */
, e# P/ V( ^: \7 pstatic void kobj_kset_join(struct kobject *kobj)( C0 u8 f/ L5 t6 H( d
{
/ J4 p3 W( P; ?        if (!kobj->kset)
3 [5 k( Y# `8 C% ?. j; A8 A- t9 b8 f                return;8 L; ?; E% e, H. |5 f

: @+ z( m* T% i, `4 v        kset_get(kobj->kset);        /*增加kset引用计数*/
. s7 ~9 Z* T2 ?) n        spin_lock(&kobj->kset->list_lock);
9 Q7 m! k8 u5 y7 d6 }9 Z        list_add_tail(&kobj->entry, &kobj->kset->list);        /*将kojbect添加到kset结构中的链表当中*/+ D6 R3 M) {& B5 \% o! o# X
        spin_unlock(&kobj->kset->list_lock);7 e3 j2 ]# {: ~9 n# y$ o
}% `# R$ a5 s1 ~( K' Z% z
kset_register函数执行完成后,将在/sys/bus/下建立目录platform。此刻,我们先来看下kset和kobject之间的关系。  T( Q/ N8 d# s* o4 o9 j' t& t

6 F( q: C# b' N6 ~
2 {. h- e* I! M- e& e/ ^
2 \# t, D( h# }; W' J1 |7 s然后,调用了bus_create_file函数在/sys/bus/platform/下建立文件uevent。( Z. K5 H' k7 [0 s6 \+ j

# J$ M* i/ U# J- m5 M! Z+ Gint bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
6 [, H- n  W1 v- A' W{
# F9 Q# d+ ^$ A        int error;6 J: S' F7 s7 e' B1 @
        if (bus_get(bus)) {- x, {! D& y5 d! c  F$ I
                error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);4 {) _6 F$ b0 G5 O: C3 m; U, C
                bus_put(bus);
: R$ L. i2 X0 u1 ~. u7 {, `8 H/ ^! A( E        } else
! i$ l+ i" H* e2 h9 I                error = -EINVAL;8 x8 l! ]3 T1 B9 I
        return error;( b3 @" i8 h3 b) g  |! I1 `
}4 H5 X9 ~" v+ q+ t# w9 T! b
EXPORT_SYMBOL_GPL(bus_create_file);
( g6 G% o: a+ o, u& r有关底层的sysfs将在后面叙述,这里只要关注参数&bus->p->subsys.kobj,表示在该kset下建立文件,也就是platform下建立。
9 H  K' z( R7 Q, o, D. i接着调用了2次kset_create_and_add,分别在/sys/bus/platform/下建立了文件夹devices和drivers。该函数位于第3节开始处。
9 J9 d( }9 m  K# N8 i
$ |2 b+ W! \, }1 x7 C& u8 S这里和第3节调用kset_create_and_add时的最主要一个区别就是:此时的parent参数不为NULL,而是&priv->subsys.kobj。) |* Z0 y9 v* \

( R( P# O8 r/ K+ c! A也就是说,将要创建的kset的kobject->parent = &priv->subsys.kobj,也即新建的kset被包含在platform文件夹对应的kset中。, x+ l# X- u. h. Y2 z3 f
6 R% l' ~! d0 o$ `$ N' ^
我们来看下关系图:
) J* U5 }! S: q- m) V* N6 F  ^/ R( A& M

# W2 l8 R6 G) S3 ?5 \- V) d* N1 v6 E1 B, B/ |- ]
随后,调用了add_probe_files创建了属性文件drivers_autoprobe和drivers_probe。
1 {1 B& w  }2 Y- e6 e, ], e! q! I+ ^" q: z, E$ |
static int add_probe_files(struct bus_type *bus)
; K4 ^# h- a2 g! U: @2 f# U! m" Y{
( k( i5 t) g1 l- u5 T" B: A5 s        int retval;
, Z% m* P* a! _% C$ G2 W
4 U7 Z2 Q! ]/ _  C        retval = bus_create_file(bus, &bus_attr_drivers_probe);7 q! ]( D" R, F  u& N0 ?0 L
        if (retval)
, }+ @1 H$ g' s7 G" [: t" h                goto out;
! t# A( j/ j0 i. i. I  T
* C) |+ _) l/ z- ^, W        retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);! f  W8 D6 ~5 R  D: i3 H" S
        if (retval)0 r' C3 v; O4 N( p; _, a9 u
                bus_remove_file(bus, &bus_attr_drivers_probe);! B( b; v* w, z1 [) q( b
out:3 O  l* z- ?( Z0 A8 ^
        return retval;
* Y# t% f* ^( }$ i}  m, W' }' R+ D. F% T. U
该函数只是简单的调用了两次bus_create_file,该函数已在前面叙述过。
. o$ |; a) F5 o0 \最后调用bus_add_attrs创建总线相关的属性文件。% _, x* W/ ~6 s" U$ e0 t3 j
3 j7 J; u& R+ ]9 t$ S6 P
/**
/ E3 Z! v  r3 K) a * bus_add_attrs - Add default attributes for this bus.1 y/ z( V4 p1 V1 \6 Q
* @bus: Bus that has just been registered.! L: @- `$ ^. ]# o
*/: t1 m# n5 d4 c6 F( l+ o

# S; C  q( c% R& ?6 r# D: Estatic int bus_add_attrs(struct bus_type *bus)1 h& B5 O( r" b
{1 C. I# v. i  ^( {5 q8 Y+ h
        int error = 0;
2 c( w& a% \& p& o        int i;8 [% w5 \( ^! p9 u  _

2 A$ B' o* P! o4 j4 c        if (bus->bus_attrs) {+ @+ o- [! {, d2 E
                for (i = 0; attr_name(bus->bus_attrs); i++) {9 y( X) R$ E1 N  _0 E" p
                        error = bus_create_file(bus, &bus->bus_attrs);4 w, G+ c1 c5 e( A
                        if (error)
0 J" y0 ^- q! j& E1 X: a$ B                                goto err;  M' w6 A: [$ h; c
                }' F3 G# g3 \4 z3 e, s0 |1 U+ b# O
        }4 l* x" [6 ?+ f3 k1 m( {$ W* W" K
done:
/ d' O) J0 }' d' t. U0 E        return error;6 R% [$ H5 r0 H8 h
err:2 X2 G! Q: v$ U. T! E1 Z
        while (--i >= 0); L- T# B5 O' N0 Z! b
                bus_remove_file(bus, &bus->bus_attrs);- U9 Y, n+ x5 d& q& r( P6 A
        goto done;0 [8 _! o# q2 T
}: X$ G6 \  ~& q% l
我们可以看到这个函数将根据bus_type->bus_arrts来创建属性文件。不过,在本例中,bus_arrts从未给出定义,因此次函数不做任何工作。
5 \: R# {6 j$ _3 \( x好了,整个bus_register调用完成了,我们来看下sysfs中实际的情况。
, I$ U3 R( i. {) D+ _
4 c: n; l9 X2 H( r, ^; t[root@yj423 platform]#pwd
: [1 B- I6 g1 L. M! P. s: V! @3 S5 N/sys/bus/platform
- S5 y1 Q5 K+ I7 f' G5 O[root@yj423 platform]#ls
+ F" z1 n% s& Y( ^devices            drivers            drivers_autoprobe  drivers_probe      uevent
: N% o1 O; V. K; m- r1 n最后,我们对整个bus_register的过程进行一个小结。
4 z3 B% ^4 p; \+ |/ l# M$ B, K4 b3 h

+ {, i% ?5 q4 `9 |' ]
; M. b9 P" k: y, o9 h/ S6. device举例
1 O, ]7 X) Q4 l: z1 m& r本节将首先讲述如何在/sys/devices下建立虚拟的platform设备,然后再讲述如何在/sys/devices/platform/下建立子设备。
/ H6 K* \5 P% J0 v0 @
% x5 J# z) D- c/ u. W6.1 虚拟的platform设备# j+ w' i& U* n! W9 m/ ^
之所以叫虚拟是因为这个platform并不代表任何实际存在的设备,但是platform将是所有具体设备的父设备。+ g: b. F$ W' p# e9 e

/ h  T1 m) z' C+ E* R9 `在第5节,platform_bus_init函数中还调用了device_register,现在对其做出分析。
" P/ f( J9 P& E; o4 H* f: J8 |( a+ h3 y, k6 a
int __init platform_bus_init(void)0 Q9 }6 H! c6 N
{
! p% M% R3 N  F" W# U2 B! b; L        int error;; Y2 i' `: y: K7 O7 l; K6 L( q
/ v- a$ z' T% ~3 f
        early_platform_cleanup();9 d1 \  y. n3 `
* u. a# @2 U& Q& {
        error = device_register(&platform_bus);
+ n2 @. T$ v# T4 Y        if (error)7 e8 R$ O# [8 s: p1 e5 @( H
                return error;4 @8 O4 Y# ~& ~1 w+ s$ B' ~6 Q
        error =  bus_register(&platform_bus_type);
# V+ b, y8 F& r: R        if (error)! Q% X$ B5 _# t
                device_unregister(&platform_bus);
$ ~. {4 E0 x2 o' u1 |        return error;% {8 Y% d6 `" I% I9 K
}1 a0 E1 Z; p6 }0 Q( D
, ^/ s% _. M  R: _
struct device platform_bus = {
" E; j# y2 t6 M/ H    .init_name    = "platform",
! ?4 V0 y6 z% {  C, U2 e- E};# e2 g7 B& J4 q5 O. j( \  r
EXPORT_SYMBOL_GPL(platform_bus)
7 I5 ?$ E4 |" I( o( v+ g1 X下列函数位于drivers/base/core.c。) B/ Y1 D* b( [+ c$ F" d  w
/**  u+ ?1 M8 b% f' V1 w+ K
* device_register - register a device with the system./ I7 u5 p/ _4 Z1 c0 u
* @dev: pointer to the device structure
& b# B* Z- g% D$ @ *6 p! C/ F$ E, n1 M$ p- G6 c- L
* This happens in two clean steps - initialize the device/ g1 Z0 g7 T7 e) z
* and add it to the system. The two steps can be called8 Z8 y6 H, }. k5 `/ J! K& m
* separately, but this is the easiest and most common.6 B* {5 G, G( j5 K
* I.e. you should only call the two helpers separately if. ?; g5 }+ l* r5 U
* have a clearly defined need to use and refcount the device
; {+ E; _0 _2 Y/ h9 [) g; h * before it is added to the hierarchy.
9 x% M2 r' U+ k+ h) y *
0 r+ q/ V* f8 s3 [2 Y. i * NOTE: _Never_ directly free @dev after calling this function, even& F* M7 [& ^/ F/ Y+ S$ B8 c
* if it returned an error! Always use put_device() to give up the( ~! |) J; `1 q8 r, _0 a. z, E
* reference initialized in this function instead.: j0 B4 u4 T" X" T2 Q
*/
% M! H# e* Q$ C! S5 V+ oint device_register(struct device *dev)6 [% E& V3 I0 N, ]3 r
{
+ P3 |+ |; L3 ~$ ]! S) W& X& s        device_initialize(dev);        /*初始化dev的某些字段*/% Q* G# n' X! A6 h; \/ z: r
        return device_add(dev); /*将设备添加到系统中*/
/ b7 T. z' k; h, \}% f: Q+ \, _" P; G- `) u) x; [

' ^. L1 @  z6 r' \- T* o一个设备的注册分成两部,每步通过调用一个函数函数。首先先看第一步:0 s2 l- Y) m* A; ]$ v

' w: K: h: q$ |0 y下列函数位于drivers/base/core.c。
' g& R. [$ H. Y; K+ J/**/ H# Y% p/ t3 {% `
* device_initialize - init device structure.' x0 E1 h6 T/ ~# n% S
* @dev: device.# s9 b, K$ ?4 i. |  b" e# b: ~1 T# |
*9 i$ K' V& Y& O3 {9 [& t
* This prepares the device for use by other layers by initializing
% W: ?1 H, I1 s7 u% o) b+ E * its fields.
! b  e, \: j" j$ D& `3 U. p# W * It is the first half of device_register(), if called by
1 g. n* B$ M1 A: k0 ^/ }+ g( N * that function, though it can also be called separately, so one
  p( b; T% ~$ Y3 L# h( _3 Z% e+ q * may use @dev's fields. In particular, get_device()/put_device()! C" e$ W, @' h4 t& t, Q8 t& B' ~1 S
* may be used for reference counting of @dev after calling this
" {7 ^1 |6 C. J- [' q8 H * function.8 H  W, T. y: M. K4 {: Z
** E# L/ a( i' _0 S$ Y4 ~! Y9 c9 g
* NOTE: Use put_device() to give up your reference instead of freeing
1 o+ j- [$ d0 V" C# z * @dev directly once you have called this function.- G7 X! N& I* M: b
*/
/ q! z( G2 x7 i" rvoid device_initialize(struct device *dev)+ ^5 }6 M1 k. ?. h! Q" x8 A
{
9 n' l7 f- {6 u' c    dev->kobj.kset = devices_kset;        /*设置kobj属于哪个kset,/sys/devices/*/
" S$ v% X1 [4 ^0 m2 e6 ?    kobject_init(&dev->kobj, &device_ktype);/*初始化dev->kobj*/$ h# S" B: i0 l$ l/ v. X
    INIT_LIST_HEAD(&dev->dma_pools);    /*初始化链表头*/
8 h. t9 e- G# A! h4 K/ K5 m    init_MUTEX(&dev->sem);                /*初始化互斥体*/
% b/ O) u, R. x, e9 Q    spin_lock_init(&dev->devres_lock);    /*初始化自旋锁*/' l- Q3 u2 D; u( _9 I0 A$ }; O
    INIT_LIST_HEAD(&dev->devres_head);    /*初始化链表头*/9 n9 y* Y, |+ M. S8 @+ [, Q$ P
    device_init_wakeup(dev, 0);            /*设置该device不能唤醒*/& a- A4 \2 q4 t- @+ S2 p6 W7 g
    device_pm_init(dev);                /*设置该device可操作*/
) X" L( X. {+ d2 j' X* M7 {    set_dev_node(dev, -1);                /*设置NUMA节点*/
* P" ^5 ?+ F# ]1 B9 Y}- e; l/ U5 h+ }9 q
6.1.1 有关devices_kset
1 i& A( [* D; ]% t+ ?9 K首先其中用到了devices_kset对象,这个对象和第3节当中的bus_kset是同样的性质,也就是说该对象表示一个目录。/ \3 m) Y0 P3 e4 M3 Z
& K: k) M' k# @: [( D$ ^& v
该对象的建立是在devices_init函数中完成的。
) b9 d1 }/ H) @3 xint __init devices_init(void)
. r$ f! F) W6 q' x& C2 h{
% s: h  y$ S: k        devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);! `; C( ]) a! c4 D' P- y" m
        if (!devices_kset)
+ b( ], `' o$ b0 h: Y5 p2 v( z                return -ENOMEM;
# b' s/ K3 p8 v        dev_kobj = kobject_create_and_add("dev", NULL);) q" X! I( t* Q/ O( T
        if (!dev_kobj): P# t9 ^, T$ r+ M
                goto dev_kobj_err;
5 s+ _" S% s5 _6 z, Q        sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
' v/ d' ]5 u% R) [' j        if (!sysfs_dev_block_kobj)3 a! ]2 H) O* i; O4 f' E9 E
                goto block_kobj_err;
1 ^( C* P. C3 w% a) O) w        sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
5 \9 w* @3 M" }& X. y        if (!sysfs_dev_char_kobj)7 _6 f) @& r9 y5 G' j1 v
                goto char_kobj_err;0 I, ?7 e3 c; L. }" x6 u+ w

3 J/ e  ^6 M" p4 o8 V# @8 `% _        return 0;3 q2 {! V* k! @# u9 A' _/ A6 V
" {. V/ w) t6 e' f' n
char_kobj_err:7 m: L' Z( \7 t! E7 ^
        kobject_put(sysfs_dev_block_kobj);
" w8 v7 w* x" H" ~  [( B1 [ block_kobj_err:+ P- K. A2 f8 L8 h+ }
        kobject_put(dev_kobj);
. M+ t* m& {" x; _: { dev_kobj_err:
  S+ K3 ]) v- S9 r9 R        kset_unregister(devices_kset);
/ h& Y) B6 d4 P. w6 ]2 g; P        return -ENOMEM;
( A' [0 [1 n2 G" \' o' ~}, @) p' u8 G; ^, F( \, K2 s
由此可见,devices_kset对象表示的目录为/sys下的devices目录。( Y: b2 N0 Q5 g  `
6.1.2 kobject_init
8 t/ Z, T5 A# E# c下列函数位于lib/kojbect.c。7 H- l6 y& ]0 ?) O
/**
" l/ ?8 \( ~3 ]8 [+ {( \ * kobject_init - initialize a kobject structure: D: S4 k0 F7 v6 L* Z) S' P& K
* @kobj: pointer to the kobject to initialize) m" `) |" a% J
* @ktype: pointer to the ktype for this kobject.$ ~7 H4 c! ?+ `: C
*8 ^7 }" W, ?/ Z
* This function will properly initialize a kobject such that it can then
0 c+ e/ k! C) O1 l4 Z, D  }3 n0 W * be passed to the kobject_add() call., S' C+ D# _3 c
*! C# R, y- @2 E% O$ K# \
* After this function is called, the kobject MUST be cleaned up by a call
) |& Z* o" s7 f; G * to kobject_put(), not by a call to kfree directly to ensure that all of
! j1 M/ a0 x: P3 J * the memory is cleaned up properly.
( k- q* A* f$ o2 c* r; Y( ^( z/ n */: W& w1 I, e& e
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)  R& i$ J& T* h
{
! b+ l2 v. L; X5 \5 H        char *err_str;! F9 Y* Y. }+ ~. M" U

4 K' A; ~7 w$ k% |/ ~6 F        if (!kobj) {! K& x+ ~, e# L/ E
                err_str = "invalid kobject pointer!";
0 `3 s% c2 ^- l; f8 P& p9 ~: G+ S1 P                goto error;& }/ `5 x' D* O& x/ Y0 E$ U7 \7 e
        }) Y3 H" \6 z( ~! d: F# ]. U
        if (!ktype) {" K2 q/ _0 C& G+ d6 v, |. W
                err_str = "must have a ktype to be initialized properly!\n";
4 v, n0 t. g2 i& a                goto error;4 S* ?7 n4 N1 z) f  E; o8 Z
        }
/ D  {! j2 r! O4 e4 E        if (kobj->state_initialized) {8 D, I1 v9 T' S% e( u, Z% b, b
                /* do not error out as sometimes we can recover */; n9 s- N; y% E) m
                printk(KERN_ERR "kobject (%p): tried to init an initialized ", ^  s/ n# m( [& Q
                       "object, something is seriously wrong.\n", kobj);: @" z) w! F5 J" o1 ?/ A+ j
                dump_stack();) g: G( S3 t( q
        }/ S# _- f  n0 t

2 g6 w) V4 l3 o( l) f# Q0 I        kobject_init_internal(kobj);
7 s/ G# R6 I7 t7 Z3 t) }        kobj->ktype = ktype;& [# X6 v) S0 h7 |4 M2 x3 o2 j
        return;6 z( V/ b  [5 E( r7 m8 N. G1 g. z1 B! X

8 E, `0 B& z8 q/ ?( Cerror:+ T# e1 u' d6 K
        printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
( ~1 t* j3 a/ P/ u! }        dump_stack();
4 J) {' n6 k" T}) e; B+ k3 B' v
EXPORT_SYMBOL(kobject_init);: j  ]; E# A+ S/ @: S/ h2 W
5 t4 a2 Z/ V" _3 ?
static void kobject_init_internal(struct kobject *kobj)' E6 d& c. z7 o& ^6 z
{
& n$ x* V' X: ?* ~  w& H6 x    if (!kobj)
0 J& [  h/ }" n- _  ~        return;0 q$ M0 v! R1 n% B
    kref_init(&kobj->kref);            /*初始化引用基计数*/7 ~2 X, F9 j/ X4 w% c+ q0 t
    INIT_LIST_HEAD(&kobj->entry);    /*初始化链表头*/
% R! X2 H6 A- I! i" Q2 G  c  g    kobj->state_in_sysfs = 0;: h, c( _6 m# m- M  o' G# k
    kobj->state_add_uevent_sent = 0;
7 l' Y; U6 Y" o2 r* p    kobj->state_remove_uevent_sent = 0;
9 B/ x  R. ^7 y    kobj->state_initialized = 1;' e: q( q& E& g& x6 K& P4 d
}
0 v2 \( D6 x& m' m5 O该函数在做了一系列的必要检查后,调用kobject_init_internal初始化了kobject的某些字段。, k3 H. [- S$ {2 F
6.1.3 device_init_wakeup
" \. r* j6 _* |  h: r8 S2 P0 x参数val为0,设置该device不能够唤醒。
" i3 V6 c. W  M7 S#ifdef CONFIG_PM1 A: R7 F8 v& G6 p

* O$ P& v: K" ^0 f3 z/* changes to device_may_wakeup take effect on the next pm state change.
  z1 F3 H' l! i! m$ m) B6 u* o2 | * by default, devices should wakeup if they can.4 v+ w0 X! F- ]% @
*/& Y# y2 N; p8 E+ ?" Z
static inline void device_init_wakeup(struct device *dev, int val)
: ]( d% q$ F6 d* c{, ~% M! z& g& D
        dev->power.can_wakeup = dev->power.should_wakeup = !!val;: @/ O% I* x7 v
}
( B+ j: Z$ X; ]9 E/ X( n0 G。。。。。。4 a& w  E; G# z
#else /* !CONFIG_PM */; _8 X, E0 Z( l: W, C
$ ]' ^( k! G2 t5 ?0 c
/* For some reason the next two routines work even without CONFIG_PM */
- {8 ~; {4 W' _static inline void device_init_wakeup(struct device *dev, int val)
' P8 f* K2 Z( y{4 U: F% m% r) d+ p6 e
    dev->power.can_wakeup = !!val;
# h0 J( v4 ^/ x* a}
$ A4 X' [* |: E+ ^。。。。。。
. q+ A: |9 t$ Y9 }, \( C#endif/ T# [/ i' y% e* i1 S4 |( y( r8 h" t# a

1 f4 t1 S7 {$ \4 T. x' H" X' i$ z9 Z  U6 |* W9 Q
6.1.4 device_pm_init
' `- Q# c5 X2 f% U1 L; m设置电源的状态。7 M" a) p! m' K, ?2 o1 v
static inline void device_pm_init(struct device *dev)) d4 Q/ ~, I2 {/ d  M- r  p
{4 v% U" y9 G( c) @
        dev->power.status = DPM_ON;    /*该device被认为可操作*/8 q: Y1 }2 e9 W+ Z' W' D* ]
}
' f& J* h% I! L# e6.1.5 set_dev_node; A7 P0 `) k0 j) a
如果使用NUMA,则设置NUMA节点。2 P9 {% h* u3 q+ r9 ^  `3 L
#ifdef CONFIG_NUMA
8 a% N/ y. s$ J$ p! S- Z% g, V。。。。。。
2 n+ W; L+ E9 j% U, R0 ^# L5 i) v2 |static inline void set_dev_node(struct device *dev, int node)
/ _5 o9 x, H" r- h# e5 Y' A; K  h{: ?5 w- f! y3 c3 N2 a9 |
        dev->numa_node = node;
- M8 F) w$ `8 ?8 x2 g: d) {}; z0 ~& [( M) z
#else& C7 e  O0 o. T" z0 K  _* }
。。。。。。
6 Q! t0 }' _% i+ m' r) B0 mstatic inline void set_dev_node(struct device *dev, int node)) C0 s# U) Z! s/ X
{2 i0 k2 `% n& z
}8 N- }5 A" Z  {
#endif* ~& F4 D$ S+ [& a; f0 L

6 _! H  n! L6 c  O6.2 device_add+ W; j2 `( [# n% k7 `
接下来是注册的第二步:调用device_add。5 d$ F/ Y: w! ^/ i) V% q8 P# Z8 d
: l4 R- D8 R" k6 U7 b6 C3 t
/**
; O. r$ M# J- ^) r * device_add - add device to device hierarchy.
9 t0 p/ S) s: K. O; n3 G * @dev: device.
4 N. C+ }$ A+ S0 R5 I% d& ] *# T0 ~7 x1 N4 C7 e+ k1 D
* This is part 2 of device_register(), though may be called7 D$ F& f" l! J/ I$ [5 x
* separately _iff_ device_initialize() has been called separately.
) V4 c  D9 `2 h$ A' [ *
# Z" |9 p/ N9 c5 T * This adds @dev to the kobject hierarchy via kobject_add(), adds it9 ]* i% G( z6 s3 Z4 L
* to the global and sibling lists for the device, then
$ G- ]3 o% o+ `( Z$ k" X$ Y2 S  K& B * adds it to the other relevant subsystems of the driver model.; }. y8 Y# J. T% i7 W
*
2 T" b+ S+ ~8 f" P: i2 i. D9 ] * NOTE: _Never_ directly free @dev after calling this function, even
. ]- q+ G! D* T: i * if it returned an error! Always use put_device() to give up your0 b# x+ X- K( ^5 Q6 H
* reference instead.
* C' ~, u2 q. o  E */- ?5 y$ ?- L; k, w. D+ R
int device_add(struct device *dev)( ~) O3 R5 T3 y, G. u# N: v. [8 D
{9 X8 Y: w/ ]( [- L* A% g" C2 \
        struct device *parent = NULL;
% ^: s, {9 Z3 _* U" x        struct class_interface *class_intf;
* F1 i& q2 y( ^2 W7 h3 k" d: X        int error = -EINVAL;2 t2 d% l. T& ?, J+ D: T
' v( e/ ?( L: E+ I
        dev = get_device(dev);        /*增加引用计数*/: B; x4 ?2 P: g2 G( c
        if (!dev)
* s0 \& W1 m7 K! g% g; D                goto done;1 o' ^2 _0 R; P

5 ^1 v4 F) U+ A$ [9 ?. ]$ j2 g4 z        dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);        /*分配device_private结构*/
* j9 {4 c9 \6 Z" f        if (!dev->p) {/ y3 U( P9 T* L# ?5 t% Z* W) h. l2 x
                error = -ENOMEM;' T* ~4 G$ t  ~! e" N* |% Q
                goto done;6 p/ Y' l! H4 p( [" F& S
        }
+ e3 V- W8 w% j        dev->p->device = dev;        /*保存dev*/
0 |  ^& p4 G! V: M- e- C1 u        klist_init(&dev->p->klist_children, klist_children_get,        /*初始化内核链表*/
% B3 H0 K* W) R1 H% Q                   klist_children_put);! c3 A4 B$ N4 T9 N8 e5 d

1 E+ }! c9 ~* v. f, B) T  W! m        /*" Q' k; g2 n2 Y) A& |
         * for statically allocated devices, which should all be converted$ k% e( L" G6 P% E, o
         * some day, we need to initialize the name. We prevent reading back
2 f6 {0 M; _% z. R         * the name, and force the use of dev_name()7 Z9 q" F: t7 r. h6 E( P# F) J5 Z+ c
         */) a  z: A4 \: s& U
        if (dev->init_name) {
4 l0 M* J* m" H, g# ]                dev_set_name(dev, dev->init_name);         /*dev->kobject->name = dev->init_name*/+ H. a! \# F6 N' ]' ^7 ^
                dev->init_name = NULL;* S! _1 X1 |) r: Z+ o3 N8 N* c/ [
        }4 i& z8 s3 [8 h& g, e. Y, h% w0 S

9 J# F; S  V3 L9 K' L        if (!dev_name(dev))        /*检查dev->kobject->name*/' v$ g& r0 x4 Q0 [3 R9 h
                goto name_error;2 t0 g* t+ A% z
2 q" E2 o9 a' o% q1 s
        pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
2 M3 c8 \! e7 L5 U" I; e) q, w; L8 p% N3 ~7 b% t7 }
        parent = get_device(dev->parent);        /*增加父设备引用计数*/* l% Q0 [  q# j) d. Y
        setup_parent(dev, parent);                        /*设置dev->kobject->parent*/" U) V1 K: b0 H9 J$ \

' B; ]9 b/ F2 g; T        /* use parent numa_node */
4 v- o* @# e! E' b( P3 v        if (parent)
& K, p, x5 z1 @* j6 ?1 m0 _4 D. H& _                set_dev_node(dev, dev_to_node(parent));
# }) z3 m6 D# g4 {, z  E, d; e8 u& [8 R" I/ B/ L
        /* first, register with generic layer. */
; i( ?+ S% B/ ^% q; e        /* we require the name to be set before, and pass NULL */
& i# P5 d/ M9 @" G        /* 执行完以后,将在/sys/devices/下建立目录XXX,目录名XXX为dev->kobj->name*/- p% K* n0 r0 ?9 F" y1 M
        error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);        9 ?+ A7 z8 R2 x- Y4 i' d" i
        if (error)
! s% j: P& h7 [$ ]                goto Error;
. n6 g/ ?/ n+ P/ ?2 s/ x# H2 }: t, v) v" Y) r6 @& C
        /* notify platform of device entry */
+ I2 N8 o: P0 j' z+ r8 V' V        if (platform_notify)! C0 b. m/ B. n0 z& w
                platform_notify(dev);' p7 B+ m. C- Q$ V  J3 W

# L; [$ D2 {" o+ i9 A# K        /*在XXX下建立文件uevent*/" Z$ h$ W" A+ F! U6 U& M
        error = device_create_file(dev, &uevent_attr);
# [' D5 ?, z5 r2 I% j  N        if (error)- C5 I& q& {- `2 s6 F, U
                goto attrError;
9 X1 H. F: B" g1 ^; ^
% M8 V. `( S. i        if (MAJOR(dev->devt)) {/*主设备号不为0*/
* V3 c: ]6 w  B, n                error = device_create_file(dev, &devt_attr);/*创建属性文件dev*/! d0 I" l" Z+ w2 x
                if (error)4 n3 s( M3 K: ~2 [3 M% k
                        goto ueventattrError;
3 ]3 J9 B2 q: }  K) N4 y- x9 b) E
: L. T. T3 l$ d6 Z3 a/ d0 y. F) P$ F0 {4 a                /* 在sys/dev/char/下建立symlink,名字为主设备号:次设备号,该链接指向XXX */
5 c# `- ]9 c# c$ }                error = device_create_sys_dev_entry(dev);
7 N( ~, j% }2 ?, y" }0 {                if (error)
7 R) }! a/ M: \5 v# z8 ?3 l                        goto devtattrError;8 I) Z( r0 M; n0 a
        }2 }: o4 T8 {9 j5 L) ~! H

$ E6 w: {' L' }/ r! A1 Y: h3 c7 |        error = device_add_class_symlinks(dev);: a" n- p$ o' V9 O$ r/ D
        if (error)3 j+ ~# B! P* _, T8 t. v. V! b
                goto SymlinkError;; }# P! R0 U/ E9 n# j
        error = device_add_attrs(dev);        /*添加类设备属型文件和属性组*/1 ?! y8 D  }" V. G! K, Z' t# w. a
        if (error)
2 O" @* K7 X9 p6 i! D                goto AttrsError;
6 f) x! [% e. s" Y0 N% C- m( J( f        error = bus_add_device(dev);        /*添加3个symlink*/& t+ }3 W: q' s) o/ [) c2 i, A4 d
        if (error)' d2 X$ K4 N/ W# T: K( E
                goto BusError;
" Y% u+ I% r! ~, e. X        error = dpm_sysfs_add(dev);                /*创建power子目录,并在其下添加电源管理的属性组文件*/
/ q, P9 Q' E- w7 _% A$ M        if (error)
, i& M9 `. B8 z$ B( [9 a                goto DPMError;" G( p. `3 A8 i' _/ Y
        device_pm_add(dev);                                /*将该device添加到电源管理链表中*/
1 `  W. G  @. P" d
# b$ R( p" Q3 w. s  B0 I" c        /* Notify clients of device addition.  This call must come; ?8 {0 K$ b. i8 q" V' b
         * after dpm_sysf_add() and before kobject_uevent().
8 I' _  O7 b: ?! e; B         */% k( h( k/ E) g. B8 R$ ~# d
        if (dev->bus)" U  ?6 k! F8 d8 b8 V+ C
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,! y+ d7 D( D: C  b
                                             BUS_NOTIFY_ADD_DEVICE, dev);5 r' k! W- }5 J& N- _! \- c
# D) A" w+ i' Q& t
        kobject_uevent(&dev->kobj, KOBJ_ADD);        /*通知用户层*/
5 K+ r& C2 e; G8 A        bus_attach_device(dev);                                        /*将设备添加到总线的设备链表中,并尝试获取驱动*/; B. x. @3 h" ^3 q
        if (parent)+ q/ y/ m# C9 Z4 P7 v
                klist_add_tail(&dev->p->knode_parent,        /*有父设备,则将该设备添加到父设备的儿子链表中*/
; ]( L% w. N; O                               &parent->p->klist_children);, F0 @' Z; a5 H

9 Y8 z# M. V1 {( m        if (dev->class) {                                                /*该设备属于某个设备类*/' w3 W) {5 D3 g1 I
                mutex_lock(&dev->class->p->class_mutex);4 M* ^& l+ h# b# t& A. Y* a
                /* tie the class to the device */
3 f" ^9 r2 G6 a. i* {0 z1 V                klist_add_tail(&dev->knode_class,        /*将device添加到class的类设备链表中*/
7 Z0 U+ m, W, v1 i- A0 r                               &dev->class->p->class_devices);5 H7 r% m* I6 d1 K( `/ {
; c5 b1 E+ @8 o/ r
                /* notify any interfaces that the device is here */0 Q' B' }4 l% |% N0 T1 ]2 y8 w# B
                list_for_each_entry(class_intf,
  o3 J4 I0 W! w& G# o9 d: q$ j6 x                                    &dev->class->p->class_interfaces, node)# |& M1 |* h4 B' X2 m
                        if (class_intf->add_dev)" y' G0 k* I* s0 r3 }+ C
                                class_intf->add_dev(dev, class_intf);
8 G! ?$ y/ |6 z                mutex_unlock(&dev->class->p->class_mutex);
  h6 n& S  S7 e4 ]7 E        }) q% l! E5 J; g. q3 K0 q
done:) f2 @2 \  i$ d' }
        put_device(dev);( b7 e" o8 `1 C" A4 ]
        return error;
/ V8 _4 G- X7 |/ B  \ DPMError:! E5 J, C! [! u/ I, A" L4 v
        bus_remove_device(dev);
6 V3 z2 l1 A2 n2 H! Y+ N. K BusError:: j& D+ J  L2 t
        device_remove_attrs(dev);
0 l& B) K, p. k AttrsError:/ ^( \% X, i. V3 O4 a7 h) `5 {$ ]" F7 F
        device_remove_class_symlinks(dev);1 p0 W+ h$ D9 Y6 A3 j
SymlinkError:& h# Y0 ?9 m& i, y) L$ E/ m7 C( V! l
        if (MAJOR(dev->devt))
8 d& v' k* h" E* Z                device_remove_sys_dev_entry(dev);
1 y/ C  K8 c7 K; w1 u devtattrError:
5 c, C) m1 i# h* s        if (MAJOR(dev->devt))
5 m. h& [( j9 j* N3 U                device_remove_file(dev, &devt_attr);, k8 T# u9 s* j% i0 X
ueventattrError:
" B3 a4 n1 d' L8 i8 o8 W3 [' ]        device_remove_file(dev, &uevent_attr);
; M6 I: I$ I/ T: O) W+ A# ?: M  y attrError:
3 W7 u* O: _, l6 H+ G* V) c. P        kobject_uevent(&dev->kobj, KOBJ_REMOVE);/ W) [+ O3 ~5 _' b: u' o/ a- m. s4 o
        kobject_del(&dev->kobj);
& Y* m% _) U3 \- m0 x) k" b& ?6 [ Error:
$ g, I3 u/ y( u        cleanup_device_parent(dev);1 V, t% ]) n' z/ D9 h5 p9 _
        if (parent). l1 u, r  @; z* Y/ V% @
                put_device(parent);# A  Q; M) n6 \; E
name_error:
& U& C5 @; n, L        kfree(dev->p);
% U, U2 c" `: h9 O        dev->p = NULL;
, p9 |  ?$ b) x$ F        goto done;. f4 z  S9 L, K, E! W* j
}
; a) a! D: U7 {+ C4 h3 n6 Q$ g7 r6 w8 ]7 F
该函数调用了非常多的其他函数,接下来对主要的函数做出分析。, B9 X8 w. f3 X! H* P. _
6.2.1 setup_parent函数. T9 G1 T% J3 t3 r) G% l0 n
下列代码位于drivers/base/core.c。
8 A: e( C0 \( w" A: j- h  i( fstatic void setup_parent(struct device *dev, struct device *parent)( b  a0 _7 M: p: I$ \" \
{7 T+ P: C" j' v; k% X/ K" x
        struct kobject *kobj;
+ ]1 k) g( \5 `# _        kobj = get_device_parent(dev, parent);3 [5 P/ Y' P0 P5 j" h1 U$ y( [
        if (kobj)2 z9 E8 G$ U" T
                dev->kobj.parent = kobj;* x! z) g" C% l: ?
}$ j; V( Q3 _1 u7 ?

9 X# {- K4 l" @' `& a5 Y) Fstatic struct kobject *get_device_parent(struct device *dev,
7 I9 U$ l7 S, f$ ^1 T                     struct device *parent)3 D% ]6 a0 q! Y3 i) V
{
9 F0 f2 D  K/ @$ Q3 B3 y    /* class devices without a parent live in /sys/class/<classname>/ */
! e0 {% c5 W: I* H6 [( P( |    if (dev->class && (!parent || parent->class != dev->class)), G! L  l0 w/ I* i& w+ r
        return &dev->class->p->class_subsys.kobj;
8 k9 C% O# M4 L    /* all other devices keep their parent */
' S6 h) N3 [# @* h5 Z* ]    else if (parent)
) |& s: W# ]% t% k% I        return &parent->kobj;
$ L: U2 M6 B4 \$ j& v/ m& J
( i% S7 z# U( {! C1 ~" _    return NULL;
7 v' f+ ^4 Z( X7 _! b/ }}* o4 [+ v/ C6 V0 l* s- I
该函数将设置dev对象的parent。在这里实际传入的parent为NULL,同时dev->class也没有定义过。因此这个函数什么都没有做。% ~# V1 Y& Y- L7 v# v
6.2.2 kobject_add函数, _1 c8 _" c& j. c+ u0 `5 j
下列代码位于lib/kobject.c。# z( j" x% s7 Q/ z' |9 q
/**# R5 m" W9 Z4 z8 e" y0 S& G8 l
* kobject_add - the main kobject add function
! c( n" |2 E  ^  X * @kobj: the kobject to add
- p4 \$ e+ `6 U * @parent: pointer to the parent of the kobject.
, w3 c8 t9 l8 j * @fmt: format to name the kobject with.* Y5 ~+ m( n) Q9 L4 \
*
+ c4 E; J* s  u* X6 b * The kobject name is set and added to the kobject hierarchy in this7 _: F9 H, J( A
* function.6 i$ p+ l* I, j
*$ t, V# k& [* a% T4 J. }
* If @parent is set, then the parent of the @kobj will be set to it.
6 I1 Z0 S8 W* b  d3 e6 [, S' I * If @parent is NULL, then the parent of the @kobj will be set to the1 P% S' J* }/ X' a2 A/ g
* kobject associted with the kset assigned to this kobject.  If no kset# G# h/ t+ ~; K7 s3 Z
* is assigned to the kobject, then the kobject will be located in the
+ S: J) c6 n# w * root of the sysfs tree.$ Y8 O' I/ F. L$ J5 W7 {! h
*
7 M' ?% V9 X: g6 ^ * If this function returns an error, kobject_put() must be called to/ k2 ?/ |' d) G" N$ K8 b
* properly clean up the memory associated with the object.
4 |9 D  U& y# X5 e) v. \ * Under no instance should the kobject that is passed to this function
0 E: X' O' `: \1 w7 [6 z * be directly freed with a call to kfree(), that can leak memory.
1 i; g9 H7 u! \ *0 X/ H  Q. D. |: H1 B3 b
* Note, no "add" uevent will be created with this call, the caller should set. y/ e/ }  w- m* U' w+ M/ F$ ^
* up all of the necessary sysfs files for the object and then call; j6 O3 m! y7 _5 E  w: x
* kobject_uevent() with the UEVENT_ADD parameter to ensure that
! Y3 A$ C5 @* ~  @5 Z6 { * userspace is properly notified of this kobject's creation.
3 s3 [6 j5 o+ E5 s# V) w: F1 I */
/ o! x2 x' S% |* \& \9 J2 ^  jint kobject_add(struct kobject *kobj, struct kobject *parent,; _1 t- M# Q& C. {# V- T1 l
                const char *fmt, ...)
8 L5 }! e( B, n3 k) u. h7 K5 s{; ]0 F$ r& R' X
        va_list args;! L; j! \3 R) {- ~% s" l6 n! l- M8 N
        int retval;. a3 u+ f/ m2 U2 k+ `( P5 q
8 N+ {. f% |: N9 J, j( [
        if (!kobj)
& c( K: a6 s; U; e( d8 }                return -EINVAL;
' ]( N. ?4 P* Z, R. f
+ C; @3 l+ g- N% I( `        if (!kobj->state_initialized) {
( @. f& C% g  I! @$ k  M                printk(KERN_ERR "kobject '%s' (%p): tried to add an "
5 L6 \4 r- X5 U; `                       "uninitialized object, something is seriously wrong.\n",
0 a; }% s1 u6 W, Q                       kobject_name(kobj), kobj);
# z9 g: z+ W+ A" T                dump_stack();
* j& `. _8 X$ t& O( Y' ?                return -EINVAL;
) G% q9 ^" C- H3 Q0 m' I        }
/ S! V- e+ z1 Y$ o( l* m( f        va_start(args, fmt);% p) @; {9 ^" k! w' w
        retval = kobject_add_varg(kobj, parent, fmt, args);
) r! t, k4 s! P5 e! N- C# B7 P        va_end(args);
# C' P7 t* f' V( c8 F
6 V) q& a) l; Y        return retval;
2 j7 e. U2 w  I}; y& Q4 E4 D. M. p1 n
EXPORT_SYMBOL(kobject_add);
. c& r) K  d3 q: T5 z4 L- o2 Y  S7 [8 X2 T& R6 S
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
% g0 ]. d7 a# _# ^5 z% c                const char *fmt, va_list vargs)5 W: N: D' z8 H0 D6 g- `- @% Z: N
{1 L7 T* `; ?  L8 K: x: S
    int retval;
2 g. s2 b( W1 P8 g5 e% W7 O0 n; S* q# _. |: [4 p! k
    retval = kobject_set_name_vargs(kobj, fmt, vargs);
/ A/ q: M" T( }& I5 k- V0 o+ k" S    if (retval) {
& [& d% y# Q1 c        printk(KERN_ERR "kobject: can not set name properly!\n");
& c/ }: c9 m8 g% }        return retval;
& ^+ s( z3 H8 S; A4 ^5 g    }
: p$ U+ z$ F' l7 Z; b    kobj->parent = parent;: m: b: s' Z6 e/ b% o
    return kobject_add_internal(kobj);
: Z. p9 ]0 ?/ K, q4 C$ M$ ?}
+ f- `8 y- d' O: E1 Y8 e5 [
/ u4 X/ x* {8 e$ o4 o/ x- A% r2 Q3 _static int kobject_add_internal(struct kobject *kobj)
4 B9 b4 c8 V( R2 d{6 Z, G% w  r" s" l
    int error = 0;
1 ^6 U, K' h: A8 E    struct kobject *parent;7 V' D: D1 T5 _: k0 x) L
8 _. }# y+ z4 {, k: n. u
    if (!kobj)/ Z* y" y4 ~, B. D
        return -ENOENT;
, G8 N  t( H) y4 m0 o: h2 z    /*检查name字段是否存在*/
8 r( r2 U' L. \9 H; M& C4 o: k( r/ d+ {    if (!kobj->name || !kobj->name[0]) {" O9 p( U5 V8 X& d& P2 }3 y  E
        WARN(1, "kobject: (%p): attempted to be registered with empty "0 V+ C; j+ s9 q
             "name!\n", kobj);
6 Q3 ], R. S0 b' x+ Z5 W. P        return -EINVAL;
2 i7 z& F( W. ^0 t4 Z: e; N    }, x3 P6 {9 L3 k- g# |) N" H+ t

7 D; }% @% J2 M) b. S  J    parent = kobject_get(kobj->parent);    /*有父对象则增加父对象引用计数*/
6 v# c' s  \5 W0 u: \* g" F+ [' {* T( U0 i7 b) J* i* e! w2 M/ J
    /* join kset if set, use it as parent if we do not already have one */
" F0 [' ]6 I' _( a& _$ D    if (kobj->kset) {    * M# j  z. Y7 X) N
        if (!parent)0 n+ q& s* b2 H4 b; B9 Q: V# N
            /*kobj属于某个kset,但是该kobj没有父对象,则以kset的kobj作为父对象*/
9 c2 m: w, P1 g. H+ M            parent = kobject_get(&kobj->kset->kobj);7 y( l* ~% v6 Y
        kobj_kset_join(kobj);        /*将kojbect添加到kset结构中的链表当中*/7 S: l: g5 z/ D
        kobj->parent = parent;
& E: i9 b% B0 z- l4 z5 E6 c    }
* J5 Z- n& E1 x' S$ }* Q+ v+ U3 g7 ^2 j) _- N! Z
    pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",+ J& ?' y5 Z7 t( h: F1 f
         kobject_name(kobj), kobj, __func__,
- h) u6 B$ D( ]* }  L0 {! P  P5 |         parent ? kobject_name(parent) : "<NULL>",* F! }. E& [3 K8 |  `$ r" z5 I
         kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");6 {+ e4 m$ b0 F0 c2 a# {
- R8 G# w4 l) b" Y" e
    error = create_dir(kobj);    /*根据kobj->name在sys中建立目录*/
2 d1 p3 X* w  d    if (error) {* e/ O* z5 I/ w6 ?2 O. V3 d+ S2 Z. |
        kobj_kset_leave(kobj);    /*删除链表项*/
/ \7 C! `! ^; W- V- S' t* ]        kobject_put(parent);    /*减少引用计数*/
; R* W6 n: Z( F, d. n% D; i( f+ ?        kobj->parent = NULL;
1 b# h1 |/ ~! Z4 M/ }0 P
; L5 y. a# I* H; x: \' E- b        /* be noisy on error issues */5 U5 f  f4 W! l  ~% R7 N
        if (error == -EEXIST)
" @% [' J+ b8 U, D! v            printk(KERN_ERR "%s failed for %s with "2 b# [3 u5 I7 V3 ?
                   "-EEXIST, don't try to register things with "
, y* D* W( T, W2 P( j: q( N2 ?2 }                   "the same name in the same directory.\n",% D2 g. i! a( s# A
                   __func__, kobject_name(kobj));
% y' w1 ]9 l9 [, z        else8 R/ c2 Z3 Q4 A7 z# K
            printk(KERN_ERR "%s failed for %s (%d)\n",
* Y/ M1 m2 T* Q1 U6 @                   __func__, kobject_name(kobj), error);
; ?2 l' t+ A" }/ B: J- K6 z        dump_stack();
; n5 V/ H/ |8 s! k" R# Z. z% o    } else
- n  E7 d1 d4 F, I/ u! z        kobj->state_in_sysfs = 1;
9 W, `/ w# U+ H1 n4 K2 Y3 z8 d! h; j8 K0 {, q& W3 T: d) e7 ~! z1 H
    return error;
4 @( l$ W- N, `5 n& t/ ?: Z}
' t& _% _; Y7 m7 D  F( H6 g3 l& F在调用时,参数parent为NULL,且dev->kobj.kset在6.1节device_initialize函数中设置为devices_kset。
, A8 Y7 ~9 E1 f而devices_kset对应着/sys/devices目录,因此该函数调用完成后将在/sys/devices目录下生成目录platform。: y( Q6 S9 K/ C$ }$ ?: H2 e

( z7 ]* U# Z  p' I但是这里比较奇怪的是,为什么platform目录没有对应的kset对象???
$ V  F# c- `+ G) w( L' S, i; c& I* ?% q7 _
6.2.3 device_create_sys_dev_entry函数2 L1 O2 Z, n9 u$ b/ m7 u
在调用该函数之前,会在/sys/devices/platform/下生成属性文件。接着如果该device的设备号不为0,则创建属性文件dev,并调用本函数。0 q$ X6 N3 h7 L! H/ C0 Y
但是,在本例中设备号devt从未设置过,显然为0,那么本函数实际并未执行。
  {" L8 n7 r7 E% ?/ f+ V
8 D9 R( W9 e4 n- I  r下列代码位于drivers/base/core.c。! c# t: c  p1 }: w$ |- m
static int device_create_sys_dev_entry(struct device *dev)! |- V' Y( R7 R: ~. E- S
{
: ]* h+ f( o6 p        struct kobject *kobj = device_to_dev_kobj(dev);
) p9 D7 ~1 c6 k% q9 R! Z        int error = 0;
3 m9 N  H! c1 t2 _+ z1 s; J        char devt_str[15];
8 _( a& l% l2 `% d# _, x9 q4 m0 m' W  F/ k
        if (kobj) {; C0 W+ s/ a) u! \$ G6 F+ M
                format_dev_t(devt_str, dev->devt);
  j( o9 Y& @1 b$ d: R0 y2 M. z                error = sysfs_create_link(kobj, &dev->kobj, devt_str);
4 k9 o& ?( s/ l        }
* P/ ]# c/ s, q1 W* J( R% ]4 P. b1 N* ]7 O* e( [( D
        return error;
7 ^% a! Q/ i1 X* N7 {}2 q* r) V7 R( e; e
/**
, z. h' C1 x+ m8 k2 V# C * device_to_dev_kobj - select a /sys/dev/ directory for the device
5 ^, K- K; {3 i! u# n/ F% x * @dev: device
+ N$ N0 J9 {, ?& {7 u! X3 f *
2 {" {' S" o: Q8 q! c8 e$ H8 e- A * By default we select char/ for new entries.  Setting class->dev_obj
, ]- L" m* M: n# ^) {$ v * to NULL prevents an entry from being created.  class->dev_kobj must& g- C9 K+ a% K6 L* R  a+ d: a
* be set (or cleared) before any devices are registered to the class
4 i/ _- S! j) R! K* e' Z+ I * otherwise device_create_sys_dev_entry() and- j2 g2 {: w. H
* device_remove_sys_dev_entry() will disagree about the the presence) d3 `& j! k5 y8 s
* of the link.
* a& y  u. B" P' ^4 n */$ a/ C2 g; c5 x+ a* m- y
static struct kobject *device_to_dev_kobj(struct device *dev)# Z. N1 N3 j/ W" c
{
4 J) i! Q+ ]  I    struct kobject *kobj;
) f( T; k- d7 H/ J% ~9 W2 F: V
' O1 f  x0 a* x9 x* y  E( v; R5 T4 e    if (dev->class)
% U, O% p) q0 o& {3 ]        kobj = dev->class->dev_kobj;
0 a- w! d- r4 ~" d7 F) {- u6 A/ G    else$ f# B1 f2 J% k: z
        kobj = sysfs_dev_char_kobj;+ I6 y: b- i2 S  T' v, n
* {9 l' K( I# U- ]8 ]% F
    return kobj;' I/ u* }1 ?1 D3 w8 I3 `& n
}# @7 `# b  h' \- C7 G+ e8 E

# Z: v# O" X9 }( z7 ^6.2.4 device_add_class_symlinks函数
$ C* q  y# p3 m( H由于dev->class为NULL,本函数其实没做任何工作。0 I: h& U  A  v
. [% ?6 @  b$ c; d
下列代码位于drivers/base/core.c。7 B) e* b8 i5 D7 g$ z1 Y7 @
static int device_add_class_symlinks(struct device *dev)- ^; ]2 x) U/ Z' {' Z
{
# y( \9 M% e' |' N        int error;
7 l# p1 t" H. q+ W) s, [0 L7 q; ?6 W8 X' g# @4 Y1 r* L  E
        if (!dev->class)
# @5 S5 \. C3 c' d1 C                return 0;
' m, \' e( T4 }2 m, R6 N- q1 ?" N1 i6 L6 K, Z0 {
        error = sysfs_create_link(&dev->kobj,
' h4 X1 W  k+ U  d                                  &dev->class->p->class_subsys.kobj,
/ B4 h- W; O2 @  }6 J                                  "subsystem");/ [- Q8 ^1 f# v9 i- N7 Q
        if (error)
3 t) Q! E' B, u7 Y+ f& @# M                goto out;: v9 B  r& b1 e' `

1 d/ K9 `( Q- o9 Y& V# m6 x2 c#ifdef CONFIG_SYSFS_DEPRECATED
/ R. a( f) B! h        /* stacked class devices need a symlink in the class directory */
, S( V" Z: ?& }7 x, V' H        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&8 i( O1 y* p2 E) C
            device_is_not_partition(dev)) {
1 Z& ], k  P7 p+ Q  n- T                error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
6 m$ b9 u; S6 b9 |! i9 F% j5 m/ [                                          &dev->kobj, dev_name(dev));
4 Y7 _% P3 {5 ~                if (error)" w# s! c9 l; {+ i
                        goto out_subsys;* ^! |: @4 i1 E$ f' U9 M7 Q: Q: f
        }! |% ^/ L0 j1 A( x2 n( G4 Z* p" T
# c' V5 m3 C1 `; e" k: d9 i* w9 X
        if (dev->parent && device_is_not_partition(dev)) {
- r% S% l4 a- B) T                struct device *parent = dev->parent;% b. f5 x# s* g1 U* n/ v. \1 g$ Y; J
                char *class_name;
$ {  O% L; K, a3 R% x* K% |$ ?
' F  X3 w) `2 l6 U9 Y                /*# l9 ^0 ~3 o" M3 s5 a
                 * stacked class devices have the 'device' link0 E1 e& H* w& }7 i% g# Q
                 * pointing to the bus device instead of the parent7 P0 C" I4 y; [9 n6 X- G
                 */
! j, r# l3 A$ Y. v/ p  v                while (parent->class && !parent->bus && parent->parent)0 W, p0 n4 G! i1 m
                        parent = parent->parent;$ {) ~* |; e3 y( C$ O+ x: t( t" ~
' [1 K+ z% F3 e! G6 p& A
                error = sysfs_create_link(&dev->kobj,( b9 b0 ^+ m; E9 \, b$ L
                                          &parent->kobj,& ^& I  Y- C$ F6 P, h
                                          "device");
2 x8 @& K5 A0 e, y3 \                if (error)2 x) k) _% j* f" O# R: S# S
                        goto out_busid;/ q; @7 S( q( u% h6 C2 U" w

) J8 V% v  H3 M3 |, S' X                class_name = make_class_name(dev->class->name,/ c0 e/ F5 |) |4 f6 `
                                                &dev->kobj);# Z3 \+ b9 Z, b; [# r* Y, Y
                if (class_name); l. F& B6 M# m- Y4 q9 }/ d( Q1 s
                        error = sysfs_create_link(&dev->parent->kobj,
2 [0 ~% w9 [7 [# }  I                                                &dev->kobj, class_name);
$ r# R$ y/ A. G  U                kfree(class_name);
7 \& j! S" p) E4 m$ S+ V                if (error). M- n% K' @# i8 ^8 s, ?) D
                        goto out_device;9 H8 w3 a! ^  b2 ?8 M
        }0 b- U; K4 d2 D7 Y2 M- L( T2 C
        return 0;
7 g' w) }! t: ^! w' S! s+ e1 X  S; O8 B% O
out_device:
; w, n3 c9 T* Q, A5 ?5 `! L        if (dev->parent && device_is_not_partition(dev))
( @/ {% I5 h' |) M" d6 Y3 U+ z( y- @                sysfs_remove_link(&dev->kobj, "device");. L5 l  ^. b8 u) R; d7 A% A1 l4 g% @
out_busid:7 E) C1 f; N5 W% k
        if (dev->kobj.parent != &dev->class->p->class_subsys.kobj &&
! u- R* K8 u5 d3 p7 q' g            device_is_not_partition(dev))8 U% n$ r  e/ p. ~4 ]& H0 s
                sysfs_remove_link(&dev->class->p->class_subsys.kobj,
* e) Z# Z9 {% k" R% P                                  dev_name(dev));+ N: Q" Y& }6 c6 @" }) c
#else
4 V, u5 i4 _& X# z5 T        /* link in the class directory pointing to the device */5 L, t- `. _3 E
        error = sysfs_create_link(&dev->class->p->class_subsys.kobj,
9 ]3 F* G( X  t$ H                                  &dev->kobj, dev_name(dev));
9 Z& I$ L9 L. O2 \3 O        if (error)
: u) q  m* @7 @  N) Q                goto out_subsys;$ Z+ C' U  B4 V' E9 ]! z
; [3 U7 X- [+ c4 M
        if (dev->parent && device_is_not_partition(dev)) {! h" V5 g) O+ g% G# K/ G! @" q3 i
                error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
2 S! ?2 I4 \! f: g6 i' t4 j7 [1 G                                          "device");1 z# {( Q, O/ k0 j
                if (error)+ h9 M7 d( D& N4 E# g
                        goto out_busid;0 y* k: T7 N: |& u% j5 L9 C8 b
        }
" q7 k, p6 a( z        return 0;& F* X7 @$ J# M7 m

4 [& O( i8 w' ]8 c7 @6 d% Lout_busid:; H* W% Y. S6 [5 [4 [5 Z2 k
        sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev_name(dev));
! t2 q* F0 J" u  K) U#endif
. u% {9 X4 q  _/ Y+ j0 t. [0 ~* j" ~) B' D; i1 a
out_subsys:
( q7 T8 J5 _* Z+ j3 Q2 m! s        sysfs_remove_link(&dev->kobj, "subsystem");# N  r7 c  |6 G+ l. }
out:
; [4 @/ U; j. ^, S0 l        return error;
% c) g8 g" B3 E' j4 A& d# [}
, `9 {1 U. W# }6.2.5 device_add_attrs函数8 f! [4 O' A) t
同样dev->class为空,什么都没干。
6 z( m" F) J+ u下列代码位于drivers/base/core.c。
6 o# [% H2 G7 [* c& Cstatic int device_add_attrs(struct device *dev)5 H1 {* {+ }: S( R) Q0 k3 p
{7 i, ?& i( o4 T" B, i3 i) Q' g% C
        struct class *class = dev->class;
/ b. H0 t& E7 C0 B8 G        struct device_type *type = dev->type;  k6 {1 ]' ]6 p
        int error;  j9 k# r0 ^& N! Z
; _9 x3 G2 w8 t/ {. Z
        if (class) {
4 g3 f  d9 z, u3 V% Q3 z. i                error = device_add_attributes(dev, class->dev_attrs);
* K: b- [: t, v( t9 ~1 E1 B1 ^0 S                if (error)
" u( T+ H5 }8 B5 L0 Q% u                        return error;: R& n9 Q# ^: y
        }6 h# ^' K' C, ]' x

. G& N$ G5 e* [2 d( V$ p" s        if (type) {
4 t5 V1 H$ v6 a) ~5 p' b$ y* }. \                error = device_add_groups(dev, type->groups);
" F- H1 Q2 i) X9 F  m) s$ x# h* k                if (error). {( s4 R6 @, t$ e, {" U  D
                        goto err_remove_class_attrs;
2 S5 e3 y8 c6 J" B4 `! V( }        }+ I0 m- x5 W0 q0 W, E
$ ^, O& k) m' {$ t" l9 M2 W
        error = device_add_groups(dev, dev->groups);; o) \4 E. Z$ j- i
        if (error)
+ z/ y. @$ i0 V                goto err_remove_type_groups;% x- E* W' J# c) P, ]

& H. _' K1 e& F4 ], D7 H        return 0;$ |, G% I3 E7 }+ q* X' U- P& `

6 i6 b' {; ?6 Z err_remove_type_groups:9 |0 e1 x3 c+ e+ c! D) q7 @! B
        if (type)4 @/ _9 x4 J8 u9 R; b; R( r
                device_remove_groups(dev, type->groups);+ w! Y7 p( U: S1 K! v
err_remove_class_attrs:
: L( e* t8 N- _% F" T        if (class)
$ o2 X2 |# k& L/ |                device_remove_attributes(dev, class->dev_attrs);" r$ Y2 x! U5 A3 \8 D

# k" y$ T. b1 p! L- Y        return error;
1 R5 V  ]+ {, b% ~3 `0 Q}' i: K0 p& D1 H2 A& o! c
6.2.6 bus_add_device函数
+ z5 O1 S7 g* Q3 Z8 Q, D由于dev->bus未指定,因此这个函数什么都没干。
  M4 g1 D" Q& q( B4 C6 ~/ {! e# L3 V- A5 d6 y# B! H) L
该函数将创建三个symlink,在sysfs中建立总线和设备间的关系。6 @; m  [! Z% l5 z6 g: V4 K; E, C
* y% ?; m# l1 T5 p- s0 \1 b$ o! \' ]
下列代码位于drivers/base/bus.c。
6 D# M1 M  M( h8 B6 v/**+ A% [6 f1 X$ I  y( H
* bus_add_device - add device to bus, n$ G3 l4 _: Y8 ?. v* ^
* @dev: device being added. F. l( w, J" R4 f
*( c! l, Z0 [( Z1 B7 ?! J
* - Add the device to its bus's list of devices.
( r' L4 S! G& Y$ w) h: f * - Create link to device's bus.  y' I7 O" v1 U6 K2 o( d) c4 }
*/
1 c: n1 \0 I1 ?# L- O! e0 B) M- mint bus_add_device(struct device *dev)8 c6 y# d3 k! a: `8 ~
{) f& `# z/ b. X
        struct bus_type *bus = bus_get(dev->bus);
4 V8 a9 r- d  a        int error = 0;9 G; k' e( f- u8 z9 K- [* O- p
) h1 D# y8 y  s7 o
        if (bus) {
- l! ~' Z) \' h5 [7 Y                pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));; p9 K( j' Z' w0 R5 X" u
                error = device_add_attrs(bus, dev);
  z& ]/ ], [; }/ P                if (error)! p; a2 x5 ^' k# [
                        goto out_put;) O. l$ V8 A9 u! J! e/ F) j5 S
                - i% `8 H2 w' |; H, n
                /*在sys/bus/XXX/devices下建立symlink,名字为设备名,该链接指向/sys/devices/下的某个目录*/. w; Y4 C/ h# l
                error = sysfs_create_link(&bus->p->devices_kset->kobj,
- g4 k* G2 F2 L                                                &dev->kobj, dev_name(dev));
# ~% W; L$ `& p/ \                if (error)
' |1 D; _! E( H, h                        goto out_id;
6 ?/ ~0 k( u" p( _& t. B1 x& E               
% a& y0 e5 p' p) f, d                /*在sys/devices/的某个目录下建立symlink,名字为subsystem,该链接指向/sys/bus/下的某个目录*/
4 S0 K( z% _9 e# p+ ~                error = sysfs_create_link(&dev->kobj,! P" l# s2 z6 B& C
                                &dev->bus->p->subsys.kobj, "subsystem");
  u6 y3 l7 y# L# Y$ o+ i                if (error)
  l' k  r. E% \7 x* U. M* V                        goto out_subsys;+ ]4 p' R% y% m, V: F
               
% Y6 l- ?" ^/ P& j! ^* s$ n                /*在sys/devices/的某个目录下建立symlink,名字为bus,该链接指向/sys/bus/下的某个目录*/
, M8 P; p; }, y. r  z$ [( z% J                error = make_deprecated_bus_links(dev);
/ s( M4 \8 _( J$ W  I7 ?                if (error)
3 s& w1 g/ F* m' k# H( o                        goto out_deprecated;; \( U, t: Z0 Y' k6 @( i0 F. C
        }
5 ]- s, L, z6 T3 _        return 0;
. l$ u$ e8 [9 p+ J% B& f+ B3 }: ?. F* u
out_deprecated:
$ }) ^$ v( q  D# `        sysfs_remove_link(&dev->kobj, "subsystem");
. P- _) }. ]  A5 b( jout_subsys:
( H4 q. E& Q9 ^/ q        sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
1 @2 Q+ t5 u3 `  ~9 Kout_id:; s* ?$ U/ ]9 L5 O7 F, o
        device_remove_attrs(bus, dev);
+ R6 o% R2 ]% b, V( }out_put:
4 |% c( G  }$ d$ l0 X" C! d        bus_put(dev->bus);
* v" e8 B7 |+ M2 _        return error;! t$ w# V7 K$ c  W- y
}4 \* i  U7 e! Q4 V

0 F$ o8 x" \' v2 \# \' g6.2.7 dpm_sysfs_add函数: R# c1 J3 `, z! q+ M6 j# z
下列代码位于drivers/base/power/sysfs.c。
! r. K  e7 a, G, G$ D& Gint dpm_sysfs_add(struct device * dev)
0 t1 C! v2 p* f{- a7 ]/ d# J! I
        return sysfs_create_group(&dev->kobj, &pm_attr_group);7 A% `' {9 m  C2 t! T1 Y; ~* l
}. R) J; [4 e6 Q; h
) k% K( A' ~8 Z1 a5 r7 Y2 A1 b  E
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
" g4 B) a! T' u% e1 U' t
  d" \/ L9 K7 ^. S  A# ^0 s
5 j. u) H, B( g; pstatic struct attribute * power_attrs[] = {
3 j& u! Q! Q! b, [' k+ S% m, f0 B    &dev_attr_wakeup.attr,/ \9 w1 t$ m# f  R' b' Y9 D# n
    NULL,3 h2 I6 {  ?) N" D
};
5 o% m" f7 G: a- r2 astatic struct attribute_group pm_attr_group = {8 X5 b1 Q1 k% T. R3 a
    .name    = "power",
0 ^) z/ |, X$ e* d" U- j6 }: M    .attrs    = power_attrs,, ^& `' a2 s+ b( ~$ h
};
# f* J2 \5 h! y* w
: h, @+ i  f2 l0 z5 |该函数将在XXX目录下建立power子目录,并在该子目录下建立属性文件wakeup。5 v! w, N3 O5 A5 @* M8 O9 g
1 Y* M" }" E5 W1 a8 N) D6 L. J
在本例中,将在/sys/bus/platform下建立子目录power并在子目录下建立wakeup文件。; E& J* o2 ]8 K1 y
6.2.8 device_pm_add函数
! k3 w: h4 O0 l. I2 ]; M下列代码位于drivers/base/power/main.c。
# Y1 V- O5 y# {/**
- C# t* Q7 N8 @5 p6 J. f/ v4 y *        device_pm_add - add a device to the list of active devices
9 i% _$ N8 k* H: K! p( D! Q$ [5 ^ *        @dev:        Device to be added to the list
& {) K8 ~1 P& a7 `* a- a9 N. i */
$ {* e2 j  R+ [4 K4 l4 g3 Z: }void device_pm_add(struct device *dev)+ ~. N- R4 ~& G: Q5 T, M' L
{
' w% n; m' S+ J        pr_debug("PM: Adding info for %s:%s\n",
( V- y  x3 Q. Z- V( B: {                 dev->bus ? dev->bus->name : "No Bus",
: @4 z" w5 Z: I" w2 S% z                 kobject_name(&dev->kobj));
/ C# u5 C( |% w* I6 w$ y        mutex_lock(&dpm_list_mtx);; K, e/ I! l' C
        if (dev->parent) {8 `' }  a, S5 Z
                if (dev->parent->power.status >= DPM_SUSPENDING)
9 _8 b  a& l, g! M- |. l( _                        dev_warn(dev, "parent %s should not be sleeping\n",! l9 N+ A3 P0 p: E+ O
                                 dev_name(dev->parent));! q0 ]2 u& ~! v) u  {# z
        } else if (transition_started) {$ }8 G- G% ^( i$ R! l" D( Y! Z
                /*4 s" n" B+ t; O: H* m& ~% c
                 * We refuse to register parentless devices while a PM
9 H# Q. D9 [5 S% s. j                 * transition is in progress in order to avoid leaving them
; `5 F# |6 u7 [6 ?  H2 g6 F5 i                 * unhandled down the road$ K  `$ d' V5 \0 z. F$ ~1 w% ~
                 */
. z; I( l, V8 L/ A' g                dev_WARN(dev, "Parentless device registered during a PM transaction\n");! o5 m2 ~5 E* g7 }0 Z
        }! Y- v! Q: h' j5 `/ r0 {

6 R7 R; F/ H$ h; P+ b2 y7 t        list_add_tail(&dev->power.entry, &dpm_list); /*将该设备添加到链表中*/+ _$ A) E4 s3 h4 ~, j. `5 H
        mutex_unlock(&dpm_list_mtx);
5 w6 ]$ E9 H5 @2 y3 q$ b}* p& t( ?$ W  t* V; Q
0 F6 I# a* Y' v- ]9 c* v
该函数只是将设备添加到电源管理链表中。/ Q4 h# S' ^8 j4 Z: s. W
6.2.9 bus_attach_device函数) ^# r3 m  h0 p' c+ s# @! K
在本例中,由于bus未指定,该函数实际不做任何工作。( m! b. }4 `3 {; T* j5 \8 L' ~
下列代码位于drivers/base/bus.c。  V2 `5 g( [7 G: \
2 F3 K* T7 A/ \, k
/**7 O" `' U( T& j6 O0 H; t
* bus_attach_device - add device to bus( }" ]0 \5 p4 }! o1 o* ?
* @dev: device tried to attach to a driver
$ o' T6 X6 S$ V% m* T9 z *0 G4 u: N% b. u  r
* - Add device to bus's list of devices.
0 G# [8 o  I' c- Z9 s7 T * - Try to attach to driver.
" ~! f8 O0 |+ g */
4 e  C* W+ }# |+ d0 d( O7 L3 Kvoid bus_attach_device(struct device *dev)# G6 B/ g1 U9 {- N; ]" Y  t
{& s, S5 f; Z: ]5 k& f! B- t( }( N
        struct bus_type *bus = dev->bus;
% x; J, l( X3 v8 Q        int ret = 0;3 l% b5 b( w, \

% V# M; T- O( q; R' C        if (bus) {$ s$ }- ]4 {1 @; e; K$ t
                if (bus->p->drivers_autoprobe)
* _- k1 |: F- Y7 Q- x2 y$ ?                        ret = device_attach(dev);        /*尝试获取驱动*/2 |/ L" ^: V# U) m
                WARN_ON(ret < 0);. `7 f4 @' }0 N7 L
                if (ret >= 0)                /*将设备挂在到总线中*/
/ t1 A' Z2 {# x                        klist_add_tail(&dev->p->knode_bus,9 I$ {. R0 d" n6 P) ~% W5 E% u* d4 _
                                       &bus->p->klist_devices);' d" n1 k4 P& D/ ^0 @) s% U0 y- m) P
        }
# C0 P! {) U- B. w! m}
! r7 r6 {. l9 T' ?+ o: [% s# \0 O" o0 x2 Z) X* [
/**+ a6 H. t) s: V8 V2 {/ M% O
* device_attach - try to attach device to a driver.
! e( g$ F4 F( u! R# {! p9 f( w4 j * @dev: device.
( h- x( f3 d3 i& h *9 q9 m; Z1 j2 E8 K3 ^& G2 M1 t
* Walk the list of drivers that the bus has and call
' q0 v2 I8 j3 S9 i; n * driver_probe_device() for each pair. If a compatible
7 F. \  S: p+ i  F+ `( I7 r * pair is found, break out and return.  ?+ L7 Y( n9 C
*/ c& ~" v! w2 V
* Returns 1 if the device was bound to a driver;
. ?  |8 e4 S' F3 m9 r * 0 if no matching device was found;1 K/ n6 n$ M3 }! i- `9 E2 j4 c1 s
* -ENODEV if the device is not registered.& w; I6 k7 O$ _; Z: T9 z
*' k" I6 s5 w) J+ J( M0 b5 {# I, D
* When called for a USB interface, @dev->parent->sem must be held.4 y  w# ~9 k4 l8 X( m$ T8 B
*/# b  s( [5 G* j6 I3 U( j
int device_attach(struct device *dev)
. b8 i$ h5 r$ B* ~, u{
! e+ P# C& g, p. _% ]1 `/ B# L    int ret = 0;
" I4 E& N( ?* R' f& k3 `7 a+ R( ]5 s4 w! k3 C
    down(&dev->sem);
4 o2 ^& u* p8 b8 ^) r- s    if (dev->driver) {    /*如果已指定驱动,即已绑定*/1 R5 }% C- a: V1 q3 |  B7 n# |$ v( R
        ret = device_bind_driver(dev);    /*在sysfs中建立链接关系*/
, C0 n" O- n. q5 K* }7 Y        if (ret == 0)3 ~1 }9 E# F  X% r5 y3 c4 X& d
            ret = 1;
! k6 y- ~! {3 S( z- \6 o        else {
5 x  e# d0 ?& J0 w/ `1 y, N6 ]            dev->driver = NULL;7 l4 m# R, G- K  i# C+ F: ?* O
            ret = 0;! [" b& A( L( s0 a( Y  m
        }
/ R2 M. i2 O3 P, r    } else {        /*尚未绑定,尝试绑定,遍历该总线上的所有驱动*/$ S4 ~* J8 l& r8 O0 |+ Q  L% L
        ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);# h: \1 w: n2 T, l
    }
: H1 [% s$ R' N    up(&dev->sem);5 i) v" A/ \: p. k  W
    return ret;
- P) H7 a+ Z5 j& G4 q8 Q}
- z; m# O/ e- v4 AEXPORT_SYMBOL_GPL(device_attach);
1 a% I/ |# ]% f) \7 E9 s6 _/ q& Y, s6 j$ t
如果bus存在的话,将会调用device_attach函数进行绑定工作。该函数首先判断dev->driver,如果非0,表示该设备已经绑定了驱动,只要在sysfs中建立链接关系即可。0 G2 I6 |( C3 Z# o) \; A
6 m. Q1 ~; i- e, r2 [. i9 z
为0表示没有绑定,接着调用bus_for_each_drv,注意作为参数传入的__device_attach,这是个函数,后面会调用它。
& T+ H1 @: f$ M' E" F; T* E- [8 ~  Q
1 I- Y1 N" P) |" o4 W0 c+ v我们来看下bus_for_each_drv:: C) d7 U8 E1 S4 U

) Q8 m4 ?% a+ s2 A, [1 _. |/**
% o0 ~5 B7 F+ T * bus_for_each_drv - driver iterator
) u% N/ h- ?2 o* b' r6 j * @bus: bus we're dealing with.
0 ~" L+ s5 Y4 a! Y+ M& T$ U * @start: driver to start iterating on.
0 {5 y# G+ L( {* n: F( A# @! B * @data: data to pass to the callback.
/ ]- Q6 t! w% t * @fn: function to call for each driver.
+ B8 ]; E% {, S *% ]. c) ]6 _1 [2 @  R
* This is nearly identical to the device iterator above.1 A  x3 `3 ]3 z  f
* We iterate over each driver that belongs to @bus, and call7 ]5 f. Q( z7 H
* @fn for each. If @fn returns anything but 0, we break out* G8 Q$ J. P* h- \% k
* and return it. If @start is not NULL, we use it as the head( G# V9 g3 `, X, ~  Y$ H
* of the list.
6 z6 w; A$ b7 n: I3 C2 V8 ^, M: U) p  ? *' y2 `1 ?/ l/ l( _% d6 v% M. u2 T
* NOTE: we don't return the driver that returns a non-zero
; D) E5 H! P; H! j- E/ R* e * value, nor do we leave the reference count incremented for that* V+ m: }: _- p" v- l9 Y
* driver. If the caller needs to know that info, it must set it
) ?0 V6 M. L4 `& J6 `# A7 v6 r' I& b * in the callback. It must also be sure to increment the refcount
5 D# O  o. P3 r, l$ c" Q * so it doesn't disappear before returning to the caller.7 |  b/ Q" o# p* X/ j
*/6 o' q, b/ V2 l- N" a8 a
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,7 k) c( Z0 ^9 e( p7 z/ j
             void *data, int (*fn)(struct device_driver *, void *))
1 }" g0 \4 j0 r- u{* B5 ?2 l$ Z, Q" e! V7 F: }' v- `
    struct klist_iter i;
. j& N# N2 g: a5 m* ?! m    struct device_driver *drv;
* M$ y4 S2 ?  J. _" s6 }    int error = 0;, I4 D" F! f* }% Y, l6 }
. X; v8 J: q* ^/ f! V
    if (!bus)  f& q* {3 C) [# e
        return -EINVAL;0 c3 h7 X3 L" ?2 m# r

) O2 k5 S8 }- M8 P: h: `% G    klist_iter_init_node(&bus->p->klist_drivers, &i,
; m% Z& W9 c) l+ }: L& x# _. m                 start ? &start->p->knode_bus : NULL);
5 p2 W4 {$ a# N" U- ^7 l    while ((drv = next_driver(&i)) && !error)
9 v% U% _+ K+ D( g+ E# @6 t        error = fn(drv, data);9 P: g( h1 A, f9 V, @
    klist_iter_exit(&i);8 T* d# M  A' A
    return error;4 s$ L0 G% @- ^# h5 D$ j$ _% O/ C$ z
}! a/ y& g% E8 e) H
EXPORT_SYMBOL_GPL(bus_for_each_drv);
0 a. G7 F) E9 n' @7 ?" N7 j1 m0 m该函数将遍历总线的drivers目录下的所有驱动,也就是/sys/bus/XXX/drivers/下的目录,为该driver调用fn函数,也就是__device_attach。我们来看下:
. v2 L9 s0 V. c( N$ B
4 m( o" e% |7 Q* O" j5 U4 S4 nstatic int __device_attach(struct device_driver *drv, void *data)9 i+ c( B. l) C/ ^# m
{0 D% ?+ l; ~, f- V
        struct device *dev = data;
) r* Z: P) n8 Q' Q: n2 k, y7 A
' K# x9 d7 O$ f2 A3 q! o. @        if (!driver_match_device(drv, dev))   /*进行匹配工作*/
1 ~9 S' l0 f1 l9 C                return 0;+ p, i7 \6 K, s) O5 I& V5 l, y  Y7 g, F
5 y3 a  J$ F. C5 v
        return driver_probe_device(drv, dev);
, m, c4 p7 E6 z$ l7 V6 t}
* V; W  x; |( ~3 k; p, Q
* K% j8 L6 _. k" xstatic inline int driver_match_device(struct device_driver *drv,$ ^$ J$ {7 [% [- N0 L4 }, }
                      struct device *dev)/ q! a. _" f9 ^/ x1 I
{
: K5 R& T) n4 R! V* N6 n4 B    return drv->bus->match ? drv->bus->match(dev, drv) : 1;7 M1 O8 U8 z$ \2 c8 H
} 8 f$ j3 O9 d& t) s  t. I: K

" U+ Y7 W4 N: M- I: q/**
9 }2 t0 M, R% `; D' j8 `8 r * driver_probe_device - attempt to bind device & driver together: v: {( j3 D/ G3 n
* @drv: driver to bind a device to
% u* i+ A$ J9 q1 G * @dev: device to try to bind to the driver
' N  x4 v8 i  i9 W *
0 l8 _3 P, y& ~! W) }4 f* {; g * This function returns -ENODEV if the device is not registered,
# ^7 [& S% {# x& _1 E" B' l* z * 1 if the device is bound sucessfully and 0 otherwise.
) U$ g( H; d7 V& M% t; l *
, u$ Y8 A3 h$ ~8 R. S# ?+ U5 B * This function must be called with @dev->sem held.  When called for a( P( e% e9 ^& z: b
* USB interface, @dev->parent->sem must be held as well.
8 s2 p. [+ B9 G */
  q  B1 w" e* [5 P, p+ S3 yint driver_probe_device(struct device_driver *drv, struct device *dev)
/ G4 O$ F* Z; c# Y  ?{& c. V  E4 [2 A) N/ s' X8 [
    int ret = 0;5 y2 ~2 S3 [: q, I" g  ^

# i6 Z5 f! `9 c6 u' k  D8 D    if (!device_is_registered(dev))    /*该device是否已在sysfs中*/
/ f; ~$ q8 Y3 G5 Q* N        return -ENODEV;
( k) e7 q/ p' b, ]3 E3 s$ F+ r5 O! n; N) z7 A2 n" w
    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",! P' `& ~' ^. V1 W  J0 }1 Y- G  m
         drv->bus->name, __func__, dev_name(dev), drv->name);
1 a3 k7 y: K) r
9 ~5 ~8 Z) e! y* W    ret = really_probe(dev, drv);/*device已在sysfs,调用really_probe*/   
: L+ U, G& S, v6 I
( @+ B6 v$ o* x3 q* K  Z" U4 J    return ret;
8 P/ A: d+ _* K' f2 h& @* Y( G}6 i. e7 F& h# u% Z
# B) b  Y+ }6 c0 q) P: J& w; Q
该函数首先调用driver_match_device函数,后者将会调用总线的match方法,如果有的话,来进行匹配工作。如果没有该方法,则返回1,表示匹配成功。
6 K2 M2 W, T1 @- u6 ]; Z" S我们这里是针对platform总线,该总线的方法将在7.6.2节中看到。1 N/ z) c5 U+ h- s8 G- h% w+ O

+ O; \9 @) h) O+ k' Q随后,又调用了driver_probe_device函数。该函数将首先判断该device是否已在sysfs中,如果在则调用really_probe,否则返回出错。  L( I) F: F# e) p( b4 N
# Y# W+ x6 q. W9 a( t8 f- N
really_probe将会调用驱动的probe并完成绑定的工作。该函数将在7.6.2节中分析。
$ G4 P1 ?' O- E, Z9 }% q6 i* V6.2.10 小结, O$ [7 K! \+ [% y. P1 p' Y
在本例中,当device_register调用完成以后,将在/sys/devices/下建立目录platform,并在platfrom下建立属性文件uevent和子目录power,最后在power子目录下建立wakeup属性文件。5 B( i+ C5 f6 x' N0 i- r0 S. \

5 ~  }# R+ H4 g5 l+ [最后以函数调用过程的总结来结束第6.2小结。
/ z' e% t2 ~# u% h8 |5 }
, Q- E/ x+ q5 e9 ], \# T
6 y' ?1 A8 l7 ~' a2 |" _/ q7 u& i4 @5 q: B' i& l" R* R% j; O9 [7 q

1 L( ?8 y& E( X1 ~7 }, o6.3 spi主控制器的平台设备
; z/ X+ n: v. S# g1 i% ^本节对一个特定的platform设备进行讲解,那就是spi主控制器的平台设备。
1 E5 j3 ^/ I2 O5 `2 F" t1 z9 S4 |% L7 S5 E+ T* S( Q* _
在内核的启动阶段,platform设备将被注册进内核。我们来看下。$ h3 Z+ Q6 L) a+ M

0 N( U7 t2 K# z2 a- b下列代码位于arch/arm/mach-s3c2440/mach-smdk2440.c) d" D9 `2 k0 m
, F  |8 ?$ J$ O) x1 o
static struct resource s3c_spi0_resource[] = {9 V9 c5 y! f6 N! b+ z6 W
    [0] = {
! E$ F! F  M9 i2 t1 G5 z# u+ ?1 A        .start = S3C24XX_PA_SPI,
5 T! q. Q6 h6 O8 D8 v, r        .end   = S3C24XX_PA_SPI + 0x1f,6 o( B4 I  ^( L/ g% ^  R! ?
        .flags = IORESOURCE_MEM,3 S  v4 p) L( V* ]) K5 i6 F
    },
& g# K2 D3 D3 k. \+ ]    [1] = {% ?6 ~$ T* M+ n" [3 o$ S3 q
        .start = IRQ_SPI0,- k9 z" @% ~5 T1 L! i! `
        .end   = IRQ_SPI0,
- L6 E. n9 b+ l& `. o        .flags = IORESOURCE_IRQ,
8 }3 x! ^, O& E2 o+ z$ Z9 C    }
) g# ^& _9 E# N; m* v! L. L3 W) N8 q: }  {1 t
};0 M7 w# \# N" t8 [1 Q' m, \

) R5 J# h2 h7 D5 {+ d; ^7 Xstatic u64 s3c_device_spi0_dmamask = 0xffffffffUL;5 \! g1 y3 j8 C4 H7 x0 \
, {4 v7 a( n8 W
struct platform_device s3c_device_spi0 = {
: d9 r( G1 T0 C! V1 P6 n3 s: U. P6 {2 s    .name          = "s3c2410-spi",
& M5 p/ W1 x9 O5 C    .id          = 0,
9 f6 N9 _! S  L* E1 g    .num_resources      = ARRAY_SIZE(s3c_spi0_resource),& C7 B6 ^/ \0 {* R4 c; @* d
    .resource      = s3c_spi0_resource,. d6 R' L' V5 a- ]- X
        .dev              = {; L$ o  N" |5 v! `$ l# s% ]
                .dma_mask = &s3c_device_spi0_dmamask,: z! {1 C. `; e& x9 I
                .coherent_dma_mask = 0xffffffffUL$ r' A, e: T) d+ y/ {0 N
        }! ^  d: V9 E* g, w
};
6 p$ @  h" z1 a# b# K% @+ T0 n% _+ f4 O5 F& x2 @/ S6 d* R
static struct platform_device *smdk2440_devices[] __initdata = {" _- N/ b- B+ e" g! L
    &s3c_device_usb,+ @+ B& I4 J+ l# V8 `8 t# Y
    &s3c_device_lcd,
8 \5 H$ A. ^4 S) j    &s3c_device_wdt,
: x  B# D( i7 P# q% `    &s3c_device_i2c0,
* R( g$ O" ]" z& j( c  f% q8 B    &s3c_device_iis,) E# I9 K* U0 n2 @
    &s3c_device_spi0,) f% j7 Y( W* v2 `0 h, a
};
: x8 N+ U/ e+ ~3 W$ q3 c; b5 \: l/ N3 H  D- W5 v( F. R& J0 ^2 ?  b$ q
. \5 q8 p7 D5 N  ]

( U9 W* a0 i. T$ I+ Dstatic void __init smdk2440_machine_init(void)( [1 d: n. u! M- a) ^0 @6 ~' l* ]
{
% i4 J* K1 ~3 p2 y( ?        s3c24xx_fb_set_platdata(&smdk2440_fb_info);9 Q7 Q7 U# V3 @$ C5 [- h4 x9 ~- M
        s3c_i2c0_set_platdata(NULL);! g9 Y- F& |7 R. w2 y. A# G4 x; T3 Q

/ j; Y/ G# W$ Q        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));: \; S$ M# A+ q0 F& u& _- X- U& m
        smdk_machine_init();
+ S, `, X) Q! Q8 N% b& s# G/ ^5 A}
* S0 p1 q" M% a+ ]2 Y: ~6 c) j* X8 O, i# U& s
在smdk2440_machine_init函数中,通过调用platform_add_devices将设备注册到内核中。接着来看下该函数。# ?3 d6 R' U0 v0 Q, ]/ ]& W* `( {! P
6.3.1 platform_add_devices
1 e- B( Y1 }- @# u8 q) D* |: v) ?/**
6 _9 n! Y; q6 j * platform_add_devices - add a numbers of platform devices
, @# }! E- [# l * @devs: array of platform devices to add
; ]0 f4 l% L& I  C * @num: number of platform devices in array
8 L! {1 p8 ?) _% V5 }0 V */
( ]: }2 S5 D) Q/ Tint platform_add_devices(struct platform_device **devs, int num)
  D/ B$ d3 |2 V0 J- b0 S) l# K9 f+ \{
! ^0 z6 X/ @! g6 w8 D        int i, ret = 0;. ]' F6 S0 a/ V: `* y
! Y/ S9 Q$ s2 B4 e( B' \" m
        for (i = 0; i < num; i++) {
, ?* C) v, w" ?4 p/ D7 q                ret = platform_device_register(devs);
( m& \: R' U3 s, q' M                if (ret) {- r7 o; B+ `: v! C/ T) s8 Z
                        while (--i >= 0)
% Y. L- T: ~1 |0 e3 L* Z                                platform_device_unregister(devs);. R1 {% [3 \7 R+ V
                        break;. r8 B! }/ W( @
                }& @& H) T7 B0 Z" ?, Y# I
        }
& f" W; R  E5 s$ p% l' c% D5 M# `: ^1 Y: S
        return ret;6 I% b: }1 U0 j, @% ?6 C8 P
}
1 V7 S4 B. t: V3 J7 ?/ M0 FEXPORT_SYMBOL_GPL(platform_add_devices);
+ c! z1 {# ?& \' y: T" z1 A1 ?% |7 ^6 C/ K4 B* o
该函数将根据devs指针数组,调用platform_device_register将platform设备逐一注册进内核。: W1 L1 @; {; E+ b* G6 h
6.3.2  platform_device_register) b/ w8 F& M7 p: [) e% D2 [# c" s. I
/**
: w2 o* C. W* {* A * platform_device_register - add a platform-level device  V) {/ X& w/ T4 U* a% s. f
* @pdev: platform device we're adding
( M1 Y+ t3 N& Z4 K' Y, c */
2 ^8 Q3 F8 t9 @5 yint platform_device_register(struct platform_device *pdev). ]6 c' u; Z/ l" h" W  H! [- M$ g+ _: z
{
0 r# S0 L5 o; H7 _        device_initialize(&pdev->dev);
& a! [& }3 E; n/ Q4 \        return platform_device_add(pdev);& N+ A$ n3 z/ H' e) ?' I) I( P
}
* Q% U- f: a1 i8 G$ P4 AEXPORT_SYMBOL_GPL(platform_device_register);
7 F  ~& ^  o+ J2 l% s+ y
' ?" w8 ]- ]/ U+ t) |( W5 ]调用了两个函数,第一个函数在6.1节已经分析过。我们来看下第二个函数。
4 W0 p# M3 ^, d/ o7 T8 i/ e9 J- t6.3.2  platform_device_register
: d5 ~( ?4 t1 T: h3 v/**$ A3 M" g5 ~* u; d) L. B; g
* platform_device_add - add a platform device to device hierarchy  G. [: x* h" g. B& W( }
* @pdev: platform device we're adding: J; ]: \8 }" k
*
" [/ _- y7 |+ ^9 N * This is part 2 of platform_device_register(), though may be called% U7 f, i* s! V2 n
* separately _iff_ pdev was allocated by platform_device_alloc().- }' S) m1 f9 v+ r
*/
3 L$ S8 x5 G: eint platform_device_add(struct platform_device *pdev)
1 ?! I1 d" i5 R" ~1 ~* R  q- H{+ K7 `- h5 I0 A" d# W
        int i, ret = 0;
- r: `4 Z7 {4 L9 Y- A) v# C$ v: W% ]; w' n4 l7 m1 A
        if (!pdev). x2 z' A3 T- q; A  F8 ]
                return -EINVAL;
8 M. F2 o* ^& ?( B
4 e8 G$ B$ z7 e  W& N        if (!pdev->dev.parent)9 j: @9 k" X1 ~" Z
                pdev->dev.parent = &platform_bus;        /*该设备的父设备是platform设备,/sys/devices/platform*/+ t: K/ K  B6 C' z$ p8 m
" y% j7 O8 w; R! B
        pdev->dev.bus = &platform_bus_type;                /*设备挂载到platform总线上*/
: {( z! F0 Y1 K* P2 X
* N1 H% l0 C+ Z# T0 }        if (pdev->id != -1)) e. H+ j  E0 M7 P  \/ p
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);( H/ K  z5 A( R0 r' a
        else
: G  e  e1 X. l4 S                dev_set_name(&pdev->dev, pdev->name);/*pdev->dev->kobj->name = pdev->name*/
0 E/ S7 X  x3 R1 m+ z- D, E4 t  z% A+ M. K9 Z' E, D
        /*遍历平台设备的资源,并将资源添加到资源树中*/
2 |, ~( l6 Y7 G# N        for (i = 0; i < pdev->num_resources; i++) {
: W* g# Y* ]8 k' f& ~                struct resource *p, *r = &pdev->resource;' V8 X. H1 ]  \; d: X# l

! Y1 d# \% M& ~9 H8 O( ~                if (r->name == NULL)
# Q: \* T7 k! P8 f+ H                        r->name = dev_name(&pdev->dev);        /*获取dev->kobject->name*/
" W, n% j, f0 j! C( E8 A
; }+ o# M" ?, A  {0 l; w                p = r->parent;
, m4 {% ~; E2 ^                if (!p) {        /*p空*/: j* w# G( ]# j$ I) }" D; Q
                        if (resource_type(r) == IORESOURCE_MEM)9 Y; L+ w( d* v: p6 S  \4 f
                                p = &iomem_resource;* w8 q) X* b7 ^$ W' [+ d
                        else if (resource_type(r) == IORESOURCE_IO)$ [- v- [; _% H- v6 ]
                                p = &ioport_resource;
- D: t8 M( n! o) J9 Y; H1 ]: E                }6 Y1 e: s: a0 F" k7 L( P7 C
9 M0 ^- f) n7 b/ @1 a; U
                if (p && insert_resource(p, r)) {        /*将资源添加到资源树中*/) b  J& D* w% m, |! E
                        printk(KERN_ERR; @5 W4 d7 S+ ?2 p0 W
                               "%s: failed to claim resource %d\n",
% a0 p3 W3 N% C8 X                               dev_name(&pdev->dev), i);/ I# B/ U& a) b! {9 b: x& b
                        ret = -EBUSY;! T& v+ `: o* s3 @7 k* A
                        goto failed;. G: A+ N) V* }9 W, a! G
                }
' l6 }& ?4 Q, `- [        }3 m( u' o. ~7 ]. W
$ V4 _  X& V3 n: `* C
        pr_debug("Registering platform device '%s'. Parent at %s\n",
, Q$ g4 t* c( t) w( i                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));4 g4 n$ a# s2 ?& @9 T- T* U
1 {7 p8 D4 h. `8 J9 j
        ret = device_add(&pdev->dev);        /*添加设备*/
# N$ g5 Z9 K1 W- J        if (ret == 0)* R; I% C7 h- e' [, a: y" z
                return ret;$ l& E6 `& T/ k5 F

3 G9 S% K2 e" F failed:" i! ]0 K+ }# Y$ V; R' m
        while (--i >= 0) {
* K2 v' c- U6 \; q$ A; g. b7 A! X9 Q                struct resource *r = &pdev->resource;
8 E/ W6 W8 S. Z                unsigned long type = resource_type(r);
' j6 |7 s$ }" {+ P  v
, a- S' a" n# D1 z" n- t# V                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
; a# d/ C8 d/ `3 Z                        release_resource(r);
9 p- G5 d/ Y! {% M* q+ g        }
2 W- i9 j& s) F  i! \; @% e9 I; D7 L
        return ret;
# n2 ]0 R, [1 U" X5 J9 |9 O" q}
. ?7 o$ X+ R3 V8 Z$ g+ IEXPORT_SYMBOL_GPL(platform_device_add);+ G. H# }3 G# t$ m0 ]
3 I1 {9 Z( `. Q4 w/ O
在这个函数的最后赫然出现了device_add函数。我们回忆下在6.1节中device_register的注册过程,该函数只调用了两个函数,一个是device_initialize函数,另一个就是device_add。
1 [) Z/ g% }6 \. c, h* r' v本节的platform_device_register函数,首先也是调用了device_initialize,但是随后他做了一些其他的工作,最后调用了device_add。
1 R% V- h. {- `0 q( K+ L. u& h! a3 M! I% r
那么这个"其他的工作"干了些什么呢?
& ^" T1 d3 h9 E# b$ @2 G: c. d
8 e* G# @0 N5 R% Z首先,它将该SPI主控制对应的平台设备的父设备设为虚拟的platform设备(platform_bus),然后将该平台设备挂在至platform总线(platform_bus_type)上,这两步尤为重要,后面我们将看到。
8 ^' E' g! Q' k7 z1 C/ Q然后,调用了dev_set_name设置了pdev->dev-kobj.name,也就是该设备对象的名字,这里的名字为s3c2410-spi.0,这个名字将被用来建立一个目录。
. Y3 ?7 x0 ?' h5 P: w8 w2 z, D
' M1 u+ P; K9 R, [0 ]- @! {% F8 v4 U' s: J最后,将平台的相关资源添加到资源树中。这不是本篇文章讨论的重点所在,所以不做过多说明。
8 v) N( e8 w  }5 U5 b  I* E8 m: [6 k9 n  N
在"其他的工作""干完之后,调用了device_add函数。那么后面的函数调用过程将和6.2小结的一致。
1 o' G% W, H6 n0 R! F/ S: t) s6 K% l( |- l- U3 ~, Y: Y
由于“其他的工作”的原因,实际执行的过程和结果将有所区别。我们来分析下。- F+ ]( H, [) ^- j3 h

( Q5 ?3 p: ?. @2 y/ f6.3.3 不一样device_add调用结果4 x8 E1 M' ?9 K7 w( g7 w
首先,在device_add被调用之前,有若干个非常重要的条件已经被设置了。如下:
) s6 Q# p. \5 K2 z, W: F$ [5 I/ ]7 ]% p8 Q
pdev->dev->kobj.kset = devices_kset9 M6 D* m# ^' {3 E
5 w9 ?( R8 Q2 V/ Q
pdev->dev-.parent = &platform_bus
9 [' S5 [3 N, M4 O! n$ b
) I3 n: }& V' [' B( v- o* g8 @pdev->dev.bus = &platform_bus_type
' N. e2 A' r9 y% w1 L; V' M( O, I% g% r
set_up函数执行时,由于参数parent为&platform_bus,因此最后将设置pdev->dev->kobj.parent = platform_bus.kobj。平台设备对象的父对象为虚拟的platform设备。
- [; p8 x6 m4 y- s+ }
: g2 g; I; X+ @7 Q# T( S- Fkobject_add函数执行时,由于参数parent的存在,将在parent对象所对应的目录下创建另一个目录。parent对象代表目录/sys/devices/下的platform,因此将在/sys/devices/platform下建立目录s3c2410-spi.0。
, O& Z( M: X+ q5 ?  H' \
/ r4 A* B/ n+ m$ i9 u8 ^device_create_file建立属性文件uevent。
! K) ?0 Q: \# C2 L& U% L! }$ K8 Qbus_add_device函数执行时,由于dev.bus 为&platform_bus_type,因此将建立三个symlink。
) W# {7 L- w# U
. N" M6 @% }2 N5 s% Q" E+ t            /sys/devices/platform/s3c2410-spi.0下建立链接subsystem和bus,他们指向/sys/bus/platform。3 o  C( d, J$ K- F. l$ l
" g5 o, Q. T; l- g1 }- N( r' y
           /sys/bus/platform/devices/下建立链接s3c2410-spi.0,指向/sys/devices/platform/s3c2410-spi.0。0 d" y! O# X( w) `) o, M$ O3 i

9 r* g& I6 |" H5 j% w' M9 J7 Mdpm_sysfs_add函数在/sys/devices/platform/s3c2410-spi.0下建立子目录power,并在该子目录下建立属性文件wakeup。+ f' W) |) H6 [& C) z

1 v1 f) W7 r" C3 S, ?0 T( q执行到这里时,sysfs已将内核中新添加的SPI主控制器平台设备呈现出来了,我们来验证下。
$ e8 M7 q! @3 e0 ?' p
* @0 U  H# f- s8 a" M# l) W; B[root@yj423 s3c2410-spi.0]#pwd) F: w5 x: K) R. ]3 g0 [
/sys/devices/platform/s3c2410-spi.0
% ?: k' q6 `  G% u6 R# n+ {[root@yj423 s3c2410-spi.0]#ll
7 k/ d0 @% T% C& \( \3 zlrwxrwxrwx    1 root     root             0 Jan  1 00:29 bus -> ../../../bus/platform% c- z; `8 M5 H# `% {
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 driver -> ../../../bus/platform/drivers/s3c2410-spi
% |2 s+ Q2 m  Q9 C# C-r--r--r--    1 root     root          4096 Jan  1 00:29 modalias4 r$ Q$ w; j" _2 a0 P
drwxr-xr-x    2 root     root             0 Jan  1 00:29 power
. I0 T  I6 v( s/ m' mdrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.0
; @( M& d3 Q3 r. L9 ~6 u8 udrwxr-xr-x    3 root     root             0 Jan  1 00:00 spi0.1
; e, W# _+ N5 r9 t( I# rlrwxrwxrwx    1 root     root             0 Jan  1 00:29 spi_master:spi0 -> ../../../class/spi_master/spi06 ?4 a: ^: p$ c( \1 f& `
lrwxrwxrwx    1 root     root             0 Jan  1 00:29 subsystem -> ../../../bus/platform
$ S# K' y9 C$ e8 c8 {) @. E- f-rw-r--r--    1 root     root          4096 Jan  1 00:29 uevent
6 {4 V8 p9 y$ u0 M# @# o; k) A. H: S3 t
[root@yj423 devices]#pwd
8 z- @1 s/ \: q7 W; K/sys/bus/platform/devices
$ i/ g, _- n! B. m3 r! k, Y/ C[root@yj423 devices]#ll s3c2410-spi.0 0 H: F- m6 O, C- }
lrwxrwxrwx    1 root     root             0 Jan  1 00:44 s3c2410-spi.0 -> ../../../devices/platform/s3c2410-spi.09 a6 [# z1 B, `  v  l+ K# V1 x
通过sysfs将设备驱动的模型层次呈现在用户空间以后,将更新内核的设备模型之间的关系,这是通过修改链表的指向来完成的。
3 C/ a% O1 S) y8 Z! S. {2 q
8 G1 _% ?7 O: }- {bus_attach_device函数执行时,将设备添加到总线的设备链表中,同时也会尝试绑定驱动,不过会失败。5 J. ]9 e# q# _
8 w+ K" v7 A2 {5 \: a7 o/ o  X$ ]
接着,由于dev->parent的存在,将SPI主控制器设备添加到父设备platform虚拟设备的儿子链表中。. R9 Q! c6 `% y3 q9 F
& ~4 h4 {2 W' |. _$ k" H
7. driver举例
5 n% d* v2 l& T6 K1 u我们已经介绍过platform总线的注册,也讲述了SPI主控制器设备作为平台设备的注册过程,在本节,将描述SPI主控制器的platform驱动是如何注册的。
8 V' e$ y! p+ C) a% X
/ R; M0 I7 i. _4 x% c7.1 s3c24xx_spi_init
& Q& Q- E- F( [下列代码位于drivers/spi/spi_s3c24xx.c。
. ]% T; F# h2 C* q% nMODULE_ALIAS("platform:s3c2410-spi");
8 E7 ^% x4 d) l. ]: |1 C  H# V) G1 jstatic struct platform_driver s3c24xx_spi_driver = {
, ?% B5 K+ |9 l    .remove        = __exit_p(s3c24xx_spi_remove),
) y; u  I2 F( d    .suspend    = s3c24xx_spi_suspend,
: M; b1 _0 C: [1 G& V    .resume        = s3c24xx_spi_resume,
  _# C& Y( I3 x4 G5 {5 Y: R' x7 W    .driver        = {# C1 i+ A0 k9 U2 a) `9 f
        .name    = "s3c2410-spi",
( j# Y0 e1 Q1 U' P% @        .owner    = THIS_MODULE,
7 {  }( ~9 Y# D( a    },
9 Q  C: z' b- \& O3 Q};- j. |, m8 o/ Q2 u( T8 V
6 q. p' D9 A. v8 ^8 i
static int __init s3c24xx_spi_init(void)
: o1 o3 W+ x* P5 Y{, R9 @& y3 `. S+ K; c. U; O
        return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);//设备不可热插拔,所以使用该函数,而不是platform_driver_register
1 m0 A4 r$ ?3 _}; J1 c5 m. L" L2 E: U
驱动注册通过调用platform_driver_probe来完成。- L* p: v' L" z" k9 d! w" L
注意:driver.name字段使用来匹配设备的,该字段必须和6.3节一开始给出的pdev.name字段相同。
! Q! U. S! m$ J$ k- v7.2  platform_driver_probe
, m) p( b. r. j( B  E4 I. ?8 a+ @2 [下列代码位于drivers/base/platform.c。
" d, `$ L, m/ I! y1 }8 Z/**
1 J8 m6 s4 m7 q' H * platform_driver_probe - register driver for non-hotpluggable device+ T' r- V* R; u( i! L' P
* @drv: platform driver structure5 M! }. w  S4 H& r( j0 W
* @probe: the driver probe routine, probably from an __init section
( W% v6 a, I2 G: y' [ *6 c9 n9 t6 R5 Q7 w+ D7 P: M1 N
* Use this instead of platform_driver_register() when you know the device4 X3 r" B! O. s* s+ w
* is not hotpluggable and has already been registered, and you want to
& B7 c5 f7 b7 { * remove its run-once probe() infrastructure from memory after the driver) R# z; F, M9 r+ `7 D
* has bound to the device.
5 b8 D4 Y3 r& J# V *
: }& I3 _+ u9 I; c * One typical use for this would be with drivers for controllers integrated1 g. X+ F" J% E3 p3 M) n( k
* into system-on-chip processors, where the controller devices have been" y# T9 W$ E. H: R: B% x
* configured as part of board setup.+ g& W0 C* j, Y3 D4 v' ]4 v
*8 v  D" Z0 {9 {1 W+ e3 l7 N9 z% B
* Returns zero if the driver registered and bound to a device, else returns5 [9 K' K. @0 @- W# U
* a negative error code and with the driver not registered.
7 S# W" D& v0 f# }; ?) M# v */
* i& @/ `: j4 }% `6 u0 r1 Y" [, B5 Tint __init_or_module platform_driver_probe(struct platform_driver *drv,
2 a& J* T* S' ~  E; f                int (*probe)(struct platform_device *))0 A0 h" n4 j) ^: g
{0 j$ o0 o* r! O: {7 M7 R
        int retval, code;& w. M: M. B' `" T$ Z' q
7 ^3 I- a7 m" i( u, B( V9 C
        /* temporary section violation during probe() */6 R, _1 `: e( H' I4 r
        drv->probe = probe;
+ w: ~5 b9 U  f& ]* R# ?6 I        retval = code = platform_driver_register(drv); /*注册platform驱动*/+ g! s+ B4 V* {4 k

2 o  ~+ T0 a6 f: T% i" `        /* Fixup that section violation, being paranoid about code scanning
" _& c. F# g- e9 v         * the list of drivers in order to probe new devices.  Check to see9 D0 H9 p' U* G$ F+ s
         * if the probe was successful, and make sure any forced probes of
, g; }' G5 i: i3 O7 T2 I, `         * new devices fail., e9 S/ E6 b% F: V2 |6 ^" y
         */# a( r* i( h0 J2 i1 s: T1 V7 S
        spin_lock(&platform_bus_type.p->klist_drivers.k_lock);' w6 |- S. q1 M  }/ G- @
        drv->probe = NULL;
8 l7 f1 v9 ], i6 J3 F1 }' c/ Y        if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))5 @* b# m( m+ Z+ C
                retval = -ENODEV;2 d/ C+ j# o! }
        drv->driver.probe = platform_drv_probe_fail;$ M! |! P& H% n, Q" @
        spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);
- K8 j! m6 R) m( U  r/ d: S! d7 h; P2 d" x+ S* o
        if (code != retval)1 _& m% P/ q; p
                platform_driver_unregister(drv);$ a' u  O3 R* t+ H' Q3 n) c; g
        return retval;8 @' u1 T1 v) }2 E! V) W4 h. q! y
}
% R9 L+ N/ r" a6 `EXPORT_SYMBOL_GPL(platform_driver_probe);
' {2 S: n! q* q" b4 F* c. a这里的重点是platform_driver_register,由它来完成了platform驱动的注册。
, r4 O+ }: F8 ]$ _7.3 platform_driver_register
2 Z1 e7 P0 p9 }* o5 ]6 i; x/**
6 a  o- E: x8 c5 b * platform_driver_register
% r: r7 a* i: e5 n * @drv: platform driver structure# b4 S2 A/ m+ ?5 \6 `  A# {) `
*/; r7 v% M! e/ k0 V9 e2 m& |8 J
int platform_driver_register(struct platform_driver *drv)4 q! U3 U) z) T
{
/ V$ G  I" t; S7 d6 f        drv->driver.bus = &platform_bus_type;
* ]. P, P5 z+ a' W  O0 \0 Q- Q        if (drv->probe)
6 [4 t+ I3 T$ d! m1 W                drv->driver.probe = platform_drv_probe;
6 p! @; |3 z) q5 @  d/ L- \9 J( h, I        if (drv->remove)$ H, r" _: w2 y/ L$ C& C* q9 O
                drv->driver.remove = platform_drv_remove;' M/ a$ F8 y% x7 ]$ r$ I7 s% @* a
        if (drv->shutdown)
. q" F8 a2 j: a5 ~7 k' d" T& ]                drv->driver.shutdown = platform_drv_shutdown;4 \/ k3 }; ~1 b# X8 L
        if (drv->suspend)+ Z, v. H' u5 h9 q
                drv->driver.suspend = platform_drv_suspend;; ~& v: _, T% [  q; T$ w
        if (drv->resume)+ ]" b! ~& b# q9 k% O) }& k  M% T
                drv->driver.resume = platform_drv_resume;) W' A2 a; y1 z9 _( z" ~' h9 Z
        return driver_register(&drv->driver); /*驱动注册*/+ F" H5 j% s; ?+ L" `+ U& ~7 D
}* O) o! K; a3 c* q
EXPORT_SYMBOL_GPL(platform_driver_register);
3 F2 s1 Q: _: S8 E2 x( h; p8 E8 T& }
driver_register函数就是driver注册的核心函数。需要注意的是,在调用函数之前,将该驱动所挂载的总线设置为platform总线(platform_bus_type)。
8 O1 h: J  O& N; P" r7.4 driver_register
* `% o9 q( j# v6 V9 u! Q8 i下列代码位于drivers/base/driver.c。
/ v3 x: u3 i7 b# M' o/**& Y- A- Q3 Q! k
* driver_register - register driver with bus
" s  |$ F% c) i! w) t, A' p * @drv: driver to register
" `! \' t' g4 Q* n, g  K  f0 i *0 O4 k% z, O* n; c2 `) z1 y
* We pass off most of the work to the bus_add_driver() call,6 ^; f! \+ g8 \9 \# B
* since most of the things we have to do deal with the bus
* b' R- r; O( u) v* o * structures.9 \  t' m, e# J  c* S4 X9 M+ d
*/4 J  g1 U# f0 Z# U$ N
int driver_register(struct device_driver *drv)) q) Y, s4 Q) p1 S
{+ T+ G" m7 `  r0 L0 J3 y9 K! m
        int ret;
% f7 @5 O( A% E7 ]' ^: C. _        struct device_driver *other;
& V1 T- m5 g* C- h; \3 B7 u2 I2 @
" L8 N1 Z: t) I/ z        BUG_ON(!drv->bus->p);
; B7 @6 o% i/ p+ k5 B% ~
0 ?0 S8 m: I8 B& v6 Z% \) C* h        if ((drv->bus->probe && drv->probe) ||& _: q. _: H9 _$ W/ c" b
            (drv->bus->remove && drv->remove) ||" v% o$ _/ |- d9 _4 c
            (drv->bus->shutdown && drv->shutdown))
$ G, x- F6 `# L3 ^                printk(KERN_WARNING "Driver '%s' needs updating - please use "
9 N# g- p* |4 H8 j6 {& D                        "bus_type methods\n", drv->name);/ p  D- e" }% O6 M/ y
1 b2 s: l' i: W$ }- G( j+ ]( b( e& Q
        other = driver_find(drv->name, drv->bus);/*用驱动名字来搜索在该总线上驱动是否已经存在*/
0 z3 u& H& V7 j+ V+ s        if (other) {        /*存在则报错*/
/ m* f, P* M, s8 j+ l                put_driver(other);
" r0 ?' n$ b/ @; O2 v6 A/ e                printk(KERN_ERR "Error: Driver '%s' is already registered, "" a+ q; U- F) I3 x0 \
                        "aborting...\n", drv->name);
+ E9 l' h5 v: f1 N7 q6 A                return -EEXIST;
6 ^4 t8 ?4 r2 q8 C* l* H* Z        }
3 J) K' h# [1 M, _* p4 _+ D% Y3 E# x8 P, Q
        ret = bus_add_driver(drv);        /*将驱动添加到一个总线中*/
- J  G& U; ~/ P! T/ O        if (ret)
) v6 ~  c% Z! A7 v2 S                return ret;' V& c/ ~4 p! g* z6 g' F. m
        ret = driver_add_groups(drv, drv->groups); /*建立属性组文件*/! I6 `4 G: f& Y0 O0 u( y$ a6 T
        if (ret)& H# \, K5 i+ {# f1 \( a
                bus_remove_driver(drv);" x0 _0 l1 F0 i) L/ k2 p
        return ret;
& x! W. |2 }3 l7 i$ q: m}
2 o% j" m/ M$ _# q0 \' J2 gEXPORT_SYMBOL_GPL(driver_register);
8 u, f* t" ~+ I4 `: V这里主要调用两个函数driver_find和bus_add_driver。前者将通过总线来搜索该驱动是否存在,后者将添加驱动到总线中。7 `, {9 I# d, i7 |% F7 U
接下来就分析这两个函数。
: s3 _8 H2 V- D% M) {8 v. u7.5 driver_find
8 q/ H) G0 C" G8 u. L( a; S( [% I下列代码位于drivers/base/driver.c。2 a- ?% h* Z$ c
/**
( x/ m  k+ \1 m/ j * driver_find - locate driver on a bus by its name.
% d* O  ]0 m+ q& c# J' f; } * @name: name of the driver.- @$ j6 Z, h8 d7 b+ j
* @bus: bus to scan for the driver.
# P- N" B1 X, Q, T *4 a4 Y5 V& u  l9 f: L  \! A
* Call kset_find_obj() to iterate over list of drivers on, f# z3 R0 g( E
* a bus to find driver by name. Return driver if found.8 w6 r- K/ w4 _: C" X
*7 L9 b$ I7 S0 G, D$ g0 m
* Note that kset_find_obj increments driver's reference count.6 ^% y2 I# m$ d  Z" L& S
*/# j( i" C4 N+ O& u5 d7 I: I
struct device_driver *driver_find(const char *name, struct bus_type *bus)
7 Y5 _) S/ Y9 B  J3 d- k; v{$ a+ j8 z, P- J
        struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);
3 X, t9 `# d9 p' E" U! w: I4 Y5 X/ m        struct driver_private *priv;
& S- L9 k6 r0 L7 ?
* z1 \8 e7 ?3 }        if (k) {
6 O$ _7 `  l3 Y0 ^- N  q                priv = to_driver(k);
9 K% b5 |+ E7 z/ d1 _% X                return priv->driver;0 l" d$ Q0 A( o9 ]& w  K! _
        }9 x0 `/ g! K1 c1 b
        return NULL;
5 S9 X+ g8 I7 }+ u5 o}
6 @" T5 c/ ~" n7 JEXPORT_SYMBOL_GPL(driver_find);
  [; D- a% j' l# r% C) @$ C
- A* n. P/ g* j/**6 m) C( D  R3 W5 Z& j+ u& y
* kset_find_obj - search for object in kset.* g" p: Y' O# B4 {. J2 b4 T
* @kset: kset we're looking in., g- `* k+ y% a7 ^  T; p
* @name: object's name.
; f5 R7 Y1 T: [+ C2 Q8 Y0 q2 z- } *0 x0 i2 M* s% ]6 `9 q  B) J" w  e
* Lock kset via @kset->subsys, and iterate over @kset->list,3 P" g1 m# }; b9 F# z4 n% ]) S
* looking for a matching kobject. If matching object is found% q6 i, ^; l2 |
* take a reference and return the object.; b0 N( D$ F* {( Y. K7 X
*/9 t: O% U- l& C" |9 b
struct kobject *kset_find_obj(struct kset *kset, const char *name)2 Q" `6 L( P, [1 B4 f8 s; n
{; ?+ y5 _% y: o% q+ z) K0 F
        struct kobject *k;3 ]1 B( e% b/ _( Y& F
        struct kobject *ret = NULL;7 e* p$ R; ~2 m' k) o& ^2 X+ w

! Y$ e. E6 }* O/ b6 \' R! z3 v7 p        spin_lock(&kset->list_lock);
$ |) `+ r/ D" }. ?' l- [' C" W! v! S        list_for_each_entry(k, &kset->list, entry) {3 v; M9 ~1 G" K+ D, V* e
                if (kobject_name(k) && !strcmp(kobject_name(k), name)) {- C# G5 Q; y+ L, Z8 X+ K+ x
                        ret = kobject_get(k);
0 \* Y; R) ], b+ F. w/ R' g  v0 c; I5 d* w                        break;
- t1 ]' z- a: g                }
0 e7 @2 d' i2 ?1 R1 B- P5 r; r        }
! S& p+ _7 S3 x- h        spin_unlock(&kset->list_lock);
9 y' T, {# o8 ~( k        return ret;
' d5 W+ n( p2 U5 m}4 K+ j" m- F: j7 {3 X9 w% G6 u) I
这里调用了kset_find_obj函数,传入的实参bus->p->drivers_kset,它对应的就是/sys/bus/platform/下的drivers目录,然后通过链表,它将搜索该目录下的所有文件,来寻找是否有名为s3c2410-spi的文件。还记得吗? kobject就是一个文件对象。如果没有找到将返回NULL,接着将调用bus_add_driver把驱动注册进内核。: a5 _9 V& m/ }; g
7.6 bus_add_driver
) p9 `- _9 v+ }0 H! @* c下列代码位于drivers/base/bus.c/ m6 o: e0 M% w6 @& U
/ `5 Z$ g) \0 i: c4 z
/**3 i2 d! W& f3 n2 h& }: m" ]
* bus_add_driver - Add a driver to the bus.8 g7 @3 Y" }7 l0 h0 F% o1 `! k" e) Q
* @drv: driver.
" y( _/ x) f4 [  v+ N */+ ]4 ]9 N3 t, S% ^0 r& V
int bus_add_driver(struct device_driver *drv)/ j# F3 F* K/ l2 G% [7 N
{7 H# A, Z# a7 e" V' [5 J6 Q6 ?( a( M
        struct bus_type *bus;! u8 O, k+ J: a+ K' A& D
        struct driver_private *priv;
. L% i6 x+ z. }- {) y% t        int error = 0;/ ]3 g* M7 ^8 i" V
7 j3 @4 E( x% a$ T1 U2 l5 _
        bus = bus_get(drv->bus);        /*增加引用计数获取bus_type*/
0 A# @) w9 U5 R: y        if (!bus)* f# X4 j& ], c# D* I& _. [  Z0 \
                return -EINVAL;
2 q3 J: _, P- w8 y4 }
+ ?8 `+ ~1 J: {, L2 d+ h4 u        pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
3 K8 p! u: z, o) I6 I; |7 h, i2 V4 e
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);        /*分配driver_private结构体*/
3 U) D+ J2 e/ J$ H: t        if (!priv) {- M4 L/ j* g3 N/ {+ ]! p
                error = -ENOMEM;
3 a9 ~$ X. V8 l* Z                goto out_put_bus;: k& f) ^6 X8 Q2 d1 H& ?3 A. ?
        }/ D) h) p1 z, v/ T7 N
        /*初始化内核链表*/
& R0 S9 s/ I, S8 c        klist_init(&priv->klist_devices, NULL, NULL);7 }% R! r5 |9 f2 x
        /*相互保存*/
  y4 o, S0 s% U        priv->driver = drv;, R5 ]! B/ I& v- p: N* q5 Z
        drv->p = priv;
$ i+ K* z( J, T! h/ V9 C; e" E        /*设置该kobj属于那个kset*/4 Q/ m5 T: x+ O& g( L7 k# T
        priv->kobj.kset = bus->p->drivers_kset;
1 B! m. H$ a2 T, [% A( D        error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,        /*parent=NULL*/. Y$ J0 i, t( V/ k( o9 F* o
                                     "%s", drv->name);        /*执行完以后,会在bus/总线名/drivers/下建立名为drv->name的目录*/: q# I8 t% d- v& V* O0 R4 n9 P
        if (error)
" M8 {' r1 q1 F, f                goto out_unregister;
7 }. w6 G! z" f* R5 X
6 e7 R( k( H3 g& y5 |        if (drv->bus->p->drivers_autoprobe) {
  m* w) h3 T5 q# O' Z: u! E                error = driver_attach(drv);        /*尝试绑定驱动和设备*/
7 j* B) S' ?' V                if (error)
0 |; E) K0 Z6 }5 r: p, ?                        goto out_unregister;
# C3 r4 i' f' {1 O  h        }& a3 t' B. Q1 N: s( L; t0 k$ k  ^" k
        /*添加该驱动到bus的内核链表中*/( [, V- j7 ^6 a: f
        klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
" l  _. i# Y' ?0 {8 ?) j! R        module_add_driver(drv->owner, drv);/*?????????*/+ V; f3 o" ?% B; J% \4 @

) K7 [7 [# D: R2 V9 [        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件uevent*/; V2 Y4 W  d/ R$ C0 Z; Z
        error = driver_create_file(drv, &driver_attr_uevent);5 r" k9 R! X) T
        if (error) {
4 ?+ s( |) V, J                printk(KERN_ERR "%s: uevent attr (%s) failed\n",
/ H2 }/ D. h; v8 I+ B$ U                        __func__, drv->name);
9 i. O5 N6 q% D# m! m- H( f        }
; \4 ]4 V" h4 C        /*利用bus->drv_attrs创建属性,位于bus/总线名/drivers/驱动名/*/% A# Z, T2 C3 G& `% M, O
        error = driver_add_attrs(bus, drv);
; L1 @! z( Z$ F8 H2 O7 D, [( Z        if (error) {& u+ T- w) v1 _! l  P1 u% M
                /* How the hell do we get out of this pickle? Give up */) E, C+ C6 a+ g  y; M  U, K! ^7 U
                printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
1 ]; g3 V8 I% Q                        __func__, drv->name);3 E/ m& ^( c" E. O$ a; A; w9 v' e
        }
) t6 F1 x4 A! F% T0 _        /*创建属性,在bus/总线名/drivers/驱动名/下建立文件bind和unbind*/# [, h7 o, m; j0 @
        error = add_bind_files(drv);
2 k* m4 S* ^& |* }. I" D        if (error) {! M. \/ Z# j- P- U: `) C* y' U
                /* Ditto */& E2 v1 r; i% Y  \8 L5 D2 ]3 N
                printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
- h) \* q8 h6 P+ u0 ^8 w                        __func__, drv->name);
8 v1 d2 a+ F% P: ~( {: [+ I4 T$ y        }
  {4 U, d4 P" p        /*通知用户空间???*/, B$ p$ m) ?/ L
        kobject_uevent(&priv->kobj, KOBJ_ADD);0 \% R3 A# q& z  J* v
        return 0;# e$ j' Z. A; p- L1 s+ p' ~
out_unregister:# g0 E& r4 c7 o; L4 a+ x
        kfree(drv->p);* b0 J2 o8 D; e1 Q8 o
        drv->p = NULL;
! U: V6 }$ P9 x1 N  Y* B/ @: X4 U        kobject_put(&priv->kobj);
& L2 H2 x& p) ^8 Z5 l; v$ Z* X2 q0 ^. x( tout_put_bus:4 W+ v5 H: g) M) s6 i+ I
        bus_put(bus);: I7 ~0 K% d+ e  `
        return error;! K: t  w$ L$ I5 o  s1 ]& g
}& [8 {! e6 R. Q
在设置driver的kobj.kset为drivers目录所对应的kset之后,调用了kobject_init_and_add,我们来看下。2 I) |+ W  H( q6 }: P: H1 e5 v; L2 }
7.6.1 kobject_init_and_add
4 r1 p; H* B* H. t( Z$ t$ y下列代码位于lib/kobject.c。; G  @) z( U( R+ A; D+ T
/**2 H& \$ d) `: L4 F. W
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
) N! i* ]$ _. ^. v6 m3 K * @kobj: pointer to the kobject to initialize5 z) R# q. }- p& U3 i7 j
* @ktype: pointer to the ktype for this kobject.
0 v. m% U8 y5 R' |1 [& ^ * @parent: pointer to the parent of this kobject.
4 d+ r5 }! j4 e6 `- h; f * @fmt: the name of the kobject., W# Q4 ^) ]; p
** T- m' `9 m! n+ d6 u4 x
* This function combines the call to kobject_init() and$ W( f1 |& h# X+ ~9 q8 A; s0 n4 W
* kobject_add().  The same type of error handling after a call to
6 V) S( D3 ~0 l, L9 P# t * kobject_add() and kobject lifetime rules are the same here.
/ m6 ]" j3 X! m8 v2 i */
! K. F* x8 v3 t5 D1 r. H7 a5 {4 iint kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,9 t4 l1 ^3 N5 ]" I8 s: G
                         struct kobject *parent, const char *fmt, ...)2 @. A$ M/ H4 E2 v
{7 \% w* J6 q. g0 P$ X% Z
        va_list args;: \' J8 S1 Z" z
        int retval;
* @1 j* S. \" l7 i5 D: p8 M& R
' L6 _( |1 s+ W        kobject_init(kobj, ktype);' {. k! M: r6 H) q1 w) f
9 A4 @' E- X+ K  W/ u& `$ O
        va_start(args, fmt);
3 K/ G7 S0 N1 N5 j0 J/ \        retval = kobject_add_varg(kobj, parent, fmt, args);3 K3 t  J& |: D: R' p
        va_end(args);
' M3 L# H2 |' ]- y: z" E5 @+ Q* }; G7 |7 D# P6 X. E7 c
        return retval;2 X  r; K$ k6 y2 _
}" O. C: F5 {' R. @: L8 |' d+ R. S
EXPORT_SYMBOL_GPL(kobject_init_and_add);+ L$ O) w* Q7 M1 K/ ^9 p
该函数中调用了两个函数,这两个函数分别在6.1.2和6.2.2中讲述过,这里不再赘述。
" i# C; x  Y! U6 p调用该函数时由于parent为NULL,但kobj.kset为drivers目录,所以将在/sys/bus/platform/drivers/下建立目录,名为s3c2410-spi。7 b# b0 \5 `8 Q0 U
& [2 h7 `) a; Y6 k
我们来验证下:5 |8 _$ k0 c* T
' D* T( q8 m7 r* i
[root@yj423 s3c2410-spi]#pwd
/ q6 G. \2 v* p/sys/bus/platform/drivers/s3c2410-spi
" K) O9 W' A4 q. _3 {接着由于drivers_autoprobe在bus_register执行的时候已经置1,将调用driver_attach。% H  O% f* u6 u8 U0 N7 K  Z

1 ^2 A# h; s7 x  \% f* a7.6.2 driver_attach& |* g1 l7 Q1 k/ }8 v
下列代码位于drivers/base/dd.c。
, E; O- C6 }4 _% A9 s/**
: x3 [. I3 L4 ?% m. M* Q * driver_attach - try to bind driver to devices.: z( l! c, y4 N. i3 K8 k
* @drv: driver.
+ J' |. e- m6 @1 [( [& f7 u$ | *
. J( O! r' k1 s * Walk the list of devices that the bus has on it and try to8 ^5 N7 F2 u$ a% U
* match the driver with each one.  If driver_probe_device()) R( l& o9 P3 G) ]
* returns 0 and the @dev->driver is set, we've found a
; o) {2 r7 h6 ] * compatible pair.
# |; J7 a1 Z1 w6 |$ Q9 D */
" C, ]" a3 ?- u% Z+ r, m$ Tint driver_attach(struct device_driver *drv), S) Z* R2 c2 ]' y# X, b
{8 I1 [/ ?, r% L+ _( F5 O) a# o. U
        return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);# [' ?1 e% g4 `8 A8 C0 ~
}1 Y" ^* a+ I# D. |/ w3 ]
EXPORT_SYMBOL_GPL(driver_attach);
# s) g+ u* T# h" Q" P/ k该函数将调用bus_for_each_dev来寻找总线上的每个设备,这里的总线即为platform总线,然后尝试绑定设备。
: n% a3 Z4 y: F) m: d# k5 j这里需要注意的是最后一个参数__driver_attach,这是一个函数名,后面将会调用它。: v/ c/ U$ E: J  ?- }
3 f  m3 H% J6 d
/**5 v( S( R* \4 a& N! x3 P
* bus_for_each_dev - device iterator.
7 @! M9 K: [% {( W' O8 ]' G0 s6 g2 j * @bus: bus type.* i3 \/ K3 g0 K' n: b* O
* @start: device to start iterating from.
! l% v# }4 u( U* p * @data: data for the callback.5 {- v; p( j: e
* @fn: function to be called for each device.
) T+ A7 S( [3 X. \ *5 ]" N5 }, }0 q
* Iterate over @bus's list of devices, and call @fn for each,/ a8 E: S* N/ x
* passing it @data. If @start is not NULL, we use that device to
) _* R/ j! O$ ^- X8 m * begin iterating from.8 r' u3 @$ ?4 ~# q; ]
*" Y% |# o* p% B) f
* We check the return of @fn each time. If it returns anything0 b) a/ }! w4 D1 @# Z7 `) q( j
* other than 0, we break out and return that value.6 Y% v/ Y# a1 ~3 M7 v
*
7 `+ p1 d- N, U * NOTE: The device that returns a non-zero value is not retained
8 ~. F: O! q7 D3 o * in any way, nor is its refcount incremented. If the caller needs6 B) u3 q# }$ `: w" u7 p
* to retain this data, it should do, and increment the reference2 q& I( `1 [0 t1 P% o* l7 m
* count in the supplied callback.
" h. i& _* e6 E7 r; `/ R */# C' n. x1 c4 a% ~
int bus_for_each_dev(struct bus_type *bus, struct device *start,* m! C* b& V& g
                     void *data, int (*fn)(struct device *, void *))
' v- p- o, v+ |  o7 ?9 g{6 \9 ?. b# }8 }9 ]
        struct klist_iter i;
- L: u8 n. R. O* u2 K1 m' A1 O! ^        struct device *dev;
7 |- d9 E, B: x- K8 Y: z# e        int error = 0;: a& `) p9 N5 P* N& v) |# T
5 T  N& q3 u: a) _& ]
        if (!bus)
) R  _# F% o3 C# @* e" t1 Q7 j                return -EINVAL;! z$ X7 I5 [! o

2 r! I8 m; p0 {  G9 T! F0 Z% w        klist_iter_init_node(&bus->p->klist_devices, &i,
& U7 e# J. _% R9 H                             (start ? &start->p->knode_bus : NULL));3 Z5 q) C+ U$ ]3 ?* L0 I$ p& d# s
        while ((dev = next_device(&i)) && !error)3 C; n# U8 J  d8 E7 f: @
                error = fn(dev, data);% \& T3 Q& y9 s2 v/ j# b
        klist_iter_exit(&i);/ h+ Z: H/ h' X# M( i5 ^3 f; K0 U
        return error;0 [7 e2 {  U! X0 B+ |" W6 a9 q
}
( L) q( X3 x& y* B7 B( b+ cEXPORT_SYMBOL_GPL(bus_for_each_dev);% V4 j: `7 K5 d/ [1 r
通过klist将遍历该总线上的所有设备,并为其调用__driver_attach函数。. T+ Y1 R( E3 P5 ^! _* I
static int __driver_attach(struct device *dev, void *data)
( v- n* n$ ?2 V1 \! s7 @4 e9 f{
* s" L. E) _: ~1 m: }        struct device_driver *drv = data;
1 S0 f+ c6 f! G8 b  v7 k; q" `( B6 H" ^
        /*
8 w, o( w) o. R0 L1 Z         * Lock device and try to bind to it. We drop the error
) O# L2 J$ D5 x4 O# ^         * here and always return 0, because we need to keep trying4 }) E# k( k: J% N' d# e! i( Q$ w
         * to bind to devices and some drivers will return an error( G1 ?4 X4 f8 K5 N. S
         * simply if it didn't support the device.
  }6 e0 C; n+ {# P5 e7 S: d         *( z+ y& k- I  a) t4 m6 w5 O: t, w
         * driver_probe_device() will spit a warning if there- l, b: c. M  p! k- B, g
         * is an error.7 L) m6 {& Q1 A/ F) f
         */8 I: `' y: d4 R2 O: a! {

# V' j& T9 N% t. p, j        if (!driver_match_device(drv, dev)). {- Y# b# ]( h  t6 V
                return 0;
8 k; q/ {7 n, T( N; }7 ?
$ d3 q% Z1 ]/ p5 Y3 m- q/ _+ l        if (dev->parent)        /* Needed for USB */
0 h) c7 c; s2 s: g) H                down(&dev->parent->sem);( P, m1 h* w+ A8 c, b
        down(&dev->sem);& {  u( ~. z/ K  o, P6 a+ ~% Y
        if (!dev->driver)! `  X  v1 d4 j. H- D
                driver_probe_device(drv, dev);
0 I3 k  U+ V- j        up(&dev->sem);
. E9 l$ P5 H4 l' r2 G$ ?- j        if (dev->parent)
  V( x9 R. Z1 u. `0 {                up(&dev->parent->sem);
' W2 O/ b* U! t9 M5 |: f- O) w- d* k- N) T* @  [
        return 0;, j' J# s6 J8 {+ r9 i! d4 ]
}
8 O! N2 p- X/ e6 _( J首先调用了driver_match_device函数,该函数进会进行匹配,如果匹配成功将返回1。我们看下这个函数:
; l3 z1 Y/ h, g' Z. Zstatic inline int driver_match_device(struct device_driver *drv,1 p4 i' R/ p9 {5 y* C1 [
                                      struct device *dev)
6 o. Y0 S2 Y5 l2 B6 I1 K{8 `* M, k0 ^8 [: E# o  ~8 _  u' m
        return drv->bus->match ? drv->bus->match(dev, drv) : 1;
+ w1 s1 i% ~% j! V, t$ f}
4 C% s5 W+ z5 n1 _8 B. U0 v5 m" ~5 @9 E: ^; K4 i: F7 t% c$ b1 [
这里直接调用了platform总线的match方法,我们来看下这个方法。  f$ F2 I# @* Z
/**, \/ O' o1 s. D& n+ q4 t+ _
* platform_match - bind platform device to platform driver.* ^- \' E- i  n) b% b; k2 @
* @dev: device.
, o% W1 d# l/ ~- ^8 i: A * @drv: driver.2 p0 {, _4 B% t8 N: B1 E; v- N" l, |( E
*
* K5 O# l& p" C# [4 d * Platform device IDs are assumed to be encoded like this:
& }1 a; D: L6 j6 H& y% x# {+ I- p0 E$ j * "<name><instance>", where <name> is a short description of the type of
6 k2 w1 b9 l( E' |0 R * device, like "pci" or "floppy", and <instance> is the enumerated3 y5 M+ [6 T  q. i! \
* instance of the device, like '0' or '42'.  Driver IDs are simply& O  B0 B' F2 U0 M3 Y
* "<name>".  So, extract the <name> from the platform_device structure,2 e, \) j1 c" h3 o+ A0 J. m
* and compare it against the name of the driver. Return whether they match
, t# q; h3 H. P( ~ * or not.
& k' w& F1 K: |- s" P! c$ d$ _ */; m8 f+ o$ |4 D% v
static int platform_match(struct device *dev, struct device_driver *drv)  Q% L# Q/ q( G. w* S* i
{
/ ?: S4 n& D0 H0 n9 L. Z; g8 i# X- X        struct platform_device *pdev = to_platform_device(dev);3 c: o$ t7 n8 q! E4 R
        struct platform_driver *pdrv = to_platform_driver(drv);
1 M1 d7 Q( t, n" K
& N9 s: L- U8 j- ]7 z- f: E        /* match against the id table first */
  e) l" K7 v! m5 M& i        if (pdrv->id_table)) z: Y' G1 P0 m3 K6 G: Y
                return platform_match_id(pdrv->id_table, pdev) != NULL;
1 T* d9 O! l- S, l  M; @. b0 B+ M$ ~1 z7 y" ]
        /* fall-back to driver name match */
+ \1 b+ w/ E/ c  ?- V# K        return (strcmp(pdev->name, drv->name) == 0);3 K* g+ K9 H( j) @
}
! d3 }5 [3 w; `# x( Q5 S该方法的核心其实就是使用stcmp进行字符匹配,判断pdev->name和drv->name是否相等。
  \4 [6 D6 O' [7 {2 T: X: s在本例中两者同为s3c2410-spi。因此匹配完成,返回1。% H4 v/ R/ T2 i

9 \* V0 O9 Z1 X2 R; i% W: A返回后,由于dev->driver为NULL,将调用driver_probe_device函数。我们来看下:
5 s, Q) C+ y5 Q- t' H7 l/ B7 g
7 w# r$ R+ U, U2 ]4 h/**9 G- v9 g+ T: G& O- g8 l6 f4 \
* driver_probe_device - attempt to bind device & driver together
4 |* |/ o3 ]' b) k3 m% ] * @drv: driver to bind a device to
, [3 l4 s8 W- D& l) e8 k7 V; @ * @dev: device to try to bind to the driver
3 b1 E, n& c# l: ] *. r8 l- H8 Z2 T
* This function returns -ENODEV if the device is not registered,/ `4 ^. D& a% m& ?  @
* 1 if the device is bound sucessfully and 0 otherwise.2 [7 _( @$ b; p0 T
*- G8 t$ Z. f- d( d+ Y$ X
* This function must be called with @dev->sem held.  When called for a+ R9 l! t3 a: _  m; U
* USB interface, @dev->parent->sem must be held as well.
4 a( e! H( g2 r) }* E' H  J& \ */
2 Q7 o, R& ^! Y0 H3 cint driver_probe_device(struct device_driver *drv, struct device *dev). \% m+ F8 [' z
{
# R2 {, ]1 f2 [7 a( g        int ret = 0;4 O, V# U9 Z0 V8 ]; c1 Q/ X
, @7 {: |! v& c+ X8 ~- F% B" d
        if (!device_is_registered(dev))
8 ]1 i' R: F; v3 L( D                return -ENODEV;, F5 I+ ?3 k) W4 Z$ s* S; s

# g0 `: o" e% b; ]        pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
- ^' e1 J1 E: z8 Y                 drv->bus->name, __func__, dev_name(dev), drv->name);
$ U1 Q( s' {5 l, s" G" S; q# [$ X' M
        ret = really_probe(dev, drv);' L/ X/ r" \) }  c& W' {

- h- }1 D3 S6 x( s& z        return ret;
; d+ @1 Z( c, h, R8 D7 w7 R}9 ?0 |. g& L. D8 w# T7 d
static inline int device_is_registered(struct device *dev), F3 b3 |/ f2 l
{
1 G. ]( A  [! X2 n    return dev->kobj.state_in_sysfs;
7 H3 Y! `7 H' @- [" T& u}! D% L# B/ }2 N. V0 T6 @
该函数将调用really_probe来绑定设备和它的驱动。
" b- A6 W1 f3 p. T  cstatic int really_probe(struct device *dev, struct device_driver *drv)
0 u* e- z8 n0 I2 ]: |$ h* C3 ]. o3 I{
/ r6 [4 D% }: s; z        int ret = 0;3 _# ]) h- g4 r, G, I

( v7 h0 k: S  P; J# e' r        atomic_inc(&probe_count);
3 I! h0 M! l1 C0 q2 c        pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
; z% Z* r1 m" C# j. V$ {7 p                 drv->bus->name, __func__, drv->name, dev_name(dev));1 G9 W  X9 [& ?, H
        WARN_ON(!list_empty(&dev->devres_head));0 p1 r5 C! A0 R' ~( o
0 V; o5 n3 g0 m* X& G6 [4 _( Z
        dev->driver = drv;5 X7 f0 B# [$ d  H! `3 {$ e
        if (driver_sysfs_add(dev)) {        /*创建两个symlink,更新sysfs*/# _2 m/ X0 k$ K4 P/ Y) `
                printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
4 Q1 O* x1 b. E                        __func__, dev_name(dev));
3 I* G4 ^3 b) b! Q% a                goto probe_failed;
- [' `3 _# q  L* |$ ]% }3 }8 S' @        }
# Q+ L# [9 o; A% P5 D1 O
, o' I: @5 i' c: `* R2 S0 |2 ?        if (dev->bus->probe) {% r$ X7 N/ i1 W) I: s3 N' z
                ret = dev->bus->probe(dev);/*调用总线的probe方法*/
& \( X0 ~+ h# l9 o/ |2 _2 J                if (ret)) V) _5 J% x# q
                        goto probe_failed;
) f4 H+ ?; Y( f8 v8 a        } else if (drv->probe) {0 V+ k* O: v0 t9 n# g
                ret = drv->probe(dev);        /*调用驱动的probe方法*/
& t1 k7 g3 U* g3 A" ^' Q) Z0 O# b                if (ret)' C7 m$ J1 @7 _& X( f/ V* {
                        goto probe_failed;
8 v! S, o' i; `2 g5 G# p# {% O        }
. e8 T9 y+ I: I' F
+ ?7 a6 t+ w; Q2 A! J        driver_bound(dev);              /*绑定设备和驱动*/2 G& |( f! c; v. o
        ret = 1;" x+ ~: v+ u/ {1 F+ [
        pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
5 d+ V. W) K7 U( @% _                 drv->bus->name, __func__, dev_name(dev), drv->name);
3 n& y2 z5 b& Q$ W) o        goto done;
7 W+ i* f# Z+ c- h9 y& e+ t+ |" y  o9 s% m( c
probe_failed:, M; B* n% V( i% `
        devres_release_all(dev);; }  P4 B1 _# W$ {' L# j
        driver_sysfs_remove(dev);
9 Y/ Y2 M; Q3 T6 S2 F2 b& P) c% I        dev->driver = NULL;% h1 K6 A: j4 Z
5 D$ g  }2 Q1 a; F, o
        if (ret != -ENODEV && ret != -ENXIO) {: u8 t2 `, P8 h, Q# J
                /* driver matched but the probe failed */
- a* s/ _' b7 u* S1 M                printk(KERN_WARNING
: s# T0 C9 G3 H+ R                       "%s: probe of %s failed with error %d\n",' n( {0 x* v# G
                       drv->name, dev_name(dev), ret);
( y& N% n  f( Z! s8 v        }# _' b8 h, S& w( ]) r
        /*
( W  r; [, h4 x- K         * Ignore errors returned by ->probe so that the next driver can try
4 s  b& u; S/ E         * its luck.
7 W3 e* I! s& n2 W         */6 ?8 a! v2 v- s8 ^9 B. `1 S" I
        ret = 0;5 `7 x  E$ e* E0 N: z# }. F+ Y
done:
; G9 h/ H# o' C) `$ U% A        atomic_dec(&probe_count);
: v# @% L5 |# p# c# j        wake_up(&probe_waitqueue);
2 E& ?% A% p9 J) d% Q* @        return ret;
' ^: K$ N( w" h. L: d7 J1 y}
4 K9 J8 U0 M7 c
+ p+ v' T- [2 }5 [9 s5 U2 c在这个函数中调用4个函数。  q2 @& ?6 J% q) \" [
/ Q$ _" h. U: ^
第一个函数driver_sysfs_add将更新sysfs。( N% B; m% i& j3 |2 I# b9 l
) {6 g( q7 w6 @1 `" W3 s
static int driver_sysfs_add(struct device *dev)1 p' V  e' x$ `3 g& q/ S
{
# D$ ^: g5 ~! x/ l2 j; B# f        int ret;9 h$ j% U: J5 l% v
        /* 在/sys/bus/XXX/drivers/XXX目录下建立symlink,链接名为kobj->name,
. B; w0 ^' Z, q* |           链接指向/sys/devices/platform/XXX */# ?8 t  N- M2 ?" m5 O- C! z" X
        ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,7 @# i- _' C- w. q6 o. e( }/ x4 m
                          kobject_name(&dev->kobj));
# I* m  B3 b) [7 E, ~* U        if (ret == 0) {
& ^: w- M2 T$ j! j                /* 在/sys/devices/platform/XXX/下建立symlink,链接名为driver,
/ Z: S$ f1 O3 H/ \# V                  指向/sys/bus/xxx/drivers目录下的某个目录*/
2 s. _" o5 U% O7 W. B+ A                ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,- v( @8 C& l* ^2 p" X# E1 U" T  n
                                        "driver");
7 L5 v8 `! H* @" Z- ?" g                if (ret)6 W9 g; L, s+ @; d) l( i
                        sysfs_remove_link(&dev->driver->p->kobj,! {1 Z& M# @: c
                                        kobject_name(&dev->kobj));/ {4 X" W: j9 ]) ]. B
        }
9 _; v; p- w  |  Q5 H! y' k        return ret;9 B8 a6 A8 g- H# J5 j/ G  P; D
}  `; J2 J: L5 d9 z( Y+ Z

! \& v- o7 ~+ Q. c. n2 Q执行完以后,建立了两个链接。
( ^3 {& u/ @, X8 T( M在/sys/bus/platform/drivers/s3c2410-spi下建立链接,指向/sys/devices/platform/s3c2410-spi.0
5 {5 e% p/ i/ ~% B+ L* e6 K/ |  W在/sys/devices/platform/s3c2410-spi.0下建立链接,指向/sys/devices/platform/s3c2410-spi.0。4 k# a. L5 Y/ {( }6 ~
这样就在用户空间呈现出驱动和设备的关系了。我们来验证下。4 w+ k( T: J$ G3 y
0 T5 H1 u5 O8 I& b& e3 m& O5 d
[root@yj423 s3c2410-spi]#pwd. V' y3 R0 {/ J0 m
/sys/bus/platform/drivers/s3c2410-spi" \6 o1 a1 N0 ?8 @
[root@yj423 s3c2410-spi]#ll s3c2410-spi.0
1 |0 H( V- }( c- z  zlrwxrwxrwx    1 root     root             0 Jan  1 02:28 s3c2410-spi.0 -> ../../../../devices/platform/s3c2410-spi.01 a# G9 v8 N0 B9 \9 \& R$ B
[root@yj423 s3c2410-spi.0]#pwd
" q9 L& C' p* `! r' X: w3 h: u/sys/devices/platform/s3c2410-spi.0
/ v- z- {. c3 V& W8 z4 n0 }[root@yj423 s3c2410-spi.0]#ll driver
& i' {, n- d0 a5 B) Rlrwxrwxrwx    1 root     root             0 Jan  1 02:26 driver -> ../../../bus/platform/drivers/s3c2410-spi- R" N% q" I4 W8 u

3 H+ L6 K4 t7 w( x第2个函数执行总线的probe方法,由于platform总线没有提供probe方法,因此不执行。4 Q# Y5 R: K1 f# n9 G9 h* n4 T

) }! g" H% q% H# o+ j第3个函数执行驱动的probe方法,驱动提供了probe,因此调用它,该函数的细节超过了本文的讨论内容,所以略过。9 e% L0 o' ~1 D& I- ^
+ t' S& q) [7 p7 x8 I
第4个函数执行driver_bound,用来绑定设备和驱动,来看下这个函数。3 s) D' g) C2 y4 a: z

$ D, M/ @7 Q& @7 Q/ Istatic void driver_bound(struct device *dev)
+ V$ M, t$ [% g5 ]9 p6 N{
9 x, f9 Q: A* \. V$ d. s        if (klist_node_attached(&dev->p->knode_driver)) {
, g% r! ]0 o" x) H! t6 L- o3 H                printk(KERN_WARNING "%s: device %s already bound\n",
* I3 `$ p! r& G/ p+ |/ W4 X, [                        __func__, kobject_name(&dev->kobj));" h, t6 w' ]% H$ T
                return;5 i# |9 [. a, x- @0 r" J
        }/ q0 a" n, }+ E

% {' s1 [, I% v' `        pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
( x6 H, P# e& b- L  x                 __func__, dev->driver->name);! _/ Y9 ?9 r! r, }- g$ D
0 ~. X* a% T2 h2 z
        if (dev->bus)
4 t& o' F7 N! @( m" B                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
6 Q  R; l# ]9 r  q                                             BUS_NOTIFY_BOUND_DRIVER, dev);9 e$ F8 M7 d* F% r& C

$ q2 V, g' i3 c6 u        klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
9 d; L1 w1 o* k}
7 I# H  u, B6 P6 v& Z其实,所谓的绑定,就是将设备的驱动节点添加到驱动支持的设备链表中。
- F8 G' t# D$ L7 E* l' o至此,通过内核链表,这个platform device 和platform driver 已经绑定完成,将继续遍历内核链表尝试匹配和绑定,直到链表结束。
. y" Q$ ]: |, x4 V$ D( b8 s- y# x* w& ~, V
在driver_attach执行完毕以后,bus_add_driver函数还有些剩余工作要完成。) G: G9 @; b& k* W; X1 p- N
) `' j" n$ d. V  e- B
首先,将驱动添加到总线的驱动列表中。
; |0 {  z# J0 }' F. u接着,如果定义了驱动属性文件,则创建。6 @3 ^1 o! W) ~6 P; I4 ?* a
最后,在/sys/bus/platform/drivers/s3c2410-spi/下建立属性文件uevent,并在同一目录下建立文件bind和unbind。7 i' {( }  |1 T+ `( k$ h7 }
+ |5 q0 J# h: i+ q1 ~
我们来验证下:
! \1 \! X  P9 M, C0 o' _& s( [7 M9 u5 m( e
[root@yj423 s3c2410-spi]#pwd
' d1 t* F2 c1 N# g/ \/sys/bus/platform/drivers/s3c2410-spi8 v8 l- G  Y. y$ T) J8 L
[root@yj423 s3c2410-spi]#ls2 y5 W: [3 q5 V( r( G
bind           s3c2410-spi.0  uevent         unbind
* T: E7 G0 s1 }3 Q0 K6 Z3 D7.7 小结. q* e, u5 P8 n& F/ Q1 f
在本节中,我们看到了platform driver是如何注册到内核中,在注册过程中,通过更新了sysfs,向用户空间展示总线,设备和驱动之间的关系。7 c0 W' J2 U* C& D; k
, e9 g% B5 _7 i- s& v
同时,还更新了链表的指向,在内核中体现了同样的关系。
, L9 s/ S  _9 o, |3 Q' u4 V
- V  P$ Y. z8 \  I+ W( ^最后以platform driver的注册过程结束本章。
9 G( a( I" i6 R7 n( _- W3 N
+ A; s4 K% A: y2 J9 `; U3 ] 9 X2 `( \1 ~+ t3 S. u# l* c8 l3 y
" Q/ X& m% _/ L( `2 v
8. sysfs底层函数
( t4 e& W: \& D5 t# S0 c# j下面讲述的内容将基于VFS,有关VFS的基本内容超过本文的范围,请参考<<深入理解Linux内核>>一书的第12章。
, S/ o, y0 p* x4 l在前面讲述的过程中,我们知道设备驱动模型是如何通过kobject将总线,设备和驱动间的层次关系在用户空间呈现出来的。事实上,就是通过目录,文件和symlink来呈现相互之间的关系。在前面的叙述中,我们并没有对目录,文件和symlink的创建进行 讲解,本章就对这些底层函数进行讲解。在讲解这些函数之前,我们先来看下,sysfs文件系统是如何注册的。
2 h0 T$ `% v- B5 Y$ ~  i
8 r3 R/ [. }( p+ _$ [; X6 `/ F8.1 注册sysfs文件系统7 Q( M1 C- o' a: {$ Z
sysfs文件系统的注册是调用sysfs_init函数来完成的,该函数在内核启动阶段被调用,我们来看下大致函数调用流程,这里不作分析。
- ^6 l& L( }2 N  L0 astart_kernel( ) ->  vfs_caches_init( ) ->  mnt_init( ) ->  mnt_init( ) ->  sysfs_init( )。3 }% y* H1 K0 E3 m! t# i
' c! K  [  B) Z4 ]& V9 B1 k: c
int __init sysfs_init(void)( \8 O: @6 g9 O" O& i
{3 a5 l1 t. A2 w6 c6 s
        int err = -ENOMEM;
/ ^# H" c8 P4 T9 u; \        /*建立cache,名字为sysfs_dir_cache*/: c* E3 Z9 W9 n& E! h5 R; a
        sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",9 _( }- M8 K* P5 Y
                                              sizeof(struct sysfs_dirent),
4 m$ w; U0 }- M" v7 t1 J  q                                              0, 0, NULL);
4 N- U/ M5 E- i% \+ o        if (!sysfs_dir_cachep)
' K1 b2 V% O  F. r# X                goto out;/ _* m6 x2 |4 f. `

' w  N* N* D0 v$ N2 S$ E        err = sysfs_inode_init();+ }! X1 G* |; ?$ G3 ?
        if (err)
( ?; ^, ^& m/ |" C. O                goto out_err;/ H* Q/ p# S1 Y$ L" [+ |( t9 N
        /*注册文件系统*/! f/ q& U- X4 Y0 V
        err = register_filesystem(&sysfs_fs_type);( q3 g7 F0 p. a3 r# h/ }. z
        if (!err) {
. Z1 p( }6 G4 m                /*注册成功,加载文件系统*/# C7 G' Q3 `9 m& K$ O
                sysfs_mount = kern_mount(&sysfs_fs_type);% K3 O% q1 F1 ~& v9 w- w
                if (IS_ERR(sysfs_mount)) {( h( \% }  Q" B' G% E8 t% ?
                        printk(KERN_ERR "sysfs: could not mount!\n");
" x6 J% B* E& @" U/ `' i0 ?. i                        err = PTR_ERR(sysfs_mount);# u6 E  O7 }! G2 _
                        sysfs_mount = NULL;: \( \# G7 S2 A* B3 d
                        unregister_filesystem(&sysfs_fs_type);
! e; y- Y  G  [+ d* z8 g4 b                        goto out_err;. q" ?4 a. v2 W6 i- m. D! n
                }# A7 o1 j0 l" H; V, B. _  f
        } else
5 t) p; O- N: t2 c                goto out_err;. j# L% a) }" i/ o
out:: g3 I' ^- g" n' K
        return err;
  v3 _# c& _; Q  cout_err:
5 m1 Q- q8 H3 n        kmem_cache_destroy(sysfs_dir_cachep);, |8 @9 r1 m! b- O# q
        sysfs_dir_cachep = NULL;
! i% U! T. x" X/ A6 j, _        goto out;, |* m$ G, T; B9 ~" K, Y0 l. U
}6 u. C9 w, E7 N& @0 U$ `+ r

( u% X$ V) y/ Z% U" Sstatic struct file_system_type sysfs_fs_type = {
( f0 Z& d1 i8 M6 w- F0 q' H+ A' J    .name        = "sysfs",2 u$ K" M# r, o5 G" K$ I- f& \) h3 s
    .get_sb        = sysfs_get_sb,( x8 t" F5 ~. |+ V- j
    .kill_sb    = kill_anon_super,* V$ J. |8 v2 H0 i( s
};% o- F) J# G: y6 N4 u4 @, W

7 J6 W7 G! a5 T" p8.1.1 register_filesystem
9 ~6 m3 n) K8 P3 ?. A, U' ]下列代码位于fs/filesystems.c。
& A0 i7 ~) J) @1 `( f- G/ _/**" N- W: N% l% A  Q
*        register_filesystem - register a new filesystem, E8 y; U! s0 e
*        @fs: the file system structure( X: ~- w# y$ x. B- A
*$ P# ~! b! z& {# A
*        Adds the file system passed to the list of file systems the kernel) ?' b3 [2 g0 x* y
*        is aware of for mount and other syscalls. Returns 0 on success,* n9 A" O) y+ n0 ?( ]3 y
*        or a negative errno code on an error.8 E6 p; f, y( b
*
: Z! i, y4 I- V% I7 k: h- ~6 \+ D: Z *        The &struct file_system_type that is passed is linked into the kernel ; H* X4 P: v, k! z
*        structures and must not be freed until the file system has been% M$ A! D; S: o1 \' w3 s( O& b6 ]
*        unregistered.$ X- Z; Z4 q* i
*/
7 U& d, n% W: L9 s8 g- H' z& R7 T) l5 Y! o& h! s) h
int register_filesystem(struct file_system_type * fs)# }% h4 P* m+ c9 r& n
{8 \; B+ m  p% K) E3 l! b. m
        int res = 0;
1 A4 L/ R5 U! ?9 N$ F, j        struct file_system_type ** p;! `! |0 }' m# F" y0 m# \$ ^! q

, a, Q6 \5 O' g/ i0 {/ p! D        BUG_ON(strchr(fs->name, '.'));
- s  b. ?& V0 h        if (fs->next)7 e+ n$ J' e/ i5 c2 K
                return -EBUSY;' N+ j- {9 ^! x7 z, V
        INIT_LIST_HEAD(&fs->fs_supers);
, M1 T9 _- P! i( r, X$ E% j        write_lock(&file_systems_lock);
! @4 k+ g( z- b        p = find_filesystem(fs->name, strlen(fs->name));        /*查找要住的文件是同是否存在,返回位置*/
4 L) {$ @8 E7 q7 `  }8 C  J        if (*p)
8 a  q5 U! F. e/ ]" |- G                res = -EBUSY;        /*该文件系统已存在,返回error*/
6 g+ |4 W( }6 }5 V% c        else  Q0 ?1 r, @% H, P, r; \7 _
                *p = fs;                /*将新的文件系统加入到链表中*/7 i* ?  F! w8 q2 z/ ?: Z, Z. x9 J
        write_unlock(&file_systems_lock);
* }6 S) |3 p8 A4 v" Q' F( o        return res;
9 k) {, v  ~8 j9 N}1 Z  b7 C( h+ I# f
static struct file_system_type **find_filesystem(const char *name, unsigned len)+ ~: b1 N2 a9 ~" y0 U
{% e; }9 b6 S1 S) z
        struct file_system_type **p;* E( B- u/ {/ G6 _& B
        for (p=&file_systems; *p; p=&(*p)->next)0 [0 [+ N6 J5 E
                if (strlen((*p)->name) == len &&- d2 W, e7 j6 M. {+ w7 d# T
                    strncmp((*p)->name, name, len) == 0)
0 m& ~2 a% i$ K3 ?: m2 J0 V5 Z                        break;
7 A4 Y5 U" N  l, z$ |        return p;
' P" }0 y/ U3 i& J: N& V}( h# l, G. ^/ r& e5 K
该函数将调用函数file_system_type,此函数根据name字段(sysfs)来查找要注册的文件系统是否已经存在。  C! S0 d# `3 K" p
如果不存在,表示还未注册,则将新的fs添加到链表中,链表的第一项为全局变量file_systems。
" @% w3 N+ M$ h* p3 K  i
0 v: ]% ]6 v2 A( @+ a# @该全局变量为单项链表,所有已注册的文件系统都被插入到这个链表当中。8 ~+ M. q  W$ Y' f& q3 p$ f% x& m; z  ^' `

- I; ]. P% d. E* f8.1.2 kern_mount函数
/ t9 y* _6 l. g$ ^6 _. s, k下列代码位于include/linux/fs.h
( ~0 c) j$ ]7 j: v) S5 ]  S' B
9 r( `, F1 a  V+ N* _6 }#define kern_mount(type) kern_mount_data(type, NULL)4 b3 Q, [# i7 ]
下列代码位于fs/sysfs/mount.c# ]5 S0 k& t4 M9 F* |* m
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
, x3 a+ n! s5 c; I' c4 t{9 T# s4 {5 Z9 ?3 K2 c  p
    return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);% @" \6 j  o8 E2 P) u$ t
}
7 E% R2 }: R; B8 I9 s5 ]0 u$ @* \2 L$ N# p! d1 E
EXPORT_SYMBOL_GPL(kern_mount_data);
7 n2 r9 i, J* C3 V, r2 \' |kern_mount实际上最后是调用了vfs_kern_mount函数。我们来看下:$ {* c/ w& i$ S% M
! i6 B5 D( `2 e  R
struct vfsmount *
3 l3 e# n+ y( Jvfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)" X5 ~/ }( n5 \3 R6 \; \! h) N
{
1 p7 x$ n( Z$ P* L# B        struct vfsmount *mnt;
( x  U5 e8 z% h        char *secdata = NULL;, L5 `* r9 }3 q; }$ k" O
        int error;
: d: F8 X8 M9 N% K7 r2 C7 k: T& A8 q: \( o% n
        if (!type)
# c9 z& M2 z$ f; H* f' D* h. N                return ERR_PTR(-ENODEV);" x4 [5 k# r' g* t# H

' T! W& Z9 }3 v7 v$ m        error = -ENOMEM;
) h" u' R4 x. b# k        mnt = alloc_vfsmnt(name);        /*分配struct vfsmount*/, N% A: U# U$ H
        if (!mnt)
  T% R" r/ ~3 M' z% h& y                goto out;
5 l# N- A% q. K; F0 e
9 h3 g; ]; B4 [; ^9 {; o3 \* L        if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {. r; x; k& y; A: ~" D7 |
                secdata = alloc_secdata();5 t4 ]5 I2 f! i, K- A! m
                if (!secdata); x! y7 Q6 s8 l3 d  v- L
                        goto out_mnt;
- P6 I6 [' P; W# W# W% P4 _; X
5 O. l; {+ d8 `# F9 {                error = security_sb_copy_data(data, secdata);3 U; d; E6 ~0 S, w( A
                if (error)9 h$ l3 d' p  H. s7 W0 V* R" b
                        goto out_free_secdata;  B% [& o( U, b# c1 u0 o3 H; H4 C% v3 y
        }6 ~# p) H) M: g' o: P
        /*get_sb方法,分配superblock对象,并初始化*/8 ^  H. w, z" F! `
        error = type->get_sb(type, flags, name, data, mnt);% i' P3 D% L' A) j
        if (error < 0)
; T0 m! N" o, j: m, U  v                goto out_free_secdata;
" l" s8 y$ J) [/ P3 i        BUG_ON(!mnt->mnt_sb);
1 C3 @9 W+ K8 [, ^! @; W8 c& T' I1 X4 @0 }! q5 z; M
        error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);' E9 A6 y; u* G% k9 x
        if (error)
' M$ y% W8 D8 \7 |3 D                 goto out_sb;3 R4 X3 g# d' |  e4 {: B* D
$ y4 n+ L2 V  e+ u6 C
        mnt->mnt_mountpoint = mnt->mnt_root;/*设置挂载点的dentry*/) B$ `1 h/ T3 B) r. J9 P
        mnt->mnt_parent = mnt;                    /*设置所挂载的fs为自己本身*/
7 |9 i% g+ i; q* N, b) U        up_write(&mnt->mnt_sb->s_umount);0 ^0 V' J0 R) e& ^3 [+ J/ z
        free_secdata(secdata);
( G- b" l' v& b' o, S+ n        return mnt;" r8 Z. t! w8 s8 }  l. [
out_sb:7 D, ~8 s8 G$ t2 p$ l2 r
        dput(mnt->mnt_root);
2 D  W0 e) T, I4 i        deactivate_locked_super(mnt->mnt_sb);
: o' w" t/ E; B7 Mout_free_secdata:. w  n4 p" u; V& l: j: w/ O: W
        free_secdata(secdata);  ~9 o8 @7 }, F. |! u
out_mnt:. C4 F0 P$ w) M. V
        free_vfsmnt(mnt);
, i0 s7 @0 A* N% x1 F5 oout:) n7 _3 Z0 X7 G8 L3 D
        return ERR_PTR(error);/ q* R/ J& p( W7 a. X: i/ S9 z
}$ m9 s& j7 X7 t# v
0 z" |6 C# J" l9 A; q
该函数在首先调用alloc_vfsmnt来分配struct vfsmount结构,并做了一些初试化工作。
% O! I3 U6 S8 r& e, E% c+ H4 l下列函数位于fs/super.c
4 D# u4 d3 M+ C, \struct vfsmount *alloc_vfsmnt(const char *name)
+ n/ d) {% l: p* x' z{
& T5 @% X. k0 }# Q9 E1 V        struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
, m- W- z0 k- A. P- _+ u% t        if (mnt) {
% `( j& P! X0 O- B$ Q                int err;
2 X1 l# y' R3 c7 k  o1 u
+ R0 Z2 p+ r! {4 i- P( o                err = mnt_alloc_id(mnt);        /*设置mnt->mnt_id*/
7 I  H8 e! B1 Y                if (err)7 o, D6 \6 e- ?$ h  Q- X' t7 ?
                        goto out_free_cache;( k2 U# O; U7 n" Z
! J. ]3 m% F2 }3 `1 V
                if (name) {4 M4 [* t7 n3 H
                        mnt->mnt_devname = kstrdup(name, GFP_KERNEL); /*拷贝name,并赋值*/
9 E8 X, ^( @4 V+ m! m* T. Z                        if (!mnt->mnt_devname)) c5 P3 s# J& S6 F+ v$ _1 D8 `3 {
                                goto out_free_id;
5 F1 w& s( O8 V) N. H4 Y0 O# ]                }1 @2 _  ~6 h% S( {& {: q* m( \. }% T
4 N, I/ n( D# J2 z* H+ J
                atomic_set(&mnt->mnt_count, 1);2 K" J! u3 E5 h- C" w+ f% s; n
                INIT_LIST_HEAD(&mnt->mnt_hash);  @) ^2 V1 ]0 T: t5 v9 c. r5 \
                INIT_LIST_HEAD(&mnt->mnt_child);
. U/ @& y. s0 J) J                INIT_LIST_HEAD(&mnt->mnt_mounts);' i- v% W+ @0 o# q* b- `
                INIT_LIST_HEAD(&mnt->mnt_list);" |+ d* c5 L' Y/ g
                INIT_LIST_HEAD(&mnt->mnt_expire);2 U2 ?( v" x0 ^+ f- W4 V5 l( G& I! b
                INIT_LIST_HEAD(&mnt->mnt_share);
  r4 W+ x3 S8 C: V3 ?( D0 r                INIT_LIST_HEAD(&mnt->mnt_slave_list);, @% a0 c, ~5 E' }
                INIT_LIST_HEAD(&mnt->mnt_slave);
. N, b$ ~: L! u: }6 }4 q                atomic_set(&mnt->__mnt_writers, 0);
8 V3 w* ?$ m4 c2 x% v2 X  F, \        }
" w/ m4 c# Z, v7 o* i! B3 Q        return mnt;' w# ]4 _. t  _1 J
- k( P) M" C( j
out_free_id:8 L7 s. }" q8 @; j5 g/ C0 ^+ O
        mnt_free_id(mnt);9 p) ^* c5 S- R; h) p! p( f8 W( K
out_free_cache:
  G% Z" c* n8 Y5 Y        kmem_cache_free(mnt_cache, mnt);. H) L8 r- ^0 i- Q! T3 F
        return NULL;& A7 S  u3 d/ f/ i
}
. M: F" V. S1 n分配好结构体以后,由于参数data为NULL,将直接调用文件系统类型提供的get_sb方法,该方法就是函数sysfs_get_sb。我们来看下:8 Q: `+ u2 v& P' S8 t4 C& V  u( ~
下列函数位于fs/sysfs/mount.c。7 p( }0 X% t. P, E
static int sysfs_get_sb(struct file_system_type *fs_type,( S- g) B0 D+ v1 B, n
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)
# F% |4 T7 L, h4 k{
% ~) j6 X8 L. T6 T  V        return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
/ ?, B1 i, V7 _  r* {}) d" v: G) Z! x# B
这里直接调用了get_sb_single函数,注意这里的第4个实参sysfs_fill_super,该参数是函数名,后面将会调用该函数。
3 i! q8 q! c" d. F0 l  {该函数将分配sysfs文件系统的superblock,获取文件系统根目录的inode和dentry。
' V+ `* P6 A# r6 v1 D2 b6 M; x' S$ w! }+ Z: g, [4 @2 Y( k1 z
该函数的执行过程相当复杂,在下一节单独讲述。" t0 c  S3 S, N
3 m0 U9 Q9 d% w# k" s
8.2 get_sb_single函数
) _" s2 o' _' }8 t  r' N2 p下列函数位于fs/sysfs/mount.c。" z  G2 J  g# l0 T" O
1 y$ E" Z" N1 T( m$ Q. d
int get_sb_single(struct file_system_type *fs_type,) w1 Y' u0 ~, J+ m5 l* f$ {* ]
        int flags, void *data,1 [6 W$ s1 Z7 N
        int (*fill_super)(struct super_block *, void *, int),6 Z3 n- W  C4 S& r' ~5 ]
        struct vfsmount *mnt). ^+ b* Z8 V5 ~! F1 f
{0 f% z/ q6 F3 u4 d" r
        struct super_block *s;
/ W# s0 D% {. A. c  X) C        int error;
3 c: ]6 B4 \* b0 k- V8 p        /*查找或者创建super_block*/
+ k9 A- u" S& c% @. B5 s        s = sget(fs_type, compare_single, set_anon_super, NULL);$ P. C) C5 w6 E5 Z$ u) @2 N
        if (IS_ERR(s))
+ L1 y; R& I: C; N: u                return PTR_ERR(s);7 Q5 G' @& R: X# M: I" l* z
        if (!s->s_root) {                /*没有根目录dentry*/
9 X; I( D7 Q! Z                s->s_flags = flags;3 W7 I7 v  y" H6 l3 \
                /*获取root( / )的 inode和dentry*/
1 s; o1 x2 s3 H7 h                error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);( J& H7 \  G" A: [4 x3 E+ h0 }
                if (error) {
" M5 c4 l8 v, g* U' W' X                        deactivate_locked_super(s);. _" X; |/ V$ w, o1 N
                        return error;+ f# h0 I/ ?' h
                }  O/ q2 ]% _  i, U7 `+ b
                s->s_flags |= MS_ACTIVE;
2 H  m1 X5 W3 U- j        }
% h+ Y' D; U; L0 j0 Y        do_remount_sb(s, flags, data, 0);/ F1 [7 K- K, I1 P$ g/ J! T7 Y
        simple_set_mnt(mnt, s);        /*设置vfsmount的superblock和根dentry*/" i5 |3 @3 F& r3 B' [; ?4 X
        return 0;/ t9 m( b2 ~7 I3 r+ w
}
  F: n1 w9 f; ?9 y" J* K( p' \4 ^! E' I7 w# t. O
EXPORT_SYMBOL(get_sb_single);
, H8 E& ~9 b# D8.2.1 sget函数" H3 j! E) h4 n3 k' f, L+ i3 y
首先调用了sget函数来查找是否9 y2 A0 R8 U; L5 ~
下列函数位于fs/super.c。6 T* a. S  S7 |9 \1 {+ N: D
/**" V5 ^( e  h6 _
*        sget        -        find or create a superblock
6 _5 F" D$ W' \6 N& Y4 A3 B *        @type:        filesystem type superblock should belong to% g6 M9 c2 v; N
*        @test:        comparison callback+ Y* J1 J3 P$ T& @' Z% }
*        @set:        setup callback' v. ~5 Y9 z2 i0 `, r
*        @data:        argument to each of them: ]+ i; G* k8 J7 Q" ~5 T( N
*/8 O, H+ g6 }$ d9 e6 P8 P
struct super_block *sget(struct file_system_type *type,4 T5 `7 s7 `6 G# F! b
                        int (*test)(struct super_block *,void *),
, i2 J$ {" Q! j7 X                        int (*set)(struct super_block *,void *),4 ]* Q. v# ]; c
                        void *data)
8 I/ E9 m& L0 H{
; J1 ~, {/ K0 l* t2 U$ Z        struct super_block *s = NULL;7 F) w( {# z, x- T- u% J
        struct super_block *old;; a% \: x! T5 G5 Y
        int err;# X8 [$ p) K9 ~: H6 L
$ c, A6 E+ e$ o; C- [  S6 \
retry:8 ]4 }( E% W5 n- h% d& i
        spin_lock(&sb_lock);  P! X; L: E+ F. Z, f
        if (test) {                       
2 P  Z& K6 [% V: S                /*遍历所有属于该文件系统的super_block*/
& h, y1 `  X4 q5 ?$ f8 l                list_for_each_entry(old, &type->fs_supers, s_instances) {
6 u) s6 m5 V( }4 b0 d* u4 i                        if (!test(old, data))
8 {& a5 v2 z- w7 z, q                                continue;; b; a, W2 v) ~9 W- j9 |
                        if (!grab_super(old))& P2 l% C6 D8 _% k
                                goto retry;
8 [6 F# _+ s' v                        if (s) {3 {5 ?4 E; a' u6 g0 n* D  X, }
                                up_write(&s->s_umount);. L2 G3 Z9 p4 i; m; l. U
                                destroy_super(s);
7 {& K1 m% T! I, u4 e; J                        }2 w9 f9 e9 c$ Q6 m
                        return old;: d) d. {/ h& X2 @# r
                }4 }; p: W: i% ?$ Z# a6 }
        }
8 @; k6 q/ i& n: T- {: c+ ]        if (!s) {
* P& T$ P$ U& D9 z& I) T  g                spin_unlock(&sb_lock);
7 p: t+ v2 D/ N% [  P4 ?1 p                s = alloc_super(type);        /*创建新的super_block并初始化*/
2 r1 E) O9 H# \# v8 l! G                if (!s)6 z$ m9 Z; X9 O9 c! l
                        return ERR_PTR(-ENOMEM);
% T9 }+ C  D, Y                goto retry;* \& x1 b) D0 ^; O; Y
        }* z  G7 M+ t. K# n
               
' }9 F* f" a  |$ H# r        err = set(s, data);                /*设置s->s_dev */6 C1 n& o# B+ ~; g3 }. j+ K
        if (err) {6 e) `0 i: |, j, J7 g" t
                spin_unlock(&sb_lock);& m7 N: `: u/ ?4 `6 |2 A
                up_write(&s->s_umount);5 ?. c" U$ E; U7 ?$ k7 j
                destroy_super(s);
2 p2 S: c; U# @2 l3 }1 U; U                return ERR_PTR(err);, w* I. s0 [$ {$ L
        }
) F5 K$ {$ o* s& B, Y; X/ \  t        s->s_type = type;
; k* O# [4 j6 r        strlcpy(s->s_id, type->name, sizeof(s->s_id));        /*拷贝name*/! s- U- K# H8 k+ |" f8 @
        list_add_tail(&s->s_list, &super_blocks);                /*将新的super_block添加到链表头super_blocks中*/& i0 ]# Z' ~7 u. d
        list_add(&s->s_instances, &type->fs_supers);        /*将新的super_block添加到相应的文件系统类型的链表中*/
5 J7 m( e% c, s" _6 p        spin_unlock(&sb_lock);0 j: x8 b9 J; J  H: a- s
        get_filesystem(type);7 {+ O$ K; g2 S+ A6 G# e0 A
        return s;
6 ~, f, E4 Y! v" f9 g+ I- v}5 k1 }) H6 ^  M3 }& V
7 W0 A& Q3 r: q( a7 H1 O4 _
EXPORT_SYMBOL(sget);
6 l( O1 P9 g9 w, @* R9 f1 p0 y该函数将遍历属于sysfs文件系统的所有superblock,本例中由于之前没有任何superblock创建,遍历立即结束。
* q( o* e  ^- i4 d( ~然后调用alloc_super函数来创建新的struct super_block。
1 R& b1 ^% F& ?% f0 P; W3 X
- c0 Z! _5 T2 M$ O+ q. s) Q$ x下列函数位于fs/super.c。5 m1 W0 r/ G" P& l3 l! a
/**
0 P7 h* Y' D5 W4 C' b9 O- I; Z *        alloc_super        -        create new superblock' N$ q+ Y, ^8 C
*        @type:        filesystem type superblock should belong to6 X: a( i+ x+ \) b1 j: e7 L
*
- g, I! c; y( ^5 F0 a1 h! L$ L) e *        Allocates and initializes a new &struct super_block.  alloc_super()
9 p1 e% O8 s( v! R1 V *        returns a pointer new superblock or %NULL if allocation had failed.
9 E2 L  D5 k' \* ^. `; Q9 ` */. Z! N1 S$ V- `: [. j0 b
static struct super_block *alloc_super(struct file_system_type *type)
( i- k9 {+ w6 ]. m7 S: D8 \' b{
- D- w6 S  ~9 B' R, ~        struct super_block *s = kzalloc(sizeof(struct super_block),  GFP_USER);/*分配并清0super_block*/
, H4 ^; Z; J. G        static struct super_operations default_op;0 F* m: D& y" J) y4 U# b* U

* g9 p3 W1 O; {1 e0 U- J1 m1 J        if (s) {, I& V% ]8 `5 f# y& F
                if (security_sb_alloc(s)) {
8 p1 F5 f. h: g) r                        kfree(s);
( @8 b& c  k8 F6 [                        s = NULL;. i" H5 y8 r' Y  d' s8 @/ t* {
                        goto out;, k! `& O: s  B
                }
, Z* ~  I/ m! f  @7 ]                INIT_LIST_HEAD(&s->s_dirty);
: q- d9 F1 ^' i$ g5 K  v% l                INIT_LIST_HEAD(&s->s_io);- E0 I( x3 G# v( ~4 n% ?5 m
                INIT_LIST_HEAD(&s->s_more_io);
- H* A4 b, V1 i$ }+ M2 B) h                INIT_LIST_HEAD(&s->s_files);
" {  c( Y' _! i" W* l                INIT_LIST_HEAD(&s->s_instances);
8 s; x$ J; H- P1 U- N1 w0 z                INIT_HLIST_HEAD(&s->s_anon);1 P2 g+ f) ?4 `0 c) A
                INIT_LIST_HEAD(&s->s_inodes);1 u" G6 {  D( |. y
                INIT_LIST_HEAD(&s->s_dentry_lru);
" m) E  t9 N% x( M2 ^4 b+ U8 @. G                INIT_LIST_HEAD(&s->s_async_list);! R3 Q: g/ [/ ~  {5 l. w2 ?9 `
                init_rwsem(&s->s_umount);
1 J( E1 d* x% [( B                mutex_init(&s->s_lock);
! @, C7 i. {1 b+ B4 {. M+ U* d, h( t9 W                lockdep_set_class(&s->s_umount, &type->s_umount_key);, `- i* {, [: n4 r  ]: q0 j2 r7 S
                /*
1 a& T& d7 R1 L( Q                 * The locking rules for s_lock are up to the
3 o3 @3 t6 u4 Z$ D% r7 `                 * filesystem. For example ext3fs has different
# Z- o* L$ S. W                 * lock ordering than usbfs:
9 l* P1 e% E8 b                 */
" l$ q( @7 t; |: K                lockdep_set_class(&s->s_lock, &type->s_lock_key);' V7 _8 B0 P9 J# k9 E4 E. X+ F7 ^
                /*
6 P7 d) ~8 J0 I0 @                 * sget() can have s_umount recursion.- H% Q& c5 M5 R/ V& _
                 *3 M& a4 p9 ]) \3 {/ c4 ^  C1 v
                 * When it cannot find a suitable sb, it allocates a new
6 ~, |5 L& l  k5 n2 p                 * one (this one), and tries again to find a suitable old8 L. D2 _# T4 S/ z+ e' w9 _
                 * one.- [1 A; L# ^; C
                 *( O- g2 J# a  z% a
                 * In case that succeeds, it will acquire the s_umount
( b) V- l$ D6 t' m5 j  Q                 * lock of the old one. Since these are clearly distrinct8 Q0 I5 m8 d; k! B  M4 L
                 * locks, and this object isn't exposed yet, there's no# U4 F: h% O0 D! s
                 * risk of deadlocks.8 m3 H( K/ w/ H" |7 I
                 *( R# R( H$ _  Z6 R5 f3 J
                 * Annotate this by putting this lock in a different, M6 X  m! U' S4 z
                 * subclass.
  W: E; _7 {* E- U1 k                 */
  o( A* f$ u4 t) ?  d5 K' ]                down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);; c) l3 p5 }1 i4 F& Y$ W; M" a
                s->s_count = S_BIAS;
5 M7 ^% L9 j7 c0 i: J' Q2 s                atomic_set(&s->s_active, 1);
9 @+ Q+ n7 Z3 I) ]' }                mutex_init(&s->s_vfs_rename_mutex);
3 l' d1 K7 x4 v                mutex_init(&s->s_dquot.dqio_mutex);
; t- Q3 Q6 Q$ P8 g2 p                mutex_init(&s->s_dquot.dqonoff_mutex);' c3 ~4 ]9 G/ S" E9 H7 V
                init_rwsem(&s->s_dquot.dqptr_sem);
7 L9 Q+ m  e& C0 u: K5 I; A) W3 v' z                init_waitqueue_head(&s->s_wait_unfrozen);$ m3 l0 j6 t# S. g6 g9 z2 F- d
                s->s_maxbytes = MAX_NON_LFS;0 v0 n! X4 E! [9 h/ D8 w
                s->dq_op = sb_dquot_ops;! f% V( k% M: s
                s->s_qcop = sb_quotactl_ops;- n, F4 p' E2 c
                s->s_op = &default_op;9 O# Z+ z4 p( O9 {2 C. r7 w( a
                s->s_time_gran = 1000000000;) i, W% W/ ?- W0 o
        }
* e1 r* G; J1 s( W% d) Cout:) b* D. ~& i2 |/ n, o/ B; g" X3 }
        return s;8 h# [3 n8 ]. N4 ^9 }
}, U# k; {: m, j0 c1 R& h/ I) n; t$ ~
分配完以后,调用作为参数传入的函数指针set,也就是set_anon_super函数,该函数用来设置s->s_dev。
) K7 z* n, Z% Q7 i$ n9 \下列函数位于fs/super.c。, j% h3 S# _* q  V# S5 F
int set_anon_super(struct super_block *s, void *data)
4 N( p/ o( I' U! q6 \! o5 o{% K' t- f+ |+ m# A% F* [
        int dev;* i& h+ K. I, R% M% x
        int error;
  Z9 S+ D% c. `7 \8 B2 v% G7 g6 k' h: p
retry:
; W  B: h) Y0 C% ]* F9 I: M9 }        if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0)/*分配ID号*/) |( E( {, e4 X
                return -ENOMEM;
5 {- M6 P* m# v3 Z  ]) i* g! O( V% G        spin_lock(&unnamed_dev_lock);2 k4 Q% F) N0 L% g$ \
        error = ida_get_new(&unnamed_dev_ida, &dev);/*获取ID号,保存在dev中*/" \6 w8 f2 r; T. q% e; J' n- j1 M* R
        spin_unlock(&unnamed_dev_lock);
% u1 h  c- @  d  ?" [4 |4 F; Y        if (error == -EAGAIN)" l, @( G1 Y& j: y! l
                /* We raced and lost with another CPU. */) d% h5 j8 w* r1 T+ n% O4 f. V
                goto retry;( T7 \5 V" j9 B8 i
        else if (error)
7 f; Z6 k( V8 K2 O6 D) |                return -EAGAIN;- `0 @* h4 K" L$ u  l2 J" S5 c

/ M6 ^% V5 y$ v6 M        if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
$ \7 k: x* m: ^& m                spin_lock(&unnamed_dev_lock);
3 O3 F  |3 h+ @! G$ ~                ida_remove(&unnamed_dev_ida, dev);
2 `9 p% |8 C4 o2 g% @: V$ M                spin_unlock(&unnamed_dev_lock);
% g- a* L0 c9 S- t# {1 U                return -EMFILE;" Y0 L) L1 B% j% h% F
        }! [, d! q* A5 K0 a( C" Q( D
        s->s_dev = MKDEV(0, dev & MINORMASK);        /*构建设备号*/7 Q8 H+ D) N# \9 W$ g3 P
        return 0;! e% M" S7 j# M! g" c" T* ]
}8 n" X* @; j: E, ^" Y! a
8.2.2  sysfs_fill_super函数, U) F% j* R' O% Y) V: ]; u: x$ ^
分配了super_block之后,将判断该super_block是否有root dentry。本例中,显然没有。然后调用形参fill_super指向的函数,也就是sysfs_fill_super函数。- B! n- D7 F2 [/ D9 r

4 F6 E2 D4 ^8 v0 M下列函数位于fs/sysfs/mount.c。+ V, t+ B; H- m( ]: u4 a8 d. b
struct super_block * sysfs_sb = NULL;
( [8 W" y, ^4 k& N3 _' v0 F; R" u1 |$ S" D$ l! Y# i
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)9 g: A! k5 i: W$ Z' Q4 V3 x
{7 L/ n( m" @# m
        struct inode *inode;% |* ?. N% Y* y- t8 U
        struct dentry *root;# G7 h/ o( j* d

. s! C* h) ~# i- c        sb->s_blocksize = PAGE_CACHE_SIZE;        /*4KB*/$ {- o) [- [! c# k/ F$ t8 E
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT; /*4KB*/
' R5 U, B7 X/ ^5 T( K, _* k        sb->s_magic = SYSFS_MAGIC;                        /*0x62656572*/0 v% j! o" A+ m7 W: B4 x$ M2 P
        sb->s_op = &sysfs_ops;) y, t( c6 g0 H9 w6 R& u
        sb->s_time_gran = 1;
7 a+ C" _$ c2 G" n% L        sysfs_sb = sb;                /*sysfs_sb即为sysfs的super_block*/
% f7 v( F1 S) D) D1 H$ E+ R: {! a# Y
0 ~. ^  z, y& |9 m# [0 j2 Q        /* get root inode, initialize and unlock it */
' J% T% |1 ^' O# \        mutex_lock(&sysfs_mutex);( D- j% h2 t& T
        inode = sysfs_get_inode(&sysfs_root); /*sysfs_root即为sysfs所在的根目录的dirent,,获取inode*/                % w0 k0 T5 j1 o4 {" Q
        mutex_unlock(&sysfs_mutex);  S: T: ?/ A$ ]! ]1 y
        if (!inode) {
: N& |) C* {3 J* G                pr_debug("sysfs: could not get root inode\n");$ x' D+ E4 ^) `
                return -ENOMEM;( K0 I/ u4 V+ F3 u! k
        }! p* i0 q' z- B8 Z) k

6 r0 E# N4 f$ f, `# h* X, |        /* instantiate and link root dentry */' h  B- V8 D0 y* N
        root = d_alloc_root(inode);        /*为获得的根inode分配root(/) dentry*/; D+ Z8 T" @- |- m9 l/ a
        if (!root) {% M! U7 a' {9 `4 T0 U! z' {2 ?
                pr_debug("%s: could not get root dentry!\n",__func__);- l2 K4 p; H1 o8 \
                iput(inode);
1 b5 m; o: t4 M; z                return -ENOMEM;! f2 q( }( J' \- Y+ ]
        }8 V) t/ r. Z' v8 @. N4 H( K
        root->d_fsdata = &sysfs_root;+ ?. r2 ?# W3 s- Y" x7 p
        sb->s_root = root;   /*保存superblock的根dentry*/
- U7 l0 C- ^, }4 Q: v        return 0;* q5 R4 e/ `/ m  S
}2 D+ V8 H3 i4 J+ i, u

1 |7 J9 L' c1 B+ o- m+ M! Estruct sysfs_dirent sysfs_root = {    /*sysfs_root即为sysfs所在的根目录的dirent*/
5 Y1 m/ N% x1 @& c% w2 w    .s_name        = "",( L' I1 I& R* K5 b0 M7 o
    .s_count    = ATOMIC_INIT(1),$ f- e; M; q: B! Z3 C
    .s_flags    = SYSFS_DIR,* S9 a, L  f3 m. n8 {
    .s_mode        = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,  |2 b4 A2 _9 h6 A) A# @
    .s_ino        = 1,+ p/ I# Z6 n& C3 a" x- s" Q
};+ ?" B" v  R8 O7 V- _3 z

5 Q- F$ x$ q- }在设置了一些字段后,设置了sysfs_sb这个全局变量,该全局变量表示的就是sysfs的super_block。( G  G# s; k# M; L
随后,调用了sysfs_get_inode函数,来获取sysfs的根目录的dirent。该函数的参数sysfs_root为全局变量,表示sysfs的根目录的sysfs_dirent。# }% L6 f' X- l, K; E; e# x

: h% @/ q, F3 v+ X我们看些这个sysfs_dirent数据结构:$ f2 U8 e% ], l5 E6 A9 {
/*, s3 q: K; o3 f4 X9 _' V$ g+ i
* sysfs_dirent - the building block of sysfs hierarchy.  Each and1 W2 ]1 l3 C  ]1 z/ M5 _( a
* every sysfs node is represented by single sysfs_dirent.
4 Q' u5 b1 S+ P( ` *6 p0 a8 d; f! j7 b" R. h
* As long as s_count reference is held, the sysfs_dirent itself is
! c" ?$ q6 [/ { * accessible.  Dereferencing s_elem or any other outer entity
1 I% l1 f: {- @+ b7 w, M0 T4 U * requires s_active reference.' C2 D) D. M% g8 B
*/7 z, L5 k( f9 P& a
struct sysfs_dirent {7 K+ y# {% j: j
        atomic_t                s_count;/ [' ]& g. x* l+ q7 x
        atomic_t                s_active;
8 {7 }$ J. S9 }3 W+ N        struct sysfs_dirent        *s_parent;
+ _- ?5 j  e1 q6 S2 _! w        struct sysfs_dirent        *s_sibling;# P. W3 B, _& k( |7 Y7 m
        const char                *s_name;! S. d+ s: A2 `+ d9 f- N

8 E' }5 N* S) [* d  T: d        union {. \1 i% d5 t3 i/ h& d8 }
                struct sysfs_elem_dir                s_dir;
. v  y2 h* p% L: }1 _1 I: D) @                struct sysfs_elem_symlink        s_symlink;
, L2 }! ]& d* u& Q3 Q                struct sysfs_elem_attr                s_attr;0 O: }: Z9 w+ l
                struct sysfs_elem_bin_attr        s_bin_attr;9 Q, F& U  ?% i; ~& Y
        };/ q' C$ J; H- K6 c0 G: ?) W* ^+ E# {

) j! Z( Q4 q1 v- \( x        unsigned int                s_flags;+ E- Z# |' `* k  K4 a, y
        ino_t                        s_ino;
* g# x( G9 T) z- j        umode_t                        s_mode;( Y4 x! }0 |2 Y. r
        struct iattr                *s_iattr;
, F- `% o: c$ K' [, X};, @4 y2 G9 ]& {) o4 L& ^
其中比较关键的就是那个联合体,针对不同的形式(目录,symlink,属性文件和可执行文件)将使用不同的数据结构。. x5 B2 I1 a& ^* J
另外,sysfs_dirent将最为dentry的fs专有数据被保存下来,这一点会在下面中看到。
: Z6 ^5 W2 P: n+ |- F8 }( R" O2 B接着,在来看下sysfs_get_inode函数:
( \( _9 t# K6 \& |下列函数位于fs/sysfs/inode.c。* {" V; F  Z& b6 h
/**
5 }# T* t2 P) _2 j: } *        sysfs_get_inode - get inode for sysfs_dirent
1 [2 t) a8 @" u# l+ p *        @sd: sysfs_dirent to allocate inode for7 Y2 [' {6 b/ Z
*" N) g( s- ~4 L  R' w$ ^+ G. s
*        Get inode for @sd.  If such inode doesn't exist, a new inode* |# d8 e/ p% ~8 i/ J9 ]; m
*        is allocated and basics are initialized.  New inode is
& o; s' `7 g3 r* O, [" {  ?. a3 a *        returned locked.
! \8 f$ I8 U: Y4 ]7 _6 I */ ^/ \* o2 X4 l3 t9 U1 d( e
*        LOCKING:
/ ~: x( x  F0 H2 v6 ], X *        Kernel thread context (may sleep).7 Y/ Z* V5 q, B$ c2 P1 _
*
% T2 C+ @" \/ @ *        RETURNS:& }" _" U& i. N7 A1 [$ ^: z! D1 N
*        Pointer to allocated inode on success, NULL on failure.8 a3 y! f. x% v. x
*/
( A$ n5 }; w. h' x9 A- p1 m' h7 pstruct inode * sysfs_get_inode(struct sysfs_dirent *sd)
9 \4 M0 x  s" m: n& M4 o{1 k7 q7 }' o# P" V
        struct inode *inode;$ B/ z: V* E. y6 {- Y1 b9 }) l

7 M( p0 w5 _& U3 t        inode = iget_locked(sysfs_sb, sd->s_ino);        /*在inode cache查找inode是否存在,不存在侧创建一个*/2 {& v" a4 b  m% I
        if (inode && (inode->i_state & I_NEW))                /*如果是新创建的inode,则包含I_NEW*/
  ~3 J  f6 f# v+ j: V. ~9 j/ J                sysfs_init_inode(sd, inode);& x1 }6 p, J6 b
4 H4 I7 m7 T  Q1 D! a, l
        return inode;/ p  U) f- A# S
}- K/ V" e0 g9 |' i
6 \6 z$ H/ u9 o3 P% y
/**
( g4 y3 h" l8 ~+ {( g7 i$ H3 J' s" h * iget_locked - obtain an inode from a mounted file system7 B, U' X. g0 m9 Y9 _
* @sb:        super block of file system* ^: i( o/ ~1 Y5 z+ `% e2 u1 }/ t6 d
* @ino:    inode number to get
- M9 U) o) G8 c- @* a2 v *
  S+ n! ~; Y3 ~: p * iget_locked() uses ifind_fast() to search for the inode specified by @ino in
0 |& G1 H) j! g3 R# F * the inode cache and if present it is returned with an increased reference5 e! d/ a; J' `
* count. This is for file systems where the inode number is sufficient for
0 b$ C: T8 ~  u. T * unique identification of an inode.1 n+ ^  i4 o) @* K
*
) \- [% ?9 Z' E * If the inode is not in cache, get_new_inode_fast() is called to allocate a# T% ?3 U, l& S
* new inode and this is returned locked, hashed, and with the I_NEW flag set.
0 L: v4 ]/ m  F( `0 F * The file system gets to fill it in before unlocking it via$ c% |! n6 q; Z' H) z. L0 |. }
* unlock_new_inode().
2 M0 Z, Q  Y) F" q3 M* z */
/ c) h+ S/ k0 z) k. B- kstruct inode *iget_locked(struct super_block *sb, unsigned long ino)( `$ X- P4 @! w1 a/ i- Y
{
/ h0 n1 i; d0 E    struct hlist_head *head = inode_hashtable + hash(sb, ino);
, w- x0 m, y. ~' q  `8 L( z    struct inode *inode;0 N; U% w: I9 w7 {
" @4 ?& |+ v$ p; `
    inode = ifind_fast(sb, head, ino);/*在inode cache查找该inode*/
7 ^0 ]; b' z- q  U. c    if (inode)( P3 E" q0 O& A- O7 R
        return inode;         /*找到了该inode*/
- Z. s3 F% S! I+ T( w1 b$ S' ?1 {    /*4 k/ x. B# `' W; g, u
     * get_new_inode_fast() will do the right thing, re-trying the search
; W$ }" Q9 f* J, p& e$ @9 g5 }& F$ C: \8 Q     * in case it had to block at any point.
0 |( n3 ?9 _0 b; H: \     */' M8 q: s$ R' J; H: z8 I, |
    return get_new_inode_fast(sb, head, ino);    /*分配一个新的inode*/0 {' S6 e! x  a- H6 ^. P7 _+ W
}
# G& X& [  Q% m' e4 E5 _EXPORT_SYMBOL(iget_locked);  D5 J2 T& b. u6 X: b* o0 M  `

$ m, j4 G. m0 U6 a% B1 L! |static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
; d" E1 A7 o+ j1 M" W{
/ x6 V9 r/ l9 F: P0 m0 o    struct bin_attribute *bin_attr;
1 p5 Q1 K' s# S2 j7 |. O8 }) N! f% l( q8 ]8 h0 f9 Y
    inode->i_private = sysfs_get(sd);$ @; w) ]2 c' z# }$ ?* a4 a
    inode->i_mapping->a_ops = &sysfs_aops;9 s3 r4 }6 n) Y. w  T! C
    inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;* {8 _. C. I" L2 n+ C
    inode->i_op = &sysfs_inode_operations;
1 ~% q3 ]- U4 e# {% H    inode->i_ino = sd->s_ino;- e- b# Q" Z& y/ {7 @8 y, c$ F
    lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
# ]! B' `8 x9 f& R( L* @9 p$ [
( E" T, b# I$ M    if (sd->s_iattr) {3 P0 F' `1 G8 s5 `* f
        /* sysfs_dirent has non-default attributes
2 m  ]2 j: V* h) N2 n         * get them for the new inode from persistent copy
' I/ t  r0 h% n' w- b8 c         * in sysfs_dirent
  i' U" u0 }3 v0 W9 z% f         */
- {( `2 Q5 t9 M- p        set_inode_attr(inode, sd->s_iattr);2 L* m: W" T8 N" X! [2 D) d. [% U
    } else( u$ l2 A& I; h9 t1 y$ T
        set_default_inode_attr(inode, sd->s_mode);/*设置inode属性*/$ I4 \1 T. M; ?: q1 r3 W

' O, t6 b: c2 `+ |: }# B! o% Z! Q% V' s: S* D& x+ k
    /* initialize inode according to type */
0 q3 ?3 u( _( Z    switch (sysfs_type(sd)) {
3 j7 }# g' M6 M) V5 m, f/ L/ P; m) f    case SYSFS_DIR:
' X/ m& k3 y& H% _        inode->i_op = &sysfs_dir_inode_operations;" P: R! d! U4 D
        inode->i_fop = &sysfs_dir_operations;, O" Q, s- A% s* D6 }5 i* L* n! R
        inode->i_nlink = sysfs_count_nlink(sd);( t4 o+ @  n) {) Y, e8 c
        break;
% F1 K# f! k( a    case SYSFS_KOBJ_ATTR:
3 K! Z. B  Y. a# ~% E( e7 z- d        inode->i_size = PAGE_SIZE;
- `% [9 B7 P1 W/ b9 p- `# Q        inode->i_fop = &sysfs_file_operations;
1 |$ L. ~' n, _: [- x        break;( n; L0 [, A6 x, L: n( J! j3 P, ~
    case SYSFS_KOBJ_BIN_ATTR:
# A8 N) C5 N2 W, o. g        bin_attr = sd->s_bin_attr.bin_attr;
( B7 A2 D( E' g" @8 |; ~2 `        inode->i_size = bin_attr->size;
; I- H, \9 h7 J( d        inode->i_fop = &bin_fops;  j4 x# P$ l. ~/ V5 x5 r
        break;1 P% P- S) B0 J
    case SYSFS_KOBJ_LINK:
  o5 Z. ?7 j  _% u5 X8 U% H5 ]% q        inode->i_op = &sysfs_symlink_inode_operations;8 d7 m3 A% Z# K# P( X! u
        break;, F+ p/ O& V/ ~" A9 s
    default:- G# S  x# g4 u$ a6 L& l
        BUG();
+ v; b( k/ Q7 s8 Z    }2 Z! A8 S! _6 w9 U
' M  l! ]3 j2 ^! `
    unlock_new_inode(inode);2 v$ Z& l% c/ t5 b, x
}
5 @7 b" K! k8 K( y! X1 t- P; U该函数首先调用了,iget_locked来查找该inode是否已存在,如果不存在则创建。如果是新创建的inode,则对inode进行初始化。8 p5 M# m; ?; C7 q# ~/ I
再获取了根目录的inode和sysfs_dirent后,调用d_alloc_root来获得dirent。- B& w. d- ]2 g) U' T! r' a
/**
) f/ ~/ @" E  q6 }5 @ * d_alloc_root - allocate root dentry
0 _4 T3 O; r2 L) ^- y * @root_inode: inode to allocate the root for
+ e' k8 d, q; l( r. y2 Z  Z& F *6 Q( f6 z: K3 T% n: A
* Allocate a root ("/") dentry for the inode given. The inode is
/ k7 U% M0 y( \9 ^ * instantiated and returned. %NULL is returned if there is insufficient
! l5 T+ z2 s' V" H * memory or the inode passed is %NULL./ n7 f, {: b* N! d/ h9 G, q
*/2 D; p/ {3 C+ v# H4 Z$ W

/ X! E: i* ?/ K+ ^+ z( ?1 Sstruct dentry * d_alloc_root(struct inode * root_inode)5 o# C! j% Q( E$ y  c7 B! {! W& U
{
3 ~0 H0 ~& t0 G+ b        struct dentry *res = NULL;
* g- s: ?  E7 w& u  o, W0 ^
/ v7 k+ v! {3 I% D. ?        if (root_inode) {' x5 S2 `' ]; K' r; {2 u
                static const struct qstr name = { .name = "/", .len = 1 };
2 e5 y3 U. @0 @1 d/ a5 h- F! u6 U0 |* x5 e
                res = d_alloc(NULL, &name);        /*分配struct dentry,没有父dentry*/
' l$ H4 f$ R" Y" V                if (res) {
- ?% }$ ]6 b5 B$ q" e: N/ i                        res->d_sb = root_inode->i_sb;* m+ |% R1 B  Q2 ]9 W& d2 y, Q
                        res->d_parent = res;       
) ^: g6 I2 Z7 y1 L/ t                        d_instantiated_instantiate(res, root_inode); /*绑定inode和dentry之间的关系*/0 n, U4 _8 ^/ `0 T
                }" c! @( z* G3 J% e5 s+ o
        }* j' O5 a; F! N. }; ?
        return res;% B! }! J* O5 h0 o$ e
}
- J* K4 p# W4 R; E; ^& a1 `( W
! t/ Z/ v* L) q) v/**+ C' m2 m0 J5 \" Z: G
* d_alloc    -    allocate a dcache entry. |& v; U" ?! ?/ t9 h; e
* @parent: parent of entry to allocate9 r2 ~5 y1 x& c8 j& O8 V
* @name: qstr of the name9 K% F# o* O/ E. \
*$ u  r9 ?, ]1 b# @* M+ `
* Allocates a dentry. It returns %NULL if there is insufficient memory
' I+ t: X' B" W * available. On a success the dentry is returned. The name passed in is+ D1 k# A% I8 s) R  a8 s
* copied and the copy passed in may be reused after this call.$ l! m/ X0 e' A
*/$ ]% J9 p5 u; Q, E0 a! Q

. N$ j% n3 j: qstruct dentry *d_alloc(struct dentry * parent, const struct qstr *name), s9 b) m4 c; A% a1 K* A4 w
{
% z, c3 W, p& }5 Z2 Y    struct dentry *dentry;
# E1 d" `3 i$ o: h& S6 _2 u; U    char *dname;
( e* X  O2 u- E9 P+ L$ o0 Y$ d' j8 k5 f4 y8 P9 i  B5 s+ O  A: [; ?
    dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL);/*分配struct dentry*/2 Q1 O& i; P8 D" r
    if (!dentry)) k5 N2 V. J" H2 _
        return NULL;
' u# b' [2 X1 U4 h/ S/ u$ u) M( ?
    if (name->len > DNAME_INLINE_LEN-1) {  l: y1 x' T; t
        dname = kmalloc(name->len + 1, GFP_KERNEL);
# P6 D5 s9 p% S3 y/ B! U        if (!dname) {
# K+ a* }0 n6 l$ M' L+ F' n            kmem_cache_free(dentry_cache, dentry);
7 D$ [, _; L9 t, k( O" f            return NULL;; z# z' x: i* a  m" T& `! c+ d
        }
4 k+ Q& _1 _) s    } else  {
! \  ]$ j/ G0 b' k; x8 @        dname = dentry->d_iname;- ~  s! _& v2 S1 y/ ?6 W6 k
    }   
- E! t1 [- E2 k) o; t, ~    dentry->d_name.name = dname;3 P$ [1 q- y5 O% i$ V

9 H3 w$ M  |7 P    dentry->d_name.len = name->len;" Q- h1 j- M$ K0 c0 |! t4 h4 M
    dentry->d_name.hash = name->hash;
4 [+ j5 m; d7 y& I4 L  w    memcpy(dname, name->name, name->len);0 K2 @1 l8 M6 g+ o: ?
    dname[name->len] = 0;  A! f2 \' Y- n; D$ g0 K* M8 o
% }  a& s# s% g
    atomic_set(&dentry->d_count, 1);
9 D4 k' U, q0 E4 B( H    dentry->d_flags = DCACHE_UNHASHED;
! a/ Z. l, {. x) A4 t" j0 O    spin_lock_init(&dentry->d_lock);! g8 i1 h8 V/ x- ?8 j" b
    dentry->d_inode = NULL;: W2 d  \/ M8 u
    dentry->d_parent = NULL;
" T* Y9 v$ I- ]    dentry->d_sb = NULL;* _7 w9 X  }$ H
    dentry->d_op = NULL;
/ k( g  Y( O+ V, Z2 X    dentry->d_fsdata = NULL;
. y/ V% v5 M, p( Q7 }. W    dentry->d_mounted = 0;( d! K- V# E& p2 x7 Q
    INIT_HLIST_NODE(&dentry->d_hash);
& G6 p* U5 `) e, j    INIT_LIST_HEAD(&dentry->d_lru);
, y2 A% P6 z& k$ B0 ~4 _" W    INIT_LIST_HEAD(&dentry->d_subdirs);
4 `( w* `& c% S& t; B    INIT_LIST_HEAD(&dentry->d_alias);# n+ u" @; o0 U" F- l

/ J. V+ J3 E* Z" ^    if (parent) {    /*有父目录,则设置指针来表示关系*/! \! C: @9 A% {
        dentry->d_parent = dget(parent);
; t% Z1 W$ n# {0 Y& X. G0 `        dentry->d_sb = parent->d_sb;  /*根dentry的父对象为自己*/
" f+ c! O' {% W$ B. d$ l! ]0 z    } else {
8 @7 C" m! p: P$ W6 ^        INIT_LIST_HEAD(&dentry->d_u.d_child);! E( r% d# P7 a
    }
; e. w4 U6 `% C4 D: w
$ o0 |0 ~9 \) `    spin_lock(&dcache_lock);
$ v$ c9 D& m3 J6 d( F    if (parent)        /*有父目录,则添加到父目录的儿子链表中*/
/ }" R+ @* P0 X4 R% H4 X        list_add(&dentry->d_u.d_child, &parent->d_subdirs);, H1 e9 e: e6 r
    dentry_stat.nr_dentry++;7 J" f9 Y; D. c2 }2 Z! _
    spin_unlock(&dcache_lock);
9 i1 I) ~$ Y/ ]6 \8 z+ b# a- u/ d7 u
% c2 }; |' \- W$ G    return dentry;
8 h. t4 c3 f; o6 C1 Q. w}
2 W& U" q/ f8 o3 j6 z7 A5 ^1 ~
2 ^* g' v$ X7 A; |+ \/**9 e$ m- a4 c. A$ d; U& M+ y' ^
* d_instantiate - fill in inode information for a dentry
% o' ?; B) z2 T, j$ n. \& v7 L * @entry: dentry to complete0 o, P& k, y& T( N2 s5 [! J
* @inode: inode to attach to this dentry& A( J  r- q2 L- W( U
*0 l$ x3 r6 w% Z( ?4 F1 E3 h
* Fill in inode information in the entry.* t0 K$ B4 y' J
*
+ Z6 J' o( U# C' ~# J. i: }3 a# R* g# ] * This turns negative dentries into productive full members
' O' b2 R: ?) Z/ i: B- Q * of society.3 p: I/ ^5 C4 f" `: ?8 u
*
0 M% o5 d( A' I" I * NOTE! This assumes that the inode count has been incremented9 k5 n1 o; v4 u
* (or otherwise set) by the caller to indicate that it is now7 k% y$ x. k) K' W/ y' e  p
* in use by the dcache.. ?! W; s$ i' Y
*/2 J" J# ~4 k" q

2 m% @! x, o& a1 [2 y6 Uvoid d_instantiate(struct dentry *entry, struct inode * inode)
5 e( R4 M8 U. A0 Q& \- t{
4 G- I( K) G3 w2 w- l& J# ~$ j) _    BUG_ON(!list_empty(&entry->d_alias));; S# S  a( Y( u* _  t; K* A
    spin_lock(&dcache_lock);4 v( Z' A  w5 X! g9 k2 J
    __d_instantiate(entry, inode);
3 @2 \9 n- p2 q3 L+ z    spin_unlock(&dcache_lock);" y% ~! v  a% ^/ i
    security_d_instantiate(entry, inode);& }& y7 ?) g* w( x1 J1 `; a
}# J3 \- Q* g- T; m& I8 f
* E  b# d4 W1 U$ U/ l5 J2 t
/* the caller must hold dcache_lock */
6 t' E4 o; ]. }" Cstatic void __d_instantiate(struct dentry *dentry, struct inode *inode)' g4 B5 W8 B9 I
{) \3 s5 y) ^6 b2 c
    if (inode)
- Z8 M* L/ s7 V+ d        list_add(&dentry->d_alias, &inode->i_dentry);/*将dentry添加到inode的链表中*/  k; E3 K3 ^9 v5 s8 H6 h
    dentry->d_inode = inode;        /*保存dentry对应的inode*/
; K9 v$ w- [9 Q. r    fsnotify_d_instantiate(dentry, inode);( w( \& N2 T9 }
}; ~$ w5 F& r; d( J: Z/ W

5 F& W5 g- A3 I- i3 ^/ P该函数首先调用了d_alloc来创建struct dentry,参数parent为NULL,既然是为根( / )建立dentry,自然没有父对象。
. r+ m, p8 K* N4 K* l接着调用d_instantiate来绑定inode和dentry之间的关系。- I6 ^, e* [1 Z# q& z7 K  @9 s
! y# ?0 u! M" A

& B5 u3 F; V' g& [在sysfs_fill_super函数执行的最后,将sysfs_root保存到了dentry->d_fsdata。
& s7 U2 I. c' @) `2 ~& t; l( M: ~* m/ _# T
可见,在sysfs中用sysfs_dirent来表示目录,但是对于VFS,还是要使用dentry来表示目录。
1 I, S- e5 i8 m
+ Z7 C4 D& x; T3 C8.2.3  do_remount_sb: }% n* ]2 H# U, u2 `
下列代码位于fs/super.c。
) V3 S( G- [( k. e; A/**9 T0 e5 w4 n1 `, B9 l
*        do_remount_sb - asks filesystem to change mount options.
* Y& ]" R5 H: _3 I2 P( P *        @sb:        superblock in question
9 {, J# B0 [( p- I  j *        @flags:        numeric part of options  f' P& X6 ?9 d( k5 }4 L5 n( N, I! M
*        @data:        the rest of options6 C* i7 f. S3 R+ n
*      @force: whether or not to force the change
2 X! t* C0 |/ r; ]4 \4 q0 p6 }& s *8 e) S- T" y3 j: B+ t' W
*        Alters the mount options of a mounted file system.! J. h3 D! ?6 i
*/+ @+ W. ~% g( Y9 ?9 O+ @9 {: L  Z6 Z
int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
* u7 j# l% s1 ?' e8 F{
- s4 ^/ t( g* i" q  k% x. K8 z. k        int retval;
6 o9 C" k) E' S" Q: ^4 Y9 o        int remount_rw;
8 J6 W: R8 \; b5 }        # T" Z% Q6 _; f! a4 l  b; g" a  }
#ifdef CONFIG_BLOCK3 g' Z  l) V( D) o
        if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
- _1 \/ Q8 g& d/ p                return -EACCES;
" B9 l& _8 t9 t; }( i. |#endif
0 Y" D+ X- ]! R' T/ |$ a        if (flags & MS_RDONLY)- [; C, E& J) e+ C% e
                acct_auto_close(sb);0 ]4 o- W$ {, O& P7 K
        shrink_dcache_sb(sb);/ R) X- Y, X  Y4 Q" u( @- f! {
        fsync_super(sb);6 a# w8 o3 A. b% f

; ~) i. D3 W% Z* g  U% v        /* If we are remounting RDONLY and current sb is read/write,. U/ x( n" ?, w+ j% o
           make sure there are no rw files opened */6 _; t- u2 |. t4 x
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {. c% D4 R8 p# D9 e: ?) O! J
                if (force)
, {8 W+ G9 G3 [( e. t                        mark_files_ro(sb);4 ]' j  H5 p1 m; f6 X! i( w- ~
                else if (!fs_may_remount_ro(sb))
6 f( z% j4 Z* v( ]) W9 c+ p                        return -EBUSY;1 A5 j% f/ w% C" X
                retval = vfs_dq_off(sb, 1);
: Z/ Z/ T. Z* [: b$ L/ {1 X. [                if (retval < 0 && retval != -ENOSYS)
" ]. {- n# _  H                        return -EBUSY;' I! D5 R0 O7 L# A, _5 }, L/ _* L
        }; h, y4 {* H8 r% V# \( x
        remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);* c5 ^. L: s; }
! ^" V0 e. n4 D7 V8 ~
        if (sb->s_op->remount_fs) {
( {$ h3 v; O  X& W& E2 ^                lock_super(sb);% h% o- N8 m( r" `# g% {' ^
                retval = sb->s_op->remount_fs(sb, &flags, data);) s$ N+ T4 c, q7 G, }; h
                unlock_super(sb);% g8 ^! f' g6 G/ I
                if (retval)
6 G' q5 m( }6 a* Q2 [                        return retval;, ]# w7 ]# i( O, x, u3 C* p) s
        }/ ^6 H" }4 H& i/ P2 p6 u
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);+ Q+ b* P) I9 T
        if (remount_rw)
  I1 B( |/ u5 ?2 T* f5 P                vfs_dq_quota_on_remount(sb);+ W1 Q4 n; V% y
        return 0;$ z8 q' L% ^1 ^: b
}
3 V' }+ I  R* O1 y: W0 s! R
  l4 a0 [0 W$ n! A% |$ Y/ V这个函数用来修改挂在选项,这个函数就不分析了,不是重点。
) m' {6 D) x7 h8.2.4simple_set_mnt5 @) @  k2 i5 v- {$ a1 Z. x
下列函数位于fs/namespace.c。
- A' {' l, n. N" W9 u$ [void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
6 f1 `+ G; b( Y{
( C- O! D: B# l& ?, c        mnt->mnt_sb = sb;+ c$ A1 \4 A0 K# I
        mnt->mnt_root = dget(sb->s_root);
0 T5 x5 C3 P" F8 {/ y}
& G  `5 I: }* z该函数设置了vfsmount的superblock和根dentry。! r- K1 n/ |  i- H; r* F3 R

1 e7 q: L6 s. p+ a8 a  N* J0 \% k8.2.5 小结
, {2 ^. O3 }$ l这里,对sysfs的注册过程做一个总结。
, N, u" E1 N8 ?% o: q' u. c
  ~$ o3 F$ H* e- }7 esysfs_init函数调用过程示意图如下:
8 w2 L( k$ H/ S, f3 n0 w  B" o* D3 Z  o# Q  z& r/ g' S! C
$ t/ Y8 V4 T; M9 s  s8 T

8 f) E7 I3 M1 J( x在整个过程中,先后使用和创建了许多struct
; H) l0 l. g6 g3 }; p8 }4 _# B; Z6 P' a
第一,根据file_system_type表示的sysfs文件系统的类型注册了sysfs。: T- Q+ h0 [1 ?* H

1 v! n) ^! `' ~3 ~3 c+ l1 }第二,建立了vfsmount。% @: k# \1 z5 t4 F' o4 }) u8 N) `' f/ I

4 i) ^) h2 R' q  S, [, M3 g第三,创建了超级块super_block。( _+ C. e4 _7 m* E% h7 [
6 X: q! Y* p4 r7 G/ h5 B- T- \
第四,根据sysfs_dirent表示的根目录,建立了inode。+ [6 A- i8 @4 Y  _& l  m
# n! A7 R8 K! ^. ]6 t2 S
最后,根据刚才建立的inode创建了dentry。
( e3 z% c& h; I  _4 k# C6 M+ W( j3 g( ]& ^6 c' c6 ]9 O) y
除了sysfs_dirent,其他5个结构体都是VFS中基本的数据结构,而sysfs_dirent则是特定于sysfs文件系统的数据结构。
& x0 N5 X3 Q! a+ l1 Z: O) n2 f. A' ~0 h2 \
8.3 创建目录
( }+ ]  |4 q$ H$ O  w- Y9 T- M2 D, Y! `在前面的描述中,使用sysfs_create_dir在sysfs下建立一个目录。我们来看下这个函数是如何来建立目录的。
* I5 m8 B5 F1 J) Y0 z7 e3 H$ @4 p' t& ]
下列代码位于fs/sysfs/dir.c。, U' A. |, h2 V' f$ x
/**" u9 ]  L7 t. V) G' s) o6 @6 E
*        sysfs_create_dir - create a directory for an object.
# N& K( G$ i1 G! y6 _) b *        @kobj:                object we're creating directory for.   x( W9 O4 _* o1 R7 w! }1 e
*/. M3 d! Y( M' n1 Y1 @+ L
int sysfs_create_dir(struct kobject * kobj), d, L5 W# x- M  G4 b) Y% r3 q- ~
{
# H# y7 D" t! m! o2 R8 g        struct sysfs_dirent *parent_sd, *sd;
# K7 T  O% R2 s0 g        int error = 0;+ l& K3 X: B5 F. W% x1 }8 A
/ K. u7 r: n/ Z3 J
        BUG_ON(!kobj);( A9 B, g4 z5 ]3 t- n9 `, K
. `, s6 S) @& n* }* x5 a
        if (kobj->parent)        /*如果有parent,获取parent对应的sys目录*/" k& w( q- {4 w0 |! Z. N! W
                parent_sd = kobj->parent->sd;! s1 a3 a, F6 S5 U6 L
        else                                /*没有则是在sys根目录*/
7 V; h0 p5 @: P  ]" C! A7 a( m$ G) X                parent_sd = &sysfs_root;
" T+ \$ X) Y- T/ u, R, P, t3 `, ?) S: A4 X; _0 @
        error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
. f% ]9 d1 C/ ]; r3 A3 Z  |& a        if (!error)1 a1 P, Q* s1 [! R  W! ^
                kobj->sd = sd;0 k  g" `! C; \" |
        return error;
  t4 d! d" |% [# {4 j5 x# J}
2 `& X' Y/ Y' s: {0 R( I1 P5 n. j2 M6 y( R1 Z* j1 h! g+ T% C$ {
函数中,首先获取待建目录的父sysfs_dirent,然后将它作为参数 来调用create_dir函数。6 h! j( e* `: I5 U7 I8 @! I) i
很明显,就是要在父sysfs_dirent下建立新的sysfs_dirent,新建立的sysfs_dirent将保存到参数sd中。
7 k; i/ {' [7 y6 J% i, ]& G! k2 ?' w7 b* N
下列代码位于fs/sysfs/dir.c。
0 }7 U5 \8 L3 a2 W" M+ rstatic int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
7 B" z  V8 `5 O& w5 M$ `# c% D2 N                      const char *name, struct sysfs_dirent **p_sd)
& W' r( U+ D6 ]{/ C( R/ i0 e; L; c7 b9 X
        umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
2 o1 _8 T6 u/ M. H, w! A        struct sysfs_addrm_cxt acxt;2 {3 Y4 D8 c2 T, \- b  W
        struct sysfs_dirent *sd;
) ^# Y5 m2 e* h$ W$ g        int rc;
& `: j1 |  \# O- T9 G
$ V0 ?5 m( b0 \7 a        /* allocate */        /*分配sysfs_dirent并初始化*/
: B/ A# Z, }1 x% x: T4 Z  `        sd = sysfs_new_dirent(name, mode, SYSFS_DIR);7 \: i8 K6 c/ y+ w" R
        if (!sd)2 a, T6 \# L. u3 r0 i) I7 u: }
                return -ENOMEM;; D3 ?( [) I$ a, p) o4 X0 Q
        sd->s_dir.kobj = kobj;         /*保存kobject对象*/& X$ ?/ f$ @! b/ M1 F7 r; h% @( I

$ y" R' I& R( y2 _        /* link in */
5 b6 {+ J2 ~4 f8 a) ~5 y7 X% G        sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/" f: ]* }0 f7 J
        rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则添加到父sysfs_dirent中*/
( I7 }4 \1 z% D3 X, ?6 u  x: B        sysfs_addrm_finish(&acxt);                /*收尾工作*/
: @$ O* U" R. ^4 C* g$ E  N4 n6 s* Y! O3 E# v9 P( e+ {( H0 D
        if (rc == 0)                /*rc为0表示创建成功*/) Y9 V/ @: C+ ?& M
                *p_sd = sd;
9 r7 L  x$ _6 ]5 j/ e1 D& m8 K  G7 l) k        else( G" L' G9 W, b8 K3 ]/ K8 k; ^: [
                sysfs_put(sd);        /*增加引用计数*/
/ F% W) c; x7 k0 p) o' w$ \# R8 q" J! o7 D' F, G" X; S" V
        return rc;
* H+ {0 W$ t( B! y; h4 f/ }}' F9 P% K9 H0 }6 M3 l4 u" O
这里要注意一下mode变量,改变了使用了宏定义SYSFS_DIR,这个就表示要创建的是一个目录。
0 p5 R1 T) J, E0 }" F1 j* |- b  `# o
mode还有几个宏定义可以使用,如下:* B/ Z& Y2 x: l$ X8 G
#define SYSFS_KOBJ_ATTR                        0x0002" s& w1 w3 D- t$ {* d
#define SYSFS_KOBJ_BIN_ATTR                0x00043 f9 y/ Z, [. d. l- N+ @- i) d
#define SYSFS_KOBJ_LINK                        0x0008  ^$ ?5 ?: e9 |. a; m
#define SYSFS_COPY_NAME                        (SYSFS_DIR | SYSFS_KOBJ_LINK)) N, h* r, P, K- l! u, N
8.3.1 sysfs_new_dirent , C, [/ t# z8 I0 w- L8 N: `- K2 P; K5 D/ V
  在create_dir函数中,首先调用了sysfs_new_dirent来建立一个新的sysfs_dirent结构体。
( I7 g9 Z2 d, l$ j3 I! S
. u' D2 r, G# B8 Y" J% `, e下列代码位于fs/sysfs/dir.c。% r1 `/ l* T3 f& ~1 j
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
# e9 M; {% g, v4 Y- r9 X9 c' e. h7 Y{
# f) R, R9 u% W: C& x5 c        char *dup_name = NULL;
; S* F! `, N  Z' s# t7 T# u        struct sysfs_dirent *sd;
4 _; Q) M0 r# C; J" E
3 u/ A! d9 L2 d8 d- L        if (type & SYSFS_COPY_NAME) {) ^7 L/ I) z2 r4 d' H: |/ O
                name = dup_name = kstrdup(name, GFP_KERNEL);
) B8 S9 E" p8 u) `, ]" o                if (!name)
! B7 K' s* [; g4 Z$ u% D' L: F                        return NULL;) z. w( r% k; k: l* y! {
        }) L7 e/ R. B! k/ V6 D- v4 x5 v+ L
        /*分配sysfs_dirent并清0*/
- J: h; O1 V* i$ q, f; x- s4 p        sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);# [4 I( m2 W# f: I8 Y1 Y2 ?# T2 j5 Z
        if (!sd): [$ }9 z7 Y5 b1 W6 b" s
                goto err_out1;
) m# A5 h2 v( E, `
; x: u& c3 }0 o7 w9 t        if (sysfs_alloc_ino(&sd->s_ino))        /*分配ID号*/
- Y% {+ _: u; K                goto err_out2;
( ^( u' `+ v$ F# o8 D4 ]' l& p  t
% G6 W1 d5 @+ u( t4 j. Y5 i5 j# x        atomic_set(&sd->s_count, 1);/ ^8 [9 \' B/ @+ V7 b0 x& R
        atomic_set(&sd->s_active, 0);! U" @# D+ u8 q0 ?

) M2 L7 [5 u$ ]  t7 V2 |5 C& k        sd->s_name = name;
6 P* a7 S: [) l+ \, E        sd->s_mode = mode;
8 U: S) X0 _! y5 o0 @, p% n' W4 Z        sd->s_flags = type;# o  C4 G4 @( |( ~( c

( D7 c  _8 m+ s9 d1 i  Q6 H* J        return sd;
: `4 ?1 w( n3 h0 U1 ]: v( D6 r$ w
  U# a3 _6 ?/ F/ ?" V err_out2:
& L" d. V  A3 Y4 ?3 w8 u0 z        kmem_cache_free(sysfs_dir_cachep, sd);, v" V, C% z- @" _# b$ @" f3 H
err_out1:4 J1 f6 t; @) \+ z4 A
        kfree(dup_name);. U2 z' d+ r: Y. }" ^
        return NULL;
8 w1 G. j; K( M3 M, G}
* B( i# ?/ _& P: C& y! X# [# J( J( b8.3.2 有关sysfs_dirent中的联合体2 y8 S, x  o4 B7 O) S* A
分配了sysfs_dirent后,设置了该结构中的联合体数据。先来看下联合体中的四个数据结构。
: T4 x5 `8 w9 n6 Z
# N; K& f# A" `/* type-specific structures for sysfs_dirent->s_* union members */4 Z# o/ y9 z4 ^+ |5 ^
struct sysfs_elem_dir {
/ o& I6 o6 _; }  v& w& G        struct kobject                *kobj;- f. ]0 n6 ^+ v0 s% m! L
        /* children list starts here and goes through sd->s_sibling */
0 w; q. M9 w( Z        struct sysfs_dirent        *children;
% B! O. e' X% j% [};
7 G, Q, j# n  n: ?# T6 B# }5 a- N3 N
struct sysfs_elem_symlink {
: g# \& {) i1 f" F- I    struct sysfs_dirent    *target_sd;1 [; ]" D* E3 y
};
6 V9 a! |8 f7 b  e3 d, c* r& ^, j: p0 @& n3 r  _
struct sysfs_elem_attr {
! t: ]$ Q( G8 w1 ~  V    struct attribute    *attr;' w3 N& L: w! J  ]( g0 o# m, f
    struct sysfs_open_dirent *open;$ O& V7 m- Z6 D' k8 Q
};
1 @, ?8 w6 |3 d& p; I. P! O
& O& K+ q7 ?2 C- S3 Wstruct sysfs_elem_bin_attr {( }/ a: h/ C* I- ^
    struct bin_attribute    *bin_attr;
$ o5 Q5 T- j' o: m    struct hlist_head    buffers;
) m& J& g' K2 E9 \% `% |+ w/ s& D# i};
; c# p- w5 o! J  {3 k  |2 W1 A; O根据sysfs_dirent所代表的类型不同,也就是目录,synlink,属性文件和bin文件,将分别使用该联合体中相应的struct。% ~) i) m9 S$ H& y( g
在本例中要创建的是目录,自然使用sysfs_elem_dir结构体,然后保存了kobject对象。
$ T  e% R# c2 n* E% ]  I9 f, Q- t- a+ V! ]# e+ j! X
在8.4和8.5中我们将分别看到sysfs_elem_attr和sysfs_elem_symlink的使用。" b6 ~1 I! Y/ ?
6 g% W; ]3 I6 R/ P; a# r( k4 i
8.3.3 sysfs_addrm_start: N5 o/ |1 f2 ~3 D, U* W
在获取了父sysfs_dirent,调用sysfs_addrm_start来获取与之对应的inode。
) g; D; c5 B8 p1 y9 h
4 H7 [7 B" g, K! B% }- j; u" F下列代码位于fs/sysfs/dir.c。
6 H5 c, l" L' }, X  R- w/**+ s, D; v0 L. P0 B9 \
*        sysfs_addrm_start - prepare for sysfs_dirent add/remove! u4 r$ {; |+ }% |
*        @acxt: pointer to sysfs_addrm_cxt to be used
, E. \5 F& d. f* j$ H# Z+ m, N *        @parent_sd: parent sysfs_dirent
% \, _1 c$ Y% \9 U$ p *' X0 e$ u* ^6 j6 g2 K
*        This function is called when the caller is about to add or, d- {% Q4 _8 j( T# h3 H
*        remove sysfs_dirent under @parent_sd.  This function acquires
2 g1 |% o; ~9 z; O' C *        sysfs_mutex, grabs inode for @parent_sd if available and lock
* {$ a3 Q6 m3 W% L *        i_mutex of it.  @acxt is used to keep and pass context to
: [# K3 b8 `/ Y! s *        other addrm functions.9 q9 n- F3 L  y8 u+ w' T* C. \0 p% Z
*9 R4 D) _& f8 `0 V4 w
*        LOCKING:# q$ k7 I6 s- ^* R3 [3 B
*        Kernel thread context (may sleep).  sysfs_mutex is locked on7 b" Y( J$ v6 F2 D
*        return.  i_mutex of parent inode is locked on return if% q8 z9 V& x9 P2 Z9 v
*        available.. f  y/ T# w+ l; f4 U2 C' r
*/; S! a! [& Q, w& N. ^
void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,; V2 _$ R9 p, P1 y8 k
                       struct sysfs_dirent *parent_sd)" m" l2 t- V9 X. P" r0 r. t3 ?, ~/ D
{
3 H2 I; m$ F- U: b( ^0 \8 s; W        struct inode *inode;
, L3 T3 a6 I; |$ D+ s: ^0 _: L
8 x6 g0 `9 @. ^        memset(acxt, 0, sizeof(*acxt));
* N4 a/ x8 R# p        acxt->parent_sd = parent_sd;
# E+ n1 l. r) W( `8 @5 K, r( P( I% `5 _3 w+ W& z# ^
        /* Lookup parent inode.  inode initialization is protected by
+ @% N  F4 P( M( R4 }' e  V         * sysfs_mutex, so inode existence can be determined by
! Y$ U8 M0 @4 U9 @1 P! p5 x$ y         * looking up inode while holding sysfs_mutex.
% ]" e/ X, X. U' Z# Z/ ?! a         */$ v+ }% G& u$ z! i
        mutex_lock(&sysfs_mutex);" T$ J" I/ }! N  c" ?5 F  B4 ~
        /*根据parent_sd来寻找父inode*/0 ^9 H. n7 C2 \% v0 [9 ]
        inode = ilookup5(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,% F" G6 c; h8 i* a
                         parent_sd);
$ q- K% |  r4 F- v- ]. f        if (inode) {) [0 V4 z$ A5 y  n4 W5 o( B
                WARN_ON(inode->i_state & I_NEW);
) O5 O! ~8 @3 {' G# d8 b) t3 B+ E( d! x$ h! W# m) c
                /* parent inode available */1 r* S" N, k, v/ ~- Y  v1 R$ G
                acxt->parent_inode = inode;                /*保存找到的父inode*/  c& D# z& K. H

! g: o' B3 h8 J4 X6 S6 a                /* sysfs_mutex is below i_mutex in lock hierarchy.
3 i; `1 @) E, ~- `) v! z                 * First, trylock i_mutex.  If fails, unlock. F4 A% O8 A) H; `9 ^0 f0 I
                 * sysfs_mutex and lock them in order.# v4 i6 q$ f, t# X8 d
                 */
) S3 g* \" C- Y& w; @                if (!mutex_trylock(&inode->i_mutex)) {
3 s2 |$ F: m4 @8 v* t                        mutex_unlock(&sysfs_mutex);
5 A: I8 f) z; j& ~. _% V$ l& [$ v                        mutex_lock(&inode->i_mutex);% l; V8 T3 i" y: k# L
                        mutex_lock(&sysfs_mutex);
9 Q* n5 g( o! e8 S                }4 n( w$ G' P$ m# K# r( m9 \: _$ n5 x
        }
* W: |- o4 @! A/ s, C9 T3 @}
, Z. S3 j0 k; {, G4 `/ K
( n: f, K* [" f3 f* O6 G" G) x% x4 ]/*
4 f+ i/ j% b" k* f. t1 {, } * Context structure to be used while adding/removing nodes.
! E. m& ]2 T7 C" l# W: I */8 w3 \/ i& c  ^, i
struct sysfs_addrm_cxt {
* t! _. W; r7 G, t    struct sysfs_dirent    *parent_sd;5 g: e. y0 c* a' Z/ \
    struct inode        *parent_inode;# e- h' X  q$ S
    struct sysfs_dirent    *removed;  A# a6 x" ^. J* D  n
    int            cnt;
) n' ^( X, }/ u9 e# B9 n' E};
' C, S: L& f) Q注意形参sysfs_addrm_cxt,该结构作用是临时存放数据。' s" J# a; a  u0 p5 a
8.3.4 sysfs_add_one
: Q0 ^4 i1 Q! N" _2 e  x/ @7 |下列代码位于fs/sysfs/dir.c。7 K1 I2 Z) G$ C* [( [% K1 n/ D6 U& F, ?' {
/**3 p8 J6 c7 Z5 @7 J5 a
*        sysfs_add_one - add sysfs_dirent to parent$ G* ], [! e0 i
*        @acxt: addrm context to use! F" @1 k( H9 z* i
*        @sd: sysfs_dirent to be added, J& y  t. \) o0 ?$ \; w
*) z/ ^- U! s) G/ j7 q
*        Get @acxt->parent_sd and set sd->s_parent to it and increment7 \, J1 q4 f. _
*        nlink of parent inode if @sd is a directory and link into the& x% Y) ]. F, k  |* V' h$ c
*        children list of the parent.
& C! X) B+ f# k( Q1 k *( h5 Q3 b$ y1 D+ ~% `, n1 ?
*        This function should be called between calls to, F/ |3 J% f# \4 E, }3 p& Z1 k6 x
*        sysfs_addrm_start() and sysfs_addrm_finish() and should be
6 X. E! K& Y! Y" A  L *        passed the same @acxt as passed to sysfs_addrm_start().
1 Q7 N" `# Y1 u *# o" `7 Z3 _7 j0 y2 Y# Z
*        LOCKING:2 y. a- X. e8 d
*        Determined by sysfs_addrm_start().
+ t, }" T" L; g# j5 x *
( J8 n  ^6 H/ Q- C5 S3 | *        RETURNS:
  @, A9 ^, ~6 K9 F2 t *        0 on success, -EEXIST if entry with the given name already
7 l( A5 ]3 n& ?2 }. A8 V *        exists.
# I2 c/ \7 A# K; ?$ Y5 q. e */  W2 i6 k( _4 V4 \9 u+ c
int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
/ b$ j5 }. P0 X8 K- F3 _8 y2 f+ s{9 }) Z7 K- ^- n9 f/ ~% i
        int ret;
! W& D. w/ a: z6 q
1 q4 i4 \* q* F        ret = __sysfs_add_one(acxt, sd);) D: u- I4 H7 t7 h& J$ N5 q
        if (ret == -EEXIST) {
7 H. ]7 L; ~. }# P                char *path = kzalloc(PATH_MAX, GFP_KERNEL);
, {7 |5 j& c' y8 b: Y                WARN(1, KERN_WARNING# E& T  f' T- g. w* f  P% H' v& r
                     "sysfs: cannot create duplicate filename '%s'\n",
3 P9 z/ C" q, P+ t7 x( ^! s                     (path == NULL) ? sd->s_name :' I/ q' P- e- |5 |$ x, X7 M4 v
                     strcat(strcat(sysfs_pathname(acxt->parent_sd, path), "/")," d5 l8 U  L) n* d3 P& @
                            sd->s_name));6 p7 N# v- K3 G8 i/ M) S
                kfree(path);
# i& d# w" n0 s; F% n0 Z$ ?  X1 p        }
9 C! u, s- H2 K* ]5 i
4 M/ q2 w) `% t) X. }; v  E: O        return ret;
. L2 q+ H$ ?$ v. n; u7 e+ g}
8 F' @0 W  S" n$ t5 H/ t6 i' r0 J9 f/ G; r8 e# g: ^# `! g9 Y
/**
6 ~! c* o1 b8 L5 A1 K" s *    __sysfs_add_one - add sysfs_dirent to parent without warning$ v; ~" D9 P( w* K3 `0 z' Y$ S4 `
*    @acxt: addrm context to use
0 Q% E1 J1 \9 e! k1 o7 E6 A% |( S *    @sd: sysfs_dirent to be added4 Y' |4 }; ?; {+ R( t6 g" l
*1 r; s! S5 F' X4 `) f
*    Get @acxt->parent_sd and set sd->s_parent to it and increment
7 J' I3 g* M$ ] *    nlink of parent inode if @sd is a directory and link into the4 a$ u- ]$ G  ]9 F( [( z( {
*    children list of the parent.$ j# k0 ^1 ~' J. _
*# F$ d4 W+ L, E8 B+ r' }4 x& d5 e' O
*    This function should be called between calls to% E* L: E: z1 h1 y$ c9 T+ q
*    sysfs_addrm_start() and sysfs_addrm_finish() and should be, `8 s4 R' A! J! @4 U' p4 I8 E0 A! @+ o
*    passed the same @acxt as passed to sysfs_addrm_start().
- e0 ^$ T: V  g! z' v *
8 m' F/ X/ b4 v9 h* u *    LOCKING:5 J0 y$ k% N  [) j/ B
*    Determined by sysfs_addrm_start().
1 E. K7 X' Y! T2 G& I *9 P# b2 f9 j# d9 e6 r
*    RETURNS:
% X: Z9 B; U: ^% q' T- R *    0 on success, -EEXIST if entry with the given name already
2 Y3 H; _. P, r0 R *    exists.( n1 ]( Y7 A" h; p  @
*/- C8 u0 M0 ~7 {! Q) u2 @0 f; f
int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
! Y, m$ ^1 A& T/ b{
  {' j! H" N% c2 J/ B% O1 P0 p5 |    /*查找该parent_sd下有无将要建立的sd,没有返回NULL*/
: G' s7 x) Y! a/ o! ?1 n! f# v$ P: |    if (sysfs_find_dirent(acxt->parent_sd, sd->s_name))
' O6 F" x) N' z- ~0 Y6 v9 {        return -EEXIST;
) F/ o& U) n9 e* `8 n6 Q( U7 \1 H2 P& i3 S- _  z1 E3 z0 V
    sd->s_parent = sysfs_get(acxt->parent_sd);    /*设置父sysfs_dirent,增加父sysfs_dirent的引用计数*/
: A( |0 A! P" c- H8 s& S. p
$ E+ R4 n2 [' I3 [    if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)    /*如果要创建的是目录或文件,并且有父inode*/
: }( `- ^# A0 `) G        inc_nlink(acxt->parent_inode);    /*inode->i_nlink加1*/
+ T) [; o/ i( f- T
/ H4 j; @8 K. t  q    acxt->cnt++;& y, g. c. t7 _& O
& K5 C/ l5 w' P4 p+ N! b
    sysfs_link_sibling(sd);- ~2 J7 C1 Y* G, y- t

9 j# @  b5 g; r    return 0;
9 b& p- ]' S! j' l9 V7 f1 ]3 ?}
  X, z- |+ J4 q6 v, }* @0 Y
6 @; T( s% V% C/**
& O% \( k4 b6 i *    sysfs_find_dirent - find sysfs_dirent with the given name
) {! m  z+ E) {% L9 y+ f *    @parent_sd: sysfs_dirent to search under
& u9 g, `( L% Q' V4 F *    @name: name to look for! a8 K- Q+ d5 Y
*
3 S5 a+ ^+ U/ s, R2 [. l, ]. f *    Look for sysfs_dirent with name @name under @parent_sd.+ J; N6 h9 _7 w/ `6 D" E0 W
*
5 Y; W: u& K4 a" w( f *    LOCKING:
* O) a3 f' a  m2 y/ r *    mutex_lock(sysfs_mutex)( K5 h9 S. \( P( K6 R# j
*
; {! Z; K3 C# I+ Z3 o# _ *    RETURNS:. x- _3 x$ l. s7 Q
*    Pointer to sysfs_dirent if found, NULL if not.# J6 \, V% R; s% f* Q( j
*/: F! s: T  R6 d) M3 N
struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
2 _5 B1 H7 g( y" f9 Z. h3 f                       const unsigned char *name)
( |2 u, h6 ^7 r5 T/ M  w{* n0 F! t. n7 |! _7 [6 Z6 H- [; \
    struct sysfs_dirent *sd;
' W" Y! o6 c! W# L
6 q# `  }2 \: e/ h; S, b* e    for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
$ v2 y: g; J, c& D        if (!strcmp(sd->s_name, name))- V$ P4 c: j- [- \" {; G
            return sd;- l0 N* X/ s8 e6 z0 R" g
    return NULL;
; I7 J  @3 z4 S6 @# j} * V3 Z, [  X$ P0 ~: l! u
2 V. z: \) Y  t  s, i
/**8 x: L0 f# B4 {; E
*    sysfs_link_sibling - link sysfs_dirent into sibling list
+ y% B- X5 H+ q" X2 [ *    @sd: sysfs_dirent of interest! j' O: r: \1 A
*
' G5 h4 o) k+ F4 V! s2 s0 G *    Link @sd into its sibling list which starts from  Y! i7 c8 C+ V, o3 `4 e/ \2 U
*    sd->s_parent->s_dir.children.
2 v9 E3 x1 S% x, D' ?, ~! l *9 A4 b* \( z# l6 b' ?
*    Locking:3 u. ~- p8 {; [' e
*    mutex_lock(sysfs_mutex)3 V  B. B; C) {  D
*/  E$ ~7 i( T- w  Z/ a" i
static void sysfs_link_sibling(struct sysfs_dirent *sd)7 C7 g5 q7 M+ m+ A5 r5 }* y
{6 F, j0 x" g: P* v" S9 A
    struct sysfs_dirent *parent_sd = sd->s_parent;, M: }$ @2 _1 q/ ]/ Q: U
    struct sysfs_dirent **pos;
8 f! j+ S8 j2 H- S% x5 u5 j
, f( j$ a, L5 ~5 x, J1 v    BUG_ON(sd->s_sibling);! p% V1 b# Z+ T
- b- R# ~9 x# p8 c
    /* Store directory entries in order by ino.  This allows
$ e. c$ b$ g+ j: E+ t. ~, s     * readdir to properly restart without having to add a
3 |7 x0 o0 Q7 ?( I     * cursor into the s_dir.children list.; @& q) r3 r0 s. Y, p$ O! T
     */3 h% y0 {% M! V
     /*children链表根据s_ino按升序排列,现在将sd插入到正确的儿子链表中*/( J# |* N; c6 e) y6 t  x2 v
    for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {5 c% l! w* n  d8 Y( k  q4 a, z
        if (sd->s_ino < (*pos)->s_ino)# B: c6 i+ S; k7 j
            break;3 f( ~8 ?% `2 R/ x& H
    }/ m8 m( W7 v7 }0 I6 L
    /*插入链表*/
  I9 ~" l9 a$ |2 ^- ~+ l    sd->s_sibling = *pos;
2 f9 A! e' e' B& R8 L$ F    *pos = sd;
& u$ S7 x! B3 R7 m5 f}; V/ x* Q' E- q
该函数直接调用了__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链表中。9 v, h5 e) W7 Z' s; z
8.3.5 sysfs_addrm_finish; l# h, _  b  b6 ^
下列代码位于fs/sysfs/dir.c。
, _0 d$ K8 K3 Q# P" N* X
& B+ v+ H( G/ y1 b8 ]9 C* u/**
0 G* T2 E- M- H* P, S0 E# C *        sysfs_addrm_finish - finish up sysfs_dirent add/remove# b3 n# P7 t' W' W1 D& g$ z- d
*        @acxt: addrm context to finish up% K$ T8 n/ U; g; S. |! f- _, O
*
+ X, Q+ ?+ x3 ^( G7 i) i4 x *        Finish up sysfs_dirent add/remove.  Resources acquired by
1 k% b$ ~0 K- i! |- a *        sysfs_addrm_start() are released and removed sysfs_dirents are5 ^, a  L8 q$ w) i
*        cleaned up.  Timestamps on the parent inode are updated.+ w. U' q7 i+ ?# p8 W  N
*
9 d9 _  j. I- |% [" c *        LOCKING:
" F8 O7 L9 @3 I5 [  f; A% V *        All mutexes acquired by sysfs_addrm_start() are released.. R; {+ O' X5 g# ?7 {) h
*/. x9 E" ^7 A) L1 A5 X8 w. Y. r
void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
6 {0 o1 e- [' R{
, L* b6 F7 a6 Z8 q2 ?) @* @        /* release resources acquired by sysfs_addrm_start() */9 f' a% S$ n* d8 B# n) @6 z! o
        mutex_unlock(&sysfs_mutex);
- t5 S& \) J; _* s7 r" O- S0 u; n        if (acxt->parent_inode) {
# p) P2 X& p# v8 E; i' d1 w                struct inode *inode = acxt->parent_inode;+ ^, k0 d4 k$ Y2 H$ j& D. i8 j- u
, ~/ T0 u/ D" O
                /* if added/removed, update timestamps on the parent */2 E+ Y3 P, w! a9 F, J, M
                if (acxt->cnt)' l4 Z6 G% Z5 o
                        inode->i_ctime = inode->i_mtime = CURRENT_TIME;/*更新父inode的时间*/
/ ], Z# H9 c0 X6 _% u7 [- K  m  U0 p  X- m- P! C7 [) i
                mutex_unlock(&inode->i_mutex);' _% K2 t2 Z- P8 b, P5 Z1 `
                iput(inode);
+ V/ x# E# Y  f3 s        }
2 N) c; F8 D& \5 W6 q  L! H5 k: w& t/ A+ b/ p; }0 z  ~
        /* kill removed sysfs_dirents */
# z* R9 J  s+ V. O  e        while (acxt->removed) {
2 a0 d! [" f" W& c  t                struct sysfs_dirent *sd = acxt->removed;& M; x* ^/ [  M1 D* L

$ k$ p9 Y6 V9 Y0 h4 l7 i( b0 g                acxt->removed = sd->s_sibling;; q( \7 n8 Y& N
                sd->s_sibling = NULL;5 _$ V% S! R3 G# m% e6 e* n& Q
+ K* V. {! O5 i6 H3 q4 {( ?
                sysfs_drop_dentry(sd);1 S) z* ^7 Z& Q; N) u: G
                sysfs_deactivate(sd);
1 m" V" I3 o; S9 }7 s- G                unmap_bin_file(sd);
/ }2 @. `0 Y( K& N# [2 }                sysfs_put(sd);3 F$ t- u9 J- Y# N3 B+ p7 J2 ?" _6 m
        }; e) [: l8 p2 T7 U3 X; m5 |, a
}! N4 |& Y' i& s, Y0 c6 c/ S1 Z' j
  E# ~. e9 M( s! e' d8 z; h" T& D
该函数结束了添加sysfs_dirent的工作,这个就不多做说明了。3 }* v. b9 b) ^* O/ U+ J

+ \$ v1 v8 \! t9 t/ h) U3 r至此,添加一个目录的工作已经完成了,添加目录的工作其实就是创建了一个新的sysfs_dirent,并把它添加到父sysfs_dirent中。" u) y- w: W5 U; p8 B$ s- P

$ G- l8 A9 ?  Q0 \. N下面我们看下如何添加属性文件。! R3 b  H% A& w* d' \- I
8.4 创建属性文件
( t" _  O! j' m1 s添加属性文件使用sysfs_create_file函数。
! h0 D' \0 B8 ^: J" w  w6 Y6 k( K8 q2 t9 l9 |# B0 \) G
下列函数位于fs/sysfs/file.c。
' H" n7 \! v0 t' U1 x$ ^  R/**+ `, I+ d0 s0 y3 D( H+ ^! O6 }# q
*        sysfs_create_file - create an attribute file for an object.$ F+ o2 Q. Y' H: ]7 E" O
*        @kobj:        object we're creating for.
5 u% {/ K! g$ n* ~% V *        @attr:        attribute descriptor.( ]% Q/ v0 f; y0 G4 B9 ?6 @$ ^% h, r
*/2 l( w0 a2 S, Q% a7 S" K" C/ I( h7 N- s% D
. [( `* ]! @- |( ?/ I5 I, b
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
4 e% ?  R3 |4 I, x& `+ ~/ n6 z- D{1 s/ g: l- g3 Z" r
        BUG_ON(!kobj || !kobj->sd || !attr);
+ f4 {& }& `4 a% {1 q
7 R. A# X$ j. m: F, K9 ?        return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);* y" h( Y6 Y% X

/ L# @# |: {) d- Q. }: G4 ^' D}
) J) W+ t% |' `6 s/ e; H: ~7 m4 }* T5 `
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
( }9 j4 D- m) k! \( t& j' C           int type)
: x* C& j8 C0 Y* |  }' [4 T{- {" X) B/ X. d0 e* `
    return sysfs_add_file_mode(dir_sd, attr, type, attr->mode);' d7 a# H# S' B4 V- K. d- p
}
6 Y% y; X4 l* k' L, |0 }
% `+ a5 ?- T& F' x! ~4 ^; @int sysfs_add_file_mode(struct sysfs_dirent *dir_sd,
7 B2 T1 R$ Q5 B; \' ^            const struct attribute *attr, int type, mode_t amode)
" x$ n8 D8 P% b/ g{7 X+ O% P" ~. C* p; H, w
    umode_t mode = (amode & S_IALLUGO) | S_IFREG;
& G3 M! `  B* D) F! U# b6 b6 z7 ?    struct sysfs_addrm_cxt acxt;
3 e( {( W: ^3 C7 a3 F" c    struct sysfs_dirent *sd;. E% ^, N. _1 }  G8 y  k
    int rc;
+ S9 V0 {& X  t% }- Y- j5 N4 k    /*分配sysfs_dirent并初始化*/2 X- _. p# N: L
    sd = sysfs_new_dirent(attr->name, mode, type);
" F; \. B5 e! [* t  y, Z    if (!sd)
5 n/ U# ~' I2 \        return -ENOMEM;
, B+ X$ D3 @( K# x, {& d0 A    sd->s_attr.attr = (void *)attr;" @& @5 `; d! S' ?9 i" F
0 B$ ^6 I% N  l! o) p9 [
    sysfs_addrm_start(&acxt, dir_sd);    /*寻找父sysfs_dirent对应的inode*/
, f' @, [" G  E4 U% ~    rc = sysfs_add_one(&acxt, sd);        /*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/
2 D0 p+ z$ v8 d) n    sysfs_addrm_finish(&acxt);            /*收尾工作*/' H* O" c6 B3 D/ i- q3 L4 w2 p

' S/ O8 ]% R6 q4 h6 f    if (rc)            /*0表示创建成功*/ - ?  O  a4 x- Q6 v
        sysfs_put(sd);
: i4 f7 M) N5 `1 _1 G; f0 y7 C5 p0 Y. U- N8 G# s& m
    return rc;8 H! B- d5 X' i& a$ V" z
}# }, k/ N) e$ g

  L5 ^' }0 ~- d' y! g. Esysfs_create_file用参数SYSFS_KOBJ_ATTR(表示建立属性文件)来调用了sysfs_add_file,后者又直接调用了sysfs_add_file_mode。
3 ]  y( D5 ]; A# k) h( isysfs_add_file_mode函数的执行和8.3节的create_dir函数非常类似,只不过它并没有保存kobject对象,也就是说该sysfs_dirent并没有一个对应的kobject对象。$ w0 x+ K" `5 y5 }3 |  E

7 Q- T2 A. z4 m  [2 b, i/ m需要注意的是,这里是建立属性文件,因此使用了联合体中的结构体s_attr。
6 v1 M  b8 H; s, f5 Y' D8.5 创建symlink8 G- E9 [' }( R- Z" R% Y* @
最后,来看下symlink的建立。9 M% j, _" V3 M8 k; Q+ U
/**3 z# V" r4 q7 [$ h$ ^- k9 z
*        sysfs_create_link - create symlink between two objects.* d# U; E8 |7 G4 w4 [/ c; T4 u' B
*        @kobj:        object whose directory we're creating the link in.1 W" ?) k: ?+ D9 e5 X
*        @target:        object we're pointing to.. D  e' r  ^7 u+ s0 i
*        @name:                name of the symlink.& B: }8 @" l* C6 h( n0 N) H, r
*/
9 a7 P, a, V1 B: O- o5 Pint sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ y) z& a5 F* j" y0 v5 s( R3 w                      const char *name)( Q- `8 p7 B4 _6 a# d
{" H, p7 b. }, S' Q7 f
        return sysfs_do_create_link(kobj, target, name, 1);# V1 w. A) \" y7 \5 V9 `6 f
}
' W3 B' y- }& d* a2 l
2 P3 M! z3 K2 vstatic int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,' Q: D3 `+ ]6 y- a% m* _) H
                const char *name, int warn)
1 R# T6 f& E) j; B6 n{. S5 r, N1 {1 {5 i
    struct sysfs_dirent *parent_sd = NULL;
; j' v6 T. Z- P4 R; k" r    struct sysfs_dirent *target_sd = NULL;/ A) O6 \( ~4 s; j$ c
    struct sysfs_dirent *sd = NULL;& D  H) U" P9 D4 G/ z3 \2 A
    struct sysfs_addrm_cxt acxt;
: w- O" h$ y4 K    int error;; X' y  R- k  m$ ~9 M
$ w7 s. {& h5 V4 m9 |3 a
    BUG_ON(!name);
$ G/ D/ n: \8 N7 A
; k- |# g( E9 e    if (!kobj)    /*kobj为空,表示在sysyfs跟目录下建立symlink*/$ U+ W% F6 _: c" ~3 {) q5 g
        parent_sd = &sysfs_root;
4 ]; y' C) m8 [" T" P    else        /*有父sysfs_dirent*/9 _: p& z: [" f: h0 l7 G
        parent_sd = kobj->sd;4 S0 v1 G, ~* E1 m$ s  C4 ?
0 Z- s/ h3 t/ ]$ g6 f
    error = -EFAULT;, J9 L3 G- i7 W1 x- b$ t' h$ K7 |
    if (!parent_sd)
- {* f) E6 p2 r$ f        goto out_put;
+ D' c2 l' V8 S" S# c. R$ s0 h( |2 P& @) R. F
    /* target->sd can go away beneath us but is protected with4 w3 s! v% [$ T- e  I+ [% e. h
     * sysfs_assoc_lock.  Fetch target_sd from it.
. |4 J+ w1 Z- Z& `! j. F! D# _7 F$ h     */
! L" }+ @6 J' I7 i    spin_lock(&sysfs_assoc_lock);7 y) s$ B" z- g% K4 S: b
    if (target->sd)  y0 g* j+ y( Q: i
        target_sd = sysfs_get(target->sd);    、/*获取目标对象的sysfs_dirent*// a1 d, I7 y" {
    spin_unlock(&sysfs_assoc_lock);
2 t+ K1 e3 }/ C$ Y3 A2 c( F$ b$ d; Z7 P2 x, `# }
    error = -ENOENT;) v0 @( q, ^* P- T' i* ^+ n" f! f
    if (!target_sd)
4 j$ v8 x* L& [/ J1 s( |        goto out_put;
4 B& q; c' U+ z2 L/ t
& P1 S5 a' @7 z5 C. ^$ A" N2 m    error = -ENOMEM;/ a4 |3 a  H) [8 b- U2 q: o
    /*分配sysfs_dirent并初始化*/, b. e2 p4 X0 A6 L
    sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);' f2 k: T& f& `: U: |5 v6 w" H
    if (!sd)
9 v; Y2 d' ^  u0 Z5 @7 a        goto out_put;
5 p, ]( _) E8 |7 x
2 i: R9 Q% N' g) |8 N$ x    sd->s_symlink.target_sd = target_sd;/*保存目标sysfs_dirent*/
$ Y: j& X, }+ z8 m  ^5 C    target_sd = NULL;    /* reference is now owned by the symlink */
4 t8 i( H2 |, T( u1 x$ z$ m) a
! _+ \2 W2 d- u' l  l    sysfs_addrm_start(&acxt, parent_sd);/*寻找父sysfs_dirent对应的inode*/* ]" u6 r6 C' o' B3 M8 y
    if (warn)
4 @" G4 [5 _: Q" Q8 E+ G3 w7 ~$ |& J        error = sysfs_add_one(&acxt, sd);/*检查父sysfs_dirent下是否已有有该sysfs_dirent,没有则创建*/1 T9 P3 s: L" i
    else- c' Q9 g3 b6 N! K
        error = __sysfs_add_one(&acxt, sd);
/ W2 F& I$ E" _# l1 O! W7 o2 Y    sysfs_addrm_finish(&acxt);            /*收尾工作*/; I9 N- A7 D" X- k2 _3 `8 D

4 _5 c: Y0 D  n" q9 H0 z7 C6 L* [. L    if (error)7 R' `0 s' x- W& u: c! B7 A
        goto out_put;6 H; G6 ~" ^2 a" L1 ^# ~

5 I2 S& g3 W) Y    return 0;
! p% l( F+ _9 v6 M8 {5 L- G  w8 @2 a1 M" Z: m5 @. `
out_put:
, O9 X7 e, F& S& Q0 a    sysfs_put(target_sd);# E/ I& W) {, o1 N; [9 k3 K
    sysfs_put(sd);( ~+ n. o' ~) |  @
    return error;
% O2 i: q' i' `* F, |}* @' b- ]  `+ O, Z

2 j+ U+ V: S0 Q& w  o" v1 o" X这个函数的执行也和8.3节的create_dir函数非常类似。其次,symlink同样没有对应的kobject对象。
+ _1 ?" A( b# m* {- N$ _& I因为sysfs_dirent表示的是symlink,这里使用了联合体中的s_symlink。同时设置了s_symlink.target_sd指向的目标sysfs_dirent为参数targed_sd。
" j/ x4 d" O" |" Z( E0 B1 j8 _3 P3 d" ~' G* X+ U
8.6 小结: y! U& h) g  d5 S
本节首先对syfs这一特殊的文件系统的注册过程进行了分析。接着对目录,属性文件和symlink的建立进行了分析。这三者的建立过程基本一致,但是目录9 Z( j: `2 }/ t$ I

+ F7 X1 q6 t6 K/ }有kobject对象,而剩余两个没有。其次,这三者的每个sysfs_dirent中,都使用了自己的联合体数据。+ }- x* a4 q9 E! f0 y& A
) |$ }/ }9 i* E. _" d9 r% Q$ L
9 总结; y+ `3 f3 @; O; y5 U/ o( G
本文首先对sysfs的核心数据kobject,kset等数据结构做出了分析,正是通过它们才能向用户空间呈现出设备驱动模型。) @4 n9 e  g3 g6 v! B8 K* g
  E8 ^* A- t! q7 L# |
接着,以/sys/bus目录的建立为例,来说明如何通过kobject和kset来建立该bus目录。" K- \3 C/ `# v! W: u$ Z+ {

# Q: t1 O' ^1 F0 H* @; ?随后,介绍了驱动模型中表示总线,设备和驱动的三个数据结构。
9 o8 E) h, c6 ~) ^: o0 P. \8 s% ]8 @. _: l
然后,介绍了platform总线(bus/platform)的注册,再介绍了虚拟的platform设备(devices/platform)的添加过程。9 B! J" F: {2 _. M: C1 p" n
* I  c" j# [! u4 y0 ?: _& s& k
之后 ,以spi主控制器的platform设备为例,介绍了该platform设备和相应的驱动的注册过程。
2 p7 N  v& p2 q4 j# [/ g
. {% q4 v& x% N% Y最后,介绍了底层sysfs文件系统的注册过程和如何建立目录,属性文件和symlink的过程。0 x" Q" m: L8 U8 k

; ?7 B& g; l- \3 Q
+ p7 x/ q1 U1 |: A
作者: CCxiaom    时间: 2020-6-17 17:22
设备驱动模型和sysfs文件系统解读




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2