(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 = ; /*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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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");
    }

}

你可能感兴趣的:((a40i)嵌入式Linux 按键驱动)