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。