嵌入式Linux驱动开发(十二)platform设备驱动实验

news2024/11/20 13:23:57

1. platform设备驱动简介

  基于驱动可重用性考虑,提出驱动分离与分层思想。平台设备驱动就是基于此。

1.1 驱动分隔与分层

1)驱动分隔:
  以I2C驱动为例,假设有三类SOC,各自对一个设备写I2C驱动,就需要3个驱动程序。但是一个设备理论上只需要一个驱动就行了,将主机驱动和设备驱动分隔开,中间由一个统一API接口连接,就是驱动分隔思想。
在这里插入图片描述
2)驱动分离:
  实际开发中主机驱动和设备驱动一般由半导体厂家和设备厂家编写好了,我们需要提供的是设备信息。这样驱动只负责驱动,设备只负责设备,中间由总线匹配,这就是Linux的驱动-总线-设备模型,也就是驱动分离。
在这里插入图片描述
3)驱动分层:
  在不同的层处理不同的内容。比如Input子系统负责所有输入相关的驱动,其最底层是设备原始驱动,获取到的输入传给input核心层处理IO模型并提供file_operations操作集合。我们编写时只需要处理输入事件的上报即可。

1.2 platform(虚拟总线)平台驱动模型

  由于有些外设没有总线概念,又需要使用总线-驱动-设备模型,因此提出platform虚拟总线,对应的由platform_driver,platform_device。Linux内核使用bus_type结构体表示总线。
  该结构体中最重要的是match函数,该函数根据注册的设备或者驱动查找相应的驱动或者设备,完成驱动和设备之间的匹配。该函数两个参数dev和drv分别为设备和驱动。
1)paltform总线

//platform总线实例
struct bus_type platform_bus_type = {
	.name = "platform",
	.dev_groups = platform_dev_groups,
	.match = platform_match,	//匹配函数
	.uevent = platform_uevent,
	.pm = &platform_dev_pm_ops,
};

//设备驱动匹配方式
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);

	/*OF类型匹配:设备树采用的匹配方式,依靠device_driver结构体的of_match_table成员变量查找---必有*/
	if (of_driver_match_device(dev, drv))
		return 1;
	/* ACPI方式 */
	if (acpi_driver_match_device(dev, drv))
		return 1;
	/* id_table匹配,依靠platform_driver结构体的id_table成员变量查找 */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;
	/* 如果id_table找不到,就直接比较驱动和设备的name字段---常用 */
	return (strcmp(pdev->name, drv->name) == 0);
}

2)paltform驱动
Linux内核使用platform_driver结构体表示虚拟驱动。其中重要的有:
 1. probe函数,驱动和设备match后就会执行。
 2. driver成员,为device_driver结构体成员变量,该结构体相当于platform_driver的基类。
 3. id_table,是一个表(数组),元素类型为platform_device_id。

3)paltform驱动编写流程
①定义platform_driver结构体变量。
②实现match和probe。
③match后,在probe里面编写具体驱动。
④在驱动入口函数调用platform_driver_register函数向内核注册一个platform驱动。

//para:要注册的platform驱动
int platform_driver_register (struct platform_driver *driver)

⑤在驱动卸载函数中通过platform_driver_unregister函数卸载驱动

void platform_driver_unregister(struct platform_driver *drv)

框架:

/* 设备结构体 */
struct xxx_dev{
	struct cdev cdev;
	/* 设备结构体其他具体内容 */
};
struct xxx_dev xxxdev; /* 定义个设备结构体变量 */

static int xxx_open(struct inode *inode, struct file *filp)	{ 
	/* 函数具体内容 */
	return 0;
}

static ssize_t xxx_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) {
	/* 函数具体内容 */
	return 0;
}

/*字符设备驱动操作集*/
static struct file_operations xxx_fops = {
	.owner = THIS_MODULE,
	.open = xxx_open,
	.write = xxx_write,
};

/*********************************************************/
/*platform 驱动的 probe 函数,以前在驱动init函数的内容写到这*/
static int xxx_probe(struct platform_device *dev) { 
	......
	cdev_init(&xxxdev.cdev, &xxx_fops); /* 注册字符设备驱动 */
	/* 函数具体内容 */
	return 0;
}

/*以前在驱动出口函数中的内容写到这*/
static int xxx_remove(struct platform_device *dev) {
	......
	cdev_del(&xxxdev.cdev);/* 删除 cdev */
	/* 函数具体内容 */
	return 0;
}

