|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
0 L4 }% q) X4 |6 Bplatform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
, M" V# h& O7 q( v1 t! B+ ]3 g( I- A0 f+ S7 C
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。5 ^' z5 [+ @6 _* {5 e
0 ?8 L" i" N4 C
Linux2.6系统中定义了一个bus_type的实例platform_bus_type
, h5 M$ U/ {9 q/ }9 c! `- y0 c' J) x/ j( ]/ z2 V% J% I
struct bus_type platform_bus_type = {& P$ A' B6 C0 _6 M
.name = "platform",
0 |/ ?& g3 \: Z) B, j% W/ _, [ .dev_attrs = platform_dev_attrs,4 _) _# O: ~6 d! A* I F7 A
.match = platform_match, //设备和驱动使用match函数来判断是否匹配3 A0 G4 F. J5 h8 e3 S
.uevent = platform_uevent,+ i2 b8 l! u" U& S7 B
.pm = PLATFORM_PM_OPS_PTR,
3 A, d4 \& ]7 K};
( f: _' E! Z7 v7 |' y, T& _/* platform_match函数用于匹配总线中的驱动和设备 */7 ?% c" N9 \. h8 n2 o6 q: x
static int platform_match(struct device *dev, struct device_driver *drv)3 S: K0 @+ G) f- C( u' N( s3 ^
{0 l* U# U) A: C# Z% `, ~% i* n) y
struct platform_device *pdev = to_platform_device(dev);. O S3 U, w0 }9 f! \
struct platform_driver *pdrv = to_platform_driver(drv);( w' y; A& a1 m7 _* l" `
: ?7 a9 J# X) f6 |, X /* match against the id table first */
1 g) ~ j9 G- o! ^8 b, k if (pdrv->id_table)' V! r: \2 J: M# E
return platform_match_id(pdrv->id_table, pdev) != NULL;$ f2 f$ F! v: y5 _! v
" V* n, v! F! _# n+ m
/* fall-back to driver name match */ ~1 i, z$ J3 @9 M9 O; ?2 g! k; E
return (strcmp(pdev->name, drv->name) == 0);& d* g1 t- {' J- E- o% g! P( D6 t. I
}6 w) ]. g! ^% O
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。
* s7 P2 }2 h2 Y- Q# d/ @platform_device结构体的定义! r, Y4 d8 x5 \$ o
- E+ V0 Z( Z+ _8 r3 l: R
) s( e6 d, _/ c- @8 I1 S5 a1 estruct platform_device {: {2 E7 T1 y$ h
const char * name; /* 名字 */7 G! `/ z# U: t9 z" a9 g$ I
int id;
. K7 r. `0 h9 B" N, K$ @* f5 `4 n struct device dev;
8 V* v2 Q! }5 Q6 t( A0 _! ~ u32 num_resources; /* 资源总数 */
" }3 ^1 C6 U+ V9 X5 @7 a0 ^; } struct resource * resource; /* 资源 */$ Q1 U$ s4 ]; L4 u7 w) e& K8 \, ~, [
1 A. X5 ]9 A" Z" o) u struct platform_device_id *id_entry;
9 H1 x! i1 y- p: t7 w; d, ~};" C+ p; u+ ^- E$ |9 X& |7 P1 I
其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
6 N+ a2 y- W8 @$ N) V! U: \+ A, k# w9 C. |
struct resource {
4 @ ~/ e+ r8 u+ ^7 R resource_size_t start; //资源的起始值8 M! m# ]1 L; h9 ~
resource_size_t end; //资源的结束值
$ E$ K* S- {+ ?8 o const char *name;5 B* R( n2 l) @7 l- j! v
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA" I9 H* a! `7 S) n
struct resource *parent, *sibling, *child;: S' N# _2 O% ~. ^; F1 ]
};6 }& ~: ]8 h5 x. A. b
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源5 J* B6 m4 g. }: @0 @
0 t6 l# G7 |/ t' c) N3 h, X. u# z# D1 C! x
/**3 s8 N8 m7 Z3 E2 \7 M: _# V, n/ q- J) m
* platform_get_resource - get a resource for a device
& l$ _4 I# i" @* O. }; ]$ x * @dev: platform device
2 W$ W5 T& h3 E; ^ * @type: resource type" \. W% O) r6 v6 y
* @num: resource index
. T# M" R+ Z* N */
: O- o1 m0 Z0 r7 Lstruct resource *platform_get_resource(struct platform_device *dev,. x; b9 i* A4 ^& j0 ` b
unsigned int type, unsigned int num)- T0 P' L" T, L4 K0 h
{. |' M2 n; |2 m0 x
int i;
( i+ c6 w% y4 [9 c* A
. J& K i8 g5 M) {* Y8 c for (i = 0; i < dev->num_resources; i++) {& k) q- Q, g! w* ~/ U* R5 m
struct resource *r = &dev->resource;
! q" K$ W4 y3 B- k+ z
! q, \1 ^3 B5 }: U" L, X7 X if (type == resource_type(r) && num-- == 0)
1 N2 D7 m T- C" [* l: \ return r;) }( a0 w0 Q7 h( r+ P
}' M& o5 s" w4 h
return NULL;
5 S. }9 v( s) \+ e) ^8 k+ d+ m* G}+ S# M' D$ g! {+ U% Q
平台设备的注册,使用platform_device_register函数& T. T: X" Q1 i( C& m# g
) S, X/ l9 G: I; X; t) a$ eint platform_device_register(struct platform_device *pdev)
; L4 k$ N5 e# G0 n; ]% G. W{
- Z2 M* ^0 R, t" L device_initialize(&pdev->dev);3 S7 \4 A* {& W; {2 x/ z
return platform_device_add(pdev);- e& J6 v( e8 P; m3 q
}- ]2 m# A/ S/ ~' s$ e
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
( v. K D- s$ K$ r) q2 \ R3 h5 Q+ B$ l; A
k8 l2 r2 n- g P9 r0 V. I
int platform_device_add(struct platform_device *pdev)
6 o5 A% C# S6 M |2 A `" }, \& O{
. t% t/ x" A) A( {* D int i, ret = 0;/ M$ p' n" z1 U Y
, B# y" F8 t* Q5 V, v( @. w
if (!pdev) /* 如果pdev为空则返回EINVAL */
+ w5 A8 a: o+ @! K6 N, E( S! M; R- ?- m return -EINVAL;, R, F" d0 a! c% E
! {2 }1 n' d) |% K I
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */1 C( g7 K% \0 w( U- n1 k* L5 k
if (!pdev->dev.parent)2 u3 m5 |* _5 a! f! X+ x" M' [# I
pdev->dev.parent = &platform_bus;
8 I. T0 d6 J4 x1 U8 `/ r
/ @4 J) L9 b5 f- F) W5 F% s pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
1 x) V' Z4 u; g& I( _2 R' Y , b. p) S, h0 \+ L6 ?; T% ~
if (pdev->id != -1) /* 如果id = -1则表示自动分配name */' Y% P6 L% I: X9 X/ P9 U1 s
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
4 f7 e; ^ C u+ L else! \& C& t3 \2 I* P! F
dev_set_name(&pdev->dev, pdev->name);6 {8 G9 `2 c! ~, r! ~
1 B1 ?0 M; T/ p& N w for (i = 0; i < pdev->num_resources; i++) {
. I! G0 e0 z0 _3 e g# |3 L& L struct resource *p, *r = &pdev->resource; /* 获取资源 */
" } Q* F8 v$ q" J/ I7 G ' E; }0 a. l, N# F! Y9 b
if (r->name == NULL)1 c" m j1 u% H& ]! K
r->name = dev_name(&pdev->dev);( Q9 E' X. Z; p6 P+ k$ L) d3 U/ `
' w+ B, _, ~4 q8 ]1 M8 U/ n! \; U1 K! ?9 K
p = r->parent;2 j( r$ R3 _$ E; [" E$ Z3 I4 a
if (!p) {
! b6 j& ~& u- K- c k w, } if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */$ C& s1 Y& ^/ Z& T0 P! e _
p = &iomem_resource;" \( n6 b8 ]1 e, r, W8 c) `7 L9 A
else if (resource_type(r) == IORESOURCE_IO)
- V6 Z0 A" o- [" D% D* C3 p! _: ` p = &ioport_resource;
5 t% }) T. ~& f, z* P9 ~, O }
4 o7 g0 D1 G6 u 6 C0 [+ m5 l1 k
if (p && insert_resource(p, r)) {
# u0 ?5 D- ?' R) x' c2 b' p printk(KERN_ERR
( X+ ]. u+ k) f d! \2 y+ c "%s: failed to claim resource %d\n"," P5 V2 t' K: J/ M x" z
dev_name(&pdev->dev), i);$ ~) y" |' |' R+ h9 i$ P7 b) L# _
ret = -EBUSY;( U) y/ n8 n1 j0 e4 Q) q9 o! {
goto failed;; {5 q+ b# q; T/ B
}6 w/ M( U; ^, i: \
}
, M% a+ g! u( Q* }$ q0 H& j# D# T, O 7 ]% O1 p2 m$ e& i
pr_debug("Registering platform device '%s'. Parent at %s\n",
- A: O u9 y! i( t% g' x, n dev_name(&pdev->dev), dev_name(pdev->dev.parent));
2 r; c' z9 \) t8 i- i1 I/ K/ J4 n
; h2 H( D8 M6 E4 i# [6 Y /* 向内核添加一个device */
" s+ A# O2 T6 H- X ret = device_add(&pdev->dev);
4 ~$ p& I' \3 r+ z1 P6 b if (ret == 0) N/ n" n2 h# ^% m
return ret;! n" c$ M% A2 A- D- Z& g
( V! ~: m4 t- }/ p
failed:
9 D3 p! l" M& H# o, a4 q( d, ^ while (--i >= 0) {
5 f% [. E5 a$ a struct resource *r = &pdev->resource;
, O' `" Y# X8 S$ I& D* G, ~, {5 j unsigned long type = resource_type(r);
5 r) z5 \8 D0 S& u5 x& Q' W) G ; W5 v; {' c* J, ]& V: P
if (type == IORESOURCE_MEM || type == IORESOURCE_IO). |3 W! ]% ?) ?5 d4 X& h( K
release_resource(r);& ~! p- z8 j: o8 t" q( K
}) z7 J, R n* _# s* z" O6 `. P
3 F& u% G: h( E V! z
return ret;
& b% Z& W# A- z5 @. ]8 G5 k8 T}
1 Y/ |0 s! G( ^# T! ]$ Rplatform_device_add最终调用device_add来完成平台设备的注册。
: ~% _+ D+ g4 E8 x2 H+ C0 r, K; Z/ P& H. v
$ d6 X! [, I! |7 c9 ?
+ g8 ]+ i' n- z2 |! _ 相反地,如果要注销平台设备则使用platform_device_unregister函数# Q8 n; ~6 R% z2 R& v
/ b8 n5 m* p- p2 A9 z
void platform_device_unregister(struct platform_device *pdev)
& g" d P* |" I2 U4 y o{
+ `* r7 f- U4 {, j! m+ a1 n platform_device_del(pdev);
7 o0 f9 W4 \' K. a* B; m$ C platform_device_put(pdev);
& C, }4 j/ Y4 Z8 n9 P/ u3 n}" K, x) S* G) a
platform_device_unregister函数调用platform_device_del函数来注销平台设备- q* S$ O1 Z* Z& a& l3 q# x
' a' X; |" D7 T8 [+ P- P$ K
void platform_device_del(struct platform_device *pdev)$ f+ T) M3 S; o1 O+ O
{
( u" d1 _# k7 @4 N5 Z) C# S7 } int i;( L) c4 Z9 r& D' A
; o4 D# e; C: R( p2 ?, `$ Y if (pdev) {
! Q* Y% j( R& e7 r) L device_del(&pdev->dev);
4 o! ]5 t0 A8 A+ j. ` 2 }6 |. S/ N8 d# o
for (i = 0; i < pdev->num_resources; i++) {7 H7 n; o \; P" x
struct resource *r = &pdev->resource;/ E1 Y d2 [% o0 Q; W, _; b
unsigned long type = resource_type(r);
' Z2 c4 K1 _/ N0 w5 K% U
- h6 o9 ]( ]% w, x i! j5 Y if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
7 X: ~0 q! m1 {4 J release_resource(r);
# b+ o; l0 ]* Q8 }8 A }
( ]( ]6 z! f6 L% U9 @ }. m, ~4 n- r% { B: X
}
) S& g e" ?' Lplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
9 G1 i) C4 V+ j. T6 H
. y; g" c5 E8 j( u( \platform_driver的定义:
Q1 m/ f' F& ], |% Z A9 r' g3 ]$ R3 P8 Y- }( Q" N! }6 W1 T
struct platform_driver {$ K% _3 c& y6 s( E( i6 p
int (*probe)(struct platform_device *);
+ ^. \/ M4 m Y! Z! ~$ T, q! {4 y int (*remove)(struct platform_device *);, e6 i+ }9 X9 W3 V3 F/ B) N" n
void (*shutdown)(struct platform_device *);$ ^& c* w7 X0 D. z; r
int (*suspend)(struct platform_device *, pm_message_t state);$ P# R4 [9 Z) z9 q1 T* ]
int (*resume)(struct platform_device *);
0 E8 N+ G U: l5 @, G struct device_driver driver;% r, }$ D, v' q% v) \0 T! Y" T+ f
const struct platform_device_id *id_table;2 e* H% l0 h) }0 e9 J0 g
};
k. s) E# c' l3 j
5 z1 t. Z/ ?. s0 d9 V+ m* b& |* y6 P* N# [
device_driver的定义:
0 I( p( d2 n4 u* M: E+ ustruct device_driver {1 f% @: e' J! o- n
const char *name;' Q% r$ u* ^9 y$ f% v% n2 R8 N1 b D0 Z
struct bus_type *bus;
2 G0 u8 U/ I/ q8 a( c: g/ ?* S, C # ~' e* n- x( ~0 v2 ] d' K6 ~
struct module *owner;
- s& y" w# k8 p# k const char *mod_name; /* used for built-in modules */
# r$ h" X- \% k+ e: p* p* V 4 [2 C3 r* ~0 [0 @! g& S. l
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */- J1 r5 M8 B _: X: n9 L ]- z
8 `' y( X' `3 B( j( M
const struct of_device_id *of_match_table;0 L- y6 G6 z: G
const struct acpi_device_id *acpi_match_table;
/ m* m) y, W& G5 ^2 a5 w) G / K' X1 I6 Q1 e; U% q
int (*probe) (struct device *dev);
: S2 o' A' p1 @6 x int (*remove) (struct device *dev);
- g& i) r" @% x' n6 G u void (*shutdown) (struct device *dev);& F+ r7 g t8 p$ Y& Z1 c7 o. i
int (*suspend) (struct device *dev, pm_message_t state);' Y2 H& v7 K& B6 L: {2 b
int (*resume) (struct device *dev);. _$ P% C& y" Q
const struct attribute_group **groups;
9 L7 z( v1 v; j
6 ]9 \- r6 g1 [ const struct dev_pm_ops *pm;
3 e: D8 I) a- L$ O % R# q9 r; p* x/ h
struct driver_private *p;
* z$ j7 H6 x! z: [};6 w; u4 V$ M) x6 b2 I
! T5 D3 w& Z, G9 \* d
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。! _& o2 [$ u1 I' B7 ]( X) c
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
$ y N5 A7 x5 F9 a2 I8 b4 Q
8 H# x" V. ^& \ q' t' f: p, z! Y5 _" B+ y" u: `
struct platform_device_id {$ H8 b, o! B$ o
char name[PLATFORM_NAME_SIZE];" D! `% U3 q3 y/ `" l
kernel_ulong_t driver_data
9 ~. l6 G8 R5 @( P1 b7 I1 z$ o$ v __attribute__((aligned(sizeof(kernel_ulong_t))));
7 {& n' C4 D( C! _/ O6 s! }8 o};
: T+ C- |$ G8 _ l( E平台驱动的注册使用platform_driver_register函数1 _ J, _7 n1 C* _% _- [
$ G' l) A7 G) p8 Y; B( f' u' b
int platform_driver_register(struct platform_driver *drv)& Y% x4 z( |. H" \2 h
{
' ?% [4 s! N& c1 C$ | drv->driver.bus = &platform_bus_type;
. U* b- Y9 D. W. w4 M" v if (drv->probe)# f m8 t/ T6 J7 n# f
drv->driver.probe = platform_drv_probe;4 b& r: V, b5 E! c- a
if (drv->remove)
: C# Y' u1 s( V0 m drv->driver.remove = platform_drv_remove;
" M) Y$ J! l7 ^1 ` if (drv->shutdown)
: F5 i' H$ y. a; B9 {" U% f7 a' F' l2 Y drv->driver.shutdown = platform_drv_shutdown;
: c. S1 A) q9 k if (drv->suspend)9 c$ c' V) Q* ]( _2 y% X8 x r
drv->driver.suspend = platform_drv_suspend; A7 J$ p* \4 M" a& g7 j8 h5 L9 {# a
if (drv->resume)4 p4 f% \) P {/ L7 H- m X
drv->driver.resume = platform_drv_resume;
% K6 M$ T6 j% Q( D0 X0 G- c return driver_register(&drv->driver);
7 s+ q% n/ `. Z' i9 E}
4 K$ [$ I" e4 ~7 T' ~) V/ S! b3 H先初始化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函数来注册平台驱动。( Y% W" T! G% j' o
相反地,要注销平台驱动的话,使用platform_driver_unregister函数( x( z6 I" M% p/ q1 y' W
l: U. x0 X4 E [3 r2 q
void platform_driver_unregister(struct platform_driver *drv)( }2 V2 @$ [4 p; x
{- R. q; E: d/ [2 {
driver_unregister(&drv->driver);: v1 [4 e K. k' \# \# T) C+ F t
}* r& A m& g! g* T
. f9 L6 _ K7 x: y j7 B附bus_drv_dev模型的框架图 T: Y+ P7 U0 ~1 i8 ~7 L
& t0 B# `& c7 u- k+ ~5 p
4 k# ~- x ]$ Q* Z0 N1 R4 |
/ W( |& ~; T. g. |' H D3 s
- h8 C# z$ w% Z: T0 r! `$ K' e. r, n
* E8 {% P# Y- {# l) z7 Q6 y. R6 r* [! b; F& H- W+ J
|
|