【I2C】通用驱动i2c-dev分析
文章目录
- 1. 前言
- 2. i2c-dev驱动的注册过程
- 3. open_i2c_dev函数分析
- 4. set_slave_addr函数分析
- 5. i2c_read_bytes函数分析
1. 前言
前面分析i2c-tool
测试工具就是基于drivers/i2c/i2c-dev.c
驱动来实现的。i2c-dev驱动在加载时会遍历所有的I2C总线(i2c_bus_type)上所有注册的adapter,并且在linux系统创建对应的字符设备,如:/dev/i2c-0
、/dev/i2c-1
、/dev/i2c-2
等。应用程序通过open打开对应的i2c字符设备,通过ioctl来收发数据。具体的架构如下图:
2. i2c-dev驱动的注册过程
在i2c-dev.c的驱动入口i2c_dev_init
函数具体操作如下:
- register_chrdev_region:注册i2c字符设备
- class_create:创建i2c-dev的class,为在linux文件系统中创建字符设备做准备。
- i2cdev_attach_adapter:通过函数
i2c_for_each_dev
遍历已经绑定的adapter,有多少个adapter就调用i2cdev_attach_adapter
函数几次。
- to_i2c_adapter:通过dev获取对应的i2c adapter。
- cdev_init:它会初始化一个重要的结构体,file_operations。
- dev_set_name:设置device name为
i2c-x
,也就是我们在字符设备创建成功后看到的/dev/i2c-x
设备。 - cdev_device_add:添加设备到系统,并且创建对应的字符设备到用户空间。
备注:
cdev_device_add这里其实调用了cdev_add和device_add。然而,device_create()是device_register()的封装,而device_register()则是device_add()的封装。
3. open_i2c_dev函数分析
open_i2c_dev是i2c-tool
工具open i2c-dev驱动的函数,根据传递的参数最终重要函数应该如下:
file = open("/dev/i2c-0", O_RDWR);
该函数的主要代码如下:
/* File Path = i2c-tools-4.3/tools/i2cbusses.c */
int open_i2c_dev(int i2cbus, char *filename, size_t size, int quiet)
{int file, len;len = snprintf(filename, size, "/dev/i2c/%d", i2cbus);if (len >= (int)size) {fprintf(stderr, "%s: path truncated\n", filename);return -EOVERFLOW;}file = open(filename, O_RDWR);if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) {len = snprintf(filename, size, "/dev/i2c-%d", i2cbus);if (len >= (int)size) {fprintf(stderr, "%s: path truncated\n", filename);return -EOVERFLOW;}file = open(filename, O_RDWR);}...return file;
}
应用层调用open后,会对应调用i2c-dev通用驱动的open函数。主要是如下几个步骤:
- to_i2c_adapter:通过minor次设备号,其实这里等同于i2c总线编号。通过它来获取对应总线的adapter。
- kzalloc:申请一个i2c client表示I2C设备,并且初始化该client的name和保存adapter与其建立联系。但是,整个open函数这里没有对I2C地址进行初始化。
- file->private_data:通过private_data保存申请的client地址,为了后面read/write/ioctl可以通过file->private_data很方便的拿到当前dev的client。
/* File Path = kernel/drivers/i2c/i2c-dev.c */
static int i2cdev_open(struct inode *inode, struct file *file)
{unsigned int minor = iminor(inode);struct i2c_client *client;struct i2c_adapter *adap;adap = i2c_get_adapter(minor);if (!adap)return -ENODEV;/* This creates an anonymous i2c_client, which may later be* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.** This client is ** NEVER REGISTERED ** with the driver model* or I2C core code!! It just holds private copies of addressing* information and maybe a PEC flag.*/client = kzalloc(sizeof(*client), GFP_KERNEL);if (!client) {i2c_put_adapter(adap);return -ENOMEM;}snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);client->adapter = adap;file->private_data = client;return 0;
}
4. set_slave_addr函数分析
open_i2c_dev是i2c-tool
工具来设置I2C的设备地址。具体代码如下:
/* File Path = i2c-tools-4.3/tools/i2cbusses.c */
int set_slave_addr(int file, int address, int force)
{/* With force, let the user read from/write to the registerseven when a driver is also running */if (ioctl(file, force ? I2C_SLAVE_FORCE : I2C_SLAVE, address) < 0) {fprintf(stderr,"Error: Could not set address to 0x%02x: %s\n",address, strerror(errno));return -errno;}return 0;
}
应用层调用ioctl I2C_SLAVE_FORCE后,会对应调用i2c-dev通用驱动对应的ioctl I2C_SLAVE_FORCE。主要是如下2个步骤:
- client = file->private_data:从private_data中获取当前I2C设备。
- client->addr = arg:设置当前I2C设备的地址信息,方便后面的read/write操作I2C设备。
/* File Path = kernel/drivers/i2c/i2c-dev.c */
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{struct i2c_client *client = file->private_data;unsigned long funcs;switch (cmd) {case I2C_SLAVE:case I2C_SLAVE_FORCE:if ((arg > 0x3ff) ||(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))return -EINVAL;if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))return -EBUSY;/* REVISIT: address could become busy later */client->addr = arg;return 0;...
}
5. i2c_read_bytes函数分析
i2c_read_bytes这个函数是我自己写的demo code,这里只列了read部分来分析,完整的demo code可以查看上一篇我的博客。主要是如下2个步骤:
- struct i2c_msg messages[2]:定义2个i2c_msg的消息体,并且初始化它。它包含了:I2C的从机设备地址、read/write的flag、数据的长度、存放数据的地址。msg[0]主要是为了发送需要读取从机的哪个寄存器,msg[1]主要的配置读取的数据长度的和存放数据的地址。
- struct i2c_rdwr_ioctl_data packets:它主要是存放i2c_msg消息地址和i2c_msg消息个数。
- ioctl:通过ioctl发送到内核。
static int i2c_read_bytes(int fd, uint8_t slave_addr, uint8_t reg_addr, uint8_t *values, uint8_t len)
{uint8_t outbuf[1];struct i2c_rdwr_ioctl_data packets;struct i2c_msg messages[2];outbuf[0] = reg_addr;messages[0].addr = slave_addr;messages[0].flags = 0;messages[0].len = sizeof(outbuf);messages[0].buf = outbuf;/* The data will get returned in this structure */messages[1].addr = slave_addr;messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;messages[1].len = len;messages[1].buf = values;/* Send the request to the kernel and get the result back */packets.msgs = messages;packets.nmsgs = 2;if(ioctl(fd, I2C_RDWR, &packets) < 0){printf("Error: Unable to send data");return -1;}return 0;
}
应用层调用ioctl I2C_RDWR后,会对应调用i2c-dev通用驱动对应的ioctl I2C_RDWR。它将应用层的数据到拷贝的内核,具体如下:
/* File Path = kernel/drivers/i2c/i2c-dev.c */
case I2C_RDWR: {struct i2c_rdwr_ioctl_data rdwr_arg;struct i2c_msg *rdwr_pa;//从用户空间拷贝数据到内核空间copy_from_user(&rdwr_arg,(struct i2c_rdwr_ioctl_data __user *)arg,sizeof(rdwr_arg));//分配一块内存空间,将用户空间的数据拷贝进去rdwr_pa = memdup_user(rdwr_arg.msgs, rdwr_arg.nmsgs * sizeof(struct i2c_msg));return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa);
}static int i2cdev_ioctl_rdwr(struct i2c_client *client, unsigned nmsgs, struct i2c_msg *msgs)
{***res = i2c_transfer(client->adapter, msgs, nmsgs);***
}
总结:其实应用层初始化的i2c_msg就是直接给内核i2c_transfer
将I2C消息发送出去的。
相关文章:

