RFC-0197:複合節點的節點群組

RFC-0197:複合節點群組
狀態已接受
領域
  • 驅動程式 SDK
說明

支援在執行階段定義複合。

問題
蓋爾特變化
作者
審查人員
提交日期 (年-月-日)2022-11-01
審查日期 (年-月-日)2022-09-26

摘要

這個 RFC 提議在執行階段,定義複合節點的方式 驅動程式架構 v2 (DFv2)

提振精神

背景

在驅動程式架構 v1 (DFv1) 中,驅動程式可建立 複合節點 在執行階段透過 AddComposite() 函式執行驅動程式會定義繫結 複合的父項和繫結屬性和驅動程式管理器的規則 建立複合節點做為驅動程式庫的子項。另一個驅動程式庫會繫結至 複合節點

在 DFv2 中,複合驅動程式會透過 繫結規則 是以驅動程式庫繫結語言編寫的靜態檔案司機抵達時 驅動程式執行器會收集與 ,然後建立複合節點。複合驅動程式庫 繫結至節點

問題

由於複合驅動程式只能以靜態方式定義複合節點,因此無法 完全取代 DFv1 的 AddComposite() 功能。這樣可以避免一些駕駛人 就必須遷移至 DFv2

某些複合節點只會在執行階段得知,因此不可能 在複合驅動程式中定義的舉例來說,ACPI 匯流排驅動程式會建立 ACPI 複合節點匯流排驅動程式啟動後,會在 ACPI 中讀取文字 並據此建立節點

靜態繫結規則也會使撰寫跨欄複合材質的困難 因為繫結規則需要瞭解建構時的節點屬性 讓應用程式從可以最快做出回應的位置 回應使用者要求舉例來說,觸控複合驅動程式庫可能需要一個節點用於 GPIO 接腳 依特定功能設計GPIO 接腳會因遊戲板而異, 難以撰寫各節點通用的主機板繫結規則。

相關人員

講師:cpu@google.com

審查人員:surajmalhotra@google.com (FDF)、dgilhooley@google.com (FDF)

諮詢:駕駛團隊成員

社交功能:

Tq-driver 共用了 RFC 草稿

設計

需求條件

這個設計的目標是建立一種機制,讓駕駛人 下列何者必須是動態的動態節點:

  • 複合節點中每個父項的繫結規則
  • 用於比對複合節點與複合驅動程式庫的繫結屬性
  • 複合節點中的父項。容器可能會在執行階段中確定 複合節點應包含特定父項

此外,DFv1 和 DFv2 也必須支援這項機制。隸屬於 轉換至 DFv2,所有 DFv1 驅動程式都必須從 AddComposite() 複合型驅動程式

總覽

本提案在驅動程式架構中新增 API,供駕駛人用於 定義裝置節點群組

當驅動程式庫定義節點群組時,程序如下:

  1. 驅動程式管理器要求驅動程式庫索引找出複合式驅動程式庫 與節點群組相符
  2. 找出相符的複合驅動程式庫後,驅動程式管理器會找出 每個節點代表的相符裝置節點
  3. 只要每個節點表示法都相符,驅動程式管理器就會建立 包含節點做為父項的複合節點,並將其繫結至複合節點 驅動程式庫。主要節點和節點名稱由複合驅動程式庫提供

device-group-bind-diagram

節點表示法

群組中的每個節點表示法皆定義如下:

  • 繫結規則:比對節點表示法與裝置的規則 節點
  • 繫結屬性 - 節點表示法中的繫結屬性 會用來比對複合式驅動程式庫的靜態繫結規則

節點群組繫結規則

繫結規則由接受和遭拒的繫結屬性值清單組成。 如要符合繫結規則,繫結的屬性必須包含所有已接受 繫結屬性值,而不是任何遭拒的屬性值。舉例來說 群組節點包含繫結規則:

  • 接受 fuchsia.BIND_PROTOCOL 值:15 和 17
  • 拒絕 fuchsia.BIND_PLATFORM_DEV_VID 值「Intel」

