平台:MTK
一.添加一个按键
1.在DCT tool keypad list 文件增加新按键的选项
alps\mediatek\source\dct\Keypad_YuSu.cmp中添加新键,如SMS快捷键
KEY_SYM
KEY_SMS
KEY_0

2.打开DCT tool 在keypad矩阵中在相应定义的按键位中添加新按键,如SMS,然后Save

3.修改linux 键盘码文件input.h
由于preloader\uboot\kernel\factory 等情况分开使用,相应的文件路径下的input.h都应该修改为新按键增加键码值
kernel\include\linux\input.h
bionic\libc\kernel\common\linux\input.h
external\kernel-headers\original\linux\input.h
external\qemu\linux_keycodes.h
mediatek\plaform\mt6575\preloader\src\drivers\inc\linux\input.h
Mediatek\plaform\mt6575\uboot\inc\linux\input.h
如KEY_SMS
    #define KEY_SMS 252

4.增加keypad layout文件键盘映射,linux和android key映射
mediatek\config\<project name>\mt6575-kpd.kl
如:
key 252 SMS 
其中252 是linux键码,SMS是android识别key值 如果是需要唤醒系统,还需要增加WAKE
如果新按键是全键盘的一些生僻字符,修改: mediatek\config\<project name>\mt6575-kpd.kcm
注意:
    如果是accdet也就耳机按键, keypad layout文件键盘映射,linux和android key映射在ACCDET.kl,Generic.kcm',电话监听的就是HEADSETHOOK

5.修改Java识别keycode
framework/base/include/ui/KeyCodelabels.h
KEYCODES数据结构后面增加
{"SMS",220}
framework/base/native/include/android/KeyCodes.h
在按键定义项增加AKEYCODE_SMS = 220;

6.修改Java 键盘事件
framework/base/core/java/android/view/keyevent.java
/**
*@hide
*/
public static final int KEYCODE_SMS =220;
最后的按键为新增的
private static final int LAST_KEYCODE ==KEYCODE_SMS;
以上/**/注释的code是android 非开放API或变量定义的时候,需要添加Java Doc的识别,否则要运行make update-api才能build通过.
如果是系统按键,修改framework/base/libs/ui/input.cpp
isSystemKey()增加case AKEYCODE_SMS:

7.修改XML文件描述符framework/base/core/res/res/values/attr.xml
<enum name="KEYCODE_SMS" value="220" />

8.增加测试验证log在android
framework\base\policy\src\com\android\internal\polidy\impl\phoneWindowManager.java
在interceptKeyBeforeDispatching()增加
if(keycode== KeyEvent.KEYCODE_SMS){
log.d(TAG, "interceptKeyTi KEYCODE_SMS keyCode="+ keyCode + " down=" + down + "
repeatCount=" + repeatCount + “ keyguardOn=” + keyguardOn + “ mHomePressed=” +
mHomePressed + “ cancled=” + canceled)

9.增加按键全局功能响应:
framework\base\policy\src\com\android\internal\polidy\impl\phoneWindow.java
分别在onKeyDown()、onKeyUp()增加对应代码
if(keycode== KeyEvent.KEYCODE_SMS){}
 
 
二.矩阵键盘原理
    不同的MTK平台内部提供的按键数目各有不同,但是扫描原理大致一样,这里以MTK6735为例来讲解记录

在初始化或是没有按键的情况下,ROW设置为输出,COL设置为输入。

 BB芯片的内部设有一个按键中断,在没有任何按键的情况下,所有CLO线为高电平,ROW线为低电平,一旦有按键按下,比如key10(ROW1,COL2)有按下,由于COL2线与ROW1线直接相连,COL2线即被拉低,只要COL线有被拉低的,内部按键中断便会响应,内部按键中断产生后,BB就知道有按键产生,这时就进行按键扫描,判断出事哪个按键按下,然后进行相应的处理。

中断产生后,BB先发出消息将所有COL线置高,所有ROW线置低,扫描COL线,比如key10(ROW1,COL2)有按下,会扫描到COL2被拉低;再将将所有ROW线置高,所有COL线置低,扫描ROW线,比如key10(ROW1,COL2)有按下,会扫描到ROW1被拉低;那么COL2和ROW1组合起来就知道哪个按键按下了。

   但是实际上按键中断产生后,扫描过程已经在BB内部迅速完成,然后把相应的按键位置用寄存器保存起来。每个寄存器16位,每一位代表一个按键,那么总共53个按键,需要4个寄存器去保存。

寄存器的每个位对应一个按键,默认为1,当有按键按下,那么相应位置0。然后系统去读这四个寄存器,就能知道是哪一个按键按下。

 
 

三.添加矩阵键盘

    这里修改的6735的3*3的矩阵键盘
    1.修改DWS
  
    注意:
        因为原理端口81和82会输出方波,所以要把除了M0和M1两种模式之外的模式取消,而且都要配置in,out模式,因为会扫描两次,就会同时作为输入输出。
 
    
   修改KEYPAD,填入矩阵,这样一般就可以了
 
修改按键键值:
   以dws为主,kernel-3.18/arch/arm64/boot/dts/cust_kpd.dtsi如果在dts中include,覆盖dws里面的
 
四.keypad驱动分析
 Kpd.c (kernel-3.10\drivers\misc\mediatek\keypad)
重要结构体
static struct platform_driver kpd_pdrv = {
.probe = kpd_pdrv_probe,
.remove = kpd_pdrv_remove,
#ifndef USE_EARLY_SUSPEND
.suspend = kpd_pdrv_suspend,
.resume = kpd_pdrv_resume,
#endif
.driver = {
.name = KPD_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = kpd_of_match,
#endif
},
};
 
kpd_mod_init
    platform_driver_register(&kpd_pdrv); //注册
 
  
进入probe
static struct file_operations kpd_dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = kpd_dev_ioctl,
.open = kpd_dev_open,
};
 
