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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
$ F2 n  ~* _9 G0 V; h
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
4 T4 \- ^7 Y1 I: a# |" }% L6 a' k7 U1 `1 V* }, ]
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。/ V; X' z' `( _- U

- ?! f7 q4 I4 zLinux2.6系统中定义了一个bus_type的实例platform_bus_type" l! q2 v8 }& {. P: u

9 s% u# d0 n+ J8 z) ^struct bus_type platform_bus_type = {
$ \! y( }7 h' @% I2 K        .name                = "platform",5 F) M" Q$ Q" @9 C4 W! l' a
        .dev_attrs        = platform_dev_attrs,
: C) G2 i7 |6 R        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
7 X! k( \' n: f! a. D$ C        .uevent                = platform_uevent,
) I# e6 K( a/ C! Z7 B2 n        .pm                = PLATFORM_PM_OPS_PTR,
& |+ A6 P! E6 M$ m( n};
% A+ k9 V' h) g. n- I. r/* platform_match函数用于匹配总线中的驱动和设备 */: Y  R  a# y' @% x  c. S: v4 B
static int platform_match(struct device *dev, struct device_driver *drv)% a2 Z& P( z9 W/ `
{
# S# M( H5 t  Z        struct platform_device *pdev = to_platform_device(dev);9 c$ {) V, s/ ]+ a& o- f
        struct platform_driver *pdrv = to_platform_driver(drv);
6 |: X7 F) X7 @" i1 Q
$ [4 c7 g* Q& u9 T        /* match against the id table first */* o5 ^$ l+ \$ i4 M6 U
        if (pdrv->id_table)
( S1 }% V# J- a, B3 }                return platform_match_id(pdrv->id_table, pdev) != NULL;
2 _& V' B( E( d$ c" z. b
( N% s& b# |; f; g        /* fall-back to driver name match */
# D8 w. m1 c* {- A! I        return (strcmp(pdev->name, drv->name) == 0);! @9 U6 s( g5 A$ d
}' s( F4 u; S! M4 e# }  i0 c$ [
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。0 |$ t6 F6 m$ [) b
platform_device结构体的定义$ G% I& G0 k- v% e

7 }9 ^1 t! A" H# ~  K5 k/ c
9 z4 y8 C8 y/ w7 u, T. U% l1 n3 u; jstruct platform_device {
! a* z  [; q! i" a: @, e0 }        const char        * name;                        /* 名字 */. t! ~: p& r2 [8 l. Z' e2 R
        int                id;0 U. X5 T9 R9 k4 ~3 u  ~, C
        struct device        dev;8 W7 K0 U" Q- h9 c) T
        u32                num_resources;                /* 资源总数 */' K9 ]7 }5 A; L' c, e! Z
        struct resource        * resource;        /* 资源 */
. F. {. N4 Q+ f% V4 Y
3 h. U/ y/ i( r* K+ T; V( X* ~        struct platform_device_id        *id_entry;
3 B) _, U) m* |) S3 T  J};
$ h/ d8 [0 F9 P4 E0 \: u- _+ z其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
" F4 a) b& I. b' z$ x8 h2 E/ ?! F" v6 [) |0 w) T
struct resource {
2 b- k: n, Q( [# P9 I) ~, q        resource_size_t start;                //资源的起始值
$ T# i  e/ I% k) o& w$ u- V        resource_size_t end;                //资源的结束值! w9 r# D7 s7 c9 }: i0 k
        const char *name;% S% v! }/ E! G: H# V
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
) P' T- A$ R; L5 q+ s        struct resource *parent, *sibling, *child;6 B3 V* U; ]* q3 f8 Q! s$ q& P
};( `: R3 K! j  P. h* W" F$ I& u8 |
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
2 M% D: |: E# m4 S4 K% l  R; D" n) X0 v& h+ Z. x+ L: J% Z  y
( M( I) R4 c  r7 X0 T2 E% D
/**- |# d4 G" c7 Q# _/ z7 I
* platform_get_resource - get a resource for a device' f, Z& [- c- {9 V$ H
* @dev: platform device
6 L0 V5 r' G: ^+ m+ D( ^ * @type: resource type- [* ^8 n5 x! i9 t4 T
* @num: resource index( M( p& D, G8 w, W& o% n( o& Y  ?
*/
* x' ~& V; }% u' q$ z7 f( Estruct resource *platform_get_resource(struct platform_device *dev,
; U! ~. y1 G0 X) {                                       unsigned int type, unsigned int num)
, Z  W! l$ z  T' p4 E! s{
2 o- w0 x* P, Y3 d! J        int i;1 ^" y; c! q! m& l9 d  d( i9 _$ c

5 h: p# }' k9 N& u3 {4 D/ J        for (i = 0; i < dev->num_resources; i++) {
) N4 G3 U7 v4 ]* L* K- l, I, o: I                struct resource *r = &dev->resource;( O" o' J- F* z, A2 {9 |) J7 A( a
& G- U  N4 a& t6 p
                if (type == resource_type(r) && num-- == 0)
6 B; d8 K1 ]" P# ]3 U$ g                        return r;
; }' [1 z" I; n  V        }
( g9 g8 w, B6 L. `1 N/ y  w        return NULL;
. L/ Y" e) ?6 p& n( T7 N}9 Q3 D& ?0 l) a4 g" h
平台设备的注册,使用platform_device_register函数& o- T$ N% \% i0 B- c# i

. n! X- A  Q) J4 S& p4 O) f& Oint platform_device_register(struct platform_device *pdev)8 u, N( r5 k7 Q; w! n
{; W- Z  A) C1 C/ K- ]; q) \* |- r  b. `
        device_initialize(&pdev->dev);
; n8 E, U1 f$ R4 r* z6 o& {; T        return platform_device_add(pdev);
  j1 `, }/ P" H' [# X  E}
