基于 WMI 的热键不起作用

Mar*_*ter 5 laptop key-mapping display

在我的 上Dell latitude e6540,WMI 热键Fn+UpFn+Down不起作用。我在内核中编译了所有必要的模块:

CONFIG_DELL_LAPTOP=m
CONFIG_DELL_WMI=m
CONFIG_DELL_WMI_AIO=m
Run Code Online (Sandbox Code Playgroud)

在前代型号 (Latitude e6520) 上,一切正常,无需任何额外设置。我在两台笔记本电脑上使用相同的(自定义构建)内核 3.16.6。在 e6520 上 wmi 可以工作,在 e6540 上则不行。

我仍然可以通过以下方式更改亮度echo

echo 35 > /sys/class/backlight/acpi_video0/brightness
Run Code Online (Sandbox Code Playgroud)

但仅作为root,显然。

Fn+UpFn+Down不会更改 中的值/sys/class/backlight/acpi_video0/brightness。在以前的模型中,它确实会更改该值。

我注意到的一件事是,在旧型号上,最大值是15. 在新模型上是95。看起来这个机制内部可能发生了一些变化。

因此我的问题是:如何让 WMI 热键在我的新笔记本电脑上工作?

我正在使用带有自定义内核 3.16.6 的 Debian wheezy。我还尝试了发行版内核 3.16(来自 Wheezy-backports 的 linux-image-3.16-0.bpo.2-amd64)并且 wmi 密钥也不起作用。

更新:

我刚刚注意到,当我在 BIOS 中时,WMI 热键可以正常工作!!!当我启动到 linux 时,它们不起作用,这真是令人惊讶。

以下是 dmesg 的输出。提到的dell_wmi: Received unknown WMI event看起来与我的问题有关,但我在旧笔记本电脑上收到相同的消息,wmi 热键正在工作。所以仅此一点似乎不是问题。

dmesg | egrep -i '(dell|wmi)'
[Tue Apr 15 22:04:30 2014] DMI: Dell Inc. Latitude E6540/05V0V4, BIOS A05 09/03/2013
[Tue Apr 15 22:04:30 2014] ACPI: RSDP 00000000000eee60 00024 (v02 DELL  )
[Tue Apr 15 22:04:30 2014] ACPI: XSDT 00000000d8fe0080 0007C (v01 DELL    CBX3    01072009 AMI  00010013)
[Tue Apr 15 22:04:30 2014] ACPI: FACP 00000000d8fed7e8 0010C (v05 DELL    CBX3    01072009 AMI  00010013)
[Tue Apr 15 22:04:30 2014] ACPI: DSDT 00000000d8fe0188 0D659 (v02 DELL    CBX3    00000014 INTL 20091112)
[Tue Apr 15 22:04:30 2014] ACPI: APIC 00000000d8fed8f8 00072 (v03 DELL    CBX3    01072009 AMI  00010013)
[Tue Apr 15 22:04:30 2014] ACPI: FPDT 00000000d8fed970 00044 (v01 DELL    CBX3    01072009 AMI  00010013)
[Tue Apr 15 22:04:30 2014] ACPI: HPET 00000000d8feed38 00038 (v01 DELL    CBX3    01072009 AMI. 00000005)
[Tue Apr 15 22:04:30 2014] ACPI: MCFG 00000000d8fef148 0003C (v01 DELL    CBX3    01072009 MSFT 00000097)
[Tue Apr 15 22:04:38 2014] dcdbas dcdbas: Dell Systems Management Base Driver (version 5.6.0-3.2)
[Tue Apr 15 22:04:39 2014] wmi: Mapper loaded
[Tue Apr 15 22:04:39 2014] input: Dell WMI hotkeys as /devices/virtual/input/input10
[Wed Apr 16 18:30:04 2014] dell_wmi: Received unknown WMI event (0x0)
[Fri Apr 18 17:09:41 2014] dell_wmi: Received unknown WMI event (0x0)
[Fri Apr 18 17:09:41 2014] dell_wmi: Received unknown WMI event (0x0)
[Fri Apr 18 17:09:49 2014] dell_wmi: Received unknown WMI event (0x0)
Run Code Online (Sandbox Code Playgroud)

更新2

修补 WMI 模块后,我收到以下关于Fn+UpFn+ 的消息Down

2014-04-18 19:00:49  kernel: [  120.731480] dell_wmi: WMBU = 0002 0010 0048
2014-04-18 19:00:49  kernel: [  120.731496] wmi: DEBUG Event GUID: 9DBB5994-A997-11DA-B012-B622A1EF5492

2014-04-18 19:00:53  kernel: [  123.935400] dell_wmi: WMBU = 0002 0010 0050
2014-04-18 19:00:53  kernel: [  123.935415] wmi: DEBUG Event GUID: 9DBB5994-A997-11DA-B012-B622A1EF5492
Run Code Online (Sandbox Code Playgroud)

更新3

同样有趣的是,笔记本电脑预装了 Ubuntu 12.04,并且 wmi 密钥在 Ubuntu 中运行。

