Linux设备驱动在系统关机时会调用哪个回调函数
核心结论
用户空间执行poweroff/shutdown命令触发系统关机流程时,你之前使用的struct dev_pm_ops中定义的suspend/resume系列回调不会被调用,设备驱动模型提供了专门的.shutdown回调用于响应关机、重启事件,外部模块形式的驱动也可以正常注册使用。
回调注册方式
- 设备驱动通用注册方法:无论驱动是编译进内核还是以外部模块加载,只需要在对应驱动的结构体中填充
.shutdown成员即可,内核在关机流程中会遍历所有已注册的设备,按设备拓扑顺序调用对应驱动的该回调。
参考代码示例:static void my_dev_shutdown(struct device *dev) { // 此处填写关机时需要执行的硬件复位、关键状态保存、资源清理逻辑 pr_info("my device: shutdown callback invoked\n"); } static struct dev_pm_ops my_dev_pm_ops = { .suspend = my_dev_suspend, .resume = my_dev_resume, // 原有挂起/恢复回调保持不变 }; static struct device_driver my_dev_driver = { .name = "my_dev", .bus = &platform_bus_type, // 根据设备实际挂载的总线类型修改 .shutdown = my_dev_shutdown, // 注册关机回调 .pm = &my_dev_pm_ops, }; - 子系统封装驱动适配:如果是平台驱动、PCI驱动、USB驱动等内核子系统已经封装好的驱动结构,对应结构中直接提供了同级的
.shutdown成员,比如struct platform_driver中,.shutdown和.probe、.remove是同级成员,直接填充后随驱动注册即可生效,不需要手动操作底层device_driver结构。 - 全局事件通知可选方案:如果你的逻辑不绑定具体硬件设备,需要响应全局关机/重启事件,可以调用
register_reboot_notifier()接口注册重启通知链回调,该回调会在设备.shutdown回调之前执行。但设备相关的逻辑优先使用设备自带的.shutdown回调,内核设备模型会保证子设备先于父设备执行回调,避免出现父设备提前下电导致子设备访问异常的问题。
场景区分注意
不要和其他驱动回调的触发场景混淆:
- 系统挂起到内存(suspend to RAM)、休眠到硬盘(hibernate)、恢复场景,走
struct dev_pm_ops中注册的suspend/resume相关回调 - 系统关机(poweroff/halt)、重启(reboot)场景,走
.shutdown回调 - 驱动手动卸载(执行
rmmod/modprobe -r)场景,走.remove回调,和关机流程独立,不要将必须的硬件清理逻辑只放在.remove回调中
外部模块开发注意事项
- 注册
.shutdown回调不需要额外的特殊操作,只要在驱动注册(如platform_driver_register()、driver_register())前完成回调填充,模块加载后回调就会自动被纳入内核关机调用链,行为和内置驱动完全一致。 .shutdown回调执行时,内核已经停止了大部分用户态进程和内核线程,内存分配、锁等待等操作很容易失败,回调逻辑要尽量精简,只做必须的硬件操作,不要执行耗时过长、依赖其他服务的逻辑。
内容的提问来源于stack exchange,提问作者fadhel
相关产品推荐
相关产品推荐

