更新于 

进阶篇-用热补丁驱动你的触摸板

版权©️声明 : 本文章神楽小白(GZ小白)的部落阁


前言

当你的触摸板无法正常工作时,或者一点也不工作时,那你可能就需要修改ACPI来修补修补你的触摸板来,使其能够正常工作。
毕竟一台笔记本电脑,用不了触摸板实在是太难受了。(如果你有钱买妙控板,那就另当别论了)

确定设备路径

1.进入Windows系统,打开设备管理器,找到人体输入学设备,确认自己是不是I2C触摸板(有可能是I2C USB),如果找不到I2C HID设备,下面的鼠标又没有PS2的时候,把每个都打开看看有没有Bios Device Name 里有 I2C

2.然后右键查看属性,在详细信息里找到触摸板的位置路径

像这里的路径就是:
_SB.PCI0.I2C0.TPD0
我们把它记下来吧,之后会用到。

确定APIC PIn

继续在Windows下,设备管理器中确认一下你的APIC Pin,到如图所示位置:

在这个地方我们也能找到需要的APIC Pin

声明:如果这里括号里的值大于等于 1024(10进制),直接去做热补丁,删掉所有有关操作系统的判断就好了

你也可以在Mac下查看APIC Pin

到Mac系统下,使用IORegistryExplorer查看APIC Pin
在右上角搜索自己的触摸板名称,比如根据我们之前照出来的路径,触摸板设备的名称就为TPD0

那么我们为什么需要知道APIC Pin呢?因为APIC Pin可以帮助你判断你的触摸板的工作状态,如果你的Pin小于2F那么你的触摸板在macOS就是APIC中断模式的,你可以理解为“半免躯模式”了,几乎不需要做什么修改就能够比较好的驱动。当然,这是极少数的情况。

大部分人应该都是大于2F的,因此触摸板会是GPIO中断模式,但因为在macOS下绝大部分人GPIO中断模式无法直接驱动,才需要制作热补丁来使其正常工作。

归纳一下就是:
Pin < 2F 或者 无IOInterruptSpecifiers,为APIC
Pin > 2F 需要制作热补丁使触摸板在GPIO模式下正常工作

APIC中断,GPIO中断与轮询

这里我们稍微了解一下触摸板工作的三个模式:

  1. APIC中断:上文有提到,也就是最好的一个工作模式,当然只有极少数人有这个运气是APIC中断
  2. GPIO中断:Windows系统下用的也是这个模式,是仅次于APIC中断的,比较高效,也是我们首先推荐的模式。触摸板热补丁也是主要针对GPIO中断比较多的修改
  3. 轮询:最低效的一个模式,但相比GPIO中断,这个模式的适用范围更广,大部分机子都能适用这个,虽然有时候可能有些问题,如,指针漂移或者不灵敏等,但却更容易驱动GPIO中断无法使用的情况下,我们就选择使用轮询模式。

总结归纳:
效率:APIC中断 > GPIO中断 > 轮询
驱动难易成度:GPIO中断 > 轮询 ,这里APIC中断不作讨论,看你运气。

触摸板热补丁制作

在这个板块,我会教你如何去做触摸板热补丁(Hotpatch),包括GPIO中断轮询两个模式的制作教程。我也会给出一个案例用于讲解,此案例请不要拿去直接用(没有人会那么傻吧)。

首先我们用Maciasl打开DSDT,并新建一个文件。然后我们将DSDT的DefinitionBlock部分复制到新建的文件中,并将其中的DSDT的字符串改为SSDT,如图:

然后我们根据之前确定的触摸板设备路径(_SB.PCI0.I2C0.TPD0)找到我们需要修改的设备(Device)。很简单,我们按Option + F在搜索框中输入自己触摸板的名称,我们这里的是TPD0,然后回车搜索,找到位于**_SB.PCI0.I2C0下的TPD0**设备。如图:

然后我们在新建的SSDT中,先添加路径Scope(_SB.PCI0.I2C0),然后将整个TPD0设备复制进去(一定要注意对应括号,不要复制错了),如图:

