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. JS 中的自定义事件和模拟事件

    在 JS 中模拟事件指的是模拟 JS 中定义的一些事件,例如点击事件,键盘事件等. 自定义事件指的是创建一个自定义的,JS 中之前没有的事件. 接下来分别说一下创建这两种事件的方法. 创建自定义事件 ...

  2. python selenium模块 xpath定位

    ''' 附w3xpath语法地址 https://www.w3school.com.cn/xpath/xpath_syntax.asp 总结: 返回匹配到所有符合条件的第一个节点,对象是 <cl ...

  3. bm25算法和tfidf

  4. 二、Go语言开发环境安装与编写第一个Hello World

    本系列文章均为学习过程中记录的笔记,欢迎和我一起来学习Go语言. 全文使用环境如下: Go语言版本:1.13 操作系统:deepin 使用工具:Goland开发工具 Go语言追溯历史 Go语言2009 ...

  5. sql注入原理+mysql相关知识点

    什么是SQL注入 sql就是经常说的数据库,而sql注入就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.SQL注入是比较常见的网络攻击 ...

  6. PE文件学习(2)导入表导出表

    转自:evil.eagle https://blog.csdn.net/evileagle/article/details/12176797 导出表是用来描述模块中的导出函数的结构,如果一个模块导出了 ...

  7. curl请求本地域名问题

    curl在本地虚拟机上请求本地接口时候,出现域名解析问题,换为ip即可,可用curl_error() 或者curl_errno来调试: vue单个文件在引入时候自己的逻辑js文件一定要放在html后引 ...

  8. linux下的.ssh文件夹路径等

    1.linux下的.ssh文件夹在~下,直接cd ~/.ssh即可 2.tp经过gd类处理过的水印图片格式为png 3.前端扒下别人家的网站如果自己本地打开有出现相同的代码段则有可能是js动态添加的, ...

  9. SQLI-LABS学习笔记(二)

    逼话少说,如有错误,烦请指出,谢谢 这两天生病,效率很低 第5关 打开页面 发现跟前几题不同,没有直接返回数据.. 加个单引号 You have an error in your SQL syntax ...

  10. DMTF 关于 CIM-XML 的幻灯片介绍

    https://members.dmtf.org/data/presentations/devcon02/JimDavis-IntroductiontoCIM-XML.pdf