为A20开发板适配红外遥控,记录遇到的问题

我手上的开发板是BananaPi-m1,自带红外接收器,这里以Android 4.2为例,虽然说是开发板,但是全志提供的东西少的可怜,A20对应的Android源码只有4.2一份,网络上的教程坑很多。

源码和编译工具

BananaPi-Android-4.2.2-Liab 这个项目里面基本都有了,但是整个项目10G+, 我们并不需要那么多,只要克隆lichee目录就可以了。

1
2
3
4
5
6
7
mkdir BananaPi-Android-4.2.2-Liab
cd BananaPi-Android-4.2.2-Liab
git init
git remote add origin https://github.com/ChrisP-Android/BananaPi-Android-4.2.2-Liab.git
git config core.sparsecheckout true
echo "lichee/*" >> .git/info/sparse-checkout
git pull --depth=1 origin master

编译工具使用gcc-linaro,使用Ubuntu软件仓库上的arm-linux-gnueabihf-gcc都是5以上的版本,没办法编译。

获取config.gz

/proc/config.gz拷贝出来,这里指的是开发板上运行的Android上拷贝出来的,解压放到BananaPi-Android-4.2.2-Liab/lichee/linux-3.4/目录。编译时候发现编译EMAC驱动和GMAC驱动出错,修改.config,取消EMAC和GMAC驱动的编译。

1
2
CONFIG_SUNXI_EMAC=n
CONFIG_SUNXI_GMAC=n

这样子就可以编译出能用的内核了。

修改Ir驱动

修改linux-3.4/drivers/input/keyboard/ir-keymap.h将其中的

1
#define IR_CHECK_ADDR_COD

注释掉,即跳过遥控码检查,这样能接受所有支持NEC协议的遥控发来的信号。修改linux-3.4/drivers/input/keyboard/sun7i-ir.c在458行,添加打印用户码的语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static int ir_code_valid(unsigned long code)
{
printk(KERN_DEBUG "IR_CODE:0x%x\n",code);//添加这一句
unsigned long tmp1, tmp2;
#ifdef IR_CHECK_ADDR_CODE
/* Check Address Value */
if ((code&0xffff) != (ir_addr_code&0xffff))
return 0; /* Address Error */
tmp1 = code & 0x00ff0000;
tmp2 = (code & 0xff000000)>>8;
return ((tmp1^tmp2)==0x00ff0000); /* Check User Code */
#else
/* Do Not Check Address Value */
tmp1 = code & 0x00ff00ff;
tmp2 = (code & 0xff00ff00)>>8;
//return ((tmp1^tmp2)==0x00ff00ff);
return (((tmp1^tmp2) & 0x00ff0000)==0x00ff0000 );
#endif /* #ifdef IR_CHECK_ADDR_CODE */
}

重新编译,将编译得到sun7i-ir.ko驱动挂载上去,调试,获取遥控上的按键码还有用户码,用户码指的是每个遥控对应的ID,按键码对应每个按键的ID。

1
2
getevent //获取按键码,这里获得的按键码是十六进制,后面使用的时候需要转为十进制
dmesg | grep IR_CODE //这里获取的用户码为后面四位,不需要调换顺序

将上面需要的内容记录下来。

适配红外遥控器

修改linux-3.4/drivers/input/keyboard/ir-keymap.h中下面代码

1
2
#define IR_CHECK_ADDR_COD // 还原回来
#define IR_ADDR_CODE (0x9f00) // 修改为你获取到的用户码

修改linux-3.4/drivers/input/keyboard/sun7i-ir.c在683左右,

1
2
3
4
if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("ir_para", "ir_addr_code", &ir_addr_code)){
pr_err("%s: ir_addr_code script_get_item error. \n",__func__ );
ir_addr_code = 0x9f00; // 修改为你获取到的用户码
}

这里有一个坑,在458

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static int ir_code_valid(unsigned long code)
{
unsigned long tmp1, tmp2;
#ifdef IR_CHECK_ADDR_CODE
/* Check Address Value */
if ((code&0xffff) != (ir_addr_code&0xffff))
/* 这里的ir_addr_code貌似是从缓存里面读取的,我卸载掉原先的驱动,
然后挂载新的驱动,这里的ir_addr_code并没有立即生效,不知道是从配
置文件读取还是从缓存读取,解决的办法是直接把ir_addr_code替换为刚才获取的用户码 */
return 0; /* Address Error */
tmp1 = code & 0x00ff0000;
tmp2 = (code & 0xff000000)>>8;
return ((tmp1^tmp2)==0x00ff0000); /* Check User Code */
#else
/* Do Not Check Address Value */
tmp1 = code & 0x00ff00ff;
tmp2 = (code & 0xff00ff00)>>8;
//return ((tmp1^tmp2)==0x00ff00ff);
return (((tmp1^tmp2) & 0x00ff0000)==0x00ff0000 );
#endif /* #ifdef IR_CHECK_ADDR_CODE */
}

单独编译红外驱动模块

注意 第一次要完整编译,然后才可以单独编译某个模块,单独编译的命令如下:

1
make -j4 CONFIG_IR_SUN7I=m ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- M=drivers/input/keyboard

将编译出来的sun7i-ir.ko替换系统中对应的驱动,使用getevent可以打印出来,接下来就简单了,还有问题的话,看看之前哪里出错。

修改/system/usr/keylayout/sun7i-ir.kl文件,将之前获取到的按键替换进去,每个按键码对应一个标签,关于按键标签可以在安卓源码中的 KeycodeLabels.h 文件找到,这里提供一份整理好看,点击查看。关于标签后面的Tag,WAKE表示唤醒并发送按键到软件,WAKE_DROPPED表示唤醒不发送按键,还有一些特殊的按键比如PROG_RED PROG_BLUE PROG_GREEN PROG_YELLOW对应遥控的红黄蓝绿按键,有的话也可以添加上去。

重启,适配完成。

其他

这块板子是三年前买的,即使现在网上很多号称自主研发的高清机顶盒都采用A20方案,换个桌面,其他都没换,硬解1080p压力不大,但是声音硬解能力不行,比如AC3,驱动不完整是硬伤,不支持kodi,除了价格便宜没有其他优势,如果想买开发板,推荐树莓派,资料全。