Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add control of libusb DLL on Windows #48

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ include(cmake/XLinkDependencies.cmake)

# Link to libusb
target_link_libraries(${TARGET_NAME} PRIVATE usb-1.0)
if(WIN32 AND NOT MINGW)
target_link_libraries(${TARGET_NAME} PRIVATE delayimp.lib Pathcch.lib)
# workaround https://gitlab.kitware.com/cmake/cmake/-/issues/20022
target_link_options(${TARGET_NAME} PUBLIC "$<LINK_ONLY:/DELAYLOAD:libusb-1.0$<$<CONFIG:Debug>:d>.dll>")
endif()

if(WIN32)
target_compile_definitions(${TARGET_NAME} PRIVATE WIN32_LEAN_AND_MEAN)
Expand Down
3 changes: 2 additions & 1 deletion cmake/XLink.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ if(WIN32)
set(XLINK_PLATFORM_INCLUDE ${XLINK_ROOT_DIR}/src/pc/Win/include)

file(GLOB XLINK_PLATFORM_SRC "${XLINK_ROOT_DIR}/src/pc/Win/src/*.c")
list(APPEND XLINK_SOURCES ${XLINK_PLATFORM_SRC})
file(GLOB XLINK_PLATFORM_SRC_CPP "${XLINK_ROOT_DIR}/src/pc/Win/src/*.cpp")
list(APPEND XLINK_SOURCES ${XLINK_PLATFORM_SRC} ${XLINK_PLATFORM_SRC_CPP})
endif()

