]> git.saurik.com Git - apple/system_cmds.git/blob - update.tproj/disk_power.c
system_cmds-336.20.tar.gz
[apple/system_cmds.git] / update.tproj / disk_power.c
1 #include <IOKit/IOKitLib.h>
2 #include <IOKit/pwr_mgt/IOPMLib.h>
3 #include <IOKit/pwr_mgt/IOPM.h>
4
5 #include <time.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <assert.h>
10
11 #include "disk_power.h"
12
13 int PowerStateSummary( IOATAPowerState powerState );
14
15 /*
16 -- PowerStateString()
17 */
18
19 char * PowerStateString( IOATAPowerState x, int opt_summary )
20 {
21 char * result;
22
23 if ( opt_summary )
24 {
25 switch ( PowerStateSummary( x ) )
26 {
27 case -1:
28 result = "ON";
29 break;
30 case 0: // This is the only value where the two scales collide.
31 result = "OFF";
32 break;
33 default:
34 fprintf(stderr, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__, (int)x);
35 result = "UNKNOWN";
36 break;
37 }
38 }
39 else
40 {
41 switch ( x )
42 {
43 case kIOATAPowerStateSystemSleep: // This is the only value where the two scales collide.
44 result = "SystemSleep";
45 break;
46 case kIOATAPowerStateSleep:
47 result = "Sleep";
48 break;
49 case kIOATAPowerStateStandby:
50 result = "Standby";
51 break;
52 case kIOATAPowerStateIdle:
53 result = "Idle";
54 break;
55 case kIOATAPowerStateActive:
56 result = "Active";
57 break;
58 default:
59 fprintf(stderr, "ERROR: %s: unknown IOATAPowerState %d\n", __FUNCTION__, (int)x);
60 result = "UNKNOWN";
61 break;
62 }
63 }
64
65 return result;
66
67 } // PowerStateString()
68
69 /*
70 -- PowerStatesMax()
71 */
72
73 IOATAPowerState PowerStatesMax( IOATAPowerStates * powerStates )
74 {
75 IOATAPowerState driverDesire = powerStates->driverDesire;
76 IOATAPowerState deviceDesire = powerStates->deviceDesire;
77 IOATAPowerState userDesire = powerStates->userDesire;
78
79 IOATAPowerState maxState = 0;
80
81 if ( driverDesire > maxState ) maxState = driverDesire;
82
83 if ( deviceDesire > maxState ) maxState = deviceDesire;
84
85 if ( userDesire > maxState ) maxState = userDesire;
86
87 return maxState;
88
89 } // PowerStatesMax()
90
91 /*
92 -- PowerStateSummary()
93 */
94
95 /* Returns
96 -- -1 == ON
97 -- 0 == OFF
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.
100 */
101
102 int PowerStateSummary( IOATAPowerState powerState )
103 {
104 int result;
105
106 // Summarizing twice does nothing. Idempotent.
107 if ( powerState <= 0 )
108 result = powerState;
109 else
110 #if 1
111 if ( 0 <= powerState && powerState <= kIOATAPowerStateSleep )
112 result = 0;
113 else
114 result = -1;
115 #else
116 if ( 0 <= powerState && powerState <= kIOATAPowerStateStandby ) // Spun down.
117 result = 0; // OFF
118 else
119 if ( kIOATAPowerStateIdle <= powerState && powerState <= kIOATAPowerStateActive ) // Spun up.
120 result = -1; // ON
121 else
122 {
123 fprintf(stderr, "ERROR: %s(%d): unexpected value.\n", __FUNCTION__, powerState);
124 exit(-1);
125 }
126 #endif
127
128 return result;
129
130 } // PowerStateSummary()
131
132 /*
133 -- GetATADeviceInfo()
134 */
135
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.
138 //
139 // See GetATADeviceInfoWithRetry()
140 //
141
142 int GetATADeviceInfo( DiskDevice * device )
143 {
144 int result;
145
146 IOATAPowerStates * powerStates = & device->powerStates;
147
148 kern_return_t kr;
149 mach_port_t masterPort;
150 io_registry_entry_t service;
151 io_iterator_t iterator;
152
153 kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
154 assert(KERN_SUCCESS==kr);
155
156 /* look for drives */
157 IOServiceGetMatchingServices(masterPort, IOServiceMatching ( "ATADeviceNub" ), & iterator );
158 if ( ! iterator )
159 {
160 result = -10;
161 goto Return;
162 }
163
164 while (( service = IOIteratorNext( iterator ) ))
165 {
166 CFStringRef str = nil;
167 CFMutableDictionaryRef properties = nil;
168 CFDictionaryRef physCharacteristics = nil;
169 io_iterator_t child_iterator;
170 io_registry_entry_t child;
171
172 // Device Model
173
174 char deviceModel[ 256 ];
175 bzero( deviceModel, sizeof deviceModel );
176
177 str = IORegistryEntryCreateCFProperty( service, CFSTR("device model"), kCFAllocatorDefault, kNilOptions );
178 if ( str )
179 {
180 CFStringGetCString( str, deviceModel, sizeof deviceModel, kCFStringEncodingMacRoman );
181 CFRelease( str );
182 }
183
184 // Device Interconnect & Device Location
185
186 char deviceInterconnect[ 256 ];
187 bzero(deviceInterconnect, sizeof deviceInterconnect );
188 char deviceLocation[ 256 ];
189 bzero(deviceLocation, sizeof deviceLocation );
190
191 IORegistryEntryCreateCFProperties( service, & properties, kCFAllocatorDefault, kNilOptions );
192 if ( properties )
193 {
194 physCharacteristics = CFDictionaryGetValue( properties, CFSTR("Protocol Characteristics") );
195 if ( physCharacteristics )
196 {
197 // device interconnect
198 str = CFDictionaryGetValue( physCharacteristics, CFSTR("Physical Interconnect") );
199 if ( str )
200 {
201 CFStringGetCString( str, deviceInterconnect, sizeof deviceInterconnect, kCFStringEncodingMacRoman );
202 }
203
204 // device location
205 str = CFDictionaryGetValue( physCharacteristics, CFSTR("Physical Interconnect Location") );
206 if ( str )
207 {
208 CFStringGetCString( str, deviceLocation, sizeof deviceLocation, kCFStringEncodingMacRoman );
209 }
210 }
211
212 CFRelease( properties );
213 }
214
215 IORegistryEntryGetChildIterator( service, kIOServicePlane, & child_iterator );
216 while (( child = IOIteratorNext( child_iterator ) ))
217 {
218 int driverDesire, deviceDesire, userDesire;
219
220 // fill in interconnect info if we don't already have it
221 if ( 0 == strlen(deviceInterconnect) )
222 {
223 str = IORegistryEntryCreateCFProperty( child, CFSTR("Physical Interconnect"), kCFAllocatorDefault, kNilOptions );
224 if ( str )
225 {
226 CFStringGetCString( str, deviceInterconnect, sizeof deviceInterconnect, kCFStringEncodingMacRoman );
227 CFRelease( str );
228 }
229 }
230
231 if ( 0 == strlen( deviceLocation ) )
232 {
233 str = IORegistryEntryCreateCFProperty( child, CFSTR("Physical Interconnect Location"), kCFAllocatorDefault, kNilOptions );
234 if ( str )
235 {
236 CFStringGetCString( str, deviceLocation, sizeof deviceLocation , kCFStringEncodingMacRoman );
237 CFRelease( str );
238 }
239 }
240
241 // Device Type
242
243 char deviceType[ 256 ];
244 bzero( deviceType, sizeof deviceType );
245
246 // Power State
247
248 char powerState[ 256 ];
249 bzero( powerState, sizeof powerState );
250
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 );
253 if ( str )
254 {
255 CFStringGetCString( str, deviceType, sizeof deviceType, kCFStringEncodingMacRoman );
256 CFRelease( str );
257
258 if ( 0 == strcmp( deviceType, "ata" ) ) // regular ATA disks (not ATAPI)
259 {
260 IORegistryEntryCreateCFProperties( child, & properties, kCFAllocatorDefault, kNilOptions );
261 if ( properties )
262 {
263 str = CFDictionaryGetValue( properties, CFSTR("Power Management private data") );
264 if ( str )
265 {
266 CFStringGetCString( str, powerState, sizeof powerState, kCFStringEncodingMacRoman );
267 }
268 CFRelease( properties );
269 }
270 }
271 }
272
273 if ( 3 == sscanf ( powerState,
274 "{ this object = %*x, interested driver = %*x, driverDesire = %d, deviceDesire = %d, ourDesiredPowerState = %d, previousRequest = %*d }",
275 & driverDesire, & deviceDesire, & userDesire
276 )
277 )
278 {
279 device->timestamp = time( NULL );
280
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
284
285 powerStates->driverDesire = driverDesire;
286 powerStates->deviceDesire = deviceDesire;
287 powerStates->userDesire = userDesire;
288
289 IOObjectRelease( child_iterator );
290 IOObjectRelease( iterator );
291
292 result = 0;
293 goto Return;
294 }
295
296 } // while (child...)
297
298 IOObjectRelease( child_iterator );
299
300 } // while (service...)
301
302 IOObjectRelease( iterator );
303
304 result = -11;
305 goto Return;
306
307 Return:
308 return result;
309
310 } // GetATADeviceInfo()
311
312
313 /*
314 -- GetATADeviceInfoWithRetry()
315 */
316
317 // Devices are often momentarily busy, e.g., when spinning up. Retry up to 10 times, 1 second apart.
318
319 int GetATADeviceInfoWithRetry( DiskDevice * diskDevice )
320 {
321 int err;
322
323 int retryNumber;
324
325 for ( retryNumber = 0; retryNumber < 10; retryNumber++ )
326 {
327 err = GetATADeviceInfo( diskDevice );
328 if ( noErr == err )
329 {
330 goto Return;
331 }
332 #if 0
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 );
338 fflush(stdout);
339 #endif
340 sleep(1);
341 }
342
343 // Failure.
344 goto Return;
345
346 Return:
347 return err;
348
349 } // GetATADeviceInfoWithRetry()
350