Jump to content

ACPI patch for brightness keys on Dell laptops


Hervé
 Share

Recommended Posts

  • Administrators

It's still a recurring topic on the fourm, understandably so, so I thought I'd write a little recap about it.

 

Brightness keys patch has been subject to discussion and queries for many years and much has been written on the matter. Among others, Rehabman did some extensive research work on this several years go and provided substantial information and debugging material to work out fixes.

 

The brightness keys patch for many -if not most- Dell laptops since, at least, Ivy Bridge generations can be applied through DSDT patching or through pure SSDT patching.

A DSDT patch for E6230 was 1st mentioned at OSXL by @jpz4085 in our old Dr Hurt's VoodooPS2Controller kext thread; the work derived from Rehabman's research and publications. I found that the patch was fully reusable on other models of the E Series and I fully detailed the DSDT patch code in my E6230, E7250 or 7490 guides.

Unless I'm mistaken (happy to be corrected if required), the SSDT patch was derived from the DSDT patch by @Jake Lo and provided in various threads of his that I can't specifically remember.

 

To successfully apply the required SSDT patch, given that a little tuning may be required depending on the target platform, it's most useful to understand that brightness keys of Dell laptops usually operate at ACPI level and according to the following reversed engineered process:

  1. brightness keys operation is handled through BRT6 method.
  2. BRT6 method is attached to IGPU device but there can be a 2nd BRT6 method under GFX0 (or whatever other name) if the laptop is fitted with a dGPU too.
  3. BRT6 is usually called from EV5 method.
  4. EV5 method is usually called from SMEE method on the condition that a call to OSID method returns a value greater or equal to 32 (0x20).
  5. OSID method returns the value set in ACOS parameter (integer).
  6. ACOS is set to different values according to the nature of the Operating System. It is set to 32 (0x20) for Win Vista, 64 (0x40) for Linux or 128 (0x80) for Win7/8/8.1. Value is under 32 for Windows versions older than Vista.
  7. I'll pass on the upstream process _Q66->NEVT->SMIE->SMEE which is of no specific interest in the context of this brightness keys patch description.

 

Sample methods grabbed from Latitude E7270's extracted DSDT:

BRT6 Method

        Method (BRT6, 2, NotSerialized)
        {
            If (LEqual (Arg0, One))    // 1st arg=1 for brightness increase
            {
                Notify (LCD, 0x86)
            }
            If (And (Arg0, 0x02))      // 1st arg=2 for brigthness decrease
            {
                Notify (LCD, 0x87)
            }
        }

 

EV5 method

    Method (EV5, 2, NotSerialized)
    {
        \_SB.PCI0.IGPU.BRT6 (Arg0, Arg1)     // Call to BRT6 with 2 arguments
    }

 

SME method

    Method (SMEE, 1, NotSerialized)
    {
        Store (Arg0, Local0)
        Store (GENS (0x11, Zero, Zero), Local0)
        If (LGreaterEqual (\_SB.OSID (), 0x20))     // If OSID returns a value >= 32
        {
            If (And (Local0, 0x04))
            {
                EV5 (One, Zero)                     // Call to EV5 with 1st arg set to 1
            }
            If (And (Local0, 0x02))
            {
                EV5 (0x02, Zero)                    // Call to EV5 with 1st arg set to 2
            }
        }
        If (And (Local0, 0x08))
        {
            Store (GENS (0x1D, Zero, Zero), Local0)
            EV17 (Local0, Zero)
        }
    }

 

OSID method

        Method (OSID, 0, NotSerialized)
        {
            If (LEqual (ACOS, Zero))               // Check if ACOS lower or equal to 0
            {
                Store (One, ACOS)                  // Initialises ACOS to 1
                Store (Zero, ACSE)
                If (CondRefOf (\_OSI, Local0))     // Engages in tests according to OS identification
                {
                    If (_OSI (WXP))
                    {
                        Store (0x10, ACOS)         // Sets ACOS to 16 if Win XP
                    }
                    If (_OSI (WLG))
                    {
                        Store (0x20, ACOS)         // Sets ACOS to 32 if Win Vista
                    }
                    If (_OSI (WIN7))
                    {
                        Store (0x80, ACOS)         // Sets ACOS to 128 if Win7
                    }
                    If (_OSI (WIN8))
                    {
                        Store (0x80, ACOS)         // Sets ACOS to 128 if Win8
                        Store (One, ACSE)
                    }
                    If (_OSI (WN81))
                    {
                        Store (0x80, ACOS)         // Sets ACOS to 128 if Win8.1
                        Store (0x02, ACSE)
                    }
                    If (_OSI (LINX))
                    {
                        Store (0x40, ACOS)         // Sets ACOS to 64 if Linux
                    }
                }
                Else
                {
                    If (STRE (_OS, W98S))
                    {
                        Store (0x02, ACOS)         // Sets ACOS to 2 if Win98
                    }
                    If (STRE (_OS, WINM))
                    {
                        Store (0x04, ACOS)         // Sets ACOS to 4 if Win ME
                    }
                    If (STRE (_OS, NT5S))
                    {
                        Store (0x08, ACOS)         // Sets ACOS to 8 if Win NT
                    }
                }
            }
            Return (ACOS)                          // Value returned by OSID method
        }

 

 

