内核ACPI函数API之acpi_get_table

本文详细介绍了acpi_get_table函数的使用方法及源码分析,该函数用于在系统中查找并返回指定签名的ACPI表。文章通过示例展示了如何通过特定签名(如LPIT)获取ACPI表,并解释了函数内部实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

acpi_get_table(char *signature,
	       u32 instance, struct acpi_table_header ** out_table)
这个函数用于获取指定名称的acpi 表
其用法如下:
	struct acpi_table_lpit *lpit;
	#通过形参ACPI_SIG_LPIT 指定要当前要读取的acpi表示#define ACPI_SIG_LPIT           "LPIT"	/* Low Power Idle Table */当前要读取的表示LPIT,最后会将表头指针保存在形参lpit中

	status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit);

	if (ACPI_FAILURE(status))
		return;

其源码分析如下:
acpi_status
acpi_get_table(char *signature,
	       u32 instance, struct acpi_table_header ** out_table)
{
	u32 i;
	u32 j;
	acpi_status status = AE_NOT_FOUND;
	struct acpi_table_desc *table_desc;

	/* Parameter validation */
	#要读取acpi表的表头和最后保存表头的指针不能同时为null,否则就没啥意义
	if (!signature || !out_table) {
		return (AE_BAD_PARAMETER);
	}

	/*
	 * Note that the following line is required by some OSPMs, they only
	 * check if the returned table is NULL instead of the returned status
	 * to determined if this function is succeeded.
	 */
	 #指针值清零
	*out_table = NULL;

	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);

	/* Walk the root table list */
	#遍历acpi表,从这里可以知道所有的acpi表都是保存在acpi_gbl_root_table_list 中
	for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
	     i++) {
		table_desc = &acpi_gbl_root_table_list.tables[i];
		#这里的signature 就说表的名字,这里就是通过比较是否名字是否相等
		if (!ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
			continue;
		}
		#可以看到可以存在同名的表,例如可以同时存在两个name为LPIT的表,我可以指定读取第几个
		if (++j < instance) {
			continue;
		}
		#获得这个表头指针,将结果保存在out_table中
		status = acpi_tb_get_table(table_desc, out_table);
		break;
	}

	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
	return (status);
}

acpi_tb_get_table 的实现如下:
acpi_tb_get_table(struct acpi_table_desc *table_desc,
		  struct acpi_table_header **out_table)
{
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_tb_get_table);
	#检查这个表是否有效
	if (table_desc->validation_count == 0) {

		/* Table need to be "VALIDATED" */

		status = acpi_tb_validate_table(table_desc);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
		table_desc->validation_count++;

		/*
		 * Detect validation_count overflows to ensure that the warning
		 * message will only be printed once.
		 */
		if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
			ACPI_WARNING((AE_INFO,
				      "Table %p, Validation count overflows\n",
				      table_desc));
		}
	}
	保存这个表的指针
	*out_table = table_desc->pointer;
	return_ACPI_STATUS(AE_OK);
}

