button_drv.c:
-
/*
-
* linux/drivers/char/buttons.c
-
*
-
* This program is free software; you can redistribute it and/or modify
-
* it under the terms of the GNU General Public License version 2 as
-
* published by the Free Software Foundation.
-
*/
-
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/init.h>
-
#include <linux/delay.h>
-
#include <linux/poll.h>
-
#include <linux/irq.h>
-
#include <asm/irq.h>
-
#include <asm/io.h>
-
#include <linux/interrupt.h>
-
#include <asm/uaccess.h>
-
#include <mach/hardware.h>
-
#include <linux/platform_device.h>
-
#include <linux/cdev.h>
-
#include <linux/miscdevice.h>
-
-
#include <mach/map.h>
-
#include <mach/gpio.h>
-
#include <mach/regs-clock.h>
-
#include <mach/regs-gpio.h>
-
-
#include <linux/gpio.h>//gpio结构体的定义
-
#include <linux/sched.h>//
-
#include <linux/input.h>
-
// #include <linux/wait.h>
-
-
#define DEVICE_NAME "buttons"
-
-
struct button_desc {
-
int gpio;
-
int number;
-
char *name;
-
unsigned int key_val;
-
struct timer_list timer;
-
};
-
-
static struct button_desc buttons[] = {
-
/*
-
{ S5PV210_GPH0(0), 0, "KEY0", .timer_list, KEY_A },
-
{ S5PV210_GPH0(1), 1, "KEY1", .timer_list, KEY_B },
-
{ S5PV210_GPH0(2), 2, "KEY2", .timer_list, KEY_C },
-
{ S5PV210_GPH0(3), 3, "KEY3", .timer_list, KEY_D },
-
{ S5PV210_GPH0(4), 4, "KEY4", .timer_list, KEY_F },
-
{ S5PV210_GPH0(5), 5, "KEY5", .timer_list, KEY_G },
-
{ S5PV210_GPH2(6), 6, "KEY6", .timer_list, KEY_H },
-
{ S5PV210_GPH2(7), 7, "KEY7", .timer_list, KEY_I },
-
*/
-
{ S5PV210_GPH0(0), 0, "KEY0", KEY_A },
-
{ S5PV210_GPH0(1), 1, "KEY1", KEY_B },
-
{ S5PV210_GPH0(2), 2, "KEY2", KEY_C },
-
{ S5PV210_GPH0(3), 3, "KEY3", KEY_D },
-
{ S5PV210_GPH0(4), 4, "KEY4", KEY_E },
-
{ S5PV210_GPH0(5), 5, "KEY5", KEY_F },
-
{ S5PV210_GPH2(6), 6, "KEY6", KEY_G },
-
{ S5PV210_GPH2(7), 7, "KEY7", KEY_H },
-
};
-
-
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 input_dev *buttons_dev;
-
-
//使用定时器消抖
-
static void 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: %01d\n", bdata->number, down);
-
-
number = bdata->number;
-
if (down != (key_values[number] & 1)) {//down为1,按下,如果down!=键值&1,表示键值有变化,更新键值(置1);down为0,弹起,比较旧键值,不同则更新键值
-
//可起到进一步过滤无效按键数据的作用
-
key_values[number] = '0' + down;
-
if ( tmp)//这里判断条件不能弄错了,tmp为1表示松开。如果搞反了,会导致内核误认为是连击,一直上报事件。
-
{
-
/* 松开 : 最后一个参数: 0-松开, 1-按下 */
-
input_event(buttons_dev, EV_KEY, buttons->key_val, 0);
-
input_sync(buttons_dev);
-
}
-
else
-
{
-
/* 按下 */
-
input_event(buttons_dev, EV_KEY, buttons->key_val, 1);
-
input_sync(buttons_dev);
-
}
-
}
-
}
-
-
//按键中断
-
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));
-
-
return IRQ_HANDLED; // return 1
-
}
-
-
static int __init button_dev_init(void)
-
{
-
int irq;
-
int i;
-
int err = 0;
-
/* 1. 分配一个input_dev结构体 */
-
buttons_dev = input_allocate_device();;
-
buttons_dev->name = "button_input_device";
-
/* 2. 设置 */
-
/* 2.1 能产生哪类事件 */
-
set_bit(EV_KEY, buttons_dev->evbit);//按键
-
set_bit(EV_REP, buttons_dev->evbit);//可重复
-
-
/* 2.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
-
set_bit(KEY_A, buttons_dev->keybit);
-
set_bit(KEY_B, buttons_dev->keybit);
-
set_bit(KEY_C, buttons_dev->keybit);
-
set_bit(KEY_D, buttons_dev->keybit);
-
set_bit(KEY_E, buttons_dev->keybit);
-
set_bit(KEY_F, buttons_dev->keybit);
-
set_bit(KEY_G, buttons_dev->keybit);
-
set_bit(KEY_H, buttons_dev->keybit);
-
/* 3. 注册 */
-
err = input_register_device(buttons_dev);
-
if (err) {
-
printk(DEVICE_NAME"\t input_register_device err\n");
-
input_unregister_device(buttons_dev);
-
input_free_device(buttons_dev);
-
return -EBUSY;
-
}
-
//4. 硬件相关操作,注册8个中断和定时器
-
for (i = 0; i < ARRAY_SIZE(buttons); i++) {
-
if (!buttons[i].gpio)
-
continue;
-
//初始化定时器,setup_timer 内部调用了init_timer
-
setup_timer(&buttons[i].timer, buttons_timer,
-
(unsigned long)&buttons[i]);
-
//从io获取中断信号线
-
irq = gpio_to_irq(buttons[i].gpio);
-
//申请按键中断, 边沿触发中断
-
err = request_irq(irq, button_interrupt, IRQ_TYPE_EDGE_BOTH,
-
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;
-
}
-
-
printk(DEVICE_NAME"\tinitialized\n");
-
-
return err;
-
}
-
-
static void __exit button_dev_exit(void)
-
{
-
int irq, i;
-
-
for (i = 0; i < ARRAY_SIZE(buttons); 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);
-
}
-
input_unregister_device(buttons_dev);
-
input_free_device(buttons_dev);
-
}
-
-
module_init(button_dev_init);
-
module_exit(button_dev_exit);
-
-
MODULE_LICENSE("GPL");
-
MODULE_AUTHOR("GEC Inc.");
测试:
hexdump /dev/event0 | tail -n +10
event0数据格式:
hexdump /dev/event1 (open(/dev/event1), read(), )
秒 微秒 类 code value
004ceb0 0111 3901 26fa 0005 0000 0000 0001 0000
004cec0 0111 3901 afb9 0005 0001 001e 0002 0000
004ced0 0111 3901 afb9 0005 0000 0000 0001 0000
004cee0 0111 3901 386f 0006 0001 001e 0002 0000
004cef0 0111 3901 386f 0006 0000 0000 0001 0000
004cf00 0111 3901 c124 0006 0001 001e 0002 0000
004cf10 0111 3901 c124 0006 0000 0000 0001 0000
阅读(1350) | 评论(0) | 转发(0) |