:excl: It should also be noted that, brightness keys patching only appears to work with VoodooPS2Controller kext, not with ApplePS2Controller (at least for me and the platforms I tested). :excl:

 

To enable brightness control through the brightness keys of Dell laptops, 2 x things must be done:

  1. ensure that OSID returns a value greater or equal to 32 (0x20) for "Darwin" OS (i.e. OS X/macOS)
  2. ensure the correct key stroke codes are captured in BRT6 method (by default, BRT6 usually only operates for key stroke codes 0x86 and 0x87)

 

1) DSDT patch method:

This is most probably the simplest of the 2 x methods because it involves very basic and very easy patching of the DSDT:

  • 1st part of the patch is to insert a reference to Darwin OS as one of the tests used to set ACOS parameter to, at least, 32 (0x20).
  • 2nd part of the patch is to insert the relevant key stroke codes in BRT6 method as keyboard event notifications. One code for brightness increase and another one for brightness decrease. Rehabman's ACPI debugging tools have allowed to identify various key codes, depending on laptops:
    • brightness increase: key codes 0x10, 0x206, 0x286, 0x366, 0x0406
    • brightness decrease: key codes 0x20, 0x205, 0x285, 0x365, 0x0405
  • I have found that key codes 0x0365 and 0x0366 applied to the Latitude E6x20, E6x30, E6x40, E7x50, E7x70 or other 7x90. @Jake Lo found that codes 0x0405 and 0x0406 applied to other models such as the Precision 5510 or 7510.

 

The DSDT patch can then be applied in the line of the following code:

  • OSID method

Before:

        Method (OSID, 0, NotSerialized)
        {
            If (LEqual (ACOS, Zero))
            {
                [...]

                If (CondRefOf (\_OSI, Local0))
                {
                    [...]
                    If (_OSI (WIN7))
                    {
                        Store (0x80, ACOS)
                    }
                    [...]
                }
                [...]
            }
            Return (ACOS)
        }

After:

        Method (OSID, 0, NotSerialized)
        {
            If (LEqual (ACOS, Zero))
            {
                [...]
                If (CondRefOf (\_OSI, Local0))
                {
                    [...]
                    If (LOr (_OSI ("Darwin"), _OSI (WIN7)))     // Changes test from Win7-only to Darwin or Win7
                    {
                        Store (0x80, ACOS)                      // Thereby setting ACOS to 128 for Darwin, i.e. OS X/macOS
                    }
                    [...]
                }
                [...]
            }
            Return (ACOS)
        }

 

  • BRT6 method

Before:

        Method (BRT6, 2, NotSerialized)
        {
            If (LEqual (Arg0, One))
            {
                Notify (LCD, 0x86)
            }
            If (And (Arg0, 0x02))
            {
                Notify (LCD, 0x87)
            }
        }

After:

        Method (BRT6, 2, NotSerialized)
        {
            If (LEqual (Arg0, One))
            {
                Notify (LCD, 0x86)
                Notify (^^LPCB.PS2K, 0x0366)     // Add capture of brightness-up key stroke
            }
            If (And (Arg0, 0x02))
            {
                Notify (LCD, 0x87)
                Notify (^^LPCB.PS2K, 0x0365)     // Add capture of brightness-down key stroke
            }
        }

and that's it!

 

 

2) SSDT patch method:

Over the last few years, DSDT patching has gradually and increasingly become less fashionable within the Hackintosh community in favour of alternatives in the form of dedicated and specific SSDTs, something which is considered far more efficient because:

  1. it's based on on-the-fly ACPI objects renaming in bootloaders.
  2. it's based on injection of new ACPI code through small and targeted SSDT tables that are meant for that very supplemental purpose (SSDT means Secondary System Description Table).
  3. it avoids extracting, fixing, patching, recompiling and replacing the system's original ACPI tables and most notably the DSDT, something that can be quite arduous at times.

