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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
7 E$ w1 @4 X" O4 E
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。) z, O8 I( B+ V* v& |9 m- y* A1 k9 i
6 _. L, i7 N0 e# H4 D  h8 y9 ]
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。, N. V: N2 _# p  O, m
4 r7 z" z$ W  Y/ ?
Linux2.6系统中定义了一个bus_type的实例platform_bus_type7 x8 L7 @' E8 _( r8 J

9 F. s" s0 Y7 x& J0 P7 zstruct bus_type platform_bus_type = {
8 l, Q/ q3 i# ]  X1 S) X        .name                = "platform",) }  {% v) I1 `( x
        .dev_attrs        = platform_dev_attrs,% g& x& m- [" b# Y& g
        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配6 W8 M) _2 R1 X8 [
        .uevent                = platform_uevent,5 [2 x6 R" ]" c9 u3 A# q7 R& M
        .pm                = PLATFORM_PM_OPS_PTR,
5 I) N- I1 Y5 n+ [2 {4 Y};
. O" A( w! J4 c/* platform_match函数用于匹配总线中的驱动和设备 */" o# Y6 }; X- t2 g  u& h3 ]% O
static int platform_match(struct device *dev, struct device_driver *drv)
& J+ b" @& v4 c+ s{6 d0 G2 k3 `- O9 M
        struct platform_device *pdev = to_platform_device(dev);
8 C- F9 K7 w( C  C. q, z8 O9 Z- X        struct platform_driver *pdrv = to_platform_driver(drv);
7 _3 A) s2 B* G, u5 d. k 2 c( P# j9 E7 R+ J- e4 A* l& s
        /* match against the id table first */+ D9 h3 ~1 D0 h# u$ Y0 |
        if (pdrv->id_table), t9 O- S$ Y- J
                return platform_match_id(pdrv->id_table, pdev) != NULL;
7 g' n- T. w8 M+ h+ X: t$ I# R ; D! o/ `" R- [9 ]
        /* fall-back to driver name match */3 Q+ _; S4 c8 X2 b, b3 d5 q
        return (strcmp(pdev->name, drv->name) == 0);! o. C! X' j: |& `# Y+ l9 Z
}3 y0 o5 [3 t0 ]% e) ]7 n
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。% J/ G6 b8 n8 b6 d3 m
platform_device结构体的定义
* {+ c, l2 {9 I* w1 n  V# y2 E
* ~- R- q3 Q; Y$ W# P# x5 O& B) D
+ F! q2 i" n/ P. J* ~: F# xstruct platform_device {9 Z- b0 C8 R, E  `  b9 _( A2 |% W3 }
        const char        * name;                        /* 名字 */4 h* T8 Y8 P% j) _2 V
        int                id;) g0 ]- N/ s" V! _* |) l. b
        struct device        dev;
. @; t9 e/ J5 g        u32                num_resources;                /* 资源总数 */
8 n. C; ?: y* w        struct resource        * resource;        /* 资源 */" F+ C! u9 z- T! w

7 V1 u; c) `9 z! T        struct platform_device_id        *id_entry;
. I. {' J! `% h* r" }3 ]9 j& j};
1 G0 S4 n/ s6 C% t7 X其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。+ ~. M. n" Z0 V$ A; L" _- ]6 z

% z' }6 c. P/ t! z5 Xstruct resource {
: j1 K  d/ s* y9 Z5 x" b' H        resource_size_t start;                //资源的起始值
& ^' E6 p% I0 _+ \+ n( Y        resource_size_t end;                //资源的结束值
4 C6 O# ~5 I! h        const char *name;, @. r4 J+ u& T
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
" b8 f" a1 @1 t! }        struct resource *parent, *sibling, *child;
1 ]( x, N4 D8 Y1 X};
/ F6 M5 f6 D& c# \9 g. Y0 [有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源4 L& N* |  L: `

3 I" g& A% ?. [8 c+ l  J' w1 v. y4 P( E1 y$ r( t
/**, Z. K* R& `* d: s
* platform_get_resource - get a resource for a device
. P9 D/ ?/ F5 Y  k# p% Z6 q9 ?+ { * @dev: platform device0 B5 z2 J6 x8 r( }! Y, h
* @type: resource type' E8 C7 a# ^$ ?, Y, o9 Q
* @num: resource index- u2 }/ w$ I" R' ~8 C1 _; e/ X8 A$ j
*/
; V- d" \0 k* S5 l) _. istruct resource *platform_get_resource(struct platform_device *dev,
6 v" U+ ^$ q) t0 e+ ~7 S: J( i% R) H                                       unsigned int type, unsigned int num)
) @3 C0 q$ @# M  u" E5 x# q{+ y: E, p6 r5 [: T
        int i;