/* 匹配列表-使用设备树时的匹配方法 */
static const struct of_device_id xxx_of_match[] = {
	{ .compatible = "xxx-gpio" },
	{ }	/*of_device_id表最后一个匹配项必须为空*/
};

/*platform 平台驱动结构体*/
static struct platform_driver xxx_driver = {
	.driver = {
	//两种匹配方式-有设备树/无设备树
		.name = "xxx",
		.of_match_table = xxx_of_match,
	},
	.probe = xxx_probe,
	.remove = xxx_remove,
};

/* 驱动模块加载 */
static int __init xxxdriver_init(void) {
	return platform_driver_register(&xxx_driver);
}

/* 驱动模块卸载 */
static void __exit xxxdriver_exit(void) {
	platform_driver_unregister(&xxx_driver);
}

module_init(xxxdriver_init);
module_exit(xxxdriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");

4)paltform设备
  内核使用platform_device结构体表示虚拟设备。在不使用设备树时可以使用该结构体描述设备信息。

//将设备信息注册到内核
//para:要注册的platform设备
int platform_device_register(struct platform_device *pdev)

//注销设备
void platform_device_unregister(struct platform_device *pdev)

设备信息框架(无设备树时使用):

/* 寄存器地址定义*/
#define PERIPH1_REGISTER_BASE (0X20000000) /* 外设 1 寄存器首地址 */ 
#define PERIPH2_REGISTER_BASE (0X020E0068) /* 外设 2 寄存器首地址 */
#define REGISTER_LENGTH 4

/* 资源 */
static struct resource xxx_resources[] = {
	[0] = {
		/*resource结构体的属性*/
		.start = PERIPH1_REGISTER_BASE,
		.end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1),
		.flags = IORESOURCE_MEM,	//设备是内存类型
	}, 
};

