AppleHDA声卡修补

1. 计算编解码器命令和路径

1.1 提取codec

首先,我们需要从linux获取音频编码器的转储。因此,进入USB/CD(或)完全安装的任何Linux发行版。并在终端中输入以下命令以在桌面上以文本格式获取转储。

1
2
3
4
5
cat /proc/asound/card0/codec#0 > ~/Desktop/codec_dump.txt
# 或者
cat /proc/asound/card0/codec#1 > ~/Desktop/codec_dump.txt
# 或者
cat /proc/asound/card0/codec#2 > ~/Desktop/codec_dump.txt

1.2 整理有效节点

我们需要从编码器转储以下细节,以下是来自编解码器转储的示例ALC269的上述详细信息:

  1. Codec :Realtek ALC269VC
  2. Address : 0
  3. Vendor ID : Hex: 0x10ec0269 [Decimal: 283902569]
  4. Pin Complex Nodes with Control Name
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
Node 0x12 [Pin Complex] wcaps 0x40040b: Stereo Amp-In
Control: name="Internal Mic Boost Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Pincap 0x00000020: IN
Pin Default 0x90a60140: [Fixed] Mic at Int N/A
Conn = Digital, Color = Unknown
DefAssociation = 0x4, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x20: IN
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0

Node 0x14 [Pin Complex] wcaps 0x40018d: Stereo Amp-Out
Control: name="Speaker Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x00 0x00]
Pincap 0x00010014: OUT EAPD Detect
EAPD 0x2: EAPD
Pin Default 0x90170110: [Fixed] Speaker at Int ATAPI
Conn = ATAPI, Color = Unknown
DefAssociation = 0x1, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x40: OUT
Unsolicited: tag=00, enabled=0
Connection: 2
0x0c* 0x0d

Node 0x15 [Pin Complex] wcaps 0x40058d: Stereo Amp-Out
Control: name="Headphone Playback Switch", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x0001001c: OUT HP EAPD Detect
EAPD 0x2: EAPD
Pin Default 0x03211020: [Jack] HP Out at Ext Left
Conn = 1/8, Color = Black
DefAssociation = 0x2, Sequence = 0x0
Pin-ctls: 0xc0: OUT HP
Unsolicited: tag=01, enabled=1
Power states: D0 D1 D2 D3 EPSS
Power: setting=D3, actual=D3
Connection: 2
0x0c 0x0d*

Node 0x18 [Pin Complex] wcaps 0x40018f: Stereo Amp-In Amp-Out
Control: name="Mic Boost Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x2f, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x00001734: IN OUT Detect
Vref caps: HIZ 50 GRD 80
Pin Default 0x04a11820: [Jack] Mic at Ext Right
Conn = 1/8, Color = Black
DefAssociation = 0x2, Sequence = 0x0
Pin-ctls: 0x24: IN VREF_80
Unsolicited: tag=08, enabled=1
Connection: 1
0x0d

Node 0x19 [Pin Complex] wcaps 0x40058f: Stereo Amp-In Amp-Out
Control: name="Dock Mic Boost Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Amp-In caps: ofs=0x00, nsteps=0x03, stepsize=0x27, mute=0
Amp-In vals: [0x00 0x00]
Amp-Out caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-Out vals: [0x80 0x80]
Pincap 0x00003734: IN OUT Detect
Vref caps: HIZ 50 GRD 80 100
Pin Default 0x411111f0: [N/A] Speaker at Ext Rear
Conn = 1/8, Color = Black
DefAssociation = 0xf, Sequence = 0x0
Misc = NO_PRESENCE
Pin-ctls: 0x24: IN VREF_80
Unsolicited: tag=04, enabled=1
Power states: D0 D1 D2 D3 EPSS
Power: setting=D3, actual=D3
Connection: 2
0x0c* 0x0d
  1. Audio Mixer/Selector Nodes
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
Node 0x0b [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x17, nsteps=0x1f, stepsize=0x05, mute=1
Amp-In vals: [0x97 0x97] [0x97 0x97] [0x97 0x97] [0x97 0x97] [0x97 0x97]
Connection: 5
0x18 0x19 0x1a 0x1b 0x1d

Node 0x0c [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x00 0x00]
Connection: 2
0x02 0x0b

Node 0x0d [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00 0x00] [0x00 0x00]
Connection: 2
0x03 0x0b

Node 0x0f [Audio Mixer] wcaps 0x20010a: Mono Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x00] [0x00]
Connection: 2
0x02 0x0b

Node 0x22 [Audio Selector] wcaps 0x30010b: Stereo Amp-In
Amp-In caps: N/A
Amp-In vals: [0x00 0x00] [0x00 0x00] [0x00 0x00] [0x00 0x00] [0x00 0x00] [0x00 0x00] [0x00 0x00]
Connection: 7
0x18* 0x19 0x1a 0x1b 0x1d 0x0b 0x12