4 D! V1 W2 A7 V' X2 ^% ~platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
  T: K" W  y! c& Z( ^+ w& J( p$ }& y# [  V( s6 W: |

. H, b7 _+ O2 l5 y- Zint platform_device_add(struct platform_device *pdev)! J, T1 w: f  ?, C$ C4 G
{9 a8 \( p5 X- k# G# m6 ?; a0 F
        int i, ret = 0;
9 {$ l* ~  l( G' j! T- s  Y' t4 a7 k  S
/ Y4 I* K+ P, z. M$ _5 C$ A0 d        if (!pdev)        /* 如果pdev为空则返回EINVAL */
1 W1 e$ F7 N7 L7 B0 N, R' b+ G1 C                return -EINVAL;
% F8 c7 B3 \1 N# M . O! w! A9 S+ `* b9 u
        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */# G! G8 A. m- @/ M
        if (!pdev->dev.parent)
8 D; ^5 }! U7 L) m9 U; A; \1 r% f                pdev->dev.parent = &platform_bus;
4 K" O. n! I% m- ]0 o8 A
+ Q& D  J! P# o* _        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
) q& N9 G: Z  Q8 T& X & F) p  e, @7 }9 x: `, M1 O: y6 f
        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */$ t8 z! t" I6 U: ^# c, D7 n
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);) Y' T: ~: X6 d
        else$ ?; R( X1 o* G. Q7 j) O
                dev_set_name(&pdev->dev, pdev->name);
4 i! d) Q! E' y: p - d7 b* C' a6 G% i: ?5 s
        for (i = 0; i < pdev->num_resources; i++) {' ]* h! I+ p! |( u8 V# R% U
                struct resource *p, *r = &pdev->resource;        /* 获取资源 */" N0 ^, p8 D, S$ M: k! @5 K1 Y
( t" C. H. e3 O, V( V
                if (r->name == NULL)- k0 g1 _1 {& a, o
                        r->name = dev_name(&pdev->dev);" j: v' S8 U( Q4 w

) b3 k1 s6 G+ \& q  R# I& p* X                p = r->parent;& f& t- r8 {/ T& ~" j" t9 X
                if (!p) {& F( o- Q4 ?6 C1 V6 I
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */) v& D* q" J( l9 E; a7 n
                                p = &iomem_resource;
' |1 I. D* J9 R0 \% F: R+ W% c                        else if (resource_type(r) == IORESOURCE_IO)
4 N1 l0 ]; X3 a; ?# W                                p = &ioport_resource;- u4 C/ ]8 O$ N, ^7 w! F$ e1 ?
                }' f; k) K, D! y  f2 V' w

. h" u; ^* B% e                if (p && insert_resource(p, r)) {
/ X  D( z2 x! q4 g6 s, G( r; s+ c                        printk(KERN_ERR+ @6 S4 s5 v# h( h$ Q3 j% i- |
                               "%s: failed to claim resource %d\n",
& G9 C5 ?+ y) R6 p" Q( L                               dev_name(&pdev->dev), i);
! L' }4 H5 X% L# L( M5 r                        ret = -EBUSY;6 t  ^7 h- m- e, Z* S! H2 L& N; X
                        goto failed;7 b( M/ `$ h3 L* I: v4 t
                }3 C" i- X* S) M0 [5 e; v6 n
        }, k2 {- V$ i( B& y6 W. K
; V7 |0 o. u( v* L( ~# q. L4 {
        pr_debug("Registering platform device '%s'. Parent at %s\n",
* M: ]0 b" G/ h                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
* E$ @7 y3 G4 n; O- k6 z4 Y! { $ q3 d9 s& d* M: K
        /* 向内核添加一个device */
& H6 g9 a$ t4 u$ d( O9 ^8 [        ret = device_add(&pdev->dev);/ e$ G0 h/ P8 ]( f. i
        if (ret == 0)% O  O% ^( r: Y3 F4 [& m
                return ret;6 S& D  g3 N: L- [' F( q

/ u; l* T; y7 d# S8 v failed:& e$ V( s5 z4 h+ t/ O
        while (--i >= 0) {6 m& ~# Q/ E3 @
                struct resource *r = &pdev->resource;
, ]6 a8 S, ^+ ?5 y* v                unsigned long type = resource_type(r);
2 M0 h1 l6 u- x# l; ~% ?7 e2 m
0 C6 I' B5 \2 ]9 {" o2 h                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
! \/ L2 g! A( z                        release_resource(r);5 a" j0 h- D; F' U$ |
        }
5 s2 k9 K" c2 k! e
  A( d& M. |0 n/ G        return ret;. `3 y( _% f! @' i8 I
}0 X7 O& Y( E( F3 X* L
platform_device_add最终调用device_add来完成平台设备的注册。
, N5 @0 n6 f  Q4 I  i* U1 x$ a) T. a3 ]) H! p  ^) r
% M5 a, ~- y3 Y# @3 E
& k7 S3 \3 l; i( r
相反地,如果要注销平台设备则使用platform_device_unregister函数
0 V' P& e, f8 f, P: }4 O$ g9 p6 |, H6 h. T, Y4 J
void platform_device_unregister(struct platform_device *pdev)
) m) [* W- N* k! o3 R! n: N{% Y- x6 c% ?& V/ M; C
        platform_device_del(pdev);; m& C+ h6 I" ^( M% `( A8 i$ N
        platform_device_put(pdev);; R+ a( J* Y( o1 W9 `0 a
}8 A- T  j# Q5 M3 h  S
platform_device_unregister函数调用platform_device_del函数来注销平台设备' r- X3 I9 f5 _6 @

3 {% p% }& ^* S% W/ r7 Mvoid platform_device_del(struct platform_device *pdev). l4 O( w: |( j, O
{
" ]3 T' `" z4 m. a        int i;" R2 L% D& h+ q; j% D& f+ U# c

: l: J/ i: p+ h$ X* p) x        if (pdev) {
3 Y4 Z6 y- O/ H- [9 E% W& {                device_del(&pdev->dev);# d) D# y. [* |# J2 `) w# }5 T4 C

' Z; p( U* g7 @4 ?                for (i = 0; i < pdev->num_resources; i++) {
# e- q, ^& u  F                        struct resource *r = &pdev->resource;+ }6 D, `3 q# o( k
                        unsigned long type = resource_type(r);8 N5 E6 {: ?$ n* Y8 w4 b
) M! o/ ^+ k6 O+ f4 ?3 n. H/ m
                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
, r/ T0 q4 x6 J! c                                release_resource(r);
9 i9 [) y5 O+ T) M                }
2 R0 n& {- ?8 q5 G6 a" S4 N        }
) w  w5 P: K6 z}
. v7 B; {$ u. _platform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO& o, F. G' T; h# U5 v/ H1 z

5 ?. R# h  ?8 z1 Fplatform_driver的定义:' Q% G9 n$ F4 a

* \7 E4 ?2 I/ ]9 bstruct platform_driver {6 }0 O# s' w' A% s8 [# c# h+ r, f
        int (*probe)(struct platform_device *);
/ X- \$ h  S+ h! S# ^8 c8 l        int (*remove)(struct platform_device *);, X+ _- l# u5 S) y* T2 B! O
        void (*shutdown)(struct platform_device *);
7 \" S) V2 X. J' R# K" S* A, |% b        int (*suspend)(struct platform_device *, pm_message_t state);% W1 Y. G) \; s! r* o0 O( |
        int (*resume)(struct platform_device *);- T1 `4 N/ O7 d1 S2 `, g
        struct device_driver driver;
+ c+ H; F8 Q& q& E$ C2 j! X        const struct platform_device_id *id_table;
( X! c9 |0 l3 Q9 X};
* }, ^9 O7 g& |/ R$ `1 A4 _/ X4 ?1 ]* x. B

. |  W) B/ R8 V: [device_driver的定义:3 j. `* X, E9 U, {5 g
struct device_driver {
! V1 D( z) K" ~2 r- u6 Z        const char                *name;0 D; a( a8 z* w, L0 D9 T
        struct bus_type                *bus;
$ n& O# H  V+ F, ]
  }% o: V2 q5 w/ i/ M& O  |        struct module                *owner;) ^  j- n3 E8 i& C9 Q& }
        const char                *mod_name;        /* used for built-in modules */1 s+ {% b; k1 ?6 [9 F& K2 t# a" }$ E
: p# K( D3 r/ I, @3 L+ ?
        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */
  v" D- p& y# K0 t. e; J  D
% g+ s1 z! m$ f8 b7 _0 z        const struct of_device_id        *of_match_table;; R% j7 E! F" n4 D
        const struct acpi_device_id        *acpi_match_table;
9 o5 b( z( u: R& g" E) }( g 3 P! k7 a( p3 P# A2 n6 _
        int (*probe) (struct device *dev);
7 Q0 k3 `+ [: G3 a5 R        int (*remove) (struct device *dev);9 b. k1 u3 ~( j6 l. C% O' W: }
        void (*shutdown) (struct device *dev);
# I2 j: `7 t% n1 K. L        int (*suspend) (struct device *dev, pm_message_t state);' y, @3 I  }6 M1 ]
        int (*resume) (struct device *dev);0 Z9 R6 v7 k( g. j" O# V/ R3 E
        const struct attribute_group **groups;
5 f, K1 v* x! [) t4 } 7 g* c( Q- f$ i' x2 s1 t
        const struct dev_pm_ops *pm;: ?& L: e' c' C- q; s' o

: J+ T# N7 K' \' e        struct driver_private *p;2 q$ d/ a0 e, P$ b5 D" T
};
1 Q% p7 C( Q- b+ L% L1 T& z
6 X0 j& i6 H7 f2 b; h2 P! t* vplatform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。
) Q: Y4 w( a7 [" `% @/ F7 U: M前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
0 T' P3 \5 k1 L0 ~6 i& \2 z' K; ^2 a  a  {, E( p+ W
! j, l7 Y" k7 K$ {7 T# V  j1 }
struct platform_device_id {0 x% g, z6 P! z+ [. _2 I
        char name[PLATFORM_NAME_SIZE];/ n0 Z. ~1 H/ Y. F
        kernel_ulong_t driver_data. c% n3 h6 D/ E7 C3 D
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
7 D1 @7 ^4 a# {0 P};
3 T$ n6 }( ]6 Q1 B6 o, |7 y平台驱动的注册使用platform_driver_register函数
" _1 o( j" G: T- s; h( n" y
: z) e7 J) r4 ~7 p+ u* ]int platform_driver_register(struct platform_driver *drv)
; U; G/ v$ l* K6 F5 \! r; z( K{, |9 E# u1 W5 @: [! q! w$ i
        drv->driver.bus = &platform_bus_type;" {4 E1 E: ]/ ^% w# g
        if (drv->probe)
) V/ ]9 @; I4 S" b                drv->driver.probe = platform_drv_probe;2 a, N. J0 M3 _% J% ]0 _8 n+ U2 ]
        if (drv->remove). d/ t8 Q$ d$ k
                drv->driver.remove = platform_drv_remove;/ v+ S- E3 A; c- w
        if (drv->shutdown)
& ]2 B7 o3 u2 j0 `. ^3 I4 ]( E                drv->driver.shutdown = platform_drv_shutdown;
+ X/ D& v) A1 P$ y, z        if (drv->suspend)8 N2 F3 z0 H/ W
                drv->driver.suspend = platform_drv_suspend;
* v7 |" t$ S, S  D) u: Y7 q# i        if (drv->resume)
) k; W" K, r) b: d* a  Q                drv->driver.resume = platform_drv_resume;
4 u; i( |3 y; F; F7 K        return driver_register(&drv->driver);3 _( `4 X* p$ m) ~
}- o% B* `/ x) N, D
先初始化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! @3 m! x0 V4 }' U' c8 m
相反地,要注销平台驱动的话,使用platform_driver_unregister函数
9 C" C8 o  w  N6 M6 X3 }! J- d: R: ~( b& t
void platform_driver_unregister(struct platform_driver *drv)
1 @" G' }8 G5 I0 u{
+ u! S6 P1 c8 ]9 b: U' w+ i: e; E        driver_unregister(&drv->driver);) a" T: ]1 i. R) e$ X" l! z
}% v6 c/ M$ C7 w

' F7 d. r6 V1 n6 A附bus_drv_dev模型的框架图
' N. N( O/ L, ~' T0 o  W 8 f' M/ M) }2 q; J3 l+ h
  j- Y% r4 n/ m1 q/ Q5 j
: ?- S  c. [2 ^0 p) |4 i) Z

" i- J, w+ L2 ?+ G8 L& m3 E. E- H* {: Z6 F

. N( W2 s5 k0 n. P  F: B  k2 A
* u4 x" T; i+ T# v! z

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 23:07 , Processed in 0.171875 second(s), 26 queries , Gzip On.

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

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

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