diff --git a/src/solid/devices/CMakeLists.txt b/src/solid/devices/CMakeLists.txt index bd4153e..fcc1319 100644 --- a/src/solid/devices/CMakeLists.txt +++ b/src/solid/devices/CMakeLists.txt @@ -1,180 +1,180 @@ include (CheckCXXSourceCompiles) if(WIN32) add_definitions(-DYY_NO_UNISTD_H) endif() if(MSVC OR (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Intel")) check_cxx_source_compiles("int main() { __asm { pxor mm0, mm0 }; }" HAVE_X86_MMX) check_cxx_source_compiles("int main() { __asm { xorps xmm0, xmm0 }; }" HAVE_X86_SSE) check_cxx_source_compiles("int main() { __asm { xorpd xmm0, xmm0 }; }" HAVE_X86_SSE2) check_cxx_source_compiles("int main() { __asm { femms }; }" HAVE_X86_3DNOW) else() check_cxx_source_compiles(" #ifdef __SUNPRO_CC #define __asm__ asm #endif int main() { __asm__(\"pxor %mm0, %mm0\") ; }" HAVE_X86_MMX) check_cxx_source_compiles(" #ifdef __SUNPRO_CC #define __asm__ asm #endif int main() { __asm__(\"xorps %xmm0, %xmm0\"); }" HAVE_X86_SSE) check_cxx_source_compiles(" #ifdef __SUNPRO_CC #define __asm__ asm #endif int main() { __asm__(\"xorpd %xmm0, %xmm0\"); }" HAVE_X86_SSE2) check_cxx_source_compiles(" #ifdef __SUNPRO_CC #define __asm__ asm #endif int main() { __asm__(\"femms\"); }" HAVE_X86_3DNOW) endif() check_cxx_source_compiles(" #ifdef __SUNPRO_CC #define __asm__ asm #endif int main() { __asm__(\"mtspr 256, %0; vand %%v0, %%v0, %%v0\" : : \"r\"(-1) ); }" HAVE_PPC_ALTIVEC) configure_file(devices/config-processor.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-processor.h ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/devices/ ${CMAKE_CURRENT_SOURCE_DIR}/devices/frontend/ ${CMAKE_CURRENT_BINARY_DIR}) set(solid_LIB_SRCS ${solid_LIB_SRCS} devices/managerbase.cpp devices/solidnamespace.cpp devices/predicateparse.cpp devices/frontend/device.cpp devices/frontend/devicemanager.cpp devices/frontend/deviceinterface.cpp devices/frontend/genericinterface.cpp devices/frontend/processor.cpp devices/frontend/block.cpp devices/frontend/storagedrive.cpp devices/frontend/opticaldrive.cpp devices/frontend/storagevolume.cpp devices/frontend/opticaldisc.cpp devices/frontend/storageaccess.cpp devices/frontend/camera.cpp devices/frontend/portablemediaplayer.cpp devices/frontend/networkshare.cpp devices/frontend/battery.cpp devices/frontend/predicate.cpp devices/ifaces/battery.cpp devices/ifaces/block.cpp devices/ifaces/camera.cpp devices/ifaces/opticaldrive.cpp devices/ifaces/device.cpp devices/ifaces/deviceinterface.cpp devices/ifaces/devicemanager.cpp devices/ifaces/genericinterface.cpp devices/ifaces/networkshare.cpp devices/ifaces/opticaldisc.cpp devices/ifaces/portablemediaplayer.cpp devices/ifaces/processor.cpp devices/ifaces/storagedrive.cpp devices/ifaces/storagevolume.cpp devices/ifaces/storageaccess.cpp devices/backends/shared/rootdevice.cpp devices/backends/shared/cpufeatures.cpp ) bison_target(SolidParser devices/predicate_parser.y ${CMAKE_CURRENT_BINARY_DIR}/predicate_parser.c COMPILE_FLAGS "-p Solid -d -b predicate_parser" ) set_property(SOURCE ${CMAKE_CURRENT_BINARY_DIR}/predicate_parser.h PROPERTY SKIP_AUTOMOC TRUE) # don't run automoc on this file flex_target(SolidLexer devices/predicate_lexer.l ${CMAKE_CURRENT_BINARY_DIR}/predicate_lexer.c COMPILE_FLAGS "-P Solid" ) add_flex_bison_dependency(SolidLexer SolidParser) list(APPEND solid_LIB_SRCS ${BISON_SolidParser_OUTPUTS} ${FLEX_SolidLexer_OUTPUTS}) include(devices/backends/fakehw/CMakeLists.txt) if(NOT WIN32 AND NOT APPLE) if (CMAKE_SYSTEM_NAME MATCHES FreeBSD) option(EXPERIMENTAL_BSDISKS "Use UDisks2/bsdisks backend instead of HAL to manage disk devices" OFF) else () set(EXPERIMENTAL_BSDISKS FALSE) endif() if ( UDEV_FOUND ) message(STATUS "Building Solid UDev backend." ) include(devices/backends/udev/CMakeLists.txt) endif() message(STATUS "Building Solid UPower backend." ) include(devices/backends/upower/CMakeLists.txt) # FIXME: this should work on more Unix systems if ((CMAKE_SYSTEM_NAME MATCHES Linux AND UDEV_FOUND) OR EXPERIMENTAL_BSDISKS) message(STATUS "Building Solid UDisks2 backend." ) include(devices/backends/udisks2/CMakeLists.txt) endif () message(STATUS "Building Solid fstab backend." ) include(devices/backends/fstab/CMakeLists.txt) if (NOT CMAKE_SYSTEM_NAME MATCHES Linux) message(STATUS "Building Solid HAL backend." ) include(devices/backends/hal/CMakeLists.txt) endif() endif() include(CheckIncludeFiles) include(CheckFunctionExists) include(CheckCXXSourceCompiles) #Needed for the fstab backend check_include_files(mntent.h HAVE_MNTENT_H) check_include_files(sys/types.h HAVE_SYS_TYPES_H) check_include_files(sys/param.h HAVE_SYS_PARAM_H) check_include_files("stdio.h;sys/mnttab.h" HAVE_SYS_MNTTAB_H) check_include_files("sys/param.h;sys/mount.h" HAVE_SYS_MOUNT_H) check_function_exists(getmntinfo HAVE_GETMNTINFO) check_function_exists(setmntent HAVE_SETMNTENT) check_cxx_source_compiles(" #include #include int main(){ struct statvfs *mntbufp; int flags; return getmntinfo(&mntbufp, flags); } " GETMNTINFO_USES_STATVFS ) configure_file(devices/config-solid.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-solid.h ) if(APPLE) find_package(IOKit REQUIRED) message(STATUS "-- Building Solid IOKit backend." ) include(devices/backends/iokit/CMakeLists.txt) endif() if(WIN32) message(STATUS "-- Building Solid Windows backend." ) include(devices/backends/win/CMakeLists.txt) endif() set(solid_OPTIONAL_LIBS) if(WIN32) set(solid_OPTIONAL_LIBS ${solid_OPTIONAL_LIBS} Qt5::Network setupapi) set(solid_OPTIONAL_LIBS ${solid_OPTIONAL_LIBS} setupapi) endif() if(APPLE) - set(solid_OPTIONAL_LIBS ${IOKIT_LIBRARY}) + set(solid_OPTIONAL_LIBS ${IOKIT_LIBRARY} "-framework DiskArbitration") endif() if ( UDEV_FOUND ) set(solid_OPTIONAL_LIBS ${solid_OPTIONAL_LIBS} ${UDEV_LIBS}) endif () diff --git a/src/solid/devices/backends/iokit/CMakeLists.txt b/src/solid/devices/backends/iokit/CMakeLists.txt index dcbc666..dcc9e5f 100644 --- a/src/solid/devices/backends/iokit/CMakeLists.txt +++ b/src/solid/devices/backends/iokit/CMakeLists.txt @@ -1,9 +1,20 @@ +include_directories( + ${Qt5Core_PRIVATE_INCLUDE_DIRS} +) + set(solid_LIB_SRCS ${solid_LIB_SRCS} devices/backends/iokit/iokitmanager.cpp devices/backends/iokit/iokitdevice.cpp devices/backends/iokit/cfhelper.cpp + devices/backends/iokit/dadictionary.cpp devices/backends/iokit/iokitdeviceinterface.cpp devices/backends/iokit/iokitgenericinterface.cpp devices/backends/iokit/iokitprocessor.cpp devices/backends/iokit/iokitbattery.cpp -) \ No newline at end of file + devices/backends/iokit/iokitblock.cpp + devices/backends/iokit/iokitstorage.cpp + devices/backends/iokit/iokitvolume.cpp + devices/backends/iokit/iokitstorageaccess.cpp + devices/backends/iokit/iokitopticaldrive.cpp + devices/backends/iokit/iokitopticaldisc.cpp +) diff --git a/src/solid/devices/backends/iokit/cfhelper.cpp b/src/solid/devices/backends/iokit/cfhelper.cpp index cb33bd3..e78131f 100644 --- a/src/solid/devices/backends/iokit/cfhelper.cpp +++ b/src/solid/devices/backends/iokit/cfhelper.cpp @@ -1,177 +1,195 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include #include #include #include #include #include #include +#include + /* helper classes to convert from CF types to Qt */ static QString q_toString(const CFStringRef &str) { CFIndex length = CFStringGetLength(str); QVarLengthArray buffer(length); CFRange range = { 0, length }; CFStringGetCharacters(str, range, buffer.data()); return QString(reinterpret_cast(buffer.data()), length); } template static inline T convertCFNumber(const CFNumberRef &num, CFNumberType type) { T n; CFNumberGetValue(num, type, &n); return n; } static QVariant q_toVariant(const CFTypeRef &obj) { const CFTypeID typeId = CFGetTypeID(obj); if (typeId == CFStringGetTypeID()) { return QVariant(q_toString(static_cast(obj))); } if (typeId == CFNumberGetTypeID()) { const CFNumberRef num = static_cast(obj); const CFNumberType type = CFNumberGetType(num); switch (type) { case kCFNumberSInt8Type: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberSInt16Type: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberSInt32Type: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberSInt64Type: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberCharType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberShortType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberIntType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberLongType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberLongLongType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberFloatType: return qVariantFromValue(convertCFNumber(num, type)); case kCFNumberDoubleType: return qVariantFromValue(convertCFNumber(num, type)); default: if (CFNumberIsFloatType(num)) { return qVariantFromValue(convertCFNumber(num, kCFNumberDoubleType)); } return qVariantFromValue(convertCFNumber(num, kCFNumberLongLongType)); } } if (typeId == CFDateGetTypeID()) { QDateTime dt; dt.setTime_t(uint(kCFAbsoluteTimeIntervalSince1970)); return dt.addSecs(int(CFDateGetAbsoluteTime(static_cast(obj)))); } if (typeId == CFDataGetTypeID()) { const CFDataRef cfdata = static_cast(obj); return QByteArray(reinterpret_cast(CFDataGetBytePtr(cfdata)), CFDataGetLength(cfdata)); } if (typeId == CFBooleanGetTypeID()) { return QVariant(bool(CFBooleanGetValue(static_cast(obj)))); } if (typeId == CFArrayGetTypeID()) { const CFArrayRef cfarray = static_cast(obj); QList list; CFIndex size = CFArrayGetCount(cfarray); bool metNonString = false; for (CFIndex i = 0; i < size; ++i) { QVariant value = q_toVariant(CFArrayGetValueAtIndex(cfarray, i)); if (value.type() != QVariant::String) { metNonString = true; } list << value; } if (metNonString) { return list; } else { return QVariant(list).toStringList(); } } if (typeId == CFDictionaryGetTypeID()) { const CFDictionaryRef cfdict = static_cast(obj); const CFTypeID arrayTypeId = CFArrayGetTypeID(); int size = int(CFDictionaryGetCount(cfdict)); QVarLengthArray keys(size); QVarLengthArray values(size); CFDictionaryGetKeysAndValues(cfdict, keys.data(), values.data()); QMultiMap map; for (int i = 0; i < size; ++i) { QString key = q_toString(static_cast(keys[i])); if (CFGetTypeID(values[i]) == arrayTypeId) { const CFArrayRef cfarray = static_cast(values[i]); CFIndex arraySize = CFArrayGetCount(cfarray); for (CFIndex j = arraySize - 1; j >= 0; --j) { map.insert(key, q_toVariant(CFArrayGetValueAtIndex(cfarray, j))); } } else { map.insert(key, q_toVariant(values[i])); } } return map; } return QVariant(); } QMap q_toVariantMap(const CFMutableDictionaryRef &dict) { Q_ASSERT(dict); QMap result; const int count = CFDictionaryGetCount(dict); QVarLengthArray keys(count); QVarLengthArray values(count); CFDictionaryGetKeysAndValues(dict, const_cast(keys.data()), const_cast(values.data())); for (int i = 0; i < count; ++i) { const QString key = q_toString((CFStringRef)keys[i]); const QVariant value = q_toVariant((CFTypeRef)values[i]); result[key] = value; } return result; } +bool q_sysctlbyname(const char *name, QString &result) +{ + char *property = nullptr; + size_t size = 0; + int error = 0; + if (name && sysctlbyname(name, nullptr, &size, nullptr, 0) == 0 && size > 0) { + property = new char [size]; + error = sysctlbyname(name, property, &size, nullptr, 0); + if (!error) { + result = QLatin1String(property); + } + delete[] property; + } + return !error; +} diff --git a/src/solid/devices/backends/iokit/dadictionary.cpp b/src/solid/devices/backends/iokit/dadictionary.cpp new file mode 100644 index 0000000..af9d3de --- /dev/null +++ b/src/solid/devices/backends/iokit/dadictionary.cpp @@ -0,0 +1,98 @@ +/* + Copyright 2018 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "dadictionary_p.h" + +using namespace Solid::Backends::IOKit; + +DADictionary::DADictionary(const IOKitDevice *device) + : device(device) + , daDict(nullptr) +{ + daSession = DASessionCreate(kCFAllocatorDefault); + if (daSession) { + const QString devName = device->property(QStringLiteral("BSD Name")).toString(); + daRef = DADiskCreateFromBSDName(kCFAllocatorDefault, daSession, devName.toStdString().c_str()); + } else { + daRef = nullptr; + } +} + +DADictionary::~DADictionary() +{ + releaseDict(); + if (daRef) { + CFRelease(daRef); + daRef = nullptr; + } + if (daSession) { + CFRelease(daSession); + daSession = nullptr; + } +} + +bool DADictionary::getDict() +{ + if (daRef) { + daDict = DADiskCopyDescription(daRef); + } + return daRef != nullptr; +} + +void DADictionary::releaseDict() +{ + if (daDict) { + CFRelease(daDict); + daDict = nullptr; + } +} + +const QString DADictionary::stringForKey(const CFStringRef key) +{ + QString ret; + if (getDict()) { + ret = QString::fromCFString((const CFStringRef) CFDictionaryGetValue(daDict, key)); + } + releaseDict(); + return ret; +} + +CFURLRef DADictionary::cfUrLRefForKey(const CFStringRef key) +{ + CFURLRef ret = nullptr; + if (getDict()) { + ret = (const CFURLRef) CFDictionaryGetValue(daDict, key); + } + // we cannot release the dictionary here, or else we'd need to + // copy the CFURLRef and oblige our caller to release the return value. + return ret; +} + +bool DADictionary::boolForKey(const CFStringRef key, bool &value) +{ + if (getDict()) { + const CFBooleanRef boolRef = (const CFBooleanRef) CFDictionaryGetValue(daDict, key); + if (boolRef) { + value = CFBooleanGetValue(boolRef); + } + return boolRef != nullptr; + } + return false; +} diff --git a/src/solid/devices/backends/iokit/iokitdeviceinterface.h b/src/solid/devices/backends/iokit/dadictionary_p.h similarity index 58% copy from src/solid/devices/backends/iokit/iokitdeviceinterface.h copy to src/solid/devices/backends/iokit/dadictionary_p.h index 38eacf4..28cfc7f 100644 --- a/src/solid/devices/backends/iokit/iokitdeviceinterface.h +++ b/src/solid/devices/backends/iokit/dadictionary_p.h @@ -1,51 +1,58 @@ /* - Copyright 2009 Harald Fernengel + Copyright 2018 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ -#ifndef SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H -#define SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H +#ifndef SOLID_BACKENDS_IOKIT_DADICTIONARY_H +#define SOLID_BACKENDS_IOKIT_DADICTIONARY_H + +#include -#include #include "iokitdevice.h" -#include -#include +#include +#include namespace Solid { namespace Backends { namespace IOKit { -class DeviceInterface : public QObject, virtual public Solid::Ifaces::DeviceInterface +class DADictionary { - Q_OBJECT - Q_INTERFACES(Solid::Ifaces::DeviceInterface) public: - DeviceInterface(IOKitDevice *device); - virtual ~DeviceInterface(); - -protected: - IOKitDevice *m_device; + DADictionary(const IOKitDevice *device); + virtual ~DADictionary(); + + bool getDict(); + void releaseDict(); + const QString stringForKey(const CFStringRef key); + CFURLRef cfUrLRefForKey(const CFStringRef key); + bool boolForKey(const CFStringRef key, bool &value); + + const IOKitDevice *device; + DASessionRef daSession; + DADiskRef daRef; + CFDictionaryRef daDict; }; } } } -#endif // SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H +#endif // SOLID_BACKENDS_IOKIT_DADICTIONARY_H diff --git a/src/solid/devices/backends/iokit/iokitbattery.cpp b/src/solid/devices/backends/iokit/iokitbattery.cpp index 04646cc..69391aa 100644 --- a/src/solid/devices/backends/iokit/iokitbattery.cpp +++ b/src/solid/devices/backends/iokit/iokitbattery.cpp @@ -1,91 +1,173 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitbattery.h" #include "iokitdevice.h" -#include +#include // TODO - emit the signals using namespace Solid::Backends::IOKit; Battery::Battery(IOKitDevice *device) : DeviceInterface(device) { } Battery::~Battery() { +} + +// properties: QMap(("AdapterInfo", QVariant(int, 0)) +// ("Amperage", QVariant(int, 0)) +// ("AvgTimeToEmpty", QVariant(int, 65535)) +// ("AvgTimeToFull", QVariant(int, 65535)) +// ("BatteryInstalled", QVariant(bool, true)) +// ("BatteryInvalidWakeSeconds", QVariant(int, 30)) +// ("BatterySerialNumber", QVariant(QString, "W01286PEED3BA")) +// ("BootPathUpdated", QVariant(int, 1501532930)) +// ("CellVoltage", QVariant(QVariantList, (QVariant(int, 4136), QVariant(int, 4134), QVariant(int, 4134), QVariant(int, 0)))) +// ("CurrentCapacity", QVariant(int, 5552)) +// ("CycleCount", QVariant(int, 16)) +// ("DesignCapacity", QVariant(int, 5770)) +// ("DesignCycleCount", QVariant(int, 1000)) +// ("DeviceName", QVariant(QString, "bq20z451")) +// ("ExternalChargeCapable", QVariant(bool, true)) +// ("ExternalConnected", QVariant(bool, true)) +// ("FirmwareSerialNumber", QVariant(int, 48)) +// ("FullPathUpdated", QVariant(int, 1502790621)) +// ("FullyCharged", QVariant(bool, true)) +// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable")) +// ("InstantAmperage", QVariant(int, 0)) +// ("InstantTimeToEmpty", QVariant(int, 65535)) +// ("IsCharging", QVariant(bool, false)) +// ("LegacyBatteryInfo", QVariant(QVariantMap, QMap(("Amperage", QVariant(int, 0)) +// ("Capacity", QVariant(int, 5814)) +// ("Current", QVariant(int, 5552)) +// ("Cycle Count", QVariant(int, 16)) +// ("Flags", QVariant(int, 5)) +// ("Voltage", QVariant(int, 12403))))) +// ("Location", QVariant(int, 0)) +// ("ManufactureDate", QVariant(int, 16106)) +// ("Manufacturer", QVariant(QString, "SMP")) +// ("ManufacturerData", QVariant(QByteArray, "\x00\x00\x00\x00\x02\x01\x00\n\x01X\x00\x00\x02K6c\x03""00A\x03""ATL\x00\x12\x00\x00")) +// ("MaxCapacity", QVariant(int, 5814)) +// ("MaxErr", QVariant(int, 1)) +// ("OperationStatus", QVariant(int, 58435)) +// ("PackReserve", QVariant(int, 200)) +// ("PermanentFailureStatus", QVariant(int, 0)) +// ("PostChargeWaitSeconds", QVariant(int, 120)) +// ("PostDischargeWaitSeconds", QVariant(int, 120)) +// ("Temperature", QVariant(int, 2965)) +// ("TimeRemaining", QVariant(int, 0)) +// ("UserVisiblePathUpdated", QVariant(int, 1502790679)) +// ("Voltage", QVariant(int, 12403)) +// ("className", QVariant(QString, "AppleSmartBattery"))) + +qlonglong Battery::timeToEmpty() const +{ + if (chargeState() != Solid::Battery::Charging) { + int t = m_device->property(QStringLiteral("AvgTimeToEmpty")).toInt(); + return t == 65535 ? -1 : t * 60; + } + return -1; +} + +qlonglong Battery::timeToFull() const +{ + if (chargeState() == Solid::Battery::Charging) { + int t = m_device->property(QStringLiteral("AvgTimeToFull")).toInt(); + return t == 65535 ? -1 : t * 60; + } + return -1; +} + +double Battery::voltage() const +{ + return m_device->property(QStringLiteral("Voltage")).toInt() / 1000.0; +} + +double Battery::temperature() const +{ + return m_device->property(QStringLiteral("Temperature")).toInt() / 100.0; +} + +QString Battery::serial() const +{ + return m_device->property(QStringLiteral("BatterySerialNumber")).toString(); } bool Battery::isPresent() const { - return m_device->property(QLatin1String("ExternalConnected")).toBool(); + return m_device->property(QStringLiteral("ExternalConnected")).toBool(); } Solid::Battery::BatteryType Battery::type() const { - // TODO - how to figure that one out? - return Solid::Battery::UnknownBattery; + // TODO - how to figure that one out? Just presume we're + // only called with the main battery. + return Solid::Battery::PrimaryBattery; } int Battery::chargePercent() const { - if (m_device->property(QLatin1String("FullyCharged")).toBool()) { - return 100; - } - - int maxCapacity = m_device->property(QLatin1String("MaxCapacity")).toInt(); + // always calculate since FullyCharged remains true down to 92% or so. + int maxCapacity = m_device->property(QStringLiteral("MaxCapacity")).toInt(); if (maxCapacity == 0) { return 0; // prevent divide by 0 } - return m_device->property(QLatin1String("CurrentCapacity")).toInt() / maxCapacity; + return int(m_device->property(QStringLiteral("CurrentCapacity")).toInt() * 100.0 / maxCapacity + 0.5); } int Battery::capacity() const { - // TODO + if (m_device->iOKitPropertyExists(QStringLiteral("PermanentFailureStatus")) + && m_device->property(QStringLiteral("PermanentFailureStatus")).toInt()) { + return 0; + } return 100; } bool Battery::isRechargeable() const { - return m_device->property(QLatin1String("DesignCycleCount")).toInt() > 1; + return m_device->property(QStringLiteral("CycleCount")).toInt() > 1; } bool Battery::isPowerSupply() const { - // TODO - return true; + return m_device->iOKitPropertyExists(QStringLiteral("BatteryInstalled")) + ? m_device->property(QStringLiteral("BatteryInstalled")).toBool() + : true; } Solid::Battery::ChargeState Battery::chargeState() const { - if (m_device->property(QLatin1String("IsCharging")).toBool()) { + if (m_device->property(QStringLiteral("IsCharging")).toBool()) { return Solid::Battery::Charging; } - if (m_device->property(QLatin1String("FullyCharged")).toBool()) { - return Solid::Battery::NoCharge; + if (m_device->property(QStringLiteral("FullyCharged")).toBool()) { + return Solid::Battery::FullyCharged; } return Solid::Battery::Discharging; } diff --git a/src/solid/devices/backends/iokit/iokitbattery.h b/src/solid/devices/backends/iokit/iokitbattery.h index 19224a7..5aff592 100644 --- a/src/solid/devices/backends/iokit/iokitbattery.h +++ b/src/solid/devices/backends/iokit/iokitbattery.h @@ -1,93 +1,94 @@ /* Copyright 2009 Harald Fernengel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SOLID_BACKENDS_IOKIT_BATTERY_H #define SOLID_BACKENDS_IOKIT_BATTERY_H #include #include "iokitdeviceinterface.h" namespace Solid { namespace Backends { namespace IOKit { class IOKitDevice; class Battery : public DeviceInterface, virtual public Solid::Ifaces::Battery { Q_OBJECT Q_INTERFACES(Solid::Ifaces::Battery) public: Battery(IOKitDevice *device); virtual ~Battery(); - bool isPresent() const; - Solid::Battery::BatteryType type() const; + bool isPresent() const Q_DECL_OVERRIDE; + Solid::Battery::BatteryType type() const Q_DECL_OVERRIDE; - int chargePercent() const; - int capacity() const; + int chargePercent() const Q_DECL_OVERRIDE; + int capacity() const Q_DECL_OVERRIDE; - bool isRechargeable() const; - bool isPowerSupply() const; + bool isRechargeable() const Q_DECL_OVERRIDE; + bool isPowerSupply() const Q_DECL_OVERRIDE; - Solid::Battery::ChargeState chargeState() const; + Solid::Battery::ChargeState chargeState() const Q_DECL_OVERRIDE; + + qlonglong timeToEmpty() const Q_DECL_OVERRIDE; + qlonglong timeToFull() const Q_DECL_OVERRIDE; + double voltage() const Q_DECL_OVERRIDE; + double temperature() const Q_DECL_OVERRIDE; + QString serial() const Q_DECL_OVERRIDE; // ### the ones below are TODO - qlonglong timeToEmpty() const { return 0; } - qlonglong timeToFull() const { return 0; } - Solid::Battery::Technology technology() const { return Solid::Battery::UnknownTechnology; } - double energy() const { return 0.0; } - double energyFull() const { return 0.0; } - double energyFullDesign() const { return 0.0; } - double energyRate() const { return 0.0; } - double voltage() const { return 0.0; } - double temperature() const { return 0.0; } - - bool isRecalled() const { return false; } - QString recallVendor() const { return QString(); } - QString recallUrl() const { return QString(); } - QString serial() const { return QString(); } - - qlonglong remainingTime() const { return -1; } + Solid::Battery::Technology technology() const Q_DECL_OVERRIDE { return Solid::Battery::UnknownTechnology; } + double energy() const Q_DECL_OVERRIDE { return 0.0; } + double energyFull() const Q_DECL_OVERRIDE { return 0.0; } + double energyFullDesign() const Q_DECL_OVERRIDE { return 0.0; } + double energyRate() const Q_DECL_OVERRIDE { return 0.0; } + + bool isRecalled() const Q_DECL_OVERRIDE { return false; } + QString recallVendor() const Q_DECL_OVERRIDE { return QString(); } + QString recallUrl() const Q_DECL_OVERRIDE { return QString(); } + + qlonglong remainingTime() const Q_DECL_OVERRIDE { return -1; } Q_SIGNALS: - void energyChanged(double energy, const QString &udi); - void energyFullChanged(double energyFull, const QString &udi); - void energyFullDesignChanged(double energyFullDesign, const QString &udi); - void energyRateChanged(double energyRate, const QString &udi); - void chargePercentChanged(int value, const QString &udi); - void capacityChanged(int value, const QString &udi); - void chargeStateChanged(int newState, const QString &udi); - void presentStateChanged(bool newState, const QString &udi); - void powerSupplyStateChanged(bool newState, const QString &udi); - void timeToEmptyChanged(qlonglong time, const QString &udi); - void timeToFullChanged(qlonglong time, const QString &udi); - void temperatureChanged(double temperature, const QString &udi); - void voltageChanged(double voltage, const QString &udi); - void remainingTimeChanged(qlonglong time, const QString &udi); + void energyChanged(double energy, const QString &udi) Q_DECL_OVERRIDE; + void energyFullChanged(double energyFull, const QString &udi) Q_DECL_OVERRIDE; + void energyFullDesignChanged(double energyFullDesign, const QString &udi) Q_DECL_OVERRIDE; + void energyRateChanged(double energyRate, const QString &udi) Q_DECL_OVERRIDE; + void chargePercentChanged(int value, const QString &udi) Q_DECL_OVERRIDE; + void capacityChanged(int value, const QString &udi) Q_DECL_OVERRIDE; + void chargeStateChanged(int newState, const QString &udi) Q_DECL_OVERRIDE; + void presentStateChanged(bool newState, const QString &udi) Q_DECL_OVERRIDE; + void powerSupplyStateChanged(bool newState, const QString &udi) Q_DECL_OVERRIDE; + void timeToEmptyChanged(qlonglong time, const QString &udi) Q_DECL_OVERRIDE; + void timeToFullChanged(qlonglong time, const QString &udi) Q_DECL_OVERRIDE; + void temperatureChanged(double temperature, const QString &udi) Q_DECL_OVERRIDE; + void voltageChanged(double voltage, const QString &udi) Q_DECL_OVERRIDE; + void remainingTimeChanged(qlonglong time, const QString &udi) Q_DECL_OVERRIDE; }; } } } #endif // SOLID_BACKENDS_IOKIT_BATTERY_H diff --git a/src/solid/devices/backends/iokit/iokitprocessor.cpp b/src/solid/devices/backends/iokit/iokitblock.cpp similarity index 61% copy from src/solid/devices/backends/iokit/iokitprocessor.cpp copy to src/solid/devices/backends/iokit/iokitblock.cpp index 1f2282a..44d1612 100644 --- a/src/solid/devices/backends/iokit/iokitprocessor.cpp +++ b/src/solid/devices/backends/iokit/iokitblock.cpp @@ -1,58 +1,58 @@ /* - Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ -#include "iokitprocessor.h" -#include "iokitdevice.h" +#include "iokitblock.h" -#include +#include "iokitdevice.h" using namespace Solid::Backends::IOKit; -Processor::Processor(IOKitDevice *device) +Block::Block(IOKitDevice *device) : DeviceInterface(device) { - //IOKitDevice parent(device->parentUdi()); } -Processor::~Processor() +Block::Block(const IOKitDevice *device) + : DeviceInterface(device) { - } -int Processor::number() const +Block::~Block() { - return m_device->property(QLatin1String("IOCPUNumber")).toInt(); } -int Processor::maxSpeed() const +int Block::deviceMajor() const { - return 0; // TODO + return m_device->property(QLatin1String("BSD Major")).toInt(); } -bool Processor::canChangeFrequency() const +int Block::deviceMinor() const { - return false; // TODO + return m_device->property(QLatin1String("BSD Minor")).toInt(); } -Solid::Processor::InstructionSets Processor::instructionSets() const +QString Block::device() const { - return 0; // TODO + if (m_device->iOKitPropertyExists(QStringLiteral("BSD Name"))) { + return QStringLiteral("/dev/") + m_device->property(QLatin1String("BSD Name")).toString(); + } + return QString(); } diff --git a/src/solid/devices/backends/iokit/iokitprocessor.h b/src/solid/devices/backends/iokit/iokitblock.h similarity index 62% copy from src/solid/devices/backends/iokit/iokitprocessor.h copy to src/solid/devices/backends/iokit/iokitblock.h index 4fd6394..b3e1777 100644 --- a/src/solid/devices/backends/iokit/iokitprocessor.h +++ b/src/solid/devices/backends/iokit/iokitblock.h @@ -1,53 +1,51 @@ /* - Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ -#ifndef SOLID_BACKENDS_IOKIT_PROCESSOR_H -#define SOLID_BACKENDS_IOKIT_PROCESSOR_H +#ifndef SOLID_BACKENDS_IOKIT_BLOCK_H +#define SOLID_BACKENDS_IOKIT_BLOCK_H -#include +#include #include "iokitdeviceinterface.h" namespace Solid { namespace Backends { namespace IOKit { -class IOKitDevice; - -class Processor : public DeviceInterface, virtual public Solid::Ifaces::Processor +class Block : public DeviceInterface, virtual public Solid::Ifaces::Block { Q_OBJECT - Q_INTERFACES(Solid::Ifaces::Processor) + Q_INTERFACES(Solid::Ifaces::Block) public: - Processor(IOKitDevice *device); - virtual ~Processor(); + Block(IOKitDevice *device); + Block(const IOKitDevice *device); + virtual ~Block(); - virtual int number() const; - virtual int maxSpeed() const; - virtual bool canChangeFrequency() const; - virtual Solid::Processor::InstructionSets instructionSets() const; + virtual int deviceMajor() const Q_DECL_OVERRIDE; + virtual int deviceMinor() const Q_DECL_OVERRIDE; + virtual QString device() const Q_DECL_OVERRIDE; }; } } } -#endif // SOLID_BACKENDS_IOKIT_PROCESSOR_H +#endif // SOLID_BACKENDS_IOKIT_BLOCK_H diff --git a/src/solid/devices/backends/iokit/iokitdevice.cpp b/src/solid/devices/backends/iokit/iokitdevice.cpp index 1e7d9ae..26d33a6 100644 --- a/src/solid/devices/backends/iokit/iokitdevice.cpp +++ b/src/solid/devices/backends/iokit/iokitdevice.cpp @@ -1,239 +1,544 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitdevice.h" #include "iokitgenericinterface.h" #include "iokitprocessor.h" #include "iokitbattery.h" +#include "iokitstorage.h" +#include "iokitstorageaccess.h" +#include "iokitvolume.h" +#include "iokitopticaldrive.h" +#include "iokitopticaldisc.h" -#include +#include +#include +#include +#include + +#include +#include #include #include #include #include // from cfhelper.cpp extern QMap q_toVariantMap(const CFMutableDictionaryRef &dict); +extern bool q_sysctlbyname(const char *name, QString &result); + +typedef QSet DeviceInterfaceTypes; namespace Solid { namespace Backends { namespace IOKit { // returns a solid type from an entry and its properties -static Solid::DeviceInterface::Type typeFromEntry(const io_registry_entry_t &entry, - const QMap &properties) +static DeviceInterfaceTypes typesFromEntry(const io_registry_entry_t &entry, + const QMap &properties, + Solid::DeviceInterface::Type &mainType) { + DeviceInterfaceTypes types; + mainType = Solid::DeviceInterface::Unknown; if (IOObjectConformsTo(entry, "AppleACPICPU")) { - return Solid::DeviceInterface::Processor; + mainType = Solid::DeviceInterface::Processor; + types << mainType; } if (IOObjectConformsTo(entry, "AppleSmartBattery")) { - return Solid::DeviceInterface::Battery; + mainType = Solid::DeviceInterface::Battery; + types << mainType; + } + const QString bsdName = QStringLiteral("BSD Name"), + leaf = QStringLiteral("Leaf"); + if (IOObjectConformsTo(entry, "IOCDMedia") + || IOObjectConformsTo(entry, "IODVDMedia") + || IOObjectConformsTo(entry, "IOBDMedia")) { + mainType = Solid::DeviceInterface::OpticalDrive; + types << mainType + << Solid::DeviceInterface::OpticalDisc; + } + if (properties.contains(bsdName) && properties.value(bsdName).toString().startsWith(QStringLiteral("disk"))) { + if ((properties.contains(leaf) && properties.value(leaf).toBool() == false) + || mainType == Solid::DeviceInterface::OpticalDrive) { + if (mainType == Solid::DeviceInterface::Unknown) { + mainType = Solid::DeviceInterface::StorageDrive; + } + types << Solid::DeviceInterface::StorageDrive; + } else if (mainType == Solid::DeviceInterface::Unknown) { + mainType = Solid::DeviceInterface::StorageVolume; + } + types << Solid::DeviceInterface::StorageVolume; + } + + if (types.isEmpty()) { + types << mainType; +// qWarning() << "unsupported entry" << entry << "with properties" << properties; } - return Solid::DeviceInterface::Unknown; + return types; } // gets all properties from an entry into a QMap static QMap getProperties(const io_registry_entry_t &entry) { CFMutableDictionaryRef propertyDict = 0; if (IORegistryEntryCreateCFProperties(entry, &propertyDict, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) { return QMap(); } QMap result = q_toVariantMap(propertyDict); CFRelease(propertyDict); + io_name_t className; + IOObjectGetClass(entry, className); + result["className"] = QString::fromUtf8(className); + return result; } // gets the parent's Udi from an entry static QString getParentDeviceUdi(const io_registry_entry_t &entry) { io_registry_entry_t parent = 0; kern_return_t ret = IORegistryEntryGetParentEntry(entry, kIOServicePlane, &parent); if (ret != KERN_SUCCESS) { // don't release parent here - docs say only on success return QString(); } QString result; io_string_t pathName; ret = IORegistryEntryGetPath(parent, kIOServicePlane, pathName); if (ret == KERN_SUCCESS) { result = QString::fromUtf8(pathName); } // now we can release the parent IOObjectRelease(parent); return result; } +static const QString computerModel() +{ + QString qModel; + q_sysctlbyname("hw.model", qModel); + return qModel; +} + class IOKitDevicePrivate { public: inline IOKitDevicePrivate() - : type(Solid::DeviceInterface::Unknown) - {} + : type({Solid::DeviceInterface::Unknown}) + , parentDevice(nullptr) + { + } + ~IOKitDevicePrivate() + { + if (parentDevice) { + delete parentDevice; + parentDevice = nullptr; + } + } void init(const QString &udiString, const io_registry_entry_t &entry); + IOKitDevice* getParentDevice(); QString udi; QString parentUdi; QMap properties; - Solid::DeviceInterface::Type type; + DeviceInterfaceTypes type; + Solid::DeviceInterface::Type mainType; + IOKitDevice *parentDevice; }; void IOKitDevicePrivate::init(const QString &udiString, const io_registry_entry_t &entry) { Q_ASSERT(entry != MACH_PORT_NULL); udi = udiString; properties = getProperties(entry); - io_name_t className; - IOObjectGetClass(entry, className); - properties["className"] = QString::fromUtf8(className); - parentUdi = getParentDeviceUdi(entry); - type = typeFromEntry(entry, properties); + type = typesFromEntry(entry, properties, mainType); + if (udi.contains(QStringLiteral("IOBD")) || udi.contains(QStringLiteral("BD PX"))) { + qWarning() << "Solid: BlueRay entry" << entry << "mainType=" << mainType << "typeList:" << type + << "with properties" << properties; + } + if (mainType != Solid::DeviceInterface::Unknown) { + } IOObjectRelease(entry); } +IOKitDevice* IOKitDevicePrivate::getParentDevice() +{ + if (!parentDevice) { + parentDevice = new IOKitDevice(parentUdi); + } + return parentDevice; +} + IOKitDevice::IOKitDevice(const QString &udi, const io_registry_entry_t &entry) : d(new IOKitDevicePrivate) { d->init(udi, entry); } IOKitDevice::IOKitDevice(const QString &udi) : d(new IOKitDevicePrivate) { + if (udi.isEmpty()) { + qWarning() << Q_FUNC_INFO << "Tried to create Device from empty UDI"; + return; + } + io_registry_entry_t entry = IORegistryEntryFromPath( kIOMasterPortDefault, udi.toLocal8Bit().constData()); if (entry == MACH_PORT_NULL) { - qDebug() << Q_FUNC_INFO << "Tried to create Device from invalid UDI" << udi; + qWarning() << Q_FUNC_INFO << "Tried to create Device from invalid UDI" << udi; return; } d->init(udi, entry); } +IOKitDevice::IOKitDevice(const IOKitDevice &device) + : d(new IOKitDevicePrivate) +{ + if (device.udi().isEmpty()) { + qWarning() << Q_FUNC_INFO << "Tried to create Device from empty UDI"; + return; + } + + io_registry_entry_t entry = IORegistryEntryFromPath( + kIOMasterPortDefault, + device.udi().toLocal8Bit().constData()); + + if (entry == MACH_PORT_NULL) { + qWarning() << Q_FUNC_INFO << "Tried to create Device from invalid UDI" << device.udi(); + return; + } + + d->init(device.udi(), entry); +} + IOKitDevice::~IOKitDevice() { delete d; } +bool IOKitDevice::conformsToIOKitClass(const QString &className) const +{ + bool conforms = false; + if (!className.isEmpty()) { + io_registry_entry_t entry = IORegistryEntryFromPath( + kIOMasterPortDefault, + udi().toLocal8Bit().constData()); + if (entry != MACH_PORT_NULL) { + conforms = IOObjectConformsTo(entry, className.toLocal8Bit().constData()); + IOObjectRelease(entry); + } + } + return conforms; +} + QString IOKitDevice::udi() const { return d->udi; } QString IOKitDevice::parentUdi() const { return d->parentUdi; } QString IOKitDevice::vendor() const { - return QString(); // TODO + QString vendor; + if (parentUdi().isEmpty()) { + return QStringLiteral("Apple"); + } + switch (d->mainType) { + case Solid::DeviceInterface::Processor: + return Processor::vendor(); + break; + case Solid::DeviceInterface::Battery: + return property(QStringLiteral("Manufacturer")).toString(); + break; + case Solid::DeviceInterface::StorageDrive: + case Solid::DeviceInterface::OpticalDrive: + case Solid::DeviceInterface::OpticalDisc: + return IOKitStorage(this).vendor(); + break; + case Solid::DeviceInterface::StorageVolume: + return IOKitVolume(this).vendor(); + break; + default: + return QString(); + break; + } + return QString(); } QString IOKitDevice::product() const { + if (parentUdi().isEmpty()) { + return computerModel(); + } + switch (d->mainType) { + case Solid::DeviceInterface::Processor: + return Processor::product(); + break; + case Solid::DeviceInterface::Battery: + return property(QStringLiteral("DeviceName")).toString(); + break; + case Solid::DeviceInterface::StorageDrive: + case Solid::DeviceInterface::OpticalDrive: + case Solid::DeviceInterface::OpticalDisc: + return IOKitStorage(this).product(); + break; + case Solid::DeviceInterface::StorageVolume: + return IOKitVolume(this).product(); + break; + } return QString(); // TODO } -QString IOKitDevice::icon() const +QString IOKitDevice::description() const { - return QString(); // TODO + switch (d->mainType) { + case Solid::DeviceInterface::Processor: + return QStringLiteral("Processor"); + break; + case Solid::DeviceInterface::Battery: + return QStringLiteral("Apple Smart Battery"); + break; + case Solid::DeviceInterface::StorageDrive: + case Solid::DeviceInterface::OpticalDrive: + case Solid::DeviceInterface::OpticalDisc: + return IOKitStorage(this).description(); + break; + case Solid::DeviceInterface::StorageVolume: { + const QString volLabel = IOKitVolume(this).description(); + const QString mountPoint = IOKitStorageAccess(this).filePath(); + if (volLabel.isEmpty()) { + return QUrl::fromLocalFile(mountPoint).fileName(); + } else if (mountPoint.startsWith(QStringLiteral("/Volumes/"))) { + // Mac users will expect to see the name under which the volume is mounted here. + return QString(QStringLiteral("%1 (%2)")).arg(QUrl::fromLocalFile(mountPoint).fileName()).arg(volLabel); + } + return volLabel; + break; + } + } + return product(); // TODO } -QStringList IOKitDevice::emblems() const +QString IOKitDevice::icon() const { - return QStringList(); // TODO + // adapted from HalDevice::icon() + if (parentUdi().isEmpty()) { + if (computerModel().contains(QStringLiteral("MacBook"))) { + return QStringLiteral("computer-laptop"); + } else { + return QStringLiteral("computer"); + } + + } else if (d->type.contains(Solid::DeviceInterface::StorageDrive)) { + IOKitStorage drive(this); + Solid::StorageDrive::DriveType driveType = drive.driveType(); + + switch (driveType) { + case Solid::StorageDrive::Floppy: + // why not :) + return QStringLiteral("media-floppy"); + break; + case Solid::StorageDrive::CdromDrive: { + const IOKitOpticalDisc disc(this); + if (disc.availableContent() == Solid::OpticalDisc::Audio ) { + return QStringLiteral("media-optical-audio"); + } else switch (disc.discType()) { + case Solid::OpticalDisc::CdRom: + return QStringLiteral("media-optical-data"); + break; + case Solid::OpticalDisc::CdRecordable: + case Solid::OpticalDisc::CdRewritable: + return QStringLiteral("media-optical-recordable"); + break; + case Solid::OpticalDisc::BluRayRom: + case Solid::OpticalDisc::BluRayRecordable: + case Solid::OpticalDisc::BluRayRewritable: + return QStringLiteral("media-optical-blu-ray"); + break; + } + break; + } + case Solid::StorageDrive::SdMmc: + return QStringLiteral("media-flash-sd-mmc"); + break; + case Solid::StorageDrive::CompactFlash: + return QStringLiteral("media-flash-cf"); + break; + } + if (drive.bus() == Solid::StorageDrive::Usb) { + return QStringLiteral("drive-removable-media-usb"); + } + if (drive.isRemovable()) { + return QStringLiteral("drive-removable-media"); + } + return QStringLiteral("drive-harddisk"); + + } else if (d->mainType == Solid::DeviceInterface::StorageVolume) { + } else if (d->mainType == Solid::DeviceInterface::Battery) { + return QStringLiteral("battery"); + } else if (d->mainType == Solid::DeviceInterface::Processor) { + return QStringLiteral("cpu"); // FIXME: Doesn't follow icon spec + } else { + QString iconName = d->getParentDevice()->icon(); + + if (!iconName.isEmpty()) { + return iconName; + } + + return QStringLiteral("drive-harddisk"); + } + return QString(); } -QString IOKitDevice::description() const +QStringList IOKitDevice::emblems() const { - return product(); // TODO + return QStringList(); // TODO } QVariant IOKitDevice::property(const QString &key) const { + if (!d->properties.contains(key)) { + return QObject::property(key.toUtf8()); + } return d->properties.value(key); } QMap IOKitDevice::allProperties() const { return d->properties; } -bool IOKitDevice::propertyExists(const QString &key) const +bool IOKitDevice::iOKitPropertyExists(const QString &key) const { return d->properties.contains(key); } bool IOKitDevice::queryDeviceInterface(const Solid::DeviceInterface::Type &type) const { - return (type == Solid::DeviceInterface::GenericInterface - || type == d->type); + switch (type) { + case Solid::DeviceInterface::GenericInterface: + return true; + break; + case Solid::DeviceInterface::StorageAccess: + if (d->type.contains(Solid::DeviceInterface::StorageDrive) + || d->type.contains(Solid::DeviceInterface::StorageVolume)) { + return true; + } + break; + default: + return d->type.contains(type); + break; + } + return false; } QObject *IOKitDevice::createDeviceInterface(const Solid::DeviceInterface::Type &type) { - QObject *iface = 0; + QObject *iface = nullptr; switch (type) { case Solid::DeviceInterface::GenericInterface: iface = new GenericInterface(this); break; case Solid::DeviceInterface::Processor: - if (d->type == Solid::DeviceInterface::Processor) { + if (d->type.contains(Solid::DeviceInterface::Processor)) { iface = new Processor(this); } break; case Solid::DeviceInterface::Battery: - if (d->type == Solid::DeviceInterface::Battery) { + if (d->type.contains(Solid::DeviceInterface::Battery)) { iface = new Battery(this); } break; + case Solid::DeviceInterface::OpticalDrive: + if (d->type.contains(Solid::DeviceInterface::OpticalDrive)) { + iface = new IOKitOpticalDrive(this); + } + break; + case Solid::DeviceInterface::OpticalDisc: + if (d->type.contains(Solid::DeviceInterface::OpticalDisc)) { + iface = new IOKitOpticalDisc(this); + } + break; + case Solid::DeviceInterface::StorageDrive: + if (d->type.contains(Solid::DeviceInterface::StorageDrive)) { + iface = new IOKitStorage(this); + } + break; + case Solid::DeviceInterface::Block: + if (d->type.contains(Solid::DeviceInterface::OpticalDisc)) { + iface = new IOKitOpticalDisc(this); + } else if (d->type.contains(Solid::DeviceInterface::OpticalDrive)) { + iface = new IOKitOpticalDrive(this); + } else if (d->type.contains(Solid::DeviceInterface::StorageVolume)) { + iface = new IOKitVolume(this); + } else if (d->type.contains(Solid::DeviceInterface::StorageDrive)) { + iface = new IOKitStorage(this); + } + break; + case Solid::DeviceInterface::StorageVolume: + if (d->type.contains(Solid::DeviceInterface::StorageVolume)) { + iface = new IOKitVolume(this); + } + break; + case Solid::DeviceInterface::StorageAccess: + if (d->type.contains(Solid::DeviceInterface::StorageDrive) + || d->type.contains(Solid::DeviceInterface::StorageVolume)) { + iface = new IOKitStorageAccess(this); + } + break; // the rest is TODO } return iface; } } } } // namespaces diff --git a/src/solid/devices/backends/iokit/iokitdevice.h b/src/solid/devices/backends/iokit/iokitdevice.h index 73d61de..3e0a9e2 100644 --- a/src/solid/devices/backends/iokit/iokitdevice.h +++ b/src/solid/devices/backends/iokit/iokitdevice.h @@ -1,75 +1,78 @@ /* Copyright 2009 Harald Fernengel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SOLID_BACKENDS_IOKIT_IOKITDEVICE_H #define SOLID_BACKENDS_IOKIT_IOKITDEVICE_H #include #include namespace Solid { namespace Backends { namespace IOKit { class IOKitDevicePrivate; class IOKitManager; class IOKitDevice : public Solid::Ifaces::Device { Q_OBJECT public: IOKitDevice(const QString &udi); + IOKitDevice(const IOKitDevice &device); virtual ~IOKitDevice(); - virtual QString udi() const; - virtual QString parentUdi() const; + virtual QString udi() const Q_DECL_OVERRIDE; + virtual QString parentUdi() const Q_DECL_OVERRIDE; - virtual QString vendor() const; - virtual QString product() const; - virtual QString icon() const; - virtual QStringList emblems() const; - virtual QString description() const; + virtual QString vendor() const Q_DECL_OVERRIDE; + virtual QString product() const Q_DECL_OVERRIDE; + virtual QString icon() const Q_DECL_OVERRIDE; + virtual QStringList emblems() const Q_DECL_OVERRIDE; + virtual QString description() const Q_DECL_OVERRIDE; virtual QVariant property(const QString &key) const; virtual QMap allProperties() const; - virtual bool propertyExists(const QString &key) const; + virtual bool iOKitPropertyExists(const QString &key) const; - virtual bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const; - virtual QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type); + virtual bool queryDeviceInterface(const Solid::DeviceInterface::Type &type) const Q_DECL_OVERRIDE; + virtual QObject *createDeviceInterface(const Solid::DeviceInterface::Type &type) Q_DECL_OVERRIDE; + + bool conformsToIOKitClass(const QString &className) const; Q_SIGNALS: void propertyChanged(const QMap &changes); void conditionRaised(const QString &condition, const QString &reason); private: friend class IOKitManager; IOKitDevice(const QString &udi, const io_registry_entry_t &entry); IOKitDevicePrivate *const d; }; } } } #endif // SOLID_BACKENDS_IOKIT_IOKITDEVICE_H diff --git a/src/solid/devices/backends/iokit/iokitdeviceinterface.cpp b/src/solid/devices/backends/iokit/iokitdeviceinterface.cpp index c6dc746..d5a5d7e 100644 --- a/src/solid/devices/backends/iokit/iokitdeviceinterface.cpp +++ b/src/solid/devices/backends/iokit/iokitdeviceinterface.cpp @@ -1,33 +1,46 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitdeviceinterface.h" using namespace Solid::Backends::IOKit; DeviceInterface::DeviceInterface(IOKitDevice *device) - : QObject(device), m_device(device) + : QObject(device) + , m_device(device) + , m_deviceCopy(nullptr) { } +DeviceInterface::DeviceInterface(const IOKitDevice *device) + : QObject(device->parent()), m_deviceCopy(new IOKitDevice(*device)) +{ + m_device = m_deviceCopy; +} + DeviceInterface::~DeviceInterface() { + if (m_deviceCopy) { + delete m_deviceCopy; + m_deviceCopy = nullptr; + } } diff --git a/src/solid/devices/backends/iokit/iokitdeviceinterface.h b/src/solid/devices/backends/iokit/iokitdeviceinterface.h index 38eacf4..a1c26ff 100644 --- a/src/solid/devices/backends/iokit/iokitdeviceinterface.h +++ b/src/solid/devices/backends/iokit/iokitdeviceinterface.h @@ -1,51 +1,57 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H #define SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H #include #include "iokitdevice.h" #include #include namespace Solid { namespace Backends { namespace IOKit { class DeviceInterface : public QObject, virtual public Solid::Ifaces::DeviceInterface { Q_OBJECT Q_INTERFACES(Solid::Ifaces::DeviceInterface) public: DeviceInterface(IOKitDevice *device); + // the ctor taking a const device* argument makes a deep + // copy of the IOKitDevice; any property changes made via + // the resulting instance will not affect the original device. + DeviceInterface(const IOKitDevice *device); virtual ~DeviceInterface(); protected: IOKitDevice *m_device; + IOKitDevice *m_deviceCopy; }; } } } #endif // SOLID_BACKENDS_IOKIT_DEVICEINTERFACE_H diff --git a/src/solid/devices/backends/iokit/iokitgenericinterface.cpp b/src/solid/devices/backends/iokit/iokitgenericinterface.cpp index 29231f4..0a0a1d2 100644 --- a/src/solid/devices/backends/iokit/iokitgenericinterface.cpp +++ b/src/solid/devices/backends/iokit/iokitgenericinterface.cpp @@ -1,51 +1,51 @@ /* Copyright 2009 Harald Fernengel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitgenericinterface.h" #include "iokitdevice.h" using namespace Solid::Backends::IOKit; GenericInterface::GenericInterface(IOKitDevice *device) : DeviceInterface(device) { } GenericInterface::~GenericInterface() { } QVariant GenericInterface::property(const QString &key) const { return m_device->property(key); } QMap GenericInterface::allProperties() const { return m_device->allProperties(); } bool GenericInterface::propertyExists(const QString &key) const { - return m_device->propertyExists(key); + return m_device->iOKitPropertyExists(key); } diff --git a/src/solid/devices/backends/iokit/iokitmanager.cpp b/src/solid/devices/backends/iokit/iokitmanager.cpp index 6b86f98..869ce93 100644 --- a/src/solid/devices/backends/iokit/iokitmanager.cpp +++ b/src/solid/devices/backends/iokit/iokitmanager.cpp @@ -1,241 +1,243 @@ /* Copyright 2009 Harald Fernengel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitmanager.h" #include "iokitdevice.h" #include #include #include #include #include namespace Solid { namespace Backends { namespace IOKit { class IOKitManagerPrivate { public: inline IOKitManagerPrivate() - : port(0), source(0) + : port(nullptr), source(nullptr) {} IONotificationPortRef port; CFRunLoopSourceRef source; static const char *typeToName(Solid::DeviceInterface::Type type); static QStringList devicesFromRegistry(io_iterator_t it); QSet supportedInterfaces; }; // gets all registry pathes from an iterator QStringList IOKitManagerPrivate::devicesFromRegistry(io_iterator_t it) { QStringList result; io_object_t obj; io_string_t pathName; while ((obj = IOIteratorNext(it))) { kern_return_t ret = IORegistryEntryGetPath(obj, kIOServicePlane, pathName); if (ret != KERN_SUCCESS) { qWarning() << Q_FUNC_INFO << "IORegistryEntryGetPath failed"; continue; } result += QString::fromUtf8(pathName); ret = IOObjectRelease(obj); if (ret != KERN_SUCCESS) { // very unlikely to happen - keep it a qDebug just in case. // compiler will nuke this code in release builds. qDebug() << Q_FUNC_INFO << "Unable to release object reference"; } } IOObjectRelease(it); return result; } const char *IOKitManagerPrivate::typeToName(Solid::DeviceInterface::Type type) { switch (type) { case Solid::DeviceInterface::Unknown: return 0; case Solid::DeviceInterface::Processor: return "AppleACPICPU"; case Solid::DeviceInterface::Battery: return "AppleSmartBattery"; //Solid::DeviceInterface::GenericInterface: //Solid::DeviceInterface::Block: - //Solid::DeviceInterface::StorageAccess: - //Solid::DeviceInterface::StorageDrive: - //Solid::DeviceInterface::OpticalDrive: - //Solid::DeviceInterface::StorageVolume: - //Solid::DeviceInterface::OpticalDisc: + case Solid::DeviceInterface::StorageAccess: + case Solid::DeviceInterface::StorageDrive: + case Solid::DeviceInterface::StorageVolume: + return "IOMedia"; + case Solid::DeviceInterface::OpticalDrive: + case Solid::DeviceInterface::OpticalDisc: + return "IOCDMedia"; //Solid::DeviceInterface::Camera: //Solid::DeviceInterface::PortableMediaPlayer: } return 0; } IOKitManager::IOKitManager(QObject *parent) : Solid::Ifaces::DeviceManager(parent), d(new IOKitManagerPrivate) { d->port = IONotificationPortCreate(kIOMasterPortDefault); if (!d->port) { qWarning() << Q_FUNC_INFO << "Unable to create notification port"; return; } d->source = IONotificationPortGetRunLoopSource(d->port); if (!d->source) { qWarning() << Q_FUNC_INFO << "Unable to create notification source"; return; } CFRunLoopAddSource(CFRunLoopGetCurrent(), d->source, kCFRunLoopDefaultMode); d->supportedInterfaces << Solid::DeviceInterface::GenericInterface << Solid::DeviceInterface::Processor << Solid::DeviceInterface::Block << Solid::DeviceInterface::StorageAccess << Solid::DeviceInterface::StorageDrive << Solid::DeviceInterface::OpticalDrive << Solid::DeviceInterface::StorageVolume << Solid::DeviceInterface::OpticalDisc << Solid::DeviceInterface::Camera << Solid::DeviceInterface::PortableMediaPlayer << Solid::DeviceInterface::Battery; } IOKitManager::~IOKitManager() { if (d->source) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), d->source, kCFRunLoopDefaultMode); } if (d->port) { IONotificationPortDestroy(d->port); } delete d; } QString IOKitManager::udiPrefix() const { return QString(); //FIXME: We should probably use a prefix there... has to be tested on Mac } QSet IOKitManager::supportedInterfaces() const { return d->supportedInterfaces; } QStringList IOKitManager::allDevices() { // use an IORegistry Iterator to iterate over all devices in the service plane io_iterator_t it; kern_return_t ret = IORegistryCreateIterator( kIOMasterPortDefault, kIOServicePlane, kIORegistryIterateRecursively, &it); if (ret != KERN_SUCCESS) { qWarning() << Q_FUNC_INFO << "unable to create iterator"; return QStringList(); } return IOKitManagerPrivate::devicesFromRegistry(it); } QStringList IOKitManager::devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type) { QStringList result; if (type == Solid::DeviceInterface::Unknown) { // match all device interfaces result = allDevices(); } else { const char *deviceClassName = IOKitManagerPrivate::typeToName(type); if (!deviceClassName) { return QStringList(); } CFMutableDictionaryRef matchingDict = IOServiceMatching(deviceClassName); if (!matchingDict) { return QStringList(); } io_iterator_t it = 0; // note - IOServiceGetMatchingServices dereferences the dict kern_return_t ret = IOServiceGetMatchingServices( kIOMasterPortDefault, matchingDict, &it); result = IOKitManagerPrivate::devicesFromRegistry(it); } // if the parentUdi is an empty string, return all matches if (parentUdi.isEmpty()) { return result; } // return only matches that start with the parent's UDI QStringList filtered; Q_FOREACH (const QString &udi, result) { if (udi.startsWith(parentUdi)) { filtered += udi; } } return filtered; } QObject *IOKitManager::createDevice(const QString &udi) { io_registry_entry_t entry = IORegistryEntryFromPath( kIOMasterPortDefault, udi.toLocal8Bit().constData()); // we have to do IOObjectConformsTo - comparing the class names is not good enough //if (IOObjectConformsTo(entry, kIOEthernetInterfaceClass)) { //} if (entry == MACH_PORT_NULL) { return 0; } return new IOKitDevice(udi, entry); } } } } // namespaces diff --git a/src/solid/devices/backends/iokit/iokitopticaldisc.cpp b/src/solid/devices/backends/iokit/iokitopticaldisc.cpp new file mode 100644 index 0000000..1fc8171 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitopticaldisc.cpp @@ -0,0 +1,120 @@ +/* + Copyright 2006 Kevin Ottens + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "iokitopticaldisc.h" + +#include + +#include + +using namespace Solid::Backends::IOKit; + +IOKitOpticalDisc::IOKitOpticalDisc(IOKitDevice *device) + : IOKitVolume(device) +{ +} + +IOKitOpticalDisc::IOKitOpticalDisc(const IOKitDevice *device) + : IOKitVolume(device) +{ +} + +IOKitOpticalDisc::~IOKitOpticalDisc() +{ +} + +QString IOKitOpticalDisc::device() const +{ + const QString devName = m_device->property(QLatin1String("BSD Name")).toString(); + if (devName.startsWith(QLatin1Char('r'))) { + return QStringLiteral("/dev/") + devName; + } else { + return QStringLiteral("/dev/r") + devName; + } +} + +Solid::OpticalDisc::ContentTypes IOKitOpticalDisc::availableContent() const +{ + if (fsType() == QStringLiteral("cddafs")) { + return Solid::OpticalDisc::Audio; + } + return Solid::OpticalDisc::Data; +} + +Solid::OpticalDisc::DiscType IOKitOpticalDisc::discType() const +{ + QString type = m_device->property(QStringLiteral("Type")).toString(); + + if (type == "CD-ROM") { + return Solid::OpticalDisc::CdRom; + } else if (type == "CD-R") { + return Solid::OpticalDisc::CdRecordable; + } else if (type == "CD-RW") { + return Solid::OpticalDisc::CdRewritable; + } else if (type == "DVD-ROM") { + return Solid::OpticalDisc::DvdRom; + } else if (type == "DVD-RAM") { + return Solid::OpticalDisc::DvdRam; + } else if (type == "DVD-R") { + return Solid::OpticalDisc::DvdRecordable; + } else if (type == "DVD-RW") { + return Solid::OpticalDisc::DvdRewritable; + } else if (type == "DVD+R") { + return Solid::OpticalDisc::DvdPlusRecordable; + } else if (type == "DVD+RW") { + return Solid::OpticalDisc::DvdPlusRewritable; + } else if (type == "BD-ROM") { + return Solid::OpticalDisc::BluRayRom; + } else if (type == "BD-R") { + return Solid::OpticalDisc::BluRayRecordable; + } else if (type == "BD-RE") { + return Solid::OpticalDisc::BluRayRewritable; + } else if (type == "HD DVD-ROM") { + return Solid::OpticalDisc::HdDvdRom; + } else if (type == "HD DVD-R") { + return Solid::OpticalDisc::HdDvdRecordable; + } else if (type == "HD DVD-RW") { + return Solid::OpticalDisc::HdDvdRewritable; + } else { + return Solid::OpticalDisc::UnknownDiscType; + } +} + +bool IOKitOpticalDisc::isAppendable() const +{ + // TODO! + return isRewritable(); +} + +bool IOKitOpticalDisc::isBlank() const +{ + // TODO! + return isRewritable(); +} + +bool IOKitOpticalDisc::isRewritable() const +{ + return m_device->property(QStringLiteral("Writable")).toBool(); +} + +qulonglong IOKitOpticalDisc::capacity() const +{ + return size(); +} diff --git a/src/solid/devices/backends/iokit/iokitopticaldisc.h b/src/solid/devices/backends/iokit/iokitopticaldisc.h new file mode 100644 index 0000000..a903736 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitopticaldisc.h @@ -0,0 +1,58 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef SOLID_BACKENDS_IOKIT_OPTICALDISC_H +#define SOLID_BACKENDS_IOKIT_OPTICALDISC_H + +#include +#include "iokitvolume.h" + +namespace Solid +{ +namespace Backends +{ +namespace IOKit +{ +class IOKitOpticalDisc : public IOKitVolume, virtual public Solid::Ifaces::OpticalDisc +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::OpticalDisc) + +public: + IOKitOpticalDisc(IOKitDevice *device); + IOKitOpticalDisc(const IOKitDevice *device); + virtual ~IOKitOpticalDisc(); + + // overriden from IOKit::Block because optical discs must + // be accessed through the raw device. + virtual QString device() const Q_DECL_OVERRIDE; + + virtual Solid::OpticalDisc::ContentTypes availableContent() const Q_DECL_OVERRIDE; + virtual Solid::OpticalDisc::DiscType discType() const Q_DECL_OVERRIDE; + virtual bool isAppendable() const Q_DECL_OVERRIDE; + virtual bool isBlank() const Q_DECL_OVERRIDE; + virtual bool isRewritable() const Q_DECL_OVERRIDE; + virtual qulonglong capacity() const Q_DECL_OVERRIDE; +}; +} +} +} + +#endif // SOLID_BACKENDS_IOKIT_OPTICALDISC_H diff --git a/src/solid/devices/backends/iokit/iokitopticaldrive.cpp b/src/solid/devices/backends/iokit/iokitopticaldrive.cpp new file mode 100644 index 0000000..5dc1ccc --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitopticaldrive.cpp @@ -0,0 +1,358 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "iokitopticaldrive.h" + +#include +#include +#include + +#ifdef EJECT_USING_DISKARBITRATION +// for QCFType: +#include +#else +#include +#endif + +#include +#include +#include + +using namespace Solid::Backends::IOKit; + + +class IOKitOpticalDrive::Private +{ +public: + Private(const IOKitDevice *device, const QVariantMap &devCharMap) + : m_device(device) + , m_deviceCharacteristics(devCharMap) + { + } + virtual ~Private() + { + } + + QVariant property(const QString &key) const + { + return m_deviceCharacteristics.value(key); + } + + const IOKitDevice *m_device; + const QVariantMap m_deviceCharacteristics; + + static const QMap cdTypeMap; + static const QMap dvdTypeMap; + static const QMap bdTypeMap; + +#ifdef EJECT_USING_DISKARBITRATION + // DiskArbitration-based ejection based on the implementation in libcdio's osx.c + // in turn based on VideoLAN (VLC) code. + // Not activated by default ATM because I have only been able to test it with the + // solid-hardware5 utility and that one remains stuck after a successful return + // from IOKitOpticalDrive::eject(). It does so too when using the hdiutil external + // utility which cannot be due to using QProcess (to the best of my knowledge). + // NB: the full-fledged approach using a cancel sourc ref (cancel_signal) etc. may + // well be too complicated. + + typedef struct DAContext { + const IOKitDevice *device; + int success; + bool completed; + DASessionRef session; + CFRunLoopRef runloop; + CFRunLoopSourceRef cancel_signal; + } DAContext; + + static void cancelEjectRunloop(void*) {}; + + static void daEjectCallback(DADiskRef disk, DADissenterRef dissenter, void *context) + { + Q_UNUSED(disk); + DAContext *daContext = static_cast(context); + + if (dissenter) { + CFStringRef status = DADissenterGetStatusString(dissenter); + if (status){ + qWarning() << "Warning while ejecting" << daContext->device->property("BSD Name").toString() + << ":" << QString::fromCFString(status); + CFRelease( status ); + } + } + + daContext->success = dissenter ? false : true; + daContext->completed = TRUE; + CFRunLoopSourceSignal(daContext->cancel_signal); + CFRunLoopWakeUp(daContext->runloop); + } + + static void daUnmountCallback(DADiskRef disk, DADissenterRef dissenter, void *context) + { + DAContext *daContext = (DAContext *)context; + + if (!dissenter) { + DADiskEject(disk, kDADiskEjectOptionDefault, daEjectCallback, context); + daContext->success = (daContext->success == -1 ? true : daContext->success); + } + else { + daContext->success = false; + daContext->completed = true; + CFRunLoopSourceSignal(daContext->cancel_signal); + CFRunLoopWakeUp(daContext->runloop); + } + } + + bool eject(double timeoutSeconds) + { + CFDictionaryRef description = nullptr; + CFRunLoopSourceContext cancelRunLoopSourceContext = { + .perform = cancelEjectRunloop + }; + DAContext daContext = {m_device, -1 , false, 0, + CFRunLoopGetCurrent(), 0}; + QCFType cancel = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &cancelRunLoopSourceContext); + if (!(daContext.cancel_signal = cancel)) { + qWarning() << Q_FUNC_INFO << "failed to create cancel runloop source"; + return false; + } + QCFType session = DASessionCreate(kCFAllocatorDefault); + if (!(daContext.session = session)) { + qWarning() << Q_FUNC_INFO << "failed to create DiskArbitration session"; + return false; + } + const QString devName = m_device->property(QStringLiteral("BSD Name")).toString(); + QCFType daRef = DADiskCreateFromBSDName(kCFAllocatorDefault, daContext.session, devName.toStdString().c_str()); + if (!daRef) { + qWarning() << Q_FUNC_INFO << "failed to create DiskArbitration reference for" << devName; + return false; + } + description = DADiskCopyDescription(daRef); + if (description ){ + DASessionScheduleWithRunLoop(daContext.session, daContext.runloop, kCFRunLoopDefaultMode); + CFRunLoopAddSource(daContext.runloop, daContext.cancel_signal, kCFRunLoopDefaultMode); + if (CFDictionaryGetValueIfPresent(description, kDADiskDescriptionVolumePathKey, nullptr)) { + DADiskUnmount(daRef, kDADiskUnmountOptionWhole, daUnmountCallback, &daContext); + } + DADiskEject(daRef, kDADiskEjectOptionDefault, daEjectCallback, &daContext); + daContext.success = (daContext.success == -1 ? true : daContext.success); + while (!daContext.completed) { + if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeoutSeconds, true) == kCFRunLoopRunTimedOut) { + break; + } + } + if (daContext.completed) { + qWarning() << Q_FUNC_INFO << "ejected" << devName; + } else{ + qWarning() << Q_FUNC_INFO << "timeout ejecting" << devName; + } + CFRunLoopRemoveSource(daContext.runloop, daContext.cancel_signal, kCFRunLoopDefaultMode); + DASessionSetDispatchQueue(daContext.session, 0); + DASessionUnscheduleFromRunLoop(daContext.session, daContext.runloop, kCFRunLoopDefaultMode); + CFRelease(description); + } else { + qWarning() << Q_FUNC_INFO << "failed to fetch DiskArbitration description for" << devName; + } + return daContext.success == -1 ? false : daContext.success; + } +#endif //EJECT_USING_DISKARBITRATION +}; + +const QMap IOKitOpticalDrive::Private::cdTypeMap = { + {Solid::OpticalDrive::Cdr, kCDFeaturesWriteOnceMask}, + {Solid::OpticalDrive::Cdrw, kCDFeaturesReWriteableMask}}; +const QMap IOKitOpticalDrive::Private::dvdTypeMap = { + {Solid::OpticalDrive::Dvd, kDVDFeaturesReadStructuresMask}, + {Solid::OpticalDrive::Dvdr, kDVDFeaturesWriteOnceMask}, + {Solid::OpticalDrive::Dvdrw, kDVDFeaturesReWriteableMask}, + {Solid::OpticalDrive::Dvdram, kDVDFeaturesRandomWriteableMask}, + {Solid::OpticalDrive::Dvdplusr, kDVDFeaturesPlusRMask}, + {Solid::OpticalDrive::Dvdplusrw, kDVDFeaturesPlusRWMask}, +// not supported: +// {Solid::OpticalDrive::Dvdplusdl, "dvdplusrdl"} +// {Solid::OpticalDrive::Dvdplusdlrw, "dvdplusrwdl"} + {Solid::OpticalDrive::HdDvd, kDVDFeaturesHDReadMask}, + {Solid::OpticalDrive::HdDvdr, kDVDFeaturesHDRMask}, + {Solid::OpticalDrive::HdDvdrw, kDVDFeaturesHDRWMask}}; +const QMap IOKitOpticalDrive::Private::bdTypeMap = { + {Solid::OpticalDrive::Bd, kBDFeaturesReadMask}, + {Solid::OpticalDrive::Bdr, kBDFeaturesWriteMask}}; // also Solid::OpticalDrive::Bdre + +IOKitOpticalDrive::IOKitOpticalDrive(IOKitDevice *device) + : IOKitStorage(device) +{ + // walk up the IOKit chain to find the parent that has the "Device Characteristics" property + // In the examples I've seen this is always the 2nd parent but if ever that turns out + // to be non-guaranteed we'll need to do a true walk. + IOKitDevice ioDVDServices(IOKitDevice(device->parentUdi()).parentUdi()); + QVariantMap devCharMap; + if (!ioDVDServices.iOKitPropertyExists(QStringLiteral("Device Characteristics"))) { + qWarning() << Q_FUNC_INFO << "Grandparent of" << m_device->udi() + << "doesn't have the \"Device Characteristics\" but is" << ioDVDServices.udi(); + } else { + const QVariant devCharVar = ioDVDServices.property(QStringLiteral("Device Characteristics")); + devCharMap = devCharVar.toMap(); + } + d = new Private(device, devCharMap); +} + +IOKitOpticalDrive::~IOKitOpticalDrive() +{ +} + +// // Example properties: QMap(("BSD Major", QVariant(int, 1)) +// ("BSD Minor", QVariant(int, 12)) +// ("BSD Name", QVariant(QString, "disk3")) +// ("BSD Unit", QVariant(int, 3)) +// ("Content", QVariant(QString, "CD_partition_scheme")) +// ("Content Hint", QVariant(QString, "")) +// ("Ejectable", QVariant(bool, true)) +// ("IOBusyInterest", QVariant(QString, "IOCommand is not serializable")) +// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable")) +// ("IOMediaIcon", QVariant(QVariantMap, QMap(("CFBundleIdentifier", QVariant(QString, "com.apple.iokit.IOCDStorageFamily")) +// ("IOBundleResourceFile", QVariant(QString, "CD.icns"))))) +// ("Leaf", QVariant(bool, false)) +// ("Open", QVariant(bool, true)) +// ("Preferred Block Size", QVariant(qlonglong, 2352)) +// ("Removable", QVariant(bool, true)) +// ("Size", QVariant(qlonglong, 750932448)) +// ("TOC", QVariant(QByteArray, "\x00\xA7\x01\x01\x01\x10\x00\xA0\x00\x00\x00\x00\x01\x00\x00\x01\x12\x00\xA1\x00\x00\x00\x00\f\x00\x00\x01\x12\x00\xA2\x00\x00\x00\x00""F:J\x01\x12\x00\x01\x00\x00\x00\x00\x00\x02\x00\x01\x12\x00\x02\x00\x00\x00\x00\x07/\b\x01\x12\x00\x03\x00\x00\x00\x00\x12\b\x0E\x01\x12\x00\x04\x00\x00\x00\x00\x17\x12""0\x01\x12\x00\x05\x00\x00\x00\x00\x1B+ \x01\x12\x00\x06\x00\x00\x00\x00 \x11\n\x01\x12\x00\x07\x00\x00\x00\x00!-\n\x01\x12\x00\b\x00\x00\x00\x00'\f\x1F\x01\x12\x00\t\x00\x00\x00\x00-\x13;\x01\x12\x00\n\x00\x00\x00\x00""4%\x1E\x01\x12\x00\x0B\x00\x00\x00\x00""62 \x01\x12\x00\f\x00\x00\x00\x00""C\x06""E")) +// ("Type", QVariant(QString, "CD-ROM")) +// ("Whole", QVariant(bool, true)) +// ("Writable", QVariant(bool, false)) +// ("className", QVariant(QString, "IOCDMedia"))) +// // related useful entry: QMap(("Device Characteristics", QVariant(QVariantMap, QMap(("Async Notification", QVariant(bool, false)) +// ("BD Features", QVariant(int, 0)) +// ("CD Features", QVariant(int, 2047)) +// ("DVD Features", QVariant(int, 503)) +// ("Fast Spindown", QVariant(bool, true)) +// ("Loading Mechanism", QVariant(QString, "Slot")) +// ("Low Power Polling", QVariant(bool, false)) +// ("Power Off", QVariant(bool, true)) +// ("Product Name", QVariant(QString, "DVD-R UJ-8A8")) +// ("Product Revision Level", QVariant(QString, "HA13")) +// ("Vendor Name", QVariant(QString, "MATSHITA"))))) +// ("IOCFPlugInTypes", QVariant(QVariantMap, QMap(("97ABCF2C-23CC-11D5-A0E8-003065704866", QVariant(QString, "IOSCSIArchitectureModelFamily.kext/Contents/PlugIns/SCSITaskUserClient.kext/Contents/PlugIns/SCSITaskLib.plugin"))))) +// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable")) +// ("IOMatchCategory", QVariant(QString, "SCSITaskUserClientIniter")) +// ("IOMinimumSegmentAlignmentByteCount", QVariant(qlonglong, 4)) +// ("IOUserClientClass", QVariant(QString, "SCSITaskUserClient")) +// ("Protocol Characteristics", QVariant(QVariantMap, QMap(("AHCI Port Number", QVariant(qlonglong, 0)) +// ("ATAPI", QVariant(bool, true)) +// ("Physical Interconnect", QVariant(QString, "SATA")) +// ("Physical Interconnect Location", QVariant(QString, "Internal")) +// ("Port Speed", QVariant(QString, "1.5 Gigabit")) +// ("Read Time Out Duration", QVariant(qlonglong, 15000)) +// ("Retry Count", QVariant(qlonglong, 1)) +// ("Write Time Out Duration", QVariant(qlonglong, 15000))))) +// ("SCSITaskDeviceCategory", QVariant(QString, "SCSITaskAuthoringDevice")) +// ("SCSITaskUserClient GUID", QVariant(QByteArray, "\x00]\x0F""F\x80\xFF\xFF\xFFg\xB6\xAB\x1B\x00\x00\x00\x00")) +// ("className", QVariant(QString, "IODVDServices")) +// ("device-type", QVariant(QString, "DVD"))) +// // QMap(("CFBundleIdentifier", QVariant(QString, "com.apple.iokit.IODVDStorageFamily")) +// ("IOClass", QVariant(QString, "IODVDBlockStorageDriver")) +// ("IOGeneralInterest", QVariant(QString, "IOCommand is not serializable")) +// ("IOMatchCategory", QVariant(QString, "IODefaultMatchCategory")) +// ("IOProbeScore", QVariant(int, 0)) +// ("IOPropertyMatch", QVariant(QVariantMap, QMap(("device-type", QVariant(QString, "DVD"))))) +// ("IOProviderClass", QVariant(QString, "IODVDBlockStorageDevice")) +// ("Statistics", QVariant(QVariantMap, QMap(("Bytes (Read)", QVariant(qlonglong, 578020608)) +// ("Bytes (Write)", QVariant(qlonglong, 0)) +// ("Errors (Read)", QVariant(qlonglong, 0)) +// ("Errors (Write)", QVariant(qlonglong, 0)) +// ("Latency Time (Read)", QVariant(qlonglong, 0)) +// ("Latency Time (Write)", QVariant(qlonglong, 0)) +// ("Operations (Read)", QVariant(qlonglong, 18475)) +// ("Operations (Write)", QVariant(qlonglong, 0)) +// ("Retries (Read)", QVariant(qlonglong, 0)) +// ("Retries (Write)", QVariant(qlonglong, 0)) +// ("Total Time (Read)", QVariant(qlonglong, 219944025102)) +// ("Total Time (Write)", QVariant(qlonglong, 0))))) +// ("className", QVariant(QString, "IODVDBlockStorageDriver"))) + +Solid::OpticalDrive::MediumTypes IOKitOpticalDrive::supportedMedia() const +{ + Solid::OpticalDrive::MediumTypes supported; + + uint32_t cdFeatures = d->property(QStringLiteral("CD Features")).toInt(); + uint32_t dvdFeatures = d->property(QStringLiteral("DVD Features")).toInt(); + uint32_t bdFeatures = d->property(QStringLiteral("BD Features")).toInt(); + + qDebug() << Q_FUNC_INFO << "cdFeatures" << cdFeatures << "dvdFeatures" << dvdFeatures << "bdFeatures" << bdFeatures; + + foreach (const Solid::OpticalDrive::MediumType type, d->cdTypeMap.keys()) { + if (cdFeatures & d->cdTypeMap[type]) { + supported |= type; + } + } + foreach (const Solid::OpticalDrive::MediumType type, d->dvdTypeMap.keys()) { + if (dvdFeatures & d->dvdTypeMap[type]) { + supported |= type; + } + } + foreach (const Solid::OpticalDrive::MediumType type, d->bdTypeMap.keys()) { + if (bdFeatures & d->bdTypeMap[type]) { + supported |= type; + if (d->bdTypeMap[type] == kBDFeaturesWriteMask) { + supported |= Solid::OpticalDrive::Bdre; + } + } + } + + return supported; +} + +int IOKitOpticalDrive::readSpeed() const +{ + return 0; +} + +int IOKitOpticalDrive::writeSpeed() const +{ + return 0; +} + +QList IOKitOpticalDrive::writeSpeeds() const +{ + return {}; +} + +bool IOKitOpticalDrive::eject() +{ +#ifdef EJECT_USING_DISKARBITRATION + // give the devices 30 seconds to eject + int error = !d->eject(30.0); +#else + QProcess ejectJob; + int error = ejectJob.execute(QStandardPaths::findExecutable(QStringLiteral("hdiutil")), + {QStringLiteral("detach"), QStringLiteral("-verbose"), + QStringLiteral("/dev/") + m_device->property(QStringLiteral("BSD Name")).toString()}); + if (error) { + qWarning() << "hdiutil returned" << error << "trying to eject" << m_device->product(); + } +#endif //EJECT_USING_DISKARBITRATION + if (error) { + emit ejectDone(Solid::ErrorType::OperationFailed, QVariant(), m_device->udi()); + return false; + } else { + emit ejectDone(Solid::ErrorType::NoError, QVariant(), m_device->udi()); + return true; + } +} + diff --git a/src/solid/devices/backends/iokit/iokitopticaldrive.h b/src/solid/devices/backends/iokit/iokitopticaldrive.h new file mode 100644 index 0000000..229c324 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitopticaldrive.h @@ -0,0 +1,62 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H +#define SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H + +#include +#include "iokitstorage.h" + +namespace Solid +{ +namespace Backends +{ +namespace IOKit +{ +class IOKitOpticalDrive : public IOKitStorage, virtual public Solid::Ifaces::OpticalDrive +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::OpticalDrive) + +public: + explicit IOKitOpticalDrive(IOKitDevice *device); + virtual ~IOKitOpticalDrive(); + +public Q_SLOTS: + Solid::OpticalDrive::MediumTypes supportedMedia() const Q_DECL_OVERRIDE; + int readSpeed() const Q_DECL_OVERRIDE; + int writeSpeed() const Q_DECL_OVERRIDE; + QList writeSpeeds() const Q_DECL_OVERRIDE; + bool eject() Q_DECL_OVERRIDE; + +Q_SIGNALS: + void ejectPressed(const QString &udi) Q_DECL_OVERRIDE; + void ejectDone(Solid::ErrorType error, QVariant errorData, const QString &udi) Q_DECL_OVERRIDE; + void ejectRequested(const QString &udi); + +private: + class Private; + Private *d; +}; +} +} +} + +#endif // SOLID_BACKENDS_IOKIT_OPTICALDRIVE_H diff --git a/src/solid/devices/backends/iokit/iokitprocessor.cpp b/src/solid/devices/backends/iokit/iokitprocessor.cpp index 1f2282a..434d862 100644 --- a/src/solid/devices/backends/iokit/iokitprocessor.cpp +++ b/src/solid/devices/backends/iokit/iokitprocessor.cpp @@ -1,58 +1,99 @@ /* Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "iokitprocessor.h" #include "iokitdevice.h" #include +#include +#include +#include + +#include "../shared/cpufeatures.h" + +// from cfhelper.cpp +extern bool q_sysctlbyname(const char *name, QString &result); + using namespace Solid::Backends::IOKit; Processor::Processor(IOKitDevice *device) : DeviceInterface(device) { //IOKitDevice parent(device->parentUdi()); } Processor::~Processor() { } int Processor::number() const { return m_device->property(QLatin1String("IOCPUNumber")).toInt(); } int Processor::maxSpeed() const { - return 0; // TODO + uint64_t freq = 0; + size_t size = sizeof(freq); + + if (sysctlbyname("hw.cpufrequency", &freq, &size, nullptr, 0) < 0) { + qWarning() << "sysctl error reading hw.cpufrequency:" << strerror(errno); + return 0; + } else { + return int(freq / 1000000); + } } bool Processor::canChangeFrequency() const { - return false; // TODO + uint64_t minFreq = 0, maxFreq = 0; + size_t size = sizeof(uint64_t); + + if (sysctlbyname("hw.cpufrequency_min", &minFreq, &size, nullptr, 0) == 0 + && sysctlbyname("hw.cpufrequency_max", &maxFreq, &size, nullptr, 0) == 0) { + return maxFreq > minFreq; + } + return false; } Solid::Processor::InstructionSets Processor::instructionSets() const { - return 0; // TODO + // use sysctlbyname() and "machdep.cpu.features" + "machdep.cpu.extfeatures" + static Solid::Processor::InstructionSets cpuextensions = Solid::Backends::Shared::cpuFeatures(); + + return cpuextensions; } +QString Processor::vendor() +{ + QString qVendor; + q_sysctlbyname("machdep.cpu.vendor", qVendor); + return qVendor; +} + +QString Processor::product() +{ + QString product; + q_sysctlbyname("machdep.cpu.brand_string", product); + return product; +} diff --git a/src/solid/devices/backends/iokit/iokitprocessor.h b/src/solid/devices/backends/iokit/iokitprocessor.h index 4fd6394..5a16a6b 100644 --- a/src/solid/devices/backends/iokit/iokitprocessor.h +++ b/src/solid/devices/backends/iokit/iokitprocessor.h @@ -1,53 +1,55 @@ /* Copyright 2009 Harald Fernengel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef SOLID_BACKENDS_IOKIT_PROCESSOR_H #define SOLID_BACKENDS_IOKIT_PROCESSOR_H #include #include "iokitdeviceinterface.h" namespace Solid { namespace Backends { namespace IOKit { class IOKitDevice; class Processor : public DeviceInterface, virtual public Solid::Ifaces::Processor { Q_OBJECT Q_INTERFACES(Solid::Ifaces::Processor) public: Processor(IOKitDevice *device); virtual ~Processor(); - virtual int number() const; - virtual int maxSpeed() const; - virtual bool canChangeFrequency() const; - virtual Solid::Processor::InstructionSets instructionSets() const; + virtual int number() const Q_DECL_OVERRIDE; + virtual int maxSpeed() const Q_DECL_OVERRIDE; + virtual bool canChangeFrequency() const Q_DECL_OVERRIDE; + virtual Solid::Processor::InstructionSets instructionSets() const Q_DECL_OVERRIDE; + static QString vendor(); + static QString product(); }; } } } #endif // SOLID_BACKENDS_IOKIT_PROCESSOR_H diff --git a/src/solid/devices/backends/iokit/iokitstorage.cpp b/src/solid/devices/backends/iokit/iokitstorage.cpp new file mode 100644 index 0000000..b80d4c0 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitstorage.cpp @@ -0,0 +1,119 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "iokitstorage.h" + +#include + +#include +#include + +using namespace Solid::Backends::IOKit; + +IOKitStorage::IOKitStorage(IOKitDevice *device) + : Block(device) + , daDict(new DADictionary(device)) +{ +} + +IOKitStorage::IOKitStorage(const IOKitDevice *device) + : Block(device) + , daDict(new DADictionary(device)) +{ +} + +IOKitStorage::~IOKitStorage() +{ + delete daDict; +} + +Solid::StorageDrive::Bus IOKitStorage::bus() const +{ + const QString udi = m_device->udi(); + // TODO: figure out how to return something useful here. + if (udi.contains(QStringLiteral("/SATA@"))) { + return Solid::StorageDrive::Sata; + } + if (udi.contains(QStringLiteral("/SDXC@"))) { + // TODO: return something finer grained; the built-in card reader + // is NOT connected via USB on Macs, for instance (but there's no PCI option) + return Solid::StorageDrive::Usb; + } + if (udi.contains(QStringLiteral("/IOUSBInterface@"))) { + return Solid::StorageDrive::Usb; + } + if (daDict->stringForKey(kDADiskDescriptionDeviceProtocolKey) == QStringLiteral("USB")) { + return Solid::StorageDrive::Usb; + } + return Solid::StorageDrive::Platform; +} + +Solid::StorageDrive::DriveType IOKitStorage::driveType() const +{ + const QString udi = m_device->udi(); + const QString type = m_device->property(QLatin1String("className")).toString(); + + if (type == QStringLiteral("IOCDMedia") + || type == QStringLiteral("IOBDMedia") + || type == QStringLiteral("IODVDMedia")) { + return Solid::StorageDrive::CdromDrive; + } + if (udi.contains(QStringLiteral("/SDXC@"))) { + return Solid::StorageDrive::SdMmc; + } + if (daDict->stringForKey(kDADiskDescriptionDeviceModelKey) == QStringLiteral("Compact Flash")) { + return Solid::StorageDrive::CompactFlash; + } + return Solid::StorageDrive::HardDisk; +} + +bool IOKitStorage::isRemovable() const +{ + bool isExternal = false; + daDict->boolForKey(kDADiskDescriptionDeviceInternalKey, isExternal); + return isExternal || m_device->property(QLatin1String("Removable")).toBool(); +} + +bool IOKitStorage::isHotpluggable() const +{ + const Solid::StorageDrive::DriveType type = driveType(); + return bus() == Solid::StorageDrive::Usb + || type == Solid::StorageDrive::CdromDrive || type == Solid::StorageDrive::SdMmc; +} + +qulonglong IOKitStorage::size() const +{ + return m_device->property(QLatin1String("Size")).toULongLong(); +} + +QString IOKitStorage::vendor() const +{ + return daDict->stringForKey(kDADiskDescriptionDeviceVendorKey); +} + +QString IOKitStorage::product() const +{ + return daDict->stringForKey(kDADiskDescriptionDeviceModelKey); +} + +QString IOKitStorage::description() const +{ + return daDict->stringForKey(kDADiskDescriptionMediaNameKey); +} diff --git a/src/solid/devices/backends/iokit/iokitprocessor.h b/src/solid/devices/backends/iokit/iokitstorage.h similarity index 50% copy from src/solid/devices/backends/iokit/iokitprocessor.h copy to src/solid/devices/backends/iokit/iokitstorage.h index 4fd6394..80dcab8 100644 --- a/src/solid/devices/backends/iokit/iokitprocessor.h +++ b/src/solid/devices/backends/iokit/iokitstorage.h @@ -1,53 +1,63 @@ /* - Copyright 2009 Harald Fernengel + Copyright 2017 René J.V. Bertin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ -#ifndef SOLID_BACKENDS_IOKIT_PROCESSOR_H -#define SOLID_BACKENDS_IOKIT_PROCESSOR_H +#ifndef SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H +#define SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H -#include -#include "iokitdeviceinterface.h" +#include "iokitblock.h" +#include "dadictionary_p.h" + +#include namespace Solid { namespace Backends { namespace IOKit { -class IOKitDevice; - -class Processor : public DeviceInterface, virtual public Solid::Ifaces::Processor +class IOKitStorage : public Block, virtual public Solid::Ifaces::StorageDrive { Q_OBJECT - Q_INTERFACES(Solid::Ifaces::Processor) + Q_INTERFACES(Solid::Ifaces::StorageDrive) public: - Processor(IOKitDevice *device); - virtual ~Processor(); - - virtual int number() const; - virtual int maxSpeed() const; - virtual bool canChangeFrequency() const; - virtual Solid::Processor::InstructionSets instructionSets() const; + explicit IOKitStorage(IOKitDevice *device); + explicit IOKitStorage(const IOKitDevice *device); + ~IOKitStorage(); + + QString vendor() const; + QString product() const; + QString description() const; + +public Q_SLOTS: + Solid::StorageDrive::Bus bus() const Q_DECL_OVERRIDE; + Solid::StorageDrive::DriveType driveType() const Q_DECL_OVERRIDE; + + bool isRemovable() const Q_DECL_OVERRIDE; + bool isHotpluggable() const Q_DECL_OVERRIDE; + qulonglong size() const Q_DECL_OVERRIDE; +private: + DADictionary *daDict; }; } } } -#endif // SOLID_BACKENDS_IOKIT_PROCESSOR_H +#endif // SOLID_BACKENDS_IOKIT_IOKITSTORAGE_H diff --git a/src/solid/devices/backends/iokit/iokitstorageaccess.cpp b/src/solid/devices/backends/iokit/iokitstorageaccess.cpp new file mode 100644 index 0000000..3627415 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitstorageaccess.cpp @@ -0,0 +1,110 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "iokitstorageaccess.h" + +#include + +#include +#include + +using namespace Solid::Backends::IOKit; + +IOKitStorageAccess::IOKitStorageAccess(IOKitDevice *device) + : DeviceInterface(device) + , daDict(new DADictionary(device)) +{ + connect(device, SIGNAL(propertyChanged(QMap)), + this, SLOT(onPropertyChanged(QMap))); +} + +IOKitStorageAccess::IOKitStorageAccess(const IOKitDevice *device) + : DeviceInterface(device) + , daDict(new DADictionary(device)) +{ + connect(device, SIGNAL(propertyChanged(QMap)), + this, SLOT(onPropertyChanged(QMap))); +} + +IOKitStorageAccess::~IOKitStorageAccess() +{ + delete daDict; +} + +bool IOKitStorageAccess::isAccessible() const +{ + filePath(); + const QVariant isMounted = m_device->property(QStringLiteral("isMounted")); + return isMounted.isValid() && isMounted.toBool(); +} + +QString IOKitStorageAccess::filePath() const +{ + // mount points can change (but can they between invocations of filePath()?) + QString mountPoint; + if (const CFURLRef urlRef = daDict->cfUrLRefForKey(kDADiskDescriptionVolumePathKey)) { + const CFStringRef mpRef = CFURLCopyFileSystemPath(urlRef, kCFURLPOSIXPathStyle); + mountPoint = QString::fromCFString(mpRef); + CFRelease(mpRef); + m_device->setProperty("mountPoint", QVariant(mountPoint)); + bool isMounted = !mountPoint.isEmpty(); + const QString isMountedKey = QStringLiteral("isMounted"); + const QVariant wasMounted = m_device->property(isMountedKey); + if (wasMounted.isValid() && wasMounted.toBool() != isMounted) { + IOKitStorageAccess(m_device).onPropertyChanged(QMap{{isMountedKey,isMounted}}); + } + m_device->setProperty("isMounted", QVariant(isMounted)); + } + return mountPoint; +} + +bool IOKitStorageAccess::isIgnored() const +{ + if (m_device->iOKitPropertyExists(QStringLiteral("Open"))) { + // ignore storage volumes that aren't mounted + bool isIgnored = m_device->property(QStringLiteral("Open")).toBool() == false; + m_device->setProperty("isIgnored", QVariant(isIgnored)); + return isIgnored; + } + const QVariant isIgnored = m_device->property(QStringLiteral("isIgnored")); + return isIgnored.isValid() && isIgnored.toBool(); +} + +bool IOKitStorageAccess::setup() +{ + // TODO? + return false; +} + +bool IOKitStorageAccess::teardown() +{ + // TODO? + return false; +} + +void IOKitStorageAccess::onPropertyChanged(const QMap &changes) +{ + Q_FOREACH (const QString &property, changes.keys()) { + if (property == QStringLiteral("isMounted")) { + emit accessibilityChanged(m_device->property(QStringLiteral("isMounted")).toBool(), m_device->udi()); + } + } +} + diff --git a/src/solid/devices/backends/iokit/iokitstorageaccess.h b/src/solid/devices/backends/iokit/iokitstorageaccess.h new file mode 100644 index 0000000..6ae239b --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitstorageaccess.h @@ -0,0 +1,67 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef SOLID_BACKENDS_IOKIT_STORAGEACCESS_H +#define SOLID_BACKENDS_IOKIT_STORAGEACCESS_H + +#include +#include "iokitdeviceinterface.h" +#include "dadictionary_p.h" + +namespace Solid +{ +namespace Backends +{ +namespace IOKit +{ +class IOKitStorageAccess : public DeviceInterface, virtual public Solid::Ifaces::StorageAccess +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::StorageAccess) + +public: + IOKitStorageAccess(IOKitDevice *device); + IOKitStorageAccess(const IOKitDevice *device); + virtual ~IOKitStorageAccess(); + + bool isAccessible() const Q_DECL_OVERRIDE; + QString filePath() const Q_DECL_OVERRIDE; + bool isIgnored() const Q_DECL_OVERRIDE; +public Q_SLOTS: + bool setup() Q_DECL_OVERRIDE; + bool teardown() Q_DECL_OVERRIDE; + +Q_SIGNALS: + void accessibilityChanged(bool accessible, const QString &udi) Q_DECL_OVERRIDE; + void setupDone(Solid::ErrorType error, QVariant errorData, const QString &udi) Q_DECL_OVERRIDE; + void teardownDone(Solid::ErrorType error, QVariant errorData, const QString &udi) Q_DECL_OVERRIDE; + void setupRequested(const QString &udi) Q_DECL_OVERRIDE; + void teardownRequested(const QString &udi) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void onPropertyChanged(const QMap &changes); +private: + DADictionary *daDict; +}; +} +} +} + +#endif // SOLID_BACKENDS_IOKIT_STORAGEACCESS_H diff --git a/src/solid/devices/backends/iokit/iokitvolume.cpp b/src/solid/devices/backends/iokit/iokitvolume.cpp new file mode 100644 index 0000000..7d454b0 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitvolume.cpp @@ -0,0 +1,113 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#include "iokitvolume.h" +#include "iokitgenericinterface.h" + +#include + +#include +#include + +using namespace Solid::Backends::IOKit; + +IOKitVolume::IOKitVolume(IOKitDevice *device) + : Block(device) + , daDict(new DADictionary(device)) +{ +} + +IOKitVolume::IOKitVolume(const IOKitDevice *device) + : Block(device) + , daDict(new DADictionary(device)) +{ +} + +IOKitVolume::~IOKitVolume() +{ + delete daDict; +} + +bool IOKitVolume::isIgnored() const +{ + // ignore storage volumes that aren't mounted + bool isIgnored = m_device->property(QStringLiteral("Open")).toBool() == false; + m_device->setProperty("isIgnored", isIgnored); + m_device->setProperty("isMounted", !isIgnored); + return isIgnored; +} + +Solid::StorageVolume::UsageType IOKitVolume::usage() const +{ + const QString content = m_device->property(QStringLiteral("Content")).toString(); + if (content == QStringLiteral("CD_DA")) { + // this is (probably) a CD track + return Solid::StorageVolume::Other; + } + if (content.contains(QStringLiteral("partition_scheme"))) { + return Solid::StorageVolume::PartitionTable; + } + return Solid::StorageVolume::FileSystem; +} + +QString IOKitVolume::fsType() const +{ + return daDict->stringForKey(kDADiskDescriptionVolumeKindKey); +} + +QString IOKitVolume::label() const +{ + return daDict->stringForKey(kDADiskDescriptionVolumeNameKey); +} + +QString IOKitVolume::uuid() const +{ + return m_device->property(QStringLiteral("UUID")).toString(); +} + +qulonglong IOKitVolume::size() const +{ + return m_device->property(QStringLiteral("Size")).toULongLong(); +} + +QString IOKitVolume::encryptedContainerUdi() const +{ + return QString(); +} + +QString IOKitVolume::vendor() const +{ + return daDict->stringForKey(kDADiskDescriptionDeviceVendorKey); +} + +QString IOKitVolume::product() const +{ + return daDict->stringForKey(kDADiskDescriptionDeviceModelKey); +} + +QString IOKitVolume::description() const +{ + return daDict->stringForKey(kDADiskDescriptionMediaNameKey); +} + +DADiskRef IOKitVolume::daRef() const +{ + return daDict->daRef; +} diff --git a/src/solid/devices/backends/iokit/iokitvolume.h b/src/solid/devices/backends/iokit/iokitvolume.h new file mode 100644 index 0000000..4dc3718 --- /dev/null +++ b/src/solid/devices/backends/iokit/iokitvolume.h @@ -0,0 +1,67 @@ +/* + Copyright 2017 René J.V. Bertin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +#ifndef SOLID_BACKENDS_IOKIT_VOLUME_H +#define SOLID_BACKENDS_IOKIT_VOLUME_H + +#include +#include "iokitblock.h" +#include "dadictionary_p.h" + +#include + +namespace Solid +{ +namespace Backends +{ +namespace IOKit +{ +class IOKitVolume : public Block, virtual public Solid::Ifaces::StorageVolume +{ + Q_OBJECT + Q_INTERFACES(Solid::Ifaces::StorageVolume) + +public: + IOKitVolume(IOKitDevice *device); + IOKitVolume(const IOKitDevice *device); + virtual ~IOKitVolume(); + + bool isIgnored() const Q_DECL_OVERRIDE; + Solid::StorageVolume::UsageType usage() const Q_DECL_OVERRIDE; + QString fsType() const Q_DECL_OVERRIDE; + QString label() const Q_DECL_OVERRIDE; + QString uuid() const Q_DECL_OVERRIDE; + qulonglong size() const Q_DECL_OVERRIDE; + QString encryptedContainerUdi() const Q_DECL_OVERRIDE; + + QString vendor() const; + QString product() const; + QString description() const; + + DADiskRef daRef() const; + +private: + DADictionary *daDict; +}; +} +} +} + +#endif // SOLID_BACKENDS_IOKIT_VOLUME_H