You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

调试信息

  1. 加载模块前执行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
  1. 加载模块后执行同一命令输出:
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。

  1. 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
  1. 补充说明:按下按键时,/proc/interrupts中IRQ1的中断计数并未增加。

测试环境

  • 发行版:MX-Linux
  • 内核版本:5.18.0-4mx-amd64

问题分析与解决建议

核心原因

  1. 内核驱动抢占中断:传统PS/2键盘的IRQ1已被内核atkbd驱动占据,该驱动会直接处理键盘中断并将事件传递给输入子系统,不会将中断分发给共享的自定义处理函数。
  2. 中断机制变化:较新内核中,i8042相关中断可能被线程化处理,或被IO-APIC重映射,导致IRQ1并非实际触发的中断线。
  3. 设备类型不匹配:如果使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 17:55:00