diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-02-15 21:04:41 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-02-15 21:04:41 +0100 |
commit | 5bee9d9f0f8cf5415ad9337aed88bccac3c15ce1 (patch) | |
tree | 7aa21cde3da0200a293ece5ca0cb1330f5513b3b | |
parent | e5c93da50f3b05d312f0e3dec50baf9fcbd5ffdc (diff) | |
parent | 26ea44e3b45de4a33515c826f6f5c9aa501f57fd (diff) |
Merge remote-tracking branch 'origin/5.6' into 5.7v5.7.0-alpha1
Conflicts:
.qmake.conf
Change-Id: I0dcaa0ea10fa9ca4a04f5c3837ea70028fc9c0b8
-rw-r--r-- | dist/changes-5.6.0 | 53 | ||||
-rw-r--r-- | src/serialport/qserialportinfo.h | 3 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_freebsd.cpp | 383 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_osx.cpp | 38 | ||||
-rw-r--r-- | src/serialport/qserialportinfo_unix.cpp | 288 | ||||
-rw-r--r-- | src/serialport/serialport-lib.pri | 11 |
6 files changed, 470 insertions, 306 deletions
diff --git a/dist/changes-5.6.0 b/dist/changes-5.6.0 new file mode 100644 index 00000000..815ae54a --- /dev/null +++ b/dist/changes-5.6.0 @@ -0,0 +1,53 @@ +QtSerialPort 5.6 introduces a few new features and improvements as well as +bugfixes over the 5.5.x series. For more details, refer to the online +documentation included in this distribution. The documentation is also available +online: + + http://doc.qt.io/qt-5/index.html + +The QtSerialPort version 5.6 series is binary compatible with the 5.5.x series. +Applications compiled for 5.5 will continue to run with 5.6. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + + - Improved the documentation: + * [QTBUG-45391] Fixed the examples link. + * [QTBUG-43810] Improved the references to the readyRead() signal for + some examples. + * [QTBUG-48736] Fixed the examplesinstallpath variable in .qdocconf file. + * [QTBUG-44994] Fixed warning about supported directions on Windows(CE). + + - QSerialPortInfo: + * Added enumeration of virtual tty0tty devices, which are provided by the + http://sourceforge.net/p/tty0tty/wiki/Home/ driver. + * Fixed detection of 8250 serial port types with the udev backend. + * [QTBUG-50223] Now it enumerates the ttyTHSx devices, which are provided + by the 'Tegra Jetson TK1' board, when no udev or sysfs backends are + available. + + - QSerialPort: + * Added handling of the ERROR_PATH_NOT_FOUND error code on Windows, which + now is interpreted as QSP::DeviceNotFoundError. + * Fixed the QSP::clear() method that caused "The parameter is incorrect" + error on Windows. + * [QTBUG-48094] Added support of the termios v2 feature to configure a + custom baud rate on Linux. + * Custom speed configuration for one direction is not allowed on Linux. + Trying to do this will lead to QSP::UnsupportedOperationError. + * Now any attempt to change the policy to anything else than QSP::IgnorePolicy + will fail with QSerialPoirt::UnsupportedOperationError. + * Fixed stalling of reading with the limited buffer size on *nix. + * Improved the console warning message when a suitable custom baud rate + divisor is not found. + * [QTBUG-50052] Fixed recursion issue that is caused because of an error + in QSP::close(). diff --git a/src/serialport/qserialportinfo.h b/src/serialport/qserialportinfo.h index c72be406..45dea8a7 100644 --- a/src/serialport/qserialportinfo.h +++ b/src/serialport/qserialportinfo.h @@ -90,9 +90,6 @@ private: QSerialPortInfo(const QSerialPortInfoPrivate &dd); friend QList<QSerialPortInfo> availablePortsByUdev(bool &ok); friend QList<QSerialPortInfo> availablePortsBySysfs(bool &ok); -#ifdef Q_OS_FREEBSD - friend QList<QSerialPortInfo> availablePortsBySysctl(bool &ok); -#endif friend QList<QSerialPortInfo> availablePortsByFiltersOfDevices(bool &ok); QScopedPointer<QSerialPortInfoPrivate, QSerialPortInfoPrivateDeleter> d_ptr; }; diff --git a/src/serialport/qserialportinfo_freebsd.cpp b/src/serialport/qserialportinfo_freebsd.cpp new file mode 100644 index 00000000..49612f15 --- /dev/null +++ b/src/serialport/qserialportinfo_freebsd.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Denis Shienkov <denis.shienkov@gmail.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtSerialPort module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qserialportinfo.h" +#include "qserialportinfo_p.h" +#include "qserialport_p.h" + +#include <QtCore/qdatastream.h> +#include <QtCore/qvector.h> +#include <QtCore/qdir.h> + +#include <errno.h> +#include <sys/types.h> // kill +#include <signal.h> // kill + +#include <sys/sysctl.h> // sysctl, sysctlnametomib + +QT_BEGIN_NAMESPACE + +static QString deviceProperty(const QString &source, const QByteArray &pattern) +{ + const int firstbound = source.indexOf(QLatin1String(pattern)); + if (firstbound == -1) + return QString(); + const int lastbound = source.indexOf(QLatin1Char(' '), firstbound); + return source.mid(firstbound + pattern.size(), lastbound - firstbound - pattern.size()); +} + +static QString deviceName(const QString &pnpinfo) +{ + return deviceProperty(pnpinfo, "ttyname="); +} + +static QString deviceCount(const QString &pnpinfo) +{ + return deviceProperty(pnpinfo, "ttyports="); +} + +static quint16 deviceProductIdentifier(const QString &pnpinfo, bool &hasIdentifier) +{ + QString result = deviceProperty(pnpinfo, "product="); + return result.toInt(&hasIdentifier, 16); +} + +static quint16 deviceVendorIdentifier(const QString &pnpinfo, bool &hasIdentifier) +{ + QString result = deviceProperty(pnpinfo, "vendor="); + return result.toInt(&hasIdentifier, 16); +} + +static QString deviceSerialNumber(const QString &pnpinfo) +{ + QString serialNumber = deviceProperty(pnpinfo, "sernum="); + serialNumber.remove(QLatin1Char('"')); + return serialNumber; +} + +// A 'desc' string contains the both description and manufacturer +// properties, which are not possible to extract from the source +// string. Besides, this string can contains an other information, +// which should be excluded from the result. +static QString deviceDescriptionAndManufacturer(const QString &desc) +{ + const int classindex = desc.indexOf(QLatin1String(", class ")); + if (classindex == -1) + return desc; + return desc.mid(0, classindex); +} + +struct NodeInfo +{ + QString name; + QString value; +}; + +static QVector<int> mibFromName(const QString &name) +{ + size_t mibsize = 0; + if (::sysctlnametomib(name.toLocal8Bit().constData(), Q_NULLPTR, &mibsize) < 0 + || mibsize == 0) { + return QVector<int>(); + } + QVector<int> mib(mibsize); + if (::sysctlnametomib(name.toLocal8Bit().constData(), &mib[0], &mibsize) < 0) + return QVector<int>(); + + return mib; +} + +static QVector<int> nextOid(const QVector<int> &previousOid) +{ + QVector<int> mib; + mib.append(0); // Magic undocumented code (CTL_UNSPEC ?) + mib.append(2); // Magic undocumented code + foreach (int code, previousOid) + mib.append(code); + + size_t requiredLength = 0; + if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) + return QVector<int>(); + const size_t oidLength = requiredLength / sizeof(int); + QVector<int> oid(oidLength, 0); + if (::sysctl(&mib[0], mib.count(), &oid[0], &requiredLength, Q_NULLPTR, 0) < 0) + return QVector<int>(); + + if (previousOid.first() != oid.first()) + return QVector<int>(); + + return oid; +} + +static NodeInfo nodeForOid(const QVector<int> &oid) +{ + QVector<int> mib; + mib.append(0); // Magic undocumented code (CTL_UNSPEC ?) + mib.append(1); // Magic undocumented code + foreach (int code, oid) + mib.append(code); + + // query node name + size_t requiredLength = 0; + if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + QByteArray name(requiredLength, 0); + if (::sysctl(&mib[0], mib.count(), name.data(), &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + + // query node value + requiredLength = 0; + if (::sysctl(&oid[0], oid.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + QByteArray value(requiredLength, 0); + if (::sysctl(&oid[0], oid.count(), value.data(), &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + + // query value format + mib[1] = 4; // Magic undocumented code + requiredLength = 0; + if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + QByteArray buf(requiredLength, 0); + if (::sysctl(&mib[0], mib.count(), buf.data(), &requiredLength, Q_NULLPTR, 0) < 0) + return NodeInfo(); + + QDataStream in(buf); + in.setByteOrder(QDataStream::LittleEndian); + quint32 kind = 0; + qint8 format = 0; + in >> kind >> format; + + NodeInfo result; + + // we need only the string-type value + if (format == 'A') { + result.name = QString::fromLocal8Bit(name.constData()); + result.value = QString::fromLocal8Bit(value.constData()); + } + + return result; +} + +static QList<NodeInfo> enumerateDesiredNodes(const QVector<int> &mib) +{ + QList<NodeInfo> nodes; + + QVector<int> oid = mib; + + forever { + const QVector<int> nextoid = nextOid(oid); + if (nextoid.isEmpty()) + break; + + const NodeInfo node = nodeForOid(nextoid); + if (!node.name.isEmpty()) { + if (node.name.endsWith(QLatin1String("\%desc")) + || node.name.endsWith(QLatin1String("\%pnpinfo"))) { + nodes.append(node); + } + } + + oid = nextoid; + } + + return nodes; +} + +QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +{ + const QVector<int> mib = mibFromName(QLatin1String("dev")); + if (mib.isEmpty()) + return QList<QSerialPortInfo>(); + + const QList<NodeInfo> nodes = enumerateDesiredNodes(mib); + if (nodes.isEmpty()) + return QList<QSerialPortInfo>(); + + QDir deviceDir(QLatin1String("/dev")); + if (!(deviceDir.exists() && deviceDir.isReadable())) + return QList<QSerialPortInfo>(); + + deviceDir.setNameFilters(QStringList() << QLatin1String("cua*") << QLatin1String("tty*")); + deviceDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks); + + QList<QSerialPortInfo> cuaCandidates; + QList<QSerialPortInfo> ttyCandidates; + + foreach (const QString &portName, deviceDir.entryList()) { + if (portName.endsWith(QLatin1String(".init")) + || portName.endsWith(QLatin1String(".lock"))) { + continue; + } + + QSerialPortInfoPrivate priv; + priv.portName = portName; + priv.device = QSerialPortInfoPrivate::portNameToSystemLocation(portName); + + foreach (const NodeInfo &node, nodes) { + const int pnpinfoindex = node.name.indexOf(QLatin1String("\%pnpinfo")); + if (pnpinfoindex == -1) + continue; + + if (node.value.isEmpty()) + continue; + + QString ttyname = deviceName(node.value); + if (ttyname.isEmpty()) + continue; + + const QString ttyportscount = deviceCount(node.value); + if (ttyportscount.isEmpty()) + continue; + + const int count = ttyportscount.toInt(); + if (count == 0) + continue; + if (count > 1) { + bool matched = false; + for (int i = 0; i < count; ++i) { + const QString ends = QString(QLatin1String("%1.%2")).arg(ttyname).arg(i); + if (portName.endsWith(ends)) { + matched = true; + break; + } + } + + if (!matched) + continue; + } else { + if (!portName.endsWith(ttyname)) + continue; + } + + priv.serialNumber = deviceSerialNumber(node.value); + priv.vendorIdentifier = deviceVendorIdentifier(node.value, priv.hasVendorIdentifier); + priv.productIdentifier = deviceProductIdentifier(node.value, priv.hasProductIdentifier); + + const QString nodebase = node.name.mid(0, pnpinfoindex); + const QString descnode = QString(QLatin1String("%1\%desc")).arg(nodebase); + + // search for description and manufacturer properties + foreach (const NodeInfo &node, nodes) { + if (node.name != descnode) + continue; + + if (node.value.isEmpty()) + continue; + + // We can not separate the description and the manufacturer + // properties from the node value, so lets just duplicate it. + priv.description = deviceDescriptionAndManufacturer(node.value); + priv.manufacturer = priv.description; + break; + } + + break; + } + + if (portName.startsWith(QLatin1String("cua"))) + cuaCandidates.append(priv); + else if (portName.startsWith(QLatin1String("tty"))) + ttyCandidates.append(priv); + } + + QList<QSerialPortInfo> serialPortInfoList; + + foreach (const QSerialPortInfo &cuaCandidate, cuaCandidates) { + const QString cuaPortName = cuaCandidate.portName(); + const QString cuaToken = deviceProperty(cuaPortName, "cua"); + foreach (const QSerialPortInfo &ttyCandidate, ttyCandidates) { + const QString ttyPortName = ttyCandidate.portName(); + const QString ttyToken = deviceProperty(ttyPortName, "tty"); + if (cuaToken != ttyToken) + continue; + + serialPortInfoList.append(cuaCandidate); + serialPortInfoList.append(ttyCandidate); + } + } + + return serialPortInfoList; +} + +QList<qint32> QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} + +bool QSerialPortInfo::isBusy() const +{ + QString lockFilePath = serialPortLockFilePath(portName()); + if (lockFilePath.isEmpty()) + return false; + + QFile reader(lockFilePath); + if (!reader.open(QIODevice::ReadOnly)) + return false; + + QByteArray pidLine = reader.readLine(); + pidLine.chop(1); + if (pidLine.isEmpty()) + return false; + + qint64 pid = pidLine.toLongLong(); + + if (pid && (::kill(pid, 0) == -1) && (errno == ESRCH)) + return false; // PID doesn't exist anymore + + return true; +} + +#if QT_DEPRECATED_SINCE(5, 2) +bool QSerialPortInfo::isValid() const +{ + QFile f(systemLocation()); + return f.exists(); +} +#endif // QT_DEPRECATED_SINCE(5, 2) + +QString QSerialPortInfoPrivate::portNameToSystemLocation(const QString &source) +{ + return (source.startsWith(QLatin1Char('/')) + || source.startsWith(QLatin1String("./")) + || source.startsWith(QLatin1String("../"))) + ? source : (QLatin1String("/dev/") + source); +} + +QString QSerialPortInfoPrivate::portNameFromSystemLocation(const QString &source) +{ + return source.startsWith(QLatin1String("/dev/")) + ? source.mid(5) : source; +} + +QT_END_NAMESPACE diff --git a/src/serialport/qserialportinfo_osx.cpp b/src/serialport/qserialportinfo_osx.cpp index 72b1b53e..54912729 100644 --- a/src/serialport/qserialportinfo_osx.cpp +++ b/src/serialport/qserialportinfo_osx.cpp @@ -89,10 +89,10 @@ static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry, return value; } -static bool isCompleteInfo(const QSerialPortInfoPrivate &priv) +static bool isCompleteInfo(const QSerialPortInfoPrivate &priv, const QString &calloutDevice, const QString &dialinDevice) { - return !priv.portName.isEmpty() - && !priv.device.isEmpty() + return !calloutDevice.isEmpty() + && !dialinDevice.isEmpty() && !priv.manufacturer.isEmpty() && !priv.description.isEmpty() && !priv.serialNumber.isEmpty() @@ -100,11 +100,16 @@ static bool isCompleteInfo(const QSerialPortInfoPrivate &priv) && priv.hasVendorIdentifier; } -static QString deviceSystemLocation(io_registry_entry_t ioRegistryEntry) +static QString calloutDeviceSystemLocation(io_registry_entry_t ioRegistryEntry) { return searchStringProperty(ioRegistryEntry, QCFString(kIOCalloutDeviceKey)); } +static QString dialinDeviceSystemLocation(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kIODialinDeviceKey)); +} + static QString deviceDescription(io_registry_entry_t ioRegistryEntry) { QString result = searchStringProperty(ioRegistryEntry, QCFString(kIOPropertyProductNameKey)); @@ -168,12 +173,15 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() QSerialPortInfoPrivate priv; + QString calloutDevice; + QString dialinDevice; + forever { - if (priv.device.isEmpty()) { - priv.device = deviceSystemLocation(serialPortService); - if (!priv.device.isEmpty()) - priv.portName = QSerialPortInfoPrivate::portNameFromSystemLocation(priv.device); - } + if (calloutDevice.isEmpty()) + calloutDevice = calloutDeviceSystemLocation(serialPortService); + + if (dialinDevice.isEmpty()) + dialinDevice = dialinDeviceSystemLocation(serialPortService); if (priv.description.isEmpty()) priv.description = deviceDescription(serialPortService); @@ -196,7 +204,7 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() priv.hasProductIdentifier); } - if (isCompleteInfo(priv)) { + if (isCompleteInfo(priv, calloutDevice, dialinDevice)) { ::IOObjectRelease(serialPortService); break; } @@ -206,7 +214,15 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() break; } - serialPortInfoList.append(priv); + QSerialPortInfoPrivate calloutCandidate = priv; + calloutCandidate.device = calloutDevice; + calloutCandidate.portName = QSerialPortInfoPrivate::portNameFromSystemLocation(calloutDevice); + serialPortInfoList.append(calloutCandidate); + + QSerialPortInfoPrivate dialinCandidate = priv; + dialinCandidate.device = dialinDevice; + dialinCandidate.portName = QSerialPortInfoPrivate::portNameFromSystemLocation(dialinDevice); + serialPortInfoList.append(dialinCandidate); } ::IOObjectRelease(serialPortIterator); diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp index 601a333c..0b8b5177 100644 --- a/src/serialport/qserialportinfo_unix.cpp +++ b/src/serialport/qserialportinfo_unix.cpp @@ -48,21 +48,12 @@ #include <QtCore/qdir.h> #include <QtCore/qscopedpointer.h> -#ifdef Q_OS_FREEBSD -#include <QtCore/qdatastream.h> -#include <QtCore/qvector.h> -#endif - #include <private/qcore_unix_p.h> #include <errno.h> #include <sys/types.h> // kill #include <signal.h> // kill -#ifdef Q_OS_FREEBSD -#include <sys/sysctl.h> // sysctl, sysctlnametomib -#endif - #include "qtudev_p.h" QT_BEGIN_NAMESPACE @@ -158,280 +149,6 @@ static bool isValidSerial8250(const QString &systemLocation) return false; } -#ifdef Q_OS_FREEBSD - -static QString deviceProperty(const QString &pnpinfo, const QByteArray &pattern) -{ - const int firstbound = pnpinfo.indexOf(QLatin1String(pattern)); - if (firstbound == -1) - return QString(); - const int lastbound = pnpinfo.indexOf(QLatin1Char(' '), firstbound); - return pnpinfo.mid(firstbound + pattern.size(), lastbound - firstbound - pattern.size()); -} - -static QString deviceName(const QString &pnpinfo) -{ - return deviceProperty(pnpinfo, "ttyname="); -} - -static QString deviceCount(const QString &pnpinfo) -{ - return deviceProperty(pnpinfo, "ttyports="); -} - -static quint16 deviceProductIdentifier(const QString &pnpinfo, bool &hasIdentifier) -{ - QString result = deviceProperty(pnpinfo, "product="); - return result.toInt(&hasIdentifier, 16); -} - -static quint16 deviceVendorIdentifier(const QString &pnpinfo, bool &hasIdentifier) -{ - QString result = deviceProperty(pnpinfo, "vendor="); - return result.toInt(&hasIdentifier, 16); -} - -static QString deviceSerialNumber(const QString &pnpinfo) -{ - QString serialNumber = deviceProperty(pnpinfo, "sernum="); - serialNumber.remove(QLatin1Char('"')); - return serialNumber; -} - -// A 'desc' string contains the both description and manufacturer -// properties, which are not possible to extract from the source -// string. Besides, this string can contains an other information, -// which should be excluded from the result. -static QString deviceDescriptionAndManufacturer(const QString &desc) -{ - const int classindex = desc.indexOf(QLatin1String(", class ")); - if (classindex == -1) - return desc; - return desc.mid(0, classindex); -} - -struct NodeInfo -{ - QString name; - QString value; -}; - -static QVector<int> mibFromName(const QString &name) -{ - size_t mibsize = 0; - if (::sysctlnametomib(name.toLocal8Bit().constData(), Q_NULLPTR, &mibsize) < 0 - || mibsize == 0) { - return QVector<int>(); - } - QVector<int> mib(mibsize); - if (::sysctlnametomib(name.toLocal8Bit().constData(), &mib[0], &mibsize) < 0) - return QVector<int>(); - - return mib; -} - -static QVector<int> nextOid(const QVector<int> &previousOid) -{ - QVector<int> mib; - mib.append(0); // Magic undocumented code (CTL_UNSPEC ?) - mib.append(2); // Magic undocumented code - foreach (int code, previousOid) - mib.append(code); - - size_t requiredLength = 0; - if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) - return QVector<int>(); - const size_t oidLength = requiredLength / sizeof(int); - QVector<int> oid(oidLength, 0); - if (::sysctl(&mib[0], mib.count(), &oid[0], &requiredLength, Q_NULLPTR, 0) < 0) - return QVector<int>(); - - if (previousOid.first() != oid.first()) - return QVector<int>(); - - return oid; -} - -static NodeInfo nodeForOid(const QVector<int> &oid) -{ - QVector<int> mib; - mib.append(0); // Magic undocumented code (CTL_UNSPEC ?) - mib.append(1); // Magic undocumented code - foreach (int code, oid) - mib.append(code); - - // query node name - size_t requiredLength = 0; - if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - QByteArray name(requiredLength, 0); - if (::sysctl(&mib[0], mib.count(), name.data(), &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - - // query node value - requiredLength = 0; - if (::sysctl(&oid[0], oid.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - QByteArray value(requiredLength, 0); - if (::sysctl(&oid[0], oid.count(), value.data(), &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - - // query value format - mib[1] = 4; // Magic undocumented code - requiredLength = 0; - if (::sysctl(&mib[0], mib.count(), Q_NULLPTR, &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - QByteArray buf(requiredLength, 0); - if (::sysctl(&mib[0], mib.count(), buf.data(), &requiredLength, Q_NULLPTR, 0) < 0) - return NodeInfo(); - - QDataStream in(buf); - in.setByteOrder(QDataStream::LittleEndian); - quint32 kind = 0; - qint8 format = 0; - in >> kind >> format; - - NodeInfo result; - - // we need only the string-type value - if (format == 'A') { - result.name = QString::fromLocal8Bit(name.constData()); - result.value = QString::fromLocal8Bit(value.constData()); - } - - return result; -} - -static QList<NodeInfo> enumerateDesiredNodes(const QVector<int> &mib) -{ - QList<NodeInfo> nodes; - - QVector<int> oid = mib; - - forever { - const QVector<int> nextoid = nextOid(oid); - if (nextoid.isEmpty()) - break; - - const NodeInfo node = nodeForOid(nextoid); - if (!node.name.isEmpty()) { - if (node.name.endsWith("\%desc") - || node.name.endsWith("\%pnpinfo")) { - nodes.append(node); - } - } - - oid = nextoid; - } - - return nodes; -} - -QList<QSerialPortInfo> availablePortsBySysctl(bool &ok) -{ - const QVector<int> mib = mibFromName(QLatin1String("dev")); - if (mib.isEmpty()) { - ok = false; - return QList<QSerialPortInfo>(); - } - - const QList<NodeInfo> nodes = enumerateDesiredNodes(mib); - if (nodes.isEmpty()) { - ok = false; - return QList<QSerialPortInfo>(); - } - - QDir deviceDir(QLatin1String("/dev")); - if (!(deviceDir.exists() && deviceDir.isReadable())) { - ok = false; - return QList<QSerialPortInfo>(); - } - - deviceDir.setNameFilters(QStringList() << QLatin1String("cua*")); - deviceDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks); - - QList<QSerialPortInfo> serialPortInfoList; - - foreach (const QString &portName, deviceDir.entryList()) { - if (portName.endsWith(QLatin1String(".init")) - || portName.endsWith(QLatin1String(".lock"))) { - continue; - } - - QSerialPortInfoPrivate priv; - priv.portName = portName; - priv.device = QSerialPortInfoPrivate::portNameToSystemLocation(portName); - - foreach (const NodeInfo &node, nodes) { - const int pnpinfoindex = node.name.indexOf(QLatin1String("\%pnpinfo")); - if (pnpinfoindex == -1) - continue; - - if (node.value.isEmpty()) - continue; - - QString ttyname = deviceName(node.value); - if (ttyname.isEmpty()) - continue; - - const QString ttyportscount = deviceCount(node.value); - if (ttyportscount.isEmpty()) - continue; - - const int count = ttyportscount.toInt(); - if (count == 0) - continue; - if (count > 1) { - bool matched = false; - for (int i = 0; i < count; ++i) { - const QString ends = QString(QLatin1String("%1.%2")).arg(ttyname).arg(i); - if (portName.endsWith(ends)) { - matched = true; - break; - } - } - - if (!matched) - continue; - } else { - if (!portName.endsWith(ttyname)) - continue; - } - - priv.serialNumber = deviceSerialNumber(node.value); - priv.vendorIdentifier = deviceVendorIdentifier(node.value, priv.hasVendorIdentifier); - priv.productIdentifier = deviceProductIdentifier(node.value, priv.hasProductIdentifier); - - const QString nodebase = node.name.mid(0, pnpinfoindex); - const QString descnode = QString(QLatin1String("%1\%desc")).arg(nodebase); - - // search for description and manufacturer properties - foreach (const NodeInfo &node, nodes) { - if (node.name != descnode) - continue; - - if (node.value.isEmpty()) - continue; - - // We can not separate the description and the manufacturer - // properties from the node value, so lets just duplicate it. - priv.description = deviceDescriptionAndManufacturer(node.value); - priv.manufacturer = priv.description; - break; - } - - break; - } - - serialPortInfoList.append(priv); - } - - ok = true; - return serialPortInfoList; -} - -#endif // Q_OS_FREEBSD - static bool isRfcommDevice(const QString &portName) { if (!portName.startsWith(QLatin1String("rfcomm"))) @@ -742,11 +459,6 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts() serialPortInfoList = availablePortsBySysfs(ok); #endif -#ifdef Q_OS_FREEBSD - if (!ok) - serialPortInfoList = availablePortsBySysctl(ok); -#endif - if (!ok) serialPortInfoList = availablePortsByFiltersOfDevices(ok); diff --git a/src/serialport/serialport-lib.pri b/src/serialport/serialport-lib.pri index c3b00eaf..7179beae 100644 --- a/src/serialport/serialport-lib.pri +++ b/src/serialport/serialport-lib.pri @@ -37,14 +37,17 @@ unix { SOURCES += \ $$PWD/qserialport_unix.cpp - !osx { - SOURCES += \ - $$PWD/qserialportinfo_unix.cpp - } else { + osx { SOURCES += \ $$PWD/qserialportinfo_osx.cpp LIBS_PRIVATE += -framework IOKit -framework CoreFoundation + } else:freebsd { + SOURCES += \ + $$PWD/qserialportinfo_freebsd.cpp + } else { + SOURCES += \ + $$PWD/qserialportinfo_unix.cpp } } |