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 #pragma once
6 
7 #include <ddk/protocol/platform/proxy.h>
8 #include <ddktl/device.h>
9 #include <fbl/intrusive_wavl_tree.h>
10 #include <fbl/ref_counted.h>
11 #include <fbl/ref_ptr.h>
12 #include <fbl/unique_ptr.h>
13 #include <fbl/vector.h>
14 #include <lib/zx/channel.h>
15 
16 #include "platform-proxy-device.h"
17 #include "proxy-protocol.h"
18 
19 namespace platform_bus {
20 
21 class ProxyDevice;
22 
23 class PlatformProxy;
24 using PlatformProxyType = ddk::Device<PlatformProxy>;
25 
26 // This is the main class for the proxy side platform bus driver.
27 // It handles RPC communication with the main platform bus driver in the root devhost.
28 // It also manages a collection of protocol clients for vendor or SOC-specific protocols.
29 // In the case where these protocols exist, this class loads the protocol client drivers
30 // before starting the platform device driver.
31 class PlatformProxy : public PlatformProxyType, public fbl::RefCounted<PlatformProxy> {
32 public:
33     static zx_status_t Create(zx_device_t* parent, zx_handle_t rpc_channel);
34 
35     // Device protocol implementation.
36     void DdkRelease();
37 
38     zx_status_t Rpc(uint32_t device_id, const platform_proxy_req_t* req, size_t req_length,
39                     platform_proxy_rsp_t* resp, size_t resp_length, const zx_handle_t* in_handles,
40                     size_t in_handle_count, zx_handle_t* out_handles, size_t out_handle_count,
41                     size_t* out_actual);
42 
Rpc(uint32_t device_id,const platform_proxy_req_t * req,size_t req_length,platform_proxy_rsp_t * resp,size_t resp_length)43     inline zx_status_t Rpc(uint32_t device_id, const platform_proxy_req_t* req, size_t req_length,
44                            platform_proxy_rsp_t* resp, size_t resp_length) {
45         return Rpc(device_id, req, req_length, resp, resp_length, nullptr, 0, nullptr, 0, nullptr);
46     }
47 
48     zx_status_t GetProtocol(uint32_t proto_id, void* out);
49     zx_status_t RegisterProtocol(uint32_t proto_id, const void* protocol);
50     void UnregisterProtocol(uint32_t proto_id);
51     zx_status_t Proxy(
52          const void* req_buffer, size_t req_size, const zx_handle_t* req_handle_list,
53          size_t req_handle_count, void* out_resp_buffer, size_t resp_size, size_t* out_resp_actual,
54          zx_handle_t* out_resp_handle_list, size_t resp_handle_count,
55          size_t* out_resp_handle_actual);
56 
57 private:
58     // This class is a wrapper for a protocol added via platform_proxy_register_protocol().
59     // It also is the element type for the protocols_ WAVL tree.
60     class PlatformProtocol : public fbl::WAVLTreeContainable<fbl::unique_ptr<PlatformProtocol>> {
61     public:
PlatformProtocol(uint32_t proto_id,const ddk::AnyProtocol * protocol)62         PlatformProtocol(uint32_t proto_id, const ddk::AnyProtocol* protocol)
63             : proto_id_(proto_id), protocol_(*protocol) {}
64 
GetKey()65         inline uint32_t GetKey() const { return proto_id_; }
GetProtocol(void * out)66         inline void GetProtocol(void* out) const { memcpy(out, &protocol_, sizeof(protocol_)); }
67 
68     private:
69         const uint32_t proto_id_;
70         ddk::AnyProtocol protocol_;
71     };
72 
73     friend class fbl::RefPtr<PlatformProxy>;
74     friend class fbl::internal::MakeRefCountedHelper<PlatformProxy>;
75 
PlatformProxy(zx_device_t * parent,zx_handle_t rpc_channel)76     explicit PlatformProxy(zx_device_t* parent, zx_handle_t rpc_channel)
77         :  PlatformProxyType(parent), rpc_channel_(rpc_channel) {}
78 
79     DISALLOW_COPY_ASSIGN_AND_MOVE(PlatformProxy);
80 
81     zx_status_t Init(zx_device_t* parent);
82 
83     const zx::channel rpc_channel_;
84     fbl::WAVLTree<uint32_t, fbl::unique_ptr<PlatformProtocol>> protocols_;
85     uint32_t protocol_count_;
86 };
87 
88 } // namespace platform_bus
89 
90 __BEGIN_CDECLS
91 zx_status_t platform_proxy_create(void* ctx, zx_device_t* parent, const char* name,
92                                   const char* args, zx_handle_t rpc_channel);
93 __END_CDECLS
94