构建联想K800非官方kernel支持OTG U盘

本文同步自(最佳显示效果请点击):https://zohead.com/archives/k800-kernel-otg-udisk/

这几天专门入了个二手的联想 K800 的 Android 手机,看中的就是它是 x86 的 CPU,其采用 Intel Medfield Atom 平台,具体处理器型号为 Intel Atom Z2460,用的 Android 4.0.4 系统,具体其它配置我就不多说的。

优点:

  • 使用 Intel x86 CPU,方便程序的移植(相对 ARM 而言);
  • 4.5 寸的 1280 x 720 的 IPS 高清屏幕,主要分辨率够给力;
  • 支持 USB OTG;
  • 支持 MHL 视频输出(缺点也在这,下面再说);
  • 耗电没想象中的那么严重;
  • 使用的 Intel Atom Z2460 CPU 支持 EM64T 64 位指令;
  • 使用的 Intel Atom Z2460 CPU 支持 Intel VT-x 虚拟化技术(不过这个好像在 Android 4.1 中用处才发挥出来,暂时也用不上);
  • 很便宜。

缺点:

  • 没有单独的 HDMI 接口,视频输出需要占用 MicroUSB,OTG 与 MHL 无法同时使用;
  • OTG 不支持 U 盘(也是本文要解决的);
  • 恶心的乐 Phone,联想没有公开 kernel 源代码。

上面说的缺点里,最后一条不公开 kernel source 是联想一贯悠久的恶劣传统,也是我最忍受不了的一条。

一番努力搜寻之后,我终于找到了曲线救国的神主:Motorola。对,就是他,虽然摩托似乎从来就没有开放的基因,但被 Google 收购之后,摩托在其推出的 Intel 手机 Moto RAZR i 上终于有良心了一把:公布了 Moto RAZR i 的 kernel source。由于 Moto RAZR i 与联想 K800 同样采用 Intel Medfield 平台,因此我就赌了一把其 kernel source 会有很大程度上的相似性,结果很幸运小成功了。

1、获取源码:

首先在 SourceForge 上抓取 Moto RAZR i 的 kernel source:

http://sourceforge.net/projects/razr-i.motorola/files/

一共 100 多MB,咱先解压,打开 Makefile,确定 kernel version 是 3.0.8 版本。

给联想 K800 root,装 adb 驱动,用 adb shell 连上看,运行 uname -a 查看 K800 手机的 kernel version 是 3.0.8-g37de913,啊哈,除了后缀版本一致。然后尝试读取 /proc/config.gz,无奈联想又是没有把 kernel configuration 给导出,找不到 /proc/config.gz 文件,没办法,只能自己根据当前手机 kernel 判断 K800 当前的 kernel configuration 了。

运行:egrep '(vmx|svm)' /proc/cpuinfo,确定 CPU 支持 Intel VT-x 虚拟化技术,有点小兴奋。

2、准备编译环境:

接着在手机上查看 /proc/version,确定联想 K800 kernel 使用的 gcc 版本为 4.3.3,刚好与 Moto 介绍的一致。然后使用 git clone 从下面的地址得到编译 kernel 的 android x86 toolchain:

https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/x86/i686-android-linux-4.4.3/

需要注意 git 得到的代码中默认已经把 gcc 4.3.3 给移除了,不过运行 git log 可以看到之前的提交日志里是有的,那好办,运行下面命令回滚到最新可用的版本:

git checkout 286506f01f8ca64d6eb0e33bafb475a5cf10ff37

终于有了编译 kernel 的正确环境了(不是完整开发环境哈)。

3、编译 kernel:

Moto 提供的 kernel source 中有几个适合 Intel Medfield 平台的 config 文件,SourceForge 网站上推荐使用 i386_mfld_moto_defconfig,编译时指定 CROSS_COMPILE,但我实际编译之后的模块加载会 kernel panic。好吧,我来尝试应该是 Intel 原始推荐的 i386_mfld_defconfig 默认配置,无法编译通过,排除原因,发现 i386_mfld_defconfig 中启用的几个选项在 K800 中并没有开启,遂决定去掉,同时去掉了 Moto 特有的加密模块。

