在 Linux 内核中如何处理键盘按下?

Sea*_*ean 2 drivers keyboard interrupt linux-kernel

我目前正在学习 Linux 内核和操作系统,虽然我发现了很多关于 IRQ、驱动程序、调度和其他重要操作系统概念的优秀资源,以及与键盘相关的资源,但我很难把它们放在一起Linux 内核如何处理键盘上的按钮按下的全面概述。在这个阶段,我并没有试图理解每一个细节,而是试图将概念联系起来,有点全面。

我想到了以下场景:

  1. 我在一台只有一个处理器的 x64 机器上。
  2. 有几个进程正在运行,特别是 Editor VIM( Process #1) 和 say LibreOffice( Process #2)。
  3. 我在里面VIM按 -a键。但是,当前正在运行的进程是Process #2VIM下一个计划)。

这就是我想象现在事情会发生的方式:

  1. 键盘通过一系列步骤生成一个电信号(USB 协议编码),并通过 USB 线发送。
  2. 信号由 USB 控制器处理,并通过 PCI-e(可能还有其他控制器/总线?)发送到中断控制器 ( APIC)。处理器的APIC触发器INT Pin
  3. 处理器切换到Kernel ModeIRQ-Number从 中请求APIC,它用作Interrupt Descriptor Table Register( IDTR)的偏移量。获取描述符,然后用于获取中断处理程序例程的地址。据我了解,这个中断处理程序最初是由键盘驱动程序注册的?
  4. 中断处理程序(在本例中为键盘处理程序)被调用。

这让我想到了我的主要问题:中断处理程序通过哪种机制将按下的键传达给正确的进程 ( Process #1)?它是否真的这样做呢,还是简单的写(通过提供一个被按下的按键到缓冲区char-device?),在某时刻为只读到一个进程(目前“附加”Process #1)?我不明白什么时候Process #1 收到钥匙。它是立即处理数据,就像中断处理程序立即调度进程一样,还是在调度程序下一次调度它时处理关键数据?

  1. 当此处理程序返回 ( IRET) 时,上下文切换回先前执行的进程 ( Process #2)。

dir*_*rkt 6

到目前为止,您的理解是正确的,但是您错过了建立在此基础上的大部分复杂性。内核中的处理发生在几个层中,按键“冒泡”通过这些层。

USB 通信协议本身涉及更多。USB 的中断处理程序会对此进行处理,并在必要时从多个片段组装一个完整的 USB 数据包。

按键使用所谓的HID(“人机界面设备”)协议,该协议建立在 USB 之上。所以较低的USB内核层检测到完整的消息是一个USB HID事件,并将其传递给内核中的HID层。

HID 层根据它在初始化时从设备要求的 HID 描述符来解释此事件。然后它将事件传递到输入层。单个 HID 事件可以生成多个按键事件。

输入层用途内核的键盘布局表来映射扫描码(键盘上的键的位置)移动到键码(像A)和解释ShiftAlt等这种解释的结果通过提供/dev/input/event*到用户级处理。您可以使用evtest实时观看这些事件。

但是处理到这里还没有结束。X 服务器(负责图形)有一个通用evdev驱动程序,它从/dev/input/event*设备读取事件,然后根据第二组键盘布局表再次映射它们(您可以xmodmap通过 XKBD 扩展查看部分和全部内容)。这是因为 X 服务器早于内核输入层,并且在早期有驱动程序直接处理鼠标和 PS/2 键。

然后 X 服务器向 X 客户端(应用程序)发送一条包含键盘事件的消息。您可以通过xev应用程序查看这些消息。LibreOffice将直接处理此事件,VIM将在xterm处理该事件的an中运行,并且(您猜对了)再次为其添加一些额外的处理,最后将其传递给VIMvia stdin

够复杂吗?

  • @tritium_3:大约 25 年的 Linux 使用经验、好奇心以及谷歌和阅读的能力。在那之前我了解了 X ...... (2认同)