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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
9 H% q. ^- h5 s+ w, l9 {  D
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
, U: @) ?( X9 y" ]3 ?  r8 Z) u; j: V7 e' X0 M  V% P7 E! Q* d* `+ ~7 h
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。2 S. s: X; o) n) ~0 V6 @
$ x! h, I7 p. W1 T1 t
Linux2.6系统中定义了一个bus_type的实例platform_bus_type4 x5 `: B1 e0 T7 `5 R4 p

' p5 {5 Q( p$ x; J* `' jstruct bus_type platform_bus_type = {# v0 J! u5 J/ S& d8 _2 n
        .name                = "platform",
! P4 K7 E7 R* s: R7 S        .dev_attrs        = platform_dev_attrs,3 @2 u+ ~8 i4 o' e5 D. |
        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
) J. t  {0 n0 A        .uevent                = platform_uevent,
4 x6 E5 q" H* M/ B$ s        .pm                = PLATFORM_PM_OPS_PTR,
3 P* h7 a5 O- p" x5 ?};( F1 A* b; K* ^, B+ c  F
/* platform_match函数用于匹配总线中的驱动和设备 */+ ^0 Z% F  ~0 w- {; [
static int platform_match(struct device *dev, struct device_driver *drv)" ?6 ]3 s/ k  a3 r& a
{" N- b) F6 h1 J- W
        struct platform_device *pdev = to_platform_device(dev);7 u( ^+ ~3 c% y8 ~% Q6 E! I
        struct platform_driver *pdrv = to_platform_driver(drv);& y/ f) M. p# ?; B
6 t5 R/ Q' i5 p& A1 \
        /* match against the id table first */8 ^/ F/ R3 o* @- m# H
        if (pdrv->id_table)
* J" `. u) Y: ^- U1 Y. Q                return platform_match_id(pdrv->id_table, pdev) != NULL;
9 w- S! U" g# u% g5 K/ {9 e . Y# Q. p2 v: B! f0 L, }, N4 ^5 K( q3 R
        /* fall-back to driver name match */5 w7 P9 I# X2 u8 @
        return (strcmp(pdev->name, drv->name) == 0);- A0 i8 G: E: ~' X; s: q
}0 A: r3 Q# `+ s1 Q7 k" A
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。9 S  r/ k+ I+ t' X! @+ h) |. s
platform_device结构体的定义8 O; ^1 s6 K) H+ V) m: D
* U/ B$ i# ~  {# ]
& d. i( @; @8 L* C) y
struct platform_device {
9 w3 z0 R9 Y6 ]+ Q) A- G* }2 G        const char        * name;                        /* 名字 */
1 i' v. {. D' K# O        int                id;
6 J8 f8 q- }# w* i        struct device        dev;
* `# ?  _: m+ F4 k3 D        u32                num_resources;                /* 资源总数 */1 A8 k: o4 y5 R; E
        struct resource        * resource;        /* 资源 */
# |; B9 T& ?! n9 ~: b 2 l% }& }1 U  F1 M. u
        struct platform_device_id        *id_entry;* E% n8 s, D! ~, U2 m: {" N
};; m/ ~8 r3 H/ M' E  y
其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
3 T) S6 B, M/ C8 O( U8 Q" K# s9 d+ N! [% M3 t0 w; |: u
struct resource {
3 A5 M1 [: ?  @  c$ Q        resource_size_t start;                //资源的起始值
0 Z1 i6 @) k$ l9 y        resource_size_t end;                //资源的结束值4 a0 X& T2 Y% L1 w- \( D
        const char *name;: A& B! Z1 n; L1 P
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
7 X: o! U7 k! W/ D% P' i# p        struct resource *parent, *sibling, *child;) V3 }6 A5 ~7 ]' A5 ^9 C( R
};
# A! Q3 E* i, R6 ^8 m' O有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
2 x# |( T& B# q  t" h# B6 _% H3 A. k% i2 M* k
1 Q( e6 ?4 J3 g9 h" T4 v4 ?8 {* J
/**
' |6 F/ d2 _2 X& {! e! R% y6 P * platform_get_resource - get a resource for a device
  G. M  S" N$ l * @dev: platform device9 i1 K) l  k: |2 S; q3 }
* @type: resource type
& X; Z$ i3 z. C* O * @num: resource index9 G5 u6 ?# h) M5 e( U
*/: K) j3 {2 {' @
struct resource *platform_get_resource(struct platform_device *dev,
7 R2 T4 x8 t4 v. x% X6 {                                       unsigned int type, unsigned int num)1 v3 f; o6 l, p1 ^& O
{% X$ I' Y; v* ]9 Q" l1 K  D! r
        int i;& k- n: a5 w* E) u, I+ Z
7 N1 H( l# a- m2 w+ j" p
        for (i = 0; i < dev->num_resources; i++) {
4 ?: j( ?7 y( p* j+ E: Q* n# W                struct resource *r = &dev->resource;
; U, Q" @& T" i3 F- `- S
% X; }( K: e( X4 n  U7 K- h                if (type == resource_type(r) && num-- == 0)
4 \  M& M+ d/ Y8 J4 Y% W                        return r;
& r: x* l6 J5 A+ j4 x. j! l9 M        }7 j/ C$ W: ?( r6 e# w* s
        return NULL;2 Q* H; Z5 S% g! O+ O6 q
}1 m4 c& R* L0 R6 m
平台设备的注册,使用platform_device_register函数
; h( c: `% G& S# [7 \6 d2 s& R4 {2 j& q! l# C+ j$ t
int platform_device_register(struct platform_device *pdev), V; I5 ~$ I( \; [- J; f6 q
{
( |1 U2 L4 h2 \- D9 C, l        device_initialize(&pdev->dev);
8 u: E; w( G# z! a6 U        return platform_device_add(pdev);( ?! D0 D! o9 g& Q5 Z1 j) {9 Q1 U
}, \6 A% c! E3 {
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。  h* m. b7 Z0 L5 e

8 N; n7 D5 m! ?& C' Q$ A, d: [) m9 |' a! c; X  r7 `
int platform_device_add(struct platform_device *pdev)
( v$ o$ p% N6 u  C{! h; m, ^7 s. L  m1 r2 d# F  i+ }
        int i, ret = 0;$ ^- R% ^* s. Y' \# s8 [! i

0 U& O' R* ?7 U% q. {7 Y        if (!pdev)        /* 如果pdev为空则返回EINVAL */
+ C& w, ]8 P2 T. }9 o; j                return -EINVAL;
$ S$ D9 S! P9 t+ ]7 ^9 j 9 v2 t, N3 T/ w- i# s
        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */$ ]3 ^9 A# Z" N) y1 S- _3 ~
        if (!pdev->dev.parent)( n$ y8 I; g6 |# e! W% z
                pdev->dev.parent = &platform_bus;
6 |- j9 I; b$ @0 J1 ^6 N0 H* Q  g+ t 6 f: i" }$ ^, ^7 G6 H. h
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */! ^/ S4 e. o% Q% y9 G" M( B4 G

* Z) v, ^" b6 Y( s2 R1 a        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */
1 q! U! r' m7 A4 _                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);) ]0 v$ Z0 q6 ?7 G  o4 J7 q( b
        else* u, {: g+ M6 \( Y, X
                dev_set_name(&pdev->dev, pdev->name);
1 h, c# v: w2 A) m) k 6 a$ n# `, i6 |1 m9 W
        for (i = 0; i < pdev->num_resources; i++) {) j9 n, w2 ]; e! z
                struct resource *p, *r = &pdev->resource;        /* 获取资源 */
+ @. _+ o/ V, ^# D/ q& [8 N
& W1 ^  @- Z: e9 ]1 p9 e* Y$ ^                if (r->name == NULL)4 Z' W; K7 ^0 p# {
                        r->name = dev_name(&pdev->dev);
