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相关推荐

  1. platform_get_resource的分析

    阅读platformdriver的代码时,发现在probe函数直接调用platform_get_resource从pdev中获取io内存,但却没有判断传给probe的pdev是否属于这个驱动 ! 后来 ...

  2. 谈内核资源申请platform_get_resource、devm_request_mem_region、devm_ioremap

    以IO内存资源为例: platform_get_resource(pdev, IORESOURCE_MEM, 0); 即可得到一个IO内存资源节点指针, 包括了地址的开始,结束地址等, 该IO内存的长 ...

  3. 嵌入式Linux设备驱动程序:发现硬件配置

    嵌入式Linux设备驱动程序:发现硬件配置 Embedded Linux device drivers: Discovering the hardware configuration Interfac ...

  4. MTD NANDFLASH驱动相关知识介绍

    转:http://blog.csdn.net/zhouzhuan2008/article/details/11053877 目录 MTD总概述 MTD数据结构 MTD相关层实现 MTD,Memory ...

  5. linux驱动:TI+DM8127+GPIO(二)之驱动

    二.[GPIO驱动框架>驱动driver] 重要结构体 gpio_chip:管理一组GPIO gpio_desc:描述每个GPIO gpio_bank:封装了gpio_chip加入GPIO控制的 ...

  6. Linux驱动修炼之道-RTC子系统框架与源码分析【转】

    转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://bl ...

  7. pinctrl框架【转】

    转自:http://www.cnblogs.com/kevinhwang/p/5703192.html pinctrl框架是linux系统为统一各SOC厂家pin管理,目的是为了减少SOC厂家系统移植 ...

  8. 精彩---rtl8139网卡驱动程序分析

    学习应该是一个先把问题简单化,再把问题复杂化的过程.一开始就着手处理复杂的问题,难免让人有心惊胆颤,捉襟见肘的感觉.读Linux网卡驱动 也是一样.那长长的源码夹杂着那些我们陌生的变量和符号,望而生畏 ...

  9. I2C 总线原理与架构

    一.I2C总线原理 I2C是一种常用的串行总线,由串行数据线SDA 和串行时钟线SCL组成.I2C是一种多主机控制总线,它和USB总线不同,USB是基于master-slave机制,任何设备的通信必须 ...

  10. Linux驱动之平台设备

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

最新文章

  1. rocketmq 消息指定_RocketMq 实际案例–普通消息的发送
  2. python自学路线-自学python编程的方法路线
  3. Spring AOP相关术语解释及简单使用
  4. java 内存模型堆和本地方法
  5. 非常适合小白的 Asyncio 教程
  6. ArangoDB 3.5发布:流事务API、蒙面数据、搜索性能大幅提升、最短路径功能
  7. 26.0.0-alpha1_WildFly 8.0.0.Alpha1的发布和一些历史
  8. 云服务器拷贝文件大小,如何从云服务器上拷贝大文件
  9. Linux进程3——虚拟地址访问
  10. Visual C# 2005 - 如何于DataGridView控件中以跨数据行方式显示数据
  11. Windows 11企业版虚拟机镜像官方版下载及安装
  12. STM32编程软件分享——MDK5安装包以及调试工具
  13. 如何用excel制作xy曲线图_如何用excel制作表格?
  14. Supermicro 1024US-TRT 服务器评测:1U 机箱中的 128 个内核
  15. Codeforces - DZY Loves Sequences
  16. 探访地面通数据中心:绿色、智能、安全
  17. 测绘程序设计——基础篇(1)C#编写方位角计算程序篇1——用户界面的构造
  18. Authentication vs. Authorization 验证与授权
  19. ASP.NET MVC 框架!
  20. 【安装+配置】Mac服务端svn

热门文章

  1. 2018至2021年新春挡电影票房分析
  2. 出国常用必备英语口语
  3. 服务器无线存储器,教你把无线路由器打造成网络存储器
  4. 计算机小高考要点,小高考的复习计划
  5. html期末作业代码网页设计——蛋糕甜品店(4页) web期末作业设计网页_甜品美食大学生网页设计作业成品
  6. C# Wpf Binding 使用详解
  7. 修修补补一时爽,果断重构有担当——聊聊CRM分布式缓存优化
  8. 狂神说SpringMVC课堂笔记
  9. 餐巾计划问题 费用流
  10. 形容java工作者的句子_一些形容工作态度的句子