news 2026/3/21 11:58:51

20251229 - 驱动程序是如何向Linux内核注册(Register)自己的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
20251229 - 驱动程序是如何向Linux内核注册(Register)自己的

驱动是如何向内核**注册(Register)**自己的?是 register_chrdev 还是 platform_driver_register?二者有什么区别?为什么有了register_chrdev还要有platform_driver_register?它们到底谁才是真正的“注册”?

答案是:它们都是注册,但注册的“对象”和“目的”完全不同。

简单来说:

  • platform_driver_register是为了找硬件(匹配设备树)。
  • register_chrdev是为了给用户提供接口(生成/dev/xxx)。

在现代 Linux 驱动开发中,通常是两者配合使用:先用 Platform 注册找到硬件,然后在找到硬件的回调函数(Probe)里,再进行字符设备注册。


学习笔记:Linux 驱动的两层注册机制

1. 核心区别概览

特性register_chrdev (字符设备注册)platform_driver_register (平台驱动注册)
所属层级接口层(Interface Layer)设备模型层(Device Model Layer)
核心目的告诉内核:“我是一个字符设备,我的操作函数是f_op告诉内核:“我就是这硬件的驱动,把符合名字的设备交给我”
面向谁?面向用户空间(APP)面向内核/硬件(Device Tree)
产出物主设备号、/dev/xxx节点(配合 class_create)触发probe函数的执行
必须性如果你想让 APP 操作,必须有 (或其变体cdev_add)不是必须的 (简单的驱动可以没有),但标准驱动都有

2. 深度解析:为什么要分两层?

第一层:platform_driver_register(我是谁?我去哪里上班?)

这是 Linux“总线-设备-驱动” (Bus-Device-Driver)模型的一部分。

  • 背景:

    在设备树(Device Tree)引入之前,驱动代码里写死了硬件地址(比如 0x020E0068)。

    现在,硬件信息都写在设备树 (.dts) 里,驱动代码里不再写死地址。

  • 作用:

    platform_driver_register 的作用就是**“相亲”**。

    • 设备树说:“我有一个硬件,名字叫my-led。”
    • 驱动代码说:“我是一个驱动,我能支持名字叫my-led的硬件。”
    • 内核:把两者撮合在一起。一旦名字匹配成功,内核就会调用驱动里的probe(探测)函数。

第二层:register_chrdev(我能干什么?)

这是我们之前讲过的字符设备功能注册

  • 作用:

    不管你是怎么找到硬件的,最终你都得让 APP 能控制它。

    register_chrdev 就是去申请一个主设备号,并挂载 file_operations,让 APP 可以通过 open/read/write 来操作。


3. 它们是如何配合工作的? (标准模板)

在现代驱动中,这套流程是固定的“套娃”模式:

  1. 模块入口 (module_init):只做一件事,调用platform_driver_register
  2. 匹配成功:内核发现设备树有对应节点,自动调用驱动的probe函数。
  3. Probe 函数这里才是真正干活的地方!
    • 获取硬件资源(读设备树里的寄存器地址、中断号)。
    • 调用register_chrdev(或者是现代的alloc_chrdev_region+cdev_add)。
    • 创建设备节点 (class_create,device_create)。

代码骨架(可以背下来这个结构!)