/* platform 设备结构体 */
static struct platform_device xxxdevice = {
	.name = "xxx-gpio",
	.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("zuozhongkai");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

StarUML破解失败解决办法

明明以及安装了asar但是输入反编译命令还是显示asar不是内部命令 于是根据提示找到了这个文件夹,发现里面有asar的命令,而且输入asar -v也可以查看版本 于是我把app.asar那个文件复制过来了,然后在这个路径输入反编译命令,成功…

6.2.2邻接表法 6.2.3十字链表,邻接多重表

由于用邻接矩阵存储稀疏图会造成大量空间浪费。 而本节课我们所学的邻接表是采用顺序存储加上链式存储的方式。 arcnum指的是弧的数量 对比:树的孩子表示法(相同的实现方式) Compare: 6.2.3十字链表,邻接多重表 定义这…

Android 内存分析(java/native heap内存、虚拟内存、处理器内存 )

1.jvm 堆内存(dalvik 堆内存) 不同手机中app进程的 jvm 堆内存是不同的,因厂商在出厂设备时会自定义设置其峰值。比如,在Android Studio 创建模拟器时,会设置jvm heap 默认384m , 如下图所示: 当app 进程中java 层 new 对象(加起来总和)占用…

知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通。我们从文本数据中采集到关键信息,并抽取出其中的关系信息,然后在存入图数据库中,整个过程实现自动化,我这里将举一个文本例子进行抽取。 对于知识图谱的构建是将实体…

ThingsBoard使用jar包自己构建镜像部署

1、概述 这一节主要讲解你自己使用jar包构建镜像,一般在很多企业中,都是使用Jenkins配置流水线,自动打包,然后拷贝程序在target目录下生成的jar包,然后使用Dockerfile文件进行构建镜像,其实我这一节讲的也是类似,只是不使用Jenkins来实现自动,原理都一样,估计也是很多…

网络协议 — BGP 边界网关协议

目录 文章目录 目录BGP 和 ASBGP Router 和 RoutesBGP Message 类型和格式BGP Msg HeaderBGP Msg DataOpen MsgKeepalive MsgNotification MsgRoute-refresh MsgUpdate Msg BGP Msg 状态机 BGP RR(Route-Reflectors,路由反射器)BGP MP&#x…

基于STM32+NBIOT+华为云IOT设计的智能井盖

一、概述 智能井盖是一种通过物联网技术实现对井盖状态监测和管理的设备。当前介绍基于STM32微控制器,BC26 NBIOT模组以及华为云IOT平台设计一款智能井盖系统。该系统通过光线传感器、霍尔传感器、温湿度传感器等设备实现井盖状态的实时监测,通过NBIOT网络将数据上传到华为云…

5 Redis缓存穿透、击穿、雪崩、分布式锁、布隆过滤器

1 Redis 应用问题解决 1.1 缓存穿透 1.1.1 问题描述 key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源。比如 用一个不存在的用户 id 获取用户…

ES的概述

一、ECMASript 相关介绍 1.1什么是 ECMA ECMA ( European Computer Manufacturers Association )中文名称为欧洲计算机制 造商协会,这个组织的目标是评估、开发和认可电信和计算机标准。 1994 年后该 组织改名为 Ecma 国际。 1.2.什么…

Three.js--》模型材质与纹理的使用

目录 初识材质与纹理 修改模型材质颜色 模型添加纹理 纹理常用属性使用 纹理显示算法 设置粗糙度 纹理加载进度情况 设置环境贴图 初识材质与纹理 three.js中的材质就是几何体表面的材料。所有材质均继承自Material。ThreeJS的材质分为:基础材质、深度材质…

Linux(centos 7) 环境安装MySQL5.7

mysql安装包 链接:百度网盘 请输入提取码 提取码:b8w4 环境准备 安装好的centos 7系统 root 用户登录Linux 在根目录下创建/soft目录 上传mysql安装包到/soft目录,结果如下 准备完毕 安装 根据现有序号挨个安装 rpm 包,依…

“聪明车”接驳“智慧路”—— 智能网联车驶上新赛道

去年底,智己L7首批200台Beta体验版下线交付。 智能网联车,“新赛道”上疾驶着“新终端”。“聪明车”如何更好接驳“智慧路”?全国两会现场,不少代表委员聚焦于这一话题展开热议,出谋划策。 “只有把‘终端’牢牢掌握在…

06 - 2 分层架构模式(Layered Arch)

层 层的定义 层:软件的逻辑单元每一层都有特定的功能组件被分配到不同的层 何谓分层 将系统按照职责拆分和组织上层依赖于直接下层 下层不可以依赖于上层不可以跃层访问(理想状况) 经典分层架构 OSI 7 层架构 CS 两层架构Client&…

生动形象的傅里叶变换解析!

使用联想链条和几何直观,辅以从实际需求衍生概念的思考模式,详解什么是傅立叶变换,为什么要做傅立叶变换等,帮助记忆和理解,目的当然是标题所说:让你永远忘不了傅里叶变换这个公式。另,这篇博客…

MySQL之Server层的内存结构

前言 本文已收录在MySQL性能优化原理实战专栏,点击此处浏览更多优质内容。 前面的文章我们介绍了InnoDB存储引擎的一些内存、内存磁盘的结构以及工作原理,今天我们就来看一下关于MySQL Server层的一些内存结构。 目录 一、Binlog Cache1.1 Binlog Cache工…

jvm之远程调试

写在前面 工作中,有时会出现测试环境有问题,本地却正常的情况,此时我们就可以通过JVM提供的远程调用的功能,实现在本地debug调试测试环境代码。 1:例子1直接运行class 首先我们来定义类: package com.f…

Blender 形变类修改器:曲线

目录 形变类修改器1. 测试一:减少环切数量1.1 调整物体原点1.2 让两个物体原点重合1.3 添加曲线修改器1.4 融并边 2. 测试二:曲线的方向2.1 查看曲线的方向(曲线法向显示)2.2 在3D空间调整曲线 3. 测试三:空间位置的影…

【Minecraft开服教学】使用 MCSM 面板一键搭建我的世界服务器 并使用内网穿透公网远程联机

文章目录 前言1.Mcsmanager安装2.创建Minecraft服务器3.本地测试联机4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射内网端口 5.远程联机测试6. 配置固定远程联机端口地址6.1 保留一个固定TCP地址6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 转载自远程穿透文章&…

C语言中链表经典面试题目

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C 🔥座右铭:“不要等到什么都没有了,才下…

MySQL之Change Buffer详解

前言 本文已收录在MySQL性能优化原理实战专栏,点击此处浏览更多优质内容。 上一篇文章一文带你了解MySQL数据库InnoDB_Buffer_Pool(点击跳转)我们学习了InnoDB Buffer Pool的工作原理,其作用是减少MySQL读取数据时直接与磁盘打交道…