Node 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In
Amp-In caps: ofs=0x00, nsteps=0x00, stepsize=0x00, mute=1
Amp-In vals: [0x80 0x80] [0x00 0x00] [0x80 0x80] [0x80 0x80] [0x80 0x80] [0x80 0x80]
Connection: 6
0x18 0x19 0x1a 0x1b 0x1d 0x0b
  1. Audio Output Nodes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Node 0x02 [Audio Output] wcaps 0x1d: Stereo Amp-Out
Control: name="Speaker Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Device: name="ALC269VB Analog", type="Audio", device=0
Amp-Out caps: ofs=0x57, nsteps=0x57, stepsize=0x02, mute=0
Amp-Out vals: [0x41 0x41]
Converter: stream=5, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Node 0x03 [Audio Output] wcaps 0x1d: Stereo Amp-Out
Control: name="Headphone Playback Volume", index=0, device=0
ControlAmp: chs=3, dir=Out, idx=0, ofs=0
Amp-Out caps: ofs=0x57, nsteps=0x57, stepsize=0x02, mute=0
Amp-Out vals: [0x41 0x41]
Converter: stream=5, channel=0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
  1. Audio Input Nodes
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
Node 0x08 [Audio Input] wcaps 0x10051b: Stereo Amp-In
Amp-In caps: ofs=0x17, nsteps=0x3f, stepsize=0x02, mute=1
Amp-In vals: [0x97 0x97]
Converter: stream=0, channel=0
SDI-Select: 0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D3, actual=D3
Connection: 1
0x23
Node 0x09 [Audio Input] wcaps 0x10051b: Stereo Amp-In
Control: name="Capture Volume", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Control: name="Capture Switch", index=0, device=0
ControlAmp: chs=3, dir=In, idx=0, ofs=0
Device: name="ALC269VC Analog", type="Audio", device=0
Amp-In caps: ofs=0x17, nsteps=0x3f, stepsize=0x02, mute=1
Amp-In vals: [0x26 0x26]
Converter: stream=1, channel=0
SDI-Select: 0
PCM:
rates [0x560]: 44100 48000 96000 192000
bits [0xe]: 16 20 24
formats [0x1]: PCM
Power states: D0 D1 D2 D3 EPSS
Power: setting=D0, actual=D0
Connection: 1
0x22

2 修补XML(平台和布局)文件

2.1 从Pin复杂节点中提取值’Pin Default’、’EAPD’、’Node ID’

Complex节点获取Pin Default、EAPD和Node ID的值
举例:ACL269
Pin Complex Nodes with Control Name

1
2
3
4
5
Node 12 : Pin Default 0x90a60140 : [Fixed] Mic at Int N/A  name="Internal Mic Boost Volume"
Node 14 : Pin Default 0x90170110: [Fixed] Speaker at Int N/A EAPD: 0x02 name="Speaker Playback Switch"
Node 15 : Pin Default 0x03211020: [Jack] HP Out at Ext Left EAPD: 0x02 name="Headphone Playback Switch"
Node 18 : Pin Default 0x03a11830: [Jack] Mic at Ext Left name="Mic Boost Volume"
Node 19 : Pin Default 0x411111f0: [N/A] Speaker at Ext Rear name="Dock Mic Boost Volume"

2.2 整理成一个表格

有效节点 10进制 设备名称 Pin Default value Extracted verb data
0x12 18 Mic at Int N/A(内置麦克风) 0x90a60140 40 01 a6 90
0x14 20 Speaker at Int N/A(内置扬声器) 0x90170110 10 01 17 90
0x15 21 HP Out at Ext Left (耳机扬声器) 0x03211020 20 10 21 03
0x18 24 Mic at Ext Left(外置麦克风) 0x03a11830 30 18 a1 03

Extracted verb data : PIN默认值必须从右向左读取。我们将从其中取两个数字,然后从右至左写下来。

2.3 整理有效路径

使用codecgraph生成pathmap图

1
$ codecgraph  codec_dump.txt    # 生成codec_dump.svg就是声卡的pathmap

如果出现error: dot executable not found ( did you install graphviz? ) 的错误提示的话,那么还需要告执行下面的动作,打开终端,输入命令

1
brew install graphviz # 安装ocdecgraph所需要的依赖程序

将所生成的codec_dump.svg声卡的pathmap图,使用Sketch.app打开它,生成如下图:
pathMap图

有效节点 10进制 设备名称 Pin Default value Extracted verb data
0x12 18 Mic at Int N/A(内置麦克风) 0x90a60140 40 01 a6 90
0x14 20 Speaker at Int N/A(内置扬声器) 0x90170110 10 01 17 90
0x15 21 HP Out at Ext Left (耳机扬声器) 0x03211020 20 10 21 03
0x18 24 Mic at Ext Left(外置麦克风) 0x03a11830 30 18 a1 03

