|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
7 E$ w1 @4 X" O4 E
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。) z, O8 I( B+ V* v& |9 m- y* A1 k9 i
6 _. L, i7 N0 e# H4 D h8 y9 ]
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。, N. V: N2 _# p O, m
4 r7 z" z$ W Y/ ?
Linux2.6系统中定义了一个bus_type的实例platform_bus_type7 x8 L7 @' E8 _( r8 J
9 F. s" s0 Y7 x& J0 P7 zstruct bus_type platform_bus_type = {
8 l, Q/ q3 i# ] X1 S) X .name = "platform",) } {% v) I1 `( x
.dev_attrs = platform_dev_attrs,% g& x& m- [" b# Y& g
.match = platform_match, //设备和驱动使用match函数来判断是否匹配6 W8 M) _2 R1 X8 [
.uevent = platform_uevent,5 [2 x6 R" ]" c9 u3 A# q7 R& M
.pm = PLATFORM_PM_OPS_PTR,
5 I) N- I1 Y5 n+ [2 {4 Y};
. O" A( w! J4 c/* platform_match函数用于匹配总线中的驱动和设备 */" o# Y6 }; X- t2 g u& h3 ]% O
static int platform_match(struct device *dev, struct device_driver *drv)
& J+ b" @& v4 c+ s{6 d0 G2 k3 `- O9 M
struct platform_device *pdev = to_platform_device(dev);
8 C- F9 K7 w( C C. q, z8 O9 Z- X struct platform_driver *pdrv = to_platform_driver(drv);
7 _3 A) s2 B* G, u5 d. k 2 c( P# j9 E7 R+ J- e4 A* l& s
/* match against the id table first */+ D9 h3 ~1 D0 h# u$ Y0 |
if (pdrv->id_table), t9 O- S$ Y- J
return platform_match_id(pdrv->id_table, pdev) != NULL;
7 g' n- T. w8 M+ h+ X: t$ I# R ; D! o/ `" R- [9 ]
/* fall-back to driver name match */3 Q+ _; S4 c8 X2 b, b3 d5 q
return (strcmp(pdev->name, drv->name) == 0);! o. C! X' j: |& `# Y+ l9 Z
}3 y0 o5 [3 t0 ]% e) ]7 n
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。% J/ G6 b8 n8 b6 d3 m
platform_device结构体的定义
* {+ c, l2 {9 I* w1 n V# y2 E
* ~- R- q3 Q; Y$ W# P# x5 O& B) D
+ F! q2 i" n/ P. J* ~: F# xstruct platform_device {9 Z- b0 C8 R, E ` b9 _( A2 |% W3 }
const char * name; /* 名字 */4 h* T8 Y8 P% j) _2 V
int id;) g0 ]- N/ s" V! _* |) l. b
struct device dev;
. @; t9 e/ J5 g u32 num_resources; /* 资源总数 */
8 n. C; ?: y* w struct resource * resource; /* 资源 */" F+ C! u9 z- T! w
7 V1 u; c) `9 z! T struct platform_device_id *id_entry;
. I. {' J! `% h* r" }3 ]9 j& j};
1 G0 S4 n/ s6 C% t7 X其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。+ ~. M. n" Z0 V$ A; L" _- ]6 z
% z' }6 c. P/ t! z5 Xstruct resource {
: j1 K d/ s* y9 Z5 x" b' H resource_size_t start; //资源的起始值
& ^' E6 p% I0 _+ \+ n( Y resource_size_t end; //资源的结束值
4 C6 O# ~5 I! h const char *name;, @. r4 J+ u& T
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
" b8 f" a1 @1 t! } struct resource *parent, *sibling, *child;
1 ]( x, N4 D8 Y1 X};
/ F6 M5 f6 D& c# \9 g. Y0 [有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源4 L& N* | L: `
3 I" g& A% ?. [8 c+ l J' w1 v. y4 P( E1 y$ r( t
/**, Z. K* R& `* d: s
* platform_get_resource - get a resource for a device
. P9 D/ ?/ F5 Y k# p% Z6 q9 ?+ { * @dev: platform device0 B5 z2 J6 x8 r( }! Y, h
* @type: resource type' E8 C7 a# ^$ ?, Y, o9 Q
* @num: resource index- u2 }/ w$ I" R' ~8 C1 _; e/ X8 A$ j
*/
; V- d" \0 k* S5 l) _. istruct resource *platform_get_resource(struct platform_device *dev,
6 v" U+ ^$ q) t0 e+ ~7 S: J( i% R) H unsigned int type, unsigned int num)
) @3 C0 q$ @# M u" E5 x# q{+ y: E, p6 r5 [: T
int i;
0 ?! `; }0 S* C
; z* m6 u2 f* H' p for (i = 0; i < dev->num_resources; i++) {% D8 K8 H2 X5 u N4 y* n |
struct resource *r = &dev->resource;
3 k9 E1 U8 Z. ^7 h! U. |
5 m4 O# j+ Z3 P8 t if (type == resource_type(r) && num-- == 0)
7 A& G9 |" | z# [% x- j2 J: u% o+ \ return r;1 A$ m, x% A" M) e; R0 K
}
, F: c6 Y+ l( `8 r. N- g8 T return NULL;: m4 }8 P3 Z3 r ]
}
( j9 ?, u' L- P平台设备的注册,使用platform_device_register函数. P( G( n Z7 d5 G, Q
1 G$ Z# e6 ]/ B+ ]. [: {" W* G0 }9 lint platform_device_register(struct platform_device *pdev)0 e, a$ r/ J8 j% x4 C' o
{
, j1 {0 v: L4 n4 I device_initialize(&pdev->dev);
8 f, k% F8 c$ [' v! a. v return platform_device_add(pdev);
! t/ j9 z; |( H! s}0 l+ n. n0 Y7 O# p( D
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。0 K/ n* j. N" \% o9 R9 x
* i3 |. K% w6 O2 D- u" o* M
0 G3 ]$ H1 `; u, j) x3 {; d
int platform_device_add(struct platform_device *pdev)9 P5 ^; _3 _, h) H
{! I& d, D; R& a4 i% P8 q q
int i, ret = 0;
2 }8 B, H) J2 m, f. |8 w' e3 k 1 F ?( u0 y; w8 @6 e; O% k" z
if (!pdev) /* 如果pdev为空则返回EINVAL */( n: N2 D2 S2 @: _' K t8 K
return -EINVAL;7 ?6 s5 y( I* N) x/ p
) _) C! w6 z, Y, M8 V. u /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */
/ x6 z: i F! U if (!pdev->dev.parent)
1 Y) A" X6 S1 e# Z: B pdev->dev.parent = &platform_bus;0 H4 _$ ]' Y" E# A6 |
7 U/ W* v- Q4 l' g* U* J( D1 n
pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
# L) ]+ {2 x9 l: L" C* M " _" c! l k4 n C0 S
if (pdev->id != -1) /* 如果id = -1则表示自动分配name */4 Y( d" J- Z( ^4 i! D& n
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);9 R& i- b8 V6 R
else" ~, O& R% H7 s" N h
dev_set_name(&pdev->dev, pdev->name);
' M3 Y3 ~7 Q% ~% q 2 p6 T( i8 d' w
for (i = 0; i < pdev->num_resources; i++) {" F* Z. `* W0 R3 R: A
struct resource *p, *r = &pdev->resource; /* 获取资源 */6 A- w* t5 a0 F0 h4 U9 q3 }
$ N+ L- [! Q7 c- X
if (r->name == NULL)# D" K+ k! ^) ^5 W
r->name = dev_name(&pdev->dev);
/ s$ q8 {8 @/ r7 g2 ]
, s+ D0 C0 s+ @% ?' X5 C4 D( b p = r->parent;
- v( i# Z+ ~. s X# } if (!p) {9 m( C; a7 ] U( W+ z y; b7 V/ `
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
) ]: a9 P, L C( @ p = &iomem_resource;
/ L* h, E/ b$ D! K1 w! m else if (resource_type(r) == IORESOURCE_IO)0 g% `( Y$ \/ N' ?
p = &ioport_resource;
: K, n/ z3 C, B3 h$ \ }5 m5 S! q8 J/ G7 B
7 T! E. s+ }) g U* y' { c
if (p && insert_resource(p, r)) {6 J# ~# T; T! {: E) G6 r
printk(KERN_ERR
6 E& G- @6 m; c: e& G "%s: failed to claim resource %d\n",
* q7 n, e( u5 O- r dev_name(&pdev->dev), i);
; R5 B' v9 i: w3 ?/ t! w0 F8 ` ret = -EBUSY;
# n3 Q' y$ C+ o" p; c/ L. e goto failed;4 \/ i6 B, y9 E4 k4 Q; `2 c
}# R2 p4 \( k# W
}
; w- i' F z2 J
& u8 V$ b, {7 W* }( _" `# ~ pr_debug("Registering platform device '%s'. Parent at %s\n"," k9 s2 w2 G/ W" x) X9 ?' h
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
# L& ^7 R7 J f1 ~8 y7 h! h 7 \$ _1 O- G: r* I6 {
/* 向内核添加一个device */7 B0 E4 k3 Q1 b; J" @
ret = device_add(&pdev->dev);9 ?& v0 `& E" i5 W/ Q$ g
if (ret == 0)$ z* M- n: F; B& z$ J) \
return ret;
2 f# Z' P. |( ^1 a- c: \
; V9 \0 ^: `6 y' y! N- E failed:' k8 T' |1 i# f6 ~) o0 b% s3 Z
while (--i >= 0) {+ @3 g) H5 l# }" O9 }
struct resource *r = &pdev->resource;
7 ~7 q( i" q4 D$ d unsigned long type = resource_type(r);) O5 a6 @( O$ `; v5 ?
+ B% S( v$ n. P8 X" d) S if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
& O9 H7 ~# k" c1 Q* l) Z+ }6 n0 K release_resource(r);4 l0 V& F8 L; H$ G7 \" W
}! j, Q) W% |, R4 \4 a' g! ^6 y9 v% E
- X( c4 N6 p/ h" Z: ]
return ret;; _ G$ y7 N; A' M V n" j
}
2 z- y. X* g M+ D; i2 |% _4 Vplatform_device_add最终调用device_add来完成平台设备的注册。
1 i* H: g3 \9 V) ?; ~# ~* O. t# {4 \9 B
7 x" c: X: b! ?4 X6 X8 F
4 H3 P9 F6 w8 G+ [ 相反地,如果要注销平台设备则使用platform_device_unregister函数2 V7 ^, n9 f) i+ P( J9 _, p
1 u7 w% X% r) e4 }void platform_device_unregister(struct platform_device *pdev)" g+ R5 S* f- k) @
{2 i' }: d( ? U) u
platform_device_del(pdev);
+ u' ]7 {& H& a0 x platform_device_put(pdev);6 h* u: }+ J' D4 T
} G( P4 Y; S `( ~
platform_device_unregister函数调用platform_device_del函数来注销平台设备* O7 O; b( y$ B6 d; W0 J# @
0 ^% C0 f( ]6 n. d6 Hvoid platform_device_del(struct platform_device *pdev)9 g- p# V' @$ ^6 |0 X3 \; s! u
{
# P7 x6 t$ Y" `' t F$ y3 `2 S int i;
5 w# Z- W, z' Y1 O
9 V, }! s7 [6 j! S! O if (pdev) {% V; s; o1 ^/ ?& a( r
device_del(&pdev->dev);( w N( F$ u; ?9 i* o1 `1 z6 k
# @' V B3 s2 K) q
for (i = 0; i < pdev->num_resources; i++) {; j( j6 G- J$ l6 W! `+ E( H
struct resource *r = &pdev->resource;
: n$ Y9 L4 \# B) P2 m: Z unsigned long type = resource_type(r);
6 s& q- f* q8 z& R6 [- [. r y! W" z
# N7 U) Y; `: C! E0 a- ^ if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
9 E4 r$ B9 Y: d% _$ y H! _ release_resource(r); B4 t e/ ^; q/ G. }) k# c' Y+ l
}7 Y5 \1 P1 Y+ i! M5 a2 }) q
}
+ h3 L5 j2 e! S! ~5 h! w5 \}5 K) P* S. ^8 |. S$ X0 i( P
platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO d! z' R5 t) C& R3 J
& x; |! E0 o5 l1 Y& F7 { t/ |
platform_driver的定义:
7 q* J6 U: l& x, J1 R
% @ F4 K6 w3 ^( D# x/ v+ sstruct platform_driver {
" Z2 t3 u) D0 d+ A int (*probe)(struct platform_device *);8 m6 U( K$ d! h( K6 R
int (*remove)(struct platform_device *);: W' G/ w8 B9 K, {- |
void (*shutdown)(struct platform_device *);
: }; q; I/ k; L" L int (*suspend)(struct platform_device *, pm_message_t state);
: g$ f3 m$ L9 m: h1 s2 c int (*resume)(struct platform_device *);
# P' V1 |7 e1 K/ g struct device_driver driver;
5 P7 k B( Z$ h2 z8 u5 d const struct platform_device_id *id_table;
+ W+ R: |3 ^5 v5 L1 L};7 L# n. `# Q6 N' h
+ x1 V1 m9 t- {3 e0 G0 ]
; D% e' f' J7 f+ z6 l7 wdevice_driver的定义:6 G7 ^, o# A* H. X9 j8 E- D6 F
struct device_driver {5 g. _& `# ~" F" u6 l6 P# K$ b
const char *name; D" r# \4 l8 \& p& g1 P8 s1 J
struct bus_type *bus;
* f2 V5 z) c y
% v; O' }# V; S! O" Y% X4 b0 b struct module *owner;
& Y0 z: \4 c# v, Q& \) j const char *mod_name; /* used for built-in modules */) c) t1 ?' m! e
+ r9 @; `- A! Z! [+ u0 f bool suppress_bind_attrs; /* disables bind/unbind via sysfs */0 X5 l2 b2 d( [7 m% J8 i3 ?0 N. {1 U
; w# ` H& g9 `4 U$ S, C
const struct of_device_id *of_match_table;
Z' Z0 e' u3 O- L Q; X6 g2 m const struct acpi_device_id *acpi_match_table;! Q- a9 }4 S9 j4 s% i
5 ?. }! A. A% O0 R' T
int (*probe) (struct device *dev);4 P& ?4 _# @0 U' t( ~
int (*remove) (struct device *dev);
0 x# s d- K4 z- l void (*shutdown) (struct device *dev);
+ g1 d( t' P8 ] E4 y% C int (*suspend) (struct device *dev, pm_message_t state);
( C& H5 |: i* w int (*resume) (struct device *dev);
/ }: p; k. @# k+ C, q& G; _ const struct attribute_group **groups;
& [$ O% r; c' H% q& l3 p3 X) B
& Z# _. d: W. [ const struct dev_pm_ops *pm;( Z) H/ O% S% B7 P( u
J k2 a0 q7 z8 F+ z* }% L struct driver_private *p;
W% F( P7 L* c/ J# m, {" i};' e9 j; E3 S) }
+ o3 C+ j: t! A- T- H
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。( Z. e6 u' ~/ O3 k2 F+ Q
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。- H: B8 A- N0 B# v
0 y5 r& P- Y: K9 T2 } c3 q
d) T3 E% x1 D9 a: S3 hstruct platform_device_id {* ~' b& H* C) L( s5 l" y. m
char name[PLATFORM_NAME_SIZE];4 T T# \; U1 V" K2 F3 @* V3 `
kernel_ulong_t driver_data
+ h2 Z) d3 g" c( A __attribute__((aligned(sizeof(kernel_ulong_t))));$ w/ f( |$ t6 T6 R$ d/ ^
};* E' R T5 U! V z- G$ G
平台驱动的注册使用platform_driver_register函数- ~* D+ o5 v4 t, C" W* X
. y6 c% {( P- f5 D3 Y7 {( y- L
int platform_driver_register(struct platform_driver *drv)
: W" O8 n' Y: | f/ _+ b* z" ?) d{: l( r. s: u% e( q$ ~
drv->driver.bus = &platform_bus_type;
( _9 B( U8 |. t, W( S9 n, ~ if (drv->probe)
4 i/ n- K# t# U' P' Z drv->driver.probe = platform_drv_probe;4 m+ U. U( T' v* K% s* q( g* I
if (drv->remove)6 P" p) \4 F; l- `* e
drv->driver.remove = platform_drv_remove;4 O8 i R% t; N$ C+ L8 O7 n
if (drv->shutdown)- z- p) b2 R& Y. b- g
drv->driver.shutdown = platform_drv_shutdown;
. I: F) O8 o. `0 d y( X if (drv->suspend)
- e- w+ i- k! U# e, y: f drv->driver.suspend = platform_drv_suspend;- L9 |: ]$ y: y; A. v' h
if (drv->resume)
6 r( I+ K9 E: P9 b8 W$ A drv->driver.resume = platform_drv_resume;% `+ Q; f w- \! v% {- @# K! M
return driver_register(&drv->driver);* ~5 @9 ~0 @8 c7 U
}
- ^1 Z% E2 g8 Z& ` @先初始化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函数来注册平台驱动。% j# R! c' [; d" \
相反地,要注销平台驱动的话,使用platform_driver_unregister函数2 e9 r5 [+ d# z2 `' |8 E
% c6 y) o$ r% {
void platform_driver_unregister(struct platform_driver *drv)
' B3 p" E) h& a8 R' N# |{
' W- O+ W* w4 f driver_unregister(&drv->driver);% u9 L* w8 d! C8 V: p8 F; r0 j
}# L2 t+ l0 ^8 z$ y0 i6 E: A3 \
/ L0 e( ` y! ~. c+ S附bus_drv_dev模型的框架图: [/ x: V2 \5 P- g/ f& i8 y
9 V% _4 }: I6 Q
4 l- b1 J2 p" B' Z/ a( h1 O2 A) D3 a$ X, {; e+ l
. T! S) V& \; X9 p1 ]
7 \, _( ]0 d, o3 g7 M8 y z6 W
0 X& O; k8 t& V2 g8 y* Q3 s
/ r+ R% M o9 X4 J- d |
|