美文网首页
(a40i)嵌入式Linux 按键驱动

(a40i)嵌入式Linux 按键驱动

作者: JalynFang | 来源:发表于2020-03-13 21:47 被阅读0次

    简介

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

    相关文章

      网友评论

          本文标题:(a40i)嵌入式Linux 按键驱动

          本文链接:https://www.haomeiwen.com/subject/fhvbjhtx.html