keypad driver

keypad driver键盘是6×6矩阵式,在网上下了对应的PATCH,下载地址是https://patchwork.kernel.org/patch/71857/ 这个补丁会创建两个文件arch/arm/plat-mxc/include/mach/mxc_keypad.h//mxc_keypad_platform_data键盘平台设备的结构体/drivers/input/keyboard/mxc_

大家好,又见面了,我是你们的朋友全栈君。

键盘是6×6矩阵式,在网上下了对应的PATCH,下载地址是

https://patchwork.kernel.org/patch/71857/

 

这个补丁会创建两个文件

arch/arm/plat-mxc/include/mach/mxc_keypad.h //mxc_keypad_platform_data键盘平台设备的结构体

/drivers/input/keyboard/mxc_keypad.c //驱动实现文件

打好补丁后,会发现这个驱动是一个通用的驱动,在mx21,25,27,31等板上都可以用,所以要自己实现相应的keymap,自己实现注册键盘设备,还有注册键盘相应的时钟。

1.添加键盘设备:

2.6.32内核源码里没有对mx21键盘的支持,所以我们要自己添加键盘的结构体

所以在arch/arm/mach-mx2/device.c里,加上

static struct resource mxc_keypad_resources[] = {
        {

                .start = KPP_BASE_ADDR,
                .end = KPP_BASE_ADDR + SZ_4K – 1,
                .flags = IORESOURCE_MEM,
        },{

                .start = MXC_INT_KPP,
                .end = MXC_INT_KPP,
                .flags = IORESOURCE_IRQ,
        },
};

struct platform_device mxc_keypad_device = {
        .name = “mxc-keypad”, //这个名字必须和驱动里的名字相对应
        .id = 0,
        .num_resources = ARRAY_SIZE(mxc_keypad_resources),
        .resource = mxc_keypad_resources,
};

接下来在arch/arm/mach-mx2/device.h里最后一行加上结构体的声明

extern struct platform_device mxc_spi_device1;
extern struct platform_device mxc_spi_device2;
extern struct platform_device mxc_keypad_device;
然后进入到arch/arm/mach-mx2/mx21ads.c里

在注册的时候,添加键盘对应的注册函数,找到mxc_register_device函数,添加上

static void __init mx21ads_board_init(void)
{

        mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins),
                        “mx21ads”);

        mxc_register_device(&mxc_uart_device0, &uart_pdata);
        mxc_register_device(&mxc_uart_device2, &uart_norts_pdata);
        mxc_register_device(&mxc_uart_device3, &uart_pdata);
        mxc_register_device(&mxc_fb_device, &mx21ads_fb_data);
        mxc_register_device(&mxc_sdhc_device0, &mx21ads_sdhc_pdata);
        mxc_register_device(&mxc_nand_device, &mx21ads_nand_board_info);
       
mxc_register_device(&mxc_keypad_device, &keypad_data); //keypad_data是struct mxc_keypad_platform_data结构体,需要我们自己完成,在第二步里我会具体说明

        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
}

2.添加平台设备的数据(即定义keypad_data)

首先,根据你的键盘的实际情况,设置好keymap数组,这里我建立一个文件”mxc_keymap.h”,它是键盘的keymap数组,表明了键盘的实际按键排列情况。

#ifndef __MXC_KEYMAP_H__

#define __MXC_KEYMAP_H__

static unsigned int keymap[48] = {     //这里定义大小为48不是说有48个按键,由于在补丁的驱动实现文件mxc_keypad.c里,在建立扫描码对应的键值时,每行默认为8个按键,所以这里每行都有两个是保留键。当然具体实现你也可以修改,在mxc_keypad.c里做相应变动即可
        KEY_F1,                  //EXTRA 5
        KEY_MACRO,               //#
        KEY_0,                  //0
        KEY_KPASTERISK,         //*
        KEY_F8,                 //RECORD
        KEY_POWER,              //POWER
        KEY_RESERVED,
        KEY_RESERVED,
        KEY_F2,                 //EXTRA 4
        KEY_9,                  //9
        KEY_8,
        KEY_7,
        KEY_F9,                 //EXTRA 1
        KEY_VOLUMEDOWN,
        KEY_RESERVED,
        KEY_RESERVED,
        KEY_F3,                 //EXTRA 3
        KEY_6,
        KEY_5,
        KEY_4,
        KEY_F10,                //APP 4
        KEY_VOLUMEUP,
        KEY_RESERVED,
        KEY_RESERVED,
        KEY_F4,                 //EXTRA 2
        KEY_3,
        KEY_2,
        KEY_1,
        KEY_F11,                //APP 3
        KEY_DOWN,               //DOWN
        KEY_RESERVED,
        KEY_RESERVED,
        KEY_BACKSPACE,          //BACK
        KEY_RIGHT,              //RIGHT
        KEY_F6,                 //ACTION
        KEY_LEFT,               //LEFT
        KEY_HOME,               //HOME
        KEY_F16,                //APP 2
        KEY_RESERVED,
        KEY_RESERVED,
        KEY_END,                //END
        KEY_F5,                 //KEY 2
        KEY_UP,                 //UP
        KEY_F7,                 //KEY 1
        KEY_F12,                //SEND
        KEY_F17,                //APP 1
        KEY_RESERVED,
        KEY_RESERVED,
};

