關鍵字
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 要模擬的按鍵
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;
}