Linux设备驱动模型之platform总线深入浅出
Linux驱动之platform总线详解

Linux驱动之platform总线详解⽬录1、platform 总线简介1.1、Linux 驱动的分离和分层思想1.1.1、Linux 驱动的分离1.2、platform 平台驱动模型2、platform 框架2.1、platform 总线2.2、platform 驱动2.2.1、platform 驱动定义2.2.2、platform 驱动注册2.3、platform 设备2.3.1、platform 设备定义2.4、platform 匹配过程3、总结1、platform 总线简介1.1、Linux 驱动的分离和分层思想1.1.1、Linux 驱动的分离先讲 Linux 驱动的分离,Linux 操作系统⽀持在各类 CPU 上运⾏,因为每⼀种 CPU 对设备的驱动不⼀样,这样就造成了Linux 内核中积累了⼤量代码,并且这些代码关于同⼀设备的描述⼤致相同,这就使得内核代码很冗余。
以 CPU 通过 I2C 控制 MPU6050 为例:从图可以看出每⼀种平台下都有⼀套主机驱动和⼀套设备驱动,因为每个平台的 I2C 控制器不同,所以这个主机驱动得每个平台配⼀个⾃⼰的,但⼤家所⽤的 MPU6050 是⼀样的,所以完全可以就共⽤⼀套设备驱动代码。
完善后框架如下:当然,这只是对于 I2C 下的 MPU6050 这个设备,实际情况下,I2C 下肯定会挂载很多设备,根据这个思路,我们可以得到框架为:⽽在实际开发中,I2C 主机驱动半导体⼚家会编写好,设备驱动也由设备⼚家编写好,我们只需要提供设备信息即可,如设备接到那个 I2C 接⼝上,I2C 速度为多少。
这样就相当于把设备信息从设备驱动中剥离出来,⽽设备驱动也会⽤标准⽅法去获取设备信息(如从设备树中获取设备信息)。
这样就相当于驱动只负责驱动,设备(信息)只负责设备,想办法将两者进⾏匹配即可,来做这个匹配⼯作的就是总线,这就构成了 Linux 中的总线-驱动-设备模型。
Linux设备驱动模型与sysfs---platform总线设备驱动

Linux在2.6版本引入了设备驱动模型,设备驱动模型负责统一实现和维护一些特性,诸如:热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施1.设备驱动模型基本概念设备驱动模型主要包含:类(class)、总线(bus)、设备(device)、驱动(driver),它们的本质都是内核中的几种数据结构的“实例”∙类的本质是class结构体类型,各种不同的类其实就是class的各种实例∙总线的本质是bus_type结构体类型,各种不同的总线其实就是bus_type的各种实例∙设备的本质是device结构体类型,各种不同的设备其实就是device的各种实例∙驱动的本质是device_driver结构体类型,各种不同的驱动其实就是device_driver的各种实例2.sysfs基本概念sysfs其实就是/sys目录,其主要作用就是:展示设备驱动模型中各组件的层次关系,并将各组件的本体——内核中的数据结构以文件形式呈现,方便用户层查看及操作3./sys目录结构与设备驱动模型∙/sys目录结构很好的展示了驱动设备模型,如图:∙注意:同一个设备可能在/sys中存在多个设备文件,比如一颗led的设备文件可能在/sys/bus/platform/devices/led1,同时还有一个在/sys/class/leds/led1。
虽然他们都是同一颗led的设备文件,但是他们的来源、机制、原理都是不同的,不能混为一谈4.各组件的特性与联系∙kobject:设备驱动模型各实例的最基本单元,提供一些公用型服务如:提供该实例在sysfs中的操作方法(show和store);提供在sysfs中以文件形式存在的属性,其实就是应用接口;提供各个实例的层次架构,让sysfs中弄出目录结构。
设备驱动模型中每个实例内部都会包含一个kobject∙总线、设备、驱动,这三者有着密切的联系。
在内核中,设备和驱动是分开注册的,注册设备的时候,并不需要驱动已经存在,而驱动被注册的时候,也不需要对应的设备已经被注册。
platform设备驱动

