summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2014-06-10 17:49:02 +0400
committerDenis Shienkov <denis.shienkov@gmail.com>2014-06-30 09:06:15 +0200
commitb3df3e8deaed821b101aef2c2367326107a6254a (patch)
tree3b35927b8b00884fcbae6ea68cf7bc9edc7180d7
parentaee836176ff4bf60f6823a9defccee7f49b92a5b (diff)
downloadqtserialport-b3df3e8deaed821b101aef2c2367326107a6254a.tar.gz
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 <denis.shienkov@gmail.com>
-rw-r--r--src/serialport/qserialportinfo_win.cpp44
1 files 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 <initguid.h>
#include <setupapi.h>
+#include <cfgmgr32.h>
QT_BEGIN_NAMESPACE
@@ -122,21 +123,33 @@ static QString deviceRegistryProperty(HDEVINFO deviceInfoSet,
return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(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<wchar_t *>(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<wchar_t *>(outputBuffer.data()),
+ outputBuffer.size(), 0) != CR_SUCCESS) {
return QString();
}
+ return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(outputBuffer.constData()));
+}
- return QString::fromWCharArray(reinterpret_cast<const wchar_t *>(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> 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) {