#include <libkern/c++/OSString.h>
#include <libkern/c++/OSDictionary.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/storage/IOBlockStorageDriver.h>
#include "SCSITaskLib.h"
#include "SCSITaskLibPriv.h"
#include "IOSCSIProtocolInterface.h"
#include "IOSCSIPeripheralDeviceType05.h"
#include "IODVDServices.h"
#define DEBUG 0
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "DVD Services"
#if DEBUG
#define SCSI_DVD_SERVICES_DEBUGGING_LEVEL 0
#endif
#include "IOSCSIArchitectureModelFamilyDebugging.h"
#if ( SCSI_DVD_SERVICES_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( SCSI_DVD_SERVICES_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( SCSI_DVD_SERVICES_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#if (_DVD_USE_DATA_CACHING_)
#define _CACHE_BLOCK_COUNT_ 5
#define _CACHE_BLOCK_SIZE_ 2352
#if ( 0 )
#define CACHE_LOG(x) IOLog x
#else
#define CACHE_LOG(x)
#endif
#endif
#define super IODVDBlockStorageDevice
OSDefineMetaClassAndStructors ( IODVDServices, IODVDBlockStorageDevice );
#define kNumberRetries 4
struct BlockServicesClientData
{
IODVDServices * owner;
IOStorageCompletion completionData;
IOMemoryDescriptor * clientBuffer;
UInt32 clientStartingBlock;
UInt32 clientRequestedBlockCount;
bool clientReadCDCall;
CDSectorArea clientSectorArea;
CDSectorType clientSectorType;
UInt32 retriesLeft;
#if (_DVD_USE_DATA_CACHING_)
UInt8 * transferSegBuffer;
IOMemoryDescriptor * transferSegDesc;
UInt32 transferStart;
UInt32 transferCount;
#endif
};
typedef struct BlockServicesClientData BlockServicesClientData;
#if 0
#pragma mark -
#pragma mark ₯ Public Methods - API Exported to layers above
#pragma mark -
#endif
bool
IODVDServices::start ( IOService * provider )
{
OSNumber * cdFeatures = NULL;
OSNumber * dvdFeatures = NULL;
UInt32 cdFeaturesFlags = 0;
UInt32 dvdFeaturesFlags = 0;
bool result = false;
fProvider = OSDynamicCast ( IOSCSIPeripheralDeviceType05, provider );
require_nonzero ( fProvider, ErrorExit );
require ( super::start ( fProvider ), ErrorExit );
cdFeatures = ( OSNumber * ) fProvider->getProperty (
kIOPropertySupportedCDFeatures );
dvdFeatures = ( OSNumber * ) fProvider->getProperty (
kIOPropertySupportedDVDFeatures );
check ( cdFeatures );
check ( dvdFeatures );
cdFeaturesFlags = ( kCDFeaturesWriteOnceMask | kCDFeaturesReWriteableMask ) &
cdFeatures->unsigned32BitValue ( );
dvdFeaturesFlags = ( kDVDFeaturesWriteOnceMask | kDVDFeaturesReWriteableMask |
kDVDFeaturesRandomWriteableMask ) &
dvdFeatures->unsigned32BitValue ( );
if ( ( cdFeaturesFlags != 0 ) || ( dvdFeaturesFlags != 0 ) )
{
require ( setProperty ( kIOMatchCategoryKey,
kSCSITaskUserClientIniterKey ), ErrorExit );
}
#if (_DVD_USE_DATA_CACHING_)
fDataCacheStorage = ( UInt8 * ) IOMalloc ( _CACHE_BLOCK_COUNT_ * _CACHE_BLOCK_SIZE_ );
require_nonzero ( fDataCacheStorage, ErrorExit );
fDataCacheStartBlock = 0;
fDataCacheBlockCount = 0;
fDataCacheLock = IOSimpleLockAlloc ( );
require_nonzero_action ( fDataCacheLock,
ErrorExit,
IOFree ( fDataCacheStorage,
_CACHE_BLOCK_COUNT_ * _CACHE_BLOCK_SIZE_ ) );
#endif
setProperty ( kIOPropertyProtocolCharacteristicsKey,
fProvider->GetProtocolCharacteristicsDictionary ( ) );
setProperty ( kIOPropertyDeviceCharacteristicsKey,
fProvider->GetDeviceCharacteristicsDictionary ( ) );
registerService ( );
result = true;
ErrorExit:
return result;
}
bool
IODVDServices::open ( IOService * client,
IOOptionBits options,
IOStorageAccess access )
{
return super::open ( client, options, ( void * ) access );
}
IOReturn
IODVDServices::message ( UInt32 type,
IOService * nub,
void * arg )
{
IOReturn status = kIOReturnSuccess;
switch ( type )
{
case kSCSIServicesNotification_ExclusivityChanged:
case kIOMessageMediaStateHasChanged:
case kIOMessageTrayStateChange:
case kIOMessageMediaAccessChange:
{
status = messageClients ( type, arg );
}
break;
default:
{
status = super::message ( type, nub, arg );
}
break;
}
return status;
}
IOReturn
IODVDServices::setProperties ( OSObject * properties )
{
IOReturn status = kIOReturnBadArgument;
OSDictionary * dict = NULL;
UInt8 trayState = 0xFF;
Boolean userClientActive = false;
require_nonzero ( properties, ErrorExit );
dict = OSDynamicCast ( OSDictionary, properties );
require_nonzero ( dict, ErrorExit );
require_nonzero_action ( fProvider,
ErrorExit,
status = kIOReturnNotAttached );
fProvider->retain ( );
require_nonzero ( dict->getObject ( "TrayState" ), ReleaseProvider );
userClientActive = fProvider->GetUserClientExclusivityState ( );
require_action (
( userClientActive == false ),
ReleaseProvider,
status = kIOReturnExclusiveAccess;
messageClients ( kIOMessageTrayStateChange,
( void * ) kMessageTrayStateChangeRequestRejected ) );
fProvider->CheckPowerState ( );
status = fProvider->GetTrayState ( &trayState );
require_success ( status, ReleaseProvider );
status = fProvider->SetTrayState ( !trayState );
ReleaseProvider:
fProvider->release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doAsyncReadCD ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
CDSectorArea sectorArea,
CDSectorType sectorType,
IOStorageCompletion completion )
{
BlockServicesClientData * clientData = NULL;
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
#if (_DVD_USE_DATA_CACHING_)
if ( sectorType == kCDSectorTypeCDDA )
{
IOSimpleLockLock ( fDataCacheLock );
if ( fDataCacheBlockCount != 0 )
{
if ( ( nblks <= fDataCacheBlockCount ) && ( block >= fDataCacheStartBlock ) &&
( block + nblks <= fDataCacheStartBlock + fDataCacheBlockCount) )
{
UInt32 startByte = ( block - fDataCacheStartBlock ) * _CACHE_BLOCK_SIZE_;
buffer->writeBytes ( 0, &fDataCacheStorage[startByte], ( nblks * _CACHE_BLOCK_SIZE_ ) );
IOSimpleLockUnlock ( fDataCacheLock );
IOStorage::complete ( completion, kIOReturnSuccess, ( nblks * _CACHE_BLOCK_SIZE_ ) );
status = kIOReturnSuccess;
goto Exit;
}
}
IOSimpleLockUnlock ( fDataCacheLock );
}
#endif
clientData = IONew ( BlockServicesClientData, 1 );
require_nonzero_action ( clientData, ErrorExit, status = kIOReturnNoResources );
retain ( );
fProvider->retain ( );
clientData->owner = this;
clientData->completionData = completion;
clientData->clientBuffer = buffer;
clientData->clientStartingBlock = block;
clientData->clientRequestedBlockCount = nblks;
clientData->clientReadCDCall = true;
clientData->clientSectorArea = sectorArea;
clientData->clientSectorType = sectorType;
clientData->retriesLeft = kNumberRetries;
fProvider->CheckPowerState ( );
#if (_DVD_USE_DATA_CACHING_)
if ( sectorType == kCDSectorTypeCDDA )
{
clientData->transferSegBuffer = ( UInt8 * ) IOMalloc ( nblks * _CACHE_BLOCK_SIZE_ );
if ( clientData->transferSegBuffer != NULL )
{
IOSimpleLockLock ( fDataCacheLock );
if ( ( fDataCacheBlockCount != 0 ) && ( block > fDataCacheStartBlock ) && ( nblks > fDataCacheBlockCount ) && ( block < ( fDataCacheStartBlock + fDataCacheBlockCount ) ) ) {
UInt32 offsetBlk;
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, block = %ld\n", block ) );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, nblks = %ld\n", nblks ) );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, fDataCacheStartBlock = %ld\n", fDataCacheStartBlock ) );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, fDataCacheBlockCount = %ld\n", fDataCacheBlockCount ) );
offsetBlk = ( block - fDataCacheStartBlock );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, offsetBlk = %ld\n", offsetBlk ) );
clientData->transferCount = nblks - ( fDataCacheBlockCount - offsetBlk );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, clientData->transferCount = %ld\n", clientData->transferCount ) );
clientData->transferStart = block + ( fDataCacheBlockCount - offsetBlk );
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, clientData->transferStart = %ld\n", clientData->transferStart ) );
clientData->transferSegDesc = IOMemoryDescriptor::withAddress (
clientData->transferSegBuffer,
clientData->transferCount * _CACHE_BLOCK_SIZE_,
kIODirectionIn );
if ( clientData->transferSegDesc != NULL )
{
buffer->writeBytes ( 0,
&fDataCacheStorage[offsetBlk * _CACHE_BLOCK_SIZE_],
( ( fDataCacheBlockCount - offsetBlk ) * _CACHE_BLOCK_SIZE_ ) );
IOSimpleLockUnlock ( fDataCacheLock );
status = fProvider->AsyncReadCD ( clientData->transferSegDesc,
clientData->transferStart,
clientData->transferCount,
sectorArea,
sectorType,
( void * ) clientData );
goto Exit;
}
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, transferSegDesc = NULL\n" ) );
}
CACHE_LOG ( ( "IODVDServices::doAsyncReadCD called, transferSegBuffer = NULL\n" ) );
IOSimpleLockUnlock ( fDataCacheLock );
}
if ( clientData->transferSegBuffer != NULL )
{
IOFree ( clientData->transferSegBuffer, ( nblks * _CACHE_BLOCK_SIZE_ ) );
}
}
clientData->transferSegBuffer = NULL;
clientData->transferSegDesc = NULL;
clientData->transferStart = block;
clientData->transferCount = nblks;
#endif
status = fProvider->AsyncReadCD ( buffer,
block,
nblks,
sectorArea,
sectorType,
( void * ) clientData );
ErrorExit:
Exit:
return status;
}
IOReturn
IODVDServices::doAsyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks,
IOStorageCompletion completion )
{
BlockServicesClientData * clientData = NULL;
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
clientData = IONew ( BlockServicesClientData, 1 );
require_nonzero_action ( clientData, ErrorExit, status = kIOReturnNoResources );
retain ( );
fProvider->retain ( );
clientData->owner = this;
clientData->completionData = completion;
clientData->clientBuffer = buffer;
clientData->clientStartingBlock = block;
clientData->clientRequestedBlockCount = nblks;
clientData->clientReadCDCall = false;
clientData->retriesLeft = kNumberRetries;
fProvider->CheckPowerState ( );
#if (_DVD_USE_DATA_CACHING_)
clientData->transferSegBuffer = NULL;
clientData->transferSegDesc = NULL;
clientData->transferStart = 0;
clientData->transferCount = 0;
#endif
status = fProvider->AsyncReadWrite ( buffer, block, nblks, ( void * ) clientData );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doSyncReadWrite ( IOMemoryDescriptor * buffer,
UInt32 block,
UInt32 nblks )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SyncReadWrite ( buffer, block, nblks );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doFormatMedia ( UInt64 byteCapacity )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->FormatMedia ( byteCapacity );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
UInt32
IODVDServices::doGetFormatCapacities ( UInt64 * capacities,
UInt32 capacitiesMaxCount ) const
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doEjectMedia ( void )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
#if (_DVD_USE_DATA_CACHING_)
fDataCacheStartBlock = 0;
fDataCacheBlockCount = 0;
#endif
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->EjectTheMedia ( );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doLockUnlockMedia ( bool doLock )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->LockUnlockMedia ( doLock );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
char *
IODVDServices::getVendorString ( void )
{
return fProvider->GetVendorString ( );
}
char *
IODVDServices::getProductString ( void )
{
return fProvider->GetProductString ( );
}
char *
IODVDServices::getRevisionString ( void )
{
return fProvider->GetRevisionString ( );
}
char *
IODVDServices::getAdditionalDeviceInfoString ( void )
{
STATUS_LOG ( ( "%s::%s called\n", getName ( ), __FUNCTION__ ) );
return ( "No Additional Device Info" );
}
IOReturn
IODVDServices::reportBlockSize ( UInt64 * blockSize )
{
return fProvider->ReportBlockSize ( blockSize );
}
IOReturn
IODVDServices::reportEjectability ( bool * isEjectable )
{
return fProvider->ReportEjectability ( isEjectable );
}
IOReturn
IODVDServices::reportLockability ( bool * isLockable )
{
return fProvider->ReportLockability ( isLockable );
}
IOReturn
IODVDServices::reportMediaState ( bool * mediaPresent,
bool * changed )
{
return fProvider->ReportMediaState ( mediaPresent, changed );
}
IOReturn
IODVDServices::reportPollRequirements ( bool * pollIsRequired,
bool * pollIsExpensive )
{
return fProvider->ReportPollRequirements ( pollIsRequired, pollIsExpensive );
}
IOReturn
IODVDServices::reportMaxReadTransfer ( UInt64 blockSize,
UInt64 * max )
{
return fProvider->ReportMaxReadTransfer ( blockSize, max );
}
IOReturn
IODVDServices::reportMaxValidBlock ( UInt64 * maxBlock )
{
return fProvider->ReportMaxValidBlock ( maxBlock );
}
IOReturn
IODVDServices::reportRemovability ( bool * isRemovable )
{
return fProvider->ReportRemovability ( isRemovable );
}
IOReturn
IODVDServices::readISRC ( UInt8 track, CDISRC isrc )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadISRC ( track, isrc );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readMCN ( CDMCN mcn )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadMCN ( mcn );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readTOC ( IOMemoryDescriptor * buffer )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadTOC ( buffer );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readTOC ( IOMemoryDescriptor * buffer,
CDTOCFormat format,
UInt8 msf,
UInt8 trackSessionNumber,
UInt16 * actualByteCount )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadTOC ( buffer,
format,
msf,
trackSessionNumber,
actualByteCount );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readDiscInfo ( IOMemoryDescriptor * buffer,
UInt16 * actualByteCount )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadDiscInfo ( buffer, actualByteCount );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readTrackInfo ( IOMemoryDescriptor * buffer,
UInt32 address,
CDTrackInfoAddressType addressType,
UInt16 * actualByteCount )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadTrackInfo ( buffer,
address,
addressType,
actualByteCount );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::audioPause ( bool pause )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->AudioPause ( pause );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::audioPlay ( CDMSF timeStart, CDMSF timeStop )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->AudioPlay ( timeStart, timeStop );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::audioScan ( CDMSF timeStart, bool reverse )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->AudioScan ( timeStart, reverse );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::audioStop ( void )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->AudioStop ( );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::getAudioStatus ( CDAudioStatus * cdAudioStatus )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->GetAudioStatus ( cdAudioStatus );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::getAudioVolume ( UInt8 * leftVolume,
UInt8 * rightVolume )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->GetAudioVolume ( leftVolume, rightVolume );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::setAudioVolume ( UInt8 leftVolume, UInt8 rightVolume )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SetAudioVolume ( leftVolume, rightVolume );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::doSynchronizeCache ( void )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SynchronizeCache ( );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::reportMaxWriteTransfer ( UInt64 blockSize,
UInt64 * max )
{
return fProvider->ReportMaxWriteTransfer ( blockSize, max );
}
IOReturn
IODVDServices::reportWriteProtection ( bool * isWriteProtected )
{
return fProvider->ReportWriteProtection ( isWriteProtected );
}
UInt32
IODVDServices::getMediaType ( void )
{
return fProvider->GetMediaType ( );
}
IOReturn
IODVDServices::getSpeed ( UInt16 * kilobytesPerSecond )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->GetMediaAccessSpeed ( kilobytesPerSecond );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::setSpeed ( UInt16 kilobytesPerSecond )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SetMediaAccessSpeed ( kilobytesPerSecond );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::readDVDStructure ( IOMemoryDescriptor * buffer,
const UInt8 structureFormat,
const UInt32 logicalBlockAddress,
const UInt8 layer,
const UInt8 agid )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReadDVDStructure (
buffer,
( UInt32 ) buffer->getLength ( ),
structureFormat,
logicalBlockAddress,
layer,
agid );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::reportKey ( IOMemoryDescriptor * buffer,
const DVDKeyClass keyClass,
const UInt32 lba,
const UInt8 agid,
const DVDKeyFormat keyFormat )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->ReportKey ( buffer,
keyClass,
lba,
agid,
keyFormat );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
IOReturn
IODVDServices::sendKey ( IOMemoryDescriptor * buffer,
const DVDKeyClass keyClass,
const UInt8 agid,
const DVDKeyFormat keyFormat )
{
IOReturn status = kIOReturnNotAttached;
require ( ( isInactive ( ) == false ), ErrorExit );
retain ( );
fProvider->retain ( );
fProvider->CheckPowerState ( );
status = fProvider->SendKey ( buffer,
keyClass,
agid,
keyFormat );
fProvider->release ( );
release ( );
ErrorExit:
return status;
}
bool
IODVDServices::handleOpen ( IOService * client,
IOOptionBits options,
void * access )
{
bool result = false;
if ( ( options & kIOSCSITaskUserClientAccessMask ) == 0 )
{
result = super::handleOpen ( client, options, access );
goto Exit;
}
if ( fClients == NULL )
{
fClients = OSSet::withCapacity ( 1 );
}
require_nonzero ( fClients, ErrorExit );
fClients->setObject ( client );
result = true;
Exit:
ErrorExit:
return result;
}
void
IODVDServices::handleClose ( IOService * client,
IOOptionBits options )
{
if ( ( options & kIOSCSITaskUserClientAccessMask ) == 0 )
{
super::handleClose ( client, options );
}
else
{
fClients->removeObject ( client );
}
}
bool
IODVDServices::handleIsOpen ( const IOService * client ) const
{
bool result = false;
if ( client == NULL )
{
require_nonzero ( fClients, CallSuperClassError );
require_nonzero ( fClients->getCount ( ), CallSuperClassError );
result = true;
}
else
{
require_nonzero ( fClients, CallSuperClassError );
require ( fClients->containsObject ( client ), CallSuperClassError );
result = true;
}
return result;
CallSuperClassError:
result = super::handleIsOpen ( client );
return result;
}
#if 0
#pragma mark -
#pragma mark ₯ Public Static Methods
#pragma mark -
#endif
void
IODVDServices::AsyncReadWriteComplete ( void * clientData,
IOReturn status,
UInt64 actualByteCount )
{
IODVDServices * owner;
IOStorageCompletion returnData;
BlockServicesClientData * bsClientData;
bool commandComplete = true;
bsClientData = ( BlockServicesClientData * ) clientData;
returnData = bsClientData->completionData;
owner = bsClientData->owner;
if ( ( ( status != kIOReturnNotAttached ) &&
( status != kIOReturnOffline ) &&
( status != kIOReturnUnsupportedMode ) &&
( status != kIOReturnNotPrivileged ) &&
( status != kIOReturnSuccess ) ) &&
( bsClientData->retriesLeft > 0 ) )
{
IOReturn requestStatus;
ERROR_LOG ( ( "IODVDServices: AsyncReadWriteComplete retry\n" ) );
bsClientData->retriesLeft--;
if ( bsClientData->clientReadCDCall == true )
{
#if (_DVD_USE_DATA_CACHING_)
if ( ( bsClientData->transferSegDesc != NULL ) &&
( bsClientData->transferCount != 0 ) )
{
requestStatus = owner->fProvider->AsyncReadCD (
bsClientData->transferSegDesc,
bsClientData->transferStart,
bsClientData->transferCount,
bsClientData->clientSectorArea,
bsClientData->clientSectorType,
clientData );
}
else
{
requestStatus = owner->fProvider->AsyncReadCD (
bsClientData->clientBuffer,
bsClientData->clientStartingBlock,
bsClientData->clientRequestedBlockCount,
bsClientData->clientSectorArea,
bsClientData->clientSectorType,
clientData );
}
#else
requestStatus = owner->fProvider->AsyncReadCD (
bsClientData->clientBuffer,
bsClientData->clientStartingBlock,
bsClientData->clientRequestedBlockCount,
bsClientData->clientSectorArea,
bsClientData->clientSectorType,
clientData );
#endif
}
else
{
requestStatus = owner->fProvider->AsyncReadWrite (
bsClientData->clientBuffer,
bsClientData->clientStartingBlock,
bsClientData->clientRequestedBlockCount,
clientData );
}
if ( requestStatus != kIOReturnSuccess )
{
commandComplete = true;
}
else
{
commandComplete = false;
}
}
if ( commandComplete == true )
{
#if (_DVD_USE_DATA_CACHING_)
if ( bsClientData->transferSegBuffer != NULL )
{
if ( status == kIOReturnSuccess )
{
( bsClientData->clientBuffer )->writeBytes ( ( ( bsClientData->clientRequestedBlockCount - bsClientData->transferCount ) * _CACHE_BLOCK_SIZE_ ),
bsClientData->transferSegBuffer, ( bsClientData->transferCount * _CACHE_BLOCK_SIZE_ ) );
actualByteCount = ( bsClientData->clientRequestedBlockCount * _CACHE_BLOCK_SIZE_ );
}
( bsClientData->transferSegDesc )->release ( );
IOFree ( bsClientData->transferSegBuffer, ( bsClientData->clientRequestedBlockCount * _CACHE_BLOCK_SIZE_ ) );
}
if ( status == kIOReturnSuccess )
{
if ( ( bsClientData->clientReadCDCall == true ) && ( bsClientData->clientSectorType == kCDSectorTypeCDDA ) )
{
IOSimpleLockLock ( owner->fDataCacheLock );
if ( bsClientData->clientRequestedBlockCount >= _CACHE_BLOCK_COUNT_ )
{
UInt32 offset;
offset = ( ( bsClientData->clientRequestedBlockCount - _CACHE_BLOCK_COUNT_ ) * _CACHE_BLOCK_SIZE_ );
( bsClientData->clientBuffer )->readBytes ( offset, owner->fDataCacheStorage,
( _CACHE_BLOCK_COUNT_ * _CACHE_BLOCK_SIZE_ ) );
owner->fDataCacheStartBlock = bsClientData->clientStartingBlock + ( bsClientData->clientRequestedBlockCount - _CACHE_BLOCK_COUNT_ );
owner->fDataCacheBlockCount = _CACHE_BLOCK_COUNT_;
}
IOSimpleLockUnlock ( owner->fDataCacheLock );
}
}
#endif
IODelete ( clientData, BlockServicesClientData, 1 );
owner->fProvider->release ( );
owner->release ( );
IOStorage::complete ( returnData, status, actualByteCount );
}
}
#if 0
#pragma mark -
#pragma mark ₯ Protected Methods
#pragma mark -
#endif
void
IODVDServices::free ( void )
{
#if (_DVD_USE_DATA_CACHING_)
if ( fDataCacheStorage != NULL )
{
IOFree ( fDataCacheStorage,
( _CACHE_BLOCK_COUNT_ * _CACHE_BLOCK_SIZE_ ) );
fDataCacheStorage = NULL;
}
fDataCacheStartBlock = 0;
fDataCacheBlockCount = 0;
if ( fDataCacheLock != NULL )
{
IOSimpleLockFree ( fDataCacheLock );
fDataCacheLock = NULL;
}
#endif
super::free ( );
}
#if 0
#pragma mark -
#pragma mark ₯ VTable Padding
#pragma mark -
#endif
OSMetaClassDefineReservedUnused ( IODVDServices, 1 );
OSMetaClassDefineReservedUnused ( IODVDServices, 2 );
OSMetaClassDefineReservedUnused ( IODVDServices, 3 );
OSMetaClassDefineReservedUnused ( IODVDServices, 4 );
OSMetaClassDefineReservedUnused ( IODVDServices, 5 );
OSMetaClassDefineReservedUnused ( IODVDServices, 6 );
OSMetaClassDefineReservedUnused ( IODVDServices, 7 );
OSMetaClassDefineReservedUnused ( IODVDServices, 8 );