diff options
Diffstat (limited to 'src/serialport/qserialportinfo_mac.cpp')
-rw-r--r-- | src/serialport/qserialportinfo_mac.cpp | 337 |
1 files changed, 149 insertions, 188 deletions
diff --git a/src/serialport/qserialportinfo_mac.cpp b/src/serialport/qserialportinfo_mac.cpp index 2c2564e..03f95e7 100644 --- a/src/serialport/qserialportinfo_mac.cpp +++ b/src/serialport/qserialportinfo_mac.cpp @@ -43,6 +43,9 @@ #include "qserialportinfo.h" #include "qserialportinfo_p.h" +#include "qserialport_unix_p.h" + +#include "private/qcore_mac_p.h" #include <sys/param.h> @@ -59,235 +62,193 @@ QT_BEGIN_NAMESPACE -QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +static QCFType<CFTypeRef> searchProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey) { - QList<QSerialPortInfo> serialPortInfoList; - - static const int propertyCount = 7; + return ::IORegistryEntrySearchCFProperty( + ioRegistryEntry, kIOServicePlane, propertyKey, kCFAllocatorDefault, 0); +} +static QString searchStringProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey) +{ + const QCFString result(searchProperty(ioRegistryEntry, propertyKey).as<CFStringRef>()); + return QCFString::toQString(result); +} - ::CFMutableDictionaryRef matching = ::IOServiceMatching(kIOSerialBSDServiceValue); - if (!matching) - return serialPortInfoList; +static quint16 searchShortIntProperty(io_registry_entry_t ioRegistryEntry, + const QCFString &propertyKey, + bool &ok) +{ + const QCFType<CFTypeRef> result(searchProperty(ioRegistryEntry, propertyKey)); + quint16 value = 0; + ok = result.as<CFNumberRef>() + && (::CFNumberGetValue(result.as<CFNumberRef>(), kCFNumberShortType, &value) > 0); + return value; +} - ::CFDictionaryAddValue(matching, - CFSTR(kIOSerialBSDTypeKey), - CFSTR(kIOSerialBSDAllTypes)); +static bool isCompleteInfo(const QSerialPortInfo &portInfo) +{ + return !portInfo.portName().isEmpty() + && !portInfo.systemLocation().isEmpty() + && !portInfo.manufacturer().isEmpty() + && !portInfo.description().isEmpty() + && !portInfo.serialNumber().isEmpty() + && portInfo.hasProductIdentifier() + && portInfo.hasVendorIdentifier(); +} - io_iterator_t iter = 0; - kern_return_t kr = ::IOServiceGetMatchingServices(kIOMasterPortDefault, - matching, - &iter); +static QString devicePortName(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kIOTTYDeviceKey)); +} - if (kr != kIOReturnSuccess) - return serialPortInfoList; +static QString deviceSystemLocation(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kIOCalloutDeviceKey)); +} - io_registry_entry_t service; +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; +} - while ((service = ::IOIteratorNext(iter))) { +static QString deviceManufacturer(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kUSBVendorString)); +} - ::CFTypeRef device = 0; - ::CFTypeRef portName = 0; - ::CFTypeRef description = 0; - ::CFTypeRef manufacturer = 0; - ::CFTypeRef serialNumber = 0; - ::CFTypeRef vendorIdentifier = 0; - ::CFTypeRef productIdentifier = 0; +static QString deviceSerialNumber(io_registry_entry_t ioRegistryEntry) +{ + return searchStringProperty(ioRegistryEntry, QCFString(kUSBSerialNumberString)); +} - int matchingPropertiesCounter = 0; +static quint16 deviceVendorIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok) +{ + return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBVendorID), ok); +} - io_registry_entry_t entry = service; +static quint16 deviceProductIdentifier(io_registry_entry_t ioRegistryEntry, bool &ok) +{ + return searchShortIntProperty(ioRegistryEntry, QCFString(kUSBProductID), ok); +} - do { +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; +} - if (!device) { - device = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOCalloutDeviceKey), - kCFAllocatorDefault, - 0); - if (device) - ++matchingPropertiesCounter; - } +QList<QSerialPortInfo> QSerialPortInfo::availablePorts() +{ + CFMutableDictionaryRef serialPortDictionary = ::IOServiceMatching(kIOSerialBSDServiceValue); + if (!serialPortDictionary) + return QList<QSerialPortInfo>(); - if (!portName) { - portName = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOTTYDeviceKey), - kCFAllocatorDefault, - 0); - if (portName) - ++matchingPropertiesCounter; - } + ::CFDictionaryAddValue(serialPortDictionary, + CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDAllTypes)); - if (!description) { - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kIOPropertyProductNameKey), - kCFAllocatorDefault, - 0); - if (!description) - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBProductString), - kCFAllocatorDefault, - 0); - if (!description) - description = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR("BTName"), - kCFAllocatorDefault, - 0); - - if (description) - ++matchingPropertiesCounter; - } + io_iterator_t serialPortIterator = 0; + if (::IOServiceGetMatchingServices(kIOMasterPortDefault, serialPortDictionary, + &serialPortIterator) != KERN_SUCCESS) { + return QList<QSerialPortInfo>(); + } - if (!manufacturer) { - manufacturer = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBVendorString), - kCFAllocatorDefault, - 0); - if (manufacturer) - ++matchingPropertiesCounter; + QList<QSerialPortInfo> serialPortInfoList; - } + forever { + io_registry_entry_t serialPortService = ::IOIteratorNext(serialPortIterator); + if (!serialPortService) + break; - if (!serialNumber) { - serialNumber = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBSerialNumberString), - kCFAllocatorDefault, - 0); - if (serialNumber) - ++matchingPropertiesCounter; + QSerialPortInfo serialPortInfo; - } + forever { + if (serialPortInfo.portName().isEmpty()) + serialPortInfo.d_ptr->portName = devicePortName(serialPortService); + if (serialPortInfo.systemLocation().isEmpty()) + serialPortInfo.d_ptr->device = deviceSystemLocation(serialPortService); - if (!vendorIdentifier) { - vendorIdentifier = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBVendorID), - kCFAllocatorDefault, - 0); - if (vendorIdentifier) - ++matchingPropertiesCounter; + if (serialPortInfo.description().isEmpty()) + serialPortInfo.d_ptr->description = deviceDescription(serialPortService); - } + if (serialPortInfo.manufacturer().isEmpty()) + serialPortInfo.d_ptr->manufacturer = deviceManufacturer(serialPortService); - if (!productIdentifier) { - productIdentifier = - ::IORegistryEntrySearchCFProperty(entry, - kIOServicePlane, - CFSTR(kUSBProductID), - kCFAllocatorDefault, - 0); - if (productIdentifier) - ++matchingPropertiesCounter; + if (serialPortInfo.serialNumber().isEmpty()) + serialPortInfo.d_ptr->serialNumber = deviceSerialNumber(serialPortService); + if (!serialPortInfo.hasVendorIdentifier()) { + serialPortInfo.d_ptr->vendorIdentifier = + deviceVendorIdentifier(serialPortService, + serialPortInfo.d_ptr->hasVendorIdentifier); } - if (matchingPropertiesCounter == propertyCount) - break; - - kr = ::IORegistryEntryGetParentEntry(entry, kIOServicePlane, &entry); - - } while (kr == kIOReturnSuccess); - - (void) ::IOObjectRelease(entry); - - if (matchingPropertiesCounter > 0) { - - QSerialPortInfo serialPortInfo; - QByteArray buffer(MAXPATHLEN, 0); - - if (device) { - if (::CFStringGetCString(CFStringRef(device), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->device = QString::fromUtf8(buffer); - } - ::CFRelease(device); + if (!serialPortInfo.hasProductIdentifier()) { + serialPortInfo.d_ptr->productIdentifier = + deviceProductIdentifier(serialPortService, + serialPortInfo.d_ptr->hasProductIdentifier); } - if (portName) { - if (::CFStringGetCString(CFStringRef(portName), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->portName = QString::fromUtf8(buffer); - } - ::CFRelease(portName); + if (isCompleteInfo(serialPortInfo)) { + ::IOObjectRelease(serialPortService); + break; } - if (description) { - if (::CFStringGetCString(CFStringRef(description), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->description = QString::fromUtf8(buffer); - } - ::CFRelease(description); - } + serialPortService = parentSerialPortService(serialPortService); + if (!serialPortService) + break; + } - if (manufacturer) { - if (::CFStringGetCString(CFStringRef(manufacturer), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->manufacturer = QString::fromUtf8(buffer); - } - ::CFRelease(manufacturer); - } + serialPortInfoList.append(serialPortInfo); + } - if (serialNumber) { - if (::CFStringGetCString(CFStringRef(serialNumber), - buffer.data(), - buffer.size(), - kCFStringEncodingUTF8)) { - serialPortInfo.d_ptr->serialNumber = QString::fromUtf8(buffer); - } - ::CFRelease(serialNumber); - } + ::IOObjectRelease(serialPortIterator); - quint16 value = 0; + return serialPortInfoList; +} - if (vendorIdentifier) { - serialPortInfo.d_ptr->hasVendorIdentifier = ::CFNumberGetValue(CFNumberRef(vendorIdentifier), kCFNumberIntType, &value); - if (serialPortInfo.d_ptr->hasVendorIdentifier) - serialPortInfo.d_ptr->vendorIdentifier = value; +QList<qint32> QSerialPortInfo::standardBaudRates() +{ + return QSerialPortPrivate::standardBaudRates(); +} - ::CFRelease(vendorIdentifier); - } +bool QSerialPortInfo::isBusy() const +{ + QString lockFilePath = serialPortLockFilePath(portName()); + if (lockFilePath.isEmpty()) + return false; - if (productIdentifier) { - serialPortInfo.d_ptr->hasProductIdentifier = ::CFNumberGetValue(CFNumberRef(productIdentifier), kCFNumberIntType, &value); - if (serialPortInfo.d_ptr->hasProductIdentifier) - serialPortInfo.d_ptr->productIdentifier = value; + QFile reader(lockFilePath); + if (!reader.open(QIODevice::ReadOnly)) + return false; - ::CFRelease(productIdentifier); - } + QByteArray pidLine = reader.readLine(); + pidLine.chop(1); + if (pidLine.isEmpty()) + return false; - serialPortInfoList.append(serialPortInfo); - } + qint64 pid = pidLine.toLongLong(); - (void) ::IOObjectRelease(service); - } + if (pid && (::kill(pid, 0) == -1) && (errno == ESRCH)) + return false; // PID doesn't exist anymore - (void) ::IOObjectRelease(iter); + return true; +} - return serialPortInfoList; +bool QSerialPortInfo::isValid() const +{ + QFile f(systemLocation()); + return f.exists(); } QT_END_NAMESPACE |