万卷书   首页 > 电脑书籍 > Linux >Linux内核模块编程--中断处理程序
 
 Intel 架构键盘

警告: 这章剩下的内容都特别指定为完全的 基于Intel 架构。如果你不是在这个平台下运行,它没有用。甚至不要试图去编译这里的代码。

  在为这章写范例代码的时候我有一个问题。一方面,对于一个有用的范例,它应该运行于每个人的计算机上且有意味深长的结果。另一方面,内核已经包含了所有的通用设备的驱动程序,并且那些设备驱动程序不能和我将要写的共存。我发现的结果是写一些键盘中断的东西并且先关闭通常的键盘的中断句柄。因为在内核源文件(明确的, drivers/char/keyboard.c)中它被定义为静态符号,所以没有办法恢复它。如果你重视你的文件系统,在 insmod 这些代码前,在另一个终端上sleep 120 ; reboot 。

  这个代码将自己绑定为 IRQ 1,这是Intel 架构下的键盘控制器的IRQ(中断请求)。然后当它收到键盘中断时它就读键盘的状态( 那就是inb(0x64)的目的)和扫描代码,该代码即是键盘的返回值。然后,内核一认为它是可行的它就运行给出键所使用的代码(扫描代码的前7位)和它是被按下(第8位为0)还是被释放(第8位为1)的got_char函数。

范例 intrpt.c

/* intrpt.c - 中断句柄 */

/* Copyright (C) 1998 by Ori Pomerantz */

/* 必要头文件 */

/* 标准头文件 */
#include /* 内核工作 */
#include /* 明确指定是模块 */

/* 处理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif

#include
#include

/* 我们想中断 */
#include

#include

/* 在 2.2.3 版/usr/include/linux/version.h 中包含这个宏,
* 但 2.0.35 版不包含-因此在这加入以被需要 */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif

/* Bottom Half - 一旦内核模块认为它做任何事都是安全的时候这将被内核调用。 */
static void got_char(void *scancode)
{
printk("Scan Code %x %s.\n",
(int) *((char *) scancode) & 0x7F,
*((char *) scancode) & 0x80 ? "Released" : "Pressed");
}

/* 这个函数为键盘中断服务。它读取来自键盘的相关信息然后安排当内核认为bottom half安全的时候让它运行 */
void irq_handler(int irq,
void *dev_id,
struct pt_regs *regs)
{
/* 这些变量是静态的,因为它们需要对 bottom half 可见(通过指针)。 */
static unsigned char scancode;
static struct tq_struct task =
{NULL, 0, got_char, &scancode};
unsigned char status;

/* Read keyboard status */
status = inb(0x64);
scancode = inb(0x60);

/* 安排 bottom half 运行 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
queue_task(&task, &tq_immediate);
#else
queue_task_irq(&task, &tq_immediate);
#endif
mark_bh(IMMEDIATE_BH);
}

/* 初始化模块--登记 IRQ 句柄 */
int init_module()
{
/* 既然键盘的句柄不能和我们的共存,在我们做事情前我们不得不关闭它(释放它的 IRQ)。
* 因为我们不知道它在哪儿,所以以后没有办法恢复它--因此当我们做完时计算机将被重新启动。
*/
free_irq(1, NULL);

/* 请求 IRQ 1,键盘的 IRQ,指向我们的 irq_handler。 */
return request_irq(
1, /* PC上的键盘的 IRQ 号 */
irq_handler, /* 我们的句柄 */
SA_SHIRQ,
/* SA_SHIRQ 意味着我们将另一个句柄用于这个 IRQ。
*
* SA_INTERRUPT 能使句柄为一个快速中断。
*/
"test_keyboard_irq_handler", NULL);
}

/* 清除 */
void cleanup_module()
{
/* 它在这儿只是为了完全。它是完全不相关的,因为我们没有办法恢复通常的键盘中断因此计算机完全没用 * 了,需要被重新启动。 */
free_irq(1, NULL);
}

上一页