0 ?! `; }0 S* C
; z* m6 u2 f* H' p        for (i = 0; i < dev->num_resources; i++) {% D8 K8 H2 X5 u  N4 y* n  |
                struct resource *r = &dev->resource;
3 k9 E1 U8 Z. ^7 h! U. |
5 m4 O# j+ Z3 P8 t                if (type == resource_type(r) && num-- == 0)
7 A& G9 |" |  z# [% x- j2 J: u% o+ \                        return r;1 A$ m, x% A" M) e; R0 K
        }
, F: c6 Y+ l( `8 r. N- g8 T        return NULL;: m4 }8 P3 Z3 r  ]
}
( j9 ?, u' L- P平台设备的注册,使用platform_device_register函数. P( G( n  Z7 d5 G, Q

1 G$ Z# e6 ]/ B+ ]. [: {" W* G0 }9 lint platform_device_register(struct platform_device *pdev)0 e, a$ r/ J8 j% x4 C' o
{
, j1 {0 v: L4 n4 I        device_initialize(&pdev->dev);
8 f, k% F8 c$ [' v! a. v        return platform_device_add(pdev);
! t/ j9 z; |( H! s}0 l+ n. n0 Y7 O# p( D
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。0 K/ n* j. N" \% o9 R9 x
* i3 |. K% w6 O2 D- u" o* M
0 G3 ]$ H1 `; u, j) x3 {; d
int platform_device_add(struct platform_device *pdev)9 P5 ^; _3 _, h) H
{! I& d, D; R& a4 i% P8 q  q
        int i, ret = 0;
2 }8 B, H) J2 m, f. |8 w' e3 k 1 F  ?( u0 y; w8 @6 e; O% k" z
        if (!pdev)        /* 如果pdev为空则返回EINVAL */( n: N2 D2 S2 @: _' K  t8 K
                return -EINVAL;7 ?6 s5 y( I* N) x/ p

) _) C! w6 z, Y, M8 V. u        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */
/ x6 z: i  F! U        if (!pdev->dev.parent)
1 Y) A" X6 S1 e# Z: B                pdev->dev.parent = &platform_bus;0 H4 _$ ]' Y" E# A6 |
7 U/ W* v- Q4 l' g* U* J( D1 n
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
# L) ]+ {2 x9 l: L" C* M " _" c! l  k4 n  C0 S
        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */4 Y( d" J- Z( ^4 i! D& n
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);9 R& i- b8 V6 R
        else" ~, O& R% H7 s" N  h
                dev_set_name(&pdev->dev, pdev->name);
' M3 Y3 ~7 Q% ~% q 2 p6 T( i8 d' w
        for (i = 0; i < pdev->num_resources; i++) {" F* Z. `* W0 R3 R: A
                struct resource *p, *r = &pdev->resource;        /* 获取资源 */6 A- w* t5 a0 F0 h4 U9 q3 }
$ N+ L- [! Q7 c- X
                if (r->name == NULL)# D" K+ k! ^) ^5 W
                        r->name = dev_name(&pdev->dev);
/ s$ q8 {8 @/ r7 g2 ]
, s+ D0 C0 s+ @% ?' X5 C4 D( b                p = r->parent;
- v( i# Z+ ~. s  X# }                if (!p) {9 m( C; a7 ]  U( W+ z  y; b7 V/ `
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
) ]: a9 P, L  C( @                                p = &iomem_resource;
/ L* h, E/ b$ D! K1 w! m                        else if (resource_type(r) == IORESOURCE_IO)0 g% `( Y$ \/ N' ?
                                p = &ioport_resource;
: K, n/ z3 C, B3 h$ \                }5 m5 S! q8 J/ G7 B
7 T! E. s+ }) g  U* y' {  c
                if (p && insert_resource(p, r)) {6 J# ~# T; T! {: E) G6 r
                        printk(KERN_ERR
6 E& G- @6 m; c: e& G                               "%s: failed to claim resource %d\n",
* q7 n, e( u5 O- r                               dev_name(&pdev->dev), i);
; R5 B' v9 i: w3 ?/ t! w0 F8 `                        ret = -EBUSY;
# n3 Q' y$ C+ o" p; c/ L. e                        goto failed;4 \/ i6 B, y9 E4 k4 Q; `2 c
                }# R2 p4 \( k# W
        }
; w- i' F  z2 J
& u8 V$ b, {7 W* }( _" `# ~        pr_debug("Registering platform device '%s'. Parent at %s\n"," k9 s2 w2 G/ W" x) X9 ?' h
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
# L& ^7 R7 J  f1 ~8 y7 h! h 7 \$ _1 O- G: r* I6 {
        /* 向内核添加一个device */7 B0 E4 k3 Q1 b; J" @
        ret = device_add(&pdev->dev);9 ?& v0 `& E" i5 W/ Q$ g
        if (ret == 0)$ z* M- n: F; B& z$ J) \
                return ret;
2 f# Z' P. |( ^1 a- c: \
; V9 \0 ^: `6 y' y! N- E failed:' k8 T' |1 i# f6 ~) o0 b% s3 Z
        while (--i >= 0) {+ @3 g) H5 l# }" O9 }
                struct resource *r = &pdev->resource;
7 ~7 q( i" q4 D$ d                unsigned long type = resource_type(r);) O5 a6 @( O$ `; v5 ?

+ B% S( v$ n. P8 X" d) S                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
& O9 H7 ~# k" c1 Q* l) Z+ }6 n0 K                        release_resource(r);4 l0 V& F8 L; H$ G7 \" W
        }! j, Q) W% |, R4 \4 a' g! ^6 y9 v% E
- X( c4 N6 p/ h" Z: ]
        return ret;; _  G$ y7 N; A' M  V  n" j
}
2 z- y. X* g  M+ D; i2 |% _4 Vplatform_device_add最终调用device_add来完成平台设备的注册。
1 i* H: g3 \9 V) ?; ~# ~* O. t# {4 \9 B

7 x" c: X: b! ?4 X6 X8 F
4 H3 P9 F6 w8 G+ [ 相反地,如果要注销平台设备则使用platform_device_unregister函数2 V7 ^, n9 f) i+ P( J9 _, p

1 u7 w% X% r) e4 }void platform_device_unregister(struct platform_device *pdev)" g+ R5 S* f- k) @
{2 i' }: d( ?  U) u
        platform_device_del(pdev);
+ u' ]7 {& H& a0 x        platform_device_put(pdev);6 h* u: }+ J' D4 T
}  G( P4 Y; S  `( ~
platform_device_unregister函数调用platform_device_del函数来注销平台设备* O7 O; b( y$ B6 d; W0 J# @

0 ^% C0 f( ]6 n. d6 Hvoid platform_device_del(struct platform_device *pdev)9 g- p# V' @$ ^6 |0 X3 \; s! u
{
# P7 x6 t$ Y" `' t  F$ y3 `2 S        int i;
5 w# Z- W, z' Y1 O
9 V, }! s7 [6 j! S! O        if (pdev) {% V; s; o1 ^/ ?& a( r
                device_del(&pdev->dev);( w  N( F$ u; ?9 i* o1 `1 z6 k
# @' V  B3 s2 K) q
                for (i = 0; i < pdev->num_resources; i++) {; j( j6 G- J$ l6 W! `+ E( H
                        struct resource *r = &pdev->resource;
: n$ Y9 L4 \# B) P2 m: Z                        unsigned long type = resource_type(r);
6 s& q- f* q8 z& R6 [- [. r  y! W" z
# N7 U) Y; `: C! E0 a- ^                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
9 E4 r$ B9 Y: d% _$ y  H! _                                release_resource(r);  B4 t  e/ ^; q/ G. }) k# c' Y+ l
                }7 Y5 \1 P1 Y+ i! M5 a2 }) q
        }
+ h3 L5 j2 e! S! ~5 h! w5 \}5 K) P* S. ^8 |. S$ X0 i( P
platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO  d! z' R5 t) C& R3 J
& x; |! E0 o5 l1 Y& F7 {  t/ |
platform_driver的定义:
7 q* J6 U: l& x, J1 R
% @  F4 K6 w3 ^( D# x/ v+ sstruct platform_driver {
" Z2 t3 u) D0 d+ A        int (*probe)(struct platform_device *);8 m6 U( K$ d! h( K6 R
        int (*remove)(struct platform_device *);: W' G/ w8 B9 K, {- |
        void (*shutdown)(struct platform_device *);
: }; q; I/ k; L" L        int (*suspend)(struct platform_device *, pm_message_t state);
: g$ f3 m$ L9 m: h1 s2 c        int (*resume)(struct platform_device *);
# P' V1 |7 e1 K/ g        struct device_driver driver;
5 P7 k  B( Z$ h2 z8 u5 d        const struct platform_device_id *id_table;
+ W+ R: |3 ^5 v5 L1 L};7 L# n. `# Q6 N' h

+ x1 V1 m9 t- {3 e0 G0 ]
; D% e' f' J7 f+ z6 l7 wdevice_driver的定义:6 G7 ^, o# A* H. X9 j8 E- D6 F
struct device_driver {5 g. _& `# ~" F" u6 l6 P# K$ b
        const char                *name;  D" r# \4 l8 \& p& g1 P8 s1 J
        struct bus_type                *bus;
* f2 V5 z) c  y
% v; O' }# V; S! O" Y% X4 b0 b        struct module                *owner;
& Y0 z: \4 c# v, Q& \) j        const char                *mod_name;        /* used for built-in modules */) c) t1 ?' m! e

+ r9 @; `- A! Z! [+ u0 f        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */0 X5 l2 b2 d( [7 m% J8 i3 ?0 N. {1 U
; w# `  H& g9 `4 U$ S, C
        const struct of_device_id        *of_match_table;
  Z' Z0 e' u3 O- L  Q; X6 g2 m        const struct acpi_device_id        *acpi_match_table;! Q- a9 }4 S9 j4 s% i
5 ?. }! A. A% O0 R' T
        int (*probe) (struct device *dev);4 P& ?4 _# @0 U' t( ~
        int (*remove) (struct device *dev);
0 x# s  d- K4 z- l        void (*shutdown) (struct device *dev);
+ g1 d( t' P8 ]  E4 y% C        int (*suspend) (struct device *dev, pm_message_t state);
( C& H5 |: i* w        int (*resume) (struct device *dev);
/ }: p; k. @# k+ C, q& G; _        const struct attribute_group **groups;
& [$ O% r; c' H% q& l3 p3 X) B
& Z# _. d: W. [        const struct dev_pm_ops *pm;( Z) H/ O% S% B7 P( u

  J  k2 a0 q7 z8 F+ z* }% L        struct driver_private *p;
  W% F( P7 L* c/ J# m, {" i};' e9 j; E3 S) }
+ o3 C+ j: t! A- T- H
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。( Z. e6 u' ~/ O3 k2 F+ Q
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。- H: B8 A- N0 B# v

0 y5 r& P- Y: K9 T2 }  c3 q
  d) T3 E% x1 D9 a: S3 hstruct platform_device_id {* ~' b& H* C) L( s5 l" y. m
        char name[PLATFORM_NAME_SIZE];4 T  T# \; U1 V" K2 F3 @* V3 `
        kernel_ulong_t driver_data
+ h2 Z) d3 g" c( A                        __attribute__((aligned(sizeof(kernel_ulong_t))));$ w/ f( |$ t6 T6 R$ d/ ^
};* E' R  T5 U! V  z- G$ G
平台驱动的注册使用platform_driver_register函数- ~* D+ o5 v4 t, C" W* X
. y6 c% {( P- f5 D3 Y7 {( y- L
int platform_driver_register(struct platform_driver *drv)
: W" O8 n' Y: |  f/ _+ b* z" ?) d{: l( r. s: u% e( q$ ~
        drv->driver.bus = &platform_bus_type;
( _9 B( U8 |. t, W( S9 n, ~        if (drv->probe)
4 i/ n- K# t# U' P' Z                drv->driver.probe = platform_drv_probe;4 m+ U. U( T' v* K% s* q( g* I
        if (drv->remove)6 P" p) \4 F; l- `* e
                drv->driver.remove = platform_drv_remove;4 O8 i  R% t; N$ C+ L8 O7 n
        if (drv->shutdown)- z- p) b2 R& Y. b- g
                drv->driver.shutdown = platform_drv_shutdown;
. I: F) O8 o. `0 d  y( X        if (drv->suspend)
- e- w+ i- k! U# e, y: f                drv->driver.suspend = platform_drv_suspend;- L9 |: ]$ y: y; A. v' h
        if (drv->resume)
6 r( I+ K9 E: P9 b8 W$ A                drv->driver.resume = platform_drv_resume;% `+ Q; f  w- \! v% {- @# K! M
        return driver_register(&drv->driver);* ~5 @9 ~0 @8 c7 U
}
- ^1 Z% E2 g8 Z& `  @先初始化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函数来注册平台驱动。% j# R! c' [; d" \
相反地,要注销平台驱动的话,使用platform_driver_unregister函数2 e9 r5 [+ d# z2 `' |8 E
% c6 y) o$ r% {
void platform_driver_unregister(struct platform_driver *drv)
' B3 p" E) h& a8 R' N# |{
' W- O+ W* w4 f        driver_unregister(&drv->driver);% u9 L* w8 d! C8 V: p8 F; r0 j
}# L2 t+ l0 ^8 z$ y0 i6 E: A3 \

/ L0 e( `  y! ~. c+ S附bus_drv_dev模型的框架图: [/ x: V2 \5 P- g/ f& i8 y
9 V% _4 }: I6 Q

4 l- b1 J2 p" B' Z/ a( h1 O2 A) D3 a$ X, {; e+ l
. T! S) V& \; X9 p1 ]
7 \, _( ]0 d, o3 g7 M8 y  z6 W

0 X& O; k8 t& V2 g8 y* Q3 s
/ r+ R% M  o9 X4 J- d

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-7-1 05:55 , Processed in 0.078125 second(s), 26 queries , Gzip On.

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

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

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