Linux 下的 LED 處理¶
最簡單的形式,LED 類只允許從使用者空間控制 LED。 LED 出現在 /sys/class/leds/ 中。 LED 的最大亮度在 max_brightness 檔案中定義。 brightness 檔案將設定 LED 的亮度(取值範圍為 0-max_brightness)。 大多數 LED 沒有硬體亮度支援,因此對於非零亮度設定只會開啟。
該類還引入了 LED 觸發器的可選概念。 觸發器是基於核心的 led 事件源。 觸發器可以是簡單的,也可以是複雜的。 簡單的觸發器是不可配置的,旨在以最少的附加程式碼插入到現有的子系統中。 示例包括 disk-activity、nand-disk 和 sharpsl-charge 觸發器。 停用 led 觸發器後,程式碼會進行最佳化。
雖然複雜觸發器可用於所有 LED,但它們具有 LED 特定的引數,並且基於每個 LED 工作。 定時器觸發器就是一個例子。 定時器觸發器將定期在 LED_OFF 和當前亮度設定之間更改 LED 亮度。 “on” 和 “off” 時間可以透過 /sys/class/leds/<device>/delay_{on,off} 以毫秒為單位指定。 您可以獨立於定時器觸發器更改 LED 的亮度值。 但是,如果將亮度值設定為 LED_OFF,它也會停用定時器觸發器。
您可以透過類似於選擇 IO 排程器的方式(透過 /sys/class/leds/<device>/trigger)來更改觸發器。 一旦選擇了給定的觸發器,觸發器特定的引數可能會出現在 /sys/class/leds/<device> 中。
設計理念¶
底層的設計理念是簡單。 LED 是簡單的裝置,目標是保持少量程式碼,提供儘可能多的功能。 請記住這一點,在提出增強功能時。
LED 裝置命名¶
目前的形式是
“devicename:color:function”
- devicename
它應該引用核心建立的唯一識別符號,例如網路裝置的 phyN 或輸入裝置的 inputN,而不是硬體;與產品和給定裝置連線的匯流排相關的資訊在 sysfs 中可用,可以使用 tools/leds 中的 get_led_device_info.sh 指令碼檢索;通常,這部分主要用於與其它裝置關聯的LED。
- color
來自標頭檔案 include/dt-bindings/leds/common.h 的 LED_COLOR_ID_* 定義之一。
- function
來自標頭檔案 include/dt-bindings/leds/common.h 的 LED_FUNCTION_* 定義之一。
如果需要的顏色或功能缺失,請提交補丁至 linux-leds@vger.kernel.org。
給定平臺可能需要多個具有相同顏色和功能的 LED,僅序號不同。 在這種情況下,最好直接在驅動程式中將預定義的 LED_FUNCTION_* 名稱與所需的“-N”字尾連線。 基於 fwnode 的驅動程式可以使用 function-enumerator 屬性,然後 LED 核心將在 LED 類設備註冊時自動處理連線。
LED 子系統還具有針對名稱衝突的保護,當 LED 類裝置由熱插拔裝置的驅動程式建立並且它不提供唯一的 devicename 部分時,可能會發生名稱衝突。 在這種情況下,數值字尾(例如“_1”、“_2”、“_3”等)將新增到請求的 LED 類裝置名稱。
可能仍然存在使用供應商或產品名稱作為 devicename 的 LED 類驅動程式,但是這種方法現在已被棄用,因為它不傳達任何附加值。 產品資訊可以在 sysfs 中的其他位置找到(請參閱 tools/leds/get_led_device_info.sh)。
正確的 LED 名稱示例
“red:disk”
“white:flash”
“red:indicator”
“phy1:green:wlan”
“phy3::wlan”
“:kbd_backlight”
“input5::kbd_backlight”
“input3::numlock”
“input3::scrolllock”
“input3::capslock”
“mmc1::status”
“white:status”
get_led_device_info.sh 指令碼可用於驗證 LED 名稱是否符合此處指出的要求。 它執行 LED 類 devicename 部分的驗證,並在驗證失敗時提供有關該部分預期值的提示。 到目前為止,該指令碼支援 LED 和以下型別裝置之間關聯的驗證
輸入裝置
符合 ieee80211 標準的 USB 裝置
該指令碼可以擴充套件。
有人呼籲將 LED 屬性(例如顏色)作為單獨的 led 類屬性匯出。 作為一種不會產生太多開銷的解決方案,我建議將這些屬性作為裝置名稱的一部分。 上述命名方案為進一步的屬性留下了空間,如果需要的話。 如果名稱的某些部分不適用,只需將該部分留空即可。
亮度設定 API¶
LED 子系統核心公開了以下 API 用於設定亮度
- led_set_brightness
保證不休眠,傳遞 LED_OFF 會停止閃爍,
- led_set_brightness_sync
用於需要立即生效的用例 - 它可以阻塞呼叫者,以訪問裝置暫存器所需的時間,並且可以休眠,傳遞 LED_OFF 會停止硬體閃爍,如果啟用了軟體閃爍回退,則返回 -EBUSY。
LED 註冊 API¶
想要註冊 LED 類裝置以供其他驅動程式/使用者空間使用的驅動程式需要分配並填寫 led_classdev 結構,然後呼叫 [devm_]led_classdev_register。 如果使用了非 devm 版本,則驅動程式必須在其刪除函式中呼叫 led_classdev_unregister,然後才能釋放 led_classdev 結構。
如果驅動程式可以檢測到硬體啟動的亮度變化,因此希望具有 brightness_hw_changed 屬性,則必須在註冊之前在標誌中設定 LED_BRIGHT_HW_CHANGED 標誌。 在未註冊 LED_BRIGHT_HW_CHANGED 標誌的 classdev 上呼叫 led_classdev_notify_brightness_hw_changed 是一個錯誤,並且會觸發 WARN_ON。
硬體加速 LED 閃爍¶
某些 LED 可以被程式設計為在沒有任何 CPU 互動的情況下閃爍。 為了支援此功能,LED 驅動程式可以選擇實現 blink_set() 函式(請參閱 <linux/leds.h>)。 但是,要將 LED 設定為閃爍,最好使用 API 函式 led_blink_set(),因為它將檢查並在必要時實現軟體回退。
要關閉閃爍,請使用亮度值為 LED_OFF 的 API 函式 led_brightness_set(),它應該停止可能需要用於閃爍的任何軟體定時器。
如果呼叫 blink_set() 函式的引數為 *delay_on==0 && *delay_off==0,則它應該選擇一個使用者友好的閃爍值。 在這種情況下,驅動程式應透過 delay_on 和 delay_off 引數將所選值返回給 leds 子系統。
使用 brightness_set() 回撥函式將亮度設定為零應該完全關閉 LED,並取消先前程式設計的任何硬體閃爍功能。
硬體驅動的 LED¶
某些 LED 可以被程式設計為由硬體驅動。 這不僅限於閃爍,還包括自主關閉或開啟。 為了支援此功能,LED 需要實現各種附加操作,並且需要宣告對支援的觸發器的特定支援。
透過 hw 控制,我們指的是由硬體驅動的 LED。
LED 驅動程式必須定義以下值才能支援 hw 控制
- hw_control_trigger
LED 在 hw 控制模式下支援的唯一觸發器名稱。
- LED 驅動程式必須實現以下 API 才能支援 hw 控制
- hw_control_is_supported
檢查是否可以解析支援的觸發器傳遞的標誌,並在 LED 上啟用 hw 控制。
如果支援傳遞的標誌掩碼並且可以使用 hw_control_set() 設定,則返回 0。
如果不支援傳遞的標誌掩碼,則必須返回 -EOPNOTSUPP,LED 觸發器在這種情況下將使用軟體回退。
如果發生任何其他錯誤,例如裝置未準備好或超時,則返回負錯誤。
- hw_control_set
啟用 hw 控制。 LED 驅動程式將使用支援的觸發器傳遞的標誌,將它們解析為一組模式,並按照請求的模式設定由硬體驅動的 LED。
透過 brightness_set 設定 LED_OFF 以停用 hw 控制。
成功時返回 0,未能應用標誌時返回負錯誤號。
- hw_control_get
從已經在 hw 控制中的 LED 獲取活動模式,解析它們並在標誌中設定支援的觸發器的當前活動標誌。
成功時返回 0,未能解析初始模式時返回負錯誤號。 來自此函式的錯誤不是致命的,因為裝置可能處於連線的 LED 觸發器不支援的初始狀態。
- hw_control_get_device
返回與 hw 控制中的 LED 驅動程式關聯的裝置。 觸發器可以使用它來將此函式返回的裝置與為觸發器配置的裝置匹配,作為閃爍事件的來源,並正確啟用 hw 控制。(例如,配置為為特定 dev 閃爍的網路裝置觸發器匹配來自 get_device 的返回的 dev 以設定 hw 控制)
返回指向
struct device的指標,如果當前未連線任何裝置,則返回 NULL。
LED 驅動程式可以預設啟用其他模式,以解決無法在支援的觸發器上支援每種不同模式的問題。 例如,將閃爍速度硬編碼為固定間隔,如果未滿足某些要求,則啟用特殊功能(例如繞過閃爍)。
觸發器應首先檢查 LED 驅動程式是否支援 hw 控制 API,並檢查是否支援觸發器以驗證 hw 控制是否可能,使用 hw_control_is_supported 檢查是否支援標誌,並且僅在最後使用 hw_control_set 啟用 hw 控制。
觸發器可以使用 hw_control_get 檢查 LED 是否已經在 hw 控制中並初始化其標誌。
當 LED 處於 hw 控制中時,無法進行軟體閃爍,這樣做會有效地停用 hw 控制。
已知問題¶
LED 觸發器核心不能是模組,因為簡單的觸發器函式會導致噩夢般的依賴關係問題。 與簡單觸發器功能帶來的好處相比,我認為這是一個小問題。 LED 子系統的其餘部分可以是模組化的。