Linux驱动开发——(九)platform设备驱动

目录

一、Linux驱动的分离

二、Linux驱动的分层

三、platform平台驱动模型简介

3.1 platform_driver结构体

3.2 device_driver结构体

3.3 platform驱动API函数

四、驱动代码


一、Linux驱动的分离

对于Linux这种庞大而复杂的系统,需要非常注重代码的重用性,否则Linux内核中将会存在大量无意义的重复代码。假设现在有三个平台A、B和C,该三个平台都有MPU6050这个I2C接口的六轴传感器,如果按照写裸机I2C驱动的思路,每个平台都有一个MPU6050的驱动,因此编写出来的最简单的驱动框架如图:

如果再来几个I2C设备,比如AT24C02、FT5206(电容触摸屏)等,按照上图的写法,那么设备端的驱动将再重复编写好几次。显然在Linux驱动程序中这种写法是不推荐的,最好的做法就是每个平台的I2C控制器都提供一个统一的接口(主机驱动)每个设备也只提供一个驱动程序(设备驱动),每个设备通过统一的I2C接口驱动来访问,这样就可以大大简化驱动文件: 

此时如果再来几个I2C设备,比如AT24C02、FT5206(电容触摸屏)等,那么就是:

 这便是驱动的分隔,即将主机驱动和设备驱动分隔开来,比如I2C、SPI等等都会采用驱动分隔的方式来简化驱动的开发。

在实际的驱动开发中,主机控制器驱动一般由半导体厂家编写好,而设备驱动一般也由设备器件的厂家编写好,我们只需要提供设备信息即可。

驱动只负责驱动,设备只负责设备,将两者进行匹配即可(相当于将设备信息从设备驱动中剥离开来,驱动使用标准方法去获取到设备信息,比如从设备树中获取到设备信息,然后根据获取到的设备信息来初始化设备)——即Linux中的总线(bus)、驱动(driver)和设备(device)模型:

当向系统注册一个驱动的时候,总线就会在右侧的设备中查找,看看有没有与之匹配的设备,如果有的话就将两者联系起来;同样的,当向系统中注册一个设备的时候,总线也会在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来。Linux内核中大量的驱动程序都采用总线、驱动和设备模式,platform驱动就是这一思想下的产物。


二、Linux驱动的分层

网络有7层模型,不同的层负责不同的内容。同样的, Linux下的驱动往往也是分层的,分层的目的也是为了在不同的层处理不同的内容。

比如input子系统(经常所使用到)负责管理所有跟输入有关的驱动,包括键盘、鼠标、触摸等,最底层的就是设备原始驱动,负责获取输入设备的原始值,获取到的输入事件上报给input核心层。 input核心层会处理各种IO模型,并且提供file_operations操作集合。在编写输入设备驱动的时候只需要处理好输入事件的上报即可,至于如何处理这些上报的输入事件那是上层去考虑的。


三、platform平台驱动模型简介

platform驱动框架分为总线、设备和驱动,其中总线是Linux内核提供的,编写驱动时只需要关注设备(platform_device)和驱动(platform_driver)的具体实现即可。在无设备树的Linux内核下,需要分别编写并注册platform_device和platform_driver;在使用设备树时,设备的描述被放到了设备树中,因此platform_device不用编写,只需要实现platform_driver即可。

3.1 platform_driver结构体

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函数:当驱动与设备匹配成功以后probe函数就会执行。

driver成员:device_driver结构体变量,Linux内核里大量使用面向对象的思维,device_driver相当于基类,提供了最基础的驱动框架。plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。

id_table:platform总线匹配驱动和设备的时候采用的一种方法, id_table是个表 (数组),每个元素的类型为platform_device_id

struct platform_device_id { char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data; 
};

3.2 device_driver结构体

device_driver结构体定义在include/linux/device.h:

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 */ 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; 
};

of_match_table:采用设备树时驱动所使用的匹配表(数组),每个匹配项都为of_device_id结构体类型,此结构体定义在文件include/linux/mod_devicetable.h中,内容如下:

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

