天天看點

全志R16平台Android下添加自定義按鍵

Board:全志R16

SDK:Android KitKat 4.4.2、linux-3.4

開發内容:自定義按鍵名為SOCHIP_EXT1,接在R16開發闆的GPIOB7口。

1.先在linux-3.4/inlcude/linux/input.h

添加自定義按鍵#define SOCHIP_EXT1 0x2e8

注意該鍵值最好不要跟系統的鍵值沖突,然後編寫linux下的key driver代碼。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <mach/irqs.h>
#include <linux/interrupt.h>
#include <asm-generic/errno.h>
#include <asm-generic/errno-base.h>
#include <linux/gpio.h>
#include <mach/gpio.h>

#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/param.h>
#include <linux/jiffies.h>

#include <linux/ioport.h>
#include <linux/io.h>

/* mach/sys_config.h for allwinner platform */
#include <mach/sys_config.h>

#define KEYDEV_NAME "mykey"
#define MY_KEY      KEY_SOCHIP_EXT1

static int g_key_gpio;
static int g_key_irq;

static struct timer_list *key_timer = NULL;
static struct input_dev *key_dev = NULL;
static void __iomem *key_reg;

/* 按鍵處理終端函數 */
static irqreturn_t isr_key_func(int irq, void *arg)
{
    printk(KERN_EMERG "key intretupt is comming ...\n");

    /* HZ的值可linux源碼目錄下的.config可知,我這裡是CONFIG_HZ=100 
     * HZ代表1s鐘中斷發生的次數,此處HZ / 5 相當于 1/5秒 即 200ms
     * 增加定時器的目的是 按鍵去抖動
     */
    mod_timer(key_timer, jiffies + (HZ / ));
    return IRQ_HANDLED; 
}

/* 定時器處理函數 */
static void timer_handler(unsigned long arg)
{
    unsigned int val;
    val = gpio_get_value(g_key_gpio);

    printk("val = %d\n", val);
    if(val == ){
        printk("key up ... \n");
        input_report_key(key_dev, MY_KEY, );
        input_sync(key_dev);

    }else if(val == ){
        printk("key down ...\n");
        input_report_key(key_dev, MY_KEY, );
        input_sync(key_dev);
    }
}

/* 擷取系統配置 */
static int fetch_sysconfig(void)
{
    script_item_u    val;
    script_item_value_type_e  type;

    /* 擷取sys_config.fex中的主鍵值位key, 子健值位key_gpio的資源 
     * 如:
     * [key]
     * key_gpio = port:PB07<4><default><default><default>
     */
    type = script_get_item("key", "key_gpio", &val);
    if(SCIRPT_ITEM_VALUE_TYPE_PIO != type) {
        printk(KERN_ERR "get key_gpio from sys_config.fex is err!");
        return -EINAL;
    }
    g_key_gpio = val.gpio.gpio;

    /* 聲明io */
    gpio_request(g_key_gpio, "KEY_INT_GPIO");

    //根據IO擷取中斷ID
    g_key_irq = gpio_to_irq(g_key_gpio);
    if(g_key_irq == -ENXIO)
    {
        printk(KERN_EMERG "gpio_to_irq failed!\n");
        return -ENXIO;
    }

}


static int __init key_init(void)
{
    int ret = ;
    printk("hello key driver\n");
    //初始化定時器
    key_timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL);
    if(!key_timer){
        printk("kzalloc timer is failed!\n");
        ret = -ENOMEM;
        goto ERR1;
    }
    init_timer(key_timer);
    key_timer->function = timer_handler;//定時服務函數
    key_timer->expires = jiffies + (HZ / );//目前時間 + 定時時間 
    add_timer(key_timer);//添加定時器

    //input結構體申請記憶體
    key_dev = input_allocate_device();
    if(!key_dev){
        printk(KERN_EMERG "key: input_allocate_device failed!\n");
        ret = -ENOMEM;
        goto ERR2;
    }

    key_dev->name = KEYDEV_NAME;  //輸入裝置名字
    key_dev->phys = "input22"; //裝置節點名稱
    key_dev->id.bustype = BUS_HOST;  //裝置辨別ID屬性     用于與事件處理層進行比對
    key_dev->id.vendor = ;
    key_dev->id.product = ;
    key_dev->id.version = ;

    set_bit(EV_KEY, key_dev->evbit);//設定支援的事件類型為key
    set_bit(MY_KEY, key_dev->keybit);//設定裝置支援按鍵類型為MYKEY

    ret = fetch_sysconfig();
    if(ret){
        printk("fetch sysconfig is failed!\n");
        goto ERR4;
    }

    //2.申請中斷
    if(request_irq(g_key_irq, isr_key_func, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "key", NULL)){
        ret = -EBUSY;
        printk(KERN_EMERG "request irq failed!\n");
        goto ERR4;
    }
    //3.向input子系統注冊device
    ret = input_register_device(key_dev);
    if(ret){
        printk(KERN_EMERG "input register device failed!\n");
        goto ERR5;
    }
    return ;    
