如果要将该程序应用于具体工程中,建议将中断处理函数“button_irq()”中的“__udelay(50000)“需要改为使用内核定时器。
按键原理图

//------------------------------------------驱动程序-----------------------------------------------------
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "button"
#define MAX_KEY_COUNT 32
#define EXTINT0 *(volatile unsigned int *)S3C2410_EXTINT0
#define EXTINT1 *(volatile unsigned int *)S3C2410_EXTINT1
#define EXTINT2 *(volatile unsigned int *)S3C2410_EXTINT2
MODULE_LICENSE("GPL");//模块应该指定代码所使用的许可证
typedef struct
{
unsigned long jiffy[MAX_KEY_COUNT]; //按键时间, 如果读键时, 5秒钟以前的铵键作废
unsigned char buf[MAX_KEY_COUNT]; //按键缓冲区
unsigned int head,tail; //按键缓冲区头和尾
}KEY_BUFFER;
static KEY_BUFFER g_keyBuffer; //键盘缓冲区
static spinlock_t buffer_lock; //缓冲区锁
static int button_major = 255; //Define device major add by yoyo
static void *gpecon;
static void *gpedat;
static void *gpfcon;
static void *gpfdat;
static void *gpgcon;
static void *gpgdat;
/*
*功能: 获取当前的毫秒数(从系统启动开始)
*入口:
*/
static unsigned long GetTickCount(void)
{
struct timeva l currTick;
unsigned long ulRet;
do_gettimeofday(&currTick);
ulRet = currTick.tv_sec;
ulRet *= 1000;
ulRet += (currTick.tv_usec + 500) / 1000;
return ulRet;
}
/*
*功能: 初始化键盘缓冲区
*入口:
*/
static void init_keybuffer(void)
{
int i;
spin_lock_irq(&buffer_lock); //获得一个自旋锁具有不会受中断的干扰
g_keyBuffer.head = 0;
g_keyBuffer.tail = 0;
for(i = 0; i < MAX_KEY_COUNT; i++)
{
g_keyBuffer.buf[i] = 0;
g_keyBuffer.jiffy[i] = 0;
}
spin_unlock_irq(&buffer_lock);//释放自旋锁
}
/*
*功能: 删除过时(5秒前的按键值)
*入口:
*/
static void remove_timeoutkey(void)
{
unsigned long ulTick;
spin_lock_irq(&buffer_lock); //获得一个自旋锁具有不会受中断的干扰
while(g_keyBuffer.head != g_keyBuffer.tail)
{
ulTick = GetTickCount() - g_keyBuffer.jiffy[g_keyBuffer.head];
if (ulTick < 5000) //5秒
break;
g_keyBuffer.buf[g_keyBuffer.head] = 0;
g_keyBuffer.jiffy[g_keyBuffer.head] = 0;
g_keyBuffer.head ++;
g_keyBuffer.head &= (MAX_KEY_COUNT -1);
}
spin_unlock_irq(&buffer_lock);//释放自旋锁
}
/*
*功能: 初始化GPIO, 设置中断0, 2, 11, 19为下降沿中断
*入口:
*/
static void init_gpio(void)
{
//将GPE13 11 设置低位
writel((readl(gpecon) | ((3<<26)|(3<<22))) & (~((1<<27)|(1<<23))), gpecon); //GPE13,11 设置为输出
writel(readl(gpedat) & 0xffffd7ff, gpedat); //GPE13,11 输出为0
//将GPG6, 2 设置低位
writel((readl(gpgcon) | 0x3030) & 0xffffdfdf, gpgcon); //GPG6,2 设置为输出
writel(readl(gpgdat) & 0xffffffbb, gpgdat); //GPG6,2 输出为0
writel((readl(gpfcon) | 0x33) & 0xffffffee, gpfcon); //GPF2, 0 设置为中断
writel((readl(gpgcon) | (3<<22) | (3<<6)) & (~((1<<22) | (1<<6))), gpgcon); //GPG11,3 设置为中断
set_irq_type(IRQ_EINT0, IRQT_FALLING);
// printk("dddddddddddd=%x\n",EXTINT0);
EXTINT0=(EXTINT0&(~0x07))+0x02;
set_irq_type(IRQ_EINT2, IRQT_FALLING);
EXTINT0=(EXTINT0&(~(0x07<<8)))+(0x02<<8);
set_irq_type(IRQ_EINT11, IRQT_FALLING);
EXTINT1=(EXTINT1&(~(0x07<<12)))+(0x02<<12);
set_irq_type(IRQ_EINT19, IRQT_FALLING);
EXTINT2=(EXTINT2&(~(0x07<<12)))+(0x02<<12);
}
/*
*功能: 激活中断
*入口:
*/
static __inline void enable_irqs(voi