驅動程式元件可提供為其他駕駛人提供的功能和服務 非驅動程式庫元件的功能。 如此一來, Fuchsia 的元件架構就能將這些能力轉化為 以及目標元件駕駛也可以將自身能力匯出至 devfs,讓其他元件能夠以檔案形式加以探索 元件的命名空間
在本節中,您將公開 qemu_edu
驅動程式庫的階乘功能
從系統其他位置執行的元件取用
建立新的 FIDL 程式庫
在 Bazel 工作區中,為新的 FIDL 程式庫建立新的專案目錄:
mkdir -p fuchsia-codelab/qemu_edu/fidl
完成這個部分後,專案應具備下列目錄: 結構:
//fuchsia-codelab/qemu_edu/fidl
|- BUILD.bazel
|- qemu_edu.fidl
建立 qemu_edu/fidl/BUILD.bazel
檔案,並將下列陳述式新增至
包含 Fuchsia SDK 的必要建構規則:
qemu_edu/fidl/BUILD.bazel
:
load(
"@fuchsia_sdk//fuchsia:defs.bzl",
"fuchsia_fidl_library",
"fuchsia_fidl_llcpp_library",
)
定義驅動程式庫服務通訊協定
驅動程式會使用自訂 FIDL 公開 edu
裝置的功能
因此效能相當卓越使用以下指令將新的「qemu_edu/qemu_edu.fidl
」檔案新增至專案工作區:
包含下列內容:
qemu_edu/fidl/qemu_edu.fidl
:
library examples.qemuedu;
using zx;
/// The Device protocol provides access to the functions of the QEMU edu hardware.
@discoverable
open protocol Device {
/// Computes the factorial of 'input' using the edu device and returns the
/// result.
flexible ComputeFactorial(struct {
input uint32;
}) -> (struct {
output uint32;
}) error zx.Status;
/// Performs a liveness check and return true if the device passes.
flexible LivenessCheck() -> (struct {
result bool;
}) error zx.Status;
};
/// The Service enables the driver framework to offer the Device protocol to
/// other components.
service Service {
device client_end:Device;
};
此 FIDL 通訊協定提供兩種與階乘互動的方法
運算和有效性檢查硬體註冊都會在 edu
裝置上註冊。
將下列建構規則新增至專案的建構設定底部 編譯 FIDL 程式庫並產生 C++ 繫結:
fuchsia_fidl_library()
:宣告examples.qemuedu
FIDL ,並描述其包含的 FIDL 來源檔案。fuchsia_fidl_llcpp_library()
:說明產生的 給元件的 C++ 連接線 與此 FIDL 程式庫互動
qemu_edu/fidl/BUILD.bazel
:
fuchsia_fidl_library(
name = "examples.qemuedu",
srcs = [
"qemu_edu.fidl",
],
library = "examples.qemuedu",
visibility = ["//visibility:public"],
deps = [
"@fuchsia_sdk//fidl/zx",
],
)
fuchsia_fidl_llcpp_library(
name = "examples.qemuedu_cc",
library = ":examples.qemuedu",
visibility = ["//visibility:public"],
deps = [
"@fuchsia_sdk//fidl/zx:zx_llcpp_cc",
"@fuchsia_sdk//pkg/fidl_cpp_wire",
],
)
實作驅動程式庫服務通訊協定
定義 FIDL 通訊協定後,您需要更新驅動程式庫才能導入 並將這個通訊協定提供給其他元件
完成這個部分後,專案應具備下列目錄: 結構:
//fuchsia-codelab/qemu_edu/drivers
|- BUILD.bazel
|- meta
| |- qemu_edu.cml
|- edu_device.cc
|- edu_device.h
|- edu_server.cc
|- edu_server.h
|- qemu_edu.bind
|- qemu_edu.cc
|- qemu_edu.h
在專案目錄中建立新的 qemu_edu/drivers/edu_server.h
檔案
並在當中加入下列內容:
examples.qemuedu
程式庫並建立新的 QemuEduServer
類別,
實作 FIDL 通訊協定的伺服器端:
qemu_edu/drivers/edu_server.h
:
#ifndef FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_
#define FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_
#include <fidl/examples.qemuedu/cpp/wire.h>
#include <lib/driver/logging/cpp/structured_logger.h>
#include "edu_device.h"
namespace qemu_edu {
// FIDL server implementation for the `examples.qemuedu/Device` protocol.
class QemuEduServer : public fidl::WireServer<examples_qemuedu::Device> {
public:
explicit QemuEduServer(std::weak_ptr<edu_device::QemuEduDevice> device)
: device_(std::move(device)) {}
static fidl::ServerBindingRef<examples_qemuedu::Device> BindDeviceClient(
async_dispatcher_t* dispatcher, std::weak_ptr<edu_device::QemuEduDevice> device,
fidl::ServerEnd<examples_qemuedu::Device> request) {
// Bind each connection request to a unique FIDL server instance
auto server_impl = std::make_unique<QemuEduServer>(device);
return fidl::BindServer(dispatcher, std::move(request), std::move(server_impl),
std::mem_fn(&QemuEduServer::OnUnbound));
}
// This method is called when a server connection is torn down.
void OnUnbound(fidl::UnbindInfo info, fidl::ServerEnd<examples_qemuedu::Device> server_end) {
if (info.is_peer_closed()) {
FDF_LOG(DEBUG, "Client disconnected");
} else if (!info.is_user_initiated()) {
FDF_LOG(ERROR, "Client connection unbound: %s", info.status_string());
}
}
// fidl::WireServer<examples_qemuedu::Device>
void ComputeFactorial(ComputeFactorialRequestView request,
ComputeFactorialCompleter::Sync& completer) override;
void LivenessCheck(LivenessCheckCompleter::Sync& completer) override;
void handle_unknown_method(fidl::UnknownMethodMetadata<examples_qemuedu::Device> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
private:
std::weak_ptr<edu_device::QemuEduDevice> device_;
};
} // namespace qemu_edu
#endif // FUCHSIA_CODELAB_QEMU_EDU_SERVER_H_
在專案目錄中建立新的 qemu_edu/drivers/edu_server.cc
檔案
包含下列內容來實作 examples.qemuedu/Device
並對應至裝置資源方法:
qemu_edu/drivers/edu_server.cc
:
#include "edu_server.h"
namespace qemu_edu {
// Driver Service: Compute factorial on the edu device
void QemuEduServer::ComputeFactorial(ComputeFactorialRequestView request,
ComputeFactorialCompleter::Sync& completer) {
auto edu_device = device_.lock();
if (!edu_device) {
FDF_LOG(ERROR, "Unable to access device resources.");
completer.ReplyError(ZX_ERR_BAD_STATE);
return;
}
uint32_t input = request->input;
edu_device->ComputeFactorial(
input, [completer = completer.ToAsync()](zx::result<uint32_t> result_status) mutable {
if (result_status.is_error()) {
completer.ReplyError(result_status.error_value());
return;
}
uint32_t factorial = result_status.value();
completer.ReplySuccess(factorial);
});
}
// Driver Service: Complete a liveness check on the edu device
void QemuEduServer::LivenessCheck(LivenessCheckCompleter::Sync& completer) {
auto edu_device = device_.lock();
if (!edu_device) {
FDF_LOG(ERROR, "Unable to access device resources.");
completer.ReplyError(ZX_ERR_BAD_STATE);
return;
}
constexpr uint32_t kChallenge = 0xdeadbeef;
constexpr uint32_t kExpectedResponse = ~(kChallenge);
auto status = edu_device->LivenessCheck(kChallenge);
if (status.is_error()) {
FDF_LOG(ERROR, "Unable to send liveness check request.");
completer.ReplyError(status.error_value());
return;
}
const bool alive = (status.value() == kExpectedResponse);
FDF_SLOG(INFO, "Replying with", KV("result", alive));
completer.ReplySuccess(alive);
}
} // namespace qemu_edu
更新驅動程式庫的元件資訊清單,以宣告並公開 FIDL 通訊協定 一項能力
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: '' },
],
},
use: [
{ service: 'fuchsia.hardware.pci.Service' },
],
// Provide the device capability to other components
capabilities: [
{ service: 'examples.qemuedu.Service' },
],
expose: [
{
service: 'examples.qemuedu.Service',
from: 'self',
},
],
}
更新驅動程式庫的建構設定,以依附於
新的 examples.qemuedu
程式庫:
qemu_edu/drivers/BUILD.bazel
:
fuchsia_cc_driver(
name = "qemu_edu",
srcs = [
"edu_device.cc",
"edu_device.h",
"edu_server.cc",
"edu_server.h",
"qemu_edu.cc",
"qemu_edu.h",
],
deps = [
"//fuchsia-codelab/qemu_edu/fidl:examples.qemuedu_cc",
"@fuchsia_sdk//fidl/fuchsia.hardware.pci:fuchsia.hardware.pci_llcpp_cc",
"@fuchsia_sdk//pkg/driver_component_cpp",
"@fuchsia_sdk//pkg/driver_devfs_cpp",
"@fuchsia_sdk//pkg/hwreg",
"@fuchsia_sdk//pkg/mmio",
],
)
匯出及提供通訊協定
qemu_edu
驅動程式庫會使 examples.qemuedu/Device
通訊協定成為
可透過 devfs 找到其他元件用於找出哪些驅動程式庫服務
可以使用非驅動程式庫元件查詢裝置
檔案系統 (通常掛接到元件命名空間中的 /dev
),然後掃描
檔案系統下的目錄和檔案
驅動程式管理員可將 devfs 中的項目別名為特定裝置類別項目
(例如 /dev/class/input
) 會將通訊協定 ID 與已知
提供的裝置類別如果非驅動程式庫元件不知道確切路徑
是特定類型,而非特定類型
在本練習中,edu
裝置不符合已知的類別,因此您將
將這個項目設為未分類裝置。
更新驅動程式庫元件的資訊清單,以要求 fuchsia.devics.fs.Exporter
能力:
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: '' },
],
},
use: [
{ service: 'fuchsia.hardware.pci.Service' },
],
// Provide the device capability to other components
capabilities: [
{ service: 'examples.qemuedu.Service' },
],
expose: [
{
service: 'examples.qemuedu.Service',
from: 'self',
},
],
}
更新驅動程式庫的 Start()
方法,開始提供 examples.qemuedu/Device
通訊協定
複製到符合裝置節點拓撲路徑的新 devfs 項目:
qemu_edu/drivers/qemu_edu.cc
:
#include "qemu_edu.h"
#include <lib/driver/component/cpp/driver_export.h>
#include "edu_server.h"
// Initialize this driver instance
zx::result<> QemuEduDriver::Start() {
// ...
// Report the version information from the edu device.
auto version_reg = device_->IdentificationRegister();
FDF_SLOG(INFO, "edu device version", KV("major", version_reg.major_version()),
KV("minor", version_reg.minor_version()));
// Serve the examples.qemuedu/Service capability.
examples_qemuedu::Service::InstanceHandler handler({
.device = fit::bind_member<&QemuEduDriver::Serve>(this),
});
auto add_result = outgoing()->AddService<examples_qemuedu::Service>(std::move(handler));
if (add_result.is_error()) {
FDF_SLOG(ERROR, "Failed to add Device service", KV("status", add_result.status_string()));
return add_result.take_error();
}
if (zx::result result = ExportToDevfs(); result.is_error()) {
FDF_SLOG(ERROR, "Failed to export to devfs", KV("status", result.status_string()));
return result.take_error();
}
// Create and export a devfs entry for the driver service.
return zx::ok();
}
其他元件現在可找到 qemu_edu
驅動程式庫的功能。
重建驅動程式庫
使用 bazel build
指令驗證驅動程式庫是否成功建構:
程式碼變更:
bazel build //fuchsia-codelab/qemu_edu/drivers:pkg
恭喜!您已成功從 Fuchsia 驅動程式公開 FIDL 服務。