嵌入式Linux input

前言

這是前4篇:

本篇介紹下input子系統, 用於檢測按鍵輸入, 採用米爾MYS-6ULX板子出廠配置的系統. 主要參考自野火的9. 檢測按鍵輸入(input子系統) .

input子系統

input子系統是Linux對輸入設備提供的統一驅動框架。如按鍵、鍵盤、觸摸屏和鼠標等輸入設備的驅動方式是類似的,當出現按鍵、觸摸等操作時,硬件產生中斷,然後CPU直接讀取引腳電平,或通過SPI、I2C等通訊方式從設備的寄存器讀取具體的按鍵值或觸摸座標,然後把這些信息提交給內核。使用input子系統 驅動的輸入設備可以通過統一的數據結構提交給內核,該數據結構包括輸入的時間、類型、代號以及具體的鍵值或座標,而內則通過/dev/input目錄下的文件接口傳遞給用戶空間。

上篇LED, GPIO的操作在/sys/class/leds/sys/class/gpio, input也有對應的目錄, 如:

root@mys6ull14x14:~# cat /sys/class/input/event2/device/name
gpio-keys

這個對應板子上的用戶按鍵:
在這裏插入圖片描述

假如我們使用的是GPIO子系統框架來編寫按鍵驅動程序,在應用層的操作中,需要使用”/sys/class/gpio/gpio*/direction”文件配置爲輸入方向,然後使用循環讀取”/sys/class/gpio/gpio*/value”文件的值來獲得按鍵的狀態,但由於對value文件的read讀 取操作不會阻塞,所以進程會不停地讀取文件內容來判斷按鍵值,佔用CPU寶貴的運算資源。

在輸入事件檢測的應用中,通常使用主線程直接 循環讀取”/dev/input/event*”設備文件獲取事件的數據結構,然後通過消 息隊列通知其它子線程,從而響應輸入操作。

此處使用的是開發板KEY按鍵 在”/dev/input/by-path”下的鏈接文件名,此處不使用”/dev/input/event*”只是 爲了讓程序不受其它輸入設備而影響了事件編號。

root@mys6ull14x14:~/nfs_share# ls /dev/input/by-path
platform-2040000.tsc-event
platform-20cc000.snvs:snvs-powerkey-event
platform-ci_hdrc.1-usb-0:1.2:1.0-event-mouse
platform-ci_hdrc.1-usb-0:1.2:1.0-mouse
platform-gpio-keys-event

如果cat /dev/input/by-path/platform-gpio-keys-event, 按下按鍵會發現亂碼, 可以用evtest檢測:

root@mys6ull14x14:~/nfs_share# evtest
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0:      20cc000.snvs:snvs-powerkey
/dev/input/event1:      iMX6UL TouchScreen Controller
/dev/input/event2:      gpio-keys
Select the device event number [0-2]: 2
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "gpio-keys"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 2 (KEY_1)
Properties:
Testing ... (interrupt to exit)
Event: time 1507355347.797407, type 1 (EV_KEY), code 2 (KEY_1), value 0
Event: time 1507355347.797407, -------------- SYN_REPORT ------------
Event: time 1507355347.977336, type 1 (EV_KEY), code 2 (KEY_1), value 1
Event: time 1507355347.977336, -------------- SYN_REPORT ------------

按鍵檢測C代碼

新建gpio_key.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>

const char default_path[] = "/dev/input/by-path/platform-gpio-keys-event";

int main(int argc, char *argv[])
{
    int fd;
    struct input_event event;
    char *path;

    printf("This is a input device demo.\n");

    path = (char *)default_path;

    fd = open(path, O_RDONLY);
    if (fd < 0)
    {
        printf("Fail to open device:%s.\n", path);
        exit(1);
    }

    printf("Test device: %s.\nWaiting for input...\n", path);

    while (1)
    {
        if (read(fd, &event, sizeof(event)) == sizeof(event))
        {
            //EV_SYN是事件分隔標誌,不打印
            if (event.type != EV_SYN)
                printf("Event: time %ld.%ld, type %d, code %d,value %d\n",
                       event.time.tv_sec, event.time.tv_usec,
                       event.type,
                       event.code,
                       event.value);
        }
    }
    close(fd);

    return 0;
}

編譯arm-linux-gnueabihf-gcc -o gpio_key gpio_key.c, NFS掛載後直接在開發板串口終端輸入./gpio_key運行, 按下按鍵:

root@mys6ull14x14:~/nfs_share/Code/cache# ./gpio_key
This is a input device demo.
Test device: /dev/input/by-path/platform-gpio-keys-event.
Waiting for input...
Event: time 1507358199.167780, type 1, code 2,value 0
Event: time 1507358199.437382, type 1, code 2,value 1

或者改自米爾的例子也大同小異:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>

const char key_path[] = "/dev/input/event2";

int main(int argc, char *argv[])
{
    int ledn;
    char *tmp;
    int keys_fd;
    struct input_event t;

    keys_fd = open(key_path, O_RDONLY);
    if (keys_fd <= 0)
    {
        printf("open %s device error!\n", &key_path);
        return 0;
    }

    printf("Hit any key on board ......\n");

    while (1)
    {
        if (read(keys_fd, &t, sizeof(t)) == sizeof(t))
        {
            if (t.type == EV_KEY)
            {
                if (t.value == 0 || t.value == 1)
                {
                    printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");
                    if (t.code == KEY_ESC)
                        break;
                }
            }
        }
    }

    close(keys_fd);
    return 0;
}

運行如下:

root@mys6ull14x14:~/nfs_share/Code/cache# ./gpio_key1
Hit any key on board ......
key 2 Released
key 2 Pressed
key 2 Released
key 2 Pressed

微信公衆號

歡迎掃描關注我的微信公衆號, 及時獲取最新文章:
在這裏插入圖片描述

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