修改Remix OS kernel支持Chromebook触控板

继续接着上一篇文章「修改Remix OS适配Chromebook键盘」的修改之后在我的 Dell Chromebook 11 上使用 ext4 U 盘形式的 Remix OS PC 版已经是比较顺利了,那么剩下最大的问题就是触控板问题了,要知道之前我使用 Remix OS 的时候都是必须插着一个 USB 鼠标的。

Chromebook 的触控板由于比较特殊之前很多网友安装的 Ubuntu 系统里经常也用不了,这里我以 Dell Chromebook 11 为例子对 Remix OS PC 版内核模块做一些修改可以实现 Remix OS 下基本的触控功能,对于在 Chromebook 上单独安装的 Linux 系统下想使用触控板的用户也能做一个参考。

下面的篇幅有很大一部分是对 Remix OS 不能使用 Chromebook 触控板的原因分析,不想了解技术细节的话可以直接拖到最后「修改 Remix OS 系统文件」部分下载并使用我修改编译出来的适合 Remix OS 的内核模块哦。

编写这篇文章时我使用的是 Remix OS PC 版 2016-02-01 alpha 版本,对应 Android x86 5.1.1 版本,Linux kernel 版本 4.0.9;
我使用的 Chrome OS 版本是 48.0.2564.116 正式版,Linux kernel 版本 3.8.11。

触控板问题分析

首先确认能正常工作的 Chrome OS 下的 Chromebook 触控板相关信息,看看 Linux 输入设备中的触控板设备:

I: Bus=0018 Vendor=0000 Product=0000 Version=0001
N: Name="Cypress APA Trackpad (cyapa)"
P: Phys=i2c-9-0067/input0
S: Sysfs=/devices/pci0000:00/0000:00:15.1/i2c-9/9-0067/input/input7
U: Uniq=
H: Handlers=event7 
B: PROP=5
B: EV=b
B: KEY=e520 10000 0 0 0 0
B: ABS=660800001000003

可以看到 Dell Chromebook 11 上的触控板其实用的是 Cypress 家的 APA I2C 输入设备,Chrome OS 上对应 i2c-9 适配器,I2C 地址是 67,对应的 I2C 输入设备驱动为 cyapa

提示

其它也有不少三星、HP 之类的 Chromebook 设备用的是 I2C 触控板,但不一定是同一厂商的,有的是使用 ELAN 等 I2C 触控板;
另外具体机器上 I2C 地址是固定的,i2c-9 适配器则是 Linux kernel 自动生成的并不固定。

接下来看看 I2C 适配器实际对应的设备位置和名称:

chronos@localhost ~ $ cd /sys/class/i2c-adapter/
chronos@localhost /sys/class/i2c-adapter $ ls -dl *
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-0 -> ../../devices/pci0000:00/0000:00:02.0/i2c-0
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-1 -> ../../devices/pci0000:00/0000:00:02.0/i2c-1
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-10 -> ../../devices/pci0000:00/0000:00:15.2/i2c-10
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-2 -> ../../devices/pci0000:00/0000:00:02.0/i2c-2
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-3 -> ../../devices/pci0000:00/0000:00:02.0/i2c-3
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-4 -> ../../devices/pci0000:00/0000:00:02.0/i2c-4
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-5 -> ../../devices/pci0000:00/0000:00:02.0/i2c-5
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-6 -> ../../devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/i2c-6
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-7 -> ../../devices/pci0000:00/0000:00:02.0/drm/card0/card0-DP-1/i2c-7
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-8 -> ../../devices/pci0000:00/0000:00:1f.3/i2c-8
lrwxrwxrwx 1 root root 0 Mar  1 22:38 i2c-9 -> ../../devices/pci0000:00/0000:00:15.1/i2c-9
chronos@localhost /sys/class/i2c-adapter $ cat i2c-*/name
i915 gmbus ssc
i2c-designware-pci-1
i915 gmbus vga
i915 gmbus panel
i915 gmbus dpc
i915 gmbus dpb
i915 gmbus dpd
DPDDC-A
DPDDC-B
SMBus I801 adapter at 0400
i2c-designware-pci-0

