Linux
為 Nvidia Optimus 破譯此 Acer Aspire 4830TG ACPI 程式碼
我試圖從具有 Nvidia Optimus 混合圖形系統的 Acer Aspire 4830TG 的 ACPI 表中了解以下 NVOP 方法。頂部的 NVOP 方法定義了一組指令,稍後可以在 _DSM 方法中使用。我應該使用 acpi_call 模組或 byo-switcheroo 模組呼叫哪種方法來按需打開/關閉卡?
請看下面的程式碼:
Method (NVOP, 4, Serialized) { Name (_T_0, Zero) Store ("------- NV OPTIMUS DSM --------", Debug) If (LNotEqual (Arg1, 0x0100)) { Return (0x80000001) } While (One) { Store (ToInteger (Arg2), _T_0) If (LEqual (_T_0, Zero)) { Store (Buffer (0x04) { 0x61, 0x00, 0x01, 0x0C }, Local0) Return (Local0) } Else { If (LEqual (_T_0, 0x05)) { Name (TMP5, Buffer (0x04) { 0x00, 0x00, 0x00, 0x00 }) CreateField (TMP5, Zero, 0x04, DAVF) CreateField (TMP5, 0x04, One, LIDF) CreateField (TMP5, 0x08, 0x06, TOGN) CreateField (Arg3, 0x1F, One, NCSM) CreateField (Arg3, 0x19, 0x05, NCSN) CreateField (Arg3, 0x18, One, DIMK) CreateField (Arg3, 0x0C, 0x0C, ACTD) CreateField (Arg3, Zero, 0x0C, ATTD) If (ToInteger (NCSM)) { Store (ToInteger (NCSN), TOGN) } Else { If (ToInteger (DIMK)) { GETD (ToInteger (ATTD), ToInteger (ACTD)) Store (\_SB.PCI0.PEG0.PEGP.NTOI, TOGN) Store (One, DAVF) } } Return (TMP5) } Else { If (LEqual (_T_0, 0x06)) { Name (TMP6, Package (0x0F) { Ones, 0x2C, Ones, 0x2C, Ones, 0x2C, Ones, Ones, 0x2C, Ones, Ones, 0x2C, Ones, Ones, 0x2C }) Store (\_SB.PCI0.GFX0.IDI2, Index (TMP6, Zero)) Store (\_SB.PCI0.GFX0.IDI1, Index (TMP6, 0x02)) Store (\_SB.PCI0.GFX0.IDI4, Index (TMP6, 0x04)) Store (\_SB.PCI0.GFX0.IDI2, Index (TMP6, 0x06)) Store (\_SB.PCI0.GFX0.IDI1, Index (TMP6, 0x07)) Store (\_SB.PCI0.GFX0.IDI2, Index (TMP6, 0x09)) Store (\_SB.PCI0.GFX0.IDI4, Index (TMP6, 0x0A)) Store (\_SB.PCI0.GFX0.IDI1, Index (TMP6, 0x0C)) Store (\_SB.PCI0.GFX0.IDI4, Index (TMP6, 0x0D)) Return (TMP6) } Else { If (LEqual (_T_0, 0x10)) { Return (\_SB.PCI0.PEG0.PEGP.GOBT (Arg3)) } Else { If (LEqual (_T_0, 0x1A)) { CreateField (Arg3, 0x18, 0x02, OPCE) CreateField (Arg3, Zero, One, FLCH) If (ToInteger (FLCH)) { Store (ToInteger (OPCE), OMPR) } Name (RBUF, Buffer (0x04) { 0x00, 0x00, 0x00, 0x00 }) CreateField (RBUF, Zero, One, OPEN) CreateField (RBUF, 0x03, 0x02, CGCS) CreateField (RBUF, 0x06, One, SHPC) CreateField (RBUF, 0x18, 0x03, DGPC) CreateField (RBUF, 0x1B, 0x02, HDAC) Store (One, OPEN) Store (One, SHPC) Store (0x02, HDAC) Store (One, DGPC) If (\_SB.PCI0.PEG0.PEGP.GSTA ()) { Store (0x03, CGCS) } Else { Store (Zero, CGCS) } Return (RBUF) } Else { If (LEqual (_T_0, 0x1B)) { Store (Arg3, Local0) CreateField (Local0, Zero, One, OPFL) CreateField (Local0, One, One, OPVL) If (ToInteger (OPVL)) { Store (Zero, OPTF) If (ToInteger (OPFL)) { Store (One, OPTF) } } Store (OPTF, Local0) Return (Local0) } Else { Return (0x80000002) } } } } } } Break } } Method (GOBT, 1, NotSerialized) { Name (OPVK, Buffer (0xE2) { /* 0000 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0008 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0010 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0018 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0020 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0028 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0030 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0038 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0040 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0048 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0050 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0058 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0068 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0078 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0088 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0098 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00A8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00B8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00C8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00D8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00E0 */ 0x00, 0x00 }) CreateWordField (Arg0, 0x02, USRG) If (LEqual (USRG, 0x564B)) { Return (OPVK) } Return (Zero) } Method (_INI, 0, NotSerialized) { Store (Zero, \_SB.PCI0.PEG0.PEGP._ADR) } Method (GSTA, 0, Serialized) { If (LEqual (\_SB.PCI0.PEG0.PEGP.PI17, One)) { Return (One) } Else { Return (Zero) } } Method (_ON, 0, Serialized) { \_SB.PCI0.PEG0.PEGP.PWRE () Store (Zero, LNKD) While (LLess (LNKS, 0x07)) { Sleep (One) } Store (Zero, CMDR) Store (VGAB, VGAR) Store (0x06, CMDR) } Method (_OFF, 0, Serialized) { Store (VGAR, VGAB) Store (One, LNKD) While (LNotEqual (LNKS, Zero)) { Sleep (One) } \_SB.PCI0.PEG0.PEGP.PWRD () } Method (_PS0, 0, NotSerialized) { If (DGOS) { GLSC () \_SB.PCI0.PEG0.PEGP._ON () GLSR () Store (Zero, DGOS) Store (Zero, MLTF) Store (Zero, \_SB.PCI0.LPCB.EC0.DSPM) } } Method (_PS3, 0, NotSerialized) { If (LEqual (\_SB.PCI0.PEG0.PEGP.OMPR, 0x03)) { GLSC () \_SB.PCI0.PEG0.PEGP._OFF () GLSR () Store (One, DGOS) Store (0x02, \_SB.PCI0.PEG0.PEGP.OMPR) Store (One, \_SB.PCI0.LPCB.EC0.DSPM) } } Method (_STA, 0, Serialized) { Return (0x0F) } Method (_ROM, 2, NotSerialized) { Store (Arg0, Local0) Store (Arg1, Local1) If (LGreater (Local1, 0x1000)) { Store (0x1000, Local1) } If (LGreater (Local0, 0x00010000)) { Return (Buffer (Local1) { 0x00 }) } If (LGreater (Local0, RVBS)) { Return (Buffer (Local1) { 0x00 }) } Multiply (Local1, 0x08, Local3) Name (ROM1, Buffer (0x8000) { 0x00 }) Name (ROM2, Buffer (Local1) { 0x00 }) If (LLess (Local0, 0x8000)) { Store (RBF1, ROM1) } Else { Subtract (Local0, 0x8000, Local0) Store (RBF2, ROM1) } Multiply (Local0, 0x08, Local2) CreateField (ROM1, Local2, Local3, TMPB) Store (TMPB, ROM2) Return (ROM2) } Method (MXMX, 1, Serialized) { If (LEqual (Arg0, One)) { P8XH (One, 0x99, P8XH (Zero, One, Return (One), Return (Zero))) } } Name (MXM3, Buffer (0x45) { /* 0000 */ 0x4D, 0x58, 0x4D, 0x5F, 0x03, 0x00, 0x3D, 0x00, /* 0008 */ 0x30, 0x10, 0xB8, 0xFF, 0xF9, 0x3E, 0x00, 0x00, /* 0010 */ 0x00, 0x01, 0x8A, 0xFF, 0xF9, 0x3E, 0x00, 0x00, /* 0018 */ 0x60, 0x79, 0xD0, 0xFE, 0xF9, 0x3E, 0x00, 0x00, /* 0020 */ 0x20, 0x2B, 0xE2, 0xFE, 0xF9, 0x3E, 0x00, 0x00, /* 0028 */ 0x60, 0x6C, 0xEA, 0xFE, 0xF9, 0x3E, 0x00, 0x00, /* 0030 */ 0x01, 0x90, 0x01, 0x00, 0x03, 0x00, 0x90, 0x01, /* 0038 */ 0x13, 0x00, 0x90, 0x01, 0xE5, 0x0D, 0x01, 0x01, /* 0040 */ 0x01, 0x00, 0x00, 0x00, 0x96 }) Method (_DSM, 4, Serialized) { Name (_T_0, Zero) If (LEqual (Arg0, Buffer (0x10) { /* 0000 */ 0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47, /* 0008 */ 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0 })) { Return (\_SB.PCI0.PEG0.PEGP.NVOP (Arg0, Arg1, Arg2, Arg3)) } If (LEqual (Arg0, Buffer (0x10) { /* 0000 */ 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C, /* 0008 */ 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 })) { While (One) { Store (ToInteger (Arg2), _T_0) If (LEqual (_T_0, Zero)) { Return (Buffer (0x04) { 0x01, 0x00, 0x01, 0x01 }) } Else { If (LEqual (_T_0, 0x18)) { Return (Buffer (0x04) { 0x00, 0x03, 0x00, 0x00 }) } Else { If (LEqual (_T_0, 0x10)) { If (LEqual (Arg1, 0x0300)) { Return (MXM3) } } } } Break } Return (0x80000002) } Return (0x80000001) }
原始 ACPI 表可在此處獲得:http:
//bugs.launchpad.net/lpbugreporter/+bug/752542/+attachment/2235754/+files/Aspire%204830TG.tar.gz
分析您發布的程式碼以及 ass
acpi_call
使我得出結論,最可能的候選人應該是:echo '\_SB.PCI0.PEG0.PEGP._OFF' > /proc/acpi/call
關閉卡並
echo '\_SB.PCI0.PEG0.PEGP._ON' > /proc/acpi/call
重新打開它。
您應該可以安全地測試這些,如
README
foracpi_call
狀態:測試所有方法應該沒問題
並且
\_SB.PCI0.PEG0.PEGP._OFF
是在他們的test_off.sh
腳本中測試的方法之一。同時,它是..._OFF
您的 ACPI 程式碼中出現的唯一方法。如果這些不按您的預期工作,您可以嘗試
\_SB.PCI0.PEG0.PEGP._PS3
暫停和\_SB.PCI0.PEG0.PEGP._PS0
恢復。在您的程式碼中,這些方法似乎通過一些額外的測試等呼叫..._OFF
and.._ON
。它們的名稱也暗示了在開機/掛起狀態之間切換的關係。