ERR5:
    free_irq(g_key_irq, NULL);
ERR4:
    gpio_free(g_key_gpio);
ERR3:
    input_free_device(key_dev);
ERR2:
    kfree(key_timer);
ERR1:
    return ret;
}

static void __exit key_exit(void)
{ 
    del_timer(key_timer);  //删除定時器
    kfree(key_timer);//釋放記憶體
    free_irq(g_key_irq, NULL); //釋放中斷id
    gpio_free(g_key_gpio); //第二種方式釋放申請的記憶體資源
    input_unregister_device(key_dev);//解input注冊

    printk("goodbye key driver\n");
}
module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("orange");
MODULE_DESCRIPTION("key driver");
           

2.修改xxx.kl安卓下的按鍵映射檔案,R16平台SDK對應的kl檔案在android/device/softwinner/xxx/configs/sunxi-keyboard.kl,也可通過cat /proc/bus/input/devices 可找到相應的驅動名。(其他kl檔案可在frameworks//base/data/keyboards/中找到)添加key 744 SOCHIP_EXT1。

3.修改framework層的相關檔案,R16平台SDK相關檔案對應的路徑如下:

=>android/frameworks/native/include/input/KeycodeLabels.h中添加如下對應的代碼:

{ "ASSIST",  },
     { "BRIGHTNESS_DOWN",  },
     { "BRIGHTNESS_UP",  },
     { "MEDIA_AUDIO_TRACK",  },
     { "SOCHIP_EXT1" , },  ==>此處添加
           

=>android/frameworks/native/include/android/keycodes.h中添加如下對應的代碼:

265     AKEYCODE_ASSIST          = 219,
266     AKEYCODE_BRIGHTNESS_DOWN = 220,
267     AKEYCODE_BRIGHTNESS_UP   = 221,
268     AKEYCODE_MEDIA_AUDIO_TRACK = 222,
269     AKEYCODE_SOCHIP_EXT1 = 223,   ==>此處添加
           

=>android/frameworks/base/core/res/res/values/attrs.xml中添加如下對應的代碼:

<enum name="KEYCODE_ASSIST" value="219" />
         <enum name="KEYCODE_BRIGHTNESS_DOWN" value="220" />
         <enum name="KEYCODE_BRIGHTNESS_UP" value="221" />
         <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
         <enum name="KEYCODE_SOCHIP_EXT1" value="223" />  ==>此處添加
           

=>android/frameworks/base/core/java/android/view/KeyEvent.java 此檔案有兩處修改,分别如下:

第一處修改:

public static final int KEYCODE_BRIGHTNESS_UP   = ;
      /** Key code constant: Audio Track key
 633      * Switches the audio tracks. */
      public static final int KEYCODE_MEDIA_AUDIO_TRACK = ;
  
      public static final int KEYCODE_SOCHIP_EXT1 = ; ==>此處添加
  
      private static final int LAST_KEYCODE  = KEYCODE_SOCHIP_EXT1;==>此處若LAST_KEYCODE對應的上一行是什麼按鍵就指派什麼。
           

第二處修改:

names.append(KEYCODE_ASSIST, "KEYCODE_ASSIST");
          names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN");
          names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP");
          names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK");
          names.append(KEYCODE_SOCHIP_EXT1, "KEYCODE_SOCHIP_EXT1");==>此處添加
           

=>android/device/softwinner/astar-evb/configs/sunxi-keyboard.kl中添加如下

key    HOME              WAKE
   key     BACK              WAKE
   key    MENU              WAKE_DROPPED
   key    VOLUME_UP
   key    VOLUME_DOWN
   key    SOCHIP_EXT1   ==>此處添加  
           

=>android/frameworks/native/libs/input/Input.cpp =>修改 bool KeyEvent::isSystemKey(int32_t keyCode) ,添加AKEYCODE_SOCHIP_EXT1 ,如添加了代表此按鍵為系統按鍵。

case AKEYCODE_SEARCH:
         case AKEYCODE_BRIGHTNESS_DOWN:
         case AKEYCODE_BRIGHTNESS_UP:
         case AKEYCODE_MEDIA_AUDIO_TRACK:
         case AKEYCODE_SOCHIP_EXT1:
           

最後切記執行make update-api 把剛剛修改的内容更新,可在frameworks/base/api/current.txt找到更新後添加到裡面的按鍵内容,如本文,我們可以搜尋SOCHIP_EXT1,找到的内容如下:

field public static final int KEYCODE_SLASH = ; // 0x4c
     field public static final int KEYCODE_SOCHIP_EXT1 = ; // 0xdf ==>此處
     field public static final int KEYCODE_SOFT_LEFT = ; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = ; // 0x2
           

若沒有執行make update-api是找不到你所添加的按鍵對應的内容,最後編譯、打包、燒錄,至此添加自定義按鍵成功,相關解析按鍵布局的kl檔案可在frameworks/base/services/input/EventHub.cpp。