Skip to content

Commit

Permalink
Adding initial libusb integration
Browse files Browse the repository at this point in the history
  • Loading branch information
janweinstock committed Apr 2, 2024
1 parent ff8876f commit 5a180dc
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 0 deletions.
30 changes: 30 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ option(VCML_USE_SLIRP "Use SLIRP for networking" ON)
option(VCML_USE_TAP "Use TAP for networking" ON)
option(VCML_USE_LUA "Use LUA for scripting" ON)
option(VCML_USE_SOCKETCAN "Use CAN sockets" ON)
option(VCML_USE_USB "Use LibUSB for host USB devices" ON)
option(VCML_BUILD_TESTS "Build unit tests" OFF)
option(VCML_BUILD_UTILS "Build utility programs" ON)
option(VCML_COVERAGE "Enable generation of code coverage data" OFF)
Expand Down Expand Up @@ -49,6 +50,24 @@ endif()
if(VCML_USE_SOCKETCAN)
check_include_file("linux/can/raw.h" SOCKETCAN_FOUND)
endif()
if(VCML_USE_USB)
find_package(PkgConfig QUIET)
pkg_check_modules(PKGCFG_LIBUSB QUIET libusb-1.0)
find_path(LIBUSB_INCLUDE_DIRS NAMES "libusb.h"
HINTS $ENV{LIBUSB_HOME}/include ${PKGCFG_LIBUSB_INCLUDE_DIRS})

find_library(LIBUSB_LIBRARIES NAMES "usb-1.0"
HINTS $ENV{LIBUSB_HOME}/lib ${PKGCFG_LIBUSB_LIBRARY_DIRS})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibUSB
REQUIRED_VARS LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES
VERSION_VAR PKGCFG_LIBUSB_VERSION)
mark_as_advanced(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES)
message(DEBUG "LIBUSB_FOUND " ${LIBUSB_FOUND})
message(DEBUG "LIBUSB_INCLUDE_DIRS " ${LIBUSB_INCLUDE_DIRS})
message(DEBUG "LIBUSB_LIBRARIES " ${LIBUSB_LIBRARIES})
endif()

