47 使用linux内核源码里的按键驱动<GPIO Buttons>

这个设备驱动适用于,每个按键是连接到一个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");
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值