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

Linux平台总线驱动设备模型

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x

9 N+ Y; _$ L& S. bplatform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。
  P4 h8 h" i# ~) w. ]& b0 X, Y( V8 N- W& J% ]
总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
: e1 H# {( p1 v3 ?1 B3 J: ~
) ?& ~. _! w* g+ ?! k$ I/ WLinux2.6系统中定义了一个bus_type的实例platform_bus_type
5 m( j4 A4 D, z3 K3 t: t) c& {% o" D; M$ Q
struct bus_type platform_bus_type = {7 n, R1 [2 i% N3 K. I  n* R
        .name                = "platform"," \) A$ p0 H" H6 T
        .dev_attrs        = platform_dev_attrs,1 b! q- p4 q% ~5 S& _8 k
        .match                = platform_match,                //设备和驱动使用match函数来判断是否匹配
. D* G/ V4 G7 \5 K* e        .uevent                = platform_uevent,
: R, m- g/ ]* |% z, v$ U        .pm                = PLATFORM_PM_OPS_PTR,
# T6 z5 S% Z& Y, F/ i3 W+ _" }% v};- z6 W5 E3 t: w" A
/* platform_match函数用于匹配总线中的驱动和设备 */3 P9 I0 M+ v" @
static int platform_match(struct device *dev, struct device_driver *drv): Y1 N, [2 @, Q
{9 i) F0 ?# T: h0 [$ Y
        struct platform_device *pdev = to_platform_device(dev);5 }' A$ g- V/ K0 H
        struct platform_driver *pdrv = to_platform_driver(drv);8 I$ {) Q% r% L

7 F& A( V" d# L( y# I, ?        /* match against the id table first */  p5 X0 W+ y4 d. V: J$ G* i1 A
        if (pdrv->id_table)2 ]$ o1 q8 o/ t/ C0 M& m5 ^
                return platform_match_id(pdrv->id_table, pdev) != NULL;
  Q# \! H! @: g  X! p1 _  @- R3 M 4 C( u2 F6 M$ V& f
        /* fall-back to driver name match */& @, A0 k5 J5 [
        return (strcmp(pdev->name, drv->name) == 0);
( e0 U% P/ _& x) o6 F. c6 _}
- k( {* [9 \$ E! splatform_match函数首先判断是否由id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数。8 d+ E$ b; W  p6 _' M& @$ D
platform_device结构体的定义8 c. G; p! z. f6 D0 q' I

0 J: k" u# S0 Q1 c/ g. _
) J! ~2 P7 P+ U  H, M6 Mstruct platform_device {
( V& v; \% ^0 \- ^" X2 U4 ]+ P" A$ _        const char        * name;                        /* 名字 */' Z+ b# t  ^6 j. l: B% g
        int                id;
' X2 J  K. y6 ?5 v        struct device        dev;; o1 U* g# q' G0 b7 _. ]" R) r  c
        u32                num_resources;                /* 资源总数 */1 B+ F  d( R: e2 _, v
        struct resource        * resource;        /* 资源 */6 Q% M# W/ b1 s3 I$ n; y6 I
8 ^/ h$ T* W# m
        struct platform_device_id        *id_entry;8 P2 e7 K! G& ~$ ]7 O8 v
};
5 K+ i: L6 Y$ @" G1 H7 V其中有个重要的成员是resource,是设备的资源信息,如IO地址,中断号等。: O0 B  j- O. e: S
# S+ }1 |: s( O
struct resource {
  T5 K" q1 `$ K  A1 V  ~        resource_size_t start;                //资源的起始值- r6 q% e: w$ [6 n
        resource_size_t end;                //资源的结束值
3 X" ?) ]' V* O  S9 z! Y. L        const char *name;
: e4 j" I5 ^2 J6 p; \% t  m2 E        unsigned long flags;                //资源的类型,如IORESOURCE_IO,IORESOURCE_MEM,IORESOURCE_IRQ,IORESOURCE_DMA
# j6 i( {; {4 ~        struct resource *parent, *sibling, *child;* a6 @$ P* ^* Z; ~9 e
};
' w) O) ~2 l/ F3 Q. R  n有的设备可能有多个资源,通常使用platform_get_resource函数来获取资源
6 z* l6 q: Q* L8 f5 y$ h% H9 x4 w7 P! O& X9 q4 p. C! D) F! L2 |
* r7 H8 P& }0 R1 V
/**
% o6 \& M( h" u4 \ * platform_get_resource - get a resource for a device% F  |0 T; s3 D. q9 Q" x! \
* @dev: platform device
. T8 n# E% X9 c' r * @type: resource type
7 M. ?& b2 K. ] * @num: resource index9 b( v3 U0 S7 [
*/
9 R' K) G* O( }3 `struct resource *platform_get_resource(struct platform_device *dev,
' Z; T9 q7 e  C% W- }8 P4 x                                       unsigned int type, unsigned int num)
$ ~7 [% v( |( [2 r- b3 |{
# R& f# I6 k# l. ]* j9 |        int i;
3 {, M6 p' F( G  U0 l. }. V0 D- Y
) R, m% P- x* u; y; D. V# O- m6 s        for (i = 0; i < dev->num_resources; i++) {
" K. a  b6 u; ]8 h1 o                struct resource *r = &dev->resource;7 E3 j7 o& L. X, ?

( O; j2 ]; Y4 X' J                if (type == resource_type(r) && num-- == 0)
4 l; d; I# Q9 h1 v# H/ `                        return r;
$ M- Y' E2 D, k2 {        }7 O2 Z- ^: K4 ]
        return NULL;
9 h; p# g9 [4 [2 |}
$ H; \* G# E$ b平台设备的注册,使用platform_device_register函数
  E9 |7 h- p" B
% P& l+ x3 W4 k1 R2 _7 Q! Tint platform_device_register(struct platform_device *pdev)2 X, I) ]" d, |' d6 Y" g" g/ I
{
8 c; p8 a0 N: C        device_initialize(&pdev->dev);2 K5 V5 k* X8 i5 `4 S6 L
        return platform_device_add(pdev);/ [' Z; n- K$ I0 C
}
! Y- Q" r  p5 A: w4 P" |platform_device_register函数先通过device_initialize函数初始化platform_device的device成员,然后调用platform_device_add向内核添加一个平台设备。2 z& @6 U0 A- v

( Z. B$ [3 U# O
$ J+ U! |" R' n  E- `* d, o" xint platform_device_add(struct platform_device *pdev)9 b3 E2 y" ]; n* W' v! u( B* m
{
: B0 {8 a7 L2 X; O        int i, ret = 0;
  U; q3 X" U5 i  [ ) `* W$ x* F% b6 ]" I
        if (!pdev)        /* 如果pdev为空则返回EINVAL */+ q: M( [: w+ e  `9 C( p9 S! G2 Y1 N
                return -EINVAL;
. K2 U" a9 F0 T. e3 t  @3 D
+ c/ ], `* m  `0 v- f' R# h$ Q        /* 如果pdev->dev.parent为空则将pdev->dev.parent设置为platform_bus */9 |  q3 B. H* p8 h! \
        if (!pdev->dev.parent)
# I' g8 y6 o# s3 _# U: f6 a                pdev->dev.parent = &platform_bus;
+ w! E5 k& [' A9 m + w- G8 t+ C4 w) L! T& b
        pdev->dev.bus = &platform_bus_type;        /* 设置总线类型 */
- J1 f& [$ |+ M5 H9 r* {) G 8 @3 U/ u/ _- b/ H* A" q- C. F
        if (pdev->id != -1)                /* 如果id = -1则表示自动分配name */, H/ T/ j9 f3 J" O$ I
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);. B8 M  J2 K- N# o
        else' d' W7 ^) X- [9 @8 j: v- k# o
                dev_set_name(&pdev->dev, pdev->name);
# w4 i: \6 W% |2 d: _) H! I0 ]
- D6 i" k& W" y" V8 p        for (i = 0; i < pdev->num_resources; i++) {6 q% Q; N9 j7 ^/ p) ]
                struct resource *p, *r = &pdev->resource;        /* 获取资源 */% ~8 H% O5 o: Z$ s

. C. K- q/ r+ ~% B; l' S                if (r->name == NULL)
' H% v' `7 R, W' C; G                        r->name = dev_name(&pdev->dev);
& ?. }1 I3 M& ]- P
* f! \- B6 F1 t; @) @0 h                p = r->parent;0 _8 i3 u0 F( P  r
                if (!p) {7 G6 t; p* r3 o
                        if (resource_type(r) == IORESOURCE_MEM) /* 设置资源类型 */9 A$ d9 L" t' \8 k$ Y3 W+ |4 ^; Y- P( f: a
                                p = &iomem_resource;1 k) F2 I6 T* r' \1 U+ n
                        else if (resource_type(r) == IORESOURCE_IO)2 ~. R& D, K' W1 k/ R
                                p = &ioport_resource;( e) \( Z$ t) S8 P2 ]
                }& R; v# r: A  Q" K% i) Z

( {( U# Y  z5 _) Q- p, p! v# A                if (p && insert_resource(p, r)) {! f5 A* O+ [- T* F) d2 Z! P6 R$ g
                        printk(KERN_ERR" b* {* i" W$ ~0 l
                               "%s: failed to claim resource %d\n",
* F3 h% _# b( _: ~( _6 g& p2 h                               dev_name(&pdev->dev), i);2 k  f. j) @) A, y0 W: a+ n
                        ret = -EBUSY;4 a3 L, H$ {/ V( ^7 `6 K$ `" M
                        goto failed;" C) K+ b7 h) ~& [- X4 W
                }
: d0 d9 i/ H. {        }, M2 h1 j& T8 ~
2 _- `3 K6 k7 _: T9 Y
        pr_debug("Registering platform device '%s'. Parent at %s\n",
9 u- H* R: u, J# e4 N# S) _! n3 [                 dev_name(&pdev->dev), dev_name(pdev->dev.parent));. G. _' U* ~; B
! |% x+ _& g0 f+ [( |3 `
        /* 向内核添加一个device */# P8 |& h' M, _3 @
        ret = device_add(&pdev->dev);
" p. J$ f3 O# A6 u# `% X- V        if (ret == 0)4 l; R5 ]8 _7 g5 `" {6 n
                return ret;
9 I- D  e2 z" ?/ ?# S & i8 U1 G: r; Q3 L# h- I  @! v6 I* ~
failed:
( p( P0 ~! A" ~- K* O$ [) U: F: K        while (--i >= 0) {: Q: q0 @* P. t- c  i" K$ K" g8 q
                struct resource *r = &pdev->resource;5 n1 V* F  M9 w" I4 H) ^
                unsigned long type = resource_type(r);! a- u) v3 R, s/ M" x# r
( G" C7 E- K2 ?% }$ D
                if (type == IORESOURCE_MEM || type == IORESOURCE_IO)6 c+ g( q9 Q$ F+ u$ ^) L) R
                        release_resource(r);
& a: h+ {( l3 `6 d        }
2 k8 u/ O/ J! p0 e: P
" Q+ g& K' c6 \( n  v        return ret;
" \# j, r/ ?7 |# G& @% m}
6 Y3 Z3 G2 L8 d/ w, i" f' O) Jplatform_device_add最终调用device_add来完成平台设备的注册。+ P1 L  ^( I0 y8 H+ y0 Z
% K$ n8 h" O1 L" _. v  d# o8 x0 D
, S3 o$ w; Y$ d+ c; {

9 C6 I$ _$ M$ z. X- b8 g; L# Q$ V 相反地,如果要注销平台设备则使用platform_device_unregister函数
( G. V' D9 T! P4 n  h" x4 s% _# Q# k6 @2 o0 E
void platform_device_unregister(struct platform_device *pdev)
' e+ C1 h' Y6 w: {% W1 j{, _$ r: h& C1 n8 \! u
        platform_device_del(pdev);
" h3 j; `5 Y; n: i" C5 i5 E* h        platform_device_put(pdev);
3 o, A; X: C' `1 p/ w  W}
" A! v7 a) R+ n9 {( rplatform_device_unregister函数调用platform_device_del函数来注销平台设备
! F9 V1 Z* p4 n$ W) `- e( j2 s1 ]2 h, f( l8 l9 P5 G$ F! o  C3 j
void platform_device_del(struct platform_device *pdev)
; e1 Y# Y$ @0 [{
3 ^% l' ^- d5 ^5 b' B        int i;
0 L* C) k$ y1 k# D: `. @
* Q5 F5 {0 Y; {5 }5 Y        if (pdev) {
/ D0 d( i/ V! `                device_del(&pdev->dev);7 Z. ]0 ?  s9 J, v; U
( E& F2 V4 m# ?  h1 ]0 i. Y, Y
                for (i = 0; i < pdev->num_resources; i++) {
  w4 ^4 }4 {2 D4 W                        struct resource *r = &pdev->resource;& z+ K" s+ I1 j* t& B9 A6 d
                        unsigned long type = resource_type(r);* c6 B( F! B" X' a3 k
0 r1 P. H3 h6 N
                        if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
  G8 R& y# u$ `3 Y                                release_resource(r);4 q2 s  A& S/ s# @5 L5 l! x4 a) B& f
                }
- t4 _2 }- n) E+ D4 X        }
0 V; f- I) n  M5 z}
3 K' i( s6 I, v% jplatform_device_del函数调用device_del函数来删除平台设备,相应地,要释放资源应调用release_resource函数,前提是资源的类型必须为IORESOURCE_MEM或者IORESOURCE_IO8 \9 k, i9 N+ R# m3 K( _; A' |
, k; `4 _" V' y& z. T$ F7 O: }+ p4 V3 \) J
platform_driver的定义:: X  L: x2 g6 v! W3 }: v5 W4 S. q5 H  x
: W0 d' d9 Y% i) F% w
struct platform_driver {4 b4 D, c! X6 a4 U5 E
        int (*probe)(struct platform_device *);3 a6 s6 {+ T- M1 N4 g& U
        int (*remove)(struct platform_device *);4 k" b1 c0 V3 B4 w% |9 {1 g% B! j5 X
        void (*shutdown)(struct platform_device *);7 K  e+ Z- B7 t+ \# N) B
        int (*suspend)(struct platform_device *, pm_message_t state);
% c0 Y4 W9 t. e4 u8 U7 u        int (*resume)(struct platform_device *);3 \8 [6 Y8 w0 @) |1 u% M4 D
        struct device_driver driver;
" H3 }4 Q9 N1 D        const struct platform_device_id *id_table;
4 v  d' V& R/ \+ W};
  N3 A. F1 M% m4 ?) n0 l( V( I5 i1 ]+ B! K% x
# ~( W9 r2 X" T. ^6 Z
device_driver的定义:3 D# o/ b4 }+ w- ]" L
struct device_driver {
  }5 w  b2 H! j$ n        const char                *name;
; J$ B5 v, E: Q9 J; D        struct bus_type                *bus;# F; B. y) Y3 P* q

* R* I% p5 \4 `$ [        struct module                *owner;" c. L  [' ]( ?8 @4 u5 J, [
        const char                *mod_name;        /* used for built-in modules */; @1 N% V; Q3 z! V& ~# D
$ ^; h; c- t- M
        bool suppress_bind_attrs;        /* disables bind/unbind via sysfs */
, A! N8 [0 E" {% j/ |4 r * V* v2 d6 u3 `1 s* k  W3 V
        const struct of_device_id        *of_match_table;
' @0 \1 @8 l# _: \- ^        const struct acpi_device_id        *acpi_match_table;
* y2 z0 `/ s; P$ F8 H3 J! k9 }% G ; x" {9 S' v3 X! l) Q
        int (*probe) (struct device *dev);
* I: p5 x+ G: ?0 R% H' u; N        int (*remove) (struct device *dev);
! t3 N0 t' e& o! Z; _; P        void (*shutdown) (struct device *dev);: w+ i2 e3 Z# _3 c8 e( F
        int (*suspend) (struct device *dev, pm_message_t state);9 L2 {: y/ U/ J
        int (*resume) (struct device *dev);
! H, `( k! }) {. x        const struct attribute_group **groups;8 u1 M) H) ]* Z4 n; P  R: V
1 d3 r4 f) ]- A$ ?
        const struct dev_pm_ops *pm;1 x) x$ W# |2 X! W. J
, n, @7 }1 I$ Q0 H* X! f' ~* f+ v
        struct driver_private *p;
9 R, I3 E- h3 p! U  ^0 ^$ |% w};
* i" F( j" v4 u+ e# `: A. L# V' C8 O0 [  Q! S
platform_driver结构体有device_driver成员,该成员的各自字段如上所示,device_driver也有probe、remove、shutdown等函数,在平台驱动注册的时候被初始化。; [' Y0 L/ |9 o8 F# T; {- {0 b
前面说过,当系统中存在有平台设备和平台驱动通过总线的match函数匹配后则会调用platform_driver的probe函数,参数为platform_device,有时候也通过id_table来判断是否匹配。
% C! r2 ?. v2 s" E$ E# e# _* Q& R; r2 o: r0 ~& M6 H& N) S
  J$ x1 k/ e. o1 [' }! _$ r
struct platform_device_id {$ u5 Z+ K, h, g  F. b  ]8 r$ v/ I/ Y
        char name[PLATFORM_NAME_SIZE];
& s6 ?/ ~+ G9 q        kernel_ulong_t driver_data
% Y% u, e/ t- i5 R+ N                        __attribute__((aligned(sizeof(kernel_ulong_t))));3 V& G! ?" p9 n5 X; m  c
};5 q! b% g* f$ t1 ~7 O, U6 ?! z
平台驱动的注册使用platform_driver_register函数' s3 r1 Q4 R; X
2 l6 W: j( N( G5 s, n$ f3 b
int platform_driver_register(struct platform_driver *drv)+ `& C" H, E  S& c
{
- M2 z# L* [/ p/ o        drv->driver.bus = &platform_bus_type;
" f7 p( E1 s* Y9 T% {4 V8 H        if (drv->probe)
: i. M6 M! s/ e$ d4 P$ v5 |                drv->driver.probe = platform_drv_probe;  {/ S$ B% F, {& ~5 R
        if (drv->remove)
' q& m: Z5 ?0 n& K; S- D                drv->driver.remove = platform_drv_remove;
+ b# o* L3 g5 F8 C1 ?        if (drv->shutdown): m& x8 @, M! F
                drv->driver.shutdown = platform_drv_shutdown;% O; H8 d" C. R: r3 F' Q. n0 l
        if (drv->suspend)
5 v. j- q( b4 z                drv->driver.suspend = platform_drv_suspend;
9 h2 X) G/ l- q0 j9 B. U        if (drv->resume); Q+ @- _; B# z  c
                drv->driver.resume = platform_drv_resume;
, ~# f2 C2 N" [/ k. z8 P6 J: r        return driver_register(&drv->driver);! O& z! x$ H0 e: C( T& |! ?6 D. \
}1 x0 _* v% a# R1 s# n
先初始化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函数来注册平台驱动。
$ o6 o+ P+ E, E  K相反地,要注销平台驱动的话,使用platform_driver_unregister函数
7 y" M. A% d! V7 D+ Z0 K
- X: x1 M: e6 z( f) ^void platform_driver_unregister(struct platform_driver *drv)! M) G) h  M& U' }
{4 ~1 X& K' D$ T# L
        driver_unregister(&drv->driver);
- u/ u6 \$ m% d}' m$ d0 v; I- X( x0 M
0 B5 r9 A! l% u* D7 \8 }' D
附bus_drv_dev模型的框架图
: H! c: X: N1 B) s
0 g0 O' t$ H3 \7 B3 }: i+ c- _2 I# ]5 X' n$ V7 m
' Z+ Y4 w3 f% q5 ~. _
% ?' f4 E' {! Z

( E5 g5 L& c6 x
+ @$ X' Z$ S- @8 g* o. Q7 V  D1 K! T1 @. `- k5 R/ J7 H+ O. |# g: w

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-7-2 21:17 , Processed in 0.109375 second(s), 26 queries , Gzip On.

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

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

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