利用INPUT子系统实现多个按键驱动
1.驱动程序
#include <linux/init.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#define KEY_NUM 1 //定义按键的个数
#define IRQ_FLAGS (IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING) //中断触发方式
//设计一个设备对象
struct event_key_dsc{
char *key_name; //按键名字
int key_code; //键值(在设备树中定义(本程序的键值是KEY_POWER(116)))
int gpionum; //gpio号
int irqnum; //中断号
struct device_node *cnp; //用来存放设备树中的节点地址,方便后面操作
};
struct event_key_dsc all_key[KEY_NUM]; //定义结构体数组,描述多个对象
struct input_dev *inputdev; //创建一个input_dev对象指针
struct timer_list key_timer; //定义一个定时器,用于按键消抖
static int get_device_node_form_devtree(void)
{
//获取设备树中的key_node父节点
int ret;
int i = 0;
const char *string_name;
struct device_node*cnp;
struct device_node*prev = NULL;
struct device_node *np = of_find_node_by_path("/key_node");
if(np){
printk("find key_node success\n");
}else{
printk("find key_node failed\n");
ret = -1;
goto get_node_err;
}
//遍历子节点
do{
cnp = of_get_next_child(np,prev);
if(cnp != NULL){
all_key[i].cnp = cnp; //将节点地址保存在每个结构体里面
//获取相关属性的值
if(of_property_read_u32(cnp, "key_code", &all_key[i].key_code) < 0){
printk("of_property_read_u32 failed\n");
ret =-1;
goto get_node_err;
}
//获取中断号
all_key[i].irqnum = irq_of_parse_and_map(cnp, 0);
if(of_property_read_string(cnp, "key_name", &string_name) !=0){
printk("of_property_read_string failed\n");
ret =-1;
goto get_node_err;
}
all_key[i].key_name = string_name;
} printk("key_name=%s,key_code=%d,irqnum=%d\n",all_key[i].key_name,
all_key[i].key_code,all_key[i].irqnum);
prev = cnp;
i++;
}while(of_get_next_child(np,prev) != NULL);
return 0;
get_node_err:
return ret;
}
/*中断处理函数*/
static irqreturn_t input_key_irq_handler(int irq,void *dev_id)
{
//struct event_key_dsc *key_desc = (struct event_key_dsc *)dev_id;
key_timer.data = (volatile long)dev_id;
mod_timer(&key_timer, jiffies + msecs_to_jiffies(10)); //延时10ms秒
return IRQ_HANDLED;
}
/*定时器回调函数*/
void timer_function(unsigned long arg)
{
printk("---%s-------------\n", __FUNCTION__);
struct event_key_dsc *key_desc = (struct event_key_dsc *)arg;
int gpionum = of_get_named_gpio(key_desc->cnp, "key_gpio", 0);
//通过gpio子系统获得按键状态
int value = gpio_get_value(gpionum);
if(value)//抬起
{
input_report_key(inputdev, key_desc->key_code, 0);
input_sync(inputdev);//上报数据结束
}else{
input_report_key(inputdev, key_desc->key_code, 1);
input_sync(inputdev);//上报数据结束
}
}
static int __init input_key_dev_init(void)
{
int ret;
int i=0;
//1.分配一个input_dev对象的内存
inputdev = input_allocate_device();
if(inputdev == NULL)
{
printk("input_allocate_device failed\n");
ret = -ENOMEM;
goto erralloc;
}
//2.初始化input_dev对象
//表示当前设备可以产生按键数据
__set_bit(EV_KEY, inputdev->evbit);
//3.从设备树中获取相关信息
get_device_node_form_devtree();
for(i = 0;i<KEY_NUM;i++)
{
//4.设置键值
__set_bit(all_key[i].key_code, inputdev->keybit);
//5.注册申请中断
ret = request_irq(all_key[i].irqnum, input_key_irq_handler, IRQ_FLAGS,
all_key[i].key_name, &all_key[i]);
if(ret != 0)
{
printk("request_irq failed\n");
ret = -1;
goto errrequest_irq;
}
}
//6.注册input_device对象
ret = input_register_device(inputdev);
if(ret != 0)
{
printk("input_register_device failed\n");
ret = -1;
goto errrregister_dev;
}
//7.创建定时器
init_timer(&key_timer);
key_timer.function = timer_function;
return 0;
errrregister_dev:
for(i = 0;i<KEY_NUM;i++){
free_irq(all_key[i].irqnum, &all_key[i]);
}
errrequest_irq:
input_free_device(inputdev);
erralloc:
return ret;
}
static void __exit input_key_dev_exit(void)
{
int i;
del_timer(&key_timer);
input_unregister_device(inputdev);
for(i = 0;i<KEY_NUM;i++){
free_irq(all_key[i].irqnum, &all_key[i]);
}
input_free_device(inputdev);
}
module_init(input_key_dev_init);
module_exit(input_key_dev_exit);
MODULE_LICENSE("GPL");
2.普通应用程序
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
int ret;
struct input_event Key_Event;
if(argc !=2)
{
printf("parameter not enough!\n");
exit(-1);
}
fd = open(argv[1],O_RDWR);
if(fd < 0)
{
perror("open");
exit(-1);
}
while(1)
{
read(fd,&Key_Event,sizeof(struct input_event));
if(ret < 0)
{
perror("read");
exit(-1);
}
if(Key_Event.type == EV_KEY)
{
switch(Key_Event.code)
{
case KEY_POWER:
if(Key_Event.value)
{
printf("app key pressed\n");
}else{
printf("app key up\n");
}
break;
}
}
}
close(fd);
return 0;
}