然后我们将TPD0进行改名,改成TPXX或者其他的什么都可以,只要不与DSDT中其他的设备名称相同有冲突。我们在新建的SSDT中查找TPD0,并将所有找到的TPD0,都改成TPXX(或者自己改的名称)。

改名前:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
DefinitionBlock ("", "SSDT", 2, "DELL  ", "CBX3   ", 0x01072009)
{
Scope (_SB.PCI0.I2C0)
{
Device (TPD0)
{
Name (HID2, Zero)
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "NULL",
0x00, ResourceConsumer, _Y38, Exclusive,
)
})
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0000
}
})
Name (SBFI, ResourceTemplate ()
{
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, _Y39)
{
0x00000000,
}
})
CreateWordField (SBFB, \_SB.PCI0.I2C0.TPD0._Y38._ADR, BADR) // _ADR: Address
CreateDWordField (SBFB, \_SB.PCI0.I2C0.TPD0._Y38._SPE, SPED) // _SPE: Speed
CreateWordField (SBFG, 0x17, INT1)
CreateDWordField (SBFI, \_SB.PCI0.I2C0.TPD0._Y39._INT, INT2) // _INT: Interrupts
Method (GTID, 1, Serialized)
{
If (Arg0)
{
Switch (CBID)
{
Case (0x0896)
{
Return ("DELL0896")
}
Case (0x0895)
{
Return ("DELL0895")
}
Case (0x0894)
{
Return ("DELL0894")
}
Case (0x08A5)
{
Return ("DELL08A5")
}
Case (0x08A6)
{
Return ("DELL08A6")
}
Case (0x089C)
{
Return ("DELL089C")
}
Case (0x089D)
{
Return ("DELL089D")
}
Case (0x089E)
{
Return ("DELL089E")
}
Case (0x089F)
{
Return ("DELL089F")
}
Case (0x08A7)
{
Return ("DELL08A7")
}
Case (0x08A8)
{
Return ("DELL08A8")
}
Case (0x08A9)
{
Return ("DELL08A9")
}
Case (0x08BC)
{
Return ("DELL08BC")
}
Case (0x08BD)
{
Return ("DELL08BD")
}
Case (0x08C0)
{
Return ("DELL08C0")
}
Case (0x0949)
{
Return ("DELL0949")
}
Default
{
Return ("DELL0949")
}

}
}
Else
{
Return (0x20)
}
}

Method (_INI, 0, Serialized) // _INI: Initialize
{
If ((OSYS < 0x07DC))
{
SRXO (GPDI, One)
}

INT1 = GNUM (GPDI)
INT2 = INUM (GPDI)
If ((TPDM == Zero))
{
SHPO (GPDI, One)
}

If ((TPDT == One))
{
_HID = "SYNA2393"
HID2 = 0x20
Return (Zero)
}

If ((TPDT == 0x02))
{
_HID = "06CB2846"
HID2 = 0x20
Return (Zero)
}

If ((TPDT == 0x06))
{
_HID = "ALPS0000"
HID2 = 0x20
BADR = 0x2C
Return (Zero)
}

If ((TPDT == 0x05))
{
_HID = GTID (One)
HID2 = TPDH /* \TPDH */
Switch (CBID)
{
Case (0x08BC)
{
BADR = 0x15
}
Case (0x08BD)
{
BADR = TPDB /* \TPDB */
}
Case (0x08C0)
{
BADR = TPDB /* \TPDB */
}
Default
{
BADR = TPDB /* \TPDB */
}

}

If ((TPDS == Zero))
{
SPED = 0x000186A0
}

If ((TPDS == One))
{
SPED = 0x00061A80
}

If ((TPDS == 0x02))
{
SPED = 0x000F4240
}

Return (Zero)
}
}

Name (_HID, "XXXX0000") // _HID: Hardware ID
Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID: Compatible ID
Name (_S0W, 0x03) // _S0W: S0 Device Wake State
Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method
{
If ((Arg0 == HIDG))
{
Return (HIDD (Arg0, Arg1, Arg2, Arg3, HID2))
}

If ((Arg0 == TP7G))
{
Return (TP7D (Arg0, Arg1, Arg2, Arg3, SBFB, SBFG))
}

Return (Buffer (One)
{
0x00 // .
})
}

