Merge branch 'topic/hda' into for-linus
[safe/jmp/linux-2.6] / drivers / acpi / thermal.c
index 766bd25..99e6f1f 100644 (file)
@@ -47,7 +47,6 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
-#define ACPI_THERMAL_COMPONENT         0x04000000
 #define ACPI_THERMAL_CLASS             "thermal_zone"
 #define ACPI_THERMAL_DEVICE_NAME       "Thermal Zone"
 #define ACPI_THERMAL_FILE_STATE                "state"
@@ -198,6 +197,7 @@ struct acpi_thermal {
 };
 
 static const struct file_operations acpi_thermal_state_fops = {
+       .owner = THIS_MODULE,
        .open = acpi_thermal_state_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
@@ -205,6 +205,7 @@ static const struct file_operations acpi_thermal_state_fops = {
 };
 
 static const struct file_operations acpi_thermal_temp_fops = {
+       .owner = THIS_MODULE,
        .open = acpi_thermal_temp_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
@@ -212,6 +213,7 @@ static const struct file_operations acpi_thermal_temp_fops = {
 };
 
 static const struct file_operations acpi_thermal_trip_fops = {
+       .owner = THIS_MODULE,
        .open = acpi_thermal_trip_open_fs,
        .read = seq_read,
        .llseek = seq_lseek,
@@ -219,6 +221,7 @@ static const struct file_operations acpi_thermal_trip_fops = {
 };
 
 static const struct file_operations acpi_thermal_cooling_fops = {
+       .owner = THIS_MODULE,
        .open = acpi_thermal_cooling_open_fs,
        .read = seq_read,
        .write = acpi_thermal_write_cooling_mode,
@@ -227,6 +230,7 @@ static const struct file_operations acpi_thermal_cooling_fops = {
 };
 
 static const struct file_operations acpi_thermal_polling_fops = {
+       .owner = THIS_MODULE,
        .open = acpi_thermal_polling_open_fs,
        .read = seq_read,
        .write = acpi_thermal_write_polling,
@@ -241,18 +245,18 @@ static const struct file_operations acpi_thermal_polling_fops = {
 static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
 {
        acpi_status status = AE_OK;
-
+       unsigned long long tmp;
 
        if (!tz)
                return -EINVAL;
 
        tz->last_temperature = tz->temperature;
 
-       status =
-           acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
+       status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
+       tz->temperature = tmp;
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
                          tz->temperature));
 
@@ -262,17 +266,16 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
 static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
 {
        acpi_status status = AE_OK;
-
+       unsigned long long tmp;
 
        if (!tz)
                return -EINVAL;
 
-       status =
-           acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
-                                 &tz->polling_frequency);
+       status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
+       tz->polling_frequency = tmp;
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
                          tz->polling_frequency));
 
@@ -351,6 +354,7 @@ do {        \
 static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 {
        acpi_status status = AE_OK;
+       unsigned long long tmp;
        struct acpi_handle_list devices;
        int valid = 0;
        int i;
@@ -358,11 +362,19 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        /* Critical Shutdown (required) */
        if (flag & ACPI_TRIPS_CRITICAL) {
                status = acpi_evaluate_integer(tz->device->handle,
-                               "_CRT", NULL, &tz->trips.critical.temperature);
-               if (ACPI_FAILURE(status)) {
+                               "_CRT", NULL, &tmp);
+               tz->trips.critical.temperature = tmp;
+               /*
+                * Treat freezing temperatures as invalid as well; some
+                * BIOSes return really low values and cause reboots at startup.
+                * Below zero (Celcius) values clearly aren't right for sure..
+                * ... so lets discard those as invalid.
+                */
+               if (ACPI_FAILURE(status) ||
+                               tz->trips.critical.temperature <= 2732) {
                        tz->trips.critical.flags.valid = 0;
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "No critical threshold"));
+                                       "No or invalid critical threshold"));
                        return -ENODEV;
                } else {
                        tz->trips.critical.flags.valid = 1;
@@ -376,10 +388,12 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                        } else if (crt > 0) {
                                unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
                                /*
-                                * Allow override to lower critical threshold
+                                * Allow override critical threshold
                                 */
-                               if (crt_k < tz->trips.critical.temperature)
-                                       tz->trips.critical.temperature = crt_k;
+                               if (crt_k > tz->trips.critical.temperature)
+                                       printk(KERN_WARNING PREFIX
+                                               "Critical threshold %d C\n", crt);
+                               tz->trips.critical.temperature = crt_k;
                        }
                }
        }
