[知其然不知其所以然-1]input device与UI的交互方式

最近要写一段button driver,照着内核的button.c抄了一遍,发现不能工作(这几乎是一定的)。不得已查了一下acpid的源码,把input device driver

与UI中的acpid deamon交互方式搞的一知半解了。但我又不想花时间在这上面,由于对driver不太熟(其实我对所有模块都不熟),

比较危险的事情就是深度优先学习一个知识,这样学习容易迷失方向。

其实我们大可以把不了解的模块先看作一个黑盒,了解他是怎么用的,

大体流程怎样就可以,不伤大雅,后期有需要再dig into the code。

为了不浪费看官的时间,以下内容可以不用再看了,因为重点都在上面,由于懒惰本人写的语焉不详,仅供个人参考。

1. x86下,有人按了power button键,这个时候很可能是一个fix event中断,或者是一个sci中断,

总之在我的机器上,这个中断最后是由Embedded Controller

驱动的Query method回调来处理,这个method会通过ACPI的notify机制

(你别管这个是什么机制了,就理解成调用button driver的notify回调就好了),

往button driver传0xc6号软件event,表示发生了power button的press事件,

嗯, power button的notify回调里,会根据这个编号做两件事,这两件事要达到的目的,

就是给用户态程序(主要就是UI守护进程,也就是我们的例子acpid),发送power button

按键这个消息,然后守护进程再根据这个消息,做预定义的一些操作;

2.目前已知的比较常用的内核通知用户的方式有哪些? netlink是一种比较经典的对不对?

 另外,作为power button,本身也是一个input device,所以input device交互机制

也用上了。为什么button driver要用两种方式来传递呢? 因为有些发行版的守护进程,

只用netlink来接受内核消息,另一些发行版,则跟踪input device的消息,所以

为了安全起见,两种方式都通知。

3.先看input device的通知,其实就一句话:

input_report_key(input, keycode, 0);
input_sync(input);

什么,你说是两句话?不,你一定是眼花了,这两句其实可以看作一句谢谢。

中间的传递就不说了,总之,最后的效果时,用户态程序可以通过read(/dev/input/eventx,buf),

来读取buf->event.KEY和buf->event.CODE以及buf->event.VALUE,

这三个值分别是EV_KEY,KEY_POWER,以及1, 这表示,

一个类型为EV_KEY的按键设备被按下了(value=1),这个设备的名字叫KEY_POWER。

 3.1 你一定有疑问了,这个eventx的x怎么得到?(神马?你没有疑问?看文章要随时质疑才能进步),

这是通过:

cat /proc/bus/input/devices的H: Handlers=sysrq kdb event12 

得到,也就是12

  3.2 用户态进程(acpid)得到这个消息后,会执行相应的操作(后面等netlink说完一起总结)

4. 再来看netlink往用户态传递消息的代码:

acpi_bus_generate_netlink_event(
device->pnp.device_class,
dev_name(&device->dev),
event, ++button->pushed);

也就是通过套接字往用户态传递一个数据结构(device_class, bus_id, type, value)

5 最后来看 作为守护进程的acpid, 会怎么处理这些消息:

首先,acpid的工作原理是,检查/etc/acpi/events目录下的rule文件,

找到匹配的事件后,就执行该事件对应的action(我靠,我怎么老是中英文夹杂)

比如这里有一个文件叫powerbtn:

event=button[ /]power

action=/etc/acpi/powerbtn.sh

意思就是说,凡是正则匹配button[ /]power的消息,都给我去执行/etc/acpi/powerbtn.sh,

后者里面很可能就是一句poweroff。 button[ /]power的意思是,要么匹配“button power ”,

要么匹配“button/power”字符串。之前我们在步骤3说到,acpid会收到一个结构

(EV_KEY,KEY_POWER,1)于是acpid就根据这个结构体返回一个字符串叫

"button/power PBTN 0000080 000000",然后用这个字符串去正则查找是否有

button[ /]power,于是就找到了,从而fork , execv(etc/acpi/powerbtn.sh);

对于netlink也是一样的原理,acpid收到(device_class, bus_id, type, value)后,

会把这个结构体做成一个字符串叫"button/power button 0x80 1",也用button[ /]power去正则匹配,

也找到了,从而执行fork , execv(etc/acpi/powerbtn.sh),我们可以看到,button driver如果

要传递netlink消息给用户态,必须给dev_class(dev)设置成跟用户态约定好的字符,

比如这里的"button/power",这样用户态才能匹配上。


好,我说完了。能看到这里的读者都是好同志。

你可能感兴趣的:([知其然不知其所以然-1]input device与UI的交互方式)