You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux块设备驱动开发:无probe获取struct device及Regulator内核Oops问题

解决devm_regulator_get触发内核Oops的问题,以及块设备改造思路

首先得明确你遇到的核心问题:手动vmalloc的struct device没有正确接入内核设备模型,而devm_regulator_get这类devm系列函数严重依赖设备模型的资源管理机制,这才导致了Oops。

为什么会触发Oops?

devm(device resource management)系列函数是基于设备的生命周期来管理资源的,它需要设备结构体(struct device)已经被正确初始化并加入到内核的设备树/总线体系中。你直接用vmalloc分配的device,既没有设置正确的父设备、总线类型,也没有调用device_initialize()和device_add()把它注册到设备模型里,devm的资源链表根本没建立,regulator子系统查找电源时自然会访问非法指针,触发Oops。

正确的解决思路(推荐复用Platform框架)

既然之前的字符设备是基于platform_device做的,完全没必要抛弃probe函数——反而应该复用platform框架来完成块设备的初始化,这才是符合Linux驱动规范的做法:

  1. 回归platform_driver的probe函数
    把原来手动初始化GPIO、Regulator的逻辑移回probe里,这里的struct device *dev是platform_device自带的、已经正确注册到设备模型的指针,调用devm_regulator_get(dev, "power")(假设你的regulator在设备树里的名字是power)就不会有问题了。

  2. 在probe中注册块设备
    块设备的注册流程可以嵌入到probe函数里,大致步骤:

    • 调用register_blkdev()注册块设备号
    • 分配gendisk结构体(用alloc_disk())
    • 设置gendisk的major、first_minor、fops、queue等字段
    • 绑定你的硬件操作逻辑(比如原来字符设备里的Clock/Data/Power引脚控制、私有协议读写)到块设备的request函数或者直接的读写回调
    • 调用add_disk()把gendisk加入系统
  3. 迁移原有逻辑到块设备接口
    你原来的字符设备是处理字节流,而块设备是按扇区(通常512字节)来操作的,需要把私有协议里的文件拆分存储逻辑,映射到扇区的读写请求上。比如:

    • 当块设备收到读扇区请求时,通过私有协议读取对应位置的数据,填充到请求的buffer里
    • 写请求则把buffer里的扇区数据,通过私有协议写入硬件存储

如果非要手动初始化设备(不推荐)

如果你坚持不用probe,那必须把手动分配的device正确接入设备模型:

  • 调用device_initialize(&your_dev)初始化设备
  • 设置your_dev.parent为一个合法的父设备(比如sysfs里的某个总线节点,或者设备树里的父节点设备)
  • 设置your_dev.bus为对应的总线类型(比如&platform_bus_type)
  • 调用device_add(&your_dev)把设备注册到系统
  • 之后再调用devm_regulator_get(&your_dev, ...)才可能正常工作

但这种方式非常繁琐,容易引入其他设备模型相关的问题,完全没必要——复用platform框架是更稳妥、更符合Linux驱动设计理念的选择。

内容的提问来源于stack exchange,提问作者Arkaik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 10:05:28