@@ -387,12 +401,13 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        /* Critical Sleep (optional) */
        if (flag & ACPI_TRIPS_HOT) {
                status = acpi_evaluate_integer(tz->device->handle,
-                               "_HOT", NULL, &tz->trips.hot.temperature);
+                               "_HOT", NULL, &tmp);
                if (ACPI_FAILURE(status)) {
                        tz->trips.hot.flags.valid = 0;
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                        "No hot threshold\n"));
                } else {
+                       tz->trips.hot.temperature = tmp;
                        tz->trips.hot.flags.valid = 1;
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                        "Found hot threshold [%lu]\n",
@@ -401,38 +416,46 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        }
 
        /* Passive (optional) */
-       if (flag & ACPI_TRIPS_PASSIVE) {
+       if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
+               (flag == ACPI_TRIPS_INIT)) {
                valid = tz->trips.passive.flags.valid;
                if (psv == -1) {
                        status = AE_SUPPORT;
                } else if (psv > 0) {
-                       tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+                       tmp = CELSIUS_TO_KELVIN(psv);
                        status = AE_OK;
                } else {
                        status = acpi_evaluate_integer(tz->device->handle,
-                               "_PSV", NULL, &tz->trips.passive.temperature);
+                               "_PSV", NULL, &tmp);
                }
 
                if (ACPI_FAILURE(status))
                        tz->trips.passive.flags.valid = 0;
                else {
+                       tz->trips.passive.temperature = tmp;
                        tz->trips.passive.flags.valid = 1;
                        if (flag == ACPI_TRIPS_INIT) {
                                status = acpi_evaluate_integer(
                                                tz->device->handle, "_TC1",
-                                               NULL, &tz->trips.passive.tc1);
+                                               NULL, &tmp);
                                if (ACPI_FAILURE(status))
                                        tz->trips.passive.flags.valid = 0;
+                               else
+                                       tz->trips.passive.tc1 = tmp;
                                status = acpi_evaluate_integer(
                                                tz->device->handle, "_TC2",
-                                               NULL, &tz->trips.passive.tc2);
+                                               NULL, &tmp);
                                if (ACPI_FAILURE(status))
                                        tz->trips.passive.flags.valid = 0;
+                               else
+                                       tz->trips.passive.tc2 = tmp;
                                status = acpi_evaluate_integer(
                                                tz->device->handle, "_TSP",
-                                               NULL, &tz->trips.passive.tsp);
+                                               NULL, &tmp);
                                if (ACPI_FAILURE(status))
                                        tz->trips.passive.flags.valid = 0;
+                               else
+                                       tz->trips.passive.tsp = tmp;
                        }
                }
        }
@@ -440,8 +463,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                memset(&devices, 0, sizeof(struct acpi_handle_list));
                status = acpi_evaluate_reference(tz->device->handle, "_PSL",
                                                        NULL, &devices);
-               if (ACPI_FAILURE(status))
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_WARNING PREFIX
+                               "Invalid passive threshold\n");
                        tz->trips.passive.flags.valid = 0;
+               }
                else
                        tz->trips.passive.flags.valid = 1;
 
@@ -465,9 +491,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                if (act == -1)
                        break; /* disable all active trip points */
 
-               if (flag & ACPI_TRIPS_ACTIVE) {
+               if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
+                       tz->trips.active[i].flags.valid)) {
                        status = acpi_evaluate_integer(tz->device->handle,
-                               name, NULL, &tz->trips.active[i].temperature);
+                                                       name, NULL, &tmp);
                        if (ACPI_FAILURE(status)) {
                                tz->trips.active[i].flags.valid = 0;
                                if (i == 0)
@@ -488,8 +515,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                                                tz->trips.active[i - 2].temperature :
                                                CELSIUS_TO_KELVIN(act));
                                break;
