正点原子linux阿尔法开发板使用——input子系统

INPUT驱动框架

为了处理按键、鼠标、键盘、触摸屏等设备。

input子系统也是字符设备,input核心层会帮我们注册input字符设备驱动。既然内核已经帮我们修改好了input驱动,那么我们需要做什么呢?
需要完善输入设备,完善输入设备的时候就要按照input子系统的驱动框架要求来。

1、input_dev(表示具体的输入设备)
申请并初始化并注册input_dev。使用input_allocate_device申请,evbit表示输入事件,比如按键对应的事件就是EV_KEY,如果要连按,那么还要加EV_REP。

在这里插入图片描述
事件类型如下:
在这里插入图片描述
设置按键对应的键值,也就是keybit。
初始化完成input_dev以后,需要向内核注册。使用input_register_device
在这里插入图片描述
在这里插入图片描述
2、事件上报
按键按下以后上报事件,比如对于按键而言就是在按键中断服务函数,或者消抖定时器函数里面获取按键按下情况,并且上报,可以使用:
input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);(表示输入设备)
对于按键而言,也可以使用:
input_report_key
使用上面两个函数上报完成输入事件以后,还需要使用input_sync做同步!!!非常重要!!!

结构体中添加新成员:
在这里插入图片描述

input子系统代码

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/atomic.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/semaphore.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <linux/input.h>

#define	  KEYINPUT_NAME "keyinput"
#define   KEYINPUT_COUNT 1 
#define IMX6ULIRQOFF 0 /* 关灯 */
#define IMX6ULIRQON 1 /* 开灯 */

#define KEY_NUM 	1

#define KEY0_VALUE 0X01
#define INVAKEY 0XFF

/*按键结构体*/
struct irq_keydesc{
	int gpio;			/*io编号*/
	int irqnum;			/*中断号*/
	unsigned char value;	/*键值*/
	char name[10];		/*名字*/
	irqreturn_t (*handler)(int ,void *);					/*中断处理函数*/

};

struct keyinput_dev {

	struct device_node *nd; //设备节点

	struct irq_keydesc	irqkey[KEY_NUM];

	struct timer_list	timer;
	
	struct input_dev *input_dev; //输入子系统

};

struct keyinput_dev keyinput; //keyinput设备

static irqreturn_t key0_handler(int irq,void *dev_id)
{

	struct keyinput_dev *dev = dev_id;	

	dev->timer.data = (volatile unsigned long)dev_id;
	mod_timer(&dev->timer,jiffies + msecs_to_jiffies(10)); //10ms
	return IRQ_HANDLED;
}

/*定时器处理函数*/
static void timer_func(unsigned long arg)
{
	int value = 0;

	struct keyinput_dev *dev = (struct keyinput_dev *)arg;	

	value = gpio_get_value(dev->irqkey[0].gpio);
	if (value == 0) 
	{
		/*上报按键数值,按下*/
		input_event(dev->input_dev,EV_KEY,KEY_0,1);
		//同步
		input_sync(dev->input_dev);
	}
	else if (value == 1)
	{
		/*上报按键数值,释放*/
		input_event(dev->input_dev,EV_KEY,KEY_0,1);
		input_sync(dev->input_dev);
	}
	//重新开启定时器
	//mod_timer(&dev->timer,jiffies + msecs_to_jiffies(dev->timerperiod));
	
}

