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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

0 L4 }% q) X4 |6 Bplatform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
, M" V# h& O7 q( v1 t! B+ ]3 g( I- A0 f+ S7 C
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。5 ^' z5 [+ @6 _* {5 e
0 ?8 L" i" N4 C
Linux2.6系统中定义了一个bus_type的实例platform_bus_type
, h5 M$ U/ {9 q/ }9 c! `- y0 c' J) x/ j( ]/ z2 V% J% I
struct bus_type platform_bus_type = {& P$ A' B6 C0 _6 M
        .name                = "platform",
0 |/ ?& g3 \: Z) B, j% W/ _, [        .dev_attrs        = platform_dev_attrs,4 _) _# O: ~6 d! A* I  F7 A
        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配3 A0 G4 F. J5 h8 e3 S
        .uevent                = platform_uevent,+ i2 b8 l! u" U& S7 B
        .pm                = PLATFORM_PM_OPS_PTR,
3 A, d4 \& ]7 K};
( f: _' E! Z7 v7 |' y, T& _/* platform_match函数用于匹配总线中的驱动和设备 */7 ?% c" N9 \. h8 n2 o6 q: x
static int platform_match(struct device *dev, struct device_driver *drv)3 S: K0 @+ G) f- C( u' N( s3 ^
{0 l* U# U) A: C# Z% `, ~% i* n) y
        struct platform_device *pdev = to_platform_device(dev);. O  S3 U, w0 }9 f! \
        struct platform_driver *pdrv = to_platform_driver(drv);( w' y; A& a1 m7 _* l" `

: ?7 a9 J# X) f6 |, X        /* match against the id table first */
1 g) ~  j9 G- o! ^8 b, k        if (pdrv->id_table)' V! r: \2 J: M# E
                return platform_match_id(pdrv->id_table, pdev) != NULL;$ f2 f$ F! v: y5 _! v
" V* n, v! F! _# n+ m
        /* fall-back to driver name match */  ~1 i, z$ J3 @9 M9 O; ?2 g! k; E
        return (strcmp(pdev->name, drv->name) == 0);& d* g1 t- {' J- E- o% g! P( D6 t. I
}6 w) ]. g! ^% O
platform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。
* s7 P2 }2 h2 Y- Q# d/ @platform_device结构体的定义! r, Y4 d8 x5 \$ o
- E+ V0 Z( Z+ _8 r3 l: R

) s( e6 d, _/ c- @8 I1 S5 a1 estruct platform_device {: {2 E7 T1 y$ h
        const char        * name;                        /* 名字 */7 G! `/ z# U: t9 z" a9 g$ I
        int                id;
. K7 r. `0 h9 B" N, K$ @* f5 `4 n        struct device        dev;
8 V* v2 Q! }5 Q6 t( A0 _! ~        u32                num_resources;                /* 资源总数 */
" }3 ^1 C6 U+ V9 X5 @7 a0 ^; }        struct resource        * resource;        /* 资源 */$ Q1 U$ s4 ]; L4 u7 w) e& K8 \, ~, [

1 A. X5 ]9 A" Z" o) u        struct platform_device_id        *id_entry;
9 H1 x! i1 y- p: t7 w; d, ~};" C+ p; u+ ^- E$ |9 X& |7 P1 I
其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。
6 N+ a2 y- W8 @$ N) V! U: \+ A, k# w9 C. |
struct resource {
4 @  ~/ e+ r8 u+ ^7 R        resource_size_t start;                //资源的起始值8 M! m# ]1 L; h9 ~
        resource_size_t end;                //资源的结束值
$ E$ K* S- {+ ?8 o        const char *name;5 B* R( n2 l) @7 l- j! v
        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA" I9 H* a! `7 S) n
        struct resource *parent, *sibling, *child;: S' N# _2 O% ~. ^; F1 ]
};6 }& ~: ]8 h5 x. A. b
有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源5 J* B6 m4 g. }: @0 @

