編輯:關於Android編程
Android底層開發之Linux輸入子系統要不要判斷系統休眠狀態上報鍵值
題外話:一個問題研究到最後,那邊記錄文檔的前半部分基本上都是無用的,甚至是錯誤的。重點在最後,前邊僅僅是一些假想推測。
在調試一下紅外遙控器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手機的實現方式。
還有一點:按鍵中的狀0,並不是input_sync(ddata->input);發出的,它只會發出當前的值。它僅僅是一個「同步」,意思是數據都准備好了,可以發送了。還是沒有對驅動了解的很清楚加上自己的一些瞎想像誤導了自己。內核input驅動中是不區分POWER鍵,WAKEUP鍵;真是有差異了,問題一定是出在了自己的驅動代碼中。
這幾天開發要用到微信授權的功能,所以就研究了一下。可是微信開放平台接入指南裡有幾個地方寫的不清不楚。在此總結一下,以便需要的人。很多微信公眾平台的應用如果移植到app上的
一、VC與模板概念的理解MVC本來是存在於Desktop程序中的,M是指數據模型,V是指用戶界面,C則是控制器。使用MVC的目的是將M和V的實現代碼分離,從而使同一個程序
關於Handler的總結。 Message:消息,其中包含了消息ID,消息處理對象以及處理的數據等,由MessageQueue統一列隊,終由Handler處理。 H
HttpURLConnection 拋出異常 Http的URL鏈接, 會發生錯誤, 主要原因是 在主UI線程中, 使用網絡調用(network call),