#include <IOKit/assert.h>
#include <IOKit/IOLib.h>
#include <IOKit/storage/IOStorage.h>
#define super IOService
OSDefineMetaClassAndAbstractStructors(IOStorage, IOService)
#if TARGET_OS_OSX && defined(__x86_64__)
#define kIOStorageSynchronizeOptionsUnsupported ( ( IOStorage::ExpansionData * ) 1 )
extern "C" void _ZN9IOStorage16synchronizeCacheEP9IOService( IOStorage *, IOService * );
extern "C" void _ZN9IOStorage11synchronizeEP9IOServiceyyj( IOStorage *, IOService *, UInt64, UInt64, IOStorageSynchronizeOptions );
#define storageSynchronizeOptions( storage ) ( ( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService * ) ) &IOStorage::synchronizeCache ) == _ZN9IOStorage16synchronizeCacheEP9IOService ) && \
( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService *, UInt64, UInt64, IOStorageSynchronizeOptions ) ) &IOStorage::synchronize ) != _ZN9IOStorage11synchronizeEP9IOServiceyyj ) )
#endif
class IOStorageSyncerLock
{
protected:
IOLock * _lock;
public:
inline IOStorageSyncerLock( )
{
_lock = IOLockAlloc( );
}
inline ~IOStorageSyncerLock( )
{
if ( _lock ) IOLockFree( _lock );
}
inline void lock( )
{
IOLockLock( _lock );
}
inline void unlock( )
{
IOLockUnlock( _lock );
}
inline void sleep( void * event )
{
IOLockSleep( _lock, event, THREAD_UNINT );
}
inline void wakeup( void * event )
{
IOLockWakeup( _lock, event, false );
}
};
static IOStorageSyncerLock gIOStorageSyncerLock;
class IOStorageSyncer
{
protected:
IOReturn _status;
bool _wakeup;
public:
IOStorageSyncer( )
{
_wakeup = false;
}
IOReturn wait( )
{
gIOStorageSyncerLock.lock( );
while ( _wakeup == false )
{
gIOStorageSyncerLock.sleep( this );
}
gIOStorageSyncerLock.unlock( );
return _status;
}
void signal( IOReturn status )
{
_status = status;
gIOStorageSyncerLock.lock( );
_wakeup = true;
gIOStorageSyncerLock.wakeup( this );
gIOStorageSyncerLock.unlock( );
}
};
static void storageCompletion(void * target,
void * parameter,
IOReturn status,
UInt64 actualByteCount)
{
if (parameter) *((UInt64 *)parameter) = actualByteCount;
((IOStorageSyncer *)target)->signal(status);
}
#if TARGET_OS_OSX && defined(__x86_64__)
bool IOStorage::attach(IOService * provider)
{
if ( super::attach( provider ) == false )
{
return false;
}
if ( storageSynchronizeOptions( this ) == false )
{
_respondsTo_synchronizeCache = kIOStorageSynchronizeOptionsUnsupported;
}
if ( _respondsTo_synchronizeCache )
{
OSDictionary * features;
features = OSDynamicCast( OSDictionary, getProperty( kIOStorageFeaturesKey, gIOServicePlane ) );
if ( features )
{
features = OSDictionary::withDictionary( features );
if ( features )
{
features->removeObject( kIOStorageFeatureBarrier );
setProperty( kIOStorageFeaturesKey, features );
features->release( );
}
}
}
return true;
}
#endif
void IOStorage::complete(IOStorageCompletion * completion,
IOReturn status,
UInt64 actualByteCount)
{
if ( completion && completion->action )
{
( completion->action )( completion->target, completion->parameter, status, actualByteCount );
}
}
bool IOStorage::open(IOService * client,
IOOptionBits options,
IOStorageAccess access)
{
return super::open(client, options, (void *) (uintptr_t) access);
}
IOReturn IOStorage::read(IOService * client,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageAttributes * attributes,
UInt64 * actualByteCount)
{
IOStorageCompletion completion;
IOStorageSyncer syncer;
completion.target = &syncer;
completion.action = storageCompletion;
completion.parameter = actualByteCount;
read(client, byteStart, buffer, attributes, &completion);
return syncer.wait();
}
IOReturn IOStorage::write(IOService * client,
UInt64 byteStart,
IOMemoryDescriptor * buffer,
IOStorageAttributes * attributes,
UInt64 * actualByteCount)
{
IOStorageCompletion completion;
IOStorageSyncer syncer;
completion.target = &syncer;
completion.action = storageCompletion;
completion.parameter = actualByteCount;
write(client, byteStart, buffer, attributes, &completion);
return syncer.wait();
}
#if TARGET_OS_OSX && defined(__x86_64__)
IOReturn IOStorage::discard(IOService * client,
UInt64 byteStart,
UInt64 byteCount)
{
return kIOReturnUnsupported;
}
IOReturn IOStorage::unmap(IOService * client,
IOStorageExtent * extents,
UInt32 extentsCount,
IOStorageUnmapOptions options)
{
return kIOReturnUnsupported;
}
#endif
IOReturn
IOStorage::getProvisionStatus(IOService * client,
UInt64 byteStart,
UInt64 byteCount,
UInt32 * extentsCount,
IOStorageProvisionExtent * extents,
IOStorageGetProvisionStatusOptions options)
{
return kIOReturnUnsupported;
}
bool IOStorage::lockPhysicalExtents(IOService * client)
{
return false;
}
IOStorage * IOStorage::copyPhysicalExtent(IOService * client,
UInt64 * byteStart,
UInt64 * byteCount)
{
return NULL;
}
void IOStorage::unlockPhysicalExtents(IOService * client)
{
return;
}
IOReturn IOStorage::setPriority(IOService * client,
IOStorageExtent * extents,
UInt32 extentsCount,
IOStoragePriority priority)
{
return kIOReturnUnsupported;
}
#if TARGET_OS_OSX && defined(__x86_64__)
IOReturn IOStorage::synchronizeCache(IOService * client)
{
if ( _respondsTo_synchronizeCache )
{
return synchronize( client, 0, 0, _kIOStorageSynchronizeOption_super__synchronizeCache );
}
else
{
return synchronize( client, 0, 0 );
}
}
IOReturn IOStorage::synchronize(IOService * client,
UInt64 byteStart,
UInt64 byteCount,
IOStorageSynchronizeOptions options)
{
return synchronizeCache( client );
}
#endif
OSMetaClassDefineReservedUsed(IOStorage, 0);
OSMetaClassDefineReservedUsed(IOStorage, 1);
OSMetaClassDefineReservedUsed(IOStorage, 2);
OSMetaClassDefineReservedUsed(IOStorage, 3);
OSMetaClassDefineReservedUsed(IOStorage, 4);
OSMetaClassDefineReservedUsed(IOStorage, 5);
OSMetaClassDefineReservedUsed(IOStorage, 6);
OSMetaClassDefineReservedUnused(IOStorage, 7);
OSMetaClassDefineReservedUnused(IOStorage, 8);
OSMetaClassDefineReservedUnused(IOStorage, 9);
OSMetaClassDefineReservedUnused(IOStorage, 10);
OSMetaClassDefineReservedUnused(IOStorage, 11);
OSMetaClassDefineReservedUnused(IOStorage, 12);
OSMetaClassDefineReservedUnused(IOStorage, 13);
OSMetaClassDefineReservedUnused(IOStorage, 14);
OSMetaClassDefineReservedUnused(IOStorage, 15);