Laptop

基於 WMI 的熱鍵不起作用

  • February 9, 2015

在我Dell latitude e6540的 上,WMI 熱鍵Fn+UpFn+Down不起作用。我在我的核心中編譯了所有必要的模組:

CONFIG_DELL_LAPTOP=m
CONFIG_DELL_WMI=m
CONFIG_DELL_WMI_AIO=m

在前代機型(Latitude e6520)上,一切正常,無需任何額外設置。我在兩台筆記型電腦上都使用相同的(自定義建構)核心 3.16.6。在 e6520 上 wmi 有效,在 e6540 上無效。

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

echo 35 > /sys/class/backlight/acpi_video0/brightness

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)

更新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

更新3

同樣有趣的是,筆記型電腦預裝了 Ubuntu 12.04,並且 wmi 鍵在 Ubuntu 中工作。

您可以安裝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

將通知方法替換為您在正常設置中使用的任何內容,例如notify-send.

這篇文章描述了我如何根據您的 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 */
}

但是請注意,有兩種情況可能會阻止返回事件程式碼(但此處不適用):

  • 如果 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 
  • 如果\_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)

現在,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

現在按熱鍵並查看您的核心日誌。你需要找出確切的格式是什麼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]);

引用自:https://unix.stackexchange.com/questions/124938