From b3df3e8deaed821b101aef2c2367326107a6254a Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Tue, 10 Jun 2014 17:49:02 +0400 Subject: Improve the serial number handling on Windows The standard USB CDC driver (usbser.sys) does not add information of serial number to the device instance identifier of the child devices (serial ports), so our algorithm returns an empty string. But information about a serial number is stored in the device identifier of the parental node. Thus, it is necessary to get this parent identifier, using these recommendations from MSDN: http://msdn.microsoft.com/en-us/library/windows/hardware/ff549417%28v=vs.85%29.aspx For this purpose is used the set of new functions from the "Configuration Manager Functions" family. Therefore it was necessary: * Rewrite the deviceInstanceIdentifier() function. Now this function accepts one DEVINST parameter and returns the corresponding device instance identifier string. * Add the new parentDeviceInstanceNumber() function. This function accepts a DEVINST of the child device and returns a DEVINST of the parent device. Thus, the new algorithm tries to extract a serial number from the current (child) device and in case it is empty, try to extract from the parent. Tested on Windows 7/8 with the Segger JLink device (provides the CDC serial port) using Qt4 (MSVC2010) and then Qt5 (MSVC2012, MinGW). Also are checked other devices for possible regressions: * on-board serial port * com0com virtual serial port * USB FTDI serial port no regressions found. Change-Id: Ic6afc258f45aa374ec77dc0b586d479b5286359f Reviewed-by: Denis Shienkov --- src/serialport/qserialportinfo_win.cpp | 44 ++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/serialport/qserialportinfo_win.cpp b/src/serialport/qserialportinfo_win.cpp index 8e449c4..dd6a907 100644 --- a/src/serialport/qserialportinfo_win.cpp +++ b/src/serialport/qserialportinfo_win.cpp @@ -51,6 +51,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -122,21 +123,33 @@ static QString deviceRegistryProperty(HDEVINFO deviceInfoSet, return QString::fromWCharArray(reinterpret_cast(devicePropertyByteArray.constData())); } -static QString deviceInstanceIdentifier(HDEVINFO deviceInfoSet, - PSP_DEVINFO_DATA deviceInfoData) +static QString deviceInstanceIdentifier(DEVINST deviceInstanceNumber) { - DWORD requiredSize = 0; - if (::SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, NULL, 0, &requiredSize)) + ULONG numberOfChars = 0; + if (::CM_Get_Device_ID_Size(&numberOfChars, deviceInstanceNumber, 0) != CR_SUCCESS) return QString(); - - QByteArray data(requiredSize * sizeof(wchar_t), 0); - if (!::SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, - reinterpret_cast(data.data()), data.size(), NULL)) { - // TODO: error handling with GetLastError + // The size does not include the terminating null character. + ++numberOfChars; + QByteArray outputBuffer(numberOfChars * sizeof(wchar_t), 0); + if (::CM_Get_Device_ID(deviceInstanceNumber, reinterpret_cast(outputBuffer.data()), + outputBuffer.size(), 0) != CR_SUCCESS) { return QString(); } + return QString::fromWCharArray(reinterpret_cast(outputBuffer.constData())); +} - return QString::fromWCharArray(reinterpret_cast(data.constData())); +static DEVINST parentDeviceInstanceNumber(DEVINST childDeviceInstanceNumber) +{ + ULONG nodeStatus = 0; + ULONG problemNumber = 0; + if (::CM_Get_DevNode_Status(&nodeStatus, &problemNumber, + childDeviceInstanceNumber, 0) != CR_SUCCESS) { + return 0; + } + DEVINST parentInstanceNumber = 0; + if (::CM_Get_Parent(&parentInstanceNumber, childDeviceInstanceNumber, 0) != CR_SUCCESS) + return 0; + return parentInstanceNumber; } static QString devicePortName(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData) @@ -254,9 +267,14 @@ QList QSerialPortInfo::availablePorts() serialPortInfo.d_ptr->manufacturer = deviceRegistryProperty(deviceInfoSet, &deviceInfoData, SPDRP_MFG); - s = deviceInstanceIdentifier(deviceInfoSet, &deviceInfoData).toUpper(); - - serialPortInfo.d_ptr->serialNumber = deviceSerialNumber(s); + s = deviceInstanceIdentifier(deviceInfoData.DevInst).toUpper(); + QString serialNumber = deviceSerialNumber(s); + if (serialNumber.isEmpty()) { + const DEVINST parentDevNumber = parentDeviceInstanceNumber(deviceInfoData.DevInst); + const QString parentDevIdentifier = deviceInstanceIdentifier(parentDevNumber).toUpper(); + serialNumber = deviceSerialNumber(parentDevIdentifier); + } + serialPortInfo.d_ptr->serialNumber = serialNumber; int index = s.indexOf(usbVendorIdentifierPrefix); if (index != -1) { -- cgit v1.2.1