前言

区分设备驱动模型平台设备驱动模型

设备驱动模型 可以理解为 总线、设备、驱动

平台设备驱动模型 就是那些 Linux 内核管理没有物理总线(即是不需要特殊时序控制的设备)(也是Linux内核没有自动创建相应驱动总线的设备类型)的设备的一套 Linux 平台总线、平台模型、平台驱动的模型。

7. 平台设备驱动

为解决驱动代码和设备信息耦合问题,linux提出了设备驱动模型。

注意,前面的总线、设备、驱动是一个软件层面的抽象,与 SOC 中物理总线概念不一样。

物理总线:芯片与各个功能外设之间传送信息的公共通信干线,包括数据总线、地址总线和控制总线,以此来传输各种通信时序

驱动总线:负责管理驱动和设备。制定设备和驱动的匹配规则。一旦总线上注册了新设备/驱动,总线便执行匹配程序。

对于常见的 I2C、SPI、USB物理总线Linux 内核都会自动创建与之对应的 驱动总线。所以 I2C设备、SPI设备、USB设备都会挂在在相应的总线上。

相对的,实际项目开发中还有很多结构简单的设备是不需要特殊的时序控制的。也就没有相应的物理总线,Linux 也不会为它们创建相应的驱动总线。如 LED、RTC时钟、按键等等。

但是为了这些简单的设备也能遵循设备驱动模型,Linux 内核引入了一种虚拟总线--平台总线

平台总线 用于管理、挂在那些没有物理总线的设备,且,这些设备被称为平台设备,对应的设备驱动被称为平台驱动

平台设备使用 platform_device 结构体进行表示,继承了设备驱动模型中的 device 结构体。

平台驱动使用 platform_driver 结构体进行表示,继承了设备驱动模型中的 device_driver 结构体。

7.1 平台总线

Linux内核只有一条平台总线,用于图一管理简单设备--platform_bus_type

7.1.1 平台总线注册和匹配方式

最先比较

  • 最先比较 platform_device.driver_overrideplatform_driver.driver.name

  • 可以设置 platform_devicedriver_override,强制选择某个 platform_driver

其次比较

  • 其次比较 platform_device.nameplatform_driver.id_table[i].name

  • platform_driver.id_tableplatform_device_id 指针,表示该 drv 支持若干个 device,它里面列出了各个 device{.name, .driver_data},其中的 name 表示该 drv 支持的设备的名字,driver_data是些提供给该 device 的私有数据。

最后比较

  • 最后比较 platform_device.nameplatform_driver.driver.name

  • 由于 platform_driver.id_table 可能为空,所以,接下来就可以使用 platform_driver.driver.name 来匹配。

7.1.2 源码分析

平台总线

  • 内核使用 bus_type 来抽象系统中的总线。相应地,内核使用 platform_bus_type 来描述平台总线。
  • 源码:
struct bus_type platform_bus_type = {

    .name           = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops, }; EXPORT_SYMBOL_GPL(platform_bus_type);
  • 位于 内核源码/driver/base/platform.c

  • 该总线在Linux内核启动的时候自动进行注册

  • 平台总线初始化函数源码:

int __init platform_bus_init(void){
int error;
...
error = bus_register(&platform_bus_type);
...
return error;}
  • 位于 内核源码/driver/base/platform.c
  • error = bus_register(&platform_bus_type); 就是向Linux内核注册 plateform_bus_type 平台总线。

建议:以上匹配规则及源码,可以追踪函数 platform_match 源码来分析。

7.2 平台设备

7.2.1 platform_device

平台设备

  • 使用 platform_device 描述平台设备。
  • 源码:
struct platform_device {
const char *name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
/* 省略部分成员 */
};
  • 位于 内核源码/include/linux/platform_device.h
  • name:设备名称,总线进行匹配时,会比较设备和驱动的名称是否一致;
  • id:指定设备的编号,Linux支持同名的设备,而同名设备之间则是通过该编号进行区分;
  • dev:Linux设备模型中的device结构体,platform_device 通过继承该结构体可复用它的相关代码,方便内核管理平台设备;
  • num_resources:记录资源的个数,当结构体成员 resource 存放的是数组时,需要记录 resource 数组的个数,内核提供了宏定义 ARRAY_SIZE 用于计算数组的个数;
  • resource:平台设备提供给驱动的资源,如irq,dma,内存等等;
  • id_entry:平台总线提供的另一种匹配方式,原理依然是通过比较字符串,这里的 id_entry 用于保存匹配的结果;

7.2.2 设备信息

