Created
January 30, 2023 18:56
-
-
Save Novakov/894862d4e9d8316ef5bd976cc85c2ea1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdio> | |
#include <exception> | |
#include <memory> | |
#include <Windows.h> | |
#include "libusb.h" | |
#include "utils.hpp" | |
namespace libusb | |
{ | |
namespace details | |
{ | |
struct ContextDeleter | |
{ | |
void operator()(libusb_context* ctx) | |
{ | |
if(ctx != nullptr) | |
{ | |
libusb_exit(ctx); | |
} | |
} | |
}; | |
struct DeviceDeleter | |
{ | |
void operator()(libusb_device_handle* device) | |
{ | |
if(device != nullptr) | |
{ | |
libusb_close(device); | |
} | |
} | |
}; | |
} | |
using ContextHandle = std::unique_ptr<libusb_context, details::ContextDeleter>; | |
using DeviceHandle = std::unique_ptr<libusb_device_handle, details::DeviceDeleter>; | |
class ClaimedInterface | |
{ | |
public: | |
ClaimedInterface(const ClaimedInterface&) = delete; | |
ClaimedInterface& operator=(const ClaimedInterface&) = delete; | |
ClaimedInterface() : _device{nullptr}, _iface{0} | |
{ | |
} | |
ClaimedInterface(DeviceHandle::pointer device, std::uint8_t iface) : | |
_device{device}, | |
_iface{iface} | |
{ | |
} | |
ClaimedInterface(ClaimedInterface&& other) : _device{other._device}, _iface{other._iface} | |
{ | |
other._device = nullptr; | |
other._iface = 0; | |
} | |
~ClaimedInterface() | |
{ | |
if(_device != nullptr) | |
{ | |
libusb_release_interface(_device, _iface); | |
_device = nullptr; | |
_iface = 0; | |
} | |
} | |
ClaimedInterface& operator=(ClaimedInterface&& other) | |
{ | |
ClaimedInterface tmp{std::move(other)}; | |
std::swap(_device, tmp._device); | |
std::swap(_iface, tmp._iface); | |
return *this; | |
} | |
private: | |
DeviceHandle::pointer _device; | |
std::uint8_t _iface; | |
}; | |
class Device | |
{ | |
public: | |
explicit Device(DeviceHandle handle) : _handle{std::move(handle)} | |
{ | |
} | |
Device(Device&&) = default; | |
Device& operator=(Device&&) = default; | |
ClaimedInterface ClaimInterface(std::uint8_t iface) | |
{ | |
if(libusb_claim_interface(_handle.get(), iface) != LIBUSB_SUCCESS) | |
{ | |
printf("Failed to claim interface\n"); | |
throw std::exception("Failed to claim interface"); | |
} | |
return ClaimedInterface(_handle.get(), iface); | |
} | |
void ControlTransfer(std::uint8_t requestType, std::uint8_t request, std::uint16_t value, std::uint16_t index) | |
{ | |
auto r = libusb_control_transfer( | |
_handle.get(), requestType, request, value, index, nullptr, 0, 0); | |
printf("result = %d\n", r); | |
} | |
private: | |
DeviceHandle _handle; | |
}; | |
ContextHandle Init() | |
{ | |
libusb_context* ctx = nullptr; | |
if(libusb_init(&ctx) != LIBUSB_SUCCESS) | |
{ | |
throw std::exception("Failed to initialize context"); | |
} | |
return ContextHandle{ctx, {}}; | |
} | |
Device OpenByVidPid(const ContextHandle& context, std::uint16_t vid, std::uint16_t pid) | |
{ | |
auto h = libusb_open_device_with_vid_pid(context.get(), vid, pid); | |
if(h == nullptr) | |
{ | |
throw std::exception("Failed to open device"); | |
} | |
return Device{DeviceHandle{h, {}}}; | |
} | |
} | |
static constexpr std::uint16_t VID = 0x4D4E; | |
static constexpr std::uint16_t PID = 0x4455; | |
int main() | |
{ | |
printf("Hello World\n"); | |
auto context = libusb::Init(); | |
libusb_set_debug(context.get(), 255); | |
printf("Scenario 1\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("Claiming\n"); | |
auto claimed3 = device.ClaimInterface(3); | |
auto claimed2 = device.ClaimInterface(2); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
2); | |
} | |
printf("Scenario 2\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("Claiming\n"); | |
auto claimed = device.ClaimInterface(0); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
0); | |
} | |
printf("Scenario 3\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("Claiming\n"); | |
auto claimed = device.ClaimInterface(4); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
4); | |
} | |
printf("Scenario 4\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("\tStep1\n"); | |
{ | |
auto claimed3 = device.ClaimInterface(3); | |
auto claimed2 = device.ClaimInterface(2); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
2); | |
} | |
printf("\tStep2\n"); | |
{ | |
auto claimed3 = device.ClaimInterface(3); | |
auto claimed2 = device.ClaimInterface(2); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
2); | |
} | |
} | |
printf("Scenario 5\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
{ | |
auto claimed = device.ClaimInterface(0); | |
} | |
} | |
printf("Scenario 6\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
{ | |
printf("Claiming interface\n"); | |
auto claimed = device.ClaimInterface(4); | |
printf("Interface claimed\n"); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
4); | |
} | |
printf("Before closing device\n"); | |
} | |
printf("Scenario 7\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientDevice | UsbRequestType::TypeVendor, | |
0xAA, | |
0, | |
0x20); | |
} | |
printf("Scenario 8\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("claiming\n"); | |
auto claimed = device.ClaimInterface(4); | |
printf("ctrl transfer\n"); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientDevice | UsbRequestType::TypeVendor, | |
0xAA, | |
0, | |
0x20); | |
} | |
printf("Scenario 9\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("Device opened. Not disconnect it\n"); | |
getchar(); | |
printf("Claiming interface\n"); | |
auto claimed = device.ClaimInterface(4); | |
printf("Interface claimed\n"); | |
} | |
printf("Scenario 10\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("Device opened. Not disconnect it\n"); | |
getchar(); | |
printf("Claiming interface\n"); | |
auto claimed = device.ClaimInterface(2); | |
printf("Interface claimed\n"); | |
} | |
printf("Scenario 11\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, PID); | |
printf("--->\n"); | |
{ | |
auto claimed = device.ClaimInterface(14); | |
} | |
printf("<---\n"); | |
} | |
printf("Scenario 12\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, 0x4E43); | |
printf("--->\n"); | |
{ | |
auto claimed = device.ClaimInterface(1); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientInterface | UsbRequestType::TypeClass, | |
0x01, | |
0x20, | |
1); | |
} | |
printf("<---\n"); | |
} | |
printf("Scenario 13\n"); | |
{ | |
auto device = libusb::OpenByVidPid(context, VID, 0x4E49); | |
printf("--->\n"); | |
{ | |
// auto claimed = device.ClaimInterface(1); | |
device.ControlTransfer( | |
UsbRequestType::DeviceToHost | UsbRequestType::RecipientDevice | UsbRequestType::TypeVendor, | |
0x01, | |
0x20, | |
0); | |
} | |
printf("<---\n"); | |
} | |
puts("Done\n"); | |
getchar(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <cstdint> | |
#include <string> | |
#include <memory> | |
#include <Windows.h> | |
#include <winusb.h> | |
#include <SetupAPI.h> | |
struct UsbRequestType { | |
// Direction | |
static constexpr std::uint8_t HostToDevice = 0 << 7; | |
static constexpr std::uint8_t DeviceToHost = 1 << 7; | |
// Type | |
static constexpr std::uint8_t TypeVendor = 2 << 5; | |
static constexpr std::uint8_t TypeClass = 1 << 5; | |
// Recipient | |
static constexpr std::uint8_t RecipientInterface = 1 << 0; | |
static constexpr std::uint8_t RecipientDevice = 0 << 0; | |
}; | |
struct DeviceInfoHandleDeleter { | |
void operator()(void *ptr) { | |
SetupDiDestroyDeviceInfoList(ptr); | |
} | |
}; | |
using DeviceInfoHandle = std::unique_ptr<void, DeviceInfoHandleDeleter>; | |
struct WinUsbInterfaceHandleDeleter { | |
void operator()(void *ptr) { | |
WinUsb_Free(ptr); | |
} | |
}; | |
using WinUsbInterfaceHandle = std::unique_ptr<void, WinUsbInterfaceHandleDeleter>; | |
std::string FindDevicePathByGUID(const GUID *interfaceGuid); | |
WinUsbInterfaceHandle OpenUsbDevice(const std::string &devicePath); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment