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