Mar*_*ter 5 laptop key-mapping display
在我的 上Dell latitude e6540,WMI 热键Fn+Up和Fn+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+Up和Fn+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)
修补 WMI 模块后,我收到以下关于Fn+Up和Fn+ 的消息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)
同样有趣的是,笔记本电脑预装了 Ubuntu 12.04,并且 wmi 密钥在 Ubuntu 中运行。
这篇文章描述了我如何根据 acpidump 中的 DSDT 进行 WMI 调试(SSDT 在这里不包含相关细节)。
\_SB.AMW0是戴尔 ACPI 固件中的 WMI 设备。该\EV4方法调用\WMNF它是在\_SB.AMW0设备上调用的唯一方法(函数SWEV= 设置?WMI 事件)。\EV4是由嵌入式/键盘控制器调用的方法。
现在,SWEV是Set WMI Event,CMEV很可能是Clear WMI Event。在调用 时SWEV,WMEV变量(“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。返回值现在取决于 的值WMEV。WVPT在返回的缓冲区中设置 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)
您可以安装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。