compatible:对于设备树而言,通过设备节点的compatible属性值和of_match_table中每个项目的compatible成员变量进行比较,如果有相等的就表示设备和此驱动匹配成功。

注意,of_device_id表最后一个匹配项必须是空的

3.3 platform驱动API函数

在编写platform驱动时,首先定义一个platform_driver结构体变量,然后实现结构体中的各个成员变量(重点是实现匹配方法以及probe函数)。当驱动和设备匹配成功以后probe函数就会执行,具体的驱动程序在probe函数里面编写,比如字符设备驱动等等。

当我们定义并初始化好platform_driver结构体变量以后,需要在驱动入口函数里面调用platform_driver_register函数向Linux内核注册一个platform驱动

int platform_driver_register (struct platform_driver *driver) 

driver:要注册的platform驱动。
返回值:负数即失败;0即成功。

驱动卸载函数中通过platform_driver_unregister函数卸载platform驱动

void platform_driver_unregister(struct platform_driver *drv)

drv:要卸载的platform驱动。
返回值:无。


四、驱动代码

platform驱动框架:

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函数 
* 驱动与设备匹配成功以后此函数就会执行 
*/ 
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" }, { /* Sentinel */ } 
}; /* 
* 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");

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

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

相关文章

IntelliJ IDEA - Lombok supports: OpenJDK javac, ECJ

问题描述 java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled.Your processor is: com.sun.proxy.$Proxy26Lombok supports: OpenJDK javac, ECJ 解决方案 在 IDEA 设置中 File -> Settings 中找到配置如下&#xff1…

从系统到模块,逐步深入PLL设计

锁相环(PLL)电路广泛存在于各种应用之中,大到手机,服务器,小到智能手表,家用MCU。时钟信号的合成,数据的采样还原都需要PLL电路的深度参与。 何为锁相环(PLL)&#xff1…

由于找不到xinput1_3.dll,无法继续执行代码的详细修复方法

在日常使用电脑进行工作或娱乐时:系统突然弹出一个错误提示,明确指出“xinput1_3.dll文件丢失”。这个问题可能会导致游戏无法正常运行。为了解决这个问题,我通过查阅资料和实践总结出了以下五种解决方法,希望能对遇到类似问题的朋…

Mysql基础(三)DDL之create table语句

一 create table 创表 说明: create table相关语句从功能上进行讲解补充: 前面已经讲解过相关的约束,已进行相关的铺垫声明: 参考价值较少,了解即可 ① 基本语法 思考: 约束加在哪里? ② 创建新表 强调:使…

任务调度xxljob的使用记录

1.基本使用 a.下载代码,地址:https://gitee.com/xuxueli0323/xxl-job.git b.执行sql,修改配置,启动任务调度中心的代码 启动代码后任务调度中心访问地址:http://localhost:8080/xxl-job-admin(自己机器…

岚图汽车与东软睿驰签署战略合作协议

4月26日,东软睿驰与岚图汽车正式签署战略合作协议,双方将结合在各自领域拥有的产业资源、技术研发和资本运作等优势,聚焦智能化产品和应用,建立长期共赢的战略合作伙伴关系,通过不断探索未来新技术、新产业、新业态和新模式,围绕用户需求共同打造极致的智能出行体验。 图为岚图…

Rust Web开发实战:打造高效稳定的服务端应用

Rust Web开发实战:打造高效稳定的服务端应用 本书将带领您从零开始构建Web应用程序,无论是API、微服务还是单体应用,都将一一涵盖。您将学到如何优雅地对外开放API,如何连接数据库以安全存储数据,以及如何对应用程序进…

VPN的基本概念

随着互联网的普及和应用的广泛,网络安全和隐私保护越来越受到人们的关注。在这个信息爆炸的时代,我们的个人信息、数据通信可能会受到各种威胁,如何保护自己的隐私和数据安全成为了一个迫切的问题。而VPN(Virtual Private Network…

Quarto Dashboards 教程 3:Dashboard Data Display

「写在前面」 学习一个软件最好的方法就是啃它的官方文档。本着自己学习、分享他人的态度,分享官方文档的中文教程。软件可能随时更新,建议配合官方文档一起阅读。推荐先按顺序阅读往期内容: 1.quarto 教程 1:Hello, Quarto 2.qu…

混合注意力 ACmix | On the Integration of Self-Attention and Convolution

论文名称:《On the Integration of Self-Attention and Convolution》 论文地址:2111.14556 (arxiv.org) 卷积和自注意力是两种强大的表示学习技术,通常被认为是两种截然不同的并列方法。在本文中,我们展示了它们之间存在一种强烈…

history命令显示时间戳、IP地址、用户名

一、前置知识 history命令的功能是显示和管理用户所执行过的所有命令记录。这些记录默认被Linux系统保存。用户可以使用history命令查阅这些记录,也可以对其记录进行修改和删除操作。 history命令的常用参数如下: -a: 保存命令记录-c: 清空命令记录-d:…

JavaScript 如何理解柯里化函数结构及调用

文章目录 柯里化函数是什么逐步理解柯里化函数 柯里化函数是什么 柯里化(Currying)函数,又称部分求值,是一种函数转换技术。这种技术将一个接受多个参数的函数转换为一系列接受单一参数的函数。具体来说,一个柯里化的…

2024 java使用Graceful Response,告别自己去封装响应,可以接收数据异常,快看我这一篇,足够你用!

参考官网手册地址&#xff1a;快速入门 | Docs 一、导入依赖&#xff08;根据springboot查看对应依赖版本&#xff09; <!-- Graceful --><dependency><groupId>com.feiniaojin</groupId><artifactId>graceful-response</artifactId&g…

微信小程序与web-view网页进行通信的尝试

首先&#xff0c;微信小程序向web-view传递数据一般通过地址栏传参的形式&#xff08;给src赋值或者修改hash&#xff09;&#xff0c;这样一般就已经能够满足实际开发需求了&#xff0c;所以这里主要探讨web-view向微信小程序传参。下面&#xff0c;我们从官方文档入手&#x…

基于51单片机智能窗帘仿真设计( proteus仿真+程序+设计报告+讲解视频)

基于51单片机智能窗帘仿真设计( proteus仿真程序设计报告讲解视频&#xff09; 基于51单片机智能窗帘仿真设计 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真设计4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单资料下载链接&#xff1a; 仿真图proteus8.9及以上…

【JAVA进阶篇教学】第七篇:Spring中常用注解

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第七篇&#xff1a;Spring中常用注解 在Java Spring框架中&#xff0c;注解&#xff08;Annotation&#xff09;是一种元数据&#xff0c;它提供了关于程序代码的额外信息&#xff0c;这些信息可以用于编译时检查、运行时…

【国信华源北斗型雨量站新品亮相第三届防汛抗旱抢险新技术新产品展示会】

4月24—25日&#xff0c;第三届防汛抗旱抢险新技术、新产品应用研讨与展示会暨中国水利企业协会防灾与抢险装备技术分会年会在河南郑州召开。由《中国防汛抗旱》杂志社、水利部防洪抗旱减灾工程技术研究中心主办&#xff0c;围绕我国防汛抗旱形势、防灾与抢险新技术新产品现状和…

vue2实现字节流byte[]数组的图片预览

项目使用vantui框架&#xff0c;后端返回图片的字节流byte[]数组&#xff0c;在移动端实现预览&#xff0c;实现代码如下&#xff1a; <template><!-- 附件预览 --><div class"file-preview-wrap"><van-overlay :show"show"><…

【Markdown笔记】——设置markdown中文字的颜色

【Markdown笔记】——设置markdown中文字的颜色 Markdownmarkdown中设置文字颜色常用颜色对照表【含RGB值对照】 &#x1f49d;&#x1f49d;&#x1f49d; 欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#x…

笔记:能量谱密度与功率谱密度(二)

目录 一、ESD与PSD的定义、单位、性质 二、对ESD与PSD的直观理解 三、总结&#xff1a; 某物理量的“分布”在离散系统中&#xff0c;各点(纵坐标含义&#xff09;的物理意义仍然是该物理量&#xff0c;而在连续系统中&#xff0c;各点&#xff08;纵坐标含义&#xff09;的物…