1. 程式人生 > >linux4.1.15核心GPOP_KEY按鍵原理和使用

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;

實際上就是呼叫一個阻塞型的讀函式, 所以這個函式儘量放在單獨的一個執行緒中處理, 鍵值就是在前面板級支援包中定義並註冊的值。