x64架构机器最新Linux内核中键盘中断处理失效问题
内核键盘中断模块无法触发处理函数的问题
问题描述
编写了一个基础内核模块,意图统计键盘中断生成次数并输出至内核printk循环缓冲区,但自定义的keyboard_handler中断处理函数从未被执行。
模块代码
#include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/delay.h> MODULE_LICENSE("GPL"); // 键盘IRQ号为1 static int irq = 1, dev = 0xaa, counter = 0; static irqreturn_t keyboard_handler(int irq, void *dev) { pr_info("Keyboard Counter:%d\n", counter++); return IRQ_NONE; } /* 注册中断 */ static int test_interrupt_init(void) { pr_info("%s: In init\n", __func__); return request_irq(irq, keyboard_handler, IRQF_SHARED, "my_keyboard_handler", &dev); } static void test_interrupt_exit(void) { pr_info("%s: In exit\n", __func__); synchronize_irq(irq); /* 同步中断 */ free_irq(irq, &dev); } module_init(test_interrupt_init); module_exit(test_interrupt_exit);
调试信息
- 加载模块前执行
sudo cat /proc/interrupts | less输出:
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 93 IR-IO-APIC 1-edge i8042
- 加载模块后执行同一命令输出:
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15 1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 93 IR-IO-APIC 1-edge i8042, my_keyboard_handler
可见request_irq已成功注册my_keyboard_handler。
- dmesg输出:
[48485.839232] test_interrupt_init: In init [48504.831010] test_interrupt_exit: In exit
生成该输出的操作步骤:
$ sudo insmod hello.ko $ sdsds sdsds: command not found $ sudo rmmod hello
- 补充说明:按下按键时,
/proc/interrupts中IRQ1的中断计数并未增加。
测试环境
- 发行版:MX-Linux
- 内核版本:
5.18.0-4mx-amd64
问题分析与解决建议
核心原因
- 内核驱动抢占中断:传统PS/2键盘的IRQ1已被内核
atkbd驱动占据,该驱动会直接处理键盘中断并将事件传递给输入子系统,不会将中断分发给共享的自定义处理函数。 - 中断机制变化:较新内核中,i8042相关中断可能被线程化处理,或被IO-APIC重映射,导致IRQ1并非实际触发的中断线。
- 设备类型不匹配:如果使用USB键盘,实际使用的是USB控制器分配的动态中断号,而非IRQ1。
解决方法
方法1:确认实际键盘中断号
执行以下命令查找真实的键盘中断:
dmesg | grep -i keyboard cat /proc/interrupts | grep -i "kbd\|input"
USB键盘的中断号会关联到uhci_hcd/ehci_hcd等USB控制器,而非IRQ1。
方法2:临时卸载内核键盘驱动(仅测试用)
若为PS/2键盘,可先卸载atkbd驱动,再加载自定义模块:
sudo rmmod atkbd sudo insmod hello.ko
此操作会导致系统自带键盘驱动失效,仅用于验证中断处理函数是否正常工作,测试完成后需重新加载驱动:
sudo modprobe atkbd
方法3:改用输入子系统监听事件(推荐)
直接注册硬件中断并非现代Linux处理输入事件的标准方式,建议基于input_subsystem编写模块,通过输入子系统监听键盘事件,避免直接操作硬件中断。
代码修正注意点
若坚持使用中断方式,需注意:
- 共享中断时,处理函数需读取硬件状态寄存器判断是否为自身设备触发的中断,处理完成后返回
IRQ_HANDLED,否则返回IRQ_NONE - 避免与内核已有驱动抢占同一中断线,除非明确卸载对应驱动
内容的提问来源于stack exchange,提问作者Pratikkumar Bulani
相关产品推荐
相关产品推荐

