|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
1 m5 i n b9 t& `5 v1 w
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。# Q% d1 m# n$ { t3 z* h- m
$ b4 m- \. B' U p7 G }* V$ y6 {- h总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。. Y* z& a; e" i, z# R0 ^8 H* I# S
; D2 I; e# u9 r! _+ H& {
Linux2.6系统中定义了一个bus_type的实例platform_bus_type9 Q8 |3 C8 D! `( |
2 d0 Z# _" l- Y* W7 K! z3 W3 j
struct bus_type platform_bus_type = {
. t( i; x% y5 ?1 U+ e! u .name = "platform",( l- S6 h4 Z3 Q9 q' j
.dev_attrs = platform_dev_attrs,% M) ]+ I; W4 O( i
.match = platform_match, //设备和驱动使用match函数来判断是否匹配
9 s% g4 q. t. J5 ] .uevent = platform_uevent,* n# |7 g" V; z6 Q, Z# f
.pm = PLATFORM_PM_OPS_PTR,* f$ @# ^2 X! P. r
};
1 T8 X" O; d7 s) l/* platform_match函数用于匹配总线中的驱动和设备 */
) U m4 _0 f" h6 R* {) Wstatic int platform_match(struct device *dev, struct device_driver *drv)
; w3 q+ v s. b! q: y' P{
, n" P) X) X9 ~2 e- z! G struct platform_device *pdev = to_platform_device(dev);
( S* G: ^. q8 Q5 _ struct platform_driver *pdrv = to_platform_driver(drv);: q' [7 k; n" u( }3 z* B
1 {( v4 @7 R4 M/ Q4 H /* match against the id table first */
& b) v8 ?# o, P if (pdrv->id_table)
, l5 _/ m5 ^+ C, a9 S) D return platform_match_id(pdrv->id_table, pdev) != NULL;. g: d5 @, y( Y( @0 x
, ]) K0 F! c# W/ I/ M0 J [5 C /* fall-back to driver name match */
0 V$ c/ m0 h: G4 ?8 I. r" V return (strcmp(pdev->name, drv->name) == 0);
3 D. i1 n0 Y( @; Z8 J}1 H2 W n7 m' ?
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。
8 m E* t3 O0 r1 v3 A1 t+ p5 [0 @platform_device结构体的定义
i- ? q4 m" M1 P; \' A* q+ Z( r% _0 ]# `8 Z) B
! U' `( ?9 d ^ W
struct platform_device {
9 |( t- X% ~8 p: j const char * name; /* 名字 */3 h2 I" B3 p. c, e1 H! V2 k
int id;2 V2 g" h, N. G8 F% c% S7 _
struct device dev;0 m) J7 o; }# c! A! x/ l
u32 num_resources; /* 资源总数 */
* ^2 ?4 W( z& k5 z: j; n struct resource * resource; /* 资源 */8 B3 y' Z0 J) ]. v
% ]4 @ D& F( J4 ~
struct platform_device_id *id_entry;. Q' L+ {5 A0 \( G: ^; ~8 ~: E
};
; u7 M3 _- W' b9 p% d其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
J- b. Y1 n& A, Y) ?& C
) d/ K" W, f3 ~+ b5 u$ R l) f6 Cstruct resource {: Y( c3 z- u8 m, t
resource_size_t start; //资源的起始值0 G2 A% l4 \, F! P
resource_size_t end; //资源的结束值, v0 Q6 I) w5 i* ~
const char *name;+ a, I% W' H4 U7 w( A
unsigned long flags; //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
5 q! c- J# z+ c# `$ D7 V5 ?, W struct resource *parent, *sibling, *child;
0 I( A, x% b! s* g};: N/ p) ]2 y. b( c. }
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
: N8 f1 C4 W( Z' n$ v' o% p4 g! D' q9 q" n) E% B+ [: h& h
8 b# [6 @+ X- O5 D0 i/**
; a& P4 f0 O1 S9 f. K * platform_get_resource - get a resource for a device' s4 j/ u: I V3 n
* @dev: platform device
1 k) g' Q5 X" C) n9 }( S * @type: resource type' o0 o+ _% q; R( d; z; U6 _
* @num: resource index
8 k, A1 d+ `& |: q: y' N1 C. H */# [: f& \9 H- C2 E# s* v# v+ Z6 n
struct resource *platform_get_resource(struct platform_device *dev,
- I) t) K1 }9 X5 }4 A5 D I unsigned int type, unsigned int num)
" z7 v; k) @4 u; v! k{
. B& V5 }* {( N1 j int i;9 P2 h+ M9 E9 [
, M i6 Z5 ^9 e$ b/ f7 M for (i = 0; i < dev->num_resources; i++) {
% r) p$ q$ T% J& X! H& D3 n struct resource *r = &dev->resource;2 n. j2 k! F" N. R" \1 A+ M4 ?0 Q
$ y4 ~; v4 a' J% a+ Q5 N3 _& W if (type == resource_type(r) && num-- == 0)) G# P, y. [3 Q% M% T/ I
return r;
( Q _5 `. A# q7 p. I3 w7 z }
& J. F/ l1 {, V) n! ]- \ return NULL;
. K7 F; L' n8 k+ c2 t5 ^}
( X# j; h8 G. ^& X平台设备的注册,使用platform_device_register函数
! \! V0 z; e7 f6 c4 U7 D# V
7 b. X n6 @* x) f- hint platform_device_register(struct platform_device *pdev)+ T+ T5 g+ T$ Y: E- c$ Z- f( t
{
+ z6 n& b0 E# E) l! r4 t" [8 b( p+ {6 H device_initialize(&pdev->dev);
4 d- P" J: v" ]9 V return platform_device_add(pdev);
4 O/ r+ |1 J) }8 Z# |}' w$ o1 }5 ?* U0 l$ m b. X
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
" M; |& [9 p' F3 b" a) j/ ]# ~. V3 K* V: y5 F- D: J- A
1 `8 Y4 [8 O; H0 H+ O) n$ c7 gint platform_device_add(struct platform_device *pdev)! S9 @# f" \+ e: j, W8 |
{) J5 ?& H7 a# k) M5 V! U! T
int i, ret = 0;
& [. L5 ]. G) e; j/ R- z- r: x7 x ( j" ~9 ~. ]- |
if (!pdev) /* 如果pdev为空则返回EINVAL */
/ O. Z9 u0 x I7 P- u( T return -EINVAL;
( @8 L. k, E' ?7 {! t8 b, w" Z: B, ] - e4 \% `" a# L; w, k
/* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */
! \1 A$ A1 L' d6 z if (!pdev->dev.parent)+ m; S, k2 q4 L( L- Z: Z+ K; y8 Y
pdev->dev.parent = &platform_bus;
9 ~8 ?" k, s7 U5 H+ y9 ?' I
6 b( z) H. n) K pdev->dev.bus = &platform_bus_type; /* 设置总线类型 */
, f+ v; A8 J, \. i' ~4 k; M, e " H/ c4 V* ?$ F' M. B9 ]
if (pdev->id != -1) /* 如果id = -1则表示自动分配name */+ b) ?8 s: Q( X6 q2 t
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
7 e9 ^9 m/ q: |' Z2 U else/ k- O+ y0 \% p) ]6 C. j
dev_set_name(&pdev->dev, pdev->name);3 J O" }1 R/ @/ \* b
/ e; d7 d9 _% [, M5 T6 a1 V9 a
for (i = 0; i < pdev->num_resources; i++) {9 O9 R/ b% B$ _+ G- t9 |
struct resource *p, *r = &pdev->resource; /* 获取资源 */
2 k5 f* @, E! ?; K3 j& H+ q3 Q
- I: ]9 Z4 J u9 Q- } if (r->name == NULL)
$ a6 X* h J A Q# c: x% c r->name = dev_name(&pdev->dev);
# H& F4 c D% ~
! _4 v, U$ @& J1 L; N, V$ ` p = r->parent;+ z5 c& Y$ @0 W2 {- }/ L; i
if (!p) {( |/ _; G* N, }8 x, {+ k
if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
|& j G' @5 x& R p = &iomem_resource;& D4 c+ _4 D. V4 M
else if (resource_type(r) == IORESOURCE_IO)& F+ M* f7 d6 w. D4 U0 U* r
p = &ioport_resource;
& n A9 s, _& O; x6 }5 v }
/ t( W; r3 _# {+ ?- Q$ O5 E1 b2 O 9 b- @$ q/ k5 W0 M! u
if (p && insert_resource(p, r)) { r/ M$ a+ c8 {3 @2 [
printk(KERN_ERR
5 ^8 W) J M' Y1 H) h2 }+ t "%s: failed to claim resource %d\n",
k. e! B: \: c. d. w# y6 C dev_name(&pdev->dev), i);
: |! J' p3 B1 _# `/ H$ h1 \4 p ret = -EBUSY;4 J- J1 ^% ^$ B9 |
goto failed;
. K; n# \* C- d- b @- h, q' O, s }
h4 P1 d2 Y& f% D+ `0 e }
s9 Z' O( a, ~# I3 y: r1 C: f
: `0 ^, _) w, Q1 @1 T pr_debug("Registering platform device '%s'. Parent at %s\n",: z, @8 P* K- l& g( t
dev_name(&pdev->dev), dev_name(pdev->dev.parent));* N0 @+ {7 {% C0 r+ R
( B: A$ l7 K3 a5 V: O+ K/ }1 o /* 向内核添加一个device */
7 m+ y6 t+ i. C9 n5 t8 Z ret = device_add(&pdev->dev);- z4 R1 a& {- [3 I6 X
if (ret == 0)
" K {" K/ k$ v3 r return ret;
* N, B# o* w9 J8 f6 k
! D1 o b/ H% r! F failed:5 p5 o, H2 p5 L3 V+ p. I
while (--i >= 0) {
% `- z( \1 X+ ]( |1 z2 c$ A struct resource *r = &pdev->resource;& }9 B5 w" _) A g+ H
unsigned long type = resource_type(r);
* F9 k1 c% |4 B Q L4 i0 R9 B ' n( z8 {) F) y1 e# c5 x' c `
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)1 l$ y+ o5 r H! X+ ?
release_resource(r);+ p' T, o& z0 p0 l) f( x0 g
}
. W% s" n P( y3 w
7 _! O3 G! k& L8 y return ret;
2 K' }, w m, [$ L7 x}
; {/ ^1 r( C# hplatform_device_add最终调用device_add来完成平台设备的注册。
+ L+ b/ L# X+ |1 [" J {7 }$ W/ Y) @& {, f) {/ X- ^
4 B. n2 I. d3 M6 _9 f
' H$ Q! f7 n3 n* W
相反地,如果要注销平台设备则使用platform_device_unregister函数
! d( p' p7 t: q2 q, }7 K! f! n8 }9 ^3 m2 k7 P m$ p
void platform_device_unregister(struct platform_device *pdev)
$ c5 @9 A$ R) h& Z; l. w! S# T0 Q{ B6 q' @$ z8 Y
platform_device_del(pdev);5 ^3 c4 L4 v. O' S4 \
platform_device_put(pdev);
* L( H" o7 v$ C0 i6 W0 z& V}; A; d9 K$ y" t8 O2 L0 p
platform_device_unregister函数调用platform_device_del函数来注销平台设备
/ u: [5 \8 D% |2 y, l$ H7 e3 F7 C4 y# }" P+ ]
void platform_device_del(struct platform_device *pdev)+ l% h, [( o3 o; c3 q9 v
{0 G, t+ Y. ]/ R s! l5 l+ J
int i;" {9 v3 R! Z: A
* c" {% {2 T. {+ D+ N$ ~
if (pdev) {
0 f+ G- f4 F5 C5 ?; L$ l, P$ z device_del(&pdev->dev);" x+ d+ x! D4 n K/ N: H- T
7 B/ j: l# a6 i for (i = 0; i < pdev->num_resources; i++) {
" _; O% D0 W6 X% _6 d O struct resource *r = &pdev->resource;
0 H' w# ~/ s K) f unsigned long type = resource_type(r);
: o$ c7 T5 X. k 3 {+ M, {" T$ q8 p
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
4 v2 K: k% Y0 z* F" M5 ]# O# U release_resource(r);
: s$ Q$ E+ `# Z* Q8 n5 v0 q }
8 l; R$ d! K! T }) U; x9 i2 l6 G; Q; L
}
6 X; u# N9 z9 I" Lplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
4 }% O' h2 }2 C) [& J
' X& c" G, _9 P4 g% h* X* Nplatform_driver的定义:
3 R9 C' l, Z. {$ L' L/ ]1 g' y/ I! o @( r' a
struct platform_driver {$ t8 ? A9 E# I2 n" A6 I+ X
int (*probe)(struct platform_device *);
2 ^+ `5 Q& A: F) J+ \2 } int (*remove)(struct platform_device *);* k4 @ ]0 g: ?, \$ ^
void (*shutdown)(struct platform_device *);
+ ~' P9 S) N. h! ^$ d int (*suspend)(struct platform_device *, pm_message_t state);0 Z" u: W. h+ E% `, Y. W j
int (*resume)(struct platform_device *);
$ e$ @4 P% `3 w* t9 f6 r+ a# U struct device_driver driver;
0 Z5 L, i9 x( F1 D8 ^ const struct platform_device_id *id_table;
: M8 `8 I2 G5 B4 E1 {0 u d};
( Z9 D" K- [9 l4 u; T2 I @8 f4 r& o& m9 X
6 I/ i V7 x* y/ X, Idevice_driver的定义:) Z7 V. X' H( f( c" [/ w/ W2 x( q
struct device_driver {
5 F$ X. ^( I, H, s h const char *name; ]8 q f3 z8 r( {( u* `+ n; [
struct bus_type *bus;+ ^- r1 c5 o9 e" k7 I9 y
9 D; f% K9 D4 }. q7 R w struct module *owner;# ~$ u, t0 A( T! q* k
const char *mod_name; /* used for built-in modules */
+ }! ]% q+ l* I/ M, j: T0 ?4 H
9 C( I6 J. t8 U/ }1 c bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
; o6 n/ \0 m6 y. Y
8 H7 ]4 {: k7 W2 B I$ x const struct of_device_id *of_match_table;' p# L. s' E1 ^3 `
const struct acpi_device_id *acpi_match_table;. E+ z7 o0 ~8 A6 [3 Q* Q4 U4 x6 n0 N
+ S+ Z" g6 x. X. S b5 ? int (*probe) (struct device *dev);
" l$ _/ a3 _) B/ ]5 }7 f/ M int (*remove) (struct device *dev);
5 ]) f3 ]5 U$ |* H void (*shutdown) (struct device *dev); O* F8 L# G6 z/ H
int (*suspend) (struct device *dev, pm_message_t state);/ v3 v/ C- J% F
int (*resume) (struct device *dev);7 @. z2 }3 M8 [* u, B: e: w9 P- k) e
const struct attribute_group **groups;
7 ?3 `1 Y" X. T( s T& l : M3 [- U3 K' ~4 `: [# J8 m& m
const struct dev_pm_ops *pm;0 j" [: l# E- g. n- F) F" P
. ]8 W& a v* [4 Y& t' t) h
struct driver_private *p;
6 Z) Q0 |$ J$ i4 y};1 k& e3 |* J, q
3 e+ V& c% N wplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
/ \1 p- V. ^) q4 r前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。( G) H+ {- D' w& t6 w+ `6 ~
, L5 }6 K: C1 h) ?7 b7 J% e/ S4 N" t k
struct platform_device_id {
: m8 r2 {" U. p$ } char name[PLATFORM_NAME_SIZE];
6 S8 I' h8 M" A kernel_ulong_t driver_data
9 A) P* K& g5 V __attribute__((aligned(sizeof(kernel_ulong_t))));
# b1 a' Z% @- C- X6 c! ?; v1 [};
4 }1 z# h/ s& B7 ~平台驱动的注册使用platform_driver_register函数
9 Y: a) ^" q R+ W0 e' a6 [2 J1 Q% z2 o: n3 H" |& }) Y
int platform_driver_register(struct platform_driver *drv)2 A. d4 n2 n! a9 S
{5 [& {4 C5 S J. Y% X$ V6 ^
drv->driver.bus = &platform_bus_type;
6 {( `' p( V& ]! ^& H5 p; n# M if (drv->probe)2 ^* e& e3 |; I9 j
drv->driver.probe = platform_drv_probe;$ ~: y! v& X& Z# L
if (drv->remove)
. o1 F* v) e/ c0 X drv->driver.remove = platform_drv_remove;
* p% D5 I0 V8 W, L5 L5 d- F if (drv->shutdown)( ^% J' ?% m. ^
drv->driver.shutdown = platform_drv_shutdown;, s- P; q% r. n
if (drv->suspend)6 I/ C; g! V# y& I* x" y0 W
drv->driver.suspend = platform_drv_suspend;* v; r* Y' n' B3 \
if (drv->resume); _/ n) T" \' W, H4 q/ l2 c
drv->driver.resume = platform_drv_resume;) h1 M" L- i5 U7 D# q
return driver_register(&drv->driver);
5 Q( T- Q+ W; b7 W} H: a/ S* }+ @) 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函数来注册平台驱动。
+ A* g" j! w8 `7 [/ _9 u6 O$ [0 J相反地,要注销平台驱动的话,使用platform_driver_unregister函数
# t5 D, O% i. D: _3 K7 q: D
) h n" q i3 t' Hvoid platform_driver_unregister(struct platform_driver *drv)
. R7 F8 f4 Z5 a$ o( R$ {{
. [, A8 B5 U& |4 v- D7 l& g driver_unregister(&drv->driver);
0 U* G5 H) T5 q$ W* W" _% k}
/ r$ ^1 n U% u- Q
. {+ |8 w9 t4 t/ U' r附bus_drv_dev模型的框架图3 k' g( a2 J5 V( N* x/ _+ a
8 y3 f! x- E* V+ @# V# V' s9 s* K. o& K, R& X0 O
% X- n# v2 K' m! o8 g& b7 O
: r* }; @7 O( S! U h! B7 Q+ n# e3 _' F' A( n) q$ s( ]
4 b& b8 i4 H R: F* \, L3 V6 b' ?
. e0 c6 g& I4 X% C& W& D+ A |
|