繫結至裝置節點

為了向 Fuchsia 系統中的裝置提供服務,驅動程式必須繫結至裝置節點。驅動程式管理員會維護節點的拓撲,其中每個節點代表對系統中硬體或虛擬裝置的存取權。繫結至裝置節點後,驅動程式庫就會開始為該節點代表的裝置提供服務。

這個架構會將每個節點的節點屬性與驅動程式庫提供的一組繫結規則建立關聯,藉此比對驅動程式和裝置節點。繫結規則是一組邏輯規則,用於說明驅動程式庫支援的節點屬性。

在本節中,您將建立架構驅動程式庫,以便繫結至 edu 裝置並實作裸驅動程式庫架構掛鉤。

建立新的驅動程式庫元件

首先,請在 Bazel 工作區中為名為 qemu_edu 的驅動程式庫元件建立新的專案目錄:

mkdir -p fuchsia-codelab/qemu_edu/drivers

完成這個部分後,專案應具有以下目錄結構:

//fuchsia-codelab/qemu_edu/drivers
                  |- BUILD.bazel
                  |- meta
                  |   |- qemu_edu.cml
                  |- qemu_edu.bind
                  |- qemu_edu.cc
                  |- qemu_edu.h

建立 qemu_edu/drivers/BUILD.bazel 檔案並新增下列陳述式,從 Fuchsia SDK 納入必要的建構規則:

qemu_edu/drivers/BUILD.bazel

load(
    "@fuchsia_sdk//fuchsia:defs.bzl",
    "fuchsia_cc_driver",
    "fuchsia_component_manifest",
    "fuchsia_driver_bind_bytecode",
    "fuchsia_driver_component",
    "fuchsia_package",
)

新增元件資訊清單

元件資訊清單檔案會定義元件執行檔的屬性,包括繫結規則和元件功能。系統會使用 driver 執行元件,將驅動程式載入為共用程式庫 (.so)。

建立 qemu_edu/drivers/meta/qemu_edu.cml 檔案並新增以下內容:

qemu_edu/drivers/meta/qemu_edu.cml

{
    include: [
        "syslog/client.shard.cml",
    ],
    program: {
        runner: 'driver',
        binary: 'driver/libqemu_edu.so',
        bind: 'meta/bind/qemu_edu.bindbc',
        // Identifies the device categories, for compatibility tests. This
        // example driver uses the 'misc' category; real drivers should
        // select a more specific category.
        device_categories: [
          { category: 'misc', subcategory: '' },
        ],
    },
}

請在 qemu_edu/drivers/BUILD.bazel 檔案的底部新增以下建構規則,以編譯元件資訊清單:

  • fuchsia_component_manifest():說明來源檔案和依附元件,以編譯驅動程式庫元件資訊清單

qemu_edu/drivers/BUILD.bazel

fuchsia_component_manifest(
    name = "manifest",
    src = "meta/qemu_edu.cml",
    includes = [
        "@fuchsia_sdk//pkg/syslog:client",
    ],
)

設定繫結規則

繫結規則會說明這個驅動程式庫可支援哪些裝置節點。這些項目會以一系列條件陳述式的形式列出,可參照裝置節點屬性中的鍵/值組合。為了讓驅動程式庫視為相符,所有規則都必須針對指定裝置節點評估為 true。

建立 qemu_edu/drivers/qemu_edu.bind 並新增下列繫結規則,宣告驅動程式庫支援符合 edu 裝置的 VID 和 DID 的 PCI 裝置:

qemu_edu/drivers/qemu_edu.bind

using fuchsia.pci;

fuchsia.BIND_FIDL_PROTOCOL == fuchsia.pci.BIND_FIDL_PROTOCOL.DEVICE;

// PCI VID/DID pair defined in the QEMU edu device specification:
fuchsia.BIND_PCI_VID == 0x1234;
fuchsia.BIND_PCI_DID == 0x11e8;

請在 qemu_edu/drivers/BUILD.bazel 檔案的底部新增下列建構規則,以便編譯繫結規則:

  • fuchsia_driver_bytecode_bind_rules():說明驅動程式庫的繫結規則的具體細節。rules 屬性會指定包含此驅動程式庫繫結規則的檔案。deps 屬性會指定要與規則中指定的繫結規則搭配使用的繫結程式庫