<think>我们已经在之前讨论过devm_request_threaded_irq,现在用户询问的是platform_get_irq函数,这是一个与设备树相关的中断获取函数。根据引用,我们知道它在设备驱动开发中用于从platform_device中获取中断资源。下面我将详细解释这个函数。###platform_get_irq函数详解`platform_get_irq`是Linux内核中用于从`platform_device`获取中断号(IRQnumber)的函数。它在设备驱动探测(probe)阶段被调用,用于将设备树(DeviceTree)或ACPI表中描述的中断资源转换为内核可用的中断号。####函数原型```cintplatform_get_irq(structplatform_device*dev,unsignedintnum);```参数说明:1.`structplatform_device*dev`:指向`platform_device`的指针,通常由驱动探测函数传入。2.`unsignedintnum`:要获取的中断资源的索引号(从0开始)。因为一个设备可能有多个中断源,索引表示第几个中断资源。返回值:-成功:返回非负整数的中断号(IRQnumber)。-失败:返回一个负的错误码(如`-ENXIO`表示索引超出中断资源范围)[^2]。####使用场景通常在驱动程序的`probe`函数中调用,用于获取设备树中定义的中断号。例如:```cstaticintmy_driver_probe(structplatform_device*pdev){intirq=platform_get_irq(pdev,0);if(irq<0){dev_err(&pdev->dev,"获取中断失败:%d\n",irq);returnirq;//直接返回错误码}//注册中断处理函数(如使用devm_request_threaded_irq)...}```####工作原理根据引用[^3],内核在启动过程中解析设备树(DTB)并创建`platform_device`结构时,会将每个设备的`interrupts`属性转化为内核中断号:1.设备树节点中定义的中断资源,通过`of_irq_get()`函数映射为IRQnumber。2.这些中断号被存储在`platform_device`的`resource`数组中。3.`platform_get_irq()`本质上是从`resource`数组的`IORESOURCE_IRQ`类型资源中读取对应索引的中断号[^2][^3]。例如,设备树节点:```dtsmy_device{compatible="vendor,my-device";interrupts=<3IRQ_TYPE_EDGE_RISING>;};```在驱动中调用`platform_get_irq(pdev,0)`即可获取该中断号(此处为3)。####错误处理常见的返回值错误码:-`-EPROBE_DEFER`:表示中断资源尚未准备好,需要延迟探测(DeferredProbe)[^2]。-`-ENXIO`:请求的索引超出设备中断资源数量。-`-EINVAL`:无效的参数。####最佳实践1.**避免硬编码中断号**:使用此函数可让驱动与平台无关。2.**处理索引变化**:当设备树节点中定义多个中断时,应检查每个中断的索引顺序。3.**延迟探测支持**:当返回`-EPROBE_DEFER`时,驱动应返回该错误以等待中断控制器初始化完成[^3]。####与`platform_get_resource`的关系根据引用[^5],`platform_get_resource()`是更通用的资源获取函数,可以用于IRQ、内存区域等:```cstructresource*p_irq=platform_get_resource(pdev,IORESOURCE_IRQ,0);if(!p_irq){//错误处理}intirq=p_irq->start;```而`platform_get_irq`是它的快捷方式,封装了中断资源类型的判断和错误处理。---###相关问题1.如何使用设备树为设备配置多个中断源?2.如何处理中断请求失败(返回`-EPROBE_DEFER`)的情况?3.`platform_get_irq`和`of_irq_get`有什么区别?4.为什么推荐使用`platform_get_irq`而不是直接使用设备树节点解析中断?</think> ### `platform_get_irq` 函数详解 `platform_get_irq` 是 Linux 设备驱动开发中用于**安全获取中断号(IRQ)** 的核心函数,主要用于从 `platform_device` 中提取设备树(DT)或 ACPI 配置的中断资源。以下是详细解释: --- #### 一、函数原型与参数 ```c int platform_get_irq(struct platform_device *pdev, unsigned int index); ``` - **`pdev`**:`platform_device` 结构体指针,代表内核抽象的设备实体[^1] - **`index`**:中断资源索引号(从 0 开始),用于定位多个中断源 - **返回值**: - 成功:正整数的**硬件中断号**(如 32、64) - 失败:**负的错误码**(如 `-ENXIO` 表示中断不存在)[^2][^3] --- #### 二、典型用法(驱动开发示例) ```c static int my_driver_probe(struct platform_device *pdev) { // 1. 获取设备第一个中断资源(index=0) int irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "无法获取中断号: %d\n", irq); return irq; // 返回错误码(负值) } // 2. 注册中断处理函数(使用线程化中断) int ret = devm_request_threaded_irq(&pdev->dev, irq, top_half_handler, bottom_half_thread, IRQF_ONESHOT, "my-device", NULL); if (ret) { dev_err(&pdev->dev, "中断注册失败: %d\n", ret); return ret; } return 0; } ``` --- #### 三、内部工作机制 当内核初始化时(通过 `of_platform_bus_create()`): 1. **解析设备树** - 读取设备树(DT)的 `interrupts` 属性 - 调用 `of_irq_to_resource_table()` 转换为 `resource` 结构体 ```dts my_device { interrupts = <0 123 4>; // 控制器编号+中断号+触发方式 }; ``` 2. **存储中断信息** - 将解析后的中断号存入 `platform_device->resource` 数组 - 类型标记为 `IORESOURCE_IRQ`[^3] 3. **驱动获取中断** - `platform_get_irq()` 通过索引访问 `resource` 数组 - 返回**已映射的有效中断号**(原始设备树值需经中断控制器转换) --- #### 四、关键特性 1. **设备树依赖性** - 中断资源**必须先在设备树声明**(不适用于非DT设备) 2. **错误处理优先** - **必须检查返回值**(错误码而非0值),例如: ```c if (irq < 0) // 而不是 if (irq == 0) ``` 3. **多中断支持** - 通过 `index` 获取多个中断源(如设备多个功能模块独立中断) ```c int irq1 = platform_get_irq(pdev, 0); // 主中断 int irq2 = platform_get_irq(pdev, 1); // 辅助中断 ``` 4. **设备树修改安全** - 驱动**无需硬编码中断号**,适配不同硬件只需调整设备树 --- #### 五、常见错误场景 | 错误代码 | 原因 | 解决方案 | |---------------|------------------------------|--------------------------| | **-EPROBE_DEFER** | 依赖资源未初始化 | 延迟探测机制重试[^2] | | **-ENXIO** | `index` 超出中断资源数量 | 检查设备树中断定义个数 | | **-EINVAL** | 设备树未声明中断属性 | 添加 `interrupts` 到DT节点 | --- ### 相关问题 1. 如何验证设备树中的中断配置是否正确映射到内核? 2. `platform_get_irq` 和 `platform_get_resource` 在资源获取上有何区别? 3. 多级中断控制器(如 GIC+GPIO)场景下中断号如何传递? 4. 驱动如何处理共享中断号(多个设备使用同一条中断线)? > **提示**:设备树中断配置需结合 `<interrupt-parent>` 指定控制器节点[^3],映射过程由 `irqdomain` 机制自动完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值