|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
9 H% q. ^- h5 s+ w, l9 { D
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
, U: @) ?( X9 y" ]3 ? r8 Z) u; j: V7 e' X0 M V% P7 E! Q* d* `+ ~7 h
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。2 S. s: X; o) n) ~0 V6 @
$ x! h, I7 p. W1 T1 t
Linux2.6系统中定义了一个bus_type的实例platform_bus_type4 x5 `: B1 e0 T7 `5 R4 p
' p5 {5 Q( p$ x; J* `' jstruct bus_type platform_bus_type = {# v0 J! u5 J/ S& d8 _2 n
.name = "platform",
! P4 K7 E7 R* s: R7 S .dev_attrs = platform_dev_attrs,3 @2 u+ ~8 i4 o' e5 D. |
.match = platform_match, //设备和驱动使用match函数来判断是否匹配
) J. t {0 n0 A .uevent = platform_uevent,
4 x6 E5 q" H* M/ B$ s .pm = PLATFORM_PM_OPS_PTR,
3 P* h7 a5 O- p" x5 ?};( F1 A* b; K* ^, B+ c F
/* platform_match函数用于匹配总线中的驱动和设备 */+ ^0 Z% F ~0 w- {; [
static int platform_match(struct device *dev, struct device_driver *drv)" ?6 ]3 s/ k a3 r& a
{" N- b) F6 h1 J- W
struct platform_device *pdev = to_platform_device(dev);7 u( ^+ ~3 c% y8 ~% Q6 E! I
struct platform_driver *pdrv = to_platform_driver(drv);& y/ f) M. p# ?; B
6 t5 R/ Q' i5 p& A1 \
/* match against the id table first */8 ^/ F/ R3 o* @- m# H
if (pdrv->id_table)
* J" `. u) Y: ^- U1 Y. Q return platform_match_id(pdrv->id_table, pdev) != NULL;
9 w- S! U" g# u% g5 K/ {9 e . Y# Q. p2 v: B! f0 L, }, N4 ^5 K( q3 R
/* fall-back to driver name match */5 w7 P9 I# X2 u8 @
return (strcmp(pdev->name, drv->name) == 0);- A0 i8 G: E: ~' X; s: q
}0 A: r3 Q# `+ s1 Q7 k" A
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。9 S r/ k+ I+ t' X! @+ h) |. s
platform_device结构体的定义8 O; ^1 s6 K) H+ V) m: D
* U/ B$ i# ~ {# ]
& d. i( @; @8 L* C) y
struct platform_device {
9 w3 z0 R9 Y6 ]+ Q) A- G* }2 G const char * name; /* 名字 */
1 i' v. {. D' K# O int id;
6 J8 f8 q- }# w* i struct device dev;
* `# ? _: m+ F4 k3 D u32 num_resources; /* 资源总数 */1 A8 k: o4 y5 R; E
struct resource * resource; /* 资源 */
# |; B9 T& ?! n9 ~: b 2 l% }& }1 U F1 M. u
struct platform_device_id *id_entry;* E% n8 s, D! ~, U2 m: {" N
};; m/ ~8 r3 H/ M' E y
其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
3 T) S6 B, M/ C8 O( U8 Q" K# s9 d+ N! [% M3 t0 w; |: u
struct resource {
3 A5 M1 [: ? @ c$ Q resource_size_t start; //资源的起始值
0 Z1 i6 @) k$ l9 y resource_size_t end; //资源的结束值4 a0 X& T2 Y% L1 w- \( D
const char *name;: A& B! Z1 n; L1 P
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
7 X: o! U7 k! W/ D% P' i# p struct resource *parent, *sibling, *child;) V3 }6 A5 ~7 ]' A5 ^9 C( R
};
# A! Q3 E* i, R6 ^8 m' O有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
2 x# |( T& B# q t" h# B6 _% H3 A. k% i2 M* k
1 Q( e6 ?4 J3 g9 h" T4 v4 ?8 {* J
/**
' |6 F/ d2 _2 X& {! e! R% y6 P * platform_get_resource - get a resource for a device
G. M S" N$ l * @dev: platform device9 i1 K) l k: |2 S; q3 }
* @type: resource type
& X; Z$ i3 z. C* O * @num: resource index9 G5 u6 ?# h) M5 e( U
*/: K) j3 {2 {' @
struct resource *platform_get_resource(struct platform_device *dev,
7 R2 T4 x8 t4 v. x% X6 { unsigned int type, unsigned int num)1 v3 f; o6 l, p1 ^& O
{% X$ I' Y; v* ]9 Q" l1 K D! r
int i;& k- n: a5 w* E) u, I+ Z
7 N1 H( l# a- m2 w+ j" p
for (i = 0; i < dev->num_resources; i++) {
4 ?: j( ?7 y( p* j+ E: Q* n# W struct resource *r = &dev->resource;
; U, Q" @& T" i3 F- `- S
% X; }( K: e( X4 n U7 K- h if (type == resource_type(r) && num-- == 0)
4 \ M& M+ d/ Y8 J4 Y% W return r;
& r: x* l6 J5 A+ j4 x. j! l9 M }7 j/ C$ W: ?( r6 e# w* s
return NULL;2 Q* H; Z5 S% g! O+ O6 q
}1 m4 c& R* L0 R6 m
平台设备的注册,使用platform_device_register函数
; h( c: `% G& S# [7 \6 d2 s& R4 {2 j& q! l# C+ j$ t
int platform_device_register(struct platform_device *pdev), V; I5 ~$ I( \; [- J; f6 q
{
( |1 U2 L4 h2 \- D9 C, l device_initialize(&pdev->dev);
8 u: E; w( G# z! a6 U return platform_device_add(pdev);( ?! D0 D! o9 g& Q5 Z1 j) {9 Q1 U
}, \6 A% c! E3 {
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。 h* m. b7 Z0 L5 e
8 N; n7 D5 m! ?& C' Q$ A, d: [) m9 |' a! c; X r7 `
int platform_device_add(struct platform_device *pdev)
( v$ o$ p% N6 u C{! h; m, ^7 s. L m1 r2 d# F i+ }
int i, ret = 0;$ ^- R% ^* s. Y' \# s8 [! i
0 U& O' R* ?7 U% q. {7 Y if (!pdev) /* 如果pdev为空则返回EINVAL */
+ C& w, ]8 P2 T. }9 o; j return -EINVAL;
$ S$ D9 S! P9 t+ ]7 ^9 j 9 v2 t, N3 T/ w- i# s
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */$ ]3 ^9 A# Z" N) y1 S- _3 ~
if (!pdev->dev.parent)( n$ y8 I; g6 |# e! W% z
pdev->dev.parent = &platform_bus;
6 |- j9 I; b$ @0 J1 ^6 N0 H* Q g+ t 6 f: i" }$ ^, ^7 G6 H. h
pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */! ^/ S4 e. o% Q% y9 G" M( B4 G
* Z) v, ^" b6 Y( s2 R1 a if (pdev->id != -1) /* 如果id = -1则表示自动分配name */
1 q! U! r' m7 A4 _ dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);) ]0 v$ Z0 q6 ?7 G o4 J7 q( b
else* u, {: g+ M6 \( Y, X
dev_set_name(&pdev->dev, pdev->name);
1 h, c# v: w2 A) m) k 6 a$ n# `, i6 |1 m9 W
for (i = 0; i < pdev->num_resources; i++) {) j9 n, w2 ]; e! z
struct resource *p, *r = &pdev->resource; /* 获取资源 */
+ @. _+ o/ V, ^# D/ q& [8 N
& W1 ^ @- Z: e9 ]1 p9 e* Y$ ^ if (r->name == NULL)4 Z' W; K7 ^0 p# {
r->name = dev_name(&pdev->dev);
& g! x* r6 m; |# H% e, i4 e ( G/ |0 ?& Q1 F7 a2 m0 {5 z1 x
p = r->parent;
5 c i, g; T1 i. A7 c; K4 c% } if (!p) {# X* D5 S2 X/ \ f1 f5 f
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
& z# K# Y7 J8 }7 v7 y; V p = &iomem_resource;& [" ]4 L" p$ `& b/ D3 E6 _
else if (resource_type(r) == IORESOURCE_IO)
* p- d2 g# x K/ _3 t) n1 @ p = &ioport_resource;# h$ A- W' P! g) _, V5 }
}! [' q0 X+ h6 y! N: l
6 U9 e' Q3 m- |6 C+ z# O1 a3 P, i if (p && insert_resource(p, r)) {
) i/ Q) }' o: w# b% b# s8 P printk(KERN_ERR
2 W' Q8 D/ ~( n1 C- k "%s: failed to claim resource %d\n",, z. `) {! t: j. P6 [, p1 }$ L
dev_name(&pdev->dev), i);9 h: A7 E3 Q' P" J" |
ret = -EBUSY;
9 F, t) j9 J: @/ \7 `) m3 u goto failed;8 c4 p0 j5 t6 J2 Z5 g
}! }% W$ x8 w% J. r
}# p2 m$ s% l+ W
% H% n* Q3 H! m( g5 i. O: `" _ pr_debug("Registering platform device '%s'. Parent at %s\n",
^4 u& D3 g' k9 G5 B/ x dev_name(&pdev->dev), dev_name(pdev->dev.parent));
4 Z r5 y$ X W2 z 6 S' O' i9 @# P8 A5 m
/* 向内核添加一个device */$ A2 e6 o2 u1 l4 U6 [9 ~; ?
ret = device_add(&pdev->dev);
! z( V$ c3 l1 V9 \- T* v if (ret == 0); x5 e: \% g4 g5 @0 ]! D
return ret;
- f) m$ [. @/ c; C
4 L4 ]0 W8 a. ^3 t y n: D failed:
3 ?3 ^, s* w# M Z4 M& g6 h0 Z while (--i >= 0) {
7 g7 p) e8 N5 W) s6 f8 M struct resource *r = &pdev->resource;
& g3 J9 J; h: ^! N: e6 _8 k unsigned long type = resource_type(r);
+ B1 m" I( K/ f) T. g: I) J( F
, h; _ Q6 Y& E. m: ~! N if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
" J9 ^% p7 L2 y- P* E, f" Z: w1 E release_resource(r);
1 u2 n! m& @ V. k4 X* B' q }1 R. ^2 P7 d1 B @
h( j% p" S/ A4 n. z. U' c
return ret;; [7 r3 `& { \, K" ]
}! W) _# P6 _% l+ g, b y; r# O$ E
platform_device_add最终调用device_add来完成平台设备的注册。
7 N9 O( r. t8 w3 M% s6 ?2 |4 x L9 r$ P, `, p
7 o4 o, q ?% w5 I
2 }- B9 p1 Z4 l 相反地,如果要注销平台设备则使用platform_device_unregister函数
0 x7 Q- m* @8 _7 k$ x8 N: }5 @" N4 T, U4 i/ R4 Y
void platform_device_unregister(struct platform_device *pdev)
$ ~8 a4 w. x! R7 N{0 c. K8 `) s" d; Q5 t6 m
platform_device_del(pdev);
! o' `5 Q4 g2 W platform_device_put(pdev);6 W' {1 [/ E0 W: L6 x
}
, G0 x# U& h. [0 r, K O. Rplatform_device_unregister函数调用platform_device_del函数来注销平台设备# m6 A$ c* D. }& L' f
2 X$ N7 ]) p& @7 z
void platform_device_del(struct platform_device *pdev)
. J( W; X" a- x8 `; `: a{
0 b8 ~, ~7 M% }2 i% h+ d int i;
; ]1 L$ `( a! h7 t$ J; y" c
! j l* y0 ^% ^: b if (pdev) {/ L! Z7 u* G7 q4 O
device_del(&pdev->dev);2 Q0 r) {4 t4 w! l5 @
- U0 J2 q8 ^, u. X
for (i = 0; i < pdev->num_resources; i++) {2 L3 _) D7 J& a2 |
struct resource *r = &pdev->resource;7 u+ J$ T7 n6 P2 s/ e
unsigned long type = resource_type(r);1 W6 b3 l A! Y% T, W( }4 G
7 j+ c. _) E& O) e: x" I- L
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)$ g2 u" U* V' y/ o a5 V9 n
release_resource(r);
& y6 t& j# i% v. |! _ }- n2 Q% C6 }; `
}- j% V+ m% g9 O* J# Z8 _( V
}. w8 ^/ `% M8 e3 b2 U6 P4 g% X7 p! }
platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
* w* _. i, W% I: x4 t- d
1 c3 Z2 h4 Y! \0 l- v5 Gplatform_driver的定义:9 i0 B4 `0 ] U
: X* ~) y! L8 D+ W5 [6 T2 A
struct platform_driver {
4 S! m3 a) ^) Y! @+ V6 s5 Q int (*probe)(struct platform_device *);
5 I8 ]9 R, o8 [1 q int (*remove)(struct platform_device *);
4 w9 h( P0 V( C! W% v& F) }# T6 N void (*shutdown)(struct platform_device *);
0 x4 Z J, `, \+ r- B3 D# i- L# L int (*suspend)(struct platform_device *, pm_message_t state);- }# Y4 r1 x5 t
int (*resume)(struct platform_device *);
; V& R5 p! M4 w, |4 a @3 Z struct device_driver driver;
" W( t. N; t, q l- j; J) a! T const struct platform_device_id *id_table;2 A# i. |8 i; P& Z9 |
};+ T- ]1 P5 x6 F+ l5 \
# g h9 y6 B S6 w2 g: ^/ Y( S0 e4 M) e# Z+ }6 {" l5 F5 c
device_driver的定义:5 e7 v3 d! |: o. F/ F; g$ H
struct device_driver {. a4 {0 ^5 e. p8 ?
const char *name;# D' u3 j) E' S( e
struct bus_type *bus;& i7 G F8 O Y4 I7 l) _7 I0 A
( c$ r6 _1 G- y struct module *owner;
. |; v& z n2 A, e \# ]0 q& r8 u const char *mod_name; /* used for built-in modules */3 w- b% i& A3 Y9 j
8 e9 t4 e- o9 s( ]5 N& T! i bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
$ _0 i3 z; b2 y3 w- d
1 t* D5 X* a9 ] q2 h3 E const struct of_device_id *of_match_table;
0 c- ] K7 [+ Z9 l const struct acpi_device_id *acpi_match_table;
5 I3 P: I$ Y7 c0 b - R) a% v2 y" a8 `$ k
int (*probe) (struct device *dev);
# E+ P. t! t. {2 l/ s, E int (*remove) (struct device *dev);
3 }$ l6 ~# J5 j2 q! ^/ D void (*shutdown) (struct device *dev);, Y5 z5 U+ z6 P. W
int (*suspend) (struct device *dev, pm_message_t state);! y3 y8 H. i9 F- r( Y3 V- n8 ]
int (*resume) (struct device *dev);
" L7 p' k- j' L5 G! P, \ s& h) t7 t5 w const struct attribute_group **groups;; G* s! }( o& s; W& l
8 U( L" Q+ s' G; s& O4 ^& _ const struct dev_pm_ops *pm; Q; M! l2 x8 q) |& Q8 V
3 V. J) y: g" ?* F
struct driver_private *p;
) m* x! H5 s- `& x' P" U p7 h( m8 x};& \8 M: z. [* `# x
4 d$ y8 u6 D; Yplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
# H6 k8 R& ^7 Q, G2 M% k1 O前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
% [; @2 k. x3 q! }4 U! A# n; s' o) K$ K' J) w& X8 D5 i# ^
1 ~$ v9 {7 j' a; V2 C, w! M5 r
struct platform_device_id {
4 K: e, f. d( D$ e char name[PLATFORM_NAME_SIZE];
( [4 q$ K% e. ~) m* [' q kernel_ulong_t driver_data
3 S; U) B3 a4 _9 S- u __attribute__((aligned(sizeof(kernel_ulong_t))));& g7 J! H$ z$ E4 t7 Y( e
};7 Q) Q7 X# O8 v0 m2 k+ @ m& B
平台驱动的注册使用platform_driver_register函数
% Q5 f4 ?/ x8 {% G: k; M+ S3 w
+ r5 ^0 y+ D2 l$ K' h' oint platform_driver_register(struct platform_driver *drv) _8 X+ `) N, k6 X3 \! I
{
) z W$ `' Q+ T, N4 e6 @9 _! B drv->driver.bus = &platform_bus_type;: X$ b( J. j% ?* ~! ]% Q" Z9 n
if (drv->probe)2 l! J( v; w# N# a5 S
drv->driver.probe = platform_drv_probe;- c" c7 v# ?- e" L$ j& k9 f# q
if (drv->remove)
0 K$ `0 R4 S8 n6 x8 E2 \7 K2 y" T drv->driver.remove = platform_drv_remove;
' ~# i( p7 J# `4 H if (drv->shutdown)
2 X, U' |# j" A* A% I4 P drv->driver.shutdown = platform_drv_shutdown;
3 X4 B9 Z7 \6 {* o5 ?* Z if (drv->suspend)
# t$ c* ^6 U$ z+ C drv->driver.suspend = platform_drv_suspend;9 U, `! e! H5 V
if (drv->resume): v- _4 M9 _0 W# D) G
drv->driver.resume = platform_drv_resume;0 d- ?7 O5 Z& f! J9 a
return driver_register(&drv->driver);+ T$ [7 W0 @- r k' G
}
0 N: L8 J& j" A' i1 e先初始化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函数来注册平台驱动。7 z) Z# _) b3 v3 |# F6 E+ S
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
. k; q8 n; i+ e, L5 m$ U4 h2 M# z$ V
void platform_driver_unregister(struct platform_driver *drv)
( C& z: ^5 m9 p% F{5 a6 P9 s4 P# z1 c
driver_unregister(&drv->driver);, H a8 w5 W7 x- X* W
}: F: f; a; x; }' ]# G+ Y
1 f `% ?2 P" q附bus_drv_dev模型的框架图
& `8 c/ F$ A$ I. Q4 |
1 m8 U9 c( o: ~" E6 i* a6 w: }; n
! T \( z w5 J
& R3 I* |. U. E/ _
+ Q- e! |& V* _
# p! i& C2 z, S% J; f8 L
6 v7 }- j) l& W4 m! B! q7 g n
6 g8 a- Q5 c+ O# J9 Q5 ^ |
|