Linux

為 Nvidia Optimus 破譯此 Acer Aspire 4830TG ACPI 程式碼

  • November 16, 2018

我試圖從具有 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

分析您發布的程式碼以及 assacpi_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恢復。在您的程式碼中,這些方法似乎通過一些額外的測試等呼叫..._OFFand .._ON。它們的名稱也暗示了在開機/掛起狀態之間切換的關係。

引用自:https://unix.stackexchange.com/questions/17457