diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 164 | ||||
-rw-r--r-- | drivers/acpi/bus.c | 8 | ||||
-rw-r--r-- | drivers/acpi/button.c | 37 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 146 | ||||
-rw-r--r-- | drivers/acpi/fan.c | 72 | ||||
-rw-r--r-- | drivers/acpi/power.c | 63 | ||||
-rw-r--r-- | drivers/acpi/sleep/main.c | 5 |
8 files changed, 236 insertions, 267 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5d0e26a5c34c..ecd87d7aa9f6 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -88,7 +88,8 @@ config ACPI_PROC_EVENT | |||
88 | 88 | ||
89 | config ACPI_AC | 89 | config ACPI_AC |
90 | tristate "AC Adapter" | 90 | tristate "AC Adapter" |
91 | depends on X86 && POWER_SUPPLY | 91 | depends on X86 |
92 | select POWER_SUPPLY | ||
92 | default y | 93 | default y |
93 | help | 94 | help |
94 | This driver adds support for the AC Adapter object, which indicates | 95 | This driver adds support for the AC Adapter object, which indicates |
@@ -97,7 +98,8 @@ config ACPI_AC | |||
97 | 98 | ||
98 | config ACPI_BATTERY | 99 | config ACPI_BATTERY |
99 | tristate "Battery" | 100 | tristate "Battery" |
100 | depends on X86 && POWER_SUPPLY | 101 | depends on X86 |
102 | select POWER_SUPPLY | ||
101 | default y | 103 | default y |
102 | help | 104 | help |
103 | This driver adds support for battery information through | 105 | This driver adds support for battery information through |
@@ -352,7 +354,7 @@ config ACPI_HOTPLUG_MEMORY | |||
352 | config ACPI_SBS | 354 | config ACPI_SBS |
353 | tristate "Smart Battery System" | 355 | tristate "Smart Battery System" |
354 | depends on X86 | 356 | depends on X86 |
355 | depends on POWER_SUPPLY | 357 | select POWER_SUPPLY |
356 | help | 358 | help |
357 | This driver adds support for the Smart Battery System, another | 359 | This driver adds support for the Smart Battery System, another |
358 | type of access to battery information, found on some laptops. | 360 | type of access to battery information, found on some laptops. |
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 681e26b56b11..c2ce0ad21693 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -125,11 +125,15 @@ static int acpi_battery_technology(struct acpi_battery *battery) | |||
125 | return POWER_SUPPLY_TECHNOLOGY_NiMH; | 125 | return POWER_SUPPLY_TECHNOLOGY_NiMH; |
126 | if (!strcasecmp("LION", battery->type)) | 126 | if (!strcasecmp("LION", battery->type)) |
127 | return POWER_SUPPLY_TECHNOLOGY_LION; | 127 | return POWER_SUPPLY_TECHNOLOGY_LION; |
128 | if (!strcasecmp("LI-ION", battery->type)) | ||
129 | return POWER_SUPPLY_TECHNOLOGY_LION; | ||
128 | if (!strcasecmp("LiP", battery->type)) | 130 | if (!strcasecmp("LiP", battery->type)) |
129 | return POWER_SUPPLY_TECHNOLOGY_LIPO; | 131 | return POWER_SUPPLY_TECHNOLOGY_LIPO; |
130 | return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; | 132 | return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; |
131 | } | 133 | } |
132 | 134 | ||
135 | static int acpi_battery_update(struct acpi_battery *battery); | ||
136 | |||
133 | static int acpi_battery_get_property(struct power_supply *psy, | 137 | static int acpi_battery_get_property(struct power_supply *psy, |
134 | enum power_supply_property psp, | 138 | enum power_supply_property psp, |
135 | union power_supply_propval *val) | 139 | union power_supply_propval *val) |
@@ -139,6 +143,7 @@ static int acpi_battery_get_property(struct power_supply *psy, | |||
139 | if ((!acpi_battery_present(battery)) && | 143 | if ((!acpi_battery_present(battery)) && |
140 | psp != POWER_SUPPLY_PROP_PRESENT) | 144 | psp != POWER_SUPPLY_PROP_PRESENT) |
141 | return -ENODEV; | 145 | return -ENODEV; |
146 | acpi_battery_update(battery); | ||
142 | switch (psp) { | 147 | switch (psp) { |
143 | case POWER_SUPPLY_PROP_STATUS: | 148 | case POWER_SUPPLY_PROP_STATUS: |
144 | if (battery->state & 0x01) | 149 | if (battery->state & 0x01) |
@@ -257,7 +262,7 @@ static int extract_package(struct acpi_battery *battery, | |||
257 | union acpi_object *package, | 262 | union acpi_object *package, |
258 | struct acpi_offsets *offsets, int num) | 263 | struct acpi_offsets *offsets, int num) |
259 | { | 264 | { |
260 | int i, *x; | 265 | int i; |
261 | union acpi_object *element; | 266 | union acpi_object *element; |
262 | if (package->type != ACPI_TYPE_PACKAGE) | 267 | if (package->type != ACPI_TYPE_PACKAGE) |
263 | return -EFAULT; | 268 | return -EFAULT; |
@@ -266,16 +271,21 @@ static int extract_package(struct acpi_battery *battery, | |||
266 | return -EFAULT; | 271 | return -EFAULT; |
267 | element = &package->package.elements[i]; | 272 | element = &package->package.elements[i]; |
268 | if (offsets[i].mode) { | 273 | if (offsets[i].mode) { |
269 | if (element->type != ACPI_TYPE_STRING && | 274 | u8 *ptr = (u8 *)battery + offsets[i].offset; |
270 | element->type != ACPI_TYPE_BUFFER) | 275 | if (element->type == ACPI_TYPE_STRING || |
271 | return -EFAULT; | 276 | element->type == ACPI_TYPE_BUFFER) |
272 | strncpy((u8 *)battery + offsets[i].offset, | 277 | strncpy(ptr, element->string.pointer, 32); |
273 | element->string.pointer, 32); | 278 | else if (element->type == ACPI_TYPE_INTEGER) { |
279 | strncpy(ptr, (u8 *)&element->integer.value, | ||
280 | sizeof(acpi_integer)); | ||
281 | ptr[sizeof(acpi_integer)] = 0; | ||
282 | } else return -EFAULT; | ||
274 | } else { | 283 | } else { |
275 | if (element->type != ACPI_TYPE_INTEGER) | 284 | if (element->type == ACPI_TYPE_INTEGER) { |
276 | return -EFAULT; | 285 | int *x = (int *)((u8 *)battery + |
277 | x = (int *)((u8 *)battery + offsets[i].offset); | 286 | offsets[i].offset); |
278 | *x = element->integer.value; | 287 | *x = element->integer.value; |
288 | } else return -EFAULT; | ||
279 | } | 289 | } |
280 | } | 290 | } |
281 | return 0; | 291 | return 0; |
@@ -385,29 +395,81 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery) | |||
385 | return acpi_battery_set_alarm(battery); | 395 | return acpi_battery_set_alarm(battery); |
386 | } | 396 | } |
387 | 397 | ||
398 | static ssize_t acpi_battery_alarm_show(struct device *dev, | ||
399 | struct device_attribute *attr, | ||
400 | char *buf) | ||
401 | { | ||
402 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
403 | return sprintf(buf, "%d\n", battery->alarm * 1000); | ||
404 | } | ||
405 | |||
406 | static ssize_t acpi_battery_alarm_store(struct device *dev, | ||
407 | struct device_attribute *attr, | ||
408 | const char *buf, size_t count) | ||
409 | { | ||
410 | unsigned long x; | ||
411 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
412 | if (sscanf(buf, "%ld\n", &x) == 1) | ||
413 | battery->alarm = x/1000; | ||
414 | if (acpi_battery_present(battery)) | ||
415 | acpi_battery_set_alarm(battery); | ||
416 | return count; | ||
417 | } | ||
418 | |||
419 | static struct device_attribute alarm_attr = { | ||
420 | .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, | ||
421 | .show = acpi_battery_alarm_show, | ||
422 | .store = acpi_battery_alarm_store, | ||
423 | }; | ||
424 | |||
425 | static int sysfs_add_battery(struct acpi_battery *battery) | ||
426 | { | ||
427 | int result; | ||
428 | |||
429 | battery->update_time = 0; | ||
430 | result = acpi_battery_get_info(battery); | ||
431 | acpi_battery_init_alarm(battery); | ||
432 | if (result) | ||
433 | return result; | ||
434 | if (battery->power_unit) { | ||
435 | battery->bat.properties = charge_battery_props; | ||
436 | battery->bat.num_properties = | ||
437 | ARRAY_SIZE(charge_battery_props); | ||
438 | } else { | ||
439 | battery->bat.properties = energy_battery_props; | ||
440 | battery->bat.num_properties = | ||
441 | ARRAY_SIZE(energy_battery_props); | ||
442 | } | ||
443 | |||
444 | battery->bat.name = acpi_device_bid(battery->device); | ||
445 | battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
446 | battery->bat.get_property = acpi_battery_get_property; | ||
447 | |||
448 | result = power_supply_register(&battery->device->dev, &battery->bat); | ||
449 | if (result) | ||
450 | return result; | ||
451 | return device_create_file(battery->bat.dev, &alarm_attr); | ||
452 | } | ||
453 | |||
454 | static void sysfs_remove_battery(struct acpi_battery *battery) | ||
455 | { | ||
456 | if (!battery->bat.dev) | ||
457 | return; | ||
458 | device_remove_file(battery->bat.dev, &alarm_attr); | ||
459 | power_supply_unregister(&battery->bat); | ||
460 | } | ||
461 | |||
388 | static int acpi_battery_update(struct acpi_battery *battery) | 462 | static int acpi_battery_update(struct acpi_battery *battery) |
389 | { | 463 | { |
390 | int saved_present = acpi_battery_present(battery); | ||
391 | int result = acpi_battery_get_status(battery); | 464 | int result = acpi_battery_get_status(battery); |
392 | if (result || !acpi_battery_present(battery)) | 465 | if (result) |
393 | return result; | 466 | return result; |
394 | if (saved_present != acpi_battery_present(battery) || | 467 | if (!acpi_battery_present(battery)) { |
395 | !battery->update_time) { | 468 | sysfs_remove_battery(battery); |
396 | battery->update_time = 0; | 469 | return 0; |
397 | result = acpi_battery_get_info(battery); | ||
398 | if (result) | ||
399 | return result; | ||
400 | if (battery->power_unit) { | ||
401 | battery->bat.properties = charge_battery_props; | ||
402 | battery->bat.num_properties = | ||
403 | ARRAY_SIZE(charge_battery_props); | ||
404 | } else { | ||
405 | battery->bat.properties = energy_battery_props; | ||
406 | battery->bat.num_properties = | ||
407 | ARRAY_SIZE(energy_battery_props); | ||
408 | } | ||
409 | acpi_battery_init_alarm(battery); | ||
410 | } | 470 | } |
471 | if (!battery->bat.dev) | ||
472 | sysfs_add_battery(battery); | ||
411 | return acpi_battery_get_state(battery); | 473 | return acpi_battery_get_state(battery); |
412 | } | 474 | } |
413 | 475 | ||
@@ -554,10 +616,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file, | |||
554 | 616 | ||
555 | if (!battery || (count > sizeof(alarm_string) - 1)) | 617 | if (!battery || (count > sizeof(alarm_string) - 1)) |
556 | return -EINVAL; | 618 | return -EINVAL; |
557 | if (result) { | ||
558 | result = -ENODEV; | ||
559 | goto end; | ||
560 | } | ||
561 | if (!acpi_battery_present(battery)) { | 619 | if (!acpi_battery_present(battery)) { |
562 | result = -ENODEV; | 620 | result = -ENODEV; |
563 | goto end; | 621 | goto end; |
@@ -688,33 +746,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device) | |||
688 | 746 | ||
689 | #endif | 747 | #endif |
690 | 748 | ||
691 | static ssize_t acpi_battery_alarm_show(struct device *dev, | ||
692 | struct device_attribute *attr, | ||
693 | char *buf) | ||
694 | { | ||
695 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
696 | return sprintf(buf, "%d\n", battery->alarm * 1000); | ||
697 | } | ||
698 | |||
699 | static ssize_t acpi_battery_alarm_store(struct device *dev, | ||
700 | struct device_attribute *attr, | ||
701 | const char *buf, size_t count) | ||
702 | { | ||
703 | unsigned long x; | ||
704 | struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); | ||
705 | if (sscanf(buf, "%ld\n", &x) == 1) | ||
706 | battery->alarm = x/1000; | ||
707 | if (acpi_battery_present(battery)) | ||
708 | acpi_battery_set_alarm(battery); | ||
709 | return count; | ||
710 | } | ||
711 | |||
712 | static struct device_attribute alarm_attr = { | ||
713 | .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE}, | ||
714 | .show = acpi_battery_alarm_show, | ||
715 | .store = acpi_battery_alarm_store, | ||
716 | }; | ||
717 | |||
718 | /* -------------------------------------------------------------------------- | 749 | /* -------------------------------------------------------------------------- |
719 | Driver Interface | 750 | Driver Interface |
720 | -------------------------------------------------------------------------- */ | 751 | -------------------------------------------------------------------------- */ |
@@ -732,7 +763,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
732 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 763 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
733 | device->dev.bus_id, event, | 764 | device->dev.bus_id, event, |
734 | acpi_battery_present(battery)); | 765 | acpi_battery_present(battery)); |
735 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | 766 | /* acpi_batter_update could remove power_supply object */ |
767 | if (battery->bat.dev) | ||
768 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | ||
736 | } | 769 | } |
737 | 770 | ||
738 | static int acpi_battery_add(struct acpi_device *device) | 771 | static int acpi_battery_add(struct acpi_device *device) |
@@ -756,11 +789,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
756 | if (result) | 789 | if (result) |
757 | goto end; | 790 | goto end; |
758 | #endif | 791 | #endif |
759 | battery->bat.name = acpi_device_bid(device); | ||
760 | battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
761 | battery->bat.get_property = acpi_battery_get_property; | ||
762 | result = power_supply_register(&battery->device->dev, &battery->bat); | ||
763 | result = device_create_file(battery->bat.dev, &alarm_attr); | ||
764 | status = acpi_install_notify_handler(device->handle, | 792 | status = acpi_install_notify_handler(device->handle, |
765 | ACPI_ALL_NOTIFY, | 793 | ACPI_ALL_NOTIFY, |
766 | acpi_battery_notify, battery); | 794 | acpi_battery_notify, battery); |
@@ -796,10 +824,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
796 | #ifdef CONFIG_ACPI_PROCFS | 824 | #ifdef CONFIG_ACPI_PROCFS |
797 | acpi_battery_remove_fs(device); | 825 | acpi_battery_remove_fs(device); |
798 | #endif | 826 | #endif |
799 | if (battery->bat.dev) { | 827 | sysfs_remove_battery(battery); |
800 | device_remove_file(battery->bat.dev, &alarm_attr); | ||
801 | power_supply_unregister(&battery->bat); | ||
802 | } | ||
803 | mutex_destroy(&battery->lock); | 828 | mutex_destroy(&battery->lock); |
804 | kfree(battery); | 829 | kfree(battery); |
805 | return 0; | 830 | return 0; |
@@ -813,6 +838,7 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
813 | return -EINVAL; | 838 | return -EINVAL; |
814 | battery = acpi_driver_data(device); | 839 | battery = acpi_driver_data(device); |
815 | battery->update_time = 0; | 840 | battery->update_time = 0; |
841 | acpi_battery_update(battery); | ||
816 | return 0; | 842 | return 0; |
817 | } | 843 | } |
818 | 844 | ||
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index fb2cff9a2d24..49d432d0a12c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -198,12 +198,10 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
198 | return -ENODEV; | 198 | return -ENODEV; |
199 | } | 199 | } |
200 | /* | 200 | /* |
201 | * Get device's current power state if it's unknown | 201 | * Get device's current power state |
202 | * This means device power state isn't initialized or previous setting failed | ||
203 | */ | 202 | */ |
204 | if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state) | 203 | acpi_bus_get_power(device->handle, &device->power.state); |
205 | acpi_bus_get_power(device->handle, &device->power.state); | 204 | if (state == device->power.state) { |
206 | if ((state == device->power.state) && !device->flags.force_power_state) { | ||
207 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 205 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", |
208 | state)); | 206 | state)); |
209 | return 0; | 207 | return 0; |
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 301e832e6961..24a7865a57cb 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -78,6 +78,7 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids); | |||
78 | 78 | ||
79 | static int acpi_button_add(struct acpi_device *device); | 79 | static int acpi_button_add(struct acpi_device *device); |
80 | static int acpi_button_remove(struct acpi_device *device, int type); | 80 | static int acpi_button_remove(struct acpi_device *device, int type); |
81 | static int acpi_button_resume(struct acpi_device *device); | ||
81 | static int acpi_button_info_open_fs(struct inode *inode, struct file *file); | 82 | static int acpi_button_info_open_fs(struct inode *inode, struct file *file); |
82 | static int acpi_button_state_open_fs(struct inode *inode, struct file *file); | 83 | static int acpi_button_state_open_fs(struct inode *inode, struct file *file); |
83 | 84 | ||
@@ -87,6 +88,7 @@ static struct acpi_driver acpi_button_driver = { | |||
87 | .ids = button_device_ids, | 88 | .ids = button_device_ids, |
88 | .ops = { | 89 | .ops = { |
89 | .add = acpi_button_add, | 90 | .add = acpi_button_add, |
91 | .resume = acpi_button_resume, | ||
90 | .remove = acpi_button_remove, | 92 | .remove = acpi_button_remove, |
91 | }, | 93 | }, |
92 | }; | 94 | }; |
@@ -253,6 +255,19 @@ static int acpi_button_remove_fs(struct acpi_device *device) | |||
253 | /* -------------------------------------------------------------------------- | 255 | /* -------------------------------------------------------------------------- |
254 | Driver Interface | 256 | Driver Interface |
255 | -------------------------------------------------------------------------- */ | 257 | -------------------------------------------------------------------------- */ |
258 | static int acpi_lid_send_state(struct acpi_button *button) | ||
259 | { | ||
260 | unsigned long state; | ||
261 | acpi_status status; | ||
262 | |||
263 | status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, | ||
264 | &state); | ||
265 | if (ACPI_FAILURE(status)) | ||
266 | return -ENODEV; | ||
267 | /* input layer checks if event is redundant */ | ||
268 | input_report_switch(button->input, SW_LID, !state); | ||
269 | return 0; | ||
270 | } | ||
256 | 271 | ||
257 | static void acpi_button_notify(acpi_handle handle, u32 event, void *data) | 272 | static void acpi_button_notify(acpi_handle handle, u32 event, void *data) |
258 | { | 273 | { |
@@ -265,15 +280,8 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) | |||
265 | switch (event) { | 280 | switch (event) { |
266 | case ACPI_BUTTON_NOTIFY_STATUS: | 281 | case ACPI_BUTTON_NOTIFY_STATUS: |
267 | input = button->input; | 282 | input = button->input; |
268 | |||
269 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 283 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
270 | struct acpi_handle *handle = button->device->handle; | 284 | acpi_lid_send_state(button); |
271 | unsigned long state; | ||
272 | |||
273 | if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID", | ||
274 | NULL, &state))) | ||
275 | input_report_switch(input, SW_LID, !state); | ||
276 | |||
277 | } else { | 285 | } else { |
278 | int keycode = test_bit(KEY_SLEEP, input->keybit) ? | 286 | int keycode = test_bit(KEY_SLEEP, input->keybit) ? |
279 | KEY_SLEEP : KEY_POWER; | 287 | KEY_SLEEP : KEY_POWER; |
@@ -336,6 +344,17 @@ static int acpi_button_install_notify_handlers(struct acpi_button *button) | |||
336 | return ACPI_FAILURE(status) ? -ENODEV : 0; | 344 | return ACPI_FAILURE(status) ? -ENODEV : 0; |
337 | } | 345 | } |
338 | 346 | ||
347 | static int acpi_button_resume(struct acpi_device *device) | ||
348 | { | ||
349 | struct acpi_button *button; | ||
350 | if (!device) | ||
351 | return -EINVAL; | ||
352 | button = acpi_driver_data(device); | ||
353 | if (button && button->type == ACPI_BUTTON_TYPE_LID) | ||
354 | return acpi_lid_send_state(button); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
339 | static void acpi_button_remove_notify_handlers(struct acpi_button *button) | 358 | static void acpi_button_remove_notify_handlers(struct acpi_button *button) |
340 | { | 359 | { |
341 | switch (button->type) { | 360 | switch (button->type) { |
@@ -453,6 +472,8 @@ static int acpi_button_add(struct acpi_device *device) | |||
453 | error = input_register_device(input); | 472 | error = input_register_device(input); |
454 | if (error) | 473 | if (error) |
455 | goto err_remove_handlers; | 474 | goto err_remove_handlers; |
475 | if (button->type == ACPI_BUTTON_TYPE_LID) | ||
476 | acpi_lid_send_state(button); | ||
456 | 477 | ||
457 | if (device->wakeup.flags.valid) { | 478 | if (device->wakeup.flags.valid) { |
458 | /* Button's GPE is run-wake GPE */ | 479 | /* Button's GPE is run-wake GPE */ |
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7b4178393e34..06b78e5e33a1 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -65,16 +65,18 @@ enum ec_command { | |||
65 | /* EC events */ | 65 | /* EC events */ |
66 | enum ec_event { | 66 | enum ec_event { |
67 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | 67 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ |
68 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ | 68 | ACPI_EC_EVENT_IBF_0, /* Input buffer empty */ |
69 | }; | 69 | }; |
70 | 70 | ||
71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ | 71 | #define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */ |
72 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ | 72 | #define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */ |
73 | 73 | ||
74 | static enum ec_mode { | 74 | enum { |
75 | EC_INTR = 1, /* Output buffer full */ | 75 | EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */ |
76 | EC_POLL, /* Input buffer empty */ | 76 | EC_FLAGS_QUERY_PENDING, /* Query is pending */ |
77 | } acpi_ec_mode = EC_INTR; | 77 | EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */ |
78 | EC_FLAGS_ONLY_IBF_GPE, /* Expect GPE only for IBF = 0 event */ | ||
79 | }; | ||
78 | 80 | ||
79 | static int acpi_ec_remove(struct acpi_device *device, int type); | 81 | static int acpi_ec_remove(struct acpi_device *device, int type); |
80 | static int acpi_ec_start(struct acpi_device *device); | 82 | static int acpi_ec_start(struct acpi_device *device); |
@@ -116,9 +118,8 @@ static struct acpi_ec { | |||
116 | unsigned long command_addr; | 118 | unsigned long command_addr; |
117 | unsigned long data_addr; | 119 | unsigned long data_addr; |
118 | unsigned long global_lock; | 120 | unsigned long global_lock; |
121 | unsigned long flags; | ||
119 | struct mutex lock; | 122 | struct mutex lock; |
120 | atomic_t query_pending; | ||
121 | atomic_t event_count; | ||
122 | wait_queue_head_t wait; | 123 | wait_queue_head_t wait; |
123 | struct list_head list; | 124 | struct list_head list; |
124 | u8 handlers_installed; | 125 | u8 handlers_installed; |
@@ -148,45 +149,54 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) | |||
148 | outb(data, ec->data_addr); | 149 | outb(data, ec->data_addr); |
149 | } | 150 | } |
150 | 151 | ||
151 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event, | 152 | static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) |
152 | unsigned old_count) | ||
153 | { | 153 | { |
154 | u8 status = acpi_ec_read_status(ec); | 154 | if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags)) |
155 | if (old_count == atomic_read(&ec->event_count)) | ||
156 | return 0; | 155 | return 0; |
157 | if (event == ACPI_EC_EVENT_OBF_1) { | 156 | if (event == ACPI_EC_EVENT_OBF_1) { |
158 | if (status & ACPI_EC_FLAG_OBF) | 157 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF) |
159 | return 1; | 158 | return 1; |
160 | } else if (event == ACPI_EC_EVENT_IBF_0) { | 159 | } else if (event == ACPI_EC_EVENT_IBF_0) { |
161 | if (!(status & ACPI_EC_FLAG_IBF)) | 160 | if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)) |
162 | return 1; | 161 | return 1; |
163 | } | 162 | } |
164 | 163 | ||
165 | return 0; | 164 | return 0; |
166 | } | 165 | } |
167 | 166 | ||
168 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, | 167 | static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) |
169 | unsigned count, int force_poll) | ||
170 | { | 168 | { |
171 | if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) { | 169 | if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) && |
170 | likely(!force_poll)) { | ||
171 | if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event), | ||
172 | msecs_to_jiffies(ACPI_EC_DELAY))) | ||
173 | return 0; | ||
174 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
175 | if (acpi_ec_check_status(ec, event)) { | ||
176 | if (event == ACPI_EC_EVENT_OBF_1) { | ||
177 | /* miss OBF = 1 GPE, don't expect it anymore */ | ||
178 | printk(KERN_INFO PREFIX "missing OBF_1 confirmation," | ||
179 | "switching to degraded mode.\n"); | ||
180 | set_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags); | ||
181 | } else { | ||
182 | /* missing GPEs, switch back to poll mode */ | ||
183 | printk(KERN_INFO PREFIX "missing IBF_1 confirmations," | ||
184 | "switch off interrupt mode.\n"); | ||
185 | clear_bit(EC_FLAGS_GPE_MODE, &ec->flags); | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | } else { | ||
172 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); | 190 | unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY); |
191 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
173 | while (time_before(jiffies, delay)) { | 192 | while (time_before(jiffies, delay)) { |
174 | if (acpi_ec_check_status(ec, event, 0)) | 193 | if (acpi_ec_check_status(ec, event)) |
175 | return 0; | 194 | return 0; |
176 | } | 195 | } |
177 | } else { | 196 | } |
178 | if (wait_event_timeout(ec->wait, | 197 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," |
179 | acpi_ec_check_status(ec, event, count), | ||
180 | msecs_to_jiffies(ACPI_EC_DELAY)) || | ||
181 | acpi_ec_check_status(ec, event, 0)) { | ||
182 | return 0; | ||
183 | } else { | ||
184 | printk(KERN_ERR PREFIX "acpi_ec_wait timeout," | ||
185 | " status = %d, expect_event = %d\n", | 198 | " status = %d, expect_event = %d\n", |
186 | acpi_ec_read_status(ec), event); | 199 | acpi_ec_read_status(ec), event); |
187 | } | ||
188 | } | ||
189 | |||
190 | return -ETIME; | 200 | return -ETIME; |
191 | } | 201 | } |
192 | 202 | ||
@@ -196,39 +206,42 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command, | |||
196 | int force_poll) | 206 | int force_poll) |
197 | { | 207 | { |
198 | int result = 0; | 208 | int result = 0; |
199 | unsigned count = atomic_read(&ec->event_count); | 209 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
200 | acpi_ec_write_cmd(ec, command); | 210 | acpi_ec_write_cmd(ec, command); |
201 | 211 | ||
202 | for (; wdata_len > 0; --wdata_len) { | 212 | for (; wdata_len > 0; --wdata_len) { |
203 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); | 213 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
204 | if (result) { | 214 | if (result) { |
205 | printk(KERN_ERR PREFIX | 215 | printk(KERN_ERR PREFIX |
206 | "write_cmd timeout, command = %d\n", command); | 216 | "write_cmd timeout, command = %d\n", command); |
207 | goto end; | 217 | goto end; |
208 | } | 218 | } |
209 | count = atomic_read(&ec->event_count); | 219 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
210 | acpi_ec_write_data(ec, *(wdata++)); | 220 | acpi_ec_write_data(ec, *(wdata++)); |
211 | } | 221 | } |
212 | 222 | ||
213 | if (!rdata_len) { | 223 | if (!rdata_len) { |
214 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll); | 224 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll); |
215 | if (result) { | 225 | if (result) { |
216 | printk(KERN_ERR PREFIX | 226 | printk(KERN_ERR PREFIX |
217 | "finish-write timeout, command = %d\n", command); | 227 | "finish-write timeout, command = %d\n", command); |
218 | goto end; | 228 | goto end; |
219 | } | 229 | } |
220 | } else if (command == ACPI_EC_COMMAND_QUERY) { | 230 | } else if (command == ACPI_EC_COMMAND_QUERY) |
221 | atomic_set(&ec->query_pending, 0); | 231 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
222 | } | ||
223 | 232 | ||
224 | for (; rdata_len > 0; --rdata_len) { | 233 | for (; rdata_len > 0; --rdata_len) { |
225 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll); | 234 | if (test_bit(EC_FLAGS_ONLY_IBF_GPE, &ec->flags)) |
235 | force_poll = 1; | ||
236 | result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll); | ||
226 | if (result) { | 237 | if (result) { |
227 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", | 238 | printk(KERN_ERR PREFIX "read timeout, command = %d\n", |
228 | command); | 239 | command); |
229 | goto end; | 240 | goto end; |
230 | } | 241 | } |
231 | count = atomic_read(&ec->event_count); | 242 | /* Don't expect GPE after last read */ |
243 | if (rdata_len > 1) | ||
244 | set_bit(EC_FLAGS_WAIT_GPE, &ec->flags); | ||
232 | *(rdata++) = acpi_ec_read_data(ec); | 245 | *(rdata++) = acpi_ec_read_data(ec); |
233 | } | 246 | } |
234 | end: | 247 | end: |
@@ -258,10 +271,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
258 | } | 271 | } |
259 | } | 272 | } |
260 | 273 | ||
261 | /* Make sure GPE is enabled before doing transaction */ | 274 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0); |
262 | acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR); | ||
263 | |||
264 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); | ||
265 | if (status) { | 275 | if (status) { |
266 | printk(KERN_ERR PREFIX | 276 | printk(KERN_ERR PREFIX |
267 | "input buffer is not empty, aborting transaction\n"); | 277 | "input buffer is not empty, aborting transaction\n"); |
@@ -435,9 +445,9 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | |||
435 | 445 | ||
436 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | 446 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) |
437 | { | 447 | { |
438 | struct acpi_ec_query_handler *handler; | 448 | struct acpi_ec_query_handler *handler, *tmp; |
439 | mutex_lock(&ec->lock); | 449 | mutex_lock(&ec->lock); |
440 | list_for_each_entry(handler, &ec->list, node) { | 450 | list_for_each_entry_safe(handler, tmp, &ec->list, node) { |
441 | if (query_bit == handler->query_bit) { | 451 | if (query_bit == handler->query_bit) { |
442 | list_del(&handler->node); | 452 | list_del(&handler->node); |
443 | kfree(handler); | 453 | kfree(handler); |
@@ -476,23 +486,24 @@ static void acpi_ec_gpe_query(void *ec_cxt) | |||
476 | static u32 acpi_ec_gpe_handler(void *data) | 486 | static u32 acpi_ec_gpe_handler(void *data) |
477 | { | 487 | { |
478 | acpi_status status = AE_OK; | 488 | acpi_status status = AE_OK; |
479 | u8 value; | ||
480 | struct acpi_ec *ec = data; | 489 | struct acpi_ec *ec = data; |
481 | 490 | ||
482 | atomic_inc(&ec->event_count); | 491 | clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); |
483 | 492 | if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) | |
484 | if (acpi_ec_mode == EC_INTR) { | ||
485 | wake_up(&ec->wait); | 493 | wake_up(&ec->wait); |
486 | } | ||
487 | 494 | ||
488 | value = acpi_ec_read_status(ec); | 495 | if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) { |
489 | if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { | 496 | if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) |
490 | atomic_set(&ec->query_pending, 1); | 497 | status = acpi_os_execute(OSL_EC_BURST_HANDLER, |
491 | status = | 498 | acpi_ec_gpe_query, ec); |
492 | acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); | 499 | } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) { |
500 | /* this is non-query, must be confirmation */ | ||
501 | printk(KERN_INFO PREFIX "non-query interrupt received," | ||
502 | " switching to interrupt mode\n"); | ||
503 | set_bit(EC_FLAGS_GPE_MODE, &ec->flags); | ||
493 | } | 504 | } |
494 | 505 | ||
495 | return status == AE_OK ? | 506 | return ACPI_SUCCESS(status) ? |
496 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; | 507 | ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED; |
497 | } | 508 | } |
498 | 509 | ||
@@ -641,13 +652,10 @@ static struct acpi_ec *make_acpi_ec(void) | |||
641 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 652 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
642 | if (!ec) | 653 | if (!ec) |
643 | return NULL; | 654 | return NULL; |
644 | 655 | ec->flags = 1 << EC_FLAGS_QUERY_PENDING; | |
645 | atomic_set(&ec->query_pending, 1); | ||
646 | atomic_set(&ec->event_count, 1); | ||
647 | mutex_init(&ec->lock); | 656 | mutex_init(&ec->lock); |
648 | init_waitqueue_head(&ec->wait); | 657 | init_waitqueue_head(&ec->wait); |
649 | INIT_LIST_HEAD(&ec->list); | 658 | INIT_LIST_HEAD(&ec->list); |
650 | |||
651 | return ec; | 659 | return ec; |
652 | } | 660 | } |
653 | 661 | ||
@@ -741,6 +749,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
741 | acpi_ec_add_fs(device); | 749 | acpi_ec_add_fs(device); |
742 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", | 750 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", |
743 | ec->gpe, ec->command_addr, ec->data_addr); | 751 | ec->gpe, ec->command_addr, ec->data_addr); |
752 | printk(KERN_INFO PREFIX "driver started in %s mode\n", | ||
753 | (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll"); | ||
744 | return 0; | 754 | return 0; |
745 | } | 755 | } |
746 | 756 | ||
@@ -833,7 +843,7 @@ static int acpi_ec_start(struct acpi_device *device) | |||
833 | ret = ec_install_handlers(ec); | 843 | ret = ec_install_handlers(ec); |
834 | 844 | ||
835 | /* EC is fully operational, allow queries */ | 845 | /* EC is fully operational, allow queries */ |
836 | atomic_set(&ec->query_pending, 0); | 846 | clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); |
837 | return ret; | 847 | return ret; |
838 | } | 848 | } |
839 | 849 | ||
@@ -924,20 +934,4 @@ static void __exit acpi_ec_exit(void) | |||
924 | 934 | ||
925 | return; | 935 | return; |
926 | } | 936 | } |
927 | #endif /* 0 */ | 937 | #endif /* 0 */ |
928 | |||
929 | static int __init acpi_ec_set_intr_mode(char *str) | ||
930 | { | ||
931 | int intr; | ||
932 | |||
933 | if (!get_option(&str, &intr)) | ||
934 | return 0; | ||
935 | |||
936 | acpi_ec_mode = (intr) ? EC_INTR : EC_POLL; | ||
937 | |||
938 | printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling"); | ||
939 | |||
940 | return 1; | ||
941 | } | ||
942 | |||
943 | __setup("ec_intr=", acpi_ec_set_intr_mode); | ||
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index c81f6bdb68b8..a5a5532db268 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
@@ -47,8 +47,6 @@ MODULE_LICENSE("GPL"); | |||
47 | 47 | ||
48 | static int acpi_fan_add(struct acpi_device *device); | 48 | static int acpi_fan_add(struct acpi_device *device); |
49 | static int acpi_fan_remove(struct acpi_device *device, int type); | 49 | static int acpi_fan_remove(struct acpi_device *device, int type); |
50 | static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); | ||
51 | static int acpi_fan_resume(struct acpi_device *device); | ||
52 | 50 | ||
53 | static const struct acpi_device_id fan_device_ids[] = { | 51 | static const struct acpi_device_id fan_device_ids[] = { |
54 | {"PNP0C0B", 0}, | 52 | {"PNP0C0B", 0}, |
@@ -63,15 +61,9 @@ static struct acpi_driver acpi_fan_driver = { | |||
63 | .ops = { | 61 | .ops = { |
64 | .add = acpi_fan_add, | 62 | .add = acpi_fan_add, |
65 | .remove = acpi_fan_remove, | 63 | .remove = acpi_fan_remove, |
66 | .suspend = acpi_fan_suspend, | ||
67 | .resume = acpi_fan_resume, | ||
68 | }, | 64 | }, |
69 | }; | 65 | }; |
70 | 66 | ||
71 | struct acpi_fan { | ||
72 | struct acpi_device * device; | ||
73 | }; | ||
74 | |||
75 | /* -------------------------------------------------------------------------- | 67 | /* -------------------------------------------------------------------------- |
76 | FS Interface (/proc) | 68 | FS Interface (/proc) |
77 | -------------------------------------------------------------------------- */ | 69 | -------------------------------------------------------------------------- */ |
@@ -80,12 +72,12 @@ static struct proc_dir_entry *acpi_fan_dir; | |||
80 | 72 | ||
81 | static int acpi_fan_read_state(struct seq_file *seq, void *offset) | 73 | static int acpi_fan_read_state(struct seq_file *seq, void *offset) |
82 | { | 74 | { |
83 | struct acpi_fan *fan = seq->private; | 75 | struct acpi_device *device = seq->private; |
84 | int state = 0; | 76 | int state = 0; |
85 | 77 | ||
86 | 78 | ||
87 | if (fan) { | 79 | if (device) { |
88 | if (acpi_bus_get_power(fan->device->handle, &state)) | 80 | if (acpi_bus_get_power(device->handle, &state)) |
89 | seq_printf(seq, "status: ERROR\n"); | 81 | seq_printf(seq, "status: ERROR\n"); |
90 | else | 82 | else |
91 | seq_printf(seq, "status: %s\n", | 83 | seq_printf(seq, "status: %s\n", |
@@ -105,11 +97,10 @@ acpi_fan_write_state(struct file *file, const char __user * buffer, | |||
105 | { | 97 | { |
106 | int result = 0; | 98 | int result = 0; |
107 | struct seq_file *m = file->private_data; | 99 | struct seq_file *m = file->private_data; |
108 | struct acpi_fan *fan = m->private; | 100 | struct acpi_device *device = m->private; |
109 | char state_string[12] = { '\0' }; | 101 | char state_string[12] = { '\0' }; |
110 | 102 | ||
111 | 103 | if (count > sizeof(state_string) - 1) | |
112 | if (!fan || (count > sizeof(state_string) - 1)) | ||
113 | return -EINVAL; | 104 | return -EINVAL; |
114 | 105 | ||
115 | if (copy_from_user(state_string, buffer, count)) | 106 | if (copy_from_user(state_string, buffer, count)) |
@@ -117,7 +108,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer, | |||
117 | 108 | ||
118 | state_string[count] = '\0'; | 109 | state_string[count] = '\0'; |
119 | 110 | ||
120 | result = acpi_bus_set_power(fan->device->handle, | 111 | result = acpi_bus_set_power(device->handle, |
121 | simple_strtoul(state_string, NULL, 0)); | 112 | simple_strtoul(state_string, NULL, 0)); |
122 | if (result) | 113 | if (result) |
123 | return result; | 114 | return result; |
@@ -158,7 +149,7 @@ static int acpi_fan_add_fs(struct acpi_device *device) | |||
158 | return -ENODEV; | 149 | return -ENODEV; |
159 | else { | 150 | else { |
160 | entry->proc_fops = &acpi_fan_state_ops; | 151 | entry->proc_fops = &acpi_fan_state_ops; |
161 | entry->data = acpi_driver_data(device); | 152 | entry->data = device; |
162 | entry->owner = THIS_MODULE; | 153 | entry->owner = THIS_MODULE; |
163 | } | 154 | } |
164 | 155 | ||
@@ -191,14 +182,8 @@ static int acpi_fan_add(struct acpi_device *device) | |||
191 | if (!device) | 182 | if (!device) |
192 | return -EINVAL; | 183 | return -EINVAL; |
193 | 184 | ||
194 | fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL); | ||
195 | if (!fan) | ||
196 | return -ENOMEM; | ||
197 | |||
198 | fan->device = device; | ||
199 | strcpy(acpi_device_name(device), "Fan"); | 185 | strcpy(acpi_device_name(device), "Fan"); |
200 | strcpy(acpi_device_class(device), ACPI_FAN_CLASS); | 186 | strcpy(acpi_device_class(device), ACPI_FAN_CLASS); |
201 | acpi_driver_data(device) = fan; | ||
202 | 187 | ||
203 | result = acpi_bus_get_power(device->handle, &state); | 188 | result = acpi_bus_get_power(device->handle, &state); |
204 | if (result) { | 189 | if (result) { |
@@ -206,10 +191,6 @@ static int acpi_fan_add(struct acpi_device *device) | |||
206 | goto end; | 191 | goto end; |
207 | } | 192 | } |
208 | 193 | ||
209 | device->flags.force_power_state = 1; | ||
210 | acpi_bus_set_power(device->handle, state); | ||
211 | device->flags.force_power_state = 0; | ||
212 | |||
213 | result = acpi_fan_add_fs(device); | 194 | result = acpi_fan_add_fs(device); |
214 | if (result) | 195 | if (result) |
215 | goto end; | 196 | goto end; |
@@ -227,53 +208,14 @@ static int acpi_fan_add(struct acpi_device *device) | |||
227 | 208 | ||
228 | static int acpi_fan_remove(struct acpi_device *device, int type) | 209 | static int acpi_fan_remove(struct acpi_device *device, int type) |
229 | { | 210 | { |
230 | struct acpi_fan *fan = NULL; | ||
231 | |||
232 | |||
233 | if (!device || !acpi_driver_data(device)) | 211 | if (!device || !acpi_driver_data(device)) |
234 | return -EINVAL; | 212 | return -EINVAL; |
235 | 213 | ||
236 | fan = acpi_driver_data(device); | ||
237 | |||
238 | acpi_fan_remove_fs(device); | 214 | acpi_fan_remove_fs(device); |
239 | 215 | ||
240 | kfree(fan); | ||
241 | |||
242 | return 0; | 216 | return 0; |
243 | } | 217 | } |
244 | 218 | ||
245 | static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) | ||
246 | { | ||
247 | if (!device) | ||
248 | return -EINVAL; | ||
249 | |||
250 | acpi_bus_set_power(device->handle, ACPI_STATE_D0); | ||
251 | |||
252 | return AE_OK; | ||
253 | } | ||
254 | |||
255 | static int acpi_fan_resume(struct acpi_device *device) | ||
256 | { | ||
257 | int result = 0; | ||
258 | int power_state = 0; | ||
259 | |||
260 | if (!device) | ||
261 | return -EINVAL; | ||
262 | |||
263 | result = acpi_bus_get_power(device->handle, &power_state); | ||
264 | if (result) { | ||
265 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
266 | "Error reading fan power state\n")); | ||
267 | return result; | ||
268 | } | ||
269 | |||
270 | device->flags.force_power_state = 1; | ||
271 | acpi_bus_set_power(device->handle, power_state); | ||
272 | device->flags.force_power_state = 0; | ||
273 | |||
274 | return result; | ||
275 | } | ||
276 | |||
277 | static int __init acpi_fan_init(void) | 219 | static int __init acpi_fan_init(void) |
278 | { | 220 | { |
279 | int result = 0; | 221 | int result = 0; |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 57b9a2998fd0..af1769a20c7a 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -86,7 +86,6 @@ struct acpi_power_resource { | |||
86 | acpi_bus_id name; | 86 | acpi_bus_id name; |
87 | u32 system_level; | 87 | u32 system_level; |
88 | u32 order; | 88 | u32 order; |
89 | int state; | ||
90 | struct mutex resource_lock; | 89 | struct mutex resource_lock; |
91 | struct list_head reference; | 90 | struct list_head reference; |
92 | }; | 91 | }; |
@@ -128,33 +127,31 @@ acpi_power_get_context(acpi_handle handle, | |||
128 | return 0; | 127 | return 0; |
129 | } | 128 | } |
130 | 129 | ||
131 | static int acpi_power_get_state(struct acpi_power_resource *resource) | 130 | static int acpi_power_get_state(struct acpi_power_resource *resource, int *state) |
132 | { | 131 | { |
133 | acpi_status status = AE_OK; | 132 | acpi_status status = AE_OK; |
134 | unsigned long sta = 0; | 133 | unsigned long sta = 0; |
135 | 134 | ||
136 | 135 | ||
137 | if (!resource) | 136 | if (!resource || !state) |
138 | return -EINVAL; | 137 | return -EINVAL; |
139 | 138 | ||
140 | status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta); | 139 | status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta); |
141 | if (ACPI_FAILURE(status)) | 140 | if (ACPI_FAILURE(status)) |
142 | return -ENODEV; | 141 | return -ENODEV; |
143 | 142 | ||
144 | if (sta & 0x01) | 143 | *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: |
145 | resource->state = ACPI_POWER_RESOURCE_STATE_ON; | 144 | ACPI_POWER_RESOURCE_STATE_OFF; |
146 | else | ||
147 | resource->state = ACPI_POWER_RESOURCE_STATE_OFF; | ||
148 | 145 | ||
149 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", | 146 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", |
150 | resource->name, resource->state ? "on" : "off")); | 147 | resource->name, state ? "on" : "off")); |
151 | 148 | ||
152 | return 0; | 149 | return 0; |
153 | } | 150 | } |
154 | 151 | ||
155 | static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) | 152 | static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) |
156 | { | 153 | { |
157 | int result = 0; | 154 | int result = 0, state1; |
158 | struct acpi_power_resource *resource = NULL; | 155 | struct acpi_power_resource *resource = NULL; |
159 | u32 i = 0; | 156 | u32 i = 0; |
160 | 157 | ||
@@ -168,11 +165,11 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) | |||
168 | result = acpi_power_get_context(list->handles[i], &resource); | 165 | result = acpi_power_get_context(list->handles[i], &resource); |
169 | if (result) | 166 | if (result) |
170 | return result; | 167 | return result; |
171 | result = acpi_power_get_state(resource); | 168 | result = acpi_power_get_state(resource, &state1); |
172 | if (result) | 169 | if (result) |
173 | return result; | 170 | return result; |
174 | 171 | ||
175 | *state = resource->state; | 172 | *state = state1; |
176 | 173 | ||
177 | if (*state != ACPI_POWER_RESOURCE_STATE_ON) | 174 | if (*state != ACPI_POWER_RESOURCE_STATE_ON) |
178 | break; | 175 | break; |
@@ -186,7 +183,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) | |||
186 | 183 | ||
187 | static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) | 184 | static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) |
188 | { | 185 | { |
189 | int result = 0; | 186 | int result = 0, state; |
190 | int found = 0; | 187 | int found = 0; |
191 | acpi_status status = AE_OK; | 188 | acpi_status status = AE_OK; |
192 | struct acpi_power_resource *resource = NULL; | 189 | struct acpi_power_resource *resource = NULL; |
@@ -224,20 +221,14 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) | |||
224 | } | 221 | } |
225 | mutex_unlock(&resource->resource_lock); | 222 | mutex_unlock(&resource->resource_lock); |
226 | 223 | ||
227 | if (resource->state == ACPI_POWER_RESOURCE_STATE_ON) { | ||
228 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n", | ||
229 | resource->name)); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); | 224 | status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL); |
234 | if (ACPI_FAILURE(status)) | 225 | if (ACPI_FAILURE(status)) |
235 | return -ENODEV; | 226 | return -ENODEV; |
236 | 227 | ||
237 | result = acpi_power_get_state(resource); | 228 | result = acpi_power_get_state(resource, &state); |
238 | if (result) | 229 | if (result) |
239 | return result; | 230 | return result; |
240 | if (resource->state != ACPI_POWER_RESOURCE_STATE_ON) | 231 | if (state != ACPI_POWER_RESOURCE_STATE_ON) |
241 | return -ENOEXEC; | 232 | return -ENOEXEC; |
242 | 233 | ||
243 | /* Update the power resource's _device_ power state */ | 234 | /* Update the power resource's _device_ power state */ |
@@ -250,7 +241,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev) | |||
250 | 241 | ||
251 | static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) | 242 | static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) |
252 | { | 243 | { |
253 | int result = 0; | 244 | int result = 0, state; |
254 | acpi_status status = AE_OK; | 245 | acpi_status status = AE_OK; |
255 | struct acpi_power_resource *resource = NULL; | 246 | struct acpi_power_resource *resource = NULL; |
256 | struct list_head *node, *next; | 247 | struct list_head *node, *next; |
@@ -281,20 +272,14 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) | |||
281 | } | 272 | } |
282 | mutex_unlock(&resource->resource_lock); | 273 | mutex_unlock(&resource->resource_lock); |
283 | 274 | ||
284 | if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) { | ||
285 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n", | ||
286 | resource->name)); | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); | 275 | status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL); |
291 | if (ACPI_FAILURE(status)) | 276 | if (ACPI_FAILURE(status)) |
292 | return -ENODEV; | 277 | return -ENODEV; |
293 | 278 | ||
294 | result = acpi_power_get_state(resource); | 279 | result = acpi_power_get_state(resource, &state); |
295 | if (result) | 280 | if (result) |
296 | return result; | 281 | return result; |
297 | if (resource->state != ACPI_POWER_RESOURCE_STATE_OFF) | 282 | if (state != ACPI_POWER_RESOURCE_STATE_OFF) |
298 | return -ENOEXEC; | 283 | return -ENOEXEC; |
299 | 284 | ||
300 | /* Update the power resource's _device_ power state */ | 285 | /* Update the power resource's _device_ power state */ |
@@ -494,7 +479,7 @@ static struct proc_dir_entry *acpi_power_dir; | |||
494 | static int acpi_power_seq_show(struct seq_file *seq, void *offset) | 479 | static int acpi_power_seq_show(struct seq_file *seq, void *offset) |
495 | { | 480 | { |
496 | int count = 0; | 481 | int count = 0; |
497 | int result = 0; | 482 | int result = 0, state; |
498 | struct acpi_power_resource *resource = NULL; | 483 | struct acpi_power_resource *resource = NULL; |
499 | struct list_head *node, *next; | 484 | struct list_head *node, *next; |
500 | struct acpi_power_reference *ref; | 485 | struct acpi_power_reference *ref; |
@@ -505,12 +490,12 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset) | |||
505 | if (!resource) | 490 | if (!resource) |
506 | goto end; | 491 | goto end; |
507 | 492 | ||
508 | result = acpi_power_get_state(resource); | 493 | result = acpi_power_get_state(resource, &state); |
509 | if (result) | 494 | if (result) |
510 | goto end; | 495 | goto end; |
511 | 496 | ||
512 | seq_puts(seq, "state: "); | 497 | seq_puts(seq, "state: "); |
513 | switch (resource->state) { | 498 | switch (state) { |
514 | case ACPI_POWER_RESOURCE_STATE_ON: | 499 | case ACPI_POWER_RESOURCE_STATE_ON: |
515 | seq_puts(seq, "on\n"); | 500 | seq_puts(seq, "on\n"); |
516 | break; | 501 | break; |
@@ -591,7 +576,7 @@ static int acpi_power_remove_fs(struct acpi_device *device) | |||
591 | 576 | ||
592 | static int acpi_power_add(struct acpi_device *device) | 577 | static int acpi_power_add(struct acpi_device *device) |
593 | { | 578 | { |
594 | int result = 0; | 579 | int result = 0, state; |
595 | acpi_status status = AE_OK; | 580 | acpi_status status = AE_OK; |
596 | struct acpi_power_resource *resource = NULL; | 581 | struct acpi_power_resource *resource = NULL; |
597 | union acpi_object acpi_object; | 582 | union acpi_object acpi_object; |
@@ -622,11 +607,11 @@ static int acpi_power_add(struct acpi_device *device) | |||
622 | resource->system_level = acpi_object.power_resource.system_level; | 607 | resource->system_level = acpi_object.power_resource.system_level; |
623 | resource->order = acpi_object.power_resource.resource_order; | 608 | resource->order = acpi_object.power_resource.resource_order; |
624 | 609 | ||
625 | result = acpi_power_get_state(resource); | 610 | result = acpi_power_get_state(resource, &state); |
626 | if (result) | 611 | if (result) |
627 | goto end; | 612 | goto end; |
628 | 613 | ||
629 | switch (resource->state) { | 614 | switch (state) { |
630 | case ACPI_POWER_RESOURCE_STATE_ON: | 615 | case ACPI_POWER_RESOURCE_STATE_ON: |
631 | device->power.state = ACPI_STATE_D0; | 616 | device->power.state = ACPI_STATE_D0; |
632 | break; | 617 | break; |
@@ -643,7 +628,7 @@ static int acpi_power_add(struct acpi_device *device) | |||
643 | goto end; | 628 | goto end; |
644 | 629 | ||
645 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), | 630 | printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), |
646 | acpi_device_bid(device), resource->state ? "on" : "off"); | 631 | acpi_device_bid(device), state ? "on" : "off"); |
647 | 632 | ||
648 | end: | 633 | end: |
649 | if (result) | 634 | if (result) |
@@ -680,7 +665,7 @@ static int acpi_power_remove(struct acpi_device *device, int type) | |||
680 | 665 | ||
681 | static int acpi_power_resume(struct acpi_device *device) | 666 | static int acpi_power_resume(struct acpi_device *device) |
682 | { | 667 | { |
683 | int result = 0; | 668 | int result = 0, state; |
684 | struct acpi_power_resource *resource = NULL; | 669 | struct acpi_power_resource *resource = NULL; |
685 | struct acpi_power_reference *ref; | 670 | struct acpi_power_reference *ref; |
686 | 671 | ||
@@ -689,12 +674,12 @@ static int acpi_power_resume(struct acpi_device *device) | |||
689 | 674 | ||
690 | resource = (struct acpi_power_resource *)acpi_driver_data(device); | 675 | resource = (struct acpi_power_resource *)acpi_driver_data(device); |
691 | 676 | ||
692 | result = acpi_power_get_state(resource); | 677 | result = acpi_power_get_state(resource, &state); |
693 | if (result) | 678 | if (result) |
694 | return result; | 679 | return result; |
695 | 680 | ||
696 | mutex_lock(&resource->resource_lock); | 681 | mutex_lock(&resource->resource_lock); |
697 | if ((resource->state == ACPI_POWER_RESOURCE_STATE_OFF) && | 682 | if (state == ACPI_POWER_RESOURCE_STATE_OFF && |
698 | !list_empty(&resource->reference)) { | 683 | !list_empty(&resource->reference)) { |
699 | ref = container_of(resource->reference.next, struct acpi_power_reference, node); | 684 | ref = container_of(resource->reference.next, struct acpi_power_reference, node); |
700 | mutex_unlock(&resource->resource_lock); | 685 | mutex_unlock(&resource->resource_lock); |
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index f3d3867303ec..2c0b6630f8ba 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -167,8 +167,8 @@ static void acpi_pm_finish(void) | |||
167 | { | 167 | { |
168 | u32 acpi_state = acpi_target_sleep_state; | 168 | u32 acpi_state = acpi_target_sleep_state; |
169 | 169 | ||
170 | acpi_leave_sleep_state(acpi_state); | ||
171 | acpi_disable_wakeup_device(acpi_state); | 170 | acpi_disable_wakeup_device(acpi_state); |
171 | acpi_leave_sleep_state(acpi_state); | ||
172 | 172 | ||
173 | /* reset firmware waking vector */ | 173 | /* reset firmware waking vector */ |
174 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 174 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
@@ -272,8 +272,8 @@ static void acpi_hibernation_finish(void) | |||
272 | * enable it here. | 272 | * enable it here. |
273 | */ | 273 | */ |
274 | acpi_enable(); | 274 | acpi_enable(); |
275 | acpi_leave_sleep_state(ACPI_STATE_S4); | ||
276 | acpi_disable_wakeup_device(ACPI_STATE_S4); | 275 | acpi_disable_wakeup_device(ACPI_STATE_S4); |
276 | acpi_leave_sleep_state(ACPI_STATE_S4); | ||
277 | 277 | ||
278 | /* reset firmware waking vector */ | 278 | /* reset firmware waking vector */ |
279 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 279 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
@@ -410,6 +410,7 @@ static void acpi_power_off(void) | |||
410 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ | 410 | /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */ |
411 | printk("%s called\n", __FUNCTION__); | 411 | printk("%s called\n", __FUNCTION__); |
412 | local_irq_disable(); | 412 | local_irq_disable(); |
413 | acpi_enable_wakeup_device(ACPI_STATE_S5); | ||
413 | acpi_enter_sleep_state(ACPI_STATE_S5); | 414 | acpi_enter_sleep_state(ACPI_STATE_S5); |
414 | } | 415 | } |
415 | 416 | ||