找回密码
 注册
关于网站域名变更的通知
查看: 270|回复: 1
打印 上一主题 下一主题

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-4-21 10:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
4 O" u) w: B7 B7 L5 O, T
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。2 @/ }4 v/ `$ e2 t% u1 u/ e

1 J6 e/ {$ d% Y9 I4 \! O总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。4 X2 h# e" a9 z& @+ T4 y& ^
$ e" b9 \; U5 N; B/ z) L0 S
Linux2.6系统中定义了一个bus_type的实例platform_bus_type1 c0 [2 Y& ~  e" V

$ W+ U' o9 L2 V2 q- kstruct bus_type platform_bus_type = {9 N  v4 L% {% s( c9 f4 F) C
        .name                = "platform",& E4 d4 Q4 W( x
        .dev_attrs        = platform_dev_attrs,
$ D4 \- X2 S3 t$ P7 f        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
4 n. X9 b2 w2 u! f( Y( R+ N. i        .uevent                = platform_uevent,& _6 U. b) z, o/ m# J( g
        .pm                = PLATFORM_PM_OPS_PTR,3 |6 q1 w; k3 i4 ?8 Z% A
};% |. l( M  B% l4 p1 [
/* platform_match函数用于匹配总线中的驱动和设备 */$ L. j- J0 N& l, }/ [& @! L% ]) R! U
static int platform_match(struct device *dev, struct device_driver *drv)# c. V( G" ^) c+ l, Z
{
8 a5 S( G! ]+ V: I        struct platform_device *pdev = to_platform_device(dev);
1 Z' q! r* Q9 m/ ?, d        struct platform_driver *pdrv = to_platform_driver(drv);
& ?! ]- P, L7 a4 d. f
. o; t/ n- A) v: Y+ r& w        /* match against the id table first */
, n2 ^  I* i! s        if (pdrv->id_table). k4 [" ~7 d, j! j7 f
                return platform_match_id(pdrv->id_table, pdev) != NULL;
8 d5 q- `# h$ x" f# N( |% E * y& l. p4 D* C( a
        /* fall-back to driver name match */
' F; l& g6 @: f  g- m* H        return (strcmp(pdev->name, drv->name) == 0);1 c" N2 D7 L3 {  I. ~7 ]5 }/ l- [
}: b- L4 V3 D! I" f4 U& S
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。& I7 R: c* ~8 E- n; f
platform_device结构体的定义
& t7 c9 w  w( y# Z% f5 c7 J. g; T1 M# T; _8 o4 C2 H: u( J4 A* r
& i( U6 H) @  s+ E7 u4 y
struct platform_device {
# l. X& f" Y3 e8 z$ L- U1 _2 f$ H* D        const char        * name;                        /* 名字 */
5 R# z5 j* h& f5 H; _7 Q# K- R# Q        int                id;9 W: F9 P$ a8 N  z' ]
        struct device        dev;
) W; E; R+ U5 C3 i        u32                num_resources;                /* 资源总数 */9 _* V/ v0 A8 Z
        struct resource        * resource;        /* 资源 */
) U) t5 W) u' L
; z# z0 X  K% X# u        struct platform_device_id        *id_entry;% @9 m& n+ Y/ T2 z
};
: h+ T& q$ m/ f1 G( u其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
) i( s9 S1 L! N8 L) {* u' d3 {  F" j1 M9 }3 Z6 f  J
struct resource {
4 Z! a2 b* }, H! y5 }        resource_size_t start;                //资源的起始值6 w# s7 B0 y' @% }- {9 t# d/ Y! c
        resource_size_t end;                //资源的结束值: R( g. F6 c( h- P; Z
        const char *name;
