|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
4 O" u) w: B7 B7 L5 O, T
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。2 @/ }4 v/ `$ e2 t% u1 u/ e
1 J6 e/ {$ d% Y9 I4 \! O总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。4 X2 h# e" a9 z& @+ T4 y& ^
$ e" b9 \; U5 N; B/ z) L0 S
Linux2.6系统中定义了一个bus_type的实例platform_bus_type1 c0 [2 Y& ~ e" V
$ W+ U' o9 L2 V2 q- kstruct bus_type platform_bus_type = {9 N v4 L% {% s( c9 f4 F) C
.name = "platform",& E4 d4 Q4 W( x
.dev_attrs = platform_dev_attrs,
$ D4 \- X2 S3 t$ P7 f .match = platform_match, //设备和驱动使用match函数来判断是否匹配
4 n. X9 b2 w2 u! f( Y( R+ N. i .uevent = platform_uevent,& _6 U. b) z, o/ m# J( g
.pm = PLATFORM_PM_OPS_PTR,3 |6 q1 w; k3 i4 ?8 Z% A
};% |. l( M B% l4 p1 [
/* platform_match函数用于匹配总线中的驱动和设备 */$ L. j- J0 N& l, }/ [& @! L% ]) R! U
static int platform_match(struct device *dev, struct device_driver *drv)# c. V( G" ^) c+ l, Z
{
8 a5 S( G! ]+ V: I struct platform_device *pdev = to_platform_device(dev);
1 Z' q! r* Q9 m/ ?, d struct platform_driver *pdrv = to_platform_driver(drv);
& ?! ]- P, L7 a4 d. f
. o; t/ n- A) v: Y+ r& w /* match against the id table first */
, n2 ^ I* i! s if (pdrv->id_table). k4 [" ~7 d, j! j7 f
return platform_match_id(pdrv->id_table, pdev) != NULL;
8 d5 q- `# h$ x" f# N( |% E * y& l. p4 D* C( a
/* fall-back to driver name match */
' F; l& g6 @: f g- m* H return (strcmp(pdev->name, drv->name) == 0);1 c" N2 D7 L3 { I. ~7 ]5 }/ l- [
}: b- L4 V3 D! I" f4 U& S
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。& I7 R: c* ~8 E- n; f
platform_device结构体的定义
& t7 c9 w w( y# Z% f5 c7 J. g; T1 M# T; _8 o4 C2 H: u( J4 A* r
& i( U6 H) @ s+ E7 u4 y
struct platform_device {
# l. X& f" Y3 e8 z$ L- U1 _2 f$ H* D const char * name; /* 名字 */
5 R# z5 j* h& f5 H; _7 Q# K- R# Q int id;9 W: F9 P$ a8 N z' ]
struct device dev;
) W; E; R+ U5 C3 i u32 num_resources; /* 资源总数 */9 _* V/ v0 A8 Z
struct resource * resource; /* 资源 */
) U) t5 W) u' L
; z# z0 X K% X# u struct platform_device_id *id_entry;% @9 m& n+ Y/ T2 z
};
: h+ T& q$ m/ f1 G( u其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
) i( s9 S1 L! N8 L) {* u' d3 { F" j1 M9 }3 Z6 f J
struct resource {
4 Z! a2 b* }, H! y5 } resource_size_t start; //资源的起始值6 w# s7 B0 y' @% }- {9 t# d/ Y! c
resource_size_t end; //资源的结束值: R( g. F6 c( h- P; Z
const char *name;
9 i" G' f4 W0 w; W4 q unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
S: b$ B4 X9 S' ]% B7 G/ k struct resource *parent, *sibling, *child;2 H2 p2 C; B. X4 t6 r, I& v! K
};4 \* `' N( }& a. `/ P! s' R
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源- V) I/ T! A9 b6 n0 {3 x
1 G5 S7 o0 w& x! ?. S. ^/ b1 c" O! \, n- [& r( S7 v
/**
6 s: ]8 d) b1 ]; k: {' i2 S * platform_get_resource - get a resource for a device l) K: x0 G/ ?! @
* @dev: platform device
, F4 l8 m4 P3 D; q# j* W6 w6 Q1 b * @type: resource type7 k9 {# n, ?, G. O9 i. _1 X
* @num: resource index9 g. ]. K4 Y# S6 T
*/) `2 I: v6 Z$ c. N$ K! [
struct resource *platform_get_resource(struct platform_device *dev,) B7 v" X o, L( K! P
unsigned int type, unsigned int num)2 q" w4 x" u( s/ {! u
{+ _: N; S- L. e
int i;4 ]/ A( `/ }0 K- ^
) L+ C: N; G, A5 a for (i = 0; i < dev->num_resources; i++) {% k/ E) K M0 H# ]
struct resource *r = &dev->resource;1 n; v# F1 l* {& l. n) I
8 V! R. [4 s! u1 X9 M if (type == resource_type(r) && num-- == 0)8 u; |% n! k& v/ q( f" T
return r;* i# i7 I2 S/ J
}+ r0 ^5 s7 r" C0 p7 P) h
return NULL;( l& _/ e+ Z0 S A# B
}7 P2 x0 v8 l" P* C) p2 T5 r& K3 o
平台设备的注册,使用platform_device_register函数: f& ?6 P2 }& r# I7 u
- v$ i3 i% l( y6 i! q5 @! W- _' y
int platform_device_register(struct platform_device *pdev)7 m8 {+ U5 N9 I% m2 W- |3 \
{
& T1 M) p5 C) k+ u device_initialize(&pdev->dev);
, a, |$ a. P, ?9 l u6 n* ? return platform_device_add(pdev);
. i7 y/ M' ?( G}7 q/ X( L& _7 `, a5 {9 e9 h) X& |
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。, f# o) V# l R& I
( H# a; `) E% o1 d n0 C
1 R- F4 _/ M5 }3 B3 |, [+ v Y
int platform_device_add(struct platform_device *pdev)
% ^5 _# {4 x. h8 {: T{, a* ^( n. Z% p, [8 W; J& ]0 z
int i, ret = 0;6 e8 w9 _5 L2 w/ R( z2 N1 i
6 s$ K* {: s, R5 V) U( A
if (!pdev) /* 如果pdev为空则返回EINVAL */% h/ y9 i$ c2 c! |
return -EINVAL;8 f+ p3 O! f! F* N, Y
4 U4 J. _4 r9 `9 {
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */! I; y2 ?9 z2 Z
if (!pdev->dev.parent)
( G1 h3 G' N2 K. ` pdev->dev.parent = &platform_bus;
; R$ f5 k2 o5 |/ v# v6 B2 q: } : v$ D. L0 H8 t# Z# q9 w
pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
# R5 D7 e9 u* f : `7 T. X* y! Q4 p" H5 g
if (pdev->id != -1) /* 如果id = -1则表示自动分配name */
& N$ g9 C. S$ J" V% q dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
3 ]& Y; b# |; t* | else* C$ \( A" j6 A& E( u7 V) p1 d$ d
dev_set_name(&pdev->dev, pdev->name);
u, p' S' j+ E$ {" D* c
8 ]8 r9 @/ l. K4 M+ X# U% I for (i = 0; i < pdev->num_resources; i++) {' H" J1 F l; S G% u% \" d% L; n
struct resource *p, *r = &pdev->resource; /* 获取资源 */6 C; d' d& ^9 R; i) t5 u0 ~) G
! S+ B7 g6 A6 @- E if (r->name == NULL)0 b; t7 Q+ ]" d0 C8 N* H/ V
r->name = dev_name(&pdev->dev);
& w* R: i% i. B3 D [* k' l
! o, E, v8 k" l! v p = r->parent;
* M3 E3 H D3 L if (!p) {* T# ? H/ B+ A
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */( v! c/ @ C6 h7 c% p
p = &iomem_resource;+ T, E! I1 e1 K( @
else if (resource_type(r) == IORESOURCE_IO)
- {% s9 M8 a0 z6 l' [0 ?# z p = &ioport_resource;" }0 U) z& q0 P9 f0 w' r7 D) u
}
+ B4 Q# l5 n2 W& Y% n " R* k1 a3 O6 b, Y& V6 J* ^% b
if (p && insert_resource(p, r)) {
. Z% j- w2 h8 I9 x2 z0 c printk(KERN_ERR2 F1 l& O& `" ~, [+ t8 m1 P' d- R
"%s: failed to claim resource %d\n",& C4 j" a f* ^2 w* t
dev_name(&pdev->dev), i);6 P$ O* e/ f' ?# a
ret = -EBUSY;3 a$ Y/ O+ ?: R3 e i. R- S
goto failed;
& F' P! h! k) r1 d$ `1 Z }
. b6 i/ U' X6 _) m7 ]$ P" Z3 x4 V2 l }
8 I/ r, _3 H9 Z2 B! X0 \ , v7 K# B- k0 N: [# f- B
pr_debug("Registering platform device '%s'. Parent at %s\n",' D/ r- J3 W Q, C" M; l: j' l
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
+ m; Q9 ?6 C9 V: B5 j3 Y) S' D0 _
1 S6 w7 u# I2 Z5 m/ w- a7 p /* 向内核添加一个device */0 t w3 P# _1 A' Z$ M
ret = device_add(&pdev->dev);
& P* A0 I8 h) ?2 B5 v if (ret == 0)! P+ E) d; e$ Z- w" B$ k _1 _" l
return ret;- t8 x$ [! F& e u
3 C, K y: f% f2 ?6 r6 d/ i! I
failed:, T5 ]4 y. W3 w8 }* p5 g
while (--i >= 0) {+ z: C) O* ?) T( n9 p: v
struct resource *r = &pdev->resource;
j# v+ [5 [( x' o. ? unsigned long type = resource_type(r);( i, k+ X% U3 x+ b
0 z# p! O. o7 d2 d
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)) s2 u+ U5 H; S! C a5 @2 P9 K
release_resource(r);9 D( a& ?6 b5 \' }' D$ @# M
}2 u7 O9 \2 t' ]
& q5 v- R2 j4 G$ V/ o, u5 P return ret;
3 u! y L, C) P0 I! @; H}
7 M* q$ T5 @4 n/ U( Q; D$ T$ Yplatform_device_add最终调用device_add来完成平台设备的注册。
3 @/ d3 h+ l# P2 k7 v3 d
+ A3 }4 N* K j, x) f- b4 j- F( O4 w$ v9 z" J& f- Q' \/ W
D) T# o \5 q 相反地,如果要注销平台设备则使用platform_device_unregister函数7 O- O6 E8 X; [& K* O4 E% |9 x
o& o$ y( E# n: J$ j( P+ h
void platform_device_unregister(struct platform_device *pdev)
* L# q$ u0 T: @, |& t: h{
. {, H9 ^8 z R% L platform_device_del(pdev); _* X) Q4 k! t J3 o4 k6 N2 j
platform_device_put(pdev);
8 T! p X( h8 [}
" H% E8 n f( J2 lplatform_device_unregister函数调用platform_device_del函数来注销平台设备0 F5 V7 @* Z+ z( r$ L* G
% z5 M/ D) |' |! G' t q
void platform_device_del(struct platform_device *pdev)
+ X7 ?/ x. f' Q3 l{3 Y3 \' G7 }0 k* a
int i;: b" z5 h+ E p8 r
+ E0 V0 ^: T- r9 r" ?- v4 w
if (pdev) {. [' o+ \3 K& F
device_del(&pdev->dev);6 \, L4 ?. D, @* l
, }- J7 ^& W5 _* P/ E
for (i = 0; i < pdev->num_resources; i++) {
. O* C) _9 ~; X! z+ D& F) R/ R9 ~ o struct resource *r = &pdev->resource;6 v2 }) e$ j* i9 e# ?* t
unsigned long type = resource_type(r);
$ |7 b8 ]% C# `7 R9 t7 K' R
2 _0 q5 G( X+ ~9 |( g if (type == IORESOURCE_MEM || type == IORESOURCE_IO). e- m# X1 q2 n. V! @! n
release_resource(r);' g% J5 j+ t# R. Y. I' o. t- I+ y
}
. d, N, [2 M, q8 ~+ |! a }
$ B" X- } s0 r. t6 ?3 h9 u- T}
& W8 H+ `% x4 \4 V0 E5 M& u. g" D. `platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO8 P. w3 I ?$ }# A( v
; z7 y0 K k8 @- gplatform_driver的定义:
; f% e/ E' M J. W1 l
5 `7 n! r0 `- u0 I- D, _struct platform_driver {
) [1 l) Z# V4 M E8 s( ~& ] int (*probe)(struct platform_device *);( D/ C* T4 w2 P. c2 @. K8 n
int (*remove)(struct platform_device *);
9 ^/ g" u: D. T1 W8 k void (*shutdown)(struct platform_device *);
. _- N5 D1 B1 [/ [ int (*suspend)(struct platform_device *, pm_message_t state);
! }/ h4 b9 n1 _8 K int (*resume)(struct platform_device *);
# Z+ ?4 o/ L" w, } struct device_driver driver;
G2 Z3 \& E( N0 t. ~ const struct platform_device_id *id_table;
6 u6 Z4 U* z0 Y5 S};
% ?% q6 m. U. @/ q( \7 \
" L- \6 U$ w: ~" |/ s( K! s
q4 V: r" A* W9 o- @% kdevice_driver的定义:9 E+ i1 H0 \! q4 I: o/ c; ]' O- z
struct device_driver {; H7 B7 `( a! ] p3 x
const char *name;) V6 V |8 c8 p N5 M
struct bus_type *bus;
5 B k- X8 h3 h" l% w& f 7 r& L0 z6 \; B5 B& q
struct module *owner;
' s9 O% K2 ?& [8 n1 y: k const char *mod_name; /* used for built-in modules */
2 X2 b8 b4 T/ D& u# y
& Z# [9 t* _0 ?% m bool suppress_bind_attrs; /* disables bind/unbind via sysfs */2 Q; u) C- A' W
3 @; Z9 g k1 Y* G6 |, w, P2 I5 r2 H
const struct of_device_id *of_match_table;
9 w' i# T; Y( [* v8 Z) a( { const struct acpi_device_id *acpi_match_table;# ?. r7 |7 t$ r+ z
7 K# m, G5 K% U1 A9 C, X2 p7 t int (*probe) (struct device *dev);
3 V3 u' |3 `9 |, ^% l int (*remove) (struct device *dev);
9 H+ n( X% G8 R% {( n+ b void (*shutdown) (struct device *dev);
: r+ r4 {- Q; v% e int (*suspend) (struct device *dev, pm_message_t state);& O" `) `; \1 {7 B: |
int (*resume) (struct device *dev);4 R7 ^" r7 s3 o
const struct attribute_group **groups;! W) j$ Y: u0 X2 o1 _ ?8 ^# l1 Y
8 R( @1 R" f8 l; Y- G8 y
const struct dev_pm_ops *pm;
; O) ^! a1 t: b5 l0 s- g" ^# c
( `$ Q6 F( _9 A" R& ]3 d- Y3 i' n struct driver_private *p;
* q# c3 D) p5 h+ U! o};
' ~& S5 [, z0 R$ V$ }! r6 h \, @; w5 S1 f
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。. k+ Z( r, M: W1 ~" Y7 S' ]
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
; ]0 H: n+ V" Y# ~4 _) d, o* ]7 b% l! c
4 P, u. C- k) x0 i( ^ }struct platform_device_id {
1 w( E0 R+ J6 D q' B: Z3 h: x char name[PLATFORM_NAME_SIZE];) A, p0 p5 y. g4 ?
kernel_ulong_t driver_data
5 p' e9 E& p3 q. G __attribute__((aligned(sizeof(kernel_ulong_t))));; F6 p% P/ s+ a( t- B+ d3 K
};
4 W$ h6 I/ v' z, Q, [平台驱动的注册使用platform_driver_register函数
7 W* b1 X, K& I$ X5 F. L% V+ x
! T" o0 M; B3 `. t7 M2 Z) o( Dint platform_driver_register(struct platform_driver *drv)$ W3 M' P4 I# y& G1 v k
{
4 J2 K) j- @9 i7 |: U( m drv->driver.bus = &platform_bus_type;
3 M* Q3 R I+ y( L1 s& K6 E if (drv->probe)& q0 H1 z* m6 Z
drv->driver.probe = platform_drv_probe;2 y( a8 l( ~1 j. _) P! k- @+ W
if (drv->remove)
1 }" j5 T: G5 R2 O7 c drv->driver.remove = platform_drv_remove;4 `. J- z- B5 I" `1 ^) K: Z3 m
if (drv->shutdown) s. L- {8 O! u" {1 }4 ` ?
drv->driver.shutdown = platform_drv_shutdown;
* @2 f/ g3 }5 @4 }4 x' k if (drv->suspend)
7 d) ^& J+ }2 W3 g n: Y drv->driver.suspend = platform_drv_suspend;
) e- I$ y7 O1 H% Y if (drv->resume)9 d. I% t2 l& H9 G( O4 t2 x
drv->driver.resume = platform_drv_resume;
?3 @1 Y5 B" s$ ?2 T return driver_register(&drv->driver);! O8 s/ u) d; c8 z9 d/ l* m: U1 r
}
6 b/ X E4 E3 E9 J" c' Q( K先初始化platform_driver里的driver,该driver的类型为device_driver,设置driver的bus为platform_bus_type;设置driver的probe为platform_drv_probe;设置driver的remove为platform_drv_remove;设置driver的shutdown为platform_drv_shutdown;设置driver的suspend为platform_drv_suspend;设置driver的resume为platform_drv_resume,最后调用driver_register函数来注册平台驱动。, e1 }& j0 q2 i6 B* O v5 G
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
+ d0 w7 f. S! O) E; u9 {
6 O5 {* q7 k* X- u) f7 D9 kvoid platform_driver_unregister(struct platform_driver *drv)* a& E5 i! B( A y, [/ s
{
9 l; j" o- h% l# k& s driver_unregister(&drv->driver);
% g& Z5 K5 w3 k9 d3 L5 ~}# O# f3 d+ ]$ u; j! Q- ^
, q m* f$ D/ E" A6 X附bus_drv_dev模型的框架图
/ q, d1 B/ [7 B4 v. _) a" |2 I' z" l
5 d0 g, M8 S/ C4 Q) v( d# v/ s
0 V, }+ U- u! O, u3 e$ ~& g6 h; g$ p$ A; l
) g4 {' ~+ w$ S% F- S2 c
1 j" O- O6 D1 X/ @: o4 O g" |" K" t. z
) B, x8 ~" Z( Y3 Q0 G6 Z
|
|