-                       } else
+                       } else {
+                               tz->trips.active[i].temperature = tmp;
                                tz->trips.active[i].flags.valid = 1;
+                       }
                }
 
                name[2] = 'L';
@@ -497,8 +526,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                        memset(&devices, 0, sizeof(struct acpi_handle_list));
                        status = acpi_evaluate_reference(tz->device->handle,
                                                name, NULL, &devices);
-                       if (ACPI_FAILURE(status))
+                       if (ACPI_FAILURE(status)) {
+                               printk(KERN_WARNING PREFIX
+                                       "Invalid active%d threshold\n", i);
                                tz->trips.active[i].flags.valid = 0;
+                       }
                        else
                                tz->trips.active[i].flags.valid = 1;
 
@@ -551,7 +583,7 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
        acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
                                tz->trips.critical.flags.enabled);
        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
-                                         tz->device->dev.bus_id,
+                                         dev_name(&tz->device->dev),
                                          ACPI_THERMAL_NOTIFY_CRITICAL,
                                          tz->trips.critical.flags.enabled);
 
@@ -580,7 +612,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
        acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
                                tz->trips.hot.flags.enabled);
        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
-                                         tz->device->dev.bus_id,
+                                         dev_name(&tz->device->dev),
                                          ACPI_THERMAL_NOTIFY_HOT,
                                          tz->trips.hot.flags.enabled);
 
@@ -757,6 +789,47 @@ static void acpi_thermal_run(unsigned long data)
                acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
 }
 
+static void acpi_thermal_active_off(void *data)
+{
+       int result = 0;
+       struct acpi_thermal *tz = data;
+       int i = 0;
+       int j = 0;
+       struct acpi_thermal_active *active = NULL;
+
+       if (!tz) {
+               printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+               return;
+       }
+
+       result = acpi_thermal_get_temperature(tz);
+       if (result)
+               return;
+
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+               active = &(tz->trips.active[i]);
+               if (!active || !active->flags.valid)
+                       break;
+               if (tz->temperature >= active->temperature) {
+                       /*
+                        * If the thermal temperature is greater than the
+                        * active threshod, unnecessary to turn off the
+                        * the active cooling device.
+                        */
+                       continue;
+               }
+               /*
+                * Below Threshold?
+                * ----------------
+                * Turn OFF all cooling devices associated with this
+                * threshold.
+                */
+               for (j = 0; j < active->devices.count; j++)
+                       result = acpi_bus_set_power(active->devices.handles[j],
+                                                   ACPI_STATE_D3);
+       }
+}
+
 static void acpi_thermal_check(void *data)
 {
        int result = 0;
@@ -884,10 +957,15 @@ static void acpi_thermal_check(void *data)
 static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
 {
        struct acpi_thermal *tz = thermal->devdata;
+       int result;
 
        if (!tz)
                return -EINVAL;
 
+       result = acpi_thermal_get_temperature(tz);
+       if (result)
+               return result;
+
        return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
 }
 
@@ -1012,6 +1090,18 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
        return -EINVAL;
 }
 
+static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+                               unsigned long *temperature) {
+       struct acpi_thermal *tz = thermal->devdata;
+
+       if (tz->trips.critical.flags.valid) {
+               *temperature = KELVIN_TO_MILLICELSIUS(
+                               tz->trips.critical.temperature);
+               return 0;
+       } else
+               return -EINVAL;
+}
+
 typedef int (*cb)(struct thermal_zone_device *, int,
                  struct thermal_cooling_device *);
 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1103,6 +1193,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
        .set_mode = thermal_set_mode,
        .get_trip_type = thermal_get_trip_type,
        .get_trip_temp = thermal_get_trip_temp,
