裝置驅動程式庫生命週期

裝置驅動程式經判定後,就會載入驅動程式代管程序程序 。決定載入與否的繫結程式 是驅動程式庫可繫結之裝置的說明。具有約束力的計畫 以小型網域特定語言定義,該語言已編譯為位元碼 會與驅動程式庫一起發行

Intel 乙太網路驅動程式的繫結程式範例:

fuchsia.device.protocol == fuchsia.pci.protocol.PCI_DEVICE;
fuchsia.pci.vendor == fuchsia.pci.vendor.INTEL;
accept fuchsia.pci.device {
    0x100E, // Qemu
    0x15A3, // Broadwell
    0x1570, // Skylake
    0x1533, // I210 standalone
    0x15b7, // Skull Canyon NUC
    0x15b8, // I219
    0x15d8, // Kaby Lake NUC
}

繫結編譯器會採用繫結程式,並輸出 C 標頭檔案, 會定義巨集 ZIRCON_DRIVERZIRCON_DRIVER 巨集包含 必要的編譯器指令,可將繫結程式放入 ELF NOTE 部分,方便裝置協調人員檢查 完全載入驅動程式庫程式。

ZIRCON_DRIVER 的第二個參數是 zx_driver_ops_t 結構指標 (由 lib/ddk/driver.h 定義, 會定義 init、繫結、create 和 release 方法。

驅動程式庫載入驅動程式主機程序時,系統會叫用 init(),並允許 任何全域初始化作業。通常不需要。如果 init() 方法為 但驅動程式庫載入失敗

系統會叫用 bind(),為驅動程式庫提供要繫結的裝置。裝置 符合驅動程式庫發布的繫結規則。如果 bind() 方法成功, 驅動程式庫「必須」建立新裝置,並將其新增為傳入的裝置子項 加入 bind() 方法。詳情請參閱裝置生命週期。

針對平台/系統匯流排驅動程式或 Proxy 驅動程式,系統會叫用 create()。對於 大多數的驅動程式皆不需要使用這個方法。

系統會在驅動程式庫卸載前叫用 release(),直到驅動程式的所有裝置都結束 在 bind() 及其他位置所建立的資源已遭刪除。目前這個方法: never:駕駛座落於駕駛座的壽命後,會一直留在車上 上傳資料集之後,您可以運用 AutoML 自動完成部分資料準備工作

裝置生命週期

在驅動程式主機程序中,裝置會以 zx_device_t 結構的樹狀結構的形式存在, 是駕駛人看不見的畫面這些是從 device_add() 建立,也就是 驅動程式庫提供 zx_protocol_device_t 結構由 這個結構中的函式指標稱為「裝置作業」。 各種結構和函式都定義於 device.h

device_add() 函式會建立新的裝置,並將其新增為 提供的家長裝置。該上層裝置必須是通過測試的裝置 在裝置驅動程式庫程式的 bind() 方法中,或 由同一部裝置驅動程式庫建立

device_add() 的副作用是將新建立的裝置新增至裝置 提供給「裝置協調者」維護的全球裝置檔案系統。如果 裝置尚未實作 init() 掛鉤,表示裝置會立即生效 可在 devfs 中開啟節點

系統會在 device_add() 之後叫用 init() 掛鉤。這對於使用者 需要進行延伸初始化或探測,且不需要執行的驅動程式 開發人員明顯地發布裝置,直到成功發布為止 (並安靜地移除 如果失敗則建議通知)。駕駛應在呼叫 device_init_reply() 後呼叫 也已完成初始化這則回覆不一定要 該呼叫端透過 init() 掛鉤呼叫。裝置仍會隱藏, 保證在目前之前 不會移除

裝置僅供參考。可在驅動程式庫建立時取得參照 含有 device_add() 且遠端程序開啟裝置的裝置 透過裝置檔案系統

從呼叫 device_init_reply() 或呼叫 device_add() 的那一刻起 如未實作 init() 掛鉤,SDK 可能會呼叫其他裝置作業 驅動程式代管程序。

在裝置上呼叫 device_async_remove() 時,這麼做會安排移除作業 及其子系

移除裝置的程序包含四個部分:執行裝置的 unbind() 掛鉤、 從裝置檔案系統中移除裝置,並捨棄取得的參考資料 由 device_add()執行,並正在執行裝置的 release() 掛鉤。

叫用 unbind() 方法時,這會向驅動程式庫發出信號,該方法應啟動 關閉裝置,並在取消繫結後呼叫 device_unbind_reply()。 取消繫結也成為 FIDL 交易的硬性阻礙。 FDF 不允許任何新的 FIDL 交易或連線 會在呼叫 Unbind 時建立。駕駛負責 可用來結案或回覆尚未解決的交易 並在處理 FIDL 訊息時取消繫結。 此為選用提示。如未實作,系統會將其視為 device_unbind_reply() 都會立即呼叫呼叫 device_unbind_reply 時, 所有 FIDL 連線都會終止。

如果 unbind() 方法為 則可能是父項裝置 (已完成) 未繫結) 可以繼續接收裝置方法呼叫或通訊協定方法 呼叫。建議您在完成解除繫結前 上層裝置應安排這些方法傳回錯誤, 在兒童移除完成前來自孩童的來電。 工作或造成非預期的互動

