这里整理一下按键的通用版本,也就大家都用的按键处理版本,结构比较清晰:
直接上代码:
five_buttons.c
/*
GPIO Driver driver for EasyARM-iMX283
AUTHOR:JIAOCHENGLIANG
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/capability.h>
#include <linux/rtc.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include </usr/src/linux-2.6.35.3/arch/arm/mach-mx28/mx28_pins.h>
#include <linux/list.h>
#include<linux/init.h>
#include<linux/module.h>
#include<mach/gpio.h>
#include <linux/gpio.h>
#include<asm/io.h>
#include"/usr/src/linux-2.6.35.3/arch/arm/mach-mx28/mx28_pins.h"
#include "/usr/src/linux-2.6.35.3/arch/arm/plat-mxs/include/mach/pinctrl.h"
#include "/usr/src/linux-2.6.35.3/arch/arm/mach-mx28/include/mach/mx28.h"
#include<linux/fs.h>
#include <linux/io.h>
#include<asm/uaccess.h>
#include<linux/miscdevice.h>
#include<linux/irq.h>
#include <asm/irq.h>
#include<linux/sched.h>
#include<linux/interrupt.h>
#include<linux/timer.h>
#include <linux/poll.h>
#include <linux/input.h>
#include <linux/time.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#define KEY_GPIO_1 MXS_PIN_TO_GPIO(PINID_LCD_D17)
#define KEY_GPIO_2 MXS_PIN_TO_GPIO(PINID_LCD_D18)
#define KEY_GPIO_3 MXS_PIN_TO_GPIO(PINID_SSP0_DATA4)
#define KEY_GPIO_4 MXS_PIN_TO_GPIO(PINID_SSP0_DATA5)
#define KEY_GPIO_5 MXS_PIN_TO_GPIO(PINID_SSP0_DATA6)
/*set to 0 自动分配主设备号,否则手动分配,但是如果已经被占用,便会分配失败*/
#define BUTTON_MAJOR 0
#define KEY_STATUS_DOWN '0'
#define KEY_STATUS_UP '1'
#define DEVICE_NAME "five_buttons"
struct button_desc {
int gpio;
int number;
char *name;
struct timer_list timer;
};
static struct button_desc buttons[] = {
{ KEY_GPIO_1, 1, "KEY_A" },
{ KEY_GPIO_2, 2, "KEY_B" },
{ KEY_GPIO_3, 3, "KEY_C" },
{ KEY_GPIO_4, 4, "KEY_D" },
{ KEY_GPIO_5, 5, "KEY_E" },
};
static volatile char key_values[] = {
'0', '0', '0', '0', '0', '0', '0', '0'
};
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;
static struct fasync_struct *button_async;
static void IMX287_buttons_timer(unsigned long _data)
{
struct button_desc *bdata = (struct button_desc *)_data;
int down;
int number;
unsigned tmp;
tmp = gpio_get_value(bdata->gpio);
/* active low */
down = !tmp;
printk("KEY %d: %08x\n", bdata->number, down);
number = bdata->number;
if (down != (key_values[number] & 1)) {
key_values[number] = '0' + down;
ev_press = 1;
wake_up_interruptible(&button_waitq);
}
}
static irqreturn_t button_interrupt(int irq, void *dev_id)
{
struct button_desc *bdata = (struct button_desc *)dev_id;
mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(40));
//发送信号SIGIO信号给fasync_struct 结构体所描述的PID,触发应用程序的SIGIO信号处理函数
kill_fasync(&button_async, SIGIO, POLL_IN);
return IRQ_HANDLED;
}
static int IMX287_buttons_open(struct inode *inode, struct file *file)
{
int irq;
int i;
int err = 0;
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
if (!buttons[i].gpio)
continue;
setup_timer(&buttons[i].timer, IMX287_buttons_timer,
(unsigned long)&buttons[i]);
irq = gpio_to_irq(buttons[i].gpio);
//设置中断触发模式
**err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_FALLING,
buttons[i].name, (void *)&buttons[i]);**
if (err)
break;
}
if (err) {
i--;
for (; i >= 0; i--) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
disable_irq(irq);
free_irq(irq, (void *)&buttons[i]);
del_timer_sync(&buttons[i].timer);
}
return -EBUSY;
}
ev_press = 1;
return 0;
}
static int IMX287_buttons_close(struct inode *inode, struct file *file)
{
int irq, i;
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
if (!buttons[i].gpio)
continue;
irq = gpio_to_irq(buttons[i].gpio);
free_irq(irq, (void *)&buttons[i]);
del_timer_sync(&buttons[i].timer);
}
return 0;
}
static int IMX287_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((void *)buff, (const void *)(&key_values),
min(sizeof(key_values), count));
return err ? -EFAULT : min(sizeof(key_values), count);
}
static unsigned int IMX287_buttons_poll( struct file *file,
struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static int IMX287_buttons_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
//初始化/释放 fasync_struct 结构体 (fasync_struct->fa_file->f_owner->pid)
return fasync_helper(fd, filp, on, &button_async);
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = IMX287_buttons_open,
.release = IMX287_buttons_close,
.read = IMX287_buttons_read,
.poll = IMX287_buttons_poll,
.fasync = IMX287_buttons_fasync,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init button_dev_init(void)
{
int ret;
ret = misc_register(&misc);
printk(DEVICE_NAME"\tinitialized\n");
if(ret<0){
printk("Add cdev failed!\n");
}
return ret;
}
static void __exit button_dev_exit(void)
{
misc_deregister(&misc);
}
module_init(button_dev_init);
module_exit(button_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("BQRelay Inc.");
编译后,挂载到板子上
看到/dev下有five_buttons 这个设备文件
cat five_buttons
就会有按键键值和按下弹起的内容出现
当然,直接按键也可以看到。
程序设置里面,设置中断触发模式,要不然容易捕捉不到中断信号。