Method (_STA, 0, NotSerialized) // _STA: Status
{
If (((TPDT != Zero) && (I2CN & One)))
{
Return (0x0F)
}

Return (Zero)
}

Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
If ((OSYS < 0x07DC))
{
Return (SBFI) /* \_SB_.PCI0.I2C0.TPD0.SBFI */
}

If ((TPDM == Zero))
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
}

Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFI))
}
}
}
}

改名后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DefinitionBlock ("", "SSDT", 2, "DELL  ", "CBX3   ", 0x01072009)
{
Scope (_SB.PCI0.I2C0)
{
Device (TPXX) //这里将TPD0改为了TPXX
{
······

CreateWordField (SBFB, \_SB.PCI0.I2C0.TPXX._Y38._ADR, BADR) // 这里将TPD0改为了TPXX
CreateDWordField (SBFB, \_SB.PCI0.I2C0.TPXX._Y38._SPE, SPED) // 这里将TPD0改为了TPXX
CreateWordField (SBFG, 0x17, INT1)
CreateDWordField (SBFI, \_SB.PCI0.I2C0.TPXX._Y39._INT, INT2) // 这里将TPD0改为了TPXX

······
//没有改动的地方就没有列出来了
}
}
}

其实我们不难发现,其实也就DeviceCreateWordField那里需要改。

然后我们注意到Method (_CRS, 0, NotSerialized),我们需要对他进行修改,我们看到这里有许多判断语句,其实我们只需要一句Return (ConcatenateResTemplate (XXXX, XXXX)),其它都可以删除掉。当然,如果你的**_CRS里面还有些赋值语句或者其他的一些语句**,不只有If判断语句的话,那么就不要乱删了,以防出现问题。

修正 TPXX 内容:

  • 所有 TPD0 替换为 TPXX

  • 补丁中 _STA 部分替换为:

1
2
3
4
5
6
7
8
9
10
11
Method (_STA, 0, NotSerialized)
{
If (_OSI ("Darwin"))
{
Return (0x0F)
}
Else
{
Return (Zero)
}
}
  • 查找 SDS1 (禁止 TPD0 时用到的变量),将原 If (SDS1...) 修改为 If (one)

  • 查找 OSYS,删除(注释掉)以下内容:

    1
    2
    3
    4
    //If (LLess (OSYS, 0x07DC))
    //{
    // SRXO (GPDI, One)
    //}

    注:OSYS 小于 0x07DC 时,I2C 设备不工作(0x07DC代表 Windows8)。

GPIO中断实现

这里建议您先实现了轮询模式,再来移植中断

实现GPIO中断,我们需要做如下修改。

首先,我们先来讲解一些触摸板的相关内容。我们可以在触摸板设备中找到如下,GpioInt(GPIO中断)、Interrupt(APIC中断) 。

先看SBFI,这个用来实现APIC中断的,当这个值无效的时候(也就是APIC Pin大于2F的时候),走的是轮询

1
2
3
4
5
6
7
8
9
······
Name (SBFI, ResourceTemplate ()
{
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, _Y39)
{
0x00000000,
}
})
······

我们再来看SBFB,这个轮询中断都可以调用。当然也有的**_CSR里面不返回这个,而是返回了>I2CM,其实两者的用处是一样的,但I2CM**里面包括了更多的东西。
我们可以这样理解吧,I2CM>=SBFB

1
2
3
4
5
6
7
8
9
······
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "NULL",
0x00, ResourceConsumer, _Y38, Exclusive,
)
})
······

这里有一个重点,那就是SBFG,其实我们看的不是SBFG这个名字,而是里面的GpioInt,这是中断所需要的。

1
2
3
4
5
6
7
8
9
10
11
······
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0000
}
})
······

讲解完了这些,我们就正式开始动手进行修改吧

  1. 补全缺少的内容。如果你发现你没有GpioInt,那么你就复制下面那段代码到自己建立的触摸板设备(TPXX)中。
1
2
3
4
5
6
7
8
9
10
11
······
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0000
}
})
······

