Re: acer-wmi: Nitro button doesn't produce a WMI event

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 24.12.24 um 19:45 schrieb Hridesh MG:

Am 24.12.24 um 00:06 schrieb Armin Wolf:
This WMI call is already supported by the driver and exposed to userspace using the platform profile interface.
It seems however that your device:

- does only support the turbo profile and not the other OC settings

- only supports a subset of the platform profile choices

- uses a different EC address for storing the current platform profile

Can you test kernel patches? I can prepare a patch for you which:

- puts your device on the necessary whitelists

- fixes the platform profile handling

Thanks,
Armin Wolf
Oh I see, thank you for your work! Actually, could I work on the patch
myself? I'd like to take this as an opportunity to learn something
new, I'm also a mentee under the LFX kernel bug fixing mentorship
program and was hoping to create a patch which could count towards my
graduation requirements out of this issue.

I understood the rest, but if it isn't too much of a bother, could you
tell me how you found out the EC address? (or the fact that it was
different)

Thanks,
Hridesh MG

This is the full definition of the Acer gaming WMI interface on your machine:

[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("Class used to Gaming Function, Version 2.88"), guid("{7A4DDFE7-5B5D-40B4-8595-4408E0CC7F56}")]
class AcerGamingFunction {
  [key, read] string InstanceName;
  [read] boolean Active;

