/**************************************************************************
* Author : Deadline_h
* Time : 2017-3-4
* Brief : This is a input system driver of OK6410 based on the 3.0.1 kernel
* 如果同样的事件,事件的值不变,只能上报一次。
**************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int irq_flag[6] = {0}; //用于判断,是否注册中断成功。
struct timer_list my_timer;
static unsigned timer_flag = 0;
static struct input_dev * my_input_dev;
#define GPM_CON 0x7F008820
#define GPM_DAT 0x7F008824
#define GPN_CON 0x7F008830
#define GPN_DAT 0x7F008834
#define EINT0FLTCON0 0x7F008910
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
volatile unsigned long *gpncon = NULL;
volatile unsigned long *gpndat = NULL;
struct key_irq_dec{
unsigned int irq;
unsigned long flags;
const char * name;
};
static struct key_irq_dec key_irq[]={
{IRQ_EINT(0),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key1"},//key1 双边缘触发
{IRQ_EINT(1),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key2"},//key2
{IRQ_EINT(2),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key3"},//key3
{IRQ_EINT(3),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key4"},//key4
{IRQ_EINT(4),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key5"},//key5
{IRQ_EINT(5),(IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),"key6"},//key6
};
static void my_timer_func(void)
{
unsigned int data = 0;
timer_flag = 0;
data = readl(gpndat);
if((data&(1<<0))==0)//key1
{
printk(KERN_WARNING"key 1 down\n");
input_event(my_input_dev,EV_KEY,KEY_0, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_0, 0); //上报事件
}
/**************************************************************************/
if((data&(1<<1))==0)//key2
{
printk(KERN_WARNING"key 2 down\n");
input_event(my_input_dev,EV_KEY,KEY_1, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_1, 0); //上报事件
}
/**************************************************************************/
if((data&(1<<2))==0)//key3
{
printk(KERN_WARNING"key 3 down\n");
input_event(my_input_dev,EV_KEY,KEY_L, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_L, 0); //上报事件
}
/**************************************************************************/
if((data&(1<<3))==0)//key4
{
printk(KERN_WARNING"key 4 down\n");
input_event(my_input_dev,EV_KEY,KEY_S, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_S, 0); //上报事件
}
/**************************************************************************/
if((data&(1<<4))==0)//key5
{
printk(KERN_WARNING"key 5 down\n");
input_event(my_input_dev,EV_KEY,KEY_LEFTSHIFT, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_LEFTSHIFT, 0); //上报事件
}
/**************************************************************************/
if((data&(1<<5))==0)//key6
{
printk(KERN_WARNING"key 6 down\n");
input_event(my_input_dev,EV_KEY,KEY_ENTER, 1); //上报事件
}
else
{
input_event(my_input_dev,EV_KEY,KEY_ENTER, 0); //上报事件
}
/**************************************************************************/
input_sync(my_input_dev);//上报同步事件,表示上报结束
}
static irqreturn_t key_irq_handler(int irq, void * dev_id)//interrupt handler
{
// printk(KERN_WARNING"irq = %d , dev = %d\n",irq,dev_id);
if(timer_flag == 0)
mod_timer(&my_timer, jiffies + (1 * HZ) / 10);//启动定时器 定时器 100ms
timer_flag = 1;
return 0; //中断处理函数要有返回值,不然内核会打印一些错误信息。
}
void key_hw_init(void) //配置IO口为中断模式
{
unsigned int data;
gpncon= ioremap(GPN_CON,4);
gpndat= ioremap(GPN_DAT,4);
data = readl(gpncon);
data &= ~((0b11<<0)|(0b11<<2)|(0b11<<4)|(0b11<<6)|(0b11<<8)|(0b11<<10)); //设置按键1与按键6
data |= ((0b10<<0)|(0b10<<2)|(0b10<<4)|(0b10<<6)|(0b10<<8)|(0b10<<10)); //设置按键1与按键6
writel(data,gpncon);
}
static int dri_init(void)
{
unsigned int i = 0;
unsigned int irq_retval = 0;
key_hw_init();//将按键引脚配置为中断模式
printk(KERN_WARNING "my input sys device register\n");
my_input_dev = input_allocate_device(); //分配一个input_dev结构体
set_bit(EV_KEY, my_input_dev->evbit); //设置能产生什么类型的事件
//set_bit(EV_REP, my_input_dev->evbit); //设置能产生什么类型的事件
set_bit(KEY_0, my_input_dev->keybit); //设置能产生什么事件
set_bit(KEY_1, my_input_dev->keybit);
set_bit(KEY_L, my_input_dev->keybit);
set_bit(KEY_S, my_input_dev->keybit);
set_bit(KEY_LEFTSHIFT, my_input_dev->keybit);
set_bit(KEY_ENTER, my_input_dev->keybit);
input_register_device(my_input_dev); //注册input_dev
init_timer(&my_timer); //初始化定时器
my_timer.function = (void *)my_timer_func;
add_timer(&my_timer); //添加定时器
for(i=0;i<6;i++)//如果中断注册不成功,可能是因为该中断号已经注册过了,需要配置内核。或者设置成共享中断
{
irq_retval = request_irq(key_irq[i].irq,key_irq_handler,key_irq[i].flags,key_irq[i].name,0); //注册中断
if(irq_retval == 0)
{
irq_flag[i] = 0;
//printk(KERN_WARNING"irq_%d request succeed\n",i);
}
else
{
irq_flag[i] = -1;
printk(KERN_WARNING"irq_%d request failded,return val %d\n",i,irq_retval);
}
}
return 0;
}
static void dri_exit(void)
{
unsigned int i = 0;
printk(KERN_WARNING "module delete\n");
for(i=0;i<6;i++)
{
if(irq_flag[i] == 0) //注册成功的中断才注销中断
free_irq(key_irq[i].irq,0); //注销中断
}
del_timer(&my_timer); //删除定时器
input_unregister_device(my_input_dev); //注销input_dev
input_free_device(my_input_dev); //释放input_dev的内存
}
module_init(dri_init);
module_exit(dri_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Deadline_h");
MODULE_VERSION("V1.0");
应用测试程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
int fd;
int key_value,i=0;
struct input_event ev_key;
fd = open("/dev/event2", O_RDWR);
if (fd < 0) {
printf("open failed\n");
exit(1);
}
while(1)
{
read(fd,&ev_key,sizeof(struct input_event));
if(EV_KEY==ev_key.type)
printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code,ev_key.value);
if(EV_SYN==ev_key.type)
printf("syn event\n\n");
}
close(fd);
return 0;
}