summaryrefslogtreecommitdiffstats
path: root/src/serialport/qserialportinfo_unix.cpp
diff options
context:
space:
mode:
authorDenis Shienkov <denis.shienkov@gmail.com>2013-07-19 00:23:41 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-08-20 08:54:27 +0200
commit4bdbbe4c87676ca94daae947ac5908d77966319b (patch)
tree6b02a6e10bf220958fd4b37f67d7aefc2d5f50d8 /src/serialport/qserialportinfo_unix.cpp
parente5494bca0edda46260aed0beebc62e51e04c55fa (diff)
Linux: Getting properties of USB devices if has no libudev
This decision is based on parse of contents of /sys directory. Many distros of Linux use /sys as a virtual file system to export data from the kernel to userspace applications. Thus this decision shall work only at those kernels in which are this feature is enabled at assembling. The initial path are received from the symlink "/sys/class/tty/<device name>", that points to the lowest kernel node with the device properties. For this path name is starting an analysis of matching to the keywords of subsystems (e.g. "pnp", "platform","usb" and so forth), which by implication characterize the type of the device. The device type is used to define a choice of further algorithm of passing each parent directory: * For "pnp" devices (standard onboard devices): The device info with empty properties is added directly to the resulting list. Because we still can not get desired properties for "pnp" devices. * For "platform" devices (pseudo terminals): Skip processing and don't add to the list. Because pseudo-ports aren't support by the library. * For "usb" devices: Pass each parental directory and look the "events" key file. From this file it is reading contents and to find in it the predetermined set of "magic" keywords. If all keywords are found, then we can be sure that current directory is the required. Contents of files "product", "manufacturer", "idVendor", "idProduct" is give requested properties of the device. * For other devices: Skip processing and don't add to the list. This decision was tested in ArchLinux x64 and Fedora 19 x64 with the onboard serial ports, USB PL2303 converter and USB modem ZTE MF180. Change-Id: I5a736a98656e8767b713af837f8b52557176c236 Reviewed-by: Laszlo Papp <lpapp@kde.org> Reviewed-by: Sergey Belyashov <Sergey.Belyashov@gmail.com>
Diffstat (limited to 'src/serialport/qserialportinfo_unix.cpp')
-rw-r--r--src/serialport/qserialportinfo_unix.cpp71
1 files changed, 68 insertions, 3 deletions
diff --git a/src/serialport/qserialportinfo_unix.cpp b/src/serialport/qserialportinfo_unix.cpp
index fec1b4a1..6344e052 100644
--- a/src/serialport/qserialportinfo_unix.cpp
+++ b/src/serialport/qserialportinfo_unix.cpp
@@ -224,10 +224,75 @@ QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
serialPortInfo.d_ptr->device = deviceFilePath;
serialPortInfo.d_ptr->portName = QSerialPortPrivate::portNameFromSystemLocation(deviceFilePath);
- // Get description, manufacturer, vendor identifier, product
- // identifier are not supported.
+ bool canAppendToList = true;
- serialPortInfoList.append(serialPortInfo);
+#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);
}
}