前言

Linux 设备和驱动通常都需要挂接在一种总线上,例如PCI、USB、I2C、SPI 等的设备存在真实的总线,这自然不是问题,但是SOC上的外设控制器、挂接在SoC内存空间的外设等却不依附于此类总线。基于这一背景,linux形成了一种虚拟的总线,称为platform 总线,相应的设备称为platform_device,而驱动成为platform_driver。

platform总线的出现提高了代码的重用性、实现了设备与驱动的分离,增强了可移植性。之前的驱动开发是把驱动信息和设备信息都写在一起,当模块很多时,就大大增加了冗余代码,不易于维护开发。

本篇章将对platform总线涉及的基础知识进行讲解,下篇章再通过阅读内核platform源码文件疏通具体工作过程。

1  总线、设备和驱动模型

1.1  驱动分离

驱动开发中,为了提高代码的重用性,采取了驱动分离的方法,每个平台驱动都会对应有主机驱动设备驱动,主机驱动就是平台下相应控制器的驱动。

拿I2C来举例,I2C主机控制器的驱动每个平台都不一样,由soc芯片厂家编写,中间有个核心层提供统一接口,设备驱动调用统一接口编写,这样设备驱动就可以适用于任何平台了,一般设备驱动由设备器件厂家编写提供。

1.2  驱动、设备分离

在设备驱动中不填写任何设备信息,驱动使用中通过标准方法获取设备信息(例如从设备树中获取),然后根据设备信息初始化设备;可以在设备树中填入设备信息,像设备挂接在哪个I2C接口上、名字、物理地址、速率设置多少等;这样就把设备信息从设备驱动中分离出来了。设备、驱动分离后就需要有方法将它们连接匹配上,此时总线(bus)就充当这个角色。

当我们向系统注册一个驱动的时候,总线就会在右侧的设备中查找,看看有没有与之匹配的设备,如果有的话就将两者联系起来。同样的,当向系统中注册一个设备的时候,总线就会在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来。

2  platform 框架模型

linux中为了解决有些外设没有总线这个概念的问题,故引出了虚拟总线(platform)这个概念。相应的驱动、设备叫platform_driver、platform_device。

2.1  platform总线

结构体bus_type描述总线,定义在include/linux/device.h中;


struct bus_type {const char      *name;const char      *dev_name;struct device       *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */const struct attribute_group **bus_groups;   //总线属性const struct attribute_group **dev_groups;   //设备属性const struct attribute_group **drv_groups;   //驱动属性int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};

参数name:定义总线的名字;

参数match函数:完成设备与驱动间的匹配,该函数有两个参数(dev、drv)分别表示设备                                和驱动对应的结构体;

2.2  platform驱动

结构体platform_driver表示platform驱动,定义在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 (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;bool prevent_deferred_probe;
};

参数probe函数:当driver 和device 匹配成功的时候,就会执行probe 函数;

参数remove函数:当driver 和device 任意一个remove 的时候,就会执行这个函数;

参数id_table:保存了很多id 信息。id 信息存放着这个platformd 驱动所支持的驱动类型。

device_driver结构体定义在 include/linux/device.h;着重关注of_device_id结构体;

struct device_driver {const char      *name;struct bus_type     *bus;struct module       *owner;const char      *mod_name;  /* used for built-in modules */bool suppress_bind_attrs;   /* disables bind/unbind via sysfs */enum probe_type probe_type;const struct of_device_id   *of_match_table;const struct acpi_device_id *acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};

结构体platform_device_idof_device_id定义在/linux/mod_devicetable.h

struct platform_device_id {char name[PLATFORM_NAME_SIZE];kernel_ulong_t driver_data;
};struct of_device_id {char    name[32];char    type[32];char    compatible[128];const void *data;
};

2.2.1  platform驱动注册函数

int platform_driver_register (struct platform_driver *driver)

参数driver:要注册的 platform驱动,定义好的platform_driver结构体变量;
返回值: 负数,失败; 0,成功。

2.2.2  platform 驱动卸载函数

void platform_driver_unregister(struct platform_driver *drv)

参数drv:要卸载的 platform驱动。

2.3  platform设备

platform_device这个结构体表示 platform设备,如果内核使用设备树来描述设备信息,就不需要使用platform_device结构体描述了。(现在的开发中很多都是使用设备树来描述了)

struct platform_device {const char  *name;int     id;bool        id_auto;struct device   dev;u32     num_resources;struct resource *resource;const struct platform_device_id *id_entry;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata    archdata;
};

参数name:platform设备的名字,用来和platform驱动相匹配。名字相同才能匹配成功;

参数id:是用来区分如果设备名字相同的时候(通过在后面添加一个数字来代表不同的设                         备),通常为 -1 ;

参数resource:资源结构体,描述设备信息;

参数num_resource:资源结构体数量。

resource结构体定义再/linux/ioport.h中;

flag表示资源类型,内核定义了可选的资源类型,常用类型有IORESOURCE_IO(IO 的内存)、IORESOURCE_MEM( 表述一段物理内存)、IORESOURCE_IRQ (表示中断),如下代码:

struct resource {resource_size_t start;resource_size_t end;const char *name;unsigned long flags;struct resource *parent, *sibling, *child;
};/** IO resources have these defined flags.*/
#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_EXCLUSIVE    0x08000000  /* Userland may not map this resource */
#define IORESOURCE_DISABLED 0x10000000
#define IORESOURCE_UNSET    0x20000000  /* No address assigned yet */

2.3.1  platform设备注册函数

int platform_device_register(struct platform_device *pdev)

参数pdev:要注册的 platform设备。
返回值: 负数,失败; 0,成功。

2.3.2  platform设备卸载函数

void platform_device_unregister(struct platform_device *pdev)

参数pdev:要注销的 platform设备。

2.3.3  获取资源函数

struct resource *platform_get_resource(struct platform_device *,unsigned int, unsigned int);
第一个参数:平台设备变量;
第二个参数:资源类型;
第三个参数:索引号,资源处在同类资源的哪个位置上,大家注意理解同类资源是指flags 一模一样。

2.3.4  申请IO内存

#define request_mem_region(start,n,name) \

__request_region(&iomem_resource, (start), (n), (name), 0)

第一个参数:起始地址;

第二个参数:长度;

第三个参数:名字。

linux 驱动开发之platform设备驱动一(4)相关推荐