【I2C】通用驱动i2c-dev分析
文章目录1. 前言2. i2c-dev驱动的注册过程3. open_i2c_dev函数分析4. set_slave_addr函数分析5. i2c_read_bytes函数分析1. 前言 前面分析i2c-tool测试工具就是基于drivers/i2c/i2c-dev.c驱动来实现的。i2c-dev驱动在加载时会遍历所有的I2C总线(i2c_bus_type)上所有注册的adap…...

用GPT-4写代码不用翻墙了?Cursor告诉你:可以~~
目录 一、介绍 二、使用方法 三、其他实例 1.正则表达式 2.自动化测试脚本 3.聊聊技术 一、介绍 Cursor主要功能是根据用户的描述写代码或者进行对话,对话的范围仅限技术方面。优点是不用翻墙、不需要账号。Cursor基于GPT模型,具体什么版本不祥&#…...

硬件语言Verilog HDL牛客刷题day03 时序逻辑部分
1.VL21 根据状态转移表实现时序电路 1.题目: 某同步时序电路转换表如下,请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。 2.解题思路 2.1 首先同步时序电路 , 时钟上升沿触发, 复位信号rst 低电…...
day31 ● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和
● 455.分发饼干 ● 376. 摆动序列 ● 53. 最大子序和 在本次的题目中,我们使用了贪心算法来解决三个问题:分发饼干、摆动序列、最大子序和。这三个问题都可以使用贪心算法来解决,而且贪心算法的时间复杂度相对较低,能够在较短的…...

MobTech 秒验|本机号码一键登录会泄露隐私吗
本机号码一键登录是一种新型的应用登录方式,它可以利用运营商的数据网关认证能力,实现手机号免密登录,提高用户体验和转化率,降低验证成本和流失率。本机号码一键登录支持三大运营商号码认证,3秒内完成手机号验证&…...

