几百块钱的Windows寨板一般都是这样的配置:CPU是Intel的Baytrail z3735f,或者Cherrytrail z8300/z8350,都是不到2GHz的四核凌动x86,而后者的核显性能数倍于前者(虽然性能都不高,但还是属于吊打树莓派的那种)。内存一般是2GB,而z83xx可以上4GB,只是性能会有所降低。闪存一般是32GB的emmc flash,聊胜于无。外设方面就是触屏WiFi蓝牙SD卡USB云云。它们一般跑着win10或者win+Android双系统。
对于树莓派一类玩家而言这些寨板吸引人的地方在于,价格便宜!x86的性能强!主频高内存大!WiFi!屏幕!然而虽然是x86的机器,它们并不能直接安装Ubuntu一类系统,原因在于:
- 32位UEFI,因为32位的Windows占用空间小一些
- 驱动非常不齐全
以没经过处理的Ubuntu-1404
为例,64位镜像因为机子UEFI是32位的而无法启动,32位镜像没有EFI启动文件也启动不了。强行给32位镜像补上EFI文件则可以顺利安装,然而电池、SD卡、触屏、WiFi、声卡、屏幕调光、按键、陀螺仪、摄像头之类的驱动统统没有,只有USB能用。。。
要解决这两个问题势必要经过一些折腾。
启动镜像
少数安卓双系统的机子用的是64位UEFI,因此可以直接启动64位镜像。然而大多数机子并不能直接启动Ubuntu镜像。虽然32位UEFI只可以运行32位的.efi
,但是multiarch
版的镜像的efi可以接着启动64位的程序,从而启动到grub并继续启动下去。
multi-arch
新版的Debian 9可以直接下载multi-arch版本的镜像,它的关键是有efi/boot/bootia32.efi
这个文件,从而可以用32位UEFI启动64位镜像。但是Debian装后只有基本系统,后续定制起来有点麻烦。
有个野生的名叫XJUbuntu的发行版定制了很多东西,其中有个玩家在他的台电X98 plus平板上定制Ubuntu 16.04,跑通了很多东西,制作了所谓XJUbuntuTAB。但是这个镜像很大,定制的xfce桌面我也并不特别习惯,并且很多关键驱动如电池、触屏在我平板上都不行。
如果要用原生Ubuntu,可以将bootia32.efi
加到其中从而使其可以启动;
linuxium的工具
Linuxium是个机顶盒、电视棒的Linux玩家,他的博客有很多非常有意思的东西。为了在x86的电视棒上跑Ubuntu,他开发了isorespin.sh这个脚本,功能非常多,包括:
- 添加32位UEFI启动文件
- 添加Apollo lake的必要文件(对于N3450系列的赛扬芯平板)
- 更改Linux内核,从而添加驱动补丁
- 新增软件包等,从而添加固件和驱动
- 运行脚本
其实这些都是Ubuntu-LiveCD定制的工作,只是Ubuntu的wiki上对于UEFI的定制说明太少了。
利用isorespin.sh
,可以为64位Ubuntu 18.04添加32位启动项:
$ isorespin.sh -i ubuntu-18.04-desktop-amd64.iso
因为它需要mount镜像,所以它需要root权限。需要留意的是虽然它可以用--atom
来添加特别的驱动,比方说rtl8723bs的WiFi和蓝牙。但是这都要梯子才能下载,命令行中sudo之后的代理有点问题,所以这些东西还是启动之后再安装吧。大概半个小时之后它会生成一个名叫linuxium-ubuntu-18.04-desktop-amd64.iso
的镜像(大部分时间用在squashfs的解压和重新生成上)。
选择哪个桌面
Ubuntu 17.10开始的官方发行版桌面为GNOME;但现在的GNOME 3问题在于太过耗资源了,刚启动就占了1个多GB,开两个gnome-terminal就快要炸了。轻量级的桌面有LXDE、XFCE等等,个人感觉XFCE稍微好看点。。。
Linux驱动
越新版的内核,一些外设的驱动越有可能得到支持。比方说最新的Ubuntu 18.04,在我的昂达V101W
上就能用SD卡、电池、背光调节、陀螺仪、开关机按钮了。其他的能折腾出来的驱动罗列如下。
WiFi
一般网卡是rtl8723bs,它的驱动已经合并到linux 4.12的staging目录下面了,所以Ubuntu 18.04有它的驱动。但是网卡还需要一个固件,可以从hadess的github上下载。
dmesg看到缺少这个固件:
$ dmesg | grep rtl8723
...
[ 170.823731] rtl8723bs: acquire FW from file:rtlwifi/rtl8723bs_nic.bin
[ 170.823790] rtl8723bs mmc0:0001:1: Direct firmware load for rtlwifi/rtl8723bs_nic.bin failed with error -2
...
就把固件复制到/lib/firmware/rtlwifi/
目录下面,重新加载驱动即可。
$ sudo cp rtl8723bs_nic.bin /lib/firmware/rtlwifi/
$ sudo modprobe -r r8723bs
$ sudo modprobe r8723bs
$ dmesg | grep rtl8723
...
[ 228.095947] rtl8723bs: acquire FW from file:rtlwifi/rtl8723bs_nic.bin
...
$ ifconfig wlan0
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.2.225 netmask 255.255.255.0 broadcast 192.168.2.255
inet6 fe80::74b5:1920:54c6:e8d prefixlen 64 scopeid 0x20<link>
ether 8c:18:d9:1f:3e:fd txqueuelen 1000 (以太网)
RX packets 579 bytes 705015 (705.0 KB)
RX errors 0 dropped 582 overruns 0 frame 0
TX packets 605 bytes 70957 (70.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
对于博通系列的SDIO网卡也一样是补上固件就能用了。博通的驱动比较通用,几乎支持所有的AP6xxx
模块;它除了需要固件以为还需要配置文件,这些都可以在github上找到,比方说华硕T100的固件。
值得一提的是,Lubuntu 18.04的rtl8723bs则直接可用。
蓝牙
蓝牙一般都是通过串口,以HCI协议进行交互。老版内核会认出一个MMIO的串口(通常是ttyS4
),由一个systemd守护进程(而不是内核驱动)通过这个串口下载蓝牙固件、初始化、与之交互,详见这个仓库的start_bt.sh。
但是新版的内核引入了所谓serdev
的概念,驱动事宜都由内核解决。这时串口就不仅仅是一个“字符设备”,而是一个“总线”了。这时它就不会将串口/dev/ttySx
暴露给用户空间了。然而rtl8723bs的蓝牙驱动现在内核里面又没有,所以就需要一些内核补丁。
- 可以用这个补丁,它简单地加了一个判断,不要将OBDA8723设备注册为
serdev
,从而可以用之前的systemd守护进程。 - 或者用这些补丁就详细实现了HCI5协议以及rtl8723bs的驱动,进而不需要用户空间的systemd了。其实这些补丁来自于Linux-sunxi,虽然说是全志的专用内核,但是也包含了很多新奇趣怪的驱动,比方说jwrdegoede这位兄弟貌似在搞GPD win掌机的驱动。。
linux 4.17内核打了sunxi的补丁,加上蓝牙的固件和配置文件(lwfinger的仓库里面有),蓝牙就可以愉快地跑了。
[ 8.027854] Bluetooth: hci0: rtl: examining hci_ver=06 hci_rev=000b lmp_ver=06 lmp_subver=8723
[ 8.032153] Bluetooth: hci0: rom_version status=0 version=1
[ 8.032183] Bluetooth: hci0: rtl: loading rtl_bt/rtl8723bs_fw.bin
[ 8.033786] Bluetooth: hci0: rtl: loading rtl_bt/rtl8723bs_config-OBDA8723.bin
[ 8.064135] Bluetooth: hci0: cfg_sz 55, total size 24263
触屏
很多win或安卓平板用的触屏芯片都是gslx680,一个I2C接口的电容屏芯片。它也需要固件,根据电容屏的行列布线不同而需要不同的固件。好事情是驱动和固件都能找到。
- gslx680-acpi适用于ACPI平台,可以加入内核中。
- gsl-firmware适用于不同的平板,如果没有支持的平板的话可用里面的工具自己生成。
对于我的昂达V101W-V5平板来说,可以从昂达旧官网上下载Windows驱动。找到TP/SileadTouch.fw
这个固件,然后利用gsl-firmware的工具来生成适用的固件:
$ tools/unscramble SileadTouch.fw silead_ts.fw
$ sudo cp silead_ts.fw /lib/firmware
生成的固件直接丢在/lib/firmware/
目录下面就行了。这时启动之后就可以用触屏了。
[ 6.736112] gslx680 i2c-MSSL1680:00: gsl_ts_probe: got a device named MSSL1680:00 at address 0x40, IRQ 23, flags 0x0
[ 6.768964] byt_gpio INT33FC:02: [Firmware Bug]: pin 21 forcibly re-configured as GPIO
[ 6.770426] input: Silead GSLx680 Touchscreen as /devices/platform/80860F41:03/i2c-3/i2c-MSSL1680:00/input/input4
启动之后可以使用xinput_calibrator
进行更细致的微调。
另外要想加一些手势操作比方说长按右键、两根手指、三根手指、滑动等等,可以用touchegg
来配置。
声卡
Windows平板用的声卡一般都是alc5640
,对于新版内核来说也是这样,有驱动没固件没配置文件。
- 固件可以直接用华硕T100的固件,添加到
/lib/firmware/intel/
目录下面。 - 配置文件用这份UCM,需要复制到
/usr/share/alsa/ucm/bytcr-rt5640/
目录下面。 - 另外还需要用
alsa
的工具来配置默认输出。
linuxium用这些方法弄好了Intel计算棒的HDMI音频输出,同样道理也可以弄好普通声卡输出。
首先查看有哪些音频设备:
$ aplay -l
**** PLAYBACK 硬體裝置清單 ****
card 0: Audio [Intel HDMI/DP LPE Audio], device 0: HdmiLpeAudio [Intel HDMI/DP LPE Audio]
子设备: 1/1
子设备 #0: subdevice #0
card 0: Audio [Intel HDMI/DP LPE Audio], device 1: HdmiLpeAudio [Intel HDMI/DP LPE Audio]
子设备: 1/1
子设备 #0: subdevice #0
card 1: bytcrrt5640 [bytcr-rt5640], device 0: 1 []
子设备: 1/1
子设备 #0: subdevice #0
card 1: bytcrrt5640 [bytcr-rt5640], device 1: Deep-Buffer Audio (*) []
子设备: 1/1
子设备 #0: subdevice #0
可见card 1
那里有两个bytcr-rt5640
设备。试着用card1,device0
来播放测试音频:
$ aplay -D plughw:1,0 /usr/share/sounds/alsa/Front_Left.wav
正在播放 WAVE '/usr/share/sounds/alsa/Front_Left.wav' : Signed 16 bit Little Endian, 频率48000Hz, Mono
不出意外可以听到扬声器说出“front left”这句话来。
然后我们就要修改/etc/pulse/default.pa
来设置默认音频设备了。找到加载module-alsa-sink
这一行,取消注释,并加上device=hw:1,0
load-module module-alsa-sink device=hw:1,0
然后把下面一段的“Automatically load driver modules”的那几行都注释掉。
重启,就可以有声音了。然而只是扬声器有效,耳机并不行,想必是ucm文件没有这份配置。
一些踩坑记录:
- 如果没有固件,则声卡不能成功初始化
- 如果没有ucm文件,则dmesg中会不断刷屏说“byt-rt5640 byt-rt5640: ASoC: CPU DAI baytrail-pcm-audio not registered”
- 如果没有修改
/etc/pulse/default.pa
,那么在登录之前就有声音,进桌面就没声音。
电池
平板用的电源管理芯片一般是AXP288
,它能输出多路直流电源并管理锂电池,通过I2C接口来配置和读取信息。在老板内核里面没有axp288驱动,于是Icenowy大神就写了一个systemd来生成一个测试电源,并利用i2cget
来读取AXP288的寄存器,从而得到电量、是否充电之类的信息。
新版内核就有AXP288驱动了,在不少平板上都可以愉快使用,但是在我之前收的一块拆机主板上电量读取总是为0。翻手册发现,电量输出有两个可能的寄存器,一个是0xB9
,一个是0xE4
,前者通过电流积分来算容量,后者则根据电压来估计容量,一般情况下读前者就行了。Linux驱动中读电量的fuel_gauge_get_property()函数读取的是前面的那个寄存器寄存器,而这块板子读出来就是0,只能读后面的寄存器。于是修改如下:
@@ -498,7 +498,7 @@
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- ret = fuel_gauge_reg_readb(info, AXP20X_FG_RES);
+ ret = fuel_gauge_reg_readb(info, AXP288_FG_OCV_CAP_REG);
if (ret < 0)
goto fuel_gauge_read_err;
这些情况在拆机主板上可能比较常见,因为长时间没电池可能导致AXP288的计数器出了问题。