其实不是我的触摸屏,是bugzilla上有人在问,为什么他Surface 3上的触摸屏不工作。然后根据dmesg看到启动时的一堆可疑告警信息:
Sep 05 14:14:04 localhost kernel: ACPI Error: No handler for Region [GPOR] (ffff88013f4af3a8) [GeneralPurposeIo] (20150619/evregion-163) Sep 05 14:14:04 localhost kernel: ACPI Error: Region GeneralPurposeIo (ID=8) has no handler (20150619/exfldio-297) Sep 05 14:14:04 localhost kernel: ACPI Error: Method parse/execution failed [\_SB_.PCI0.SPI1.NTRG._STA] (Node ffff88013f4b15a0), AE_NOT_EXIST (20150619/psparse-536) (Full log at https://bugzilla.kernel.org/attachment.cgi?id=186711 ) Which in the DSDT corresponds to: Scope (_SB.PCI0.SPI1) { Device (NTRG) { Name (_HID, "MSHW0037") // _HID: Hardware ID Name (_UID, One) // _UID: Unique ID Name (_DEP, Package (0x04) // _DEP: Dependencies { GPO0, GPO1, GPO3, SPI1 }) The MSHW0037 device is the touchscreen, in Windows' device manager program.
发现大概意思是,linux没有给OperationRegion这种区域设置操作方法,导致访问这个OperationRegion区间时出错。
什么是OperationRegion? 就是一段物理地址区间,它用的比较多的场合,是一些IO空间,比如说该问题里的:
OperationRegion (GPOR, GeneralPurposeIo, Zero, One) Field (GPOR, ByteAcc, NoLock, Preserve) { Connection ( GpioIo (Shared, PullDefault, 0x0000, 0x0000, IoRestrictionNone, "\\_SB.GPO3", 0x00, ResourceConsumer, , ) { // Pin list 0x0051 } ), SDCD, 1, Connection ( GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly, "\\_SB.GPO3", 0x00, ResourceConsumer, , ) { // Pin list 0x003D } ), PDN1, 1 }
然后,我们还想访问这个区间里的某些字节,比如SDCD开始的一个bit,或者PDN1开始的一个bit。
或者说我们直接想访问gpio controller的pinlist 0x51,或者pinlist 0x3D,都需要操作这个区间,而ASL代码里,
访问这些区间的代码片段,一般就是Store(SDCD,0xaaa)这种。那么对于Linux来说,需要把Store的这句话解析
成访问GeneralPurposeIo空间的访问,这个针对具体空间的操作,就需要相关的驱动来实现,比如这个例子里,
就需要实现对GeneralPurposeIo读写的回调,也就是对GPIO controller的读写。这就是address space handler
的来历。对cherryview平台来说,回调是pinctrl driver在probe到INT33FF这个gpio controller后,在
acpi_gpiochip_request_regions函数内,通过acpi_install_address_space_handler安装上了gpio区间的操作
实现函数。
在开头提出的故障现象中,可以看出,有设备尝试访问gpio区间却发现gpio区间函数没有安装,于是失败了。失败的结果
是,设备MSHW0037的gpio驱动初始化不正常,导致触摸屏无法工作。再详细一点说,就是MSHW0037设备在
访问_STA时,尝试通过读取GPO0的数据,而这个时候,GPO0的驱动,也就是cherryview的驱动还没有加载,从而
执行_STA返回错误(注意,不是_STA的值返回错误,而是执行_STA这个动作返回错误):
Method (_STA, 0, NotSerialized) // _STA: Status { If ((^^^^GPO0.HELD == One)) { Return (0x0F) } Else { Return (Zero) } }执行失败的结果是,MSHW0037设备对应的acpi_device不会被创建,于是SPI slave驱动加载时,将不会成功,从而触摸屏不工作。
->acpi_bus_get_status_handle->
acpi_evaluate_integer(handle, "_STA", NULL, sta);
返回AE_NOT_EXIST,从而acpi_bus_type_and_status返回-ENODEV,
从而acpi_bus_check_add认为已经执行完毕,就返回了,不会继续执行acpi_add_single_object来
为设备创建acpi_device。
那么问题出在哪里呢,是_STA设计不周全,应该考虑到启动过程中,gpio可能还不可访问。要改_STA比较麻烦,
毕竟MS是不太愿意改bios的,于是在linux里做些小动作,我们可以这样,就算_STA返回不可执行,我们
也给设备状态设置为0,表示当前不可用,但执行这个_STA还是返回成功,这样让后续流程继续执行
acpi_device的创建。从而让SPI驱动能够被加载成功。