利用INPUT子系统实现多个按键驱动


利用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;
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值