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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
! }0 f3 P, J& l- V# k
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
* F0 {0 v- y6 {& ?! V
$ Z$ N' K  e/ @3 C$ ~总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
" u) W; Y* r% h# @& S2 d3 P. D/ T7 \$ ?0 g, D* O
Linux2.6系统中定义了一个bus_type的实例platform_bus_type3 C7 F: N/ G6 A1 u; M3 T

( X! X% w0 _/ Y1 h* i0 T7 y2 Estruct bus_type platform_bus_type = {% N1 S* R: Q) ~& a
        .name                = "platform",
! ]1 b6 q( A: k% G6 J        .dev_attrs        = platform_dev_attrs,
; D- C+ M# e! Q$ P; K" c3 x& o! c        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
% B, `# T, f0 L; |        .uevent                = platform_uevent,& X, ]  W' a- ~( A; r
        .pm                = PLATFORM_PM_OPS_PTR,; O# @+ a: a) Y; @
};
* Y' z2 G" |0 v8 w; B; e# g: H; t/* platform_match函数用于匹配总线中的驱动和设备 */* b5 ^6 J& c" r/ @
static int platform_match(struct device *dev, struct device_driver *drv)
0 J( w5 K8 G* V+ i3 S& f# X{+ z. Z+ @. A# N! i& k& o; [  {5 |
        struct platform_device *pdev = to_platform_device(dev);
& ]  q  O7 U3 R% Q" |  k        struct platform_driver *pdrv = to_platform_driver(drv);
1 I$ I" I# s' } 6 A& p' b0 p7 j# O% m1 u) Z
        /* match against the id table first */
: n0 l& m/ E- ]8 ?$ c! c4 Y9 V        if (pdrv->id_table)6 b1 d6 m8 h/ C  }6 A, {
                return platform_match_id(pdrv->id_table, pdev) != NULL;" i2 J4 H) G8 }
) N9 L3 J; C! ]8 Y# j+ i: `
        /* fall-back to driver name match */
9 U; J' C: u8 X, ^' f        return (strcmp(pdev->name, drv->name) == 0);
/ S1 m5 \5 m3 n7 ]1 w) e6 o}* o9 S7 i- s* C2 j
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。
0 }+ h) ~6 U. `' x' |: g% splatform_device结构体的定义
# J8 z' I+ c! G  ?
6 m6 \, ^% Y* d* j% C: w3 g' E, S# A
3 n3 ]# S; \" z2 B, ]4 u; Kstruct platform_device {
& e1 N: i1 e. z  P        const char        * name;                        /* 名字 */1 g% c- Q: k- n5 [, p9 |* _  x2 }
        int                id;% X6 g* C9 Y  A; L2 d
        struct device        dev;
  l. N4 B; g& B: {        u32                num_resources;                /* 资源总数 */6 D+ Z5 c: |' D# V8 I9 a, t
        struct resource        * resource;        /* 资源 */( M3 |7 b! A+ v: }* r* H
6 a9 L5 @& y! D; k5 c. J; _( _% S
        struct platform_device_id        *id_entry;
6 j: B* h6 d' K/ k};: A9 i  p6 H5 j# o  z) d
其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。) o/ x* N$ P0 ~% D: m
% I  w/ ^% m+ W$ E  t
struct resource {- \0 ?% j  H6 {" h. y; U% v, K
        resource_size_t start;                //资源的起始值# m7 O  |" g+ m
        resource_size_t end;                //资源的结束值
3 y- T4 M+ N* R8 n7 O/ z  |/ I, q5 e        const char *name;+ H+ k2 e, q* n: N7 A# E6 S
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA, \% G& ?! u' o+ u( ~
        struct resource *parent, *sibling, *child;
( X# ]( F0 n$ a8 I' P};8 s$ B3 P- M) h: f' ~: B& |
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
) g3 u) {* X# a; \9 a: f0 w+ r( R# d1 Z# j  t# f- S

3 b6 c% Q! L3 ~* w1 g/**
* D0 M7 B2 d: K7 d * platform_get_resource - get a resource for a device$ I$ t8 z6 K7 n2 c
* @dev: platform device! j1 ]' Q5 z4 l7 `4 g: J3 @
* @type: resource type+ l( y5 d2 ^5 D5 _2 B
* @num: resource index1 s% ~# u2 i; b! _# i3 V6 n
*/
! S/ t$ A& z% ]. Qstruct resource *platform_get_resource(struct platform_device *dev,3 `) p4 X) R* N
                                       unsigned int type, unsigned int num). h0 M& d) n& l7 ~  B" C8 O3 e
{
) C  Z6 M$ I& x) p6 u        int i;6 h6 _0 s. S2 u- L& F/ q8 y. {# M, S

0 C* ?+ L* ~/ f" d+ x5 I+ W        for (i = 0; i < dev->num_resources; i++) {* ^# ^$ a2 O/ o6 Z) S- t- n5 p  H) K+ f
                struct resource *r = &dev->resource;
- B# |" f, K, s, x3 ?5 O) N# ^ 4 ^' `/ A; B, P, c! ^
                if (type == resource_type(r) && num-- == 0)
6 n+ B" h/ j0 X+ B                        return r;* Q# s9 ^" }# g" e5 Y3 P+ v* a! L
        }- |3 G# w, `$ C
        return NULL;. G+ b  v8 k' f" \
}
$ \4 q6 \  h' r9 E6 `# ^平台设备的注册,使用platform_device_register函数8 m3 }- N( h, B. [
" a3 ^" _" [* h6 ?) m
int platform_device_register(struct platform_device *pdev)
% x1 q# Z+ z) }( O! ]1 b3 y+ @{. \% x" f* O6 J0 V5 I# E. }- ^, _
        device_initialize(&pdev->dev);
