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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

- w  u% f% S7 |' @* [platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
  s" p6 n0 h9 f+ b$ O5 v; U9 ]5 v! G- @* ?7 k
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。, x. v0 a3 c  o

4 r6 O4 r" V% k$ w5 b1 RLinux2.6系统中定义了一个bus_type的实例platform_bus_type2 p8 l& r6 H$ x5 C

& `1 M$ K$ H3 [3 A+ y4 kstruct bus_type platform_bus_type = {
% H6 v  X. o; x        .name                = "platform",7 c7 @# g/ m2 V
        .dev_attrs        = platform_dev_attrs,0 `# T  ~% A, Q1 g: ]5 Z" Y
        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
9 `/ r- K* u( g1 N        .uevent                = platform_uevent,3 \% S( ~' c' ~
        .pm                = PLATFORM_PM_OPS_PTR,
) E8 [, s" P4 @; h% ^/ d};8 _4 L6 j9 I) y" U
/* platform_match函数用于匹配总线中的驱动和设备 */
5 U; l' G- |0 f$ |static int platform_match(struct device *dev, struct device_driver *drv)3 O3 C3 a. R# W2 D
{: L. Q4 L# m; j6 _7 W; \
        struct platform_device *pdev = to_platform_device(dev);
$ Z( w! O; r5 ^- r- [, b0 V        struct platform_driver *pdrv = to_platform_driver(drv);2 c% ?/ I! i+ d$ b

9 ]: |* Q  m6 d        /* match against the id table first */
" {" p- L- {5 ^        if (pdrv->id_table): @% E5 r5 Q. E
                return platform_match_id(pdrv->id_table, pdev) != NULL;7 u! N( K' K; h1 c- B* Z" l
$ I+ G( j6 o- }8 ~6 l, S7 [2 _
        /* fall-back to driver name match */" p" L+ s$ H/ v5 w' m1 H& T
        return (strcmp(pdev->name, drv->name) == 0);2 @+ e; D* q  X
}
6 `1 |, |8 G; e# }+ v$ u! B4 \platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。" q* O2 L5 M5 `6 y; H% m3 k7 P
platform_device结构体的定义
+ t; D* X- x. s# R$ b: ?  C+ o
$ `/ i# S* z1 y5 ]- A: p: }
) V7 m2 W4 f  m2 Ystruct platform_device {. V/ k' q; l% D. a
        const char        * name;                        /* 名字 */8 `; v, n) P0 b1 @1 {# s& U
        int                id;
4 L5 G5 _& Z4 u: r  r- H( E        struct device        dev;1 x; \$ f% A# F* W0 R
        u32                num_resources;                /* 资源总数 */8 O! w* h% x* _# L3 S' a, V% k
        struct resource        * resource;        /* 资源 */
* o5 H4 p6 U& J) Y( Z0 d
  g8 l7 a. u+ k& w5 Y; L1 e        struct platform_device_id        *id_entry;
9 L& g/ o( p  H( F5 c0 L& |* \};
/ A( e  V- d" y; R8 o% W: L1 `其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。4 B% ?9 W/ Q, c7 ^1 }0 }' O
3 w/ k- i* c; C, |" r
struct resource {
5 r8 c& y! a7 Y$ M0 l5 K8 q  ?        resource_size_t start;                //资源的起始值
- }9 I. L# J2 j        resource_size_t end;                //资源的结束值5 }2 E9 C( t" P2 v! e4 t+ z
        const char *name;/ v4 U/ ~8 ~* n* ^8 c
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
. i6 ]1 G) t: u0 Y3 B& F        struct resource *parent, *sibling, *child;* [  v  \3 v. G7 g) q: C
};( a4 L0 @2 H- @2 @. f
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源8 i: _  j0 K9 W: `: X+ G( }( \5 l& j
9 q9 ?2 j. L1 |5 P

" p! i2 l" W6 M, W5 E/**. ?% E" h! X* C
* platform_get_resource - get a resource for a device3 F2 q9 |7 A1 O  n
* @dev: platform device
6 [) e4 u& ~+ r# | * @type: resource type
0 k: X4 w  G9 l5 ` * @num: resource index
! S2 j+ ^" D: \ */% \+ }6 Q. ?" ?4 r* H
struct resource *platform_get_resource(struct platform_device *dev,
* ^5 q6 k" Y+ L0 _                                       unsigned int type, unsigned int num)
0 h- M& `& b$ s6 _{
8 r; F4 C7 Q4 B9 i: F+ y        int i;
; {- U6 I0 M$ l  w3 h" M* ~ ; a# N- h' w8 U2 j% q( D' T6 ?
        for (i = 0; i < dev->num_resources; i++) {0 ^" i; r, O( [- p' X3 S
                struct resource *r = &dev->resource;1 o6 [5 I4 P' V6 k8 L

) A  t1 G+ \: b5 D! m4 [2 S                if (type == resource_type(r) && num-- == 0)% f& o  p% z3 i, ^$ H
                        return r;4 O) c+ V& t+ r+ q, h4 G
        }' R5 c9 X; S) w7 n; w
        return NULL;2 u) v: }* A' Q& r' ?5 Y' L
}  v0 ]& @9 |( Y  N( _" n
平台设备的注册,使用platform_device_register函数0 j) r# [7 s; X% ~: p1 B8 e

" x$ \; K' W1 o& D: t* W, ^& jint platform_device_register(struct platform_device *pdev)0 q1 C: s' L( h( h9 m' `5 Y
{/ S; z/ K7 I: c
        device_initialize(&pdev->dev);/ e# \4 Z* i: j9 N$ P. h1 Y+ q
        return platform_device_add(pdev);
( B5 ^0 y% ~3 w. B" Z! d}
9 q- `& [7 e; |+ y$ kplatform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
3 D' o: B8 T/ q$ p5 _  c4 |, Z( Z2 X9 l! x$ f! b

. G  \; g7 f! K" d! z( v- A" bint platform_device_add(struct platform_device *pdev)
% S% X+ i, n# p+ {6 L+ t$ p{" m, W1 e5 E4 h8 \2 |* }$ r
        int i, ret = 0;
  h# z- }3 \3 d. L9 }, o 5 w% M' l/ s4 W7 L4 C6 Z+ g
        if (!pdev)        /* 如果pdev为空则返回EINVAL */4 o4 T" E; p# S$ |
                return -EINVAL;
9 s0 S) }. M, U+ v( p* _ * a# P8 \% V  }8 \& N$ c
        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */
% J* O3 S* @$ G        if (!pdev->dev.parent)
6 q7 m& Y& |6 _  }2 |# Q6 \                pdev->dev.parent = &platform_bus;4 Z* f6 N1 l+ e
' `/ z4 x% s% z* E- K
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
7 I! A3 [! z7 W% q: J
- T. Q3 D( }. i0 r: q        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */
0 v& I- o3 i& S$ @" o/ P: I                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
% x  S8 g; w% ^! @8 r: N        else6 T% ~( w+ j6 \. m- ]2 D0 }
                dev_set_name(&pdev->dev, pdev->name);# a2 V) `3 I7 i0 l9 w$ w5 F
9 s9 t6 J2 ]# N! ?# C0 n* u
        for (i = 0; i < pdev->num_resources; i++) {
/ d+ S. n! H' p0 w4 f3 Q6 K                struct resource *p, *r = &pdev->resource;        /* 获取资源 */+ @# c* i& e/ y& N6 V% v: ?) l

6 |+ I7 R4 G2 p' P$ [8 ~. }                if (r->name == NULL)* k. c) m: ~; n; C0 n
                        r->name = dev_name(&pdev->dev);/ X" D; K& l2 k' G- e; _# G
6 r0 N$ Y  ?0 u# Y3 i
                p = r->parent;; Y' {) v* f: P& @
                if (!p) {9 M# ^" H2 W/ T% l7 a
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
; Y( J9 |7 c/ F                                p = &iomem_resource;
6 _2 J, Q! O- i4 M5 i                        else if (resource_type(r) == IORESOURCE_IO)
& `0 P. q8 w1 ?" W8 Q4 t' i+ m! R                                p = &ioport_resource;. V2 G6 _: B1 @, K, _! s$ w: U2 A0 N
                }
$ e4 r& a' [7 Q. x
; l- d7 V  O$ b2 [9 i7 X                if (p && insert_resource(p, r)) {
* l3 k$ B8 }1 B4 @% |6 p- X                        printk(KERN_ERR# i" }# ]* U' K( j( t( r$ K4 Z
                               "%s: failed to claim resource %d\n",- p* h; J' `( g( ?/ C
                               dev_name(&pdev->dev), i);4 b- i, J- z/ W% ^0 v. m
                        ret = -EBUSY;
* W0 y1 c9 l( h$ F                        goto failed;
6 s, M0 k5 Y0 _) N                }9 ^) W$ J! m7 W6 E$ F! ?" B
        }% R$ i' n4 ]2 M1 P& t
9 b$ o, x. c' t: \
        pr_debug("Registering platform device '%s'. Parent at %s\n",9 T7 |2 ?0 Z, w
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
5 f7 m0 K6 O3 k) V1 F& W  R
! w$ `1 I- W& }( g: e        /* 向内核添加一个device */
. i' |* ]& r2 `) I        ret = device_add(&pdev->dev);/ `; Y8 a6 }" U# w# F4 b9 h
        if (ret == 0)
0 {3 N0 B+ ^3 H) N0 I3 V                return ret;
5 U' C- s3 G8 q$ g 3 n& {3 B8 X- y, ~0 y
failed:  f: c" }6 t! E% [- h6 `
        while (--i >= 0) {* t. p; p" i2 i
                struct resource *r = &pdev->resource;8 [/ C& X. N- \/ `  U* R
                unsigned long type = resource_type(r);% m3 d1 |' \* P3 m& C* j

8 O2 Y  b, ~* X! T% u3 w                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
" X9 K* w& N/ W& h( q                        release_resource(r);3 k$ h8 v: Z' i4 n
        }
3 w0 L' ^+ ~; z& d7 R
& e) Y+ `5 f, U        return ret;
9 B. p' L- @! [3 x. I0 a}; V0 x' V  n+ z# s. {6 Q4 t6 e
platform_device_add最终调用device_add来完成平台设备的注册。
+ {/ n6 C" M8 q% {( {! v1 J0 [% H4 K3 J' h

0 Q9 N, @: m# _. c2 A2 N
3 A  O2 S( T! \ 相反地,如果要注销平台设备则使用platform_device_unregister函数! e+ q% C$ z3 w

' U) b" i0 |8 t6 o5 fvoid platform_device_unregister(struct platform_device *pdev)# u' ]: d# |2 X4 c: x8 M: F- J  F
{
7 u$ X: |3 q% t) `* r6 {2 h* F/ z        platform_device_del(pdev);5 Q; {0 c9 e0 \1 Z# t) N4 f4 V
        platform_device_put(pdev);' t& l  l. Z- W, F, I6 j
}& p1 ]( p! h  E3 [+ T
platform_device_unregister函数调用platform_device_del函数来注销平台设备0 \: V0 V/ a/ D% I# k+ \0 c* i9 b
, g8 R" q% q* U
void platform_device_del(struct platform_device *pdev)- [0 A5 E* Q1 B! {+ }
{% K0 x9 ~( F) b  R. v! i: r
        int i;
7 _  |% ?2 f5 C3 f: H" w
2 j! Y/ ]/ J7 Y1 Y- ]. N7 c        if (pdev) {
$ O! M8 |* |) q/ }                device_del(&pdev->dev);
/ z: A* x9 o6 c7 X! I& C
0 g1 t( \/ F% h( O: J2 D5 W% r* ^+ r                for (i = 0; i < pdev->num_resources; i++) {
8 n% u  Y. H' w3 d6 l: W                        struct resource *r = &pdev->resource;
0 n* L* X* ~  q5 s5 ]1 @                        unsigned long type = resource_type(r);, S$ C0 F# D) W: N

& R5 X0 \( o" A# }* m4 e; m                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)$ I! L' s* `1 t: a& j) l! ~; L5 P
                                release_resource(r);' w9 G7 b2 V+ z) B
                }6 q& C7 e0 O; x9 L
        }
$ \# S' h: C* [: k! M: _: S}
1 `) [. E1 R' }4 `, X; G" rplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
5 p( h2 K  l" d$ q, S. I
. V$ }! C2 A$ G2 tplatform_driver的定义:
0 z# f) g% L* S
$ e' U2 k# D$ |struct platform_driver {
6 F  q; X6 c  d7 K6 p7 b" N        int (*probe)(struct platform_device *);
3 A& k) u8 r5 o$ {' G* I        int (*remove)(struct platform_device *);
+ f* C. I+ O1 p. b( ]8 s! ?        void (*shutdown)(struct platform_device *);
- P* d$ G- _6 C# D. C5 u        int (*suspend)(struct platform_device *, pm_message_t state);
, x1 T( S, o% C) o        int (*resume)(struct platform_device *);
$ @" \0 n# i. C  q( V; d        struct device_driver driver;) d8 n5 L3 g6 t* n# W: Q
        const struct platform_device_id *id_table;
  V% {. r1 J5 Y2 z- J};
# t9 m8 \1 X8 X# I9 h4 s
: C! n+ G  V+ K7 ~% l7 T$ D; A5 a5 b& v6 O1 S7 e. @5 i) T
device_driver的定义:
- p7 a5 R0 \9 j+ ?! Z( Xstruct device_driver {
3 `* T5 a  F; W- D0 l        const char                *name;
# k; A) ^3 u: D) X' ^4 n        struct bus_type                *bus;
3 C6 [" a* M# @, c1 ~( E
0 r7 V% Y1 Z" [1 C        struct module                *owner;5 o# ?' H5 D9 J0 o3 _
        const char                *mod_name;        /* used for built-in modules */
6 O' J2 {3 O6 } * ^/ v0 o) j7 w) {5 |7 M
        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */
8 o' j- R/ }9 a
' A. M# X1 f& L# K3 b7 m        const struct of_device_id        *of_match_table;/ G' D* j' N: U: E' Z) F) a
        const struct acpi_device_id        *acpi_match_table;) u! g' ^2 N: H- F! p
, \6 C6 ~8 e; U
        int (*probe) (struct device *dev);
/ X, m' F* \$ Y! c5 u7 Y$ M& P        int (*remove) (struct device *dev);
8 E$ B# M7 C  s. O& `1 w$ h        void (*shutdown) (struct device *dev);
9 b1 s* I- m- w0 Z. A  W        int (*suspend) (struct device *dev, pm_message_t state);
8 M# u( |- |# y5 K5 x        int (*resume) (struct device *dev);
& t+ [4 z( P, W/ r; X( A9 F        const struct attribute_group **groups;
4 v) L& j( `2 q- r( W
* x  f% F# C% n9 I4 [+ |1 \. H        const struct dev_pm_ops *pm;; o+ j' e% b5 v. O/ A+ h- i
+ s5 y8 X) B7 o5 L! T! B
        struct driver_private *p;
$ O, e. b+ I9 H};: }1 f1 s& }! ~) t4 _3 J% R

+ |+ g" F0 h% U+ gplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
' Q" d- x/ j% T3 E前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
8 ?+ J7 A" Z8 ?  y% X1 z3 H8 {+ T% D5 M' d- @/ S2 f: {# w
6 R" u/ `4 }5 ?, e1 A1 R) A) t
struct platform_device_id {
3 m- n$ H/ }7 C        char name[PLATFORM_NAME_SIZE];1 v7 [: v: o- D( c$ F
        kernel_ulong_t driver_data
/ B8 E% |- o+ g' w; `                        __attribute__((aligned(sizeof(kernel_ulong_t))));
) I( O, }7 l& E% z( d. q$ l9 Q8 [};/ R; R9 D, ]8 b5 }9 t9 d; c
平台驱动的注册使用platform_driver_register函数
" U; J0 y$ Y, j8 _0 I, E3 `  a3 x% x' O8 u7 R) K7 U5 ]
int platform_driver_register(struct platform_driver *drv)
5 t1 L- X' Y! L5 i. M' ?  z{
- Y  r/ @- a4 w6 Q, k        drv->driver.bus = &platform_bus_type;/ H5 ~- W4 d* X( y* H# t" U: A
        if (drv->probe)/ H9 M2 e$ Q# F
                drv->driver.probe = platform_drv_probe;/ Y, |+ D- e/ Z
        if (drv->remove)# Z8 J5 p7 @4 w+ A9 K
                drv->driver.remove = platform_drv_remove;
- ~9 x( ]1 o* y/ v$ i        if (drv->shutdown)
5 P# S1 [: h" L: U* C8 F5 k( L; A                drv->driver.shutdown = platform_drv_shutdown;
8 }3 J5 o3 E* V: |6 }9 N        if (drv->suspend)
- a! j" s3 n1 t2 X, k  B                drv->driver.suspend = platform_drv_suspend;
* F: M& [& U0 y0 h  T2 {        if (drv->resume)
) O/ E" [7 N; ^, `1 Q7 i& T$ S                drv->driver.resume = platform_drv_resume;
7 n4 ?! K, X2 [- K$ ]        return driver_register(&drv->driver);8 a3 r- o6 N. o" H
}7 {, J: i9 s& W; A- d) {* m
先初始化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函数来注册平台驱动。
. R: P  e1 [/ u% w- E9 i0 a9 ?& f相反地,要注销平台驱动的话,使用platform_driver_unregister函数
( p( \: K4 a  l( ?1 i/ n) C  N' F3 W  @0 z8 W! l. P
void platform_driver_unregister(struct platform_driver *drv)
$ D  O) @2 m/ z; q- ^' T, J{
4 Y2 c0 V  B6 P: u7 I0 d$ U        driver_unregister(&drv->driver);
4 C, i  c! o, @}
7 L, h% U3 o1 C# @
5 U! O8 m: [4 d  L: c附bus_drv_dev模型的框架图5 R1 W  w, U; Q& b. D9 z& H

( A% W. N0 W9 d, B* i' B+ Y; I8 C/ i$ e3 @, R' Z$ |0 U
9 I1 m4 D; H3 P

# C! e$ p& C6 v1 A2 O& e7 |4 U+ `( B  o- Q5 h/ c4 T
# V. o8 l1 Q6 H( T2 B0 ?
9 G0 S9 a7 M  z- k* F

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-26 10:11 , Processed in 0.156250 second(s), 26 queries , Gzip On.

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

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

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