(a40i)嵌入式Linux 按键驱动

简介

        Linux内核已经集成按键驱动。按键和键盘在Linux上都属于输入设备;Linux内核为此专门抽象了一个input输入子系统框架来管理该类事件;
        按键驱动采用platform框架,因此我们只需要在设备树文件中添加相应节点即可;接下来我们学习如何在全志 a40i平台下使用Linux内核自带的按键驱动来驱动 board 上按键。

开发环境介绍

  • 主机操作系统:Ubuntu14.04 64位
  • 目标平台:A40I (ARM Cortex-A7)
  • 交叉工具链:arm-linux-gnueabi,gcc5.3.1
  • 内核版本:3.10

使能Linux内核自带的按键驱动

        使用Linux内核自带的LED灯驱动首先需要配置Linux内核,使能自带的LED灯驱动;使能方法如下:

Step1. 打开Linux配置菜单
make ARCH=arm menuconfig
Step2. 打开按键驱动配置项
Device Drivers  ---> 
    Input device support  ---> 
        [*]   Keyboards  --->
              <*>   GPIO Buttons 

选中“GPIO Buttons ”将其编译进内核中;
Linux内核自带的KEY驱动文件为:drivers/input/keyboard/gpio_keys.c

Step3. 添加设备树节点

根据内核提供的LED设备树节点添加参考说明文档:
Documentation/devicetree/bindings/input/gpio-keys.txt;
在设备树文件中添加KEY设备节点:

gpio-keys {
    compatible = "gpio-keys";
    pinctrl-names = "default";

    key_1 {
        label = "reset";
        gpios = <&pio PI 12 6 0 0 0>;
        linux,code = <KEY_HANJA>; /*123*/
        gpio-key,wakeup;
    };
};

①、创建KEY节点名字gpio-keys,节点名字可根据情景取;
②、gpio-keys节点的compatible属性值必须为“gpio-keys”,由驱动文件决定;
③、所有的KEY都是gpio-keys的子节点,每个子节点可以用如下属性描述自己:
        gpios: KEY所连接的GPIO信息,在a40i平台下,相信的GPIO dts描述可参考A40I Pinctrl(GPIO)接口使用说明书V1.0.pdf;
        interrupts: KEY所使用的GPIO中断信息,不是必须的,可以不写;
        label: KEY名字;
        linux,code: KEY要模拟的按键
④、如果按键要连按的话加入:autorepeat;

应用测试

通过 cat /proc/bus/input/devices 来查看设备是否加载成功;

Func1.hexdump测试

hexdump: 查看文件的内容,比如二进制文件中包含的某些字符串,通常用来调试驱动用;
使用hexdump命令来查看/dev/input/event3文件,数据就是event结构
我们来看看event的结构体:input_event:

struct input_event {
    struct timeval time;   //事件发生的时间
    __u16 type;            //  哪类事件, 比如键盘事件
    __u16 code;          // 对应的事件里支持的哪个变量,比如按键K
    __s32 value;         // 对应的变量里的数值, 比如松开按键则是1,反之为0
};

把 time里的成员展开如下:

struct input_event {
    long   tv_sec;     /* seconds */          //秒
    long   tv_usec;    /* microseconds */     //微妙

    __u16 type;      //  哪类事件, 比如键盘事件  
    __u16 code;    // 对应的事件里支持的哪个变量,比如按键K
    __s32 value;   // 对应的变量里的数值, 比如松开按键则是1,反之为0
};

以按开发板的按键 KEY_HANJA(123),为例(因为数据是从低到高打印的,所以数据是反的):

hexdump /dev/input/event3调试按键驱动:
/*按下时:*/
//hexdump序列号        秒        微妙   键盘事件 code=KEY_HANJA  value=1(按下)
0000000             2a4b 5e6a  c309 0001   0001      007b       0001 0000
//hexdump序列号        秒         微妙     同步事件    code      value=0
0000010             2a4b 5e6a  c309 0001   0000      0000       0000 0000