! B" R* _0 O5 x9 j( z" K+ L        return platform_device_add(pdev);- |0 s6 E4 g  g) l' g. C
}
( h4 b6 p( H( ~$ `% `( K/ pplatform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。$ c- C4 v! t. c4 S9 M
- x4 G9 z3 e: z; z

; |) L: {; }: j9 P  y+ o" y! g" Jint platform_device_add(struct platform_device *pdev)
' S2 ?0 g/ h1 ^" `$ W) z{+ }- o* B' Y; {$ x4 M8 f
        int i, ret = 0;; G6 |" O+ _1 v! T+ P) W8 G8 k

& u7 v4 F* |. B4 K( c        if (!pdev)        /* 如果pdev为空则返回EINVAL */: i1 \3 P$ o& _, L
                return -EINVAL;, E, d% D  _' c

& F) T2 q8 Z- }8 N        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */: e% P2 a' t! V+ @$ U
        if (!pdev->dev.parent)
6 C6 m9 @3 G  D, ^' p/ w                pdev->dev.parent = &platform_bus;% @, K6 o+ W7 |( N; J$ V2 A( {
1 n. t5 R2 p, @# B
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 *// W6 w3 f% J# r7 Q1 ]0 e: E0 m

' Y7 p/ q) e1 e- ], b, F2 ]3 C        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */1 i7 U5 C( ~: C6 }# C* [9 l
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
& \7 O) H6 v4 g1 \. `2 v( G3 E8 t5 w        else; |$ J6 ~8 @, s0 b
                dev_set_name(&pdev->dev, pdev->name);1 c* t) y! \! [( D9 p- a
4 P) Q7 H& m) q1 o" U) r
        for (i = 0; i < pdev->num_resources; i++) {
, {% Q0 i# P9 u7 L: o                struct resource *p, *r = &pdev->resource;        /* 获取资源 */
* ]( E7 d+ `% L$ t0 r2 _0 F, b ; ~& y+ f7 |$ O4 N
                if (r->name == NULL)
0 ~, r3 _2 y" U' Y. J1 r                        r->name = dev_name(&pdev->dev);
- q4 n% _" @1 T7 c( I
# o- U, |: M) g  m7 `/ Q! t                p = r->parent;
; g, `5 {3 P. M* {% E7 R4 D                if (!p) {- b9 S) Q) ]* i1 x$ s# h. y
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */
' {6 `$ L- S% M1 r  F                                p = &iomem_resource;' j, j* o+ H$ E4 w
                        else if (resource_type(r) == IORESOURCE_IO)
  V2 \9 @. O. \/ r& c                                p = &ioport_resource;
5 b- g" m) O( Q- V; v0 ?1 E                }. S: {. F* r, X# O5 b

1 @- G) \3 |! C- Z5 Q                if (p && insert_resource(p, r)) {( t) K8 C3 J% Q
                        printk(KERN_ERR  c: q  i7 {+ Y6 B
                               "%s: failed to claim resource %d\n",
' i1 C, N% j- E! \+ V' Z                               dev_name(&pdev->dev), i);
* U# I' c3 t* K% L# _                        ret = -EBUSY;
$ j1 c0 P7 U5 \, Z                        goto failed;8 d* V) L. w, h
                }1 Y8 |: I: E; f" _
        }8 _3 r5 G& R" n# z5 e& g2 k6 R
" D" V& ]2 L% P6 |0 Q
        pr_debug("Registering platform device '%s'. Parent at %s\n",# \4 ]9 t% X6 X/ G* @% e
                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));' t5 `! h6 Y% k0 b+ y% A9 M0 a

! N) J, L8 c: Q4 K' G1 x! V        /* 向内核添加一个device */4 |$ m0 K" T# Q2 z6 a4 y
        ret = device_add(&pdev->dev);0 u+ J  V, s% ?& |
        if (ret == 0)" Y+ G3 \+ s8 r& L  i( Y5 W
                return ret;. V- B% J" z6 g0 h/ i) M3 h

