linux內核中gpio-key驅動程序的使用

關鍵字

dtsi、gpio、key、input子系統、event解析、長按按鍵檢測

gpio_keys說明

key是嵌入式開發中常用到的東西,linux內核中也早已爲我們做了一套成熟的機制。

linux內核下的 drivers/input/keyboard/gpio_keys.c實現了一個體繫結構無關的GPIO按鍵驅動,使用此按鍵驅動,只需在相應的設備樹定義相關的數據即可。驅動的實現非常簡單,但是較適合於實現獨立式按鍵驅動。

gpio-keys是基於input架構實現的一個通用GPIO按鍵驅動。該驅動基於platform_driver架構,實現了驅動和設備分離,符合Linux設備驅動模型的思想。工程中的按鍵驅動我們一般都會基於gpio-keys來寫,所以我們有必要對gpio_keys進行分析。

此處我在應用層進行了處理,使其支持長按檢測(我的程序設置爲長按6S打印),嘗試在驅動層修改消抖時間,實現的效果很差,所以放棄了。

dtsi 設備樹的實現

  • 設備樹的實現大都大同小異,填寫必要的參數即可,下邊我做了標註。

gpio_keys {

    compatible = "gpio-keys";

    label = "gpio-keys";



    pinctrl-names = "default";

    pinctrl-0 = <&key_recovery_default>;



    recovery {

     label = "recovery";

     gpios = <&tlmm 23 GPIO_ACTIVE_HIGH>;

     linux,input-type = <1>;

     linux,code = <115>;

    /*這三項根據需求添加*/

    gpio-key,wakeup;

    debounce-interval = <15>;

    linux,can-disable;

    };

 };

1、節點名字爲“gpio-keys”。

2、gpio-keys 節點的 compatible 屬性值一定要設置爲“gpio-keys”。

3、所有的 KEY 都是 gpio-keys 的子節點,每個子節點可以用如下屬性描述自己:

gpios:KEY 所連接的 GPIO 信息。

interrupts:KEY 所使用 GPIO 中斷信息,不是必須的,可以不寫。

label:KEY 名字

linux,code:KEY 要模擬的按鍵\color{red}{可以直接填數字}

gpio-key,wakeup:可以被喚醒

debounce-interval:消抖時間

  • 其他字段

1、如果按鍵要支持連按的話要加入 autorepeat

驅動程序簡單分析

這就是一個標準的 platform 驅動框架,如果要使用設備樹來描述 KEY 設備信息的話,設備節點的 compatible 屬性值要設置爲“gpio-keys”。當設備和驅動匹配以後 gpio_keys_probe 函數就會執行


static struct platform_driver gpio_keys_device_driver = {

 .probe = gpio_keys_probe,

 .driver = {

  .name = "gpio-keys",

  .pm = &gpio_keys_pm_ops,

  .of_match_table = gpio_keys_of_match,

 }

};

設備樹的解析,從設備樹中獲取到 KEY 相關的設備節點信息


static int gpio_keys_probe(struct platform_device *pdev)

{

if (!pdata) {

  pdata = gpio_keys_get_devtree_pdata(dev);

  if (IS_ERR(pdata))

   return PTR_ERR(pdata);

 }

}

查看讀取event

  • 查看event事件

ls -l /dev/input

  • 查看文件內容

hexdump /dev/input/event0

應用層解析鍵值


#define RECOVERY_KEY "/dev/input/event2"

#define RECOVERY_KEY_CODE 115

#define RECOVERY_KEY_PRESS 0



void recovery_key_press_timer(int sig)

{

 if(SIGALRM == sig)

 {

  printf("alarm 6s.\n");

 }



 return;

}





static void read_recovery_key_event()

{

 int fd = -1, ret = -1;

 struct input_event ev;



 fd = open(RECOVERY_KEY, O_RDONLY);

 if (fd < 0)

 {

  printf("open RECOVERY_KEY event failed.\n");

  return;

 }



 memset(&ev, 0, sizeof(struct input_event));

 ret = read(fd, &ev, sizeof(struct input_event));

 if (ret != sizeof(struct input_event))

 {

  printf("read RECOVERY_KEY event failed.\n");

  close(fd);

 }



 if( (RECOVERY_KEY_CODE == ev.code) && (RECOVERY_KEY_PRESS == ev.value) )

 {

  printf("recovery-key press.\n");

  alarm(6);

 }

 else

 {

  printf("recovery-key release.\n");

  alarm(0);

 }



 close(fd);

}



int main(int argc, char **argv)

{

    int rc = 0;

 signal(SIGALRM, recovery_key_press_timer);

 while(1)

 {

  read_recovery_key_event();

 }

    return 0;

}

參考鏈接

LEDE/OpenWRT處理基於GPIO的Power鍵

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章