Contribute
Register

USB 3.0 DSDT mods

Status
Not open for further replies.
Joined
Jan 18, 2013
Messages
271
Motherboard
Mac mini
CPU
i[5/7]
Graphics
HD[3/4]000
Mac
  1. 0
Classic Mac
  1. 0
Mobile Phone
  1. 0
Part I

I want to share something with you. I've seen people copying lines from Apple ACPI tables into their own tables. Probably without even knowing what it does, and in some cases it is pointless. Have a look at this code snippet:
Code:
[FONT=Menlo]
[/FONT]​[FONT=Menlo]Alias (SBV1, SDGV)
[/FONT][FONT=Menlo]Method (_DSM, 4, Serialized)[/FONT]
[FONT=Menlo]{[/FONT]
[FONT=Menlo]    If (LEqual (Arg0, Buffer (0x10)[/FONT]
[FONT=Menlo]        {[/FONT]
[FONT=Menlo]            /* 0000 */ 0x8F, 0x70, 0xFC, 0xA5, 0x75, 0x87, 0xA6, 0x4B, [/FONT]
[FONT=Menlo]            /* 0008 */ 0xBD, 0x0C, 0xBA, 0x90, 0xA1, 0xEC, 0x72, 0xF8[/FONT]
[FONT=Menlo]        }))[/FONT]
[FONT=Menlo]    {[/FONT]
[FONT=Menlo]        Name (_T_0, Zero)[/FONT]
[FONT=Menlo]        Store (ToInteger (Arg2), _T_0)[/FONT]
[FONT=Menlo]        If (LEqual (_T_0, Zero))[/FONT]
[FONT=Menlo]        {[/FONT]
[FONT=Menlo]            If (LEqual (Arg1, One))[/FONT]
[FONT=Menlo]            {[/FONT]
[FONT=Menlo]                Return (Buffer (One)[/FONT]
[FONT=Menlo]                {[/FONT]
[FONT=Menlo]                    0x07[/FONT]
[FONT=Menlo]                })[/FONT]
[FONT=Menlo]            }[/FONT]
[FONT=Menlo]            Else[/FONT]
[FONT=Menlo]            {[/FONT]
[FONT=Menlo]                Return (Buffer (One)[/FONT]
[FONT=Menlo]                {[/FONT]
[FONT=Menlo]                    0x00[/FONT]
[FONT=Menlo]                })[/FONT]
[FONT=Menlo]            }[/FONT]
[FONT=Menlo]        }[/FONT]
[FONT=Menlo]        Else[/FONT]
[FONT=Menlo]        {[/FONT]
[FONT=Menlo]            If (LEqual (_T_0, One))[/FONT]
[FONT=Menlo]            {[/FONT]
[FONT=Menlo]                If (LEqual (SDGV, 0xFF))[/FONT]
[FONT=Menlo]                {[/FONT]
[FONT=Menlo]                    Return (Zero)[/FONT]
[FONT=Menlo]                }[/FONT]
[FONT=Menlo]                Else[/FONT]
[FONT=Menlo]                {[/FONT]
[FONT=Menlo]                    Return (One)[/FONT]
[FONT=Menlo]                }[/FONT]
[FONT=Menlo]            }[/FONT]
[FONT=Menlo]            Else[/FONT]
[FONT=Menlo]            {[/FONT]
[FONT=Menlo]                If (LEqual (_T_0, 0x02))[/FONT]
[FONT=Menlo]                {[/FONT]
[FONT=Menlo]                    Return (SDGV)[/FONT]
[FONT=Menlo]                }[/FONT]
[FONT=Menlo]            }[/FONT]
[FONT=Menlo]        }[/FONT]
[FONT=Menlo]    }[/FONT]
[FONT=Menlo]
[/FONT]
[FONT=Menlo]    Return (Zero)[/FONT]
[FONT=Menlo]}[/FONT]
You may find one or more of them in your EHCn methods, but again. Having them is pointless, because Arg0 isn't matching with the given UUID (in the buffer) on OS X. In short. This whole stupid block can be removed.

