#include<linux/timer.h>
#include<linux/fs.h>
#include<linux/delay.h>
#include<linux/jiffies.h>
#include<linux/kernel.h>
#include<asm/string.h>
#include<asm/io.h>
#include<linux/module.h>
#include<linux/types.h>
#include<linux/mm.h>
#include<linux/gpio.h>
#include<linux/cdev.h>
#include<linux/wait.h>
#include<linux/sched.h>
#include<linux/poll.h>
#define MAX_KEYS 6
#define KEY_TIMER_DELAY HZ/5
MODULE_LICENSE("Dual BSD/GPL");
static struct timer_list key_timer;
static int key_major=0;
static int key_values[MAX_KEYS]={0};
static int ev_press=0;
static struct timer_list key_timer;
static struct cdev KeyDevs;
wait_queue_head_t key_waitq;
unsigned int key_desc[MAX_KEYS]={S3C2410_GPG(0),S3C2410_GPG(3),S3C2410_GPG(5),S3C2410_GPG(6),S3C2410_GPG(7),S3C2410_GPG(11)};
void key_timer_handle(unsigned long data)
{
unsigned int *key_p=(unsigned int *)data;
int down;
static unsigned char pressed[MAX_KEYS]={0};
int i;
for(i=0;i<MAX_KEYS;i++,key_p++)
{
s3c2410_gpio_setpin(*key_p,0<<0);
down=s3c2410_gpio_getpin(*key_p);
if(down==0)
{
pressed[i]++;
}
ndelay(10);
if(down==0&&pressed[i]==1)
{
printk("pressed
");
key_values[i]=i+1;
ev_press=1;
wake_up_interruptible(&key_waitq);
}
if(down==1&&pressed[i]==1)
pressed[i]=0;
}
key_timer.expires=jiffies+KEY_TIMER_DELAY;
add_timer(&key_timer);
}
static int key_open(struct inode *inode,struct file *filp)
{
init_waitqueue_head(&key_waitq);
init_timer(&key_timer);
key_timer.function=&key_timer_handle;
key_timer.data=(unsigned long)&key_desc;
key_timer.expires=jiffies+KEY_TIMER_DELAY;
add_timer(&key_timer);
return 0;
}
static unsigned int key_poll(struct file *file,struct poll_table_struct *wait)
{
unsigned int mask=0;
poll_wait(file,&key_waitq,wait);
if(ev_press)
mask|=POLLIN|POLLRDNORM;
return mask;
}
static ssize_t key_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
unsigned long err;
if(!ev_press)
{
if(filp->f_flags&O_NONBLOCK)
return -EAGAIN;
else
wait_event_interruptible(key_waitq,ev_press);
}
ev_press=0;
err=copy_to_user(buff,key_values,min(sizeof(key_values),count));
memset(key_values,0,sizeof(key_values));
return err?-EFAULT:min(sizeof(key_values),count);
}
static int key_release(struct inode *node,struct file *file)
{
del_timer(&key_timer);
return 0;
}
static void key_setup_cdev(struct cdev *dev,int minor,struct file_operations *fops)
{
int err,devno=MKDEV(key_major,minor);
cdev_init(dev,fops);
dev->owner=THIS_MODULE;
dev->ops=fops;
err=cdev_add(dev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding key %d",err,minor);
}
static struct file_operations key_ops={
.owner=THIS_MODULE,
.open=key_open,
.release=key_release,
.read=key_read,
.poll=key_poll,
};
static int __init keys_init(void)
{
int result;
dev_t dev=MKDEV(key_major,0);
result=alloc_chrdev_region(&dev,0,1,"key");
key_major=MAJOR(dev);
if(result<0)
{
printk(KERN_WARNING "key: unable to get major %d
",key_major);
return result;
}
if(key_major==0)
key_major=result;
key_setup_cdev(&KeyDevs,0,&key_ops);
printk("key device installed,with major %d
",key_major);
return 0;
}
static void __exit key_exit(void)
{
cdev_del(&KeyDevs);
unregister_chrdev_region(MKDEV(key_major,0),1);
printk("key devices uninstalled
");
}
module_init(keys_init);
module_exit(key_exit);