1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "platform-device.h" 6 7#include <assert.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11 12#include <ddk/binding.h> 13#include <ddk/debug.h> 14#include <ddk/device.h> 15#include <ddk/driver.h> 16#include <ddk/metadata.h> 17#include <ddk/protocol/platform-defs.h> 18#include <fbl/function.h> 19#include <zircon/syscalls/resource.h> 20 21#include "platform-bus.h" 22 23namespace platform_bus { 24 25zx_status_t PlatformDevice::Create(const pbus_dev_t* pdev, zx_device_t* parent, PlatformBus* bus, 26 fbl::unique_ptr<platform_bus::PlatformDevice>* out) { 27 fbl::AllocChecker ac; 28 fbl::unique_ptr<platform_bus::PlatformDevice> dev(new (&ac) 29 platform_bus::PlatformDevice(parent, bus, pdev)); 30 if (!ac.check()) { 31 return ZX_ERR_NO_MEMORY; 32 } 33 auto status = dev->Init(pdev); 34 if (status != ZX_OK) { 35 return status; 36 } 37 out->swap(dev); 38 return ZX_OK; 39} 40 41PlatformDevice::PlatformDevice(zx_device_t* parent, PlatformBus* bus, const pbus_dev_t* pdev) 42 : PlatformDeviceType(parent), bus_(bus), vid_(pdev->vid), pid_(pdev->pid), 43 did_(pdev->did), resource_tree_(ROOT_DEVICE_ID) { 44 strlcpy(name_, pdev->name, sizeof(name_)); 45} 46 47zx_status_t PlatformDevice::Init(const pbus_dev_t* pdev) { 48 uint32_t next_device_id = ROOT_DEVICE_ID + 1; 49 auto status = resource_tree_.Init(pdev, &next_device_id); 50 if (status != ZX_OK) { 51 return status; 52 } 53 54 fbl::AllocChecker ac; 55 device_index_.reserve(resource_tree_.DeviceCount(), &ac); 56 if (!ac.check()) { 57 return ZX_ERR_NO_MEMORY; 58 } 59 resource_tree_.BuildDeviceIndex(&device_index_); 60 61 return ZX_OK; 62} 63 64// Create a resource and pass it back to the proxy along with necessary metadata 65// to create/map the VMO in the driver process. 66zx_status_t PlatformDevice::RpcGetMmio(const DeviceResources* dr, uint32_t index, zx_paddr_t* out_paddr, 67 size_t* out_length, zx_handle_t* out_handle, 68 uint32_t* out_handle_count) { 69 if (index >= dr->mmio_count()) { 70 return ZX_ERR_OUT_OF_RANGE; 71 } 72 73 const pbus_mmio_t& mmio = dr->mmio(index); 74 zx_handle_t handle; 75 char rsrc_name[ZX_MAX_NAME_LEN]; 76 snprintf(rsrc_name, ZX_MAX_NAME_LEN - 1, "%s.pbus[%u]", name_, index); 77 zx_status_t status = zx_resource_create(bus_->GetResource(), ZX_RSRC_KIND_MMIO, mmio.base, 78 mmio.length, rsrc_name, sizeof(rsrc_name), &handle); 79 if (status != ZX_OK) { 80 zxlogf(ERROR, "%s: pdev_rpc_get_mmio: zx_resource_create failed: %d\n", name_, status); 81 return status; 82 } 83 84 *out_paddr = mmio.base; 85 *out_length = mmio.length; 86 *out_handle_count = 1; 87 *out_handle = handle; 88 return ZX_OK; 89} 90 91// Create a resource and pass it back to the proxy along with necessary metadata 92// to create the IRQ in the driver process. 93zx_status_t PlatformDevice::RpcGetInterrupt(const DeviceResources* dr, uint32_t index, 94 uint32_t* out_irq, uint32_t* out_mode, 95 zx_handle_t* out_handle, uint32_t* out_handle_count) { 96 if (index >= dr->irq_count()) { 97 return ZX_ERR_OUT_OF_RANGE; 98 } 99 100 zx_handle_t handle; 101 const pbus_irq_t& irq = dr->irq(index); 102 uint32_t options = ZX_RSRC_KIND_IRQ | ZX_RSRC_FLAG_EXCLUSIVE; 103 char rsrc_name[ZX_MAX_NAME_LEN]; 104 snprintf(rsrc_name, ZX_MAX_NAME_LEN - 1, "%s.pbus[%u]", name_, index); 105 zx_status_t status = zx_resource_create(bus_->GetResource(), options, irq.irq, 1, rsrc_name, 106 sizeof(rsrc_name), &handle); 107 if (status != ZX_OK) { 108 return status; 109 } 110 111 *out_irq = irq.irq; 112 *out_mode = irq.mode; 113 *out_handle_count = 1; 114 *out_handle = handle; 115 return status; 116} 117 118zx_status_t PlatformDevice::RpcGetBti(const DeviceResources* dr, uint32_t index, 119 zx_handle_t* out_handle, uint32_t* out_handle_count) { 120 if (index >= dr->bti_count()) { 121 return ZX_ERR_OUT_OF_RANGE; 122 } 123 124 const pbus_bti_t& bti = dr->bti(index); 125 126 zx_status_t status = bus_->GetBti(bti.iommu_index, bti.bti_id, out_handle); 127 128 if (status == ZX_OK) { 129 *out_handle_count = 1; 130 } 131 132 return status; 133} 134 135zx_status_t PlatformDevice::RpcGetDeviceInfo(const DeviceResources* dr, pdev_device_info_t* out_info) { 136 pdev_device_info_t info = { 137 .vid = vid_, 138 .pid = pid_, 139 .did = did_, 140 .mmio_count = static_cast<uint32_t>(dr->mmio_count()), 141 .irq_count = static_cast<uint32_t>(dr->irq_count()), 142 .gpio_count = static_cast<uint32_t>(dr->gpio_count()), 143 .i2c_channel_count = static_cast<uint32_t>(dr->i2c_channel_count()), 144 .clk_count = static_cast<uint32_t>(dr->clk_count()), 145 .bti_count = static_cast<uint32_t>(dr->bti_count()), 146 .metadata_count = static_cast<uint32_t>(dr->metadata_count() + dr->boot_metadata_count()), 147 .reserved = {}, 148 .name = {}, 149 }; 150 static_assert(sizeof(info.name) == sizeof(name_), ""); 151 memcpy(info.name, name_, sizeof(out_info->name)); 152 memcpy(out_info, &info, sizeof(info)); 153 154 return ZX_OK; 155} 156 157zx_status_t PlatformDevice::RpcDeviceAdd(const DeviceResources* dr, uint32_t index, 158 uint32_t* out_device_id) { 159 if (index >= dr->child_count()) { 160 return ZX_ERR_OUT_OF_RANGE; 161 } 162 // TODO(voydanoff) verify that this device has not already been added? 163 *out_device_id = dr->child_index(index); 164 return ZX_OK; 165} 166 167zx_status_t PlatformDevice::RpcGetMetadata(const DeviceResources* dr, uint32_t index, 168 uint32_t* out_type, uint8_t* buf, uint32_t buf_size, 169 uint32_t* actual) { 170 if (index >= dr->metadata_count() + dr->boot_metadata_count()) { 171 return ZX_ERR_OUT_OF_RANGE; 172 } 173 174 if (index < dr->metadata_count()) { 175 auto& metadata = dr->metadata(index); 176 if (metadata.len > buf_size) { 177 return ZX_ERR_BUFFER_TOO_SMALL; 178 } 179 memcpy(buf, metadata.data, metadata.len); 180 *out_type = metadata.type; 181 *actual = metadata.len; 182 return ZX_OK; 183 } else { 184 // boot_metadata indices follow metadata indices. 185 index -= static_cast<uint32_t>(dr->metadata_count()); 186 187 auto& metadata = dr->boot_metadata(index); 188 const void* data; 189 uint32_t length; 190 auto status = bus_->GetZbiMetadata(metadata.zbi_type, metadata.zbi_extra, &data, &length); 191 if (status == ZX_OK) { 192 if (length > buf_size) { 193 return ZX_ERR_BUFFER_TOO_SMALL; 194 } 195 memcpy(buf, data, length); 196 *out_type = metadata.zbi_type; 197 *actual = length; 198 } 199 return status; 200 } 201} 202 203zx_status_t PlatformDevice::RpcGetProtocols(const DeviceResources* dr, uint32_t* out_protocols, 204 uint32_t* out_protocol_count) { 205 auto count = dr->protocol_count(); 206 memcpy(out_protocols, dr->protocols(), count * sizeof(*out_protocols)); 207 *out_protocol_count = static_cast<uint32_t>(count); 208 return ZX_OK; 209} 210 211zx_status_t PlatformDevice::RpcGpioConfigIn(const DeviceResources* dr, uint32_t index, uint32_t flags) { 212 if (bus_->gpio() == nullptr) { 213 return ZX_ERR_NOT_SUPPORTED; 214 } 215 if (index >= dr->gpio_count()) { 216 return ZX_ERR_OUT_OF_RANGE; 217 } 218 219 return bus_->gpio()->ConfigIn(dr->gpio(index).gpio, flags); 220} 221 222zx_status_t PlatformDevice::RpcGpioConfigOut(const DeviceResources* dr, uint32_t index, 223 uint8_t initial_value) { 224 if (bus_->gpio() == nullptr) { 225 return ZX_ERR_NOT_SUPPORTED; 226 } 227 if (index >= dr->gpio_count()) { 228 return ZX_ERR_OUT_OF_RANGE; 229 } 230 231 return bus_->gpio()->ConfigOut(dr->gpio(index).gpio, initial_value); 232} 233 234zx_status_t PlatformDevice::RpcGpioSetAltFunction(const DeviceResources* dr, uint32_t index, 235 uint64_t function) { 236 if (bus_->gpio() == nullptr) { 237 return ZX_ERR_NOT_SUPPORTED; 238 } 239 if (index >= dr->gpio_count()) { 240 return ZX_ERR_OUT_OF_RANGE; 241 } 242 243 return bus_->gpio()->SetAltFunction(dr->gpio(index).gpio, function); 244} 245 246zx_status_t PlatformDevice::RpcGpioRead(const DeviceResources* dr, uint32_t index, 247 uint8_t* out_value) { 248 if (bus_->gpio() == nullptr) { 249 return ZX_ERR_NOT_SUPPORTED; 250 } 251 if (index >= dr->gpio_count()) { 252 return ZX_ERR_OUT_OF_RANGE; 253 } 254 255 return bus_->gpio()->Read(dr->gpio(index).gpio, out_value); 256} 257 258zx_status_t PlatformDevice::RpcGpioWrite(const DeviceResources* dr, uint32_t index, uint8_t value) { 259 if (bus_->gpio() == nullptr) { 260 return ZX_ERR_NOT_SUPPORTED; 261 } 262 if (index >= dr->gpio_count()) { 263 return ZX_ERR_OUT_OF_RANGE; 264 } 265 266 return bus_->gpio()->Write(dr->gpio(index).gpio, value); 267} 268 269zx_status_t PlatformDevice::RpcGpioGetInterrupt(const DeviceResources* dr, uint32_t index, 270 uint32_t flags, zx_handle_t* out_handle, 271 uint32_t* out_handle_count) { 272 if (bus_->gpio() == nullptr) { 273 return ZX_ERR_NOT_SUPPORTED; 274 } 275 if (index >= dr->gpio_count()) { 276 return ZX_ERR_OUT_OF_RANGE; 277 } 278 279 zx_status_t status = bus_->gpio()->GetInterrupt(dr->gpio(index).gpio, flags, out_handle); 280 if (status == ZX_OK) { 281 *out_handle_count = 1; 282 } 283 return status; 284} 285 286zx_status_t PlatformDevice::RpcGpioReleaseInterrupt(const DeviceResources* dr, uint32_t index) { 287 if (bus_->gpio() == nullptr) { 288 return ZX_ERR_NOT_SUPPORTED; 289 } 290 if (index >= dr->gpio_count()) { 291 return ZX_ERR_OUT_OF_RANGE; 292 } 293 return bus_->gpio()->ReleaseInterrupt(dr->gpio(index).gpio); 294} 295 296zx_status_t PlatformDevice::RpcGpioSetPolarity(const DeviceResources* dr, uint32_t index, 297 uint32_t flags) { 298 if (bus_->gpio() == nullptr) { 299 return ZX_ERR_NOT_SUPPORTED; 300 } 301 if (index >= dr->gpio_count()) { 302 return ZX_ERR_OUT_OF_RANGE; 303 } 304 return bus_->gpio()->SetPolarity(dr->gpio(index).gpio, flags); 305} 306 307zx_status_t PlatformDevice::RpcI2cTransact(const DeviceResources* dr, uint32_t txid, 308 rpc_i2c_req_t* req, zx_handle_t channel) { 309 if (bus_->i2c() == nullptr) { 310 return ZX_ERR_NOT_SUPPORTED; 311 } 312 uint32_t index = req->index; 313 if (index >= dr->i2c_channel_count()) { 314 return ZX_ERR_OUT_OF_RANGE; 315 } 316 const pbus_i2c_channel_t& pdev_channel = dr->i2c_channel(index); 317 318 return bus_->I2cTransact(txid, req, &pdev_channel, channel); 319} 320 321zx_status_t PlatformDevice::RpcI2cGetMaxTransferSize(const DeviceResources* dr, uint32_t index, 322 size_t* out_size) { 323 if (bus_->i2c() == nullptr) { 324 return ZX_ERR_NOT_SUPPORTED; 325 } 326 if (index >= dr->i2c_channel_count()) { 327 return ZX_ERR_OUT_OF_RANGE; 328 } 329 const pbus_i2c_channel_t& pdev_channel = dr->i2c_channel(index); 330 331 return bus_->i2c()->GetMaxTransferSize(pdev_channel.bus_id, out_size); 332} 333 334zx_status_t PlatformDevice::RpcClkEnable(const DeviceResources* dr, uint32_t index) { 335 if (bus_->clk() == nullptr) { 336 return ZX_ERR_NOT_SUPPORTED; 337 } 338 if (index >= dr->clk_count()) { 339 return ZX_ERR_OUT_OF_RANGE; 340 } 341 342 return bus_->clk()->Enable(dr->clk(index).clk); 343} 344 345zx_status_t PlatformDevice::RpcClkDisable(const DeviceResources* dr, uint32_t index) { 346 if (bus_->clk() == nullptr) { 347 return ZX_ERR_NOT_SUPPORTED; 348 } 349 if (index >= dr->clk_count()) { 350 return ZX_ERR_OUT_OF_RANGE; 351 } 352 353 return bus_->clk()->Disable(dr->clk(index).clk); 354} 355 356zx_status_t PlatformDevice::DdkRxrpc(zx_handle_t channel) { 357 if (channel == ZX_HANDLE_INVALID) { 358 // proxy device has connected 359 return ZX_OK; 360 } 361 362 uint8_t req_buf[PROXY_MAX_TRANSFER_SIZE]; 363 uint8_t resp_buf[PROXY_MAX_TRANSFER_SIZE]; 364 auto* req_header = reinterpret_cast<platform_proxy_req_t*>(&req_buf); 365 auto* resp_header = reinterpret_cast<platform_proxy_rsp_t*>(&resp_buf); 366 uint32_t actual; 367 zx_handle_t req_handles[ZX_CHANNEL_MAX_MSG_HANDLES]; 368 zx_handle_t resp_handles[ZX_CHANNEL_MAX_MSG_HANDLES]; 369 uint32_t req_handle_count; 370 uint32_t resp_handle_count = 0; 371 372 auto status = zx_channel_read(channel, 0, &req_buf, req_handles, sizeof(req_buf), 373 fbl::count_of(req_handles), &actual, &req_handle_count); 374 if (status != ZX_OK) { 375 zxlogf(ERROR, "platform_dev_rxrpc: zx_channel_read failed %d\n", status); 376 return status; 377 } 378 379 const uint32_t index = req_header->device_id; 380 if (index >= device_index_.size()) { 381 return ZX_ERR_OUT_OF_RANGE; 382 } 383 const DeviceResources* dr = device_index_[index]; 384 385 resp_header->txid = req_header->txid; 386 uint32_t resp_len; 387 388 switch (req_header->proto_id) { 389 case ZX_PROTOCOL_PLATFORM_DEV: { 390 auto req = reinterpret_cast<rpc_pdev_req_t*>(&req_buf); 391 if (actual < sizeof(*req)) { 392 zxlogf(ERROR, "%s received %u, expecting %zu\n", __FUNCTION__, actual, sizeof(*req)); 393 return ZX_ERR_INTERNAL; 394 } 395 auto resp = reinterpret_cast<rpc_pdev_rsp_t*>(&resp_buf); 396 resp_len = sizeof(*resp); 397 398 switch (req_header->op) { 399 case PDEV_GET_MMIO: 400 status = RpcGetMmio(dr, req->index, &resp->paddr, &resp->length, resp_handles, 401 &resp_handle_count); 402 break; 403 case PDEV_GET_INTERRUPT: 404 status = RpcGetInterrupt(dr, req->index, &resp->irq, &resp->mode, resp_handles, 405 &resp_handle_count); 406 break; 407 case PDEV_GET_BTI: 408 status = RpcGetBti(dr, req->index, resp_handles, &resp_handle_count); 409 break; 410 case PDEV_GET_DEVICE_INFO: 411 status = RpcGetDeviceInfo(dr, &resp->device_info); 412 break; 413 case PDEV_GET_BOARD_INFO: 414 status = bus_->GetBoardInfo(&resp->board_info); 415 break; 416 case PDEV_DEVICE_ADD: 417 status = RpcDeviceAdd(dr, req->index, &resp->device_id); 418 break; 419 case PDEV_GET_METADATA: { 420 auto resp = reinterpret_cast<rpc_pdev_metadata_rsp_t*>(resp_buf); 421 static_assert(sizeof(*resp) == sizeof(resp_buf), ""); 422 auto buf_size = static_cast<uint32_t>(sizeof(resp_buf) - sizeof(*resp_header)); 423 status = RpcGetMetadata(dr, req->index, &resp->pdev.metadata_type, resp->metadata, 424 buf_size, &resp->pdev.metadata_length); 425 resp_len += resp->pdev.metadata_length; 426 break; 427 } 428 case PDEV_GET_PROTOCOLS: { 429 auto protos = reinterpret_cast<uint32_t*>(&resp[1]); 430 status = RpcGetProtocols(dr, protos, &resp->protocol_count); 431 resp_len += static_cast<uint32_t>(resp->protocol_count * sizeof(*protos)); 432 break; 433 } 434 default: 435 zxlogf(ERROR, "%s: unknown pdev op %u\n", __func__, req_header->op); 436 return ZX_ERR_INTERNAL; 437 } 438 break; 439 } 440 case ZX_PROTOCOL_GPIO: { 441 auto req = reinterpret_cast<rpc_gpio_req_t*>(&req_buf); 442 if (actual < sizeof(*req)) { 443 zxlogf(ERROR, "%s received %u, expecting %zu\n", __FUNCTION__, actual, sizeof(*req)); 444 return ZX_ERR_INTERNAL; 445 } 446 auto resp = reinterpret_cast<rpc_gpio_rsp_t*>(&resp_buf); 447 resp_len = sizeof(*resp); 448 449 switch (req_header->op) { 450 case GPIO_CONFIG_IN: 451 status = RpcGpioConfigIn(dr, req->index, req->flags); 452 break; 453 case GPIO_CONFIG_OUT: 454 status = RpcGpioConfigOut(dr, req->index, req->value); 455 break; 456 case GPIO_SET_ALT_FUNCTION: 457 status = RpcGpioSetAltFunction(dr, req->index, req->alt_function); 458 break; 459 case GPIO_READ: 460 status = RpcGpioRead(dr, req->index, &resp->value); 461 break; 462 case GPIO_WRITE: 463 status = RpcGpioWrite(dr, req->index, req->value); 464 break; 465 case GPIO_GET_INTERRUPT: 466 status = RpcGpioGetInterrupt(dr, req->index, req->flags, resp_handles, 467 &resp_handle_count); 468 break; 469 case GPIO_RELEASE_INTERRUPT: 470 status = RpcGpioReleaseInterrupt(dr, req->index); 471 break; 472 case GPIO_SET_POLARITY: 473 status = RpcGpioSetPolarity(dr, req->index, req->polarity); 474 break; 475 default: 476 zxlogf(ERROR, "%s: unknown GPIO op %u\n", __func__, req_header->op); 477 return ZX_ERR_INTERNAL; 478 } 479 break; 480 } 481 case ZX_PROTOCOL_I2C: { 482 auto req = reinterpret_cast<rpc_i2c_req_t*>(&req_buf); 483 if (actual < sizeof(*req)) { 484 zxlogf(ERROR, "%s received %u, expecting %zu\n", __FUNCTION__, actual, sizeof(*req)); 485 return ZX_ERR_INTERNAL; 486 } 487 auto resp = reinterpret_cast<rpc_i2c_rsp_t*>(&resp_buf); 488 resp_len = sizeof(*resp); 489 490 switch (req_header->op) { 491 case I2C_GET_MAX_TRANSFER: 492 status = RpcI2cGetMaxTransferSize(dr, req->index, &resp->max_transfer); 493 break; 494 case I2C_TRANSACT: { 495 status = RpcI2cTransact(dr, req_header->txid, req, channel); 496 if (status == ZX_OK) { 497 // If platform_i2c_transact succeeds, we return immmediately instead of calling 498 // zx_channel_write below. Instead we will respond in platform_i2c_complete(). 499 return ZX_OK; 500 } 501 break; 502 } 503 default: 504 zxlogf(ERROR, "%s: unknown I2C op %u\n", __func__, req_header->op); 505 return ZX_ERR_INTERNAL; 506 } 507 break; 508 } 509 case ZX_PROTOCOL_CLK: { 510 auto req = reinterpret_cast<rpc_clk_req_t*>(&req_buf); 511 if (actual < sizeof(*req)) { 512 zxlogf(ERROR, "%s received %u, expecting %zu\n", __FUNCTION__, actual, sizeof(*req)); 513 return ZX_ERR_INTERNAL; 514 } 515 resp_len = sizeof(*resp_header); 516 517 switch (req_header->op) { 518 case CLK_ENABLE: 519 status = RpcClkEnable(dr, req->index); 520 break; 521 case CLK_DISABLE: 522 status = RpcClkDisable(dr, req->index); 523 break; 524 default: 525 zxlogf(ERROR, "%s: unknown clk op %u\n", __func__, req_header->op); 526 return ZX_ERR_INTERNAL; 527 } 528 break; 529 } 530 default: { 531 platform_proxy_args_t args = { 532 .req = req_header, 533 .req_size = actual, 534 .resp = resp_header, 535 .resp_size = sizeof(resp_buf), 536 .req_handles = req_handles, 537 .req_handle_count = req_handle_count, 538 .resp_handles = resp_handles, 539 .resp_handle_count = fbl::count_of(resp_handles), 540 .resp_actual_size = 0, 541 .resp_actual_handles = 0, 542 }; 543 status = bus_->Proxy(&args); 544 if (status == ZX_OK) { 545 status = args.resp->status; 546 } 547 resp_len = args.resp_actual_size; 548 resp_handle_count = args.resp_actual_handles; 549 break; 550 } 551 } 552 553 // set op to match request so zx_channel_write will return our response 554 resp_header->status = status; 555 status = zx_channel_write(channel, 0, resp_header, resp_len, 556 (resp_handle_count ? resp_handles : nullptr), resp_handle_count); 557 if (status != ZX_OK) { 558 zxlogf(ERROR, "platform_dev_rxrpc: zx_channel_write failed %d\n", status); 559 } 560 return status; 561} 562 563void PlatformDevice::DdkRelease() { 564 delete this; 565} 566 567zx_status_t PlatformDevice::Start() { 568 char name[ZX_DEVICE_NAME_MAX]; 569 if (vid_ == PDEV_VID_GENERIC && pid_ == PDEV_PID_GENERIC && did_ == PDEV_DID_KPCI) { 570 strlcpy(name, "pci", sizeof(name)); 571 } else { 572 snprintf(name, sizeof(name), "%02x:%02x:%01x", vid_, pid_, did_); 573 } 574 char argstr[64]; 575 snprintf(argstr, sizeof(argstr), "pdev:%s,", name); 576 577 // Platform devices run in their own devhosts. 578 uint32_t device_add_flags = DEVICE_ADD_MUST_ISOLATE; 579 580 const DeviceResources* dr = device_index_[ROOT_DEVICE_ID]; 581 const size_t metadata_count = dr->metadata_count(); 582 const size_t boot_metadata_count = dr->boot_metadata_count(); 583 if (metadata_count > 0 || boot_metadata_count > 0) { 584 // Keep device invisible until after we add its metadata. 585 device_add_flags |= DEVICE_ADD_INVISIBLE; 586 } 587 588 zx_status_t status; 589 if (dr->protocol_count() > 0) { 590 // PlatformDevice::Start with protocols 591 status = DdkAdd(name, device_add_flags, nullptr, 0, ZX_PROTOCOL_PLATFORM_PROXY, argstr); 592 } else { 593 zx_device_prop_t props[] = { 594 {BIND_PLATFORM_DEV_VID, 0, vid_}, 595 {BIND_PLATFORM_DEV_PID, 0, pid_}, 596 {BIND_PLATFORM_DEV_DID, 0, did_}, 597 }; 598 599 status = DdkAdd(name, device_add_flags, props, fbl::count_of(props), ZX_PROTOCOL_PLATFORM_DEV, 600 argstr); 601 } 602 603 if (status != ZX_OK) { 604 return status; 605 } 606 607 if (metadata_count > 0 || boot_metadata_count > 0) { 608 for (size_t i = 0; i < metadata_count; i++) { 609 const auto& metadata = dr->metadata(i); 610 status = DdkAddMetadata(metadata.type, metadata.data, metadata.len); 611 if (status != ZX_OK) { 612 DdkRemove(); 613 return status; 614 } 615 } 616 617 for (size_t i = 0; i < boot_metadata_count; i++) { 618 const auto& metadata = dr->boot_metadata(i); 619 const void* data; 620 uint32_t length; 621 status = bus_->GetZbiMetadata(metadata.zbi_type, metadata.zbi_extra, &data, &length); 622 if (status == ZX_OK) { 623 status = DdkAddMetadata(metadata.zbi_type, data, length); 624 } 625 if (status != ZX_OK) { 626 DdkRemove(); 627 return status; 628 } 629 } 630 631 DdkMakeVisible(); 632 } 633 634 return ZX_OK; 635} 636 637} // namespace platform_bus 638