如何编写i2c字符设备驱动并修改引导硬件驱动,有哪些步骤?

为什么引导阶段要动i2c设备驱动

嵌入式Linux开发中,修改引导阶段的硬件设备驱动往往不是改一个probe函数那么简单,真正卡住大家的,是字符设备节点注册时机和i2c核心框架的初始化顺序。 早年调试一块传感器板子时,我在/dev/i2c-2上反复open失败,折腾半天才发现驱动在引导阶段还没注册进i2c总线,应用层根本摸不到设备,如果你的板子在uboot引导完、内核起来后需要立即用某个i2c外设,比如触摸屏、电源管理芯片或陀螺仪,那你面对的就是同一类问题。

行业共识认为,引导阶段涉及的外设驱动修改,核心矛盾在于内核子系统初始化顺序和应用层访问需求之间的错位,i2c设备的字符设备驱动,本质上是把内核i2c核心框架里的设备操作暴露成/dev节点,要在引导阶段就让这个节点可用,必须搞清楚i2c适配器注册、设备驱动probe、以及miscdevice或cdev注册这三者的时序关系。

linux驱动系列学习之i2c子系统教程
加载中
linux驱动系列学习之i2c子系统教程

i2c设备驱动与字符设备驱动注册流程差异

很多人搞混一个概念:i2c设备驱动和字符设备驱动是两套注册逻辑,但它们最终会在/dev节点上汇合。 i2c设备驱动走i2c_add_driver注册到i2c总线,由内核匹配设备树里的compatible属性后触发probe,字符设备驱动走alloc_chrdev_region和cdev_add,依赖设备号,引导阶段要修改的,往往是让i2c设备在probe后立刻创建对应的字符设备节点。

标准流程下的两个阶段

内核正常启动时,i2c适配器(i2c controller)先注册到i2c核心,然后挂载在适配器上的设备由i2c_driver完成匹配,这套流程在系统启动早期就会执行,但字符设备节点的生成通常依赖udev或mdev,在initramfs阶段可能尚未运行。

阶段 i2c设备驱动动作 字符设备动作 引导期可达性
内核早期 注册i2c_driver,等待匹配 尚未创建设备节点 不可访问
devtmpfs挂载后 probe执行,寄存器初始化 可通过devtmpfs自动创建设备节点 基本可达
用户态启动后 设备已就绪 应用层可直接open 完全可达

引导阶段修改的关键,就是把字符设备节点的创建时机从依赖用户态udev,

如何编写i2c字符设备驱动并修改引导硬件驱动,有哪些步骤?

提前到驱动的probe内部完成。

为什么字符设备比i2c协议层更好用

i2c设备驱动里直接写i2c_smbus_read_byte_data操作硬件很顺手,但应用层没法直接调用内核函数,字符设备驱动封装了file_operations接口,用户态通过read/write/ioctl就能操作设备,引导阶段做系统初始化时,要先用字符设备把硬件调通,后面再做协议封装就顺理成章。

修改引导阶段的i2c字符设备驱动实操步骤

这套修改思路我在imx6和stm32mp1平台上都验证过,核心思路是:在i2c_driver的probe回调里直接注册字符设备,不依赖用户态事件。

第一步:确认设备树中的i2c外设状态

先看设备树里外设节点是否使能,如果节点状态是disabled,引导阶段i2c适配器扫描不到设备,驱动永远不会probe。

&i2c2 {
    status = "okay";
    touch: touch@38 {
        compatible = "myvendor,touch";
        reg = <0x38>;
        interrupt-parent = <&gpio1>;
        interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
    };
};

确保status = "okay",reg地址与硬件实际的i2c从机地址一致,这一步出错,引导阶段设备就直接消失了。

第二步:在probe中动态创建设备节点

这是修改的核心,在struct i2c_driver的probe函数里,调用class_create和device_create生成/dev/my_i2c_dev节点,这样绕开了udev,只要内核的devtmpfs挂载,节点就自动出现在文件系统里。

static int my_i2c_probe(struct i2c_client client,
                        const struct i2c_device_id id)
{
    struct my_dev dev;
    dev = devm_kzalloc(&client->dev, sizeof(dev), GFP_KERNEL);
    dev->major = register_chrdev(0, "my_i2c_dev", &my_fops);
    dev->cls = class_create(THIS_MODULE, "my_i2c_class");
    device_create(dev->cls, NULL, MKDEV(dev->major, 0),
                  NULL, "my_i2c_dev");
    i2c_set_clientdata(client, dev);
    return 0;
}

引导阶段的内核日志里,你能看到my_i2c_dev节点在i2c-2 adapter注册之后出现,而不再是系统启动很久后被用户态mdev补建。

第三步:调整注册时机

如果节点出来了,但上电太快设备ready标志还没拉高,可以把

如何编写i2c字符设备驱动并修改引导硬件驱动,有哪些步骤?

probe里的硬件初始化拆成两部分:一部分只读寄存器确认设备在线,另一部分通过schedule_delayed_work延时到引导阶段后期做完整配置,这样既保证了引导阶段驱动能加载,又不跟设备上电时序打架。