9 i" G' f4 W0 w; W4 q        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
  S: b$ B4 X9 S' ]% B7 G/ k        struct resource *parent, *sibling, *child;2 H2 p2 C; B. X4 t6 r, I& v! K
};4 \* `' N( }& a. `/ P! s' R
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源- V) I/ T! A9 b6 n0 {3 x

1 G5 S7 o0 w& x! ?. S. ^/ b1 c" O! \, n- [& r( S7 v
/**
6 s: ]8 d) b1 ]; k: {' i2 S * platform_get_resource - get a resource for a device  l) K: x0 G/ ?! @
* @dev: platform device
, F4 l8 m4 P3 D; q# j* W6 w6 Q1 b * @type: resource type7 k9 {# n, ?, G. O9 i. _1 X
* @num: resource index9 g. ]. K4 Y# S6 T
*/) `2 I: v6 Z$ c. N$ K! [
struct resource *platform_get_resource(struct platform_device *dev,) B7 v" X  o, L( K! P
                                       unsigned int type, unsigned int num)2 q" w4 x" u( s/ {! u
{+ _: N; S- L. e
        int i;4 ]/ A( `/ }0 K- ^

) L+ C: N; G, A5 a        for (i = 0; i < dev->num_resources; i++) {% k/ E) K  M0 H# ]
                struct resource *r = &dev->resource;1 n; v# F1 l* {& l. n) I

