Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am trying to make sense of the following NVOP Method from the ACPI tables for an Acer Aspire 4830TG with an Nvidia Optimus hybrid graphics system. The NVOP method on top defines a bunch of instructions that can be used later on in the _DSM method. Which method should I call with the acpi_call module or the byo-switcheroo module to switch on/off the card on demand?

See the code below:

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)
}

The original ACPI tables are available here:
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

share|improve this question

2 Answers 2

up vote 4 down vote accepted
+200

Analyzing the code you posted as well ass acpi_call leads me to the the conclusion that most probable candidates should be:

echo '\_SB.PCI0.PEG0.PEGP._OFF' > /proc/acpi/call

to turn the card off and

echo '\_SB.PCI0.PEG0.PEGP._ON' > /proc/acpi/call

to turn it back on again.

You should be safe to test those, as the README for acpi_call states:

It SHOULD be ok to test all of the methods

And \_SB.PCI0.PEG0.PEGP._OFF is one of the methods tested in their test_off.sh script. At the same time, it is the only ..._OFF method appearing in your ACPI code.

If those do not work as you'd expect, you might try instead \_SB.PCI0.PEG0.PEGP._PS3 for suspending and \_SB.PCI0.PEG0.PEGP._PS0 for resuming. In your code, these methods seem to call the ..._OFF and .._ON with some additional tests etc. Their names also suggest relation to switching between power on/suspend states.

share|improve this answer
    
@avilella Well, have you tried it? Or is it not the type of answer you were looking for? –  rozcietrzewiacz Aug 5 '11 at 7:33
1  
so would it be ok to call _PS3 and _PS0 even if one only wants to switch the card on/off? –  130490868091234 Aug 5 '11 at 8:13
    
Well, I can't guarantee you that - but from what I understand how ACPI works, if it doesn't, then in the worst case you'd have to shutdown and restart your computer. So I'd just try. Only the manufacturers can really know, what exactly each function does. What you must hold on to is their naming schemes - and intuition :) –  rozcietrzewiacz Aug 5 '11 at 8:22
1  
But for sure, I'd first try the \_SB.PCI0.PEG0.PEGP._OFF, since it is one of the default method names known to acpi_call. –  rozcietrzewiacz Aug 5 '11 at 8:23

Directly calling _ON and _OFF is not recommended. I have analysed many ACPI tables for the "correct" ACPI methods that allow you to toggle the power state and have concluded that there are two generic methods that do disable the Nvidia card.

Your laptop seems to support both methods according to SSDT4 file on Launchpad. Performing ACPI method calls using acpi_call is not the recommended way to toggle power as it breaks with suspend. You should use bbswitch instead, a method that does properly handle toggling the power on suspend / resume. (disclosure: I am the author of it)

For more technical details, see http://wiki.bumblebee-project.org/ACPI-for-Developers. I have done a comparison between acpi_call, bbswitch and vgaswitcheroo on http://wiki.bumblebee-project.org/Comparison-of-PM-methods.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.