platform_get_resource
platform_get_resource函数
在后续Linux设备驱动开发中会用到此函数,且在后续文章中会跳转过来,提前埋下种子。
文中提到的《设备树如何转换成platform_device》和《Linux设备树解析》,后续会更新。
platform_get_resource函数原型
功能:从设备中获取相关资源。
参数@dev:平台设备。描述设备信息的,有设备树描述。
参数@type: 资源类型。下文详细讲解。
参数@num: 资源索引。同类型资源进行重新编号后的下标编号,注意和资源数组中的元素数量即num_resources区别。(要注意这一点),最后总结时会讲到。
/*** platform_get_resource - get a resource for a device* @dev: platform device* @type: resource type* @num: resource index*/
struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)
{u32 i;for (i = 0; i < dev->num_resources; i++) {struct resource *r = &dev->resource[i];if (type == resource_type(r) && num-- == 0)return r;}return NULL;
}
补充Linux下设备资源相关知识
IIC、SPI、GPIO 等这些外设都有对应的寄存器,这些寄存器其实就是一组内存空间,Linux内核使用resource结构体来描述一段内存空间,“resource”翻译出来就是“资源”,因此用resource结构体描述的都是设备资源信息,resource 结构体定义在include/linux/ioport.h 中,定义如下:
/** Resources are tree-like, allowing* nesting etc..*/struct resource {resource_size_t start;resource_size_t end;const char *name;unsigned long flags;unsigned long desc;struct resource *parent, *sibling, *child;};对于 32 位的 SOC 来说,resource_size_t 是 u32 类型的。
其中 start 表示开始地址,end 表示结束地址,
name 是这个资源的名字,flags 是资源标志位,一般表示资源类型,
可选的资源标志定义在文件 include/linux/ioport.h 中,如下所示:/** IO resources have these defined flags.** PCI devices expose these flags to userspace in the "resource" sysfs file,* so don't move them.*/
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_REG 0x00000300 /* Register offsets */
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
#define IORESOURCE_BUS 0x00001000#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
#define IORESOURCE_READONLY 0x00004000
#define IORESOURCE_CACHEABLE 0x00008000
#define IORESOURCE_RANGELENGTH 0x00010000
#define IORESOURCE_SHADOWABLE 0x00020000#define IORESOURCE_SIZEALIGN 0x00040000 /* size indicates alignment */
#define IORESOURCE_STARTALIGN 0x00080000 /* start field is alignment */#define IORESOURCE_MEM_64 0x00100000
#define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */
#define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */#define IORESOURCE_EXT_TYPE_BITS 0x01000000 /* Resource extended types */
#define IORESOURCE_SYSRAM 0x01000000 /* System RAM (modifier) */#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */#define IORESOURCE_DISABLED 0x10000000
#define IORESOURCE_UNSET 0x20000000 /* No address assigned yet */
#define IORESOURCE_AUTO 0x40000000
#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */
大家一般最常见的资源标志就是IORESOURCE_MEM ,IORESOURCE_REG 和 IORESOURCE_IRQ 等。比如后续更新的Linux下CAN驱动开发中也使用了platform_get_resource(pdev,IORESOURCE_MEM, 0),IORESOURCE_MEM代表内存地址。
回到正题,继续分析上面函数
描述设备信息,传统的用 platform_device 来描述设备信息。当 Linux 内核支持了设备树以后就不需要用户手动去注册platform 设备了。因为设备信息都放到了设备树中去描述,Linux 内核启动的时候会从设备树中读取设备信息,然后将其组织成 platform_device 形式,至于设备树到 platform_device 的具体过程参考《设备树如何转换成platform_device》
下面列举platform_device这种“古老”方式来编写设备信息,用来分析platform_get_resource如何拿到设备信息的。设备树方式来编写设备信息的框架就不写了,现在很常用,后续更新设备树的详细介绍,包括语法等,参考《Linux设备树解析》。
/******************** 采用自定义platform_device这种“古老”方式来编写设备信息 **********************/
// 简要描述xxxdevice.c 即platform_device框架如下所示#include <linux/xxx.h>
....../* 寄存器地址定义*/
#define PERIPH1_REGISTER_BASE (0X20000000) /* 外设 1 寄存器首地址 */
#define PERIPH2_REGISTER_BASE (0X020E0068) /* 外设 2 寄存器首地址 */
#define REGISTER_LENGTH 4/* 设备资源信息 */
static struct resource xxx_resources[] = {[0] = {.start = PERIPH1_REGISTER_BASE,.end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,},[1] = {.start = PERIPH2_REGISTER_BASE,.end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,},
};/* platform 设备结构体 */
static struct platform_device xxxdevice = {.name = "xxx-peripheral",.id = -1,.num_resources = ARRAY_SIZE(xxx_resources),.resource = xxx_resources,
};/* 设备模块加载 */
static int __init xxxdevice_init(void)
{return platform_device_register(&xxxdevice);
}/* 设备模块注销 */
static void __exit xxx_resourcesdevice_exit(void)
{platform_device_unregister(&xxxdevice);
}module_init(xxxdevice_init);
module_exit(xxxdevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("TieTouXiaoGe");/*********************************************** 结束 *********************************************/
所以上述for循环的次数即资源数组xxx_resources[]的元素数量。
struct resource *r = &dev->resource[i]; 表示从第一份资源开始逐个搜索,
然后if (type == resource_type( r ) && num-- == 0),这行代码首先通过
type == resource_type( r )判断当前这份资源的类型是否匹配,如果匹配则再通过num-- == 0判断是否是你要的(这里先判断是否等于0再自减1),如果不匹配重新提取下一份资源而不会执行num-- == 0这一句代码。通过以上两步就能定位到你要找的资源了,接着把资源返回即可。如果都不匹配则return NULL。
总结
// 设备驱动开发中常用
struct resource *res
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
// 获取设备内存地址资源。struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num)
unsigned int type决定资源的类型,unsigned int num决定type类型的第几份资源(从0开始)。即使同类型资源在资源数组中不是连续排放也可以定位得到该资源。比如第一份IORESOURCE_IRQ类型资源在resource[2],而第二份在resource[5],那platform_get_resource(pdev,IORESOURCE_IRQ,0);可以定位第一份IORESOURCE_IRQ资源;
platform_get_resource(pdev,IORESOURCE_IRQ,1);可以定位第二份IORESOURCE_IRQ资源。
之所以能定位到资源,在于函数实现中的这一行代码:
if (type == resource_type( r ) && num-- == 0)该行代码,如果没有匹配资源类型,
num-- == 0不会执行而重新提取下一份资源,只有资源匹配了才会寻找该类型的第几份资源,即使这些资源排放不连续。(解释了上面的参数@num)
platform_get_resource相关推荐
- platform_get_resource的分析
阅读platformdriver的代码时,发现在probe函数直接调用platform_get_resource从pdev中获取io内存,但却没有判断传给probe的pdev是否属于这个驱动 ! 后来 ...
- 谈内核资源申请platform_get_resource、devm_request_mem_region、devm_ioremap
以IO内存资源为例: platform_get_resource(pdev, IORESOURCE_MEM, 0); 即可得到一个IO内存资源节点指针, 包括了地址的开始,结束地址等, 该IO内存的长 ...
- 嵌入式Linux设备驱动程序:发现硬件配置
嵌入式Linux设备驱动程序:发现硬件配置 Embedded Linux device drivers: Discovering the hardware configuration Interfac ...
- MTD NANDFLASH驱动相关知识介绍
转:http://blog.csdn.net/zhouzhuan2008/article/details/11053877 目录 MTD总概述 MTD数据结构 MTD相关层实现 MTD,Memory ...
- linux驱动:TI+DM8127+GPIO(二)之驱动
二.[GPIO驱动框架>驱动driver] 重要结构体 gpio_chip:管理一组GPIO gpio_desc:描述每个GPIO gpio_bank:封装了gpio_chip加入GPIO控制的 ...
- Linux驱动修炼之道-RTC子系统框架与源码分析【转】
转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://bl ...
- pinctrl框架【转】
转自:http://www.cnblogs.com/kevinhwang/p/5703192.html pinctrl框架是linux系统为统一各SOC厂家pin管理,目的是为了减少SOC厂家系统移植 ...
- 精彩---rtl8139网卡驱动程序分析
学习应该是一个先把问题简单化,再把问题复杂化的过程.一开始就着手处理复杂的问题,难免让人有心惊胆颤,捉襟见肘的感觉.读Linux网卡驱动 也是一样.那长长的源码夹杂着那些我们陌生的变量和符号,望而生畏 ...
- I2C 总线原理与架构
一.I2C总线原理 I2C是一种常用的串行总线,由串行数据线SDA 和串行时钟线SCL组成.I2C是一种多主机控制总线,它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须 ...
- Linux驱动之平台设备
<平台设备设备驱动> a:背景: 平台总线是Linux2.6的设备驱动模型中,关心总线,设备和驱动这3个实体.一个现实的Linux设备和驱动通常需要挂接在一种总线上(比如本身依附于PCI, ...
最新文章
- rocketmq 消息指定_RocketMq 实际案例–普通消息的发送
- python自学路线-自学python编程的方法路线
- Spring AOP相关术语解释及简单使用
- java 内存模型堆和本地方法
- 非常适合小白的 Asyncio 教程
- ArangoDB 3.5发布:流事务API、蒙面数据、搜索性能大幅提升、最短路径功能
- 26.0.0-alpha1_WildFly 8.0.0.Alpha1的发布和一些历史
- 云服务器拷贝文件大小,如何从云服务器上拷贝大文件
- Linux进程3——虚拟地址访问
- Visual C# 2005 - 如何于DataGridView控件中以跨数据行方式显示数据
- Windows 11企业版虚拟机镜像官方版下载及安装
- STM32编程软件分享——MDK5安装包以及调试工具
- 如何用excel制作xy曲线图_如何用excel制作表格?
- Supermicro 1024US-TRT 服务器评测:1U 机箱中的 128 个内核
- Codeforces - DZY Loves Sequences
- 探访地面通数据中心:绿色、智能、安全
- 测绘程序设计——基础篇(1)C#编写方位角计算程序篇1——用户界面的构造
- Authentication vs. Authorization 验证与授权
- ASP.NET MVC 框架!
- 【安装+配置】Mac服务端svn