diff options
author | Denis Shienkov <denis.shienkov@gmail.com> | 2013-07-19 00:23:41 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-08-20 08:54:27 +0200 |
commit | 4bdbbe4c87676ca94daae947ac5908d77966319b (patch) | |
tree | 6b02a6e10bf220958fd4b37f67d7aefc2d5f50d8 /src/serialport/qserialportinfo_unix.cpp | |
parent | e5494bca0edda46260aed0beebc62e51e04c55fa (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.cpp | 71 |
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); } } |