文章目录
一、通用输入设备(evdev.c)识别
通用事件处理器(drivers/input/evdev.c),使用最多。
此事件处理器创建的设备文件范例 如下:
/dev/input/event0
/dev/input/event1
…
二、shell指令:查看输入设备名和event对应关系
cat /proc/bus/input/devices
三、BIT_MASK宏
include/asm-generic/bitops/non-atomic.h
指定1左移多少位
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
四、input_set_capability() 函数
drivers/input/input.c
void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
{
switch (type) {
case EV_KEY:// 按键类事件
// 设置允许上报的具体的按键事件
// 设置完后系统允许上报code具体事件
__set_bit(code, dev->keybit);
break;
case EV_REL:
__set_bit(code, dev->relbit);
break;
case EV_ABS:
input_alloc_absinfo(dev);
if (!dev->absinfo)
return;
__set_bit(code, dev->absbit);
break;
...
}
-
type:上报的具体输入事件类型
按键输入类型:EV_KEY
坐标输入类型:EV_REL、EV_ABS
特殊类型:EV_SYN
同步事件:通知用户空间的程序接收消息
… -
code
记录输入事件类型中的具体事件
键盘发生按键输入类型事件时,记录键盘那个值被按下
…
五、例程
1、驱动源文件
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/input.h>
#include <asm/uaccess.h>
struct device_node *button_device_node = NULL; //定义按键设备节点结构体
unsigned button_GPIO_number = 0; //保存button使用的GPIO引脚编号
u32 interrupt_number = 0; // button 引脚中断编号
/*input 子系统相关内容*/
#define BUTTON_NAME "input_button"
struct input_dev *button_input_dev = NULL; //定义按键对应的输入子系统结构体
/*按键中断处理函数*/
static irqreturn_t button_irq_hander(int irq, void *dev_id)
{
int button_satus = 0;
/*读取按键引脚的电平,根据读取得到的结果输入按键状态*/
button_satus = gpio_get_value(button_GPIO_number);
if(0 == button_satus)
{
input_report_key(button_input_dev, KEY_1, 0);
input_sync(button_input_dev);
}
else
{
input_report_key(button_input_dev, KEY_1, 1);
input_sync(button_input_dev);
}
return IRQ_HANDLED;
}
/*
*驱动初始化函数
*/
static int __init button_driver_init(void)
{
int error;
printk(KERN_ERR"button_driver_init \n");
/*获取按键 设备树节点*/
button_device_node = of_find_node_by_path("/button_interrupt");
if (NULL == button_device_node)
{
printk(KERN_ERR "of_find_node_by_path error!");
return -1;
}
/*获取按键使用的GPIO*/
button_GPIO_number = of_get_named_gpio(button_device_node, "button_gpio", 0);
if (0 == button_GPIO_number)
{
printk(KERN_ERR"of_get_named_gpio error");
return -1;
}
/*申请GPIO , 记得释放*/
error = gpio_request(button_GPIO_number, "button_gpio");
if (error < 0)
{
printk(KERN_ERR "gpio_request error");
gpio_free(button_GPIO_number);
return -1;
}
error = gpio_direction_input(button_GPIO_number); //设置引脚为输入模式
/*获取中断号*/
interrupt_number = irq_of_parse_and_map(button_device_node, 0);
printk(KERN_ERR"\n interrupt_number = %d \n", interrupt_number);
/*申请中断, 记得释放*/
error = request_irq(interrupt_number, button_irq_hander, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "button_interrupt", NULL);
if (error != 0)
{
printk(KERN_ERR "request_irq error:%d\r\n",error);
gpio_free(button_GPIO_number);
free_irq(interrupt_number, NULL);
return -1;
}
/*申请输入子系统结构体*/
button_input_dev = input_allocate_device();
if (NULL == button_input_dev)
{
printk(KERN_ERR "input_allocate_device error");
return -1;
}
button_input_dev->name = BUTTON_NAME;
/*设置要使用的输入事件类型*/
button_input_dev->evbit[0] = BIT_MASK(EV_KEY);
/*标记设备能够触发的事件类型、具体事件代号*/
input_set_capability(button_input_dev, EV_KEY, KEY_1);
/*注册输入设备*/
error = input_register_device(button_input_dev);
if (0 != error)
{
printk(KERN_ERR "input_register_device error:%d",error);
gpio_free(button_GPIO_number);
free_irq(interrupt_number, NULL);
input_unregister_device(button_input_dev);
return -1;
}
return 0;
}
/*
*驱动注销函数
*/
static void __exit button_driver_exit(void)
{
printk(KERN_ERR "button_driver_exit\n");
/*释放申请的引脚,和中断*/
gpio_free(button_GPIO_number);
free_irq(interrupt_number, NULL);
// 注销input_dev结构体
input_unregister_device(button_input_dev);
/*释放输入子系统相关内容*/
input_free_device(button_input_dev);
}
module_init(button_driver_init);
module_exit(button_driver_exit);
MODULE_LICENSE("GPL");
2、测试app
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <linux/input.h>
// 通过此结构体来从用户空间获取上报的事件
// 驱动层read接口返回的就是这个结构体
struct input_event button_input_event;
int button_status = 0; //保存按键状态;
int main(int argc, char *argv[])
{
int error = -20;
int button_status = 0;
/*打开文件*/
// 参数1可以通过:cat /proc/bus/input/devices 来确定设备名对应的event
int fd = open("/dev/input/event1", O_RDONLY);
if (fd < 0)
{
printf("open file : /dev/input/event1 error!\n");
return -1;
}
printf("wait button down... \n");
printf("wait button down... \n");
do
{
/*读取按键状态*/
error = read(fd, &button_input_event, sizeof(button_input_event));
if (error < 0)
{
printf("read file error! \n");
}
if((button_input_event.type == 1) && (button_input_event.code == 2))
{
if(button_input_event.value == 0)
{
printf("button up\n");
}
else if(button_input_event.value == 1)
{
printf("button down\n");
}
}
} while (1);
printf("button Down !\n");
/*关闭文件*/
error = close(fd);
if (error < 0)
{
printf("close file error! \n");
}
return 0;
}