input_report_XXX函数

 

输入子系统设备通告各种事件通过input_report_XXX族函数
 
/* 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。这些API 其实都是input_event()的封装.代码如下:

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);//调用事件分发函数input_handle_event,做进一步的传递
 spin_unlock_irqrestore(&dev->event_lock, flags);
 }
}
首先,先判断设备产生的这个事件是否合法.如果合法,流程转入到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_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);
}
在这里,我们忽略掉具体事件的处理.到最后,如果该事件需要input device 来完成的,就会将disposition 设置成INPUT_PASS_TO_DEVICE.如果需要handler 来完成的,就将dispostion 设为INPUT_PASS_TO_HANDLERS.如果需要两者都参与,将disposition 设置为INPUT_PASS_TO_ALL.需要输入设备参与的,回调设备的event 函数.如果需要handler 参与的.调用input_pass_event()

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);//获取独占设备的handle的指针
 if (handle)
 handle->handler->event(handle, type, code, value);//如果有独占设备的handle,则仅仅将事件传给独占的handle对应的handler
 else
 list_for_each_entry_rcu(handle, &dev->h_list, d_node)//遍历与此设备连接的每一个handle
 if (handle->open)//如果handle已经打开
 handle->handler->event(handle,
 type, code, value);//将事件分发给handler的事件处理函数
 rcu_read_unlock();
}
如果input device 被强制指定了handler,则调用该handler 的event 函数.结合handle 注册的分析.我们知道.会将handle 挂到input device 的h_list 链表上.如果没有为input device 强制指定handler.就会遍历input device->h_list 上的handle 成员.如果该handle 被打开,则调用与输入设备对应的handler 的event()函数.注意,只有在handle 被打开的情况下才会接收到事件.另外,输入设备的handler 强制设置一般是用带EVIOCGRAB 标志的ioctl 来完成的.如下是发图的方示总结evnet 的处理过程:

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值