`
fuerbosi
  • 浏览: 463064 次
文章分类
社区版块
存档分类
最新评论

基于platform机制的驱动模型

 
阅读更多

1、 哪些适用于plarform驱动?
platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,这样拥有更好的可移植性。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。Platform driver通过platform bus获取platform_device。

通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独立的资源(地址总线和IRQs),都可以用 platform_driver来管理,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。

platform_device最大的特定是CPU直接寻址设备的寄存器空间,即使对于其他总线设备,设备本身的寄存器无法通过CPU总线访问,但总线的controller仍然需要通过platform bus来管理。

总之,platfrom_driver的根本目的是为了统一管理系统的外设资源,为驱动程序提供统一的接口来访问系统资源,将驱动和资源分离,提高程序的可移植性。

2、 基于platform总线的驱动开发流程
基于Platform总线的驱动开发流程如下:
• 定义初始化platform bus
• 定义各种platform devices
• 注册各种platform devices
• 定义相关platform driver
• 注册相关platform driver
• 操作相关设备
3、 何谓platform bus?
Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。因此从2.6内核开始引入了设备模型。

总线是处理器和一个或多个设备之间的通道,在设备模型中, 所有的设备都通过总线相连。总线可以相互插入。设备模型展示了总线和它们所控制的设备之间的实际连接。

Platform总线是2.6 kernel中最近引入的一种虚拟总线,主要用来管理CPU的片上资源,具有更好的移植性,因此在2.6 kernel中,很多驱动都用platform改写了。
platform_bus_type的定义如下:
  1. http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L609
  2. 609struct bus_type platform_bus_type = {
  3. 610 .name = "platform",
  4. 611 .dev_attrs = platform_dev_attrs,
  5. 612 .match = platform_match,
  6. 613 .uevent = platform_uevent,
  7. 614 .suspend = platform_suspend,
  8. 615 .suspend_late = platform_suspend_late,
  9. 616 .resume_early = platform_resume_early,
  10. 617 .resume = platform_resume,
  11. 618};
  12. 619EXPORT_SYMBOL_GPL(platform_bus_type);
  13. http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L55
  14. 55struct bus_type {
  15. 56 const char *name;
  16. 57 struct bus_attribute *bus_attrs;
  17. 58 struct device_attribute *dev_attrs;
  18. 59 struct driver_attribute *drv_attrs;
  19. 60
  20. 61 int (*match)(struct device *dev, struct device_driver *drv);
  21. 62 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  22. 63 int (*probe)(struct device *dev);
  23. 64 int (*remove)(struct device *dev);
  24. 65 void (*shutdown)(struct device *dev);
  25. 66
  26. 67 int (*suspend)(struct device *dev, pm_message_t state);
  27. 68 int (*suspend_late)(struct device *dev, pm_message_t state);
  28. 69 int (*resume_early)(struct device *dev);
  29. 70 int (*resume)(struct device *dev);
  30. 71
  31. 72 struct bus_type_private *p;
  32. 73};
总线名称是"platform",其只是bus_type的一种,定义了总线的属性,同时platform_bus_type还有相关操作方法,如挂起、中止、匹配及hotplug事件等。
总线bus是联系driver和device的中间枢纽。Device通过所属的bus找到driver,由match操作方法进行匹配。
4 bus、device及driver三者之间的关系
在数据结构设计上,总线、设备及驱动三者相互关联。

platform device包含device,根据device可以获得相应的bus及driver。

设备添加到总线上后形成一个双向循环链表,根据总线可以获得其上挂接的所有device,进而获得了 platform device。根据device也可以获得驱动该总线上所有设备的相关driver。

platform driver包含driver,根据driver可以获得相应的bus,进而获得bus上所有的device,进一步获得platform device,根据name对driver与platform device进行匹配,匹配成功后将device与相应的driver关联起来,即实现了platform device和platform driver的关联。

匹配成功后调用driver的probe进而调用platform driver的probe,在probe里实现驱动特定的功能。
5、 device和platform_device
Plarform device会有一个名字用于driver binding(在注册driver的时候会查找driver的目标设备的bus位置,这个过程称为driver binding),另外IRQ以及地址空间等资源也要给出 。

platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L16中,定义原型如下:
  1. struct platform_device {
  2. const char * name; //定义平台设备的名称,此处设备的命名应和相应驱动程序命名一致

  3. int id;
  4. struct device dev;
  5. u32 num_resources;
  6. struct resource * resource; //定义平台设备的资源
  7. };
在这个结构里封装了struct device及struct resource。可知:platform_device由device派生而来,是一种特殊的device。

下面来看一下platform_device结构体中最重要的一个成员struct resource * resource。struct resource被定义在http://lxr.linux.no/#linux+v2.6.25/include/linux/ioport.h#L18中,定义原型如下:
  1. struct resource {
  2. resource_size_t start; //定义资源的起始地址
  3. resource_size_t end; //定义资源的结束地址
  4. const char *name; //定义资源的名称
  5. unsigned long flags; 定义资源的类型,比如MEM,IO,IRQ,DMA类型
  6. struct resource *parent, *sibling, *child;
  7. };
这个结构表示设备所拥有的资源,即I/O端口、I/O映射内存、中断及DMA等。这里的地址指的是物理地址。
6、device_register和platform_device_register

  1. int device_register(struct device *dev)
  2. {
  3. device_initialize(dev);
  4. return device_add(dev);
  5. }
  6. //初始化一个设备,然后加入到系统中

  7. int platform_device_register(struct platform_device *pdev)
  8. {
  9. device_initialize(&pdev->dev);
  10. return platform_device_add(pdev);
  11. }
  12. EXPORT_SYMBOL_GPL(platform_device_register);
我们看到注册一个platform device分为了两部分,初始化这个platform_device,然后将此platform_device添加到platform总线中。输入参数platform_device可以是静态的全局设备。

另外一种机制就是动态申请platform_device_alloc一个platform_device设备,然后通过platform_device_add_resources及platform_device_add_data等添加相关资源和属性。

无论哪一种platform_device,最终都将通过platform_device_add这册到platform总线上。
device_register()和platform_device_register()都会首先初始化设备
区别在于第二步:其实platform_device_add()包括device_add(),不过要先注册resources,然后将设备挂接到特定的platform总线。
7 device_driver和platform driver
Platform device是一种device自己是不会做事情的,要有人为它做事情,那就是platform driver。platform driver遵循linux系统的driver model。对于device的discovery/enumerate都不是driver自己完成的而是由由系统的driver注册机制完成。driver编写人员只要将注册必须的数据结构初始化并调用注册driver的kernel API就可以了。

接下来来看platform_driver结构体的原型定义,在http://lxr.linux.no/#linux+v2.6.25/include/linux/platform_device.h#L48中,代码如下:
  1. struct platform_driver {
  2. int (*probe)(struct platform_device *);
  3. int (*remove)(struct platform_device *);
  4. void (*shutdown)(struct platform_device *);
  5. int (*suspend)(struct platform_device *, pm_message_t state);
  6. int (*suspend_late)(struct platform_device *, pm_message_t state);
  7. int (*resume_early)(struct platform_device *);
  8. int (*resume)(struct platform_device *);
  9. struct device_driver driver;
  10. };

可见,它包含了设备操作的几个功能函数,同时包含了一个device_driver结构,说明device_driver是platform_driver的基类。驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于http://lxr.linux.no/#linux+v2.6.25/include/linux/device.h#L121中:
  1. struct device_driver {
  2. const char *name;
  3. struct bus_type *bus;
  4. struct module *owner;
  5. const char *mod_name; /* used for built-in modules */
  6. int (*probe) (struct device *dev);
  7. int (*remove) (struct device *dev);
  8. void (*shutdown) (struct device *dev);
  9. int (*suspend) (struct device *dev, pm_message_t state);
  10. int (*resume) (struct device *dev);
  11. struct attribute_group **groups;
  12. struct driver_private *p;
  13. };
device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。

需要注意这两个变量:name和owner。其作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。

device_driver结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。内核正是通过这个一致性来为驱动程序找到资源,即 platform_device中的resource。
8 driver_register 和platform_driver_register

内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在http://lxr.linux.no/#linux+v2.6.25/drivers/base/platform.c#L458文件中,具体实现代码如下:

  1. int platform_driver_register(struct platform_driver *drv)
  2. {
  3. drv->driver.bus = &platform_bus_type;
  4. /*设置成platform_bus_type这个很重要,因为driver和device是通过bus联系在一起的,具体在本例中是通过 platform_bus_type中注册的回调例程和属性来是实现的, driver与device的匹配就是通过 platform_bus_type注册的回调例程platform_match ()来完成的。*/

  5. if (drv->probe)
  6. drv->driver.probe = platform_drv_probe;
  7. //在really_probe函数中,回调了platform_drv_probe函数

  8. if (drv->remove)
  9. drv->driver.remove = platform_drv_remove;
  10. if (drv->shutdown)
  11. drv->driver.shutdown = platform_drv_shutdown;
  12. if (drv->suspend)
  13. drv->driver.suspend = platform_drv_suspend;
  14. if (drv->resume)
  15. drv->driver.resume = platform_drv_resume;
  16. return driver_register(&drv->driver);
  17. }
  18. EXPORT_SYMBOL_GPL(platform_driver_register);

不要被上面的platform_drv_XXX吓倒了,它们其实很简单,就是将struct device转换为struct platform_device和struct platform_driver,然后调用platform_driver中的相应接口函数。那为什么不直接调用platform_drv_XXX等接口呢?这就是Linux内核中面向对象的设计思想。

device_driver提供了一些操作接口,但其并没有实现,相当于一些虚函数,由派生类platform_driver进行重载,无论何种类型的driver都是基于device_driver派生而来的,device_driver中具体的各种操作都是基于统一的基类接口的,这样就实现了面向对象的设计。

更详细的请看:http://blog.csdn.net/sailor_8318/article/details/5267698
分享到:
评论

相关推荐

    详解Linux2.6内核中基于platform机制的驱动模型

    本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型。首先介绍了Platform总线的基本概念,接着介绍了platform device和platform driver的定义和加载过程,分析了其与基类device 和driver的派生关系及在...

    论文研究-基于MDA的GBDSS决策服务组合平台模型与运作机制.pdf

    论文研究-基于MDA的GBDSS决策服务组合平台模型与运作机制.pdf, 基于网格的决策支持系统(Grid based decision support system, GBDSS)的决策服务组合建模既要考虑领域内...

    基于高通MSM_8x60的I2C驱动终极讲解

    网上的I2C驱动讲解已经很多啦,我想不想画蛇添足,我想写一个完整的I2C驱动,包括系统启动,总线注册,驱动注册,设备注册,里面会贯穿Linux设备驱动模型,platform机制等等,基于高通MSM 8x60,I2C控制器为qup,

    2020未来智慧园区白皮书.pdf

    未来智慧园区“1-3-4-1”蓝图框架,以愿景驱动各方力量为智慧园区建设服务,以建设目标指引智慧园区建设方向,以全面感知、泛在联接、主动服务和智能进化为基本特征明确建设需求,以技术为保障打造园区物理世界和...

    Java 1.6 API 中文 New

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...

    JAVA_API1.6文档(中文)

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...

    java api最新7.0

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...

    [Java参考文档].JDK_API 1.6

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类。...

    [Java参考文档]

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...

    JavaAPI1.6中文chm文档 part1

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...

    JavaAPI中文chm文档 part2

    java.util 包含 collection 框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组)。 java.util.concurrent 在并发编程中很常用的实用工具类...

    java开源包1

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包11

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包2

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包3

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包6

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

    java开源包5

    提供了一个基于对象模型的 ActionScript 字节码,并提供了 ActionScript 字节码统计工具。 Java类重加载工具 JReloader JReloader 是一个用来重新加载class文件而无需重启JVM的工具。 PHPJava Bridge php调用java...

Global site tag (gtag.js) - Google Analytics