#include <CoreFoundation/CoreFoundation.h>
#include <DiskArbitration/DiskArbitration.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
#include "ExternalMedia.h"
#include "PMAssertions.h"
#include "PrivateLib.h"
#if !TARGET_OS_EMBEDDED
#define _kExternalMediaAssertionName "com.apple.powermanagement.externalmediamounted"
static bool weLikeTheDisk(DADiskRef disk);
static void adjustExternalDiskAssertion(void);
static void _DiskDisappeared(DADiskRef disk, void *context);
static void _DiskAppeared(DADiskRef disk, void * context);
static CFMutableSetRef gExternalMediaSet = NULL;
static IOPMAssertionID gDiskAssertionID = kIOPMNullAssertionID;
static DASessionRef gDASession = NULL;
__private_extern__ void ExternalMedia_prime(void)
{
gExternalMediaSet = CFSetCreateMutable(0, 0, &kCFTypeSetCallBacks);
if (!gExternalMediaSet)
return;
gDASession = DASessionCreate(0);
DARegisterDiskAppearedCallback(gDASession, kDADiskDescriptionMatchVolumeMountable, _DiskAppeared, NULL);
DARegisterDiskDisappearedCallback(gDASession, kDADiskDescriptionMatchVolumeMountable, _DiskDisappeared, NULL);
DASessionScheduleWithRunLoop(gDASession, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
static void _DiskDisappeared(DADiskRef disk, void *context)
{
if (weLikeTheDisk(disk))
{
CFSetRemoveValue(gExternalMediaSet, disk);
adjustExternalDiskAssertion();
}
}
static void _DiskAppeared(DADiskRef disk, void * context)
{
if (weLikeTheDisk(disk))
{
CFSetSetValue(gExternalMediaSet, disk);
adjustExternalDiskAssertion();
}
}
static bool weLikeTheDisk(DADiskRef disk)
{
CFDictionaryRef description = NULL;
CFStringRef protocol = NULL;
bool ret = false;
description = DADiskCopyDescription(disk);
if (description) {
if (CFDictionaryGetValue(description, kDADiskDescriptionDeviceInternalKey) == kCFBooleanFalse) {
ret = true;
} else {
protocol = CFDictionaryGetValue(description, kDADiskDescriptionDeviceProtocolKey);
if (protocol &&
(CFEqual(protocol, CFSTR(kIOPropertyPhysicalInterconnectTypeUSB)) ||
CFEqual(protocol, CFSTR(kIOPropertyPhysicalInterconnectTypeSecureDigital))))
{
ret = true;
}
}
CFRelease(description);
}
return ret;
}
static void adjustExternalDiskAssertion()
{
CFIndex deviceCount = CFSetGetCount(gExternalMediaSet);
if (0 == deviceCount)
{
InternalReleaseAssertion(&gDiskAssertionID);
return;
}
if (0 < deviceCount)
{
CFMutableDictionaryRef assertionDescription = NULL;
assertionDescription = _IOPMAssertionDescriptionCreate(
_kIOPMAssertionTypeExternalMedia,
CFSTR(_kExternalMediaAssertionName),
NULL, CFSTR("An external media device is attached."), NULL, 0, NULL);
InternalCreateAssertion(assertionDescription,
&gDiskAssertionID);
CFRelease(assertionDescription);
return;
}
return;
}
#endif