: {/ K1 Q0 ~# L2 m0 i- Z$ H. w failed:0 y0 {+ }: w8 e6 D4 q2 p9 m
        while (--i >= 0) {
) B+ i6 }* y) a4 ]                struct resource *r = &pdev->resource;
1 t8 Q- O7 P7 L9 x- w! r3 k                unsigned long type = resource_type(r);
  L; h6 {  J& x" \# B
5 t7 x7 T  v/ z  ]( ?, b                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)( {6 ]6 s* ^" Q7 L* T; x4 X) F
                        release_resource(r);  D( l! X6 e8 |9 D# B% n" W
        }
# _. z1 @* }% [2 M1 Q- t, ~; @
0 d- ?- G- k% z+ x/ @0 o2 ^/ _        return ret;, f& N. y7 p5 @* @9 e7 Y1 T+ R
}
6 q; G! M( w' n% z/ Splatform_device_add最终调用device_add来完成平台设备的注册。* b- m$ f1 l0 J7 b: g6 l% s% h
7 Z0 a- V* o4 m% K: N: u
0 ], }5 ]- w( G6 s2 o+ l0 ]' A; [
( q( c6 L1 L* }6 a8 y( Z
相反地,如果要注销平台设备则使用platform_device_unregister函数3 ~6 e/ i7 F$ n: s5 S5 l* [
: {. B. O8 z( g* ~1 |( }; R  y2 W
void platform_device_unregister(struct platform_device *pdev)) ^8 a5 B0 _  K0 V
{
! i, x8 L6 `9 n5 \( L        platform_device_del(pdev);
6 J; z0 h; o9 D& b        platform_device_put(pdev);
' N- ~7 i. f3 ~0 J$ Q! E}4 [+ y6 t5 d9 ]( H
platform_device_unregister函数调用platform_device_del函数来注销平台设备8 q3 e4 M2 G, G9 f0 w

3 A# e( y" {3 Y8 u( v  [void platform_device_del(struct platform_device *pdev)
4 n. n2 `1 k: h  T{/ _& U+ s$ x! Y9 q" \( n
        int i;
/ p1 Q4 u& E9 P4 D! s0 w2 O
: P) R9 Q! u. M8 t2 w8 q0 V% o' e. C        if (pdev) {
& A4 j6 C% I# ^* o( S                device_del(&pdev->dev);
/ j2 h" H  s, d* l & }; j0 O+ m' G; z( ?% t- O. p
                for (i = 0; i < pdev->num_resources; i++) {
& q) ^( J" d7 x4 L! R                        struct resource *r = &pdev->resource;) @# k+ W" r0 U( A2 V. r9 H
                        unsigned long type = resource_type(r);% C0 C% h( u& l8 h

  `$ k" J! j# `1 \, r$ X1 U$ m1 H                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
2 U) W4 w2 K0 V' R' C% o& {                                release_resource(r);" N" g* m' b7 h1 I3 ]' ~* E1 G! [
                }
. h+ T6 ~+ ?& j3 ?* {1 M4 x        }
6 m* b4 R; \  b2 h3 Q# C}
) f* h- m1 D/ ~$ iplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO2 ?& Z/ ~3 r5 x

) t+ J% k% Q/ g  m/ V3 F% c8 p$ h/ w( b2 aplatform_driver的定义:
, Q* v. r4 s6 I( w5 {) c* h
, E2 c& y( Q7 C# b8 Nstruct platform_driver {
( d# P; J) t6 A5 G5 a- G        int (*probe)(struct platform_device *);, t3 R  x/ {$ q* O) r
        int (*remove)(struct platform_device *);
5 D) P: n7 b) `3 k0 V" G" E        void (*shutdown)(struct platform_device *);" Z+ R+ W  D6 {
        int (*suspend)(struct platform_device *, pm_message_t state);" J* e* n( \7 ?2 \7 [
        int (*resume)(struct platform_device *);; l( n. a& C) T0 Y. ]
        struct device_driver driver;
% V8 A; {5 l. Y8 M        const struct platform_device_id *id_table;# p) d' R/ ~) V! R& h
};& r5 }" U) w# X* S) M

& M8 I2 I7 {0 @" A5 x7 k
7 C$ H7 I" J. K, I: M9 |& a" gdevice_driver的定义:
8 n- C+ K# s7 T, q' Istruct device_driver {
- Y  L2 F6 L$ {5 z& R        const char                *name;+ h8 t2 N6 A4 E+ N* c  U' _! k
        struct bus_type                *bus;
/ z  c2 [$ j: n; T; L  v9 P
2 R9 b# P6 b; l. f        struct module                *owner;
/ S4 N) a! V& t) q$ |/ {! r' C        const char                *mod_name;        /* used for built-in modules */
0 w' }2 c( }, z7 ^$ i+ C/ _ 6 G- j6 G& C! v3 j( R% @, V
        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */
# ~: N1 S6 V+ N" E9 t% {
0 k9 @- u; ]$ }& ^, k: E/ N/ e        const struct of_device_id        *of_match_table;
3 A% }# P: ^7 K4 {# f$ c" ~2 R0 z        const struct acpi_device_id        *acpi_match_table;
+ U! Q$ u2 }% X  ]2 @ % i1 i: A. A& H
        int (*probe) (struct device *dev);! K1 o' h5 h0 ]( @+ z: C
        int (*remove) (struct device *dev);0 e5 v9 w2 z) a. K6 u0 e
        void (*shutdown) (struct device *dev);) C* [! z" W1 I* l. T9 q4 L6 T
        int (*suspend) (struct device *dev, pm_message_t state);
0 Q' q8 g6 [; j% r        int (*resume) (struct device *dev);
  s5 t. X7 s4 O        const struct attribute_group **groups;+ J" ~9 O5 O* ?; g5 w4 i) [& O8 Z: p7 f
7 \) s* Y6 Q% V" p7 L' e% ]
        const struct dev_pm_ops *pm;3 B* g1 U- t9 c! K

2 w# n: H6 U2 L        struct driver_private *p;
$ L6 a. d& K& ?( ^& g* k( c};0 y8 T" B1 T' F* \9 j  g8 R' M+ i' @
6 F2 j( k, Q/ v5 G
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
* l* f3 |- q8 t* v) X( L前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。6 u& R( V- a' A! `! }; p8 G$ M
1 q! i1 y. D  a- |
3 J4 Q2 l) N" }. Z
struct platform_device_id {
* D7 r0 {( k1 v% ?4 `  V1 c% E0 M        char name[PLATFORM_NAME_SIZE];4 F5 X1 Y1 k1 Y9 f
        kernel_ulong_t driver_data
2 v4 g, z1 s& T' i5 N% P                        __attribute__((aligned(sizeof(kernel_ulong_t))));, v4 u4 M1 k4 h: x6 r$ |
};/ V9 L3 _( U- i
平台驱动的注册使用platform_driver_register函数
9 O, A. d3 u( @% U* y7 A3 ]* q) h
& o/ h+ Y8 `0 sint platform_driver_register(struct platform_driver *drv)) ~2 i8 ]  f: V
{! u4 v0 j7 d$ x' t6 W% U
        drv->driver.bus = &platform_bus_type;
% X2 _# s3 }4 m& I# V* S        if (drv->probe)
  k1 H- o% [8 o* M4 Y3 M& q& M                drv->driver.probe = platform_drv_probe;+ M; M& e: ^" l8 [- h: ?
        if (drv->remove)
% O% b, Q: G0 s& B0 ?0 g                drv->driver.remove = platform_drv_remove;( d& ?% }! C# j- F9 k
        if (drv->shutdown)0 V, B5 f. t5 D
                drv->driver.shutdown = platform_drv_shutdown;
0 e- K" U& v$ w" s        if (drv->suspend)
" V  |8 ^6 M, X2 |& j                drv->driver.suspend = platform_drv_suspend;! k" a3 \" u( U; C  \
        if (drv->resume)
3 Y7 A3 f1 O- I. ~! f# J1 p& |                drv->driver.resume = platform_drv_resume;
: y$ e* P% I1 R" ~3 j$ _) Q; S        return driver_register(&drv->driver);
7 W$ e3 w5 H5 ^}" {( q+ X! u. O. N7 [
先初始化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函数来注册平台驱动。
- q& z- @; S+ K. {) x3 W! Z相反地,要注销平台驱动的话,使用platform_driver_unregister函数
" B$ N5 `! B% V. e  c( L1 A7 L
: _/ C9 H2 n- x( T' S8 v- nvoid platform_driver_unregister(struct platform_driver *drv)
, l& j  g. u0 E, F3 r{( [, T5 y) M0 K. L, z# K& b$ b& ?
        driver_unregister(&drv->driver);
9 y) T. ^: v6 v4 z0 f}5 p  p( c" P+ p( m$ [/ J, F
: z6 m# D( [, [8 ?
附bus_drv_dev模型的框架图  ]/ t) m0 `& b0 X7 R, Q

& e' w8 M$ O+ D2 j
; U9 T, o' `! q) o/ j( R9 X. E/ \2 z5 H

3 w5 s! s, H, k" r7 c6 n" f0 J5 C* M4 f+ f% v

4 y# i9 a1 f, w+ b2 d  W7 X% }6 ~
" s; v) j& t$ a  V% v9 A8 t

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-26 09:20 , Processed in 0.218750 second(s), 26 queries , Gzip On.

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

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

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