複合裝置

簡介

本節將說明複合裝置。 複合裝置是指由其他裝置組成的裝置。

這些裝置能解決硬體層級的組成問題 顯示「裝置」(從使用者的角度來看) 不同的硬體區塊

例如:

  • 由 I2C 裝置和 GPIO 組成的觸控面板,
  • 由 MAC 晶片和一或多個 PHY 組成的乙太網路裝置;或
  • 由音訊控制器和一組轉碼器組成的音訊裝置。

在這些情況下,董事會知道硬體的關係 驅動程式庫在啟動時 (靜態或透過動態方式,例如 ACPI)。

我們將使用 astro-audio 裝置做為範例:

圖:I2C 匯流排搭配 GPIO 的複合硬體裝置

這部裝置具有以下特色:

  • I2C 匯流排介面
  • 兩組 GPIO (一組用於錯誤,一組用於啟用)
  • 用於大量資料移轉的 MMIO (記憶體對應 I/O),以及
  • 產生中斷給驅動程式庫的 IRQ (中斷要求) 行。

請注意,ZX_PROTOCOL_I2CZX_PROTOCOL_GPIO 通訊協定是用於 轉移資料;也就是傳送和接收 I2C 訊息和 GPIO PIN 碼 分別由不同的驅動程式提供資訊

ZX_PROTOCOL_PDEV 部分不同, 這裡的通訊協定只會用來授予存取權 (在 圖表) 提交給 MMIO 和 IRQ;以及實際的 MMIO 資料和中斷情形不會PDEV 處理;並由「astro-audio」驅動程式直接處理 機器學習是向機器提供資料和答案 讓機器自行探索規則的科學

建立複合裝置

如要建立複合裝置,您必須設定數個資料結構。

繫結操作說明

我們需要一些具約束力的指示 (zx_bind_inst_t),告訴我們 是我們相得益彰的裝置

astro-audio 裝置上,你可以:

static const zx_bind_inst_t i2c_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
    BI_ABORT_IF(NE, BIND_I2C_BUS_ID, ASTRO_I2C_3),
    BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, I2C_AUDIO_CODEC_ADDR),
};

static const zx_bind_inst_t fault_gpio_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_AUDIO_SOC_FAULT_L),
};

static const zx_bind_inst_t enable_gpio_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_SOC_AUDIO_EN),
};

這些繫結操作說明可用來尋找裝置。

有三個繫結的指令陣列I2C (i2c_match[]) 裝置和 兩個 GPIO (fault_gpio_match[]enable_gpio_match[])。

這些指示接著會放入結構陣列中 (device_fragment_part_t),用於定義每個片段:

圖:收集至片段的繫結操作說明
陣列

astro-audio 裝置上,你可以:

static const device_fragment_part_t i2c_fragment[] = {
    { countof(i2c_match), i2c_match },
};

static const device_fragment_part_t fault_gpio_fragment[] = {
    { countof(fault_gpio_match), fault_gpio_match },
};

static const device_fragment_part_t enable_gpio_fragment[] = {
    { countof(enable_gpio_match), enable_gpio_match },
};

目前我們有三個片段裝置 i2c_fragment[]fault_gpio_fragment[]enable_gpio_fragment[]

片段裝置比對規則

你必須遵守下列規則:

  1. 最後一個元素必須描述目標裝置本身。
  2. 其餘元素必須符合從根到 定義目標裝置 系統可能會略過部分裝置,但每個元素都必須 進行比對

最後,我們會將這些變數合併成名為 fragments[] 的匯總函式。 device_fragment_t:

圖:將片段收集為匯總

完成這個步驟後,我們就能使用單一 ID fragments[] 建立 BERT 模型

astro-audio 中,如下所示:

static const device_fragment_t fragments[] = {
    { "i2c", countof(i2c_fragment), i2c_fragment },
    { "gpio-fault", countof(fault_gpio_fragment), fault_gpio_fragment },
    { "gpio-enable", countof(enable_gpio_fragment), enable_gpio_fragment },
};

正在建立裝置

如果是簡單的 (非複合) 裝置,我們則使用 device_add()

如果是複合型裝置,我們會使用 device_add_composite_deprecated()

zx_status_t device_add_composite_deprecated(
    zx_device_t* dev,
    const char* name,
    const zx_device_prop_t* props,
    size_t props_count,
    const device_fragment_t* fragments,
    size_t fragments_count,
    uint32_t coresident_device_index);

引數如下:

