IOATABlockStorageDriverPM.cpp [plain text]
#include "IOATABlockStorageDriver.h"
#define super IOService
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 1 )
#define PANIC_NOW(x) IOPanic x
#else
#define PANIC_NOW(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 2 )
#define ERROR_LOG(x) IOLog x
#else
#define ERROR_LOG(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_DEBUGGING_LEVEL >= 3 )
#define STATUS_LOG(x) IOLog x
#else
#define STATUS_LOG(x)
#endif
#if ( ATA_BLOCK_STORAGE_DRIVER_PM_DEBUGGING_LEVEL >= 1 )
#define SERIAL_STATUS_LOG(x) kprintf x
#else
#define SERIAL_STATUS_LOG(x)
#endif
enum
{
kThreadDelayInterval = 500, k100SecondsInMicroSeconds = 100 * 1000 * 1000
};
enum
{
kATAIdleDevice = 1,
kATAStandbyDevice = 2,
kATASleepDevice = 3
};
enum
{
kPowerManagementScaleFactor = kSecondsInAMinute / ( kIOATAPowerStateActive - kIOATAPowerStateSleep )
};
static IOPMPowerState sPowerStates[kIOATAPowerStates] =
{
{ kIOPMPowerStateVersion1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, 0, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, (IOPMDeviceUsable | kIOPMPreventIdleSleep), IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, (IOPMDeviceUsable | kIOPMPreventIdleSleep), IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 },
{ kIOPMPowerStateVersion1, (IOPMDeviceUsable | IOPMMaxPerformance | kIOPMPreventIdleSleep), IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
};
#if ( ATA_MASS_STORAGE_DEBUG == 1 )
static const char * sPowerStateNames[] =
{
"System Sleep",
"Sleep",
"Standby",
"Idle",
"Active"
};
#endif
UInt32
IOATABlockStorageDriver::initialPowerStateForDomainState (
IOPMPowerFlags flags )
{
return kIOATAPowerStateActive;
}
void
IOATABlockStorageDriver::initForPM ( void )
{
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::initForPM called\n" ) );
registerPowerDriver ( this, sPowerStates, kIOATAPowerStates );
SERIAL_STATUS_LOG ( ( "registerPowerDriver\n" ) );
changePowerStateTo ( kIOATAPowerStateSleep );
SERIAL_STATUS_LOG ( ( "changePowerStateTo\n" ) );
}
IOReturn
IOATABlockStorageDriver::setAggressiveness ( UInt32 type, UInt32 minutes )
{
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::setAggressiveness called\n" ) );
if ( type == kPMMinutesToSpinDown )
{
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver: setting idle timer to %ld min\n", minutes ) );
setIdleTimerPeriod ( minutes * kPowerManagementScaleFactor );
}
return ( super::setAggressiveness ( type, minutes ) );
}
void
IOATABlockStorageDriver::checkPowerState ( void )
{
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::checkPowerState called\n" ) );
activityTickle ( kIOPMSuperclassPolicy1, ( UInt32 ) kIOATAPowerStateActive );
fCommandGate->runAction ( ( IOCommandGate::Action )
&IOATABlockStorageDriver::sHandleCheckPowerState );
}
void
IOATABlockStorageDriver::sHandleCheckPowerState ( IOATABlockStorageDriver * self )
{
self->handleCheckPowerState ( );
}
void
IOATABlockStorageDriver::handleCheckPowerState ( void )
{
while ( fCurrentPowerState != kIOATAPowerStateActive )
{
fCommandGate->commandSleep ( &fCurrentPowerState, THREAD_UNINT );
}
fNumCommandsOutstanding++;
}
IOReturn
IOATABlockStorageDriver::setPowerState (
UInt32 powerStateOrdinal,
IOService * whichDevice )
{
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::setPowerState called\n" ) );
SERIAL_STATUS_LOG ( ( "powerStateOrdinal = %ld\n", powerStateOrdinal ) );
fCommandGate->runAction ( ( IOCommandGate::Action )
&IOATABlockStorageDriver::sHandleSetPowerState,
( void * ) powerStateOrdinal );
return k100SecondsInMicroSeconds;
}
void
IOATABlockStorageDriver::sHandleSetPowerState (
IOATABlockStorageDriver * self,
UInt32 powerStateOrdinal )
{
if ( self->isInactive ( ) == false )
{
self->handleSetPowerState ( powerStateOrdinal );
}
}
void
IOATABlockStorageDriver::handleSetPowerState ( UInt32 powerStateOrdinal )
{
AbsoluteTime time;
fProposedPowerState = powerStateOrdinal;
if ( ( fPowerTransitionInProgress == false ) || fPowerAckInProgress )
{
fPowerTransitionInProgress = true;
clock_interval_to_deadline ( kThreadDelayInterval, kMillisecondScale, &time );
( void ) thread_call_enter_delayed ( fPowerManagementThread, time );
}
}
void
IOATABlockStorageDriver::sPowerManagement ( thread_call_param_t whichDevice )
{
IOATABlockStorageDriver * self;
self = ( IOATABlockStorageDriver * ) whichDevice;
if ( ( self != NULL ) && ( self->isInactive ( ) == false ) )
{
self->retain ( );
self->handlePowerChange ( );
self->fPowerAckInProgress = true;
self->acknowledgeSetPowerState ( );
self->fPowerAckInProgress = false;
self->fPowerTransitionInProgress = false;
self->release ( );
}
else
{
self->fPowerTransitionInProgress = false;
}
}
void
IOATABlockStorageDriver::handlePowerChange ( void )
{
UInt32 count = 0;
SERIAL_STATUS_LOG ( ( "IOATABlockStorageDriver::handlePowerChange called\n" ) );
while ( fProposedPowerState != fCurrentPowerState )
{
if ( count > 32 )
{
break;
}
switch ( fProposedPowerState )
{
case kIOATAPowerStateSystemSleep:
if ( fCurrentPowerState == kIOATAPowerStateSleep )
{
fCurrentPowerState = kIOATAPowerStateSystemSleep;
break;
}
case kIOATAPowerStateSleep:
{
bool resetOccurred = false;
fCurrentPowerState = fProposedPowerState;
fCommandGate->runAction ( ( IOCommandGate::Action )
&IOATABlockStorageDriver::sSetWakeupResetOccurred,
( void * ) resetOccurred );
while ( fNumCommandsOutstanding != 0 )
{
IOSleep ( 1 );
}
( void ) issuePowerTransition ( kATASleepDevice );
}
break;
case kIOATAPowerStateStandby:
{
if ( fCurrentPowerState <= kIOATAPowerStateSleep )
{
( void ) resetATADevice ( );
fCurrentPowerState = kIOATAPowerStateStandby;
}
else if ( fCurrentPowerState != kIOATAPowerStateStandby )
{
( void ) issuePowerTransition ( kATAStandbyDevice );
fCurrentPowerState = kIOATAPowerStateStandby;
}
}
break;
case kIOATAPowerStateIdle:
{
if ( fCurrentPowerState <= kIOATAPowerStateSleep )
{
( void ) resetATADevice ( );
fCurrentPowerState = kIOATAPowerStateStandby;
}
if ( fCurrentPowerState != kIOATAPowerStateIdle )
{
( void ) issuePowerTransition ( kATAIdleDevice );
fCurrentPowerState = kIOATAPowerStateIdle;
}
}
break;
case kIOATAPowerStateActive:
{
if ( fCurrentPowerState <= kIOATAPowerStateSleep )
{
bool resetOccurred = false;
fCommandGate->runAction ( ( IOCommandGate::Action )
&IOATABlockStorageDriver::sCheckWakeupResetOccurred,
( void * ) &resetOccurred );
if ( resetOccurred == false )
{
( void ) resetATADevice ( );
}
}
fCurrentPowerState = kIOATAPowerStateActive;
fCommandGate->commandWakeup ( &fCurrentPowerState, false );
}
break;
default:
PANIC_NOW ( ( "Undefined power state issued\n" ) );
break;
}
count++;
}
}
IOReturn
IOATABlockStorageDriver::issuePowerTransition ( UInt32 function )
{
IOReturn status = kIOReturnSuccess;
IOSyncer * syncer;
if ( fATASocketType == kPCCardSocket )
{
return status;
}
if ( ( function == kATAStandbyDevice ) || ( function == kATAIdleDevice ) )
{
return status;
}
syncer = ( IOSyncer * ) fPowerManagementCommand->refCon;
fPowerManagementCommand->zeroCommand ( );
fPowerManagementCommand->setUnit ( fATAUnitID );
fPowerManagementCommand->setTimeoutMS ( kATATimeout10Seconds );
fPowerManagementCommand->setDevice_Head ( fATAUnitID << 4 );
fPowerManagementCommand->setOpcode ( kATAFnExecIO );
fPowerManagementCommand->setCallbackPtr (
&IOATABlockStorageDriver::sHandleSimpleSyncTransaction );
switch ( function )
{
case kATAIdleDevice:
fPowerManagementCommand->setCommand ( kATAcmdIdleImmed );
break;
case kATAStandbyDevice:
fPowerManagementCommand->setCommand ( kATAcmdStandbyImmed );
break;
case kATASleepDevice:
fPowerManagementCommand->setCommand ( kATAcmdSleep );
break;
default:
PANIC_NOW ( ( "Invalid command in IOATABlockStorageDriver::issuePowerTransition\n" ) );
break;
}
fATADevice->executeCommand ( fPowerManagementCommand );
status = syncer->wait ( false );
syncer->reinit ( );
return status;
}
void
IOATABlockStorageDriver::setWakeupResetOccurred ( bool resetOccurred )
{
fWakeUpResetOccurred = resetOccurred;
}
void
IOATABlockStorageDriver::sSetWakeupResetOccurred ( IOATABlockStorageDriver * driver,
bool resetOccurred )
{
driver->setWakeupResetOccurred ( resetOccurred );
}
bool
IOATABlockStorageDriver::checkWakeupResetOccurred ( void )
{
return fWakeUpResetOccurred;
}
void
IOATABlockStorageDriver::sCheckWakeupResetOccurred ( IOATABlockStorageDriver * driver,
void * resetOccurred )
{
bool * reset = ( bool * ) resetOccurred;
*reset = driver->checkWakeupResetOccurred ( );
return;
}