MTK 平台Android系统遥控器映射关系
在我们工作中,经常要去适配遥控器的工作,但是大部时候我们是移植其他工程上的代码来修改,可能对Android系统中的按键关系有些不清楚,下面以MTK平台为例,介绍下Android系统中按键映射关系(以应用层的KEYCODE_POWER键为例)。
我们先从上往下看
第一、应用的按键值。
第一, 在应用上我们按遥控器Power按键,会抛出26,这个按键值的定义在(/framework/base/core/android/view/KeyEvent.java)文件中,如下:
public static final int KEYCODE_POWER = 26; (向应用层的抛上的键值就是26)
第二、应用层与Android系统映射关系
应用上的这个按键值会与Android系统中的键值相对应起来,
对应关系在(/framework/native/include/input/KeycodelLables.h)文件中
如下:
static const KeycodeLabel KEYCODES[] = {
{"SOFT_LEFT", 1 },
{"SOFT_RIGHT", 2 },
{"HOME", 3 },
{"BACK", 4 },
{"CALL", 5 },
{"ENDCALL", 6 },
{ "0",7 },
{ "1",8 },
{ "2",9 },
{ "3",10 },
{ "4",11 },
{ "5",12 },
{ "6",13 },
{ "7",14 },
{ "8",15 },
{ "9",16 },
{"STAR", 17 },
{"POUND", 18 },
{"DPAD_UP", 19 },
{"DPAD_DOWN", 20 },
{"DPAD_LEFT", 21 },
{"DPAD_RIGHT", 22 },
{"DPAD_CENTER", 23 },
{"VOLUME_UP", 24 },
{"VOLUME_DOWN", 25 },
{ "POWER", 26 }, (POWER是android系统定义的宏,26表示应用层上的键值)
..........
};
同时系统里面有个遥控器资源文件(/framework/base/core/res/res/values/attrs.xml),这个文件里面按键关系跟上面的KeycodelLables.h文件关系是一致的。
如下:
<attr name="keycode">
<enumname="KEYCODE_UNKNOWN" value="0" />
<enumname="KEYCODE_SOFT_LEFT" value="1" />
<enumname="KEYCODE_SOFT_RIGHT" value="2" />
<enumname="KEYCODE_HOME" value="3" />
<enumname="KEYCODE_BACK" value="4" />
<enumname="KEYCODE_CALL" value="5" />
<enumname="KEYCODE_ENDCALL" value="6" />
……………………………………………………
…………………………………………………………………………
<enumname="KEYCODE_VOLUME_DOWN" value="25" />
<enumname="KEYCODE_POWER" value="26" />
<enumname="KEYCODE_CAMERA" value="27" />
<enumname="KEYCODE_CLEAR" value="28" />
<enumname="KEYCODE_A" value="29" />
………………………………………………………………
……………………………………………………………………………………
</attr>
第三步、Android系统按键跟Linux内核中键值的映射关系
涉及到文件(framework/base/data/keyboards/Vendor_000b_Product_000b.kl)
文件格式如下:
key 116 POWER WAKE (116表示Linux 里面的键值,POWER表示 android 系统的键值)
key 60 SETTINGS
key 172 HOME
key 139 MENU
key 14 BACK
key 103 DPAD_UP
key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 108 DPAD_DOWN
key 28 DPAD_CENTER
key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
key 115 VOLUME_UP
#red
key 64 F6
#green
key 65 F7
#yellow
key 66 F8
#blue
key 67 F9
key 104 PAGE_UP
key 109 PAGE_DOWN
key 87 CHANNEL_UP
key 88 CHANNEL_DOWN
key 164 MEDIA_PLAY_PAUSE
key 2 1
key 3 2
key 4 3
key 5 4
key 6 5
key 7 6
key 8 7
key 9 8
key 10 9
key 11 0
# (*) (#)
key 522 STAR
key 523 POUND
Linux中的键值定义
(/mediate/platform/mt8127/include/linux/input.h)
#define KEY_END 107
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
#define KEY_MACRO 112
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
#define KEY_POWER 116 /* SC System Power Down*/
#define KEY_KPEQUAL 117
#define KEY_KPPLUSMINUS 118
#define KEY_PAUSE 119
#define KEY_SCALE 120 /* AL Compiz Scale(Expose) */
第四步、Liunx中键值与红外键值(物理键值)映射关系
(涉及到文件:/mediate/platform/mt8127/kernel/drivers/ir/mtk_ir_cus_nec.h)
// this table is used in normal mode, fornormal_boot
static struct rc_map_table mtk_nec_table[] ={
{0xdc,KEY_POWER},
//{0x98, KEY_F3}, //sound track
{0x9c, KEY_MUTE}, //mute
{0x8d, KEY_F2},//setting
//{0xd6, KEY_F5},//refresh
{0xcd, KEY_F6}, //red
{0x91, KEY_F7}, //green
{0x83, KEY_F8}, //yellow
{0xc3, KEY_F9}, //blue
{0x88, KEY_HOMEPAGE},
{0x82, KEY_MENU},
{0xc5, KEY_BACKSPACE},
{0xca, KEY_UP},
{0xd2, KEY_DOWN},
{0x99, KEY_LEFT},
{0xc1, KEY_RIGHT},
{0xce, KEY_ENTER},
{0x95, KEY_PLAYPAUSE},
{0x80, KEY_VOLUMEUP},
{0x81, KEY_VOLUMEDOWN},
{0xdd, KEY_PAGEUP},
{0x8c, KEY_PAGEDOWN},
{0x85, KEY_F11},
{0x86, KEY_F12},
{0x87, KEY_0},
{0x92, KEY_1},
{0x93, KEY_2},
{0xcc, KEY_3},
{0x8e, KEY_4},
{0x8f, KEY_5},
{0xc8, KEY_6},
{0x8a, KEY_7},
{0x8b, KEY_8},
{0xc4, KEY_9},
{0xda, KEY_NUMERIC_STAR},//*
{0xd0, KEY_NUMERIC_POUND},//#
};
第五、遥控器映射关系图
前面四大步骤已经介绍了,大概关系如下图
第六步、如何快速更改的遥控器按键值
上述五大步骤主要涉及到的是遥控器的映射关系,但是在我们实际修改遥控中,涉及到的修改主要是:
修改物理键值(mtk_ir_cus_nes.h),和kl文件中的遥控器按键的映射关系值
一般我们的遥控器的的协议是NEC,需要修改的主要是物理按键和用户码,
物理键值和用户码,一般都会给出的。如果没有给出,我们可以通过遥控器内核打印来查看相应的物理键值和用户码
第七步 常见问题
1、厂商给的用户码和物理键值不对
答:通过遥控器的内核打印可以找到相应按键的物理键值和遥控器的用户码
2、 Kl文件书写问题
答: 当我们新的遥控添加进去后,发现部分按键操作不对。但是查找映射关系,都是对的。这个时候,我们需要查看下我们添加的kl文件是否加载上
解决方法,通过dumpsys命令来查看新加的kl文件是否加载进去,如果没有,说明新增的kl文件书写有问题,这个时候需要我们自己去一个个排查
3、Android如何加载遥控器kl文件
答:kl文件命令是有要求的,
Vendor_000b_Product_000b.kl 这个文件的命名规则是:
红蓝色分别是VID和PID
如: kernel/ drivers/input/keyboard/atkbd.c键盘驱动中定义了 input_dev->id.vendor = 0×0001; input_dev->id.product = 0×0001;,那么与之对应的配置名为Vendor_0001_Product_0001.kl
MTK平台涉及到到的文件如下:
\mediatek\platform\mt8127\kernel\drivers\ir\mtk_ir_core.cmtk_ir_core.h
#define IR_BUS BUS_HOST
#define IR_VERSION 11
#define IR_PRODUCT 11
#define IR_VENDOR 11
\mediatek\platform\mt8127\kernel\drivers\ir\mtk_ir_core.cmtk_ir_core.c
static int mtk_ir_core_probe(struct platform_device*pdev)
{
struct mtk_ir_core_platform_data *pdata =pdev->dev.platform_data;
struct rc_dev *rcdev = NULL ;
int ret = 0;
/* id = -1, it is the mtk_ir_dev_parent,
only for registerlirc_driver and begin mtk_ir_input_thread,
bause lirc_driverand mtk_ir_input_thread are for all devices*/
if (-1 ==pdev->id)
{
mtk_ir_core_create_attr(&(pdev->dev));// create device attribute
ret =mtk_ir_lirc_register(&(pdev->dev));
if (ret)
{
IR_LOG_ALWAYS("mtk_ir_lirc_register fail ret(%d) !!!\n",ret);
}
return ret;
}
/* register really ir device nec or rc5 orrc6 ....*/
ASSERT(pdata != NULL);
ASSERT(pdata->init_hw != NULL);
ASSERT(pdata->uninit_hw != NULL);
ASSERT(pdata->p_map_list != NULL);
ASSERT(pdata->ir_hw_decode != NULL);
platform_device_unregister(mtk_rc_core.dev_current);// first unregister old device
ret = pdata->init_hw(); // init this ir's hw
if (ret)
{
IR_LOG_ALWAYS(" fail to init_hw forir_dev(%s) ret = %d!!!\n",
pdata->input_name, ret);
goto err_init_hw;
}
rcdev = rc_allocate_device(); // alloc rcdevice and rc->input
if (!rcdev) {
ret = -ENOMEM;
IR_LOG_ALWAYS("rc_allocate_devicefail\n");
goto err_allocate_device;
}
rcdev->driver_type = RC_DRIVER_SCANCODE;
rcdev->allowed_protos =pdata->p_map_list->map.rc_type;
rcdev->input_name = pdata->input_name;// /proc/bus/input/devices
rcdev->input_id.bustype = BUS_HOST;
rcdev->input_id.version = IR_VERSION;
rcdev->input_id.product= IR_PRODUCT;
rcdev->input_id.vendor= IR_VENDOR;
rcdev->driver_name = MTK_IR_DRIVER_NAME;
rcdev->map_name =pdata->p_map_list->map.name;
ret = rc_register_device(rcdev);
if (ret < 0) {
IR_LOG_ALWAYS( "failed to register rcdevice for ir_dev(%s) ret(%d)!!!\n",
pdata->input_name, ret);
goto err_register_rc_device;
}
rc_set_keypress_timeout(pdata->i4_keypress_timeout);
clear_bit(EV_MSC,rcdev->input_dev->evbit);
clear_bit(MSC_SCAN,rcdev->input_dev->mscbit);
#if MTK_IRRX_AS_MOUSE_INPUT
mtk_rc_core.p_devmouse =mtk_ir_mouse_register_input(pdev);
if (NULL == mtk_rc_core.p_devmouse)
{
IR_LOG_ALWAYS("fail to registerir_mouse device(%s)\n",pdata->mousename);
goto err_register_mousedev;
}
#endif
mtk_rc_core.rcdev = rcdev;
mtk_rc_core.dev_current = pdev;
ret =mtk_ir_core_register_swirq(IRQF_TRIGGER_LOW);
if (ret)
{
goto err_request_irq;
}
if (g_ir_timer.function == NULL)
{
init_timer(&g_ir_timer);
g_ir_timer.function = mtk_ir_timer_function;
g_ir_timer.expires = jiffies + TIMER_PERIOD;
add_timer(&g_ir_timer);
}
return 0;
err_request_irq:
rc_unregister_device(rcdev);
rcdev = NULL;
err_register_mousedev:
err_register_rc_device:
rc_free_device(rcdev);
rcdev = NULL;
mtk_rc_core.rcdev = NULL;
err_allocate_device:
pdata->uninit_hw();
err_init_hw:
return ret;
}