定义 platformf_driver
注册 platform_driver
/* 参考drivers/base/platform.c */ static const struct platform_device_id *platform_match_id( const struct platform_device_id *id,struct platform_device *pdev) { while (id->name[0]) { if (strcmp(pdev->name, id->name) == 0) { pdev->id_entry = id; return id; } id++; } return NULL; }
platform设备注册/注销
• int platform_device_register(struct platform_device *pdev) • void platform_device_unregister(struct platform_device *pdev)
platform驱动注册/注销
platform总线匹配
/* 参考drivers/base/platform.c */ static int platform_match(struct device *dev, struct device_driver *drv) { struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); /* 因为没有配置CONFIG_OF_DEVICE ,这里返回0,不执行这个if 分支 */ if (of_driver_match_device(dev, drv)) return 1; /*这里也是返回0,不执行这个if 分支*/ if (acpi_driver_match_device(dev, drv)) return 1; /* 如果pdrv->id_table存在的话,调用platform_match_id函数 * 如果匹配成功,则返回1,否则返回0 */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* 如果前面都失败,则最后比较平台设备里的名字和设备驱动里的名字 * 即比较platform_ 与device_ * 如果匹配成功,则返回1,否则返回0 */ return (strcmp(pdev->name, drv->name) == 0); }
详解Linux2.6内核中基于platform机制的驱动模型

详解Linux2.6内核中基于platform机制的驱动模型【摘要】本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型。
首先介绍了Platform总线的基本概念,接着介绍了platform device和platform driver的定义和加载过程,分析了其与基类device 和driver的派生关系及在此过程中面向对象的设计思想。
最后以ARM S3C2440中I2C控制器为例介绍了基于platform总线的驱动开发流程。
【关键字】platform_bus, platform_device, resource , platform_driver, file_operations目录1 何谓platform bus? 22 device和platform_device 33 device_register和platform_device_register 54 device_driver和platform driver 85 driver_register 和platform_driver_register 106 bus、device及driver三者之间的关系177 哪些适用于plarform驱动?188 基于platform总线的驱动开发流程188.1 初始化platform_bus 198.2 定义platform_device 228.3 注册platform_device 228.4 定义platform_driver 288.5 注册platform_driver 298.6 操作设备321 何谓platform bus?Linux系统中许多部分对设备是如何链接的并不感兴趣,但是他们需要知道哪些类型的设备是可以使用的。
设备模型提供了一种机制来对设备进行分类,在更高的功能层面上描述这些设备,并使得这些设备对用户空间可见。
因此从2.6内核开始引入了设备模型。
深入解析LinuxPlatform_device及驱动

深⼊解析LinuxPlatform_device及驱动[导读] 前⽂分析了Linux设备驱动的驱动模型,本⽂来聊聊Platform_driver/Platform_device这个类。
做嵌⼊式Linux的驱动,这个也是绕不开的,所以来学习分析总结⼀下。
上⽂阅读:注:代码分析基于linux-5.4.31为什么有Platform_driver前⽂谈到的总线驱动模型(注这个图是照着bootlin的⽂档绘制的):同时,根据代码分析其基础数据结构框架关系如下(UML关系并不严谨,仅为理解⽅便):可见驱动程序的模型分层有⼀层总线基础层,那么对于嵌⼊式开发领域⽽⾔,有很多SOC芯⽚内置了各种外设,并⽐如LCD,UART、audio、摄像头⼝等等,并没有总线。
为了统⼀驱动架构抽象,所以引⼊了platform bus这个虚拟的总线模型。
做过嵌⼊式开发的⼈应该都有体会,这类设备在嵌⼊式系统中⾮常多,所以在研究具体某类设备的驱动开发之前,有必要研究platform 设备的驱动模型。
在强调⼀下这个是统⼀在总线驱动模型这个体系内的。
驱动模型的实现定义在./include/linux/platform_device.h中,来梳理⼀下这些数据结构间的关系:platform_device ⽤于抽象平台设备platform_driver ⽤于抽象匹配平台设备对应的驱动程序通过继承演化关系分析,platform_device/platform_driver 仍然统⼀于总线驱动模型,只是虚拟出来了⼀条platform bus这样⼀条虚拟总线。
platform_bus在哪⾥实现的呢?该模块的实现位于./driver/base/platform.c中struct device platform_bus = {.init_name = "platform",};platform.c导出了⼀系列内核全局操作接⼝集:EXPORT_SYMBOL_GPL(platform_bus);EXPORT_SYMBOL_GPL(__platform_driver_register);EXPORT_SYMBOL_GPL(__platform_driver_probe);EXPORT_SYMBOL_GPL(platform_get_resource_byname);EXPORT_SYMBOL_GPL(platform_get_irq_byname);....那么既然这条总线并不存在,往往并不能实现设备枚举、热插拔等功能。
Linux设备驱动之platform

