diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2014-06-10 17:49:02 +0400 |
---|---|---|
committer | Denis Shienkov <denis.shienkov@gmail.com> | 2014-06-30 09:06:15 +0200 |
commit | b3df3e8deaed821b101aef2c2367326107a6254a (patch) | |
tree | 3b35927b8b00884fcbae6ea68cf7bc9edc7180d7 /src | |
parent | aee836176ff4bf60f6823a9defccee7f49b92a5b (diff) | |
download | qtserialport-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>
Diffstat (limited to 'src')
-rw-r--r-- | src/serialport/qserialportinfo_win.cpp | 44 |
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) { |