接著,如果裝置包含 15 或 17 的 fuchsia.BIND_PROTOCOL 屬性,不含「Intel」值 fuchsia.BIND_PLATFORM_DEV_VID 屬性。

複合式繫結規則中的選用節點

由於某些父項的可用性只能在執行階段得知,因此複合 驅動程式必須能支援選用節點方法是透過繫結語言 需要更新,好讓複合驅動程式將節點標示為「非必要」:

primary node "sysmem" {
  fuchsia.BIND_PROTOCOL == fuchsia.sysmem.BIND_PROTOCOL.DEVICE;
}

optional node "acpi" {
  fuchsia.BIND_PROTOCOL == fuchsia.acpi.BIND_PROTOCOL.DEVICE;
}

比對複合驅動程式

比對程序會透過將複合驅動程式庫程式的繫結規則套用到 節點表示法繫結屬性。符合下列情況時,比對成功 已完成:

  • 所有節點表示法都必須與複合式繫結規則中的節點相符
  • 所有非選擇性的複合繫結規則節點都必須與節點相符 兩者的向量表示法
  • 比對不會模稜兩可:
    • 每個節點表示法只能對應一個複合式繫結 規則節點
    • 節點表示法與複合中的相同節點不得比對 繫結規則
  • 節點不需要依序比對

如果發生不明確的情況,系統會顯示警告訊息。

composite_bind_diagram

節點群組 API

驅動程式必須使用 FIDL 透過 NodeGroupManager 新增節點群組 套用至 fuchsia.driver.framework FIDL 程式庫中的通訊協定:

device_group.fidl

@discoverable
protocol NodeGroupManager {
    AddNodeGroup(fuchsia.driver.framework.NodeGroup) -> (struct {}) error zx.status;
};

節點群組以 FIDL 表示:

/// Represents the conditions for evaluating the device
/// group properties.
type Condition = strict enum {
    ACCEPT = 0;
    REJECT = 1;
};

/// Represents a bind rule for a node group node.
type BindRule = struct {
    /// Property key.
    key NodePropertyKey;

    /// Condition for evaluating the property values in
    /// the matching process. The values are accepted or
    /// rejected based on the condition.
    condition Condition;

    /// A list of property values. Must not be empty. The property
    /// values must be the same type.
    values vector<NodePropertyValue>:MAX_PROPERTY_COUNT;
};

/// Struct that represents a node in a node group.
type NodeRepresentation = struct {
    /// Bind rules for the node group node. Keys must be unique.
    bind_rules: vector<BindRule>:MAX_PROPERTY_COUNT;

    /// Properties used for matching composite bind rules. Keys must be unique.
    bind_properties vector<NodeProperty>:MAX_PROPERTY_COUNT;
};

/// Struct that represents a node group.
type NodeGroup = table {
    /// The node group's name.
    1: name string:MAX;

    /// The nodes in the node group.
    2: nodes vector<NodeRepresentation>:MAX;
};

*NodeProperty 是在 Topology.fidl 中定義

範例:焦點技術觸控驅動程式

DFv1 定義

在 DFv1 中,焦距觸控驅動程式包含下列繫結規則: fuchsia.platform;

fuchsia.BIND_COMPOSITE == 1;
fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.platform.BIND_PLATFORM_DEV_VID.GENERIC;
fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH;

複合裝置是在 astro-touch 中定義:

// Composite binding rules for focaltech touch driver.
const zx_bind_inst_t ft_i2c_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
    BI_ABORT_IF(NE, BIND_I2C_BUS_ID, ASTRO_I2C_2),
    BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, I2C_FOCALTECH_TOUCH_ADDR),
};
const zx_bind_inst_t goodix_i2c_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
    BI_ABORT_IF(NE, BIND_I2C_BUS_ID, ASTRO_I2C_2),
    BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, I2C_GOODIX_TOUCH_ADDR),
};
static const zx_bind_inst_t gpio_int_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_TOUCH_INTERRUPT),
};
static const zx_bind_inst_t gpio_reset_match[] = {
    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_TOUCH_RESET),
};