0x15 EAPD 0x2
0x14 EAPD 0x2

2.3.1 生成ConfigData

For the Pin complex Node 12 :
0 + 12 + 71c + 40 = 01271c40
0 + 12 + 71d + 01 = 01271d01
0 + 12 + 71e + a6 = 01271ea6
0 + 12 + 71f + 90 = 01271f90

For the Pin Complex Node 14 :
0 + 14 + 71c + 10 = 01471c10
0 + 14 + 71d + 01 = 01471d01
0 + 14 + 71e + 17 = 01471e17
0 + 14 + 71f + 90 = 01471f90

For the Pin Complex Node 15 :
0 + 15 + 71c + 20 = 01571c20
0 + 15 + 71d + 10 = 01571d10
0 + 15 + 71e + 21 = 01571e21
0 + 15 + 71f + 03 = 01571f03

For the Pin Complex Node 18 :
0 + 18 + 71c + 30 = 01871c30
0 + 18 + 71d + 18 = 01871d18
0 + 18 + 71e + a1 = 01871ea1
0 + 18 + 71f + 03 = 01871f03

2.3.2 排列configdata

01271c40 01271d01 01271ea6 01271f90
01471c10 01471d01 01471e17 01471f90
01571c20 01571d10 01571e21 01571f03
01871c30 01871d18 01871ea1 01871f03
01470c02 01570c02

<01271c40 01271d01="" 01271ea6="" 01271f90="" 01471c10="" 01471d01="" 01471e17="" 01471f90="" 01571c20="" 01571d10="" 01571e21="" 01571f03="" 01871c30="" 01871d18="" 01871ea1="" 01871f03="" 01470c02="">

2.3.3 修改configdata

01271c⓻⓼ 01271d⓹⓺ 01271e⓷⓸ 01271f⓵⓶
01471c⓻⓼ 01471d⓹⓺ 01471e⓷⓸ 01471f⓵⓶
01571c⓻⓼ 01571d⓹⓺ 01571e⓷⓸ 01571f⓵⓶
01871c⓻⓼ 01871d⓹⓺ 01871e⓷⓸ 01871f⓵⓶
01470c02 01570c02

⓻是接口顺序。

数字越低优先权就越高。每一个接口的顺序必须不一样。
Mic at Int N/A =5
HP Out at Ext Rear =1
Mic at Ext Rear = 4
Line In at Ext Rear =4
Speaker at Int N/A =1
SPDIF Out at Ext Rear =3
line out=2
如果无line out则
Mic at Int N/A =5
HP Out at Ext Rear =1
Mic at Ext Rear = 4
Line In at Ext Rear =4
Speaker at Int N/A =2
SPDIF Out at Ext Rear =3

⓼为line out

line out设置为f,其余皆为0

⓹为接口颜色

0 = Unknown
1 = Black
2 = Grey
3 = Blue
4 = Green
5 = Red
6 = Orange
7 = Yellow
8 = Purple
9 = Pink
A - D = Reserved
E = White
F = Other

⓺ 接口一般是0

意思是当接口被检测到就直接使用。如果是本本的话内建的麦克风和喇叭要设成1。理论是当我们把耳机插入本本机口的时候,内建喇叭会静音,耳机0接口被检测到就是用耳机。
Mic at Int N/A =1
HP Out at Ext Rear =0
Mic at Ext Rear = 0
Line In at Ext Rear =0
Speaker at Int N/A =1
SPDIF Out at Ext Rear =1
line out=0

⓷ 说明特定接口的功能是什么,对应以下设置就OK
0 = Line Out
1 = Speaker
2 = HP Out
3 = CD
4 = SPDIF Out
5 = Digital Other Out
6 = Modem Line Side
7 = Modem Handset Side
8 = Line In
9 = AUX
A = Mic In
B = Telephone
C = SPDIF In
D = Digital Other In
E = Reserved
F = Other

⓸ 连接装置类型

0 = Unknown
1 = 1/8” stereo/mono
2 = 1/4’ stereo/mono
3 = ATAPI internal
4 = RCA
5 = Optical
6 = Other Digital
7 = Other Analog
8 = Multichannel Analog (DIN)
9 = XLR/Professional
A = RJ-11 (Modem)
B = Combination
F = Other
通常接口是 1/8” stereo/mono,SPDIF 是 Optical。本本内建的接口是 ATAPI internal。

Mic at Int N/A =3
HP Out at Ext Rear =1
Mic at Ext Rear = 1
Line In at Ext Rear =1
Speaker at Int N/A =3
SPDIF Out at Ext Rear =5
line out=1

