blob: fc79a113493c00fe8a510fa09e9e4c0870e2abce [file]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_CONNECTIVITY_WLAN_DRIVERS_TESTING_LIB_SIM_DEVICE_DEVICE_H_
#define SRC_CONNECTIVITY_WLAN_DRIVERS_TESTING_LIB_SIM_DEVICE_DEVICE_H_
/* Add an abstracted device interface that can be used for wlan driver tests without involving
* devmgr.
*/
#include <lib/ddk/device.h>
#include <lib/ddk/driver.h>
#include <zircon/assert.h>
#include <optional>
#include <thread>
#include <vector>
#ifdef DEBUG
#define DBG_PRT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG_PRT(fmt, ...)
#endif // DEBUG
namespace wlan::simulation {
class FakeDevMgr;
// Provide storage and lifetime management for device_add_args_t and its fields. Use this to make
// copies of device_add_args_t with a lifetime that extends beyond the original device_add_args_t
// object. Note that some fields in device_add_args_t cannot be managed by this class, specifically
// fields that are of private types. This includes types like zx_device_prop_t (props field),
// and zx_device_str_prop_t (str_props field). In the future this list may expand as
// device_add_args_t changes.
class DeviceAddArgs {
public:
DeviceAddArgs() = default;
DeviceAddArgs(const DeviceAddArgs& args);
DeviceAddArgs& operator=(const DeviceAddArgs& other);
explicit DeviceAddArgs(const device_add_args_t& args);
DeviceAddArgs& operator=(const device_add_args_t& other);
const device_add_args_t& Args() const { return args_; }
private:
void CopyRawDeviceAddArgs(const device_add_args_t& args);
void SetRawPointers();
device_add_args_t args_ = {};
std::string name_;
std::optional<zx_protocol_device_t> ops_;
std::vector<device_power_state_info_t> power_states_;
std::vector<device_performance_state_info_t> performance_states_;
std::vector<std::string> fidl_protocol_offer_strings_;
std::vector<const char*> fidl_protocol_offers_;
std::string proxy_args_;
};
class FakeDevice {
public:
bool IsRootParent() const;
zx_status_t AddChild(device_add_args_t* args, zx_device_t** out);
void AsyncRemove();
void AddRef() { ++ref_count_; }
void Release() { --ref_count_; }
uint32_t RefCount() const { return ref_count_; }
uint64_t Id() const { return id_; }
zx_device_t* Parent() const { return parent_; }
const device_add_args_t& DevArgs() const { return dev_args_.Args(); }
wlan::simulation::FakeDevMgr& DevMgr() { return *dev_mgr_; }
protected:
// Don't create instances of this class, it only serves as a base class for zx_device.
FakeDevice(uint64_t id, zx_device_t* parent, device_add_args_t dev_args,
wlan::simulation::FakeDevMgr* dev_mgr);
~FakeDevice() = default;
// You should not need to copy this class, only pass around pointers to instances of it.
FakeDevice(const FakeDevice&) = delete;
FakeDevice& operator=(const FakeDevice&) = delete;
private:
uint64_t id_;
zx_device_t* parent_;
DeviceAddArgs dev_args_;
uint32_t ref_count_;
FakeDevMgr* dev_mgr_;
};
// Fake DeviceManager is a drop-in replacement for Fuchsia's DeviceManager in unit tests.
// In particular, this fake DeviceManager provides functionality to add and remove devices,
// as well as iterate through the device list. It also provides some convenience methods
// for accessing previously added devices.
// Note: Devices are *not* ordered in any particular way.
class FakeDevMgr {
public:
FakeDevMgr();
~FakeDevMgr();
using devices_t = std::vector<std::unique_ptr<zx_device_t>>;
using iterator = devices_t::iterator;
using const_iterator = devices_t::const_iterator;
using Predicate = std::function<bool(zx_device_t*)>;
// Default C++ iterator implementation:
iterator begin() { return devices_.begin(); }
iterator end() { return devices_.end(); }
const_iterator begin() const { return devices_.begin(); }
const_iterator end() const { return devices_.end(); }
const_iterator cbegin() const { return devices_.cbegin(); }
const_iterator cend() const { return devices_.cend(); }
void DeviceInitReply(zx_device_t* device, zx_status_t status,
const device_init_reply_args_t* args);
void DeviceUnbindReply(zx_device_t* device);
zx_status_t DeviceAdd(zx_device_t* parent, device_add_args_t* args, zx_device_t** out);
void DeviceAsyncRemove(zx_device_t* device);
zx_device_t* FindFirst(const Predicate& pred) const;
zx_device_t* FindFirstByProtocolId(uint32_t proto_id) const;
zx_device_t* FindLatest(const Predicate& pred);
zx_device_t* FindLatestByProtocolId(uint32_t proto_id);
bool ContainsDevice(zx_device_t* device) const;
bool ContainsDevice(uint64_t id) const;
size_t DeviceCount();
size_t DeviceCountByProtocolId(uint32_t proto_id);
zx_device_t* GetRootDevice();
private:
enum class DdkCallState;
bool DeviceUnreference(zx_device_t* device);
void DeviceUnbind(zx_device_t* device);
std::vector<zx_device_t*> GetChildren(zx_device_t* device);
// The device id of fake root device, the value is 1, initialized with constructor.
const uint64_t fake_root_dev_id_;
// The device counter starts from 2, because 0 and 1 are reserved for fake root device.
uint64_t dev_counter_ = 2;
devices_t devices_;
std::thread::id init_thread_id_;
std::thread::id unbind_thread_id_;
DdkCallState init_state_;
DdkCallState unbind_state_;
zx_status_t init_result_;
};
} // namespace wlan::simulation
struct zx_device : public wlan::simulation::FakeDevice {
zx_device(uint64_t id, zx_device_t* parent, device_add_args_t dev_args,
wlan::simulation::FakeDevMgr* dev_mgr)
: FakeDevice(id, parent, dev_args, dev_mgr) {}
};
#endif // SRC_CONNECTIVITY_WLAN_DRIVERS_TESTING_LIB_SIM_DEVICE_DEVICE_H_