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