|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
$ F2 n ~* _9 G0 V; h
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
4 T4 \- ^7 Y1 I: a# |" }% L6 a' k7 U1 `1 V* }, ]
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。/ V; X' z' `( _- U
- ?! f7 q4 I4 zLinux2.6系统中定义了一个bus_type的实例platform_bus_type" l! q2 v8 }& {. P: u
9 s% u# d0 n+ J8 z) ^struct bus_type platform_bus_type = {
$ \! y( }7 h' @% I2 K .name = "platform",5 F) M" Q$ Q" @9 C4 W! l' a
.dev_attrs = platform_dev_attrs,
: C) G2 i7 |6 R .match = platform_match, //设备和驱动使用match函数来判断是否匹配
7 X! k( \' n: f! a. D$ C .uevent = platform_uevent,
) I# e6 K( a/ C! Z7 B2 n .pm = PLATFORM_PM_OPS_PTR,
& |+ A6 P! E6 M$ m( n};
% A+ k9 V' h) g. n- I. r/* platform_match函数用于匹配总线中的驱动和设备 */: Y R a# y' @% x c. S: v4 B
static int platform_match(struct device *dev, struct device_driver *drv)% a2 Z& P( z9 W/ `
{
# S# M( H5 t Z struct platform_device *pdev = to_platform_device(dev);9 c$ {) V, s/ ]+ a& o- f
struct platform_driver *pdrv = to_platform_driver(drv);
6 |: X7 F) X7 @" i1 Q
$ [4 c7 g* Q& u9 T /* match against the id table first */* o5 ^$ l+ \$ i4 M6 U
if (pdrv->id_table)
( S1 }% V# J- a, B3 } return platform_match_id(pdrv->id_table, pdev) != NULL;
2 _& V' B( E( d$ c" z. b
( N% s& b# |; f; g /* fall-back to driver name match */
# D8 w. m1 c* {- A! I return (strcmp(pdev->name, drv->name) == 0);! @9 U6 s( g5 A$ d
}' s( F4 u; S! M4 e# } i0 c$ [
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。0 |$ t6 F6 m$ [) b
platform_device结构体的定义$ G% I& G0 k- v% e
7 }9 ^1 t! A" H# ~ K5 k/ c
9 z4 y8 C8 y/ w7 u, T. U% l1 n3 u; jstruct platform_device {
! a* z [; q! i" a: @, e0 } const char * name; /* 名字 */. t! ~: p& r2 [8 l. Z' e2 R
int id;0 U. X5 T9 R9 k4 ~3 u ~, C
struct device dev;8 W7 K0 U" Q- h9 c) T
u32 num_resources; /* 资源总数 */' K9 ]7 }5 A; L' c, e! Z
struct resource * resource; /* 资源 */
. F. {. N4 Q+ f% V4 Y
3 h. U/ y/ i( r* K+ T; V( X* ~ struct platform_device_id *id_entry;
3 B) _, U) m* |) S3 T J};
$ h/ d8 [0 F9 P4 E0 \: u- _+ z其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
" F4 a) b& I. b' z$ x8 h2 E/ ?! F" v6 [) |0 w) T
struct resource {
2 b- k: n, Q( [# P9 I) ~, q resource_size_t start; //资源的起始值
$ T# i e/ I% k) o& w$ u- V resource_size_t end; //资源的结束值! w9 r# D7 s7 c9 }: i0 k
const char *name;% S% v! }/ E! G: H# V
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
) P' T- A$ R; L5 q+ s struct resource *parent, *sibling, *child;6 B3 V* U; ]* q3 f8 Q! s$ q& P
};( `: R3 K! j P. h* W" F$ I& u8 |
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
2 M% D: |: E# m4 S4 K% l R; D" n) X0 v& h+ Z. x+ L: J% Z y
( M( I) R4 c r7 X0 T2 E% D
/**- |# d4 G" c7 Q# _/ z7 I
* platform_get_resource - get a resource for a device' f, Z& [- c- {9 V$ H
* @dev: platform device
6 L0 V5 r' G: ^+ m+ D( ^ * @type: resource type- [* ^8 n5 x! i9 t4 T
* @num: resource index( M( p& D, G8 w, W& o% n( o& Y ?
*/
* x' ~& V; }% u' q$ z7 f( Estruct resource *platform_get_resource(struct platform_device *dev,
; U! ~. y1 G0 X) { unsigned int type, unsigned int num)
, Z W! l$ z T' p4 E! s{
2 o- w0 x* P, Y3 d! J int i;1 ^" y; c! q! m& l9 d d( i9 _$ c
5 h: p# }' k9 N& u3 {4 D/ J for (i = 0; i < dev->num_resources; i++) {
) N4 G3 U7 v4 ]* L* K- l, I, o: I struct resource *r = &dev->resource;( O" o' J- F* z, A2 {9 |) J7 A( a
& G- U N4 a& t6 p
if (type == resource_type(r) && num-- == 0)
6 B; d8 K1 ]" P# ]3 U$ g return r;
; }' [1 z" I; n V }
( g9 g8 w, B6 L. `1 N/ y w return NULL;
. L/ Y" e) ?6 p& n( T7 N}9 Q3 D& ?0 l) a4 g" h
平台设备的注册,使用platform_device_register函数& o- T$ N% \% i0 B- c# i
. n! X- A Q) J4 S& p4 O) f& Oint platform_device_register(struct platform_device *pdev)8 u, N( r5 k7 Q; w! n
{; W- Z A) C1 C/ K- ]; q) \* |- r b. `
device_initialize(&pdev->dev);
; n8 E, U1 f$ R4 r* z6 o& {; T return platform_device_add(pdev);
j1 `, }/ P" H' [# X E}
4 D! V1 W2 A7 V' X2 ^% ~platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
T: K" W y! c& Z( ^+ w& J( p$ }& y# [ V( s6 W: |
. H, b7 _+ O2 l5 y- Zint platform_device_add(struct platform_device *pdev)! J, T1 w: f ?, C$ C4 G
{9 a8 \( p5 X- k# G# m6 ?; a0 F
int i, ret = 0;
9 {$ l* ~ l( G' j! T- s Y' t4 a7 k S
/ Y4 I* K+ P, z. M$ _5 C$ A0 d if (!pdev) /* 如果pdev为空则返回EINVAL */
1 W1 e$ F7 N7 L7 B0 N, R' b+ G1 C return -EINVAL;
% F8 c7 B3 \1 N# M . O! w! A9 S+ `* b9 u
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */# G! G8 A. m- @/ M
if (!pdev->dev.parent)
8 D; ^5 }! U7 L) m9 U; A; \1 r% f pdev->dev.parent = &platform_bus;
4 K" O. n! I% m- ]0 o8 A
+ Q& D J! P# o* _ pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
) q& N9 G: Z Q8 T& X & F) p e, @7 }9 x: `, M1 O: y6 f
if (pdev->id != -1) /* 如果id = -1则表示自动分配name */$ t8 z! t" I6 U: ^# c, D7 n
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);) Y' T: ~: X6 d
else$ ?; R( X1 o* G. Q7 j) O
dev_set_name(&pdev->dev, pdev->name);
4 i! d) Q! E' y: p - d7 b* C' a6 G% i: ?5 s
for (i = 0; i < pdev->num_resources; i++) {' ]* h! I+ p! |( u8 V# R% U
struct resource *p, *r = &pdev->resource; /* 获取资源 */" N0 ^, p8 D, S$ M: k! @5 K1 Y
( t" C. H. e3 O, V( V
if (r->name == NULL)- k0 g1 _1 {& a, o
r->name = dev_name(&pdev->dev);" j: v' S8 U( Q4 w
) b3 k1 s6 G+ \& q R# I& p* X p = r->parent;& f& t- r8 {/ T& ~" j" t9 X
if (!p) {& F( o- Q4 ?6 C1 V6 I
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */) v& D* q" J( l9 E; a7 n
p = &iomem_resource;
' |1 I. D* J9 R0 \% F: R+ W% c else if (resource_type(r) == IORESOURCE_IO)
4 N1 l0 ]; X3 a; ?# W p = &ioport_resource;- u4 C/ ]8 O$ N, ^7 w! F$ e1 ?
}' f; k) K, D! y f2 V' w
. h" u; ^* B% e if (p && insert_resource(p, r)) {
/ X D( z2 x! q4 g6 s, G( r; s+ c printk(KERN_ERR+ @6 S4 s5 v# h( h$ Q3 j% i- |
"%s: failed to claim resource %d\n",
& G9 C5 ?+ y) R6 p" Q( L dev_name(&pdev->dev), i);
! L' }4 H5 X% L# L( M5 r ret = -EBUSY;6 t ^7 h- m- e, Z* S! H2 L& N; X
goto failed;7 b( M/ `$ h3 L* I: v4 t
}3 C" i- X* S) M0 [5 e; v6 n
}, k2 {- V$ i( B& y6 W. K
; V7 |0 o. u( v* L( ~# q. L4 {
pr_debug("Registering platform device '%s'. Parent at %s\n",
* M: ]0 b" G/ h dev_name(&pdev->dev), dev_name(pdev->dev.parent));
* E$ @7 y3 G4 n; O- k6 z4 Y! { $ q3 d9 s& d* M: K
/* 向内核添加一个device */
& H6 g9 a$ t4 u$ d( O9 ^8 [ ret = device_add(&pdev->dev);/ e$ G0 h/ P8 ]( f. i
if (ret == 0)% O O% ^( r: Y3 F4 [& m
return ret;6 S& D g3 N: L- [' F( q
/ u; l* T; y7 d# S8 v failed:& e$ V( s5 z4 h+ t/ O
while (--i >= 0) {6 m& ~# Q/ E3 @
struct resource *r = &pdev->resource;
, ]6 a8 S, ^+ ?5 y* v unsigned long type = resource_type(r);
2 M0 h1 l6 u- x# l; ~% ?7 e2 m
0 C6 I' B5 \2 ]9 {" o2 h if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
! \/ L2 g! A( z release_resource(r);5 a" j0 h- D; F' U$ |
}
5 s2 k9 K" c2 k! e
A( d& M. |0 n/ G return ret;. `3 y( _% f! @' i8 I
}0 X7 O& Y( E( F3 X* L
platform_device_add最终调用device_add来完成平台设备的注册。
, N5 @0 n6 f Q4 I i* U1 x$ a) T. a3 ]) H! p ^) r
% M5 a, ~- y3 Y# @3 E
& k7 S3 \3 l; i( r
相反地,如果要注销平台设备则使用platform_device_unregister函数
0 V' P& e, f8 f, P: }4 O$ g9 p6 |, H6 h. T, Y4 J
void platform_device_unregister(struct platform_device *pdev)
) m) [* W- N* k! o3 R! n: N{% Y- x6 c% ?& V/ M; C
platform_device_del(pdev);; m& C+ h6 I" ^( M% `( A8 i$ N
platform_device_put(pdev);; R+ a( J* Y( o1 W9 `0 a
}8 A- T j# Q5 M3 h S
platform_device_unregister函数调用platform_device_del函数来注销平台设备' r- X3 I9 f5 _6 @
3 {% p% }& ^* S% W/ r7 Mvoid platform_device_del(struct platform_device *pdev). l4 O( w: |( j, O
{
" ]3 T' `" z4 m. a int i;" R2 L% D& h+ q; j% D& f+ U# c
: l: J/ i: p+ h$ X* p) x if (pdev) {
3 Y4 Z6 y- O/ H- [9 E% W& { device_del(&pdev->dev);# d) D# y. [* |# J2 `) w# }5 T4 C
' Z; p( U* g7 @4 ? for (i = 0; i < pdev->num_resources; i++) {
# e- q, ^& u F struct resource *r = &pdev->resource;+ }6 D, `3 q# o( k
unsigned long type = resource_type(r);8 N5 E6 {: ?$ n* Y8 w4 b
) M! o/ ^+ k6 O+ f4 ?3 n. H/ m
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
, r/ T0 q4 x6 J! c release_resource(r);
9 i9 [) y5 O+ T) M }
2 R0 n& {- ?8 q5 G6 a" S4 N }
) w w5 P: K6 z}
. v7 B; {$ u. _platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO& o, F. G' T; h# U5 v/ H1 z
5 ?. R# h ?8 z1 Fplatform_driver的定义:' Q% G9 n$ F4 a
* \7 E4 ?2 I/ ]9 bstruct platform_driver {6 }0 O# s' w' A% s8 [# c# h+ r, f
int (*probe)(struct platform_device *);
/ X- \$ h S+ h! S# ^8 c8 l int (*remove)(struct platform_device *);, X+ _- l# u5 S) y* T2 B! O
void (*shutdown)(struct platform_device *);
7 \" S) V2 X. J' R# K" S* A, |% b int (*suspend)(struct platform_device *, pm_message_t state);% W1 Y. G) \; s! r* o0 O( |
int (*resume)(struct platform_device *);- T1 `4 N/ O7 d1 S2 `, g
struct device_driver driver;
+ c+ H; F8 Q& q& E$ C2 j! X const struct platform_device_id *id_table;
( X! c9 |0 l3 Q9 X};
* }, ^9 O7 g& |/ R$ `1 A4 _/ X4 ?1 ]* x. B
. | W) B/ R8 V: [device_driver的定义:3 j. `* X, E9 U, {5 g
struct device_driver {
! V1 D( z) K" ~2 r- u6 Z const char *name;0 D; a( a8 z* w, L0 D9 T
struct bus_type *bus;
$ n& O# H V+ F, ]
}% o: V2 q5 w/ i/ M& O | struct module *owner;) ^ j- n3 E8 i& C9 Q& }
const char *mod_name; /* used for built-in modules */1 s+ {% b; k1 ?6 [9 F& K2 t# a" }$ E
: p# K( D3 r/ I, @3 L+ ?
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
v" D- p& y# K0 t. e; J D
% g+ s1 z! m$ f8 b7 _0 z const struct of_device_id *of_match_table;; R% j7 E! F" n4 D
const struct acpi_device_id *acpi_match_table;
9 o5 b( z( u: R& g" E) }( g 3 P! k7 a( p3 P# A2 n6 _
int (*probe) (struct device *dev);
7 Q0 k3 `+ [: G3 a5 R int (*remove) (struct device *dev);9 b. k1 u3 ~( j6 l. C% O' W: }
void (*shutdown) (struct device *dev);
# I2 j: `7 t% n1 K. L int (*suspend) (struct device *dev, pm_message_t state);' y, @3 I }6 M1 ]
int (*resume) (struct device *dev);0 Z9 R6 v7 k( g. j" O# V/ R3 E
const struct attribute_group **groups;
5 f, K1 v* x! [) t4 } 7 g* c( Q- f$ i' x2 s1 t
const struct dev_pm_ops *pm;: ?& L: e' c' C- q; s' o
: J+ T# N7 K' \' e struct driver_private *p;2 q$ d/ a0 e, P$ b5 D" T
};
1 Q% p7 C( Q- b+ L% L1 T& z
6 X0 j& i6 H7 f2 b; h2 P! t* vplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
) Q: Y4 w( a7 [" `% @/ F7 U: M前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
0 T' P3 \5 k1 L0 ~6 i& \2 z' K; ^2 a a {, E( p+ W
! j, l7 Y" k7 K$ {7 T# V j1 }
struct platform_device_id {0 x% g, z6 P! z+ [. _2 I
char name[PLATFORM_NAME_SIZE];/ n0 Z. ~1 H/ Y. F
kernel_ulong_t driver_data. c% n3 h6 D/ E7 C3 D
__attribute__((aligned(sizeof(kernel_ulong_t))));
7 D1 @7 ^4 a# {0 P};
3 T$ n6 }( ]6 Q1 B6 o, |7 y平台驱动的注册使用platform_driver_register函数
" _1 o( j" G: T- s; h( n" y
: z) e7 J) r4 ~7 p+ u* ]int platform_driver_register(struct platform_driver *drv)
; U; G/ v$ l* K6 F5 \! r; z( K{, |9 E# u1 W5 @: [! q! w$ i
drv->driver.bus = &platform_bus_type;" {4 E1 E: ]/ ^% w# g
if (drv->probe)
) V/ ]9 @; I4 S" b drv->driver.probe = platform_drv_probe;2 a, N. J0 M3 _% J% ]0 _8 n+ U2 ]
if (drv->remove). d/ t8 Q$ d$ k
drv->driver.remove = platform_drv_remove;/ v+ S- E3 A; c- w
if (drv->shutdown)
& ]2 B7 o3 u2 j0 `. ^3 I4 ]( E drv->driver.shutdown = platform_drv_shutdown;
+ X/ D& v) A1 P$ y, z if (drv->suspend)8 N2 F3 z0 H/ W
drv->driver.suspend = platform_drv_suspend;
* v7 |" t$ S, S D) u: Y7 q# i if (drv->resume)
) k; W" K, r) b: d* a Q drv->driver.resume = platform_drv_resume;
4 u; i( |3 y; F; F7 K return driver_register(&drv->driver);3 _( `4 X* p$ m) ~
}- o% B* `/ x) N, D
先初始化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函数来注册平台驱动。" q! @3 m! x0 V4 }' U' c8 m
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
9 C" C8 o w N6 M6 X3 }! J- d: R: ~( b& t
void platform_driver_unregister(struct platform_driver *drv)
1 @" G' }8 G5 I0 u{
+ u! S6 P1 c8 ]9 b: U' w+ i: e; E driver_unregister(&drv->driver);) a" T: ]1 i. R) e$ X" l! z
}% v6 c/ M$ C7 w
' F7 d. r6 V1 n6 A附bus_drv_dev模型的框架图
' N. N( O/ L, ~' T0 o W
8 f' M/ M) }2 q; J3 l+ h
j- Y% r4 n/ m1 q/ Q5 j
: ?- S c. [2 ^0 p) |4 i) Z
" i- J, w+ L2 ?+ G8 L& m3 E. E- H* {: Z6 F
. N( W2 s5 k0 n. P F: B k2 A
* u4 x" T; i+ T# v! z |
|