static int keyio_init(struct keyinput_dev *dev)
{
	/*1、按键的初始化*/
	int i = 0;
	int ret = 0;
	dev->nd = of_find_node_by_path("/key");
	if (dev->nd == NULL)
	{
		printk("key node not find!\r\n");
		return -EINVAL;
	}

	for(i = 0; i <KEY_NUM;i++){
		
		dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpio",i);
		if (dev->irqkey[i].gpio < 0) {
		printk("can't get key%d\r\n", i);
		}
		
	}
	for(i = 0; i <KEY_NUM;i++){
		// /*获取按键的IO编号*/
		// dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpios",i);

		memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));

		sprintf(dev->irqkey[i].name,"KEY%d",i);

		gpio_request(dev->irqkey[i].gpio,dev->irqkey[i].name);

		gpio_direction_input(dev->irqkey[i].gpio);

		dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);

		printk("key%d:gpio=%d, irqnum=%d\r\n",i,dev->irqkey[i].gpio,dev->irqkey[i].irqnum);
		//或者
		//dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd,i);
	}

	dev->irqkey[0].handler = key0_handler;
	dev->irqkey[0].value = KEY_0;
	/*2、中断初始化*/


	for(i = 0; i <KEY_NUM;i++){
		ret = request_irq(dev->irqkey[i].irqnum,dev->irqkey[i].handler,
		IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
		dev->irqkey[i].name,&keyinput);

		if (ret<0)
		{
			printk("irq request_irq err");
			goto fail_irq;
		}
	}

	/*3 初始化定时器*/
	init_timer(&keyinput.timer);

	keyinput.timer.function = timer_func;

	keyinput.timer.data = (unsigned long)&keyinput;

	return 0;

fail_irq:
	for(i = 0; i <KEY_NUM;i++)
		gpio_free(dev->irqkey[i].gpio);
	return ret;
}

static int __init keyinput_init(void)
{

	int ret = 0;
	/*初始化IO*/
	ret = keyio_init(&keyinput);
	if (ret<0)
	{
		goto fail_keyinit;
	}
	/*注册input_dev*/
	keyinput.input_dev = input_allocate_device();
	if(keyinput.input_dev == NULL){
		ret = -EINVAL;
		goto fail_keyinit;
	}

	keyinput.input_dev->name = KEYINPUT_NAME;
	__set_bit(EV_KEY,keyinput.input_dev->evbit);//设置捕获的按键事件
	__set_bit(EV_REP,keyinput.input_dev->evbit);//设置捕获的重复事件
	__set_bit(KEY_0,keyinput.input_dev->keybit);//设置捕获的按键值
	
	ret =  input_register_device(keyinput.input_dev);
	if (ret)
	{
		goto input_register_device_failed;
	}
	
	return 0;
input_register_device_failed:
	input_free_device(keyinput.input_dev);
fail_keyinit:
	return ret;
}

static void __exit keyinput_exit(void)
{
	int i = 0;
	
	//1、释放中断
	for(i = 0; i <KEY_NUM;i++)
	free_irq(keyinput.irqkey[i].irqnum,&keyinput);

	//2、释放IO
	for(i = 0; i <KEY_NUM;i++)
	gpio_free(keyinput.irqkey[i].gpio);

	/*3、删除定时器*/
	del_timer_sync(&keyinput.timer);

	/*4、注销input_dev*/
	input_unregister_device(keyinput.input_dev);
	input_free_device(keyinput.input_dev);
}
//模块加载函数
module_init(keyinput_init);
//模块卸载
module_exit(keyinput_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("qhy");

input详解
结构体成员
在这里插入图片描述
结构体 input_event 是一个结构体。
在这里插入图片描述
在这里插入图片描述

应用程序编写

#if 1
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <linux/input.h>
/*input_event 结构体变量*/

static struct input_event input_event;

int main(int argc, char **argv)
{
    int fd = 0;
    int cnt = 0;
    int ret = 0;

    if (argc != 2)
    {
        printf("Error Usage:\r\n");
        return -1;
    }

    fd = open(argv[1], O_RDWR);
    if (fd<0)
    {
        perror("open error");
        exit(-1);
    }

    while (1)
    {
       ret = read(fd, &input_event,sizeof(input_event));
       if (ret > 0){
           switch (input_event.type){
                case EV_KEY:
                    if(input_event.code < BTN_MISC)
                    {
                        printf("key %d %s\r\n", input_event.code,input_event.value ? "press" : "release");
                        //printf("EV_KEY 事件\r\n");
                    }
                    else {
                        printf("button %d %s\r\n", input_event.code,input_event.value ? "press" : "release");}
                        
                    break;
                case EV_SYN:
                    //printf("EV_SYN 事件\r\n");
                    break;
                case EV_REL:
                    break;
                case EV_ABS:
                    break;
                default:
                    break;
           }  
       }else{
           {
               printf("key boom\r\n");
           } 
       } 
    }  
    /*close*/
    close(fd);

    exit(0);
}
#endif // 0


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值