1. 程式人生 > >47 使用linux核心原始碼裡的按鍵驅動

47 使用linux核心原始碼裡的按鍵驅動

這個裝置驅動適用於,每個按鍵是連線到一個io口, 而且這個io口還有中斷功能的

需要在linux核心配置裡選上相關的配置。在核心原始碼目錄下:

    make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

    Device Drivers  --->
        Input device support  --->
            [*]   Keyboards  --->
                <*>   GPIO Buttons
選擇上後,再編核心,再使用新的核心映象啟動系統

使用新核心啟動後,可以查看出裝置驅動是否已選擇上:
/sys/bus/platform/drivers/目錄下應有”gpio-keys”目錄

驅動原始碼在”drivers/input/keyboard/gpio_keys.c”, 裡面是一個平臺驅動,我們只要寫平臺裝置描述硬體的資源與此驅動匹配即可.

819 static struct platform_driver gpio_keys_device_driver = {
820     .probe      = gpio_keys_probe,
821     .remove     = __devexit_p(gpio_keys_remove),
822
.driver = { 823 .name = "gpio-keys", // 可匹配名為"gpio-keys"的平臺裝置 824 .owner = THIS_MODULE, 825 .pm = &gpio_keys_pm_ops, 826 .of_match_table = gpio_keys_of_match, //按這個成員來匹配平臺裝置也是可以的,要求裝置的名字為"gpio-keys" 827 } 828 }; //通過閱讀平臺驅動的probe函式,可得知我們寫的平臺裝置應提供具本哪些硬體資訊. 647
static int __devinit gpio_keys_probe(struct platform_device *pdev) 648 { 649 const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; //這裡可得知我們寫的平臺裝置的platform_data成員應當提供gpio_keys_platform_data型別資料 650 struct gpio_keys_drvdata *ddata; //在裝置驅動裡對每個匹配上的裝置都準備一個獨立的資料 651 struct device *dev = &pdev->dev; 652 struct gpio_keys_platform_data alt_pdata; 653 struct input_dev *input; 654 int i, error; 655 int wakeup = 0; ... //對gpio_keys_drvdata物件的初始化 //輸入裝置物件的初始化 ... 751 }

/////////////////////

//通過probe函式,可以確定我們寫平臺裝置時只需通過platform_data成員提供平臺驅動所需的資訊,無需再提供resource.
//再確定結構體gpio_keys_platform_data的每個成員的作用即可,如不清楚具體用途,可以在驅動程式碼裡通過檢視對成員值的訪問推出用途.

"include/linux/gpio_keys.h"

//每個struct gpio_key_button的物件表示一個按鍵的具體資訊
struct gpio_keys_button {
    //此按鍵對應的鍵碼
    unsigned int code;  /* input event code (KEY_*, SW_*) */

    //此按鍵對應的一個io口
    int gpio;       /* -1 if this key does not support gpio */

    //通過檢視驅動程式碼,可得知表示是否按鍵按下是低電平,如是則設1.
    int active_low;

    //就是申請io口,申請中斷時使用的名字
    const char *desc;

    //輸入裝置的事件型別,按鍵用EV_KEY
    unsigned int type;  /* input event type (EV_KEY, EV_SW, EV_ABS) */

    //表示按鍵按下時是否喚醒系統, 這個需要io口硬體上有這功能
    int wakeup;     /* configure the button as a wake-up source */

    //防抖動用,間隔多久時間
    int debounce_interval;  /* debounce ticks interval in msecs */
    ...
}; 


//gpio_keys_paltform_data物件表示一個輸入裝置, 一個輸入裝置可有多個按鍵
struct gpio_keys_platform_data {
    //多個按鍵需要用gpio_keys_button的變數陣列才可以, buttons成員用於裝陣列首地址
    struct gpio_keys_button *buttons;

    //在按鍵數組裡的元素個數
    int nbuttons;

    //輪詢的按鍵的平臺驅動所用  
    unsigned int poll_interval; /* polling interval in msecs -
                       for polling driver only */

    //鍵按住時,是否重複提交按鍵
    unsigned int rep:1;     /* enable input subsystem auto repeat */

    //裝置這邊需在使用前所做的初始化工作,由裝置驅動呼叫. 在輸入裝置產生的裝置檔案開啟時觸發呼叫
    int (*enable)(struct device *dev);

    //裝置這邊需在結束工作前所做的工作, 由裝置驅動呼叫.在輸入裝置產生的裝置檔案關閉時觸發呼叫
    void (*disable)(struct device *dev);

    const char *name;       /* input device name */
};

////////////////////////////////////////////////////////////////////////////////////
這裡寫圖片描述
現用一個按鍵連線再板上,SIG腳接到PA20. 當鍵按下時,SIG腳為高電平。鍵鬆開時,SIG腳為低電平.

mypdev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <mach/gpio.h>

struct gpio_keys_button btns[] = {
    {KEY_L, GPIOA(20), 0, "mygpio-keys", EV_KEY, 0, 100},
};

struct gpio_keys_platform_data pdata = {
    .buttons = btns,
    .nbuttons = ARRAY_SIZE(btns),
    .rep = 1,
    .name = "mygpio-keys",
};

struct platform_device mypdev = {
    .name = "gpio-keys", //與平臺驅動的名字一致才會匹配上
    .id = -1,
    .dev = {
        .platform_data = &pdata,
    },
};

module_driver(mypdev, platform_device_register, platform_device_unregister);
MODULE_LICENSE("GPL");