static struct miscdevice kpd_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = KPD_NAME,
.fops = &kpd_dev_fops,
};
 
kpd_pdrv_probe
    kpd_ldvt_test_init();/* API 2 for kpd LFVT test enviroment settings */
        /* set kpd GPIO to kpd mode */
mtk_kpd_gpio_set();  //单独分析
        temp_reg = readw(KP_SEL); //读取KP_SEL寄存器的值 ,Used to select:1: Single keypad or double keypad 2: Which cols and rows are used when using double keypad

        temp_reg &= ~(0x1); //我们这里single

        /* set kpd enable and sel register */

mt_reg_sync_writew(temp_reg, KP_SEL);
mt_reg_sync_writew(0x1, KP_EN);
        kpd_input_dev = input_allocate_device();
    /* fulfill custom settings */
    kpd_memory_setting
        kpd_init_keymap(kpd_keymap);
            keymap[i] = kpd_keymap[i];  //初始化keymap:kpd_keymap[KPD_NUM_KEYS] = KPD_INIT_KEYMAP();
kpd_init_keymap_state(kpd_keymap_state);
            keymap_state[i] = kpd_keymap_state[i];  //kpd_keymap_state[KPD_NUM_MEMS] = {0xffff, 0xffff, 0xffff, 0xffff, 0x00ff};
    r = input_register_device(kpd_input_dev);
    r = misc_register(&kpd_dev);
    /* register IRQ and EINT */
    kpd_set_debounce(KPD_KEY_DEBOUNCE); //设置防反跳时间
    r = request_irq(kp_irqnr, kpd_irq_handler, IRQF_TRIGGER_NONE, KPD_NAME, NULL); //keypad处理函数
    long_press_reboot_function_setting();/* /API 4 for kpd long press reboot function setting */ 
    hrtimer_init(&aee_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); //初始化高精度定时器,相对模式
    aee_timer.function = aee_timer_func; //处理函数
    hrtimer_init(&aee_timer_5s, CLOCK_MONOTONIC, HRTIMER_MODE_REL); //第二个
    aee_timer_5s.function = aee_timer_5s_func;
    
 
    mtk_kpd_gpio_set();
            mtk_kpd_gpios_get  //得到DWS里面的设置的行和列的gpio和模式
                #ifdef GPIO_KPD_KROW0_PIN
ROW_REG[0] = GPIO_KPD_KROW0_PIN;
GPIO_MODE[0] |= GPIO_KPD_KROW0_PIN_M_KROW;
        #endif
            /* KCOL: GPIO INPUT + PULL ENABLE + PULL UP */ 设置列的模式

    mt_set_gpio_mode(COL_REG[i], ((GPIO_MODE[i] >> 4) & 0x0f));
    mt_set_gpio_dir(COL_REG[i], 0);
    mt_set_gpio_pull_enable(COL_REG[i], 1);

    mt_set_gpio_pull_select(COL_REG[i], 1);
            /* KROW: GPIO output + pull disable + pull down */
    mt_set_gpio_mode(ROW_REG[i], (GPIO_MODE[i] & 0x0f));
    mt_set_gpio_dir(ROW_REG[i], 1);
    mt_set_gpio_pull_enable(ROW_REG[i], 0);
    mt_set_gpio_pull_select(ROW_REG[i], 0);
 
 
 
