/********************************************************************
EINT0 -----( GPF0 )----INPUT EINT2 -----( GPF2 )----INPUT
*********************************************************************/
#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>
#define DEVICE_NAME "button"
#define MAX_KEY_COUNT 32
typedef struct
{
unsigned long jiffy[MAX_KEY_COUNT];
unsigned char buf[MAX_KEY_COUNT];
unsigned int head,tail;
}KEY_BUFFER;
static KEY_BUFFER g_keyBuffer;
static spinlock_t buffer_lock;
static int major = 231; //Define device major
/*
static void *gpfcon;
static void *gpfdat;
*/
#define gpf_con (volatile unsigned long)ioremap(0x56000050,4)
#define gpf_dat (volatile unsigned long)ioremap(0x56000054,4)
static unsigned long GetTickCount(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);
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);
}
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)
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);
}
static void init_gpio(void)
{
// writel((readl(gpf_con)) | ((3<<0)|(3<<4))) &(~((1<<0) | (1<<4))),gpf_con );
writel((readl(gpf_con) |0x33)&0xffffffee,gpf_con);
set_irq_type(IRQ_EINT0, IRQT_FALLING);
set_irq_type(IRQ_EINT2, IRQT_FALLING);
}
static __inline void enable_irqs(void)
{
enable_irq(IRQ_EINT0);
enable_irq(IRQ_EINT2);
}
static __inline void disable_irqs(void)
{
disable_irq(IRQ_EINT0);
disable_irq(IRQ_EINT2);
}
static __inline unsigned char button_scan(int irq)
{
long lGPF;
lGPF = readl(gpf_dat);
if ((lGPF & (1<<0)) == 0) return 1; //eint0
else if((lGPF & (1<<2)) == 0) return 2; //eint2
return 0xff ;
}
static irqreturn_t button_irq(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char ucKey;
int i,j;
disable_irqs();
for(i =0 ;i<3000;i++)
for(j=0;j<2000;j++);
ucKey = button_scan(irq);
if ((ucKey >= 1) && (ucKey <= 16))
{
printk("0x%2x /n",ucKey);
if (((g_keyBuffer.head + 1) & (MAX_KEY_COUNT - 1)) != g_keyBuffer.tail)
{
spin_lock_irq(&buffer_lock);
g_keyBuffer.buf[g_keyBuffer.tail] = ucKey;
g_keyBuffer.jiffy[g_keyBuffer.tail] = GetTickCount();
g_keyBuffer.tail ++;
g_keyBuffer.tail &= (MAX_KEY_COUNT -1);
spin_unlock_irq(&buffer_lock);
}
}
init_gpio();
enable_irqs();
return 0;
}
static __inline int request_irqs()
{
int ret;
ret = request_irq(IRQ_EINT0, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);
if (ret < 0)
return ret;
ret = request_irq(IRQ_EINT2, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);
if (ret >= 0)
{
free_irq(IRQ_EINT2, button_irq);
}
free_irq(IRQ_EINT0, button_irq);
return ret;
}
static __inline void free_irqs()
{
free_irq(IRQ_EINT0, button_irq);
free_irq(IRQ_EINT2, button_irq);
}
static int button_open(struct inode *inode,struct file *filp)
{
int ret = nonseekable_open(inode, filp);
if (ret >= 0)
{
init_keybuffer();
enable_irqs();
}
return ret;
}
static int button_release(struct inode *inode,struct file *filp)
{
disable_irqs();
return 0;
}
static ssize_t button_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
ssize_t ret = 0;
remove_timeoutkey();
spin_lock_irq(&buffer_lock);
while((g_keyBuffer.head != g_keyBuffer.tail) && (((size_t)ret) < count) )
{
buffer[ret] = (char)(g_keyBuffer.buf[g_keyBuffer.head]);
g_keyBuffer.buf[g_keyBuffer.head] = 0;
g_keyBuffer.jiffy[g_keyBuffer.head] = 0;
g_keyBuffer.head ++;
g_keyBuffer.head &= (MAX_KEY_COUNT -1);
ret ++;
}
spin_unlock_irq(&buffer_lock);
return ret;
}
static int button_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
init_keybuffer();
return 1;
}
static struct file_operations button_fops =
{
.owner = THIS_MODULE,
.ioctl = button_ioctl,
.open = button_open,
.read = button_read,
.release = button_release,
};
static int __init button_init(void)
{
int ret;
/*
gpfcon = ioremap(0x56000050, 0x04);
gpfdat = ioremap(0x56000054, 0x04);
*/
init_gpio();
ret = request_irqs();
if (ret < 0) return ret;
ret = register_chrdev(major, DEVICE_NAME, &button_fops);
if (ret < 0)
{
free_irqs();
return ret;
}
devfs_mk_cdev(MKDEV(major, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, DEVICE_NAME);
disable_irqs();
printk("button initialized./n");
return 0;
}
static void __exit button_exit(void)
{
disable_irqs();
free_irqs();
devfs_remove(DEVICE_NAME);
unregister_chrdev(major, DEVICE_NAME);
}
module_init(button_init);
module_exit(button_exit);
MODULE_AUTHOR("ranruoyu1003@yahoo.com.cn ( 421083868)");
MODULE_DESCRIPTION("button Driver");
MODULE_LICENSE("RAN");
/**************************start***********************/
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <asm/delay.h>
main()
{
int fd;
char key = 0;
fd = open("/dev/button", O_RDWR);
if (fd == -1)
{
printf("open device button errr!/n");
return 0;
}
ioctl(fd, 0, 0);
while(key != 16)
{
if (read(fd, &key, 1) > 0)
{
printf("*********************Key Value = %d*****************************/n", key);
}
}
close(fd);
return 0;
}