aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r--drivers/acpi/bus.c153
1 files changed, 81 insertions, 72 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index d68bd61072bb..7ced61f39492 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir);
52 52
53#define STRUCT_TO_INT(s) (*((int*)&s)) 53#define STRUCT_TO_INT(s) (*((int*)&s))
54 54
55static int set_power_nocheck(const struct dmi_system_id *id)
56{
57 printk(KERN_NOTICE PREFIX "%s detected - "
58 "disable power check in power transition\n", id->ident);
59 acpi_power_nocheck = 1;
60 return 0;
61}
62static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = {
63 {
64 set_power_nocheck, "HP Pavilion 05", {
65 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
66 DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"),
67 DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL},
68 {},
69};
70
71 55
72#ifdef CONFIG_X86 56#ifdef CONFIG_X86
73static int set_copy_dsdt(const struct dmi_system_id *id) 57static int set_copy_dsdt(const struct dmi_system_id *id)
@@ -196,33 +180,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data);
196 Power Management 180 Power Management
197 -------------------------------------------------------------------------- */ 181 -------------------------------------------------------------------------- */
198 182
199int acpi_bus_get_power(acpi_handle handle, int *state) 183static int __acpi_bus_get_power(struct acpi_device *device, int *state)
200{ 184{
201 int result = 0; 185 int result = 0;
202 acpi_status status = 0; 186 acpi_status status = 0;
203 struct acpi_device *device = NULL;
204 unsigned long long psc = 0; 187 unsigned long long psc = 0;
205 188
206 189 if (!device || !state)
207 result = acpi_bus_get_device(handle, &device); 190 return -EINVAL;
208 if (result)
209 return result;
210 191
211 *state = ACPI_STATE_UNKNOWN; 192 *state = ACPI_STATE_UNKNOWN;
212 193
213 if (!device->flags.power_manageable) { 194 if (device->flags.power_manageable) {
214 /* TBD: Non-recursive algorithm for walking up hierarchy */
215 if (device->parent)
216 *state = device->parent->power.state;
217 else
218 *state = ACPI_STATE_D0;
219 } else {
220 /* 195 /*
221 * Get the device's power state either directly (via _PSC) or 196 * Get the device's power state either directly (via _PSC) or
222 * indirectly (via power resources). 197 * indirectly (via power resources).
223 */ 198 */
224 if (device->power.flags.power_resources) { 199 if (device->power.flags.power_resources) {
225 result = acpi_power_get_inferred_state(device); 200 result = acpi_power_get_inferred_state(device, state);
226 if (result) 201 if (result)
227 return result; 202 return result;
228 } else if (device->power.flags.explicit_get) { 203 } else if (device->power.flags.explicit_get) {
@@ -230,59 +205,33 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
230 NULL, &psc); 205 NULL, &psc);
231 if (ACPI_FAILURE(status)) 206 if (ACPI_FAILURE(status))
232 return -ENODEV; 207 return -ENODEV;
233 device->power.state = (int)psc; 208 *state = (int)psc;
234 } 209 }
235 210 } else {
236 *state = device->power.state; 211 /* TBD: Non-recursive algorithm for walking up hierarchy. */
212 *state = device->parent ?
213 device->parent->power.state : ACPI_STATE_D0;
237 } 214 }
238 215
239 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", 216 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
240 device->pnp.bus_id, device->power.state)); 217 device->pnp.bus_id, *state));
241 218
242 return 0; 219 return 0;
243} 220}
244 221
245EXPORT_SYMBOL(acpi_bus_get_power);
246 222
247int acpi_bus_set_power(acpi_handle handle, int state) 223static int __acpi_bus_set_power(struct acpi_device *device, int state)
248{ 224{
249 int result = 0; 225 int result = 0;
250 acpi_status status = AE_OK; 226 acpi_status status = AE_OK;
251 struct acpi_device *device = NULL;
252 char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; 227 char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
253 228
254 229 if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
255 result = acpi_bus_get_device(handle, &device);
256 if (result)
257 return result;
258
259 if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
260 return -EINVAL; 230 return -EINVAL;
261 231
262 /* Make sure this is a valid target state */ 232 /* Make sure this is a valid target state */
263 233
264 if (!device->flags.power_manageable) { 234 if (state == device->power.state) {
265 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
266 kobject_name(&device->dev.kobj)));
267 return -ENODEV;
268 }
269 /*
270 * Get device's current power state
271 */
272 if (!acpi_power_nocheck) {
273 /*
274 * Maybe the incorrect power state is returned on the bogus
275 * bios, which is different with the real power state.
276 * For example: the bios returns D0 state and the real power
277 * state is D3. OS expects to set the device to D0 state. In
278 * such case if OS uses the power state returned by the BIOS,
279 * the device can't be transisted to the correct power state.
280 * So if the acpi_power_nocheck is set, it is unnecessary to
281 * get the power state by calling acpi_bus_get_power.
282 */
283 acpi_bus_get_power(device->handle, &device->power.state);
284 }
285 if ((state == device->power.state) && !device->flags.force_power_state) {
286 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", 235 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
287 state)); 236 state));
288 return 0; 237 return 0;
@@ -351,8 +300,75 @@ int acpi_bus_set_power(acpi_handle handle, int state)
351 return result; 300 return result;
352} 301}
353 302
303
304int acpi_bus_set_power(acpi_handle handle, int state)
305{
306 struct acpi_device *device;
307 int result;
308
309 result = acpi_bus_get_device(handle, &device);
310 if (result)
311 return result;
312
313 if (!device->flags.power_manageable) {
314 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
315 "Device [%s] is not power manageable\n",
316 dev_name(&device->dev)));
317 return -ENODEV;
318 }
319
320 return __acpi_bus_set_power(device, state);
321}
354EXPORT_SYMBOL(acpi_bus_set_power); 322EXPORT_SYMBOL(acpi_bus_set_power);
355 323
324
325int acpi_bus_init_power(struct acpi_device *device)
326{
327 int state;
328 int result;
329
330 if (!device)
331 return -EINVAL;
332
333 device->power.state = ACPI_STATE_UNKNOWN;
334
335 result = __acpi_bus_get_power(device, &state);
336 if (result)
337 return result;
338
339 if (device->power.flags.power_resources)
340 result = acpi_power_on_resources(device, state);
341
342 if (!result)
343 device->power.state = state;
344
345 return result;
346}
347
348
349int acpi_bus_update_power(acpi_handle handle, int *state_p)
350{
351 struct acpi_device *device;
352 int state;
353 int result;
354
355 result = acpi_bus_get_device(handle, &device);
356 if (result)
357 return result;
358
359 result = __acpi_bus_get_power(device, &state);
360 if (result)
361 return result;
362
363 result = __acpi_bus_set_power(device, state);
364 if (!result && state_p)
365 *state_p = state;
366
367 return result;
368}
369EXPORT_SYMBOL_GPL(acpi_bus_update_power);
370
371
356bool acpi_bus_power_manageable(acpi_handle handle) 372bool acpi_bus_power_manageable(acpi_handle handle)
357{ 373{
358 struct acpi_device *device; 374 struct acpi_device *device;
@@ -1023,15 +1039,8 @@ static int __init acpi_init(void)
1023 if (acpi_disabled) 1039 if (acpi_disabled)
1024 return result; 1040 return result;
1025 1041
1026 /*
1027 * If the laptop falls into the DMI check table, the power state check
1028 * will be disabled in the course of device power transition.
1029 */
1030 dmi_check_system(power_nocheck_dmi_table);
1031
1032 acpi_scan_init(); 1042 acpi_scan_init();
1033 acpi_ec_init(); 1043 acpi_ec_init();
1034 acpi_power_init();
1035 acpi_debugfs_init(); 1044 acpi_debugfs_init();
1036 acpi_sleep_proc_init(); 1045 acpi_sleep_proc_init();
1037 acpi_wakeup_device_init(); 1046 acpi_wakeup_device_init();