long_press_reboot_function_setting();/* /API 4 for kpd long press reboot function setting */ 
    if (get_boot_mode() == NORMAL_BOOT)  //如果正常启动
 
            #ifdef ONEKEY_REBOOT_NORMAL_MODE   //一个按键重启
pmic_set_register_value(PMIC_RG_PWRKEY_RST_EN,0x01); //使能
pmic_set_register_value(PMIC_RG_HOMEKEY_RST_EN,0x00); //去掉
pmic_set_register_value(PMIC_RG_PWRKEY_RST_TD,KPD_PMIC_LPRST_TD);  //写入超时时间,11s这里
#endif    
#ifdef TWOKEY_REBOOT_NORMAL_MODE
pmic_set_register_value(PMIC_RG_PWRKEY_RST_EN,0x01);
pmic_set_register_value(PMIC_RG_HOMEKEY_RST_EN,0x01);
pmic_set_register_value(PMIC_RG_PWRKEY_RST_TD,KPD_PMIC_LPRST_TD);
#endif
    esle
         #ifdef ONEKEY_REBOOT_OTHER_MODE
pmic_set_register_value(PMIC_RG_PWRKEY_RST_EN,0x01);
pmic_set_register_value(PMIC_RG_HOMEKEY_RST_EN,0x00);
pmic_set_register_value(PMIC_RG_PWRKEY_RST_TD,KPD_PMIC_LPRST_TD);
#endif
 
#ifdef TWOKEY_REBOOT_OTHER_MODE
pmic_set_register_value(PMIC_RG_PWRKEY_RST_EN,0x01);
pmic_set_register_value(PMIC_RG_HOMEKEY_RST_EN,0x01);
pmic_set_register_value(PMIC_RG_PWRKEY_RST_TD,KPD_PMIC_LPRST_TD);
#endif
 
 
分析keypad处理函数kpd_irq_handler
kpd_irq_handler
     tasklet_schedule(&kpd_keymap_tasklet); //调用tasklet
          kpd_keymap_handler
                kpd_get_keymap_state(new_state); //从寄存器得到keypad状态
                for (i = 0; i < KPD_NUM_MEMS; i++) {
                   change = new_state[i] ^ kpd_keymap_state[i]; //按键有无变化
                   for (j = 0; j < 16; j++) { //具体按键哪个按键变化
mask = 1U << j;
                   } 
                   hw_keycode = (i << 4) + j; //得到按键的在keymap具体值
  /* bit is 1: not pressed, 0: pressed */
  pressed = !(new_state[i] & mask);    //判断是按键还是松开
                  linux_keycode = kpd_keymap[hw_keycode]; //从keymap得到linuxkey
                  kpd_aee_handler(linux_keycode, pressed); //如果是KEY_VOLUMEUP或者KEY_VOLUMEDOWN
                        kpd_update_aee_state(); 
                             /* if volumeup and volumedown was pressed the same time then start the time of ten seconds */
            aee_timer_started = true;
                            hrtimer_start(&aee_timer_5s, ktime_set(AEE_DELAY_TIME_5S, 0), HRTIMER_MODE_REL); //打开5s
                            hrtimer_start(&aee_timer, ktime_set(AEE_DELAY_TIME, 0), HRTIMER_MODE_REL);  //15s
                 input_report_key(kpd_input_dev, linux_keycode, pressed); //上报按键
                 .........处理一些情况
 
 
aee_timer_func
   /* aee_kernel_reminding("manual dump ", "Triggered by press KEY_VOLUMEUP+KEY_VOLUMEDOWN"); */
    aee_trigger_kdb(); //就是使能KDB的操作,一个调试工具,kernel debug bridge
 
 
aee_timer_5s_func
    /* printk("kpd: vol up+vol down AEE manual dump timer 5s !\n"); */
    flags_5s = true;
         
 
 
 
 
 

Android系统添加key和keypad的更多相关文章

  1. android系统添加预置APP(so库自动释放)

    将APK直接放入系统目录中,会导致APK找不到so文件.正常情况下的安装是使用PackageManager,它会将so文件拷贝到系统读取的so目录(system/lib或system/lib64)下, ...

  2. Android 系统添加SELinux权限

    本文为博主原创文章,转载请注明出处:https://i.cnblogs.com/EditPosts.aspx?postid=11185476 CPU:RK3288 系统:Android 5.1 SEL ...

  3. 第一章Android系统移植与驱动开发概述--读书笔记

    以前,初步学习过嵌入式Linux驱动开发的基础课程,对于驱动开发可以说是有了一点点微末的基础吧.首先我们要对Android嵌入式系统有一个初步的认识,Android系统发展到今天已经具备了完善的架构. ...

  4. Android系统移植与调试之------->如何修改Android设备添加重启、飞行模式、静音模式等功能(二)

    今天要说的是为Android设备添加重启.飞行模式.静音模式按钮,客户需求中需要添加这项功能,在长按电源键弹出的菜单中没有这些选项,谨以此文记录自己添加这个功能的过程. 首先找到长按电源键弹出的对话框 ...

  5. 嵌入式linux和嵌入式android系统有什么区别和联系?

    转自:http://bbs.eeworld.com.cn/thread-430437-1-1.html 这个问题很多人问,尤其是初入嵌入式的菜鸟.其实大家都认为android是java,已经不是lin ...

  6. android系统release签名

    转自:http://blog.csdn.net/yangkai6121/article/details/38682321 为什么需要给Android系统签个名才能进行CTS认证呢?原来我们通过make ...

  7. Android系统的五种数据存储形式(一)

    Android系统有五种数据存储形式,分别是文件存储.SP存储.数据库存储.contentprovider 内容提供者.网络存储.其中,前四个是本地存储.存储的类型包括简单文本.窗口状态存储.音频视频 ...

  8. Android下添加新的自定义键值和按键处理流程

            Android下添加新的自定义键值和按键处理流程     说出来不怕大家笑话,我写这篇博客的原因在于前几天去一个小公司面试Android系统工程师,然后在面试的时候对方的技术总监问了我 ...

  9. [原创]Android系统中常用JAVA类源码浅析之HashMap

    由于是浅析,所以我只分析常用的接口,注意是Android系统中的JAVA类,可能和JDK的源码有区别. 首先从构造函数开始, /** * Min capacity (other than zero) ...

随机推荐

  1. 51nod1548 欧姆诺姆和糖果

    思路: 只有兩種糖果,枚舉其中一種糖果的數量就可以得到一個可行解: 但總有一種糖果的數量是較少的,並且該數量小於sqrt(C): 簡單證明: 1.若有任一糖果的質量大於sqrt(C),則必定有一糖果的 ...

  2. codevs1298, hdu1392 (凸包模板)

    题意: 求凸包周长. 总结: 测试模板. 代码: #include <iostream> #include <cstdio> #include <cstring> ...

  3. Spring Boot入门之Hello World

    Spring Boot介绍 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不 ...

  4. C语言单文件模板

    #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stri ...

  5. D. Bash and a Tough Math Puzzle 解析(線段樹、數論)

    Codeforce 914 D. Bash and a Tough Math Puzzle 解析(線段樹.數論) 今天我們來看看CF914D 題目連結 題目 給你一個長度為\(n\)的數列\(a\), ...

  6. eclipse配置springMVC

    基础还是创建一个Dynamic web project. WEB-INF/lib中添加必需的jar. commons-logging-1.1.3.jar spring-aop-4.3.6.RELEAS ...

  7. 学会这些CSS,再也不用切图!!!

    三角形 利用border-color支持transparent这一特性,隐藏三条边框,实现三角形. <style> .triangle { width: 0; height: 0; bor ...

  8. net core webapi多版本控制与nswag 交互

    前言 首先希望webapi 支持多版本,swagger针对不同的版本可进行交互.netcore 基于Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer 包, ...

  9. Python+Selenium(1)- 环境搭建

    一,Selenium 简介 Selenium是目前最流行的web自动化测试工具,也常用于网络爬虫,已经更新到3以上的版本. 1,组件 它提供了以下web自动化测试组件: Selenium IDE,Fi ...

  10. C#中的release和debug模式

    以下内容来源:https://www.cnblogs.com/rgjycs/p/9254332.html 在程序调试时的debug和release 网上有如下的描述:Debug 通常称为调试版本,它包 ...