这里我们只以其中的一行为例来分析一下如何给我们的input子系统上报事件。
input_report_abs(data->input_dev, ABS_RX, rbuf[0]);继续跟踪:
static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_ABS, code, value);
}
可以看到,该函数也是只调用了一个input_event函数。网名为“拉登他爹”要骂人了:“为什么一行代码也来实现一个函数,这不是忽悠老子吗?”兄弟,你要体会我们那些写linux内核代码的哥们的用心良苦(你说你想要逃,偏偏注定要落脚 ,情灭了爱熄了 ,剩下空心要不要 ,春已走花又落 ,用心良苦却成空 ,我的痛怎么形容 ,一生爱错放你的手 。张宇大哥很经典的一首歌)他们这么做完全是希望同一个函数能同时被多个其他函数调用,达到代码复用的作用,比如这里input_event(dev, EV_ABS, code, value);根据第二个参数的不同来进行不同的处理来。下次兄弟你又要处理一个按键事件,我们就直接可以这样:
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_KEY, code, value);
}
好了,废话不多说,继续跟踪进来:
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
1 unsigned long flags;
2 if (is_event_supported(type, dev->evbit, EV_MAX)) {
3 spin_lock_irqsave(&dev->event_lock, flags);
4 add_input_randomness(type, code, value);
5 input_handle_event(dev, type, code, value);
6 spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
终于看到一个还像个函数的函数了,至少有那么6行代码。兄弟,其实你我都应该感到很幸福。Linux内核中达到几百行代码代码的函数比比皆是。
1行,定义一个标识符,等下会用到。
2行,判断我们的input 设备中的evbit中是否设置了EV_ABS这个标识,以表示支持绝对值坐标。回想第二节中的set_bit(EV_ABS, akm->input_dev->evbit);没有错,我们是有设置的,所以可以往下走。
3、6两行,为我们的临界区代码加个自旋锁,防止并发访问。细心的哥们可能会发现,这和我们平时的自旋锁有些不同,一般的自旋锁都是spin_lock()和spin_unlock()成对出现的。这里好像多长了个尾巴。没错,男人和女人的某些区别好像也在这里,不好意思,思想又游离了…继续回来,我们这个自旋锁条件更苛刻。一般的自旋锁保护临界区代码不受其他cpu和本cpu的抢占进程打扰。这两个长尾巴的哥们更狠,他连我们的中断也一并拒之门外。总之,通告天下,被我占有的东西,你天王老子都别想再碰,除非我释放她了。够狠吧!是的,男人就应该对自己狠一点。补充一句:前面定义的那个flag就是用来保存被我们拒之门外的那个中断的状态信息的。
4行,为内核产生随机因子。
5行,真正有悟性的哥们应该扫一眼这几行代码就会发现,这一行才是真正的国家宝藏所在,难道这就是所谓的天赋,你不得不佩服尼古拉斯凯奇的犀利,凭着那么一点点信息就可以发现那么大的宝藏。不过现实生活中这样事情发生的概率就好比张曼玉突然为了你和她的外籍男友分手,然后来到长安,为的就是能默默守侯在你身边。继续跟进input_handle_event(dev, type, code, value):
又是一来自 input core的函数。
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;
}
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);
}
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:
1 if (is_event_supported(code, dev->absbit, ABS_MAX))
2 {
3 value = input_defuzz_abs_event(value,
4 dev->abs[code], dev->absfuzz[code]);
5 if (dev->abs[code] != value)
6 {
dev->abs[code] = value;
7 disposition = INPUT_PASS_TO_HANDLERS;
8 }
9 }
10 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);
}
有兄弟要发话了:“好长的一堆代码“,是的,我承认,这是我这篇文档到目前为止最长的一个函数。不够在大学里面稍微学了一点点C语言的哥们应该都不觉得它复杂,否则你就将无言见江东父老,更对不起谭浩强大哥。整个函数先一个switch。然后根据不同的case进行不同的处理,得到不同的disposition变量值。然后,然后就到整个代码的最后六行代码了,是不是简单的一B。这里我们传进来的参数正好是EV_ABS。所以我们只需把注意力放到代码中的加粗部分。
1行,判断我们的input 设备中的absbit中是否设置了ABS_RX,显然前面我们已经设置了不信你回过头来看看第二节中那个曾经没有讲过的函数。相信哥们你的c语言代码阅读能力绝对在我之上,区区几行代码怎么能唬得了你。
3-4行,进行误差校准。这里我初始化时设置为0。故其实啥也没干,星星还是那颗星星哟,月亮还是那个月亮, value也还是那个value。
5-7行,把value的值付给dev->abs[code],dev->abs[code]记录的是上一次该坐标值。如果是第一次,显然为0.所以最终我们得到了disposition = INPUT_PASS_TO_HANDLERS。默默地做了那么多前期工作为的就是得到她。现在终于如愿以偿,带着她从此开始浪迹天涯…..
浪到哪儿去了呢?聪明的你马上发现了浪到了最后两行代码。太阳依然发光,地球依然转动,你依然爱着心中的那个她,故事依然还在继续,input_pass_event(dev, type, code, value)也依然还在传值,他到底要把那个我们收集到的type、code、value传到哪儿去呢?想知道吗?想的话请看下一节。