0就是插入接口的,就像麦克风、喇叭等。如果你dump出来有 [N/A] 的就是无用的port,这里的数字是4。
而9通常是给本本的,像内置喇叭、内置麦克风等Mic at Int N/A =9
HP Out at Ext Rear =0
Mic at Ext Rear = 0
Line In at Ext Rear =0
Speaker at Int N/A =9
SPDIF Out at Ext Rear =0
line out=0

⓶ 表示接口所在的位置

0 = Rear
1 = Front
8=HDMI
9=ATAPI
我的设置如下
Mic at Int N/A =9
HP Out at Ext Rear =1
Mic at Ext Rear = 1
Line In at Ext Rear =1
Speaker at Int N/A =9
SPDIF Out at Ext Rear =0
line out=1

01271c40 01271d01 01271ea3 01271f99
01471c10 01471d01 01471e13 01471f99 01470c02
01571c20 01571d10 01571e21 01571f01 01570c02
01871c30 01871d10 01871ea1 01871f01

2.4 计算PathMaps

有效节点 10进制 设备名称 路径16进制 路径10进制
0x14 20 Speaker at Int N/A(内置扬声器) 0x14–>0x0d–0x03 20–>13–>3
0x15 21 HP Out at Ext Left (耳机扬声器) 0x15–>0x0c–>0x02 21–>12–>2
0x12 18 Mic at Int N/A(内置麦克风) 0x12–>0x22–>0x09 18–>34–>9
0x18 24 Mic at Ext Left(外置麦克风) 0x18–>0x23–>0x08 24–>35–>8

3. 修改AppleALC

3.1 创建AppleALC的本地仓库的克隆版本

1
git clone https://github.com/vit9696/AppleALC   # 克隆AppleALC到本地

3.2 修改PinConfig.kext

打开AppleALC目录,进入Resources目录,你会发现这里面躺着截止到目前所支持的声卡的全部型号.我的声卡是ALC256,我就点击ALC256为便于理解,我将除了ALC256之外的其它型号的声卡目录全部删除了,它看起来如下图所示:
AppleALC Resources目录

我们会发现该目录下包括了一个定义文件Info.plist,打开Info.plist,你会发现,它定义了一个声卡驱动所需要的数据,CodecID后面的617是ALC269的0x269的10进制数值,CodecName是声卡名称的描述,这里是ALC269,,接下来是Files,它分成两部分,一部分是Layouts,它定义声卡设备的布局,另一部分是Platforms,它定义声卡的平台注入,包括有效节点和路径的定义。

3.3 修改layout和Platforms数据

依据所计算的PathMaps,修改Platforms.xml

描述声卡型号以及声卡ID信息
首先向zlib文件转换为xml文件才可以编辑
LayoutID修改为1(全篇LayoutID所有统一为1,也可统一为其他数字),修改codecID为283902569,这是0x10ec0269十六进制转换过来的。在codec_dump开头中可以找到,macos的计算器有进制转换功能。
pathmapID修改为269。部分声卡需要删除lineout项才能驱动,需要自行尝试。

外置mic需要修改电压控制值来实现外置mic驱动。
搜索codec中外置mic下的vref值,vref含义为初始电压基础上增加的百分比,如图为vref为80。当vref不为Hiz时,muteGPIO={(vref转换为16进制)+”0100”+node id}转换为10进制,codec中vref表示的是十进制,计算时转为16进制。如:在节点 0x18发现vref_80,80转换为16进制=50,则muteGPIO=(50010018)转换为10进制=1342242840;如果vref为Hiz,则muteGPIO=0
由于外置mic需要通过linein实现,因此修改linein中的muteGPIO为1342242840

3.4 修改pinconfigs.kext

Applealc-master——resources——pinconfigs.kext——contents中的info.Plist
集合了所有声卡的信息,我们只用保留需要的,为防止冲突,只修改第一项,其他都可以删除。第一项中修改codec为alc892,codecID为283904146,这是0x10ec0892十六进制转换过来的。在codec_dump开头中可以找到,macos的计算器有进制转换功能。configData中修改为自己的configdata即可。LayoutID修改为1(全篇LayoutID所有统一为1,也可统一为其他数字)
由于外置mic需要通过linein实现,因此修改linein中的muteGPIO为838926360

3.5 最后确认

最后确认一共需要修改和定制的为4个文件:
1.Applealc-master——resources——alc269—>Platforms.xml.zlib
2.Applealc-master——resources——alc269—>layout1.xml.zlib
3.Applealc-master—>resources—>alc269—>info.Plist
4.Applealc-master—>resources—>pinconfigs.kext—>contents—>info.Plist
全篇所有的layoutID都为1,如果需要修改其他数字,需要注意layout文件名也需要修改,如layout25.xmI.zlib