www.pudn.com > 嵌入式linux9应用开发祥解.rar > keyboard.C


/*键盘驱动范例  keybd.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; 
 
  /*读取键盘状态*/ 
  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); 
}