Skip to content

Instantly share code, notes, and snippets.

@Novakov
Created January 30, 2023 18:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Novakov/894862d4e9d8316ef5bd976cc85c2ea1 to your computer and use it in GitHub Desktop.
Save Novakov/894862d4e9d8316ef5bd976cc85c2ea1 to your computer and use it in GitHub Desktop.
#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();
}
#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