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
) 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
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
# 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; [
' 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
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, ]
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. \
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
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