Linux设备驱动之platform
根据Linux设备模型可知,一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等却不依附于此类总线。
基于这一背景,Linux设计了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动称为platform_driver。
设计目的
兼容设备模型
使得设备被挂接在一个总线上,因此,符合Linux 2.6 的设备模型。
其结果是,配套的sysfs 结点、设备电源管理都成为可能。
BSP和驱动隔离
在BSP中定义platform设备和设备使用的资源、设备的具体配置信息。
而在驱动中,只需要通过通用API去获取资源和数据,做到了板相关代码和驱动代码的分离,使得驱动具有更好的可扩展性和跨平台性。
软件架构
内核中Platform设备有关的实现位于include/linux/platform_device.h和drivers/base/platform.c两个文件中,它的软件架构如下:
由图片可知,Platform设备在内核中的实现主要包括三个部分:
Platform Bus,基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备;
Platform Device,基于底层device模块,抽象出Platform Device,用于表示Platform设备;Platform Driver,基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform 设备。
platfrm 总线、设备与驱动

platform 总线、设备与驱动2013-09-04 17:38:36分类:LINUXLinux2.6的设备驱动模型中,关心总线、设备和驱动3个实体,总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,在系统每次注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动称为platform_driver。
platform_device结构体:点击(此处)折叠或打开1.struct platform_device {2.const char * name;3. u32 id;4. struct device dev;5. u32 num_resources;6. struct resource * resource;7.};platform_driver结构体:点击(此处)折叠或打开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.};系统中为platform总线定义了一个bus_type的实例platform_bus_type:点击(此处)折叠或打开1.struct bus_type platform_bus_type ={ ="platform",3..dev_attrs = platform_dev_attrs,4..match = platform_match,5..uevent = platform_uevent,6..suspend = platform_suspend,7..suspend_late = platform_suspend_late,8..resume_early = platform_resume_early,9..resume= platform_resume,10.};下面就以2.6.22.6内核和DM9000为例,介绍下platform总线、设备与驱动在代码中的实现,DM9000驱动部分,依照《嵌入式Linux应用开发完全手册》进行配置,配置如下:arch\arm\plat-s3c24xx\common-smdk.c文件中添加,对应的是platform_device这个结构体:点击(此处)折叠或打开1.#include <linux/dm9000.h>2.3.static struct resource s3c_dm9k_resource[]={4.[0]={5..start = S3C2410_CS4,//ADDR2 = 0 ,发送地址时使用这个地址6..end= S3C2410_CS4 + 3,7..flags = IORESOURCE_MEM,8.},9.[1]={10..start = S3C2410_CS4 + 4,//ADDR2 = 1 ,发送数据时使用这个地址11..end= S3C2410_CS4 + 4 + 3,12..flags = IORESOURCE_MEM,13.},14.[2]={15..start = IRQ_EINT7,//IRQ_DM900016..end= IRQ_EINT7,//IRQ_DM900017..flags = IORESOURCE_IRQ,18.}19.20.};21.22.static struct dm9000_plat_data s3c_dm9k_platdata ={23..flags = DM9000_PLATF_16BITONLY,//数据总线宽度为1624.};25.26.static struct platform_device s3c_device_dm9k ={ ="dm9000",28..id = 0,29..num_resources = ARRAY_SIZE(s3c_dm9k_resource),30..resource = s3c_dm9k_resource,31..dev ={32..platform_data =&s3c_dm9k_platdata,33.}34.};35.36.37.static struct platform_device __initdata *smdk_devs[]={38.……39.&s3c_device_dm9k,40.};那么很显然有platform_device就对应应该有个platform_driver,其在dm9000.c文件中:点击(此处)折叠或打开1.static struct platform_driver dm9000_driver ={2..driver ={ ="dm9000",4..owner = THIS_MODULE,5.},6..probe = dm9000_probe,7..remove = dm9000_drv_remove,8..suspend = dm9000_drv_suspend,9..resume= dm9000_drv_resume,10.};那么具体去加载platform_device和platform_driver到函数是什么呢?在内核代码中可以找到:点击(此处)折叠或打开1.static int __init dm9000_init(void)2.{3.……4. return platform_driver_register(&dm9000_driver);/* search board and register */5.}6.module_init(dm9000_init);7.8.void __init smdk_machine_init(void)9.{10.……11. platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));12.……13.}有一点需要注明:对platform_device的定义通常是在BSP的板文件中实现,在板文件中,platform_device归纳为一个数组,最终通过platform_add_devices(struct platform_device **devs, int num)函数统一注册。
Linux驱动之总线驱动模型

