diff options
-rw-r--r-- | drivers/acpi/bus.c | 14 | ||||
-rw-r--r-- | drivers/acpi/fan.c | 40 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 110 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 16 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 6 |
5 files changed, 178 insertions, 8 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b77f03d51f0b..dd3983cece92 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -205,12 +205,14 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
205 | * Get device's current power state if it's unknown | 205 | * Get device's current power state if it's unknown |
206 | * This means device power state isn't initialized or previous setting failed | 206 | * This means device power state isn't initialized or previous setting failed |
207 | */ | 207 | */ |
208 | if (device->power.state == ACPI_STATE_UNKNOWN) | 208 | if (!device->flags.force_power_state) { |
209 | acpi_bus_get_power(device->handle, &device->power.state); | 209 | if (device->power.state == ACPI_STATE_UNKNOWN) |
210 | if (state == device->power.state) { | 210 | acpi_bus_get_power(device->handle, &device->power.state); |
211 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 211 | if (state == device->power.state) { |
212 | state)); | 212 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", |
213 | return_VALUE(0); | 213 | state)); |
214 | return_VALUE(0); | ||
215 | } | ||
214 | } | 216 | } |
215 | if (!device->power.states[state].flags.valid) { | 217 | if (!device->power.states[state].flags.valid) { |
216 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", | 218 | ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", |
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index e8165c4f162a..1cd25784b7a4 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
@@ -48,6 +48,8 @@ MODULE_LICENSE("GPL"); | |||
48 | 48 | ||
49 | static int acpi_fan_add(struct acpi_device *device); | 49 | static int acpi_fan_add(struct acpi_device *device); |
50 | static int acpi_fan_remove(struct acpi_device *device, int type); | 50 | static int acpi_fan_remove(struct acpi_device *device, int type); |
51 | static int acpi_fan_suspend(struct acpi_device *device, int state); | ||
52 | static int acpi_fan_resume(struct acpi_device *device, int state); | ||
51 | 53 | ||
52 | static struct acpi_driver acpi_fan_driver = { | 54 | static struct acpi_driver acpi_fan_driver = { |
53 | .name = ACPI_FAN_DRIVER_NAME, | 55 | .name = ACPI_FAN_DRIVER_NAME, |
@@ -56,6 +58,8 @@ static struct acpi_driver acpi_fan_driver = { | |||
56 | .ops = { | 58 | .ops = { |
57 | .add = acpi_fan_add, | 59 | .add = acpi_fan_add, |
58 | .remove = acpi_fan_remove, | 60 | .remove = acpi_fan_remove, |
61 | .suspend = acpi_fan_suspend, | ||
62 | .resume = acpi_fan_resume, | ||
59 | }, | 63 | }, |
60 | }; | 64 | }; |
61 | 65 | ||
@@ -206,6 +210,10 @@ static int acpi_fan_add(struct acpi_device *device) | |||
206 | goto end; | 210 | goto end; |
207 | } | 211 | } |
208 | 212 | ||
213 | device->flags.force_power_state = 1; | ||
214 | acpi_bus_set_power(device->handle, state); | ||
215 | device->flags.force_power_state = 0; | ||
216 | |||
209 | result = acpi_fan_add_fs(device); | 217 | result = acpi_fan_add_fs(device); |
210 | if (result) | 218 | if (result) |
211 | goto end; | 219 | goto end; |
@@ -239,6 +247,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type) | |||
239 | return_VALUE(0); | 247 | return_VALUE(0); |
240 | } | 248 | } |
241 | 249 | ||
250 | static int acpi_fan_suspend(struct acpi_device *device, int state) | ||
251 | { | ||
252 | if (!device) | ||
253 | return -EINVAL; | ||
254 | |||
255 | acpi_bus_set_power(device->handle, ACPI_STATE_D0); | ||
256 | |||
257 | return AE_OK; | ||
258 | } | ||
259 | |||
260 | static int acpi_fan_resume(struct acpi_device *device, int state) | ||
261 | { | ||
262 | int result = 0; | ||
263 | int power_state = 0; | ||
264 | |||
265 | if (!device) | ||
266 | return -EINVAL; | ||
267 | |||
268 | result = acpi_bus_get_power(device->handle, &power_state); | ||
269 | if (result) { | ||
270 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
271 | "Error reading fan power state\n")); | ||
272 | return result; | ||
273 | } | ||
274 | |||
275 | device->flags.force_power_state = 1; | ||
276 | acpi_bus_set_power(device->handle, power_state); | ||
277 | device->flags.force_power_state = 0; | ||
278 | |||
279 | return result; | ||
280 | } | ||
281 | |||
242 | static int __init acpi_fan_init(void) | 282 | static int __init acpi_fan_init(void) |
243 | { | 283 | { |
244 | int result = 0; | 284 | int result = 0; |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fe3693de7ba3..f8316a05ede7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -1341,6 +1341,100 @@ static int acpi_bus_scan_fixed(struct acpi_device *root) | |||
1341 | return_VALUE(result); | 1341 | return_VALUE(result); |
1342 | } | 1342 | } |
1343 | 1343 | ||
1344 | |||
1345 | static inline struct acpi_device * to_acpi_dev(struct device * dev) | ||
1346 | { | ||
1347 | return container_of(dev, struct acpi_device, dev); | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state) | ||
1352 | { | ||
1353 | struct acpi_device * dev, * next; | ||
1354 | int result; | ||
1355 | |||
1356 | spin_lock(&acpi_device_lock); | ||
1357 | list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) { | ||
1358 | if (dev->driver && dev->driver->ops.suspend) { | ||
1359 | spin_unlock(&acpi_device_lock); | ||
1360 | result = dev->driver->ops.suspend(dev, 0); | ||
1361 | if (result) { | ||
1362 | printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n", | ||
1363 | acpi_device_name(dev), | ||
1364 | acpi_device_bid(dev), result); | ||
1365 | } | ||
1366 | spin_lock(&acpi_device_lock); | ||
1367 | } | ||
1368 | } | ||
1369 | spin_unlock(&acpi_device_lock); | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | |||
1374 | static int acpi_device_suspend(struct device * dev, pm_message_t state) | ||
1375 | { | ||
1376 | struct acpi_device * acpi_dev = to_acpi_dev(dev); | ||
1377 | |||
1378 | /* | ||
1379 | * For now, we should only register 1 generic device - | ||
1380 | * the ACPI root device - and from there, we walk the | ||
1381 | * tree of ACPI devices to suspend each one using the | ||
1382 | * ACPI driver methods. | ||
1383 | */ | ||
1384 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
1385 | root_suspend(acpi_dev, state); | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | |||
1391 | static int root_resume(struct acpi_device * acpi_dev) | ||
1392 | { | ||
1393 | struct acpi_device * dev, * next; | ||
1394 | int result; | ||
1395 | |||
1396 | spin_lock(&acpi_device_lock); | ||
1397 | list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) { | ||
1398 | if (dev->driver && dev->driver->ops.resume) { | ||
1399 | spin_unlock(&acpi_device_lock); | ||
1400 | result = dev->driver->ops.resume(dev, 0); | ||
1401 | if (result) { | ||
1402 | printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n", | ||
1403 | acpi_device_name(dev), | ||
1404 | acpi_device_bid(dev), result); | ||
1405 | } | ||
1406 | spin_lock(&acpi_device_lock); | ||
1407 | } | ||
1408 | } | ||
1409 | spin_unlock(&acpi_device_lock); | ||
1410 | return 0; | ||
1411 | } | ||
1412 | |||
1413 | |||
1414 | static int acpi_device_resume(struct device * dev) | ||
1415 | { | ||
1416 | struct acpi_device * acpi_dev = to_acpi_dev(dev); | ||
1417 | |||
1418 | /* | ||
1419 | * For now, we should only register 1 generic device - | ||
1420 | * the ACPI root device - and from there, we walk the | ||
1421 | * tree of ACPI devices to resume each one using the | ||
1422 | * ACPI driver methods. | ||
1423 | */ | ||
1424 | if (acpi_dev->handle == ACPI_ROOT_OBJECT) | ||
1425 | root_resume(acpi_dev); | ||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | struct bus_type acpi_bus_type = { | ||
1431 | .name = "acpi", | ||
1432 | .suspend = acpi_device_suspend, | ||
1433 | .resume = acpi_device_resume, | ||
1434 | }; | ||
1435 | |||
1436 | |||
1437 | |||
1344 | static int __init acpi_scan_init(void) | 1438 | static int __init acpi_scan_init(void) |
1345 | { | 1439 | { |
1346 | int result; | 1440 | int result; |
@@ -1353,6 +1447,12 @@ static int __init acpi_scan_init(void) | |||
1353 | 1447 | ||
1354 | kset_register(&acpi_namespace_kset); | 1448 | kset_register(&acpi_namespace_kset); |
1355 | 1449 | ||
1450 | result = bus_register(&acpi_bus_type); | ||
1451 | if (result) { | ||
1452 | /* We don't want to quit even if we failed to add suspend/resume */ | ||
1453 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | ||
1454 | } | ||
1455 | |||
1356 | /* | 1456 | /* |
1357 | * Create the root device in the bus's device tree | 1457 | * Create the root device in the bus's device tree |
1358 | */ | 1458 | */ |
@@ -1362,6 +1462,16 @@ static int __init acpi_scan_init(void) | |||
1362 | goto Done; | 1462 | goto Done; |
1363 | 1463 | ||
1364 | result = acpi_start_single_object(acpi_root); | 1464 | result = acpi_start_single_object(acpi_root); |
1465 | if (result) | ||
1466 | goto Done; | ||
1467 | |||
1468 | acpi_root->dev.bus = &acpi_bus_type; | ||
1469 | snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name); | ||
1470 | result = device_register(&acpi_root->dev); | ||
1471 | if (result) { | ||
1472 | /* We don't want to quit even if we failed to add suspend/resume */ | ||
1473 | printk(KERN_ERR PREFIX "Could not register device\n"); | ||
1474 | } | ||
1365 | 1475 | ||
1366 | /* | 1476 | /* |
1367 | * Enumerate devices in the ACPI namespace. | 1477 | * Enumerate devices in the ACPI namespace. |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f003763de7bb..e7fe3a14fdaf 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -82,6 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n"); | |||
82 | 82 | ||
83 | static int acpi_thermal_add(struct acpi_device *device); | 83 | static int acpi_thermal_add(struct acpi_device *device); |
84 | static int acpi_thermal_remove(struct acpi_device *device, int type); | 84 | static int acpi_thermal_remove(struct acpi_device *device, int type); |
85 | static int acpi_thermal_resume(struct acpi_device *device, int state); | ||
85 | static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); | 86 | static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file); |
86 | static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); | 87 | static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file); |
87 | static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); | 88 | static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file); |
@@ -103,6 +104,7 @@ static struct acpi_driver acpi_thermal_driver = { | |||
103 | .ops = { | 104 | .ops = { |
104 | .add = acpi_thermal_add, | 105 | .add = acpi_thermal_add, |
105 | .remove = acpi_thermal_remove, | 106 | .remove = acpi_thermal_remove, |
107 | .resume = acpi_thermal_resume, | ||
106 | }, | 108 | }, |
107 | }; | 109 | }; |
108 | 110 | ||
@@ -1417,6 +1419,20 @@ static int acpi_thermal_remove(struct acpi_device *device, int type) | |||
1417 | return_VALUE(0); | 1419 | return_VALUE(0); |
1418 | } | 1420 | } |
1419 | 1421 | ||
1422 | static int acpi_thermal_resume(struct acpi_device *device, int state) | ||
1423 | { | ||
1424 | struct acpi_thermal *tz = NULL; | ||
1425 | |||
1426 | if (!device || !acpi_driver_data(device)) | ||
1427 | return_VALUE(-EINVAL); | ||
1428 | |||
1429 | tz = (struct acpi_thermal *)acpi_driver_data(device); | ||
1430 | |||
1431 | acpi_thermal_check(tz); | ||
1432 | |||
1433 | return AE_OK; | ||
1434 | } | ||
1435 | |||
1420 | static int __init acpi_thermal_init(void) | 1436 | static int __init acpi_thermal_init(void) |
1421 | { | 1437 | { |
1422 | int result = 0; | 1438 | int result = 0; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 8c7590fdd822..a2b3e390a503 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #ifndef __ACPI_BUS_H__ | 26 | #ifndef __ACPI_BUS_H__ |
27 | #define __ACPI_BUS_H__ | 27 | #define __ACPI_BUS_H__ |
28 | 28 | ||
29 | #include <linux/kobject.h> | 29 | #include <linux/device.h> |
30 | 30 | ||
31 | #include <acpi/acpi.h> | 31 | #include <acpi/acpi.h> |
32 | 32 | ||
@@ -169,7 +169,8 @@ struct acpi_device_flags { | |||
169 | u32 power_manageable:1; | 169 | u32 power_manageable:1; |
170 | u32 performance_manageable:1; | 170 | u32 performance_manageable:1; |
171 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ | 171 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ |
172 | u32 reserved:20; | 172 | u32 force_power_state:1; |
173 | u32 reserved:19; | ||
173 | }; | 174 | }; |
174 | 175 | ||
175 | /* File System */ | 176 | /* File System */ |
@@ -296,6 +297,7 @@ struct acpi_device { | |||
296 | struct acpi_driver *driver; | 297 | struct acpi_driver *driver; |
297 | void *driver_data; | 298 | void *driver_data; |
298 | struct kobject kobj; | 299 | struct kobject kobj; |
300 | struct device dev; | ||
299 | }; | 301 | }; |
300 | 302 | ||
301 | #define acpi_driver_data(d) ((d)->driver_data) | 303 | #define acpi_driver_data(d) ((d)->driver_data) |