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