一、input子系统简介
1.1、input子系统原理
在Linux中,输
入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event
Handler)组成。其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理
层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱
动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。下面用图形来描述一下这三者的关系!
从上图可以看出,对于设备驱动层,主要涉及结构体input_dev,对于核心层,主要涉及结构体handle,而对于事件层涉及到了结构体handler。接下来会对这三个结构体进行详细的描述。
现在我们从设备模型来看下input子系统所处的位置:
从上图可以看出,input处于kernel层,input向下操作设备寄存器,向上提供了设备驱动程序操作的设备节点。
1.2、注册input核心
这里所说的input核心,就是指input.c文件中提供的函数,包括1.1中涉及三个结构体的操作函数。
在input.c文件中,有模块初始化和退出函数,如:
-
struct class input_class = {
-
.name = "input",
-
.devnode = input_devnode,
-
};
-
static int __init input_init(void)
-
{
-
int err;
-
-
err = class_register(&input_class);
-
if (err) {
-
pr_err("unable to register input_dev class\n");
-
return err;
-
}
-
-
err = input_proc_init();
-
if (err)
-
goto fail1;
-
-
err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
-
if (err) {
-
pr_err("unable to register char major %d", INPUT_MAJOR);
-
goto fail2;
-
}
-
-
return 0;
-
-
fail2: input_proc_exit();
-
fail1: class_unregister(&input_class);
-
return err;
-
}
-
static void __exit input_exit(void)
-
{
-
input_proc_exit();
-
unregister_chrdev(INPUT_MAJOR, "input");
-
class_unregister(&input_class);
-
}
-
subsys_initcall(input_init);
-
module_exit(input_exit);
说明:
1) 这里初始化使用的是subsys_initcall,具有较高优先级。
2) 在初始化中,首先注册了input类,实际就是在/sys/class目录下建立一个input目录。
3) input的proc文件系统初始化。
4) 静态注册设备号。
二、input_dev设备相关函数
在上面“输入子系统图”中,最左边是设备驱动层,其中涉及结构体input_dev,现在就来讲述其中涉及到的结构体和操作函数。
2.1、input_dev结构体简述
-
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
-
struct input_dev {
-
const char *name;
-
const char *phys;
-
const char *uniq;
-
struct input_id id;
-
-
unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
-
-
unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
-
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)];
-
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];
-
-
struct input_mt_slot *mt;
-
int mtsize;
-
int slot;
-
int trkid;
-
-
struct input_absinfo *absinfo;
-
-
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
-
unsigned long led[BITS_TO_LONGS(LED_CNT)];
-
unsigned long snd[BITS_TO_LONGS(SND_CNT)];
-
unsigned long sw[BITS_TO_LONGS(SW_CNT)];
-
-
int (*open)(struct input_dev *dev);
-
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;
-
-
bool sync;
-
-
struct device dev;
-
-
struct list_head h_list;
-
struct list_head node;
-
};
说明:
1) 结构体中包括名称、id和链表等。
2) 结构体中有很多数组,数组成员大小使用宏BITS_TO_LONGS计算。
3) 因为这些数组中,每个成员中的一位代表一种类型,所以此处就是根据其支持最多的类型,计算出数组中需要几个成员。
2.2、分配input_dev设备函数:input_allocate_device()
-
struct input_dev *input_allocate_device(void)
-
{
-
struct input_dev *dev;
-
-
dev = kzalloc(sizeof(struct input_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);
-
INIT_LIST_HEAD(&dev->h_list);
-
INIT_LIST_HEAD(&dev->node);
-
-
__module_get(THIS_MODULE);
-
}
-
-
return dev;
-
}
说明:
1) 首先申请了结构体input_dev内存。
2) 如果申请成功,对其成员进行初始化,包括对设备的类型和类初始化,设备的类属于input,则其会显示在/sys/class/input目录下。
3) 对input设备中的设备进行初始化。
4) 初始化互斥锁和链表。
2.3、注册input_dev设备函数:input_register_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 (!dev->hint_events_per_packet)
-
dev->hint_events_per_packet =
-
input_estimate_events_per_packet(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);
-
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) {
-
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;
-
}
说明:
1) 首先设置,支持同步。
2) 初始化延时定时器,初始化其成员变量。
3) 初始化设备dev成员。
4) 将input设备中的链表链入input设备全局链表input_dev_list中。
5) 遍历链表input_handler_list,由于input设备注册先执行,所以此处input_handler链表为空,不执行input_attach_handler(dev, handler);。
接下来看下定时器到时执行函数input_repeat_key():
-
/*
-
* Generate software autorepeat event. Note that we take
-
* dev->event_lock here to avoid racing with input_event
-
* which may cause keys get "stuck".
-
*/
-
static void input_repeat_key(unsigned long data)
-
{
-
struct input_dev *dev = (void *) data;
-
unsigned long flags;
-
-
spin_lock_irqsave(&dev->event_lock, flags);
-
-
if (test_bit(dev->repeat_key, dev->key) &&
-
is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
-
-
input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
-
-
if (dev->sync) {
-
/*
-
* Only send SYN_REPORT if we are not in a middle
-
* of driver parsing a new hardware packet.
-
* Otherwise assume that the driver will send
-
* SYN_REPORT once it's done.
-
*/
-
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-
}
-
-
if (dev->rep[REP_PERIOD])
-
mod_timer(&dev->timer, jiffies +
-
msecs_to_jiffies(dev->rep[REP_PERIOD]));
-
}
-
-
spin_unlock_irqrestore(&dev->event_lock, flags);
-
}
说明:
1) 在触摸屏中,该函数在持续触摸状态下会被调用。即如果触摸屏一直被按下,那么每隔定时时间到达,此函数即被执行。
2) 首先上自旋锁,保护临界区。
3) 判断是否支持按键事件。
4) 报告按键值,如果此次支持同步,向应用层报告同步事件。
5) 如果设置了定时器重新启动周期,那么就重新启动定时器。
2.4、注销input设备函数input_unregister_device()
-
void input_unregister_device(struct input_dev *dev)
-
{
-
struct input_handle *handle, *next;
-
-
input_disconnect_device(dev);
-
-
mutex_lock(&input_mutex);
-
-
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
-
handle->handler->disconnect(handle);
-
WARN_ON(!list_empty(&dev->h_list));
-
-
del_timer_sync(&dev->timer);
-
list_del_init(&dev->node);
-
-
input_wakeup_procfs_readers();
-
-
mutex_unlock(&input_mutex);
-
-
device_unregister(&dev->dev);
-
}
说明:
1) 注销函数是注册函数的相反过程。
2) 主要就是删除注销函数中申请的资源。
3) 调用handler中注册的断开函数。
三、handler相关函数
3.1、handler结构体简述
handler结构体内容如下:
-
struct input_handler {
-
-
void *private;
-
-
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
-
bool (*match)(struct input_handler *handler, struct input_dev *dev);
-
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
-
void (*disconnect)(struct input_handle *handle);
-
void (*start)(struct input_handle *handle);
-
-
const struct file_operations *fops;
-
int minor;
-
const char *name;
-
-
const struct input_device_id *id_table;
-
-
struct list_head h_list;
-
struct list_head node;
-
}
说明:
1) handler结构体中定义了input回调函数,包括链接、释放事件函数等。
2) 定义了应用层操作结构体。
3) 定义了设备的次设备号。
4) 定义了input设备ID表。
5) 定义了链表。
3.2、注册handler函数input_register_handler()
在讨论handler之前,先看一下input.c文件中的全局数组变量:static struct input_handler *input_table[8];。
从上可以看到,此数组共有8个成员。在Linux中,最多可以支持8个handler,每个handler最多可以支持32个次设备。也即
32*8=256。那么在注册input_handler时,其成员.minor必须是32的倍数,即:0、32、64、96、128、160、192和
224。这些数是一个handler的次设备号的基址。
handler注册程序如下:
-
int input_register_handler(struct input_handler *handler)
-
{
-
struct input_dev *dev;
-
int retval;
-
-
retval = mutex_lock_interruptible(&input_mutex);
-
if (retval)
-
return retval;
-
-
INIT_LIST_HEAD(&handler->h_list);
-
-
if (handler->fops != NULL) {
-
if (input_table[handler->minor >> 5]) {
-
retval = -EBUSY;
-
goto out;
-
}
-
input_table[handler->minor >> 5] = handler;
-
}
-
-
list_add_tail(&handler->node, &input_handler_list);
-
-
list_for_each_entry(dev, &input_dev_list, node)
-
input_attach_handler(dev, handler);
-
-
input_wakeup_procfs_readers();
-
-
out:
-
mutex_unlock(&input_mutex);
-
return retval;
-
}
说明:
1) 首先锁定互斥锁,然后初始化handler中的链表。
2) 判断handler中是否有fops成员,如果有就按照次设备作为标识保存handler。
3) 将handler的链表插入handler的全局链表input_handler_list中。
4) 遍历input_dev_list设备链表,由2.2中知道,此时input设备链表中已经有成员了。
5) 关联input设备和handler,程序如下:
-
static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
-
{
-
const struct input_device_id *id;
-
int error;
-
-
id = input_match_device(handler, dev);
-
if (!id)
-
return -ENODEV;
-
-
error = handler->connect(handler, dev, id);
-
if (error && error != -ENODEV)
-
pr_err("failed to attach handler %s to device %s, error: %d\n",
-
handler->name, kobject_name(&dev->dev.kobj), error);
-
-
return error;
-
}
说明:
1) 首先查找匹配的设备。
2) 调用handler的连接函数,也就是《input子系统(一)--GSC3280触摸屏驱动》中的tsdev_connect()函数。
3) tsdev_connect()函数中使用input_register_handle()注册了handle。
四、handle相关函数
4.1、handle结构体简述
-
struct input_handle {
-
-
void *private;
-
-
int open;
-
const char *name;
-
-
struct input_dev *dev;
-
struct input_handler *handler;
-
-
struct list_head d_node;
-
struct list_head h_node;
-
};
说明:
1) 结构体中定义私有指针和名称等。
2) 定义input设备和handler指针。
3) 定义链表。
4.2、handle注册函数input_register_handle():
-
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;
-
}
说明:
1) 函数分别将handle的链表插入到设备和handler的链表中。
五、input核心中触摸屏相关函数
4.1、input_set_abs_params()
-
struct input_absinfo {
-
__s32 value;
-
__s32 minimum;
-
__s32 maximum;
-
__s32 fuzz;
-
__s32 flat;
-
__s32 resolution;
-
};
-
void input_alloc_absinfo(struct input_dev *dev)
-
{
-
if (!dev->absinfo)
-
dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo),
-
GFP_KERNEL);
-
-
WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
-
}
-
void input_set_abs_params(struct input_dev *dev, unsigned int axis,
-
int min, int max, int fuzz, int flat)
-
{
-
struct input_absinfo *absinfo;
-
-
input_alloc_absinfo(dev);
-
if (!dev->absinfo)
-
return;
-
-
absinfo = &dev->absinfo[axis];
-
absinfo->minimum = min;
-
absinfo->maximum = max;
-
absinfo->fuzz = fuzz;
-
absinfo->flat = flat;
-
-
dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
-
}
说明:
1) 首先查看设备是否有absinfo结构体,如果没有,就申请。
2) 对absinfo结构体初始化,设置其最大最小值。
3) 设置input设备结构体中的absbit数组,表示对相应操作类型的支持。
4.2、报告事件函数
input_report_abs()、input_report_key()和input_sync()等报告事件函数中,查看其函数体,最后都是调用input_event()函数,如下:
-
static inline int is_event_supported(unsigned int code,
-
unsigned long *bm, unsigned int max)
-
{
-
return code <= max && test_bit(code, bm);
-
}
-
void input_event(struct input_dev *dev,
-
unsigned int type, unsigned int code, int value)
-
{
-
unsigned long flags;
-
-
if (is_event_supported(type, dev->evbit, EV_MAX)) {
-
-
spin_lock_irqsave(&dev->event_lock, flags);
-
add_input_randomness(type, code, value);
-
input_handle_event(dev, type, code, value);
-
spin_unlock_irqrestore(&dev->event_lock, flags);
-
}
-
}
说明:
1) 首先判断是否支持此类型。
2) 如果支持,调用input_handle_event(dev, type, code, value);函数。
-
static void input_handle_event(struct input_dev *dev,
-
unsigned int type, unsigned int code, int value)
-
{
-
int disposition = INPUT_IGNORE_EVENT;
-
-
switch (type) {
-
-
case EV_SYN:
-
switch (code) {
-
case SYN_CONFIG:
-
disposition = INPUT_PASS_TO_ALL;
-
break;
-
-
case SYN_REPORT:
-
if (!dev->sync) {
-
dev->sync = true;
-
disposition = INPUT_PASS_TO_HANDLERS;
-
}
-
break;
-
case SYN_MT_REPORT:
-
dev->sync = false;
-
disposition = INPUT_PASS_TO_HANDLERS;
-
break;
-
}
-
break;
-
-
case EV_KEY:
-
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-
!!test_bit(code, dev->key) != value) {
-
-
if (value != 2) {
-
__change_bit(code, dev->key);
-
if (value)
-
input_start_autorepeat(dev, code);
-
else
-
input_stop_autorepeat(dev);
-
}
-
-
disposition = INPUT_PASS_TO_HANDLERS;
-
}
-
break;
-
-
case EV_SW:
-
if (is_event_supported(code, dev->swbit, SW_MAX) &&
-
!!test_bit(code, dev->sw) != value) {
-
-
__change_bit(code, dev->sw);
-
disposition = INPUT_PASS_TO_HANDLERS;
-
}
-
break;
-
-
case EV_ABS:
-
if (is_event_supported(code, dev->absbit, ABS_MAX))
-
disposition = input_handle_abs_event(dev, code, &value);
-
-
break;
-
-
case EV_REL:
-
if (is_event_supported(code, dev->relbit, REL_MAX) && value)
-
disposition = INPUT_PASS_TO_HANDLERS;
-
-
break;
-
-
case EV_MSC:
-
if (is_event_supported(code, dev->mscbit, MSC_MAX))
-
disposition = INPUT_PASS_TO_ALL;
-
-
break;
-
-
case EV_LED:
-
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
-
!!test_bit(code, dev->led) != value) {
-
-
__change_bit(code, dev->led);
-
disposition = INPUT_PASS_TO_ALL;
-
}
-
break;
-
-
case EV_SND:
-
if (is_event_supported(code, dev->sndbit, SND_MAX)) {
-
-
if (!!test_bit(code, dev->snd) != !!value)
-
__change_bit(code, dev->snd);
-
disposition = INPUT_PASS_TO_ALL;
-
}
-
break;
-
-
case EV_REP:
-
if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
-
dev->rep[code] = value;
-
disposition = INPUT_PASS_TO_ALL;
-
}
-
break;
-
-
case EV_FF:
-
if (value >= 0)
-
disposition = INPUT_PASS_TO_ALL;
-
break;
-
-
case EV_PWR:
-
disposition = INPUT_PASS_TO_ALL;
-
break;
-
}
-
-
if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-
dev->sync = false;
-
-
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
-
dev->event(dev, type, code, value);
-
-
if (disposition & INPUT_PASS_TO_HANDLERS)
-
input_pass_event(dev, type, code, value);
-
}
说明:
1) 我们拿EV_ABS事件作为例子,最后调用input_handle_abs_event(dev, code, &value);函数。
-
static int input_handle_abs_event(struct input_dev *dev,
-
unsigned int code, int *pval)
-
{
-
bool is_mt_event;
-
int *pold;
-
-
if (code == ABS_MT_SLOT) {
-
/*
-
* "Stage" the event; we'll flush it later, when we
-
* get actual touch data.
-
*/
-
if (*pval >= 0 && *pval < dev->mtsize)
-
dev->slot = *pval;
-
-
return INPUT_IGNORE_EVENT;
-
}
-
-
is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
-
-
if (!is_mt_event) {
-
pold = &dev->absinfo[code].value;
-
} else if (dev->mt) {
-
struct input_mt_slot *mtslot = &dev->mt[dev->slot];
-
pold = &mtslot->abs[code - ABS_MT_FIRST];
-
} else {
-
/*
-
* Bypass filtering for multi-touch events when
-
* not employing slots.
-
*/
-
pold = NULL;
-
}
-
-
if (pold) {
-
*pval = input_defuzz_abs_event(*pval, *pold,
-
dev->absinfo[code].fuzz);
-
if (*pold == *pval)
-
return INPUT_IGNORE_EVENT;
-
-
*pold = *pval;
-
}
-
-
/* Flush pending "slot" event */
-
if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
-
input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
-
input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
-
}
-
-
return INPUT_PASS_TO_HANDLERS;
-
}
-
static void input_pass_event(struct input_dev *dev,
-
unsigned int type, unsigned int code, int value)
-
{
-
struct input_handler *handler;
-
struct input_handle *handle;
-
-
rcu_read_lock();
-
-
handle = rcu_dereference(dev->grab);
-
if (handle)
-
handle->handler->event(handle, type, code, value);
-
else {
-
bool filtered = false;
-
-
list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
-
if (!handle->open)
-
continue;
-
-
handler = handle->handler;
-
if (!handler->filter) {
-
if (filtered)
-
break;
-
-
handler->event(handle, type, code, value);
-
-
} else if (handler->filter(handle, type, code, value))
-
filtered = true;
-
}
-
}
-
-
rcu_read_unlock();
-
}
说明:
1) 在input_handle_abs_event(dev, code, &value);函数中,调用input_pass_event()函数,该函数调用handler中的event函数,即《input子系统(一)--GSC3280触摸屏驱动》3.3中的tsdev_event()函数。