参考了友善之臂的按键驱动程序和韦东山写的《嵌入式Linux应用开发完全手册》【下载见http://www.linuxidc.com/Linux/2011-01/31114.htm】一书的第20章—Linux异常处理体系结构部分的按键驱动程序,修改了部分内容,学习了嵌入式Linux下按键驱动程序。
按照习惯,先看原理,对所学习的知识结构有了大致的了解了开始阅读别人的代码,仔细分析代码实现的每个过程。由于时间有限,我只了解了一些概念性的理论和内核代码中部分数据结构,学习的过程还有待深入。对于我这样的初学者来说,想把资料中所介绍的每个原理和具体的实现方法都完全掌握,恐怕不止是时间的问题,我所追求的是一种快速上手的方法,先学会用再深入学习。
下面是经我改动后的按键驱动程序:
/*buttons_driver.c*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "buttons"
struct button_irq_desc {
int irq;
int pin;
int pin_setting;
int number;
char *name;
};
static struct button_irq_desc button_irqs [] = {
{IRQ_EINT8 , S3C2410_GPG0 , S3C2410_GPG0_EINT8 , 0, "KEY0"},
{IRQ_EINT11, S3C2410_GPG3 , S3C2410_GPG3_EINT11 , 1, "KEY1"},
{IRQ_EINT13, S3C2410_GPG5 , S3C2410_GPG5_EINT13 , 2, "KEY2"},
{IRQ_EINT15, S3C2410_GPG7 , S3C2410_GPG7_EINT15 , 3, "KEY3"},
{IRQ_EINT14, S3C2410_GPG6 , S3C2410_GPG6_EINT14 , 4, "KEY4"},
{IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_EINT19, 5, "KEY5"},
};
static volatile char key_values [] = {'0', '0', '0', '0', '0', '0'};
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
static irqreturn_t buttons_interrupt(int irq, void *dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
if ('0'== key_values[button_irqs->number]) { // Changed
key_values[button_irqs->number] = '1';
}
else if('1' == key_values[button_irqs->number]){
key_values[button_irqs->number] = '0';
}
ev_press = 1;
wake_up_interruptible(&button_waitq);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
{
int i;
int err;
//set the interrupt to falling
//友善的是上升沿和下降沿都中断,这里改成下降沿中断
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_FALLING,
button_irqs[i].name, (void *)&button_irqs[i]);
if (err)
break;
}
if (err) {
i--;
for (; i >= 0; i--) {
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return -EBUSY;
}
ev_press = 1;
return 0;
}
static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
{
int i;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
}
return 0;
}
static int s3c24xx_buttons_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(button_waitq, ev_press);
}
ev_press = 0;
err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
return err ? -EFAULT : min(sizeof(key_values), count);
}
#if 0
static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = 0;