基于ARM设备的AOSP:如何通过IRQ编号获取关联的所有输入事件处理程序
刚好在ARM架构的AOSP环境下折腾过类似的内核输入子系统需求,给你梳理下可行的实现思路:
通过IRQ编号获取关联的输入处理程序
Linux内核中,所有注册的IRQ处理逻辑都挂在struct irqaction链表上,要定位到输入子系统相关的处理程序,你可以从IRQ对应的描述结构入手:
- 首先调用内核函数
irq_to_desc(unsigned int irq)(声明在<linux/irqdesc.h>),拿到该IRQ对应的struct irq_desc *desc指针。如果返回NULL,说明这个IRQ编号无效。 - 接着通过
desc->action访问第一个struct irqaction节点,然后用action->next遍历整个链表,就能拿到该IRQ下所有注册的处理程序。 - 筛选输入相关的处理程序:输入驱动通常会把
struct input_dev指针作为dev_id参数传给request_irq(),你可以通过检查action->dev_id是否为有效的input_dev(验证input_dev->magic字段是否等于INPUT_DEV_MAGIC),或者对比action->handler的函数地址是否属于输入子系统(比如常见的input_handle_irq,或者设备驱动自定义的中断处理函数)。
如果你是在用户态开发,没法直接访问内核结构,得写一个简单的内核模块,遍历指定IRQ的irqaction链表,筛选出输入相关的处理程序后,通过proc节点把信息暴露到用户态。这里给个简化的代码片段参考:
#include <linux/module.h> #include <linux/irq.h> #include <linux/irqdesc.h> #include <linux/input.h> static int dump_irq_input_handlers(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); struct irqaction *action; if (!desc) { pr_err("IRQ %d is invalid\n", irq); return -EINVAL; } // 操作IRQ结构必须加自旋锁,防止并发修改 spin_lock(&desc->lock); action = desc->action; while (action) { struct input_dev *dev = action->dev_id; // 验证是否为有效的input_dev if (dev && dev->magic == INPUT_DEV_MAGIC) { pr_info("IRQ %d: Input handler %pF, device: %s\n", irq, action->handler, dev->name); } action = action->next; } spin_unlock(&desc->lock); return 0; } // 可以添加模块参数或者proc节点接口来触发这个函数 module_param(irq, uint, 0444); MODULE_PARM_DESC(irq, "IRQ number to dump input handlers");
映射输入设备的处理程序到触发的事件
对于指定输入设备(比如鼠标),要把处理程序和它触发的事件关联起来,分两种场景来看:
1. 查看设备支持的事件类型
如果只是想知道设备能上报哪些事件,不需要直接关联到处理程序,可以通过struct input_dev的位图字段获取:
input_dev->evbit:记录设备支持的顶级事件类型(比如EV_KEY按键事件、EV_REL相对坐标事件、EV_ABS绝对坐标事件)。- 针对每个顶级类型,查看对应的子位图:比如
EV_KEY对应keybit,EV_REL对应relbit,里面记录了具体的事件码(比如鼠标的REL_X、REL_Y)。
用户态下可以直接用AOSP自带的getevent工具快速查看:执行getevent -l会列出所有输入设备的事件类型和具体事件码,非常方便。
2. 关联中断处理程序与上报事件
因为一个输入设备的中断处理程序通常会在一次中断中上报多种事件(比如鼠标移动时会同时上报REL_X和REL_Y),要做精准映射的话,有两种方式:
- 分析驱动代码:找到目标设备的驱动源码,查看其中断处理函数的逻辑,看它在读取硬件数据后会调用哪些
input_report_*()系列函数(比如input_report_rel()上报相对位移),这些函数对应的就是触发的事件。 - 内核模块跟踪:在模块中挂钩目标设备的中断处理函数,或者在
input_report_*()函数处添加跟踪逻辑,记录每次中断触发时上报的事件,从而关联处理程序和事件。不过这种方式需要修改内核或者使用kprobe等动态跟踪技术,对内核版本有一定要求。
注意事项
- 操作IRQ相关内核结构时,必须持有对应的自旋锁(比如
desc->lock),避免并发修改导致的问题。 - AOSP对应的内核版本可能有差异,部分结构或函数名可能略有不同,需要对应内核的头文件来适配。
- 用户态无法直接访问内核的
irq_desc或input_dev结构,必须通过内核模块或者系统工具(如getevent、cat /proc/interrupts)间接获取信息。
内容的提问来源于stack exchange,提问作者Dustin Colten McAfee
相关产品推荐
相关产品推荐

