diff --git a/TabletDriverService/HIDDevice.cpp b/TabletDriverService/HIDDevice.cpp index d64ad11..ca2e60b 100644 --- a/TabletDriverService/HIDDevice.cpp +++ b/TabletDriverService/HIDDevice.cpp @@ -4,20 +4,27 @@ #define LOG_MODULE "HIDDevice" #include "Logger.h" -HIDDevice::HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage) : HIDDevice() { +HIDDevice::HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage, bool IsExclusive) { this->vendorId = VendorId; this->productId = ProductId; this->usagePage = UsagePage; this->usage = Usage; - if(this->OpenDevice(&this->_deviceHandle, this->vendorId, this->productId, this->usagePage, this->usage)) { + this->isExclusive = IsExclusive; + if(this->OpenDevice(&this->_deviceHandle, this->vendorId, this->productId, this->usagePage, this->usage, this->isExclusive)) { isOpen = true; } isReading = false; } +HIDDevice::HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage) : HIDDevice(VendorId, ProductId, UsagePage, Usage, false) { +} + HIDDevice::HIDDevice() { isOpen = false; isReading = false; + _manufacturerName = ""; + _productName = ""; + _serialNumber = ""; _deviceHandle = NULL; } @@ -25,21 +32,58 @@ HIDDevice::~HIDDevice() { CloseDevice(); } -bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage) { + +bool GetHIDStrings(HANDLE deviceHandle, string *manufacturerName, string *productName, string *serialNumber) { + BYTE buffer[1024]; + int i; + + // HID manufacturer string + if(HidD_GetManufacturerString(deviceHandle, &buffer, sizeof(buffer))) { + for(i = 0; i < (int)sizeof(buffer); i += 2) { + if(buffer[i]) manufacturerName->push_back(buffer[i]); + else break; + } + } + + // HID product string + if(HidD_GetProductString(deviceHandle, &buffer, sizeof(buffer))) { + for(i = 0; i < (int)sizeof(buffer); i += 2) { + if(buffer[i]) productName->push_back(buffer[i]); + else break; + } + } + + // HID serial number + if(HidD_GetSerialNumberString(deviceHandle, &buffer, sizeof(buffer))) { + for(i = 0; i < (int)sizeof(buffer); i += 2) { + if(buffer[i]) serialNumber->push_back(buffer[i]); + else break; + } + } + + return true; +} + + +// +// Open device +// +bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage, bool exclusive) { HDEVINFO deviceInfo; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; SP_DEVINFO_DATA deviceInfoData; DWORD dwSize, dwMemberIdx; GUID hidGuid; - BYTE stringBytes[1024]; PHIDP_PREPARSED_DATA hidPreparsedData; HIDD_ATTRIBUTES hidAttributes; HIDP_CAPS hidCapabilities; + string manufacturerName; + string productName; + string serialNumber; HANDLE deviceHandle; - HANDLE resultHandle = 0; HidD_GetHidGuid(&hidGuid); @@ -68,15 +112,29 @@ bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, US // Get interface detail if(SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, deviceInterfaceDetailData, dwSize, &dwSize, &deviceInfoData)) { - // Open HID - deviceHandle = CreateFile( - deviceInterfaceDetailData->DevicePath, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - 0, - NULL); + // Open HID in exclusive mode + if(exclusive) { + deviceHandle = CreateFile( + deviceInterfaceDetailData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + 0, // No sharing + NULL, + OPEN_EXISTING, + 0, + NULL); + } + + // Open HID in sharing mode + else { + deviceHandle = CreateFile( + deviceInterfaceDetailData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + } // HID handle valid? if(deviceHandle != INVALID_HANDLE_VALUE) { @@ -93,34 +151,17 @@ bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, US // Debug logging if(this->debugEnabled) { - string manufacturerName = ""; - string productName = ""; - - // HID manufacturer string - if(HidD_GetManufacturerString(deviceHandle, &stringBytes, sizeof(stringBytes))) { - for(int i = 0; i < (int)sizeof(stringBytes); i += 2) { - if(stringBytes[i]) { - manufacturerName.push_back(stringBytes[i]); - } - else { - break; - } - } - } - - // HID product string - if(HidD_GetProductString(deviceHandle, &stringBytes, sizeof(stringBytes))) { - for(int i = 0; i < (int)sizeof(stringBytes); i += 2) { - if(stringBytes[i]) { - productName.push_back(stringBytes[i]); - } - else { - break; - } - } - } - - LOG_DEBUG("HID Device: Vendor: '%s' Product: '%s'\n", manufacturerName.c_str(), productName.c_str()); + manufacturerName = ""; + productName = ""; + serialNumber = ""; + + GetHIDStrings(deviceHandle, &manufacturerName, &productName, &serialNumber); + + LOG_DEBUG("HID Device: Vendor: '%s' Product: '%s', Serial: '%s'\n", + manufacturerName.c_str(), + productName.c_str(), + serialNumber.c_str() + ); LOG_DEBUG(" Vendor Id: 0x%04X, Product Id: 0x%04X\n", hidAttributes.VendorID, hidAttributes.ProductID @@ -144,6 +185,8 @@ bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, US hidCapabilities.UsagePage == usagePage && hidCapabilities.Usage == usage ) { + GetHIDStrings(deviceHandle, &_manufacturerName, &_productName, &_serialNumber); + resultHandle = deviceHandle; } @@ -176,6 +219,14 @@ bool HIDDevice::OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, US return false; } +// +// Open device +// +bool HIDDevice::OpenDevice(HANDLE * handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage) +{ + return OpenDevice(handle, vendorId, productId, usagePage, usage, false); +} + // Read HID report int HIDDevice::Read(void *buffer, int length) { //return HidD_GetInputReport(_deviceHandle, buffer, length); @@ -222,6 +273,47 @@ int HIDDevice::StringRequest(UCHAR stringId, UCHAR * buffer, int length) return 0; } +string HIDDevice::GetString(UCHAR stringId) +{ + string resultString = ""; + UCHAR buffer[256]; + int bytesRead = 0; + + if(isReading) { + throw runtime_error("HID string request can't be sent when the device is in use!"); + } + else { + bytesRead = StringRequest(stringId, buffer, 256); + } + + // Reply received? + if(bytesRead > 0) { + for(int i = 0; i < bytesRead; i += 2) { + resultString.push_back(buffer[i]); + } + } + + return resultString; +} + +// Get HID manufacturer name +string HIDDevice::GetManufacturerName() +{ + return _manufacturerName; +} + +// Get HID product name +string HIDDevice::GetProductName() +{ + return _productName; +} + +// Get HID serial number +string HIDDevice::GetSerialNumber() +{ + return _serialNumber; +} + // Close the device void HIDDevice::CloseDevice() { if(isOpen && _deviceHandle != NULL && _deviceHandle != INVALID_HANDLE_VALUE) { diff --git a/TabletDriverService/HIDDevice.h b/TabletDriverService/HIDDevice.h index d6af4f8..1ca2001 100644 --- a/TabletDriverService/HIDDevice.h +++ b/TabletDriverService/HIDDevice.h @@ -16,6 +16,9 @@ using namespace std; class HIDDevice { private: HANDLE _deviceHandle; + string _manufacturerName; + string _productName; + string _serialNumber; public: bool isOpen; bool debugEnabled; @@ -24,15 +27,23 @@ class HIDDevice { USHORT productId; USHORT usagePage; USHORT usage; + bool isExclusive; + + HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage, bool IsExclusive); HIDDevice(USHORT VendorId, USHORT ProductId, USHORT UsagePage, USHORT Usage); HIDDevice(); ~HIDDevice(); + bool OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage, bool exclusive); bool OpenDevice(HANDLE *handle, USHORT vendorId, USHORT productId, USHORT usagePage, USHORT usage); int Read(void *buffer, int length); int Write(void *buffer, int length); bool SetFeature(void *buffer, int length); bool GetFeature(void *buffer, int length); int StringRequest(UCHAR stringId, UCHAR *buffer, int length); + string GetString(UCHAR stringId); + string GetManufacturerName(); + string GetProductName(); + string GetSerialNumber(); void CloseDevice(); }; \ No newline at end of file diff --git a/TabletDriverService/USBDevice.cpp b/TabletDriverService/USBDevice.cpp index 272f718..e4762e4 100644 --- a/TabletDriverService/USBDevice.cpp +++ b/TabletDriverService/USBDevice.cpp @@ -7,7 +7,7 @@ USBDevice::USBDevice(string Guid) { this->guid = Guid; isOpen = false; - if(this->OpenDevice(&_deviceHandle, &_usbHandle, guid)) { + if(this->OpenDevice(&_deviceHandle, &_usbHandle, &deviceDescriptor, guid)) { isOpen = true; } } @@ -16,31 +16,29 @@ USBDevice::~USBDevice() { } -bool USBDevice::OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *outUSBHandle, string usbDeviceGUIDString) { +bool USBDevice::OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *outUSBHandle, USB_DEVICE_DESCRIPTOR *outDeviceDescriptor, string usbDeviceGUIDString) { GUID usbDeviceGUID; HDEVINFO deviceInfo; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; SP_DEVINFO_DATA deviceInfoData; + USB_DEVICE_DESCRIPTOR usbDeviceDescriptor; + USB_INTERFACE_DESCRIPTOR usbInterfaceDescriptor; + DWORD dwSize; DWORD dwMemberIdx; + ULONG bytesRead = 0; + bool deviceFound = false; HANDLE deviceHandle = 0; WINUSB_INTERFACE_HANDLE usbHandle = 0; - bool deviceFound = false; - - USB_INTERFACE_DESCRIPTOR usbInterfaceDescriptor; - - ULONG readBytes = 0; - - - - + // Create GUID wstring std::wstring stemp = std::wstring(usbDeviceGUIDString.begin(), usbDeviceGUIDString.end()); LPCWSTR wstringGUID = stemp.c_str(); + // Create CLSID from GUID string HRESULT hr = CLSIDFromString(wstringGUID, (LPCLSID)&usbDeviceGUID); if(hr != S_OK) { LOG_ERROR("Can't create the USB Device GUID!\n"); @@ -55,38 +53,39 @@ bool USBDevice::OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *out return false; } - // Enumerate device interface data + // Enumerate device interfaces deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); dwMemberIdx = 0; SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &usbDeviceGUID, dwMemberIdx, &deviceInterfaceData); + while(GetLastError() != ERROR_NO_MORE_ITEMS) { - // Get the required buffer size. + // Get the required interface detail buffer size. deviceInfoData.cbSize = sizeof(deviceInfoData); SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, NULL, 0, &dwSize, NULL); - // Allocate memory + // Allocate memory for interface detail data deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(dwSize); deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Get device interface detail data if(SetupDiGetDeviceInterfaceDetail(deviceInfo, &deviceInterfaceData, deviceInterfaceDetailData, dwSize, &dwSize, &deviceInfoData)) { - //LOG_DEBUG("USB Device path: %S\n", deviceInterfaceDetailData->DevicePath); - - // Create File - deviceHandle = CreateFile(deviceInterfaceDetailData->DevicePath, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - NULL); - + // Create device file + deviceHandle = CreateFile( + deviceInterfaceDetailData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL + ); + + // Check file handle if(deviceHandle != INVALID_HANDLE_VALUE) { - //LOG_DEBUG("Handle: %lu\n", (ULONG)deviceHandle); - // Init WinUsb + // Initialize WinUsb WinUsb_Initialize(deviceHandle, &usbHandle); if(!usbHandle) { LOG_ERROR("ERROR! Unable to initialize WinUSB!\n"); @@ -94,35 +93,63 @@ bool USBDevice::OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *out CloseHandle(deviceHandle); return false; } - //LOG_DEBUG("USB Handle: %d\n", (ULONG)usbHandle); - - // Query interface settings - ZeroMemory(&usbInterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR)); - - // Can query interface settings? - if(WinUsb_QueryInterfaceSettings(usbHandle, 0, &usbInterfaceDescriptor)) { + // Clear descriptors + memset(&usbDeviceDescriptor, 0, sizeof(USB_DEVICE_DESCRIPTOR)); + memset(&usbInterfaceDescriptor, 0, sizeof(USB_INTERFACE_DESCRIPTOR)); + bytesRead = 0; + + // + // Is the device valid? + // + if( + // Get device descriptor + WinUsb_GetDescriptor( + usbHandle, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0x409, + (UCHAR*)&usbDeviceDescriptor, + sizeof(usbDeviceDescriptor), + &bytesRead + ) + && + + // Get device interface settings + WinUsb_QueryInterfaceSettings(usbHandle, 0, &usbInterfaceDescriptor) + ) { + + // Copy handles memcpy(outDeviceHandle, &deviceHandle, sizeof(HANDLE)); memcpy(outUSBHandle, &usbHandle, sizeof(WINUSB_INTERFACE_HANDLE)); + + // Copy device descriptor + memcpy(outDeviceDescriptor, &usbDeviceDescriptor, sizeof(usbDeviceDescriptor)); + deviceFound = true; } + + // + // Invalid device + // else { + + // Free WinUSB handle if(usbHandle && usbHandle != INVALID_HANDLE_VALUE) WinUsb_Free(usbHandle); + // Free device file if(deviceHandle && deviceHandle != INVALID_HANDLE_VALUE) CloseHandle(deviceHandle); } } } - // Free memory - std::free(deviceInterfaceDetailData); + // Destroy interface detail data + free(deviceInterfaceDetailData); - // Continue looping + // Enumerate to the next interface SetupDiEnumDeviceInterfaces(deviceInfo, NULL, &usbDeviceGUID, ++dwMemberIdx, &deviceInterfaceData); } + // Destroy device info list SetupDiDestroyDeviceInfoList(deviceInfo); return deviceFound; @@ -188,6 +215,46 @@ int USBDevice::StringRequest(UCHAR stringId, UCHAR *buffer, int length) return bytesRead; } +string USBDevice::GetString(UCHAR stringId) { + string resultString = ""; + UCHAR buffer[256]; + int bytesRead = 0; + + bytesRead = StringRequest(stringId, buffer, 256); + + // Reply received? + if(bytesRead > 0) { + for(int i = 0; i < bytesRead; i += 2) { + resultString.push_back(buffer[i]); + } + } + + return resultString; +} + +// Get WinUSB device manufacturer name +string USBDevice::GetManufacturerName() { + if(deviceDescriptor.iManufacturer == 0) return ""; + return GetString(deviceDescriptor.iManufacturer); +} + +// Get WinUSB device product name +string USBDevice::GetProductName() +{ + if(deviceDescriptor.iProduct == 0) return ""; + return GetString(deviceDescriptor.iProduct); +} + +// Get WinUSB device serial number +string USBDevice::GetSerialNumber() +{ + if(deviceDescriptor.iSerialNumber == 0) return ""; + return GetString(deviceDescriptor.iSerialNumber); +} + +// +// Close WinUSB device +// void USBDevice::CloseDevice() { if(_usbHandle != NULL && _usbHandle != INVALID_HANDLE_VALUE) { try { diff --git a/TabletDriverService/USBDevice.h b/TabletDriverService/USBDevice.h index 9214e63..a4f6967 100644 --- a/TabletDriverService/USBDevice.h +++ b/TabletDriverService/USBDevice.h @@ -19,9 +19,10 @@ class USBDevice { private: HANDLE _deviceHandle; WINUSB_INTERFACE_HANDLE _usbHandle; - bool OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *outUSBHandle, string usbDeviceGUIDString); + bool OpenDevice(HANDLE *outDeviceHandle, WINUSB_INTERFACE_HANDLE *outUSBHandle, USB_DEVICE_DESCRIPTOR *outDeviceDescriptor, string usbDeviceGUIDString); public: string guid; + USB_DEVICE_DESCRIPTOR deviceDescriptor; bool isOpen; USBDevice(string Guid); @@ -30,5 +31,9 @@ class USBDevice { int Write(UCHAR pipeId, void *buffer, int length); int ControlTransfer(UCHAR requestType, UCHAR request, USHORT value, USHORT index, void *buffer, USHORT length); int StringRequest(UCHAR stringId, UCHAR *buffer, int length); + string GetString(UCHAR stringId); + string GetManufacturerName(); + string GetProductName(); + string GetSerialNumber(); void CloseDevice(); }; \ No newline at end of file