可以看到触控板的 I2C 适配器 i2c-9 在 PCI 设备 0000:00:15.1 上,名称为:i2c-designware-pci-0,另外系统里还有 i2c-10 适配器在 0000:00:15.2 上,名称为:i2c-designware-pci-1,这两个适配器对应的 I2C 总线驱动是:i2c-designware-pci

下面就可以在 Chromebook 上启动 Remix OS 确认其内核下 I2C 设备信息是否正确:

chronos@localhost ~ $ cd /sys/class/i2c-adapter/
root@remix_cn_x86_64:/sys/class/i2c-adapter # ls -dl *
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-0 -> ../../devices/pci0000:00/0000:00:02.0/i2c-0
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-1 -> ../../devices/pci0000:00/0000:00:02.0/i2c-1
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-10 -> ../../devices/pci0000:00/0000:00:1f.3/i2c-10
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-2 -> ../../devices/pci0000:00/0000:00:02.0/i2c-2
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-3 -> ../../devices/pci0000:00/0000:00:02.0/i2c-3
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-4 -> ../../devices/pci0000:00/0000:00:02.0/i2c-4
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-5 -> ../../devices/pci0000:00/0000:00:02.0/i2c-5
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-6 -> ../../devices/pci0000:00/0000:00:02.0/i2c-6
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-7 -> ../../devices/pci0000:00/0000:00:02.0/i2c-7
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-8 -> ../../devices/pci0000:00/0000:00:15.1/i2c-8
lrwxrwxrwx root     root              2016-03-01 00:24 i2c-9 -> ../../devices/pci0000:00/0000:00:15.2/i2c-9
root@remix_cn_x86_64:/sys/class/i2c-adapter # cat i2c-*/name
i915 gmbus ssc
i915 gmbus vga
SMBus I801 adapter at 0400
i915 gmbus panel
i915 gmbus dpc
i915 gmbus dpb
i915 gmbus dpd
DPDDC-A
DPDDC-B
i2c-designware-pci
i2c-designware-pci

这样可以发现 Remix OS 内核下两个 I2C 适配器为 i2c-8 和 i2c-9,虽然 i2c-8 是触控板设备但是使用起来应该是没有影响的,I2C 总线驱动也是正确的,但适配器名称都是一样的 i2c-designware-pci

同时进一步确认之后发现 Remix OS 内核下虽然没有 Chrome OS 里直接使用的 cyapa 驱动,但其默认集成了新的 Linux kernel 里自带的 cyapatp 驱动。cyapa 是 Google 为 Chromebook 内核专门修改的 Cypress Gen3 系列触控板驱动,而查看源代码之后发现 cyapatp 驱动不但支持 Cypress Gen3 系列触控板,也支持新的 Gen5 系列触控板,这样按说 cyapatp 直接就是支持我的 Chromebook 触控板设备的。

比较郁闷的是我直接在 Remix OS 终端里运行 modprobe cyapatp 命令虽然能成功加载驱动,但系统中并没有注册任何新的输入设备。

Chromebook kernel 研究

没办法就只能先检出 Chrome OS 当前使用的 3.8.11 版本内核源代码研究下了,检出方法可以参考我之前写的「在Koding云平台上编译Chromebook kernel」这篇文章,Chrome OS kernel 分支可以在这里看到:

https://chromium.googlesource.com/chromiumos/third_party/kernel/

稍微研究后发现原来 Chrome OS kernel 里增加了一个 chromeos_laptop 平台相关的驱动,Chrome OS 系统启动时会加载这个驱动(实际上是直接编译到 Chrome OS kernel 中的),chromeos_laptop 中会自动尝试查找并实例化 Chromebook 上的 I2C/SMBus 设备,看看其中的部分代码:

#define CYAPA_TP_I2C_ADDR	0x67

const char *i2c_adapter_names[] = {
	"SMBus I801 adapter",
	"i915 gmbus vga",
	"i915 gmbus panel",
	"i2c-designware-pci-0",
	"i2c-designware-pci-1",
};

