linux下驱动学习—平台总线 (3)
platform 设备驱动
在设备驱动模型中, 引入总线的概念可以对驱动代码和设备信息进行分离。但是驱动中总线的概念是软件层面的一种抽象,与我们SOC中物理总线的概念并不严格相等:
物理总线:芯片与各个功能外设之间传送信息的公共通信干线,其中又包括数据总线、地址总线和控制总线,以此来传输各种通信时序。驱动总线:负责管理设备和驱动。制定设备和驱动的匹配规则,一旦总线上注册了新的设备或者是新的驱动,总线将尝试为它们进行配对。
一般对于I2C、SPI、USB这些常见类型的物理总线来说,Linux内核会自动创建与之相应的驱动总线,因此I2C设备、SPI设备、 USB设备自然是注册挂载在相应的总线上。但是,实际项目开发中还有很多结构简单的设备,对它们进行控制并不需要特殊的时序。 它们也就没有相应的物理总线,比如led、rtc时钟、蜂鸣器、按键等等,Linux内核将不会为它们创建相应的驱动总线。
为了使这部分设备的驱动开发也能够遵循设备驱动模型,Linux内核引入了一种虚拟的总线——平台总线(platform bus)。 平台总线用于管理、挂载那些没有相应物理总线的设备,这些设备被称为平台设备,对应的设备驱动则被称为平台驱动。 平台设备驱动的核心依然是Linux设备驱动模型,平台设备使用platform_device结构体来进行表示,其继承了设备驱动模型中的device结构体。 而平台驱动使用platform_driver结构体来进行表示,其则是继承了设备驱动模型中的device_driver结构体。
platfrom_device结构体
内核使用platform_device结构体来描述平台设备,结构体原型如下:
platform_device结构体在内核源码/include/linux/platform_device.h中
struct platform_device {const char *name;int id;struct device dev;u32 num_resources;struct resource *resource;const struct platform_device_id *id_entry;/* 省略部分成员 */};
name: 设备名称,总线进行匹配时,会比较设备和驱动的名称是否一致;
id: 指定设备的编号,Linux支持同名的设备,而同名设备之间则是通过该编号进行区分; dev:Linux设备模型中的device结构体,linux内核大量使用了面向对象思想,platform_device通过继承该结构体可复用它的相关代码,方便内核管理平台设备;
num_resources: 记录资源的个数,当结构体成员resource存放的是数组时,需要记录resource数组的个数,内核提供了宏;
platform_driver结构体
内核中使用platform_driver结构体来描述平台驱动,结构体原型如下所示:
platform_driver结构体在内核源码/include/platform_device.h中
struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;};
probe:函数指针,驱动开发人员需要在驱动程序中初始化该函数指针,当总线为设备和驱动匹配上之后,会回调执行该函数。我们一般通过该函数,对设备进行一系列的初始化。
remove:函数指针,驱动开发人员需要在驱动程序中初始化该函数指针,当我们移除某个平台设备时,会回调执行该函数指针,该函数实现的操作,通常是probe函数实现操作的逆过程。
driver:Linux设备模型中用于抽象驱动的device_driver结构体,platform_driver继承该结构体,也就获取了设备模型驱动对象的特性;
id_table:表示该驱动能够兼容的设备类型。
现在,如果写platform驱动,第一反应应该是先写设备树,就不要想着platform_device了,就当它被设备树替代了吧。
简介
在代码中添加of_device_id类型结构体数组。
platform驱动是如何被加载的。就是通过.compatible匹配完成的。如下所示
static const struct of_device_id my_of_ids[] = {{.compatible = "my_platform"},{},
};
MODULE_DEVICE_TABLE(of,my_of_ids);
##注意两点:
1.这个MODULE_DEVICE_TABLE宏一定不能忘记。不写不会报错。但是匹配不到。
2.my_of_id是一个数组,且最后一项必须空值。否则一定出错。
修改设备树
在根节点下添加这个东西,简单就是美呀。
hehe{compatible = "my_platform";};MODULE_DEVICE_TABLEmy_of_ids注册到一个总线设备表中,如果设备树中有与它的compatible一致的节点,就是两个字符串相同,就匹配成功。platform_driver的probe就会被调用。没有匹配成功,platform_driver的probe就不会被调用。我们这里都是"my_platform"字符串,所以肯定匹配成功。
源码
在代码里我故意将driver的name("hello pd")和设备树的节点("hehe")写的不一样,主要是说明以下几点。
1.这两个东西可以不同。
2.根据后面的测试结果可知,sys目录出现的是driver的name属性值,而不是设备树的"hehe"。
3.driver的name值和设备树的compatible的值也没有关系。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>static const struct of_device_id my_of_ids[] = {{.compatible = "my_platform"},{},
};MODULE_DEVICE_TABLE(of,my_of_ids);
static int my_probe(struct platform_device *device)
{printk("probe\n");return 0;
}
static int my_remove(struct platform_device *device)
{printk("remove\n");return 0;
}
static struct platform_driver my_platform_driver = {.probe = my_probe,.remove = my_remove,.driver = {.name = "hello pd",.of_match_table = my_of_ids,.owner = THIS_MODULE,},
};module_platform_driver(my_platform_driver);MODULE_LICENSE("GPL");
测试
root@host:/server# insmod helloworld.ko
[ 301.880475] probe
root@host:/server#
匹配成功,probe函数执行。
那么.driver的name属性是干什么的?这是容易混淆的地方,看看下面,这个name属性是sys目录下的驱动的名字。位于/sys/bus/platform/drivers下。
root@host:/sys/bus/platform/drivers# ls -ls0 drwxr-xr-x 2 root root 0 Jan 1 05:41 hello pd
/*略*/
从下面可以看出,name 字符串中间有空格是很不好的习惯。加了也没错。
root@host:/sys/bus/platform/drivers# ls hello\ pd/
bind hehe module uevent unbind
root@host:/sys/bus/platform/drivers#
从这里的结果可知,"hehe"作为"hello pd"的子文件夹出现
遍历hehe文件夹
root@host:/sys/bus/platform/drivers/hello pd# ls hehe
driver modalias power uevent
driver_override of_node subsystem
再看of_node文件夹
root@host:/sys/devices/platform/hehe# ls -ls
total 00 lrwxrwxrwx 1 root root 0 Jan 1 06:13 driver -> ../../../bus/platform/drivers/hello pd0 -rw-r--r-- 1 root root 4096 Jan 1 05:36 driver_override0 -r--r--r-- 1 root root 4096 Jan 1 05:36 modalias0 lrwxrwxrwx 1 root root 0 Jan 1 05:36 of_node -> ../../../firmware/devicetree/base/hehe0 drwxr-xr-x 2 root root 0 Jan 1 05:36 power0 lrwxrwxrwx 1 root root 0 Jan 1 05:36 subsystem -> ../../../bus/platform0 -rw-r--r-- 1 root root 4096 Jan 1 05:36 uevent
root@host:/sys/devices/platform/hehe#
of_node被链接到了…/…/…/firmware/devicetree/base/hehe也就是/sys/firmware/devicetree/base/hehe目录,从这里得到一个信息,/sys/firmware/devicetree里面是设备树。在目录只有一个base目录
在该base目录下有如下内容,他们都是设备树的根节点的子节点。如果想知道设备树里有什么就来这里找。
root@host:/sys/firmware/devicetree/base# ls
#address-cells model
#size-cells myled
aliases name
chosen pxp_v4l2
clocks regulators
compatible reserved-memory
cpus sii902x-reset
hehe soc
interrupt-controller@00a01000 spi4
leds wsinput
memory wskey
root@host:/sys/firmware/devicetree/base#
相关文章:
linux下驱动学习—平台总线 (3)
platform 设备驱动 在设备驱动模型中, 引入总线的概念可以对驱动代码和设备信息进行分离。但是驱动中总线的概念是软件层面的一种抽象,与我们SOC中物理总线的概念并不严格相等: 物理总线:芯片与各个功能外设之间传送信息的公共通…...
【leetcode】字符串中的第一个唯一字符
题目描述 给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。 用例 示例 1: 输入: s “leetcode” 输出: 0 示例 2: 输入: s “loveleetcode” 输出: 2 示例 3: 输入: s “aabb”…...
Serverless与Kubernetes(K8s)的区别、优缺点及应用场景
Serverless与Kubernetes(K8s)的区别 架构模型 Serverless是一种基于事件驱动的计算模型,它允许开发者编写应用程序时无需关心底层的基础设施。在Serverless架构中,云服务提供商会负责管理服务器、操作系统、运行时环境等基础设施&…...
参数小,性能强!开源多模态模型—TinyGPT-V
安徽工程大学、南洋理工大学和理海大学的研究人员开源了多模态大模型——TinyGPT-V。 TinyGPT-V以微软开源的Phi-2作为基础大语言模型,同时使用了视觉模型EVA实现多模态能力。尽管TinyGPT-V只有28亿参数,但其性能可以媲美上百亿参数的模型。 此外&…...
C++系列十五:字符串
字符串 1 、创建和初始化C字符串2. C字符串的常用操作3. C字符串处理函数4. C字符串在实际开发中的应用 C中的字符串是由字符组成的序列。字符串常用于处理文本数据,例如用户输入、文件内容等。C标准库提供了一个名为std::string的类,用于表示和处理字符…...
你了解计算机网络的发展历史吗?
1.什么是计算机网络 计算机网络是指将一群具有独立功能的计算机通过通信设备以及传输媒体被互联起来的,在通信软件的支持下,实现计算机间资源共享、信息交换或协同工作的系统。计算机网络是计算机技术与通信技术紧密结合的产物,两者的迅速发展…...
Qt/QML编程学习之心得:Linux下Thread线程创建(26)
GUI设计中经常为了不将界面卡死,会用到线程Thread,而作为GUI设计工具,Qt也提供了一个这样的类,即QThread。 QThread对象管理程序中的一个控制线程。线程QThread开始在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。 也可以通过…...
如何在数学建模竞赛中稳定拿奖
✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心&…...
Camunda Sub Process
一:内嵌子流程 repositoryService.createDeployment().name("内嵌子流程").addClasspathResource("bpmn/embed_sub_process.bpmn").deploy(); identityService.setAuthenticatedUserId("huihui"); ProcessInstance processInstance …...
golang 生成一年的周数
// GetWeekTimeCycleForGBT74082005 获取星期周期 中华人民共和国国家标准 GB/T 7408-2005 // 参数 year 年份 GB/T 7408-2005 func GetWeekTimeCycleForGBT74082005(year int) (*[]TimeCycle, error) {var yearstart time.Time //当年最开始一天var yearend time.Time //当年…...
植物大战僵尸-C语言搭建童年游戏(easyx)
游戏索引 游戏名称:植物大战僵尸 游戏介绍: 本游戏是在B站博主<程序员Rock>的视频指导下完成 想学的更详细的小伙伴可以移步到<程序员Rock>视频 语言项目:完整版植物大战僵尸!可能是B站最好的植物大战僵尸教程了&…...
c++学习:容器list实战(获取目录返回容器list)
新建一个dir.h,声明dir类 #ifndef DIR_H #define DIR_H#include <sys/types.h>#include <dirent.h> #include <stdio.h> #include <string.h>#include <iostream> #include <list>class Dir { public:Dir();static std::list<std::str…...
【Linux】Linux系统编程——Linux目录结构
Linux的文件系统呈现为一种树状结构,以根目录/为最顶层,其下分布着各种不同的子目录,每个目录都有其特定的用途和功能。下面是Linux目录结构的详细介绍: 1. 根目录 / 根目录是整个文件系统的基础。所有的目录和文件都从这里开始…...
卫星时钟服务器、NTP时钟服务器、GPS北斗网络时钟系统
卫星时钟服务器、NTP时钟服务器、GPS北斗网络时钟系统 卫星时钟服务器、NTP时钟服务器、GPS北斗网络时钟系统 卫星时钟服务器、NTP时钟服务器、GPS北斗网络时钟系统 应用背景 根据人民银行第2012年第8期《金融业信息安全风险提示》建议大力推广采用能够接收GPS和北斗时钟源信号…...
【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft
【Kafka-3.x-教程】专栏: 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…...
全网第一篇教你怎么总结多线程知识
于「全景图」,我之前也有一直在构建,可是因为知识储备不够,确实很难构建出来。稍微了解过并发领域知识的人都知道,里面的知识点、概念多而散:线程安全、锁、同步、异步、阻塞、非阻塞、死锁、队列(为什么并发要跟队列扯…...
Mondo备份linux操作系统为iso镜像 —— 筑梦之路
简介 Mondo Rescue(以下简称Mondo)可以说是Linux 下的Ghost,它可以将你的系统像照相一样备份至磁带,CD-R,CD-RW,NFS或硬盘分区。Mondo广泛支援LVM,RAID,ext2, ext3, JFS, XFS,Reise…...
《微信小程序开发从入门到实战》学习七十八
6.10 录音API 6.10.2 音频输入源PI 使用wx.getAvaliableAudioSources可获取当前支持的音频输入源,自基础库2.1.0开始支持。示例代码如下: wx.getAvaliableAudioSources({ success(res){ console.log(res.audioSources) } }) res.audioSources是一个数…...
React 入门 - 05(响应式与事件绑定)
本章内容 目录 一、响应式设计思想二、React 中的事件绑定 继上一节我们简单实现一个 TodoList来更加了解编写组件的一些细节。本节继续这个案例功能的完成。 一、响应式设计思想 1、在原生的 JS中,如果要实现点击”提交“按钮就将输入框的内容添加至页面列表中&…...
【APACHE】的认识和基础配置参数
#主页传送:江南的江 #每日鸡汤:人生没有如果和假设,只有后果和结果。生活有进有退,输什么也不能输心情。生活简单就是迷人的,学会简单其实就是不简单。要学会平静地接受现实,学会对自己说声顺其自然,学会坦…...
Maven Shade Plugin实战:解决Spring Boot胖JAR打包中的5个常见坑
Maven Shade Plugin实战:解决Spring Boot胖JAR打包中的5个常见坑 Spring Boot开发者们对"胖JAR"(fat JAR)应该都不陌生——这种将所有依赖打包进单个可执行文件的方式,极大简化了部署流程。但当你真正使用Maven Shade P…...
RAG集成:如何让你的企业知识库成为AI的“长期记忆”
核心命题:AI没有记忆,但你的知识库可以成为它的“外脑”。RAG(检索增强生成)是GEO的终极形态:让企业私有数据成为AI生成答案的唯一信源。引言:老陈的新困境——当AI“看见”了你的店,却“看不见…...
GEE引擎封挂实战:从M2参数到RunGate网关的完整配置指南
GEE引擎封挂实战:从M2参数到RunGate网关的完整配置指南 在游戏运营过程中,外挂问题一直是困扰开发者和运营者的顽疾。对于使用GEE引擎的游戏服务器来说,如何有效防范和打击外挂行为,维护游戏公平性,是每个技术团队必须…...
告别传统知识蒸馏:用‘逆向蒸馏’在MVTec数据集上实现98.5%的异常检测精度
逆向蒸馏:工业质检场景下的异常检测新范式 在工业质检领域,异常检测一直是计算机视觉技术落地的核心挑战之一。传统方法往往受限于样本不平衡、缺陷类型多样等问题,而基于深度学习的方案又面临标注成本高、泛化能力不足的困境。CVPR 2022提出…...
网页时光机:如何永久保存消失的网页内容
网页时光机:如何永久保存消失的网页内容 【免费下载链接】wayback-machine-webextension A web browser extension for Chrome, Firefox, Edge, and Safari 14. 项目地址: https://gitcode.com/gh_mirrors/wa/wayback-machine-webextension 你是否遇到过这样…...
杭州污水提升泵靠谱厂家
在杭州及周边地区进行地下室改造、商业空间建设或解决特殊排污需求时,选择一家技术可靠、服务专业的污水提升泵厂家至关重要。在众多厂家中,杭州富阳赛特仪表阀门有限公司(赛斯瑞特) 凭借其深厚的技术积淀、过硬的产品品质和完善的…...
新手福音:通过快马平台零代码基础理解qun329群聊应用开发
作为一个刚接触编程的新手,想要理解群聊应用开发确实容易一头雾水。最近我在尝试用InsCode(快马)平台搭建类似qun329的简单群聊网页时,发现整个过程比想象中简单很多。下面分享我的学习过程,希望能帮到同样零基础的朋友。 项目结构规划 首先明…...
douyin-downloader完全指南:音频高效提取的创新方法
douyin-downloader完全指南:音频高效提取的创新方法 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support…...
青铜器RDM研发管理平台
我们深耕研发管理服务20余年,依托 10 余年研发管理实战经验,累计为超 10000 家企业提供专业培训、为200 余家企业深度咨询,打造完全自主知识产权的研发管理数字化平台 —— 青铜器 RDM。以 IPD、CMMI、Scrum、PMBOK 等业界最佳实践为内核&…...
新手入门:零基础借助快马生成你的第一个openmaic网页版调用程序
今天想和大家分享一个特别适合新手入门的实践项目——如何借助InsCode(快马)平台快速生成你的第一个openmaic网页版调用程序。作为一个刚接触AI开发的新手,我最初看到各种API文档和代码示例时也是一头雾水,但通过这个可视化工具,居然半小时就…...