I also see people using stuff like this:
Code:
[FONT=Menlo]Method (_PRW, 0, NotSerialized)[/FONT]
[FONT=Menlo]{[/FONT]
[FONT=Menlo]    If (OSDW)[/FONT]
[FONT=Menlo]    {[/FONT]
[FONT=Menlo]        Return (Package (0x02)[/FONT]
[FONT=Menlo]        {[/FONT]
[FONT=Menlo]            0x0D, [/FONT]
[FONT=Menlo]            0x04[/FONT]
[FONT=Menlo]        })[/FONT]
[FONT=Menlo]    }[/FONT]
[FONT=Menlo]    Else[/FONT]
[FONT=Menlo]    {[/FONT]
[FONT=Menlo]        Return (Package (0x02)[/FONT]
[FONT=Menlo]        {[/FONT]
[FONT=Menlo]            0x0D, [/FONT]
[FONT=Menlo]            0x03[/FONT]
[FONT=Menlo]        })[/FONT]
[FONT=Menlo]    }[/FONT]
[FONT=Menlo]}[/FONT]
Why? Why check OSDW when you are in fact running OS X and your DSDT/SSDT will only be used for OS X? I don't get it. To me that is pointless. All you need is this one-liner:
Code:
[FONT=Menlo]Name (_PRW, Package (0x02) { 0x0D, 0x04 })[/FONT]
Much cleaner without all clutter. Don't you agree? In short. Do not check for something that you already know. Let's have a look at another great example.
Code:
[FONT=Menlo]Method (DTGP, 5, NotSerialized)
{
    If (LEqual (Arg0, Buffer (0x10)
        {
            /* 0000 */ 0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44, 
            /* 0008 */ 0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B
        }))
    {
        If (LEqual (Arg1, One))
        {
            If (LEqual (Arg2, Zero))
            {
                Store (Buffer (0x01)
                {
                    0x03
                }, Arg4)
                Return (One)
            }

            If (LEqual (Arg2, One))
            {
                Return (One)
            }
        }
    }

    Store (Buffer (0x01)
    {
        0x00
    }, Arg4)


    Return (Zero)
}
[/FONT]
Ah yes. You need to have this method. Right? Nope. You don't. Not to mention that this method will check all sixteen bytes of the UUID (in the buffer) twice. Which of course slows down the startup process.

Let's stop this madness. Stop living in the 90's. Use something like this when you need to set device properties from ACPI tables:
Code:
Device (EHCn)
{
    Name (AAPL, Package (0x0B)
    {
        "AAPL,current-available",
        0x0834, 
        "AAPL,current-extra", 
        0x0898, 
        "AAPL,current-extra-in-sleep", 
        0x0640, 
        "AAPL,max-port-current-in-sleep", 
        0x0834, 
        "AAPL,device-internal", 
        0x02, 
        Buffer (One) { 0x00 }
    })

    Method (_DSM, 4, NotSerialized)
    {
        If (LEqual (Arg2, Zero))
        {
            Return (Buffer (One) { 0x03 })
        }

        Return (RefOf (AAPL))
    }
Another example of clutter free/faster ACPI code.

Don't forget this important rule folks. We're not Apple. They want to support Window, Linux and OS X. We don't. Or at least I don't ;)

Oh yes. There is a lot more that we can change, but not today. Taking things one step at a time.
 
