diff options
Diffstat (limited to 'utils/hwstub/lib/hwstub_virtual.cpp')
-rw-r--r-- | utils/hwstub/lib/hwstub_virtual.cpp | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/utils/hwstub/lib/hwstub_virtual.cpp b/utils/hwstub/lib/hwstub_virtual.cpp new file mode 100644 index 0000000000..fada56fb83 --- /dev/null +++ b/utils/hwstub/lib/hwstub_virtual.cpp @@ -0,0 +1,335 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2016 by Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "hwstub_virtual.hpp" +#include <algorithm> +#include <cstring> + +namespace hwstub { +namespace virt { + +/** + * Context + */ +context::context() +{ +} + +context::~context() +{ +} + +std::shared_ptr<context> context::create() +{ + // NOTE: can't use make_shared() because of the protected ctor */ + return std::shared_ptr<context>(new context()); +} + +std::shared_ptr<context> context::create_spec(const std::string& spec, std::string *error) +{ + std::shared_ptr<context> ctx = create(); + /* parse spec */ + std::string str = spec; + while(!str.empty()) + { + /* find next separator, if any */ + std::string dev_spec; + size_t dev_sep = str.find(';'); + if(dev_sep == std::string::npos) + { + dev_spec = str; + str.clear(); + } + else + { + dev_spec = str.substr(0, dev_sep); + str = str.substr(dev_sep + 1); + } + /* handle dev spec: find ( and )*/ + size_t lparen = dev_spec.find('('); + if(lparen == std::string::npos) + { + if(error) + *error = "invalid device spec '" + dev_spec + "': missing ("; + return std::shared_ptr<context>(); + } + if(dev_spec.back() != ')') + { + if(error) + *error = "invalid device spec '" + dev_spec + "': missing )"; + return std::shared_ptr<context>(); + } + std::string args = dev_spec.substr(lparen + 1, dev_spec.size() - lparen - 2); + std::string type = dev_spec.substr(0, lparen); + if(type == "dummy") + { + ctx->connect(std::make_shared<dummy_hardware>(args)); + } + else + { + if(error) + *error = "invalid device spec '" + dev_spec + "': unknown device type"; + return std::shared_ptr<context>(); + } + } + return ctx; +} + +bool context::connect(std::shared_ptr<hardware> hw) +{ + std::unique_lock<std::recursive_mutex> lock(m_mutex); + if(std::find(m_hwlist.begin(), m_hwlist.end(), hw) != m_hwlist.end()) + return false; + m_hwlist.push_back(hw); + return true; +} + +bool context::disconnect(std::shared_ptr<hardware> hw) +{ + std::unique_lock<std::recursive_mutex> lock(m_mutex); + auto it = std::find(m_hwlist.begin(), m_hwlist.end(), hw); + if(it == m_hwlist.end()) + return false; + m_hwlist.erase(it); + return true; +} + +std::shared_ptr<hardware> context::from_ctx_dev(ctx_dev_t dev) +{ + return ((hardware *)dev)->shared_from_this(); +} + +hwstub::context::ctx_dev_t context::to_ctx_dev(std::shared_ptr<hardware>& dev) +{ + return (ctx_dev_t)dev.get(); +} + +error context::fetch_device_list(std::vector<ctx_dev_t>& list, void*& ptr) +{ + (void) ptr; + list.resize(m_hwlist.size()); + for(size_t i = 0; i < m_hwlist.size(); i++) + list[i] = to_ctx_dev(m_hwlist[i]); + return error::SUCCESS; +} + +void context::destroy_device_list(void *ptr) +{ + (void) ptr; +} + +error context::create_device(ctx_dev_t dev, std::shared_ptr<hwstub::device>& hwdev) +{ + // NOTE: can't use make_shared() because of the protected ctor */ + hwdev.reset(new device(shared_from_this(), from_ctx_dev(dev))); + return error::SUCCESS; +} + +bool context::match_device(ctx_dev_t dev, std::shared_ptr<hwstub::device> hwdev) +{ + device *udev = dynamic_cast<device*>(hwdev.get()); + return udev != nullptr && udev->native_device().get() == from_ctx_dev(dev).get(); +} + +/** + * Device + */ +device::device(std::shared_ptr<hwstub::context> ctx, std::shared_ptr<hardware> dev) + :hwstub::device(ctx), m_hwdev(dev) +{ +} + +device::~device() +{ +} + +std::shared_ptr<hardware> device::native_device() +{ + return m_hwdev.lock(); +} + +error device::open_dev(std::shared_ptr<hwstub::handle>& h) +{ + // NOTE: can't use make_shared() because of the protected ctor */ + h.reset(new handle(shared_from_this())); + return error::SUCCESS; +} + +bool device::has_multiple_open() const +{ + return true; +} + +/** + * Handle + */ +handle::handle(std::shared_ptr<hwstub::device> dev) + :hwstub::handle(dev) +{ + m_hwdev = dynamic_cast<device*>(dev.get())->native_device(); +} + +handle::~handle() +{ +} + + +error handle::read_dev(uint32_t addr, void *buf, size_t& sz, bool atomic) +{ + auto p = m_hwdev.lock(); + return p ? p->read_dev(addr, buf, sz, atomic) : error::DISCONNECTED; +} + +error handle::write_dev(uint32_t addr, const void *buf, size_t& sz, bool atomic) +{ + auto p = m_hwdev.lock(); + return p ? p->write_dev(addr, buf, sz, atomic) : error::DISCONNECTED; +} + +error handle::get_dev_desc(uint16_t desc, void *buf, size_t& buf_sz) +{ + auto p = m_hwdev.lock(); + return p ? p->get_dev_desc(desc, buf, buf_sz) : error::DISCONNECTED; +} + +error handle::get_dev_log(void *buf, size_t& buf_sz) +{ + auto p = m_hwdev.lock(); + return p ? p->get_dev_log(buf, buf_sz) : error::DISCONNECTED; +} + +error handle::exec_dev(uint32_t addr, uint16_t flags) +{ + auto p = m_hwdev.lock(); + return p ? p->exec_dev(addr, flags) : error::DISCONNECTED; +} + +error handle::status() const +{ + return hwstub::handle::status(); +} + +size_t handle::get_buffer_size() +{ + auto p = m_hwdev.lock(); + return p ? p->get_buffer_size() : 1; +} + +/** + * Hardware + */ +hardware::hardware() +{ +} + +hardware::~hardware() +{ +} + +/** + * Dummy hardware + */ +dummy_hardware::dummy_hardware(const std::string& name) +{ + m_desc_version.bLength = sizeof(m_desc_version); + m_desc_version.bDescriptorType = HWSTUB_DT_VERSION; + m_desc_version.bMajor = HWSTUB_VERSION_MAJOR; + m_desc_version.bMinor = HWSTUB_VERSION_MINOR; + m_desc_version.bRevision = 0; + + m_desc_layout.bLength = sizeof(m_desc_layout); + m_desc_layout.bDescriptorType = HWSTUB_DT_LAYOUT; + m_desc_layout.dCodeStart = 0; + m_desc_layout.dCodeSize = 0; + m_desc_layout.dStackStart = 0; + m_desc_layout.dStackSize = 0; + m_desc_layout.dBufferStart = 0; + m_desc_layout.dBufferSize = 1; + + m_desc_target.bLength = sizeof(m_desc_target); + m_desc_target.bDescriptorType = HWSTUB_DT_TARGET; + m_desc_target.dID = HWSTUB_TARGET_UNK; + strncpy(m_desc_target.bName, name.c_str(), sizeof(m_desc_target.bName)); + m_desc_target.bName[sizeof(m_desc_target.bName) - 1] = 0; +} + +dummy_hardware::~dummy_hardware() +{ +} + +error dummy_hardware::read_dev(uint32_t addr, void *buf, size_t& sz, bool atomic) +{ + (void) addr; + (void) buf; + (void) sz; + (void) atomic; + return error::DUMMY; +} + +error dummy_hardware::write_dev(uint32_t addr, const void *buf, size_t& sz, bool atomic) +{ + (void) addr; + (void) buf; + (void) sz; + (void) atomic; + return error::DUMMY; +} + +error dummy_hardware::get_dev_desc(uint16_t desc, void *buf, size_t& buf_sz) +{ + void *p = nullptr; + switch(desc) + { + case HWSTUB_DT_VERSION: p = &m_desc_version; break; + case HWSTUB_DT_LAYOUT: p = &m_desc_layout; break; + case HWSTUB_DT_TARGET: p = &m_desc_target; break; + default: break; + } + if(p == nullptr) + return error::ERROR; + /* size is in the bLength field of the descriptor */ + size_t desc_sz = *(uint8_t *)p; + buf_sz = std::min(buf_sz, desc_sz); + memcpy(buf, p, buf_sz); + return error::SUCCESS; +} + +error dummy_hardware::get_dev_log(void *buf, size_t& buf_sz) +{ + (void) buf; + (void) buf_sz; + return error::DUMMY; +} + +error dummy_hardware::exec_dev(uint32_t addr, uint16_t flags) +{ + (void) addr; + (void) flags; + return error::DUMMY; +} + +size_t dummy_hardware::get_buffer_size() +{ + return 1; +} + +} // namespace virt +} // namespace net + |