第四步:验证字符设备可见性

在内核启动参数里加initcall_debug,能清楚看到i2c驱动注册的调用顺序,用udevadm info查看设备属性,或者直接在引导阶段的initramfs shell里执行:

ls -l /dev/my_i2c_dev
hexdump -C /dev/my_i2c_dev

如果第二步做对了,这两个命令能看到设备节点和原始寄存器值,说明字符设备驱动在引导阶段已经生效。

引导阶段修改的坑和解决思路

设备节点优先级问题

devtmpfs在挂载根文件系统之前可能没有执行权限规则,导致节点有了但权限不对,在device_create里指定devnode回调,强制设置为0660或0666,解决权限不一致的问题。

i2c总线号漂移

引导阶段如果有多个i2c控制器,总线号可能在每次启动时变化,在设备节点里增加alias属性,或者在驱动里通过of_find_i2c_adapter_by_node绑定固定的device_node,这一点在修改引导设备驱动时特别容易忽略,一旦总线号漂移,字符设备节点对应到错误的适配器上。

寄存器初始化冲突

有些i2c外设芯片的复位逻辑在引导阶段会被bootloader操作过一遍,内核驱动probe时如果重复复位,寄存器状态反而乱了,在驱动里加一个判断:如果芯片ID寄存器已经是预期值,跳过复位流程,这是修改引导设备驱动时最需要仔细的细节。

i2c设备驱动修改后如何验证引导影响

验证修改是否成功,不能只盯着字符设备节点,业内专家指出,引导阶段的设备驱动改动必须做双重确认:设备树匹配成功 + 应用层真实读写成功。

一个快速有效的方法是写一个小的initramfs脚本,在系统init进程启动前完成i2c设备自检:

#!/bin/sh
mount -t devtmpfs devtmpfs /dev
if [ -e /dev/my_i2c_dev ]; then
    echo "I2C device ready in early boot"
    # 读取设备的版本寄存器做自检
    i2cget -y 2 0x38 0x00
else
    echo "I2C device NOT ready"
    exit 1
fi

把这个脚本放进initramfs的init脚本靠前位置,就能在引导阶段真实检验驱动修改是否满足了硬件设备的需求。

如何编写i2c字符设备驱动并修改引导硬件驱动,有哪些步骤?

i2c设备驱动与字符设备驱动的适配关系

很多从事驱动开发的朋友经常在选型时纠结:既然i2c设备驱动已经很成熟了,为什么还要额外包一层字符设备驱动?在引导阶段这个场景下,答案很明确:i2c设备驱动不直接面向应用层,它解决的是内核里谁匹配谁的问题;字符设备驱动解决的是用户态怎么操作设备的问题。

引导阶段想通过简单的shell脚本操作外设,就必须有字符设备节点,修改引导的硬件设备驱动,本质上是把i2c设备驱动里能做的事,提前在字符设备驱动里曝光出来。

固定一个优先级判断:i2c设备驱动负责跟硬件沟通,字符设备驱动负责跟用户态沟通。 两者之间通过container_of和i2c_get_clientdata互相索引,在修改引导阶段的驱动时,这个索引关系要保证在内核的device_register和bus_add_driver之间完整建立。

常见问题与排查方法

为什么probe执行了但/dev节点不存在

可能是字符设备的device_create用了错误的父设备,检查device_create的parent参数是否传了&client->dev,如果传NULL,devtmpfs无法把它关联到i2c总线上,节点即使创建了也会被udev规则清理掉。

引导阶段二次probe导致资源冲突

如果驱动同时注册到了i2c核心和设备树中,可能触发两次probe,检查.id_table和of_match_table是否重复匹配了同一个设备,多数情况下,删掉其中一种匹配方式就能解决。

内核版本之间的API差异

Linux 6.x移除了部分老版本字符设备接口,如果你在移植旧驱动,register_chrdev仍然可用,但它分配的是静态设备号范围,更推荐用alloc_chrdev_region配合cdev_add,避免引导阶段设备号冲突,具体差异可以参考内核文档Documentation/driver-api/driver-model/下的说明。

Q&A模块中另一个典型问题是:修改i2c设备驱动后没有重新编译整个内核,只生成了.ko模块,引导阶段怎么加载?答案就是检查initramfs里是否包含了该模块,或者将模块用modprobe预加载到initramfs中,第三个问题关于i2c设备驱动如何添加调试打印,建议用dev_info和dev_err配合dynamic_debug控制,不要在内核配置里打开所有调试宏,引导阶段日志量越大,越难定位问题点。

首发原创文章,作者:王坚‌,如若转载,请注明出处:https://test.idctop.com/article/580920.html

赞 (0)
我的世界温布的服务器号码是多少
上一篇 2026年8月18日 20:44
服务器16G能承受多少人游戏?,服务器内存怎么选
下一篇 2026年8月18日 20:45

