2012年11月15日 星期四

仿製 AppleHDA - ALC269 for Lenovo S10

Preface

最近試著讓 Lenovo S10(Atom N270) 吃上 Mac OS X,查了些資料,發現 Mountain Lion(kext 全都是 64-bit only) 是無望,理論的極限為 Lion(32-bit kext supported),可以 demo,但是 very unusable,下一篇我會談如何讓 S10 demo Lion(僅能如此)。因此 S10 可供日常使用的上限,就是 Snow Leopard。

關於如何讓 S10 吃上 Snow Leopard 我想資源最豐富的是 Lenovo IdeaPad S Series Forum,我就是根據 vaniii 所製作的 enabler(http://s10lenovo.com/viewtopic.php?f=33&t=3280) 來讓 S10 的各項功能在 Mac 底下得以使用。而 vaniii 用來驅動 ALC269 的方法是使用 VoodooHDA,功能上基本可用,但跑 Hackintosh 的精神是能折騰就盡量折騰能多用一個 Apple 原生的 kext 是一個。恰巧,在 vaniii 的大樓底下 rals2007(http://s10lenovo.com/viewtopic.php?f=33&t=3280&start=2580#p32373) 這位仁兄為大家仿製了一個 AppleHDA,我測試後,確實可用,但有兩個缺點:
  1. 仿製版本過時,其版本為 1.8.7,並非 Snow Leopard 10.6.8(10K549) 所用的 2.0.5
  2. kernel log 大約每 30 秒產生一個錯誤訊息,且是不斷地重複,從開機載入 AppleHDA 就開始
Error message 重複性的產生——這是一個可大可小的問題,看起來是不影響使用,但自從我讓 S10 硬上 Lion 後,絕不允許這種週期性的報錯(如果你曾被 syslogd 吃掉 80%↑ 的 CPU resource  荼毒過,我想你會和我一樣......)。然而 VoodooHDA 並不會如此,但我也不想回頭。

試著找其他人修改的 ALC269,結果就查到遠景上 nksmiles 所發表的教學,先用隨附的 AppleHDA, 可惜不管用,看來同為 ALC269 但腳位的接法卻是不同(實際操作時驗證這一點,差異在內建麥克風所在的節點不相同),但既然附有教學,我便嘗試自行仿製給 S10 專用的 AppleHDA,以下就是我實作之後的一些見解與補充。


在開始之前,我們先來確認一些前置知識:

Reference

  • <Ref1> 完整製作仿冒 LegacyHDA.kext - 紫米http://bbs.pcbeta.com/viewthread-623626-1-1.html
    仿 AppleHDA 的三大要素:ConfigData, Layout, PathMap, 我皆是根據紫米的流程走下來,因此不打算全盤講起,實際操作前建議至少瞄過一遍,紫米講的很詳盡,當初我可是拿這篇不斷的交相對照才學會。
  • <Ref2> ALC269仿冒驱动完美工作!分享修改方法。 - nksmiles - http://bbs.pcbeta.com/viewthread-888781-1-1.html
    因為紫米是使用 ALC883 做為教學案例,一些參數上的設定,對我而言參考價值是不太充足,身為同宗的 ALC269(僅腳位接法差異),在算 ConfigData 時,可說是半個標準答案。
  • <Ref3> 抛弃10.6的声卡驱动,修改lion原版声卡驱动来驱动你的声卡 - jianyili -http://bbs.pcbeta.com/viewthread-869832-1-1.html
    這篇看似與我們無關,但如果你把 rals2007 所仿製的 v1.8.7 與現行 v2.0.5 AppleHDA 相比較,確實會發現內部檔案架構有變化。據 jianyili 的說法,其實自 10.6.6 起 AppleHDA 就已經改變,而 Lion 沿用這樣的變化。假設,我們照紫米的教學使用 LegacyHDA,然後再透過 jianyili 的教學轉成新版格式,那就拐了個彎。其實我們只要詳讀此篇,就可以直接用新版的格式直接開始仿製。
  • <Ref4> 一步一步教你搞定仿冒声卡【针对新手】- serco76 - http://bbs.pcbeta.com/viewthread-953645-1-1.html
    serco76 給新手提供了一個很好的邏輯思維,對於整個仿製 AppleHDA 的過程上,我個人覺得它是屬於上乘心法,初讀很容易不知其所以然,一旦有實作經驗過後的再讀,更能體會箇中精妙。
真心建議閱讀本篇的讀者,都至少瞄過上述四篇大著,我的一些論述都是建基於此,紫米那篇更要讀通,其他三篇是做衍生與補充,其實能看懂這四篇的人,我這篇看不看都無所謂,充其量就是整理和一點小註解。

【修改對象】

  • ConfigData ---> AppleHDA.kext/Contents/PlugIns/AppleHardwareConfigDriver.kext/Contents/Info.plist
  • Layout ---> AppleHDA.kext/Contents/Resources/layout269.xml(layoutXXX.xml 是與 LayoutID 相對應)
  • PathMap ---> AppleHDA.kext/Contents/Resources/Platforms.xml
這是自 Snow Leopard 後期,到 Lion 之後,新版 AppleHDA 應該修改的架構,更詳盡的說明請參閱 <Ref3> jianyili 的文章,此處就簡單結論如上。

ConfigData

根據紫米的教學,我從 openSUSE 12.3 Milestone 1 取得的 Codec.txt 概略如下:# cat /proc/asound/card0/codec#X > ~/Desktop/Codec.txt 可以先透過檔案瀏覽器(e.g., Dolphin) 先到 /proc/asound/card0/ 查看,X 基本上可能為 0, 1, 2,確認過後再輸入上面指令

Codec: Realtek ALC269 Address: 0 Vendor Id: 0x10ec0269 0x11 0x411111f0 [N/A] Speaker at Ext Rear Black 0x12 0x411111f0 [N/A] Speaker at Ext Rear Black 0x14 0x99138110 [Fixed] Speaker at Int ATAPI Purple 0x15 0x0321441f [Jack] HP Out at Ext Left Green 0x16 0x411111f0 [N/A] Speaker at Ext Rear Black 0x18 0x03a19c20 [Jack] Mic at Ext Left Pink VREF_80 0x19 0x99a3092f [Fixed] Mic at Int ATAPI Unknown VREF_80 0x1a 0x411111f0 [N/A] Speaker at Ext Rear Black VREF_HIZ 0x1b 0x411111f0 [N/A] Speaker at Ext Rear Black VREF_HIZ 0x1d 0x4015812d [N/A] Speaker at Ext N/A Purple 0x1e 0x411111f0 [N/A] Speaker at Ext Rear Black 這裡使用顏色作為區分以方便識別,主要是兩組輸入、輸出,紫色底色的 0x1d 用途不明,不像主要作用的 pin,暫時先標記起來。

[Note]我的 Pin Default 組數不是 12 !!!


是的!ALC269 根據 Codec.txt 的資訊只有 11 組。Pin Default 的數目是與晶片有關,不同的晶片自然有著不同的數目,ConfigData 需填入的 data 並非一個固定大小。初學時看著紫米的範例,想說完蛋少了一組,直到發現 nksmiles 對於 ALC269 的設定(同為 11 組),才肯定了我的猜測。進一步的說,AppleHDA 並不在意有多少組 Pin Default,而是你在 ConfigData 內填入多少資料,它據此做多少事。假設,我只描述輸出相關設備,那麼會工作的就僅可能是輸出設備,沒描述的輸入設備自然不會工作,也不會去干擾輸出設備(serco76 的教學就是這樣做,一開始只先專著在輸出設備,稍候再完備輸入設備)

經過 Little-Endian 排序整理之後如下:
11 f0 11 11 41 [N/A] Speaker Black 12 f0 11 11 41 [N/A] Speaker Black 14 10 81 13 99 [Fixed] Speaker Purple 15 1f 44 21 03 [Jack] HP Out Green 16 f0 11 11 41 [N/A] Speaker Black 18 20 9c a1 03 [Jack] Mic Pink VREF_80 19 2f 09 a3 99 [Fixed] Mic Unknown VREF_80 1a f0 11 11 41 [N/A] Speaker Black VREF_HIZ 1b f0 11 11 41 [N/A] Speaker Black VREF_HIZ 1d 2d 81 15 40 [N/A] Speaker Purple 1e f0 11 11 41 [N/A] Speaker Black
仿 Apple 化後: Node c d e f Config =========================================================== 11 f0 00 00 40 01171cf0 01171d00 01171e00 01171f40 12 f0 00 00 40 01271cf0 01271d00 01271e00 01271f40 14 40 81 10 90 01471c40 01471d81 01471e10 01471f90 15 50 40 21 01 01571c50 01571d40 01571e21 01571f01 16 f0 00 00 40 01671cf0 01671d00 01671e00 01671f40 18 70 90 a1 01 01871c70 01871d90 01871ea1 01871f01 19 10 01 a0 90 01971c10 01971d01 01971ea0 01971f90 1a f0 00 00 40 01a71cf0 01a71d00 01a71e00 01a71f40 1b f0 00 00 40 01b71cf0 01b71d00 01b71e00 01b71f40 1d f0 00 00 40 01d71cf0 01d71d00 01d71e00 01d71f40 1e f0 00 00 40 01e71cf0 01e71d00 01e71e00 01e71f40 其實就是做 Pin Dedault 數值的修正,讓它更貼近 Apple 原生的值,請參考紫米所提供 Mac 機型的設定值修改,此處我給幾個 comment
  • 對於紫米在第一位置 Default Association 所給的定義我有些質疑,他說 No. 6 = Line Out, No. 7 = SPIDF Out, No. 8 = ExtMic, 但對照他給的 Mac 參考範例,ExtMic 所在 pin 腳所設的值皆為 7,而 SPIDF Out 所在 pin 腳皆設為 6,合理的懷疑,正確值為 No. 6 = SPIDF Out, No. 7 = ExtMic。因此,我自己就如此實驗,在 System Profiler 顯示也沒錯。
  • nksmiles 提到為了讓內建 Mic 工作,必須將 ExtMic 的第五位設為 8(Line In) 來規避,但我看 Mac 確實都將內、外接 Mic 的第五位設成 a。自己試著實驗,發現並無問題,推測原因應該是與第一位有關,nksmiles 選擇將第一位設為 2,但我仿照 Mac 將第一位設成 7。
  • 作用不明的 Node 1d,請果斷將它屏蔽

Final Config: Address + Node + 71c +【12】 Address + Node + 71d +【34】 Address + Node + 71e +【56】 Address + Node + 71f +【78】 因此得到 ConfigData 為: <01171cf0 01171d00 01171e00 01171f40 01271cf0 01271d00 01271e00 01271f40 01471c40 01471d81 01471e10 01471f90 01571c50 01571d40 01571e21 01571f01 01671cf0 01671d00 01671e00 01671f40 01871c70 01871d90 01871ea1 01871f01 01971c10 01971d01 01971ea0 01971f90 01a71cf0 01a71d00 01a71e00 01a71f40 01b71cf0 01b71d00 01b71e00 01b71f40 01d71cf0 01d71d00 01d71e00 01d71f40 01e71cf0 01e71d00 01e71e00 01e71f40 01470c02> 因為在 Codex.txt 裡 Node 14 曾經出現過 EAPD,所以必須在結尾多加上 01470c02,這是為了讓揚聲器正常發聲;如果不加,耳機正常工作,揚聲器無聲。原理請見威廉第三大師的論述(http://bbs.pcbeta.com/forum.php?mod=viewthread&tid=623626&page=3#pid13444785)

<ConfigData 設定>


CodecID = 283,902,569(= 0x10EC0269)
ConfigData --> 將剛才算出的 ConfigData 填入(angle brackets 不需要,僅數值就好,共 180 bytes[(4 * 11 + 1) * 4])
LayoutID = 269, 待會在 layout269.xml 也要對應設定

Layout

MuteGPIO

MuteGPIO = VREF(Hex) + 0100 + NodeID When VREF_HIZ appears, MuteGPIO = 0 Node 18 = 50(VREF 80) + 0100 + 18 = 0x50010018 = 1342242840 Node 19 = 50(VREF 80) + 0100 + 19 = 0x50010019 = 1342242841

<Overview>


CodecID = 283,902,569, LayoutID = 269 皆與 ConfigData 處相對應;
PathMapID = 269 則需與 Platforms.xml 對應

<Layout 設定>


MuteGPIO 對應填入,
SignalProcessing 就保留 legacyHDA 模板的設定值,為音效增益的部份,就算沒加應該也是不影響功能。

[Trick] 讓聲音更清晰


參考 rals2007 修改的 1.8.7 裡之設定會發現,他在 Headphone 和 IntSpeaker 處,除 MaximumBootBeepValue 外,其他什麼也沒有,AmpPostDelay, AmpPreDelay, Headset_dBV 皆沒設。我個人試用後,感覺揚聲器的聲音似乎比較清晰,而所測試的音樂為動漫歌曲,多為女聲高音,推測是去掉 AmpPostDelayAmpPreDelay 的關係。如果加上去的話,清晰度似乎會降低,因為很少聽重金屬搖滾之類的歌曲,沒有測試對其影響,如對低音部有興趣者,可自行比較,我個人是拿掉不用。

PathMap

[Fixed] Mic 0x07 > 0x24 > 0x19 => 7 > 36 > 25 [Jack] Mic 0x07 > 0x24 > 0x18 => 7 > 36 > 24 [Fixed] Speaker 0x14 > 0x0c > 0x02 => 20 > 12 > 2 [Jack] HP Out 0x15 > 0x0d > 0x03 => 21 > 13 > 3 看了很多人他們設置 PathMap 的路徑,雖然配法並非唯一,只要符合 connection 的關係,但是我發現到各個 Path 都是絕對獨立的,它們不會去共用節點,那到底能不能共用呢?紫米提供的 MacBook Pro 5,2 範例,給了一個很有趣的回答:它的內、外接 Mic 的走法一開始都是 7 > 36 > 然後才是各自的節點。顯然在 Mac 共用節點並不違法,我試著仿效,結果看來是沒問題的。至於是不是有任何副作用,我不知道,有疑慮的話,使用多數教學所採用的獨立路徑;這個方式有沒有比較好,我亦不知道,但它提供一條新的道路來讓人折騰嘗試。


此處 PathMapID 與 layout269.xml 裡面的 PathMapID 必須相同,才能被正確的載入


Item 0 是輸入裝置
  • Item 0: 內建麥克風
  • Item 1: 外接麥克風
Item 1 是輸出裝置
  • Item 0: 揚聲器
  • Item 1: 耳機(Headphone)

我在此處讓輸入、輸出裝置能夠自動切換,因此每個 Item 恰都有兩個子項;如需改成手動切換,請自行將裝置獨立,意即有兩個輸入(出)裝置,底下僅各只有一個裝置。

<輸入裝置 NodeID 的設定>


Boost 我直接沿用 rals2007 在其 1.8.7 所設定的值(內建麥克風 = 3, 外接麥克風 = 1)

<輸入裝置 Amp 的設定>


內建、外接麥克風皆在第一個節點上添加 Amp,底下的 4 個項目都設為 Yes

<輸出裝置 NodeID 的設定>


紫米的教學裡談到,Amp 僅需加在第二個節點處就好,這樣做在我的 S10 上會產生 sound assertion error messages, 並且使整個 AppleHDA 不 work。參考 rals2007 在 v1.8.7 的配法,他不選第二個,而是在第三個節點處加上 Amp,功能正常,但我卻無法在系統偏好設定下勾選靜音。偶然間找到一個 based on Lion 10.7.0(11a494) 版本號為 2.1.1 AppleHDA,依稀記得是在遠景上找的,詳細位置已不記得,同樣是 patch for ALC269,一試之下,喇叭有聲音,系統偏好設定可靜音,打開它的 Platforms.xml 來看,他居然在所有輸出裝置三個節點上都加上 Amp,因此我推薦仿照其配置,將 Amp 設給所有輸出裝置的節點。

<輸出裝置 Amp 的設定>


三個節點都要添加 Amp,且除 VolumeInputAmp = No 外,其餘三項都設為 Yes

Binary Patch

# perl -pi -e 's|\x62\x02\xec\x10|\x69\x02\xec\x10|g' AppleHDA.kext/Contents/MacOS/AppleHDA
這是將 AppleHDA 原生支援的 ALC262 換成我們的 ALC269,當然也可以用 hexedit tool(e.g., 0xED),但我沒用過不熟。此外,我是有點疑問,Apple 原生支援的晶片組(e.g., ALC885, ...etc)也不少,我們一定要用 ALC262 當作被取代對象嗎?不能換成其他的嗎?有興趣的人可朝這方面研究一下。

DSDT

首先將 DTGP method 加入 DSDT
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) }
放在 DSDT 的最開頭處即可