Let's stop this madness. Stop living in the 90's. Use something like this when you need to set device properties from ACPI tables:
Code:
Device (EHCn)
{
    Name (AAPL, Package (0x0B)
    {
        "AAPL,current-available",
        0x0834, 
        "AAPL,current-extra", 
        0x0898, 
        "AAPL,current-extra-in-sleep", 
        0x0640, 
        "AAPL,max-port-current-in-sleep", 
        0x0834, 
        "AAPL,device-internal", 
        0x02, 
        Buffer (One) { 0x00 }
    })

    Method (_DSM, 4, NotSerialized)
    {
        If (LEqual (Arg2, Zero))
        {
            Return (Buffer (One) { 0x03 })
        }

        Return (RefOf (AAPL))
    }

Thanks Pike for posting this. I've been wondering about these kind of issues for a while. Couple of questions specifically related to DTGP method though:

- So what you're saying is that Arg0 (evidently a UUID) *always* matches the Buffer being tested (on OS X).
- Arg1 is always One
- Arg2 is always Zero or One (never anything else, which would be the Store (Buffer() { 0 }, Arg4) case)
- I'm not so sure of the RefOf(AAPL) part. I tried this the other day and it didn't work. I had to do the Store (..., Local0), Return (Local0). Maybe I was doing something wrong (will retry).

And how did you determine what code path is being taken on OS X. Is there a way to get Store ("xxx" , Debug) to show in Console?
 
BTW, I do find that I can write these methods even simpler...

Not USB3 related (sorry), but same concept:

Code:
        Method(_DSM, 4, NotSerialized)
        {
            If (LEqual (Arg2, Zero)) { Return (Buffer() { 0x03 } ) }
            Return (Package()
            {
                "AAPL00,DualLink", 
                Buffer() { 0x01, 0x00, 0x00, 0x00 },
                "AAPL,snb-platform-id",
                Buffer() { 0x00, 0x00, 0x01, 0x00 }
            })
        }
 
Thanks Pike for posting this. I've been wondering about these kind of issues for a while. Couple of questions specifically related to DTGP method though:

- So what you're saying is that Arg0 (evidently a UUID) *always* matches the Buffer being tested (on OS X).
Yes.

- Arg1 is always One
Yes, version number is always One. For now. This may change in a future OS upgrade, but we won't have to deal with it, though people who use DTGP method will.

- Arg2 is always Zero or One (never anything else, which would be the Store (Buffer() { 0 }, Arg4) case)
Arg2 represents function numbers (bit wise) and Zero (bit 0) is the query action when the method is loaded (at startup) to gather the supported function numbers. We return 0x03 (bit 0 and 1) here, and thus Zero and One are supported. Anything else is illegal/unsupported.

Returning 0x07 (setting bit 2) instead of 0x03 would add function 0x02 to the supported functions, meaning that
Code:
[FONT=Menlo]If (LEqual (Arg2, 0x02))[/FONT]
can be used.

- I'm not so sure of the RefOf(AAPL) part. I tried this the other day and it didn't work. I had to do the Store (..., Local0), Return (Local0). Maybe I was doing something wrong (will retry).
RefOf(Obj) returns a reference – 32/64 bit pointer – to any given object, which is a lot less expensive to pass on to other methods.

Also. You may want to change the 0x02 into Zero for device XHC1, without duplicating the data for three devices. This is where a next method will come in handy. I'll add that with my next update. This should also tell you why I didn't inject the data from the _DSM method directly.

And how did you determine what code path is being taken on OS X. Is there a way to get Store ("xxx" , Debug) to show in Console?[/QUOTE]
I use AcpiExec from https://www.acpica.org/overview.php but in this specific case (DTGP) it was actually my father who figured it all out back in the day (Google Master Chief P5K PRO). The rest is common sense.
 
Part II

Let's look at a few more examples. Look at this code snippet:
Code:
Method (_S3D, 0, NotSerialized)
{
    Return (0x03)
}


Method (_S4D, 0, NotSerialized)
{
    Return (0x03)
}
Which I always change into this:
Code:
Name (_S3D, 0x03)
Name (_S4D, 0x03)
Simply because we can. Here's another one:
Code:
Method (_PRW, 0, NotSerialized)
{
    If (OSDW)
    {
        Return (Package (0x02)
        {
            0x0D, 
            0x04
        })
    }
    Else
    {
        Return (Package (0x02)
        {
            0x0D, 
            0x03
        })
    }
}
Another one liner:
Code:
Name (_PRW, Package (0x02) { 0x0D, 0x04 })
Now. The general consensus is that as long as you don't have to compute any code in a Method, then you can replace it with Name() as both are named objects in the same ACPI namespace, and behave exactly the same. Again. When nothing is computed.


In other words, this:
Code:
Method (MBSD, 0, NotSerialized)
{
    Return (0x01)
}
Can be changed into:
Code:
Name (MBSD, One)
And this:
Code:
Method (XHCN, 0, NotSerialized)
{
    Return (0x01)
}
Can be changed into:
Code:
Name (XHCN, One)
However. Something like this not:
Code:
Method (BTRS, 0, Serialized)
{
    Store (0x00, GP54)
    Store (0x00, GD54)
    Sleep (0x10)
    Store (0x01, GD54)
    Sleep (0x04)
}
Because it executes (computes) code.

Now back to another example of useless OSDW checking.
Code:
Method (XHCA, 0, NotSerialized)
{
    If (LNot (OSDW))
    {
        Store (0x01, \_SB.PCI0.XHC1.PASS)
    }


    Store (0x01, \_SB.PCI0.XHC1.PAHC)
}
Simply change this into:
Code:
Method (XHCA, 0, NotSerialized)
{
    Store (0x01, \_SB.PCI0.XHC1.PAHC)
}
Repeat this for every Method. This way you reduce the code size, and speedup the startup process.
 
Yes, version number is always One. For now. This may change in a future OS upgrade, but we won't have to deal with it, though people who use DTGP method will.

Got it. Arg1 is version number. Awesome to know.

Arg2 represents function numbers (bit wise) and Zero (bit 0) is the query action when the method is loaded (at startup) to gather the supported function numbers. We return 0x03 (bit 0 and 1) here, and thus Zero and One are supported. Anything else is illegal/unsupported.

Got it. Arg2 == 0 is query for supported functions as bitmask [as buffer of bits] (a little weird that the query itself has representation as bit0, but ok). So Store (Buffer() { 0 }, Arg4) response is an error response, saying "I told you I only support function 0 and 1, and you gave me something else").

