[ddk][api] Add API to get length of device metadata This patch adds a new method (device_get_metadata_size) to the DDK API, which allows the retrieval of the size of a given metadata key on a device. Test: runtests -t driver-test Change-Id: Ib2535b17e3e2b6b9bc225835d6ac27e288aadd52
diff --git a/system/core/devmgr/devhost/api.cpp b/system/core/devmgr/devhost/api.cpp index e1475a4..dcc5ede 100644 --- a/system/core/devmgr/devhost/api.cpp +++ b/system/core/devmgr/devhost/api.cpp
@@ -237,6 +237,13 @@ return devhost_get_metadata(dev_ref, type, buf, buflen, actual); } +__EXPORT zx_status_t device_get_metadata_size(zx_device_t* dev, uint32_t type, + size_t* out_size) { + ApiAutoLock lock; + auto dev_ref = fbl::WrapRefPtr(dev); + return devhost_get_metadata_size(dev_ref, type, out_size); +} + __EXPORT zx_status_t device_add_metadata(zx_device_t* dev, uint32_t type, const void* data, size_t length) { ApiAutoLock lock;
diff --git a/system/core/devmgr/devhost/devhost.cpp b/system/core/devmgr/devhost/devhost.cpp index f7e44db..7eed1eb 100644 --- a/system/core/devmgr/devhost/devhost.cpp +++ b/system/core/devmgr/devhost/devhost.cpp
@@ -1117,6 +1117,30 @@ return ZX_OK; } +zx_status_t devhost_get_metadata_size(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, + size_t* out_length) { + + const zx::channel& rpc = *dev->rpc; + if (!rpc.is_valid()) { + return ZX_ERR_IO_REFUSED; + } + log_rpc(dev, "get-metadata"); + zx_status_t call_status; + zx_status_t status = fuchsia_device_manager_CoordinatorGetMetadataSize( + rpc.get(), type, &call_status, out_length); + if (status != ZX_OK) { + log(ERROR, "devhost: rpc:get-metadata sending failed: %d\n", status); + return status; + } + if (call_status != ZX_OK) { + if (call_status != ZX_ERR_NOT_FOUND) { + log(ERROR, "devhost: rpc:get-metadata failed: %d\n", call_status); + } + return call_status; + } + return ZX_OK; +} + zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, const void* data, size_t length) { if (!data && length) {
diff --git a/system/core/devmgr/devhost/devhost.h b/system/core/devmgr/devhost/devhost.h index 8731f3d..6eb5c5b 100644 --- a/system/core/devmgr/devhost/devhost.h +++ b/system/core/devmgr/devhost/devhost.h
@@ -175,6 +175,9 @@ zx_status_t devhost_get_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, void* buf, size_t buflen, size_t* actual) REQ_DM_LOCK; +zx_status_t devhost_get_metadata_size(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, + size_t* size) REQ_DM_LOCK; + zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, const void* data, size_t length) REQ_DM_LOCK;
diff --git a/system/core/devmgr/devmgr/coordinator.cpp b/system/core/devmgr/devmgr/coordinator.cpp index cdaad7c..c70e3d7 100644 --- a/system/core/devmgr/devmgr/coordinator.cpp +++ b/system/core/devmgr/devmgr/coordinator.cpp
@@ -1122,6 +1122,37 @@ return ZX_ERR_NOT_FOUND; } +zx_status_t Coordinator::GetMetadataSize(Device* dev, uint32_t type, size_t* size) { + // search dev and its parent devices for a match + Device* test = dev; + while (test) { + for (const auto& md : test->metadata) { + if (md.type == type) { + *size = md.length; + return ZX_OK; + } + } + test = test->parent; + } + + // if no metadata is found, check list of metadata added via device_publish_metadata() + char path[fuchsia_device_manager_PATH_MAX]; + zx_status_t status = GetTopoPath(dev, path, sizeof(path)); + if (status != ZX_OK) { + return status; + } + + for (const auto& md : published_metadata_) { + const char* md_path = md.Data() + md.length; + if (md.type == type && path_is_child(md_path, path)) { + *size = md.length; + return ZX_OK; + } + } + + return ZX_ERR_NOT_FOUND; +} + zx_status_t Coordinator::AddMetadata(Device* dev, uint32_t type, const void* data, uint32_t length) { fbl::unique_ptr<Metadata> md; @@ -1303,6 +1334,16 @@ return fuchsia_device_manager_CoordinatorGetMetadata_reply(txn, status, data, actual); } +static zx_status_t fidl_GetMetadataSize(void* ctx, uint32_t key, fidl_txn_t* txn) { + auto dev = static_cast<Device*>(ctx); + size_t size; + zx_status_t status = dev->coordinator->GetMetadataSize(dev, key, &size); + if (status != ZX_OK) { + return fuchsia_device_manager_CoordinatorGetMetadataSize_reply(txn, status, 0); + } + return fuchsia_device_manager_CoordinatorGetMetadataSize_reply(txn, status, size); +} + static zx_status_t fidl_AddMetadata(void* ctx, uint32_t key, const uint8_t* data_data, size_t data_count, fidl_txn_t* txn) { static_assert(fuchsia_device_manager_METADATA_MAX <= UINT32_MAX); @@ -1440,6 +1481,7 @@ .GetTopologicalPath = fidl_GetTopologicalPath, .LoadFirmware = fidl_LoadFirmware, .GetMetadata = fidl_GetMetadata, + .GetMetadataSize = fidl_GetMetadataSize, .AddMetadata = fidl_AddMetadata, .PublishMetadata = fidl_PublishMetadata, .DmCommand = fidl_DmCommand,
diff --git a/system/core/devmgr/devmgr/coordinator.h b/system/core/devmgr/devmgr/coordinator.h index 1b42a4b..239d868 100644 --- a/system/core/devmgr/devmgr/coordinator.h +++ b/system/core/devmgr/devmgr/coordinator.h
@@ -328,6 +328,7 @@ zx_status_t GetMetadata(Device* dev, uint32_t type, void* buffer, size_t buflen, size_t* actual); + zx_status_t GetMetadataSize(Device* dev, uint32_t type, size_t* size); zx_status_t AddMetadata(Device* dev, uint32_t type, const void* data, uint32_t length); zx_status_t PublishMetadata(Device* dev, const char* path, uint32_t type, const void* data, uint32_t length);
diff --git a/system/dev/test/ddk-test/metadata-test.c b/system/dev/test/ddk-test/metadata-test.c index 2cec219..efa65cf 100644 --- a/system/dev/test/ddk-test/metadata-test.c +++ b/system/dev/test/ddk-test/metadata-test.c
@@ -20,9 +20,14 @@ status = device_get_metadata(ddk_test_dev, 1, buffer,sizeof(buffer), &actual); ASSERT_EQ(status, ZX_ERR_NOT_FOUND, "device_get_metadata did not return ZX_ERR_NOT_FOUND"); + status = device_get_metadata_size(ddk_test_dev, 1, &actual); + ASSERT_EQ(status, ZX_ERR_NOT_FOUND, "device_get_metadata_size should return ZX_ERR_NOT_FOUND"); + status = device_add_metadata(ddk_test_dev, 1, TEST_STRING, strlen(TEST_STRING) + 1); ASSERT_EQ(status, ZX_OK, "device_add_metadata failed"); + status = device_get_metadata_size(ddk_test_dev, 1, &actual); + ASSERT_EQ(strlen(TEST_STRING)+1, actual, "Incorrect output length was returned."); status = device_get_metadata(ddk_test_dev, 1, buffer, sizeof(buffer), &actual); ASSERT_EQ(status, ZX_OK, "device_get_metadata failed"); ASSERT_EQ(actual, strlen(TEST_STRING) + 1, "");
diff --git a/system/fidl/fuchsia-device-manager/coordinator.fidl b/system/fidl/fuchsia-device-manager/coordinator.fidl index 227b0a6..d31df50 100644 --- a/system/fidl/fuchsia-device-manager/coordinator.fidl +++ b/system/fidl/fuchsia-device-manager/coordinator.fidl
@@ -128,6 +128,10 @@ 0x10000018: GetMetadata(uint32 key) -> (zx.status status, vector<uint8>:METADATA_MAX? data); + /// Retrieve the metadata size associated with this device and the given key. + GetMetadataSize(uint32 key) + -> (zx.status status, uint64 size); + /// Add metadata blob associated with this device and the given key. /// TODO(teisenbe): Document the behavior of calling this twice with the same /// key. I believe the current behavior results in inaccessible data that is
diff --git a/system/ulib/ddk/include/ddk/device.h b/system/ulib/ddk/include/ddk/device.h index e0115bb..0e0a9e7 100644 --- a/system/ulib/ddk/include/ddk/device.h +++ b/system/ulib/ddk/include/ddk/device.h
@@ -264,6 +264,10 @@ zx_status_t device_get_metadata(zx_device_t* dev, uint32_t type, void* buf, size_t buflen, size_t* actual); +// retrieves metadata size for a specific device +// searches parent devices to find a match +zx_status_t device_get_metadata_size(zx_device_t* dev, uint32_t type, size_t* out_size); + // Adds metadata to a specific device. zx_status_t device_add_metadata(zx_device_t* dev, uint32_t type, const void* data, size_t length);