完美驱动 AppleHDA

在黑苹果中声卡驱动算是比较复杂的一部分,如果觉得麻烦可以选择 VoodooHDA 万能声卡驱动,但是这个驱动的缺点比较多,用起来始终不太舒服。最早在 10.9 的时候折腾了一次声卡驱动,
当时自己改的 AppleHDA 只支持输出,即 Speaker 和 HeadPhone, 相当长的一段时间都够用了,不过前一阵子需要用到麦克风的时候比较多,总是需要切换到 Windows 下,所以决定还是争取完美驱动,于是重新修改了一遍,这里是一点记录和补充。

引用

InsanelyMac 和 PCBeta 等等论坛上面有大量的教程,不过内容良莠不齐,下面是我制作过程中参考的几篇:
1. [教程] 完整製作仿冒 LegacyHDA.kext (12/16): 最经典的教程,每一步十分详细,不过是按照台式机处理的,而且有些细节现在的新版已经有了变化,不过仍然是最值得参考的帖子。
2. Guide to patch AppleHDA for your codec: InsanelyMac 上面的一篇教程,有些示例图已经失效了,但是提供了很多实用的工具,能够极大简化整个修改过程。
3. 仿製 AppleHDA – ALC269 for Lenovo S10: 一篇制作 ALC269 的记录,也比较详细,更重要的是补充了一些细节,以及上面帖子中的一些不足。

工具包

Guide to patch AppleHDA for your codec 中的工具包和 zlib.pl 组成,包含有:

  • Verbit: 用来自动生成 ConfigData, 免去了一个个节点手动整理的过程
  • codecgraph: 生成节点间关系图,用来制作 PathMap
  • convert_hex_to_dec.rb: 用于将十六进制值转换为十进制
  • zlib.pl: 解压/压缩 zlib 文件,修改 Layout 和 PathMap 会用到

下载地址为:

修改过程

1. 从 Linux 中提取 codec

并不需要安装到硬盘上,用U盘做一个 Ubuntu 的 Live USB 启动即可,相关文件在 /proc/asound/ 目录中,根据具体的设备提取

cat /proc/asound/card0/codec#0 > ~/codec_dump.txt

保存这个文件,然后回到 OS X

2. 使用 codecgraph 生成描述 PathMap 的 svg 矢量图

先把 codec_dump.txt 里的 AFG Function Id: 0x1 (unsol 0) 一行删除,然后输入:

./codecgraph codec_dump.txt 

convert_hex_to_dec.rb 脚本将其中的十六进制数字转换为十进制

./convert_hex_to_dec.rb codec_dump.txt.svg > codec_dump_dec.txt.svg

3. 使用 verbit 自动生成粗略的 ConfigData

./Verbit codec_dump.txt> verbs.txt 

注意这一步生成的 ConfigData 中可能会有数字错误显示为了10进制,可以用系统内置的计算器转换回16进制数。
生成并换算16进制以后的结果,无用的节点已经被自动剔除:

《完美驱动 AppleHDA》

另外这一步生成的 ConfigData 并不完全正确 ,仍然需要手动进行更改。

4. 修正 ConfigData

4.1 ConfigData 各位定义

Address + Node + 71c +【12】
Address + Node + 71d +【34】
Address + Node + 71e +【56】
Address + Node + 71f +【78】

Address 在你的 codec_dump.txt 开头定义,而 Node 则是对应的接口序号,71c,71d,71e,71f 是固定的,所以需要改的内容分别是每组的最后两位数,一共是8个位置:

1. Default Association

和 Sequence 一起用来表示设备间的关联,用来处理多声道,按照之前提取的 codec_dump.txt 信息选择。
需要注意的是,笔记本外置麦克风 Mic Ext 需要设置为 Line In 而不是 Ext Mic,否则不能正常工作。

1. Mic
2. Line In
3. SPDIF In
4. IntSpeaker
5. Headphone
6. SPDIF Out
7. Ext Mic
8. Line Out
F. 屏蔽

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        1           4
HP Out at Ext Rear          4           5
Mic at Ext Rear             3           2
Mic at Int ATAPI            5           1
Line Out at Ext N/A         6           8
SPDIF Out at Int ATAPI      2           6
2. Sequence:

一般设置为0即可,多声道需要分别设定

0. 后左与后右
1. 中央与重低音
2. 前左与前右声道

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        0           0
HP Out at Ext Rear          0           0
Mic at Ext Rear             0           0
Mic at Int ATAPI            0           0
Line Out at Ext N/A         0           0
SPDIF Out at Int ATAPI      0           0
3. Color

接口颜色,依然按照上面提取的 codec_dump.txt 设置

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

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        0           0
HP Out at Ext Rear          4           4
Mic at Ext Rear             9           9
Mic at Int ATAPI            0           0
Line Out at Ext N/A         8           8
SPDIF Out at Int ATAPI      0           0
4. Miscellaneous

插口侦测设置,定义如下

0=Jack Detect Override [外接设备]
1=Jack Detect Disabled [内置设备]

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        0           1
HP Out at Ext Rear          0           0
Mic at Ext Rear             0           0
Mic at Int ATAPI            0           1
Line Out at Ext N/A         0           0
SPDIF Out at Int ATAPI      0           0
5. Default Device

设备类型,注意这里的外置麦克风 Mic Ext 一定要设置为 Line In

0=Line Out
1=Speaker
2=HeadPhone Out
3=CD ATAPI
4=SPDIF Out
5=Digital Out
8=Line In
A=Mic
C=SPDIF In
D=Digital In
F=Other

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        1           1
HP Out at Ext Rear          2           2
Mic at Ext Rear             a           8
Mic at Int ATAPI            a           a
Line Out at Ext N/A         0           0
SPDIF Out at Int ATAPI      4           4
6. Connection Type

连接类型,圆形的 3.5 mm 接口设为1,笔记本内置的设备如果标有 ATAPI 则设为3,其他内置未知的设为0,屏蔽的设备也设置为0

0=Unknow
1=1/8 Stereo/Mono [也即 3.5mm 接口]
3=ATAPI Internal
4=RCA
5=Optical
6=Digital
B=Combination
F=Other

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        3           3
HP Out at Ext Rear          1           1
Mic at Ext Rear             1           1
Mic at Int ATAPI            3           3
Line Out at Ext N/A         3           3
SPDIF Out at Int ATAPI      3           3
7. Port

端口,用来确定是否有外部接口

0=External Jack [外接设备]
4=External No Connection [屏蔽设备]
9=Internal Fixed Function Device [内置设备]

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        9           9
HP Out at Ext Rear          0           0
Mic at Ext Rear             0           0
Mic at Int ATAPI            9           9
Line Out at Ext N/A         4           4
SPDIF Out at Int ATAPI      9           9
8. Location

外部插孔所在位置,一般设为1,屏蔽的装置设为0

0=N/A
1=Rear
8=Special (HDMI 01)
9=Special (ATAPI 01)

修改:

设备                        修改前       修改后
Speaker at Int ATAPI        0           0
HP Out at Ext Rear          1           1
Mic at Ext Rear             1           1
Mic at Int ATAPI            0           0
Line Out at Ext N/A         0           0
SPDIF Out at Int ATAPI      0           0

最后得到的正确结果为:

0x01471c40  0x01471d00  0x01471e13  0x01471f90
0x01571c50  0x01571d40  0x01571e21  0x01571f01
0x01871c20  0x01871d90  0x01871e81  0x01871f01
0x01971c10  0x01971d01  0x01971ea3  0x01971f90
0x01d71c80  0x01d71d80  0x01d71e03  0x01d71f40
0x01e71c60  0x01e71d00  0x01e71e43  0x01e71f90

移除0x, 整理, 如果你的 codec_dump.txt 文件里面出现过 EAPD 字样,在最后加上 01470c02.
最终修正过的 ConfigData:

<01471c40 01471d00 01471e13 01471f90 01571c50 01571d40 01571e21 01571f01 01871c20 01871d90 01871e81 01871f01 01971c10 01971d01 01971ea3 01971f90 01d71c80 01d71d80 01d71e03 01d71f40 01e71c60 01e71d00 01e71e43 01e71f90 01470c02>

修改 AppleHDAHardwareConfigDriver.kext

打开 AppleHDA.kext/Contents/PlugIns/AppleHDAHardwareConfigDriver.kext/Contents/Info.plist 文件,找到 IOPersonalities -> HDA Hardware Config Resource -> HDAConfigDefault -> Item 0 这一项的子项:

  • ConfigData: 如果没有这项则新建,类型为 Data; 如果已经有了,把上面的 ConfigData 填入;
  • CodecID: 根据 codec_dump.txt 文件中的 Vendor Id 的十六进制值转换为十进制:0x10ec0269 = 283,902,569, 填入即可;
  • FuncGroup: 按照 codec_dump.txt 中的值填写(就是前面删去那行的内容),一般为1
  • LayoutID: 需要选一个已经存在的 LayoutID, 这里我选择了 86.

至此 ConfigData 相关修改完成。

5. PathMap

由生成的 svg 向量图及 codec_dump.txt 文件分析得到 PathMap,
由 svg 向量图中找到可能的路径,然后在 codec_dump.txt 中每一个节点处查看类型是否合适,基本的节点类型规则是:

对于输入设备:AudioInput -> Audio Mixer/Audio Selector -> Pin Complex
对于输出设备:Pin Complex -> Audio Mixer -> Audio Output

比如我的 ALC269 找出的各设备路径:

[Mic Int] 7 -> 36 -> 25 (十六进制:0x07 -> 0x24 -> 0x19)
[Mic Ext] 8 -> 35 -> 24 (十六进制:0x08 -> 0x23 -> 0x18)
[Speaker] 20 -> 12 -> 2 (十六进制:0x14 -> 0x0c -> 0x02)
[HeadPhone] 21 -> 13 -> 3 (十六进制:0x15 -> 0x0d -> 0x03)
[SPDIF] 30 -> 6 (十六进制:0x1e -> 0x06)

修改 Platforms.xml.zlib

perl zlib.pl inflate Platforms.xml.zlib > Platforms.xml

《完美驱动 AppleHDA》

其中 PathMap 下 Item0, Item1, Item2 节点 等等每个是一组设备,如果是同一组中的设备,配合正确的 ConfigData 可以实现插入自动切换。
这里我的 Item0 中为 Mic Int 和 Mic Ext, 而 Item1 为 Speaker 和 HeadPhone, 即:

《完美驱动 AppleHDA》

输入设备的 PathMap:

《完美驱动 AppleHDA》

Boost 值: Mic Int = 3, Mic Ext = 1

输入设备的 Amp 中四项全部设置为 YES:

《完美驱动 AppleHDA》

输出设备的 PathMap:

《完美驱动 AppleHDA》

另外根据 仿製 AppleHDA – ALC269 for Lenovo S10 这篇教程的介绍,我在输出设备的三个节点下都添加了 Amp 节点。

输出设备的 Amp 中 VolumeInputAmp 为 NO, 其余全部为 YES:

《完美驱动 AppleHDA》

修改完成后,重新压缩为 zlib:

perl zlib.pl deflate Platforms.xml > Platforms.xml.zlib

6. Layout

由 codec_dump.txt 文件计算出 layout 相关数值
计算 MuteGPIO:

MuteGPIO = VREF(Hex) + 0100 + NodeID
当你的 codec_dump.txt 对应节点信息中存在 VREF_HIZ 时, MuteGPIO = 0

例如:
Node 18 = 50(VREF 80) + 0100 + 18 = 0x50010018 = 1342242840
Node 19 = 50(VREF 80) + 0100 + 19 = 0x50010019 = 1342242841

解压 LayoutXX.xml.zlib, 我这里是 Layout86.xml.zlib:

perl zlib.pl inflate layout86.xml.zlib > layout86.xml

如图:

《完美驱动 AppleHDA》

修改完成后,重新压缩为 zlib:

perl zlib.pl deflate layout86.xml > layout86.xml.zlib

7. 对 AppleHDA 进行 Bin patch

通过对驱动文件打补丁,让我们的设备能被 AppleHDA 正确识别。
我这里用的是将 ALC262(10ec0262) 代码替换为 ALC269(10ec0269).
可以用脚本或者用 Clover 的 KextsToPatch 功能:

  • 脚本:
perl -pi -e 's|\x62\x02\xec\x10|\x69\x02\xec\x10|g' AppleHDA.kext/Contents/MacOS/AppleHDA
  • KextsToPatch:
    编辑 config.plist 最好用专门的编辑器(XCode, Plist Editor 等)而不是文本编辑器,文本编辑器会显示已编码的 Data 值。这里的 Find 值为<6202ec10>,Replace 值为 <6902ec10>
<dict>
    <key>Name</key>
    <string>AppleHDA</string>
    <key>Comment</key>
    <string>ALC269</string>
    <key>Find</key>
    <data>YgLsEA==</data>
    <key>Replace</key>
    <data>aQLsEA==</data>
</dict>

如图,是在 plist 编辑器中:

《完美驱动 AppleHDA》

8. 修改 DSDT

给 DSDT 打补丁这一步,需要你的 DSDT 中已经有了 DTGP 方法:

Method (DTGP, 5, NotSerialized)
    {
        If (LEqual (Arg0, Buffer (0x10)
            {
                /* 0000 */    0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44, 
                /* 0008 */    0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B
            }))
    {
        If (LEqual (Arg1, One))
        {
            If (LEqual (Arg2, Zero))
            {
                Store (Buffer (One)
                    {
                        0x03
                    }, Arg4)
                Return (One)
            }

            If (LEqual (Arg2, One))
            {
                Return (One)
            }
        }
    }

    Store (Buffer (One)
        {
            0x00
        }, Arg4)
    Return (Zero)
}

然后找到 HDEF 设备的 _DSM 方法,修改为如下:

Method (_DSM, 4, NotSerialized)
{
    Store (Package (0x0A)
        {
            "hda-gfx", 
            Buffer (0x0A)
            {
                "onboard-1"
            }, 

            "codec-id", 
            Buffer (0x04)
            {
                0x69, 0x02, 0xEC, 0x10
            }, 

            "layout-id", 
            Buffer (0x04)
            {
                0x56
            }, 

            "device-type", 
            Buffer (0x11)
            {
                "ALC269"
            }, 

            "PinConfigurations", 
                Buffer (Zero) {}
        }, Local0)
    DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0))
    Return (Local0)
}

9. 修复权限并重建内核缓存

这一步我直接使用了 Kext Utility 进行这两步,如果你需要的话,可以在下面的地址下载

待权限修复完成,缓存重建后,重启系统,声卡就已经能够正常工作了。

10. 备份 ConfigData, Platforms.xml.zlib, LayoutXX.xml.zlib, 以便升级之后使用

如果你用 Clover 的话,系统是可以直接无痛升级的,不过升级后 AppleHDA.kext 又会被替换为系统自带版本。因此你需要备份整理好的 ConfigData, Platforms.xml.zlib, LayoutXX.xml.zlib, 以后升级直接填入 ConfigData, 覆盖两个 zlib 文件并重建缓存即可。

总结

制作 AppleHDA 的过程比较复杂,但是并不困难。另外,其实声音部分还有一个重要的 HDMI 声音输出部分,由于我的 HDMI 只接显示器,没有声音输出的需求,所以这一部分就没有折腾。
对于每次升级后都需要再次修改上述三个部分的问题,InsanelyMac 和 PCBeta 上面都有相关的教程能一劳永逸的解决这个问题,不过我一直没有尝试,如果 Clover 将来推出相关的功能在考虑吧。

  1. sark说道:

    :exclaim: 这么棒的文章怎么不发到远景呢!!!!!

发表评论

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