Linux platform设备驱动模型

前言

为什么要往平台设备驱动迁移?这里需要引入设备,总线,驱动这三个概念。上一篇字符型设备驱动的实现实际将设备和驱动集成到同一个文件中实现,如果这里有硬件A的驱动硬件B的驱动硬件C的驱动,然后有三类用户接口E接口F接口G,这里用户接口是提供给用户层调用的接口,每一种接口又必须兼容这三种硬件,按照原来的实现方式,为了适配所有的使用需求,理论上会出现A+EA+FA+GB+EB+FB+GC+EC+FC+G,这几种实现方式,而表现在代码中的则是

#if A
#elif B
#elif C
#endif

当然,目前接口数量和硬件数量不是很庞大的时候,维护上暂时不会造成太大的问题,所以,这里引入了设备/总线/驱动的机制,实现了驱动和设备之间的解耦,这里我的理解是和设计模式中的中介者模式比较相似。

框架

大致地整理了一下platform设备驱动模型的整体框架。

设备与驱动的分离

设备(device)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/platform_device.h> static struct platform_device *character_dev; static int __init cnc_platform_character_init(void){ int ret = 0;
character_dev = platform_device_alloc("cnc_platform_character", -1);
if (!character_dev)
return -ENOMEM;
ret = platform_device_add(character_dev);
if (ret) {
platform_device_put(character_dev);
printk("\n\n\n\n\n Success platform_device_put(character_dev)\n\n\n\n\n");
return ret;
}
printk("\n\n\n\n\n Failed platform_device_put(character_dev)\n\n\n\n\n");
return 0;
}
module_init(cnc_platform_character_init); static void __exit cnc_platform_character_exit(void){
printk("%s call\n",__func__);
platform_device_unregister(character_dev); }
module_exit(cnc_platform_character_exit); MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");

驱动(driver)

#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h> #include <linux/of_device.h> #define DRIVER_DATA_SIZE 4096 struct cnc_character_st{
struct cdev device;
u8 data[DRIVER_DATA_SIZE];
struct miscdevice miscdev;
}; //TODO
static ssize_t cnc_character_read (struct file * fd, char __user * data, size_t len, loff_t * offset){
ssize_t ret = 0;
return ret;
} //TODO
static ssize_t cnc_character_write (struct file * fd, const char __user * data, size_t len, loff_t * offset){
ssize_t ret = 0;
return ret;
} //TODO
static long cnc_character_unlocked_ioctl (struct file * fd, unsigned int data, unsigned long cmd){
long ret = 0;
return ret;
} //TODO
static int cnc_character_open (struct inode * node, struct file * fd){
int ret = 0;
return ret;
}
//TODO
static int cnc_character_release (struct inode * node, struct file * fd){
int ret = 0;
return ret;
} static const struct file_operations cnc_character_ops = {
.owner = THIS_MODULE,
.read = cnc_character_read,
.write = cnc_character_write,
.open = cnc_character_open,
.unlocked_ioctl = cnc_character_unlocked_ioctl,
.release = cnc_character_release,
}; static int cnc_character_probe(struct platform_device *pdev){ int ret = 0;
struct cnc_character_st *character_dev; character_dev = devm_kzalloc(&pdev->dev, sizeof(*character_dev),GFP_KERNEL); character_dev->miscdev.minor = MISC_DYNAMIC_MINOR;
character_dev->miscdev.name = "cnc_platform_character";
character_dev->miscdev.fops = &cnc_character_ops;
//ret = misc_register(&character_dev->miscdev);
platform_set_drvdata(pdev, character_dev);
ret = misc_register(&character_dev->miscdev); if(ret < 0){
return ret;
}
return 0; } static int cnc_character_remove(struct platform_device *pdev){ struct cnc_character_st *gl = platform_get_drvdata(pdev);
printk("%s call\n",__func__);
misc_deregister(&gl->miscdev);
return 0;
} static struct platform_driver cnc_character_driver = {
.driver = {
.name = "cnc_platform_character",
.owner = THIS_MODULE,
},
.probe = cnc_character_probe,
.remove = cnc_character_remove,
}; module_platform_driver(cnc_character_driver); MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");

匹配(match)

