1470 lines
45 KiB
C++
1470 lines
45 KiB
C++
#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();
|
||
}
|
||
|