#endif /*MXC_KEYMAP_H*/

接下来,进入arch/arm/mach-mx2/mx21ads.c,首先添加包含文件mxc_keypad.h,然后添加静态结构体变量并初始化。

在文件开头包含文件的地方添加上

#include <mach/mxc_keypad.h>

然后定义静态结构体keypad_data

static struct mxc_keypad_platform_data keypad_data = {

        .matrix_key_rows = 6, //实际用到的行,MX21键盘模块最大支持8×8,但我这里只用到了6×6
        .matrix_key_cols = 6, //实际用到的列
        .matrix_key_map = keymap, //按键映射数组
        .matrix_key_map_size = 48, //映射的按键数
        .debounce_ms = SAMPLE_PERIOD, //消除抖动的延时,这里我设置的是20ms,可以根据实际情况修改
};

3.时钟注册

查看arch/arm/mach-mx2/clock-mx21.c

可以发现其实键盘的时钟结构体已经注册过了,

        _REGISTER_CLOCK(“imx-i2c.0”, NULL, i2c_clk)
        _REGISTER_CLOCK(“mxc-keypad”, NULL, kpp_clk)
       

但是在mxc_keypad.c里获得时钟的时候,调用clk_get的参数与注册的时钟名不匹配,

keypad->clk = clk_get(NULL, “kpp”);
        if (IS_ERR(keypad->clk)) {

                dev_err(&pdev->dev, “failed to get keypad clock/n”);
                error = PTR_ERR(keypad->clk);
                goto failed_free_io;
        }

这里有两种方法,第一修改_REGISTER_CLOCK(“mxc-keypad”,NULL,kpp_clk)

改成 _REGISTER_CLOCK(NULL,”kpp”,kpp_clk);

第二种是修改mxc_keypad.c里的clk_get的参数,改成 clk_get(“mxc-keypad”,NULL);

个人倾向于第一种,呵呵,改驱动的代码万一改错麻烦就大得多了。

———————————————-

这里我以为已经改好了,所以写了个测试的应用程序keytest来测试

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <linux/input.h>

int fd;
int loop_flag = 1;

void exit_loop()
{

        loop_flag–;
}

void deal_int(int signum)
{

        if(fd > 0)
                close(fd);
        exit_loop();
}

int main()
{

        struct input_event evt;

        fd = open(“/dev/input/event0”,O_RDWR);

        if(fd < 0)
                printf(“Can not open/n”);

        while(loop_flag > 0)
        {

                read(fd,&evt,sizeof(struct input_event));
                switch(evt.type)
                {

                        case EV_KEY:
                                printf(“Key –>/nCode: %d/nValue: %d/n”,evt.code,evt.value);
                        break;
                        case EV_MSC:
                              printf(“MSC –>/nCode: %d/nValue: %d/n”,evt.code,evt.value);
                        break;
                        case EV_SYN:
                                printf(“<– /n”);
                        default:
                                printf(“…/n”);
                }
        }

        return 0;
}

启动板子,发现键盘设备被识别,而且/dev/input/下有event0,

cat sys/class/input/input0/name得到
mxc-keypad

说明驱动正常,设备也注册好了

所以使用keytest来测试,结果发现没有发生EV_KEY,事件,这说明input_report_key函数没有成功

查看内核源码,发现input_report_key()实际上调用的是input_event(),这个函数首先会检测合法位,也就是说会检测按键的code是否已经添加到了struct input_dev的keybit里(input_dev->keybit)

所以回到驱动实现文件mxc_keypad.c里

发现static void mxc_keypad_build_keycode(struct mxc_keypad *keypad)
这个函数在添加扫描码的时候,使用循环来处理

for (i = 0; i < pdata->matrix_key_map_size; i++) {

                unsigned int key = pdata->matrix_key_map[i];
                unsigned int row = KEY_ROW(key);
                unsigned int col = KEY_COL(key);
                unsigned int scancode = MATRIX_SCAN_CODE(row, col,
                                                         MATRIX_ROW_SHIFT);

                keycode = KEY_VAL(key);
                keypad->keycodes[scancode] = keycode;
                __set_bit(keycode, input_dev->keybit);
        }
