13.input 子系统
驱动程序¶
input_dev 注册过程如下:
1、使用 input_allocate_device 函数申请一个 input_dev。
2、初始化 input_dev 的事件类型以及事件值。
3、使用 input_register_device 函数向 Linux 系统注册前面初始化好的 input_dev。
4、卸载input驱动的时候需要先使用input_unregister_device 函数注销掉注册的input_dev,然后使用 input_free_device 函数释放掉前面申请的 input_dev。
struct key_dev{
struct class *class;
struct device *device;
struct device_node *nd;
struct gpio_desc *gpiod;
struct timer_list timer;
struct input_dev *inputdev;
int gpio;
int irq;
int major;
int minor;
};
static int gpio_key_probe(struct platform_device *pdev)
{
/*初始化引脚、注册中断、初始化定时器*/
key.inputdev = input_allocate_device();
key.inputdev->name = KEYINPUT_NAME;
#if 0
/* 初始化input_dev,设置产生哪些事件 */
__set_bit(EV_KEY, keyinputdev.inputdev->evbit); /* 设置产生按键事件 */
__set_bit(EV_REP, keyinputdev.inputdev->evbit); /* 重复事件,比如按下去不放开,就会一直输出信息*/
/* 初始化input_dev,设置产生哪些按键 */
__set_bit(KEY_0, keyinputdev.inputdev->keybit);
#endif
#if 0
keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0);
#endif
#if 1
key.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(key.inputdev, EV_KEY, KEY_0);
#endif
/* 注册输入设备 */
ret = input_register_device(key.inputdev);
if (ret) {
printk("register input device failed!\r\n");
return ret;
}
return 0;
}
在remove中释放掉这个注册的函数
static int gpio_key_remove(struct platform_device *pdev)
{
printk("%s %s line %d\r\n", __FILE__, __FUNCTION__, __LINE__);
/* 释放input_dev */
input_unregister_device(key.inputdev);
input_free_device(key.inputdev);
//释放gpio
gpiod_put(key.gpiod);
del_timer(&key.timer);
//注销中断
free_irq(key.irq, &key);
return 0;
}
上报输入事件¶
在这个例程中,我在中断中触发了一个定时器,所以在定时器处理函数中来进行按键值的上报
static void key_timer_expire(unsigned long data)
{
/* data ==> gpio */
struct key_dev *gpio_key = (struct key_dev *)data;
int val;
val = gpiod_get_value(gpio_key->gpiod);
printk("key %d %d\n", gpio_key->gpio, val);
if(val == 0){ /* 按下按键 */
/* 上报按键值 */
//input_event(dev->inputdev, EV_KEY, KEY_0, 1);
input_report_key(gpio_key->inputdev, KEY_0, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
input_sync(gpio_key->inputdev);
printk("input_sync1\n");
} else { /* 按键松开 */
//input_event(dev->inputdev, EV_KEY, KEY_0, 0);
input_report_key(gpio_key->inputdev, KEY_0, 0);
input_sync(gpio_key->inputdev);
printk("input_sync2\n");
}
}
应用程序¶
#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>
static struct input_event inputevent;
int main(int argc, char *argv[])
{
int fd;
int err = 0;
char *filename;
filename = argv[1];
if(argc != 2) {
printf("Error Usage!\r\n");
return -1;
}
fd = open(filename, O_RDWR);
if (fd < 0) {
printf("Can't open file %s\r\n", filename);
return -1;
}
while (1) {
err = read(fd, &inputevent, sizeof(inputevent));
if (err > 0) { /* 读取数据成功 */
switch (inputevent.type) {
case EV_KEY:
if (inputevent.code < BTN_MISC) { /* 键盘键值 */
printf("key %d %s\r\n", inputevent.code, inputevent.value ? "press" : "release");
} else {
printf("button %d %s\r\n", inputevent.code, inputevent.value ? "press" : "release");
}
break;
/* 其他类型的事件,自行处理 */
case EV_REL:
break;
case EV_ABS:
break;
case EV_MSC:
break;
case EV_SW:
break;
}
} else {
printf("读取数据失败\r\n");
}
}
return 0;
}