code_twain/device/win_usb/win_usb.cpp

1470 lines
44 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "win_usb.h"
#include <initguid.h>
#include <usbiodef.h>
#include <usbioctl.h>
#include <SetupAPI.h>
#include <hidsdi.h>
#include <winusb.h>
#include <rpc.h>
//#include <winioctl.h>
#include <usbscan.h>
#include <Dbt.h>
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib")
#pragma comment(lib, "winusb.lib")
#pragma comment(lib, "rpcrt4.lib")
#pragma comment(lib, "advapi32.lib") // for Reg...
#if defined(OEM_NONE) || defined(OEM_LISCHENG) || defined(OEM_HANWANG)|| defined(OEM_ZHONGJING)
#include "../wrapper/hg_log.h"
#else
#define VLOG_MINI_1(l, f, d) printf(f, d)
#define VLOG_MINI_2(l, f, d1, d2) printf(f, d1, d2)
#define VLOG_MINI_3(l, f, d1, d2, d3) printf(f, d1, d2, d3)
#define VLOG_MINI_4(l, f, d1, d2, d3, d4) printf(f, d1, d2, d3, d4)
#endif
#include "usbview/enum.h"
#include "../../../sdk/include/huagao/brand.h"
#pragma warning(disable: 4996)
#define MSG_DEVICE_PNP WM_USER + 1 // wParam: (bool)arrive; lParam: usb_device*
#define bzero(a, l) memset(a, 0, l)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usb_callback ...
usb_callback::usb_callback(libusb_hotplug_callback_fn cb
, void* param)
: usb_cb_(cb), usb_cb_param_(param)
{}
usb_callback::~usb_callback()
{}
void usb_callback::notify(libusb_context* ctx, usb_device* dev, int ev)
{
usb_cb_(ctx, (libusb_device*)dev, (libusb_hotplug_event)ev, usb_cb_param_);
}
std::string u2utf8(const wchar_t* u)
{
#if defined(OEM_NONE) || defined(OEM_LISCHENG) || defined(OEM_HANWANG) || defined(OEM_ZHONGJING)
return hg_log::u2utf8(u);
#else
int len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), NULL, 0, NULL, NULL);
char *ansi = new char[len + 4];
len = WideCharToMultiByte(CP_UTF8, 0, u, lstrlenW(u), ansi, len, NULL, NULL);
ansi[len--] = 0;
std::string utf8(ansi);
delete[] ansi;
return utf8;
#endif
}
std::wstring ansi2unicode(const char* ansi, UINT cp = CP_ACP)
{
int len = MultiByteToWideChar(cp, 0, ansi, lstrlenA(ansi), NULL, 0);
wchar_t* buf = new wchar_t[len + 4];
memset(buf, 0, (len + 4) * 2);
len = MultiByteToWideChar(cp, 0, ansi, lstrlenA(ansi), buf, len);
buf[len--] = 0;
std::wstring unic(buf);
delete[] buf;
return unic;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OVERLAPPED ...
ovl_cls::ovl_cls() : ref_(1), io_bytes_(0)
{
memset(&ovl_, 0, sizeof(ovl_));
ovl_.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
}
ovl_cls::~ovl_cls()
{
CloseHandle(ovl_.hEvent);
}
LPOVERLAPPED ovl_cls::over_lapped(void)
{
return &ovl_;
}
LPDWORD ovl_cls::io_bytes(void)
{
return &io_bytes_;
}
void ovl_cls::reset(void)
{
HANDLE h = ovl_.hEvent;
memset(&ovl_, 0, sizeof(ovl_));
ovl_.hEvent = h;
io_bytes_ = 0;
ResetEvent(h);
}
bool ovl_cls::is_waited(void)
{
return WaitForSingleObject(ovl_.hEvent, 0) == WAIT_OBJECT_0;
}
ovl_mgr::ovl_mgr()
{}
ovl_mgr::~ovl_mgr()
{
for (auto& v : ovls_)
v->release();
}
ovl_cls* ovl_mgr::get_ovl(void)
{
std::lock_guard<std::mutex> lock(lock_);
ovl_cls* o = NULL;
for (auto& v : ovls_)
{
if (v->is_waited())
{
o = v;
o->add_ref();
o->reset();
break;
}
}
if (!o)
{
o = new ovl_cls();
ovls_.push_back(o);
o->add_ref();
}
return o;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usb_device ...
usb_device::usb_device(const USBDEV& dev) : ref_(1), udev_(dev), is_ok_(false)
, dev_desc_(NULL), handle_(NULL), online_(true), timout_ms_(1000)
{
memset(&guid_, 0, sizeof(guid_));
}
usb_device::~usb_device()
{
clear();
}
HANDLE usb_device::find_pipe(UCHAR addr, int type, int* index)
{
for (size_t i = 0; i < pipes_.size(); ++i)
{
if (pipes_[i].address == addr && pipes_[i].type == type)
{
if (index)
*index = i;
return pipes_[i].pipe;
}
}
return NULL;
}
HANDLE usb_device::open_usb(const char* usb_name, DWORD access, DWORD share)
{
std::wstring unic(ansi2unicode(usb_name));
SECURITY_ATTRIBUTES sa = { 0 };
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
return CreateFileW(unic.c_str(), access, share, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
}
int usb_device::set_timeout(HANDLE h)
{
USBSCAN_TIMEOUT uto = { 0 };
DWORD cbr = 0;
uto.TimeoutEvent = uto.TimeoutRead = uto.TimeoutWrite = (timout_ms_ + 500) / 1000;
return DeviceIoControl(h, IOCTL_SET_TIMEOUT, &uto, sizeof(uto), NULL, 0, &cbr, NULL) ? LIBUSB_SUCCESS : LIBUSB_ERROR_IO;
//COMMTIMEOUTS to = { 0 };
//to.ReadIntervalTimeout = timout_ms_;
//to.ReadTotalTimeoutConstant = timout_ms_;
//to.ReadTotalTimeoutMultiplier = 1;
//
//SetCommTimeouts(h, &to);
}
void usb_device::vid_pid_from_name(const char* name, int* vid, int* pid)
{
// name: \\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
std::string s(name ? name : "");
size_t pos = 0;
std::transform(s.begin(), s.end(), s.begin(), tolower);
pos = s.find("vid_");
if (pos != std::string::npos && vid)
*vid = usb_device::from_hex_string(s.c_str() + pos + 4);
pos = s.find("pid_");
if (pos != std::string::npos && pid)
*pid = usb_device::from_hex_string(s.c_str() + pos + 4);
}
DWORD usb_device::from_hex_string(const char* hex_str)
{
DWORD v = 0;
for (int i = 0; hex_str[i]; ++i)
{
DWORD now = 0;
if (hex_str[i] >= '0' && hex_str[i] <= '9')
now = hex_str[i] - '0';
else if (hex_str[i] >= 'a' && hex_str[i] <= 'f')
now = hex_str[i] - 'a' + 10;
else if (hex_str[i] >= 'A' && hex_str[i] <= 'F')
now = hex_str[i] - 'A' + 10;
else
break;
v <<= 4;
v += now;
}
return v;
}
std::string usb_device::name_without_guid(const char* name)
{
std::string no_guid(name);
size_t pos = no_guid.find("#{");
if (pos != std::string::npos)
no_guid.erase(pos);
return no_guid;
}
std::string usb_device::usb_scan_name(const char* reg_key)
{
std::wstring path(L"SYSTEM\\CurrentControlSet\\Control\\Class\\" + ansi2unicode(reg_key, CP_UTF8));
HKEY key = NULL;
int err = RegOpenKeyW(HKEY_LOCAL_MACHINE, path.c_str(), &key);
std::string ret("");
if (key)
{
char val[256] = { 0 };
DWORD len = _countof(val) - 1,
type = REG_SZ;
if (RegQueryValueExW(key, L"CreateFileName", NULL, &type, (LPBYTE)val, &len) == ERROR_SUCCESS)
{
val[len] = 0;
ret = u2utf8((wchar_t*)val);
}
RegCloseKey(key);
}
return ret;
}
long usb_device::add_ref(void)
{
return InterlockedIncrement(&ref_);
}
long usb_device::release(void)
{
long ref = InterlockedDecrement(&ref_);
if (ref == 0)
delete this;
return ref;
}
usb_device& usb_device::operator=(const GUID& guid)
{
guid_ = guid;
return *this;
}
std::string usb_device::name(void)
{
return udev_.name;
}
USBDEV& usb_device::dev(void)
{
return udev_;
}
GUID usb_device::guid(void)
{
return guid_;
}
bool usb_device::is_ok(void)
{
return is_ok_;
}
bool usb_device::is_open(void)
{
return handle_ != NULL;
}
bool usb_device::is_online(void)
{
return online_;
}
void usb_device::set_online(bool online)
{
online_ = online;
}
uint8_t usb_device::port(void)
{
if (!dev_desc_)
init();
return udev_.port;
}
uint8_t usb_device::address(void)
{
if (!dev_desc_)
init();
return udev_.addr;
}
std::string usb_device::reg_path(void)
{
return udev_.driver_key;
}
bool usb_device::init(void)
{
PUSBDEVICEINFO info = NULL;
GUID guid;
clear();
usb_monitor::enum_usb_device(&usb_monitor::find_parent_hub, &udev_, true);
VLOG_MINI_3(LOG_LEVEL_ALL, "Device '%s' at hub '%s + %d'\r\n", udev_.name.c_str(), udev_.hub.c_str(), udev_.port);
if (!udev_.hub.empty())
{
HANDLE h = CreateFileA(udev_.hub.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (h != INVALID_HANDLE_VALUE)
{
info = enumerate_hub_port(h, udev_.port);
CloseHandle(h);
}
}
#define COPY_MEMBER(d, s, m) \
(d)->m = (s)->m
if (info)
{
udev_.addr = info->ConnectionInfo->DeviceAddress;
if (info->ConnectionInfo)
{
dev_desc_ = new libusb_device_descriptor;
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bLength);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDescriptorType);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bcdUSB);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceClass);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceSubClass);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bDeviceProtocol);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bMaxPacketSize0);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, idVendor);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, idProduct);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bcdDevice);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iManufacturer);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iProduct);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, iSerialNumber);
COPY_MEMBER(dev_desc_, &info->ConnectionInfo->DeviceDescriptor, bNumConfigurations);
}
if (info->ConfigDesc)
{
libusb_config_descriptor* desc = NULL;
PUSB_COMMON_DESCRIPTOR cmn = (PUSB_COMMON_DESCRIPTOR)(info->ConfigDesc + 1);
int if_ind = 0, ep_ind = 0, used = 0;
while (used < info->ConfigDesc->SetupPacket.wLength && cmn->bLength)
{
if (USB_CONFIGURATION_DESCRIPTOR_TYPE == cmn->bDescriptorType)
{
PUSB_CONFIGURATION_DESCRIPTOR conf = (PUSB_CONFIGURATION_DESCRIPTOR)cmn;
if (desc)
cfg_desc_.push_back(desc);
desc = new libusb_config_descriptor;
memset(desc, 0, sizeof(*desc));
COPY_MEMBER(desc, conf, bLength);
COPY_MEMBER(desc, conf, bDescriptorType);
COPY_MEMBER(desc, conf, wTotalLength);
COPY_MEMBER(desc, conf, bNumInterfaces);
COPY_MEMBER(desc, conf, bConfigurationValue);
COPY_MEMBER(desc, conf, iConfiguration);
COPY_MEMBER(desc, conf, bmAttributes);
COPY_MEMBER(desc, conf, MaxPower);
desc->usb_if = new libusb_interface[desc->bNumInterfaces];
memset(desc->usb_if, 0, desc->bNumInterfaces * sizeof(desc->usb_if[0]));
ep_ind = if_ind = 0;
}
else if (USB_INTERFACE_DESCRIPTOR_TYPE == cmn->bDescriptorType)
{
PUSB_INTERFACE_DESCRIPTOR ifd = (PUSB_INTERFACE_DESCRIPTOR)cmn;
libusb_interface_descriptor* uid = NULL;
desc->usb_if[if_ind].num_altsetting = 1;
desc->usb_if[if_ind].altsetting = uid = new libusb_interface_descriptor;
memset(uid, 0, sizeof(libusb_interface_descriptor));
COPY_MEMBER(uid, ifd, bLength);
COPY_MEMBER(uid, ifd, bDescriptorType);
COPY_MEMBER(uid, ifd, bInterfaceNumber);
COPY_MEMBER(uid, ifd, bAlternateSetting);
COPY_MEMBER(uid, ifd, bNumEndpoints);
COPY_MEMBER(uid, ifd, bInterfaceClass);
COPY_MEMBER(uid, ifd, bInterfaceSubClass);
COPY_MEMBER(uid, ifd, bInterfaceProtocol);
COPY_MEMBER(uid, ifd, iInterface);
uid->endpoint = new libusb_endpoint_descriptor[desc->usb_if[if_ind].altsetting->bNumEndpoints];
if_ind++;
ep_ind = 0;
}
else if (USB_ENDPOINT_DESCRIPTOR_TYPE == cmn->bDescriptorType)
{
PUSB_ENDPOINT_DESCRIPTOR endp = (PUSB_ENDPOINT_DESCRIPTOR)cmn;
libusb_endpoint_descriptor* uep = (libusb_endpoint_descriptor*)((void*)&desc->usb_if[if_ind - 1].altsetting->endpoint[ep_ind]);
memset(uep, 0, sizeof(*uep));
COPY_MEMBER(uep, endp, bLength);
COPY_MEMBER(uep, endp, bDescriptorType);
COPY_MEMBER(uep, endp, bEndpointAddress);
COPY_MEMBER(uep, endp, bmAttributes);
COPY_MEMBER(uep, endp, wMaxPacketSize);
COPY_MEMBER(uep, endp, bInterval);
ep_ind++;
}
used += cmn->bLength;
cmn = (PUSB_COMMON_DESCRIPTOR)((PCHAR)cmn + cmn->bLength);
}
if (desc)
cfg_desc_.push_back(desc);
is_ok_ = !cfg_desc_.empty();
}
free_usb_device_info(info);
}
return is_ok_;
}
void usb_device::clear(void)
{
close();
if (dev_desc_)
delete dev_desc_;
dev_desc_ = NULL;
for (size_t i = 0; i < cfg_desc_.size(); ++i)
{
if (cfg_desc_[i]->usb_if)
{
for (size_t j = 0; j < cfg_desc_[i]->bNumInterfaces; ++j)
{
if (cfg_desc_[i]->usb_if[j].altsetting->endpoint)
delete[] cfg_desc_[i]->usb_if[j].altsetting->endpoint;
}
delete[] cfg_desc_[i]->usb_if;
}
delete cfg_desc_[i];
}
cfg_desc_.clear();
is_ok_ = false;
}
int usb_device::get_descriptor(libusb_device_descriptor* desc)
{
if (dev_desc_)
memcpy(desc, dev_desc_, sizeof(*desc));
else
{
char cls[128] = { 0 };
SetupDiGetClassDescriptionA(&guid_, cls, _countof(cls) - 1, NULL);
std::transform(cls, cls + lstrlenA(cls), cls, tolower);
if (strcmp(cls, "usb") == 0)
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_HUB;
else if (strcmp(cls, "image") == 0)
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_IMAGE;
else if (strcmp(cls, "hidclass") == 0)
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_HID;
else
desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_VENDOR_SPEC;
desc->idVendor = udev_.vid;
desc->idProduct = udev_.pid;
desc->bcdUSB = 0x200; // USB2.0 ?
desc->bcdDevice = 0; // ?
desc->bDescriptorType = libusb_descriptor_type::LIBUSB_DT_DEVICE;
desc->bDeviceProtocol = 0;
desc->bDeviceSubClass = libusb_class_code::LIBUSB_CLASS_IMAGE;
desc->bLength = sizeof(*desc);
desc->bMaxPacketSize0 = 512;
desc->bNumConfigurations = 1; // ?
desc->iManufacturer = 0;
desc->iSerialNumber = 0;
desc->iProduct = 0;
}
return LIBUSB_SUCCESS;
}
int usb_device::get_config_descriptor(int index, libusb_config_descriptor** desc)
{
if (index >= 0 && index < cfg_desc_.size())
*desc = cfg_desc_[index];
else
return LIBUSB_ERROR_INVALID_PARAM;
return LIBUSB_SUCCESS;
}
int usb_device::open(libusb_device_handle** dev_handle)
{
if (handle_)
return LIBUSB_ERROR_BUSY;
if (!dev_desc_)
init();
HANDLE h = open_usb(udev_.name.c_str());
if (h == INVALID_HANDLE_VALUE)
{
*dev_handle = NULL;
return online_ ? LIBUSB_ERROR_IO : LIBUSB_ERROR_NO_DEVICE;
}
USBSCAN_PIPE_CONFIGURATION upc = { 0 };
DWORD cbr = 0;
std::string fmt("\\%d"), root("");
if (udev_.driver_key.length())
root = usb_device::usb_scan_name(udev_.driver_key.c_str());
if (root.empty())
{
VLOG_MINI_1(LOG_LEVEL_WARNING, "Cannot find '\\\\.\\Usbscan' name for '%s', try run in Administrator!\r\n", udev_.name.c_str());
root = udev_.name;
fmt = "\\%04d";
}
else
{
VLOG_MINI_2(LOG_LEVEL_WARNING, "Nice: '%s' for '%s'.\r\n", root.c_str(), udev_.name.c_str());
}
if (DeviceIoControl(h, IOCTL_GET_PIPE_CONFIGURATION, NULL, 0, &upc, sizeof(upc), &cbr, NULL))
{
int type = PIPE_TYPE::WRITE_DATA_PIPE;
DeviceIoControl(h, IOCTL_RESET_PIPE, &type, sizeof(type), NULL, NULL, &cbr, NULL);
for (int i = 0; i < upc.NumberOfPipes; ++i)
{
USBPIPE up = { 0 };
char ind[80] = { 0 };
up.address = upc.PipeInfo[i].EndpointAddress;
up.type = upc.PipeInfo[i].PipeType;
sprintf_s(ind, _countof(ind) - 1, fmt.c_str(), i);
up.pipe = open_usb((root + ind).c_str());
if (up.pipe != INVALID_HANDLE_VALUE)
{
set_timeout(up.pipe);
up.index = i;
pipes_.push_back(up);
}
}
}
set_timeout(h);
handle_ = h == INVALID_HANDLE_VALUE ? NULL : (libusb_device_handle*)h;
*dev_handle = (libusb_device_handle*)this;
return LIBUSB_SUCCESS;
}
int usb_device::close(void)
{
for (size_t i = 0; i < pipes_.size(); ++i)
{
CancelIo(pipes_[i].pipe);
CloseHandle(pipes_[i].pipe);
}
pipes_.clear();
if (handle_)
{
OVERLAPPED ovl = { 0 };
PIPE_TYPE type = ALL_PIPE;
DWORD cbr = 0;
ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
DeviceIoControl(handle_, IOCTL_CANCEL_IO, &type, sizeof(type), NULL, 0, &cbr, &ovl);
WaitForSingleObject(ovl.hEvent, 1000);
CloseHandle(ovl.hEvent);
CancelIo(handle_);
CloseHandle((HANDLE)handle_);
handle_ = NULL;
}
return LIBUSB_SUCCESS;
}
int usb_device::set_timeout(unsigned milliseconds)
{
timout_ms_ = milliseconds;
for (size_t i = 0; i < pipes_.size(); ++i)
{
set_timeout(pipes_[i].pipe);
}
if (handle_)
set_timeout(handle_);
return LIBUSB_SUCCESS;
}
int usb_device::transfer_bulk(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout)
{
int ret = LIBUSB_ERROR_NOT_SUPPORTED, ind = 0;
HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_BULK, &ind);
if (h)
{
ovl_cls* oc = ovl_mgr_.get_ovl();
DWORD io = 0;
BOOL result = FALSE;
if (endpoint & BULKIN_FLAG)
result = ReadFile(h, data, *length, oc->io_bytes(), oc->over_lapped());
else
{
// oc->over_lapped()->Offset = oc->over_lapped()->OffsetHigh = -1;
result = WriteFile(h, data, *length, oc->io_bytes(), oc->over_lapped());
}
if (result)
{
FlushFileBuffers(h);
*length = *oc->io_bytes();
ret = LIBUSB_SUCCESS;
}
else
{
io = GetLastError();
if (io == ERROR_IO_PENDING)
{
if (WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_OBJECT_0)
{
GetOverlappedResult(h, oc->over_lapped(), oc->io_bytes(), FALSE);
*length = *oc->io_bytes();
if (*length == 0 && oc->over_lapped()->Internal != ERROR_SUCCESS)
{
ret = LIBUSB_ERROR_IO;
VLOG_MINI_2(LOG_LEVEL_WARNING, "Bulk-Transfer of endpoint 0x%02x failed with code 0x%08X\n", endpoint, oc->over_lapped()->Internal);
}
else
ret = LIBUSB_SUCCESS;
}
else
ret = LIBUSB_ERROR_TIMEOUT;
}
else
{
if (endpoint & BULKIN_FLAG)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Read-bulk = %d, set error as LIBUSB_ERROR_PIPE\r\n", io);
}
else
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "Write-bulk = %d, set error as LIBUSB_ERROR_PIPE\r\n", io);
}
ret = LIBUSB_ERROR_PIPE;
}
}
oc->release();
}
return ret;
}
int usb_device::transfer_control(uint8_t type, uint8_t req, uint16_t val, uint16_t ind, unsigned char* data, uint16_t len, unsigned timeout)
{
// return transfer bytes ...
int ret = 0; // LIBUSB_ERROR_NOT_FOUND;
_IO_BLOCK_EX irp;
if ((HANDLE)handle_ != INVALID_HANDLE_VALUE)
{
DWORD io = 0;
ovl_cls *oc = ovl_mgr_.get_ovl();
irp.bmRequestType = (type >> 5) & 0x03;
irp.bRequest = req;
irp.fTransferDirectionIn = type >> 7;
irp.pbyData = data;
irp.uIndex = ind;
irp.uLength = len;
irp.uOffset = val;
if (DeviceIoControl((HANDLE)handle_, IOCTL_SEND_USB_REQUEST, &irp, sizeof(irp), data, len, oc->io_bytes(), oc->over_lapped()))
{
if (irp.fTransferDirectionIn)
{
GetOverlappedResult((HANDLE)handle_, oc->over_lapped(), oc->io_bytes(), FALSE);
ret = *oc->io_bytes();
}
else
{
ret = len;
}
}
else if (GetLastError() == ERROR_IO_PENDING)
{
ret = WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_TIMEOUT ? 0 : *oc->io_bytes();
}
else
{
io = GetLastError();
if (io == ERROR_ACCESS_DENIED)
ret = LIBUSB_ERROR_ACCESS;
else if (io == ERROR_SEM_TIMEOUT)
ret = LIBUSB_ERROR_TIMEOUT;
else
ret = LIBUSB_ERROR_PIPE;
// ret = 0;
}
oc->release();
}
return ret;
}
int usb_device::transfer_interrupt(unsigned endpoint, unsigned char* data, int* length, unsigned int timeout)
{
int ret = LIBUSB_ERROR_NOT_SUPPORTED, len = *length;
HANDLE h = find_pipe(endpoint, USBSCAN_PIPE_INTERRUPT);
DWORD io = 0;
*length = 0;
if (h)
{
ovl_cls* oc = ovl_mgr_.get_ovl();
if (DeviceIoControl(h, IOCTL_WAIT_ON_DEVICE_EVENT, NULL, 0, data, len, oc->io_bytes(), oc->over_lapped()))
{
ret = LIBUSB_SUCCESS;
*length = *oc->io_bytes();
}
else
{
io = GetLastError();
if (io == ERROR_IO_PENDING)
{
if (WaitForSingleObject(oc->over_lapped()->hEvent, timeout) == WAIT_OBJECT_0)
{
GetOverlappedResult(h, oc->over_lapped(), oc->io_bytes(), FALSE);
*length = *oc->io_bytes();
ret = LIBUSB_SUCCESS;
}
else
{
ret = LIBUSB_ERROR_TIMEOUT;
// 此错误可能导致后续新产生的数据被填充进data故取消该操作 BUG-242
CancelIo(h);
}
}
else
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "DeviceIoControl(INT-EP) = %d, set error as LIBUSB_ERROR_PIPE\r\n", io);
ret = LIBUSB_ERROR_PIPE;
}
}
oc->release();
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usb_monitor ...
usb_monitor* usb_monitor::usb_monitor_ = NULL;
UINT usb_monitor::find_usb_timer_ = 101;
usb_monitor::usb_monitor() : wnd_monitor_(NULL), handle_msg_id_(0), run_(true)
{
handle_msg_.reset(new std::thread(&usb_monitor::thread_handle_device_change_msg, this));
}
usb_monitor::~usb_monitor()
{
quit();
}
int usb_monitor::enum_usb_device(bool(__stdcall* found_usb)(LPUSBDEV dev, void* param), void* param, bool hub)
{
GUID hid = hub ? GUID_DEVINTERFACE_USB_HUB : GUID_DEVINTERFACE_USB_DEVICE;
HDEVINFO dev_info = NULL;
int ind = 0;
SP_DEVICE_INTERFACE_DATA id = { 0 };
SP_DEVINFO_DATA sdd = { 0 };
dev_info = SetupDiGetClassDevsW(&hid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (!dev_info)
return GetLastError();
id.cbSize = sizeof(id);
while (SetupDiEnumDeviceInterfaces(dev_info, NULL, &hid, ind++, &id))
{
PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL;
DWORD size = 0;
SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, 0, &size, NULL);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[size + 4];
memset(buf, 0, (size + 4) * 2);
buf->cbSize = sizeof(*buf);
if (SetupDiGetDeviceInterfaceDetailW(dev_info, &id, buf, buf->cbSize + size, NULL, NULL))
{
USBDEV dev;
DWORD len = size;
dev.name = u2utf8(buf->DevicePath);
usb_device::vid_pid_from_name(dev.name.c_str(), &dev.vid, &dev.pid);
sdd.cbSize = sizeof(sdd);
SetupDiEnumDeviceInfo(dev_info, ind - 1, &sdd);
if (SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_DRIVER, NULL, (PBYTE)buf->DevicePath, len, &len)) // driver key
dev.driver_key = u2utf8(buf->DevicePath);
len = size;
if(SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_DEVICEDESC, NULL, (PBYTE)buf->DevicePath, len, &len)) // device description
dev.desc = u2utf8(buf->DevicePath);
len = size;
if (SetupDiGetDeviceRegistryPropertyW(dev_info, &sdd, SPDRP_ADDRESS, NULL, (PBYTE)buf->DevicePath, len, &len)) // device description
dev.port = *(int*)buf->DevicePath;
if (!found_usb(&dev, param))
{
delete[](char*)buf;
break;
}
}
delete[](char*)buf;
}
id.cbSize = sizeof(id);
}
SetupDiDestroyDeviceInfoList(dev_info);
return ERROR_SUCCESS;
}
bool __stdcall usb_monitor::find_all_usb_devices(LPUSBDEV dev, void* param/*std::vector<USBDEV>* */)
{
std::vector<USBDEV>* devs = (std::vector<USBDEV>*)param;
devs->push_back(*dev);
return true;
}
bool __stdcall usb_monitor::usb_dev_by_name(LPUSBDEV dev, void* param/*LPUSBDEV*/)
{
LPUSBDEV devt = (LPUSBDEV)param;
if (stricmp(usb_device::name_without_guid(devt->name.c_str()).c_str(), usb_device::name_without_guid(dev->name.c_str()).c_str()) == 0)
{
devt->driver_key = dev->driver_key;
devt->desc = dev->desc;
devt->vid = dev->vid;
devt->pid = dev->pid;
devt->port = dev->port;
return false;
}
return true;
}
bool __stdcall usb_monitor::find_parent_hub(LPUSBDEV hub, void* param/*LPUSBDEV*/)
{
LPUSBDEV t = (LPUSBDEV)param;
if (t->driver_key.empty() || t->port == 0)
return false;
HANDLE h = CreateFileA(hub->name.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
bool go = true;
char buf[512] = { 0 };
DWORD bytes = 0;
if (h == INVALID_HANDLE_VALUE)
return true;
USB_NODE_CONNECTION_DRIVERKEY_NAME* name = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)buf;
name->ConnectionIndex = t->port;
name->ActualLength = (sizeof(buf) - sizeof(*name)) / 2 - 1;
if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, name, sizeof(*name), name, name->ActualLength, &bytes, NULL))
{
if (u2utf8(name->DriverKeyName) == t->driver_key)
{
t->hub = hub->name;
go = false;
}
}
CloseHandle(h);
return go;
}
bool usb_monitor::is_desired_usb_device(int vid, int pid)
{
return true; // vid == PRODUCT_VID || vid == PRODUCT_VENDOR_HG1;
}
LRESULT CALLBACK usb_monitor::monitor_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
usb_monitor* monitor = (usb_monitor*)GetPropW(hwnd, MONITOR_WINDOW_OWNER);
if (msg == WM_CREATE)
{
LPCREATESTRUCTW data = (LPCREATESTRUCTW)lp;
SetPropW(hwnd, MONITOR_WINDOW_OWNER, (HANDLE)data->lpCreateParams);
return 0;
}
else if (monitor && msg == WM_TIMER && wp == usb_monitor::find_usb_timer_)
{
monitor->find_usb_and_trigger_event();
return 0;
}
else if (!monitor || msg != WM_DEVICECHANGE)
return DefWindowProcW(hwnd, msg, wp, lp);
return monitor->on_usb_pnp(wp, lp);
}
void usb_monitor::register_monitor_wnd(const wchar_t* cls)
{
WNDCLASSW wc = { 0 };
wc.lpfnWndProc = &usb_monitor::monitor_wnd_proc;
wc.lpszClassName = cls;
wc.hInstance = GetModuleHandleW(NULL);
RegisterClassW(&wc);
}
void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive)
{
std::lock_guard<std::mutex> lock(lock_);
int ev = arrive ? LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT;
std::string noguid(usb_device::name_without_guid(dev->name().c_str()));
if (arrive)
{
bool found = false;
for(size_t i = 0; i < devices_.size(); ++i)
{
// if (devices_[i]->name() == dev->name())
if (stricmp(usb_device::name_without_guid(devices_[i]->name().c_str()).c_str(), noguid.c_str()) == 0)
{
if (devices_[i]->is_online())
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already in device queue and received ARRIVE again, discard this event.\n", dev->name().c_str());
// dev->release();
return;
}
else
{
devices_[i]->clear();
devices_[i]->dev() = dev->dev(); // use NEW connection info ...
dev->release();
dev = devices_[i];
dev->add_ref();
dev->set_online(true);
found = true;
break;
}
}
}
if (!found)
{
devices_.push_back(dev);
dev->add_ref();
}
}
else
{
bool discard = false;
for (size_t i = 0; i < devices_.size(); ++i)
{
// if (devices_[i]->name() == dev->name())
if (stricmp(usb_device::name_without_guid(devices_[i]->name().c_str()).c_str(), noguid.c_str()) == 0)
{
dev->release();
dev = devices_[i];
dev->add_ref();
if (dev->is_online())
{
dev->set_online(false);
discard = false;
}
else
{
discard = true;
}
break;
}
}
if (discard)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already offline and received LEAVE again, discard this event.\n", dev->name().c_str());
return;
}
}
for (size_t i = 0; i < cbs_.size(); ++i)
cbs_[i]->notify((libusb_context*)this, dev, ev);
}
int usb_monitor::on_usb_pnp(WPARAM wp, LPARAM lp)
{
int ret = 0;
DEV_BROADCAST_HDR* dbt = (DEV_BROADCAST_HDR*)lp;
if (!dbt || dbt->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
return wp == DBT_DEVICEQUERYREMOVE;
PDEV_BROADCAST_DEVICEINTERFACE_W dev = (PDEV_BROADCAST_DEVICEINTERFACE_W)lp;
if (dev->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
{
return wp == DBT_DEVICEQUERYREMOVE;
}
std::string utf8(u2utf8(dev->dbcc_name));
if (wp == DBT_DEVICEQUERYREMOVE)
return cur_dev_name_ != utf8;
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "event '%08x' of device %s\n", wp, utf8.c_str());
int vid = 0,
pid = 0;
usb_device::vid_pid_from_name(utf8.c_str(), &vid, &pid);
if (!usb_monitor::is_desired_usb_device(vid, pid))
return 0;
USBDEV udev;
udev.name = utf8;
usb_monitor::enum_usb_device(&usb_monitor::usb_dev_by_name, &udev);
if (wp == DBT_DEVICEARRIVAL && udev.driver_key.empty())
{
VLOG_MINI_1(LOG_LEVEL_FATAL, "Failed: driver key for '%s' is not found!\r\n", utf8.c_str());
}
usb_device* ud = new usb_device(udev);
*ud = dev->dbcc_classguid;
if (!PostThreadMessageW(handle_msg_id_, MSG_DEVICE_PNP, wp == DBT_DEVICEARRIVAL, (LPARAM)ud))
ud->release();
return ret;
}
void usb_monitor::find_usb_and_trigger_event(void)
{
std::vector<USBDEV> old(found_usb_devs_);
found_usb_devs_.clear();
usb_monitor::enum_usb_device(&usb_monitor::find_all_usb_devices, &found_usb_devs_);
for (size_t i = 0; i < found_usb_devs_.size(); ++i)
{
if (!usb_monitor::is_desired_usb_device(found_usb_devs_[i].vid, found_usb_devs_[i].pid))
{
found_usb_devs_.erase(found_usb_devs_.begin() + i);
i--;
}
}
for (size_t i = 0; i < found_usb_devs_.size(); ++i)
{
std::vector<USBDEV>::iterator it = std::find(old.begin(), old.end(), found_usb_devs_[i]);
if (it == old.end())
{
usb_device* dev = new usb_device(found_usb_devs_[i]);
notify_usb_event(dev, true);
dev->release();
}
else
old.erase(it);
}
for (size_t i = 0; i < old.size(); ++i)
{
usb_device* dev = new usb_device(old[i]);
notify_usb_event(dev, false);
dev->release();
}
}
usb_callback* usb_monitor::reg_callback(libusb_hotplug_callback_fn cb, void* param)
{
usb_callback* obj = new usb_callback(cb, param);
{
std::lock_guard<std::mutex> lock(lock_);
cbs_.push_back(obj);
}
return obj;
}
void usb_monitor::unreg_callback(usb_callback* cb)
{
std::lock_guard<std::mutex> lock(lock_);
for (int i = 0; i < cbs_.size(); ++i)
{
if (cbs_[i] == cb)
{
cbs_.erase(cbs_.begin() + i);
delete cb;
break;
}
}
}
void usb_monitor::thread_run_device_event_wnd(void)
{
MSG msg = { 0 };
const wchar_t* cls = L"usb_pnp_wnd";
register_monitor_wnd(cls);
wnd_monitor_ = CreateWindowW(cls, L"usb", WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), this);
if (!IsWindow(wnd_monitor_))
{
if(run_)
Sleep(1000);
return;
}
if (run_)
{
BOOL ret = TRUE;
DEV_BROADCAST_HDR dbh = { 0 };
HDEVNOTIFY notify = NULL;
// mannual triggered at beginning ...
find_usb_and_trigger_event();
dbh.dbch_size = sizeof(dbh);
dbh.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notify = RegisterDeviceNotificationW(wnd_monitor_, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if (!notify && GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR)
{
DEV_BROADCAST_DEVICEINTERFACE_A di = { 0 };
di.dbcc_size = (sizeof(di) + 3) / 4 * 4;
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
UuidFromStringA((RPC_CSTR)IMAGE_CLASS_GUID, &di.dbcc_classguid);
notify = RegisterDeviceNotificationA(wnd_monitor_, &di, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "RegisterDeviceNotificationA = 0x%08x, error = %d. di.dbcc_size = %d\n", notify, GetLastError(), di.dbcc_size);
if (!notify)
SetTimer(wnd_monitor_, usb_monitor::find_usb_timer_, 1000, NULL);
}
ret = GetLastError();
while (run_ && (ret = GetMessageW(&msg, wnd_monitor_, 0, 0)))
{
if (ret == -1)
break;
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
UnregisterDeviceNotification(notify);
}
DestroyWindow(wnd_monitor_);
UnregisterClassW(cls, GetModuleHandleW(NULL));
}
void usb_monitor::thread_handle_device_change_msg(void)
{
MSG msg = { 0 };
BOOL ret = FALSE;
handle_msg_id_ = GetCurrentThreadId();
while ((ret = GetMessageW(&msg, NULL, 0, 0)))
{
if (ret == -1)
break;
if (msg.message == MSG_DEVICE_PNP)
{
char buf[40] = { 0 };
usb_device* dev = (usb_device*)msg.lParam;
//if(msg.wParam)
// dev->init();
notify_usb_event(dev, msg.wParam);
// dev->release ?
dev->release();
}
else
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
}
void usb_monitor::quit(void)
{
KillTimer(wnd_monitor_, usb_monitor::find_usb_timer_);
run_ = false;
if (handle_msg_.get())
{
PostThreadMessageW(handle_msg_id_, WM_QUIT, 0, 0);
if (handle_msg_->joinable())
handle_msg_->join();
handle_msg_.reset();
}
if (IsWindow(wnd_monitor_))
{
PostMessage(wnd_monitor_, WM_QUIT, 0, 0);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// libusb APIs ...
int LIBUSB_CALL libusb_init(libusb_context** ctx)
{
if (ctx)
*ctx = (libusb_context*)new usb_monitor();
else if(!usb_monitor::usb_monitor_)
usb_monitor::usb_monitor_ = new usb_monitor();
return LIBUSB_SUCCESS;
}
void LIBUSB_CALL libusb_exit(libusb_context* ctx)
{
usb_monitor* usb = (usb_monitor*)ctx;
if (usb)
{
usb->quit();
delete usb;
}
}
int LIBUSB_CALL libusb_hotplug_register_callback(libusb_context* ctx,
libusb_hotplug_event events,
libusb_hotplug_flag flags,
int vendor_id, int product_id,
int dev_class,
libusb_hotplug_callback_fn cb_fn,
void* user_data,
libusb_hotplug_callback_handle* callback_handle)
{
if (ctx)
*callback_handle = (libusb_hotplug_callback_handle)((usb_monitor*)ctx)->reg_callback(cb_fn, user_data);
else if (usb_monitor::usb_monitor_)
*callback_handle = (libusb_hotplug_callback_handle)usb_monitor::usb_monitor_->reg_callback(cb_fn, user_data);
return LIBUSB_SUCCESS;
}
void LIBUSB_CALL libusb_hotplug_deregister_callback(libusb_context* ctx, libusb_hotplug_callback_handle callback_handle)
{
if (ctx)
((usb_monitor*)ctx)->unreg_callback((usb_callback*)callback_handle);
else if (usb_monitor::usb_monitor_)
usb_monitor::usb_monitor_->unreg_callback((usb_callback*)callback_handle);
}
int LIBUSB_CALL libusb_handle_events_timeout(libusb_context* ctx, struct timeval* tv)
{
// NOTE: for the caller is in a separate thread, this call will blocked while process exited, or libusb_exit called
((usb_monitor*)ctx)->thread_run_device_event_wnd();
return LIBUSB_SUCCESS;
}
libusb_device* LIBUSB_CALL libusb_ref_device(libusb_device* dev)
{
if (dev)
((usb_device*)dev)->add_ref();
return dev;
}
void LIBUSB_CALL libusb_unref_device(libusb_device* dev)
{
if (dev)
((usb_device*)dev)->release();
}
int LIBUSB_CALL libusb_get_device_descriptor(libusb_device* dev, struct libusb_device_descriptor* desc)
{
if (!dev)
return LIBUSB_ERROR_INVALID_PARAM;
return ((usb_device*)dev)->get_descriptor(desc);
}
int LIBUSB_CALL libusb_get_config_descriptor(libusb_device* dev, uint8_t config_index, struct libusb_config_descriptor** config)
{
if (!dev)
return LIBUSB_ERROR_INVALID_PARAM;
return ((usb_device*)dev)->get_config_descriptor(config_index, config);
}
void LIBUSB_CALL libusb_free_config_descriptor(struct libusb_config_descriptor* config)
{
// because the configuration descriptor is member of device, nothing to do here ...
}
int LIBUSB_CALL libusb_reset_device(libusb_device_handle* dev_handle)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context* ctx, libusb_device*** list)
{
// to be implemented later ...
return 0;
}
void LIBUSB_CALL libusb_free_device_list(libusb_device** list, int unref_devices)
{
// to be implemented later ...
}
int LIBUSB_CALL libusb_set_auto_detach_kernel_driver(libusb_device_handle* dev_handle, int enable)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_claim_interface(libusb_device_handle* dev_handle, int interface_number)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_release_interface(libusb_device_handle* dev_handle, int interface_number)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_set_configuration(libusb_device_handle* dev_handle, int configuration)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_kernel_driver_active(libusb_device_handle* dev_handle, int interface_number)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_detach_kernel_driver(libusb_device_handle* dev_handle, int interface_number)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
int LIBUSB_CALL libusb_attach_kernel_driver(libusb_device_handle* dev_handle, int interface_number)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
libusb_device_handle* LIBUSB_CALL libusb_open_device_with_vid_pid(libusb_context* ctx, uint16_t vendor_id, uint16_t product_id)
{
// to be implemented later ...
return NULL;
}
int LIBUSB_CALL libusb_clear_halt(libusb_device_handle* dev_handle, unsigned char endpoint)
{
// to be implemented later ...
return LIBUSB_SUCCESS;
}
const char* LIBUSB_CALL libusb_error_name(int errcode)
{
#define RETURN_IF(e) \
if(errcode == e) \
return #e;
RETURN_IF(LIBUSB_SUCCESS);
RETURN_IF(LIBUSB_ERROR_IO);
RETURN_IF(LIBUSB_ERROR_INVALID_PARAM);
RETURN_IF(LIBUSB_ERROR_ACCESS);
RETURN_IF(LIBUSB_ERROR_NO_DEVICE);
RETURN_IF(LIBUSB_ERROR_NOT_FOUND);
RETURN_IF(LIBUSB_ERROR_BUSY);
RETURN_IF(LIBUSB_ERROR_TIMEOUT);
RETURN_IF(LIBUSB_ERROR_OVERFLOW);
RETURN_IF(LIBUSB_ERROR_PIPE);
RETURN_IF(LIBUSB_ERROR_INTERRUPTED);
RETURN_IF(LIBUSB_ERROR_NO_MEM);
RETURN_IF(LIBUSB_ERROR_NOT_SUPPORTED);
RETURN_IF(LIBUSB_ERROR_OTHER);
return "Unknown error";
}
int LIBUSB_CALL libusb_open(libusb_device* dev, libusb_device_handle** dev_handle)
{
if (!dev)
return LIBUSB_ERROR_INVALID_PARAM;
return ((usb_device*)dev)->open(dev_handle);
}
void LIBUSB_CALL libusb_close(libusb_device_handle* dev_handle)
{
if (dev_handle)
{
((usb_device*)dev_handle)->close();
}
}
int LIBUSB_CALL libusb_control_transfer(libusb_device_handle* dev_handle,
uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char* data, uint16_t wLength, unsigned int timeout)
{
if (!dev_handle)
return LIBUSB_ERROR_INVALID_PARAM;
return ((usb_device*)dev_handle)->transfer_control(request_type, bRequest, wValue, wIndex, data, wLength, timeout);
}
int LIBUSB_CALL libusb_bulk_transfer(libusb_device_handle* dev_handle,
unsigned char endpoint, unsigned char* data, int length,
int* actual_length, unsigned int timeout)
{
if (!dev_handle)
return LIBUSB_ERROR_INVALID_PARAM;
if (actual_length)
*actual_length = length;
else
actual_length = &length;
return ((usb_device*)dev_handle)->transfer_bulk(endpoint, data, actual_length, timeout);
}
int LIBUSB_CALL libusb_interrupt_transfer(libusb_device_handle* dev_handle,
unsigned char endpoint, unsigned char* data, int length,
int* actual_length, unsigned int timeout)
{
if (!dev_handle)
return LIBUSB_ERROR_INVALID_PARAM;
if (actual_length)
*actual_length = length;
else
actual_length = &length;
return ((usb_device*)dev_handle)->transfer_interrupt(endpoint, data, actual_length, timeout);
}
int LIBUSB_CALL libusb_set_timeout(libusb_device_handle* h, unsigned int milliseconds)
{
if (!h)
return LIBUSB_ERROR_INVALID_PARAM;
return ((usb_device*)h)->set_timeout(milliseconds);
}
void LIBUSB_CALL libusb_quit(libusb_context* ctx)
{
if (ctx)
((usb_monitor*)ctx)->quit();
}
uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device* device)
{
if(!device)
return 0;
return ((usb_device*)device)->address();
}