修改配置之后,能编译了,但编译到 android USB gadget 代码时又有报错,查看代码,发现 Moto 对 android USB gadget 代码做了特殊改动,好吧,这我暂时不需要修改,根据 Moto 增加的 define 修改 drivers/usb/gadget/android.c,去掉 Moto 特有的改动,尽量使代码默认 Intel 原生(看来联想对 Intel 的代码改动很少,这是个好处,嘿嘿,下面也有悲催的地方),再次开始编译。

这次终于比较顺利了,能编译到链接 kernel image 的地方了,但又有报错,这时就不管了,因为我压根就不指望这个编译出来的 zImage 能直接用在联想 K800 手机上,而且联想也没开放制作其 boot image 的工具和方法,就算 zImage 有了也不知道怎么刷到手机上。

接下来编译 kernel modules,这步比较顺利,我把 CIFS、USB Mass Storage(包括 scsi disk 支持)、usbnet、usb serial converter、tun 等需要的模块都选中,都正确编译出来了。

4、修改调试:

拿到手机上加载 cifs.ko,正常,/proc/filesystems 中已经有了 cifs,但挂载文件系统时发现 dmesg 里有 out of memory 报错,一会就 kernel panic 了。

强制重启手机,这时才发现 cifs.ko 大小有 3MB 多,明显太大,查看 config 发现默认启用了 debug kernel,Moto 的默认配置中未启用,不得不说联想真是够懒的,这个影响性能的东西竟然木有去掉。

本来想禁用 CONFIG_DEBUG_KERNEL,但无意发现手机里有 /proc/sched_debug 调度器调试文件,这个是依赖 CONFIG_DEBUG_KERNEL 的,说明 debug kernel 必须启用了。最后发现 i386_mfld_defconfig 中默认的 SLUB debug 等几个选项在联想 K800 kernel 中是关闭的,保存 config 重新编译。由于启用了 debug kernel,编译出来的模块不可避免的都很大,不得不用 strip --strip-unneeded *.ko 来去除没用的东西。

再次拷贝到手机上,insmod cifs.ko,正常,mount 挂载 Windows 共享目录终于不 panic 了,但用户验证失败,看 dmesg 发现 kernel 缺少 md4 支持,将 md4 模块也编译拷到手机上开始测试:

insmod md4.ko
insmod cifs.ko
mount -t cifs -o username=xxx,password=xxx //192.168.1.xxx/share /mnt

挂载终于正常了。小激动人心,灰常不容易,总不辜负我 panic 了好几次的 K800 手机。话说每次 panic 都得强制抠电池再开机滴啊,555。

下面开始测试外接 U 盘(必须要有 USB OTG 线哦):

insmod scsi_mod.ko
insmod sd_mod.ko
insmod usb-storage.ko

插上 U 盘,手机没任何反应,不过在 dmesg 里已经能看到上来的 sda 设备,运行 fdisk -l 命令可成功看到分区,看来只是手机系统没有做自动挂载外置 U 盘的处理(也正常,本来就不支持),自动挂载可以考虑装 StickMount 之类的软件哦。

使用 USB 转 串口(和实际芯片有关):

insmod usbserial.ko
insmod pl2303.ko

使用 USB 有线网卡(和实际芯片有关):

insmod usbnet.ko
insmod asix.ko

5、总结:

到这地步对我来说已经是颇有进展了,我暂时只看重 U 盘支持这个模块,嘿嘿。其它东西等有关时再来折腾了。

下面是我放出的压缩包下载链接:

http://miseal.googlecode.com/files/k800-kernel-config-modules.7z

里面包含我现在编译 kernel 使用的 config 和编译出来的一些有用的 kernel modules,不想自己编译的哥们就自行使用,由于这根本不是官方 kernel,我不对任何导致你的 K800 手机 panic 挂掉的后果承担责任,哈哈。