summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2016-02-15 21:04:41 +0100
committerLiang Qi <liang.qi@theqtcompany.com>2016-02-15 21:04:41 +0100
commit5bee9d9f0f8cf5415ad9337aed88bccac3c15ce1 (patch)
tree7aa21cde3da0200a293ece5ca0cb1330f5513b3b
parente5c93da50f3b05d312f0e3dec50baf9fcbd5ffdc (diff)
parent26ea44e3b45de4a33515c826f6f5c9aa501f57fd (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.053
-rw-r--r--src/serialport/qserialportinfo.h3
-rw-r--r--src/serialport/qserialportinfo_freebsd.cpp383
-rw-r--r--src/serialport/qserialportinfo_osx.cpp38
-rw-r--r--src/serialport/qserialportinfo_unix.cpp288
-rw-r--r--src/serialport/serialport-lib.pri11
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
}
}