IOUFIStorageServices.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include "IOUFIStorageServices.h"
#if ( USB_MASS_STORAGE_DEBUG == 1 )
#define PANIC_NOW(x) panic x
#define DEBUG_LEVEL 1
#include <IOKit/usb/IOUSBLog.h>
#define STATUS_LOG(x) USBLog x
#else
#define PANIC_NOW(x)
#define STATUS_LOG(x)
#endif
#define kNumberRetries 4
enum
{
kMaximumBlockCountRead = 128,
kMaximumBlockCountWrite = 128,
kMaximumByteCountRead = 65536,
kMaximumByteCountWrite = 65536
};
struct BlockServicesClientData
{
IOUFIStorageServices * owner;
IOStorageCompletion completionData;
IOMemoryDescriptor * clientBuffer;
UInt32 clientStartingBlock;
UInt32 clientRequestedBlockCount;
UInt32 clientRequestedBlockSize;
UInt32 retriesLeft;
};
typedef struct BlockServicesClientData BlockServicesClientData;
#define super IOBlockStorageDevice
OSDefineMetaClassAndStructors ( IOUFIStorageServices, IOBlockStorageDevice );
bool
IOUFIStorageServices::attach ( IOService * provider )
{
OSDictionary * scsiCharacterDict = NULL;
STATUS_LOG ( ( 6, "%s[%p]:: attach called", getName(), this ) );
if ( !super::attach ( provider ) )
{
return false;
}
fProvider = OSDynamicCast ( IOUSBMassStorageUFIDevice, provider );
if ( fProvider == NULL )
{
STATUS_LOG ( ( 1, "%s[%p]:: attach; wrong provider type!", getName(), this ) );
return false;
}
setProperty ( kIOPropertyProtocolCharacteristicsKey, fProvider->GetProtocolCharacteristicsDictionary ( ) );
setProperty ( kIOPropertyDeviceCharacteristicsKey, fProvider->GetDeviceCharacteristicsDictionary ( ) );
scsiCharacterDict = OSDynamicCast ( OSDictionary, fProvider->getProperty( kIOPropertySCSIDeviceCharacteristicsKey ) );
if ( scsiCharacterDict == NULL )
{
setProperty ( kIOMaximumBlockCountReadKey, kMaximumBlockCountRead );
setProperty ( kIOMaximumBlockCountWriteKey, kMaximumBlockCountWrite );
setProperty ( kIOMaximumByteCountReadKey, kMaximumByteCountRead );
setProperty ( kIOMaximumByteCountWriteKey, kMaximumByteCountWrite );
}
else
{
OSNumber * number = NULL;
UInt32 maxBlockCount = 0;
UInt64 maxByteCount = 0;
maxBlockCount = kMaximumBlockCountRead;
number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountReadKey ) );
if ( number != NULL )
{
maxBlockCount = number->unsigned32BitValue ( );
if ( maxBlockCount == 0 )
{
maxBlockCount = kMaximumBlockCountRead;
}
}
setProperty ( kIOMaximumBlockCountReadKey, maxBlockCount );
maxBlockCount = kMaximumBlockCountWrite;
number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountWriteKey ) );
if ( number != NULL )
{
maxBlockCount = number->unsigned32BitValue ( );
if ( maxBlockCount == 0 )
{
maxBlockCount = kMaximumBlockCountWrite;
}
}
setProperty ( kIOMaximumBlockCountWriteKey, maxBlockCount );
maxByteCount = kMaximumByteCountRead;
number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountReadKey ) );
if ( number != NULL )
{
maxByteCount = number->unsigned32BitValue ( );
if ( maxByteCount == 0 )
{
maxByteCount = kMaximumByteCountRead;
}
}
setProperty ( kIOMaximumByteCountReadKey, maxByteCount );
maxByteCount = kMaximumByteCountWrite;
number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountWriteKey ) );
if ( number != NULL )
{
maxByteCount = number->unsigned32BitValue ( );
if ( maxByteCount == 0 )
{
maxByteCount = kMaximumByteCountWrite;
}
}
setProperty ( kIOMaximumByteCountWriteKey, maxByteCount );
}
fMediaChanged = false;
fMediaPresent = false;
STATUS_LOG ( ( 6, "%s[%p]:: attach exiting", getName(), this ) );
return true;
}
void
IOUFIStorageServices::detach( IOService * provider )
{
STATUS_LOG ( ( 6, "%s[%p]: detach called", getName(), this ) );
super::detach( provider );
STATUS_LOG ( ( 6, "%s[%p]: detach exiting", getName(), this ) );
}
IOReturn
IOUFIStorageServices::message( UInt32 type,
IOService * nub,
void * arg )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG ( ( 6, "%s[%p]::message called", getName(), this ) );
switch ( type )
{
case kIOMessageMediaStateHasChanged:
{
STATUS_LOG ( ( 5, "%s[%p]:: type = kIOMessageMediaStateHasChanged, nub = %p", getName(), this, nub ) );
fMediaChanged = true;
fMediaPresent = true;
status = messageClients ( type, arg, sizeof ( IOMediaState ) );
STATUS_LOG ( ( 5, "%s[%p]:: status = %ld", getName(), this, ( UInt32 ) status ) );
}
break;
default:
{
status = super::message ( type, nub, arg );
}
break;
}
return status;
}
void
IOUFIStorageServices::AsyncReadWriteComplete ( void * clientData,
IOReturn status,
UInt64 actualByteCount )
{
IOUFIStorageServices * owner;
BlockServicesClientData * servicesData;
IOStorageCompletion returnData;
bool commandComplete = true;
servicesData = ( BlockServicesClientData * ) clientData;
returnData = servicesData->completionData;
owner = servicesData->owner;
STATUS_LOG ( ( 5, "%s[%p]:: AsyncReadWriteComplete; command status %x", owner->getName(), owner, status ) );
if ( ( ( status != kIOReturnNotAttached ) && ( status != kIOReturnOffline ) &&
( status != kIOReturnSuccess ) ) && ( servicesData->retriesLeft > 0 ) )
{
IOReturn requestStatus;
STATUS_LOG ( (5, "%s[%p]:: AsyncReadWriteComplete; retry command", owner->getName(), owner ) );
servicesData->retriesLeft--;
requestStatus = owner->fProvider->AsyncReadWrite (
servicesData->clientBuffer,
servicesData->clientStartingBlock,
servicesData->clientRequestedBlockCount,
servicesData->clientRequestedBlockSize,
clientData );
if ( requestStatus != kIOReturnSuccess )
{
commandComplete = true;
}
else
{
commandComplete = false;
}
}
if ( commandComplete == true )
{
IOFree ( clientData, sizeof ( BlockServicesClientData ) );
owner->fProvider->release();
owner->release();
IOStorage::complete ( &returnData, status, actualByteCount );
}
}
IOReturn
IOUFIStorageServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion )
{
UNUSED ( buffer );
UNUSED ( block );
UNUSED ( nblks );
UNUSED ( completion );
return kIOReturnUnsupported;
}
IOReturn
IOUFIStorageServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt64 block,
UInt64 nblks,
IOStorageAttributes * attributes,
IOStorageCompletion * completion )
{
BlockServicesClientData * clientData;
IODirection direction;
IOReturn requestStatus;
UInt32 requestBlockSize;
UNUSED ( attributes );
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
direction = buffer->getDirection();
if ( ( direction != kIODirectionIn ) && ( direction != kIODirectionOut ) )
{
return kIOReturnBadArgument;
}
clientData = ( BlockServicesClientData * ) IOMalloc ( sizeof( BlockServicesClientData ) );
if ( clientData == NULL )
{
STATUS_LOG ( ( 1, "%s[%p]:: doAsyncReadWrite; clientData malloc failed!", getName(), this ) );
return kIOReturnNoResources;
}
retain();
fProvider->retain();
requestBlockSize = fProvider->ReportMediumBlockSize();
STATUS_LOG ( ( 5, "%s[%p]:: doAsyncReadWrite; save completion data!", getName(), this ) );
clientData->owner = this;
clientData->completionData = *completion;
clientData->clientBuffer = buffer;
clientData->clientStartingBlock = block;
clientData->clientRequestedBlockCount = nblks;
clientData->clientRequestedBlockSize = requestBlockSize;
clientData->retriesLeft = kNumberRetries;
requestStatus = fProvider->AsyncReadWrite ( buffer, block, nblks, ( UInt64 ) requestBlockSize, ( void * ) clientData );
if ( requestStatus != kIOReturnSuccess )
{
if ( clientData != NULL )
{
IOFree ( clientData, sizeof ( BlockServicesClientData ) );
}
}
return requestStatus;
}
IOReturn
IOUFIStorageServices::doSyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOReturn result;
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
retain();
fProvider->retain();
result = fProvider->SyncReadWrite( buffer, block, nblks, fProvider->ReportMediumBlockSize() );
fProvider->release();
release();
return result;
}
IOReturn
IOUFIStorageServices::doEjectMedia ( void )
{
IOReturn result;
fMediaPresent = false;
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
retain();
fProvider->retain();
result = fProvider->EjectTheMedium();
fProvider->release();
release();
return result;
}
IOReturn
IOUFIStorageServices::doFormatMedia ( UInt64 byteCapacity )
{
IOReturn result;
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
retain();
fProvider->retain();
result = fProvider->FormatMedium( byteCapacity / ( fProvider->ReportMediumBlockSize() ),
fProvider->ReportMediumBlockSize() );
fProvider->release();
release();
return result;
}
UInt32
IOUFIStorageServices::doGetFormatCapacities ( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
IOReturn result;
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
retain();
fProvider->retain();
result = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount );
fProvider->release();
release();
return result;
}
IOReturn
IOUFIStorageServices::doLockUnlockMedia ( bool doLock )
{
UNUSED ( doLock );
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::doSynchronizeCache ( void )
{
if ( isInactive() != false )
{
return kIOReturnNotAttached;
}
return kIOReturnSuccess;
}
char *
IOUFIStorageServices::getVendorString ( void )
{
return fProvider->GetVendorString ( );
}
char *
IOUFIStorageServices::getProductString ( void )
{
return fProvider->GetProductString ( );
}
char *
IOUFIStorageServices::getRevisionString ( void )
{
return fProvider->GetRevisionString ( );
}
char *
IOUFIStorageServices::getAdditionalDeviceInfoString ( void )
{
STATUS_LOG ( (6, "%s::%s called", getName ( ), __FUNCTION__ ) );
return ( ( char * ) "No Additional Device Info" );
}
IOReturn
IOUFIStorageServices::reportBlockSize ( UInt64 * blockSize )
{
*blockSize = fProvider->ReportMediumBlockSize ( );
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportEjectability ( bool * isEjectable )
{
*isEjectable = true;
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportLockability ( bool * isLockable )
{
*isLockable = true;
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportPollRequirements ( bool * pollIsRequired,
bool * pollIsExpensive )
{
*pollIsRequired = false;
*pollIsExpensive = false;
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportMaxValidBlock ( UInt64 * maxBlock )
{
*maxBlock = ( fProvider->ReportMediumTotalBlockCount ( ) - 1 );
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportMediaState ( bool * mediaPresent,
bool * changed )
{
STATUS_LOG ( ( 6, "%s[%p]::reportMediaState.", getName(), this ) );
*mediaPresent = fMediaPresent;
*changed = fMediaChanged;
if ( fMediaChanged )
{
fMediaChanged = !fMediaChanged;
}
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportRemovability ( bool * isRemovable )
{
*isRemovable = true;
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::reportWriteProtection ( bool * isWriteProtected )
{
*isWriteProtected = fProvider->ReportMediumWriteProtection();
return kIOReturnSuccess;
}
IOReturn
IOUFIStorageServices::getWriteCacheState ( bool * enabled )
{
UNUSED ( enabled );
return ( kIOReturnUnsupported );
}
IOReturn
IOUFIStorageServices::setWriteCacheState ( bool enabled )
{
UNUSED ( enabled );
return ( kIOReturnUnsupported );
}
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 1 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 2 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 3 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 4 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 5 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 6 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 7 );
OSMetaClassDefineReservedUnused( IOUFIStorageServices, 8 );