随着系统结构演化越来越复杂,Linux内核对设备描述衍生出一般性的抽象描述,形成一个分层体系结构,从而引入了设备驱动模型。
这样描述还是不够让人理解,来看一下这些需求就好理解些:•Linux内核可以在各种体系结构和硬件平台上运行,因此需要最大限度地提高代码在平台之间的可重用性。
•分层实现也实现了软件工程的高内聚-低耦合的设计思想。
低耦合体现在对外提供统一的抽象访问接口,高内聚将相关度紧密的集中抽象实现。
•Linux内核驱动程序模型是先前在内核中使用的所有不同驱动程序模型的统一。
它旨在通过将一组数据和操作整合到全局可访问的数据结构中,来扩展基于基础总线来桥接设备驱动程序。
传统的驱动模型为它们所控制的设备实现了某种类似于树的结构(有时只是一个列表)。
不同类型的总线之间没有任何一致性。
驱动模型抽象了啥当前驱动程序模型为描述总线和总线下可能出现的设备提供了一个通用的、统一的模型。
统一总线模型包括一组所有总线都具有的公共属性和一组公共回调,如总线探测期间的设备发现、总线关闭、总线电源管理等。
通用的设备和桥接接口反映了现代计算机的目标:即执行无缝设备“即插即用”,电源管理和热插拔的能力。
特别是,英特尔和微软规定的模型(即ACPI)可确保与x86兼容的系统上几乎任何总线上的几乎所有设备都可以在此范式下工作。
当然,虽然大多数总线都支持其中大多数操作,但并不是每条总线都能够支持所有此类操作。
那么哪些通用需求被抽象出来了呢?•电源系统和系统关机,对于电源管理与系统关机对于设备相关的操作进行抽象实现。
关机为什么要被抽象出来管理,比如设备操作正在进行此时系统收到关机指令,那么在设备模型层就会遍历系统设备硬件,确保系统正确关机。
•用户空间访问:sysfs虚拟文件系统实现与设备模型对外的访问抽象,这也是为什么说Linux 设备也是文件的由来。
实际从软件架构层面看,这其实是一个软件桥接模块,抽象出统一用户访问接口,桥接了设备驱动。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux设备驱动模型之platform总线深入浅出
在Linux2.6以后的设备驱动模型中,需关心总线,设备和驱动这三种实体,总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。
对于依附在USB、PCI、I2C、SPI等物理总线来这些都不是问题。
但是在嵌入式系统里面,在Soc系统中集成的独立外设控制器,挂接在Soc内存空间的外设等却不依附在此类总线。
基于这一背景,Linux发明了一种总线,称为platform。
相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是一种虚拟、抽象出来的总线,实际中并不存在这样的总线。
platform总线相关代码:driver\base\platform.c 文件相关结构体定义:include\linux\platform_device.h 文件中
platform总线管理下最重要的两个结构体是platform_device和platform_driver 分别表示设备和驱动在Linux中的定义如下一:platform_driver
//include\linux\platform_device.h struct platform_driver { int (*probe)(struct platform_device *); //探测函数,在注册平台设备时被调用int (*remove)(struct platform_device *); //删除函数,在注销平台设备时被调用void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); //挂起函数,在关机被调用int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *);//恢复函数,在开机时被调用struct device_driver driver;//设备驱动结构};
1
2
3
4
5
6
7
8。