我试图从带有 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
http://github.com/mkottman/acpi_call
http://github.com/awilliam/asus-switcheroo
答案1
分析您发布的代码和代码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
和 以及.._ON
一些附加测试等。它们的名称还暗示了与开机/挂起状态之间切换的关系。
答案2
不建议直接调用_ON
。_OFF
我分析了许多 ACPI 表中“正确”的 ACPI 方法,这些方法允许您切换电源状态,并得出结论,有两种通用方法可以禁用 Nvidia 卡。
根据 Launchpad 上的 SSDT4 文件,您的笔记本电脑似乎支持这两种方法。acpi_call
不建议使用执行 ACPI 方法调用来切换电源,因为它会因挂起而中断。你应该使用bbswitch
相反,一种方法做正确处理暂停/恢复电源的切换。 (披露:我是它的作者)
有关更多技术细节,请参阅http://wiki.bumblebee-project.org/ACPI-for-Developers。我已经对 acpi_call、bbswitch 和 vgaswitcheroo 进行了比较http://wiki.bumblebee-project.org/Comparison-of-PM-methods。