您的位置:首页 > 运维架构 > Linux

linux键盘input_event浅析【转】

2016-01-07 11:15 579 查看
转自:/article/2159704.html

input_event(mxckbd_dev, EV_KEY, mxckpd_keycodes[scancode], 0);

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);
}
}

***********************************************************************************************
static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max)
{
return code <= max && test_bit(code, bm);
}

static inline int test_bit(int nr, const volatile unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
***********************************************************************************************
void add_input_randomness(unsigned int type, unsigned int code, unsigned int value)
{
static unsigned char last_value;

/* ignore autorepeat and the like */
if (value == last_value)
return;

DEBUG_ENT("input event\n");
last_value = value;
add_timer_randomness(&input_timer_state, (type << 4) ^ code ^ (code >> 4) ^ 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_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);
}

// INPUT_PASS_TO_HANDLERS: 事件处理的方式是传递给事件处理器
disposition = INPUT_PASS_TO_HANDLERS;
}
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);
}

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);

//如果是绑定的handle,则调用绑定的handler->event函数
if (handle)
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;

// 调用相关的事件处理器的event函数,进行事件的处理
handler->event(handle, type, code, value);

}
else if(handler->filter(handle, type, code, value))
filtered = true;
}
}

rcu_read_unlock();
}

static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) // evdev.c
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
struct timespec ts;

ktime_get_ts(&ts);

// 将传过来的事件,赋值给input_event结构
event.time.tv_sec = ts.tv_sec;
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绑定了client那么,处理这个客户端,触摸屏驱动没有绑定
evdev_pass_event(client, &event);
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函数最终将事件传递给了用户端的client结构中的input_event数组中,只需将这个input_event数组
// 复制给用户空间,进程就能收到触摸屏按下的信息了。具体处理由具体的应用程序来完成。
static void evdev_pass_event(struct evdev_client *client, struct input_event *event) // evdev.c
{
/*
* Interrupts are disabled, just acquire the lock
*/
spin_lock(&client->buffer_lock);
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);
}
***********************************************************************************************
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: