|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
- w u% f% S7 |' @* [platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
s" p6 n0 h9 f+ b$ O5 v; U9 ]5 v! G- @* ?7 k
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。, x. v0 a3 c o
4 r6 O4 r" V% k$ w5 b1 RLinux2.6系统中定义了一个bus_type的实例platform_bus_type2 p8 l& r6 H$ x5 C
& `1 M$ K$ H3 [3 A+ y4 kstruct bus_type platform_bus_type = {
% H6 v X. o; x .name = "platform",7 c7 @# g/ m2 V
.dev_attrs = platform_dev_attrs,0 `# T ~% A, Q1 g: ]5 Z" Y
.match = platform_match, //设备和驱动使用match函数来判断是否匹配
9 `/ r- K* u( g1 N .uevent = platform_uevent,3 \% S( ~' c' ~
.pm = PLATFORM_PM_OPS_PTR,
) E8 [, s" P4 @; h% ^/ d};8 _4 L6 j9 I) y" U
/* platform_match函数用于匹配总线中的驱动和设备 */
5 U; l' G- |0 f$ |static int platform_match(struct device *dev, struct device_driver *drv)3 O3 C3 a. R# W2 D
{: L. Q4 L# m; j6 _7 W; \
struct platform_device *pdev = to_platform_device(dev);
$ Z( w! O; r5 ^- r- [, b0 V struct platform_driver *pdrv = to_platform_driver(drv);2 c% ?/ I! i+ d$ b
9 ]: |* Q m6 d /* match against the id table first */
" {" p- L- {5 ^ if (pdrv->id_table): @% E5 r5 Q. E
return platform_match_id(pdrv->id_table, pdev) != NULL;7 u! N( K' K; h1 c- B* Z" l
$ I+ G( j6 o- }8 ~6 l, S7 [2 _
/* fall-back to driver name match */" p" L+ s$ H/ v5 w' m1 H& T
return (strcmp(pdev->name, drv->name) == 0);2 @+ e; D* q X
}
6 `1 |, |8 G; e# }+ v$ u! B4 \platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。" q* O2 L5 M5 `6 y; H% m3 k7 P
platform_device结构体的定义
+ t; D* X- x. s# R$ b: ? C+ o
$ `/ i# S* z1 y5 ]- A: p: }
) V7 m2 W4 f m2 Ystruct platform_device {. V/ k' q; l% D. a
const char * name; /* 名字 */8 `; v, n) P0 b1 @1 {# s& U
int id;
4 L5 G5 _& Z4 u: r r- H( E struct device dev;1 x; \$ f% A# F* W0 R
u32 num_resources; /* 资源总数 */8 O! w* h% x* _# L3 S' a, V% k
struct resource * resource; /* 资源 */
* o5 H4 p6 U& J) Y( Z0 d
g8 l7 a. u+ k& w5 Y; L1 e struct platform_device_id *id_entry;
9 L& g/ o( p H( F5 c0 L& |* \};
/ A( e V- d" y; R8 o% W: L1 `其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。4 B% ?9 W/ Q, c7 ^1 }0 }' O
3 w/ k- i* c; C, |" r
struct resource {
5 r8 c& y! a7 Y$ M0 l5 K8 q ? resource_size_t start; //资源的起始值
- }9 I. L# J2 j resource_size_t end; //资源的结束值5 }2 E9 C( t" P2 v! e4 t+ z
const char *name;/ v4 U/ ~8 ~* n* ^8 c
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
. i6 ]1 G) t: u0 Y3 B& F struct resource *parent, *sibling, *child;* [ v \3 v. G7 g) q: C
};( a4 L0 @2 H- @2 @. f
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源8 i: _ j0 K9 W: `: X+ G( }( \5 l& j
9 q9 ?2 j. L1 |5 P
" p! i2 l" W6 M, W5 E/**. ?% E" h! X* C
* platform_get_resource - get a resource for a device3 F2 q9 |7 A1 O n
* @dev: platform device
6 [) e4 u& ~+ r# | * @type: resource type
0 k: X4 w G9 l5 ` * @num: resource index
! S2 j+ ^" D: \ */% \+ }6 Q. ?" ?4 r* H
struct resource *platform_get_resource(struct platform_device *dev,
* ^5 q6 k" Y+ L0 _ unsigned int type, unsigned int num)
0 h- M& `& b$ s6 _{
8 r; F4 C7 Q4 B9 i: F+ y int i;
; {- U6 I0 M$ l w3 h" M* ~ ; a# N- h' w8 U2 j% q( D' T6 ?
for (i = 0; i < dev->num_resources; i++) {0 ^" i; r, O( [- p' X3 S
struct resource *r = &dev->resource;1 o6 [5 I4 P' V6 k8 L
) A t1 G+ \: b5 D! m4 [2 S if (type == resource_type(r) && num-- == 0)% f& o p% z3 i, ^$ H
return r;4 O) c+ V& t+ r+ q, h4 G
}' R5 c9 X; S) w7 n; w
return NULL;2 u) v: }* A' Q& r' ?5 Y' L
} v0 ]& @9 |( Y N( _" n
平台设备的注册,使用platform_device_register函数0 j) r# [7 s; X% ~: p1 B8 e
" x$ \; K' W1 o& D: t* W, ^& jint platform_device_register(struct platform_device *pdev)0 q1 C: s' L( h( h9 m' `5 Y
{/ S; z/ K7 I: c
device_initialize(&pdev->dev);/ e# \4 Z* i: j9 N$ P. h1 Y+ q
return platform_device_add(pdev);
( B5 ^0 y% ~3 w. B" Z! d}
9 q- `& [7 e; |+ y$ kplatform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
3 D' o: B8 T/ q$ p5 _ c4 |, Z( Z2 X9 l! x$ f! b
. G \; g7 f! K" d! z( v- A" bint platform_device_add(struct platform_device *pdev)
% S% X+ i, n# p+ {6 L+ t$ p{" m, W1 e5 E4 h8 \2 |* }$ r
int i, ret = 0;
h# z- }3 \3 d. L9 }, o 5 w% M' l/ s4 W7 L4 C6 Z+ g
if (!pdev) /* 如果pdev为空则返回EINVAL */4 o4 T" E; p# S$ |
return -EINVAL;
9 s0 S) }. M, U+ v( p* _ * a# P8 \% V }8 \& N$ c
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */
% J* O3 S* @$ G if (!pdev->dev.parent)
6 q7 m& Y& |6 _ }2 |# Q6 \ pdev->dev.parent = &platform_bus;4 Z* f6 N1 l+ e
' `/ z4 x% s% z* E- K
pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
7 I! A3 [! z7 W% q: J
- T. Q3 D( }. i0 r: q if (pdev->id != -1) /* 如果id = -1则表示自动分配name */
0 v& I- o3 i& S$ @" o/ P: I dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
% x S8 g; w% ^! @8 r: N else6 T% ~( w+ j6 \. m- ]2 D0 }
dev_set_name(&pdev->dev, pdev->name);# a2 V) `3 I7 i0 l9 w$ w5 F
9 s9 t6 J2 ]# N! ?# C0 n* u
for (i = 0; i < pdev->num_resources; i++) {
/ d+ S. n! H' p0 w4 f3 Q6 K struct resource *p, *r = &pdev->resource; /* 获取资源 */+ @# c* i& e/ y& N6 V% v: ?) l
6 |+ I7 R4 G2 p' P$ [8 ~. } if (r->name == NULL)* k. c) m: ~; n; C0 n
r->name = dev_name(&pdev->dev);/ X" D; K& l2 k' G- e; _# G
6 r0 N$ Y ?0 u# Y3 i
p = r->parent;; Y' {) v* f: P& @
if (!p) {9 M# ^" H2 W/ T% l7 a
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
; Y( J9 |7 c/ F p = &iomem_resource;
6 _2 J, Q! O- i4 M5 i else if (resource_type(r) == IORESOURCE_IO)
& `0 P. q8 w1 ?" W8 Q4 t' i+ m! R p = &ioport_resource;. V2 G6 _: B1 @, K, _! s$ w: U2 A0 N
}
$ e4 r& a' [7 Q. x
; l- d7 V O$ b2 [9 i7 X if (p && insert_resource(p, r)) {
* l3 k$ B8 }1 B4 @% |6 p- X printk(KERN_ERR# i" }# ]* U' K( j( t( r$ K4 Z
"%s: failed to claim resource %d\n",- p* h; J' `( g( ?/ C
dev_name(&pdev->dev), i);4 b- i, J- z/ W% ^0 v. m
ret = -EBUSY;
* W0 y1 c9 l( h$ F goto failed;
6 s, M0 k5 Y0 _) N }9 ^) W$ J! m7 W6 E$ F! ?" B
}% R$ i' n4 ]2 M1 P& t
9 b$ o, x. c' t: \
pr_debug("Registering platform device '%s'. Parent at %s\n",9 T7 |2 ?0 Z, w
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
5 f7 m0 K6 O3 k) V1 F& W R
! w$ `1 I- W& }( g: e /* 向内核添加一个device */
. i' |* ]& r2 `) I ret = device_add(&pdev->dev);/ `; Y8 a6 }" U# w# F4 b9 h
if (ret == 0)
0 {3 N0 B+ ^3 H) N0 I3 V return ret;
5 U' C- s3 G8 q$ g 3 n& {3 B8 X- y, ~0 y
failed: f: c" }6 t! E% [- h6 `
while (--i >= 0) {* t. p; p" i2 i
struct resource *r = &pdev->resource;8 [/ C& X. N- \/ ` U* R
unsigned long type = resource_type(r);% m3 d1 |' \* P3 m& C* j
8 O2 Y b, ~* X! T% u3 w if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
" X9 K* w& N/ W& h( q release_resource(r);3 k$ h8 v: Z' i4 n
}
3 w0 L' ^+ ~; z& d7 R
& e) Y+ `5 f, U return ret;
9 B. p' L- @! [3 x. I0 a}; V0 x' V n+ z# s. {6 Q4 t6 e
platform_device_add最终调用device_add来完成平台设备的注册。
+ {/ n6 C" M8 q% {( {! v1 J0 [% H4 K3 J' h
0 Q9 N, @: m# _. c2 A2 N
3 A O2 S( T! \ 相反地,如果要注销平台设备则使用platform_device_unregister函数! e+ q% C$ z3 w
' U) b" i0 |8 t6 o5 fvoid platform_device_unregister(struct platform_device *pdev)# u' ]: d# |2 X4 c: x8 M: F- J F
{
7 u$ X: |3 q% t) `* r6 {2 h* F/ z platform_device_del(pdev);5 Q; {0 c9 e0 \1 Z# t) N4 f4 V
platform_device_put(pdev);' t& l l. Z- W, F, I6 j
}& p1 ]( p! h E3 [+ T
platform_device_unregister函数调用platform_device_del函数来注销平台设备0 \: V0 V/ a/ D% I# k+ \0 c* i9 b
, g8 R" q% q* U
void platform_device_del(struct platform_device *pdev)- [0 A5 E* Q1 B! {+ }
{% K0 x9 ~( F) b R. v! i: r
int i;
7 _ |% ?2 f5 C3 f: H" w
2 j! Y/ ]/ J7 Y1 Y- ]. N7 c if (pdev) {
$ O! M8 |* |) q/ } device_del(&pdev->dev);
/ z: A* x9 o6 c7 X! I& C
0 g1 t( \/ F% h( O: J2 D5 W% r* ^+ r for (i = 0; i < pdev->num_resources; i++) {
8 n% u Y. H' w3 d6 l: W struct resource *r = &pdev->resource;
0 n* L* X* ~ q5 s5 ]1 @ unsigned long type = resource_type(r);, S$ C0 F# D) W: N
& R5 X0 \( o" A# }* m4 e; m if (type == IORESOURCE_MEM || type == IORESOURCE_IO)$ I! L' s* `1 t: a& j) l! ~; L5 P
release_resource(r);' w9 G7 b2 V+ z) B
}6 q& C7 e0 O; x9 L
}
$ \# S' h: C* [: k! M: _: S}
1 `) [. E1 R' }4 `, X; G" rplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
5 p( h2 K l" d$ q, S. I
. V$ }! C2 A$ G2 tplatform_driver的定义:
0 z# f) g% L* S
$ e' U2 k# D$ |struct platform_driver {
6 F q; X6 c d7 K6 p7 b" N int (*probe)(struct platform_device *);
3 A& k) u8 r5 o$ {' G* I int (*remove)(struct platform_device *);
+ f* C. I+ O1 p. b( ]8 s! ? void (*shutdown)(struct platform_device *);
- P* d$ G- _6 C# D. C5 u int (*suspend)(struct platform_device *, pm_message_t state);
, x1 T( S, o% C) o int (*resume)(struct platform_device *);
$ @" \0 n# i. C q( V; d struct device_driver driver;) d8 n5 L3 g6 t* n# W: Q
const struct platform_device_id *id_table;
V% {. r1 J5 Y2 z- J};
# t9 m8 \1 X8 X# I9 h4 s
: C! n+ G V+ K7 ~% l7 T$ D; A5 a5 b& v6 O1 S7 e. @5 i) T
device_driver的定义:
- p7 a5 R0 \9 j+ ?! Z( Xstruct device_driver {
3 `* T5 a F; W- D0 l const char *name;
# k; A) ^3 u: D) X' ^4 n struct bus_type *bus;
3 C6 [" a* M# @, c1 ~( E
0 r7 V% Y1 Z" [1 C struct module *owner;5 o# ?' H5 D9 J0 o3 _
const char *mod_name; /* used for built-in modules */
6 O' J2 {3 O6 } * ^/ v0 o) j7 w) {5 |7 M
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
8 o' j- R/ }9 a
' A. M# X1 f& L# K3 b7 m const struct of_device_id *of_match_table;/ G' D* j' N: U: E' Z) F) a
const struct acpi_device_id *acpi_match_table;) u! g' ^2 N: H- F! p
, \6 C6 ~8 e; U
int (*probe) (struct device *dev);
/ X, m' F* \$ Y! c5 u7 Y$ M& P int (*remove) (struct device *dev);
8 E$ B# M7 C s. O& `1 w$ h void (*shutdown) (struct device *dev);
9 b1 s* I- m- w0 Z. A W int (*suspend) (struct device *dev, pm_message_t state);
8 M# u( |- |# y5 K5 x int (*resume) (struct device *dev);
& t+ [4 z( P, W/ r; X( A9 F const struct attribute_group **groups;
4 v) L& j( `2 q- r( W
* x f% F# C% n9 I4 [+ |1 \. H const struct dev_pm_ops *pm;; o+ j' e% b5 v. O/ A+ h- i
+ s5 y8 X) B7 o5 L! T! B
struct driver_private *p;
$ O, e. b+ I9 H};: }1 f1 s& }! ~) t4 _3 J% R
+ |+ g" F0 h% U+ gplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
' Q" d- x/ j% T3 E前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
8 ?+ J7 A" Z8 ? y% X1 z3 H8 {+ T% D5 M' d- @/ S2 f: {# w
6 R" u/ `4 }5 ?, e1 A1 R) A) t
struct platform_device_id {
3 m- n$ H/ }7 C char name[PLATFORM_NAME_SIZE];1 v7 [: v: o- D( c$ F
kernel_ulong_t driver_data
/ B8 E% |- o+ g' w; ` __attribute__((aligned(sizeof(kernel_ulong_t))));
) I( O, }7 l& E% z( d. q$ l9 Q8 [};/ R; R9 D, ]8 b5 }9 t9 d; c
平台驱动的注册使用platform_driver_register函数
" U; J0 y$ Y, j8 _0 I, E3 ` a3 x% x' O8 u7 R) K7 U5 ]
int platform_driver_register(struct platform_driver *drv)
5 t1 L- X' Y! L5 i. M' ? z{
- Y r/ @- a4 w6 Q, k drv->driver.bus = &platform_bus_type;/ H5 ~- W4 d* X( y* H# t" U: A
if (drv->probe)/ H9 M2 e$ Q# F
drv->driver.probe = platform_drv_probe;/ Y, |+ D- e/ Z
if (drv->remove)# Z8 J5 p7 @4 w+ A9 K
drv->driver.remove = platform_drv_remove;
- ~9 x( ]1 o* y/ v$ i if (drv->shutdown)
5 P# S1 [: h" L: U* C8 F5 k( L; A drv->driver.shutdown = platform_drv_shutdown;
8 }3 J5 o3 E* V: |6 }9 N if (drv->suspend)
- a! j" s3 n1 t2 X, k B drv->driver.suspend = platform_drv_suspend;
* F: M& [& U0 y0 h T2 { if (drv->resume)
) O/ E" [7 N; ^, `1 Q7 i& T$ S drv->driver.resume = platform_drv_resume;
7 n4 ?! K, X2 [- K$ ] return driver_register(&drv->driver);8 a3 r- o6 N. o" H
}7 {, J: i9 s& W; A- d) {* m
先初始化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函数来注册平台驱动。
. R: P e1 [/ u% w- E9 i0 a9 ?& f相反地,要注销平台驱动的话,使用platform_driver_unregister函数
( p( \: K4 a l( ?1 i/ n) C N' F3 W @0 z8 W! l. P
void platform_driver_unregister(struct platform_driver *drv)
$ D O) @2 m/ z; q- ^' T, J{
4 Y2 c0 V B6 P: u7 I0 d$ U driver_unregister(&drv->driver);
4 C, i c! o, @}
7 L, h% U3 o1 C# @
5 U! O8 m: [4 d L: c附bus_drv_dev模型的框架图5 R1 W w, U; Q& b. D9 z& H
( A% W. N0 W9 d, B* i' B+ Y; I8 C/ i$ e3 @, R' Z$ |0 U
9 I1 m4 D; H3 P
# C! e$ p& C6 v1 A2 O& e7 |4 U+ `( B o- Q5 h/ c4 T
# V. o8 l1 Q6 H( T2 B0 ?
9 G0 S9 a7 M z- k* F
|
|