linux4.1.15核心GPOP_KEY按鍵原理和使用
本文將以imx6q的板子(核心版本4.1.15)和相應BSP程式碼來詳細描述在linux下, 使用GPIO當做按鍵的實現原理及使用方法。
Linux 核心下的 drivers/input/keyboard/gpio_keys.c實現了一個體繫結構無關的GPIO按鍵驅動,使用此按鍵驅動,只需在相應的裝置樹定義相關的資料即可。驅動的實現非常簡單,但是較適合於實現獨立式按鍵驅動。
gpio-keys是基於input架構實現的一個通用GPIO按鍵驅動。該驅動基於platform_driver架構,實現了驅動和裝置分離,符合Linux裝置驅動模型的思想。工程中的按鍵驅動我們一般都會基於gpio-keys來寫,所以我們有必要對gpio_keys進行分析。
裝置樹相關設定
一. GPIO-KEY的實現原理
1. 裝置樹定義GPIO按鍵:
vi arch/arm/boot/dts/imx6qdl-sabresd.dtsi:
gpio-keys {
compatible = "gpio-keys";/*名字非常關鍵, 找驅動就靠它來匹配了*/
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_keys>;
home {
label = "Home Button";
gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
gpio-key,wakeup;
linux,code = <KEY_HOME>; //102
};
enter {
label = "Enter Button";
gpios = <&gpio4 5 GPIO_ACTIVE_LOW>;
gpio-key,wakeup;
linux,code = <KEY_POWER>; //28
};
esc {
label = "Esc Button";
gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
gpio-key,wakeup;
linux,code = <KEY_ESC>; //1
};
back {
label = "Back Button";
gpios = <&gpio4 20 GPIO_ACTIVE_LOW>;
gpio-key,wakeup;
linux,code = <KEY_BACK>; //158
};
};
2.匹配驅動:
vi drivers/input/keyboard/gpio_keys.c:
首先init進去會根據名字匹配這個驅動
static int __init gpio_keys_init(void){
return platform_driver_register(&gpio_keys_device_driver);
}
static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = gpio_keys_remove,
.driver = {
.name = "gpio-keys",/*發現沒有, 名字跟裝置樹的名字一模一樣*/
.pm = &gpio_keys_pm_ops,
.of_match_table = of_match_ptr(gpio_keys_of_match),
}
};
之所以找到這個驅動, 主要就是因為他們的名字都是: gpio-keys。
接著就進入.probe
在gpio_keys_probe()函式中, 會註冊一個input裝置, 並建立相應的裝置檔案。
二 . GPIO_KEY使用
使用方式比較簡單,和普通的檔案操作一樣, 先開啟裝置檔案, 再讀檔案獲取鍵值即可:
1. 開啟裝置檔案,
我的裝置上gpio_key對應的裝置檔案是/dev/input/event0, 不同的平臺裝置檔案可能會有差異, 如果不清楚對應的裝置檔案, 可以用下面的命令來檢視:
開啟裝置程式碼如下:
/*1.key device*/
fd_key= open(KEY_DEVICE_FILE, O_RDONLY);
if(fd_key< 0) {
LOGE("can'topen key device file");
returnfd_key;
}
2. 獲取按鍵值及按鍵型別:
struct input_event key_evt;
monitor_key:
ret = read(fd_key, (unsigned char*)&key_evt, sizeof(struct input_event)); /*阻塞型讀函式*/
if(ret < 0) {
LOGE("read key eventfailed :%d", ret);
}
/*filter unknown key 以下的值要根據底層設定的值而定*/
else if(key_evt.code != 102&& /*KEY_home*/
key_evt.code != 28 && /*KEY_enter*/
key_evt.code != 1 && /*KEY_esc*/
key_evt.code != 158 ){ /*KEY_back*/
LOGE("unknown key code:%d", key_evt.code);
goto monitor_key;
}
else { /*valid key*/
/*
* key_val[0..7] = key code
* key_val[8] = key value: 0 - released, 1 - pressed.
*/
key_val = ((int8_t)key_evt.value<< 8) | ((uint8_t)key_evt.code);
//LOGE("get key eventcode:%d, value:%d, type:%d, %d", key_evt.code, key_evt.value,key_evt.type, key_val);
}
return key_val;
實際上就是呼叫一個阻塞型的讀函式, 所以這個函式儘量放在單獨的一個執行緒中處理, 鍵值就是在前面板級支援包中定義並註冊的值。