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
다음 과 같이 안전하게 테스트할 수 있습니다 acpi_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.