0 t6 l# G7 |/ t' c) N3 h, X. u# z# D1 C! x
/**3 s8 N8 m7 Z3 E2 \7 M: _# V, n/ q- J) m
* platform_get_resource - get a resource for a device
& l$ _4 I# i" @* O. }; ]$ x * @dev: platform device
2 W$ W5 T& h3 E; ^ * @type: resource type" \. W% O) r6 v6 y
* @num: resource index
. T# M" R+ Z* N */
: O- o1 m0 Z0 r7 Lstruct resource *platform_get_resource(struct platform_device *dev,. x; b9 i* A4 ^& j0 `  b
                                       unsigned int type, unsigned int num)- T0 P' L" T, L4 K0 h
{. |' M2 n; |2 m0 x
        int i;
( i+ c6 w% y4 [9 c* A
. J& K  i8 g5 M) {* Y8 c        for (i = 0; i < dev->num_resources; i++) {& k) q- Q, g! w* ~/ U* R5 m
                struct resource *r = &dev->resource;
! q" K$ W4 y3 B- k+ z
! q, \1 ^3 B5 }: U" L, X7 X                if (type == resource_type(r) && num-- == 0)
1 N2 D7 m  T- C" [* l: \                        return r;) }( a0 w0 Q7 h( r+ P
        }' M& o5 s" w4 h
        return NULL;
5 S. }9 v( s) \+ e) ^8 k+ d+ m* G}+ S# M' D$ g! {+ U% Q
平台设备的注册,使用platform_device_register函数& T. T: X" Q1 i( C& m# g

) S, X/ l9 G: I; X; t) a$ eint platform_device_register(struct platform_device *pdev)
; L4 k$ N5 e# G0 n; ]% G. W{
- Z2 M* ^0 R, t" L        device_initialize(&pdev->dev);3 S7 \4 A* {& W; {2 x/ z
        return platform_device_add(pdev);- e& J6 v( e8 P; m3 q
}- ]2 m# A/ S/ ~' s$ e
platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。
( v. K  D- s$ K$ r) q2 \  R3 h5 Q+ B$ l; A
  k8 l2 r2 n- g  P9 r0 V. I
int platform_device_add(struct platform_device *pdev)
6 o5 A% C# S6 M  |2 A  `" }, \& O{
. t% t/ x" A) A( {* D        int i, ret = 0;/ M$ p' n" z1 U  Y
, B# y" F8 t* Q5 V, v( @. w
        if (!pdev)        /* 如果pdev为空则返回EINVAL */
+ w5 A8 a: o+ @! K6 N, E( S! M; R- ?- m                return -EINVAL;, R, F" d0 a! c% E
! {2 }1 n' d) |% K  I
        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */1 C( g7 K% \0 w( U- n1 k* L5 k
        if (!pdev->dev.parent)2 u3 m5 |* _5 a! f! X+ x" M' [# I
                pdev->dev.parent = &platform_bus;
8 I. T0 d6 J4 x1 U8 `/ r
/ @4 J) L9 b5 f- F) W5 F% s        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
1 x) V' Z4 u; g& I( _2 R' Y , b. p) S, h0 \+ L6 ?; T% ~
        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */' Y% P6 L% I: X9 X/ P9 U1 s
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
4 f7 e; ^  C  u+ L        else! \& C& t3 \2 I* P! F
                dev_set_name(&pdev->dev, pdev->name);6 {8 G9 `2 c! ~, r! ~

1 B1 ?0 M; T/ p& N  w        for (i = 0; i < pdev->num_resources; i++) {
. I! G0 e0 z0 _3 e  g# |3 L& L                struct resource *p, *r = &pdev->resource;        /* 获取资源 */
" }  Q* F8 v$ q" J/ I7 G ' E; }0 a. l, N# F! Y9 b
                if (r->name == NULL)1 c" m  j1 u% H& ]! K
                        r->name = dev_name(&pdev->dev);( Q9 E' X. Z; p6 P+ k$ L) d3 U/ `
' w+ B, _, ~4 q8 ]1 M8 U/ n! \; U1 K! ?9 K
                p = r->parent;2 j( r$ R3 _$ E; [" E$ Z3 I4 a
                if (!p) {
! b6 j& ~& u- K- c  k  w, }                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */$ C& s1 Y& ^/ Z& T0 P! e  _
                                p = &iomem_resource;" \( n6 b8 ]1 e, r, W8 c) `7 L9 A
                        else if (resource_type(r) == IORESOURCE_IO)
- V6 Z0 A" o- [" D% D* C3 p! _: `                                p = &ioport_resource;
5 t% }) T. ~& f, z* P9 ~, O                }
4 o7 g0 D1 G6 u 6 C0 [+ m5 l1 k
                if (p && insert_resource(p, r)) {
# u0 ?5 D- ?' R) x' c2 b' p                        printk(KERN_ERR
( X+ ]. u+ k) f  d! \2 y+ c                               "%s: failed to claim resource %d\n"," P5 V2 t' K: J/ M  x" z
                               dev_name(&pdev->dev), i);$ ~) y" |' |' R+ h9 i$ P7 b) L# _
                        ret = -EBUSY;( U) y/ n8 n1 j0 e4 Q) q9 o! {
                        goto failed;; {5 q+ b# q; T/ B
                }6 w/ M( U; ^, i: \
        }
, M% a+ g! u( Q* }$ q0 H& j# D# T, O 7 ]% O1 p2 m$ e& i
        pr_debug("Registering platform device '%s'. Parent at %s\n",
- A: O  u9 y! i( t% g' x, n                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));
2 r; c' z9 \) t8 i- i1 I/ K/ J4 n
; h2 H( D8 M6 E4 i# [6 Y        /* 向内核添加一个device */
" s+ A# O2 T6 H- X        ret = device_add(&pdev->dev);
4 ~$ p& I' \3 r+ z1 P6 b        if (ret == 0)  N/ n" n2 h# ^% m
                return ret;! n" c$ M% A2 A- D- Z& g
( V! ~: m4 t- }/ p
failed:
9 D3 p! l" M& H# o, a4 q( d, ^        while (--i >= 0) {
5 f% [. E5 a$ a                struct resource *r = &pdev->resource;
, O' `" Y# X8 S$ I& D* G, ~, {5 j                unsigned long type = resource_type(r);
5 r) z5 \8 D0 S& u5 x& Q' W) G ; W5 v; {' c* J, ]& V: P
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO). |3 W! ]% ?) ?5 d4 X& h( K
                        release_resource(r);& ~! p- z8 j: o8 t" q( K
        }) z7 J, R  n* _# s* z" O6 `. P
3 F& u% G: h( E  V! z
        return ret;
& b% Z& W# A- z5 @. ]8 G5 k8 T}
1 Y/ |0 s! G( ^# T! ]$ Rplatform_device_add最终调用device_add来完成平台设备的注册。
: ~% _+ D+ g4 E8 x2 H+ C0 r, K; Z/ P& H. v

$ d6 X! [, I! |7 c9 ?
+ g8 ]+ i' n- z2 |! _ 相反地,如果要注销平台设备则使用platform_device_unregister函数# Q8 n; ~6 R% z2 R& v
/ b8 n5 m* p- p2 A9 z
void platform_device_unregister(struct platform_device *pdev)
& g" d  P* |" I2 U4 y  o{
+ `* r7 f- U4 {, j! m+ a1 n        platform_device_del(pdev);
7 o0 f9 W4 \' K. a* B; m$ C        platform_device_put(pdev);
& C, }4 j/ Y4 Z8 n9 P/ u3 n}" K, x) S* G) a
platform_device_unregister函数调用platform_device_del函数来注销平台设备- q* S$ O1 Z* Z& a& l3 q# x
' a' X; |" D7 T8 [+ P- P$ K
void platform_device_del(struct platform_device *pdev)$ f+ T) M3 S; o1 O+ O
{
( u" d1 _# k7 @4 N5 Z) C# S7 }        int i;( L) c4 Z9 r& D' A

; o4 D# e; C: R( p2 ?, `$ Y        if (pdev) {
! Q* Y% j( R& e7 r) L                device_del(&pdev->dev);
4 o! ]5 t0 A8 A+ j. ` 2 }6 |. S/ N8 d# o
                for (i = 0; i < pdev->num_resources; i++) {7 H7 n; o  \; P" x
                        struct resource *r = &pdev->resource;/ E1 Y  d2 [% o0 Q; W, _; b
                        unsigned long type = resource_type(r);
' Z2 c4 K1 _/ N0 w5 K% U
- h6 o9 ]( ]% w, x  i! j5 Y                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
7 X: ~0 q! m1 {4 J                                release_resource(r);
# b+ o; l0 ]* Q8 }8 A                }
( ]( ]6 z! f6 L% U9 @        }. m, ~4 n- r% {  B: X
}
) S& g  e" ?' Lplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO
9 G1 i) C4 V+ j. T6 H
. y; g" c5 E8 j( u( \platform_driver的定义:
  Q1 m/ f' F& ], |% Z  A9 r' g3 ]$ R3 P8 Y- }( Q" N! }6 W1 T
struct platform_driver {$ K% _3 c& y6 s( E( i6 p
        int (*probe)(struct platform_device *);
+ ^. \/ M4 m  Y! Z! ~$ T, q! {4 y        int (*remove)(struct platform_device *);, e6 i+ }9 X9 W3 V3 F/ B) N" n
        void (*shutdown)(struct platform_device *);$ ^& c* w7 X0 D. z; r
        int (*suspend)(struct platform_device *, pm_message_t state);$ P# R4 [9 Z) z9 q1 T* ]
        int (*resume)(struct platform_device *);
0 E8 N+ G  U: l5 @, G        struct device_driver driver;% r, }$ D, v' q% v) \0 T! Y" T+ f
        const struct platform_device_id *id_table;2 e* H% l0 h) }0 e9 J0 g
};
  k. s) E# c' l3 j
5 z1 t. Z/ ?. s0 d9 V+ m* b& |* y6 P* N# [
device_driver的定义:
0 I( p( d2 n4 u* M: E+ ustruct device_driver {1 f% @: e' J! o- n
        const char                *name;' Q% r$ u* ^9 y$ f% v% n2 R8 N1 b  D0 Z
        struct bus_type                *bus;
2 G0 u8 U/ I/ q8 a( c: g/ ?* S, C # ~' e* n- x( ~0 v2 ]  d' K6 ~
        struct module                *owner;
- s& y" w# k8 p# k        const char                *mod_name;        /* used for built-in modules */
# r$ h" X- \% k+ e: p* p* V 4 [2 C3 r* ~0 [0 @! g& S. l
        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */- J1 r5 M8 B  _: X: n9 L  ]- z
8 `' y( X' `3 B( j( M
        const struct of_device_id        *of_match_table;0 L- y6 G6 z: G
        const struct acpi_device_id        *acpi_match_table;
/ m* m) y, W& G5 ^2 a5 w) G / K' X1 I6 Q1 e; U% q
        int (*probe) (struct device *dev);
: S2 o' A' p1 @6 x        int (*remove) (struct device *dev);
- g& i) r" @% x' n6 G  u        void (*shutdown) (struct device *dev);& F+ r7 g  t8 p$ Y& Z1 c7 o. i
        int (*suspend) (struct device *dev, pm_message_t state);' Y2 H& v7 K& B6 L: {2 b
        int (*resume) (struct device *dev);. _$ P% C& y" Q
        const struct attribute_group **groups;
9 L7 z( v1 v; j
6 ]9 \- r6 g1 [        const struct dev_pm_ops *pm;
3 e: D8 I) a- L$ O % R# q9 r; p* x/ h
        struct driver_private *p;
* z$ j7 H6 x! z: [};6 w; u4 V$ M) x6 b2 I
! T5 D3 w& Z, G9 \* d
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。! _& o2 [$ u1 I' B7 ]( X) c
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
$ y  N5 A7 x5 F9 a2 I8 b4 Q
8 H# x" V. ^& \  q' t' f: p, z! Y5 _" B+ y" u: `
struct platform_device_id {$ H8 b, o! B$ o
        char name[PLATFORM_NAME_SIZE];" D! `% U3 q3 y/ `" l
        kernel_ulong_t driver_data
9 ~. l6 G8 R5 @( P1 b7 I1 z$ o$ v                        __attribute__((aligned(sizeof(kernel_ulong_t))));
7 {& n' C4 D( C! _/ O6 s! }8 o};
: T+ C- |$ G8 _  l( E平台驱动的注册使用platform_driver_register函数1 _  J, _7 n1 C* _% _- [
$ G' l) A7 G) p8 Y; B( f' u' b
int platform_driver_register(struct platform_driver *drv)& Y% x4 z( |. H" \2 h
{
' ?% [4 s! N& c1 C$ |        drv->driver.bus = &platform_bus_type;
. U* b- Y9 D. W. w4 M" v        if (drv->probe)# f  m8 t/ T6 J7 n# f
                drv->driver.probe = platform_drv_probe;4 b& r: V, b5 E! c- a
        if (drv->remove)
: C# Y' u1 s( V0 m                drv->driver.remove = platform_drv_remove;
" M) Y$ J! l7 ^1 `        if (drv->shutdown)
: F5 i' H$ y. a; B9 {" U% f7 a' F' l2 Y                drv->driver.shutdown = platform_drv_shutdown;
: c. S1 A) q9 k        if (drv->suspend)9 c$ c' V) Q* ]( _2 y% X8 x  r
                drv->driver.suspend = platform_drv_suspend;  A7 J$ p* \4 M" a& g7 j8 h5 L9 {# a
        if (drv->resume)4 p4 f% \) P  {/ L7 H- m  X
                drv->driver.resume = platform_drv_resume;
% K6 M$ T6 j% Q( D0 X0 G- c        return driver_register(&drv->driver);
7 s+ q% n/ `. Z' i9 E}
4 K$ [$ I" e4 ~7 T' ~) V/ S! b3 H先初始化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函数来注册平台驱动。( Y% W" T! G% j' o
相反地,要注销平台驱动的话,使用platform_driver_unregister函数( x( z6 I" M% p/ q1 y' W
  l: U. x0 X4 E  [3 r2 q
void platform_driver_unregister(struct platform_driver *drv)( }2 V2 @$ [4 p; x
{- R. q; E: d/ [2 {
        driver_unregister(&drv->driver);: v1 [4 e  K. k' \# \# T) C+ F  t
}* r& A  m& g! g* T

. f9 L6 _  K7 x: y  j7 B附bus_drv_dev模型的框架图  T: Y+ P7 U0 ~1 i8 ~7 L
& t0 B# `& c7 u- k+ ~5 p
4 k# ~- x  ]$ Q* Z0 N1 R4 |
/ W( |& ~; T. g. |' H  D3 s

- h8 C# z$ w% Z: T0 r! `$ K' e. r, n

* E8 {% P# Y- {# l) z7 Q6 y. R6 r* [! b; F& H- W+ J

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-26 05:47 , Processed in 0.187500 second(s), 27 queries , Gzip On.

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

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

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