/* Keep this enum consistent with i2c_adapter_names */
enum i2c_adapter_type {
	I2C_ADAPTER_SMBUS = 0,
	I2C_ADAPTER_VGADDC,
	I2C_ADAPTER_PANEL,
	I2C_ADAPTER_I2C0,
	I2C_ADAPTER_I2C1,
};

static struct i2c_board_info cyapa_device = {
	I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
	.flags		= I2C_CLIENT_WAKE,
};

static struct chromeos_laptop wolf = {
	.i2c_peripherals = {
		/* Touchpad. */
		{ .add = setup_cyapa_tp, I2C_ADAPTER_I2C0 },
		/* Elan Touchpad option. */
		{ .add = setup_elantech_tp, I2C_ADAPTER_I2C0 },
	},
};

static struct i2c_client *add_i2c_device(const char *name,
						enum i2c_adapter_type type,
						struct i2c_board_info *info)
{
	const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
	return __add_probed_i2c_device(name,
				       find_i2c_adapter_num(type),
				       info,
				       addr_list);
}

static int setup_cyapa_tp(enum i2c_adapter_type type)
{
	if (tp)
		return 0;

	/* add cyapa touchpad */
	tp = add_i2c_device("trackpad", type, &cyapa_device);
	return (!tp) ? -EAGAIN : 0;
}

稍微分析下可以看到 chromeos_laptop 驱动是根据名称找到当前系统中的 I2C 适配器的,找到之后最后根据 I2C 地址调用 i2c_new_probed_device 函数实例化 I2C 设备,而这里 cyapa 触控板驱动使用的 I2C 适配器名称固定为 i2c-designware-pci-0

这样就有 Remix OS 下使用触控板的解决思路了,我们可以修改 i2c-designware-pci 驱动使其报上来的两个 I2C 适配器使用不同的名称,并加入 chromeos_laptop 驱动这样就可以正常使用新的 cyapatp 驱动;或者也可以不修改 i2c-designware-pci 而直接加入并修改 chromeos_laptop 中的触控板 I2C 适配器名称,为了后续 I2C 的区分我决定用第一种方法。

Remix OS kernel 修改

首先我们就要检出技德不久前开放的 Remix OS kernel 代码了,地址在这里:

https://github.com/jide-opensource/remixos-kernel/

值得一提的是 Remix OS 内核基本就是使用的默认 android-x86_64_defconfig 配置,先开始修改 i2c-designware-pcidrv.c 代码以支持使用不同的 I2C 适配器名称:

--- a/i2c-designware-pcidrv.c	2016-03-02 01:04:19.330843871 +0800
+++ b/i2c-designware-pcidrv.c	2016-03-01 00:18:04.502977140 +0800
@@ -48,7 +48,8 @@ enum dw_pci_ctl_id_t {
 	medfield_5,
 
 	baytrail,
-	haswell,
+	haswell_0,
+	haswell_1,
 };
 
 struct dw_scl_sda_cfg {
@@ -148,7 +149,15 @@ static struct dw_pci_controller dw_pci_c
 		.functionality = I2C_FUNC_10BIT_ADDR,
 		.scl_sda_cfg = &byt_config,
 	},
