Linux input子系统
input子系统统一了内核的输入事件,通过注册input驱动类型来与上层交互,input输入子系统的核心是输入模块,它必须是 加载到任何其他输入模块之前-它作为一种方式 两组模块之间的通信,input子系统的驱动主要分为:设备驱动层、input core和input handler
1.input dev结构体
struct input_dev {
const char *name; //设备名
const char *phys; //设备在系统中的物理路径
const char *uniq; //该设备的唯一标识码
struct input_id id; //设备id号
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; //设备属性和奇事
unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //设备支持的事件类型位 such as EV_KEY,EV_REL
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //设备所拥有的按键/按钮的位
unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //设备的相对轴的位
unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //设备的绝对轴的位
unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; //设备支持的杂项事件的位
unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; //设备存在led的位
unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; //设备支持音效的位
unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; //设备支持的力反馈效应
unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; //设备上存在的开关
unsigned int hint_events_per_packet;
unsigned int keycodemax; //支持的键值的最大个数
unsigned int keycodesize; //每个键值的大小
void *keycode; //存储按键值的数组首地址
int (*setkeycode)(struct input_dev *dev, //修改键值函数
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int (*getkeycode)(struct input_dev *dev, //获取键值函数
struct input_keymap_entry *ke);
struct ff_device *ff; //
unsigned int repeat_key; //用来存储最近一个按键按下的键值,通常用来实现重复报键值
struct timer_list timer; //定时器
int rep[REP_CNT]; //当前重复上报的参数(delay rate)
struct input_mt *mt; //指向多点触控状态的指针
struct input_absinfo *absinfo;
unsigned long key[BITS_TO_LONGS(KEY_CNT)]; //反映了设备的按键/按钮的当前状态
unsigned long led[BITS_TO_LONGS(LED_CNT)]; //当前led状态
unsigned long snd[BITS_TO_LONGS(SND_CNT)]; //当前音效的状态
unsigned long sw[BITS_TO_LONGS(SW_CNT)]; //当前开关的状态
int (*open)(struct input_dev *dev); //open
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file); //清空
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle __rcu *grab;
spinlock_t event_lock;
struct mutex mutex;
unsigned int users;
bool going_away;
struct device dev;
struct list_head h_list;
struct list_head node;
unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
bool devres_managed;
ktime_t timestamp[INPUT_CLK_MAX];
};
2.常用api
1.input_allocate_device
//为新的input device申请内存
return struct input_dev or NULL
struct input_dev *input_allocate_device(void)
{
static atomic_t input_no = ATOMIC_INIT(-1);
struct input_dev *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev) {
dev->dev.type = &input_dev_type;
dev->dev.class = &input_class;
device_initialize(&dev->dev);
mutex_init(&dev->mutex);
spin_lock_init(&dev->event_lock);
timer_setup(&dev->timer, NULL, 0);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
dev_set_name(&dev->dev, "input%lu",
(unsigned long)atomic_inc_return(&input_no));
__module_get(THIS_MODULE);
}
return dev;
}
2.input_register_device
//注册input 设备
int input_register_device(struct input_dev *dev)
{
struct input_devres *devres = NULL;
struct input_handler *handler;
unsigned int packet_size;
const char *path;
int error;
if (test_bit(EV_ABS, dev->evbit) && !dev->absinfo) {
dev_err(&dev->dev,
"Absolute device without dev->absinfo, refusing to register\n");
return -EINVAL;
}
if (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister,
sizeof(*devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;
devres->input = dev;
}
/* Every input device generates EV_SYN/SYN_REPORT events. */
__set_bit(EV_SYN, dev->evbit);
/* KEY_RESERVED is not supposed to be transmitted to userspace. */
__clear_bit(KEY_RESERVED, dev->keybit);
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
packet_size = input_estimate_events_per_packet(dev);
if (dev->hint_events_per_packet < packet_size)
dev->hint_events_per_packet = packet_size;
dev->max_vals = dev->hint_events_per_packet + 2;
dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
if (!dev->vals) {
error = -ENOMEM;
goto err_devres_free;
}
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
*/
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD])
input_enable_softrepeat(dev, 250, 33);
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
error = device_add(&dev->dev);
if (error)
goto err_free_vals;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
dev->name ? dev->name : "Unspecified device",
path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error)
goto err_device_del;
list_add_tail(&dev->node, &input_dev_list);
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
mutex_unlock(&input_mutex);
if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
__func__, dev_name(&dev->dev));
devres_add(dev->dev.parent, devres);
}
return 0;
err_device_del:
device_del(&dev->dev);
err_free_vals:
kfree(dev->vals);
dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
}
3.注册input设备流程
首先调用input_allocate_device函数申请一个input dev设备----->设置key的类型参数等、------->配置input设备的name----------------->input_register_device注册input设备---------------->申请一个中断上报input事件
4.上报的数据
上报的数据通常是event types,types对应于一个相同逻辑输入结构的一组Codes。每个type都有一组可用的codes用于产生输入事件。每个type可用的codes的详细信息请参考Codes一节的内容。相关的code参考input-event-codes.h
codes | 作用 |
---|---|
EV_SYN: | 用于事件间的分割标志。事件可能按时间或空间进行分割,就像在多点触摸协议中的例子 |
EV_KEY | 用来描述键盘,按键或者类似键盘设备的状态变化 |
EV_REL | 用来描述相对坐标轴上数值的变化,例如:鼠标向左方移动了5个单位 |
EV_ABS | 用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值 |
EV_MSC | 当不能匹配现有的类型时,使用该类型进行描述 |
EV_SW | 用来描述具备两种状态的输入开关 |
EV_LED | 用于控制设备上的LED灯的开和关 |
EV_SND | 用来给设备输出提示声音 |
EV_REP | 用于可以自动重复的设备(autorepeating) |
EV_FF | 用来给输入设备发送强制回馈命令 |
EV_PWR | 特别用于电源开关的输入 |
EV_FF_STATUS | 用于接收设备的强制反馈状态 |
5.应用读取input数据
int Parase_data()
{
struct input_event Keydata;
int fd = -1;
int ret = 0;
fd = open("/dev/input/event1", O_RDONLY);
if(fd == -1)
{
perror("open event1 fail\n");
return -1;
}
while(ret = read(fd, &Keydata, sizeof(Keydata)))!=0){
printf("type:%d\n", Keydata.type);
printf("code:%d\n", Keydata.code);
printf("value:%d\n", Keydata.value);
}
close(fd);
}