平台设备的工作是为 驱动程序 提供 设备信息。包括 硬件信息 和 软件信息。

  • 硬件信息:驱动程序需要使用到的寄存器、中断号、内存资源、IO口等等;
  • 软件信息:以太网设备中的 MAC 地址、I2C 设备中的设备地址等等。

硬件信息

  • 硬件信息使用 struct resource 来保存设备所提供的资源。
  • 源码:
/**
* Resources are tree-like, allowing nesting etc..
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
/* 省略部分成员 */
};
  • 位于 内核源码/include/linux/ioport.h
  • name:资源名字,可为 NULL;
  • start、end:指定资源的起始地址及结束地址;
    • 对于 IORESOURCE_IO 和 IORESOURCE_MEM 是有起始和结束地址的,若只有一个引脚或者一个通道,那么 start == end
  • flags:用于指定资源的类型,在 Linux 中,资源包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型,如:
    • IORESOURCE_IO:IO 地址空间,对应于 IO 端口映射方式;
    • IORESOURCE_MEM:外设可直接寻址的地址空间;
    • IORESOURCE_IRQ:指定该设备使用哪个中断;
    • IORESOURCE_DMA:指定 DMA 通道。

设备驱动程序主要目的还是操作设备的寄存器。

不同架构的计算机提供不同的操作接口,主要有IO端口映射IO内存映射两种方式。

IO端口映射方式:

  • 只能通过专门的接口函数才能访问。

IO内存映射方式:

  • 可以像内存一样访问,去读写寄存器。

软件信息

  • 软件信息需要以私有数据保存;
  • platform_device 结构体中继承有 device 结构体,成员为 dev,该结构体里面的 platform_data 可以用于保存设备的私有数据。
    • platform__datavoid * 类型的万能指针,所以,只需要把私有数据的地址付给 platform_data 即可。

7.2.3 注册/注销平台设备

注册:platform_device_register

  • 注册平台设备,挂在到平台总线上。
  • 函数原型:int platform_device_register(struct platform_device *pdev);位于 内核源码/drivers/base/platform.c
    • pdedplatform_device 类型结构体指针;
    • 返回:
      • 成功:0;
      • 失败:负数。

注销:platform_device_unregister

  • 注销平台设备。
  • 函数原型:void platform_device_unregister(struct platform_device *pdev);位于 **

    内核源码/drivers/base/platform.c**。

    • pdedplatform_device 类型结构体指针;

7.3 平台驱动

7.3.1 platform_driver

平台驱动

  • 使用 platform_driver 描述平台驱动。
  • 源码:
struct platform_driver {

    int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
  • 位于 内核源码/include/platform_device.h

  • probe:匹配成功后执行的回调函数。

  • remove:移除某个平台设备是的回调函数。

  • driver:Linux 设备模型中用于抽象驱动的 device_driver 结构体,platform_driver 继承该结构体,也就获取了设备模型驱动对象的特性。

  • id_table:表示该驱动能够兼容的设备类型。

  • platform_device_id

    • name:指定驱动名称。(用于和 platform_device 中的 name 比较,匹配。)
    • driver_data:用于保存设备的配置。
    • 源码:
struct platform_device_id
{
char name[PLATFORM_NAME_SIZE];
kernel_ulong_t driver_data;
};

7.3.2 注册/注销平台驱动

注册:platform_driver_register

  • 注册平台驱动,挂在到平台总线上。
  • 函数原型:int platform_driver_register(struct platform_driver *drv)
    • drvplatform_driver 类型结构体指针;
    • 返回:
      • 成功:0;
      • 失败:负数。

注销:platform_driver_unregister

  • 注销平台启动驱动。
  • 函数原型:void platform_driver_unregister(struct platform_driver *drv);位于 **

    内核源码/drivers/base/platform.c**。

    • drvplatform_driver 类型结构体指针;

7.3.3 平台驱动获取设备信息

首先要知道的是,平台设备的硬件信息保存在 resource 结构体中。而软件信息则保存在 platform_data 中。

获取硬件信息:platform_get_resource

  • 获取平台设备提供的资源结构体。一般用在 probe 函数中。、

  • 函数原型:struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);

  • dev:指定获取哪个平台设备的资源;

  • type:指定获取资源的类型,如IORESOURCE_MEM、IORESOURCE_IO等;

  • num:指定要获取的资源编号。每个设备所需要的资源的个数是不一样的。且不同资源的编号是不一样的。

  • 返回:

    • 成功:struct resouce 结构体类型指针;
    • 失败:NULL。
  • 若要获取的资源类型为 IORESOURCE_IRQ,平台设备驱动还提供以下函数接口,来获取中断引脚。

    • 函数原型:int platform_get_irq(struct platform_device *pdev, unsigned int num)

      • pedv:指定需要获取哪个平台设备的资源;
      • num:指定要获取的资源编号。
    • 返回:
      • 成功:可用中断号;
      • 失败:负数。