RefOf(Obj) returns a reference – 32/64 bit pointer – to any given object, which is a lot less expensive to pass on to other methods.

I understand what RefOf does. The question is whether the calling code expects to dereference the result. As it turns out, it does not. I use the following "mini SSDT" to boot my Unibeast USB installer on my dual-link display laptop:

Code:
DefinitionBlock("ssdt.aml", "SSDT", 2, "HPQOEM", "general", 0x00001000)
{
    External(_SB.PCI0.GFX0, DeviceObj)
    
    Scope(_SB.PCI0.GFX0)
    {
        Method(_DSM, 4, NotSerialized)
        {
            If (LEqual (Arg2, Zero)) { Return (Buffer() { 0x03 } ) }
            Name(AAPL, Package()
            {
                "AAPL00,DualLink", 
                Buffer() { 0x01, 0x00, 0x00, 0x00 },
                "AAPL,snb-platform-id",
                Buffer() { 0x00, 0x00, 0x01, 0x00 }
            })
            Return (AAPL)
        }
    }
}

It works as written above... (simplified thanks to the discussion here)

Changing the 'return' to the following causes it to break:
Code:
            Return (RefOf(AAPL))

I don't think the caller is expecting to dereference the result, so that particular 'optimization' is certainly not universal.

RehabMan said:
And how did you determine what code path is being taken on OS X. Is there a way to get Store ("xxx" , Debug) to show in Console?
I use AcpiExec from...

So, no way to get AppleACPIPlatform.kext to show stores to Debug object?
I was thinking of writing a kext that would interact with a debug facility that could easily be injected into DSDT just for the purpose of tracking code path in DSDT. DSDT code would store debug output in a ring buffer, and kext would poll specific DSDT methods to pull data out of ring buffer if available and write it via IOLog. I guess the idea still has some merit.

What good would the standalone ACPI interpreter provided by Intel do in this case, when we are interested in how Apple's drivers/OS are calling into DSDT code? Maybe I'm missing something...
 
I updated a lot of my patch code with your suggestions, thanks.

Following your advice about OSDW not being needed how would you change the following code.

Code:
Method (_OSC, 4, Serialized)
{
    Store (Arg3, Local0)
    CreateDWordField (Local0, Zero, CDW1)
    CreateDWordField (Local0, 0x04, CDW2)
    CreateDWordField (Local0, 0x08, CDW3)
    Store (CDW2, SUPP)
    Store (CDW3, CTRL)

    If (LEqual (One, OSDW ())) {
        If (LAnd (LEqual (Arg0, GUID), NEXP)) {
            If (Not (And (CDW1, One))) {
                If (And (CTRL, 0x02)) {
                    NHPG ()
                }

                If (And (CTRL, 0x04)) {
                    NPME ()
                }
            }

            If (LNotEqual (Arg1, One)) {
                Or (CDW1, 0x08, CDW1)
            }

            If (LNotEqual (CDW3, CTRL)) {
                Or (CDW1, 0x10, CDW1)
            }

            Store (CTRL, CDW3)
            Store (CTRL, OSCC)
            Return (Local0)
        }
        Else {
            Or (CDW1, 0x04, CDW1)
            Return (Local0)
        }
    }
    Else {
        If (LEqual (Arg0, Buffer (0x10)
            {
                0xA9,0x12,0x95,0x7C,0x05,0x17,0xB4,0x4C,
                0xAF,0x7D,0x50,0x6A,0x24,0x23,0xAB,0x71
            }))
        {
            Store (One, ^XHC1.PASS)
            Store (One, ^XHC1.PAHC)
            Store (One, ^XHC1.PBSS)
            Store (One, ^XHC1.PBHC)
            Store (One, ^XHC1.PCSS)
            Store (One, ^XHC1.PCHC)
            Store (One, ^XHC1.PDSS)
            Store (One, ^XHC1.PDHC)
        }
        Return (Local0)
    }
}
 
