1// Copyright 2018 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-proxy-device.h" 6 7#include <stdint.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11#include <threads.h> 12 13#include <ddk/binding.h> 14#include <ddk/debug.h> 15#include <ddk/device.h> 16#include <ddk/driver.h> 17#include <ddk/protocol/platform-bus.h> 18#include <ddk/protocol/platform-device.h> 19#include <fbl/auto_call.h> 20#include <fbl/unique_ptr.h> 21#include <lib/zx/vmar.h> 22#include <lib/zx/vmo.h> 23 24#include "platform-proxy.h" 25#include "proxy-protocol.h" 26 27// The implementation of the platform bus protocol in this file is for use by 28// drivers that exist in a proxy devhost and communicate with the platform bus 29// over an RPC channel. 30// 31// More information can be found at the top of platform-device.cpp. 32 33namespace platform_bus { 34 35zx_status_t ProxyDevice::GpioConfigIn(void* ctx, uint32_t flags) { 36 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 37 auto thiz = gpio_ctx->thiz; 38 rpc_gpio_req_t req = {}; 39 rpc_gpio_rsp_t resp = {}; 40 req.header.proto_id = ZX_PROTOCOL_GPIO; 41 req.header.op = GPIO_CONFIG_IN; 42 req.index = gpio_ctx->index; 43 req.flags = flags; 44 45 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 46 sizeof(resp)); 47} 48 49zx_status_t ProxyDevice::GpioConfigOut(void* ctx, uint8_t initial_value) { 50 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 51 auto thiz = gpio_ctx->thiz; 52 rpc_gpio_req_t req = {}; 53 rpc_gpio_rsp_t resp = {}; 54 req.header.proto_id = ZX_PROTOCOL_GPIO; 55 req.header.op = GPIO_CONFIG_OUT; 56 req.index = gpio_ctx->index; 57 req.value = initial_value; 58 59 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 60 sizeof(resp)); 61} 62 63zx_status_t ProxyDevice::GpioSetAltFunction(void* ctx, uint64_t function) { 64 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 65 auto thiz = gpio_ctx->thiz; 66 rpc_gpio_req_t req = {}; 67 rpc_gpio_rsp_t resp = {}; 68 req.header.proto_id = ZX_PROTOCOL_GPIO; 69 req.header.op = GPIO_SET_ALT_FUNCTION; 70 req.index = gpio_ctx->index; 71 req.alt_function = function; 72 73 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 74 sizeof(resp)); 75} 76 77zx_status_t ProxyDevice::GpioGetInterrupt(void* ctx, uint32_t flags, zx_handle_t* out_handle) { 78 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 79 auto thiz = gpio_ctx->thiz; 80 rpc_gpio_req_t req = {}; 81 rpc_gpio_rsp_t resp = {}; 82 req.header.proto_id = ZX_PROTOCOL_GPIO; 83 req.header.op = GPIO_GET_INTERRUPT; 84 req.index = gpio_ctx->index; 85 req.flags = flags; 86 87 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp), 88 nullptr, 0, out_handle, 1, nullptr); 89} 90 91zx_status_t ProxyDevice::GpioSetPolarity(void* ctx, uint32_t polarity) { 92 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 93 auto thiz = gpio_ctx->thiz; 94 rpc_gpio_req_t req = {}; 95 rpc_gpio_rsp_t resp = {}; 96 req.header.proto_id = ZX_PROTOCOL_GPIO; 97 req.header.op = GPIO_SET_POLARITY; 98 req.index = gpio_ctx->index; 99 req.polarity = polarity; 100 101 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 102 sizeof(resp)); 103} 104 105zx_status_t ProxyDevice::GpioReleaseInterrupt(void* ctx) { 106 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 107 auto thiz = gpio_ctx->thiz; 108 rpc_gpio_req_t req = {}; 109 rpc_gpio_rsp_t resp = {}; 110 req.header.proto_id = ZX_PROTOCOL_GPIO; 111 req.header.op = GPIO_RELEASE_INTERRUPT; 112 req.index = gpio_ctx->index; 113 114 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 115 sizeof(resp)); 116} 117 118zx_status_t ProxyDevice::GpioRead(void* ctx, uint8_t* out_value) { 119 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 120 auto thiz = gpio_ctx->thiz; 121 rpc_gpio_req_t req = {}; 122 rpc_gpio_rsp_t resp = {}; 123 req.header.proto_id = ZX_PROTOCOL_GPIO; 124 req.header.op = GPIO_READ; 125 req.index = gpio_ctx->index; 126 127 auto status = thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 128 sizeof(resp)); 129 130 if (status != ZX_OK) { 131 return status; 132 } 133 *out_value = resp.value; 134 return ZX_OK; 135} 136 137zx_status_t ProxyDevice::GpioWrite(void* ctx, uint8_t value) { 138 auto gpio_ctx = static_cast<GpioCtx*>(ctx); 139 auto thiz = gpio_ctx->thiz; 140 rpc_gpio_req_t req = {}; 141 rpc_gpio_rsp_t resp = {}; 142 req.header.proto_id = ZX_PROTOCOL_GPIO; 143 req.header.op = GPIO_WRITE; 144 req.index = gpio_ctx->index; 145 req.value = value; 146 147 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 148 sizeof(resp)); 149} 150 151zx_status_t ProxyDevice::I2cGetMaxTransferSize(void* ctx, size_t* out_size) { 152 auto i2c_ctx = static_cast<I2cCtx*>(ctx); 153 auto thiz = i2c_ctx->thiz; 154 rpc_i2c_req_t req = {}; 155 rpc_i2c_rsp_t resp = {}; 156 req.header.proto_id = ZX_PROTOCOL_I2C; 157 req.header.op = I2C_GET_MAX_TRANSFER; 158 req.index = i2c_ctx->index; 159 160 auto status = thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp.header, 161 sizeof(resp)); 162 if (status == ZX_OK) { 163 *out_size = resp.max_transfer; 164 } 165 return status; 166} 167 168zx_status_t ProxyDevice::I2cGetInterrupt(void* ctx, uint32_t flags, zx_handle_t* out_handle) { 169 return ZX_ERR_NOT_SUPPORTED; 170} 171 172zx_status_t ProxyDevice::I2cTransact(void* ctx, i2c_op_t* ops, size_t cnt, 173 i2c_transact_cb transact_cb, void* cookie) { 174 auto i2c_ctx = static_cast<I2cCtx*>(ctx); 175 auto thiz = i2c_ctx->thiz; 176 size_t writes_length = 0; 177 size_t reads_length = 0; 178 for (size_t i = 0; i < cnt; ++i) { 179 if (ops[i].is_read) { 180 reads_length += ops[i].length; 181 } else { 182 writes_length += ops[i].length; 183 } 184 } 185 if (!writes_length && !reads_length) { 186 return ZX_ERR_INVALID_ARGS; 187 } 188 189 size_t req_length = sizeof(rpc_i2c_req_t) + cnt * sizeof(i2c_rpc_op_t) + writes_length; 190 if (req_length >= PROXY_MAX_TRANSFER_SIZE) { 191 return ZX_ERR_INVALID_ARGS; 192 } 193 uint8_t req_buffer[PROXY_MAX_TRANSFER_SIZE]; 194 auto req = reinterpret_cast<rpc_i2c_req_t*>(req_buffer); 195 req->header.proto_id = ZX_PROTOCOL_I2C; 196 req->header.op = I2C_TRANSACT; 197 req->index = i2c_ctx->index; 198 req->cnt = cnt; 199 req->transact_cb = transact_cb; 200 req->cookie = cookie; 201 202 auto rpc_ops = reinterpret_cast<i2c_rpc_op_t*>(req + 1); 203 ZX_ASSERT(cnt < I2C_MAX_RW_OPS); 204 for (size_t i = 0; i < cnt; ++i) { 205 rpc_ops[i].length = ops[i].length; 206 rpc_ops[i].is_read = ops[i].is_read; 207 rpc_ops[i].stop = ops[i].stop; 208 } 209 uint8_t* p_writes = reinterpret_cast<uint8_t*>(rpc_ops) + cnt * sizeof(i2c_rpc_op_t); 210 for (size_t i = 0; i < cnt; ++i) { 211 if (!ops[i].is_read) { 212 memcpy(p_writes, ops[i].buf, ops[i].length); 213 p_writes += ops[i].length; 214 } 215 } 216 217 const size_t resp_length = sizeof(rpc_i2c_rsp_t) + reads_length; 218 if (resp_length >= PROXY_MAX_TRANSFER_SIZE) { 219 return ZX_ERR_INVALID_ARGS; 220 } 221 uint8_t resp_buffer[PROXY_MAX_TRANSFER_SIZE]; 222 rpc_i2c_rsp_t* rsp = reinterpret_cast<rpc_i2c_rsp_t*>(resp_buffer); 223 uint32_t actual; 224 auto status = thiz->proxy_->Rpc(thiz->device_id_, &req->header, 225 static_cast<uint32_t>(req_length), 226 &rsp->header, static_cast<uint32_t>(resp_length), 227 nullptr, 0, nullptr, 0, &actual); 228 if (status != ZX_OK) { 229 return status; 230 } 231 232 // TODO(voydanoff) This proxying code actually implements i2c_transact synchronously 233 // due to the fact that it is unsafe to respond asynchronously on the devmgr rxrpc channel. 234 // In the future we may want to redo the plumbing to allow this to be truly asynchronous. 235 236 if (actual != resp_length) { 237 status = ZX_ERR_INTERNAL; 238 } else { 239 status = rsp->header.status; 240 } 241 if (transact_cb) { 242 i2c_op_t read_ops[I2C_MAX_RW_OPS]; 243 size_t read_ops_cnt = 0; 244 uint8_t* p_reads = reinterpret_cast<uint8_t*>(rsp + 1); 245 for (size_t i = 0; i < cnt; ++i) { 246 if (ops[i].is_read) { 247 read_ops[read_ops_cnt] = ops[i]; 248 read_ops[read_ops_cnt].buf = p_reads; 249 read_ops_cnt++; 250 p_reads += ops[i].length; 251 } 252 } 253 transact_cb(status, read_ops, read_ops_cnt, rsp->cookie); 254 } 255 256 return ZX_OK; 257} 258 259zx_status_t ProxyDevice::ClkEnable(void* ctx, uint32_t index) { 260 ProxyDevice* thiz = static_cast<ProxyDevice*>(ctx); 261 rpc_clk_req_t req = {}; 262 platform_proxy_rsp_t resp = {}; 263 req.header.proto_id = ZX_PROTOCOL_CLK; 264 req.header.op = CLK_ENABLE; 265 req.index = index; 266 267 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp, sizeof(resp)); 268} 269 270zx_status_t ProxyDevice::ClkDisable(void* ctx, uint32_t index) { 271 ProxyDevice* thiz = static_cast<ProxyDevice*>(ctx); 272 rpc_clk_req_t req = {}; 273 platform_proxy_rsp_t resp = {}; 274 req.header.proto_id = ZX_PROTOCOL_CLK; 275 req.header.op = CLK_DISABLE; 276 req.index = index; 277 278 return thiz->proxy_->Rpc(thiz->device_id_, &req.header, sizeof(req), &resp, sizeof(resp)); 279} 280 281zx_status_t ProxyDevice::GetMmio(uint32_t index, pdev_mmio_t* out_mmio) { 282 if (index >= mmios_.size()) { 283 return ZX_ERR_OUT_OF_RANGE; 284 } 285 286 const Mmio& mmio = mmios_[index]; 287 const zx_paddr_t vmo_base = ROUNDDOWN(mmio.base, PAGE_SIZE); 288 const size_t vmo_size = ROUNDUP(mmio.base + mmio.length - vmo_base, PAGE_SIZE); 289 zx::vmo vmo; 290 291 zx_status_t status = zx_vmo_create_physical(mmio.resource.get(), vmo_base, vmo_size, 292 vmo.reset_and_get_address()); 293 if (status != ZX_OK) { 294 zxlogf(ERROR, "%s %s: creating vmo failed %d\n", name_, __FUNCTION__, status); 295 return status; 296 } 297 298 char name[32]; 299 snprintf(name, sizeof(name), "%s mmio %u", name_, index); 300 status = vmo.set_property(ZX_PROP_NAME, name, sizeof(name)); 301 if (status != ZX_OK) { 302 zxlogf(ERROR, "%s %s: setting vmo name failed %d\n", name_, __FUNCTION__, status); 303 return status; 304 } 305 306 out_mmio->offset = mmio.base - vmo_base; 307 out_mmio->vmo = vmo.release(); 308 out_mmio->size = mmio.length; 309 return ZX_OK; 310} 311 312// TODO(surajmalhotra): Remove after migrating all clients off. 313zx_status_t ProxyDevice::MapMmio(uint32_t index, uint32_t cache_policy, void** out_vaddr, 314 size_t* out_size, zx_paddr_t* out_paddr, 315 zx_handle_t* out_handle) { 316 if (index >= mmios_.size()) { 317 return ZX_ERR_OUT_OF_RANGE; 318 } 319 320 const Mmio& mmio = mmios_[index]; 321 const zx_paddr_t vmo_base = ROUNDDOWN(mmio.base, PAGE_SIZE); 322 const size_t vmo_size = ROUNDUP(mmio.base + mmio.length - vmo_base, PAGE_SIZE); 323 zx::vmo vmo; 324 325 zx_status_t status = zx_vmo_create_physical(mmio.resource.get(), vmo_base, vmo_size, 326 vmo.reset_and_get_address()); 327 if (status != ZX_OK) { 328 zxlogf(ERROR, "%s %s: creating vmo failed %d\n", name_, __FUNCTION__, status); 329 return status; 330 } 331 332 char name[32]; 333 snprintf(name, sizeof(name), "%s mmio %u", name_, index); 334 status = vmo.set_property(ZX_PROP_NAME, name, sizeof(name)); 335 if (status != ZX_OK) { 336 zxlogf(ERROR, "%s %s: setting vmo name failed %d\n", name_, __FUNCTION__, status); 337 return status; 338 } 339 340 status = vmo.set_cache_policy(cache_policy); 341 if (status != ZX_OK) { 342 zxlogf(ERROR, "%s %s: setting cache policy failed %d\n", name_, __FUNCTION__, status); 343 return status; 344 } 345 346 uintptr_t virt; 347 status = zx::vmar::root_self()->map(0, vmo, 0, vmo_size, ZX_VM_PERM_READ | 348 ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE, &virt); 349 if (status != ZX_OK) { 350 zxlogf(ERROR, "%s %s: mapping vmar failed %d\n", name_, __FUNCTION__, status); 351 return status; 352 } 353 354 *out_size = mmio.length; 355 if (out_paddr) { 356 *out_paddr = mmio.base; 357 } 358 *out_vaddr = reinterpret_cast<void*>(virt + (mmio.base - vmo_base)); 359 *out_handle = vmo.release(); 360 return ZX_OK; 361 362} 363 364zx_status_t ProxyDevice::MapInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle) { 365 if (index >= irqs_.size()) { 366 return ZX_ERR_OUT_OF_RANGE; 367 } 368 369 Irq* irq = &irqs_[index]; 370 if (flags == 0) { 371 flags = irq->mode; 372 } 373 zx_handle_t handle; 374 zx_status_t status = zx_interrupt_create(irq->resource.get(), irq->irq, flags, &handle); 375 if (status != ZX_OK) { 376 zxlogf(ERROR, "%s %s: creating interrupt failed: %d\n", name_, __FUNCTION__, status); 377 return status; 378 } 379 380 *out_handle = handle; 381 return ZX_OK; 382} 383 384zx_status_t ProxyDevice::GetBti(uint32_t index, zx_handle_t* out_handle) { 385 rpc_pdev_req_t req = {}; 386 rpc_pdev_rsp_t resp = {}; 387 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 388 req.header.op = PDEV_GET_BTI; 389 req.index = index; 390 391 return proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp), nullptr, 0, 392 out_handle, 1, nullptr); 393} 394 395zx_status_t ProxyDevice::GetDeviceInfo(pdev_device_info_t* out_info) { 396 rpc_pdev_req_t req = {}; 397 rpc_pdev_rsp_t resp = {}; 398 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 399 req.header.op = PDEV_GET_DEVICE_INFO; 400 401 auto status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp)); 402 if (status != ZX_OK) { 403 return status; 404 } 405 memcpy(out_info, &resp.device_info, sizeof(*out_info)); 406 return ZX_OK; 407} 408 409zx_status_t ProxyDevice::GetBoardInfo(pdev_board_info_t* out_info) { 410 rpc_pdev_req_t req = {}; 411 rpc_pdev_rsp_t resp = {}; 412 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 413 req.header.op = PDEV_GET_BOARD_INFO; 414 415 auto status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp)); 416 if (status != ZX_OK) { 417 return status; 418 } 419 memcpy(out_info, &resp.board_info, sizeof(*out_info)); 420 return ZX_OK; 421} 422 423zx_status_t ProxyDevice::DeviceAdd(uint32_t index, device_add_args_t* args, zx_device_t** out) { 424 rpc_pdev_req_t req = {}; 425 rpc_pdev_rsp_t resp = {}; 426 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 427 req.header.op = PDEV_DEVICE_ADD; 428 req.index = index; 429 430 auto status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp)); 431 if (status != ZX_OK) { 432 return status; 433 } 434 435 return CreateChild(zxdev(), resp.device_id, proxy_, args); 436} 437 438zx_status_t ProxyDevice::GetProtocol(uint32_t proto_id, uint32_t index, void* out_protocol) { 439 // Return the GPIO protocol for the given index. 440 if (proto_id == ZX_PROTOCOL_GPIO) { 441 if (index >= gpio_ctxs_.size()) { 442 return ZX_ERR_OUT_OF_RANGE; 443 } 444 auto proto = static_cast<gpio_protocol_t*>(out_protocol); 445 proto->ops = &gpio_proto_ops_; 446 proto->ctx = &gpio_ctxs_[index]; 447 return ZX_OK; 448 } 449 450 if (proto_id == ZX_PROTOCOL_I2C) { 451 if (index >= i2c_ctxs_.size()) { 452 return ZX_ERR_OUT_OF_RANGE; 453 } 454 auto proto = static_cast<i2c_protocol_t*>(out_protocol); 455 proto->ops = &i2c_proto_ops_; 456 proto->ctx = &i2c_ctxs_[index]; 457 return ZX_OK; 458 } 459 460 // For other protocols, fall through to DdkGetProtocol if index is zero 461 if (index != 0) { 462 return ZX_ERR_OUT_OF_RANGE; 463 } 464 return DdkGetProtocol(proto_id, out_protocol); 465} 466 467zx_status_t ProxyDevice::CreateRoot(zx_device_t* parent, fbl::RefPtr<PlatformProxy> proxy) { 468 fbl::AllocChecker ac; 469 auto dev = fbl::make_unique_checked<ProxyDevice>(&ac,parent, ROOT_DEVICE_ID, proxy); 470 if (!ac.check()) { 471 return ZX_ERR_NO_MEMORY; 472 } 473 auto status = dev->InitRoot(); 474 if (status != ZX_OK) { 475 return status; 476 } 477 478 // devmgr is now in charge of the device. 479 __UNUSED auto* dummy = dev.release(); 480 return ZX_OK; 481} 482 483zx_status_t ProxyDevice::CreateChild(zx_device_t* parent, uint32_t device_id, 484 fbl::RefPtr<PlatformProxy> proxy, device_add_args_t* args) { 485 fbl::AllocChecker ac; 486 fbl::unique_ptr<ProxyDevice> dev(new (&ac) platform_bus::ProxyDevice(parent, device_id, proxy)); 487 if (!ac.check()) { 488 return ZX_ERR_NO_MEMORY; 489 } 490 auto status = dev->InitChild(args); 491 if (status != ZX_OK) { 492 return status; 493 } 494 495 // devmgr is now in charge of the device. 496 __UNUSED auto* dummy = dev.release(); 497 return ZX_OK; 498} 499 500ProxyDevice::ProxyDevice(zx_device_t* parent, uint32_t device_id, 501 fbl::RefPtr<PlatformProxy> proxy) 502 : ProxyDeviceType(parent), device_id_(device_id), proxy_(proxy) { 503 // Initialize protocol ops 504 clk_proto_ops_.enable = ClkEnable; 505 clk_proto_ops_.disable = ClkDisable; 506 gpio_proto_ops_.config_in = GpioConfigIn; 507 gpio_proto_ops_.config_out = GpioConfigOut; 508 gpio_proto_ops_.set_alt_function = GpioSetAltFunction; 509 gpio_proto_ops_.read = GpioRead; 510 gpio_proto_ops_.write = GpioWrite; 511 gpio_proto_ops_.get_interrupt = GpioGetInterrupt; 512 gpio_proto_ops_.release_interrupt = GpioReleaseInterrupt; 513 gpio_proto_ops_.set_polarity = GpioSetPolarity; 514 i2c_proto_ops_.transact = I2cTransact; 515 i2c_proto_ops_.get_max_transfer_size = I2cGetMaxTransferSize; 516 i2c_proto_ops_.get_interrupt = I2cGetInterrupt; 517} 518 519zx_status_t ProxyDevice::InitCommon() { 520 pdev_device_info_t info; 521 auto status = GetDeviceInfo(&info); 522 if (status != ZX_OK) { 523 return status; 524 } 525 memcpy(name_, info.name, sizeof(name_)); 526 metadata_count_ = info.metadata_count; 527 528 fbl::AllocChecker ac; 529 530 for (uint32_t i = 0; i < info.mmio_count; i++) { 531 rpc_pdev_req_t req = {}; 532 rpc_pdev_rsp_t resp = {}; 533 zx_handle_t rsrc_handle; 534 535 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 536 req.header.op = PDEV_GET_MMIO; 537 req.index = i; 538 status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp), 539 NULL, 0, &rsrc_handle, 1, NULL); 540 if (status != ZX_OK) { 541 return status; 542 } 543 544 Mmio mmio; 545 mmio.base = resp.paddr; 546 mmio.length = resp.length; 547 mmio.resource.reset(rsrc_handle); 548 mmios_.push_back(fbl::move(mmio), &ac); 549 if (!ac.check()) { 550 return ZX_ERR_NO_MEMORY; 551 } 552 553 zxlogf(SPEW, "%s: received MMIO %u (base %#lx length %#lx handle %#x)\n", name_, i, 554 mmio.base, mmio.length, mmio.resource.get()); 555 } 556 557 for (uint32_t i = 0; i < info.irq_count; i++) { 558 rpc_pdev_req_t req = {}; 559 rpc_pdev_rsp_t resp = {}; 560 zx_handle_t rsrc_handle; 561 562 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 563 req.header.op = PDEV_GET_INTERRUPT; 564 req.index = i; 565 status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.header, sizeof(resp), 566 NULL, 0, &rsrc_handle, 1, NULL); 567 if (status != ZX_OK) { 568 return status; 569 } 570 571 Irq irq; 572 irq.irq = resp.irq; 573 irq.mode = resp.mode; 574 irq.resource.reset(rsrc_handle); 575 irqs_.push_back(fbl::move(irq), &ac); 576 if (!ac.check()) { 577 return ZX_ERR_NO_MEMORY; 578 } 579 580 zxlogf(SPEW, "%s: received IRQ %u (irq %#x handle %#x)\n", name_, i, irq.irq, 581 irq.resource.get()); 582 } 583 584 uint32_t gpio_count = info.gpio_count; 585 if (gpio_count > 0) { 586 gpio_ctxs_.reset(new (&ac) GpioCtx[gpio_count], gpio_count); 587 if (!ac.check()) { 588 return ZX_ERR_NO_MEMORY; 589 } 590 591 for (uint32_t i = 0; i < info.gpio_count; i++) { 592 gpio_ctxs_[i].thiz = this; 593 gpio_ctxs_[i].index = i; 594 } 595 } 596 597 uint32_t i2c_count = info.i2c_channel_count; 598 if (i2c_count > 0) { 599 i2c_ctxs_.reset(new (&ac) I2cCtx[i2c_count], i2c_count); 600 if (!ac.check()) { 601 return ZX_ERR_NO_MEMORY; 602 } 603 604 for (uint32_t i = 0; i < i2c_count; i++) { 605 i2c_ctxs_[i].thiz = this; 606 i2c_ctxs_[i].index = i; 607 } 608 } 609 610 return ZX_OK; 611} 612 613zx_status_t ProxyDevice::InitRoot() { 614 auto status = InitCommon(); 615 if (status != ZX_OK) { 616 return status; 617 } 618 return DdkAdd(name_); 619} 620 621zx_status_t ProxyDevice::InitChild(device_add_args_t* args) { 622 auto status = InitCommon(); 623 if (status != ZX_OK) { 624 return status; 625 } 626 627 ctx_ = args->ctx; 628 device_ops_ = args->ops; 629 proto_id_ = args->proto_id; 630 proto_ops_ = args->proto_ops; 631 632 device_add_args_t new_args = *args; 633 // Replace ctx and device protocol ops with ours so we can intercept device_get_protocol(). 634 new_args.ctx = this; 635 new_args.ops = &ddk_device_proto_; 636 637 if (metadata_count_ == 0) { 638 return device_add(parent(), &new_args, &zxdev_); 639 } 640 641 new_args.flags |= DEVICE_ADD_INVISIBLE; 642 status = device_add(parent(), &new_args, &zxdev_); 643 if (status != ZX_OK) { 644 return status; 645 } 646 // Remove ourselves from the devmgr if something goes wrong. 647 auto cleanup = fbl::MakeAutoCall([this]() { DdkRemove(); }); 648 649 for (uint32_t i = 0; i < metadata_count_; i++) { 650 rpc_pdev_req_t req = {}; 651 rpc_pdev_metadata_rsp_t resp = {}; 652 req.header.proto_id = ZX_PROTOCOL_PLATFORM_DEV; 653 req.header.op = PDEV_GET_METADATA; 654 req.index = i; 655 656 status = proxy_->Rpc(device_id_, &req.header, sizeof(req), &resp.pdev.header, 657 sizeof(resp)); 658 if (status != ZX_OK) { 659 return status; 660 } 661 status = DdkAddMetadata(resp.pdev.metadata_type, resp.metadata, 662 resp.pdev.metadata_length); 663 if (status != ZX_OK) { 664 return status; 665 } 666 } 667 668 cleanup.cancel(); 669 // Make ourselves visible after all metadata has been added successfully. 670 DdkMakeVisible(); 671 return ZX_OK; 672} 673 674zx_status_t ProxyDevice::DdkGetProtocol(uint32_t proto_id, void* out) { 675 auto* proto = static_cast<ddk::AnyProtocol*>(out); 676 677 // Try driver's get_protocol() first, if it is implemented. 678 if (device_ops_ && device_ops_->get_protocol) { 679 if (device_ops_->get_protocol(ctx_, proto_id, out) == ZX_OK) { 680 return ZX_OK; 681 } 682 } 683 684 // Next try driver's primary protocol. 685 if (proto_ops_ && proto_id_ == proto_id) { 686 proto->ops = proto_ops_; 687 proto->ctx = ctx_; 688 return ZX_OK; 689 } 690 691 // Finally, protocols provided by platform bus. 692 proto->ctx = this; 693 switch (proto_id) { 694 case ZX_PROTOCOL_PLATFORM_DEV: { 695 proto->ops = &pdev_proto_ops_; 696 break; 697 } 698 case ZX_PROTOCOL_GPIO: { 699 auto count = gpio_ctxs_.size(); 700 if (count == 0) { 701 return ZX_ERR_NOT_SUPPORTED; 702 } else if (count > 1) { 703 zxlogf(ERROR, "%s: device has more than one GPIO\n", __func__); 704 return ZX_ERR_BAD_STATE; 705 } 706 // Return zeroth GPIO resource. 707 proto->ops = &gpio_proto_ops_; 708 proto->ctx = &gpio_ctxs_[0]; 709 return ZX_OK; 710 } 711 case ZX_PROTOCOL_I2C: { 712 auto count = i2c_ctxs_.size(); 713 if (count == 0) { 714 return ZX_ERR_NOT_SUPPORTED; 715 } else if (count > 1) { 716 zxlogf(ERROR, "%s: device has more than one I2C channel\n", __func__); 717 return ZX_ERR_BAD_STATE; 718 } 719 // Return zeroth I2C resource. 720 proto->ops = &i2c_proto_ops_; 721 proto->ctx = &i2c_ctxs_[0]; 722 return ZX_OK; 723 } 724 case ZX_PROTOCOL_CLK: { 725 proto->ops = &clk_proto_ops_; 726 break; 727 } 728 default: 729 return proxy_->GetProtocol(proto_id, out);; 730 } 731 return ZX_OK; 732} 733 734zx_status_t ProxyDevice::DdkOpen(zx_device_t** dev_out, uint32_t flags) { 735 if (device_ops_ && device_ops_->open) { 736 return device_ops_->open(ctx_, dev_out, flags); 737 } 738 return ZX_ERR_NOT_SUPPORTED; 739} 740 741zx_status_t ProxyDevice::DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { 742 if (device_ops_ && device_ops_->open_at) { 743 return device_ops_->open_at(ctx_, dev_out, path, flags); 744 } 745 return ZX_ERR_NOT_SUPPORTED; 746} 747 748zx_status_t ProxyDevice::DdkClose(uint32_t flags) { 749 if (device_ops_ && device_ops_->close) { 750 return device_ops_->close(ctx_, flags); 751 } 752 return ZX_ERR_NOT_SUPPORTED; 753} 754 755void ProxyDevice::DdkUnbind() { 756 if (device_ops_ && device_ops_->unbind) { 757 device_ops_->unbind(ctx_); 758 } 759} 760 761void ProxyDevice::DdkRelease() { 762 if (device_ops_ && device_ops_->release) { 763 device_ops_->release(ctx_); 764 } 765 delete this; 766} 767 768zx_status_t ProxyDevice::DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual) { 769 if (device_ops_ && device_ops_->read) { 770 return device_ops_->read(ctx_, buf, count, off, actual); 771 } 772 return ZX_ERR_NOT_SUPPORTED; 773} 774 775zx_status_t ProxyDevice::DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) { 776 if (device_ops_ && device_ops_->write) { 777 return device_ops_->write(ctx_, buf, count, off, actual); 778 } 779 return ZX_ERR_NOT_SUPPORTED; 780} 781 782zx_off_t ProxyDevice::DdkGetSize() { 783 if (device_ops_ && device_ops_->get_size) { 784 return device_ops_->get_size(ctx_); 785 } 786 return ZX_ERR_NOT_SUPPORTED; 787} 788 789zx_status_t ProxyDevice::DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, 790 size_t out_len, size_t* actual) { 791 if (device_ops_ && device_ops_->ioctl) { 792 return device_ops_->ioctl(ctx_, op, in_buf, in_len, out_buf, out_len, actual); 793 } 794 return ZX_ERR_NOT_SUPPORTED; 795} 796 797zx_status_t ProxyDevice::DdkSuspend(uint32_t flags) { 798 if (device_ops_ && device_ops_->suspend) { 799 return device_ops_->suspend(ctx_, flags); 800 } 801 return ZX_ERR_NOT_SUPPORTED; 802} 803 804zx_status_t ProxyDevice::DdkResume(uint32_t flags) { 805 if (device_ops_ && device_ops_->resume) { 806 return device_ops_->resume(ctx_, flags); 807 } 808 return ZX_ERR_NOT_SUPPORTED; 809} 810 811zx_status_t ProxyDevice::DdkRxrpc(zx_handle_t channel) { 812 if (device_ops_ && device_ops_->rxrpc) { 813 return device_ops_->rxrpc(ctx_, channel); 814 } 815 return ZX_ERR_NOT_SUPPORTED; 816} 817 818} // namespace platform_bus 819