1 #include <IOKit/IOKitLib.h>
2 #include <IOKit/pwr_mgt/IOPMLib.h>
3 #include <IOKit/pwr_mgt/IOPM.h>
11 #include "disk_power.h"
13 int PowerStateSummary( IOATAPowerState powerState
);
19 char * PowerStateString( IOATAPowerState x
, int opt_summary
)
25 switch ( PowerStateSummary( x
) )
30 case 0: // This is the only value where the two scales collide.
34 fprintf(stderr
, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__
, (int)x
);
43 case kIOATAPowerStateSystemSleep
: // This is the only value where the two scales collide.
44 result
= "SystemSleep";
46 case kIOATAPowerStateSleep
:
49 case kIOATAPowerStateStandby
:
52 case kIOATAPowerStateIdle
:
55 case kIOATAPowerStateActive
:
59 fprintf(stderr
, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__
, (int)x
);
67 } // PowerStateString()
73 IOATAPowerState
PowerStatesMax( IOATAPowerStates
* powerStates
)
75 IOATAPowerState driverDesire
= powerStates
->driverDesire
;
76 IOATAPowerState deviceDesire
= powerStates
->deviceDesire
;
77 IOATAPowerState userDesire
= powerStates
->userDesire
;
79 IOATAPowerState maxState
= 0;
81 if ( driverDesire
> maxState
) maxState
= driverDesire
;
83 if ( deviceDesire
> maxState
) maxState
= deviceDesire
;
85 if ( userDesire
> maxState
) maxState
= userDesire
;
92 -- PowerStateSummary()
98 -- Can be used together with the positive values denoting IOATAPowerState's.
99 -- But you have to be careful not to confuse with OFF == 0 == kIOATAPowerStateSystemSleep.
102 int PowerStateSummary( IOATAPowerState powerState
)
106 // Summarizing twice does nothing. Idempotent.
107 if ( powerState
<= 0 )
111 if ( 0 <= powerState
&& powerState
<= kIOATAPowerStateSleep
)
116 if ( 0 <= powerState
&& powerState
<= kIOATAPowerStateStandby
) // Spun down.
119 if ( kIOATAPowerStateIdle
<= powerState
&& powerState
<= kIOATAPowerStateActive
) // Spun up.
123 fprintf(stderr
, "ERROR: %s(%d): unexpected value.\n", __FUNCTION__
, powerState
);
130 } // PowerStateSummary()
133 -- GetATADeviceInfo()
136 // Fairly often this returns -11, meaning that it was unable to locate a matching device.
137 // If this happens, just wait awhile and try again.
139 // See GetATADeviceInfoWithRetry()
142 int GetATADeviceInfo( DiskDevice
* device
)
146 IOATAPowerStates
* powerStates
= & device
->powerStates
;
149 mach_port_t masterPort
;
150 io_registry_entry_t service
;
151 io_iterator_t iterator
;
153 kr
= IOMasterPort(MACH_PORT_NULL
, &masterPort
);
154 assert(KERN_SUCCESS
==kr
);
156 /* look for drives */
157 IOServiceGetMatchingServices(masterPort
, IOServiceMatching ( "ATADeviceNub" ), & iterator
);
164 while (( service
= IOIteratorNext( iterator
) ))
166 CFStringRef str
= nil
;
167 CFMutableDictionaryRef properties
= nil
;
168 CFDictionaryRef physCharacteristics
= nil
;
169 io_iterator_t child_iterator
;
170 io_registry_entry_t child
;
174 char deviceModel
[ 256 ];
175 bzero( deviceModel
, sizeof deviceModel
);
177 str
= IORegistryEntryCreateCFProperty( service
, CFSTR("device model"), kCFAllocatorDefault
, kNilOptions
);
180 CFStringGetCString( str
, deviceModel
, sizeof deviceModel
, kCFStringEncodingMacRoman
);
184 // Device Interconnect & Device Location
186 char deviceInterconnect
[ 256 ];
187 bzero(deviceInterconnect
, sizeof deviceInterconnect
);
188 char deviceLocation
[ 256 ];
189 bzero(deviceLocation
, sizeof deviceLocation
);
191 IORegistryEntryCreateCFProperties( service
, & properties
, kCFAllocatorDefault
, kNilOptions
);
194 physCharacteristics
= CFDictionaryGetValue( properties
, CFSTR("Protocol Characteristics") );
195 if ( physCharacteristics
)
197 // device interconnect
198 str
= CFDictionaryGetValue( physCharacteristics
, CFSTR("Physical Interconnect") );
201 CFStringGetCString( str
, deviceInterconnect
, sizeof deviceInterconnect
, kCFStringEncodingMacRoman
);
205 str
= CFDictionaryGetValue( physCharacteristics
, CFSTR("Physical Interconnect Location") );
208 CFStringGetCString( str
, deviceLocation
, sizeof deviceLocation
, kCFStringEncodingMacRoman
);
212 CFRelease( properties
);
215 IORegistryEntryGetChildIterator( service
, kIOServicePlane
, & child_iterator
);
216 while (( child
= IOIteratorNext( child_iterator
) ))
218 int driverDesire
, deviceDesire
, userDesire
;
220 // fill in interconnect info if we don't already have it
221 if ( 0 == strlen(deviceInterconnect
) )
223 str
= IORegistryEntryCreateCFProperty( child
, CFSTR("Physical Interconnect"), kCFAllocatorDefault
, kNilOptions
);
226 CFStringGetCString( str
, deviceInterconnect
, sizeof deviceInterconnect
, kCFStringEncodingMacRoman
);
231 if ( 0 == strlen( deviceLocation
) )
233 str
= IORegistryEntryCreateCFProperty( child
, CFSTR("Physical Interconnect Location"), kCFAllocatorDefault
, kNilOptions
);
236 CFStringGetCString( str
, deviceLocation
, sizeof deviceLocation
, kCFStringEncodingMacRoman
);
243 char deviceType
[ 256 ];
244 bzero( deviceType
, sizeof deviceType
);
248 char powerState
[ 256 ];
249 bzero( powerState
, sizeof powerState
);
251 // find out what type of device this is - ATAPI will be added as SCSI devices
252 str
= IORegistryEntryCreateCFProperty( service
, CFSTR("ata device type"), kCFAllocatorDefault
, kNilOptions
);
255 CFStringGetCString( str
, deviceType
, sizeof deviceType
, kCFStringEncodingMacRoman
);
258 if ( 0 == strcmp( deviceType
, "ata" ) ) // regular ATA disks (not ATAPI)
260 IORegistryEntryCreateCFProperties( child
, & properties
, kCFAllocatorDefault
, kNilOptions
);
263 str
= CFDictionaryGetValue( properties
, CFSTR("Power Management private data") );
266 CFStringGetCString( str
, powerState
, sizeof powerState
, kCFStringEncodingMacRoman
);
268 CFRelease( properties
);
273 if ( 3 == sscanf ( powerState
,
274 "{ this object = %*x, interested driver = %*x, driverDesire = %d, deviceDesire = %d, ourDesiredPowerState = %d, previousRequest = %*d }",
275 & driverDesire
, & deviceDesire
, & userDesire
279 device
->timestamp
= time( NULL
);
281 device
->name
= strdup( deviceModel
); // copy of the original
282 device
->location
= strdup( deviceLocation
); // copy of the original
283 device
->interconnect
= strdup( deviceInterconnect
); // copy of the original
285 powerStates
->driverDesire
= driverDesire
;
286 powerStates
->deviceDesire
= deviceDesire
;
287 powerStates
->userDesire
= userDesire
;
289 IOObjectRelease( child_iterator
);
290 IOObjectRelease( iterator
);
296 } // while (child...)
298 IOObjectRelease( child_iterator
);
300 } // while (service...)
302 IOObjectRelease( iterator
);
310 } // GetATADeviceInfo()
314 -- GetATADeviceInfoWithRetry()
317 // Devices are often momentarily busy, e.g., when spinning up. Retry up to 10 times, 1 second apart.
319 int GetATADeviceInfoWithRetry( DiskDevice
* diskDevice
)
325 for ( retryNumber
= 0; retryNumber
< 10; retryNumber
++ )
327 err
= GetATADeviceInfo( diskDevice
);
333 char errorStringBuffer
[ 256 ];
334 char * errorString
= errorStringBuffer
;
335 errorString
+= sprintf_timestamp_now( errorString
);
336 errorString
+= sprintf(errorString
, ": WARNING: %s: sleeping and retrying...\n", __FUNCTION__
);
337 fputs( errorStringBuffer
, stderr
);
349 } // GetATADeviceInfoWithRetry()