只有在建立驅動程式庫完成後,才會呼叫 release() 方法 因此該裝置的所有已開啟執行個體都已關閉 且該裝置的所有子項都已解除繫結並釋出。這個 是驅動程式庫最後摧毀或釋出任何相關資源的最後機會 與使用者保持連線不適用於該裝置的「zx_device_trelease() 退貨後。針對以下項目呼叫任何裝置方法或通訊協定方法: 在此時間點後,從上層裝置取得的通訊協定屬於違法內容,且 可能會導致當機

卸除序列示例

為了說明 unbind()release() 在拆除過程中的運作方式, 下方為 USB WLAN 驅動程式庫通常會如何處理。簡單來說 unbind() 呼叫序列為由上而下,release() 序列則是由下而上。

請注意,這只是一個範例,這可能與實際的 WLAN 驅動程式庫不一致 目前的狀態。

假設 WLAN 裝置已插入 USB 裝置,且具有 PHY 介面 透過 USB 裝置建立除了 PHY 介面外,2 個 MAC 介面之外 已在 PHY 介面下建立。

            +------------+
            | USB Device | .unbind()
            +------------+ .release()
                  |
            +------------+
            |  WLAN PHY  | .unbind()
            +------------+ .release()
              |        |
    +------------+  +------------+
    | WLAN MAC 0 |  | WLAN MAC 1 | .unbind()
    +------------+  +------------+ .release()

現在我們拔除這部 USB WLAN 裝置

  • USB XHCI 偵測到移除情形,並呼叫 device_async_remove(usb_device)

  • 這會導致系統呼叫 USB 裝置的 unbind()。 取消繫結後,會呼叫 device_unbind_reply()

    usb_device_unbind(void* ctx) {
        // Stop interrupt or anything to prevent incoming requests.
        ...

        device_unbind_reply(usb_dev);
    }
  • 當 USB 裝置完成解除繫結時,系統會呼叫 WLAN PHY 的 unbind()。 取消繫結後,會呼叫 device_unbind_reply()
    wlan_phy_unbind(void* ctx) {
        // Stop interrupt or anything to prevent incoming requests.
        ...

        device_unbind_reply(wlan_phy);
    }
  • 當 wlan_phy 完成取消繫結時,將會對其所有子項呼叫 unbind() (wlan_mac_0、wlan_mac_1)。
    wlan_mac_unbind(void* ctx) {
        // Stop accepting new requests, and notify clients that this device is offline (often just
        // by returning a ZX_ERR_IO_NOT_PRESENT to any requests that happen after unbind).
        ...

        device_unbind_reply(iface_mac_X);
    }
  • 移除裝置的所有用戶端,且該裝置沒有任何孩童後: 其 ref 將達到 0,系統會呼叫其 release() 方法。

  • 系統會呼叫 WLAN MAC 0 和 1 的 release()

    wlan_mac_release(void* ctx) {
        // Release sources allocated at creation.
        ...

        // Delete the object here.
        ...
    }
  • wlan_phy 沒有開放的連線,但仍有子裝置 (wlan_mac_0 和 wlan_mac_1)。 等到兩者都釋放後,其 Recount 最後就會變成零,並產生了 release() 方法。
    wlan_phy_release(void* ctx) {
        // Release sources allocated at creation.
        ...

        // Delete the object here.
        ...
    }
  • 當 USB 裝置現在沒有任何子裝置或開啟連線時,系統就會呼叫其 release()