static const device_fragment_part_t ft_i2c_fragment[] = {
    {countof(ft_i2c_match), ft_i2c_match},
};
static const device_fragment_part_t goodix_i2c_fragment[] = {
    {countof(goodix_i2c_match), goodix_i2c_match},
};
static const device_fragment_part_t gpio_int_fragment[] = {
    {countof(gpio_int_match), gpio_int_match},
};
static const device_fragment_part_t gpio_reset_fragment[] = {
    {countof(gpio_reset_match), gpio_reset_match},
};

static const device_fragment_t ft_fragments[] = {
    {"i2c", countof(ft_i2c_fragment), ft_i2c_fragment},
    {"gpio-int", countof(gpio_int_fragment), gpio_int_fragment},
    {"gpio-reset", countof(gpio_reset_fragment), gpio_reset_fragment},
};
static const device_fragment_t goodix_fragments[] = {
    {"i2c", countof(goodix_i2c_fragment), goodix_i2c_fragment},
    {"gpio-int", countof(gpio_int_fragment), gpio_int_fragment},
    {"gpio-reset", countof(gpio_reset_fragment), gpio_reset_fragment},
};

const zx_device_prop_t props[] = {
    {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_GENERIC},
    {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_ASTRO},
    {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_FOCALTOUCH},
};

然後使用 DdkAddComposite() API 新增:

const composite_device_desc_t comp_desc = {
    .props = props,
    .props_count = std::size(props),
    .fragments = ft3x27_touch_fragments,
    .fragments_count = std::size(ft3x27_touch_fragments),
    .primary_fragment = "i2c",
};

zx_status_t status = DdkAddComposite("ft3x27-touch", &comp_desc);
if (status != ZX_OK) {
   zxlogf(ERROR, "%s(ft3x27): CompositeDeviceAdd failed: %d", __func__, status);
   return status;
}
包含節點群組的複合驅動程式

使用節點群組時,節點表示法繫結規則可與 GPIO 接腳規則相符 並為 GPIO 接腳類型提供繫結屬性。這樣一來 複合型驅動程式庫,用於包含非主面板適用的繫結規則 保持開啟。

假設有 fuchsia.gpio 繫結程式庫:

library fuchsia.gpio;

extend uint fuchsia.BIND_PROTOCOL {
  DEVICE = 20,
  IMPL = 21,
};

enum FUNCTION {
   TOUCH_INTERRUPT,
   TOUCH_RESET,
};

節點群組可以定義如下:

node {
   bind_rules {
     fuchsia.BIND_FIDL_PROTOCOL == fuchsia.i2c.BIND_FIDL_PROTOCOL.DEVICE;
     fuchsia.BIND_I2C_BUS_ID == fuchsia.i2c.BIND_I2C_BUS_ID.ASTRO_2;
     fuchsia.BIND_I2C_ADDRESS == fuchsia.i2c.BIND_I2C_ADDRESS.FOCALTECH_TOUCH;
   },
   bind_properties {
     fuchsia.BIND_FIDL_PROTOCOL: fuchsia.i2c.BIND_FIDL_PROTOCOL.DEVICE,
     fuchsia.gpio.FUNCTION: fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH,
   }
}

node {
   bind_rules {
     fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
     fuchsia.BIND_GPIO_PIN == fuchsia.amlogic.platform.s905d3.GPIOZ_PIN_ID.PIN_6;
   },
   bind_properties {
     fuchsia.BIND_PROTOCOL: fuchsia.gpio.BIND_PROTOCOL.DEVICE,
     fuchsia.gpio.FUNCTION: fuchsia.gpio.FUNCTION.TOUCH_INTERRUPT,
     fuchsia.gpio.BIND_PLATFORM_DEV_DID:
        fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH,
   }
}

node {
   bind_rules {
     fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
     fuchsia.BIND_GPIO_PIN == fuchsia.amlogic.platform.s905d3.GPIOZ_PIN_ID.PIN_9;
   },
   bind_properties {
     fuchsia.BIND_PROTOCOL: fuchsia.gpio.BIND_PROTOCOL.DEVICE,
     fuchsia.gpio.FUNCTION: fuchsia.gpio.FUNCTION.TOUCH_RESET,
     fuchsia.BIND_PLATFORM_DEV_DID:
         fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH,
   }
}