qemu_edu/drivers/BUILD.bazel

fuchsia_driver_bind_bytecode(
    name = "bind_bytecode",
    output = "qemu_edu.bindbc",
    rules = "qemu_edu.bind",
    deps = [
        "@fuchsia_sdk//bind/fuchsia.pci",
    ],
)

實作驅動程式庫掛鉤

繫結驅動程式庫後,架構會載入元件二進位檔,並建構使用 FUCHSIA_DRIVER_EXPORT() 巨集註冊的驅動程式庫類別例項。驅動程式會覆寫 Start() 方法以執行任何初始化工作。

建立 qemu_edu/drivers/qemu_edu.hqemu_edu/drivers/qemu_edu.cc,並新增下列樣板程式碼,以建立驅動程式庫類別並設定初始 Start() 掛鉤:

qemu_edu/drivers/qemu_edu.h

#ifndef FUCHSIA_CODELAB_CC_QEMU_EDU_H_
#define FUCHSIA_CODELAB_CC_QEMU_EDU_H_

#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/devfs/cpp/connector.h>
#include <fidl/examples.qemuedu/cpp/wire.h>

namespace qemu_edu {

class QemuEduDriver : public fdf::DriverBase {

 public:
  QemuEduDriver(fdf::DriverStartArgs start_args,
                fdf::UnownedSynchronizedDispatcher driver_dispatcher)
      : fdf::DriverBase("qemu-edu", std::move(start_args), std::move(driver_dispatcher)),
        devfs_connector_(fit::bind_member<&QemuEduDriver::Serve>(this)) {}

  virtual ~QemuEduDriver() = default;

  // Start hook called by the driver factory.
  zx::result<> Start() override;

 private:
  zx::result<> ExportToDevfs();
  void Serve(fidl::ServerEnd<examples_qemuedu::Device> request);

  fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
  driver_devfs::Connector<examples_qemuedu::Device> devfs_connector_;
};

}  // namespace qemu_edu

#endif  // FUCHSIA_CODELAB_CC_QEMU_EDU_H_

qemu_edu/drivers/qemu_edu.cc

#include "qemu_edu.h"

#include <lib/driver/component/cpp/driver_export.h>

namespace qemu_edu {

// Initialize this driver instance
zx::result<> QemuEduDriver::Start() {

  FDF_SLOG(INFO, "edu driver loaded successfully");

  return zx::ok();
}

}  // namespace qemu_edu

// Register driver hooks with the framework
FUCHSIA_DRIVER_EXPORT(qemu_edu::QemuEduDriver);

請在 qemu_edu/drivers/BUILD.bazel 檔案的底部新增以下建構規則,將驅動程式庫程式碼編譯為共用程式庫二進位檔:

  • fuchsia_cc_driver():指定用於建構 Fuchsia 專用 C++ 驅動程式庫的來源和標頭檔案 (例如 qemu_edu.ccqemu_edu.h)。

qemu_edu/drivers/BUILD.bazel

fuchsia_cc_driver(
    name = "qemu_edu",
    srcs = [
        "qemu_edu.cc",
        "qemu_edu.h",
    ],
    deps = [
        "@fuchsia_sdk//pkg/driver_component_cpp",
        "@fuchsia_sdk//pkg/driver_devfs_cpp",
        "@fuchsia_sdk//pkg/hwreg",
        "@fuchsia_sdk//pkg/mmio",
    ],
)

載入驅動程式庫

完成初始鷹架後,您可以將驅動程式庫發布至本機套件存放區,並確認驅動程式已成功繫結至 edu 裝置。

qemu_edu/drivers/BUILD.bazel 檔案的底部新增下列規則,將驅動程式庫元件建構至 Fuchsia 套件中:

  • fuchsia_driver_component():說明 qemu_edu 驅動程式庫元件的二進位檔和成果。
  • fuchsia_package():將驅動程式庫元件建構成 Fuchsia 套件

qemu_edu/drivers/BUILD.bazel

fuchsia_driver_component(
    name = "component",
    bind_bytecode = ":bind_bytecode",
    driver_lib = ":qemu_edu",
    manifest = ":manifest",
)

