3.3 中断申请函数
/*申请系统中断,中断方式为下降沿触发*/
static int request irqs(void)
{
struct key info *k;
int i;
for (i= 0; i < sizeof(key info tab) / sizeof(key info tab [1]); i++)
{
k = key info tab + i;
set external irq (k->irq no, EXT LOWLEVEL, GPIO PULLUP DIS);
//设置低电平触发
if   (request irq (k->irq no,  &buttons irq,  SA INTERRUPT,
DEVICE NAME,
i))  //申请中断,将 键序号作为参数传入中断服务程序
{
return  - 1;
}
}
return 0;
}
  3.4 中断释放函数
  /*释放中断*/
  static void free irqs(void)
  {
  struct key info *k;
  int i;
  for (i= 0; i < sizeof(key info tab) / sizeof(key info tab [1]); i++)
  {
  k = key info tab + i;
  free irq (k->irq no, buttons irq); //释放中断
  }
  }
  4 按键设备驱动中断和定时器处理程序
  在按键按下之后,将发生中断,在中断处理程序中,应该先关闭中断进去查询模式,延时以消抖如下中断处理过程只有顶半部,没有底半部。
  4.1 中断处理程序
  static void s3c2410 eint key (int irq, void *dev id, struct pt regs
  *reg)
  {
  int key = dev id;
  disable irq (key info tab [key].irq no); //关中断,转入查询 式
  keydev.keyStatus[key] = KEYSTATUS DOWNX;//状态为按下
  _
  key timer [key].expires == jiffies + KEY TIMER DELAY1;//延迟
  add timer (&key timer[key]); //启动定时器
  }
  4.2 定时器处理流程
  按键按下时,该按键将记录字啊缓冲区,同时定时器启动延时,每次记录新的键值时,等待队列被唤醒,其代码如下。
//按键设备驱动的定时器处理函数
static void key timer handler (unsigned long data)
{
int key = data;
if (ISKEY DOWN (key))
{
if (keydev.keyStatus[key] == KEYSTATUS DOWNX)
//从中断进入
{
keydev .keyStatus[key] = KEYSTATUS DOWN;
key timer[key].expires == jiffies + KEY TIMER DELAY; //延迟
keyEvent ();  //记录键值,唤醒等待队列
add timer(&key timer [key]);
}
else
{
key timer[key].expires == jiffies + KEY TIMER DELAY; //延迟
add timer(&key timer [key]);
}
}
else       //键已抬起
{
keydev.keyStatus[key] = KEYSTATUS UP;
enable irq (key info tab [key].irq no);
}
  5 打开和释放函数
  这里主要是设置keydev.head和keydev.tail还有按键事件函数指针keyEvent的值,按键设备驱动的打开、释放函数如下:
static int s3c2410 key open (struct inode *inode, struct file *filp)
{
keydev .head = keydev .tail = 0; //清空 键动作缓冲区
keyEvent = keyEvent raw; //函数指针指向 键处理函数keyEvent raw
return 0;
}
static int s3c2410 key release (struct inode *inode, struct file *filp)
{
keyEvent = keyEvent dummy; //函数指针指向空函数
return 0;
}
  6 读函数
  读函数主要是提供对按键设备结构体缓冲区的读并复制到用户空间,当keydev.head != keydev.tail时,说明缓冲区有数据,使用copy_to_user()函数拷贝到用户空间,反之根据用户空间是阻塞还是非阻塞读分为以下两种情况:
  非阻塞读:没有按键缓存,直接返回- EAGAIN;
  阻塞读:在keydev.wq等待队列上睡眠,直到有按键记录 到缓冲区后被唤醒。
//按键设备驱动的读函数
static ssize t s3c2410 key read (struct file *filp,char *buf,ssize tcount, loff t*ppos)
{
retry: if (keydev.head != keydev .tail)
//当前循环队列中有数据
{
key ret = keyRead (); //读取按键
copy to user(..); //把数据从内核空间传送到用户空间
}
else
{
if (filp->f flags &O NONBLOCK)
//若用户采用非阻塞方式读取
{
return  - EAGAIN;
}
interruptible sleep on (&(keydev .wq));
//用户采用阻塞方式读取,调用该函数使进程睡眠
goto retry;
}
return 0;
}