summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2013-08-27 15:53:29 +0400
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-22 19:44:52 +0200
commit0973537c5471288726b929250199a41435729bee (patch)
tree0fcdef3ff7418d1f4d8349c54b6419935e1e2d66
parenteea6754a5f907cf66bdc497b587e3a4a43fadc99 (diff)
Use sysfs on Linux when available
This change is the continuation of the previous: * sha1: 4bdbbe4c87676ca94daae947ac5908d77966319b The previous operation was to use the nodes in the "/dev" hierarchy. The "sysfs" was only used for extending the information that cannot be obtained from "/dev", like manufacturer, description of the device, etc. This decision had a shortcoming of expansion of the list of filters in case of appearance the new device with the new name. Besides, the Linux kernel has a lot drivers, each of which provide a various names for an serial devices, so we can't know all these names. Now the sysfs is used directly, without filters. To search for devices we use an appropriate "/sys/class/tty" directory that contains all necessary info. Notes: * There are possible some regressions relating to enumeration of rfcomm, ircomm devices. Because this devices can belong to other subsystems which we do not process and skip at present. It needs to be checked and submitted the set of next patches to fix it. * If sysfs is not available, the fallback algorithm uses the "/dev" hierarchy by having a predefined device entry list. Tested on: * Fedora 19 Desktop Edition (64-bit) * Ubuntu 12.04.2 LTS (32-bit) with on-board (PnP) and pluggable (USB) devices using Qt4 and then Qt5. Change-Id: Ia242bb2ed81d17b6f826a187454bb9d2a12d40a9 Reviewed-by: Laszlo Papp <lpapp@kde.org> Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
-rw-r--r--src/serialport/qserialportinfo_unix.cpp230
1 files changed, 128 insertions, 102 deletions
diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp
index 1856c0e0..ea5a1b38 100644
--- a/src/serialport/qserialportinfo_unix.cpp
+++ b/src/serialport/qserialportinfo_unix.cpp
@@ -49,7 +49,7 @@
#ifndef Q_OS_MAC
-#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
+#ifdef HAVE_LIBUDEV
extern "C"
{
#include <libudev.h>
@@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE
#ifndef Q_OS_MAC
-#if !(defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV))
+#ifndef HAVE_LIBUDEV
static inline const QStringList& filtersOfDevices()
{
@@ -90,13 +90,135 @@ static inline const QStringList& filtersOfDevices()
return deviceFileNameFilterList;
}
-#endif
+static QStringList filteredDeviceFilePaths()
+{
+ QStringList result;
+
+ QDir deviceDir(QLatin1String("/dev"));
+ if (deviceDir.exists()) {
+ deviceDir.setNameFilters(filtersOfDevices());
+ deviceDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks);
+ QStringList deviceFilePaths;
+ foreach (const QFileInfo &deviceFileInfo, deviceDir.entryInfoList()) {
+ const QString deviceAbsoluteFilePath = deviceFileInfo.absoluteFilePath();
+ if (!deviceFilePaths.contains(deviceAbsoluteFilePath)) {
+ deviceFilePaths.append(deviceAbsoluteFilePath);
+ result.append(deviceAbsoluteFilePath);
+ }
+ }
+ }
+
+ return result;
+}
QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
{
QList<QSerialPortInfo> serialPortInfoList;
-#if defined (Q_OS_LINUX) && defined (HAVE_LIBUDEV)
+ bool sysfsEnabled = false;
+
+#ifdef Q_OS_LINUX
+
+ QDir ttySysClassDir(QLatin1String("/sys/class/tty"));
+ sysfsEnabled = ttySysClassDir.exists() && ttySysClassDir.isReadable();
+
+ if (sysfsEnabled) {
+ ttySysClassDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ foreach (const QFileInfo &fileInfo, ttySysClassDir.entryInfoList()) {
+ if (!fileInfo.isSymLink())
+ continue;
+
+ const QString targetPath = fileInfo.symLinkTarget();
+ const int lastIndexOfSlash = targetPath.lastIndexOf(QLatin1Char('/'));
+ if (lastIndexOfSlash == -1)
+ continue;
+
+ bool canAppendToList = true;
+ QSerialPortInfo serialPortInfo;
+
+ if (targetPath.contains(QLatin1String("pnp"))) {
+ // TODO: Implement me.
+ } else if (targetPath.contains(QLatin1String("platform"))) {
+ // Platform 'pseudo' bus for legacy device.
+ // Skip this devices because this type of subsystem does
+ // not include a real physical serial device.
+ canAppendToList = false;
+ } else if (targetPath.contains(QLatin1String("usb"))) {
+
+ QDir targetDir(targetPath);
+ targetDir.setFilter(QDir::Files | QDir::Readable);
+ targetDir.setNameFilters(QStringList(QLatin1String("uevent")));
+
+ do {
+ const QFileInfoList entryInfoList = targetDir.entryInfoList();
+ if (entryInfoList.isEmpty())
+ continue;
+
+ QFile uevent(entryInfoList.first().absoluteFilePath());
+ if (!uevent.open(QIODevice::ReadOnly | QIODevice::Text))
+ continue;
+
+ const QString ueventContent = QString::fromLatin1(uevent.readAll());
+
+ if (ueventContent.contains(QLatin1String("DEVTYPE=usb_device"))
+ && ueventContent.contains(QLatin1String("DRIVER=usb"))) {
+
+ QFile description(QFileInfo(targetDir, QLatin1String("product")).absoluteFilePath());
+ if (description.open(QIODevice::ReadOnly | QIODevice::Text))
+ serialPortInfo.d_ptr->description = QString::fromLatin1(description.readAll()).simplified();
+
+ QFile manufacturer(QFileInfo(targetDir, QLatin1String("manufacturer")).absoluteFilePath());
+ if (manufacturer.open(QIODevice::ReadOnly | QIODevice::Text))
+ serialPortInfo.d_ptr->manufacturer = QString::fromLatin1(manufacturer.readAll()).simplified();
+
+ QFile vendorIdentifier(QFileInfo(targetDir, QLatin1String("idVendor")).absoluteFilePath());
+ if (vendorIdentifier.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ serialPortInfo.d_ptr->vendorIdentifier = QString::fromLatin1(vendorIdentifier.readAll())
+ .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16);
+ }
+
+ QFile productIdentifier(QFileInfo(targetDir, QLatin1String("idProduct")).absoluteFilePath());
+ if (productIdentifier.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ serialPortInfo.d_ptr->productIdentifier = QString::fromLatin1(productIdentifier.readAll())
+ .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16);
+ }
+
+ break;
+ }
+ } while (targetDir.cdUp());
+
+ } else {
+ // unknown types of devices
+ canAppendToList = false;
+ }
+
+ if (canAppendToList) {
+ serialPortInfo.d_ptr->portName = targetPath.mid(lastIndexOfSlash + 1);
+ serialPortInfo.d_ptr->device = QSerialPortPrivate::portNameToSystemLocation(serialPortInfo.d_ptr->portName);
+ serialPortInfoList.append(serialPortInfo);
+ }
+ }
+ }
+
+#endif
+
+ if (!sysfsEnabled) {
+ foreach (const QString &deviceFilePath, filteredDeviceFilePaths()) {
+ QSerialPortInfo serialPortInfo;
+ serialPortInfo.d_ptr->device = deviceFilePath;
+ serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath);
+ serialPortInfoList.append(serialPortInfo);
+ }
+ }
+
+ return serialPortInfoList;
+}
+
+#else
+
+QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
+{
+ QList<QSerialPortInfo> serialPortInfoList;
// White list for devices without a parent
static const QString rfcommDeviceName(QLatin1String("rfcomm"));
@@ -202,107 +324,11 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
::udev_unref(udev);
}
-#elif defined (Q_OS_FREEBSD) && defined (HAVE_LIBUSB)
- // TODO: Implement me.
-#else
-
- QDir devDir(QLatin1String("/dev"));
- if (devDir.exists()) {
-
- devDir.setNameFilters(filtersOfDevices());
- devDir.setFilter(QDir::Files | QDir::System | QDir::NoSymLinks);
-
- QStringList foundDevices; // Found devices list.
-
- foreach (const QFileInfo &deviceFileInfo, devDir.entryInfoList()) {
- QString deviceFilePath = deviceFileInfo.absoluteFilePath();
- if (!foundDevices.contains(deviceFilePath)) {
- foundDevices.append(deviceFilePath);
-
- QSerialPortInfo serialPortInfo;
-
- serialPortInfo.d_ptr->device = deviceFilePath;
- serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath);
-
- bool canAppendToList = true;
-
-#if defined (Q_OS_LINUX)
-
- const QFileInfo ttySysClassFileInfo(QDir(QLatin1String("/sys/class/tty"))
- .absoluteFilePath(serialPortInfo.d_ptr->portName));
-
- const QString targetPath = ttySysClassFileInfo.isSymLink()
- ? ttySysClassFileInfo.symLinkTarget() : ttySysClassFileInfo.canonicalPath();
-
- if (targetPath.contains(QLatin1String("pnp"))) {
- // TODO: Implement me.
- } else if (targetPath.contains(QLatin1String("platform"))) {
- // Platform 'pseudo' bus for legacy device.
- // Skip this devices because this type of subsystem does
- // not include a real physical serial device.
- canAppendToList = false;
- } else if (targetPath.contains(QLatin1String("usb"))) {
-
- QDir targetDir(targetPath);
- targetDir.setFilter(QDir::Files | QDir::Readable);
- targetDir.setNameFilters(QStringList(QLatin1String("uevent")));
-
- do {
- const QFileInfoList entryInfoList = targetDir.entryInfoList();
- if (entryInfoList.isEmpty())
- continue;
-
- QFile uevent(entryInfoList.first().absoluteFilePath());
- if (!uevent.open(QIODevice::ReadOnly | QIODevice::Text))
- continue;
-
- const QString ueventContent(uevent.readAll());
-
- if (ueventContent.contains(QLatin1String("DEVTYPE=usb_device"))
- && ueventContent.contains(QLatin1String("DRIVER=usb"))) {
-
- QFile description(QFileInfo(targetDir, QLatin1String("product")).absoluteFilePath());
- if (description.open(QIODevice::ReadOnly | QIODevice::Text))
- serialPortInfo.d_ptr->description = QString(description.readAll()).simplified();
-
- QFile manufacturer(QFileInfo(targetDir, QLatin1String("manufacturer")).absoluteFilePath());
- if (manufacturer.open(QIODevice::ReadOnly | QIODevice::Text))
- serialPortInfo.d_ptr->manufacturer = QString(manufacturer.readAll()).simplified();
-
- QFile vendorIdentifier(QFileInfo(targetDir, QLatin1String("idVendor")).absoluteFilePath());
- if (vendorIdentifier.open(QIODevice::ReadOnly | QIODevice::Text)) {
- serialPortInfo.d_ptr->vendorIdentifier = QString::fromLatin1(vendorIdentifier.readAll())
- .toInt(&serialPortInfo.d_ptr->hasVendorIdentifier, 16);
- }
-
- QFile productIdentifier(QFileInfo(targetDir, QLatin1String("idProduct")).absoluteFilePath());
- if (productIdentifier.open(QIODevice::ReadOnly | QIODevice::Text)) {
- serialPortInfo.d_ptr->productIdentifier = QString::fromLatin1(productIdentifier.readAll())
- .toInt(&serialPortInfo.d_ptr->hasProductIdentifier, 16);
- }
-
- break;
- }
- } while (targetDir.cdUp());
-
- } else {
- // Unknown types of devices
- canAppendToList = false;
- }
-
-#endif
- if (canAppendToList)
- serialPortInfoList.append(serialPortInfo);
-
- }
- }
- }
-
-#endif
-
return serialPortInfoList;
}
+#endif
+
#endif // Q_OS_MAC
// common part