获取软件信息:dev_get_platdata

* dev:struct device 结构体类型指针。

static inline void *dev_get_platdata(const struct device *dev)
{
return dev->platform_data;
}

参考

【linux】驱动-7-平台设备驱动的更多相关文章

  1. 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联

    转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...

  2. [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联

    转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...

  3. Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)

    Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...

  4. Linux Platform devices 平台设备驱动

    设备总线驱动模型:http://blog.csdn.net/lizuobin2/article/details/51570196 本文主要参考:http://www.wowotech.net/devi ...

  5. 【Linux高级驱动】平台设备驱动机制的编程流程与编译进内核

    [平台设备驱动机制的编程流程] [如何将驱动静态的编译进内核镜像] 1.添加资源(dev-led.c) 1.1:一般来说,系统习惯上将资源放在arch/arm/plat-samsung/目录中 cp ...

  6. 嵌入式Linux驱动学习之路(十七)驱动程序分层分离概念-平台设备驱动

    平台设备驱动: 包含BUS(总线).DEVICE.DRIVER. DEVICE:硬件相关的代码 DRIVER:比较稳定的代码 BUS有一个driver链表和device链表. ①把device放入bu ...

  7. 【Linux高级驱动】linux设备驱动模型之平台设备驱动机制

    [1:引言: linux字符设备驱动的基本编程流程] 1.实现模块加载函数  a.申请主设备号    register_chrdev(major,name,file_operations);  b.创 ...

  8. Linux驱动之平台设备

    <平台设备设备驱动> a:背景: 平台总线是Linux2.6的设备驱动模型中,关心总线,设备和驱动这3个实体.一个现实的Linux设备和驱动通常需要挂接在一种总线上(比如本身依附于PCI, ...

  9. Linux驱动设计——字符设备驱动(一)

    Linux字符设别驱动结构 cdev结构体 struct cdev { struct kobject kobj; struct module *owner; const struct file_ope ...

随机推荐

  1. js bitwise operation all in one

    js bitwise operation all in one 位运算 & 按位与 | 按位或 ^ 按位异或 / XOR let a = 5; // 000000000000000000000 ...

  2. 树莓派 4B 入门教程

    树莓派 4B 入门教程 Raspberry Pi, Raspberry Pi 3B, Raspberry Pi 4B 树莓派 4B 入门手册 PDF Raspberry Pi Beginners Gu ...

  3. auto responsive rem

    auto responsive rem 移动端适配 ;(function(win, lib) { var doc = win.document; var docEl = doc.documentEle ...

  4. Node.js & process.env & OS Platform checker

    Node.js & process.env & OS Platform checker Window 10 Windows 7 ia32 CentOS $ node # process ...

  5. 如何导出android内部存储的文件(不用root)

    这段时间公司项目,涉及到数据缓存,由于需要缓冲的数据太多.太大,通过网络请求,再缓存到本地sqlite数据库,太费时间,消耗流量.所以准备先在本地保存一个标准版sqlite数据库(包含数据),打包到a ...

  6. JS实现点击加载更多效果

    适用场景:后端直接把所有的文章都给你调出来了,但是领导又让做点击加载更多效果...(宝宝心里苦啊)   点击加载更多效果:         第一个和第二个参数分别是btn和ul的DOM(必填)     ...

  7. 如何在ASP.NET Core中编写高效的控制器

    ​通过遵循最佳实践,可以编写更好的控制器.所谓的"瘦"控制器(指代码更少.职责更少的控制器)更容易阅读和维护.而且,一旦你的控制器很瘦,可能就不需要对它们进行太多测试了.相反,你可 ...

  8. 行业动态 | Apache Pulsar 对现代数据堆栈至关重要的四个原因

    与 Kafka 相比,Pulsar 的架构使它在跨地域复制.扩展.多租户和队列等方面具有重要的优势.   1 月 27 日,DataStax 宣布收购Kesque(Pulsar 即服务),加入到了 P ...

  9. JVM性能调优经验总结

    本文转载自JVM性能调优经验总结 说明 调优是一个循序渐进的过程,必然需要经历多次迭代,最终才能换取一个较好的折中方案. 在JVM调优这个领域,没有任何一种调优方案是适用于所有应用场景的,同时,切勿极 ...

  10. Byte Buddy学习笔记

    本文转载自Byte Buddy学习笔记 简介 Byte Buddy是一个JVM的运行时代码生成器,你可以利用它创建任何类,且不像JDK动态代理那样强制实现一个接口.Byte Buddy还提供了简单的A ...