I updated a lot of my patch code with your suggestions, thanks.

Following your advice about OSDW not being needed how would you change the following code.

Code:
Method (_OSC, 4, Serialized)
{
    Store (Arg3, Local0)
    CreateDWordField (Local0, Zero, CDW1)
    CreateDWordField (Local0, 0x04, CDW2)
    CreateDWordField (Local0, 0x08, CDW3)
    Store (CDW2, SUPP)
    Store (CDW3, CTRL)

    If (LEqual (One, OSDW ())) {
        If (LAnd (LEqual (Arg0, GUID), NEXP)) {
            If (Not (And (CDW1, One))) {
                If (And (CTRL, 0x02)) {
                    NHPG ()
                }

                If (And (CTRL, 0x04)) {
                    NPME ()
                }
            }

            If (LNotEqual (Arg1, One)) {
                Or (CDW1, 0x08, CDW1)
            }

            If (LNotEqual (CDW3, CTRL)) {
                Or (CDW1, 0x10, CDW1)
            }

            Store (CTRL, CDW3)
            Store (CTRL, OSCC)
            Return (Local0)
        }
        Else {
            Or (CDW1, 0x04, CDW1)
            Return (Local0)
        }
    }
    Else {
        If (LEqual (Arg0, Buffer (0x10)
            {
                0xA9,0x12,0x95,0x7C,0x05,0x17,0xB4,0x4C,
                0xAF,0x7D,0x50,0x6A,0x24,0x23,0xAB,0x71
            }))
        {
            Store (One, ^XHC1.PASS)
            Store (One, ^XHC1.PAHC)
            Store (One, ^XHC1.PBSS)
            Store (One, ^XHC1.PBHC)
            Store (One, ^XHC1.PCSS)
            Store (One, ^XHC1.PCHC)
            Store (One, ^XHC1.PDSS)
            Store (One, ^XHC1.PDHC)
        }
        Return (Local0)
    }
}

Typically, OSDW returns 1 when it is Darwin. So the else case is for some other OS we are not interested in.

So, it becomes:
Code:
Method (_OSC, 4, Serialized)
{
    Store (Arg3, Local0)
    CreateDWordField (Local0, Zero, CDW1)
    CreateDWordField (Local0, 0x04, CDW2)
    CreateDWordField (Local0, 0x08, CDW3)
    Store (CDW2, SUPP)
    Store (CDW3, CTRL)

        If (LAnd (LEqual (Arg0, GUID), NEXP)) {
            If (Not (And (CDW1, One))) {
                If (And (CTRL, 0x02)) {
                    NHPG ()
                }

                If (And (CTRL, 0x04)) {
                    NPME ()
                }
            }

            If (LNotEqual (Arg1, One)) {
                Or (CDW1, 0x08, CDW1)
            }

            If (LNotEqual (CDW3, CTRL)) {
                Or (CDW1, 0x10, CDW1)
            }

            Store (CTRL, CDW3)
            Store (CTRL, OSCC)
            Return (Local0)
        }
        Else {
            Or (CDW1, 0x04, CDW1)
            Return (Local0)
        }
}

Note: I didn't bother fixing the indenting...
 
Part I

Let's stop this madness. Stop living in the 90's. Use something like this when you need to set device properties from ACPI tables:
Code:
Device (EHCn)
{
    Name (AAPL, Package (0x0B)
    {
        "AAPL,current-available",
        0x0834, 
        "AAPL,current-extra", 
        0x0898, 
        "AAPL,current-extra-in-sleep", 
        0x0640, 
        "AAPL,max-port-current-in-sleep", 
        0x0834, 
        "AAPL,device-internal", 
        0x02, 
        Buffer (One) { 0x00 }
    })

    Method (_DSM, 4, NotSerialized)
    {
        If (LEqual (Arg2, Zero))
        {
            Return (Buffer (One) { 0x03 })
        }

        Return (RefOf (AAPL))
    }


Oh yes. There is a lot more that we can change, but not today. Taking things one step at a time.[/QUOTE]

Sorry but this method does not working for me. I use 10.9 and with this code I can not charge the iPad, only with DTGP method.
Maybe I need change something else, but I do not know.

Thanks
 
Sorry but this method does not working for me. I use 10.9 and with this code I can not charge the iPad, only with DTGP method.
Maybe I need change something else, but I do not know.

Thanks

Read the entire thread. The use of RefOf(AAPL) is not valid.
 
Status
Not open for further replies.
Back
Top