11#include "libmythbase/mythconfig.h"
19#include <IOKit/IOKitLib.h>
20#include <IOKit/storage/IOMedia.h>
21#include <IOKit/storage/IOCDMedia.h>
22#include <IOKit/storage/IODVDMedia.h>
23#include <IOKit/storage/IOBlockStorageDevice.h>
24#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
25#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
26#include <DiskArbitration/DiskArbitration.h>
29#define IOMainPort IOMasterPort
37 CFArrayRef keys,
void *context);
48 kern_return_t kernResult;
51 QString msg = QString(
"FindMediaType() - ");
54 kernResult = IORegistryEntryCreateIterator(service,
56 kIORegistryIterateRecursively
57 | kIORegistryIterateParents,
60 if (KERN_SUCCESS != kernResult)
62 LOG(VB_GENERAL, LOG_CRIT, msg +
63 QString(
"IORegistryEntryCreateIterator returned %1")
68 LOG(VB_GENERAL, LOG_CRIT, msg +
69 "IORegistryEntryCreateIterator returned NULL iterator");
75 IOObjectRetain(service);
79 bool isWholeMedia =
false;
80 if (IOObjectConformsTo(service, kIOMediaClass))
84 wholeMedia = IORegistryEntryCreateCFProperty
85 (service, CFSTR(kIOMediaWholeKey),
86 kCFAllocatorDefault, 0);
90 LOG(VB_GENERAL, LOG_ALERT, msg +
91 "Could not retrieve Whole property");
95 isWholeMedia = CFBooleanGetValue((CFBooleanRef)wholeMedia);
96 CFRelease(wholeMedia);
102 if (IOObjectConformsTo(service, kIODVDMediaClass))
104 else if (IOObjectConformsTo(service, kIOCDMediaClass))
108 IOObjectRelease(service);
110 }
while ((service = IOIteratorNext(iter))
113 IOObjectRelease(iter);
123 CFMutableDictionaryRef matchingDict;
124 kern_return_t kernResult;
126 io_service_t service;
127 QString msg = QString(
"MediaTypeForBSDName(%1)")
132 if (!bsdName || !*bsdName)
134 LOG(VB_GENERAL, LOG_ALERT, msg +
" - No name supplied?");
138 matchingDict = IOBSDNameMatching(
sMasterPort, 0, bsdName);
141 LOG(VB_GENERAL, LOG_ALERT,
142 msg +
" - IOBSDNameMatching() returned a NULL dictionary.");
148 kernResult = IOServiceGetMatchingServices(
sMasterPort, matchingDict, &iter);
150 if (KERN_SUCCESS != kernResult)
152 LOG(VB_GENERAL, LOG_ALERT,
153 QString(msg +
" - IOServiceGetMatchingServices() returned %2")
159 LOG(VB_GENERAL, LOG_ALERT,
160 msg +
" - IOServiceGetMatchingServices() returned a NULL "
165 service = IOIteratorNext(iter);
169 IOObjectRelease(iter);
173 LOG(VB_GENERAL, LOG_ALERT,
174 msg +
" - IOIteratorNext() returned a NULL iterator");
178 IOObjectRelease(service);
193 CFDictionaryGetValue(diskDetails, kDADiskDescriptionVolumeNameKey);
198 size = CFStringGetLength(name) + 1;
199 volName = (
char *) malloc(size);
202 LOG(VB_GENERAL, LOG_ALERT,
203 QString(
"getVolName() - Can't malloc(%1)?").arg(size));
207 if (!CFStringGetCString(name, volName, size, kCFStringEncodingUTF8))
219static QString
getModel(CFDictionaryRef diskDetails)
225 if (kCFBooleanTrue ==
226 CFDictionaryGetValue(diskDetails,
227 kDADiskDescriptionDeviceInternalKey))
228 desc.append(
"Internal ");
231 strRef = CFDictionaryGetValue(diskDetails,
232 kDADiskDescriptionDeviceVendorKey);
235 desc.append(CFStringGetCStringPtr((CFStringRef)strRef,
236 kCFStringEncodingMacRoman));
241 strRef = CFDictionaryGetValue(diskDetails,
242 kDADiskDescriptionDeviceModelKey);
245 desc.append(CFStringGetCStringPtr((CFStringRef)strRef,
246 kCFStringEncodingMacRoman));
251 desc.truncate(desc.length() - 1);
267 const char *BSDname = DADiskGetBSDName(disk);
268 CFDictionaryRef details;
273 QString msg =
"diskAppearedCallback() - ";
279 LOG(VB_MEDIA, LOG_INFO, msg +
"Skipping non-local device");
285 LOG(VB_GENERAL, LOG_ALERT, msg +
"Error. Invoked with a NULL context.");
297 details = DADiskCopyDescription(disk);
299 if (kCFBooleanFalse ==
300 CFDictionaryGetValue(details, kDADiskDescriptionMediaRemovableKey))
302 LOG(VB_MEDIA, LOG_INFO, msg + QString(
"Skipping non-removable %1")
312 LOG(VB_MEDIA, LOG_INFO, msg + QString(
"No volume name for dev %1")
320 if (model.contains(
"Disk Image"))
322 LOG(VB_MEDIA, LOG_INFO, msg + QString(
"DMG %1 mounted, ignoring")
336 LOG(VB_MEDIA, LOG_INFO, QString(
"Found disk %1 - volume name '%2'.")
337 .arg(BSDname).arg(volName));
339 mtd->
diskInsert(BSDname, volName, model, isCDorDVD);
347 const char *BSDname = DADiskGetBSDName(disk);
355 if (CFArrayContainsValue(keys, CFRangeMake(0, CFArrayGetCount(keys)),
356 kDADiskDescriptionVolumeNameKey))
358 const char *BSDname = DADiskGetBSDName(disk);
359 CFDictionaryRef details = DADiskCopyDescription(disk);
362 LOG(VB_MEDIA, LOG_INFO, QString(
"Disk %1 - changed name to '%2'.")
363 .arg(BSDname).arg(volName));
366 ->diskRename(BSDname, volName);
379 CFDictionaryRef match = kDADiskDescriptionMatchVolumeMountable;
380 DASessionRef daSession = DASessionCreate(kCFAllocatorDefault);
384 DARegisterDiskAppearedCallback(daSession, match,
386 DARegisterDiskDisappearedCallback(daSession, match,
388 DARegisterDiskDescriptionChangedCallback(daSession, match,
389 kDADiskDescriptionWatchVolumeName,
392 DASessionScheduleWithRunLoop(daSession,
393 CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
402 CFRunLoopRunInMode(kCFRunLoopDefaultMode,
409 CFRelease(daSession);
421 QString model,
bool isCDorDVD)
424 QString msg =
"MonitorThreadDarwin::diskInsert";
426 LOG(VB_MEDIA, LOG_DEBUG, msg + QString(
"(%1,%2,'%3',%4)")
427 .arg(devName).arg(volName).arg(model).arg(isCDorDVD));
436 LOG(VB_GENERAL, LOG_ALERT, msg +
"Couldn't create MythMediaDevice.");
445 QString mnt =
"/Volumes/"; mnt += volName;
452 LOG(VB_MEDIA, LOG_WARNING,
453 (msg +
"() - Waiting for mount '%1' to become stable.").arg(mnt));
454 usleep(std::chrono::microseconds(120000));
455 if ( ++attempts > 4 )
456 usleep(std::chrono::microseconds(200000));
460 LOG(VB_MEDIA, LOG_ALERT, msg +
"() - Giving up");
482 LOG(VB_MEDIA, LOG_DEBUG,
483 QString(
"MonitorThreadDarwin::diskRemove(%1)").arg(devName));
490 LOG(VB_MEDIA, LOG_INFO,
"Couldn't find MythMediaDevice: " + devName);
503 LOG(VB_MEDIA, LOG_DEBUG,
504 QString(
"MonitorThreadDarwin::diskRename(%1,%2)")
505 .arg(devName).arg(volName));
515 pDevice->
setMountPath((QString(
"/Volumes/") + volName).toLatin1());
523 LOG(VB_MEDIA, LOG_INFO,
524 QString(
"Couldn't find MythMediaDevice: %1").arg(devName));
548 qRegisterMetaType<MythMediaStatus>(
"MythMediaStatus");
550 LOG(VB_MEDIA, LOG_NOTICE,
"Starting MediaMonitor");
564 LOG(VB_GENERAL, LOG_ERR,
"MediaMonitor::AddDevice(null)");
594 CFMutableDictionaryRef props =
nullptr;
596 props = (CFMutableDictionaryRef) IORegistryEntrySearchCFProperty(drive, kIOServicePlane, CFSTR(kIOPropertyProtocolCharacteristicsKey), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
600 const void *location = CFDictionaryGetValue(props, CFSTR(kIOPropertyPhysicalInterconnectLocationKey));
601 if (CFEqual(location, CFSTR(
"Internal")))
602 desc.append(
"Internal ");
605 props = (CFMutableDictionaryRef) IORegistryEntrySearchCFProperty(drive, kIOServicePlane, CFSTR(kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
608 const void *product = CFDictionaryGetValue(props, CFSTR(kIOPropertyProductNameKey));
609 const void *vendor = CFDictionaryGetValue(props, CFSTR(kIOPropertyVendorNameKey));
612 desc.append(CFStringGetCStringPtr((CFStringRef)vendor, kCFStringEncodingMacRoman));
617 desc.append(CFStringGetCStringPtr((CFStringRef)product, kCFStringEncodingMacRoman));
623 desc.truncate(desc.length() - 1);
639 kern_return_t kernResult;
640 CFMutableDictionaryRef devices;
643 QString msg = QString(
"GetCDRomBlockDevices() - ");
646 devices = IOServiceMatching(kIOBlockStorageDeviceClass);
649 LOG(VB_GENERAL, LOG_ALERT, msg +
"No Storage Devices? Unlikely!");
654 kernResult = IOServiceGetMatchingServices(
sMasterPort, devices, &iter);
656 if (KERN_SUCCESS != kernResult)
658 LOG(VB_GENERAL, LOG_ALERT, msg +
659 QString(
"IORegistryEntryCreateIterator returned %1")
665 LOG(VB_GENERAL, LOG_ALERT, msg +
666 "IORegistryEntryCreateIterator returned a NULL iterator");
672 while ((drive = IOIteratorNext(iter)))
674 CFMutableDictionaryRef
p =
nullptr;
676 IORegistryEntryCreateCFProperties(drive, &
p, kCFAllocatorDefault, 0);
679 const void *
type = CFDictionaryGetValue(
p, CFSTR(
"device-type"));
681 if (CFEqual(
type, CFSTR(
"DVD")) || CFEqual(
type, CFSTR(
"CD")))
686 LOG(VB_MEDIA, LOG_INFO, desc.prepend(
"Found CD/DVD: "));
691 LOG(VB_GENERAL, LOG_ALERT,
692 msg +
"Could not retrieve drive properties");
694 IOObjectRelease(drive);
697 IOObjectRelease(iter);
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
static void usleep(std::chrono::microseconds time)
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
void diskRemove(QString devName)
void diskRename(const char *devName, const char *volName)
Deal with the user, or another program, renaming a volume.
void diskInsert(const char *devName, const char *volName, QString model, bool isCDorDVD=1)
Create a MythMedia instance and insert in MythMediaMonitor list.
void run(void) override
Use the DiskArbitration Daemon to inform us of media changes.
QPointer< MediaMonitor > m_monitor
static MythCDROM * get(QObject *par, const QString &devicePath, bool SuperMount, bool AllowEject)
static MythHDD * Get(QObject *par, const char *devicePath, bool SuperMount, bool AllowEject)
Helper function used to create a new instance of a hard disk device.
static const iso6937table * d
#define LOG(_MASK_, _LEVEL_, _QSTRING_)