diff --git a/external/libusb/libusb.vcxproj b/external/libusb/libusb.vcxproj
index ab0f529c..ddd33f5c 100644
--- a/external/libusb/libusb.vcxproj
+++ b/external/libusb/libusb.vcxproj
@@ -23,13 +23,14 @@
-
+
+
diff --git a/external/libusb/libusb.vcxproj.filters b/external/libusb/libusb.vcxproj.filters
index 0fd41508..8eaf05b1 100644
--- a/external/libusb/libusb.vcxproj.filters
+++ b/external/libusb/libusb.vcxproj.filters
@@ -5,7 +5,7 @@
-
+
@@ -14,5 +14,6 @@
+
\ No newline at end of file
diff --git a/external/libusb/src/libwinusb.h b/external/libusb/src/libwinusb.h
new file mode 100644
index 00000000..c19c2735
--- /dev/null
+++ b/external/libusb/src/libwinusb.h
@@ -0,0 +1,1299 @@
+//
+// libwinusb.h
+// Copyright (C) 2019 Marius Greuel. All rights reserved.
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#pragma comment(lib, "winusb")
+#pragma comment(lib, "setupapi")
+
+namespace LibWinUsb
+{
+ class Handle
+ {
+ public:
+ Handle() = default;
+
+ ~Handle()
+ {
+ Close();
+ }
+
+ Handle(const Handle&) = delete;
+ Handle& operator=(const Handle& other) = delete;
+ Handle(Handle&&) = default;
+ Handle& operator=(Handle&& other) = default;
+
+ operator HANDLE() const noexcept
+ {
+ return m_handle;
+ }
+
+ void Close() noexcept
+ {
+ if (m_handle != nullptr)
+ {
+ CloseHandle(m_handle);
+ m_handle = nullptr;
+ }
+ }
+
+ void Attach(HANDLE handle) noexcept
+ {
+ assert(m_handle == nullptr);
+ m_handle = handle;
+ }
+
+ HANDLE Detach() noexcept
+ {
+ HANDLE handle = m_handle;
+ m_handle = nullptr;
+ return handle;
+ }
+
+ protected:
+ HANDLE m_handle = nullptr;
+ };
+
+ class Event : public Handle
+ {
+ public:
+ Event() = default;
+ Event(const Event&) = delete;
+ Event& operator=(const Event& other) = delete;
+ Event(Event&&) = default;
+ Event& operator=(Event&& other) = default;
+
+ HRESULT Create(BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName = nullptr, LPSECURITY_ATTRIBUTES lpAttributes = nullptr) noexcept
+ {
+ HANDLE hEvent = CreateEventW(lpAttributes, bManualReset, bInitialState, lpName);
+ if (hEvent == nullptr)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ Close();
+ Attach(hEvent);
+ return S_OK;
+ }
+
+ HRESULT Open(LPCWSTR lpName, DWORD dwDesiredAccess = EVENT_ALL_ACCESS, BOOL bInheritHandle = FALSE) noexcept
+ {
+ HANDLE hEvent = OpenEventW(dwDesiredAccess, bInheritHandle, lpName);
+ if (hEvent == nullptr)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ Close();
+ Attach(hEvent);
+ return S_OK;
+ }
+
+ HRESULT Set() noexcept
+ {
+ if (!SetEvent(m_handle))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ return S_OK;
+ }
+
+ HRESULT Reset() noexcept
+ {
+ if (!ResetEvent(m_handle))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ return S_OK;
+ }
+ };
+
+ class AutoResetEvent : public Event
+ {
+ public:
+ HRESULT Create(BOOL bInitialState = FALSE, LPCWSTR lpName = nullptr, LPSECURITY_ATTRIBUTES lpAttributes = nullptr)
+ {
+ return Event::Create(FALSE, bInitialState, lpName, lpAttributes);
+ }
+ };
+
+ class ManualResetEvent : public Event
+ {
+ public:
+ HRESULT Create(BOOL bInitialState = FALSE, LPCWSTR lpName = nullptr, LPSECURITY_ATTRIBUTES lpAttributes = nullptr)
+ {
+ return Event::Create(TRUE, bInitialState, lpName, lpAttributes);
+ }
+ };
+
+ class Encoding
+ {
+ public:
+ static std::string ToAnsi(const std::wstring& text)
+ {
+ std::string str;
+
+ if (!text.empty())
+ {
+ int chars = ::WideCharToMultiByte(CP_ACP, 0, text.c_str(), static_cast(text.size()), nullptr, 0, nullptr, nullptr);
+ if (chars == 0)
+ {
+ return std::string();
+ }
+
+ str.resize(chars);
+ chars = ::WideCharToMultiByte(CP_ACP, 0, text.c_str(), static_cast(text.size()), &str[0], static_cast(str.size()), nullptr, nullptr);
+ if (chars == 0)
+ {
+ return std::string();
+ }
+ }
+
+ return str;
+ }
+
+ static std::wstring ToUnicode(const std::string& text)
+ {
+ std::wstring str;
+
+ if (!text.empty())
+ {
+ int chars = ::MultiByteToWideChar(CP_ACP, 0, text.c_str(), static_cast(text.size()), nullptr, 0);
+ if (chars == 0)
+ {
+ return std::wstring();
+ }
+
+ str.resize(chars);
+ chars = ::MultiByteToWideChar(CP_ACP, 0, text.c_str(), static_cast(text.size()), &str[0], static_cast(str.size()));
+ if (chars == 0)
+ {
+ return std::wstring();
+ }
+ }
+
+ return str;
+ }
+ };
+
+ class DeviceInfo : public SP_DEVINFO_DATA
+ {
+ public:
+ DeviceInfo()
+ {
+ static_cast(*this) = { sizeof(SP_DEVINFO_DATA) };
+ }
+
+ DeviceInfo(const DeviceInfo&) = delete;
+ DeviceInfo& operator=(const DeviceInfo& other) = delete;
+ DeviceInfo(DeviceInfo&&) = delete;
+ DeviceInfo& operator=(DeviceInfo&& other) = delete;
+
+ public:
+ HRESULT Open(HDEVINFO hDeviceInfoSet, LPCWSTR pszDeviceInstanceId, HWND hwndParent = nullptr, DWORD dwOpenFlags = 0)
+ {
+ if (!SetupDiOpenDeviceInfoW(hDeviceInfoSet, pszDeviceInstanceId, hwndParent, dwOpenFlags, this))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ return S_OK;
+ }
+
+ HRESULT GetProperty(HDEVINFO hDeviceInfoSet, const DEVPROPKEY* key, bool& value)
+ {
+ DEVPROP_BOOLEAN buffer{};
+ DEVPROPTYPE type = DEVPROP_TYPE_EMPTY;
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, reinterpret_cast(&buffer), sizeof(buffer), &dwRequiredSize, 0))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (type != DEVPROP_TYPE_BOOLEAN)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
+ }
+
+ value = buffer != DEVPROP_FALSE;
+ return S_OK;
+ }
+
+ HRESULT GetProperty(HDEVINFO hDeviceInfoSet, const DEVPROPKEY* key, uint32_t& value)
+ {
+ uint32_t buffer{};
+ DEVPROPTYPE type = DEVPROP_TYPE_EMPTY;
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, reinterpret_cast(&buffer), sizeof(buffer), &dwRequiredSize, 0))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (type != DEVPROP_TYPE_UINT32)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
+ }
+
+ value = buffer;
+ return S_OK;
+ }
+
+ HRESULT GetProperty(HDEVINFO hDeviceInfoSet, const DEVPROPKEY* key, GUID& value)
+ {
+ GUID buffer{};
+ DEVPROPTYPE type = DEVPROP_TYPE_EMPTY;
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, reinterpret_cast(&buffer), sizeof(buffer), &dwRequiredSize, 0))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ if (type != DEVPROP_TYPE_GUID)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
+ }
+
+ value = buffer;
+ return S_OK;
+ }
+
+ HRESULT GetProperty(HDEVINFO hDeviceInfoSet, const DEVPROPKEY* key, std::wstring& value)
+ {
+ DEVPROPTYPE type = DEVPROP_TYPE_EMPTY;
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, nullptr, 0, &dwRequiredSize, 0))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ if (type != DEVPROP_TYPE_STRING)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
+ }
+
+ std::vector buffer(dwRequiredSize);
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, buffer.data(), dwRequiredSize, nullptr, 0))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ LPCWSTR pszValue = reinterpret_cast(buffer.data());
+ DWORD dwChars = dwRequiredSize / sizeof(WCHAR);
+ if (dwChars > 0 && pszValue[dwChars - 1] == 0)
+ {
+ dwChars--;
+ }
+
+ value = std::wstring(pszValue, dwChars);
+ return S_OK;
+ }
+
+ HRESULT GetProperty(HDEVINFO hDeviceInfoSet, const DEVPROPKEY* key, std::vector& values)
+ {
+ DEVPROPTYPE type = DEVPROP_TYPE_EMPTY;
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, nullptr, 0, &dwRequiredSize, 0))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ if (type != DEVPROP_TYPE_STRING_LIST)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
+ }
+
+ std::vector buffer(dwRequiredSize);
+ if (!SetupDiGetDevicePropertyW(hDeviceInfoSet, this, key, &type, buffer.data(), dwRequiredSize, nullptr, 0))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ auto data = reinterpret_cast(buffer.data());
+ while (*data != 0)
+ {
+ values.push_back(data);
+ data += wcslen(data) + 1;
+ }
+
+ return S_OK;
+ }
+ };
+
+ class DeviceInfoSet
+ {
+ public:
+ DeviceInfoSet() = default;
+ DeviceInfoSet(const DeviceInfoSet&) = delete;
+ DeviceInfoSet& operator=(const DeviceInfoSet& other) = delete;
+ DeviceInfoSet(DeviceInfoSet&&) = delete;
+ DeviceInfoSet& operator=(DeviceInfoSet&& other) = delete;
+
+ ~DeviceInfoSet()
+ {
+ Destroy();
+ }
+
+ public:
+ operator HDEVINFO() const noexcept
+ {
+ return m_hDeviceInfoSet;
+ }
+
+ public:
+ HRESULT Create(const GUID* classGuid, HWND hwndParent)
+ {
+ Destroy();
+
+ HDEVINFO hDeviceInfoSet = SetupDiCreateDeviceInfoList(classGuid, hwndParent);
+ if (hDeviceInfoSet == INVALID_HANDLE_VALUE)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ m_hDeviceInfoSet = hDeviceInfoSet;
+ return S_OK;
+ }
+
+ HRESULT GetClassDevs(const GUID* classGuid, PCWSTR pszEnumerator, HWND hWndParent, DWORD dwFlags)
+ {
+ Destroy();
+
+ HDEVINFO hDeviceInfoSet = SetupDiGetClassDevsW(classGuid, pszEnumerator, hWndParent, dwFlags);
+ if (hDeviceInfoSet == INVALID_HANDLE_VALUE)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ m_hDeviceInfoSet = hDeviceInfoSet;
+ return S_OK;
+ }
+
+ void Destroy()
+ {
+ if (m_hDeviceInfoSet != INVALID_HANDLE_VALUE)
+ {
+ SetupDiDestroyDeviceInfoList(m_hDeviceInfoSet);
+ m_hDeviceInfoSet = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ private:
+ HDEVINFO m_hDeviceInfoSet = INVALID_HANDLE_VALUE;
+ };
+
+ class UsbDriver
+ {
+ public:
+ virtual ~UsbDriver()
+ {
+ Close();
+ }
+
+ UsbDriver() = default;
+ UsbDriver(const UsbDriver&) = delete;
+ UsbDriver& operator=(const UsbDriver& other) = delete;
+ UsbDriver(UsbDriver&&) = delete;
+ UsbDriver& operator=(UsbDriver&& other) = delete;
+
+ public:
+ virtual HRESULT Open(LPCWSTR pszPath)
+ {
+ Close();
+
+ HANDLE hDevice = CreateFileW(
+ pszPath,
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ nullptr);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ m_hDevice.Attach(hDevice);
+ return S_OK;
+ }
+
+ virtual void Close()
+ {
+ m_hDevice.Close();
+ }
+
+ virtual HRESULT GetDescriptor(uint8_t type, uint8_t index, uint16_t languageID, void* buffer, uint16_t bufferSize, uint32_t* bytesReturned, uint32_t timeout) = 0;
+ virtual HRESULT ControlTransfer(uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, void* buffer, uint16_t bufferSize, uint32_t* bytesReturned, uint32_t timeout) = 0;
+ virtual HRESULT SetConfiguration(uint8_t configuration) = 0;
+ virtual HRESULT ClaimInterface(uint8_t interfaceIndex) = 0;
+ virtual HRESULT ReleaseInterface(uint8_t interfaceIndex) = 0;
+ virtual HRESULT SetAlternateSetting(uint8_t interfaceIndex, uint8_t alternate) = 0;
+ virtual HRESULT ReadPipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesRead, uint32_t timeout) = 0;
+ virtual HRESULT WritePipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesWritten, uint32_t timeout) = 0;
+
+ protected:
+ Handle m_hDevice;
+ };
+
+ class WinUsbDriver : public UsbDriver
+ {
+ public:
+ HRESULT Open(LPCWSTR pszPath) override
+ {
+ HRESULT hr = UsbDriver::Open(pszPath);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ WINUSB_INTERFACE_HANDLE hWinUsbInterface = nullptr;
+ if (!WinUsb_Initialize(m_hDevice, &hWinUsbInterface))
+ {
+ DWORD dwError = GetLastError();
+ Close();
+ return HRESULT_FROM_WIN32(dwError);
+ }
+
+ m_hWinUsbInterface = hWinUsbInterface;
+ return S_OK;
+ }
+
+ void Close() override
+ {
+ if (m_hWinUsbInterface != nullptr)
+ {
+ WinUsb_Free(m_hWinUsbInterface);
+ m_hWinUsbInterface = nullptr;
+ }
+
+ UsbDriver::Close();
+ }
+
+ HRESULT GetDescriptor(uint8_t type, uint8_t index, uint16_t languageID, void* buffer, uint16_t bufferSize, uint32_t* bytesReturned, uint32_t timeout) override
+ {
+ UNREFERENCED_PARAMETER(timeout);
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = 0;
+ }
+
+ ULONG bytesTransferred = 0;
+ if (!WinUsb_GetDescriptor(m_hWinUsbInterface, type, index, languageID, static_cast(buffer), bufferSize, &bytesTransferred))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = bytesTransferred;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT ControlTransfer(uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, void* buffer, uint16_t bufferSize, uint32_t* bytesReturned, uint32_t timeout) override
+ {
+ UNREFERENCED_PARAMETER(timeout);
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = 0;
+ }
+
+ WINUSB_SETUP_PACKET packet{};
+ packet.RequestType = requesttype;
+ packet.Request = request;
+ packet.Value = value;
+ packet.Index = index;
+ packet.Length = bufferSize;
+
+ ULONG bytesTransferred = 0;
+ if (!WinUsb_ControlTransfer(m_hWinUsbInterface, packet, static_cast(buffer), bufferSize, &bytesTransferred, nullptr))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = bytesTransferred;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT SetConfiguration(uint8_t configuration) override
+ {
+ // Not supported, fail silently.
+ return S_FALSE;
+ }
+
+ HRESULT ClaimInterface(uint8_t interfaceIndex) override
+ {
+ m_associatedInterface.index = interfaceIndex;
+
+ if (interfaceIndex > 0)
+ {
+ WINUSB_INTERFACE_HANDLE handle = nullptr;
+ if (!WinUsb_GetAssociatedInterface(m_hWinUsbInterface, interfaceIndex, &handle))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ m_associatedInterface.first = false;
+ m_associatedInterface.handle = handle;
+ }
+ else
+ {
+ m_associatedInterface.first = true;
+ m_associatedInterface.handle = m_hWinUsbInterface;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT ReleaseInterface(uint8_t interfaceIndex) override
+ {
+ if (interfaceIndex != m_associatedInterface.index)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+ }
+
+ if (m_associatedInterface.handle != nullptr && !m_associatedInterface.first)
+ {
+ WinUsb_Free(m_associatedInterface.handle);
+ m_associatedInterface.handle = nullptr;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT SetAlternateSetting(uint8_t interfaceIndex, uint8_t alternate) override
+ {
+ if (m_associatedInterface.handle == nullptr)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+ }
+
+ return E_FAIL;
+ }
+
+ HRESULT ReadPipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesRead, uint32_t timeout) override
+ {
+ UNREFERENCED_PARAMETER(timeout);
+
+ if (bytesRead != nullptr)
+ {
+ *bytesRead = 0;
+ }
+
+ if (m_associatedInterface.handle == nullptr)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+ }
+
+ if (!WinUsb_SetPipePolicy(m_associatedInterface.handle, pipeId, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ ULONG lengthTransferred = 0;
+ if (!WinUsb_ReadPipe(m_associatedInterface.handle, pipeId, static_cast(buffer), bufferSize, &lengthTransferred, nullptr))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (bytesRead != nullptr)
+ {
+ *bytesRead = lengthTransferred;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT WritePipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesWritten, uint32_t timeout) override
+ {
+ UNREFERENCED_PARAMETER(timeout);
+
+ if (bytesWritten != nullptr)
+ {
+ *bytesWritten = 0;
+ }
+
+ if (m_associatedInterface.handle == nullptr)
+ {
+ return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
+ }
+
+ if (!WinUsb_SetPipePolicy(m_associatedInterface.handle, pipeId, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ ULONG lengthTransferred = 0;
+ if (!WinUsb_WritePipe(m_associatedInterface.handle, pipeId, static_cast(buffer), bufferSize, &lengthTransferred, nullptr))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (bytesWritten != nullptr)
+ {
+ *bytesWritten = lengthTransferred;
+ }
+
+ return S_OK;
+ }
+
+ private:
+ struct Interface
+ {
+ WINUSB_INTERFACE_HANDLE handle = nullptr;
+ uint8_t index = 0;
+ bool first = false;
+ };
+
+ WINUSB_INTERFACE_HANDLE m_hWinUsbInterface = nullptr;
+ Interface m_associatedInterface;
+ };
+
+ class LibUsbDriver : public UsbDriver
+ {
+ public:
+ HRESULT Open(LPCWSTR pszPath) override
+ {
+ HRESULT hr = UsbDriver::Open(pszPath);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = m_event.Create();
+ if (FAILED(hr))
+ {
+ Close();
+ return hr;
+ }
+
+ return S_OK;
+ }
+
+ void Close() override
+ {
+ m_event.Close();
+ UsbDriver::Close();
+ }
+
+ HRESULT GetDescriptor(uint8_t type, uint8_t index, uint16_t languageID, void* buffer, uint16_t bufferSize, uint32_t* bytesReturned, uint32_t timeout) override
+ {
+ libusb_request data{};
+ data.timeout = timeout;
+ data.descriptor.type = type;
+ data.descriptor.index = index;
+ data.descriptor.language_id = languageID;
+ data.descriptor.recipient = USB_RECIP_DEVICE;
+ return DeviceIoControl(LIBUSB_IOCTL_GET_DESCRIPTOR, &data, sizeof(data), buffer, bufferSize, bytesReturned);
+ }
+
+ HRESULT ControlTransfer(uint8_t requesttype, uint8_t request, uint16_t value, uint16_t index, void* buffer, uint16_t bufferSize, uint32_t* bytesTransmitted, uint32_t timeout) override
+ {
+ libusb_request data{};
+ data.timeout = timeout;
+
+ uint32_t ioControlCode = 0;
+ switch (requesttype & (0x03 << 5))
+ {
+ case USB_TYPE_STANDARD:
+ switch (request)
+ {
+ case USB_REQ_GET_STATUS:
+ ioControlCode = LIBUSB_IOCTL_GET_STATUS;
+ data.status.recipient = requesttype & 0x1F;
+ data.status.index = index;
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ ioControlCode = LIBUSB_IOCTL_CLEAR_FEATURE;
+ data.feature.recipient = requesttype & 0x1F;
+ data.feature.feature = value;
+ data.feature.index = index;
+ break;
+ case USB_REQ_SET_FEATURE:
+ ioControlCode = LIBUSB_IOCTL_SET_FEATURE;
+ data.feature.recipient = requesttype & 0x1F;
+ data.feature.feature = value;
+ data.feature.index = index;
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ ioControlCode = LIBUSB_IOCTL_GET_DESCRIPTOR;
+ data.descriptor.recipient = requesttype & 0x1F;
+ data.descriptor.type = (value >> 8) & 0xFF;
+ data.descriptor.index = value & 0xFF;
+ data.descriptor.language_id = index;
+ break;
+ case USB_REQ_SET_DESCRIPTOR:
+ ioControlCode = LIBUSB_IOCTL_SET_DESCRIPTOR;
+ data.descriptor.recipient = requesttype & 0x1F;
+ data.descriptor.type = (value >> 8) & 0xFF;
+ data.descriptor.index = value & 0xFF;
+ data.descriptor.language_id = index;
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ ioControlCode = LIBUSB_IOCTL_GET_CONFIGURATION;
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ data.configuration.configuration = value;
+ ioControlCode = LIBUSB_IOCTL_SET_CONFIGURATION;
+ break;
+ case USB_REQ_GET_INTERFACE:
+ ioControlCode = LIBUSB_IOCTL_GET_INTERFACE;
+ data.intf.interface_number = index;
+ break;
+ case USB_REQ_SET_INTERFACE:
+ ioControlCode = LIBUSB_IOCTL_SET_INTERFACE;
+ data.intf.interface_number = index;
+ data.intf.altsetting_number = value;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+ break;
+ case USB_TYPE_CLASS:
+ case USB_TYPE_VENDOR:
+ ioControlCode = (requesttype & 0x80) != 0 ? LIBUSB_IOCTL_VENDOR_READ : LIBUSB_IOCTL_VENDOR_WRITE;
+ data.vendor.type = (requesttype >> 5) & 0x03;
+ data.vendor.recipient = requesttype & 0x1F;
+ data.vendor.request = request;
+ data.vendor.value = value;
+ data.vendor.index = index;
+ break;
+ default:
+ return E_INVALIDARG;
+ }
+
+ if ((requesttype & USB_ENDPOINT_IN) == 0)
+ {
+ if (bytesTransmitted != nullptr)
+ {
+ *bytesTransmitted = 0;
+ }
+
+ if (bufferSize > 0)
+ {
+ std::vector out(sizeof(data) + bufferSize);
+ std::memcpy(out.data(), &data, sizeof(data));
+ std::memcpy(out.data() + sizeof(data), buffer, bufferSize);
+ HRESULT hr = DeviceIoControl(ioControlCode, out.data(), sizeof(data) + bufferSize, nullptr, 0);
+ if (FAILED(hr))
+ return hr;
+
+ if (bytesTransmitted != nullptr)
+ {
+ *bytesTransmitted = bufferSize;
+ }
+
+ return hr;
+ }
+ else
+ {
+ return DeviceIoControl(ioControlCode, &data, sizeof(data), nullptr, 0);
+ }
+ }
+ else
+ {
+ return DeviceIoControl(ioControlCode, &data, sizeof(data), buffer, bufferSize, bytesTransmitted);
+ }
+ }
+
+ HRESULT SetConfiguration(uint8_t configuration) override
+ {
+ libusb_request data{};
+ data.configuration.configuration = configuration;
+ data.timeout = LIBUSB_DEFAULT_TIMEOUT;
+ return DeviceIoControl(LIBUSB_IOCTL_SET_CONFIGURATION, &data, sizeof(data), nullptr, 0);
+ }
+
+ HRESULT ClaimInterface(uint8_t interfaceIndex) override
+ {
+ libusb_request data{};
+ data.intf.interface_number = interfaceIndex;
+ data.timeout = LIBUSB_DEFAULT_TIMEOUT;
+ return DeviceIoControl(LIBUSB_IOCTL_CLAIM_INTERFACE, &data, sizeof(data), nullptr, 0);
+ }
+
+ HRESULT ReleaseInterface(uint8_t interfaceIndex) override
+ {
+ libusb_request data{};
+ data.intf.interface_number = interfaceIndex;
+ data.timeout = LIBUSB_DEFAULT_TIMEOUT;
+ return DeviceIoControl(LIBUSB_IOCTL_RELEASE_INTERFACE, &data, sizeof(data), nullptr, 0);
+ }
+
+ HRESULT SetAlternateSetting(uint8_t interfaceIndex, uint8_t alternate) override
+ {
+ libusb_request data{};
+ data.intf.interface_number = interfaceIndex;
+ data.intf.altsetting_number = alternate;
+ data.timeout = LIBUSB_DEFAULT_TIMEOUT;
+ return DeviceIoControl(LIBUSB_IOCTL_SET_INTERFACE, &data, sizeof(data), nullptr, 0);
+ }
+
+ HRESULT ReadPipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesRead, uint32_t timeout) override
+ {
+ return DeviceIoTransfer(LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ, pipeId, buffer, bufferSize, bytesRead, timeout);
+ }
+
+ HRESULT WritePipe(uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesWritten, uint32_t timeout) override
+ {
+ return DeviceIoTransfer(LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE, pipeId, buffer, bufferSize, bytesWritten, timeout);
+ }
+
+ private:
+ static const uint32_t LIBUSB_DEFAULT_TIMEOUT = 5000;
+
+ static const uint32_t LIBUSB_IOCTL_SET_CONFIGURATION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_GET_CONFIGURATION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_SET_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_GET_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_SET_FEATURE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_CLEAR_FEATURE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_GET_STATUS = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_SET_DESCRIPTOR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_GET_DESCRIPTOR = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80A, METHOD_IN_DIRECT, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_VENDOR_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_VENDOR_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_RESET_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_ABORT_ENDPOINT = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_RESET_DEVICE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_SET_DEBUG_LEVEL = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_GET_VERSION = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x812, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_ISOCHRONOUS_WRITE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x813, METHOD_IN_DIRECT, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_ISOCHRONOUS_READ = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x814, METHOD_OUT_DIRECT, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_CLAIM_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x815, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ static const uint32_t LIBUSB_IOCTL_RELEASE_INTERFACE = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x816, METHOD_BUFFERED, FILE_ANY_ACCESS);
+
+#include
+
+ struct interface_request
+ {
+ uint32_t interface_number;
+ uint32_t altsetting_number;
+ uint8_t intf_use_index : 1;
+ uint8_t altf_use_index : 1;
+ uint8_t : 6;
+ int16_t interface_index;
+ int16_t altsetting_index;
+ };
+
+ struct libusb_request
+ {
+ uint32_t timeout;
+ union
+ {
+ struct
+ {
+ uint32_t configuration;
+ } configuration;
+ interface_request intf;
+ struct
+ {
+ uint32_t endpoint;
+ uint32_t packet_size;
+ uint32_t max_transfer_size;
+ uint32_t transfer_flags;
+ uint32_t iso_start_frame_latency;
+ } endpoint;
+ struct
+ {
+ uint32_t type;
+ uint32_t recipient;
+ uint32_t request;
+ uint32_t value;
+ uint32_t index;
+ } vendor;
+ struct
+ {
+ uint32_t recipient;
+ uint32_t feature;
+ uint32_t index;
+ } feature;
+ struct
+ {
+ uint32_t recipient;
+ uint32_t index;
+ uint32_t status;
+ } status;
+ struct
+ {
+ uint32_t type;
+ uint32_t index;
+ uint32_t language_id;
+ uint32_t recipient;
+ } descriptor;
+ struct
+ {
+ uint32_t level;
+ } debug;
+ struct
+ {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t micro;
+ uint32_t nano;
+ uint32_t mod_value;
+ } version;
+ struct
+ {
+ uint32_t property;
+ } device_property;
+ struct
+ {
+ uint32_t key_type;
+ uint32_t name_offset;
+ uint32_t value_offset;
+ uint32_t value_length;
+ } device_registry_key;
+ struct
+ {
+ uint32_t objname_index;
+ } objname;
+ struct
+ {
+ uint32_t information_type;
+ } query_device;
+ struct
+ {
+ uint32_t interface_index;
+ uint32_t pipe_id;
+ uint32_t policy_type;
+ } pipe_policy;
+ struct
+ {
+ uint32_t policy_type;
+ } power_policy;
+ struct
+ {
+ uint32_t reset_type;
+ } reset_ex;
+ struct
+ {
+ uint8_t request_type;
+ uint8_t request;
+ uint16_t value;
+ uint16_t index;
+ uint16_t length;
+ } control;
+ };
+ };
+
+#include
+
+ private:
+ static const uint32_t maxReadWriteSize = 0x10000;
+
+ HRESULT DeviceIoTransfer(uint32_t ioControlCode, uint8_t pipeId, void* buffer, uint32_t bufferSize, uint32_t* bytesTransferred, uint32_t timeout)
+ {
+ if (bytesTransferred != nullptr)
+ {
+ *bytesTransferred = 0;
+ }
+
+ if (timeout == 0)
+ {
+ timeout = INFINITE;
+ }
+
+ ManualResetEvent event;
+ HRESULT hr = event.Create();
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ uint32_t transferred = 0;
+ while (bufferSize > 0)
+ {
+ uint32_t chunkSize = bufferSize > maxReadWriteSize ? maxReadWriteSize : bufferSize;
+
+ libusb_request transfer{};
+ transfer.endpoint.endpoint = pipeId;
+ transfer.endpoint.packet_size = 0;
+
+ event.Reset();
+
+ OVERLAPPED overlapped{};
+ overlapped.hEvent = event;
+ hr = DeviceIoControl(ioControlCode, &transfer, sizeof(transfer), buffer, chunkSize, nullptr, &overlapped);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ if (WaitForSingleObject(overlapped.hEvent, timeout) != WAIT_OBJECT_0)
+ {
+ libusb_request cancel{};
+ cancel.endpoint.endpoint = pipeId;
+ cancel.timeout = LIBUSB_DEFAULT_TIMEOUT;
+ DeviceIoControl(LIBUSB_IOCTL_ABORT_ENDPOINT, &cancel, sizeof(cancel), nullptr, 0);
+ return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+ }
+
+ DWORD dwNumberOfBytesTransferred = 0;
+ if (!GetOverlappedResult(m_hDevice, &overlapped, &dwNumberOfBytesTransferred, TRUE))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ transferred += dwNumberOfBytesTransferred;
+ if (dwNumberOfBytesTransferred != chunkSize)
+ {
+ break;
+ }
+
+ buffer = static_cast(buffer) + dwNumberOfBytesTransferred;
+ bufferSize -= dwNumberOfBytesTransferred;
+ }
+
+ if (bytesTransferred != nullptr)
+ {
+ *bytesTransferred = transferred;
+ }
+
+ return S_OK;
+ }
+
+ HRESULT DeviceIoControl(
+ uint32_t ioControlCode,
+ void* lpInBuffer,
+ uint32_t inBufferSize,
+ void* pOutBuffer,
+ uint32_t outBufferSize,
+ uint32_t* bytesReturned = nullptr,
+ LPOVERLAPPED pOverlapped = nullptr)
+ {
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = 0;
+ }
+
+ if (pOverlapped == nullptr)
+ {
+ m_event.Reset();
+
+ OVERLAPPED overlapped{};
+ overlapped.hEvent = m_event;
+ if (!::DeviceIoControl(m_hDevice, ioControlCode, lpInBuffer, inBufferSize, pOutBuffer, outBufferSize, nullptr, &overlapped))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_IO_PENDING)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ DWORD dwNumberOfBytesTransferred = 0;
+ if (!::GetOverlappedResult(m_hDevice, &overlapped, &dwNumberOfBytesTransferred, TRUE))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = dwNumberOfBytesTransferred;
+ }
+ }
+ else
+ {
+ DWORD dwBytesReturned = 0;
+ if (!::DeviceIoControl(m_hDevice, ioControlCode, lpInBuffer, inBufferSize, pOutBuffer, outBufferSize, &dwBytesReturned, pOverlapped))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_IO_PENDING)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ if (bytesReturned != nullptr)
+ {
+ *bytesReturned = dwBytesReturned;
+ }
+ }
+
+ return S_OK;
+ }
+
+ private:
+ ManualResetEvent m_event;
+ };
+
+ class UsbDevice
+ {
+ friend class UsbDeviceEnumerator;
+
+ public:
+ UsbDevice() = default;
+ UsbDevice(const UsbDevice&) = delete;
+ UsbDevice& operator=(const UsbDevice& other) = delete;
+ UsbDevice(UsbDevice&&) = delete;
+ UsbDevice& operator=(UsbDevice&& other) = delete;
+
+ public:
+ std::wstring GetInstanceId() const { return m_instanceId; }
+ std::wstring GetInterfacePath() const { return m_interfacePath; }
+ std::wstring GetService() const { return m_service; }
+
+ public:
+ HRESULT Open(std::unique_ptr& driver)
+ {
+ return Open(m_service, m_interfacePath, driver);
+ }
+
+ static HRESULT Open(const std::wstring& service, const std::wstring& interfacePath, std::unique_ptr& driver)
+ {
+ if (_wcsicmp(service.c_str(), L"WINUSB") == 0)
+ {
+ driver = std::make_unique();
+ }
+ else if (_wcsicmp(service.c_str(), L"libusb0") == 0 || _wcsicmp(service.c_str(), L"libusbK") == 0)
+ {
+ driver = std::make_unique();
+ }
+ else
+ {
+ return E_NOTIMPL;
+ }
+
+ return driver->Open(interfacePath.c_str());
+ }
+
+ private:
+ std::wstring m_instanceId;
+ std::wstring m_interfacePath;
+ std::wstring m_service;
+ };
+
+ class UsbDeviceEnumerator
+ {
+ public:
+ UsbDeviceEnumerator() = default;
+ UsbDeviceEnumerator(const UsbDeviceEnumerator&) = delete;
+ UsbDeviceEnumerator& operator=(const UsbDeviceEnumerator& other) = delete;
+ UsbDeviceEnumerator(UsbDeviceEnumerator&&) = delete;
+ UsbDeviceEnumerator& operator=(UsbDeviceEnumerator&& other) = delete;
+
+ public:
+ std::vector>& GetDevices() { return m_devices; }
+
+ public:
+ HRESULT EnumerateDevices()
+ {
+ DeviceInfoSet deviceInfoSet;
+ HRESULT hr = deviceInfoSet.GetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (FAILED(hr))
+ return hr;
+
+ for (DWORD index = 0; ; index++)
+ {
+ DeviceInfo deviceInfo;
+ if (!SetupDiEnumDeviceInfo(deviceInfoSet, index, &deviceInfo))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_ITEMS)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+
+ break;
+ }
+
+ SP_DEVICE_INTERFACE_DATA deviceInterface = { sizeof(SP_DEVICE_INTERFACE_DATA) };
+ if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfo, &GUID_DEVINTERFACE_USB_DEVICE, 0, &deviceInterface))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_ITEMS)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+ else
+ {
+ auto device = std::make_unique();
+
+ uint32_t installState = 0;
+ if (SUCCEEDED(deviceInfo.GetProperty(deviceInfoSet, &DEVPKEY_Device_InstanceId, device->m_instanceId)) &&
+ SUCCEEDED(deviceInfo.GetProperty(deviceInfoSet, &DEVPKEY_Device_InstallState, installState)) &&
+ SUCCEEDED(deviceInfo.GetProperty(deviceInfoSet, &DEVPKEY_Device_Service, device->m_service)) &&
+ SUCCEEDED(GetDeviceInterfacePath(deviceInfoSet, &deviceInterface, device->m_interfacePath)) &&
+ installState == 0)
+ {
+ m_devices.push_back(std::move(device));
+ }
+ }
+ }
+
+ return S_OK;
+ }
+
+ HRESULT GetDeviceInterfacePath(HDEVINFO hDeviceInfoSet, PSP_DEVICE_INTERFACE_DATA pDeviceInterfaceData, std::wstring& deviceInterfacePath)
+ {
+ DWORD dwRequiredSize = 0;
+ if (!SetupDiGetDeviceInterfaceDetailW(hDeviceInfoSet, pDeviceInterfaceData, nullptr, 0, &dwRequiredSize, nullptr))
+ {
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_INSUFFICIENT_BUFFER)
+ {
+ return HRESULT_FROM_WIN32(dwError);
+ }
+ }
+
+ std::vector buffer(dwRequiredSize);
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W* pDeviceInterfaceDetailData = reinterpret_cast(buffer.data());
+ pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+
+ if (!SetupDiGetDeviceInterfaceDetailW(hDeviceInfoSet, pDeviceInterfaceData, pDeviceInterfaceDetailData, dwRequiredSize, &dwRequiredSize, nullptr))
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ deviceInterfacePath = pDeviceInterfaceDetailData->DevicePath;
+ return S_OK;
+ }
+
+ private:
+ std::vector> m_devices;
+ };
+}
diff --git a/external/libusb/src/windows.c b/external/libusb/src/windows.c
deleted file mode 100644
index b9a79a07..00000000
--- a/external/libusb/src/windows.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/* libusb-win32, Generic Windows USB Library
- * Copyright (c) 2002-2005 Stephan Meyer
- * Copyright (c) 2000-2005 Johannes Erdfelt
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "lusb0_usb.h"
-#include "error.h"
-#include "usbi.h"
-#include "driver_api.h"
-#include "registry.h"
-#include "libusb-win32_version.h"
-
-#define LIBUSB_WIN32_DLL_LARGE_TRANSFER_SUPPORT
-
-#define LIBUSB_DEFAULT_TIMEOUT 5000
-#define LIBUSB_DEVICE_NAME "\\\\.\\libusb0-"
-#define LIBUSB_BUS_NAME "bus-0"
-#define LIBUSB_MAX_DEVICES 256
-
-typedef struct
-{
- usb_dev_handle *dev;
- libusb_request req;
- char *bytes;
- int size;
- DWORD control_code;
- OVERLAPPED ol;
-} usb_context_t;
-
-
-static struct usb_version _usb_version =
-{
- { VERSION_MAJOR,
- VERSION_MINOR,
- VERSION_MICRO,
- VERSION_NANO },
- { -1, -1, -1, -1 }
-};
-
-
-static int _usb_setup_async(usb_dev_handle *dev, void **context,
- DWORD control_code,
- unsigned char ep, int pktsize);
-static int _usb_transfer_sync(usb_dev_handle *dev, int control_code,
- int ep, int pktsize, char *bytes, int size,
- int timeout);
-
-static int usb_get_configuration(usb_dev_handle *dev, bool_t cached);
-static int _usb_cancel_io(usb_context_t *context);
-static int _usb_abort_ep(usb_dev_handle *dev, unsigned int ep);
-
-static int _usb_io_sync(HANDLE dev, unsigned int code, void *in, int in_size,
- void *out, int out_size, int *ret);
-static int _usb_reap_async(void *context, int timeout, int cancel);
-static int _usb_add_virtual_hub(struct usb_bus *bus);
-
-static void _usb_free_bus_list(struct usb_bus *bus);
-static void _usb_free_dev_list(struct usb_device *dev);
-static void _usb_deinit(void);
-
-/* DLL main entry point */
-BOOL WINAPI DllMain(HANDLE module, DWORD reason, LPVOID reserved)
-{
- switch (reason)
- {
- case DLL_PROCESS_ATTACH:
- break;
- case DLL_PROCESS_DETACH:
- _usb_deinit();
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- break;
- default:
- break;
- }
- return TRUE;
-}
-
-
-static int usb_get_configuration(usb_dev_handle *dev, bool_t cached)
-{
- int ret;
- char config;
- libusb_request request;
-
- if (cached)
- {
- memset(&request, 0, sizeof(request));
- request.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_GET_CACHED_CONFIGURATION,
- &request, sizeof(request), &request, sizeof(request), &ret))
- {
- USBERR("sending get cached configuration ioctl failed, win error: %s\n", usb_win_error_to_string());
- ret = -usb_win_error_to_errno();
- }
-
- if (ret < 1)
- ret = -EINVAL;
- else
- config = *((char*)&request);
- }
- else
- {
- ret = usb_control_msg(dev, USB_RECIP_DEVICE | USB_ENDPOINT_IN,
- USB_REQ_GET_CONFIGURATION, 0, 0, &config, 1,
- LIBUSB_DEFAULT_TIMEOUT);
- }
-
- if(ret < 0)
- return ret;
-
- return config;
-}
-
-int usb_os_open(usb_dev_handle *dev)
-{
- char dev_name[LIBUSB_PATH_MAX];
- char *p;
- int config;
- if (!dev)
- {
- USBERR("invalid device handle %p", dev);
- return -EINVAL;
- }
-
- dev->impl_info = INVALID_HANDLE_VALUE;
- dev->config = 0;
- dev->interface = -1;
- dev->altsetting = -1;
-
- if (!dev->device->filename)
- {
- USBERR0("invalid file name\n");
- return -ENOENT;
- }
-
- /* build the Windows file name from the unique device name */
- strcpy(dev_name, dev->device->filename);
-
- p = strstr(dev_name, "--");
-
- if (!p)
- {
- USBERR("invalid file name %s\n", dev->device->filename);
- return -ENOENT;
- }
-
- *p = 0;
-
- dev->impl_info = CreateFile(dev_name, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR("failed to open %s: win error: %s",
- dev->device->filename, usb_win_error_to_string());
- return -ENOENT;
- }
-
- // get the cached configuration (no device i/o)
- config = usb_get_configuration(dev, TRUE);
- if (config > 0)
- {
- dev->config = config;
- dev->interface = -1;
- dev->altsetting = -1;
- }
-
- return 0;
-}
-
-int usb_os_close(usb_dev_handle *dev)
-{
- if (dev->impl_info != INVALID_HANDLE_VALUE)
- {
- if (dev->interface >= 0)
- {
- usb_release_interface(dev, dev->interface);
- }
-
- CloseHandle(dev->impl_info);
- dev->impl_info = INVALID_HANDLE_VALUE;
- dev->interface = -1;
- dev->altsetting = -1;
- }
-
- return 0;
-}
-
-int usb_set_configuration(usb_dev_handle *dev, int configuration)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("error: device not open\n");
- return -EINVAL;
- }
-
- if (dev->config == configuration)
- {
- return 0;
- }
-
- if (dev->interface >= 0)
- {
- USBERR0("can't change configuration, an interface is still in use (claimed)\n");
- return -EINVAL;
- }
-
- req.configuration.configuration = configuration;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_SET_CONFIGURATION,
- &req, sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not set config %d: "
- "win error: %s", configuration, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- dev->config = configuration;
- dev->interface = -1;
- dev->altsetting = -1;
-
- return 0;
-}
-
-int usb_claim_interface(usb_dev_handle *dev, int interface)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- if (!dev->config)
- {
- USBERR("could not claim interface %d, invalid configuration %d\n", interface, dev->config);
- return -EINVAL;
- }
-
- if (dev->interface == interface)
- {
- return 0;
- }
-
- req.intf.interface_number = interface;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_CLAIM_INTERFACE,
- &req, sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not claim interface %d, "
- "win error: %s", interface, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
- else
- {
- dev->interface = interface;
- dev->altsetting = 0;
- return 0;
- }
-}
-
-int usb_release_interface(usb_dev_handle *dev, int interface)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- if (!dev->config)
- {
- USBERR("could not release interface %d, invalid configuration %d\n", interface, dev->config);
- return -EINVAL;
- }
-
- req.intf.interface_number = interface;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_RELEASE_INTERFACE,
- &req, sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not release interface %d, "
- "win error: %s", interface, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
- else
- {
- dev->interface = -1;
- dev->altsetting = -1;
-
- return 0;
- }
-}
-
-int usb_set_altinterface(usb_dev_handle *dev, int alternate)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- if (dev->config <= 0)
- {
- USBERR("could not set alt interface %d: invalid configuration %d\n", alternate, dev->config);
- return -EINVAL;
- }
-
- if (dev->interface < 0)
- {
- USBERR("could not set alt interface %d: no interface claimed\n", alternate);
- return -EINVAL;
- }
-
- req.intf.interface_number = dev->interface;
- req.intf.altsetting_number = alternate;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_SET_INTERFACE,
- &req, sizeof(libusb_request),
- NULL, 0, NULL))
- {
- USBERR("could not set alt interface "
- "%d/%d: win error: %s",
- dev->interface, alternate, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- dev->altsetting = alternate;
-
- return 0;
-}
-
-static int _usb_setup_async(usb_dev_handle *dev, void **context,
- DWORD control_code,
- unsigned char ep, int pktsize)
-{
- usb_context_t **c = (usb_context_t **)context;
-
- if (((control_code == LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE)
- || (control_code == LIBUSB_IOCTL_ISOCHRONOUS_WRITE))
- && (ep & USB_ENDPOINT_IN))
- {
- USBERR("invalid endpoint 0x%02x", ep);
- return -EINVAL;
- }
-
- if (((control_code == LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ)
- || (control_code == LIBUSB_IOCTL_ISOCHRONOUS_READ))
- && !(ep & USB_ENDPOINT_IN))
- {
- USBERR("invalid endpoint 0x%02x\n", ep);
- return -EINVAL;
- }
-
- *c = malloc(sizeof(usb_context_t));
-
- if (!*c)
- {
- USBERR0("memory allocation error\n");
- return -ENOMEM;
- }
-
- memset(*c, 0, sizeof(usb_context_t));
-
- (*c)->dev = dev;
- (*c)->req.endpoint.endpoint = ep;
- (*c)->req.endpoint.packet_size = pktsize;
- (*c)->control_code = control_code;
-
- (*c)->ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- if (!(*c)->ol.hEvent)
- {
- free(*c);
- *c = NULL;
- USBERR("creating event failed: win error: %s",
- usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-int usb_submit_async(void *context, char *bytes, int size)
-{
- usb_context_t *c = (usb_context_t *)context;
-
- if (!c)
- {
- USBERR0("invalid context");
- return -EINVAL;
- }
-
- if (c->dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- if (c->dev->config <= 0)
- {
- USBERR("invalid configuration %d\n", c->dev->config);
- return -EINVAL;
- }
-
- if (c->dev->interface < 0)
- {
- USBERR("invalid interface %d\n", c->dev->interface);
- return -EINVAL;
- }
-
-
- c->ol.Offset = 0;
- c->ol.OffsetHigh = 0;
- c->bytes = bytes;
- c->size = size;
-
- ResetEvent(c->ol.hEvent);
-
- if (!DeviceIoControl(c->dev->impl_info,
- c->control_code,
- &c->req, sizeof(libusb_request),
- c->bytes,
- c->size, NULL, &c->ol))
- {
- if (GetLastError() != ERROR_IO_PENDING)
- {
- USBERR("submitting request failed, "
- "win error: %s", usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
- }
-
- return 0;
-}
-
-static int _usb_reap_async(void *context, int timeout, int cancel)
-{
- usb_context_t *c = (usb_context_t *)context;
- ULONG ret = 0;
-
- if (!c)
- {
- USBERR0("invalid context\n");
- return -EINVAL;
- }
-
- if (WaitForSingleObject(c->ol.hEvent, timeout) == WAIT_TIMEOUT)
- {
- /* request timed out */
- if (cancel)
- {
- _usb_cancel_io(c);
- }
-
- USBERR0("timeout error\n");
- return -ETRANSFER_TIMEDOUT;
- }
-
- if (!GetOverlappedResult(c->dev->impl_info, &c->ol, &ret, TRUE))
- {
- USBERR("reaping request failed, win error: %s\n",usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return ret;
-}
-
-int usb_reap_async(void *context, int timeout)
-{
- return _usb_reap_async(context, timeout, TRUE);
-}
-
-int usb_reap_async_nocancel(void *context, int timeout)
-{
- return _usb_reap_async(context, timeout, FALSE);
-}
-
-
-int usb_cancel_async(void *context)
-{
- /* NOTE that this function will cancel all pending URBs */
- /* on the same endpoint as this particular context, or even */
- /* all pending URBs for this particular device. */
-
- usb_context_t *c = (usb_context_t *)context;
-
- if (!c)
- {
- USBERR0("invalid context\n");
- return -EINVAL;
- }
-
- if (c->dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- _usb_cancel_io(c);
-
- return 0;
-}
-
-int usb_free_async(void **context)
-{
- usb_context_t **c = (usb_context_t **)context;
-
- if (!*c)
- {
- USBERR0("invalid context\n");
- return -EINVAL;
- }
-
- CloseHandle((*c)->ol.hEvent);
-
- free(*c);
- *c = NULL;
-
- return 0;
-}
-
-static int _usb_transfer_sync(usb_dev_handle *dev, int control_code,
- int ep, int pktsize, char *bytes, int size,
- int timeout)
-{
- void *context = NULL;
- int transmitted = 0;
- int ret;
- int requested;
-
- if (!timeout) timeout=INFINITE;
- ret = _usb_setup_async(dev, &context, control_code, (unsigned char )ep,
- pktsize);
-
- if (ret < 0)
- {
- return ret;
- }
-
- do
- {
-#ifdef LIBUSB_WIN32_DLL_LARGE_TRANSFER_SUPPORT
- requested = size > LIBUSB_MAX_READ_WRITE ? LIBUSB_MAX_READ_WRITE : size;
-#else
- requested = size;
-#endif
- ret = usb_submit_async(context, bytes, requested);
-
- if (ret < 0)
- {
- transmitted = ret;
- break;
- }
-
- ret = usb_reap_async(context, timeout);
-
- if (ret < 0)
- {
- transmitted = ret;
- break;
- }
-
- transmitted += ret;
- bytes += ret;
- size -= ret;
- }
- while (size > 0 && ret == requested);
-
- usb_free_async(&context);
-
- return transmitted;
-}
-
-int usb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- return _usb_transfer_sync(dev, LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE,
- ep, 0, bytes, size, timeout);
-}
-
-int usb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- return _usb_transfer_sync(dev, LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
- ep, 0, bytes, size, timeout);
-}
-
-int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- return _usb_transfer_sync(dev, LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE,
- ep, 0, bytes, size, timeout);
-}
-
-int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size,
- int timeout)
-{
- return _usb_transfer_sync(dev, LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
- ep, 0, bytes, size, timeout);
-}
-
-int usb_isochronous_setup_async(usb_dev_handle *dev, void **context,
- unsigned char ep, int pktsize)
-{
- if (ep & 0x80)
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_ISOCHRONOUS_READ,
- ep, pktsize);
- else
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_ISOCHRONOUS_WRITE,
- ep, pktsize);
-}
-
-int usb_bulk_setup_async(usb_dev_handle *dev, void **context, unsigned char ep)
-{
- if (ep & 0x80)
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
- ep, 0);
- else
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE,
- ep, 0);
-}
-
-int usb_interrupt_setup_async(usb_dev_handle *dev, void **context,
- unsigned char ep)
-{
- if (ep & 0x80)
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
- ep, 0);
- else
- return _usb_setup_async(dev, context, LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE,
- ep, 0);
-}
-
-int usb_control_msg(usb_dev_handle *dev, int requesttype, int request,
- int value, int index, char *bytes, int size, int timeout)
-{
- int read = 0;
- libusb_request req;
- void *out = &req;
- int out_size = sizeof(libusb_request);
- void *in = bytes;
- int in_size = size;
- int code;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- req.timeout = timeout;
-
- /* windows doesn't support generic control messages, so it needs to be */
- /* split up */
- switch (requesttype & (0x03 << 5))
- {
- case USB_TYPE_STANDARD:
- switch (request)
- {
- case USB_REQ_GET_STATUS:
- req.status.recipient = requesttype & 0x1F;
- req.status.index = index;
- code = LIBUSB_IOCTL_GET_STATUS;
- break;
-
- case USB_REQ_CLEAR_FEATURE:
- req.feature.recipient = requesttype & 0x1F;
- req.feature.feature = value;
- req.feature.index = index;
- code = LIBUSB_IOCTL_CLEAR_FEATURE;
- break;
-
- case USB_REQ_SET_FEATURE:
- req.feature.recipient = requesttype & 0x1F;
- req.feature.feature = value;
- req.feature.index = index;
- code = LIBUSB_IOCTL_SET_FEATURE;
- break;
-
- case USB_REQ_GET_DESCRIPTOR:
- req.descriptor.recipient = requesttype & 0x1F;
- req.descriptor.type = (value >> 8) & 0xFF;
- req.descriptor.index = value & 0xFF;
- req.descriptor.language_id = index;
- code = LIBUSB_IOCTL_GET_DESCRIPTOR;
- break;
-
- case USB_REQ_SET_DESCRIPTOR:
- req.descriptor.recipient = requesttype & 0x1F;
- req.descriptor.type = (value >> 8) & 0xFF;
- req.descriptor.index = value & 0xFF;
- req.descriptor.language_id = index;
- code = LIBUSB_IOCTL_SET_DESCRIPTOR;
- break;
-
- case USB_REQ_GET_CONFIGURATION:
- code = LIBUSB_IOCTL_GET_CONFIGURATION;
- break;
-
- case USB_REQ_SET_CONFIGURATION:
- req.configuration.configuration = value;
- code = LIBUSB_IOCTL_SET_CONFIGURATION;
- break;
-
- case USB_REQ_GET_INTERFACE:
- req.intf.interface_number = index;
- code = LIBUSB_IOCTL_GET_INTERFACE;
- break;
-
- case USB_REQ_SET_INTERFACE:
- req.intf.interface_number = index;
- req.intf.altsetting_number = value;
- code = LIBUSB_IOCTL_SET_INTERFACE;
- break;
-
- default:
- USBERR("invalid request 0x%x", request);
- return -EINVAL;
- }
- break;
-
- case USB_TYPE_VENDOR:
- case USB_TYPE_CLASS:
-
- req.vendor.type = (requesttype >> 5) & 0x03;
- req.vendor.recipient = requesttype & 0x1F;
- req.vendor.request = request;
- req.vendor.value = value;
- req.vendor.index = index;
-
- if (requesttype & 0x80)
- code = LIBUSB_IOCTL_VENDOR_READ;
- else
- code = LIBUSB_IOCTL_VENDOR_WRITE;
- break;
-
- case USB_TYPE_RESERVED:
- default:
- USBERR("invalid or unsupported request type: %x",
- requesttype);
- return -EINVAL;
- }
-
- /* out request? */
- if (!(requesttype & USB_ENDPOINT_IN))
- {
- if (!(out = malloc(sizeof(libusb_request) + size)))
- {
- USBERR0("memory allocation failed\n");
- return -ENOMEM;
- }
-
- memcpy(out, &req, sizeof(libusb_request));
- memcpy((char *)out + sizeof(libusb_request), bytes, size);
- out_size = sizeof(libusb_request) + size;
- in = NULL;
- in_size = 0;
- }
-
- if (!_usb_io_sync(dev->impl_info, code, out, out_size, in, in_size, &read))
- {
- USBERR("sending control message failed, win error: %s\n", usb_win_error_to_string());
- if (!(requesttype & USB_ENDPOINT_IN))
- {
- free(out);
- }
- return -usb_win_error_to_errno();
- }
-
- /* out request? */
- if (!(requesttype & USB_ENDPOINT_IN))
- {
- free(out);
- return size;
- }
- else
- return read;
-}
-
-
-int usb_os_find_busses(struct usb_bus **busses)
-{
- struct usb_bus *bus = NULL;
-
- /* create one 'virtual' bus */
-
- bus = malloc(sizeof(struct usb_bus));
-
- if (!bus)
- {
- USBERR0("memory allocation failed\n");
- return -ENOMEM;
- }
-
- memset(bus, 0, sizeof(*bus));
- strcpy(bus->dirname, LIBUSB_BUS_NAME);
-
- USBMSG("found %s\n", bus->dirname);
-
- *busses = bus;
-
- return 0;
-}
-
-int usb_os_find_devices(struct usb_bus *bus, struct usb_device **devices)
-{
- int i;
- struct usb_device *dev, *fdev = NULL;
- char dev_name[LIBUSB_PATH_MAX];
- int ret;
- HANDLE handle;
- libusb_request req;
-
- for (i = 1; i < LIBUSB_MAX_DEVICES; i++)
- {
- ret = 0;
-
- _snprintf(dev_name, sizeof(dev_name) - 1,"%s%04d",
- LIBUSB_DEVICE_NAME, i);
-
- if (!(dev = malloc(sizeof(*dev))))
- {
- USBERR0("memory allocation failed\n");
- return -ENOMEM;
- }
-
- memset(dev, 0, sizeof(*dev));
- dev->bus = bus;
- dev->devnum = (unsigned char)i;
-
- handle = CreateFile(dev_name, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
-
- if (handle == INVALID_HANDLE_VALUE)
- {
- free(dev);
- continue;
- }
-
- /* retrieve device descriptor */
- req.descriptor.type = USB_DT_DEVICE;
- req.descriptor.recipient = USB_RECIP_DEVICE;
- req.descriptor.index = 0;
- req.descriptor.language_id = 0;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- _usb_io_sync(handle, LIBUSB_IOCTL_GET_DESCRIPTOR,
- &req, sizeof(libusb_request),
- &dev->descriptor, USB_DT_DEVICE_SIZE, &ret);
-
- if (ret < USB_DT_DEVICE_SIZE)
- {
- USBERR0("couldn't read device descriptor\n");
- free(dev);
- CloseHandle(handle);
- continue;
- }
-
- _snprintf(dev->filename, LIBUSB_PATH_MAX - 1, "%s--0x%04x-0x%04x",
- dev_name, dev->descriptor.idVendor, dev->descriptor.idProduct);
-
- CloseHandle(handle);
-
- LIST_ADD(fdev, dev);
-
- USBMSG("found %s on %s\n", dev->filename, bus->dirname);
- }
-
- *devices = fdev;
-
- return 0;
-}
-
-
-void usb_os_init(void)
-{
- HANDLE dev;
- libusb_request req;
- int i;
- int ret;
- char dev_name[LIBUSB_PATH_MAX];
-
- USBMSG("dll version: %d.%d.%d.%d\n",
- VERSION_MAJOR, VERSION_MINOR,
- VERSION_MICRO, VERSION_NANO);
-
-
- for (i = 1; i < LIBUSB_MAX_DEVICES; i++)
- {
- /* build the Windows file name */
- _snprintf(dev_name, sizeof(dev_name) - 1,"%s%04d",
- LIBUSB_DEVICE_NAME, i);
-
- dev = CreateFile(dev_name, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
-
- if (dev == INVALID_HANDLE_VALUE)
- {
- continue;
- }
-
- if (!_usb_io_sync(dev, LIBUSB_IOCTL_GET_VERSION,
- &req, sizeof(libusb_request),
- &req, sizeof(libusb_request), &ret)
- || (ret < sizeof(libusb_request)))
- {
- USBERR0("getting driver version failed\n");
- CloseHandle(dev);
- continue;
- }
- else
- {
- _usb_version.driver.major = req.version.major;
- _usb_version.driver.minor = req.version.minor;
- _usb_version.driver.micro = req.version.micro;
- _usb_version.driver.nano = req.version.nano;
-
- USBMSG("driver version: %d.%d.%d.%d\n",
- req.version.major, req.version.minor,
- req.version.micro, req.version.nano);
-
- /* set debug level */
- req.timeout = 0;
- req.debug.level = usb_log_get_level();
-
- if (!_usb_io_sync(dev, LIBUSB_IOCTL_SET_DEBUG_LEVEL,
- &req, sizeof(libusb_request),
- NULL, 0, NULL))
- {
- USBERR0("setting debug level failed");
- }
-
- CloseHandle(dev);
- break;
- }
- }
-}
-
-
-int usb_resetep(usb_dev_handle *dev, unsigned int ep)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- req.endpoint.endpoint = (int)ep;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_ABORT_ENDPOINT, &req,
- sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not abort ep 0x%02x, win error: %s\n", ep, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_RESET_ENDPOINT, &req,
- sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not reset ep 0x%02x, win error: %s\n", ep, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-int usb_clear_halt(usb_dev_handle *dev, unsigned int ep)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- req.endpoint.endpoint = (int)ep;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_RESET_ENDPOINT, &req,
- sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not clear halt, ep 0x%02x, "
- "win error: %s", ep, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-int usb_reset(usb_dev_handle *dev)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_RESET_DEVICE,
- &req, sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not reset device, win error: %s\n", usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-int usb_reset_ex(usb_dev_handle *dev, unsigned int reset_type)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open\n");
- return -EINVAL;
- }
-
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
- req.reset_ex.reset_type = reset_type;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_RESET_DEVICE_EX,
- &req, sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not reset device, win error: %s\n", usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-const struct usb_version *usb_get_version(void)
-{
- return &_usb_version;
-}
-
-void usb_set_debug(int level)
-{
- HANDLE dev;
- libusb_request req;
- int i;
- char dev_name[LIBUSB_PATH_MAX];
-
- if (usb_log_get_level() || level)
- {
- USBMSG("setting debugging level to %d (%s)\n",
- level, level ? "on" : "off");
- }
-
- usb_log_set_level(level);
-
- /* find a valid device */
- for (i = 1; i < LIBUSB_MAX_DEVICES; i++)
- {
- /* build the Windows file name */
- _snprintf(dev_name, sizeof(dev_name) - 1,"%s%04d",
- LIBUSB_DEVICE_NAME, i);
-
- dev = CreateFile(dev_name, 0, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED, NULL);
-
- if (dev == INVALID_HANDLE_VALUE)
- {
- continue;
- }
-
- /* set debug level */
- req.timeout = 0;
- req.debug.level = usb_log_get_level();
-
- if (!_usb_io_sync(dev, LIBUSB_IOCTL_SET_DEBUG_LEVEL,
- &req, sizeof(libusb_request),
- NULL, 0, NULL))
- {
- USBERR0("setting debug level failed\n");
- }
-
- CloseHandle(dev);
-
- break;
- }
-}
-
-int usb_os_determine_children(struct usb_bus *bus)
-{
- struct usb_device *dev;
- int i = 0;
-
- /* add a virtual hub to the bus to emulate this feature */
- if (_usb_add_virtual_hub(bus))
- {
- if (bus->root_dev->children)
- {
- free(bus->root_dev->children);
- }
-
- bus->root_dev->num_children = 0;
- for (dev = bus->devices; dev; dev = dev->next)
- bus->root_dev->num_children++;
-
- bus->root_dev->children
- = malloc(sizeof(struct usb_device *) * bus->root_dev->num_children);
-
- for (dev = bus->devices; dev; dev = dev->next)
- bus->root_dev->children[i++] = dev;
- }
-
- return 0;
-}
-
-static int _usb_cancel_io(usb_context_t *context)
-{
- int ret;
- ret = _usb_abort_ep(context->dev, context->req.endpoint.endpoint);
- WaitForSingleObject(context->ol.hEvent, 0);
- return ret;
-}
-
-static int _usb_abort_ep(usb_dev_handle *dev, unsigned int ep)
-{
- libusb_request req;
-
- if (dev->impl_info == INVALID_HANDLE_VALUE)
- {
- USBERR0("device not open");
- return -EINVAL;
- }
-
- req.endpoint.endpoint = (int)ep;
- req.timeout = LIBUSB_DEFAULT_TIMEOUT;
-
- if (!_usb_io_sync(dev->impl_info, LIBUSB_IOCTL_ABORT_ENDPOINT, &req,
- sizeof(libusb_request), NULL, 0, NULL))
- {
- USBERR("could not abort ep 0x%02x, win error: %s\n", ep, usb_win_error_to_string());
- return -usb_win_error_to_errno();
- }
-
- return 0;
-}
-
-static int _usb_io_sync(HANDLE dev, unsigned int code, void *out, int out_size,
- void *in, int in_size, int *ret)
-{
- OVERLAPPED ol;
- DWORD _ret;
-
- memset(&ol, 0, sizeof(ol));
-
- if (ret)
- *ret = 0;
-
- ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- if (!ol.hEvent)
- return FALSE;
-
- if (!DeviceIoControl(dev, code, out, out_size, in, in_size, NULL, &ol))
- {
- if (GetLastError() != ERROR_IO_PENDING)
- {
- CloseHandle(ol.hEvent);
- return FALSE;
- }
- }
-
- if (GetOverlappedResult(dev, &ol, &_ret, TRUE))
- {
- if (ret)
- *ret = (int)_ret;
- CloseHandle(ol.hEvent);
- return TRUE;
- }
-
- CloseHandle(ol.hEvent);
- return FALSE;
-}
-
-static int _usb_add_virtual_hub(struct usb_bus *bus)
-{
- struct usb_device *dev;
-
- if (!bus->root_dev)
- {
- if (!(dev = malloc(sizeof(*dev))))
- return FALSE;
-
- memset(dev, 0, sizeof(*dev));
- strcpy(dev->filename, "virtual-hub");
- dev->bus = bus;
-
- dev->descriptor.bLength = USB_DT_DEVICE_SIZE;
- dev->descriptor.bDescriptorType = USB_DT_DEVICE;
- dev->descriptor.bcdUSB = 0x0200;
- dev->descriptor.bDeviceClass = USB_CLASS_HUB;
- dev->descriptor.bDeviceSubClass = 0;
- dev->descriptor.bDeviceProtocol = 0;
- dev->descriptor.bMaxPacketSize0 = 64;
- dev->descriptor.idVendor = 0;
- dev->descriptor.idProduct = 0;
- dev->descriptor.bcdDevice = 0x100;
- dev->descriptor.iManufacturer = 0;
- dev->descriptor.iProduct = 0;
- dev->descriptor.iSerialNumber = 0;
- dev->descriptor.bNumConfigurations = 0;
-
- bus->root_dev = dev;
- }
-
- return TRUE;
-}
-
-static void _usb_free_bus_list(struct usb_bus *bus)
-{
- if (bus)
- {
- _usb_free_bus_list(bus->next);
- if (bus->root_dev)
- usb_free_dev(bus->root_dev);
- _usb_free_dev_list(bus->devices);
- usb_free_bus(bus);
- }
-}
-
-static void _usb_free_dev_list(struct usb_device *dev)
-{
- if (dev)
- {
- _usb_free_dev_list(dev->next);
- usb_free_dev(dev);
- }
-}
-
-static void _usb_deinit(void)
-{
- _usb_free_bus_list(usb_get_busses());
-}
diff --git a/external/libusb/src/windows.cpp b/external/libusb/src/windows.cpp
new file mode 100644
index 00000000..2ac8b705
--- /dev/null
+++ b/external/libusb/src/windows.cpp
@@ -0,0 +1,470 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2019 Marius Greuel
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "libwinusb.h"
+
+extern "C"
+{
+#include "error.h"
+#include "usbi.h"
+}
+
+static std::string CreateMessageFromError(HRESULT hr)
+{
+ LPSTR pszMessage = nullptr;
+ DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, hr, 0, (LPSTR)&pszMessage, 0, nullptr);
+ if (dwChars > 0 && pszMessage != nullptr)
+ {
+ if (dwChars > 0 && pszMessage[dwChars - 1] == '\n')
+ dwChars--;
+
+ if (dwChars > 0 && pszMessage[dwChars - 1] == '\r')
+ dwChars--;
+
+ std::string message = std::string(pszMessage, dwChars);
+ LocalFree(pszMessage);
+ return message;
+ }
+ else
+ {
+ return "Unknown error";
+ }
+}
+
+static int usb_hresult_to_errno(HRESULT hr)
+{
+ if (SUCCEEDED(hr))
+ return 0;
+
+ switch (hr)
+ {
+ case HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER):
+ return EINVAL;
+ case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
+ return ENOMEM;
+ case HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED):
+ return EPERM;
+ case HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE):
+ case HRESULT_FROM_WIN32(ERROR_BAD_DEVICE):
+ case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
+ return ENODEV;
+ case HRESULT_FROM_WIN32(ERROR_SEM_TIMEOUT):
+ case HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED):
+ return ETIMEDOUT;
+ default:
+ return EIO;
+ }
+}
+
+void usb_os_init(void)
+{
+}
+
+void usb_set_debug(int level)
+{
+ if (usb_log_get_level() || level)
+ {
+ USBMSG("setting debugging level to %d (%s)\n", level, level ? "on" : "off");
+ }
+
+ usb_log_set_level(static_cast(level));
+}
+
+int usb_os_find_busses(struct usb_bus** busses)
+{
+ auto bus = static_cast(std::malloc(sizeof(struct usb_bus)));
+ if (bus == nullptr)
+ {
+ USBERR("memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ std::memset(bus, 0, sizeof(*bus));
+ std::strcpy(bus->dirname, "bus-0");
+
+ USBMSG("found %s\n", bus->dirname);
+
+ *busses = bus;
+ return 0;
+}
+
+int usb_os_find_devices(struct usb_bus* bus, struct usb_device** devices)
+{
+ if (bus == nullptr)
+ {
+ return -EINVAL;
+ }
+
+ if (devices == nullptr)
+ {
+ return -EINVAL;
+ }
+
+ LibWinUsb::UsbDeviceEnumerator enumerator;
+ HRESULT hr = enumerator.EnumerateDevices();
+ if (FAILED(hr))
+ {
+ return -1;
+ }
+
+ struct usb_device* fdev = nullptr;
+
+ const auto& list = enumerator.GetDevices();
+ for (const auto& item : list)
+ {
+ struct usb_device* dev = static_cast(std::malloc(sizeof(struct usb_device)));
+ if (dev == nullptr)
+ {
+ USBERR0("memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ std::memset(dev, 0, sizeof(*dev));
+
+ std::unique_ptr driver;
+ if (FAILED(item->Open(driver)) ||
+ FAILED(driver->GetDescriptor(USB_DT_DEVICE, 0, 0, &dev->descriptor, sizeof(dev->descriptor), nullptr, 5000)))
+ {
+ USBERR0("couldn't read device descriptor\n");
+ free(dev);
+ continue;
+ }
+
+ _snprintf(dev->filename, LIBUSB_PATH_MAX - 1, "%s--%s",
+ LibWinUsb::Encoding::ToAnsi(item->GetInterfacePath()).c_str(),
+ LibWinUsb::Encoding::ToAnsi(item->GetService()).c_str());
+
+ LIST_ADD(fdev, dev);
+
+ USBMSG("found %s on %s\n", dev->filename, bus->dirname);
+ }
+
+ *devices = fdev;
+ return 0;
+}
+
+int usb_os_determine_children(struct usb_bus* bus)
+{
+ return 0;
+}
+
+int usb_os_open(usb_dev_handle* dev)
+{
+ if (dev == nullptr)
+ {
+ USBERR("invalid device handle %p", dev);
+ return -EINVAL;
+ }
+
+ dev->impl_info = nullptr;
+ dev->config = 0;
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ std::string dev_name = dev->device->filename;
+ auto pos = dev_name.find("--");
+ if (pos == std::string::npos)
+ {
+ USBERR("invalid file name %s\n", dev->device->filename);
+ return -ENOENT;
+ }
+
+ std::unique_ptr driver;
+ HRESULT hr = LibWinUsb::UsbDevice::Open(LibWinUsb::Encoding::ToUnicode(dev_name.substr(pos + 2)), LibWinUsb::Encoding::ToUnicode(dev_name.substr(0, pos)), driver);
+ if (FAILED(hr))
+ {
+ USBERR("failed to open %s: win error: %s\n", dev->device->filename, CreateMessageFromError(hr).c_str());
+ return -ENOENT;
+ }
+
+ dev->impl_info = driver.release();
+
+ return 0;
+}
+
+int usb_os_close(usb_dev_handle* dev)
+{
+ delete static_cast(dev->impl_info);
+
+ dev->impl_info = nullptr;
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ return 0;
+}
+
+int usb_control_msg(usb_dev_handle* dev, int requestType, int request, int value, int index, char* bytes, int size, int timeout)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("error: device not open\n");
+ return -EINVAL;
+ }
+
+ if (requestType == (USB_ENDPOINT_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) && request == USB_REQ_GET_DESCRIPTOR)
+ {
+ uint32_t bytesReturned = 0;
+ HRESULT hr = static_cast(dev->impl_info)->GetDescriptor(
+ static_cast(value >> 8),
+ static_cast(value),
+ static_cast(index),
+ bytes,
+ static_cast(size),
+ &bytesReturned,
+ timeout);
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ return static_cast(bytesReturned);
+ }
+ else
+ {
+ uint32_t bytesReturned = 0;
+ HRESULT hr = static_cast(dev->impl_info)->ControlTransfer(
+ static_cast(requestType),
+ static_cast(request),
+ static_cast(value),
+ static_cast(index),
+ bytes,
+ static_cast(size),
+ &bytesReturned,
+ timeout);
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ return static_cast(bytesReturned);
+ }
+}
+
+int usb_set_configuration(usb_dev_handle* dev, int configuration)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("error: device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == configuration)
+ {
+ return 0;
+ }
+
+ if (dev->interface >= 0)
+ {
+ USBERR0("can't change configuration, an interface is still in use (claimed)\n");
+ return -EINVAL;
+ }
+
+ HRESULT hr = static_cast(dev->impl_info)->SetConfiguration(static_cast(configuration));
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ dev->config = configuration;
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ return 0;
+}
+
+int usb_claim_interface(usb_dev_handle* dev, int interface)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == 0)
+ {
+ USBERR("could not claim interface %d, invalid configuration %d\n", interface, dev->config);
+ return -EINVAL;
+ }
+
+ if (dev->interface == interface)
+ {
+ return 0;
+ }
+
+ HRESULT hr = static_cast(dev->impl_info)->ClaimInterface(static_cast(interface));
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ dev->interface = interface;
+ dev->altsetting = 0;
+
+ return 0;
+}
+
+int usb_release_interface(usb_dev_handle* dev, int interface)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == 0)
+ {
+ USBERR("could not release interface %d, invalid configuration %d\n", interface, dev->config);
+ return -EINVAL;
+ }
+
+ HRESULT hr = static_cast(dev->impl_info)->ReleaseInterface(static_cast(interface));
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ dev->interface = -1;
+ dev->altsetting = -1;
+
+ return 0;
+}
+
+int usb_set_altinterface(usb_dev_handle* dev, int alternate)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == 0)
+ {
+ USBERR("could not set alt interface %d: invalid configuration %d\n", alternate, dev->config);
+ return -EINVAL;
+ }
+
+ if (dev->interface < 0)
+ {
+ USBERR("could not set alt interface %d: no interface claimed\n", alternate);
+ return -EINVAL;
+ }
+
+ HRESULT hr = static_cast(dev->impl_info)->SetAlternateSetting(
+ static_cast(dev->interface),
+ static_cast(alternate));
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ dev->altsetting = alternate;
+
+ return 0;
+}
+
+int usb_bulk_read(usb_dev_handle* dev, int ep, char* bytes, int size, int timeout)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == 0)
+ {
+ USBERR("invalid configuration %d\n", dev->config);
+ return -EINVAL;
+ }
+
+ if (dev->interface < 0)
+ {
+ USBERR("invalid interface %d\n", dev->interface);
+ return -EINVAL;
+ }
+
+ if ((ep & USB_ENDPOINT_IN) == 0)
+ {
+ USBERR("invalid endpoint 0x%02x", ep);
+ return -EINVAL;
+ }
+
+ uint32_t bytesRead = 0;
+ HRESULT hr = static_cast(dev->impl_info)->ReadPipe(
+ static_cast(ep),
+ bytes,
+ size,
+ &bytesRead,
+ timeout);
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ return static_cast(bytesRead);
+}
+
+int usb_bulk_write(usb_dev_handle* dev, int ep, char* bytes, int size, int timeout)
+{
+ if (dev->impl_info == nullptr)
+ {
+ USBERR0("device not open\n");
+ return -EINVAL;
+ }
+
+ if (dev->config == 0)
+ {
+ USBERR("invalid configuration %d\n", dev->config);
+ return -EINVAL;
+ }
+
+ if (dev->interface < 0)
+ {
+ USBERR("invalid interface %d\n", dev->interface);
+ return -EINVAL;
+ }
+
+ if ((ep & USB_ENDPOINT_IN) != 0)
+ {
+ USBERR("invalid endpoint 0x%02x", ep);
+ return -EINVAL;
+ }
+
+ uint32_t bytesWritten = 0;
+ HRESULT hr = static_cast(dev->impl_info)->WritePipe(
+ static_cast(ep),
+ bytes,
+ size,
+ &bytesWritten,
+ timeout);
+ if (FAILED(hr))
+ {
+ return -usb_hresult_to_errno(hr);
+ }
+
+ return static_cast(bytesWritten);
+}
+
+int usb_interrupt_read(usb_dev_handle* dev, int ep, char* bytes, int size, int timeout)
+{
+ return usb_bulk_read(dev, ep, bytes, size, timeout);
+}
+
+int usb_interrupt_write(usb_dev_handle* dev, int ep, char* bytes, int size, int timeout)
+{
+ return usb_bulk_write(dev, ep, bytes, size, timeout);
+}