然後在 Device (HDEF) 下加入以下 method
Method (_DSM, 4, NotSerialized) { Store (Package (0x0A) { "codec-id", Buffer (0x04) { 0x69, 0x02, 0xEC, 0x10 }, "layout-id", Buffer (0x04) { 0x0D, 0x01, 0x00, 0x00 }, "device-type", Buffer (0x0F) { "Realtek ALC269" }, "hda-gfx", Buffer (0x0A) { "onboard-1" }, "PinConfigurations", Buffer (Zero) {} }, Local0) DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0)) Return (Local0) }
如果你一路跟隨至此,並將所有步驟執行完成,且沒有遺漏,那麼恭喜!你的 AppleHDA 已經製作完成,可以將它扔進 S/L/E(別忘記修復權限),之後重新開機,看看你的揚聲器是否可以發聲了呢!沒有意外,就盡情享受 AppleHDA 帶來的原生支援唄!^^

Postfix

Sound assertion "0 == hdaGfxCandidate" failed in AppleHDAController at line 1082 goto Exit

這個錯誤訊息會在載入 AppleHDA 出現一次。起因於 Injection 的不完整,造成 kernel log 出現錯誤訊息,目前看來並不影響仿製 AppleHDA 的功能。

Solution: 需在 DSDT 中的 Device (GFX0) 加入 "hda-gfx" 的資訊