8 V! R. [4 s! u1 X9 M                if (type == resource_type(r) && num-- == 0)8 u; |% n! k& v/ q( f" T
                        return r;* i# i7 I2 S/ J
        }+ r0 ^5 s7 r" C0 p7 P) h
        return NULL;( l& _/ e+ Z0 S  A# B
}7 P2 x0 v8 l" P* C) p2 T5 r& K3 o
平台设备的注册,使用platform_device_register函数: f& ?6 P2 }& r# I7 u
- v$ i3 i% l( y6 i! q5 @! W- _' y
int platform_device_register(struct platform_device *pdev)7 m8 {+ U5 N9 I% m2 W- |3 \
{
& T1 M) p5 C) k+ u        device_initialize(&pdev->dev);
, a, |$ a. P, ?9 l  u6 n* ?        return platform_device_add(pdev);
. i7 y/ M' ?( G}7 q/ X( L& _7 `, a5 {9 e9 h) X& |
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。, f# o) V# l  R& I
( H# a; `) E% o1 d  n0 C
1 R- F4 _/ M5 }3 B3 |, [+ v  Y
int platform_device_add(struct platform_device *pdev)
% ^5 _# {4 x. h8 {: T{, a* ^( n. Z% p, [8 W; J& ]0 z
        int i, ret = 0;6 e8 w9 _5 L2 w/ R( z2 N1 i
6 s$ K* {: s, R5 V) U( A
        if (!pdev)        /* 如果pdev为空则返回EINVAL */% h/ y9 i$ c2 c! |
                return -EINVAL;8 f+ p3 O! f! F* N, Y
4 U4 J. _4 r9 `9 {
        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */! I; y2 ?9 z2 Z
        if (!pdev->dev.parent)
( G1 h3 G' N2 K. `                pdev->dev.parent = &platform_bus;
; R$ f5 k2 o5 |/ v# v6 B2 q: } : v$ D. L0 H8 t# Z# q9 w
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
# R5 D7 e9 u* f : `7 T. X* y! Q4 p" H5 g
        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */
& N$ g9 C. S$ J" V% q                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
3 ]& Y; b# |; t* |        else* C$ \( A" j6 A& E( u7 V) p1 d$ d
                dev_set_name(&pdev->dev, pdev->name);
  u, p' S' j+ E$ {" D* c
8 ]8 r9 @/ l. K4 M+ X# U% I        for (i = 0; i < pdev->num_resources; i++) {' H" J1 F  l; S  G% u% \" d% L; n
                struct resource *p, *r = &pdev->resource;        /* 获取资源 */6 C; d' d& ^9 R; i) t5 u0 ~) G

! S+ B7 g6 A6 @- E                if (r->name == NULL)0 b; t7 Q+ ]" d0 C8 N* H/ V
                        r->name = dev_name(&pdev->dev);
& w* R: i% i. B3 D  [* k' l
! o, E, v8 k" l! v                p = r->parent;
* M3 E3 H  D3 L                if (!p) {* T# ?  H/ B+ A
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */( v! c/ @  C6 h7 c% p
                                p = &iomem_resource;+ T, E! I1 e1 K( @
                        else if (resource_type(r) == IORESOURCE_IO)
- {% s9 M8 a0 z6 l' [0 ?# z                                p = &ioport_resource;" }0 U) z& q0 P9 f0 w' r7 D) u
                }
+ B4 Q# l5 n2 W& Y% n " R* k1 a3 O6 b, Y& V6 J* ^% b
                if (p && insert_resource(p, r)) {
. Z% j- w2 h8 I9 x2 z0 c                        printk(KERN_ERR2 F1 l& O& `" ~, [+ t8 m1 P' d- R
                               "%s: failed to claim resource %d\n",& C4 j" a  f* ^2 w* t
                               dev_name(&pdev->dev), i);6 P$ O* e/ f' ?# a
                        ret = -EBUSY;3 a$ Y/ O+ ?: R3 e  i. R- S
                        goto failed;
& F' P! h! k) r1 d$ `1 Z                }
. b6 i/ U' X6 _) m7 ]$ P" Z3 x4 V2 l        }
8 I/ r, _3 H9 Z2 B! X0 \ , v7 K# B- k0 N: [# f- B
        pr_debug("Registering platform device '%s'. Parent at %s\n",' D/ r- J3 W  Q, C" M; l: j' l
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
+ m; Q9 ?6 C9 V: B5 j3 Y) S' D0 _
1 S6 w7 u# I2 Z5 m/ w- a7 p        /* 向内核添加一个device */0 t  w3 P# _1 A' Z$ M
        ret = device_add(&pdev->dev);
& P* A0 I8 h) ?2 B5 v        if (ret == 0)! P+ E) d; e$ Z- w" B$ k  _1 _" l
                return ret;- t8 x$ [! F& e  u
3 C, K  y: f% f2 ?6 r6 d/ i! I
failed:, T5 ]4 y. W3 w8 }* p5 g
        while (--i >= 0) {+ z: C) O* ?) T( n9 p: v
                struct resource *r = &pdev->resource;
  j# v+ [5 [( x' o. ?                unsigned long type = resource_type(r);( i, k+ X% U3 x+ b
0 z# p! O. o7 d2 d
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)) s2 u+ U5 H; S! C  a5 @2 P9 K
                        release_resource(r);9 D( a& ?6 b5 \' }' D$ @# M
        }2 u7 O9 \2 t' ]

& q5 v- R2 j4 G$ V/ o, u5 P        return ret;
3 u! y  L, C) P0 I! @; H}
7 M* q$ T5 @4 n/ U( Q; D$ T$ Yplatform_device_add最终调用device_add来完成平台设备的注册。
3 @/ d3 h+ l# P2 k7 v3 d
+ A3 }4 N* K  j, x) f- b4 j- F( O4 w$ v9 z" J& f- Q' \/ W

  D) T# o  \5 q 相反地,如果要注销平台设备则使用platform_device_unregister函数7 O- O6 E8 X; [& K* O4 E% |9 x
  o& o$ y( E# n: J$ j( P+ h
void platform_device_unregister(struct platform_device *pdev)
* L# q$ u0 T: @, |& t: h{
. {, H9 ^8 z  R% L        platform_device_del(pdev);  _* X) Q4 k! t  J3 o4 k6 N2 j
        platform_device_put(pdev);
8 T! p  X( h8 [}
" H% E8 n  f( J2 lplatform_device_unregister函数调用platform_device_del函数来注销平台设备0 F5 V7 @* Z+ z( r$ L* G
% z5 M/ D) |' |! G' t  q
void platform_device_del(struct platform_device *pdev)
+ X7 ?/ x. f' Q3 l{3 Y3 \' G7 }0 k* a
        int i;: b" z5 h+ E  p8 r
+ E0 V0 ^: T- r9 r" ?- v4 w
        if (pdev) {. [' o+ \3 K& F
                device_del(&pdev->dev);6 \, L4 ?. D, @* l
, }- J7 ^& W5 _* P/ E
                for (i = 0; i < pdev->num_resources; i++) {
. O* C) _9 ~; X! z+ D& F) R/ R9 ~  o                        struct resource *r = &pdev->resource;6 v2 }) e$ j* i9 e# ?* t
                        unsigned long type = resource_type(r);
