Check for fan state consistency. If the device have _PSC object and power resources, check for _PSC object consistency From: Konstantin Karasyov --- drivers/acpi/fan.c | 66 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/acpi/thermal.c | 25 ++++++++++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index ec655c5..e657222 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -179,7 +179,7 @@ static int acpi_fan_add(struct acpi_device *device) { int result = 0; struct acpi_fan *fan = NULL; - int state = 0; + int state, new_state, cur_state = 0; if (!device) @@ -196,18 +196,72 @@ static int acpi_fan_add(struct acpi_device *device) result = acpi_bus_get_power(device->handle, &state); if (result) { - printk(KERN_ERR PREFIX "Reading power state\n"); + printk(KERN_ERR PREFIX "Reading power state failed for %s\n", + acpi_device_bid(device)); goto end; } - device->flags.force_power_state = 1; - acpi_bus_set_power(device->handle, state); - device->flags.force_power_state = 0; - result = acpi_fan_add_fs(device); if (result) goto end; + /* + * If the device have _PSC object and power resources, + * check for _PSC object consistency + */ + + if (fan->device->power.flags.explicit_get && + device->power.flags.power_resources) { + if (state == ACPI_STATE_D0) { + new_state = ACPI_STATE_D3; + } else { + new_state = ACPI_STATE_D0; + } + cur_state = state; + + result = acpi_bus_set_power(device->handle, new_state); + if (result) { + printk(KERN_ERR PREFIX "Setting power state %d for %s failed\n", + new_state, acpi_device_bid(device)); + goto end; + } + result = acpi_bus_get_power(device->handle, &state); + if (result) { + printk(KERN_ERR PREFIX "Reading power state failed for %s\n", + acpi_device_bid(device)); + goto end; + } + if (state != new_state) { + printk(KERN_WARNING PREFIX "Disabling explicit_get flag for %s\n", + acpi_device_bid(device)); + fan->device->power.flags.explicit_get = 0; + acpi_bus_get_power(device->handle, &state); + } + + result = acpi_bus_set_power(device->handle, cur_state); + if (result) { + printk(KERN_ERR PREFIX "Setting power state %d for %s failed\n", + cur_state, acpi_device_bid(device)); + goto end; + } + result = acpi_bus_get_power(device->handle, &state); + if (result) { + printk(KERN_ERR PREFIX "Reading power state failed for %s\n", + acpi_device_bid(device)); + goto end; + } + if (state != cur_state) { + printk(KERN_WARNING PREFIX "Disabling explicit_get flag for %s\n", + acpi_device_bid(device)); + fan->device->power.flags.explicit_get = 0; + acpi_bus_get_power(device->handle, &state); + } + } else { + device->flags.force_power_state = 1; + acpi_bus_set_power(device->handle, state); + device->flags.force_power_state = 0; + } + printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device), acpi_device_bid(device), !device->power.state ? "on" : "off"); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 0ae8b93..1e02a3d 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -1262,6 +1262,7 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) static int acpi_thermal_add(struct acpi_device *device) { int result = 0; + int i, j, power_state; acpi_status status = AE_OK; struct acpi_thermal *tz = NULL; @@ -1289,6 +1290,30 @@ static int acpi_thermal_add(struct acpi_device *device) init_timer(&tz->timer); + /* + * Check for consistency between active cooling devices + * (i.e. fans) and thermal zone structures. + * Later call for acpi_thermal_check() should set the fans + * to the proper state. + */ + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + if (!(&tz->trips.active[i])) + break; + if (!tz->trips.active[i].flags.valid) + break; + tz->trips.active[i].flags.enabled = 1; + for (j = 0; j < tz->trips.active[i].devices.count; j++) { + result = acpi_bus_get_power(tz->trips.active[i].devices. + handles[j], &power_state); + if (result || (power_state != ACPI_STATE_D0)) { + tz->trips.active[i].flags.enabled = 0; + break; + } + } + tz->state.active |= tz->trips.active[i].flags.enabled; + } + acpi_thermal_check(tz); status = acpi_install_notify_handler(device->handle,