+++ /dev/null
-#include <IOKit/IOKitLib.h>
-#include <IOKit/pwr_mgt/IOPMLib.h>
-#include <IOKit/pwr_mgt/IOPM.h>
-
-#include <time.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <assert.h>
-
-#include "disk_power.h"
-
-int PowerStateSummary( IOATAPowerState powerState );
-
-/*
--- PowerStateString()
-*/
-
-char * PowerStateString( IOATAPowerState x, int opt_summary )
-{
- char * result;
-
- if ( opt_summary )
- {
- switch ( PowerStateSummary( x ) )
- {
- case -1:
- result = "ON";
- break;
- case 0: // This is the only value where the two scales collide.
- result = "OFF";
- break;
- default:
- fprintf(stderr, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__, (int)x);
- result = "UNKNOWN";
- break;
- }
- }
- else
- {
- switch ( x )
- {
- case kIOATAPowerStateSystemSleep: // This is the only value where the two scales collide.
- result = "SystemSleep";
- break;
- case kIOATAPowerStateSleep:
- result = "Sleep";
- break;
- case kIOATAPowerStateStandby:
- result = "Standby";
- break;
- case kIOATAPowerStateIdle:
- result = "Idle";
- break;
- case kIOATAPowerStateActive:
- result = "Active";
- break;
- default:
- fprintf(stderr, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__, (int)x);
- result = "UNKNOWN";
- break;
- }
- }
-
- return result;
-
-} // PowerStateString()
-
-/*
--- PowerStatesMax()
-*/
-
-IOATAPowerState PowerStatesMax( IOATAPowerStates * powerStates )
-{
- IOATAPowerState driverDesire = powerStates->driverDesire;
- IOATAPowerState deviceDesire = powerStates->deviceDesire;
- IOATAPowerState userDesire = powerStates->userDesire;
-
- IOATAPowerState maxState = 0;
-
- if ( driverDesire > maxState ) maxState = driverDesire;
-
- if ( deviceDesire > maxState ) maxState = deviceDesire;
-
- if ( userDesire > maxState ) maxState = userDesire;
-
- return maxState;
-
-} // PowerStatesMax()
-
-/*
--- PowerStateSummary()
-*/
-
-/* Returns
--- -1 == ON
--- 0 == OFF
--- Can be used together with the positive values denoting IOATAPowerState's.
--- But you have to be careful not to confuse with OFF == 0 == kIOATAPowerStateSystemSleep.
-*/
-
-int PowerStateSummary( IOATAPowerState powerState )
-{
- int result;
-
- // Summarizing twice does nothing. Idempotent.
- if ( powerState <= 0 )
- result = powerState;
- else
-#if 1
- if ( 0 <= powerState && powerState <= kIOATAPowerStateSleep )
- result = 0;
- else
- result = -1;
-#else
- if ( 0 <= powerState && powerState <= kIOATAPowerStateStandby ) // Spun down.
- result = 0; // OFF
- else
- if ( kIOATAPowerStateIdle <= powerState && powerState <= kIOATAPowerStateActive ) // Spun up.
- result = -1; // ON
- else
- {
- fprintf(stderr, "ERROR: %s(%d): unexpected value.\n", __FUNCTION__, powerState);
- exit(-1);
- }
-#endif
-
- return result;
-
-} // PowerStateSummary()
-
-/*
--- GetATADeviceInfo()
-*/
-
-// Fairly often this returns -11, meaning that it was unable to locate a matching device.
-// If this happens, just wait awhile and try again.
-//
-// See GetATADeviceInfoWithRetry()
-//
-
-int GetATADeviceInfo( DiskDevice * device )
-{
- int result;
-
- IOATAPowerStates * powerStates = & device->powerStates;
-
- kern_return_t kr;
- mach_port_t masterPort;
- io_registry_entry_t service;
- io_iterator_t iterator;
-
- kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
- assert(KERN_SUCCESS==kr);
-
- /* look for drives */
- IOServiceGetMatchingServices(masterPort, IOServiceMatching ( "ATADeviceNub" ), & iterator );
- if ( ! iterator )
- {
- result = -10;
- goto Return;
- }
-
- while (( service = IOIteratorNext( iterator ) ))
- {
- CFStringRef str = nil;
- CFMutableDictionaryRef properties = nil;
- CFDictionaryRef physCharacteristics = nil;
- io_iterator_t child_iterator;
- io_registry_entry_t child;
-
- // Device Model
-
- char deviceModel[ 256 ];
- bzero( deviceModel, sizeof deviceModel );
-
- str = IORegistryEntryCreateCFProperty( service, CFSTR("device model"), kCFAllocatorDefault, kNilOptions );
- if ( str )
- {
- CFStringGetCString( str, deviceModel, sizeof deviceModel, kCFStringEncodingMacRoman );
- CFRelease( str );
- }
-
- // Device Interconnect & Device Location
-
- char deviceInterconnect[ 256 ];
- bzero(deviceInterconnect, sizeof deviceInterconnect );
- char deviceLocation[ 256 ];
- bzero(deviceLocation, sizeof deviceLocation );
-
- IORegistryEntryCreateCFProperties( service, & properties, kCFAllocatorDefault, kNilOptions );
- if ( properties )
- {
- physCharacteristics = CFDictionaryGetValue( properties, CFSTR("Protocol Characteristics") );
- if ( physCharacteristics )
- {
- // device interconnect
- str = CFDictionaryGetValue( physCharacteristics, CFSTR("Physical Interconnect") );
- if ( str )
- {
- CFStringGetCString( str, deviceInterconnect, sizeof deviceInterconnect, kCFStringEncodingMacRoman );
- }
-
- // device location
- str = CFDictionaryGetValue( physCharacteristics, CFSTR("Physical Interconnect Location") );
- if ( str )
- {
- CFStringGetCString( str, deviceLocation, sizeof deviceLocation, kCFStringEncodingMacRoman );
- }
- }
-
- CFRelease( properties );
- }
-
- IORegistryEntryGetChildIterator( service, kIOServicePlane, & child_iterator );
- while (( child = IOIteratorNext( child_iterator ) ))
- {
- int driverDesire, deviceDesire, userDesire;
-
- // fill in interconnect info if we don't already have it
- if ( 0 == strlen(deviceInterconnect) )
- {
- str = IORegistryEntryCreateCFProperty( child, CFSTR("Physical Interconnect"), kCFAllocatorDefault, kNilOptions );
- if ( str )
- {
- CFStringGetCString( str, deviceInterconnect, sizeof deviceInterconnect, kCFStringEncodingMacRoman );
- CFRelease( str );
- }
- }
-
- if ( 0 == strlen( deviceLocation ) )
- {
- str = IORegistryEntryCreateCFProperty( child, CFSTR("Physical Interconnect Location"), kCFAllocatorDefault, kNilOptions );
- if ( str )
- {
- CFStringGetCString( str, deviceLocation, sizeof deviceLocation , kCFStringEncodingMacRoman );
- CFRelease( str );
- }
- }
-
- // Device Type
-
- char deviceType[ 256 ];
- bzero( deviceType, sizeof deviceType );
-
- // Power State
-
- char powerState[ 256 ];
- bzero( powerState, sizeof powerState );
-
- // find out what type of device this is - ATAPI will be added as SCSI devices
- str = IORegistryEntryCreateCFProperty( service, CFSTR("ata device type"), kCFAllocatorDefault, kNilOptions );
- if ( str )
- {
- CFStringGetCString( str, deviceType, sizeof deviceType, kCFStringEncodingMacRoman );
- CFRelease( str );
-
- if ( 0 == strcmp( deviceType, "ata" ) ) // regular ATA disks (not ATAPI)
- {
- IORegistryEntryCreateCFProperties( child, & properties, kCFAllocatorDefault, kNilOptions );
- if ( properties )
- {
- str = CFDictionaryGetValue( properties, CFSTR("Power Management private data") );
- if ( str )
- {
- CFStringGetCString( str, powerState, sizeof powerState, kCFStringEncodingMacRoman );
- }
- CFRelease( properties );
- }
- }
- }
-
- if ( 3 == sscanf ( powerState,
- "{ this object = %*x, interested driver = %*x, driverDesire = %d, deviceDesire = %d, ourDesiredPowerState = %d, previousRequest = %*d }",
- & driverDesire, & deviceDesire, & userDesire
- )
- )
- {
- device->timestamp = time( NULL );
-
- device->name = strdup( deviceModel ); // copy of the original
- device->location = strdup( deviceLocation ); // copy of the original
- device->interconnect = strdup( deviceInterconnect ); // copy of the original
-
- powerStates->driverDesire = driverDesire;
- powerStates->deviceDesire = deviceDesire;
- powerStates->userDesire = userDesire;
-
- IOObjectRelease( child_iterator );
- IOObjectRelease( iterator );
-
- result = 0;
- goto Return;
- }
-
- } // while (child...)
-
- IOObjectRelease( child_iterator );
-
- } // while (service...)
-
- IOObjectRelease( iterator );
-
- result = -11;
- goto Return;
-
-Return:
- return result;
-
-} // GetATADeviceInfo()
-
-
-/*
--- GetATADeviceInfoWithRetry()
-*/
-
-// Devices are often momentarily busy, e.g., when spinning up. Retry up to 10 times, 1 second apart.
-
-int GetATADeviceInfoWithRetry( DiskDevice * diskDevice )
-{
- int err;
-
- int retryNumber;
-
- for ( retryNumber = 0; retryNumber < 10; retryNumber++ )
- {
- err = GetATADeviceInfo( diskDevice );
- if ( noErr == err )
- {
- goto Return;
- }
-#if 0
- char errorStringBuffer[ 256 ];
- char * errorString = errorStringBuffer;
- errorString += sprintf_timestamp_now( errorString );
- errorString += sprintf(errorString, ": WARNING: %s: sleeping and retrying...\n", __FUNCTION__);
- fputs( errorStringBuffer, stderr );
- fflush(stdout);
-#endif
- sleep(1);
- }
-
- // Failure.
- goto Return;
-
-Return:
- return err;
-
-} // GetATADeviceInfoWithRetry()
-