  1. Linux驱动开发之platform设备驱动实验【完整教程】

    为了方便驱动的编写,提高软件的重用性和跨平台性能,于是就提出了Linux驱动的分离和分层   驱动的分层,分层的目的时为了在不同的层处理不同的内容,最简单的驱动分层是input子系统负责管理所有跟输入 ...

  2. 驱动开发中platform设备驱动架构详解

    1.什么是platform总线 从Linux2.6开始Linux加入了一套驱动管理和注册机制-platform总线驱动模型.platform总线是一条虚拟总线(只有一条),这类总线没有对应的硬件结构. ...

  3. Linux驱动开发之PCIe Host驱动

    作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 PCI Utilitie ...

  4. Linux platform 设备驱动实验-基于正点原子IMX6ULL开发板

    我们以前的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的 ...

  5. linux内核单步调试,Linux内核驱动开发之KGDB单步调试内核(kgdboc方式)

    如何单步调试Linux内核一直困扰着linux驱动开发人员,内核有其代码量大.逻辑复杂.与硬件交互的特性.因此,有着不同于应用程序的调试方法,据统计Linux内核开 Linux内核驱动开发之KGDB原 ...

  6. Linux 设备驱动开发 —— platform 设备驱动

    一.platform总线.设备与驱动         在Linux 2.6 的设备驱动模型中,关心总线.设备和驱动3个实体,总线将设备和驱动绑定.在系统每注册一个设备的时候,会寻找与之匹配的驱动:相反 ...

  7. Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

    关与设备树的概念,我们在Exynos4412 内核移植(六)-- 设备树解析 里面已经学习过,下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构,设备树源(De ...

  8. Linux之Platform设备驱动

    目录 一.Linux 设备驱动分层和分离 1.设备驱动的分层思想 2.主机驱动和外设驱动分离思想 二.Platform 平台驱动模型 1.platform 设备 2.platform 驱动 3.pla ...

  9. Linux驱动之platform设备驱动

    当我们在一块开发板上写好了驱动,但换一块不同芯片的开发板,我们就需要重新写一个驱动.其中主要是硬件连接也就是接口发生了改变,而软件框架几乎不用通用的.所以为了更加方便地移植,能够仅修改很小的内容就达到 ...

最新文章

  1. 将集合中的内容按时间排序
  2. 联想利泰的一道做出来就给月薪7K的面试题--交通灯管理系统
  3. html中放大镜案列,Canvas实现放大镜效果完整案例分析(附代码)
  4. Hibernate中把Session和线程绑定的配置
  5. 《C++ Primer 第五版》第二章(第5小节)——using和typedef,auto和decltype总结
  6. jfinal项目部署服务器,jfinal undertow项目再集成JDK,一键安装系统服务,让部署再快一点...
  7. java求最大公约数_10道java经典算法题,小白必备,每一题都能提升你的java能力...
  8. IOT(27)---国内物联网平台的发展、技术架构演进
  9. php get教程,PHP $_GET 变量
  10. 玩具脚本-----yum源
  11. Java——IO基础
  12. uni-app 中通过 async + await + Promise 实现 request 请求同步化
  13. 手动安装.app到模拟器simulator, iOS XCode 11
  14. 用冰点文库下载百度文库里面的内容
  15. Ubuntu16.04安装中文字体SimHei
  16. 取代MS Project 的 开源工具 - OpenProj
  17. 精挑41款,好用到爆的谷歌浏览器插件,每位程序员日常编程必备
  18. 使用transmission下载BT
  19. codeforces 558D Guess Your Way Out! II
  20. 如何创建(设置)一个可以开发微信小游戏的appid

热门文章

  1. 24、高级工具--程序锁原理
  2. 使用Arduino开发ESP32(11):IO口与相关外设说明与记录
  3. 今日工作规划-2013.07.19
  4. DotNetBar for Windows Forms 14.0.0.3_冰河之刃重打包版原创发布
  5. MediaRecorder录音原生时序
  6. 法律专业难还是计算机专业难,法学计算机英语专业饭碗最难找
  7. 增值税税控设备(计算机打印机)全额抵扣,纳税人初次购买税控设备支付的费用能否抵减增值税?...
  8. [网络应用]父亲节的Google Logo创意
  9. 应届生必看的2020互联网求职指南!
  10. 企业固定资产盘点方案