$ |7 b8 ]% C# `7 R9 t7 K' R
2 _0 q5 G( X+ ~9 |( g                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO). e- m# X1 q2 n. V! @! n
                                release_resource(r);' g% J5 j+ t# R. Y. I' o. t- I+ y
                }
. d, N, [2 M, q8 ~+ |! a        }
$ B" X- }  s0 r. t6 ?3 h9 u- T}
& W8 H+ `% x4 \4 V0 E5 M& u. g" D. `platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO8 P. w3 I  ?$ }# A( v

; z7 y0 K  k8 @- gplatform_driver的定义:
; f% e/ E' M  J. W1 l
5 `7 n! r0 `- u0 I- D, _struct platform_driver {
) [1 l) Z# V4 M  E8 s( ~& ]        int (*probe)(struct platform_device *);( D/ C* T4 w2 P. c2 @. K8 n
        int (*remove)(struct platform_device *);
9 ^/ g" u: D. T1 W8 k        void (*shutdown)(struct platform_device *);
. _- N5 D1 B1 [/ [        int (*suspend)(struct platform_device *, pm_message_t state);
! }/ h4 b9 n1 _8 K        int (*resume)(struct platform_device *);
# Z+ ?4 o/ L" w, }        struct device_driver driver;
  G2 Z3 \& E( N0 t. ~        const struct platform_device_id *id_table;
6 u6 Z4 U* z0 Y5 S};
% ?% q6 m. U. @/ q( \7 \
" L- \6 U$ w: ~" |/ s( K! s
  q4 V: r" A* W9 o- @% kdevice_driver的定义:9 E+ i1 H0 \! q4 I: o/ c; ]' O- z
struct device_driver {; H7 B7 `( a! ]  p3 x
        const char                *name;) V6 V  |8 c8 p  N5 M
        struct bus_type                *bus;
5 B  k- X8 h3 h" l% w& f 7 r& L0 z6 \; B5 B& q
        struct module                *owner;
' s9 O% K2 ?& [8 n1 y: k        const char                *mod_name;        /* used for built-in modules */
2 X2 b8 b4 T/ D& u# y
& Z# [9 t* _0 ?% m        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */2 Q; u) C- A' W
3 @; Z9 g  k1 Y* G6 |, w, P2 I5 r2 H
        const struct of_device_id        *of_match_table;
9 w' i# T; Y( [* v8 Z) a( {        const struct acpi_device_id        *acpi_match_table;# ?. r7 |7 t$ r+ z

7 K# m, G5 K% U1 A9 C, X2 p7 t        int (*probe) (struct device *dev);
3 V3 u' |3 `9 |, ^% l        int (*remove) (struct device *dev);
9 H+ n( X% G8 R% {( n+ b        void (*shutdown) (struct device *dev);
: r+ r4 {- Q; v% e        int (*suspend) (struct device *dev, pm_message_t state);& O" `) `; \1 {7 B: |
        int (*resume) (struct device *dev);4 R7 ^" r7 s3 o
        const struct attribute_group **groups;! W) j$ Y: u0 X2 o1 _  ?8 ^# l1 Y
8 R( @1 R" f8 l; Y- G8 y
        const struct dev_pm_ops *pm;
; O) ^! a1 t: b5 l0 s- g" ^# c
( `$ Q6 F( _9 A" R& ]3 d- Y3 i' n        struct driver_private *p;
* q# c3 D) p5 h+ U! o};
' ~& S5 [, z0 R$ V$ }! r6 h  \, @; w5 S1 f
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。. k+ Z( r, M: W1 ~" Y7 S' ]
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
; ]0 H: n+ V" Y# ~4 _) d, o* ]7 b% l! c

4 P, u. C- k) x0 i( ^  }struct platform_device_id {
1 w( E0 R+ J6 D  q' B: Z3 h: x        char name[PLATFORM_NAME_SIZE];) A, p0 p5 y. g4 ?
        kernel_ulong_t driver_data
5 p' e9 E& p3 q. G                        __attribute__((aligned(sizeof(kernel_ulong_t))));; F6 p% P/ s+ a( t- B+ d3 K
};
4 W$ h6 I/ v' z, Q, [平台驱动的注册使用platform_driver_register函数
7 W* b1 X, K& I$ X5 F. L% V+ x
! T" o0 M; B3 `. t7 M2 Z) o( Dint platform_driver_register(struct platform_driver *drv)$ W3 M' P4 I# y& G1 v  k
{
4 J2 K) j- @9 i7 |: U( m        drv->driver.bus = &platform_bus_type;
3 M* Q3 R  I+ y( L1 s& K6 E        if (drv->probe)& q0 H1 z* m6 Z
                drv->driver.probe = platform_drv_probe;2 y( a8 l( ~1 j. _) P! k- @+ W
        if (drv->remove)
1 }" j5 T: G5 R2 O7 c                drv->driver.remove = platform_drv_remove;4 `. J- z- B5 I" `1 ^) K: Z3 m
        if (drv->shutdown)  s. L- {8 O! u" {1 }4 `  ?
                drv->driver.shutdown = platform_drv_shutdown;
* @2 f/ g3 }5 @4 }4 x' k        if (drv->suspend)
7 d) ^& J+ }2 W3 g  n: Y                drv->driver.suspend = platform_drv_suspend;
) e- I$ y7 O1 H% Y        if (drv->resume)9 d. I% t2 l& H9 G( O4 t2 x
                drv->driver.resume = platform_drv_resume;
  ?3 @1 Y5 B" s$ ?2 T        return driver_register(&drv->driver);! O8 s/ u) d; c8 z9 d/ l* m: U1 r
}
6 b/ X  E4 E3 E9 J" c' Q( K先初始化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函数来注册平台驱动。, e1 }& j0 q2 i6 B* O  v5 G
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
+ d0 w7 f. S! O) E; u9 {
6 O5 {* q7 k* X- u) f7 D9 kvoid platform_driver_unregister(struct platform_driver *drv)* a& E5 i! B( A  y, [/ s
{
9 l; j" o- h% l# k& s        driver_unregister(&drv->driver);
% g& Z5 K5 w3 k9 d3 L5 ~}# O# f3 d+ ]$ u; j! Q- ^

, q  m* f$ D/ E" A6 X附bus_drv_dev模型的框架图
/ q, d1 B/ [7 B4 v. _) a" |2 I' z" l 5 d0 g, M8 S/ C4 Q) v( d# v/ s

0 V, }+ U- u! O, u3 e$ ~& g6 h; g$ p$ A; l

) g4 {' ~+ w$ S% F- S2 c
1 j" O- O6 D1 X/ @: o4 O  g" |" K" t. z
) B, x8 ~" Z( Y3 Q0 G6 Z

该用户从未签到

2#
发表于 2020-4-21 14:20 | 只看该作者
Linux平台总线驱动设备模型
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-10-26 00:14 , Processed in 0.171875 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表