if(APPLE)
Expand Down
2 changes: 1 addition & 1 deletion include/XLink/XLinkPlatform.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ typedef enum {
// Device management. Begin.
// ------------------------------------

void XLinkPlatformInit(void* options);
xLinkPlatformErrorCode_t XLinkPlatformInit(void* options);

#ifndef __DEVICE__
/**
Expand Down
7 changes: 5 additions & 2 deletions src/pc/PlatformDeviceControl.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,19 @@ static int tcpipPlatformBootFirmware(const deviceDesc_t* deviceDesc, const char*
// XLinkPlatform API implementation. Begin.
// ------------------------------------

void XLinkPlatformInit(void* options)
xLinkPlatformErrorCode_t XLinkPlatformInit(void* options)
{
usbInitialize(options);
// check for failed initialization; LIBUSB_SUCCESS = 0
if (usbInitialize(options) != 0)
return X_LINK_PLATFORM_DRIVER_NOT_LOADED;

// TODO(themarpe) - move to tcpip_host
//tcpipInitialize();
#if (defined(_WIN32) || defined(_WIN64)) && defined(USE_TCP_IP)
WSADATA wsa_data;
WSAStartup(MAKEWORD(2,2), &wsa_data);
#endif
return X_LINK_PLATFORM_SUCCESS;
}


Expand Down
74 changes: 74 additions & 0 deletions src/pc/Win/src/win_usb_host.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Win32 api and MSVC only; not mingw, *nix, etc.
#if defined(_WIN32) && defined(_MSC_VER)

// project
#define MVLOG_UNIT_NAME xLinkUsb

// libraries
#ifdef XLINK_LIBUSB_LOCAL
#include <libusb.h>
#else
#include <libusb-1.0/libusb.h>
#endif

#include "XLink/XLinkLog.h"
#include "usb_host.h"

// std
#include <array>
#include <pathcch.h>

int usbInitialize_customdir(void** hContext) {
// get handle to the module containing a XLink static function/var
// can not use GetModuleFileNameW(nullptr) because when the main depthai app is a DLL (e.g. plugin),
// then it returns the main EXE which is usually wrong
HMODULE hXLink = nullptr;
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)&MVLOGLEVEL(global), &hXLink) == 0) {
return LIBUSB_ERROR_OVERFLOW;
}

// get path to that module
std::array<wchar_t, 2048> rawPath = {};
const auto len = GetModuleFileNameW(hXLink, rawPath.data(), static_cast<DWORD>(rawPath.size()));
if ((len == 0) || (len == rawPath.size())) {
return LIBUSB_ERROR_OVERFLOW;
}

// remove filename with string::find_last_of(), _wsplitpath_s(), PathCchRemoveFileSpec()
// using PathCchRemoveFileSpec() as it handles special cases
if (PathCchRemoveFileSpec(rawPath.data(), rawPath.size()) != S_OK) {
return LIBUSB_ERROR_OVERFLOW;
}

// persist existing custom DLL load path
bool oldGetError = false;
std::array<wchar_t, 2048> oldDllDir = {};
if (GetDllDirectoryW(static_cast<DWORD>(oldDllDir.size()), oldDllDir.data())) {
// nothing
}
else {
// SetDllDirectoryW() previously unused, or an error
oldGetError = true;
}

// set custom dll load directory
if (SetDllDirectoryW(rawPath.data()) == 0) {
return LIBUSB_ERROR_OVERFLOW;
}

// initialize libusb
int initResult = LIBUSB_SUCCESS;
__try {
initResult = libusb_init((libusb_context**)hContext);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
initResult = LIBUSB_ERROR_OVERFLOW;
}

// restore custom dll load directory
SetDllDirectoryW(oldGetError ? nullptr : oldDllDir.data());

return initResult;
}

#endif // defined(_WIN32) && defined(_MSC_VER)
3 changes: 3 additions & 0 deletions src/pc/protocols/usb_host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ int usbInitialize(void* options){
// // Debug
// mvLogLevelSet(MVLOG_DEBUG);

#if defined(_WIN32) && defined(_MSC_VER)
return usbInitialize_customdir((void**)&context);
#endif
return libusb_init(&context);
}

Expand Down
1 change: 1 addition & 0 deletions src/pc/protocols/usb_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef enum usbBootError {
} usbBootError_t;

int usbInitialize(void* options);
int usbInitialize_customdir(void** hContext);

int usb_boot(const char *addr, const void *mvcmd, unsigned size);
int get_pid_by_name(const char* name);
Expand Down
30 changes: 24 additions & 6 deletions src/shared/XLinkDevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,26 +75,29 @@ static XLinkError_t parsePlatformError(xLinkPlatformErrorCode_t rc);

XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler)
{
XLINK_RET_IF(globalHandler == NULL);
XLINK_RET_ERR_IF(pthread_mutex_lock(&init_mutex), X_LINK_ERROR);
if(init_once){
pthread_mutex_unlock(&init_mutex);
return X_LINK_SUCCESS;
}
init_once = 1;

#ifdef __DEVICE__
mvLogLevelSet(MVLOG_FATAL);
mvLogDefaultLevelSet(MVLOG_FATAL);
#endif

XLINK_RET_IF(globalHandler == NULL);
ASSERT_XLINK(XLINK_MAX_STREAMS <= MAX_POOLS_ALLOC);
glHandler = globalHandler;
if (sem_init(&pingSem,0,0)) {
mvLog(MVLOG_ERROR, "Can't create semaphore\n");
}
int i;

XLinkPlatformInit(globalHandler->options);
if (XLinkPlatformInit(globalHandler->options) != X_LINK_PLATFORM_SUCCESS) {
pthread_mutex_unlock(&init_mutex);
return X_LINK_ERROR;
}

//Using deprecated fields. Begin.
int loglevel = globalHandler->loglevel;
Expand All @@ -115,7 +118,11 @@ XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler)
controlFunctionTbl.closeLink = &dispatcherCloseLink;
controlFunctionTbl.closeDeviceFd = &dispatcherCloseDeviceFd;

XLINK_RET_IF(DispatcherInitialize(&controlFunctionTbl));
if (DispatcherInitialize(&controlFunctionTbl)) {
mvLog(MVLOG_ERROR, "Condition failed: DispatcherInitialize(&controlFunctionTbl)");
pthread_mutex_unlock(&init_mutex);
return X_LINK_ERROR;
}

//initialize availableStreams
memset(availableXLinks, 0, sizeof(availableXLinks));
Expand All @@ -134,23 +141,34 @@ XLinkError_t XLinkInitialize(XLinkGlobalHandler_t* globalHandler)

#ifdef __DEVICE__
link = getNextAvailableLink();
if (link == NULL)
if (link == NULL) {
pthread_mutex_unlock(&init_mutex);
return X_LINK_COMMUNICATION_NOT_OPEN;
}
link->peerState = XLINK_UP;
link->deviceHandle.xLinkFD = NULL;
link->deviceHandle.protocol = globalHandler->protocol;

xLinkDeviceHandle_t temp = {0};
temp.protocol = globalHandler->protocol;
XLINK_RET_IF_FAIL(DispatcherStart(&temp)); //myriad has one
{
int rc;
if (rc = DispatcherStart(&temp)) { //myriad has one
mvLog(MVLOG_ERROR, " DispatcherStart(&temp) method call failed with an error: %d", rc);
pthread_mutex_unlock(&init_mutex);
return rc;
}
}

while(((sem_wait(&pingSem) == -1) && errno == EINTR)
continue;

#endif

init_once = 1;
int status = pthread_mutex_unlock(&init_mutex);
if(status){
// rare and unstable scenario; xlink is technically initialized yet mutex unlock failed
return X_LINK_ERROR;
}

Expand Down