破译 Nvidia Optimus 的 Acer Aspire 4830TG ACPI 代码

破译 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

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

再次打开它。

应该可以安全地测试这些,如READMEforacpi_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

相关内容