在TP驱动代码分析中,接触到了input子系统,TP驱动将检测到的所有按键或者坐标都上报给了input子系统。Input子系统是所有I/O设备驱动的中间层,为上层提供了一个统一的界面。例如,在终端系统中,我们不需要去管有多少个键盘,多少个鼠标。它只要从input子系统中去取对应的事件(坐标,按键,鼠标移位等)就可以了。下面是一个input子系统的DEMO驱动,参考价值5颗星,这个是关键代码,有问题欢迎指出,不吝赐教,技术无边,多多交流。
DEMO驱动主要是注册一个input设备,通过工作队列每隔1秒向上层上报event事件。
/*
*注意:此时会生成/dev/input/eventX // X 为 0 1 2 3
*测试:cat /proc/bus/input/devices会发现注册的设备
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/input/mt.h>
#include <asm/uaccess.h>
#include <linux/version.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/input.h> //包含的头文件
static struct input_dev *sensor_input_dev; //声明一个input设备结构体
#define DEV_NAME "sensor_input_dev" //宏定义输入设备名称为sensor_input_dev
static struct delayed_work send_event; //声明一个delayed_work结构体,延时工作队列
static int temperature_report_value(struct input_dev *input, int data) //上报event的调用接口,对接到实际获取数据的接口函数
{
printk("%s:line=%d, after sensor_report_value data[%d][%x]\n",
__func__,__LINE__, data, data);
input_report_abs(input, ABS_THROTTLE, data);
input_sync(input);
return 0;
}
static int sensor_report_value(void)
{ int ret;
int result = 29; //对接到实际获取数据的接口函数,这里先随便整个数29
ret = temperature_report_value(sensor_input_dev, result);
printk("__%s(%d)__, ret = %d\n", __func__, __LINE__, ret);
return 0;
}
static void send_event_workq(struct work_struct *work) //延时工作队列要做的事都在这里实现
{
int ret;
ret = sensor_report_value();
printk("__%s(%d)__, ret = %d\n", __func__, __LINE__, ret);
schedule_delayed_work(&send_event, msecs_to_jiffies(1000)); //每隔一秒执行一次send_event_workq
}
static int __init test_init(void)
{
int ret;
printk("%s init start\n", __func__);
sensor_input_dev = input_allocate_device(); //分配输入设备,失败返回NULL
sensor_input_dev -> name = DEV_NAME; //输入设备名字
set_bit(EV_ABS, sensor_input_dev->evbit); //设置输入设备事件类型为绝对坐标事件
input_set_abs_params(sensor_input_dev, ABS_THROTTLE, 100, 65535, 0, 0);
//对于ABS_THROTTLE范围是100到65535,数据误差是+-0,中心平滑位置是0
ret = input_register_device(sensor_input_dev); //将设备注册进输入子系统
if (ret) {
pr_err("input_register_device ret: %d\n", ret);
input_free_device(sensor_input_dev);//释放内存
return -1;
}
INIT_DELAYED_WORK(&send_event, send_event_workq); //初始化工作队列
schedule_delayed_work(&send_event, msecs_to_jiffies(2000)); //2s后开启工作队列
printk("%s init end\n", __func__);
return 0;
}
static void __exit test_exit(void)
{
cancel_delayed_work_sync(&send_event); //取消工作队列
input_unregister_device(sensor_input_dev); //注销input设备
}
module_init(test_init);
module_exit(test_exit);
MODULE_DESCRIPTION("For test input system driver");
MODULE_AUTHOR("cai.zhongding");
MODULE_LICENSE("GPL");
执行getevent可以看到event上报事件:
rk3399_all:/ # getevent
add device 1: /dev/input/event3
name: "sensor_input_dev"
add device 2: /dev/input/event2
name: "rk29-keypad"
add device 3: /dev/input/event1
name: "rockchip-cdndp-sound DP Jack"
add device 4: /dev/input/event0
name: "ff420030.pwm"
/dev/input/event3: 0003 0006 00000a58
/dev/input/event3: 0000 0000 00000000
/dev/input/event3: 0003 0006 00000a56
/dev/input/event3: 0000 0000 00000000