引數 意義
dev 家長的裝置
name 裝置名稱
props 屬性 (請參閱「宣告驅動程式」)
props_count props」中的項目數量
fragments 個別片段裝置
fragments_count fragments」中的項目數量
coresident_device_index 要使用的驅動程式代管程序

dev 值必須是與「sys」對應的 zx_device_t (即月台匯流排驅動程式的裝置)。

請注意,coresident_device_index 是用來指出哪個驅動程式代管程序。 新裝置應該使用。 如果指定 UINT32_MAX,裝置就會存放在新的驅動程式代管程序中。

請注意,astro-audio 使用的是 pbus_composite_device_add() 而非 device_add_composite_deprecated()。 差別在於 pbus_composite_device_add() 是 API 提供的圖像device_add_composite_deprecated() 插入另一個片段,以透過直接存取的資源搭乘交通工具 例如 MMIO、IRQ 和 BTI。

使用複合裝置

從程式設計的角度來看,複合裝置就像一般裝置一樣, 但它沒有 banjo 通訊協定每個偶發片段都能提供 通訊協定和中繼資料,但為了便於相容性,片段不應 並能直接存取

相反地,您可以透過下列方式直接存取每個片段的通訊協定和中繼資料: 呼叫 device_get_fragment_protocol()device_get_fragment_metadata()

bool device_get_fragment_protocol (
     zx_device_t* parent,
     const char* fragment_name,
     uint32_t proto_id, void* out);

引數如下:

引數 意義
parent 代表父項的 zx_device_t 指標
fragment_name 待擷取的片段名稱
proto_id 要擷取的通訊協定 ID
out 要傳回的通訊協定指標
foo_protocol_t proto;
auto status = device_get_fragment_protocol(&composite, "fragment-name", ZX_PROTOCOL_FOO, &proto);
if (status != ZX_OK) {
    zxlogf(ERROR, "could not get protocol");
    return status;
}

與中繼資料類似:

bool device_get_fragment_metadata (
     zx_device_t* parent,
     const char* fragment_name,
     uint32_t type, void* buf,
     size_t buflen, size_t* actual);

引數如下:

引數 意義
parent 代表父項的 zx_device_t 指標
fragment_name 待擷取的片段名稱
type 要擷取的通訊協定 ID
buf 指向要填入內容的資料集指標
buflen 可寫入 buf 的位元組數量上限
actual 指向已填入實際大小的 size_t 指標
std::vector<uint8_t> data(50);
size_t actual = 0;
auto status = device_get_fragment_metadata(&composite, "fragment-name",
                                           DEVICE_METADATA_FOO, data.data(),
                                           data.size(), &actual);
if (status != ZX_OK) {
    zxlogf(ERROR, "could not get metadata");
    return status;
}

提供給 device_get_fragment_protocol() 的片段名稱, device_get_fragment_metadata() 與 提供給 device_add_Composite_deprecation()device_fragment_t 項目 。

進階主題

本文將探討一些專門 / 進階的主題。

複合裝置和 Proxy

astro-audio 驅動程式庫的實際運作情況比 首次顯示:

圖:使用 Proxy 的複合硬體裝置

片段會繫結至內部驅動程式庫 (位於 片段目錄)。

驅動程式會視需要處理跨程序邊界的 Proxy。 這個 Proxy 會使用 DEVICE_ADD_MUST_ISOLATE 機制 (導入 「隔離裝置」一節)。

透過 DEVICE_ADD_MUST_ISOLATE 新增裝置時,兩部裝置 於此建立: 並且會處於與上層裝置相同的程序,且可透過 Proxy 存取。

系統會在新的驅動程式代管程序中建立 Proxy。 驅動程式庫為 normal.so,則其驅動程式庫為 normal.proxy.so。 此驅動程式庫應實作 create() 方法, device_add() 並隱藏指定的 IPC 管道。 系統稍後會用該管道 與一般頻道聯絡 才能滿足 Proxy 的子項要求。

一般裝置會實作 rxrpc 掛鉤,由 每當接收來自管道訊息時,就會觸發驅動程式庫執行階段 與 Proxy 共用

因此,如要實作新的通訊協定 Proxy,您必須先 fragment.proxy.so 驅動程式,用於處理所需通訊協定 傳送訊息至一般裝置,並將 fragment.so 驅動程式庫修改為 提供適當的服務

片段 Proxy 是在 fragment-proxy.cc 中實作,而且 請前往 fragment.cc