__devexit_p的功能

__devexit_p是在Linux内核中用于标记可以在链接时被丢弃的设备退出函数的一个宏。该宏根据内核配置选项返回函数地址或NULL,确保在不支持模块和热插拔的环境中函数不会被误引用。

__devexit_p的功能

在看i2c驱动的时候,看到有如下代码:
.remove     = __devexit_p(i2c_gpio_remove),

这里的__devexit_p有什么作用呢?
include/linux/init.h中找到了它的定义:

/* Functions marked as __devexit may be discarded at kernel link time, depending
   on config options.  Newer versions of binutils detect references from
   retained sections to discarded sections and flag an error.  Pointers to
   __devexit functions must use __devexit_p(function_name), the wrapper will
   insert either the function_name or NULL, depending on the config options.
 */

#if defined(MODULE) || defined(CONFIG_HOTPLUG)
#define __devexit_p(x) x
#else
#define __devexit_p(x) NULL
#endif

 

意义是内核可能在不支持模块且不支持热插拔的时候,需要对 __devexit_p返回NULL。

 

<think>我们正在分析一个Linux内核模块中的`struct platform_driver`结构体定义,这是平台设备驱动的核心结构。用户希望理解这个结构体的各个字段(特别是probe、remove、suspend、resume和driver)的作用和语法,适用于Linux内核模块开发。 根据引用[1]和[2],我们可以得到以下信息: - `platform_driver`的注册需要填充这个结构体,然后调用`platform_driver_register()`。 - 它包含一个内嵌的`device_driver`结构体(即`driver`字段),其中又包含`of_match_table`等字段。 - 当驱动与设备匹配时,会调用`probe`函数;设备移除时调用`remove`函数;电源管理相关操作会调用`suspend`和`resume`。 现在,我们详细解释每个字段: 1. **probe函数**(类型为`int (*probe)(struct platform_device *)`): - 作用:当平台设备与驱动匹配成功时,由内核调用。它负责初始化设备,包括申请资源(内存、I/O、中断等)、初始化硬件、注册设备接口(如字符设备、sysfs节点)等。 - 语法示例: ```c static int my_probe(struct platform_device *pdev) { // 从pdev获取资源,初始化设备 return 0; // 成功返回0,失败返回负的错误码 } ``` 2. **remove函数**(类型为`int (*remove)(struct platform_device *)`): - 作用:当设备被移除(例如模块卸载或热拔插)时调用,负责释放资源,注销设备,与probe的操作相反。 - 语法示例: ```c static int my_remove(struct platform_device *pdev) { // 释放资源,注销设备 return 0; } ``` 3. **suspend和resume函数**(电源管理): - 作用:在系统进入休眠状态时,内核会调用驱动的`suspend`函数,使设备进入低功耗状态;在系统唤醒时,调用`resume`函数恢复设备状态。 - 语法示例: ```c static int my_suspend(struct device *dev) { // 保存状态,关闭设备或降低功耗 return 0; } static int my_resume(struct device *dev) { // 恢复设备到正常工作状态 return 0; } ``` 注意:在较新的内核中,电源管理通常通过`dev_pm_ops`结构体来定义一组更丰富的操作,然后将其赋值给`driver.pm`字段。但也可以直接使用`suspend`和`resume`字段(较少用)。 4. **driver字段**(类型为`struct device_driver`): - 这是一个内嵌结构体,包含驱动的基本信息: - `name`:驱动的名称,用于匹配设备(如果设备是通过名称匹配而非设备树)。 - `owner`:通常为`THIS_MODULE`,表示拥有该驱动的模块。 - `of_match_table`:指向`of_device_id`数组的指针,用于设备树匹配(通过compatible属性)。 - `pm`:指向`dev_pm_ops`结构体的指针,包含电源管理相关函数(如suspend, resume, freeze, thaw等)。 - 语法示例: ```c static const struct of_device_id my_of_match[] = { { .compatible = "vendor,my-device" }, {} }; static struct platform_driver my_driver = { .probe = my_probe, .remove = my_remove, .driver = { .name = "my_driver", .owner = THIS_MODULE, .of_match_table = my_of_match, .pm = &my_pm_ops, // 电源管理操作集 }, }; ``` 注意:在较新的内核中,`remove`函数可能被替换为`remove_new`或使用`__devexit`宏(已废弃),但基本概念不变。 完整示例: ```c #include <linux/module.h> #include <linux/platform_device.h> static int my_probe(struct platform_device *pdev) { // 初始化设备 return 0; } static int my_remove(struct platform_device *pdev) { // 清理设备 return 0; } static const struct of_device_id my_of_match[] = { { .compatible = "vendor,my-device" }, {} }; MODULE_DEVICE_TABLE(of, my_of_match); static struct platform_driver my_driver = { .probe = my_probe, .remove = my_remove, .driver = { .name = "my_driver", .owner = THIS_MODULE, .of_match_table = my_of_match, }, }; module_platform_driver(my_driver); ``` 这个结构体定义后,通过`module_platform_driver`宏注册,简化了模块的初始化和退出操作。 总结: - `probe`:设备匹配时初始化设备。 - `remove`:设备移除时清理资源。 - `suspend/resume`:电源管理回调(现在更常用`dev_pm_ops`结构体,通过`driver.pm`设置)。 - `driver`:包含驱动的基本信息,如名称、模块所有者、设备树匹配表等。 相关问题: 1. 在probe函数中如何获取设备树中的资源(如GPIO、时钟)? 2. 为什么在probe函数中有时需要延迟部分硬件初始化? 3. 平台设备驱动与传统字符设备驱动在架构上有何不同? 4. 如何调试probe函数未被调用的问题? 5. 在多设备系统中,如何确保平台驱动正确管理多个设备实例?</think>### `struct platform_driver` 结构体详解(Linux 内核模块开发) 在 Linux 内核驱动开发中,`struct platform_driver` 是**平台设备驱动**的核心结构体,用于实现硬件无关的驱动模型。以下是其完整定义和关键字段解析(基于 Linux 5.x 内核): ```c struct platform_driver { int (*probe)(struct platform_device *); // 设备探测函数 int (*remove)(struct platform_device *); // 设备移除函数 void (*shutdown)(struct platform_device *); // 设备关闭函数 int (*suspend)(struct platform_device *, pm_message_t); // 休眠函数 int (*resume)(struct platform_device *); // 唤醒函数 struct device_driver driver; // 内嵌的通用驱动结构 }; ``` --- ### 核心字段作用与语法 #### 1. **`.probe` 函数** **作用**:当驱动与设备匹配成功时,由内核自动调用,负责设备初始化[^1][^3]。 **语法**: ```c int (*probe)(struct platform_device *pdev); ``` **典型操作**: ```c static int my_probe(struct platform_device *pdev) { // 1. 获取设备资源(GPIO/时钟等) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 2. 初始化硬件(寄存器配置、电源管理) enable_sensor_clock(); // 3. 注册设备接口(字符设备/V4L2等) misc_register(&my_miscdev); return 0; // 成功返回0,失败返回负错误码 } ``` #### 2. **`.remove` 函数** **作用**:设备移除或驱动卸载时调用,释放资源[^1][^3]。 **语法**: ```c int (*remove)(struct platform_device *pdev); ``` **典型操作**: ```c static int my_remove(struct platform_device *pdev) { // 1. 注销设备接口 misc_deregister(&my_miscdev); // 2. 释放资源(内存/中断等) release_mem_region(res->start, resource_size(res)); return 0; } ``` #### 3. **`.suspend`/`.resume` 函数** **作用**:实现电源管理,分别对应设备休眠和唤醒时的操作[^2]。 **语法**: ```c int (*suspend)(struct platform_device *pdev, pm_message_t state); int (*resume)(struct platform_device *pdev); ``` **典型场景**: ```c static int my_suspend(struct platform_device *pdev, pm_message_t state) { // 关闭传感器电源,保存状态 power_off_sensor(); return 0; } static int my_resume(struct platform_device *pdev) { // 恢复电源,重新初始化 power_on_sensor(); init_sensor_registers(); return 0; } ``` #### 4. **`.driver` 内嵌结构体** **作用**:定义驱动元数据(名称、所有者、匹配规则等)[^1][^2]。 **关键子字段**: ```c struct device_driver { const char *name; // 驱动名称(用于匹配设备) struct module *owner; // 模块所有者(通常为THIS_MODULE) const struct of_device_id *of_match_table; // 设备树匹配表 const struct dev_pm_ops *pm; // 高级电源管理接口 }; ``` **配置示例**: ```c static const struct of_device_id my_of_match[] = { { .compatible = "vendor,sensor-123" }, // 匹配设备树节点 {} }; static struct platform_driver my_driver = { .driver = { .name = "my_sensor_drv", // /sys/bus/platform/drivers/下的名称 .owner = THIS_MODULE, // 防止模块卸载时设备仍在使用 .of_match_table = my_of_match,// 设备树匹配规则 }, .probe = my_probe, .remove = my_remove, }; ``` --- ### 驱动注册流程 通过宏简化注册(推荐方式): ```c module_platform_driver(my_driver); // 自动生成 init/exit 函数 ``` 等效于: ```c static int __init my_driver_init(void) { 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); ``` --- ### 设计优势 1. **硬件抽象** 通过 `.of_match_table` 实现设备树绑定,同一驱动适配不同硬件[^1]。 2. **生命周期管理** `probe`/`remove` 确保资源按需分配,避免无效初始化[^3]。 3. **标准化电源管理** 支持休眠/唤醒回调,与内核电源子系统集成[^2]。 --- ### 典型驱动结构示例 ```mermaid graph LR A[module_platform_driver注册] --> B[.driver定义匹配规则] B --> C{设备树匹配成功?} C -- 是 --> D[调用.probe初始化] C -- 否 --> E[等待设备出现] D --> F[注册字符设备/V4L2等] F --> G[运行中...] G -- 休眠事件 --> H[调用.suspend] H -- 唤醒事件 --> I[调用.resume] G -- 卸载模块 --> J[调用.remove释放资源] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值