linux input event 子系统

linux input event 子系统,第1张

一、linux input 子系统中,每个输入设备可以建立一个devices,如插入USB mouse的时候会建立,在系统、dev/input目录下就会生成一个对应的device,如:/dev/input/event0,可以通过读取device获取输入设备的信息 具体可以访问http://blog.sina.com.cn/s/blog_602f87700101dno6.html

0.1:关键结构体input_event信息:

struct input_event {

struct timeval time

__u16 type

__u16 code

__s32 value

}

type: 设备类型。可以设置为:

sdk封装的解决思路;

type:EV_REL鼠标设备 0x02

code : rel_x 0x00 表示x轴方向 rel_y 0x01 表示y轴方向 (一次鼠标移动会产生两个input event事件

value: EV_REL type下有正负表示方向

介绍键盘的code

Type为EV_KEY时,value: 0表示按键抬起。1表示按键按下。(4表示持续按下等?)。

问题:因为会出现一次鼠标移动就有两个事件产生,所以就要判断这一时刻到底是哪个事件

方法:

鼠标事件:

上1

下0

左2

右3

键盘事件:

上103

下108

左105

右106

停28

蓝牙键盘

1:2

2:3

3:4

4:5

5:6

w:17

a:30

s:31

d:32

EV_SYN 同步事件

EV_KEY 键盘事件

EV_REL 相对坐标事件,用于鼠标

EV_ABS 绝对坐标事件,用于摇杆

EV_MSC 其他事件

EV_LED LED灯事件

EV_SND 声音事件

EV_REP 重复按键事件

EV_FF 受力事件

EV_PWR 电源事件

EV_FF_STATUS 受力状态事件

在调试一下红外遥控器input驱动时,直接采用的是一个半成品的驱动在上边实现的自己的设备的匹配,但同时遇到了一些关于input输入子系统的疑惑。

按键一般有「按下和抬起」两个状态一般使用0和1来分别表示。一般如下方式上报按键键值就可以完成「按下和抬起」两个状态的收集。

input_event(ddata->input, EV_KEY, KEY_POWER, 1)

input_sync(ddata->input)

但是最近遇到一个奇怪的问题是内核中的KEY_WAKEUP唤醒键值使用上述方法上报时,用户空间只能检测到状态0,第二次按键时才会有状态1。这样导致Android系统不能正常唤醒,需要按两次才能唤醒系统。

目前的解决方法是将之前上报KEY_WAKEUP的地上改为KEY_POWER键值。但是好奇心引着我弄清楚它们是怎么回事。

经验出这里边上报如下一样连续上报1/0状态才可以在用户空间正常的检测到1/0状态。

input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1)

input_sync(ddata->input)

input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0)

input_sync(ddata->input)

直觉告诉我可以是由于我对这个两个api的不了解造成的,比较是凡事必有因的。

除了KEY_WAKEUP换个其它键值试试。结果和KEY_WAKEUPG一样不能同步,可以推断出是非POWER按键就不行。这可以能所在代码位置有关系:

}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){

input_event(ddata->input, EV_KEY, KEY_POWER, 1)

input_sync(ddata->input)

}

再进一步测试在非PM_SUSPEND_ON电源模式下,所有的按键都是如何的。测试结果是所有的非POWER按键都出现了按键不能同步的问题。但是不能以点概面,使用GPIO连接的物理按键并不会有此问题,那么就排除了input子系统中做了手脚。问题出就出在了Remote control驱动中对的处理。

找出了问题所在了,确实是出在了Remote control驱动中,上报键值对PM状态进行了判断,如果

static void remotectl_timer(unsigned long _data)

if(ddata->press != ddata->pre_press) {

ddata->pre_press = ddata->press = 0

if (get_suspend_state()==0){

//input_event(ddata->input, EV_KEY, ddata->keycode, 1)

//input_sync(ddata->input)

input_event(ddata->input, EV_KEY, ddata->keycode, 0)

input_sync(ddata->input)

}else if ((get_suspend_state())&&(ddata->keycode==KEY_POWER)){

//input_event(ddata->input, EV_KEY, KEY_WAKEUP, 1)

//input_sync(ddata->input)

input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0)

input_sync(ddata->input)

}

}

将过滤条件去除后,可以和GPIO连接的物理按键一样的效果了,即无论系统处理什么样的状态,休眠或者唤醒状态都上传了键值。同时这也给我带来了一个疑惑,按键驱动中要不要进行suspend状态判断,根据Android中的经验所有的状态都要上传的,响应不响应是看上层系统的决定;但是如果对于普通的嵌入式Linux系统就不一定了,如果input子系统在系统休眠的时候上传了键值,那么对应的应用层可以就会直接去响应键值。要使用哪种方法实现,这是一个悖论!结合Android的宏这样实现了:

diff --Git a/drivers/input/remotectl/rkxx_remotectl.c b/drivers/input/remotectl/rkxx_remotectl.c

index db91516..201c5dd 100644

--- a/drivers/input/remotectl/rkxx_remotectl.c

+++ b/drivers/input/remotectl/rkxx_remotectl.c

@@ -306,6 +306,10 @@ static void remotectl_do_something(unsigned long data)

if ((ddata->scanData&0x0ff) == ((~ddata->scanData >>8)&0x0ff)){

if (remotectl_keycode_lookup(ddata)){

ddata->press = 1

+#ifdef CONFIG_ANDROID // Android OS needs input event whatever suspend state

+input_event(ddata->input, EV_KEY, ddata->keycode, 1)

+input_sync(ddata->input)

+#else

if (ddata->keycode==KEY_POWER || get_suspend_state()==PM_SUSPEND_ON){

input_event(ddata->input, EV_KEY, ddata->keycode, 1)

input_sync(ddata->input)

@@ -314,6 +318,7 @@ static void remotectl_do_something(unsigned long data)

}

//input_event(ddata->input, EV_KEY, ddata->keycode, ddata->press)

//input_sync(ddata->input)

+#endif // CONFIG_ANDROID

ddata->state = RMC_SEQUENCE

}else{

ddata->state = RMC_PRELOAD

@@ -437,6 +442,10 @@ static void remotectl_timer(unsigned long _data)

if(ddata->press != ddata->pre_press) {

ddata->pre_press = ddata->press = 0

+#ifdef CONFIG_ANDROID // Android OS needs input event whatever suspend state

+input_event(ddata->input, EV_KEY, ddata->keycode, 0)

+input_sync(ddata->input)

+#else

if (get_suspend_state()==0){

//input_event(ddata->input, EV_KEY, ddata->keycode, 1)

//input_sync(ddata->input)

@@ -448,6 +457,7 @@ static void remotectl_timer(unsigned long _data)

input_event(ddata->input, EV_KEY, KEY_WAKEUP, 0)

input_sync(ddata->input)

}

+#endif // CONFIG_ANDROID

}

#ifdef CONFIG_PM

remotectl_wakeup(_data)

如果是Android系统,那么无论kernel处理什么样的休眠状态都实时地上报键值。这样保证在休眠播放音乐的时候可以控制音频大小。这也正是目前Android手机的实现方式。

http://blog.csdn.Net/kangear/article/details/40072707

还有一点:按键中的状0,并不是input_sync(ddata->input)发出的,它只会发出当前的值。它仅仅是一个「同步」,意思是数据都准备好了,可以发送了。还是没有对驱动了解的很清楚加上自己的一些瞎想像误导了自己。内核input驱动中是不区分POWER键,WAKEUP键;真是有差异了,问题一定是出在了自己的驱动代码中。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7653935.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-08
下一篇 2023-04-08

发表评论

登录后才能评论

评论列表(0条)

保存