使用定时器可以防止因为按键抖动产生的多次响应函数~~
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <linux/percpu.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#define BUT_NAME "buttons"
#define DEVCOUNT 1
struct dev_button
{
dev_t dev;
struct cdev *cdev_p;
struct class * clz;
struct class_device * clz_dev;
struct timer_list timer;
};
struct key_dev
{
char * name;
const int irq_num;
unsigned int pin;
unsigned int key_status;
};
struct dev_button button_device;
struct key_dev keys[] = {
{.name = "S2", .irq_num = IRQ_EINT0, .pin = S3C2410_GPF0, .key_status = 0},
{.name = "s3", .irq_num = IRQ_EINT2, .pin = S3C2410_GPF2, .key_status = 0},
{.name = "s4", .irq_num = IRQ_EINT11, .pin = S3C2410_GPG3, .key_status = 0},
};
void timer_function(unsigned long data)
{
struct key_dev * p_dev = (struct key_dev *)data;
if(p_dev)
{
if(p_dev->key_status)
printk("Key %s pressed!\n", p_dev->name);
else
printk("Key %s unpressed!\n", p_dev->name);
}
}
irqreturn_t key_handler(int irq, void * param)
{
struct key_dev * p_dev = (struct key_dev *)param;
if(p_dev)
{
button_device.timer.data = (unsigned long)p_dev;
if(s3c2410_gpio_getpin(p_dev->pin))
p_dev->key_status = 0;
else
p_dev->key_status = 1;
mod_timer(&(button_device.timer), jiffies + HZ/100);
}
return 0;
}
struct file_operations f_ops = {
.owner = THIS_MODULE,
};
static int __init buttons_init(void)
{
int error = 0;
ssize_t i = 0;
printk("Button's driver is installing...\n");
if ((error = alloc_chrdev_region(&(button_device.dev), 0, DEVCOUNT, BUT_NAME)) < 0) {
printk(KERN_ERR
"button: Couldn't alloc_chrdev_region, error=%d\n",
error);
goto ERR_REG_DEVT;
}
printk("Alloc character region(%d, %d).\n",
MAJOR(button_device.dev), MINOR(button_device.dev));
button_device.cdev_p = cdev_alloc();
if(NULL == button_device.cdev_p)
{
printk(KERN_ERR
"button: Couldn't cdev_alloc");
goto ERR_ALLOC;
}
printk("Alloc cdev struct.\n");
button_device.cdev_p->ops = &f_ops;
error = cdev_add(button_device.cdev_p, button_device.dev, DEVCOUNT);
if(error < 0)
{
printk(KERN_ERR
"button: Couldn't cdev_add");
goto ERR_ADD_DEV;
}
printk("Add character device.\n");
button_device.clz = class_create(THIS_MODULE, BUT_NAME);
if(button_device.clz == NULL)
{
printk(KERN_ERR
"button: Couldn't class_create");
goto ERR_CLASS_CREATE;
}
printk("create class...\n");
button_device.clz_dev = class_device_create(button_device.clz, NULL, button_device.dev, NULL, BUT_NAME);
if(NULL == button_device.clz_dev)
{
printk(KERN_ERR
"button: Couldn't class_device_create");
goto ERR_DEV_CREATE;
}
printk("create device...\n");
printk("Button's driver installed successfully.\n");
for(i = 0; i < sizeof(keys)/sizeof(struct key_dev); i++)
{
if(0 != request_irq(keys[i].irq_num, key_handler, IRQT_BOTHEDGE, keys[i].name, (void*)(keys + i)))
{
printk(KERN_ERR
"button: Couldn't request_irq %s\n", keys[i].name);
goto ERR_REQUEST_IRQ;
}
printk("request_irq %d %s successfully\n", keys[i].irq_num,
keys[i].name);
}
init_timer(&button_device.timer);
button_device.timer.function = &timer_function;
add_timer(&button_device.timer);
return 0;
ERR_REQUEST_IRQ:
for( i-=1 ; i >= 0; i--)
free_irq(keys[i].irq_num, NULL);
ERR_DEV_CREATE:
class_destroy(button_device.clz);
ERR_CLASS_CREATE:
cdev_del(button_device.cdev_p);
ERR_ADD_DEV:
kfree(button_device.cdev_p);
ERR_ALLOC:
unregister_chrdev_region(button_device.dev, DEVCOUNT);
ERR_REG_DEVT:
printk("Error happened!\n");
return -1;
}
static void __exit buttons_exit(void)
{
ssize_t i = 0;
device_destroy(button_device.clz, button_device.dev);
class_destroy(button_device.clz);
kfree(button_device.cdev_p);
unregister_chrdev_region(button_device.dev, DEVCOUNT);
del_timer(&(button_device.timer));
for( i = 0 ; i < sizeof(keys) / sizeof(struct key_dev); i++)
free_irq(keys[i].irq_num, (void*)(keys + i));
return ;
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");