大部分人都是会有GpioInt的,所以一般不需要这个步骤,没有的人不仅需要补上,而且需要计算GPIO Pin
所以说,有这个GpioInt的,是不需要去算GPIO Pin的,它自己会自动注入的,当然你想去算一个Gpio Pin也没事,不影响。

  1. 计算GPIO Pin(可选择,见上面第1步的说明)。计算这个Pin的时候,我们需要用到刚开始我们记录的APIC Pin(我之前记录的ACPI Pin0x33)。我们需要将APIC Pin转换为10进制,0x33转换过来就是51,然后我们把APICPIN = 51代入以下公式
    
    这里我们要根据不同的处理器选择,

Skylake

1
2
3
4
5
6
If APICPIN > 47 And APICPIN <= 79 Then     
GPIOPIN = APICPIN - 24
GPIOPIN2 = APICPIN + 72
ElseIf APICPIN > 79 And APICPIN <= 119 Then
GPIOPIN = APICPIN - 24
End If

CoffeeLake-H

1
2
3
4
5
6
7
8
9
10
11
12
If APICPIN > 47 And APICPIN <= 71 Then   
GPIOPIN = APICPIN - 16
GPIOPIN2 = APICPIN + 240
If APICPIN > 47 And APICPIN <= 59 Then GPIOPIN3 = APICPIN + 304
ElseIf APICPIN > 71 And APICPIN <= 95 Then
GPIOPIN = APICPIN - 8
GPIOPIN3 = APICPIN + 152
GPIOPIN2 = APICPIN + 120
ElseIf APICPIN > 95 And APICPIN <= 119 Then
GPIOPIN = APICPIN
If APICPIN > 108 And APICPIN <= 115 Then GPIOPIN2 = APICPIN + 20
End If

CoffeeLake-LFWhiskylake

1
2
3
4
5
6
7
8
9
10
If APICPIN > 47 And APICPIN <= 71 Then      
GPIOPIN = APICPIN - 16
GPIOPIN2 = APICPIN + 80
ElseIf APICPIN > 71 And APICPIN <= 95 Then
GPIOPIN2 = APICPIN + 184
GPIOPIN = APICPIN + 88
ElseIf APICPIN > 95 And APICPIN <= 119 Then
GPIOPIN = APICPIN
If APICPIN > 108 And APICPIN <= 115 Then GPIOPIN2 = APICPIN - 44
End If

最后,我们会得出GPIOPIN的10进制,我们将其再转为16进制即可。

不过在某些极端状况下,你找到的值都不起作用的话。那么此时,你只能去尝试些比较常见的数值了,如0x17、0x1b、0x340x55。(仅限 SunrisePoint)

计算好了就把GPIO Pin填入到SBFG中,如下:

1
2
3
4
5
6
7
8
9
Name (SBFG, ResourceTemplate ()    
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0017 // 这一行就是你需要填写的位置!
}
})

接下来就是**_CSR中返回语句的修改了,之前有提到我们_CSR中,我们主要修改的就是其中的Return返回语句**,那么GPIO中断呢,需要返回的是SBFB(或是I2CM等)和SBFG。下面是原来的**_CSR**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
{
If ((OSYS < 0x07DC))
{
Return (SBFI) /* \_SB_.PCI0.I2C0.TPD0.SBFI */
}

If ((TPDM == Zero))
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
}

Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFI))
}

这里,我们可以看到上面两个判断语句,我们都可以删除,删到最后就留一条Return (ConcatenateResTemplate (XXXX, XXXX))就行了。如果你的CSR里面还有其他的赋值语句等等或者你搞不懂哪些可以删除,那么你就不要乱删除了,以防删错了,直接修改所有Return语句就行了。修改结果如下:

1
2
3
4
5
Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
//Return (ConcatenateResTemplate (SBFB, SBFG))
}

这里我们返回了I2CMSBFG确定了GPIO中断模式。

到这里GPIO中断模式的修改就完成了!

轮询模式实现

这个模式就很简单了,你不需要像GPIO中断模式那样添加GPIO Pin,我们直接修改CSR中的返回语句,最终返回为SBFBSBFI就行,修改结果如下:

1
2
3
4
5
Method (_CRS, 0, NotSerialized)  // _CRS: Current Resource Settings
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFI))
//Return (ConcatenateResTemplate (SBFB, SBFI))
}

修改好了GPIO中断或者轮询到这里你的补丁本体就基本完成了!

禁用原触摸板设备

这里我们有两个方法来禁用触摸板设备,第一个方法为预置变量法,第二个方法为**_STA的修改法**,其中,第二个方法是通用的,第一个方法不一定对所有人适用!

预置变量法禁用原设备

目的:禁用原设备,防着你仿冒的设备与原设备发生冲突

这里需要我们观察原设备里的**_STA**,如下:

1
2
3
4
5
6
7
8
9
Method (_STA, 0, NotSerialized)  // _STA: Status
{
If (((TPDT != Zero) && (I2CN & One)))
{
Return (0x0F)
}

Return (Zero)
}

我们看这个If判断语句,意思是如果TPDT不等于Zero,那么则返回0x0F,也就是启用设备。那我们不就只需要让TPDT等于0不就行了吗?那样的话,它就不会执行If语句下的内容了。接下来我们在SSDT中新建一个Scope作用域,路径为根目录并把TPDT赋值为Zero,添加If判断语句确定其只在macOS下生效,如下所示:

1
2
3
4
5
6
7
Scope (\)
{
If (_OSI ("Darwin"))
{
TPDT = Zero
}
}

_STA修改法禁用原设备

这个需要我们新建一个SSDT,然后我们先写入根作用域(把DSDT中的DefinitionBlock复制到SSDT中就行,然后将里面的DSDT改为SSDT),如下:

1
2
3
DefinitionBlock ("", "SSDT", 2, "DELL", "CBX3", 0x01072009)
{
}

然后我们再添加Scope作用域,路径就是**原设备(TPD0)**的路径,如下:

1
2
3
4
5
6
DefinitionBlock ("", "SSDT", 2, "DELL", "CBX3", 0x01072009)
{
Scope (_SB.PCI0.I2C0.TPD0)
{
}
}

然后把我下面给出的**_STA复制到这个Scope作用域**中

1
2
3
4
5
6
7
8
9
10
11
Method (_STA, 0, NotSerialized)  // _STA: Status
{
If (_OSI ("Darwin"))
{
Return (Zero)
}
Else
{
Return (XSTA())
}
}

这个**_STA的意思差不多就是,在macOS下返回Zero**,也就是设备禁用状态,在其他系统下,返回XSTA

接下来补充引用声明就行了,需要补充的引用声明有两个,一个是TPD0这个设备的,还有一个就是XSTA的,写引用声明可以参考我论坛里的教程:

http://bbs.pcbeta.com/viewthread-1866928-1-1.html

也可以看本教程最后一块内容:排错-补充引用声明

最后补丁结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DefinitionBlock ("", "SSDT", 2, "DELL", "CBX3", 0x01072009)
{
External (_SB.PCI0.I2C0.TPD0,DeviceObj)
External (_SB.PCI0.I2C0.TPD0.XSTA,MethodObj)

Scope (_SB.PCI0.I2C0.TPD0)
{
Method (_STA, 0, NotSerialized) // _STA: Status
{
If (_OSI ("Darwin"))
{
Return (Zero)
}
Else
{
Return (XSTA())
}
}
}
}

当然使用这个方法不仅需要补丁,还需要添加重命名,防止**_STA**发生冲突。

我们需要用到Hex Friend这个软件,我们使用Hex Friend打开DSDT,按Option + F(你的可能不同)打开搜索框,在搜索框左侧,将Hex改为Text,然后在Find里搜索你的触摸板设备,我这里是TPD0,左边对于二进制的数字,右边对应字符,在二进制中会用高亮标出你的触摸板设备代表的二进制,然后观察你的这串高亮的数字之后是不是跟着08,是的话,你就找到了自己的触摸板设备,接着需要在右边找到你的触摸板设备,在沿着你的触摸板设备,找到下面的**_STA并把它选中,向右拉长,同时左边的高亮数字也在拉长,大致拉两段多一点就差不多了,复制你左边的高亮数字**,粘贴在Find里搜索,如果除了你现在这段没有搜到其他的,那么就可以了,否则继续拉长再搜索,直到确定只有你这段没有重复!

