IOUSBMassStorageClass.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include "IOUSBMassStorageClass.h"
#include "Debugging.h"
#include <IOKit/scsi-commands/IOSCSIPeripheralDeviceNub.h>
#if (USB_MASS_STORAGE_DEBUG == 1)
#define STATUS_LOG(x) IOLog x
#define PANIC_NOW(x) IOPanic x
#else
#define STATUS_LOG(x)
#define PANIC_NOW(x)
#endif
#define DEBUGGING_LEVEL 0
#define DEBUGLOG kprintf
#define super IOSCSIProtocolServices
OSDefineMetaClassAndStructors( IOUSBMassStorageClass, IOSCSIProtocolServices )
bool
IOUSBMassStorageClass::init( OSDictionary * propTable )
{
if( super::init( propTable ) == false)
{
return false;
}
return true;
}
bool
IOUSBMassStorageClass::start( IOService * provider )
{
IOUSBFindEndpointRequest request;
if( super::start( provider ) == false )
{
STATUS_LOG(("%s: superclass start failure.\n", getName()));
return false;
}
reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) );
bzero ( reserved, sizeof ( ExpansionData ) );
SetInterfaceReference( OSDynamicCast( IOUSBInterface, provider) );
if ( GetInterfaceReference() == NULL )
{
STATUS_LOG(("%s: the provider is not an IOUSBInterface object\n",
getName()));
return false;
}
STATUS_LOG(("%s: USB Mass Storage @ %d\n",
getName(),
GetInterfaceReference()->GetDevice()->GetAddress()));
if ( GetInterfaceReference()->open( this ) == false)
{
STATUS_LOG(("%s: could not open the interface\n", getName()));
return false;
}
fBulkInPipe = NULL;
fBulkOutPipe = NULL;
fInterruptPipe = NULL;
fClients = NULL;
SetMaxLogicalUnitNumber( 0 );
fBulkOnlyCommandTag = 0;
fBulkOnlyCommandStructInUse = false;
fCBICommandStructInUse = false;
if ( getProperty( kIOUSBMassStorageCharacteristics ) == NULL )
{
fPreferredProtocol = GetInterfaceReference()->GetInterfaceProtocol();
fPreferredSubclass = GetInterfaceReference()->GetInterfaceSubClass();
}
else
{
OSDictionary * characterDict;
characterDict = OSDynamicCast( OSDictionary,
getProperty( kIOUSBMassStorageCharacteristics ));
if ( characterDict->getObject( kIOUSBMassStoragePreferredProtocol )
== NULL )
{
fPreferredProtocol =
GetInterfaceReference()->GetInterfaceProtocol();
}
else
{
OSNumber * preferredProtocol;
preferredProtocol = OSDynamicCast( OSNumber,
characterDict->getObject( kIOUSBMassStoragePreferredProtocol ));
fPreferredProtocol = preferredProtocol->unsigned32BitValue();
}
if ( characterDict->getObject( kIOUSBMassStoragePreferredSubclass ) == NULL )
{
fPreferredSubclass =
GetInterfaceReference()->GetInterfaceSubClass();
}
else
{
OSNumber * preferredSubclass;
preferredSubclass = OSDynamicCast( OSNumber, characterDict->getObject( kIOUSBMassStoragePreferredSubclass ));
fPreferredSubclass = preferredSubclass->unsigned32BitValue();
}
}
STATUS_LOG(("%s: Preferred Protocol is: %d\n", getName(), fPreferredProtocol));
STATUS_LOG(("%s: Preferred Subclass is: %d\n", getName(), fPreferredSubclass));
STATUS_LOG(("%s: Configure the Storage interface\n", getName()));
switch ( GetInterfaceProtocol() )
{
case kProtocolControlBulkInterrupt:
{
request.type = kUSBInterrupt;
request.direction = kUSBIn;
fInterruptPipe = GetInterfaceReference()->FindNextPipe(NULL, &request);
STATUS_LOG(("%s: find interrupt pipe\n", getName()));
if(( GetInterfaceProtocol() == kProtocolControlBulkInterrupt)
&& (fInterruptPipe == 0))
{
STATUS_LOG(("%s: No interrupt pipe for CBI, abort\n", getName()));
goto abortStart;
}
}
break;
case kProtocolControlBulk:
case kProtocolBulkOnly:
{
STATUS_LOG(("%s: Bulk Only - skip interrupt pipe\n",
getName()));
fInterruptPipe = NULL;
}
break;
default:
{
goto abortStart;
}
break;
}
STATUS_LOG(("%s: find bulk in pipe\n", getName()));
request.type = kUSBBulk;
request.direction = kUSBIn;
fBulkInPipe = GetInterfaceReference()->FindNextPipe(NULL, &request);
if ( fBulkInPipe == NULL )
{
STATUS_LOG(("%s: No bulk in pipe found, aborting\n",
getName()));
goto abortStart;
}
STATUS_LOG(("%s: find bulk out pipe\n", getName()));
request.type = kUSBBulk;
request.direction = kUSBOut;
fBulkOutPipe = GetInterfaceReference()->FindNextPipe(NULL, &request);
if ( fBulkOutPipe == NULL )
{
STATUS_LOG(("%s: No bulk out pipe found, aborting\n",
getName()));
goto abortStart;
}
STATUS_LOG(("%s: successfully configured\n", getName()));
InitializePowerManagement( GetInterfaceReference() );
BeginProvidedServices();
return true;
abortStart:
STATUS_LOG(("%s: aborting startup. Stop the provider.\n", getName() ));
stop( provider );
return false;
}
void
IOUSBMassStorageClass::stop(IOService * provider)
{
STATUS_LOG(("%s: Bye bye!\n", getName()));
EndProvidedServices();
fBulkInPipe = NULL;
fBulkOutPipe = NULL;
fInterruptPipe = NULL;
super::stop(provider);
}
void
IOUSBMassStorageClass::free ( void )
{
if ( reserved != NULL )
{
if ( fClients != NULL )
{
fClients->release();
fClients = NULL;
}
IOFree ( reserved, sizeof ( ExpansionData ) );
reserved = NULL;
}
super::free ( );
}
IOReturn
IOUSBMassStorageClass::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn result;
STATUS_LOG ( ("%s: message = %lx called\n", getName(), type ) );
switch( type )
{
case kIOMessageServiceIsTerminated:
{
IOUSBInterface * currentInterface;
STATUS_LOG(("%s: message kIOMessageServiceIsTerminated.\n", getName() ));
currentInterface = GetInterfaceReference();
if ( currentInterface != NULL )
{
STATUS_LOG(("%s: message kIOMessageServiceIsTerminated interface is non NULL.\n", getName() ));
SetInterfaceReference( NULL );
currentInterface->close(this);
SendNotification_DeviceRemoved( );
}
result = kIOReturnSuccess;
}
break;
case kIOMessageServiceIsRequestingClose:
{
IOUSBInterface * currentInterface;
STATUS_LOG(("%s: message kIOMessageServiceIsRequestingClose.\n", getName() ));
SendNotification_DeviceRemoved( );
currentInterface = GetInterfaceReference();
if ( currentInterface != NULL )
{
SetInterfaceReference( NULL );
currentInterface->close(this);
}
result = kIOReturnSuccess;
}
break;
default:
{
result = super::message( type, provider, argument );
}
}
return result;
}
bool
IOUSBMassStorageClass::BeginProvidedServices( void )
{
STATUS_LOG(("%s: Determine the maximum LUN\n", getName()));
if( GetInterfaceProtocol() == kProtocolBulkOnly )
{
IOReturn status;
bool maxLUNDetermined = false;
if( getProperty( kIOUSBMassStorageCharacteristics ) != NULL )
{
OSDictionary * characterDict = OSDynamicCast( OSDictionary,
getProperty( kIOUSBMassStorageCharacteristics ));
if( characterDict->getObject( kIOUSBMassStorageMaxLogicalUnitNumber ) != NULL )
{
OSNumber * maxLUN = OSDynamicCast( OSNumber,
characterDict->getObject( kIOUSBMassStorageMaxLogicalUnitNumber ) );
if( maxLUN != NULL )
{
SetMaxLogicalUnitNumber( maxLUN->unsigned8BitValue() );
maxLUNDetermined = true;
}
}
}
if( maxLUNDetermined == false )
{
fUSBDeviceRequest.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBInterface);
fUSBDeviceRequest.bRequest = 0xFE;
fUSBDeviceRequest.wValue = 0;
fUSBDeviceRequest.wIndex = 0;
fUSBDeviceRequest.wLength = 1;
fUSBDeviceRequest.pData = &fMaxLogicalUnitNumber;
status = GetInterfaceReference()->DeviceRequest( &fUSBDeviceRequest );
if ( status != kIOReturnSuccess )
{
SetMaxLogicalUnitNumber( 0 );
if( status == kIOUSBPipeStalled )
{
UInt8 eStatus[2];
GetStatusEndpointStatus( GetControlPipe(), &eStatus[0], NULL);
}
}
}
}
else
{
SetMaxLogicalUnitNumber( 0 );
}
STATUS_LOG(("%s: Maximum supported LUN is: %d\n",
getName(),
GetMaxLogicalUnitNumber() ));
STATUS_LOG(("%s: successfully configured\n", getName()));
if ( GetMaxLogicalUnitNumber() == 0 )
{
registerService();
fClients = NULL;
}
else
{
fClients = OSSet::withCapacity( GetMaxLogicalUnitNumber() + 1 );
for ( int loopLUN = 0; loopLUN <= GetMaxLogicalUnitNumber(); loopLUN++)
{
STATUS_LOG ( ( "IOUSBMassStorageClass::CreatePeripheralDeviceNubForLUN entering.\n" ) );
IOSCSILogicalUnitNub * nub = OSTypeAlloc ( IOSCSILogicalUnitNub );
if ( nub == NULL )
{
PANIC_NOW(( "IOUSBMassStorageClass::CreatePeripheralDeviceNubForLUN failed\n" ));
return false;
}
nub->init( 0 );
if ( nub->attach( this ) == false )
{
if ( isInactive() == false )
{
PANIC_NOW(( "IOUSBMassStorageClass::CreatePeripheralDeviceNubForLUN unable to attach nub" ));
}
nub->release();
return false;
}
nub->SetLogicalUnitNumber( loopLUN );
if( nub->start( this ) == false )
{
nub->detach( this );
}
else
{
nub->registerService( kIOServiceSynchronous );
}
nub->release();
STATUS_LOG ( ( "IOUSBMassStorageClass::CreatePeripheralDeviceNubForLUN exiting.\n" ) );
}
}
return true;
}
bool
IOUSBMassStorageClass::EndProvidedServices( void )
{
return true;
}
#pragma mark -
#pragma mark *** CDB Transport Methods ***
#pragma mark -
bool
IOUSBMassStorageClass::SendSCSICommand(
SCSITaskIdentifier request,
SCSIServiceResponse * serviceResponse,
SCSITaskStatus * taskStatus )
{
IOReturn status;
*taskStatus = kSCSITaskStatus_No_Status;
*serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
STATUS_LOG(("%s: SendSCSICommand was called\n", getName()));
if ( request == NULL )
{
STATUS_LOG(("%s: SendSCSICommand was called with a NULL CDB \n",
getName()));
return true;
}
if ( GetInterfaceReference() == NULL )
{
return true;
}
#if (USB_MASS_STORAGE_DEBUG == 1)
SCSICommandDescriptorBlock cdbData;
STATUS_LOG(("%s: SendSCSICommand CDB data: ", getName()));
GetCommandDescriptorBlock( request, &cdbData );
for ( int i=0; i < GetCommandDescriptorBlockSize(request); i ++ )
{
STATUS_LOG(("%X : ", cdbData[i]));
}
STATUS_LOG(( "\n" ));
#endif
if( GetInterfaceProtocol() == kProtocolBulkOnly)
{
if ( fBulkOnlyCommandStructInUse == true )
{
return false;
}
fBulkOnlyCommandStructInUse = true;
STATUS_LOG(("%s: SendSCSICommandforBulkOnlyProtocol sent \n", getName() ));
status = SendSCSICommandForBulkOnlyProtocol( request );
if( status != kIOReturnSuccess )
{
fBulkOnlyCommandStructInUse = false;
}
STATUS_LOG(("%s: SendSCSICommandforBulkOnlyProtocol returned %d\n",
getName(),
status));
}
else
{
if ( fCBICommandStructInUse == true )
{
return false;
}
fCBICommandStructInUse = true;
status = SendSCSICommandForCBIProtocol( request );
if( status != kIOReturnSuccess )
{
fCBICommandStructInUse = false;
}
STATUS_LOG(("%s: SendSCSICommandforCBIProtocol returned %d\n",
getName(),
status));
}
if ( status == kIOReturnSuccess )
{
*serviceResponse = kSCSIServiceResponse_Request_In_Process;
}
return true;
}
void
IOUSBMassStorageClass::CompleteSCSICommand( SCSITaskIdentifier request, IOReturn status )
{
fBulkOnlyCommandStructInUse = false;
fCBICommandStructInUse = false;
if ( status == kIOReturnSuccess )
{
CommandCompleted( request, kSCSIServiceResponse_TASK_COMPLETE, kSCSITaskStatus_GOOD );
}
else
{
CommandCompleted( request, kSCSIServiceResponse_TASK_COMPLETE, kSCSITaskStatus_CHECK_CONDITION );
}
}
SCSIServiceResponse
IOUSBMassStorageClass::AbortSCSICommand( SCSITaskIdentifier abortTask )
{
IOReturn status = kIOReturnSuccess;
STATUS_LOG(("%s: AbortSCSICommand was called\n", getName()));
if ( abortTask == NULL )
{
STATUS_LOG(("%s: AbortSCSICommand was called with a NULL CDB object\n",
getName()));
return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
}
if ( GetInterfaceReference() == NULL )
{
STATUS_LOG(("%s: AbortSCSICommand was called with a NULL interface\n",
getName()));
return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
}
if(GetInterfaceReference()->GetInterfaceProtocol() == kProtocolBulkOnly)
{
status = AbortSCSICommandForBulkOnlyProtocol( abortTask );
STATUS_LOG(("%s: abortCDBforBulkOnlyProtocol returned %d\n",
getName(),
status));
}
else
{
status = AbortSCSICommandForCBIProtocol( abortTask );
STATUS_LOG(("%s: abortCDBforCBIProtocol returned %d\n",
getName(),
status));
}
return kSCSIServiceResponse_FUNCTION_REJECTED;
}
bool
IOUSBMassStorageClass::IsProtocolServiceSupported(
SCSIProtocolFeature feature,
void * serviceValue )
{
bool isSupported;
STATUS_LOG(( "IOUSBMassStorageClass::IsProtocolServiceSupported called\n"));
switch( feature )
{
case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber:
{
*((UInt32 *) serviceValue) = GetMaxLogicalUnitNumber();
isSupported = true;
}
break;
default:
{
isSupported = false;
}
break;
}
return isSupported;
}
bool
IOUSBMassStorageClass::HandleProtocolServiceFeature(
SCSIProtocolFeature feature,
void * serviceValue )
{
return false;
}
#pragma mark -
#pragma mark *** Standard USB Command Methods ***
#pragma mark -
IOReturn
IOUSBMassStorageClass::ClearFeatureEndpointStall(
IOUSBPipe * thePipe,
IOUSBCompletion * completion )
{
IOReturn status;
if ( ( GetInterfaceReference() == NULL ) ||
( thePipe == NULL ) )
{
return kIOReturnDeviceError;
}
thePipe->Reset();
bzero( &fUSBDeviceRequest, sizeof(IOUSBDevRequest));
fUSBDeviceRequest.bmRequestType = USBmakebmRequestType(kUSBNone, kUSBStandard, kUSBEndpoint);
fUSBDeviceRequest.bRequest = kUSBRqClearFeature;
fUSBDeviceRequest.wValue = 0; fUSBDeviceRequest.wIndex = thePipe->GetEndpointNumber();
if ( thePipe == GetBulkInPipe() )
{
fUSBDeviceRequest.wIndex |= 0x80;
}
status = GetInterfaceReference()->DeviceRequest( &fUSBDeviceRequest, completion );
STATUS_LOG(("%s: ClearFeatureEndpointStall returned %d\n",
getName(),
status));
return status;
}
IOReturn
IOUSBMassStorageClass::GetStatusEndpointStatus(
IOUSBPipe * thePipe,
void * endpointStatus,
IOUSBCompletion * completion )
{
IOReturn status;
if ( ( GetInterfaceReference() == NULL ) ||
( thePipe == NULL ) )
{
return kIOReturnDeviceError;
}
bzero( &fUSBDeviceRequest, sizeof(IOUSBDevRequest));
fUSBDeviceRequest.bmRequestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBEndpoint);
fUSBDeviceRequest.bRequest = kUSBRqGetStatus;
fUSBDeviceRequest.wValue = 0; fUSBDeviceRequest.wIndex = thePipe->GetEndpointNumber();
if ( thePipe == GetBulkInPipe() )
{
fUSBDeviceRequest.wIndex |= 0x80;
}
fUSBDeviceRequest.wLength = 2;
fUSBDeviceRequest.pData = endpointStatus;
status = GetInterfaceReference()->DeviceRequest( &fUSBDeviceRequest, completion );
STATUS_LOG(("%s: GetStatusEndpointStatus returned %d\n",
getName(),
status));
return status;
}
#pragma mark -
#pragma mark *** Accessor Methods For All Protocol Variables ***
#pragma mark -
IOUSBInterface *
IOUSBMassStorageClass::GetInterfaceReference( void )
{
STATUS_LOG(("%s: GetInterfaceReference \n", getName() ));
if ( fInterface == NULL )
{
STATUS_LOG(("%s: GetInterfaceReference - Interface is NULL.\n", getName() ));
}
return fInterface;
}
void
IOUSBMassStorageClass::SetInterfaceReference( IOUSBInterface * newInterface )
{
fInterface = newInterface;
}
UInt8
IOUSBMassStorageClass::GetInterfaceSubclass( void )
{
return fPreferredSubclass;
}
UInt8
IOUSBMassStorageClass::GetInterfaceProtocol( void )
{
return fPreferredProtocol;
}
IOUSBPipe *
IOUSBMassStorageClass::GetControlPipe( void )
{
if ( GetInterfaceReference() == NULL )
{
return NULL;
}
return GetInterfaceReference()->GetDevice()->GetPipeZero();
}
IOUSBPipe *
IOUSBMassStorageClass::GetBulkInPipe( void )
{
return fBulkInPipe;
}
IOUSBPipe *
IOUSBMassStorageClass::GetBulkOutPipe( void )
{
return fBulkOutPipe;
}
IOUSBPipe *
IOUSBMassStorageClass::GetInterruptPipe( void )
{
return fInterruptPipe;
}
UInt8
IOUSBMassStorageClass::GetMaxLogicalUnitNumber( void ) const
{
return fMaxLogicalUnitNumber;
}
void
IOUSBMassStorageClass::SetMaxLogicalUnitNumber( UInt8 maxLUN )
{
fMaxLogicalUnitNumber = maxLUN;
}
#pragma mark -
#pragma mark *** Accessor Methods For CBI Protocol Variables ***
#pragma mark -
CBIRequestBlock *
IOUSBMassStorageClass::GetCBIRequestBlock( void )
{
return &fCBICommandRequestBlock;
}
void
IOUSBMassStorageClass::ReleaseCBIRequestBlock( CBIRequestBlock * cbiRequestBlock )
{
cbiRequestBlock->request = NULL;
return;
}
#pragma mark -
#pragma mark *** Accessor Methods For Bulk Only Protocol Variables ***
#pragma mark -
BulkOnlyRequestBlock *
IOUSBMassStorageClass::GetBulkOnlyRequestBlock( void )
{
return &fBulkOnlyCommandRequestBlock;
}
void
IOUSBMassStorageClass::ReleaseBulkOnlyRequestBlock( BulkOnlyRequestBlock * boRequestBlock )
{
boRequestBlock->request = NULL;
return;
}
UInt32
IOUSBMassStorageClass::GetNextBulkOnlyCommandTag( void )
{
fBulkOnlyCommandTag++;
return fBulkOnlyCommandTag;
}
IOReturn
IOUSBMassStorageClass::HandlePowerOn( void )
{
UInt8 eStatus[2];
bool knownResetOnResumeDevice = false;
STATUS_LOG(("%s: HandlePowerOn\n", getName() ));
if ( getProperty( kIOUSBMassStorageCharacteristics ) != NULL )
{
OSDictionary * characterDict = OSDynamicCast(
OSDictionary,
getProperty( kIOUSBMassStorageCharacteristics ));
if ( characterDict->getObject( kIOUSBMassStorageResetOnResume ) != NULL )
{
STATUS_LOG(("%s: knownResetOnResumeDevice\n", getName() ));
knownResetOnResumeDevice = true;
}
}
if ( ( ( GetStatusEndpointStatus( GetBulkInPipe(), &eStatus[0], NULL) != kIOReturnSuccess ) ||
( knownResetOnResumeDevice == true ) ) &&
( isInactive() == false ) )
{
retain();
STATUS_LOG(("%s: kIOMessageServiceIsResumed GetStatusEndpointStatus error.\n", getName() ));
fResetInProgress = true;
IOCreateThread( IOUSBMassStorageClass::sResetDevice, this );
fCommandGate->runAction ( ( IOCommandGate::Action ) &IOUSBMassStorageClass::sWaitForReset );
}
return kIOReturnSuccess;
}
bool
IOUSBMassStorageClass::handleOpen( IOService * client,
IOOptionBits options,
void * arg )
{
bool result = false;
if ( GetMaxLogicalUnitNumber() == 0 )
{
result = super::handleOpen ( client, options, arg );
goto Exit;
}
require_nonzero ( fClients, ErrorExit );
require_nonzero ( OSDynamicCast ( IOSCSILogicalUnitNub, client ), ErrorExit );
result = fClients->setObject ( client );
Exit:
ErrorExit:
return result;
}
void
IOUSBMassStorageClass::handleClose( IOService * client,
IOOptionBits options )
{
if ( GetMaxLogicalUnitNumber() == 0 )
{
super::handleClose( client, options );
return;
}
require_nonzero ( fClients, Exit );
if ( fClients->containsObject( client ) )
{
fClients->removeObject( client );
if ( ( fClients->getCount( ) == 0 ) && isInactive( ) )
{
message( kIOMessageServiceIsRequestingClose, getProvider( ), 0 );
}
}
Exit:
return;
}
bool
IOUSBMassStorageClass::handleIsOpen( const IOService * client ) const
{
bool result = false;
UInt8 lun = GetMaxLogicalUnitNumber();
require_nonzero ( lun, CallSuperClass );
require_nonzero ( fClients, CallSuperClass );
if ( ( client == NULL ) && ( fClients->getCount ( ) != 0 ) )
{
result = true;
}
else
{
result = fClients->containsObject ( client );
}
return result;
CallSuperClass:
result = super::handleIsOpen ( client );
return result;
}
IOReturn
IOUSBMassStorageClass::sWaitForReset( void * refcon )
{
return (( IOUSBMassStorageClass * ) refcon )->GatedWaitForReset();
}
IOReturn
IOUSBMassStorageClass::GatedWaitForReset( void )
{
IOReturn status = kIOReturnSuccess;
if ( fResetInProgress == true )
{
status = fCommandGate->commandSleep( &fResetInProgress, THREAD_UNINT );
}
return status;
}
void
IOUSBMassStorageClass::sResetDevice( void * refcon )
{
IOUSBMassStorageClass * driver;
IOReturn status = kIOReturnSuccess;
driver = ( IOUSBMassStorageClass * ) refcon;
STATUS_LOG ( ( "IOUSBMassStorageClass: sResetDevice\n" ) );
if ( ( driver->GetInterfaceReference() == NULL ) ||
( driver->isInactive( ) == true ) )
{
STATUS_LOG ( ( "IOUSBMassStorageClass: sResetDevice - We are being terminated!\n" ) );
goto ErrorExit;
}
status = driver->GetInterfaceReference()->GetDevice()->ResetDevice();
STATUS_LOG ( ( "IOUSBMassStorageClass: ResetDevice() returned status = %d\n", status ) );
if ( ( driver->GetInterfaceReference() == NULL ) ||
( driver->isInactive( ) == true ) ||
( status != kIOReturnSuccess ) )
{
STATUS_LOG ( ( "IOUSBMassStorageClass: sResetDevice - We are being terminated!\n" ) );
goto ErrorExit;
}
if ( driver->GetBulkInPipe() != NULL )
{
driver->GetBulkInPipe()->Reset();
}
if ( driver->GetBulkOutPipe() != NULL )
{
driver->GetBulkOutPipe()->Reset();
}
driver->SendNotification_VerifyDeviceState();
ErrorExit:
driver->fResetInProgress = false;
driver->fCommandGate->commandWakeup( &driver->fResetInProgress, false );
driver->release();
STATUS_LOG ( ( "IOUSBMassStorageClass: sResetDevice returned\n" ) );
return;
}
OSMetaClassDefineReservedUsed( IOUSBMassStorageClass, 1 );
IOReturn
IOUSBMassStorageClass::StartDeviceRecovery( void )
{
UInt8 eStatus[2];
IOReturn status = kIOReturnError;
STATUS_LOG(("%s: StartDeviceRecovery", getName() ));
if( fBulkOnlyCommandStructInUse == true )
{
fBulkOnlyCommandRequestBlock.boCompletion.target = this;
fBulkOnlyCommandRequestBlock.boCompletion.action = &this->DeviceRecoveryCompletionAction;
status = GetStatusEndpointStatus( GetBulkInPipe(), &eStatus[0], &fBulkOnlyCommandRequestBlock.boCompletion);
}
else if( fCBICommandStructInUse == true )
{
fCBICommandRequestBlock.cbiCompletion.target = this;
fCBICommandRequestBlock.cbiCompletion.action = &this->DeviceRecoveryCompletionAction;
status = GetStatusEndpointStatus( GetBulkInPipe(), &eStatus[0], &fCBICommandRequestBlock.cbiCompletion);
}
return status;
}
OSMetaClassDefineReservedUsed( IOUSBMassStorageClass, 2 );
void
IOUSBMassStorageClass::FinishDeviceRecovery( IOReturn status )
{
SCSITaskIdentifier tempTask = NULL;
if ( status != kIOReturnSuccess)
{
STATUS_LOG(("%s: StartDeviceRecovery GetStatusEndpointStatus error.\n", getName() ));
if ( GetInterfaceReference() == NULL )
{
if( fBulkOnlyCommandStructInUse == true )
{
tempTask = fBulkOnlyCommandRequestBlock.request;
}
else if ( fCBICommandStructInUse == true )
{
tempTask = fCBICommandRequestBlock.request;
}
goto ErrorExit;
}
status = (GetInterfaceReference()->GetDevice())->ResetDevice();
SendNotification_VerifyDeviceState();
}
if( status == kIOReturnSuccess )
{
if( fBulkOnlyCommandStructInUse == true )
{
tempTask = fBulkOnlyCommandRequestBlock.request;
STATUS_LOG(("%s: StartDeviceRecovery SendSCSICommandforBulkOnlyProtocol sent \n", getName() ));
status = SendSCSICommandForBulkOnlyProtocol( tempTask );
STATUS_LOG(("%s: StartDeviceRecovery SendSCSICommandforBulkOnlyProtocol returned %d\n",
getName(),
status));
if( status != kIOReturnSuccess)
{
goto ErrorExit;
}
}
else if ( fCBICommandStructInUse == true )
{
tempTask = fCBICommandRequestBlock.request;
status = SendSCSICommandForCBIProtocol( tempTask );
STATUS_LOG(("%s: StartDeviceRecovery SendSCSICommandforCBIProtocol returned %d\n",
getName(),
status));
if( status != kIOReturnSuccess)
{
goto ErrorExit;
}
}
}
return;
ErrorExit:
if ( tempTask != NULL )
{
RejectTask( tempTask );
}
}
void
IOUSBMassStorageClass::DeviceRecoveryCompletionAction(
void * target,
void * parameter,
IOReturn status,
UInt32 bufferSizeRemaining)
{
#pragma unused( parameter, bufferSizeRemaining)
IOUSBMassStorageClass * theMSC;
theMSC = (IOUSBMassStorageClass *) target;
theMSC->FinishDeviceRecovery( status );
}
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 3 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 4 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 5 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 6 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 7 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 8 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 9 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 10 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 11 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 12 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 13 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 14 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 15 );
OSMetaClassDefineReservedUnused( IOUSBMassStorageClass, 16 );