三. 事件传递过程(以s3c2410_ts为例)
1. 事件产生
当按下触摸屏时,进入触摸屏按下中断,开始ad转换,ad转换完成进入ad完成中断,在这个中断中将事件发送出去,调用 input_report_abs(dev, ABS_X, xp);
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
input_report_abs(dev, ABS_Y, yp); 这两个函数调用了 input_event(dev, EV_ABS, code, value)
所有的事件报告函数都调用这个函数。
2. 事件报告
(1) input_event 函数分析,这个函数定义在input.c中
/**
* input_event() - report new input event
* @dev: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
*
* This function should be used by drivers implementing various input
* devices to report input events. See also input_inject_event().
*
* NOTE: input_event() may be safely used right after input device was
* allocated with input_allocate_device(), even before it is registered
* with input_register_device(), but the event will not reach any of the
* input handlers. Such early invocation of input_event() may be used
* to 'seed' initial state of a switch or initial position of absolute
* axis, etc.
*/
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);
}
}
EXPORT_SYMBOL(input_event);
(2) input_handle_event 函数分析,这个函数定义在input.c中.
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 = 1;
disposition = INPUT_PASS_TO_HANDLERS;
}
break;
case SYN_MT_REPORT:
dev->sync = 0;
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)) {
if (test_bit(code, input_abs_bypass)) {
disposition = INPUT_PASS_TO_HANDLERS;
break;
}
value = input_defuzz_abs_event(value,
dev->abs[code], dev->absfuzz[code]);
if (dev->abs[code] != value) {
dev->abs[code] = value;
disposition = INPUT_PASS_TO_HANDLERS;
}
}
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 = 0;
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);
}
函数主要是根据事件类型的不同,做相应的处理。
只关心EV_KEY类型,其他函数和事件传递关系不大,只要关心,disposition这个是事件处理的方式,默认的是INPUT_IGNORE_EVENT,忽略这个事件,如果是INPUT_PASS_TO_HANDLERS则是传递给事件处理器,如果是INPUT_PASS_TO_DEVICE,则是传递给设备处理,触摸屏驱动没有定义这个。
下面分析input_pass_event函数。
/*
* Pass event first through all filters and then, if event has not been
* filtered out, through all open handles. This function is called with
* dev->event_lock held and interrupts disabled.
*/
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->handler->event(handle, type, code, value);
else { //如果没有绑定,则遍历dev的h_list链表,寻找handle,如果handle已经打开,说明有进程读取设备关联的evdev。
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); // 调用相关的事件处理器的event函数,进行事件的处理
} else if (handler->filter(handle, type, code, value))
filtered = true;
}
}
rcu_read_unlock();
}
下面分析 evdev事件处理器的event函数: evdev_event()
/*
* Pass incoming event to all connected clients.
*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
struct timespec ts;
ktime_get_ts(&ts);
event.time.tv_sec = ts.tv_sec; //将传过来的事件,赋值给input_event结构
event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
event.type = type;
event.code = code;
event.value = value;
rcu_read_lock();
client = rcu_dereference(evdev->grab);
if (client)
evdev_pass_event(client, &event); //如果evdev绑定了client那么,处理这个客户端,触摸屏驱动没有绑定
else //遍历client链表,调用evdev_pass_event函数
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event);
rcu_read_unlock();
wake_up_interruptible(&evdev->wait); //唤醒等待的进程
}
下面分析 evdev_pass_event()函数:
static void evdev_pass_event(struct evdev_client *client,
struct input_event *event)
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
wake_lock_timeout(&client->wake_lock, 5 * HZ);
client->buffer[client->head++] = *event; //将事件赋值给客户端的input_event 数组
client->head &= EVDEV_BUFFER_SIZE - 1;
spin_unlock(&client->buffer_lock);
if (event->type == EV_SYN)
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
看出, evdev_pass_event函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。