函数static int platform_match(struct device *dev, struct device_driver *drv)在内核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); /* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name); /* Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1; /* Then try ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1; /* Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0); }

从代码中可以得知,platform_match主要根据四种情况对设备和驱动进行匹配。

根据注释可以知道,首先判断是否已经设置driver_override,后面只绑定到匹配的驱动程序。

  • 根据设备树风格的匹配;
  • 根据ACPI风格的匹配;
  • 匹配ID表(即platform_device设备名是否出现在platform_driver的ID表内)
  • 匹配platform_device设备名和驱动的name成员

参考

https://blog.csdn.net/clam_zxf/article/details/80675395

https://www.cnblogs.com/chenfulin5/p/5690661.html

http://blog.chinaunix.net/uid-25622207-id-2778126.html

Linux内核驱动学习(四)Platform设备驱动模型的更多相关文章

  1. Linux 设备驱动开发 —— platform设备驱动应用实例解析

    前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...

  2. Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介

    原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理 ...

  3. Linux学习 : 总线-设备-驱动模型

    platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...

  4. Linux I2C核心、总线和设备驱动

    目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...

  5. platform设备驱动框架

    驱动框架 通过使用platform设备驱动框架,实现led驱动与设备操作的分离.     我们关注led_drv里面的 struct platform_driver led_drv里面的.probe函 ...

  6. 【linux驱动分析】misc设备驱动

    misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义:         #define MISC_MAJO ...

  7. 十天学Linux内核之第四天---如何处理输入输出操作

    原文:十天学Linux内核之第四天---如何处理输入输出操作 真的是悲喜交加呀,本来这个寒假早上8点都去练车,两个小时之后再来实验室陪伴Linux内核,但是今天教练说没名额考试了,好纠结,不过想想就可 ...

  8. 成为Linux内核高手的四个方法

    首页 最新文章 资讯 程序员 设计 IT技术 创业 在国外 营销 趣文 特别分享 更多 > - Navigation -首页最新文章资讯程序员设计IT技术- Java & Android ...

  9. LCD驱动分析(一)字符设备驱动框架分析

    参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一>   S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...

随机推荐

  1. 大佬整理出来的干货:LDA模型实现—Python文本挖掘

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取htt ...

  2. G - Greg and Array CodeForces - 296C 差分+线段树

    题目大意:输入n,m,k.n个数,m个区间更新标记为1~m.n次操作,每次操作有两个数x,y表示执行第x~y个区间更新. 题解:通过差分来表示某个区间更新操作执行的次数.然后用线段树来更新区间. #i ...

  3. ASP.NET Core技术研究-全面认识Web服务器Kestrel

    因为IIS不支持跨平台的原因,我们在升级到ASP.NET Core后,会接触到一个新的Web服务器Kestrel.相信大家刚接触这个Kestrel时,会有各种各样的疑问. 今天我们全面认识一下ASP. ...

  4. 如何使用Jsoup爬取网页内容

    前言: 这是一篇迟到很久的文章了,人真的是越来越懒,前一阵用jsoup实现了一个功能,个人觉得和selenium的webdriver原理类似,所以今天正好有时间,就又来更新分享了. 实现场景: 爬取博 ...

  5. react: typescript integrate withRouter

    define interface: export interface INav { nav: string } export interface IModuleItem { state?: strin ...

  6. vue中解决时间在ios上显示NAN的问题

    最近在用vue,遇到倒计时在ios上显示为NAN的问题. 因为做的是倒计时支付,思路是获取服务器时间和下单时间,再转成秒级时间戳做差值. 在网上找到说是ios 不支持例如2018-09-01 10:0 ...

  7. python信息收集(一)

        在渗透测试初期,需要进行大量的信息收集.一般情况下,信息收集可以分为两大类----被动信息收集和主动信息收集.     其中,被动信息收集主要是通过各种公开的渠道来获取目标系统的信息,例如:站 ...

  8. 基于layui,Jquery 表格动态编辑 设置 编辑值为 int 或者 double 类型及默认值

    首先先推荐大家在看这篇笔记时,阅读过我写的这篇 Layui表格编辑[不依赖Layui的动态table加载] 阅读过上面那篇笔记之后呢,才能更好的理解我现在所要说的这个东西 接下来废话不多说,上代码. ...

  9. 【AspNetCore源码】设计模式 - 提供者模式

    AspNetCore源代码发现日志模块的设计模式(提供者模式),特此记录 学习设计模式的好处是,我们可以容易扩展它达到我们要求,除了要知道如何扩展它,还应该在其他地方应用它 类图 & 分析 角 ...

  10. STM32 内存分配解析及变量的存储位置

    内存映射 在一些桌面程序中,整个内存映射是通过虚拟内存来进行管理的,使用一种称为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM.在对于 RAM 紧缺的嵌入式系统中,是缺少 MMU 内存 ...