Linux内核驱动学习(四)Platform设备驱动模型
Linux platform设备驱动模型
前言
为什么要往平台设备驱动迁移?这里需要引入设备,总线,驱动这三个概念。上一篇字符型设备驱动的实现实际将设备和驱动集成到同一个文件中实现,如果这里有硬件A的驱动,硬件B的驱动,硬件C的驱动,然后有三类用户接口E,接口F和接口G,这里用户接口是提供给用户层调用的接口,每一种接口又必须兼容这三种硬件,按照原来的实现方式,为了适配所有的使用需求,理论上会出现A+E,A+F,A+G,B+E,B+F,B+G,C+E,C+F,C+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设备驱动模型的更多相关文章
- Linux 设备驱动开发 —— platform设备驱动应用实例解析
前面我们已经学习了platform设备的理论知识Linux 设备驱动开发 —— platform 设备驱动 ,下面将通过一个实例来深入我们的学习. 一.platform 驱动的工作过程 platfor ...
- Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介
原文:Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介 Linux内核分析(四) 两天没有更新了,上次博文我们分析了linux的内存管理子系统,本来我不想对接下来的进程管理 ...
- Linux学习 : 总线-设备-驱动模型
platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...
- Linux I2C核心、总线和设备驱动
目录 更新记录 一.Linux I2C 体系结构 1.1 Linux I2C 体系结构的组成部分 1.2 内核源码文件 1.3 重要的数据结构 二.Linux I2C 核心 2.1 流程 2.2 主要 ...
- platform设备驱动框架
驱动框架 通过使用platform设备驱动框架,实现led驱动与设备操作的分离. 我们关注led_drv里面的 struct platform_driver led_drv里面的.probe函 ...
- 【linux驱动分析】misc设备驱动
misc设备驱动.又称混杂设备驱动. misc设备驱动共享一个设备驱动号MISC_MAJOR.它在include\linux\major.h中定义: #define MISC_MAJO ...
- 十天学Linux内核之第四天---如何处理输入输出操作
原文:十天学Linux内核之第四天---如何处理输入输出操作 真的是悲喜交加呀,本来这个寒假早上8点都去练车,两个小时之后再来实验室陪伴Linux内核,但是今天教练说没名额考试了,好纠结,不过想想就可 ...
- 成为Linux内核高手的四个方法
首页 最新文章 资讯 程序员 设计 IT技术 创业 在国外 营销 趣文 特别分享 更多 > - Navigation -首页最新文章资讯程序员设计IT技术- Java & Android ...
- LCD驱动分析(一)字符设备驱动框架分析
参考:S3C2440 LCD驱动(FrameBuffer)实例开发<一> S3C2440 LCD驱动(FrameBuffer)实例开发<二> LCD驱动也是字符设备驱动,也 ...
随机推荐
- 域名和服务器绑定及https协议更换
服务器是之前已经购买了的 1.腾讯云产品中搜索域名注册(产品太多了懒得找,直接搜索来得快些) 2.进去之后可以选择各种后缀的域名,输入自己喜欢的,看看哪些后缀是没有被注册的.自己挑选一个就可以,按照指 ...
- Spring Cloud 系列之 Sleuth 链路追踪(三)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Sleuth 链路追踪(一) Spring Cloud 系列之 Sleuth 链路追踪(二) 本篇文章讲解 Sleu ...
- mysql---3种常用引擎 和优点
- 2019-2020-1 20199329《Linux内核原理与分析》第三周作业
<Linux内核原理与分析>第三周作业 一.上周问题总结: 第二周头脑风暴完成较慢 虚拟机libc配置错误 书本知识使用不够熟练 二.本周学习内容: 1.实验楼环境虚拟一个x86的CPU硬 ...
- [Inno Setup] 卸载 重启之后 删除文件
某些系统文件,例如驱动,不重启无法删除. 利用windows注册表里的 RunOnce.注意必须在HKLM下,否则可能权限不够. 不能直接填cmd命令,要以cmd的参数形式填写. procedure ...
- vs code 打开文件时,取消文件目录的自动定位跟踪
文件-->首选项-->设置-->在搜索栏中搜索:explorer.autoReveal; 去掉勾选即可.
- 从Spring迁移到Spring Boot
文章目录 添加Spring Boot starters 添加应用程序入口 Import Configuration和Components 迁移应用程序资源 迁移应用程序属性文件 迁移Spring We ...
- Scala的存在类型
Scala的存在类型 存在类型也叫existential type,是对类型做抽象的一种方法.可以在你不知道具体类型的情况下,就断言该类型存在. 存在类型用_来表示,你可以把它看成java中的?. 下 ...
- IDEA 之 ERROR:端口被占用
问题描述:在IDEA启动javaweb项目中未能成功启动,ERROR:端口已经被使用.但是tomcat并没有被启动. 解决方法: 打开CMD 输入以下命令 netstat -aon | finfstr ...
- Spring绑定请求参数过程以及使用@InitBinder来注册自己的属性处理器
在工作中,经常会出现前台的请求参数由于无法被正常转型,导致请求无法进到后台的问题. 比如,我有一个User.其性别的属性被定义成了枚举,如下: public enum Gender { MALE(&q ...