& g! x* r6 m; |# H% e, i4 e ( G/ |0 ?& Q1 F7 a2 m0 {5 z1 x
                p = r->parent;
5 c  i, g; T1 i. A7 c; K4 c% }                if (!p) {# X* D5 S2 X/ \  f1 f5 f
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
& z# K# Y7 J8 }7 v7 y; V                                p = &iomem_resource;& [" ]4 L" p$ `& b/ D3 E6 _
                        else if (resource_type(r) == IORESOURCE_IO)
* p- d2 g# x  K/ _3 t) n1 @                                p = &ioport_resource;# h$ A- W' P! g) _, V5 }
                }! [' q0 X+ h6 y! N: l

6 U9 e' Q3 m- |6 C+ z# O1 a3 P, i                if (p && insert_resource(p, r)) {
) i/ Q) }' o: w# b% b# s8 P                        printk(KERN_ERR
2 W' Q8 D/ ~( n1 C- k                               "%s: failed to claim resource %d\n",, z. `) {! t: j. P6 [, p1 }$ L
                               dev_name(&pdev->dev), i);9 h: A7 E3 Q' P" J" |
                        ret = -EBUSY;
9 F, t) j9 J: @/ \7 `) m3 u                        goto failed;8 c4 p0 j5 t6 J2 Z5 g
                }! }% W$ x8 w% J. r
        }# p2 m$ s% l+ W

% H% n* Q3 H! m( g5 i. O: `" _        pr_debug("Registering platform device '%s'. Parent at %s\n",
  ^4 u& D3 g' k9 G5 B/ x                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
