Linux驱动-在用户态控制I2C-两种方案ioctl和文件控制
提示Linux驱动-在用户态控制I2C文章目录前言一、参考资料二、关联代码关联源码关联源码解析核心定位核心数据结构struct i2c_dev结构体open 时创建匿名 struct i2c_client文件操作接口 i2cdev_fops重中之重i2cdev_write ()i2cdev_read ()ioctl 核心函数 i2cdev_ioctl()分支 1I2C_SLAVE / I2C_SLAVE_FORCE分支 2I2C_RDWR推荐方案入口分支 3I2C_SMBUS设备初始化与生命周期1.模块入口 i2c_dev_init2. 总线通知器 i2cdev_notifier_call3. open /release 流程两条用户态 API 路径完整调用链路对比路径 Aread () /write () 方案I2C_SLAVE路径 Bioctl (I2C_RDWR) 方案推荐三、Client 端控制代码ioctl 实现i2c 控制文件方式read/write 方式实现i2c 控制两种client端控制i2c 区别总结前言前面知识点都是基于驱动程序知识点下面我们看看用户态 client 端如何通过i2c 接口实现i2c 驱动控制。这里讲解两种控制方案ioctl 和 文件控制 方案。一、参考资料这里侧重于之前的笔记知识点i2c 基本知识点前面知识点基础一定要掌握Linux驱动-i2c 驱动框架编写Linux驱动-IIC完善FT5X06设备节点和驱动Linux驱动-I2C通信-FT5X06驱动程序部分编写Linux驱动-通过逻辑分析仪-认识-分析IIC波形Linux 驱动-I2C输入子系统相关知识点Linux驱动-IIC通信-FT5X06驱动-数据上报案例-终端测试RK3568驱动指南第十五篇 I2C-第179章在应用程序中使用I2Cioctl 知识点驱动-传参实验-ioctl驱动-地址传参实验-ioctl二、关联代码关联源码路径/kernel/drivers/i2c/i2c-dev.c关联源码解析核心定位i2c-dev.c是 Linux 内核提供的【用户态 I2C 适配器驱动】作用暴露/dev/i2c-X字符设备允许应用层程序直接操作硬件 I2C 总线不需要编写内核驱动。它不是 I2C 硬件控制器驱动只是上层封装最终所有传输都会调用 I2C 核心i2c_transfer()。核心数据结构struct i2c_dev结构体struct i2c_dev{struct list_head list;struct i2c_adapter*adap;// 指向硬件I2C适配器I2C控制器struct device dev;struct cdev cdev;// 字符设备核心结构绑定file_operations};每一条硬件 I2C 总线/dev/i2c-0//dev/i2c-1对应一个i2c_devadap底层硬件控制器RK3568/MTK 的 I2C 硬件驱动最终操作这个 adapteropen 时创建匿名struct i2c_clientstaticinti2cdev_open(struct inode*inode,struct file*file){// ...clientkzalloc(sizeof(*client),GFP_KERNEL);client-adapteradap;file-private_dataclient;}打开/dev/i2c-x时内核分配一个匿名 i2c_client。这个 client不会注册到内核设备树驱动模型仅仅用来保存从机地址client-addr由I2C_SLAVEioctl 设置标志位10bit 地址、PEC 校验等如果你使用read()/write()这套方案必须先调用ioctl(I2C_SLAVE_FORCE, addr)填充 client-addr否则读写直接报错。I2C_RDWR不需要依赖这个 client 内部 addr因为每条i2c_msg自带 addr。文件操作接口i2cdev_fops重中之重staticconststruct file_operations i2cdev_fops{.ownerTHIS_MODULE,.llseekno_llseek,.readi2cdev_read,// 用户态 read(fd, buf, len).writei2cdev_write,// 用户态 write(fd, buf, len).unlocked_ioctli2cdev_ioctl,// 用户态 ioctl().compat_ioctlcompat_i2cdev_ioctl,// 32位兼容.openi2cdev_open,.releasei2cdev_release,};i2cdev_write ()staticssize_ti2cdev_write(struct file*file,constchar__user*buf,size_t count,loff_t*offset){struct i2c_client*clientfile-private_data;// 1. 用户空间buf拷贝到内核空间 tmptmpmemdup_user(buf,count);// 2. 调用 i2c_master_sendreti2c_master_send(client,tmp,count);kfree(tmp);returnret;}i2c_master_send内部行为自动组装单条struct i2c_msg写标志调用i2c_transfer()时序START 数据 STOP每次 write 都是独立 I2C 事务首尾自动加 START/STOPi2cdev_read ()staticssize_ti2cdev_read(struct file*file,char__user*buf,size_t count,loff_t*offset){struct i2c_client*clientfile-private_data;reti2c_master_recv(client,tmp,count);// 内核数据拷贝回用户空间copy_to_user(buf,tmp,ret);}i2c_master_recv自动组装单条带I2C_M_RD的 i2c_msg时序START 读地址 接收数据 STOP致命限制// 向寄存器 0x80 写入数据 0x66ft5x06_write_reg(fd,0x80,0x66);// 读取寄存器 0x80 的值ft5x06_read_reg(fd,0x80);内核执行两次独立事务writeSTART reg STOPreadSTART READ STOP中间出现 STOP没有 RESTART绝大多数寄存器芯片FT5x06收到 STOP 后丢弃寄存器地址读取失败。根源就在read/write 各自封装独立一次 i2c_transfer无法合并多条 msg。ioctl 核心函数i2cdev_ioctl()所有ioctl(fd, cmd, arg)进入这个函数通过 cmd 分支分发。分支 1I2C_SLAVE / I2C_SLAVE_FORCEcaseI2C_SLAVE:caseI2C_SLAVE_FORCE:client-addrarg;// 把从机地址存入匿名clientreturn0;I2C_SLAVE如果内核已经有驱动占用该从地址 → 返回-EBUSYI2C_SLAVE_FORCE强制覆盖地址无视内核驱动占用⚠️ 风险用户态和内核驱动同时访问同一个从机总线冲突、数据错乱分支 2I2C_RDWR推荐方案入口caseI2C_RDWR:{struct i2c_rdwr_ioctl_data rdwr_arg;// 1. 把用户态 struct i2c_rdwr_ioctl_data 拷贝进内核copy_from_user(rdwr_arg,...);// 2. 拷贝用户态 i2c_msg 数组到内核rdwr_pamemdup_user(rdwr_arg.msgs,rdwr_arg.nmsgs*sizeof(struct i2c_msg));// 3. 调用核心处理函数returni2cdev_ioctl_rdwr(client,rdwr_arg.nmsgs,rdwr_pa);}重点i2cdev_ioctl_rdwr()一次性传入多条 i2c_msg 数组内核 I2C 核心规则同一组多条连续 i2c_msg只发送一次 START消息之间使用RESTART无 STOP全部执行完成后发送一次 STOP。✅ 刚好满足 FT5x06 寄存器读时序msg0写寄存器地址 → RESTART → msg1读数据这就是为什么I2C_RDWR可以正常读取触控芯片寄存器分支 3I2C_SMBUS提供 SMBus 简化接口兼容 SMBus 协议设备普通 I2C 寄存器外设很少使用。设备初始化与生命周期1.模块入口i2c_dev_init注册字符设备主设备号I2C_MAJOR注册总线通知器监听 I2C 适配器的插拔遍历所有已经存在的 I2C 适配器自动创建/dev/i2c-X2. 总线通知器i2cdev_notifier_call新增 I2C 适配器 →i2cdev_attach_adapter()→ 创建/dev/i2c-x卸载 I2C 适配器 →i2cdev_detach_adapter()→ 删除设备节点3. open /release 流程open(/dev/i2c-1)→i2cdev_open()→ 获取i2c_adapter → 创建匿名i2c_client存入file-private_dataclose(fd)→i2cdev_release()→ 释放i2c_client内存 → 释放adapter引用计数两条用户态 API 路径完整调用链路对比路径 Aread () /write () 方案I2C_SLAVEappwrite()→ sys_write →i2cdev_write()→i2c_master_send()→i2c_transfer()【单条msg】 appread()→ sys_read →i2cdev_read()→i2c_master_recv()→i2c_transfer()【单条msg】缺陷两次系统调用 两次独立i2c_transfer中间 STOP无法 RESTART。路径 Bioctl (I2C_RDWR) 方案推荐appioctl(fd,I2C_RDWR,data)→ sys_ioctl →i2cdev_ioctl()→i2cdev_ioctl_rdwr()→i2c_transfer(...,nmsgs条消息)优势一次系统调用多条 msg 交给内核连续执行支持 RESTART 时序。三、Client 端控制代码ioctl 实现i2c 控制#includestdio.h#includelinux/i2c.h#includelinux/i2c-dev.h#includesys/ioctl.h#includesys/types.h#includesys/stat.h#includefcntl.h#includestring.h/** * brief 从 I2C 设备的寄存器中读取数据 * param fd 打开的 I2C 设备文件描述符 * param slave_addr I2C 设备的从机地址 * param reg_addr 要读取的寄存器地址 * return 寄存器的值 */intft5x06_read_reg(intfd,unsignedcharslave_addr,unsignedcharreg_addr){unsignedchardata;struct i2c_rdwr_ioctl_data i2c_msgs;intret;// 定义两个 i2c_msg 结构体, 第一个用于写入寄存器地址, 第二个用于读取数据struct i2c_msg dev_msgs[]{[0]{.addrslave_addr,.flags0,.lensizeof(reg_addr),.bufreg_addr,},[1]{.addrslave_addr,.flagsI2C_M_RD,// 设置读取标志.lensizeof(data),.bufdata,}};i2c_msgs.msgsdev_msgs;i2c_msgs.nmsgs2;// 两个 i2c_msg 结构体// 调用 ioctl 函数执行读取操作retioctl(fd,I2C_RDWR,i2c_msgs);if(ret0){printf(read error\n);returnret;}returndata;}/** * brief 向 I2C 设备的寄存器写入数据 * param fd 打开的 I2C 设备文件描述符 * param slave_addr I2C 设备的从机地址 * param reg_addr 要写入的寄存器地址 * param data 要写入的数据 * param len 数据长度 */voidft5x06_write_reg(intfd,unsignedcharslave_addr,unsignedcharreg_addr,unsignedchar*data,intlen){unsignedcharbuff[256];struct i2c_rdwr_ioctl_data i2c_msgs;intret;// 定义一个 i2c_msg 结构体, 用于写入寄存器地址和数据struct i2c_msg dev_msgs[]{[0]{.addrslave_addr,.flags0,.lenlen1,.bufbuff,}};// 将寄存器地址和数据拷贝到 buff 数组中buff[0]reg_addr;memcpy(buff[1],data,len);i2c_msgs.msgsdev_msgs;i2c_msgs.nmsgs1;// 调用 ioctl 函数执行写入操作retioctl(fd,I2C_RDWR,i2c_msgs);if(ret0){printf(write error\n);}}intmain(intargc,char*argv[]){intfd;intID_G_THGROUP;// 打开 I2C 设备文件fdopen(/dev/i2c-1,O_RDWR);if(fd0){printf(open error\n);returnfd;}// 向 0x38 地址的寄存器 0x80 写入 0x55unsignedchardata0x55;ft5x06_write_reg(fd,0x38,0x80,data,1);// 从 0x38 地址的寄存器 0x80 读取数据ID_G_THGROUPft5x06_read_reg(fd,0x38,0x80);printf(ID_G_THGROUP is 0x%02X\n,ID_G_THGROUP);return0;}文件方式read/write 方式实现i2c 控制#includestdio.h#includesys/ioctl.h#includesys/types.h#includesys/stat.h#includefcntl.h#includestring.h#includelinux/i2c.h#includelinux/i2c-dev.h#includeunistd.h/* * 从 I2C 设备读取寄存器值 * param fd: I2C 设备文件句柄 * param reg_addr: 要读取的寄存器地址 */voidft5x06_read_reg(intfd,unsignedcharreg_addr){unsignedcharrd_data[1];rd_data[0]reg_addr;write(fd,rd_data,1);read(fd,rd_data,1);printf(reg value is %x\n,rd_data[0]);}/* * 向 I2C 设备写入寄存器值 * param fd: I2C 设备文件句柄 * param reg_addr: 要写入的寄存器地址 * param data: 要写入的数据 */voidft5x06_write_reg(intfd,unsignedcharreg_addr,unsignedchardata){unsignedcharwr_data[2];wr_data[0]reg_addr;wr_data[1]data;write(fd,wr_data,2);}intmain(intargc,char*argv[]){intfd;// 打开 I2C 设备文件fdopen(/dev/i2c-1,O_RDWR);if(fd0){printf(open error\n);returnfd;}// 设置从设备地址为 0x38ioctl(fd,I2C_SLAVE_FORCE,0x38);// 向寄存器 0x80 写入数据 0x66ft5x06_write_reg(fd,0x80,0x66);// 读取寄存器 0x80 的值ft5x06_read_reg(fd,0x80);return0;}备注并不是所有的IC 都支持这种方式所以对于主控也是默认关闭的那么自己要检查一下是否打开了这种通讯方式。当然对于从设备的i2c 的IC 可能都不支持实战中如果发现不支持要核对下时是否真的支持不然茫然。两种client端控制i2c 区别对比项I2C_RDWR (方案 1)I2C_SLAVE read/write (方案 2)系统调用入口ioctl(I2C_RDWR)open → ioctl(I2C_SLAVE) → read/write事务控制一次 ioctl 执行多条 msg支持 RESTART每次 read/write 独立事务强制 STOP从机地址每条 i2c_msg 独立指定支持多从机整个 fd 绑定单一地址切换需要重设 ioctl标准寄存器读时序完美支持写 RESTART 读时序断裂大部分芯片读取失败代码复杂度较高很低和内核驱动i2c_transfer行为高度一致上层封装内核自动拆分事务总结这里给出了两种client 端控制i2c 外设的方式。 ioctl 和 文件控制方式。多琢磨不同方案的不同、优劣自己思考。

相关新闻

3分钟掌握:如何高效获取国家中小学智慧教育平台电子课本PDF文件

3分钟掌握:如何高效获取国家中小学智慧教育平台电子课本PDF文件

3分钟掌握:如何高效获取国家中小学智慧教育平台电子课本PDF文件 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本内容。 …

2026/7/29 18:37:56 阅读更多 →
从理论到实践:Geotorch约束优化的数学原理与代码实现

从理论到实践:Geotorch约束优化的数学原理与代码实现

从理论到实践:Geotorch约束优化的数学原理与代码实现 【免费下载链接】geotorch Constrained optimization toolkit for PyTorch 项目地址: https://gitcode.com/gh_mirrors/ge/geotorch Geotorch是一个专为PyTorch设计的约束优化工具包,它提供了…

2026/7/29 18:37:56 阅读更多 →
AI学情分析报告生成逻辑全拆解(从原始行为日志到个性化干预建议的7层推理链)

AI学情分析报告生成逻辑全拆解(从原始行为日志到个性化干预建议的7层推理链)

更多请点击: https://intelliparadigm.com 第一章:AI学情分析报告生成逻辑全拆解(从原始行为日志到个性化干预建议的7层推理链) AI学情分析报告并非简单统计点击与停留时长,而是依托七层递进式语义推理引擎&#xff0…

2026/7/29 18:36:56 阅读更多 →

最新新闻

多个table水平排列后div无法包裹

多个table水平排列后div无法包裹

HTML结构 <div> <h2></h2> <table></table> <table></table> </div> table水平排列 table { float:left; } div只能包裹h2了&#xff01; 增加 div { overflow:auto; } 解决了&#xff0c;啥原理&#xff1f;

2026/7/29 18:51:01 阅读更多 →
Windows系统下Python-PCL环境配置全攻略:从编译原理到实战部署

Windows系统下Python-PCL环境配置全攻略:从编译原理到实战部署

1. 项目缘起&#xff1a;为什么要在Windows上折腾Python-PCL&#xff1f; 如果你正在处理三维点云数据&#xff0c;无论是来自激光雷达、深度相机还是三维重建算法&#xff0c;那么PCL&#xff08;Point Cloud Library&#xff09;这个名字你一定不陌生。它被誉为点云处理的“瑞…

2026/7/29 18:51:01 阅读更多 →
AG Kit与MCP服务器集成:实现高级AI功能的完整配置指南

AG Kit与MCP服务器集成:实现高级AI功能的完整配置指南

AG Kit与MCP服务器集成&#xff1a;实现高级AI功能的完整配置指南 【免费下载链接】ag-kit 项目地址: https://gitcode.com/GitHub_Trending/an/ag-kit AG Kit&#xff08;Modular AI Agent Toolkit&#xff09;是一款强大的模块化AI代理工具包&#xff0c;通过与MCP服…

2026/7/29 18:51:01 阅读更多 →
Python/机器学习项目银行客户流失预测123(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

Python/机器学习项目银行客户流失预测123(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

Python/机器学习项目银行客户流失预测123(设计源文件万字报告讲解)&#xff08;支持资料、图片参考_相关定制&#xff09;_ 机器学习/数据挖掘项目Python&#xff0c;各种数据挖掘/量化投资/机器学习/数据挖掘项目课程要求 银行客户流失预测及数据分析

2026/7/29 18:51:01 阅读更多 →
H3C IRF网络脑裂防护:BFD MAD原理、部署与排错全解

H3C IRF网络脑裂防护:BFD MAD原理、部署与排错全解

1. 项目概述&#xff1a;理解BFD MAD在IRF网络中的核心价值在构建高可靠、高可用的企业网络时&#xff0c;设备冗余和链路冗余是基础&#xff0c;但如何确保冗余设备之间能够快速、准确地感知彼此状态&#xff0c;并在主设备故障时实现无缝切换&#xff0c;才是真正的技术难点。…

2026/7/29 18:51:01 阅读更多 →
Google Gemma4开源大语言模型技术解析与应用实践

Google Gemma4开源大语言模型技术解析与应用实践

1. Gemma4项目概述Gemma4是Google最新推出的一款开源大语言模型&#xff0c;作为Gemini技术体系的重要组成部分&#xff0c;它延续了Google在AI领域的技术优势。与市面上其他开源模型相比&#xff0c;Gemma4最显著的特点是采用了创新的26B/A4B混合架构设计&#xff0c;在保持模…

2026/7/29 18:50:01 阅读更多 →

日新闻

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:00:23 阅读更多 →
AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02:合并知识功能,给 AI 问数和 RAG 场景打基础

AI编程系列02&#xff1a;合并知识功能&#xff0c;给 AI 问数和 RAG 场景打基础 在上一期「AI编程系列」中&#xff0c;我们学习了如何构建一个基础的 AI 问答系统&#xff0c;通过简单的输入输出让模型回应问题。但现实世界中的 AI 应用往往需要处理更复杂的场景&#xff1a;…

2026/7/29 0:00:23 阅读更多 →
AI智能体开发实战:从工具调用到企业级部署

AI智能体开发实战:从工具调用到企业级部署

1. 从被动问答到主动执行&#xff1a;AI Agent的范式转变过去两年&#xff0c;大语言模型最显著的应用形态是聊天机器人——用户提问&#xff0c;AI回答。但真正的生产力革命发生在2023年下半年&#xff1a;当AI学会主动调用工具完成任务时&#xff0c;生产力工具的历史被彻底改…

2026/7/29 0:00:23 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档&#xff0c;可以直接使用&#xff01;系统支持图片、视频、摄像头等多种方式检测裂缝&#xff0c;功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像&#xff01; pubg绝地求生目标检测数据集 1分类&#xff1a;e_body&#xff0c;14905个标签&#xff0c;txt格式 共计14244张图&#xff0c;99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别&#xff1a; allies enemy tag图片总量&#xff1a;7247张训练集&#xff1a;5139张验证集&#xff1a;1425张测试集&#xff1a;683张标注状态&#xff1a;全部已标注&#xff0c;即拿即用数据格式&#xff1a;支持YOLO格式及其他格式&#…

2026/7/29 15:00:03 阅读更多 →

月新闻