有了 driver2 程式庫 (DFv1 的 DDK),驅動程式庫程式碼就可以新增節點 群組:

const fdf::BindRule i2c_bind_rules[] = {
  fdf::BindRule::Accept(
      BIND_FIDL_PROTOCOL, bind_fuchsia_i2c::BIND_FIDL_PROTOCOL_DEVICE),
  fdf::BindRule::Accept(
      BIND_I2C_BUS_ID, bind_fuchsia_i2c::BIND_I2C_BUS_ID_ASTRO_2),
  fdf::BindRule::Accept(
      BIND_I2C_ADDRESS, bind_fuchsia_i2c::BIND_I2C_ADDRESS_FOCALTECH_TOUCH),
};

const fdf::NodeProperty i2c_bind_properties[] = {
  fdf::MakeProperty(BIND_FIDL_PROTOCOL,
     bind_fuchsia_i2c::BIND_FIDL_PROTOCOL_DEVICE),
  fdf::MakeProperty(BIND_PLATFORM_DEV_DID,
     bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_FOCALTOUCH),

};

const fdf::BindRule gpio_interrupt_bind_rules[] = {
  fdf::BindRule::Accept(
      BIND_PROTOCOL, bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
  fdf::BindRule::Accept(
      BIND_GPIO_PIN, bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_4),
}

const fdf::NodeProperty gpio_interrupt_bind_properties[] = {
  fdf::MakeProperty(BIND_PROTOCOL, bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
  fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION,
     bind_fuchsia_gpio::FUNCTION_TOUCH_INTERRUPT),
  fdf::MakeProperty(BIND_PLATFORM_DEV_DID,
     bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_FOCALTOUCH),
};

const fdf::BindRule gpio_reset_bind_rules[] = {
  fdf::BindRule::Accept(
      BIND_PROTOCOL, bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
  fdf::BindRule::Accept(
      BIND_GPIO_PIN, bind_fuchsia_amlogic_platform_s905d2::GPIOZ_PIN_ID_PIN_9),
};

const fdf::NodeProperty gpio_reset_bind_properties[] = {
  fdf::MakeProperty(BIND_PROTOCOL, bind_fuchsia_gpio::BIND_PROTOCOL_DEVICE),
  fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION,
       bind_fuchsia_gpio::FUNCTION_TOUCH_RESET),
  fdf::MakeProperty(BIND_PLATFORM_DEV_DID,
     bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_FOCALTOUCH),
};

auto focaltech_touch_device =
  fdf::NodeGroup(i2c_bind_rules, i2c_bind_properties)
      .AddNodeRepresentation(gpio_interrupt_bind_rules,
          gpio_interrupt_bind_properties)
      .AddNodeRepresentation(gpio_reset_bind_rules, gpio_reset_bind_properties);
fdf::AddNodeGroup(node, focaltech_touch_device);

接著,需要更新 Focaltech 驅動程式庫複合繫結規則:

composite ft3x27_touch;

using fuchsia.amlogic.platform.s905d2;
using fuchsia.gpio;
using fuchsia.i2c;
using fuchsia.platform;

primary node "i2c" {
  fuchsia.BIND_FIDL_PROTOCOL == fuchsia.i2c.BIND_FIDL_PROTOCOL.DEVICE;
  fuchsia.BIND_PLATFORM_DEV_DID ==
      fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH;
}

node "gpio-int" {
  fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
  fuchsia.gpio.GPIO_FUNCTION == fuchsia.gpio.GPIO_FUNCTION.TOUCH_INTERRUPT;
  fuchsia.BIND_PLATFORM_DEV_DID ==
      fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH;
}

node "gpio-reset" {
  fuchsia.BIND_PROTOCOL == fuchsia.gpio.BIND_PROTOCOL.DEVICE;
  fuchsia.gpio.GPIO_FUNCTION == fuchsia.gpio.GPIO_FUNCTION.TOUCH_RESET;
  fuchsia.BIND_PLATFORM_DEV_DID ==
      fuchsia.platform.BIND_PLATFORM_DEV_DID.FOCALTOUCH;
}

DFv2 複合驅動程式的變更

節點群組會取代 DFv2 複合驅動程式目前的機制。於 複合節點日後只能透過節點群組建立建立節點後 群組完整實作 DFv2,我們會將所有複合式驅動程式 並移除目前的機制

實作

這項變更將包含支援的節點群組至「fuchsia.driver.framework」 FIDL API。驅動程式管理器和索引需要更新 處理及追蹤所有節點群組

如要支援選用節點,必須更新繫結編譯器,以支援 使用繫結語言的 optional 關鍵字,並將資訊編碼為 位元碼。

遷移至節點群組

由於所有複合資料都會透過節點群組建立,所有現有項目 DFv1 和 DFv2 中的複合元件必須在準備就緒後遷移至節點群組

在 DFv1 中,AddComposite() 的所有使用方式都將替換為 DDK 中的 AddNodeGroup() 函式呼叫。這包括將驅動程式庫遷移至 ,然後使用複合型繫結規則來建立複合驅動程式庫,再以 AddNodeGroup()

在 DFv2 中,您必須為每個複合驅動程式庫建立相符的節點群組。

由於兩者都支援目前的複合驅動程式庫實作,因此可以 確保驅動程式庫索引與相符節點發生衝突。適用對象 執行個體,如果節點與複合式驅動程式庫或節點群組中的任一節點, 驅動程式庫索引可能只會傳回一個相符項目。避免這種情況的方法之一 系統會優先比對節點群組,而非複合驅動程式。

為避免發生迴歸問題,每個遷移的驅動程式庫都將經過手動驗證, 測試DFv1 的遷移作業並不困難,因此需要更多時間 驗證司機所需費用。

所有複合驅動程式都遷移至節點群組後,我們就能移除 目前的實作程序。

成效

這麼做並不會對效能產生實質影響,因為這與複合結構類似 DFv1 中的節點

人體工學

透過 FIDL 繫結直接建立節點群組並非人體工學。目的地: 我們將在此建立輔助程式庫 driver2,用於定義繫結規則和屬性。

大部分的節點群組都是透過 DSL 定義,例如 ACPI 和裝置 。因此,打造非常符合人體工學的原則並不是首要之務 透過主機驅動程式中的程式碼寫入節點群組

回溯相容性

此版本必須與 DFv1 和 DFv2 相容。為瞭解決這個問題 實作 DFv1 的節點群組DFv1 驅動程式可透過以下方式新增節點群組: DDK。所有 AddComposite() 呼叫都會遷移至節點群組。Compat 輔助程式 必須在 DFv1 和 DFv2 之間進行橋接。

安全性考量

其中一個問題在於節點群組是以動態方式定義 以靜態方式稽核 Jamboard 設定。您可以操控節點 您無須繫結至任何節點的拓撲

為瞭解決這個問題,主機驅動程式庫會是可新增節點群組的主機驅動程式。這個 可能會受到功能限制此外,我們日後會 將重要資料遷移至宣告式格式 (例如裝置樹狀結構和 ACPI) 以便稽核

隱私權注意事項

測試

系統會為此編寫整合測試和單元測試。

說明文件

我們也會更新複合裝置概念說明文件。此外, 建立節點群組時,可於編寫主面板驅動程式庫的教學課程中示範。

缺點、替代方案和未知

雖然 AddNodeGroup() 提供 AddComposite() 中的所有功能,但 仍可能出現缺漏或未能解決的應用情境。於 此外,開始將 AddComposite() 個案件遷移至節點群組時 可能還會找出更多極端情況

有一些較複雜的情況,例如 ACPI 匯流排會動態更新 逐一查看 ACPI 表格並加入複合資料。由於有許多 繫結至 ACPI 複合材料的驅動程式時,我們可能需要遷移多個 司機

既有藝術品和參考資料

驅動程式架構

複合節點

駕駛人繫結