set(src ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(inc ${CMAKE_CURRENT_SOURCE_DIR}/include)
Expand Down Expand Up @@ -281,6 +300,17 @@ else()
target_sources(vcml PRIVATE ${src}/vcml/properties/broker_nolua.cpp)
endif()

if(LIBUSB_FOUND)
message(STATUS "Building with LibUSB support")
target_compile_definitions(vcml PRIVATE HAVE_LIBUSB)
target_include_directories(vcml SYSTEM PRIVATE ${LIBUSB_INCLUDE_DIRS})
target_sources(vcml PRIVATE ${src}/vcml/models/usb/hostdev_libusb.cpp)
target_link_libraries(vcml PUBLIC ${LIBUSB_LIBRARIES})
else()
message(STATUS "Building without LibUSB support")
target_sources(vcml PRIVATE ${src}/vcml/models/usb/hostdev_nolibusb.cpp)
endif()

if(VCML_COVERAGE)
target_compile_options(vcml PUBLIC --coverage)
target_link_libraries(vcml PUBLIC -lgcov)
Expand Down
1 change: 1 addition & 0 deletions include/vcml.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
#include "vcml/models/usb/device.h"
#include "vcml/models/usb/keyboard.h"
#include "vcml/models/usb/drive.h"
#include "vcml/models/usb/hostdev.h"

#include "vcml/models/pci/device.h"
#include "vcml/models/pci/host.h"
Expand Down
58 changes: 58 additions & 0 deletions include/vcml/models/usb/hostdev.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* found in the root directory of this source tree. *
* *
******************************************************************************/

#ifndef VCML_USB_HOSTDEV_H
#define VCML_USB_HOSTDEV_H

#include "vcml/core/types.h"
#include "vcml/core/systemc.h"
#include "vcml/core/module.h"
#include "vcml/core/model.h"

#include "vcml/protocols/usb.h"
#include "vcml/models/usb/device.h"

struct libusb_context;
struct libusb_device;
struct libusb_device_handle;

namespace vcml {
namespace usb {

class hostdev : public device
{
private:
struct libusb_device* m_device;
struct libusb_device_handle* m_handle;

public:
property<u32> hostbus;
property<u32> hostaddr;

usb_target_socket usb_in;

hostdev(const sc_module_name& nm);
virtual ~hostdev();
VCML_KIND(usb::hostdev);

protected:
virtual usb_result get_data(u32 ep, u8* data, size_t len) override;
virtual usb_result set_data(u32 ep, const u8* data, size_t len) override;

virtual usb_result handle_control(u16 req, u16 val, u16 idx, u8* data,
size_t length) override;

virtual void usb_reset_device() override;
};

} // namespace usb
} // namespace vcml

#endif
97 changes: 97 additions & 0 deletions src/vcml/models/usb/hostdev_libusb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* found in the root directory of this source tree. *
* *
******************************************************************************/

#include "vcml/models/usb/hostdev.h"
#include "vcml/core/version.h"

#include <libusb.h>

namespace vcml {
namespace usb {

struct libusb {
libusb_context* context;
libusb(): context(nullptr) {
int r = libusb_init(&context);
VCML_ERROR_ON(r < 0, "failed to initialize libusb");
}

~libusb() {
if (context)
libusb_exit(context);
}

static libusb& instance() {
static libusb singleton;
return singleton;
}

libusb_device* find_device(u32 bus, u32 addr) {
libusb_device* found = nullptr;
libusb_device** list = nullptr;
size_t n = libusb_get_device_list(context, &list);
for (size_t i = 0; i < n; i++) {
if (libusb_get_bus_number(list[i]) == bus &&
libusb_get_device_address(list[i]) == addr) {
found = libusb_ref_device(list[i]);
break;
}
}

libusb_free_device_list(list, true);
return found;
}
};

hostdev::hostdev(const sc_module_name& nm):
device(nm, device_desc()),
m_device(),
m_handle(),
hostbus("hostbus", 0),
hostaddr("hostaddr", 0),
usb_in("usb_in") {
m_device = libusb::instance().find_device(hostbus, hostaddr);
VCML_ERROR_ON(!m_device, "no usb device on bus %u at address %u",
hostbus.get(), hostaddr.get());
int r = libusb_open(m_device, &m_handle);
VCML_ERROR_ON(r, "Failed to open USB device: %s", libusb_strerror(r));
}

hostdev::~hostdev() {
if (m_device)
libusb_unref_device(m_device);
}

usb_result hostdev::get_data(u32 ep, u8* data, size_t len) {
return USB_RESULT_NACK;
}

usb_result hostdev::set_data(u32 ep, const u8* data, size_t len) {
return USB_RESULT_NACK;
}

usb_result hostdev::handle_control(u16 req, u16 val, u16 idx, u8* data,
size_t length) {
switch (req) {
default:
return device::handle_control(req, val, idx, data, length);
}
}

void hostdev::usb_reset_device() {
device::usb_reset_device();
}

VCML_EXPORT_MODEL(vcml::usb::hostdev, name, args) {
return new hostdev(name);
}

} // namespace usb
} // namespace vcml
57 changes: 57 additions & 0 deletions src/vcml/models/usb/hostdev_nolibusb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* found in the root directory of this source tree. *
* *
******************************************************************************/

#include "vcml/models/usb/hostdev.h"
#include "vcml/core/version.h"

#include <libusb.h>

namespace vcml {
namespace usb {

hostdev::hostdev(const sc_module_name& nm):
device(nm, device_desc()),
m_device(),
m_handle(),
hostbus("hostbus", 0),
hostaddr("hostaddr", 0),
usb_in("usb_in") {
}

hostdev::~hostdev() {
// nothing to do
}

usb_result hostdev::get_data(u32 ep, u8* data, size_t len) {
return USB_RESULT_NACK;
}

usb_result hostdev::set_data(u32 ep, const u8* data, size_t len) {
return USB_RESULT_NACK;
}

usb_result hostdev::handle_control(u16 req, u16 val, u16 idx, u8* data,
size_t length) {
switch (req) {
default:
return device::handle_control(req, val, idx, data, length);
}
}

void hostdev::usb_reset_device() {
device::usb_reset_device();
}

VCML_EXPORT_MODEL(vcml::usb::hostdev, name, args) {
return new hostdev(name);
}

} // namespace usb
} // namespace vcml

0 comments on commit 5a180dc

Please sign in to comment.