fuchsia_package(
    name = "pkg",
    package_name = "qemu_edu",
    components = [
        ":component",
    ],
    visibility = ["//visibility:public"],
)

使用 bazel run 指令建構並執行元件目標:

bazel run //fuchsia-codelab/qemu_edu/drivers:pkg.component

bazel run 指令會執行下列步驟:

  1. 建構元件和套件。
  2. 將套件發布至本機套件存放區。
  3. 使用目標裝置註冊套件存放區。
  4. 使用 ffx driver register 載入驅動程式庫元件。

您應該會看到驅動程式庫架構會自動偵測與 edu 裝置節點的相符。

INFO: Build completed successfully, 1 total action
added repository bazel.pkg.component
Registering fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
Successfully bound:
Node 'root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl', Driver 'fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm'.

檢查系統記錄,確認驅動程式庫成功繫結後,您可以從驅動程式庫程式碼看到 FDF_SLOG() 訊息:

ffx log --filter qemu_edu
[driver_index][driver_index,driver][I] Registered driver successfully: fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm.
[driver_manager][driver_manager.cm][I]: [driver_runner.cc:959] Binding fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm to  00_06_0_
[full-pkg-drivers:root.sys.platform.pt.PCI0.bus.00_06_0_][qemu-edu,driver][I]: [fuchsia-codelab/qemu_edu/qemu_edu.cc:28] edu driver loaded successfully
[driver-hosts:driver-host-3][][I]: [../../src/devices/bin/driver_host/driver_host.cc:349] Started driver url=fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm

瞭解更新的裝置節點

現在驅動程式庫已成功繫結至裝置節點,ffx driver list 會回報驅動程式已載入:

ffx driver list --loaded
fuchsia-boot:///#meta/block.core.cm
fuchsia-boot:///#meta/bus-pci.cm
fuchsia-boot:///#meta/cpu-trace.cm
fuchsia-boot:///#meta/fvm.cm
fuchsia-boot:///#meta/hid.cm
fuchsia-boot:///#meta/intel-rtc.cm
fuchsia-boot:///#meta/netdevice-migration.cm
fuchsia-boot:///#meta/network-device.cm
fuchsia-boot:///#meta/pc-ps2.cm
fuchsia-boot:///#meta/platform-bus-x86.cm
fuchsia-boot:///#meta/platform-bus.cm
fuchsia-boot:///#meta/ramdisk.cm
fuchsia-boot:///#meta/sysmem.cm
fuchsia-boot:///#meta/virtio_block.cm
fuchsia-boot:///#meta/virtio_ethernet.cm
fuchsia-pkg://fuchsia.com/virtual_audio#meta/virtual_audio_driver.cm
fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm

使用 ffx driver list-devices 再次檢查裝置節點,並確認驅動程式現已列為 edu 裝置節點:

ffx driver list-devices root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl --verbose
Name     : 0-fidl
Moniker  : root.sys.platform.pt.PCI0.bus.00_06_0_.pci-00_06.0-fidl
Driver   : fuchsia-pkg://bazel.pkg.component/qemu_edu#meta/qemu_edu.cm
11 Properties
[ 1/ 11] : Key fuchsia.BIND_FIDL_PROTOCOL     Value 0x000004
[ 2/ 11] : Key fuchsia.BIND_PCI_VID           Value 0x001234
[ 3/ 11] : Key fuchsia.BIND_PCI_DID           Value 0x0011e8
[ 4/ 11] : Key fuchsia.BIND_PCI_CLASS         Value 0x000000
[ 5/ 11] : Key fuchsia.BIND_PCI_SUBCLASS      Value 0x0000ff
[ 6/ 11] : Key fuchsia.BIND_PCI_INTERFACE     Value 0x000000
[ 7/ 11] : Key fuchsia.BIND_PCI_REVISION      Value 0x000010
[ 8/ 11] : Key fuchsia.BIND_PCI_TOPO          Value 0x000030
[ 9/ 11] : Key "fuchsia.hardware.pci.Device"  Value true
[10/ 11] : Key fuchsia.BIND_PROTOCOL          Value 0x000000
[11/ 11] : Key "fuchsia.platform.DRIVER_FRAMEWORK_VERSION" Value 0x000002

恭喜!您已成功將驅動程式庫元件繫結至 Fuchsia 上的裝置節點。