diff --git a/device/win_usb/win_usb.cpp b/device/win_usb/win_usb.cpp index bfc80fc..7bf95ab 100644 --- a/device/win_usb/win_usb.cpp +++ b/device/win_usb/win_usb.cpp @@ -146,15 +146,10 @@ ovl_cls* ovl_mgr::get_ovl(void) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // usb_device ... -usb_device::usb_device(const char* name) : ref_(1), name_(name ? name : ""), is_ok_(false) - , dev_desc_(NULL), handle_(NULL), online_(true), timout_ms_(1000), reg_key_("") +usb_device::usb_device(const USBDEV& dev) : ref_(1), udev_(dev), is_ok_(false) + , dev_desc_(NULL), handle_(NULL), online_(true), timout_ms_(1000) { - bzero(&guid_, sizeof(guid_)); - id_ = usb_device::vid_pid_from_name(name); - - GUID guid; - UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid); - id_.addr = usb_device::get_device_address(name_.c_str(), &guid); + memset(&guid_, 0, sizeof(guid_)); } usb_device::~usb_device() { @@ -202,23 +197,20 @@ int usb_device::set_timeout(HANDLE h) //SetCommTimeouts(h, &to); } -DEVID usb_device::vid_pid_from_name(const char* name) +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} - DEVID id; 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) - id.vid = usb_device::from_hex_string(s.c_str() + pos + 4); + 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) - id.pid = usb_device::from_hex_string(s.c_str() + pos + 4); - - return id; + 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) { @@ -242,222 +234,15 @@ DWORD usb_device::from_hex_string(const char* hex_str) return v; } -std::string usb_device::driver_key_name(HANDLE file) +std::string usb_device::name_without_guid(const char* name) { - ULONG nBytes = 0; - USB_HCD_DRIVERKEY_NAME driverKeyName = { 0 }; - BOOL success = DeviceIoControl(file, IOCTL_GET_HCD_DRIVERKEY_NAME, &driverKeyName, sizeof(driverKeyName), &driverKeyName, sizeof(driverKeyName), &nBytes, NULL); - std::string ret(""); + std::string no_guid(name); + size_t pos = no_guid.find("#{"); - if (success && driverKeyName.ActualLength > nBytes) - { - PUSB_HCD_DRIVERKEY_NAME buf = (PUSB_HCD_DRIVERKEY_NAME)GlobalAlloc(GPTR, driverKeyName.ActualLength); - nBytes = driverKeyName.ActualLength; - success = DeviceIoControl(file, IOCTL_GET_HCD_DRIVERKEY_NAME, &buf, nBytes, &buf, nBytes, &nBytes, NULL); - if (success) - { - ret = u2utf8(buf->DriverKeyName); - } - GlobalFree(buf); - } + if (pos != std::string::npos) + no_guid.erase(pos); - return ret; -} -std::string usb_device::parent_hub_path_name(int vid, int pid, int *addr, std::string* reg_key) -{ - std::string ret(""); - GUID guid = GUID_DEVINTERFACE_USB_HUB; - HDEVINFO dev = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - int port = addr ? *addr : -1; - - if (dev) - { - SP_DEVICE_INTERFACE_DATA id = { 0 }; - SP_DEVINFO_DATA did; - int ind = 0; - - id.cbSize = sizeof(id); - while (SetupDiEnumDeviceInterfaces(dev, NULL, &guid, ind++, &id)) - { - PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL; - DWORD size = 0; - - if (!SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, 0, &size, NULL) && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - int bytes = size + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + 40; - buf = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)new wchar_t[bytes]; - memset(buf, 0, bytes * 2); - buf->cbSize = sizeof(*buf); - if (SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, buf->cbSize + size, NULL, NULL)) - { - std::string n(u2utf8(buf->DevicePath)); - if (find_vid_pid_in_hub(n.c_str(), vid, pid, &port, reg_key)) - ret = n; - } - delete[] buf; - if (ret.length()) - break; - } - } - SetupDiDestroyDeviceInfoList(dev); - } - if (addr) - *addr = port; - VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "Parent hub for %04X:%04X is: %s (+%d)\r\n", vid, pid, ret.c_str(), port); - - return ret; -} -bool usb_device::find_vid_pid_in_hub(const char* utf8_hub_path_name, int vid, int pid, int* addr, std::string* reg_key) -{ - bool ret = false; - HANDLE h = CreateFileA(utf8_hub_path_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - - if (h == INVALID_HANDLE_VALUE) - return ret; - - int bytes = sizeof(USB_NODE_CONNECTION_INFORMATION_EX) + (sizeof(USB_PIPE_INFO) * 30); - PUSB_NODE_CONNECTION_INFORMATION_EX connectionInfoEx = (PUSB_NODE_CONNECTION_INFORMATION_EX)new char[bytes]; - memset(connectionInfoEx, 0, bytes); - if (addr && *addr != -1) - { - connectionInfoEx->ConnectionIndex = *addr; - DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connectionInfoEx, - bytes, connectionInfoEx, bytes, (LPDWORD)&bytes, NULL); - ret = connectionInfoEx->DeviceDescriptor.idVendor == vid && connectionInfoEx->DeviceDescriptor.idProduct == pid; - if (ret && reg_key) - { - char buf[512] = { 0 }; - USB_NODE_CONNECTION_DRIVERKEY_NAME* name = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)buf; - name->ConnectionIndex = *addr; - name->ActualLength = (sizeof(buf) - sizeof(*name)) / 2 - 1; - DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, name, sizeof(*name), name, name->ActualLength, (LPDWORD)&bytes, NULL); - *reg_key = u2utf8(name->DriverKeyName); - } - } - else - { - for (int i = 1; !ret; ++i) - { - DWORD len = bytes; - connectionInfoEx->ConnectionIndex = i; - if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, connectionInfoEx, - bytes, connectionInfoEx, bytes, (LPDWORD)&bytes, NULL)) - break; - ret = connectionInfoEx->DeviceDescriptor.idVendor == vid && connectionInfoEx->DeviceDescriptor.idProduct == pid; - } - if (ret && addr) - *addr = connectionInfoEx->ConnectionIndex; - } - delete[] connectionInfoEx; - CloseHandle(h); - - return ret; -} -int usb_device::get_device_address(const char* device_name, LPGUID lpguid) -{ - int addr = -1; - GUID guid = lpguid ? *lpguid : GUID_DEVINTERFACE_USB_DEVICE; - HDEVINFO dev = NULL; - std::string ret(""), src(device_name); - - dev = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (dev) - { - SP_DEVICE_INTERFACE_DATA id = { 0 }; - SP_DEVINFO_DATA did; - int ind = 0; - size_t pos = src.find("{"); - - if (pos != std::string::npos) - src.erase(pos); - id.cbSize = sizeof(id); - while (SetupDiEnumDeviceInterfaces(dev, NULL, &guid, ind++, &id)) - { - PSP_DEVICE_INTERFACE_DETAIL_DATA_W buf = NULL; - DWORD size = 0; - - ret = ""; - if (!SetupDiGetDeviceInterfaceDetailW(dev, &id, buf, 0, &size, NULL) && - 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, &id, buf, buf->cbSize + size, NULL, NULL)) - { - wchar_t* l = wcsstr(buf->DevicePath, L"{"); - if (l) - *l = 0; - ret = u2utf8(buf->DevicePath); - } - delete buf; - } - - if (stricmp(ret.c_str(), src.c_str())) - continue; - - SP_DEVINFO_DATA dd = { 0 }; - dd.cbSize = sizeof(dd); - // for (int i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dd); ++i) - if (SetupDiEnumDeviceInfo(dev, ind - 1, &dd)) - { - SetupDiGetDeviceRegistryPropertyA(dev, &dd, SPDRP_ADDRESS, NULL, (PBYTE)&addr, sizeof(addr), NULL); - } - break; - } - SetupDiDestroyDeviceInfoList(dev); - } - - return addr; -} -std::string usb_device::usb_scan_name(DEVID id, const char* guid) -{ - // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{6BDD1FC6-810F-11D0-BEC7-08002BE2092F} - HKEY key = NULL, root = NULL; - std::string path("SYSTEM\\CurrentControlSet\\Control\\Class\\{"), name(""); - char val[256] = { 0 }; - int ind = 0, err = 0; - - path += guid; - path += "}"; - err = RegOpenKeyA(HKEY_LOCAL_MACHINE, path.c_str(), &root); - if (root) - { - DWORD index = 0; - - while (RegEnumKeyA(root, index++, val, _countof(val) - 1) == ERROR_SUCCESS) - { - RegOpenKeyA(root, val, &key); - if (key) - { - DWORD len = _countof(val) - 1, - type = REG_SZ; - if (RegQueryValueExA(key, "MatchingDeviceId", NULL, &type, (LPBYTE)val, &len) == ERROR_SUCCESS) - { - val[len] = 0; - DEVID cid = usb_device::vid_pid_from_name(val); - if (cid.vid == id.vid && cid.pid == id.pid) - { - len = _countof(val) - 1; - type = REG_SZ; - if (RegQueryValueExA(key, "CreateFileName", NULL, &type, (LPBYTE)val, &len) == ERROR_SUCCESS) - { - val[len] = 0; - name = val; - } - } - } - RegCloseKey(key); - if (!name.empty()) - break; - } - memset(val, 0, sizeof(val)); - } - RegCloseKey(root); - } - - return name; + return no_guid; } std::string usb_device::usb_scan_name(const char* reg_key) { @@ -496,21 +281,6 @@ long usb_device::release(void) return ref; } -bool usb_device::operator==(const char* name) -{ - return name_ == name; -} -bool usb_device::operator==(const DEVID& id) -{ - return id_.vid == id.vid && id_.pid == id.pid; -} - -usb_device& usb_device::operator=(const DEVID& id) -{ - id_ = id; - - return *this; -} usb_device& usb_device::operator=(const GUID& guid) { guid_ = guid; @@ -520,16 +290,16 @@ usb_device& usb_device::operator=(const GUID& guid) std::string usb_device::name(void) { - return name_; + return udev_.name; +} +USBDEV& usb_device::dev(void) +{ + return udev_; } GUID usb_device::guid(void) { return guid_; } -DEVID usb_device::id(void) -{ - return id_; -} bool usb_device::is_ok(void) { return is_ok_; @@ -545,40 +315,41 @@ bool usb_device::is_online(void) void usb_device::set_online(bool online) { online_ = online; - if (!online_) - reg_key_ = ""; } uint8_t usb_device::port(void) { if (!dev_desc_) init(); - return port_; + + return udev_.port; +} +uint8_t usb_device::address(void) +{ + if (!dev_desc_) + init(); + + return udev_.addr; } std::string usb_device::reg_path(void) { - return reg_key_; + return udev_.driver_key; } bool usb_device::init(void) { PUSBDEVICEINFO info = NULL; GUID guid; - int addr = -1; clear(); - UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &guid); - addr = usb_device::get_device_address(name_.c_str(), &guid); - //if (addr != -1) + 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()) { - std::string path(usb_device::parent_hub_path_name(id_.vid, id_.pid, &addr, ®_key_)); - if (!path.empty()) + HANDLE h = CreateFileA(udev_.hub.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (h != INVALID_HANDLE_VALUE) { - HANDLE h = CreateFileA(path.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (h != INVALID_HANDLE_VALUE) - { - info = enumerate_hub_port(h, addr); - CloseHandle(h); - } + info = enumerate_hub_port(h, udev_.port); + CloseHandle(h); } } @@ -587,7 +358,7 @@ bool usb_device::init(void) if (info) { - port_ = addr; + udev_.addr = info->ConnectionInfo->DeviceAddress; if (info->ConnectionInfo) { dev_desc_ = new libusb_device_descriptor; @@ -681,7 +452,6 @@ bool usb_device::init(void) free_usb_device_info(info); } - id_.addr = port_; return is_ok_; } @@ -709,10 +479,6 @@ void usb_device::clear(void) cfg_desc_.clear(); is_ok_ = false; } -void usb_device::online_statu_changed(bool online) -{ - online_ = online; -} int usb_device::get_descriptor(libusb_device_descriptor* desc) { if (dev_desc_) @@ -731,8 +497,8 @@ int usb_device::get_descriptor(libusb_device_descriptor* desc) desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_HID; else desc->bDeviceClass = libusb_class_code::LIBUSB_CLASS_VENDOR_SPEC; - desc->idVendor = id_.vid; - desc->idProduct = id_.pid; + desc->idVendor = udev_.vid; + desc->idProduct = udev_.pid; desc->bcdUSB = 0x200; // USB2.0 ? desc->bcdDevice = 0; // ? desc->bDescriptorType = libusb_descriptor_type::LIBUSB_DT_DEVICE; @@ -765,7 +531,7 @@ int usb_device::open(libusb_device_handle** dev_handle) if (!dev_desc_) init(); - HANDLE h = open_usb(name_.c_str()); + HANDLE h = open_usb(udev_.name.c_str()); if (h == INVALID_HANDLE_VALUE) { *dev_handle = NULL; @@ -775,22 +541,19 @@ int usb_device::open(libusb_device_handle** dev_handle) USBSCAN_PIPE_CONFIGURATION upc = { 0 }; DWORD cbr = 0; - std::string fmt("\\%d"), root(""); // (usb_device::usb_scan_name(reg_key_.empty() ? id_ : reg_key_.c_str())); - - if (reg_key_.length()) - root = usb_device::usb_scan_name(reg_key_.c_str()); - if (root.empty()) - root = usb_device::usb_scan_name(id_); + 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", name_.c_str()); - root = name_; + 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(), name_.c_str()); + 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)) { @@ -1018,6 +781,121 @@ 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* */) +{ + std::vector* devs = (std::vector*)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 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); @@ -1056,20 +934,15 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive) { std::lock_guard lock(lock_); int ev = arrive ? LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED : LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; - DEVID id = dev->id(); - - if (id.vid != PRODUCT_VID && id.vid != PRODUCT_VENDOR_HG1) - return; - - VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "WINUSB %04X:%04X(%d) %s\r\n", dev->id().vid, dev->id().pid, dev->id().addr, - arrive ? "Connected" : "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]->id() == id) + // 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()) { @@ -1079,6 +952,8 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive) } else { + devices_[i]->clear(); + devices_[i]->dev() = dev->dev(); // use NEW connection info ... dev->release(); dev = devices_[i]; dev->add_ref(); @@ -1097,36 +972,25 @@ void usb_monitor::notify_usb_event(usb_device*& dev, bool arrive) else { bool discard = false; + for (size_t i = 0; i < devices_.size(); ++i) { - if (devices_[i]->id().vid != id.vid || devices_[i]->id().pid != id.pid) - continue; - if (devices_[i]->reg_path().empty() || usb_device::usb_scan_name(devices_[i]->reg_path().c_str()).empty()) + // 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_open()) + if (dev->is_online()) { - if (dev->is_online()) - { - dev->set_online(false); - discard = false; - break; - } - else - { - // VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "%s is already offline and received LEAVE again, discard this event.\n", dev->name().c_str()); - // dev->release(); - // return; - discard = true; - } + dev->set_online(false); + discard = false; } - //else - //{ - // devices_.erase(devices_.begin() + i); - // dev->release(); - //} + else + { + discard = true; + } + break; } } if (discard) @@ -1153,67 +1017,54 @@ int usb_monitor::on_usb_pnp(WPARAM wp, LPARAM lp) return wp == DBT_DEVICEQUERYREMOVE; } + std::string utf8(u2utf8(dev->dbcc_name)); if (wp == DBT_DEVICEQUERYREMOVE) - return cur_dev_name_ != u2utf8(dev->dbcc_name); + return cur_dev_name_ != utf8; - VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "event '%08x' of device %s\n", wp, u2utf8(dev->dbcc_name).c_str()); + VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "event '%08x' of device %s\n", wp, utf8.c_str()); - usb_device* ud = new usb_device(u2utf8(dev->dbcc_name).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(std::vector& usb_devs) -{ - GUID hid = GUID_DEVINTERFACE_USB_DEVICE; // GUID_DEVINTERFACE_USB_HUB - HDEVINFO dev_info = NULL; - int ind = 0; - SP_DEVICE_INTERFACE_DATA id = { 0 }; - - // HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\DeviceClasses\{a5dcbf10-6530-11d2-901f-00c04fb951ed} - // HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB - // UuidFromStringW((RPC_WSTR)WIN_USB_GUID, &hid); - - dev_info = SetupDiGetClassDevsW(&hid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if (!dev_info) - return; - - 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)) - { - usb_devs.push_back(u2utf8(buf->DevicePath)); - } - delete[](char*)buf; - } - id.cbSize = sizeof(id); - } - SetupDiDestroyDeviceInfoList(dev_info); -} void usb_monitor::find_usb_and_trigger_event(void) { - std::vector old(found_usb_devs_); + std::vector old(found_usb_devs_); found_usb_devs_.clear(); - find_usb(found_usb_devs_); + 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) { - std::vector::iterator it = std::find(old.begin(), old.end(), found_usb_devs_[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::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].c_str()); + usb_device* dev = new usb_device(found_usb_devs_[i]); notify_usb_event(dev, true); dev->release(); } @@ -1223,7 +1074,7 @@ void usb_monitor::find_usb_and_trigger_event(void) for (size_t i = 0; i < old.size(); ++i) { - usb_device* dev = new usb_device(old[i].c_str()); + usb_device* dev = new usb_device(old[i]); notify_usb_event(dev, false); dev->release(); } @@ -1276,13 +1127,8 @@ void usb_monitor::thread_run_device_event_wnd(void) DEV_BROADCAST_HDR dbh = { 0 }; HDEVNOTIFY notify = NULL; - find_usb(found_usb_devs_); - for (size_t i = 0; i < found_usb_devs_.size(); ++i) - { - usb_device* dev = new usb_device(found_usb_devs_[i].c_str()); - notify_usb_event(dev, true); - dev->release(); - } + // mannual triggered at beginning ... + find_usb_and_trigger_event(); dbh.dbch_size = sizeof(dbh); dbh.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE; @@ -1292,7 +1138,7 @@ void usb_monitor::thread_run_device_event_wnd(void) DEV_BROADCAST_DEVICEINTERFACE_A di = { 0 }; di.dbcc_size = (sizeof(di) + 3) / 4 * 4; di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - UuidFromStringA((RPC_CSTR)HG_SCANNER_GUID, &di.dbcc_classguid); + 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) @@ -1605,6 +1451,6 @@ uint8_t LIBUSB_CALL libusb_get_device_address(libusb_device* device) if(!device) return 0; - return ((usb_device*)device)->port(); + return ((usb_device*)device)->address(); } diff --git a/device/win_usb/win_usb.h b/device/win_usb/win_usb.h index 06121ba..981a46d 100644 --- a/device/win_usb/win_usb.h +++ b/device/win_usb/win_usb.h @@ -15,25 +15,33 @@ // HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{6bdd1fc6-810f-11d0-bec7-08002be2092f} -#define HG_SCANNER_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F" +#define IMAGE_CLASS_GUID "6BDD1FC6-810F-11D0-BEC7-08002BE2092F" #define MONITOR_WINDOW_OWNER L"monitor_wnd_owner" -typedef struct _dev_id +typedef struct _usb_dev { - int vid; - int pid; - int addr; + // all members are in utf8 + std::string name; // \\?\usb#vid_0bda&pid_0129#20100201396000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed} + std::string driver_key; // {6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0016 + std::string desc; // USB Composite Device + std::string hub; // parent hub + int vid; + int pid; + int port; // port on the hub, also be ConnectionIndex + int addr; // connection address - struct _dev_id() + struct _usb_dev() { - memset(this, 0, sizeof(struct _dev_id)); + name = driver_key = desc = hub = ""; + vid = pid = port = 0; + addr = -1; } - bool operator==(const struct _dev_id& r) + bool operator==(const struct _usb_dev& r) { - return vid == r.vid && pid == r.pid && r.addr == addr; + return name == r.name; } -}DEVID; +}USBDEV, * LPUSBDEV; class ovl_cls// : public refer { @@ -83,12 +91,9 @@ class usb_device // consider as libusb_device { volatile long ref_; GUID guid_; - std::string name_; - std::string reg_key_; - DEVID id_; + USBDEV udev_; bool is_ok_; bool online_; - uint8_t port_; ovl_mgr ovl_mgr_; libusb_device_handle *handle_; // as file handle returned by CreateFile @@ -108,15 +113,12 @@ class usb_device // consider as libusb_device int set_timeout(HANDLE h); public: - usb_device(const char* name); + usb_device(const USBDEV& dev); - static DEVID vid_pid_from_name(const char* name); // device name like '\\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}' + static void vid_pid_from_name(const char* name, int *vid, int *pid); // device name like '\\?\usb#vid_3072&pid_0239#01234567aabbccddee#{a5dcbf10-6530-11d2-901f-00c04fb951ed}' static DWORD from_hex_string(const char* hex_str); - static std::string driver_key_name(HANDLE file); - static std::string parent_hub_path_name(int vid, int pid, int *addr = NULL, std::string* reg_key = NULL); + static std::string name_without_guid(const char* name); static bool find_vid_pid_in_hub(const char* utf8_hub_path_name, int vid, int pid, int *addr/*if *addr is not -1 or NULL, search the device with vid:pid and set the address in addr if it was not null, or-else chekc the device at *addr is vid:pid or not*/, std::string* reg_key/*{6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0007*/); - static int get_device_address(const char* device_name, LPGUID lpguid); - static std::string usb_scan_name(DEVID id, const char* guid = HG_SCANNER_GUID); // return \\.\Usbscan1 ... static std::string usb_scan_name(const char* reg_key/*{6bdd1fc6-810f-11d0-bec7-08002be2092f}\\0007*/); // return \\.\Usbscan1 ... long add_ref(void); @@ -126,25 +128,21 @@ protected: ~usb_device(); public: - bool operator==(const char* name); - bool operator==(const DEVID& id); - - usb_device& operator=(const DEVID& id); usb_device& operator=(const GUID& guid); std::string name(void); + USBDEV& dev(void); GUID guid(void); - DEVID id(void); bool is_ok(void); bool is_open(void); bool is_online(void); void set_online(bool online); uint8_t port(void); + uint8_t address(void); std::string reg_path(void); bool init(void); void clear(void); - void online_statu_changed(bool online); int get_descriptor(libusb_device_descriptor* desc); int get_config_descriptor(int index, libusb_config_descriptor** desc); int open(libusb_device_handle** dev_handle); @@ -178,14 +176,13 @@ class usb_monitor // consider as libusb_context HWND wnd_monitor_; std::string cur_dev_name_; volatile bool run_; - std::vector found_usb_devs_; + std::vector found_usb_devs_; static LRESULT CALLBACK monitor_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); static void register_monitor_wnd(const wchar_t* cls); void notify_usb_event(usb_device*& dev, bool arrive); int on_usb_pnp(WPARAM wp, LPARAM lp); - void find_usb(std::vector& usb_devs); void find_usb_and_trigger_event(void); public: @@ -195,6 +192,12 @@ public: static usb_monitor* usb_monitor_; static UINT find_usb_timer_; // set when RegisterDeviceNotification failed + static int enum_usb_device(bool(__stdcall* found_usb)(LPUSBDEV dev, void* param), void* param, bool hub = false); + static bool __stdcall find_all_usb_devices(LPUSBDEV dev, void* param/*std::vector* */); + static bool __stdcall usb_dev_by_name(LPUSBDEV dev, void* param/*LPUSBDEV*/); + static bool __stdcall find_parent_hub(LPUSBDEV hub, void* param/*LPUSBDEV*/); + static bool is_desired_usb_device(int vid, int pid); + public: usb_callback* reg_callback(libusb_hotplug_callback_fn cb, void* param); void unreg_callback(usb_callback* cb);