发现错在KEY_ROW和KEY_COL这两个宏,查看include/linux/matrix_keypad.h

KEY_ROW(k) ( ((k) >> 24) & 0xff )

KEY_COL(k)   (((k) >> 16) & 0xff)

也就是说这两个宏决定行列的规则是行是键值的高8位,列是键值的次高8位

查看include/linux/input.h,发现相关的KEY_*(KEY_0,KEY_UP等)的值都没有超过255,这样确定行列时,就不能使用这两个宏了,所以我注释了原来的代码,自己修改成了

/* MOD—
        for (i = 0; i < pdata->matrix_key_map_size; i++) {

                unsigned int key = pdata->matrix_key_map[i];
                unsigned int row = KEY_ROW(key);
                unsigned int col = KEY_COL(key);
                unsigned int scancode = MATRIX_SCAN_CODE(row, col,
                                                         MATRIX_ROW_SHIFT);

                keycode = KEY_VAL(key);
                keypad->keycodes[scancode] = keycode;
                __set_bit(keycode, input_dev->keybit);
        }
*/

        unsigned int row,col;
        unsigned int key;
        unsigned int scancode;

        row = col = 0;
        for(i = 0;i < pdata->matrix_key_map_size;i++)
        {

                key = pdata->matrix_key_map[i];
                scancode = MATRIX_SCAN_CODE(row,col,MATRIX_ROW_SHIFT);
                col++;
                if(col == MAX_MATRIX_KEY_COLS)
                {

                        col = 0;
                        row++;
                }   

                key = KEY_VAL(key);
                keypad->keycodes[scancode] = key;
                __set_bit(key,input_dev->keybit);
        }

这里如果哪位有更好的方法欢迎留言,因为我觉得这个方法不是很好。

重新编译,启动板子,运行keytest程序

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130064.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 两地 三中心

    两地 三中心1、两地三中心同城双中心+异地灾备中心,“两地三中心”的灾备模式,方案兼具高可用性和灾难备份的能力。同城双中心是指在同城或邻近城市建立两个可独立承担关键系统运行的数据中心,双中心具备基本等同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行;灾难情况下可在基本不丢失数据的情况下进行灾备应急切换,保持业务连续运行。与异地灾备模式相比较,同城双中心具有投资成本低、建设速度快、运维管理相对简单、可靠性更高等优点。异地灾备中心是指在异地的城市建立一.

    2022年6月30日
    29
  • java单例模式 三种_三种java单例模式概述

    java单例模式 三种_三种java单例模式概述在java语言的应用程序中,一个类Class只有一个实例存在,这是由java单例模式实现的。Java单例模式是一种常用的软件设计模式,java单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。下面就来介绍一下这三种java单例模式的相关内容。java单例模式是一种常见的设计模式,在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例,这也是…

    2022年7月25日
    5
  • cmd查看端口号是否占用

    cmd查看端口号是否占用1.查看所有端口号 netstat2.查看指定的端口号netstat-ano|findstr"8088"

    2022年5月19日
    36
  • vscode配置javaweb环境_vscode electron

    vscode配置javaweb环境_vscode electronVScode配置Java环境1、下载VSCodeVSCode下载官网2、配置中文环境如果懂英语,或者想在编程上有更好的进步,可以跳过这一步,毕竟以后工作,很多软件并非中文,但像我这样的英语困难户,还是下载了该插件,毕竟香啊(〃 ̄︶ ̄)在VSCode的左侧点击小方块,搜索Chinese(Simplified)LanguagePackforVisualStudioCode插件,点击安装。(这是安装后的界面)3、配置相关插件和Java的JDK1、新建文件(快捷键Ctrl

    2022年10月3日
    0
  • lucene分词器中的Analyzer,TokenStream, Tokenizer, TokenFilter

    lucene分词器中的Analyzer,TokenStream, Tokenizer, TokenFilterTokenStream:分词器做好处理之后得到的一个流。这个流中存储了分词的各种信息,可以通过TokenStream有效的获取到分词单元。以下是把文件流转换成分词流(TokenStream)的过程首先,通过Tokenizer来进行分词,不同分词器有着不同的Tokenzier,Tokenzier分完词后,通过TokenFilter对已经分好词的数据进行过滤,比如停止词。过滤完之后,把所有的数据组合成一个TokenStream;

    2022年7月22日
    8
  • pycharm怎么看函数源代码_python查看第三方库的源码

    pycharm怎么看函数源代码_python查看第三方库的源码pycharm查看python源代码

    2022年8月28日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号