summaryrefslogtreecommitdiff
path: root/src/serialport/qserialportinfo_osx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/serialport/qserialportinfo_osx.cpp')
-rw-r--r--src/serialport/qserialportinfo_osx.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/serialport/qserialportinfo_osx.cpp b/src/serialport/qserialportinfo_osx.cpp
new file mode 100644
index 0000000..4e73025
--- /dev/null
+++ b/src/serialport/qserialportinfo_osx.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2011-2012 Denis Shienkov <denis.shienkov@gmail.com>
+** Copyright (C) 2011 Sergey Belyashov <Sergey.Belyashov@gmail.com>
+** Copyright (C) 2012 Laszlo Papp <lpapp@kde.org>
+** 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 "private/qcore_mac_p.h"
+
+#include <sys/param.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+
+#include <IOKit/serial/IOSerialKeys.h>
+#include <IOKit/storage/IOStorageDeviceCharacteristics.h> // for kIOPropertyProductNameKey
+#include <IOKit/usb/USB.h>
+#if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
+# include <IOKit/serial/ioss.h>
+#endif
+#include <IOKit/IOBSD.h>
+
+QT_BEGIN_NAMESPACE
+
+static QCFType<CFTypeRef> searchProperty(io_registry_entry_t ioRegistryEntry,
+ const QCFString &propertyKey)
+{
+ return ::IORegistryEntrySearchCFProperty(
+ ioRegistryEntry, kIOServicePlane, propertyKey, kCFAllocatorDefault, 0);
+}
+
+static QString searchStringProperty(io_registry_entry_t ioRegistryEntry,
+ const QCFString &propertyKey)
+{
+ const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey));
+ const CFStringRef ref = result.as<CFStringRef>();
+ if (ref && (::CFGetTypeID(ref) == ::CFStringGetTypeID()))
+ return QCFString::toQString(ref);
+ return QString();
+}
+
+static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry,
+ const QCFString &propertyKey,
+ bool &ok)
+{
+ const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey));
+ const CFNumberRef ref = result.as<CFNumberRef>();
+ quint16 value = 0;
+ ok = ref && (::CFGetTypeID(ref) == ::CFNumberGetTypeID())
+ && (::CFNumberGetValue(ref, kCFNumberShortType, &value) > 0);
+ return value;
+}
+
+static bool isCompleteInfo(const QSerialPortInfoPrivate &priv)
+{
+ return !priv.portName.isEmpty()
+ && !priv.device.isEmpty()
+ && !priv.manufacturer.isEmpty()
+ && !priv.description.isEmpty()
+ && !priv.serialNumber.isEmpty()
+ && priv.hasProductIdentifier
+ && priv.hasVendorIdentifier;
+}
+
+static QString deviceSystemLocation(io_registry_entry_t ioRegistryEntry)
+{
+ return searchStringProperty(ioRegistryEntry, QCFString(kIOCalloutDeviceKey));
+}
+
+static QString deviceDescription(io_registry_entry_t ioRegistryEntry)
+{
+ QString result = searchStringProperty(ioRegistryEntry, QCFString(kIOPropertyProductNameKey));
+ if (result.isEmpty())
+ result = searchStringProperty(ioRegistryEntry, QCFString(kUSBProductString));
+ if (result.isEmpty())
+ result = searchStringProperty(ioRegistryEntry, QCFString("BTName"));
+ return result;
+}
+
+static QString deviceManufacturer(io_registry_entry_t ioRegistryEntry)
+{
+ return searchStringProperty(ioRegistryEntry, QCFString(kUSBVendorString));
+}
+
+static QString deviceSerialNumber(io_registry_entry_t ioRegistryEntry)
+{
+ return searchStringProperty(ioRegistryEntry, QCFString(kUSBSerialNumberString));
+}
+
+static quint16 deviceVendorIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok)
+{
+ return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBVendorID), ok);
+}
+
+static quint16 deviceProductIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok)
+{
+ return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBProductID), ok);
+}
+
+static io_registry_entry_t parentSerialPortService(io_registry_entry_t currentSerialPortService)
+{
+ io_registry_entry_t result = 0;
+ ::IORegistryEntryGetParentEntry(currentSerialPortService, kIOServicePlane, &result);
+ ::IOObjectRelease(currentSerialPortService);
+ return result;
+}
+
+QList<QSerialPortInfo> QSerialPortInfo::availablePorts()
+{
+ CFMutableDictionaryRef serialPortDictionary = ::IOServiceMatching(kIOSerialBSDServiceValue);
+ if (!serialPortDictionary)
+ return QList<QSerialPortInfo>();
+
+ ::CFDictionaryAddValue(serialPortDictionary,
+ CFSTR(kIOSerialBSDTypeKey),
+ CFSTR(kIOSerialBSDAllTypes));
+
+ io_iterator_t serialPortIterator = 0;
+ if (::IOServiceGetMatchingServices(kIOMasterPortDefault, serialPortDictionary,
+ &serialPortIterator) != KERN_SUCCESS) {
+ return QList<QSerialPortInfo>();
+ }
+
+ QList<QSerialPortInfo> serialPortInfoList;
+
+ forever {
+ io_registry_entry_t serialPortService = ::IOIteratorNext(serialPortIterator);
+ if (!serialPortService)
+ break;
+
+ QSerialPortInfoPrivate priv;
+
+ forever {
+ if (priv.device.isEmpty()) {
+ priv.device = deviceSystemLocation(serialPortService);
+ if (!priv.device.isEmpty())
+ priv.portName = QSerialPortInfoPrivate::portNameFromSystemLocation(priv.device);
+ }
+
+ if (priv.description.isEmpty())
+ priv.description = deviceDescription(serialPortService);
+
+ if (priv.manufacturer.isEmpty())
+ priv.manufacturer = deviceManufacturer(serialPortService);
+
+ if (priv.serialNumber.isEmpty())
+ priv.serialNumber = deviceSerialNumber(serialPortService);
+
+ if (!priv.hasVendorIdentifier) {
+ priv.vendorIdentifier =
+ deviceVendorIdentifier(serialPortService,
+ priv.hasVendorIdentifier);
+ }
+
+ if (!priv.hasProductIdentifier) {
+ priv.productIdentifier =
+ deviceProductIdentifier(serialPortService,
+ priv.hasProductIdentifier);
+ }
+
+ if (isCompleteInfo(priv)) {
+ ::IOObjectRelease(serialPortService);
+ break;
+ }
+
+ serialPortService = parentSerialPortService(serialPortService);
+ if (!serialPortService)
+ break;
+ }
+
+ serialPortInfoList.append(priv);
+ }
+
+ ::IOObjectRelease(serialPortIterator);
+
+ 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