-	[haswell] = {
+	[haswell_0] = {
+		.bus_num = -1,
+		.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.functionality = I2C_FUNC_10BIT_ADDR,
+		.scl_sda_cfg = &hsw_config,
+	},
+	[haswell_1] = {
 		.bus_num = -1,
 		.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
 		.tx_fifo_depth = 32,
@@ -258,7 +267,8 @@ static int i2c_dw_pci_probe(struct pci_d
 	adap->dev.parent = &pdev->dev;
 	adap->nr = controller->bus_num;
 
-	snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
+	snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%ld",
+		(adap->nr < 0) ? id->driver_data - haswell_0 : adap->nr);
 
 	r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
 			adap->name, dev);
@@ -314,8 +324,8 @@ static const struct pci_device_id i2_des
 	{ PCI_VDEVICE(INTEL, 0x0F46), baytrail },
 	{ PCI_VDEVICE(INTEL, 0x0F47), baytrail },
 	/* Haswell */
-	{ PCI_VDEVICE(INTEL, 0x9c61), haswell },
-	{ PCI_VDEVICE(INTEL, 0x9c62), haswell },
+	{ PCI_VDEVICE(INTEL, 0x9c61), haswell_0 },
+	{ PCI_VDEVICE(INTEL, 0x9c62), haswell_1 },
 	/* Braswell / Cherrytrail */
 	{ PCI_VDEVICE(INTEL, 0x22C1), baytrail },
 	{ PCI_VDEVICE(INTEL, 0x22C2), baytrail },

然后将 Chrome OS 3.8.11 版本 kernel 中的 chromeos_laptop 平台相关驱动加到 Remix OS 4.0.9 版本 kernel 中,最后开始编译内核 bzImage 和对应的内核模块文件,实际上编译 bzImage 只是为了生成需要的 Module.symvers 符号文件,真正要使用的是新编译生成的 i2c-designware-pci.kochromeos_laptop.ko 文件。

提示

我是在 Chromebook Crouton 64 位 Ubuntu 14.04 环境中检出并修改 Remix OS kernel 进行编译的,实际 kernel 修改、加入新驱动修改 Makefile 和 Kconfig 等还有编译操作步骤什么的这里就不说明了,编译中间可能会有无线驱动报错,稍微修改下内核配置就可以通过了。

修改 Remix OS 系统文件

我编译好的两个内核模块文件下载地址(只适用于 Remix OS PC 版 alpha 4.0.9 内核):

https://zohead.com/downloads/cbtp-remixos-20160201alpha.zip

首先可以在 Chromebook 上将新的内核模块文件放到 Remix OS U 盘中,如果你使用的是按照我之前的「Chromebook使用ext4 U盘运行Remix OS」文章介绍的方法生成的 ext4 格式 U 盘,那么修改替换 Remix OS 系统文件还是非常简单的。

(trusty)zzm@localhost:~$ sudo cp i2c-designware-pci.ko /media/removable/Android-x86/android-2016-02-02/system/lib/modules/4.0.9-android-x86_64+/kernel/drivers/i2c/busses/
(trusty)zzm@localhost:~$ sudo cp chromeos_laptop.ko /media/removable/Android-x86/android-2016-02-02/system/lib/modules/4.0.9-android-x86_64+/kernel/drivers/platform/x86/

注意

上面的命令例子中假定 Remix OS U 盘已经自动被 Chrome OS 挂载到 /media/removable/Android-x86 目录了,android-2016-02-02 是 Remix OS 系统路径,实际的挂载和系统路径不完全相同请自行检查。

下面是使用 depmod 命令重新生成新的模块依赖关系等文件,这样 Remix OS 系统在启动的时候就会自动尝试加载 chromeos_laptop 驱动,接着自动加载 cyapatp 驱动成功之后就可以直接 Chromebook 触控板了。

sudo depmod -A -b /media/removable/Android-x86/android-2016-02-02/system 4.0.9-android-x86_64+

最后说下我简单测试之后 Remix OS 中 Chromebook 触控板的使用效果:

  • 基本的移动、点击等操作可以正常工作;
  • 看起来也是支持简单的多点触控的;
  • Remix OS 桌面图标的双击功能不起作用;
  • Chrome OS 下特色的两指上下滚动功能也可以正常使用(不过由于 Android 的自然滚动方式所以方向和 Chrome OS 下是相反的);
  • 某些 App 下面支持三指同时长按然后放开之后出现右键菜单;
  • Chrome OS 下特色的两指同时点击呼出右键菜单功能无效。

总之虽然触控版的使用不像 Chrome OS 下那样完美但基本还是能满足需求的,本文中有任何错误或疑问欢迎提出指正哦,祝玩的开心~~~。

修改Remix OS kernel支持Chromebook触控板》上的评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*