However, the process involved is a much more complicated because:

  • it requires to have a minimum and non-negligeable skillset in ACPI coding.
  • it requires to analyse the code of the original ACPI tables and often work out sections of code to bypass/replace (no duplicates allowed or code is useless)

 

So, given that this method makes no change to the DSDT, it must:

  1. bypass the DSDT's BRT6 method.
  2. replace it by a new method that will include the desired keyboard notification codes; this will be done in a dedicated SSDT that can be called SSDT-BRT6.
  3. with regards to OSID and the requirement to make it return a value greater or equal to 32, there are 2 x possibilities that can be considered:
    1. as per BRT6, bypass the DSDT's OSID method and replace it by a new method that will set ACOS parameter according to "Darwin" OS
    2. replace calls to the _OSI method, that performs tests on the type of OS, by an alternative method that simulates Windows for Darwin. This allows to have the contents of the OSID method executed sequentially and set ACOS according to the last test in the list; as it stands, this happens to be the test on Linux which sets ACOS to 64, i.e. a value greater than 32 which is the minimum required. 

In order to replace the DSDT's BRT6 method by an alternative one, particular caution must be exercised because only the method must be replaced, not the call to it from EV5; so a little creativity is required here... To achieve this, ACPI renaming can be applied in the boot loader config to replace "BRT6,2" (as per contents of the method's definition) by "BRTX,2" rather than replace just "BRT6". ;)

This is achieved by configuring the following on-the-fly DSDT patch in the boot loader's config (the exact Hexadecimal string is found by opening the extracted DSDT in a Hex editor):

Find (HEX):    4252543602     // Hexadecimal sequence for "BRT6, 2" when opening DSDT with a Hex editor
Replace (HEX): 4252545802     // Hexadecimal sequence for "BRTX, 2" as replacement

 

The replacement BRT6 method can then be defined in the dedicated SSDT-BRT6 patched table with the following code:

DefinitionBlock ("", "SSDT", 2, "hack", "BRT6", 0x00000000)
{
    External (_SB_.PCI0.IGPU, DeviceObj)    // (from opcode)
    External (_SB_.PCI0.IGPU.LCD_, DeviceObj)    // (from opcode)
    External (_SB_.PCI0.LPCB.PS2K, DeviceObj)    // (from opcode)
    Scope (_SB.PCI0.IGPU)
    {
        Method (BRT6, 2, NotSerialized)
        {
            If (LEqual (Arg0, One))
            {
                Notify (LCD, 0x86)
                Notify (^^LPCB.PS2K, 0x0366)     // Capture of brightness-up key stroke
            }
            If (And (Arg0, 0x02))
            {
                Notify (LCD, 0x87)
                Notify (^^LPCB.PS2K, 0x0365)     // Capture of brightness-down key stroke
            }
        }
    }
}

 

As far as the OSID method is concerned, the trick is simply to rename it to XSID, rename _OSI method to XOSI and inject (Rehabman's ?) pre-existing and publicly available SSDT-XOSI that simulates Win7 or greater for Darwin (it basically returns true to the OS tests). This is achieved by configuring the following on-the-fly DSDT patches in the boot loader's config:

Find (HEX):    4F534944     // OSID in Hexadecimal
Replace (HEX): 58534944     // XSID in Hexadecimal

Find (HEX):    5F4F5349     // _OSI in Hexadecimal
Replace (HEX): 584F5349     // XOSI in Hexadecimal

 

Contents of the SSDT-XOSI patched table is as per documented by Rehabman:

DefinitionBlock ("", "SSDT", 2, "hack", "XOSI", 0x00000000)
{
    Method (XOSI, 1, NotSerialized)
    {
        Store (Package (0x0A)
            {
                "Windows", 
                "Windows 2001", 
                "Windows 2001 SP2", 
                "Windows 2006", 
                "Windows 2006 SP1", 
                "Windows 2006.1", 
                "Windows 2009", 
                "Windows 2012", 
                "Windows 2013", 
                "Windows 2015"
            }, Local0)
        Return (LNotEqual (Ones, Match (Local0, MEQ, Arg0, MTR, Zero, Zero)))
    }
}

 

And that's it too! ^_^

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...