科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Linux操作系统内核编程中断处理程序 (2)

Linux操作系统内核编程中断处理程序 (2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

注意:本章下面的内容都是完全针对Intel结构。如果你不是在Intel平台上的话,程序就不能工作,也不没有必要试图编译。

作者:赛迪网技术社区 来源:赛迪网技术社区 2007年10月24日

关键字: 中断 编程 内核 Linux

  • 评论
  • 分享微博
  • 分享邮件
 

Intel 结构上的键盘

注意:本章下面的内容都是完全针对Intel结构。如果你不是在Intel平台上的话,程序就不能工作,也不没有必要试图编译。

在写本章例子中的程序的时候我遇到一个问题。一方面,作为一个有用的例子它需要在每个人的机器上运行,得到正确的结果。另一方面,内核已经包含了所有普通设备的驱动程序,这些驱动程序和我要写的代码不一定能够共存。我找到的方法是给键盘中断写点东西,并且首先使正常的键盘中断无效。因为在内核源文件(drivers/char/keyboard.c)里它是作为一个静态符号被定义的,没有办法恢复它。在insmod这段代码前,在另一个终端sleep 120上做一次,如果要评估文件 系统的话,需要reboot。

这段代码把它自己绑定到IRQ1上,在Interl结构下这是键盘控制的IRQ。然后,当它接到一个键盘中断时,读出键盘的状态(这是inb(0x64)的目的)和由键盘返回的扫描码。然后,只要内核认为可以时,它就运行got_char给出键的编码(扫描码的前7位)和是否被按下的信息(如果第8位是0则表示按下,是1表示释放)。

ex intrpt.c 

/* intrpt.c - An interrupt handler. */ 


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



/* The necessary header files */ 

/* Standard in kernel modules */ 
#include /* Were doing kernel work */ 
#include /* Specifically, a module */ 

/* Deal with CONFIG_MODVERSIONS */ 
#if CONFIG_MODVERSIONS==1 
#define MODVERSIONS 
#include 
#endif 

#include 
#include 

/* We want an interrupt */ 
#include 

#include 


/* In 2.2.3 /usr/include/linux/version.h includes a 
* macro for this, but 2.0.35 doesnt - so I add it 
* here if necessary. */ 
#ifndef KERNEL_VERSION 
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c)) 
#endif 



/* Bottom Half - this will get called by the kernel 
* as soon as its safe to do everything normally 
* allowed by kernel modules. */ 
static void got_char(void *scancode) 
{ 
printk(""Scan Code %x %s. "", 
(int) *((char *) scancode) & 0x7F, 
*((char *) scancode) & 0x80 ? ""Released"" : ""Pressed""); 
} 


/* This function services keyboard interrupts. It reads 
* the relevant information from the keyboard and then 
* scheduales the bottom half to run when the kernel 
* considers it safe. */ 
void irq_handler(int irq, 
void *dev_id, 
struct pt_regs *regs) 
{ 
/* This variables are static because they need to be 
* accessible (through pointers) to the bottom 
* half routine. */ 
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); 

/* Scheduale bottom half to run */ 
#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); 
} 



/* Initialize the module - register the IRQ handler */ 
int init_module() 
{ 
/* Since the keyboard handler wont co-exist with 
* another handler, such as us, we have to disable 
* it (free its IRQ) before we do anything. Since we 
* dont know where it is, theres no way to 
* reinstate it later - so the computer will have to 
* be rebooted when were done. 
*/ 
free_irq(1, NULL); 

/* Request IRQ 1, the keyboard IRQ, to go to our 
* irq_handler. */ 
return request_irq( 
1, /* The number of the keyboard IRQ on PCs */ 
irq_handler, /* our handler */ 
SA_SHIRQ, 
/* SA_SHIRQ means were willing to have othe 
* handlers on this IRQ. 
* 
* SA_INTERRUPT can be used to make the 
* handler into a fast interrupt. 
*/ 
""test_keyboard_irq_handler"", NULL); 
} 


/* Cleanup */ 
void cleanup_module() 
{ 
/* This is only here for completeness. Its totally 
* irrelevant, since we dont have a way to restore 
* the normal keyboard interrupt so the computer 
* is completely useless and has to be rebooted. */ 
free_irq(1, NULL); 
}
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章