- 了解linux input framework
1.input framework
输入子系统由 Input Core ,Device drivers和Event Handler 三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 input driver -> Input core -> Event handler -> userspace 到达用户空间传给应用程序。
-
输入子系统设备驱动层,主要实现对硬件设备的读写访问,中断设置,并把硬件产生的事件转换为核心层定义的规范提交给事件处理层。
-
核心层,为设备驱动层提供了规范和接口。设备驱动层只要关心如何驱动硬件并获得硬件数据(例如按下的按键数据),然后调用核心层提供的接口,核心层会自动把数据提交给事件处理层。
-
事件处理层,则是用户编程的接口(设备节点),并处理驱动层提交的数据处理。
-
/dev/input目录下显示的是已经注册在内核中的设备编程接口,用户通过open这些设备文件来打开不同的输入设备进行硬件操作。
-
事件处理层为不同硬件类型提供了用户访问及处理接口。例如当我们打开设备/dev/input/mice时,会调用到事件处理层的Mouse Handler来处理输入事件,这也使得设备驱动层无需关心设备文件的操作,因为Mouse Handler已经有了对应事件处理的方法。
-
输入子系统由内核代码drivers/input/input.c构成,它的存在屏蔽了用户到设备驱动的交互细节,为设备驱动层和事件处理层提供了相互通信的统一界面。
1.1. Input Core
The core of the input subsystem is the input module, which must be loaded before any other of the input modules - it serves as a way of communication between two groups of modules:
-
Device drivers
These modules talk to the hardware (for example via USB), and provide
events (keystrokes, mouse movements) to the input module. -
Event handlers
These modules get events from input core and pass them where needed via various interfaces - keystrokes to the kernel, mouse movements via a simulated PS/2 interface to GPM and X, and so on.
1.2.Event handlers
Event handlers distribute the events from the devices to userspace and in-kernel consumers, as needed.
2.input 事件处理框架
2.1.分配、注册、注销input设备
struct input_dev *input_allocate_device(void)
int input_register_device(struct input_dev *dev)
void input_unregister_device(struct input_dev *dev)
2.2.设置input设备支持的事件类型、事件码、事件值的范围、input_id等信息
usb_to_input_id(dev, &input_dev->id);//设置bustype、vendo、product等
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);//支持的事件类型
input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);// EV_LED事件支持的事件码
for (i = 0; i < 255; i++)
set_bit(usb_kbd_keycode[i], input_dev->keybit); //EV_KEY事件支持的事件码
include/linux/input.h定义支持的类型:
# Event code Specifies
0x00 EV_SYN Separate/synchronize other events (e.g. SYN_REPORT/SYN_MT_REPORT), or report events lost (SYN_DROPPED)
0x01 EV_KEY Key press (KEY_*) or touch (BTN_TOUCH)
0x02 EV_REL Relative changes to a property. Changes relayed through REL_[XYZ] values.
0x03 EV_ABS Absolute coordinates for an event. Values are usually ABS_[XYZ], or ABS_MT for multi-touch
0x04 EV_MSC Miscellaneous codes
0x05 EV_SW Binary switches. E.g. SW_JACK_PHYSICAL_INSERT for headphone insertion
0x11 EV_LED Used for device LEDs, if any
0x12 EV_SND Used for sound devices
0x14 EV_REP Used for auto-repeating events
0x15 EV_FF Used for force-feedback capable devices (e.g. joysticks). An EVIOCSFF ioctl may be used to upload force feedback effects
0x16 EV_PWR Reserved for power events. Largely unused
0x17 EV_FF_STATUS Used for force-feedback capable devices.
一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件码。比如:EV_KEY事件,需要定义其支持哪些按键事件码。
2.3.如果需要,设置input设备的打开、关闭、写入数据时的处理方法
input_dev->open = usb_kbd_open;
input_dev->close = usb_kbd_close;
input_dev->event = usb_kbd_event;
2.4.在发生输入事件时,向子系统报告事件
用于报告EV_KEY、EV_REL、EV_ABS等事件的函数有:
void input_report_key(struct input_dev *dev, unsigned int code, int value)
void input_report_rel(struct input_dev *dev, unsigned int code, int value)
void input_report_abs(struct input_dev *dev, unsigned int code, int value)
3.Event Handler层分析
数据结构关系图
如上所示:
对于handler和device,分别用链表input_handler_list和input_device_list进行维护,当handler或者device增加或减少的时候,分别往这两链表增加或删除节点,这两条都是全局链表。
36 static LIST_HEAD(input_dev_list);
37 static LIST_HEAD(input_handler_list);
3.1.input_dev
struct input_dev {
...
unsigned long evbit[NBITS(EV_MAX)]; //表示支持哪类事件,常用有以下几种事件(可以多选)
//EV_SYN 同步事件,当使用input_event()函数后,就要使用这个上报个同步事件
//EV_KEY 键盘事件
//EV_REL (relative)相对坐标事件,比如鼠标
//EV_ABS (absolute)绝对坐标事件,比如摇杆、触摸屏感应
//EV_MSC 其他事件,功能
//EV_LED LED灯事件
//EV_SND (sound)声音事件
//EV_REP 重复键盘按键事件
//(内部会定义一个定时器,若有键盘按键事件一直按下/松开,就重复定时,时间一到就上报事件)
//EV_FF 受力事件
//EV_PWR 电源事件
//EV_FF_STATUS 受力状态事件
unsigned long keybit[NBITS(KEY_MAX)]; //存放支持的键盘按键值
//键盘变量定义在:include/linux/input.h, 比如: KEY_L(按键L)、BTN_TOUCH(触摸屏的按键)
unsigned long relbit[NBITS(REL_MAX)]; //存放支持的相对坐标值
unsigned long absbit[NBITS(ABS_MAX)]; //存放支持的绝对坐标值,存放下面4个absxxx[]
unsigned long mscbit[NBITS(MSC_MAX)]; //存放支持的其它事件,也就是功能
unsigned long ledbit[NBITS(LED_MAX)]; //存放支持的各种状态LED
unsigned long sndbit[NBITS(SND_MAX)]; //存放支持的各种声音
unsigned long ffbit[NBITS(FF_MAX)]; //存放支持的受力设备
unsigned long swbit[NBITS(SW_MAX)]; //存放支持的开关功能
...
}
3.1.1.注册input_dev
input_register_device :该函数将input_dev结构体注册到输入子系统核心中,input_dev结构体必须由input_allocate_device()函数来分配。
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
const char *path;
int error;
/* 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);
/*
* 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.
*/
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
if (!dev->getkeycode)
dev->getkeycode = input_default_getkeycode;
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
error = device_add(&dev->dev);
if (error)
return error;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
error = mutex_lock_interruptible(&input_mutex);
if (error) {
device_del(&dev->dev);
return error;
}
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);
return 0;
}
遍历input_handler_list链表,对每一个handler调用input_attach_handler函数,看是否匹配。如果匹配成功,则调用 handler->connect,连接 handler 和 input_dev。
976 static const struct input_device_id *input_match_device(struct input_handler *handler,
977 struct input_dev *dev)
978 {
979 const struct input_device_id *id;
980
981 for (id = handler->id_table; id->flags || id->driver_info; id++) {
982 if (input_match_device_id(dev, id) &&
983 (!handler->match || handler->match(handler, dev))) {
984 return id;
985 }
986 }
987
988 return NULL;
989 }
991 static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
992 {
993 const struct input_device_id *id;
994 int error;
995
996 id = input_match_device(handler, dev);
997 if (!id)
998 return -ENODEV;
999 //匹配成功则调用 handler->connect,连接 handler 和 input_dev
1000 error = handler->connect(handler, dev, id);
1001 if (error && error != -ENODEV)
1002 pr_err("failed to attach handler %s to device %s, error: %d\n",
1003 handler->name, kobject_name(&dev->dev.kobj), error);
1004
1005 return error;
1006 }
3.2.input_handler
285 struct input_handler {
286
287 void *private;
288
289 void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
290 void (*events)(struct input_handle *handle,
291 const struct input_value *vals, unsigned int count);
292 bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
293 bool (*match)(struct input_handler *handler, struct input_dev *dev);
294 int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *
295 void (*disconnect)(struct input_handle *handle);
296 void (*start)(struct input_handle *handle);
297
298 bool legacy_minors;
299 int minor;
300 const char *name;
301
302 const struct input_device_id *id_table;
304 struct list_head h_list;
305 struct list_head node;
306 };
3.2.1.注册input_handler
int __must_check input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
input_register_handler:
2213 int input_register_handler(struct input_handler *handler)
2214 {
2215 struct input_dev *dev;
2216 int error;
2217
2218 error = mutex_lock_interruptible(&input_mutex);
2219 if (error)
2220 return error;
2221
2222 INIT_LIST_HEAD(&handler->h_list);
2223
2224 list_add_tail(&handler->node, &input_handler_list);
2225
2226 list_for_each_entry(dev, &input_dev_list, node)
2227 input_attach_handler(dev, handler);
2228
2229 input_wakeup_procfs_readers();
2230
2231 mutex_unlock(&input_mutex);
2232 return 0;
遍历input_dev_list链表,对每一个dev调用input_attach_handler函数,看是否匹配。如果匹配成功,则调用 handler->connect,连接 handler 和 input_dev。
3.3.以evdev.c中的evdev_handler(drivers/input/evdev.c)为例:
static struct input_handler evdev_handler = {
.event = evdev_event, //向系统报告input事件,系统通过read方法读取
.connect = evdev_connect, //和input_dev匹配后调用connect构建
.disconnect = evdev_disconnect,
.fops = &evdev_fops, //event设备文件的操作方法
.minor = EVDEV_MINOR_BASE, //次设备号基准值
.name = "evdev",
.id_table = evdev_ids, //匹配规则
};
3.3.1.evdev_handler 注册
static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
.event = evdev_event,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
.minor = EVDEV_MINOR_BASE,
.name = "evdev",
.id_table = evdev_ids,
};
static int __init evdev_init(void)
{
return input_register_handler(&evdev_handler);
}
匹配成功后,调用evdev_connect,创建input_handle结构体,该结构体代表一个成功配对的input_dev和input_handler。input_hande 没有一个全局的链表,它注册的时候将自己分别挂在了input_device_list和 input_handler_list的h_list上了;同时,input_handle的成员.*dev,关联到input_dev结构,.*handler关联到input_handler结构 。从此,建立好了三者的铁三角关系,通过任何一方,都可以找到彼此。
320 struct input_handle {
321
322 void *private;
323
324 int open;
325 const char *name;
326
327 struct input_dev *dev;
328 struct input_handler *handler;
329
330 struct list_head d_node;
331 struct list_head h_node;
332 };
1402 evdev->handle.dev = input_get_device(dev);
1403 evdev->handle.name = dev_name(&evdev->dev);
1404 evdev->handle.handler = handler;
1405 evdev->handle.private = evdev;
1413 error = input_register_handle(&evdev->handle);
1416
1417 cdev_init(&evdev->cdev, &evdev_fops);
1419 error = cdev_device_add(&evdev->cdev, &evdev->dev);
input_register_handle:
/**
* input_register_handle - register a new input handle
* @handle: handle to register
*
* This function puts a new input handle onto device's
* and handler's lists so that events can flow through
* it once it is opened using input_open_device().
*
* This function is supposed to be called from handler's
* connect() method.
*/
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
int error;
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
error = mutex_lock_interruptible(&dev->mutex);
if (error)
return error;
/*
* Filters go to the head of the list, normal handlers
* to the tail.
*/
if (handler->filter)
list_add_rcu(&handle->d_node, &dev->h_list);
else
list_add_tail_rcu(&handle->d_node, &dev->h_list);
mutex_unlock(&dev->mutex);
/*
* Since we are supposed to be called from ->connect()
* which is mutually exclusive with ->disconnect()
* we can't be racing with input_unregister_handle()
* and so separate lock is not needed here.
*/
list_add_tail_rcu(&handle->h_node, &handler->h_list);
if (handler->start)
handler->start(handle);
return 0;
}
注册字符设备cdev_init:
1323 static const struct file_operations evdev_fops = {
1324 .owner = THIS_MODULE,
1325 .read = evdev_read,
1326 .write = evdev_write,
1327 .poll = evdev_poll,
1328 .open = evdev_open,
1329 .release = evdev_release,
1330 .unlocked_ioctl = evdev_ioctl,
1331 #ifdef CONFIG_COMPAT
1332 .compat_ioctl = evdev_ioctl_compat,
1333 #endif
1334 .fasync = evdev_fasync,
1335 .flush = evdev_flush,
详见下图:
4.输入子系统分析
drivers/input/input.c中:
static int __init input_init(void)
{
int err;
err = class_register(&input_class);
……
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
……
}
input_fops定义:
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
5.从应用层的角度出发看input子系统
在应用层调用read函数,将调用到evdev_read:
static ssize_t evdev_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
size_t read = 0;
int error;
if (count != 0 && count < input_event_size())
return -EINVAL;
for (;;) {
if (!evdev->exist || client->revoked)
return -ENODEV;
/*如果client的环形缓冲区中没有数据并且是非阻塞的,那么返回-EAGAIN,也就是try again*/
if (client->packet_head == client->tail &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
/*
* count == 0 is special - no IO is done but we check
* for error conditions (see above).
*/
if (count == 0)
break;
/*调用evdev_fetch_next_event,如果获得了数据则取出来*/
while (read + input_event_size() <= count &&
evdev_fetch_next_event(client, &event)) {
/*input_event_to_user调用copy_to_user传入用户程序中,这样读取完成*/
if (input_event_to_user(buffer + read, &event))
return -EFAULT;
read += input_event_size();
}
if (read)
break;
/*如果没有数据,并且是阻塞的,则在等待队列上等待*/
if (!(file->f_flags & O_NONBLOCK)) {
error = wait_event_interruptible(evdev->wait,
client->packet_head != client->tail ||
!evdev->exist || client->revoked);
if (error)
return error;
}
}
return read;
}
当read函数调用 wait_event_interruptible进入了休眠状态时,通过evdev_event函数唤醒:
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };
evdev_events(handle, vals, 1);
---> evdev_pass_values(client, vals, count, ev_time);
---> __pass_event
---> client->buffer[client->head++] = *event; //将input输入事件数据存放在evdev_client结构体中的缓冲区中)
---> wake_up_interruptible(&evdev->wait);
}
而evdev_event()是evdev_handler->event成员,谁调用evdev_event()这个evdev_handler->event事件驱动函数,回溯函数调用:
handler->event(handle, v->type, v->code, v->value)
---> input_to_handler
---> input_pass_values
---> input_handle_event
---> input_event //向事件处理层上报数据并唤醒
6.Input APIs
-
struct input_dev *input_allocate_device(void); //向内存中分配input_dev结构体
-
input_set_capability; //设置设备可以产生哪些事件
-
input_free_device(struct input_dev *dev); //释放内存中的input_dev结构体
-
input_register_device(struct input_dev *dev); //注册一个input_dev,若有对应的驱动事件, 则在/sys/class/input下创建这个类设备
-
input_unregister_device(struct input_dev *dev); //卸载/sys/class/input目录下的
input_dev这个类设备 -
set_bit(nr,p); //设置某个结构体成员p里面的某位等于nr,支持这个功能
- set_bit(EV_KEY,buttons_dev->evbit); //设置input_dev结构体buttons_dev->evbit支持EV_KEY
- set_bit(KEY_S,buttons_dev->keybit); //设置input_dev结构体buttons_dev->keybit支持按键”S”
-
input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat); //设置绝对位移的支持参数
- dev: 需要设置的input_dev结构体
- axis : 需要设置的数组号,常用的有: ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向)
- min: axis方向的最小值, max:axis方向的最大值, fuzz: axis方向的干扰值, flat:axis方向的平焊位置
-
input_report_abs(struct input_dev *dev, unsigned int code, int value); //上报EV_ABS事件
- *dev :要上报哪个input_dev驱动设备的事件
- code: EV_ABS事件里支持的哪个方向,比如X坐标方向则填入: ABS_X
- value:对应的方向的值,比如X坐标126
-
input_report_key(struct input_dev *dev, unsigned int code, int value); //上报EV_KEY事件
-
input_sync(struct input_dev *dev); //同步事件通知,通知系统有事件上报
7.输入设备驱动案例
案例代码描述了一个button设备,产生的事件通过BUTTON_PORT引脚获取,当有按下/释放发生时,BUTTON_IRQ被触发,以下是驱动的源代码:
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/io.h>
static struct input_dev *button_dev;
static void button_interrupt(int irq, void*dummy, struct pt_regs *fp)
{
input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
input_sync(button_dev);
}
static int __init button_init(void)
{
int error;
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button",NULL)) {
printk(KERN_ERR"button.c: Can't allocate irq %d\n", button_irq);
return -EBUSY;
}
button_dev = input_allocate_device();
if (!button_dev) {
printk(KERN_ERR"button.c: Not enough memory\n");
error = -ENOMEM;
goto err_free_irq;
}
button_dev->evbit[0] = BIT(EV_KEY);
button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
error = input_register_device(button_dev);
if (error) {
printk(KERN_ERR"button.c: Failed to register device\n");
goto err_free_dev;
}
return 0;
err_free_dev:
input_free_device(button_dev);
err_free_irq:
free_irq(BUTTON_IRQ, button_interrupt);
return error;
}
static void __exit button_exit(void)
{
input_unregister_device(button_dev);
free_irq(BUTTON_IRQ, button_interrupt);
}
module_init(button_init);
module_exit(button_exit);
8.台式机触摸屏驱动
- drivers/hid/hid-multitouch.c
refer to
- https://www.jianshu.com/p/e9cfae59e3df
- https://blog.csdn.net/zifehng/article/details/70169512