/*松开时:*/
//hexdump序列号        秒          微妙   键盘事件 code=KEY_HANJA  value=1(松开)
0000020             2a4b 5e6a   b829 0004  0001      007b       0000 0000
//hexdump序列号        秒         微妙   同步事件     code        value=0
0000030             2a4b 5e6a   b829 0004  0000      0000       0000 0000

也可以使用getevent 命令,用于获取 input 输入事件,比如获取按键上报信息、获取触摸屏上报信息等:
格式输出为event type、event code、event value;

event type(按键)          event code(KEY_HANJA)       event value(按下)
    0001                        007b                  00000001
event type(同步事件)    event code
    0000                        0000                  00000000

event type(按键)          event code(KEY_HANJA)       event value(松开)
    0001                        007b                  00000000
event type(同步事件)    event code
    0000                        0000                  00000000
Func2.系统调用测试
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <linux/input.h>
#include <errno.h>

void get_inputdev_node(char *name,char *identify);

int main(int argc,char *argv[])
{
    int fd;
    char devName[128];
    struct input_event event;
    
    get_inputdev_node(devName,"gpio-keys");
    fd = open(devName, O_RDONLY/*|O_NONBLOCK*/);
    if ( fd<=0 )
    {
        printf ("open key device error!\n");
        return -1;
    }else{
        debug("Open key success! \n");
    }
    
    while(1)
    {
        if (read(g_FdKey, &event, sizeof(event)) == sizeof(event))
        {
            
            if (event.type == EV_KEY){
                /*event.code该值看设备树节点linux,code*/
                if( (KEY_HANJA==event.code)&&(1==event.value) ){
                    printf("INPUT_KEY_DOWN !");
                }else if( (KEY_HANJA==event.code)&&(0==event.value) ){
                    ret=INPUT_KEY_UP;
                    printf("INPUT_KEY_UP !");   
                }
            }

        }else{
            printf("read empty \n");
        }   
    }
    
    close(fd);
    
    return 0;
}

/**
 * @brief 字符串分割函数
 *        将str字符以spl分割,存于dst中,并返回子字符串数量
 * 
 * @param str[in]   待分割字符串
 * @param spl[in]   分割符
 * @param dst[out]  分割后的子字符串
 * @return  返回子字符串数量
 *          
 */
int split(char dst[][SPLITELENGTH], char* str, const char* spl)
{
    int n = 0;
    char *result = NULL;
    result = strtok(str, spl);
    while( result != NULL )
    {
        strcpy(dst[n++], result);
        result = strtok(NULL, spl);
    }
    return n;
}

 /**
 * @brief   输入设备节点解析
 * 
 * @author  Jalyn
 * @date    2020-01-01
 * 
 * @param [in] identify 根据该标识做解析
 * @param [out] name    解析后的设备节点名称
 * @return  无
 */
void get_inputdev_node(char *name,char *identify)
{
    int ret=0;
    FILE *fp;
    char buf[256];
    int findFlag=0;
    char dst[10][SPLITELENGTH];

    strcpy(name,"/dev/input/event1");
    fp = fopen("/proc/bus/input/devices", "r");

    if (fp != NULL) {
        while (fgets(buf, sizeof(buf), fp) != NULL) {
            if(strstr(buf,"Name")!=NULL)
            {
                findFlag=0;
                if(strstr(buf,identify)!=NULL){
                    findFlag=1;
                }
            }
            if(findFlag==1){
                if(strstr(buf,"Handlers")!=NULL){
                    findFlag=0;
                    ret = split(dst, buf, " ");
                }
            }
        }

        if(ret!=0){
            sprintf(name,"/dev/input/%s",dst[2]);
        }

        fclose(fp);
    }else{
        printf("open /proc/bus/input/devices error!\n");
    }

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容