  [WmiMethodId(1), Implemented, read, write, Description("Set Acer Gaming Profile Configuration.")] void SetGamingProfile([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(2), Implemented, read, write, Description("Set Acer Gaming LED Behavior.")] void SetGamingLED([in] uint8 gmInput[12], [out] uint32 gmOutput);
  [WmiMethodId(3), Implemented, read, write, Description("Get Acer Gaming Profile Configuration.")] void GetGamingProfile([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(4), Implemented, read, write, Description("Get Acer Gaming LED Behavior.")] void GetGamingLED([in] uint32 gmInput, [out] uint8 gmReturn, [out] uint8 gmOutput[11]);
  [WmiMethodId(5), Implemented, read, write, Description("Get Acer Gaming System Information.")] void GetGamingSysInfo([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(6), Implemented, read, write, Description("Set Acer Gaming RGB Keyboard Setting.")] void SetGamingRgbKb([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(7), Implemented, read, write, Description("Get Acer Gaming RGB Keyboard Setting.")] void GetGamingRgbKb([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(8), Implemented, read, write, Description("Set Acer Gaming Profile Setting.")] void SetGamingProfileSetting([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(9), Implemented, read, write, Description("Get Acer Gaming Profile Setting.")] void GetGamingProfileSetting([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(10), Implemented, read, write, Description("Set Acer Gaming LED Group Behavior.")] void SetGamingLEDBehavior([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(11), Implemented, read, write, Description("Get Acer Gaming LED Group Behavior.")] void GetGamingLEDBehavior([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(12), Implemented, read, write, Description("Set Acer Gaming LED Group Color.")] void SetGamingLEDColor([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(13), Implemented, read, write, Description("Get Acer Gaming LED Group Color.")] void GetGamingLEDColor([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(14), Implemented, read, write, Description("Set Acer Gaming Fan Group Behavior.")] void SetGamingFanBehavior([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(15), Implemented, read, write, Description("Get Acer Gaming Fan Group Behavior.")] void GetGamingFanBehavior([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(16), Implemented, read, write, Description("Set Acer Gaming Fan Group Speed.")] void SetGamingFanSpeed([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(17), Implemented, read, write, Description("Get Acer Gaming Fan Group Speed.")] void GetGamingFanSpeed([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(18), Implemented, read, write, Description("Set Acer Gaming Fan Table.")] void SetGamingFanTable([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(19), Implemented, read, write, Description("Get Acer Gaming Fan Table.")] void GetGamingFanTable([out] uint64 gmOutput);
  [WmiMethodId(20), Implemented, read, write, Description("Set Acer Gaming Keyboard Backlight Behavior.")] void SetGamingKBBacklight([in] uint8 gmInput[16], [out] uint32 gmOutput);
  [WmiMethodId(21), Implemented, read, write, Description("Get Acer Gaming Keyboard Backlight Behavior.")] void GetGamingKBBacklight([in] uint32 gmInput, [out] uint8 gmReturn, [out] uint8 gmOutput[15]);
  [WmiMethodId(22), Implemented, read, write, Description("Set Acer Gaming Miscellaneous Setting.")] void SetGamingMiscSetting([in] uint64 gmInput, [out] uint32 gmOutput);
  [WmiMethodId(23), Implemented, read, write, Description("Get Acer Gaming Miscellaneous Setting.")] void GetGamingMiscSetting([in] uint32 gmInput, [out] uint64 gmOutput);
  [WmiMethodId(24), Implemented, read, write, Description("Set CPU Overclocking Profile.")] void SetCPUOverclockingProfile([in] uint8 OCProfile, [in] uint8 OCStructure[512], [out] uint8 ReturnCode, [out] uint8 Reserved[3]);
  [WmiMethodId(25), Implemented, read, write, Description("Get CPU Overclocking Profile.")] void GetCPUOverclockingProfile([in] uint8 Reserved[4], [out] uint8 ReturnCode, [out] uint8 ReturnOCProfile, [out] uint8 OCStructure[512]);
};

The method "SetGamingMiscSetting"  is used to set the platform profile. For reading however the EC is accessed by the acer-wmi driver.

This is the ACPI code responsible for handling "SetGamingMiscSetting" and "GetGamingMiscSetting" (Arg1 is the WMI method id, Arg2 contains the input arguments):

                If ((Arg1 == 0x16))
                {
                    BHSK = Arg2
                    Local0 = DerefOf (BHSK [Zero])
                    Local1 = DerefOf (BHSK [One])
                    BHSK [Zero] = 0x03
                    If ((Local0 == One))
                    {
                        \_SB.PC00.LPCB.EC0.TKST = Local1
                        BHSK [Zero] = Zero
                    }
                    ElseIf ((Local0 == 0x02))
                    {
                        WSMI (Arg1, Arg2)
                        BHSK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x05)){}
                    ElseIf ((Local0 == 0x06))
                    {
                        WSMI (Arg1, Arg2)
                        BHSK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x07)){}
                    ElseIf ((Local0 == 0x08))
                    {
                        WSMI (Arg1, Arg2)
                        BHSK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x09))
                    {
                        BHSK [Zero] = One
                    }
                    ElseIf ((Local0 == 0x0A))
                    {
                        BHSK [Zero] = 0x03
                    }
                    ElseIf ((Local0 == 0x0B))
                    {

This code in particular is responsible for setting the platform profile. Noticed the OPMS field here which is used to
store the current platform profile set by the driver.

                        \_SB.PC00.LPCB.EC0.OPMS = Local1
                        If ((OG00 == Zero))
                        {
                            If ((\_SB.GGIV (0x090E000A) == Zero))
                            {
                                If ((Local1 == Zero))
                                {
                                    \ODV0 = Zero
                                }
                                ElseIf ((Local1 == One))
                                {
                                    \ODV0 = One
                                }
                                ElseIf ((Local1 == 0x04))
                                {
                                    \ODV0 = 0x02
                                }
                            }
                            ElseIf ((Local1 == Zero))
                            {
                                \ODV0 = 0x03
                            }
                            ElseIf ((Local1 == One))
                            {
                                \ODV0 = 0x04
                            }
                            ElseIf ((Local1 == 0x04))
                            {
                                If (((CMSR (0x77) == 0x05) || (CMSR (0x77) == 0x04)))
                                {
                                    \ODV0 = 0x06
                                }
                                Else
                                {
                                    \ODV0 = 0x05
                                }
                            }
                        }

                        If ((OG00 == One))
                        {
                            If ((\_SB.GGIV (0x090E000A) == Zero))
                            {
                                If ((Local1 == Zero))
                                {
                                    \ODV0 = 0x07
                                }
                                ElseIf ((Local1 == One))
                                {
                                    \ODV0 = 0x08
                                }
                                ElseIf ((Local1 == 0x04))
                                {
                                    \ODV0 = 0x09
                                }
                            }
                            ElseIf ((Local1 == Zero))
                            {
                                \ODV0 = 0x0A
                            }
                            ElseIf ((Local1 == One))
                            {
                                \ODV0 = 0x0B
                            }
                            ElseIf ((Local1 == 0x04))
                            {
                                If (((CMSR (0x77) == 0x05) || (CMSR (0x77) == 0x04)))
                                {
                                    \ODV0 = 0x0D
                                }
                                Else
                                {
                                    \ODV0 = 0x0C
                                }
                            }
                        }

                        \_SB.IETM.ODVP ()
                        Notify (\_SB.IETM, 0x88) // Device-Specific
                        Notify (\_SB.NPCF, 0xC0) // Hardware-Specific
                        Notify (\_SB.NPCF, 0xC1) // Hardware-Specific
                        BHSK [Zero] = Zero
                    }
                    ElseIf ((Local0 == 0x0D))
                    {
                        BHSK [Zero] = 0x03
                    }
                    ElseIf ((Local0 == 0x0E))
                    {
                        BHSK [Zero] = 0x03
                    }
                    ElseIf ((Local0 == 0x0F))
                    {
                        If ((Local1 == One))
                        {
                            BHSK [Zero] = Zero
                            \_SB.PC00.LPCB.EC0.FMKY = One
                        }
                        ElseIf ((Local1 == 0x02))
                        {
                            BHSK [Zero] = Zero
                            \_SB.PC00.LPCB.EC0.FMKY = Zero
                        }
                    }
                    Else
                    {
                        BHSK [Zero] = 0x03
                        BHSK [One] = Zero
                        BHSK [0x02] = Zero
                        BHSK [0x03] = Zero
                    }

                    Return (BHSK) /* \_SB_.PC00.WMID.BHSK */
                }

                If ((Arg1 == 0x17))
                {
                    BHSK = Arg2
                    Local0 = DerefOf (BHSK [Zero])
                    BHGK [Zero] = Zero
                    BHGK [One] = 0xFF
                    If ((Local0 == One))
                    {
                        BHGK [One] = \_SB.PC00.LPCB.EC0.TKST /* External reference */
                        BHGK [Zero] = Zero
                    }
                    ElseIf ((Local0 == 0x02))
                    {
                        WSMI (Arg1, Arg2)
                        BHGK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x05)){}
                    ElseIf ((Local0 == 0x06))
                    {
                        WSMI (Arg1, Arg2)
                        BHGK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x07)){}
                    ElseIf ((Local0 == 0x08))
                    {
                        WSMI (Arg1, Arg2)
                        BHGK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x09))
                    {
                        WSMI (Arg1, Arg2)
                        BHGK = WMIB /* \_SB_.PC00.WMID.WMIB */
                    }
                    ElseIf ((Local0 == 0x0A))
                    {
                        BHGK [Zero] = Zero
                        BHGK [One] = 0x13

Side note: this field seems to contain a bitmap of the supported platform profiles on this machine.

                    }
                    ElseIf ((Local0 == 0x0B))
                    {

Calling this method ("GetGamingMiscSetting") with the same command (0x0B) would return the current platform
profile by using the OPMS field.

                        BHGK [Zero] = Zero
                        BHGK [One] = \_SB.PC00.LPCB.EC0.OPMS /* External reference */
                    }
                    ElseIf ((Local0 == 0x0C))
                    {
                        BHGK [One] = Zero
                    }
                    ElseIf ((Local0 == 0x0D))
                    {
                        BHGK [Zero] = 0x03
                    }
                    ElseIf ((Local0 == 0x0E))
                    {
                        BHGK [Zero] = 0x03
                    }
                    ElseIf ((Local0 == 0x0F))
                    {
                        If ((\_SB.PC00.LPCB.EC0.FMKY == One))
                        {
                            BHGK [Zero] = Zero
                            BHGK [One] = One
                        }
                        ElseIf ((\_SB.PC00.LPCB.EC0.FMKY == Zero))
                        {
                            BHGK [Zero] = Zero
                            BHGK [One] = 0x02
                        }
                    }
                    ElseIf ((Local0 == 0x10))
                    {
                        BHGK [Zero] = Zero
                        BHGK [One] = 0xFF
                    }
                    Else
                    {
                        BHGK [Zero] = Zero
                        BHGK [One] = 0xFF
                        BHGK [0x02] = Zero
                        BHGK [0x03] = Zero
                        BHGK [0x04] = Zero
                        BHGK [0x05] = Zero
                        BHGK [0x06] = Zero
                        BHGK [0x07] = Zero
                    }

                    Return (BHGK) /* \_SB_.PC00.WMID.BHGK */
                }

I can provide you with a basic patch which adds support for calling those two WMI methods. You can then wire-up the platform profile code
inside acer-wmi to use those WMI methods instead of trying to access the EC directly.

Thanks,
Armin Wolf





[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux