/* butt_drv.c */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/spinlock.h>
#include <asm/hardware.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm-arm/arch-s3c2410/regs-gpio.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm-arm/arch-s3c2410/irqs.h>
#include <asm-arm/irq.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/arch/regs-gpio.h>
#include "butt_drv.h"
static st_key_info_matrix key_info_matrix[MAX_COLUMN][MAX_ROW] =
{
{{10, IRQ_EINT0, S3C2410_GPF0, S3C2410_GPE11},
{11, IRQ_EINT0, S3C2410_GPF0, S3C2410_GPG6},
{12, IRQ_EINT0, S3C2410_GPF0, S3C2410_GPE13},
{16, IRQ_EINT0, S3C2410_GPF0, S3C2410_GPG2}},
{{7, IRQ_EINT2, S3C2410_GPF2, S3C2410_GPE11},
{8, IRQ_EINT2, S3C2410_GPF2, S3C2410_GPG6},
{9, IRQ_EINT2, S3C2410_GPF2, S3C2410_GPE13},
{15, IRQ_EINT2, S3C2410_GPF2, S3C2410_GPG2}},
{{4, IRQ_EINT11, S3C2410_GPG3, S3C2410_GPE11},
{5, IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG6},
{6, IRQ_EINT11, S3C2410_GPG3, S3C2410_GPE13},
{14, IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG2}},
{{1, IRQ_EINT19, S3C2410_GPG11, S3C2410_GPE11},
{2, IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG6},
{3, IRQ_EINT19, S3C2410_GPG11, S3C2410_GPE13},
{13, IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG2}},
};
static st_key_buffer key_buffer; /* 键盘缓冲区 */
static spinlock_t buffer_lock; /*缓冲区锁 */
static int button_major = 0;
/* 获取当前的毫秒数(从系统启动开始)*/
static unsigned long get_tick_count(void)
{
struct timeval 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); /* 获得一个自旋锁 */
key_buffer.head = 0;
key_buffer.tail = 0;
for(i = 0; i < MAX_KEY_COUNT; i++)
{
key_buffer.buf[i] = 0;
key_buffer.jiffy[i] = 0;
}
spin_unlock_irq(&buffer_lock); /* 释放自旋锁 */
}
/* 从缓冲删除过时数据(5秒前的按键值) */
static void remove_timeoutkey(void)
{
unsigned long tick;
spin_lock_irq(&buffer_lock); /* 获得一个自旋锁 */
while(key_buffer.head != key_buffer.tail)
{
tick = get_tick_count() - key_buffer.jiffy[key_buffer.head];
if (tick < 5000) /* 5秒 */
break;
key_buffer.buf[key_buffer.head] = 0;
key_buffer.jiffy[key_buffer.head] = 0;
key_buffer.head ++;
key_buffer.head &= (MAX_KEY_COUNT -1);
}
spin_unlock_irq(&buffer_lock); /* 释放自旋锁 */
}
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long shift = 1;
unsigned long mask = 0x03;
unsigned long con;
unsigned long flags;
if (pin < S3C2410_GPIO_BANKB)
{
shift = 0;
mask = 0x01;
}
mask <<= (S3C2410_GPIO_OFFSET(pin) << shift);
local_irq_save(flags);
con = __raw_readl(base + 0x00);
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags);
}
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
dat &= ~(1 << offs);
dat |= to << offs;
__raw_writel(dat, base + 0x04);
local_irq_restore(flags);
}
unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
unsigned long base = S3C2410_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long dat = 0;
unsigned long flags;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);
local_irq_restore(flags);
return ((dat & (1 << offs)) >> offs);
}
/* 初始化GPIO, 设置中断0, 2, 11, 19为下降沿中断 */
static void init_gpio(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_OUTP); /* GPE11 */
s3c2410_gpio_setpin(S3C2410_GPE11, 0);
s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_OUTP); /* GPE13 */
s3c2410_gpio_setpin(S3C2410_GPE13, 0);
s3c2410_gpio_cfgpin(S3C2410_GPG2, S3C2410_GPG2_OUTP); /* GPG2 */
s3c2410_gpio_setpin(S3C2410_GPG2, 0);
s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_OUTP); /* GPG6 */
s3c2410_gpio_setpin(S3C2410_GPG6, 0);
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0); /* GPF0 */
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); /* GPF2 */
s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_EINT11); /* GPG3 */
s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19); /* GPG11 */
set_irq_type(IRQ_EINT0, IRQT_FALLING);
set_irq_type(IRQ_EINT2, IRQT_FALLING);
set_irq_type(IRQ_EINT11, IRQT_FALLING);
set_irq_type(IRQ_EINT19, IRQT_FALLING);
}
/* 激活中断 */
static __inline void enable_irqs(void)
{
int i;
for (i = 0; i < MAX_COLUMN; i++)
{
enable_irq(key_info_matrix[i][0].irq_no);
}
}
/* 屏蔽中断 */
static __inline void disable_irqs(void)
{
int i;
for (i = 0; i < MAX_COLUMN; i++)
{
disable_irq(key_info_matrix[i][0].irq_no);
}
}
/*
** 进入中断后, 扫描铵键码
** 返回: 按键码(1-16), 0xff表示错误
*/
static __inline unsigned char button_scan(int irq)
{
unsigned char key_id = 0xff;
unsigned char column = 0xff, row = 0xff;
s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_INP); /* GPF0 */
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); /* GPF2 */
s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_INP); /* GPG3 */
s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_INP); /* GPG11 */
switch (irq)
{
case IRQ_EINT0: column = 0; break;
case IRQ_EINT2: column = 1; break;
case IRQ_EINT11: column = 2; break;
case IRQ_EINT19: column = 3; break;
}
if (column != 0xff)
{
s3c2410_gpio_setpin(S3C2410_GPE11, 0);
s3c2410_gpio_setpin(S3C2410_GPG6, 1);
s3c2410_gpio_setpin(S3C2410_GPE13, 1);
s3c2410_gpio_setpin(S3C2410_GPG2, 1);
if (!s3c2410_gpio_getpin(key_info_matrix[column][0].irq_gpio_port))
{
key_id = key_info_matrix[column][0].key_id;
return key_id;
}
s3c2410_gpio_setpin(S3C2410_GPE11, 1);
s3c2410_gpio_setpin(S3C2410_GPG6, 0);
s3c2410_gpio_setpin(S3C2410_GPE13, 1);
s3c2410_gpio_setpin(S3C2410_GPG2, 1);
if (!s3c2410_gpio_getpin(key_info_matrix[column][1].irq_gpio_port))
{
key_id = key_info_matrix[column][1].key_id;
return key_id;
}
s3c2410_gpio_setpin(S3C2410_GPE11, 1);
s3c2410_gpio_setpin(S3C2410_GPG6, 1);
s3c2410_gpio_setpin(S3C2410_GPE13, 0);
s3c2410_gpio_setpin(S3C2410_GPG2, 1);
if (!s3c2410_gpio_getpin(key_info_matrix[column][2].irq_gpio_port))
{
key_id = key_info_matrix[column][2].key_id;
return key_id;
}
s3c2410_gpio_setpin(S3C2410_GPE11, 1);
s3c2410_gpio_setpin(S3C2410_GPG6, 1);
s3c2410_gpio_setpin(S3C2410_GPE13, 1);
s3c2410_gpio_setpin(S3C2410_GPG2, 0);
if (!s3c2410_gpio_getpin(key_info_matrix[column][3].irq_gpio_port))
{
key_id = key_info_matrix[column][3].key_id;
return key_id;
}
}
return key_id;
}
/* 中断处理函数,其中irq为中断号 */
static irqreturn_t button_irq(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char ucKey = 0;
disable_irqs();
/* 延迟50毫秒, 屏蔽按键毛刺 */
udelay(50000);
ucKey = button_scan(irq);
if ((ucKey >= 1) && (ucKey <= 16))
{
/* 如果缓冲区已满, 则不添加 */
if (((key_buffer.head + 1) & (MAX_KEY_COUNT - 1)) != key_buffer.tail)
{
spin_lock_irq(&buffer_lock);
key_buffer.buf[key_buffer.tail] = ucKey;
key_buffer.jiffy[key_buffer.tail] = get_tick_count();
key_buffer.tail ++;
key_buffer.tail &= (MAX_KEY_COUNT -1);
spin_unlock_irq(&buffer_lock);
}
}
init_gpio();
enable_irqs();
return IRQ_HANDLED;/* 2.6内核返回值一般是这个宏 */
}
评论2