Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->Linux程序设计 ->正文

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

来源: 作者: 时间:2007-04-11 点击: [收藏] [投稿]

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

()

 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:Linux操作系统内核编程实现调度任务   下一篇:Linux系统下C语言编程--进程的创建

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号