+       .get_crit_temp = thermal_get_crit_temp,
 };
 
 static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1123,7 +1214,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
                        tz->trips.active[i].flags.valid; i++, trips++);
-       tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+       tz->thermal_zone = thermal_zone_device_register("acpitz",
                                        trips, tz, &acpi_thermal_zone_ops);
        if (IS_ERR(tz->thermal_zone))
                return -ENODEV;
@@ -1142,15 +1233,15 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
                                  acpi_bus_private_data_handler,
                                  tz->thermal_zone);
        if (ACPI_FAILURE(status)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                               "Error attaching device data\n"));
+               printk(KERN_ERR PREFIX
+                               "Error attaching device data\n");
                return -ENODEV;
        }
 
        tz->tz_enabled = 1;
 
-       printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
-                       tz->device->dev.bus_id, tz->thermal_zone->id);
+       dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
+                tz->thermal_zone->id);
        return 0;
 }
 
@@ -1419,63 +1510,47 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
        }
 
        /* 'state' [R] */
-       entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
-                                 S_IRUGO, acpi_device_dir(device));
+       entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
+                                S_IRUGO, acpi_device_dir(device),
+                                &acpi_thermal_state_fops,
+                                acpi_driver_data(device));
        if (!entry)
                return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_thermal_state_fops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
 
        /* 'temperature' [R] */
-       entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
-                                 S_IRUGO, acpi_device_dir(device));
+       entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
+                                S_IRUGO, acpi_device_dir(device),
+                                &acpi_thermal_temp_fops,
+                                acpi_driver_data(device));
        if (!entry)
                return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_thermal_temp_fops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
 
        /* 'trip_points' [R] */
-       entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-                                 S_IRUGO,
-                                 acpi_device_dir(device));
+       entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
+                                S_IRUGO,
+                                acpi_device_dir(device),
+                                &acpi_thermal_trip_fops,
+                                acpi_driver_data(device));
        if (!entry)
                return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_thermal_trip_fops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
 
        /* 'cooling_mode' [R/W] */
-       entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
-                                 S_IFREG | S_IRUGO | S_IWUSR,
-                                 acpi_device_dir(device));
+       entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
+                                S_IFREG | S_IRUGO | S_IWUSR,
+                                acpi_device_dir(device),
+                                &acpi_thermal_cooling_fops,
+                                acpi_driver_data(device));
        if (!entry)
                return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_thermal_cooling_fops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
 
        /* 'polling_frequency' [R/W] */
-       entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
-                                 S_IFREG | S_IRUGO | S_IWUSR,
-                                 acpi_device_dir(device));
+       entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
+                                S_IFREG | S_IRUGO | S_IWUSR,
+                                acpi_device_dir(device),
+                                &acpi_thermal_polling_fops,
+                                acpi_driver_data(device));
        if (!entry)
                return -ENODEV;
-       else {
-               entry->proc_fops = &acpi_thermal_polling_fops;
-               entry->data = acpi_driver_data(device);
-               entry->owner = THIS_MODULE;
-       }
-
        return 0;
 }
 
@@ -1524,14 +1599,14 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
                acpi_thermal_check(tz);
                acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
-                                                 device->dev.bus_id, event, 0);
+                                                 dev_name(&device->dev), event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
                acpi_thermal_check(tz);
                acpi_bus_generate_proc_event(device, event, 0);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
-                                                 device->dev.bus_id, event, 0);
+                                                 dev_name(&device->dev), event, 0);
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1592,7 +1667,7 @@ static int acpi_thermal_add(struct acpi_device *device)
        strcpy(tz->name, device->pnp.bus_id);
        strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
-       acpi_driver_data(device) = tz;
+       device->driver_data = tz;
        mutex_init(&tz->lock);
 
 
@@ -1610,6 +1685,8 @@ static int acpi_thermal_add(struct acpi_device *device)
 
        init_timer(&tz->timer);
 
+       acpi_thermal_active_off(tz);
+
        acpi_thermal_check(tz);
 
        status = acpi_install_notify_handler(device->handle,