然后我们打开configACPI部分中,添加重命名补丁:

1
2
3
4
5
Comment:I2C _STA to XSTA in TPD0

Find:5F535441 00A01390 929354 //这是我给出的DSDT中的,你们别抄

Replace:58535441 00A01390 929354 //在Replace中将开头的5F改成了58,意思可就是将_STA中的下划线改成了X,其他不变

这个拉长的方法是OCCLOVER通用的,下面再介绍CLOVER可以用的另一种方法。

CLOVER中,重命名有一个“桥”可以作为圈定重命名的范围,这个“桥”也就是TgtBridge。如何使用这个TgtBridge呢?很简单,首先我们先将**_STA这四个字符转换为16进制**,利用Hackintool就行,打开Hackintool的计算器,在字符串转换中,将**_STA填入到ASCII中,复制转换出来的16进制**,以此类推,再得到XSTA16进制,如下:

1
2
3
4
5
6
7
Comment:I2C _STA to XSTA in TPD0

Find:5F535441 //_STA

Replace:58535441 //XSTA

TgtBridge:

那么TgtBridge怎么填呢?我们修改的**_STA是不是在TPD0下,那么就把_STA的范围也控制在TPD0就行了,我们将TPD0以上面的方法,也转换为16进制就行了,填入到TgtBridge**中去。最后结果如下:

1
2
3
4
5
6
7
Comment:I2C _STA to XSTA in TPD0

Find:5F535441 //_STA

Replace:58535441 //XSTA

TgtBridge:54504430 //TPD0

排错-补充引用声明

正确制作完触摸板补丁后,我们会有一些错误,而处理这些错误,需要我们补充引用声明。

见我写的这篇教程中:http://bbs.pcbeta.com/viewthread-1866928-1-1.html

比如我们点击编译GNUM报错了,那么我们到DSDT中去搜素GNUM,找到其被定义的位置所在,写成引用声明External即可。