/* 1. 定义字符设备的操作函数 (给 APP 用的) */ static struct file_operations my_fops = { .owner = THIS_MODULE, .write = my_write, .open = my_open, }; /* 2. probe 函数:当驱动和设备树匹配成功时,内核自动调用 */ static int my_probe(struct platform_device *pdev) { printk("硬件匹配成功!开始初始化...\n"); // A. 获取硬件资源 (从设备树拿) // ... // B. 注册字符设备 (核心关联点!!!) // 只有到了这一步,APP 才能看到 /dev/xxx major = register_chrdev(0, "my_device", &my_fops); // C. 创建设备节点 // class_create(...); // device_create(...); return 0; } /* 3. remove 函数:卸载驱动或设备移除时调用 */ static int my_remove(struct platform_device *pdev) { // 注销字符设备 unregister_chrdev(major, "my_device"); return 0; } /* 4. 定义 Platform 驱动结构体 */ static const struct of_device_id my_match_table[] = { { .compatible = "100ask,led" }, // 这里的名字必须和设备树里的一样! { }, }; static struct platform_driver my_driver = { .probe = my_probe, // 匹配成功调这个 .remove = my_remove, // 移除时调这个 .driver = { .name = "my_led_driver", .of_match_table = my_match_table, // 指定匹配表 }, }; /* 5. 模块入口:只负责注册 Platform 驱动 */ static int __init my_driver_init(void) { // 向内核注册在这个 Platform 驱动 return platform_driver_register(&my_driver); } static void __exit my_driver_exit(void) { platform_driver_unregister(&my_driver); } module_init(my_driver_init); module_exit(my_driver_exit); module_license("GPL");

4. 图解流程

  1. insmod→ \rightarrow执行module_init
  2. platform_driver_register→ \rightarrow把驱动名字放入“相亲角”。
  3. Kernel Check→ \rightarrow发现设备树里也有个叫"100ask,led"的硬件。
  4. Match!→ \rightarrow触发my_probe函数。
  5. Inside Probe→ \rightarrow执行register_chrdev
  6. Result→ \rightarrow生成/dev/led,APP 可以使用了。

5. 常见疑惑解答

Q1: 我可以不用platform_driver_register,只写register_chrdev吗?

  • 可以。这就是所谓的“老式驱动”或“非设备树驱动”。
  • 后果:你必须在代码里硬编码寄存器物理地址(比如0x20200000)。这导致你的驱动只能在这个特定的板子上跑,换个板子(地址变了)就得改代码重新编译。
  • 现状:为了代码通用性,现在几乎都用 Platform 模式。

Q2: 我可以不用register_chrdev,只写platform_driver_register吗?

  • 不可以(除非你是做 LED 子系统、输入子系统这种高级开发)。
  • 如果你不注册字符设备,你就没有主设备号,没有/dev/xxx节点,APP 根本没办法通过文件操作来访问你的驱动。
  • platform_driver只是帮你管理硬件资源,它不负责给 APP 提供接口。

6. 总结

  • platform_driver_register:是管理层。负责让驱动程序和设备树里的硬件描述**“对上号”**。它让驱动更灵活、更通用。
  • register_chrdev:是业务层。负责实打实地生成用户接口
  • 关系:通常在platform_driverprobe函数中,去调用register_chrdev前者是壳,后者是核。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 8:33:57

告别论文焦虑,拥抱高效写作:百考通AI助手,你的专属学术智囊团

还在为毕业论文的选题、框架和内容绞尽脑汁吗?面对堆积如山的文献和复杂的开题报告,是否感到无从下手?别担心,你并不孤单。在信息爆炸的时代,每一位学子都渴望一个能真正理解需求、提供精准支持的智能伙伴。今天&#…

作者头像 李华
网站建设 2026/3/17 8:32:03

在线学习交流系统学习资料视频签到python-vue没论文

目录已开发项目效果实现截图关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!已开发项目效果实现截图 同行可拿货,招校园代理 ,本人源头供货商 在线学习交流系统学习资料视频签到py…

作者头像 李华
网站建设 2026/3/13 16:18:58

Anaconda配置自动激活特定PyTorch环境

Anaconda配置自动激活特定PyTorch环境 在深度学习项目开发中,一个常见的痛点是:每次打开终端或连接远程服务器时,总要重复执行 conda activate myenv,稍有不慎就在错误的环境中运行代码,导致“明明昨天还能跑&#xf…

作者头像 李华
网站建设 2026/3/20 4:23:42

PyTorch梯度裁剪Gradient Clipping防止爆炸

PyTorch梯度裁剪:防止训练崩溃的实用策略 在深度学习的实际训练中,模型“突然炸了”——损失值飙升到无穷大、参数变成 NaN、训练彻底失控——这种经历相信不少人都遇到过。尤其当你花了几个小时加载数据、配置环境、启动训练后,却发现第10个…

作者头像 李华