相关推荐

  • 服务器出现错误时该如何解决,常见原因有哪些

    服务器error是网站运维中最常见的故障信号,绝大多数情况下都能通过日志分析、资源监控和配置优化快速定位并解决,服务器error 500怎么解决?从日志到配置的完整排查服务器error 500表示内部服务器错误,是一个通用状态码,意味着服务器遇到了意外条件,无法完成请求,排查时,日志是突破口,日志分析是第一步N……

    2026年7月28日
    600
  • IP地址和域名的作用是什么?,短信应用怎么用?

    IP地址是互联网设备的唯一身份标识,域名是IP地址的易记名称,二者共同构成网络寻址的基础;短信应用则是移动通信中直达用户的高效信息通道,主要用于身份验证、通知提醒和营销互动,无论你是在浏览器里敲下“www.baidu.com”,还是手机“叮”一声收到一条验证码,背后都离不开这些基础技术的支撑,它们就像城市的门牌……

    2026年8月10日
    400
  • IE状态栏的隐藏方法有哪些,具体怎么设置

    隐藏IE状态栏的方法很简单,直接右键点击IE工具栏空白处,取消勾选“状态栏”即可,或者通过“查看”菜单找到“状态栏”选项取消勾选,如果你希望彻底隐藏或通过系统级设置实现,本文会提供完整步骤和高级技巧,为什么要隐藏IE状态栏?这些场景你肯定遇到过状态栏是IE浏览器底部那条显示链接地址、加载进度、安全区域等信息的窄……

    2026年8月4日
    2200
  • 什么是服务器客户端架构?服务器与客户端架构详解

    服务器与客户端的架构本质是“请求-响应”的协作模式,前者负责处理数据与逻辑,后者负责展示与交互,二者通过标准化的网络协议连接,共同构成现代互联网应用的基石,想象一下,你正在一家繁忙的餐厅用餐,客户端就是你手中的菜单和餐桌,负责展示菜品(界面)并记录你的点单(输入);服务器则是后厨,负责接收订单、烹饪食物(处理逻……

    2026年7月4日
    11810
  • 如何获取IdeaHub定制类型,有哪些类型?

    获取IdeaHub定制类型,本质是通过设备系统信息或查询接口确认当前设备所属的行业定制版本,从而匹配对应的功能与服务,如何获取IdeaHub定制类型?获取定制类型的方式有几种,从简单到专业,你可以根据自身条件选择,通过设备界面直接查看这是最直接的方法,在IdeaHub主屏幕,按以下路径操作:进入 设置 或 系统……

    2026年8月20日
    300
  • 分页查询怎么做?mysql分页查询优化

    分页查询(Pagination)是数据库开发和 Web 应用中非常常见的功能,用于将大量数据分割成较小的页面,以提高加载速度和用户体验,以下是关于分页查询的详细介绍,包括原理、常见实现方式、优缺点对比以及最佳实践,为什么需要分页?性能优化:一次性加载成千上万条数据会消耗大量内存和带宽,导致响应缓慢甚至服务器崩溃……

    2026年7月12日
    5710
  • ai大模型迭代速度有多快?大模型迭代周期是多久

    AI大模型迭代速度已从“月更”加速至“周更”甚至“日更”,企业需建立敏捷的模型评估与部署流程,以应对技术半衰期缩短带来的挑战,迭代加速背后的技术驱动力过去两年,大模型的发展轨迹呈现出明显的指数级增长特征,这种变化并非偶然,而是底层架构优化、算力提升与数据策略调整共同作用的结果,业内专家指出,这种加速趋势正在重塑……

    2026年6月15日
    3200
  • 服务器客户端如何连接数据库?连接数据库服务器失败怎么解决

    服务器、客户端与数据库服务器的连接,本质上是建立一条安全、高效且稳定的数据通信通道,其核心在于正确配置网络协议、身份认证机制及防火墙规则,确保数据能在三者间无损传输,在现代IT架构中,这三者的关系就像一家繁忙餐厅的运作模式,客户端是顾客,提出点单需求;服务器是前台和服务员,负责接收需求并协调;数据库服务器则是后……

    2026年7月4日
    17500
  • in域名支持注册的域名有哪些?,怎么注册

    .in域名是印度国家顶级域名,目前全球范围内支持个人注册,无需印度本地实体,但注册后需通过审核且部分词汇受限,如果你正在考虑注册.in域名,需要了解注册条件、价格、备案情况以及适用场景,才能做出合适选择,什么是.in域名?.in域名是印度(India)的国家顶级域名,由印度国家互联网交换中心(NIXI)管理,自……

    2026年8月4日
    4400
  • IIS服务器如何设置301定向,网页自动跳转代码怎么写?

    IIS服务器做301定向的方法主要有三种:使用IIS自带的HTTP重定向功能、配置web.config文件、或安装URL Rewrite模块,其中最简单直接的是在IIS管理器中开启“HTTP重定向”,这三种方式都能将旧网址永久跳转到新网址,同时把搜索引擎权重完整传递过去,避免网站改版或域名更换导致的流量流失,I……

    2026年8月8日
    800

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注