Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1366091
  • 博文数量: 860
  • 博客积分: 425
  • 博客等级: 下士
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-20 19:57
个人简介

对技术执着

文章分类

全部博文(860)

文章存档

2019年(16)

2018年(12)

2015年(732)

2013年(85)

2012年(15)

我的朋友

分类: LINUX

2013-05-29 18:45:47

原文地址:linux输入子系统(4) 作者:chumojing

输入子系统设备报告各种事件通过input_report_XXX族函数,例如程序清单 1.5中报告按键事件。按键、相对坐标、绝对坐标和同步事件报告的函数如程序清单 1.12所示。

 

1.12  事件报告函数

/* include/linux/input.h */

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

{

         input_event(dev, EV_KEY, code, !!value);                                                                                  

}

 

static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)

{

         input_event(dev, EV_REL, code, value);

}

 

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)

{

         input_event(dev, EV_ABS, code, value);

}

 

static inline void input_sync(struct input_dev *dev)

{

         input_event(dev, EV_SYN, SYN_REPORT, 0);

}

可以看到,这四个函数都调用了input_event,并且在将按键的value转化为布尔类型的值。所以按键传给input corevalue0(释放)或者1(按下)

input_event函数的代码如程序清单 1.13所示。

1.13  input_event

/* driver/input/input.c */

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

本函数总共有两行有效的调用:

由于输入事件具有随机性,因此用输入事件来增加内核熵池的熵。

调用事件分发函数input_handle_event,做进一步的传递。

input_handle_event的代码如所示。

 

/* driver/input/input.c */

#define INPUT_IGNORE_EVENT                 0

#define INPUT_PASS_TO_HANDLERS       1

#define INPUT_PASS_TO_DEVICE              2

#define INPUT_PASS_TO_ALL                      (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)

 

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

                            }

 

                            disposition = INPUT_PASS_TO_HANDLERS;                                                                                     

                   }

                   break;

 

         case EV_ABS:

                   if (is_event_supported(code, dev->absbit, ABS_MAX)) {                                               

 

                            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;

                  ························

         }

 

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

}

上述代码中去除了其他事件的部分,线面说明按键、相对坐标和绝对坐标的处理部分:

检查按键是否为驱动所支持,只有之前注册过的按键才会继续传递。

检查报告的按键状态是否和上次相同。如果连续多次报告按键按下,则只处理第一次。

如果不是连击事件。

翻转按键的当前状态(按下和释放)

如果是按下,则开始连击计时。

标记消息传递方向。

检查绝对坐标轴是否驱动所支持的。

根据当前报告的值和上次报告的值确定传给处理程序的绝对值大小。

如果本次需要报告的绝对值和上次不同,则将事件传递给处理函数。

检查相对坐标轴是否被驱动所支持。

可以看到input_handle_event分发事件有两个方向:驱动的回调函数dev->eventinput coreinput_pass_event。下面继续分析input_pass_event,代码如程序清单 1.14所示。

 

1.14  input_pass_event

/* driver/input/input.c */

static void input_pass_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

{

         struct input_handle *handle;

 

         rcu_read_lock();

         handle = rcu_dereference(dev->grab);                                                                                         

         if (handle)

                   handle->handler->event(handle, type, code, value);

         else

                   list_for_each_entry_rcu(handle, &dev->h_list, d_node)                                                    

                            if (handle->open)                                                                                                      

                                     handle->handler->event(handle, type, code, value);                                        

         rcu_read_unlock();

}

 

这个函数将事件分发给相关的handler

获取独占设备的handle的指针。如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler

遍历与此设备连接的每一个handle

如果hnadle已经被打开。

将事件分发给handler的事件处理函数。

到这里,input core分发事件的任务已经完成,接下来由各个handler处理接收到的事件。

阅读(723) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~