1、输入子系统框架
2、编写一个简单的设备驱动层代码
c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/input.h>
#include<linux/time.h>
struct input_dev *my_input_dev;
static void timer_function(struct timer_list *t);
DEFINE_TIMER(test_timer,timer_function);
static void timer_function(struct timer_list *t)
{
static int value = 0;
value = value?0:1;
input_event(my_input_dev,EV_KEY,KEY_1,value);
input_event(my_input_dev,EV_SYN,SYN_REPORT,0);
//printk("in timer_function\n");
mod_timer(&test_timer,jiffies_64+msecs_to_jiffies(1000));
}
static int my_input_dev_init(void)
{
int ret;
my_input_dev = input_allocate_device();
if(!my_input_dev)
{
printk("input_allocate_device is error\n");
return -1;
}
my_input_dev->name = "my_input_dev_test";
__set_bit(EV_KEY,my_input_dev->evbit);
__set_bit(EV_SYN,my_input_dev->evbit);
__set_bit(KEY_1,my_input_dev->keybit);
ret = input_register_device(my_input_dev);
if(ret < 0)
{
printk("input_register_device is error\n");
goto error;
}
test_timer.expires = jiffies_64 + msecs_to_jiffies(1000);
add_timer(&test_timer);
printk("my_input_dev_init ok\n");
return 0;
error:
printk("my_input_dev_init error\n");
input_free_device(my_input_dev);
return ret;
}
static void my_input_dev_exit(void)
{
//struct input_dev *my_input_dev;
input_unregister_device(my_input_dev);
del_timer(&test_timer);
printk("my_input_dev_exit ok\n");
}
module_init(my_input_dev_init);
module_exit(my_input_dev_exit);
MODULE_LICENSE("GPL");
编译成ko
放到开发板上加载
cat /proc/bus/input/devices
hexdump /dev/input/event11 查看上报的数据包
3、匹配规则和流程
c
input_register_device
input_attach_handler(dev, handler)
input_match_device(handler, dev)
//如果input_match_device返回id不为0,则调用connect函数
handler->connect(handler, dev, id)
遍历链表,查找匹配的事件处理层input_handler
可以看到,有没有定义match函数都可以进行匹配
通用事件处理层input_handler
这里是可以和所有的input设备驱动进行匹配
先后注册dev和handler都可以进行匹配
c
input_register_handler(&evdev_handler)
input_attach_handler(dev, handler)
input_match_device(handler, dev)
//如果input_match_device返回id不为0,则调用connect函数
handler->connect(handler, dev, id)
4、多对多的匹配关系
可以看到有四个handler和我的dev进行匹配
那为什么只生成一个设备节点呢?因为只有evdev中的connec函数注册了字符设备
可以看下kbd的connect函数
c
grep "kbd" drivers/* -nwr
5、上报数据格式分析
所以一个input_event数据包所占大小为8+2+2+4=24字节
c
tv_sec:e08f 667f 0000 0000
tv_usec:c3ac 0000 0000 0000
type:0001
code:0002
value:0001 0000
6、编写app获取type、code和value
c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<linux/input.h>
#define INPUT_DEV "/dev/input/event11"
int main()
{
struct input_event input_event;
int ret;
int fd = open(INPUT_DEV,O_RDWR);
if(fd < 0)
{
printf("open input_dev error\n");
return -1;
}
while(1)
{
ret = read(fd,&input_event,sizeof(struct input_event));
if(ret < 0)
{
printf("read input_dev error\n");
return -2;
}
printf("input_event.type = %04x,input_event.code = %04x,input_event.value = %08x\n",\
input_event.type,input_event.code,input_event.value);
}
return 0;
}
交叉编译app
c
/home/johan/share/rk3588/linux_sdk/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc app_test.c -o app_test