Lek*_*eyn 6

这篇文章描述了我如何根据 acpidump 中的 DSDT 进行 WMI 调试(SSDT 在这里不包含相关细节)。

\_SB.AMW0是戴尔 ACPI 固件中的 WMI 设备。该\EV4方法调用\WMNF它是在\_SB.AMW0设备上调用的唯一方法(函数SWEV= 设置?WMI 事件)。\EV4是由嵌入式/键盘控制器调用的方法。

现在,SWEV是Set WMI Event,CMEV很可能是Clear WMI Event。在调用 时SWEVWMEV变量(“WMI 事件”?)中的位被设置。WMI 通过调用_WED方法并检查其返回值来检查事件代码。在这个_WED方法中,它确实是可见的,WMEV被检查CMEV并被调用:

Method (_WED, 1, NotSerialized)  // _Wxx: Wake Event
{
    WVSP ()
    If (LNotEqual (Arg0, 0xD0))
    {
        WVCU ()
        Return (WMBU) /* \_SB_.AMW0.WMBU */
    }

    If (LEqual (ECD0, Zero))
    {
        WVCU ()
        Return (WMBU) /* \_SB_.AMW0.WMBU */
    }

    If (And (WMEV, 0x0200))
    {
        CWEV (0x0200)
        // WMBU = { 0x0002, 0x0000, 0xE045 }
        WVPT (0x02)
        WVPT (Zero)
        WVPT (0xE045)
    }
    Else
    {
        If (And (WMEV, 0x0100))
        {
            CWEV (0x0100)
            If (ECG4 ())
            {
                WVPT (0x02)
                WVPT (Zero)
                WVPT (0xE043)
            }
            Else
            {
                WVPT (0x02)
                WVPT (Zero)
                WVPT (0xE044)
            }
        }
        Else
        {
            If (And (WMEV, 0x0800))
            {
                Store (EC0A (WMBU), WMBU) /* \_SB_.AMW0.WMBU */
                CWEV (0x0800)
            }
        }
    }

    WVCU ()
    Return (WMBU) /* \_SB_.AMW0.WMBU */
}
Run Code Online (Sandbox Code Playgroud)

但请注意,有两种情况可能会阻止返回事件代码(但此处不适用):

  • 如果 Arg0(通知 ID)不是 0xD0。从 WMI 描述的解释中可以看出,情况并非如此:

    9DBB5994-A997-11DA-B012-B622A1EF5492:
        object_id: ? [D0 00]
        notify_id: D0
        reserved: 00
        instance_count: 1
        flags: 0x8 ACPI_WMI_EVENT 
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果\_SB.AMW0.ECD0等于0。当戴尔 WMI 代码侦听 WMI 事件时,WED0(WMI Event D0) 被调用了一个非零参数,这也不成立。

那么,让我们继续解释_WED。返回值现在取决于 的值WMEVWVPT在返回的缓冲区中设置 16 位字WMBU(并为下一次WVPT调用提前指针)。我们可以构建下表:

WMEV                returned WMBU   guessed key (see dell-wmi)
0200                0002 0000 E045  KEY_PROG1 or NumLock
0100 (ECG4())       0002 0000 E043  ??
0100 (not ECG4())   0002 0000 E044  ??
0800                ?? (value depends on EC registers)
Run Code Online (Sandbox Code Playgroud)

现在,dell-wmi 代码期望第二个字是0x0010,而不是0x0000。为了进一步调试,您应该启用debug_eventWMI 模块的选项

# remove all dependencies of WMI and WMI itself:
modprobe -vr dell-wmi
modprobe wmi debug_event
modprobe dell-wmi
Run Code Online (Sandbox Code Playgroud)

现在按热键并查看您的内核日志。您需要找出 的确切格式WMBU,我想您会获得 WMEV 0x0800 最有趣的密钥,您需要仔细研究一下。也许将此添加到dell_wmi_notify(after u16 *buffer_entry = (u16 *)obj->buffer.pointer;) 以进行调试:

pr_info("WMBU = %04x %04x %04x\n", buffer_entry[0], buffer_entry[1], buffer_entry[2]);
Run Code Online (Sandbox Code Playgroud)


jas*_*yan 3

您可以安装xbacklight ,这是一个使用RandR管理亮度的实用程序。然后,要激活它,请使用一个简单的脚本,绑定到您的两个键:

#!/usr/bin/env bash
up() {
    xbacklight -inc 10
}

down() {
    xbacklight -dec 10
}

notify() {
    bright=$(</sys/class/backlight/acpi_video0/actual_brightness)
    if [[ "$bright" -eq 95 ]]; then
        score="100%"
    else score="$(( $bright * 100 / 95 ))"
    fi
    printf '%s\n' "Backlight set to ${score}%" | dzen2 -p 3
}

if [[ $1 = up ]]; then
    up && notify
elif [[ $1 = down ]]; then
    down && notify
fi
Run Code Online (Sandbox Code Playgroud)

将您的通知方法替换为您在正常设置中使用的任何方法,例如notify-send