Method (_DSM, 4, NotSerialized) { Store (Package (0x02) { "hda-gfx", Buffer (0x0A) { "onboard-1" } }, Local0) DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0)) Return (Local0) }
這個錯誤似乎牽涉到 HDMI,參考 Acer 4750G 修正過的 DSDT([acer] 地平线:MAC记-------4750G黑苹果之新手必看(安装贴、驱动贴,引导贴,镜像制作贴)- http://benyouhui.it168.com/thread-1884141-1-1.html) 我發現有進行 hda-gfx Injection 的地方,除 Device (HDEF)Device (GFX0),尚有 Device (PEGP)[[教程] DSDT+AppleHDA修改(修复HDMI引起的sound assertion)(CX20561为例)- http://bbs.pcbeta.com/viewthread-756597-1-1.html]Device (HDAU)。因為 S10 的 DSDT 只有 HDEF 和 GFX0 這兩個 Device, 只要補上後就沒有 error message。如果在其他 PC 上想要修正這個錯誤,當在 GFX0 添加上段 code 而無法修正錯誤時,請查看是否有 Device (PEGP) 和 Device (HDAU),並為其加上上面的 code(如果你的 Device 底下已有 Method (_DSM, ...) 那就只要加入 "hda-gfx" 藍色這部分,然後在 Package 的數量上 +2[Hex])

Un-fix

Sound assertion "0 != fProvider->startPowerManagementTimerForEngine ( this, true )" failed in AppleHDAEngine at line 5635 goto handler


這個似乎與休眠回來後,音效消失相關的錯誤訊息,修正方式有二,沒有完美的解決方案:
  1. # kextunload /System/Library/Extensions/AppleHDA.kext
    # kextload /System/Library/Extensions/AppleHDA.kext
    Refer by "No sound after waking up from sleep mode" - http://www.insanelymac.com/forum/topic/212145-no-sound-after-waking-up-from-sleep-mode/#entry1425310
  2. 把耳機插入,音效自動恢復;耳機拔出,揚聲器正常!
    且經過測試,休眠前已插入耳機,經過休眠,系統恢復後,耳機能正常播音,意即耳機的 pin 腳完全不受休眠的影響。據此推測,揚聲器會因休眠後沒有音效,即有可能來自於 EAPD 開關沒有開啓。

沒有留言:

張貼留言