2023年供销合作社研究报告
第一章 行业概况 1.1 供销合作社概述 中华全国供销合作总社,是中华人民共和国全国供销合作社的联合组织。中华全国供销合作总社的前身可以追溯到1949年11月成立的中央合作事业管理局。在新中国成立初期,供销合作社就基本形成了自上而下、覆盖全国的组织…...

【ansible】实施任务控制
目录 实施任务控制 一,循环(迭代)--- loop 1,利用loop----item循环迭代任务 2,item---loop循环案例 1,定义item循环列表 2,通过变量应用列表格式 3,字典列表(迭代嵌套子…...

49天精通Java,第11天,java接口和抽象类的异同,default关键字
目录一、什么是接口二、接口的特点三、接口和类的区别四、接口和抽象类的区别五、接口的声明方式六、default默认方法大家好,我是哪吒。 一、什么是接口 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的…...
JAVA练习99-逆波兰表达式求值
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、题目-逆波兰表达式求值 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示:这里可以添加本文要记录的大概内容: 4月5…...

恶意软件、恶意软件反杀技术以及反病毒技术的详细介绍
1.恶意软件简单介绍恶意软件是指在计算机系统上执行恶意任务的病毒、蠕虫和特洛伊木马的程序,通过破坏软件进程来实施控制。腾讯移动安全实验室发布的数据显示,恶意软件由多种威胁组成,会不断弹出,所以需要采取多种方法和技术来进…...

【数据库运维】mysql备份恢复练习
目录 数据库备份,数据库为school,素材如下 1.创建student和score表 2.为student表和score表增加记录 3.备份数据库school到/backup目录 4.备份MySQL数据库为带删除表的格式,能够让该备份覆盖已有数据库而不需要手动删除原有数据库 5.直接将My…...

刷题30-对称的二叉树
对称的二叉树 思路:用递归,首先明白递归中止的条件是什么 搬用别人的看法: 做递归思考三步: 1.递归的函数要干什么? 函数的作用是判断传入的两个树是否镜像。 输入:TreeNode left, TreeNode right 输出…...

精选简历模板
1.应届生通用简历模板(.docx) 适用于应届生找工作的学生群体 https://download.csdn.net/download/weixin_43042683/87652099https://download.csdn.net/download/weixin_43042683/87652099 部分缩略图如下: 2.研究生通用简历模板(.docx)…...

蓝桥杯嵌入式第十三届客观题解析
文章目录 前言一、题目1二、题目2三、题目3四、题目4五、题目5六、题目6七、题目7八、题目8九、题目9十、题目10总结前言 本篇文章将带大家来学习蓝桥杯嵌入式的客观题了,蓝桥杯嵌入式的客观题涉及到模电,数电,单片机等知识,需要非常扎实的基础,客观题不能急于求成只能脚…...

【Redis】线程问题
文章目录单线程版本演化工作流程为什么逐渐又加入了多线程特性?影响Redis性能的主要因素->网络I/O多线程工作流程Unix网络编程中的五种I/O模型I/O多路复用工作原理:select、poll、epoll为什么Redis快单线程与多线程的比较配置文件开启多线程单线程 版本演化 Re…...

【算法题】2498. 青蛙过河 II
题目: 给你一个下标从 0 开始的整数数组 stones ,数组中的元素 严格递增 ,表示一条河中石头的位置。 一只青蛙一开始在第一块石头上,它想到达最后一块石头,然后回到第一块石头。同时每块石头 至多 到达 一次。 一次…...

【新2023Q2押题JAVA】华为OD机试 - 整理扑克牌
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:整理扑克牌 题目 给定一组数…...

【hello C语言】文件操作
目录 1. 什么是文件? 2. 程序文件 3. 数据文件 4. 文件名 5. 文件类型 5.1 二进制文件 5.2 文本文件 5.3 数据在内存中的存储 6. 文件缓冲区 7. 文件指针 8. 文件的打开和关闭 9. 文件的顺序读写 10. 文件的随机读写 10.1 fseek:根据文件指针的位置和偏移…...

OBCP第八章 OB运维、监控与异常处理-数据库监控
系统监控视图:系统视图 OceanBase 数据库为多租户架构,租户分为两种类型:普通租户以及 sys 租户。OceanBase 数据库系统表都存储在 sys 租户,且主键中存储租户号(tenant_id),区分每个租户的内容…...

已经提了离职,还有一周就走,公司突然把我移出企业微信,没法考勤打卡, 还要继续上班吗?...
黎明前的黑暗最容易出事,离职前的几天也最容易出幺蛾子,比如下面这位网友的遭遇:已经提了离职,还有一周就正式离职了,公司突然把我移出企业微信,没法考勤打卡了, 还要继续上班吗?该怎…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...