最终完成的补丁如下:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
DefinitionBlock ("", "SSDT", 2, "DELL  ", "TPXX   ", 0x01072009)
{
External (_SB_.GNUM, MethodObj) // 1 Arguments
External (_SB_.INUM, MethodObj) // 1 Arguments
External (_SB_.PCI0.HIDD, MethodObj) // 5 Arguments
External (_SB_.PCI0.HIDG, IntObj)
External (_SB_.PCI0.I2C0, DeviceObj)
External (_SB_.PCI0.I2C0.I2CX, IntObj)
External (_SB_.PCI0.I2CM, MethodObj) // 3 Arguments
External (_SB_.PCI0.TP7D, MethodObj) // 6 Arguments
External (_SB_.PCI0.TP7G, IntObj)
External (_SB_.SHPO, MethodObj) // 2 Arguments
External (CBID, FieldUnitObj)
External (GPDI, FieldUnitObj)
External (TPDB, FieldUnitObj)
External (TPDH, FieldUnitObj)
External (TPDM, FieldUnitObj)
External (TPDS, FieldUnitObj)
External (TPDT, FieldUnitObj)

Scope (\)
{
If (_OSI ("Darwin"))
{
TPDT = Zero
}
}

Scope (_SB.PCI0.I2C0)
{
Device (TPXX)
{
Name (HID2, Zero)
Name (SBFB, ResourceTemplate ()
{
I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "NULL",
0x00, ResourceConsumer, _Y00, Exclusive,
)
})
Name (SBFG, ResourceTemplate ()
{
GpioInt (Level, ActiveLow, ExclusiveAndWake, PullDefault, 0x0000,
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0000
}
})
Name (SBFI, ResourceTemplate ()
{
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, _Y01)
{
0x00000000,
}
})
CreateWordField (SBFB, \_SB.PCI0.I2C0.TPXX._Y00._ADR, BADR) // _ADR: Address
CreateDWordField (SBFB, \_SB.PCI0.I2C0.TPXX._Y00._SPE, SPED) // _SPE: Speed
CreateWordField (SBFG, 0x17, INT1)
CreateDWordField (SBFI, \_SB.PCI0.I2C0.TPXX._Y01._INT, INT2) // _INT: Interrupts
Method (GTID, 1, Serialized)
{
If (Arg0)
{
Switch (CBID)
{
Case (0x0896)
{
Return ("DELL0896")
}
Case (0x0895)
{
Return ("DELL0895")
}
Case (0x0894)
{
Return ("DELL0894")
}
Case (0x08A5)
{
Return ("DELL08A5")
}
Case (0x08A6)
{
Return ("DELL08A6")
}
Case (0x089C)
{
Return ("DELL089C")
}
Case (0x089D)
{
Return ("DELL089D")
}
Case (0x089E)
{
Return ("DELL089E")
}
Case (0x089F)
{
Return ("DELL089F")
}
Case (0x08A7)
{
Return ("DELL08A7")
}
Case (0x08A8)
{
Return ("DELL08A8")
}
Case (0x08A9)
{
Return ("DELL08A9")
}
Case (0x08BC)
{
Return ("DELL08BC")
}
Case (0x08BD)
{
Return ("DELL08BD")
}
Case (0x08C0)
{
Return ("DELL08C0")
}
Case (0x0949)
{
Return ("DELL0949")
}
Default
{
Return ("DELL0949")
}

}
}
Else
{
Return (0x20)
}
}

Method (_INI, 0, Serialized) // _INI: Initialize
{
INT1 = GNUM (GPDI)
INT2 = INUM (GPDI)
If ((TPDM == Zero))
{
SHPO (GPDI, One)
}

If (One)
{
_HID = "SYNA2393"
HID2 = 0x20
Return (Zero)
}

If (One)
{
_HID = "06CB2846"
HID2 = 0x20
Return (Zero)
}

If (One)
{
_HID = "ALPS0000"
HID2 = 0x20
BADR = 0x2C
Return (Zero)
}

If (One)
{
_HID = GTID (One)
HID2 = TPDH /* External reference */
Switch (CBID)
{
Case (0x08BC)
{
BADR = 0x15
}
Case (0x08BD)
{
BADR = TPDB /* External reference */
}
Case (0x08C0)
{
BADR = TPDB /* External reference */
}
Default
{
BADR = TPDB /* External reference */
}

}

If ((TPDS == Zero))
{
SPED = 0x000186A0
}

If ((TPDS == One))
{
SPED = 0x00061A80
}

If ((TPDS == 0x02))
{
SPED = 0x000F4240
}

Return (Zero)
}
}

Name (_HID, "XXXX0000") // _HID: Hardware ID
Name (_CID, "PNP0C50" /* HID Protocol Device (I2C bus) */) // _CID: Compatible ID
Name (_S0W, 0x03) // _S0W: S0 Device Wake State
Method (_DSM, 4, Serialized) // _DSM: Device-Specific Method
{
If ((Arg0 == HIDG))
{
Return (HIDD (Arg0, Arg1, Arg2, Arg3, HID2))
}

If ((Arg0 == TP7G))
{
Return (TP7D (Arg0, Arg1, Arg2, Arg3, SBFB, SBFG))
}

Return (Buffer (One)
{
0x00 // .
})
}

Method (_STA, 0, NotSerialized) // _STA: Status
{
If (_OSI ("Darwin"))
{
Return (0x0F)
}
Else
{
Return (Zero)
}
}

Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Return (ConcatenateResTemplate (I2CM (I2CX, BADR, SPED), SBFG))
}
}
}
}

这里也给出样本的DSDTSSDT

链接: https://pan.baidu.com/s/1eGHOyGc6AleEr1aHZxWYaA

提取密码:s9t2

鸣谢

特别感谢以下几位大佬的支持:

@penghuibingzhou

本教程建立在penghuibingzhou的教程上,进行了修改,本家如下:

https://www.penghubingzhou.cn/2019/01/06/VoodooI2C%20DSDT%20Edit/

@Bat.bat

感谢Bat大佬的鼎力支持!

本教程由Bat进行指导和修改!在Bat大佬的大力帮助下,教程进行了修改和完善,纠正了许多错误的地方!

加入博主的Hackintosh交流群:679838716