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 
6 #include <stdlib.h>
7 
8 #include <utility>
9 
10 #include <lib/fake_ddk/fake_ddk.h>
11 #include <unittest/unittest.h>
12 #include <zircon/assert.h>
13 
14 namespace fake_ddk {
15 
16 zx_device_t* kFakeDevice = reinterpret_cast<zx_device_t*>(0x55);
17 zx_device_t* kFakeParent = reinterpret_cast<zx_device_t*>(0xaa);
18 
19 Bind* Bind::instance_ = nullptr;
20 
Bind()21 Bind::Bind() {
22     ZX_ASSERT(!instance_);
23     instance_ = this;
24 }
25 
Ok()26 bool Bind::Ok() {
27     BEGIN_HELPER;
28     EXPECT_TRUE(add_called_);
29     EXPECT_TRUE(remove_called_);
30     EXPECT_FALSE(bad_parent_);
31     EXPECT_FALSE(bad_device_);
32     END_HELPER;
33 }
34 
ExpectMetadata(const void * data,size_t data_length)35 void Bind::ExpectMetadata(const void* data, size_t data_length) {
36     metadata_ = data;
37     metadata_length_ = data_length;
38 }
39 
GetMetadataInfo(int * num_calls,size_t * length)40 void Bind::GetMetadataInfo(int* num_calls, size_t* length) {
41     *num_calls = add_metadata_calls_;
42     *length = metadata_length_;
43 }
44 
SetProtocols(fbl::Array<ProtocolEntry> && protocols)45 void Bind::SetProtocols(fbl::Array<ProtocolEntry>&& protocols) {
46     protocols_ = std::move(protocols);
47 }
48 
DeviceAdd(zx_driver_t * drv,zx_device_t * parent,device_add_args_t * args,zx_device_t ** out)49 zx_status_t Bind::DeviceAdd(zx_driver_t* drv, zx_device_t* parent,
50                             device_add_args_t* args, zx_device_t** out) {
51     if (parent != kFakeParent) {
52         bad_parent_ = true;
53     }
54 
55     *out = kFakeDevice;
56     add_called_ = true;
57     return ZX_OK;
58 }
59 
DeviceRemove(zx_device_t * device)60 zx_status_t Bind::DeviceRemove(zx_device_t* device) {
61     if (device != kFakeDevice) {
62         bad_device_ = true;
63     }
64     remove_called_ = true;
65     return ZX_OK;
66 }
67 
DeviceAddMetadata(zx_device_t * device,uint32_t type,const void * data,size_t length)68 zx_status_t Bind::DeviceAddMetadata(zx_device_t* device, uint32_t type, const void* data,
69                                     size_t length) {
70     if (device != kFakeDevice) {
71         bad_device_ = true;
72     }
73 
74     if (metadata_) {
75         if (length != metadata_length_ || memcmp(data, metadata_, length) != 0) {
76             unittest_printf_critical("Unexpected metadata\n");
77             return ZX_ERR_BAD_STATE;
78         }
79     } else {
80         metadata_length_ += length;
81     }
82     add_metadata_calls_++;
83     return ZX_OK;
84 }
85 
DeviceMakeVisible(zx_device_t * device)86 void Bind::DeviceMakeVisible(zx_device_t* device) {
87     if (device != kFakeDevice) {
88         bad_device_ = true;
89     }
90     make_visible_called_ = true;
91     return;
92 }
93 
DeviceGetProtocol(const zx_device_t * device,uint32_t proto_id,void * protocol)94 zx_status_t Bind::DeviceGetProtocol(const zx_device_t* device, uint32_t proto_id, void* protocol) {
95     if (device != kFakeParent) {
96         bad_device_ = true;
97         return ZX_ERR_NOT_SUPPORTED;
98     }
99     auto out = reinterpret_cast<Protocol*>(protocol);
100     for (const auto& proto : protocols_) {
101         if (proto_id == proto.id) {
102             out->ops = proto.proto.ops;
103             out->ctx = proto.proto.ctx;
104             return ZX_OK;
105         }
106     }
107     return ZX_ERR_NOT_SUPPORTED;
108 }
109 
DeviceGetName(zx_device_t * device)110 const char* Bind::DeviceGetName(zx_device_t* device) {
111     if (device != kFakeParent) {
112         bad_device_ = true;
113     }
114     return "";
115 }
116 
117 }  // namespace fake_ddk
118 
device_add_from_driver(zx_driver_t * drv,zx_device_t * parent,device_add_args_t * args,zx_device_t ** out)119 zx_status_t device_add_from_driver(zx_driver_t* drv, zx_device_t* parent,
120                                    device_add_args_t* args, zx_device_t** out) {
121     if (!fake_ddk::Bind::Instance()) {
122         return ZX_OK;
123     }
124     return fake_ddk::Bind::Instance()->DeviceAdd(drv, parent, args, out);
125 }
126 
device_remove(zx_device_t * device)127 zx_status_t device_remove(zx_device_t* device) {
128     if (!fake_ddk::Bind::Instance()) {
129         return ZX_OK;
130     }
131     return fake_ddk::Bind::Instance()->DeviceRemove(device);
132 }
133 
device_add_metadata(zx_device_t * device,uint32_t type,const void * data,size_t length)134 zx_status_t device_add_metadata(zx_device_t* device, uint32_t type, const void* data,
135                                 size_t length) {
136     if (!fake_ddk::Bind::Instance()) {
137         return ZX_OK;
138     }
139     return fake_ddk::Bind::Instance()->DeviceAddMetadata(device, type, data, length);
140 }
141 
device_make_visible(zx_device_t * device)142 void device_make_visible(zx_device_t* device) {
143     if (fake_ddk::Bind::Instance()) {
144         fake_ddk::Bind::Instance()->DeviceMakeVisible(device);
145     }
146     return;
147 }
148 
device_get_protocol(const zx_device_t * device,uint32_t proto_id,void * protocol)149 zx_status_t device_get_protocol(const zx_device_t* device, uint32_t proto_id, void* protocol) {
150     if (!fake_ddk::Bind::Instance()) {
151         return ZX_ERR_NOT_SUPPORTED;
152     }
153     return fake_ddk::Bind::Instance()->DeviceGetProtocol(device, proto_id, protocol);
154 }
155 
device_get_name(zx_device_t * device)156 const char* device_get_name(zx_device_t* device) {
157     if (!fake_ddk::Bind::Instance()) {
158         return nullptr;
159     }
160     return fake_ddk::Bind::Instance()->DeviceGetName(device);
161 }
162 
driver_printf(uint32_t flags,const char * fmt,...)163 extern "C" void driver_printf(uint32_t flags, const char* fmt, ...) {}
164 
165 zx_driver_rec __zircon_driver_rec__ = {};
166