控制檯驅動

Linux 核心有兩種通用型別的控制檯驅動。第一種型別在引導過程中由核心分配給所有虛擬控制檯。這種型別將被稱為“系統驅動”,並且只允許存在一個系統驅動。系統驅動是持久的,它永遠不能被解除安裝,儘管它可能會變為非活動狀態。

第二種型別必須顯式載入和解除安裝。本文件將其稱為“模組化驅動”。多個模組化驅動可以隨時共存,每個驅動與其他驅動(包括系統驅動)共享控制檯。但是,模組化驅動不能接管當前被另一個模組化驅動佔用的控制檯。(例外:呼叫 do_take_over_console() 的驅動無論佔用控制檯的驅動型別如何,都將成功接管。)它們只能接管被系統驅動佔用的控制檯。同樣,如果模組化驅動被控制檯釋放,系統驅動將接管。

從程式設計師的角度來看,模組化驅動必須呼叫

do_take_over_console() - load and bind driver to console layer
give_up_console() - unload driver; it will only work if driver
                    is fully unbound

在較新的核心中,以下也可用

do_register_con_driver()
do_unregister_con_driver()

如果 sysfs 已啟用,可以檢查 /sys/class/vtconsole 的內容。這顯示了系統當前註冊的控制檯後端,其命名為 vtcon<n>,其中 <n> 是 0 到 15 的整數。因此

ls /sys/class/vtconsole
.  ..  vtcon0  vtcon1

/sys/class/vtconsole 中的每個目錄都有 3 個檔案

ls /sys/class/vtconsole/vtcon0
.  ..  bind  name  uevent

這些檔案代表什麼?

  1. bind - 這是一個讀/寫檔案。讀取時顯示驅動狀態,寫入時用於將驅動繫結或解除繫結到虛擬控制檯。可能的值為

    0
    • 表示驅動未繫結,如果執行 echo 命令,則指示驅動解除繫結

    1
    • 表示驅動已繫結,如果執行 echo 命令,則指示驅動進行繫結

  2. name - 只讀檔案。以這種格式顯示驅動名稱

    cat /sys/class/vtconsole/vtcon0/name
    (S) VGA+
    
        '(S)' stands for a (S)ystem driver, i.e., it cannot be directly
        commanded to bind or unbind
    
        'VGA+' is the name of the driver
    
    cat /sys/class/vtconsole/vtcon1/name
    (M) frame buffer device
    
        In this case, '(M)' stands for a (M)odular driver, one that can be
        directly commanded to bind or unbind.
    
  3. uevent - 忽略此檔案

解除繫結時,模組化驅動首先被分離,然後系統驅動接管該驅動騰出的控制檯。另一方面,繫結操作會將驅動繫結到當前被系統驅動佔用的控制檯。

注意1

繫結和解除繫結必須在 Kconfig 中選擇。它位於

Device Drivers ->
    Character devices ->
            Support for binding and unbinding console drivers
注意2

如果任何虛擬控制檯處於 KD_GRAPHICS 模式,則繫結或解除繫結將不會成功。將控制檯設定為 KD_GRAPHICS 的應用程式示例是 X。

此功能有多大用處?這對控制檯驅動開發者非常有用。透過將驅動從控制檯層解除繫結,可以解除安裝驅動、進行更改、重新編譯、重新載入並重新繫結驅動,而無需重新啟動核心。對於可能希望從幀緩衝控制檯切換到 VGA 控制檯,反之亦然的普通使用者,此功能也使其成為可能。(注意注意注意:請閱讀 Documentation/fb 下的 fbcon.txt 以獲取更多詳細資訊。)

開發者須知

do_take_over_console() 現已分解為

do_register_con_driver()
do_bind_con_driver() - private function

give_up_console()do_unregister_con_driver() 的一個封裝,並且驅動必須完全解除繫結才能使此呼叫成功。con_is_bound() 將檢查驅動是否已繫結。

控制檯驅動編寫者指南

為了使繫結和解除繫結控制檯功能正常工作,控制檯驅動必須遵循以下準則

  1. 所有驅動(系統驅動除外)都必須呼叫 do_register_con_driver() 或 do_take_over_console()。do_register_con_driver() 只會將驅動新增到控制檯的內部列表。它不會接管控制檯。do_take_over_console(),顧名思義,也將接管(或繫結到)控制檯。

  2. 所有在 con->con_init() 期間分配的資源都必須在 con->con_deinit() 中釋放。

  3. 所有在 con->con_startup() 中分配的資源都必須在驅動(之前已繫結)解除繫結時釋放。控制檯層沒有與 con->con_startup() 互補的呼叫,因此由驅動檢查何時可以合法釋放這些資源。在 con->con_deinit() 中呼叫 con_is_bound() 會有所幫助。如果呼叫返回 false(),則可以安全地釋放資源。必須確保這種平衡,因為當重新繫結驅動到控制檯的請求到達時,con->con_startup() 可能會再次被呼叫。

  4. 驅動退出時,請確保驅動完全解除繫結。如果滿足條件,驅動必須呼叫 do_unregister_con_driver()give_up_console()

  5. do_unregister_con_driver() 也可以在驅動無法服務控制檯請求的條件下呼叫。這可能發生在突然失去所有驅動的幀緩衝控制檯上。

當前的控制檯驅動應該仍然可以正常工作,但繫結和解除繫結它們可能會導致問題。透過最少的修復,這些驅動可以正常工作。

Antonino Daplas <adaplas@pol.net>