4 Z  r5 y$ X  W2 z 6 S' O' i9 @# P8 A5 m
        /* 向内核添加一个device */$ A2 e6 o2 u1 l4 U6 [9 ~; ?
        ret = device_add(&pdev->dev);
! z( V$ c3 l1 V9 \- T* v        if (ret == 0); x5 e: \% g4 g5 @0 ]! D
                return ret;
- f) m$ [. @/ c; C
4 L4 ]0 W8 a. ^3 t  y  n: D failed:
3 ?3 ^, s* w# M  Z4 M& g6 h0 Z        while (--i >= 0) {
7 g7 p) e8 N5 W) s6 f8 M                struct resource *r = &pdev->resource;
& g3 J9 J; h: ^! N: e6 _8 k                unsigned long type = resource_type(r);
+ B1 m" I( K/ f) T. g: I) J( F
, h; _  Q6 Y& E. m: ~! N                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
" J9 ^% p7 L2 y- P* E, f" Z: w1 E                        release_resource(r);
1 u2 n! m& @  V. k4 X* B' q        }1 R. ^2 P7 d1 B  @
  h( j% p" S/ A4 n. z. U' c
        return ret;; [7 r3 `& {  \, K" ]
}! W) _# P6 _% l+ g, b  y; r# O$ E
platform_device_add最终调用device_add来完成平台设备的注册。
7 N9 O( r. t8 w3 M% s6 ?2 |4 x  L9 r$ P, `, p

7 o4 o, q  ?% w5 I
2 }- B9 p1 Z4 l 相反地,如果要注销平台设备则使用platform_device_unregister函数
0 x7 Q- m* @8 _7 k$ x8 N: }5 @" N4 T, U4 i/ R4 Y
void platform_device_unregister(struct platform_device *pdev)
$ ~8 a4 w. x! R7 N{0 c. K8 `) s" d; Q5 t6 m
        platform_device_del(pdev);
! o' `5 Q4 g2 W        platform_device_put(pdev);6 W' {1 [/ E0 W: L6 x
}
, G0 x# U& h. [0 r, K  O. Rplatform_device_unregister函数调用platform_device_del函数来注销平台设备# m6 A$ c* D. }& L' f
2 X$ N7 ]) p& @7 z
void platform_device_del(struct platform_device *pdev)
. J( W; X" a- x8 `; `: a{
0 b8 ~, ~7 M% }2 i% h+ d        int i;
; ]1 L$ `( a! h7 t$ J; y" c
! j  l* y0 ^% ^: b        if (pdev) {/ L! Z7 u* G7 q4 O
                device_del(&pdev->dev);2 Q0 r) {4 t4 w! l5 @
- U0 J2 q8 ^, u. X
                for (i = 0; i < pdev->num_resources; i++) {2 L3 _) D7 J& a2 |
                        struct resource *r = &pdev->resource;7 u+ J$ T7 n6 P2 s/ e
                        unsigned long type = resource_type(r);1 W6 b3 l  A! Y% T, W( }4 G
7 j+ c. _) E& O) e: x" I- L
                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)$ g2 u" U* V' y/ o  a5 V9 n
                                release_resource(r);
& y6 t& j# i% v. |! _                }- n2 Q% C6 }; `
        }- j% V+ m% g9 O* J# Z8 _( V
}. w8 ^/ `% M8 e3 b2 U6 P4 g% X7 p! }
platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
* w* _. i, W% I: x4 t- d
1 c3 Z2 h4 Y! \0 l- v5 Gplatform_driver的定义:9 i0 B4 `0 ]  U
: X* ~) y! L8 D+ W5 [6 T2 A
struct platform_driver {
4 S! m3 a) ^) Y! @+ V6 s5 Q        int (*probe)(struct platform_device *);
5 I8 ]9 R, o8 [1 q        int (*remove)(struct platform_device *);
4 w9 h( P0 V( C! W% v& F) }# T6 N        void (*shutdown)(struct platform_device *);
0 x4 Z  J, `, \+ r- B3 D# i- L# L        int (*suspend)(struct platform_device *, pm_message_t state);- }# Y4 r1 x5 t
        int (*resume)(struct platform_device *);
; V& R5 p! M4 w, |4 a  @3 Z        struct device_driver driver;
" W( t. N; t, q  l- j; J) a! T        const struct platform_device_id *id_table;2 A# i. |8 i; P& Z9 |
};+ T- ]1 P5 x6 F+ l5 \

# g  h9 y6 B  S6 w2 g: ^/ Y( S0 e4 M) e# Z+ }6 {" l5 F5 c
device_driver的定义:5 e7 v3 d! |: o. F/ F; g$ H
struct device_driver {. a4 {0 ^5 e. p8 ?
        const char                *name;# D' u3 j) E' S( e
        struct bus_type                *bus;& i7 G  F8 O  Y4 I7 l) _7 I0 A

( c$ r6 _1 G- y        struct module                *owner;
. |; v& z  n2 A, e  \# ]0 q& r8 u        const char                *mod_name;        /* used for built-in modules */3 w- b% i& A3 Y9 j

8 e9 t4 e- o9 s( ]5 N& T! i        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */
$ _0 i3 z; b2 y3 w- d
1 t* D5 X* a9 ]  q2 h3 E        const struct of_device_id        *of_match_table;
0 c- ]  K7 [+ Z9 l        const struct acpi_device_id        *acpi_match_table;
5 I3 P: I$ Y7 c0 b - R) a% v2 y" a8 `$ k
        int (*probe) (struct device *dev);
# E+ P. t! t. {2 l/ s, E        int (*remove) (struct device *dev);
3 }$ l6 ~# J5 j2 q! ^/ D        void (*shutdown) (struct device *dev);, Y5 z5 U+ z6 P. W
        int (*suspend) (struct device *dev, pm_message_t state);! y3 y8 H. i9 F- r( Y3 V- n8 ]
        int (*resume) (struct device *dev);
" L7 p' k- j' L5 G! P, \  s& h) t7 t5 w        const struct attribute_group **groups;; G* s! }( o& s; W& l

8 U( L" Q+ s' G; s& O4 ^& _        const struct dev_pm_ops *pm;  Q; M! l2 x8 q) |& Q8 V
3 V. J) y: g" ?* F
        struct driver_private *p;
) m* x! H5 s- `& x' P" U  p7 h( m8 x};& \8 M: z. [* `# x

4 d$ y8 u6 D; Yplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
# H6 k8 R& ^7 Q, G2 M% k1 O前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
% [; @2 k. x3 q! }4 U! A# n; s' o) K$ K' J) w& X8 D5 i# ^
1 ~$ v9 {7 j' a; V2 C, w! M5 r
struct platform_device_id {
4 K: e, f. d( D$ e        char name[PLATFORM_NAME_SIZE];
( [4 q$ K% e. ~) m* [' q        kernel_ulong_t driver_data
3 S; U) B3 a4 _9 S- u                        __attribute__((aligned(sizeof(kernel_ulong_t))));& g7 J! H$ z$ E4 t7 Y( e
};7 Q) Q7 X# O8 v0 m2 k+ @  m& B
平台驱动的注册使用platform_driver_register函数
% Q5 f4 ?/ x8 {% G: k; M+ S3 w
+ r5 ^0 y+ D2 l$ K' h' oint platform_driver_register(struct platform_driver *drv)  _8 X+ `) N, k6 X3 \! I
{
) z  W$ `' Q+ T, N4 e6 @9 _! B        drv->driver.bus = &platform_bus_type;: X$ b( J. j% ?* ~! ]% Q" Z9 n
        if (drv->probe)2 l! J( v; w# N# a5 S
                drv->driver.probe = platform_drv_probe;- c" c7 v# ?- e" L$ j& k9 f# q
        if (drv->remove)
0 K$ `0 R4 S8 n6 x8 E2 \7 K2 y" T                drv->driver.remove = platform_drv_remove;
' ~# i( p7 J# `4 H        if (drv->shutdown)
2 X, U' |# j" A* A% I4 P                drv->driver.shutdown = platform_drv_shutdown;
3 X4 B9 Z7 \6 {* o5 ?* Z        if (drv->suspend)
# t$ c* ^6 U$ z+ C                drv->driver.suspend = platform_drv_suspend;9 U, `! e! H5 V
        if (drv->resume): v- _4 M9 _0 W# D) G
                drv->driver.resume = platform_drv_resume;0 d- ?7 O5 Z& f! J9 a
        return driver_register(&drv->driver);+ T$ [7 W0 @- r  k' G
}
0 N: L8 J& j" A' i1 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函数来注册平台驱动。7 z) Z# _) b3 v3 |# F6 E+ S
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
. k; q8 n; i+ e, L5 m$ U4 h2 M# z$ V
void platform_driver_unregister(struct platform_driver *drv)
( C& z: ^5 m9 p% F{5 a6 P9 s4 P# z1 c
        driver_unregister(&drv->driver);, H  a8 w5 W7 x- X* W
}: F: f; a; x; }' ]# G+ Y

1 f  `% ?2 P" q附bus_drv_dev模型的框架图
& `8 c/ F$ A$ I. Q4 | 1 m8 U9 c( o: ~" E6 i* a6 w: }; n
! T  \( z  w5 J
& R3 I* |. U. E/ _
+ Q- e! |& V* _

# p! i& C2 z, S% J; f8 L
6 v7 }- j) l& W4 m! B! q7 g  n
6 g8 a- Q5 c+ O# J9 Q5 ^

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 21:37 , Processed in 0.156250 second(s), 27 queries , Gzip On.

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

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

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