linux/drivers/acpi/thermal.c
<<
>>
Prefs
   1/*
   2 *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
   3 *
   4 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
   5 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
   6 *
   7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License as published by
  11 *  the Free Software Foundation; either version 2 of the License, or (at
  12 *  your option) any later version.
  13 *
  14 *  This program is distributed in the hope that it will be useful, but
  15 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 *  General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License along
  20 *  with this program; if not, write to the Free Software Foundation, Inc.,
  21 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  22 *
  23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  24 *
  25 *  This driver fully implements the ACPI thermal policy as described in the
  26 *  ACPI 2.0 Specification.
  27 *
  28 *  TBD: 1. Implement passive cooling hysteresis.
  29 *       2. Enhance passive cooling (CPU) states/limit interface to support
  30 *          concepts of 'multiple limiters', upper/lower limits, etc.
  31 *
  32 */
  33
  34#include <linux/kernel.h>
  35#include <linux/module.h>
  36#include <linux/dmi.h>
  37#include <linux/init.h>
  38#include <linux/types.h>
  39#include <linux/proc_fs.h>
  40#include <linux/jiffies.h>
  41#include <linux/kmod.h>
  42#include <linux/seq_file.h>
  43#include <linux/reboot.h>
  44#include <linux/device.h>
  45#include <asm/uaccess.h>
  46#include <linux/thermal.h>
  47#include <acpi/acpi_bus.h>
  48#include <acpi/acpi_drivers.h>
  49
  50#define ACPI_THERMAL_CLASS              "thermal_zone"
  51#define ACPI_THERMAL_DEVICE_NAME        "Thermal Zone"
  52#define ACPI_THERMAL_FILE_STATE         "state"
  53#define ACPI_THERMAL_FILE_TEMPERATURE   "temperature"
  54#define ACPI_THERMAL_FILE_TRIP_POINTS   "trip_points"
  55#define ACPI_THERMAL_FILE_COOLING_MODE  "cooling_mode"
  56#define ACPI_THERMAL_FILE_POLLING_FREQ  "polling_frequency"
  57#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
  58#define ACPI_THERMAL_NOTIFY_THRESHOLDS  0x81
  59#define ACPI_THERMAL_NOTIFY_DEVICES     0x82
  60#define ACPI_THERMAL_NOTIFY_CRITICAL    0xF0
  61#define ACPI_THERMAL_NOTIFY_HOT         0xF1
  62#define ACPI_THERMAL_MODE_ACTIVE        0x00
  63
  64#define ACPI_THERMAL_MAX_ACTIVE 10
  65#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
  66
  67#define _COMPONENT              ACPI_THERMAL_COMPONENT
  68ACPI_MODULE_NAME("thermal");
  69
  70MODULE_AUTHOR("Paul Diefenbaugh");
  71MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
  72MODULE_LICENSE("GPL");
  73
  74static int act;
  75module_param(act, int, 0644);
  76MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
  77
  78static int crt;
  79module_param(crt, int, 0644);
  80MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
  81
  82static int tzp;
  83module_param(tzp, int, 0444);
  84MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
  85
  86static int nocrt;
  87module_param(nocrt, int, 0);
  88MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
  89
  90static int off;
  91module_param(off, int, 0);
  92MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
  93
  94static int psv;
  95module_param(psv, int, 0644);
  96MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
  97
  98static int acpi_thermal_add(struct acpi_device *device);
  99static int acpi_thermal_remove(struct acpi_device *device, int type);
 100static int acpi_thermal_resume(struct acpi_device *device);
 101static void acpi_thermal_notify(struct acpi_device *device, u32 event);
 102static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 103static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 104static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
 105static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
 106static ssize_t acpi_thermal_write_cooling_mode(struct file *,
 107                                               const char __user *, size_t,
 108                                               loff_t *);
 109static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
 110static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
 111                                          size_t, loff_t *);
 112
 113static const struct acpi_device_id  thermal_device_ids[] = {
 114        {ACPI_THERMAL_HID, 0},
 115        {"", 0},
 116};
 117MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 118
 119static struct acpi_driver acpi_thermal_driver = {
 120        .name = "thermal",
 121        .class = ACPI_THERMAL_CLASS,
 122        .ids = thermal_device_ids,
 123        .ops = {
 124                .add = acpi_thermal_add,
 125                .remove = acpi_thermal_remove,
 126                .resume = acpi_thermal_resume,
 127                .notify = acpi_thermal_notify,
 128                },
 129};
 130
 131struct acpi_thermal_state {
 132        u8 critical:1;
 133        u8 hot:1;
 134        u8 passive:1;
 135        u8 active:1;
 136        u8 reserved:4;
 137        int active_index;
 138};
 139
 140struct acpi_thermal_state_flags {
 141        u8 valid:1;
 142        u8 enabled:1;
 143        u8 reserved:6;
 144};
 145
 146struct acpi_thermal_critical {
 147        struct acpi_thermal_state_flags flags;
 148        unsigned long temperature;
 149};
 150
 151struct acpi_thermal_hot {
 152        struct acpi_thermal_state_flags flags;
 153        unsigned long temperature;
 154};
 155
 156struct acpi_thermal_passive {
 157        struct acpi_thermal_state_flags flags;
 158        unsigned long temperature;
 159        unsigned long tc1;
 160        unsigned long tc2;
 161        unsigned long tsp;
 162        struct acpi_handle_list devices;
 163};
 164
 165struct acpi_thermal_active {
 166        struct acpi_thermal_state_flags flags;
 167        unsigned long temperature;
 168        struct acpi_handle_list devices;
 169};
 170
 171struct acpi_thermal_trips {
 172        struct acpi_thermal_critical critical;
 173        struct acpi_thermal_hot hot;
 174        struct acpi_thermal_passive passive;
 175        struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
 176};
 177
 178struct acpi_thermal_flags {
 179        u8 cooling_mode:1;      /* _SCP */
 180        u8 devices:1;           /* _TZD */
 181        u8 reserved:6;
 182};
 183
 184struct acpi_thermal {
 185        struct acpi_device * device;
 186        acpi_bus_id name;
 187        unsigned long temperature;
 188        unsigned long last_temperature;
 189        unsigned long polling_frequency;
 190        volatile u8 zombie;
 191        struct acpi_thermal_flags flags;
 192        struct acpi_thermal_state state;
 193        struct acpi_thermal_trips trips;
 194        struct acpi_handle_list devices;
 195        struct thermal_zone_device *thermal_zone;
 196        int tz_enabled;
 197        int kelvin_offset;
 198        struct mutex lock;
 199};
 200
 201static const struct file_operations acpi_thermal_state_fops = {
 202        .owner = THIS_MODULE,
 203        .open = acpi_thermal_state_open_fs,
 204        .read = seq_read,
 205        .llseek = seq_lseek,
 206        .release = single_release,
 207};
 208
 209static const struct file_operations acpi_thermal_temp_fops = {
 210        .owner = THIS_MODULE,
 211        .open = acpi_thermal_temp_open_fs,
 212        .read = seq_read,
 213        .llseek = seq_lseek,
 214        .release = single_release,
 215};
 216
 217static const struct file_operations acpi_thermal_trip_fops = {
 218        .owner = THIS_MODULE,
 219        .open = acpi_thermal_trip_open_fs,
 220        .read = seq_read,
 221        .llseek = seq_lseek,
 222        .release = single_release,
 223};
 224
 225static const struct file_operations acpi_thermal_cooling_fops = {
 226        .owner = THIS_MODULE,
 227        .open = acpi_thermal_cooling_open_fs,
 228        .read = seq_read,
 229        .write = acpi_thermal_write_cooling_mode,
 230        .llseek = seq_lseek,
 231        .release = single_release,
 232};
 233
 234static const struct file_operations acpi_thermal_polling_fops = {
 235        .owner = THIS_MODULE,
 236        .open = acpi_thermal_polling_open_fs,
 237        .read = seq_read,
 238        .write = acpi_thermal_write_polling,
 239        .llseek = seq_lseek,
 240        .release = single_release,
 241};
 242
 243/* --------------------------------------------------------------------------
 244                             Thermal Zone Management
 245   -------------------------------------------------------------------------- */
 246
 247static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
 248{
 249        acpi_status status = AE_OK;
 250        unsigned long long tmp;
 251
 252        if (!tz)
 253                return -EINVAL;
 254
 255        tz->last_temperature = tz->temperature;
 256
 257        status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
 258        if (ACPI_FAILURE(status))
 259                return -ENODEV;
 260
 261        tz->temperature = tmp;
 262        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
 263                          tz->temperature));
 264
 265        return 0;
 266}
 267
 268static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
 269{
 270        acpi_status status = AE_OK;
 271        unsigned long long tmp;
 272
 273        if (!tz)
 274                return -EINVAL;
 275
 276        status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
 277        if (ACPI_FAILURE(status))
 278                return -ENODEV;
 279
 280        tz->polling_frequency = tmp;
 281        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
 282                          tz->polling_frequency));
 283
 284        return 0;
 285}
 286
 287static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
 288{
 289
 290        if (!tz)
 291                return -EINVAL;
 292
 293        tz->polling_frequency = seconds * 10;   /* Convert value to deci-seconds */
 294
 295        tz->thermal_zone->polling_delay = seconds * 1000;
 296
 297        if (tz->tz_enabled)
 298                thermal_zone_device_update(tz->thermal_zone);
 299
 300        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 301                          "Polling frequency set to %lu seconds\n",
 302                          tz->polling_frequency/10));
 303
 304        return 0;
 305}
 306
 307static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
 308{
 309        acpi_status status = AE_OK;
 310        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 311        struct acpi_object_list arg_list = { 1, &arg0 };
 312        acpi_handle handle = NULL;
 313
 314
 315        if (!tz)
 316                return -EINVAL;
 317
 318        status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
 319        if (ACPI_FAILURE(status)) {
 320                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
 321                return -ENODEV;
 322        }
 323
 324        arg0.integer.value = mode;
 325
 326        status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
 327        if (ACPI_FAILURE(status))
 328                return -ENODEV;
 329
 330        return 0;
 331}
 332
 333#define ACPI_TRIPS_CRITICAL     0x01
 334#define ACPI_TRIPS_HOT          0x02
 335#define ACPI_TRIPS_PASSIVE      0x04
 336#define ACPI_TRIPS_ACTIVE       0x08
 337#define ACPI_TRIPS_DEVICES      0x10
 338
 339#define ACPI_TRIPS_REFRESH_THRESHOLDS   (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
 340#define ACPI_TRIPS_REFRESH_DEVICES      ACPI_TRIPS_DEVICES
 341
 342#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT |    \
 343                              ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |  \
 344                              ACPI_TRIPS_DEVICES)
 345
 346/*
 347 * This exception is thrown out in two cases:
 348 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
 349 *   when re-evaluating the AML code.
 350 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
 351 *   We need to re-bind the cooling devices of a thermal zone when this occurs.
 352 */
 353#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str)        \
 354do {    \
 355        if (flags != ACPI_TRIPS_INIT)   \
 356                ACPI_EXCEPTION((AE_INFO, AE_ERROR,      \
 357                "ACPI thermal trip point %s changed\n"  \
 358                "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
 359} while (0)
 360
 361static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 362{
 363        acpi_status status = AE_OK;
 364        unsigned long long tmp;
 365        struct acpi_handle_list devices;
 366        int valid = 0;
 367        int i;
 368
 369        /* Critical Shutdown (required) */
 370        if (flag & ACPI_TRIPS_CRITICAL) {
 371                status = acpi_evaluate_integer(tz->device->handle,
 372                                "_CRT", NULL, &tmp);
 373                tz->trips.critical.temperature = tmp;
 374                /*
 375                 * Treat freezing temperatures as invalid as well; some
 376                 * BIOSes return really low values and cause reboots at startup.
 377                 * Below zero (Celsius) values clearly aren't right for sure..
 378                 * ... so lets discard those as invalid.
 379                 */
 380                if (ACPI_FAILURE(status) ||
 381                                tz->trips.critical.temperature <= 2732) {
 382                        tz->trips.critical.flags.valid = 0;
 383                        ACPI_EXCEPTION((AE_INFO, status,
 384                                        "No or invalid critical threshold"));
 385                        return -ENODEV;
 386                } else {
 387                        tz->trips.critical.flags.valid = 1;
 388                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 389                                        "Found critical threshold [%lu]\n",
 390                                        tz->trips.critical.temperature));
 391                }
 392                if (tz->trips.critical.flags.valid == 1) {
 393                        if (crt == -1) {
 394                                tz->trips.critical.flags.valid = 0;
 395                        } else if (crt > 0) {
 396                                unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
 397                                /*
 398                                 * Allow override critical threshold
 399                                 */
 400                                if (crt_k > tz->trips.critical.temperature)
 401                                        printk(KERN_WARNING PREFIX
 402                                                "Critical threshold %d C\n", crt);
 403                                tz->trips.critical.temperature = crt_k;
 404                        }
 405                }
 406        }
 407
 408        /* Critical Sleep (optional) */
 409        if (flag & ACPI_TRIPS_HOT) {
 410                status = acpi_evaluate_integer(tz->device->handle,
 411                                "_HOT", NULL, &tmp);
 412                if (ACPI_FAILURE(status)) {
 413                        tz->trips.hot.flags.valid = 0;
 414                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 415                                        "No hot threshold\n"));
 416                } else {
 417                        tz->trips.hot.temperature = tmp;
 418                        tz->trips.hot.flags.valid = 1;
 419                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 420                                        "Found hot threshold [%lu]\n",
 421                                        tz->trips.critical.temperature));
 422                }
 423        }
 424
 425        /* Passive (optional) */
 426        if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
 427                (flag == ACPI_TRIPS_INIT)) {
 428                valid = tz->trips.passive.flags.valid;
 429                if (psv == -1) {
 430                        status = AE_SUPPORT;
 431                } else if (psv > 0) {
 432                        tmp = CELSIUS_TO_KELVIN(psv);
 433                        status = AE_OK;
 434                } else {
 435                        status = acpi_evaluate_integer(tz->device->handle,
 436                                "_PSV", NULL, &tmp);
 437                }
 438
 439                if (ACPI_FAILURE(status))
 440                        tz->trips.passive.flags.valid = 0;
 441                else {
 442                        tz->trips.passive.temperature = tmp;
 443                        tz->trips.passive.flags.valid = 1;
 444                        if (flag == ACPI_TRIPS_INIT) {
 445                                status = acpi_evaluate_integer(
 446                                                tz->device->handle, "_TC1",
 447                                                NULL, &tmp);
 448                                if (ACPI_FAILURE(status))
 449                                        tz->trips.passive.flags.valid = 0;
 450                                else
 451                                        tz->trips.passive.tc1 = tmp;
 452                                status = acpi_evaluate_integer(
 453                                                tz->device->handle, "_TC2",
 454                                                NULL, &tmp);
 455                                if (ACPI_FAILURE(status))
 456                                        tz->trips.passive.flags.valid = 0;
 457                                else
 458                                        tz->trips.passive.tc2 = tmp;
 459                                status = acpi_evaluate_integer(
 460                                                tz->device->handle, "_TSP",
 461                                                NULL, &tmp);
 462                                if (ACPI_FAILURE(status))
 463                                        tz->trips.passive.flags.valid = 0;
 464                                else
 465                                        tz->trips.passive.tsp = tmp;
 466                        }
 467                }
 468        }
 469        if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
 470                memset(&devices, 0, sizeof(struct acpi_handle_list));
 471                status = acpi_evaluate_reference(tz->device->handle, "_PSL",
 472                                                        NULL, &devices);
 473                if (ACPI_FAILURE(status)) {
 474                        printk(KERN_WARNING PREFIX
 475                                "Invalid passive threshold\n");
 476                        tz->trips.passive.flags.valid = 0;
 477                }
 478                else
 479                        tz->trips.passive.flags.valid = 1;
 480
 481                if (memcmp(&tz->trips.passive.devices, &devices,
 482                                sizeof(struct acpi_handle_list))) {
 483                        memcpy(&tz->trips.passive.devices, &devices,
 484                                sizeof(struct acpi_handle_list));
 485                        ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 486                }
 487        }
 488        if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
 489                if (valid != tz->trips.passive.flags.valid)
 490                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
 491        }
 492
 493        /* Active (optional) */
 494        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
 495                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
 496                valid = tz->trips.active[i].flags.valid;
 497
 498                if (act == -1)
 499                        break; /* disable all active trip points */
 500
 501                if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
 502                        tz->trips.active[i].flags.valid)) {
 503                        status = acpi_evaluate_integer(tz->device->handle,
 504                                                        name, NULL, &tmp);
 505                        if (ACPI_FAILURE(status)) {
 506                                tz->trips.active[i].flags.valid = 0;
 507                                if (i == 0)
 508                                        break;
 509                                if (act <= 0)
 510                                        break;
 511                                if (i == 1)
 512                                        tz->trips.active[0].temperature =
 513                                                CELSIUS_TO_KELVIN(act);
 514                                else
 515                                        /*
 516                                         * Don't allow override higher than
 517                                         * the next higher trip point
 518                                         */
 519                                        tz->trips.active[i - 1].temperature =
 520                                                (tz->trips.active[i - 2].temperature <
 521                                                CELSIUS_TO_KELVIN(act) ?
 522                                                tz->trips.active[i - 2].temperature :
 523                                                CELSIUS_TO_KELVIN(act));
 524                                break;
 525                        } else {
 526                                tz->trips.active[i].temperature = tmp;
 527                                tz->trips.active[i].flags.valid = 1;
 528                        }
 529                }
 530
 531                name[2] = 'L';
 532                if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
 533                        memset(&devices, 0, sizeof(struct acpi_handle_list));
 534                        status = acpi_evaluate_reference(tz->device->handle,
 535                                                name, NULL, &devices);
 536                        if (ACPI_FAILURE(status)) {
 537                                printk(KERN_WARNING PREFIX
 538                                        "Invalid active%d threshold\n", i);
 539                                tz->trips.active[i].flags.valid = 0;
 540                        }
 541                        else
 542                                tz->trips.active[i].flags.valid = 1;
 543
 544                        if (memcmp(&tz->trips.active[i].devices, &devices,
 545                                        sizeof(struct acpi_handle_list))) {
 546                                memcpy(&tz->trips.active[i].devices, &devices,
 547                                        sizeof(struct acpi_handle_list));
 548                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 549                        }
 550                }
 551                if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
 552                        if (valid != tz->trips.active[i].flags.valid)
 553                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
 554
 555                if (!tz->trips.active[i].flags.valid)
 556                        break;
 557        }
 558
 559        if (flag & ACPI_TRIPS_DEVICES) {
 560                memset(&devices, 0, sizeof(struct acpi_handle_list));
 561                status = acpi_evaluate_reference(tz->device->handle, "_TZD",
 562                                                NULL, &devices);
 563                if (memcmp(&tz->devices, &devices,
 564                                sizeof(struct acpi_handle_list))) {
 565                        memcpy(&tz->devices, &devices,
 566                                sizeof(struct acpi_handle_list));
 567                        ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
 568                }
 569        }
 570
 571        return 0;
 572}
 573
 574static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 575{
 576        return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
 577}
 578
 579static void acpi_thermal_check(void *data)
 580{
 581        struct acpi_thermal *tz = data;
 582
 583        thermal_zone_device_update(tz->thermal_zone);
 584}
 585
 586/* sys I/F for generic thermal sysfs support */
 587#define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100)
 588
 589static int thermal_get_temp(struct thermal_zone_device *thermal,
 590                            unsigned long *temp)
 591{
 592        struct acpi_thermal *tz = thermal->devdata;
 593        int result;
 594
 595        if (!tz)
 596                return -EINVAL;
 597
 598        result = acpi_thermal_get_temperature(tz);
 599        if (result)
 600                return result;
 601
 602        *temp = KELVIN_TO_MILLICELSIUS(tz->temperature, tz->kelvin_offset);
 603        return 0;
 604}
 605
 606static const char enabled[] = "kernel";
 607static const char disabled[] = "user";
 608static int thermal_get_mode(struct thermal_zone_device *thermal,
 609                                enum thermal_device_mode *mode)
 610{
 611        struct acpi_thermal *tz = thermal->devdata;
 612
 613        if (!tz)
 614                return -EINVAL;
 615
 616        *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
 617                THERMAL_DEVICE_DISABLED;
 618
 619        return 0;
 620}
 621
 622static int thermal_set_mode(struct thermal_zone_device *thermal,
 623                                enum thermal_device_mode mode)
 624{
 625        struct acpi_thermal *tz = thermal->devdata;
 626        int enable;
 627
 628        if (!tz)
 629                return -EINVAL;
 630
 631        /*
 632         * enable/disable thermal management from ACPI thermal driver
 633         */
 634        if (mode == THERMAL_DEVICE_ENABLED)
 635                enable = 1;
 636        else if (mode == THERMAL_DEVICE_DISABLED)
 637                enable = 0;
 638        else
 639                return -EINVAL;
 640
 641        if (enable != tz->tz_enabled) {
 642                tz->tz_enabled = enable;
 643                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 644                        "%s ACPI thermal control\n",
 645                        tz->tz_enabled ? enabled : disabled));
 646                acpi_thermal_check(tz);
 647        }
 648        return 0;
 649}
 650
 651static int thermal_get_trip_type(struct thermal_zone_device *thermal,
 652                                 int trip, enum thermal_trip_type *type)
 653{
 654        struct acpi_thermal *tz = thermal->devdata;
 655        int i;
 656
 657        if (!tz || trip < 0)
 658                return -EINVAL;
 659
 660        if (tz->trips.critical.flags.valid) {
 661                if (!trip) {
 662                        *type = THERMAL_TRIP_CRITICAL;
 663                        return 0;
 664                }
 665                trip--;
 666        }
 667
 668        if (tz->trips.hot.flags.valid) {
 669                if (!trip) {
 670                        *type = THERMAL_TRIP_HOT;
 671                        return 0;
 672                }
 673                trip--;
 674        }
 675
 676        if (tz->trips.passive.flags.valid) {
 677                if (!trip) {
 678                        *type = THERMAL_TRIP_PASSIVE;
 679                        return 0;
 680                }
 681                trip--;
 682        }
 683
 684        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 685                tz->trips.active[i].flags.valid; i++) {
 686                if (!trip) {
 687                        *type = THERMAL_TRIP_ACTIVE;
 688                        return 0;
 689                }
 690                trip--;
 691        }
 692
 693        return -EINVAL;
 694}
 695
 696static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
 697                                 int trip, unsigned long *temp)
 698{
 699        struct acpi_thermal *tz = thermal->devdata;
 700        int i;
 701
 702        if (!tz || trip < 0)
 703                return -EINVAL;
 704
 705        if (tz->trips.critical.flags.valid) {
 706                if (!trip) {
 707                        *temp = KELVIN_TO_MILLICELSIUS(
 708                                tz->trips.critical.temperature,
 709                                tz->kelvin_offset);
 710                        return 0;
 711                }
 712                trip--;
 713        }
 714
 715        if (tz->trips.hot.flags.valid) {
 716                if (!trip) {
 717                        *temp = KELVIN_TO_MILLICELSIUS(
 718                                tz->trips.hot.temperature,
 719                                tz->kelvin_offset);
 720                        return 0;
 721                }
 722                trip--;
 723        }
 724
 725        if (tz->trips.passive.flags.valid) {
 726                if (!trip) {
 727                        *temp = KELVIN_TO_MILLICELSIUS(
 728                                tz->trips.passive.temperature,
 729                                tz->kelvin_offset);
 730                        return 0;
 731                }
 732                trip--;
 733        }
 734
 735        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 736                tz->trips.active[i].flags.valid; i++) {
 737                if (!trip) {
 738                        *temp = KELVIN_TO_MILLICELSIUS(
 739                                tz->trips.active[i].temperature,
 740                                tz->kelvin_offset);
 741                        return 0;
 742                }
 743                trip--;
 744        }
 745
 746        return -EINVAL;
 747}
 748
 749static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
 750                                unsigned long *temperature) {
 751        struct acpi_thermal *tz = thermal->devdata;
 752
 753        if (tz->trips.critical.flags.valid) {
 754                *temperature = KELVIN_TO_MILLICELSIUS(
 755                                tz->trips.critical.temperature,
 756                                tz->kelvin_offset);
 757                return 0;
 758        } else
 759                return -EINVAL;
 760}
 761
 762static int thermal_notify(struct thermal_zone_device *thermal, int trip,
 763                           enum thermal_trip_type trip_type)
 764{
 765        u8 type = 0;
 766        struct acpi_thermal *tz = thermal->devdata;
 767
 768        if (trip_type == THERMAL_TRIP_CRITICAL)
 769                type = ACPI_THERMAL_NOTIFY_CRITICAL;
 770        else if (trip_type == THERMAL_TRIP_HOT)
 771                type = ACPI_THERMAL_NOTIFY_HOT;
 772        else
 773                return 0;
 774
 775        acpi_bus_generate_proc_event(tz->device, type, 1);
 776        acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
 777                                        dev_name(&tz->device->dev), type, 1);
 778
 779        if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
 780                return 1;
 781
 782        return 0;
 783}
 784
 785typedef int (*cb)(struct thermal_zone_device *, int,
 786                  struct thermal_cooling_device *);
 787static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
 788                                        struct thermal_cooling_device *cdev,
 789                                        cb action)
 790{
 791        struct acpi_device *device = cdev->devdata;
 792        struct acpi_thermal *tz = thermal->devdata;
 793        struct acpi_device *dev;
 794        acpi_status status;
 795        acpi_handle handle;
 796        int i;
 797        int j;
 798        int trip = -1;
 799        int result = 0;
 800
 801        if (tz->trips.critical.flags.valid)
 802                trip++;
 803
 804        if (tz->trips.hot.flags.valid)
 805                trip++;
 806
 807        if (tz->trips.passive.flags.valid) {
 808                trip++;
 809                for (i = 0; i < tz->trips.passive.devices.count;
 810                    i++) {
 811                        handle = tz->trips.passive.devices.handles[i];
 812                        status = acpi_bus_get_device(handle, &dev);
 813                        if (ACPI_SUCCESS(status) && (dev == device)) {
 814                                result = action(thermal, trip, cdev);
 815                                if (result)
 816                                        goto failed;
 817                        }
 818                }
 819        }
 820
 821        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
 822                if (!tz->trips.active[i].flags.valid)
 823                        break;
 824                trip++;
 825                for (j = 0;
 826                    j < tz->trips.active[i].devices.count;
 827                    j++) {
 828                        handle = tz->trips.active[i].devices.handles[j];
 829                        status = acpi_bus_get_device(handle, &dev);
 830                        if (ACPI_SUCCESS(status) && (dev == device)) {
 831                                result = action(thermal, trip, cdev);
 832                                if (result)
 833                                        goto failed;
 834                        }
 835                }
 836        }
 837
 838        for (i = 0; i < tz->devices.count; i++) {
 839                handle = tz->devices.handles[i];
 840                status = acpi_bus_get_device(handle, &dev);
 841                if (ACPI_SUCCESS(status) && (dev == device)) {
 842                        result = action(thermal, -1, cdev);
 843                        if (result)
 844                                goto failed;
 845                }
 846        }
 847
 848failed:
 849        return result;
 850}
 851
 852static int
 853acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
 854                                        struct thermal_cooling_device *cdev)
 855{
 856        return acpi_thermal_cooling_device_cb(thermal, cdev,
 857                                thermal_zone_bind_cooling_device);
 858}
 859
 860static int
 861acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
 862                                        struct thermal_cooling_device *cdev)
 863{
 864        return acpi_thermal_cooling_device_cb(thermal, cdev,
 865                                thermal_zone_unbind_cooling_device);
 866}
 867
 868static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 869        .bind = acpi_thermal_bind_cooling_device,
 870        .unbind = acpi_thermal_unbind_cooling_device,
 871        .get_temp = thermal_get_temp,
 872        .get_mode = thermal_get_mode,
 873        .set_mode = thermal_set_mode,
 874        .get_trip_type = thermal_get_trip_type,
 875        .get_trip_temp = thermal_get_trip_temp,
 876        .get_crit_temp = thermal_get_crit_temp,
 877        .notify = thermal_notify,
 878};
 879
 880static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 881{
 882        int trips = 0;
 883        int result;
 884        acpi_status status;
 885        int i;
 886
 887        if (tz->trips.critical.flags.valid)
 888                trips++;
 889
 890        if (tz->trips.hot.flags.valid)
 891                trips++;
 892
 893        if (tz->trips.passive.flags.valid)
 894                trips++;
 895
 896        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 897                        tz->trips.active[i].flags.valid; i++, trips++);
 898
 899        if (tz->trips.passive.flags.valid)
 900                tz->thermal_zone =
 901                        thermal_zone_device_register("acpitz", trips, tz,
 902                                                     &acpi_thermal_zone_ops,
 903                                                     tz->trips.passive.tc1,
 904                                                     tz->trips.passive.tc2,
 905                                                     tz->trips.passive.tsp*100,
 906                                                     tz->polling_frequency*100);
 907        else
 908                tz->thermal_zone =
 909                        thermal_zone_device_register("acpitz", trips, tz,
 910                                                     &acpi_thermal_zone_ops,
 911                                                     0, 0, 0,
 912                                                     tz->polling_frequency*100);
 913        if (IS_ERR(tz->thermal_zone))
 914                return -ENODEV;
 915
 916        result = sysfs_create_link(&tz->device->dev.kobj,
 917                                   &tz->thermal_zone->device.kobj, "thermal_zone");
 918        if (result)
 919                return result;
 920
 921        result = sysfs_create_link(&tz->thermal_zone->device.kobj,
 922                                   &tz->device->dev.kobj, "device");
 923        if (result)
 924                return result;
 925
 926        status = acpi_attach_data(tz->device->handle,
 927                                  acpi_bus_private_data_handler,
 928                                  tz->thermal_zone);
 929        if (ACPI_FAILURE(status)) {
 930                printk(KERN_ERR PREFIX
 931                                "Error attaching device data\n");
 932                return -ENODEV;
 933        }
 934
 935        tz->tz_enabled = 1;
 936
 937        dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 938                 tz->thermal_zone->id);
 939        return 0;
 940}
 941
 942static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
 943{
 944        sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
 945        sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
 946        thermal_zone_device_unregister(tz->thermal_zone);
 947        tz->thermal_zone = NULL;
 948        acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
 949}
 950
 951
 952/* --------------------------------------------------------------------------
 953                              FS Interface (/proc)
 954   -------------------------------------------------------------------------- */
 955
 956static struct proc_dir_entry *acpi_thermal_dir;
 957
 958static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
 959{
 960        struct acpi_thermal *tz = seq->private;
 961
 962
 963        if (!tz)
 964                goto end;
 965
 966        seq_puts(seq, "state:                   ");
 967
 968        if (!tz->state.critical && !tz->state.hot && !tz->state.passive
 969            && !tz->state.active)
 970                seq_puts(seq, "ok\n");
 971        else {
 972                if (tz->state.critical)
 973                        seq_puts(seq, "critical ");
 974                if (tz->state.hot)
 975                        seq_puts(seq, "hot ");
 976                if (tz->state.passive)
 977                        seq_puts(seq, "passive ");
 978                if (tz->state.active)
 979                        seq_printf(seq, "active[%d]", tz->state.active_index);
 980                seq_puts(seq, "\n");
 981        }
 982
 983      end:
 984        return 0;
 985}
 986
 987static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
 988{
 989        return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
 990}
 991
 992static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
 993{
 994        int result = 0;
 995        struct acpi_thermal *tz = seq->private;
 996
 997
 998        if (!tz)
 999                goto end;
1000
1001        result = acpi_thermal_get_temperature(tz);
1002        if (result)
1003                goto end;
1004
1005        seq_printf(seq, "temperature:             %ld C\n",
1006                   KELVIN_TO_CELSIUS(tz->temperature));
1007
1008      end:
1009        return 0;
1010}
1011
1012static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
1013{
1014        return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
1015}
1016
1017static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
1018{
1019        struct acpi_thermal *tz = seq->private;
1020        struct acpi_device *device;
1021        acpi_status status;
1022
1023        int i = 0;
1024        int j = 0;
1025
1026
1027        if (!tz)
1028                goto end;
1029
1030        if (tz->trips.critical.flags.valid)
1031                seq_printf(seq, "critical (S5):           %ld C%s",
1032                           KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
1033                           nocrt ? " <disabled>\n" : "\n");
1034
1035        if (tz->trips.hot.flags.valid)
1036                seq_printf(seq, "hot (S4):                %ld C%s",
1037                           KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
1038                           nocrt ? " <disabled>\n" : "\n");
1039
1040        if (tz->trips.passive.flags.valid) {
1041                seq_printf(seq,
1042                           "passive:                 %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
1043                           KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
1044                           tz->trips.passive.tc1, tz->trips.passive.tc2,
1045                           tz->trips.passive.tsp);
1046                for (j = 0; j < tz->trips.passive.devices.count; j++) {
1047                        status = acpi_bus_get_device(tz->trips.passive.devices.
1048                                                     handles[j], &device);
1049                        seq_printf(seq, "%4.4s ", status ? "" :
1050                                   acpi_device_bid(device));
1051                }
1052                seq_puts(seq, "\n");
1053        }
1054
1055        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1056                if (!(tz->trips.active[i].flags.valid))
1057                        break;
1058                seq_printf(seq, "active[%d]:               %ld C: devices=",
1059                           i,
1060                           KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
1061                for (j = 0; j < tz->trips.active[i].devices.count; j++){
1062                        status = acpi_bus_get_device(tz->trips.active[i].
1063                                                     devices.handles[j],
1064                                                     &device);
1065                        seq_printf(seq, "%4.4s ", status ? "" :
1066                                   acpi_device_bid(device));
1067                }
1068                seq_puts(seq, "\n");
1069        }
1070
1071      end:
1072        return 0;
1073}
1074
1075static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
1076{
1077        return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
1078}
1079
1080static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
1081{
1082        struct acpi_thermal *tz = seq->private;
1083
1084
1085        if (!tz)
1086                goto end;
1087
1088        if (!tz->flags.cooling_mode)
1089                seq_puts(seq, "<setting not supported>\n");
1090        else
1091                seq_puts(seq, "0 - Active; 1 - Passive\n");
1092
1093      end:
1094        return 0;
1095}
1096
1097static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
1098{
1099        return single_open(file, acpi_thermal_cooling_seq_show,
1100                           PDE(inode)->data);
1101}
1102
1103static ssize_t
1104acpi_thermal_write_cooling_mode(struct file *file,
1105                                const char __user * buffer,
1106                                size_t count, loff_t * ppos)
1107{
1108        struct seq_file *m = file->private_data;
1109        struct acpi_thermal *tz = m->private;
1110        int result = 0;
1111        char mode_string[12] = { '\0' };
1112
1113
1114        if (!tz || (count > sizeof(mode_string) - 1))
1115                return -EINVAL;
1116
1117        if (!tz->flags.cooling_mode)
1118                return -ENODEV;
1119
1120        if (copy_from_user(mode_string, buffer, count))
1121                return -EFAULT;
1122
1123        mode_string[count] = '\0';
1124
1125        result = acpi_thermal_set_cooling_mode(tz,
1126                                               simple_strtoul(mode_string, NULL,
1127                                                              0));
1128        if (result)
1129                return result;
1130
1131        acpi_thermal_check(tz);
1132
1133        return count;
1134}
1135
1136static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
1137{
1138        struct acpi_thermal *tz = seq->private;
1139
1140
1141        if (!tz)
1142                goto end;
1143
1144        if (!tz->thermal_zone->polling_delay) {
1145                seq_puts(seq, "<polling disabled>\n");
1146                goto end;
1147        }
1148
1149        seq_printf(seq, "polling frequency:       %d seconds\n",
1150                   (tz->thermal_zone->polling_delay / 1000));
1151
1152      end:
1153        return 0;
1154}
1155
1156static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
1157{
1158        return single_open(file, acpi_thermal_polling_seq_show,
1159                           PDE(inode)->data);
1160}
1161
1162static ssize_t
1163acpi_thermal_write_polling(struct file *file,
1164                           const char __user * buffer,
1165                           size_t count, loff_t * ppos)
1166{
1167        struct seq_file *m = file->private_data;
1168        struct acpi_thermal *tz = m->private;
1169        int result = 0;
1170        char polling_string[12] = { '\0' };
1171        int seconds = 0;
1172
1173
1174        if (!tz || (count > sizeof(polling_string) - 1))
1175                return -EINVAL;
1176
1177        if (copy_from_user(polling_string, buffer, count))
1178                return -EFAULT;
1179
1180        polling_string[count] = '\0';
1181
1182        seconds = simple_strtoul(polling_string, NULL, 0);
1183
1184        result = acpi_thermal_set_polling(tz, seconds);
1185        if (result)
1186                return result;
1187
1188        acpi_thermal_check(tz);
1189
1190        return count;
1191}
1192
1193static int acpi_thermal_add_fs(struct acpi_device *device)
1194{
1195        struct proc_dir_entry *entry = NULL;
1196
1197
1198        if (!acpi_device_dir(device)) {
1199                acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1200                                                     acpi_thermal_dir);
1201                if (!acpi_device_dir(device))
1202                        return -ENODEV;
1203        }
1204
1205        /* 'state' [R] */
1206        entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
1207                                 S_IRUGO, acpi_device_dir(device),
1208                                 &acpi_thermal_state_fops,
1209                                 acpi_driver_data(device));
1210        if (!entry)
1211                return -ENODEV;
1212
1213        /* 'temperature' [R] */
1214        entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
1215                                 S_IRUGO, acpi_device_dir(device),
1216                                 &acpi_thermal_temp_fops,
1217                                 acpi_driver_data(device));
1218        if (!entry)
1219                return -ENODEV;
1220
1221        /* 'trip_points' [R] */
1222        entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
1223                                 S_IRUGO,
1224                                 acpi_device_dir(device),
1225                                 &acpi_thermal_trip_fops,
1226                                 acpi_driver_data(device));
1227        if (!entry)
1228                return -ENODEV;
1229
1230        /* 'cooling_mode' [R/W] */
1231        entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
1232                                 S_IFREG | S_IRUGO | S_IWUSR,
1233                                 acpi_device_dir(device),
1234                                 &acpi_thermal_cooling_fops,
1235                                 acpi_driver_data(device));
1236        if (!entry)
1237                return -ENODEV;
1238
1239        /* 'polling_frequency' [R/W] */
1240        entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
1241                                 S_IFREG | S_IRUGO | S_IWUSR,
1242                                 acpi_device_dir(device),
1243                                 &acpi_thermal_polling_fops,
1244                                 acpi_driver_data(device));
1245        if (!entry)
1246                return -ENODEV;
1247        return 0;
1248}
1249
1250static int acpi_thermal_remove_fs(struct acpi_device *device)
1251{
1252
1253        if (acpi_device_dir(device)) {
1254                remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1255                                  acpi_device_dir(device));
1256                remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1257                                  acpi_device_dir(device));
1258                remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1259                                  acpi_device_dir(device));
1260                remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1261                                  acpi_device_dir(device));
1262                remove_proc_entry(ACPI_THERMAL_FILE_STATE,
1263                                  acpi_device_dir(device));
1264                remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
1265                acpi_device_dir(device) = NULL;
1266        }
1267
1268        return 0;
1269}
1270
1271/* --------------------------------------------------------------------------
1272                                 Driver Interface
1273   -------------------------------------------------------------------------- */
1274
1275static void acpi_thermal_notify(struct acpi_device *device, u32 event)
1276{
1277        struct acpi_thermal *tz = acpi_driver_data(device);
1278
1279
1280        if (!tz)
1281                return;
1282
1283        switch (event) {
1284        case ACPI_THERMAL_NOTIFY_TEMPERATURE:
1285                acpi_thermal_check(tz);
1286                break;
1287        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1288                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
1289                acpi_thermal_check(tz);
1290                acpi_bus_generate_proc_event(device, event, 0);
1291                acpi_bus_generate_netlink_event(device->pnp.device_class,
1292                                                  dev_name(&device->dev), event, 0);
1293                break;
1294        case ACPI_THERMAL_NOTIFY_DEVICES:
1295                acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
1296                acpi_thermal_check(tz);
1297                acpi_bus_generate_proc_event(device, event, 0);
1298                acpi_bus_generate_netlink_event(device->pnp.device_class,
1299                                                  dev_name(&device->dev), event, 0);
1300                break;
1301        default:
1302                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1303                                  "Unsupported event [0x%x]\n", event));
1304                break;
1305        }
1306}
1307
1308static int acpi_thermal_get_info(struct acpi_thermal *tz)
1309{
1310        int result = 0;
1311
1312
1313        if (!tz)
1314                return -EINVAL;
1315
1316        /* Get temperature [_TMP] (required) */
1317        result = acpi_thermal_get_temperature(tz);
1318        if (result)
1319                return result;
1320
1321        /* Get trip points [_CRT, _PSV, etc.] (required) */
1322        result = acpi_thermal_get_trip_points(tz);
1323        if (result)
1324                return result;
1325
1326        /* Set the cooling mode [_SCP] to active cooling (default) */
1327        result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1328        if (!result)
1329                tz->flags.cooling_mode = 1;
1330
1331        /* Get default polling frequency [_TZP] (optional) */
1332        if (tzp)
1333                tz->polling_frequency = tzp;
1334        else
1335                acpi_thermal_get_polling_frequency(tz);
1336
1337        return 0;
1338}
1339
1340/*
1341 * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
1342 * handles temperature values with a single decimal place. As a consequence,
1343 * some implementations use an offset of 273.1 and others use an offset of
1344 * 273.2. Try to find out which one is being used, to present the most
1345 * accurate and visually appealing number.
1346 *
1347 * The heuristic below should work for all ACPI thermal zones which have a
1348 * critical trip point with a value being a multiple of 0.5 degree Celsius.
1349 */
1350static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
1351{
1352        if (tz->trips.critical.flags.valid &&
1353            (tz->trips.critical.temperature % 5) == 1)
1354                tz->kelvin_offset = 2731;
1355        else
1356                tz->kelvin_offset = 2732;
1357}
1358
1359static int acpi_thermal_add(struct acpi_device *device)
1360{
1361        int result = 0;
1362        struct acpi_thermal *tz = NULL;
1363
1364
1365        if (!device)
1366                return -EINVAL;
1367
1368        tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1369        if (!tz)
1370                return -ENOMEM;
1371
1372        tz->device = device;
1373        strcpy(tz->name, device->pnp.bus_id);
1374        strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1375        strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1376        device->driver_data = tz;
1377        mutex_init(&tz->lock);
1378
1379
1380        result = acpi_thermal_get_info(tz);
1381        if (result)
1382                goto free_memory;
1383
1384        acpi_thermal_guess_offset(tz);
1385
1386        result = acpi_thermal_register_thermal_zone(tz);
1387        if (result)
1388                goto free_memory;
1389
1390        result = acpi_thermal_add_fs(device);
1391        if (result)
1392                goto unregister_thermal_zone;
1393
1394        printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1395               acpi_device_name(device), acpi_device_bid(device),
1396               KELVIN_TO_CELSIUS(tz->temperature));
1397        goto end;
1398
1399unregister_thermal_zone:
1400        thermal_zone_device_unregister(tz->thermal_zone);
1401free_memory:
1402        kfree(tz);
1403end:
1404        return result;
1405}
1406
1407static int acpi_thermal_remove(struct acpi_device *device, int type)
1408{
1409        struct acpi_thermal *tz = NULL;
1410
1411        if (!device || !acpi_driver_data(device))
1412                return -EINVAL;
1413
1414        tz = acpi_driver_data(device);
1415
1416        acpi_thermal_remove_fs(device);
1417        acpi_thermal_unregister_thermal_zone(tz);
1418        mutex_destroy(&tz->lock);
1419        kfree(tz);
1420        return 0;
1421}
1422
1423static int acpi_thermal_resume(struct acpi_device *device)
1424{
1425        struct acpi_thermal *tz = NULL;
1426        int i, j, power_state, result;
1427
1428
1429        if (!device || !acpi_driver_data(device))
1430                return -EINVAL;
1431
1432        tz = acpi_driver_data(device);
1433
1434        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1435                if (!(&tz->trips.active[i]))
1436                        break;
1437                if (!tz->trips.active[i].flags.valid)
1438                        break;
1439                tz->trips.active[i].flags.enabled = 1;
1440                for (j = 0; j < tz->trips.active[i].devices.count; j++) {
1441                        result = acpi_bus_get_power(tz->trips.active[i].devices.
1442                            handles[j], &power_state);
1443                        if (result || (power_state != ACPI_STATE_D0)) {
1444                                tz->trips.active[i].flags.enabled = 0;
1445                                break;
1446                        }
1447                }
1448                tz->state.active |= tz->trips.active[i].flags.enabled;
1449        }
1450
1451        acpi_thermal_check(tz);
1452
1453        return AE_OK;
1454}
1455
1456static int thermal_act(const struct dmi_system_id *d) {
1457
1458        if (act == 0) {
1459                printk(KERN_NOTICE "ACPI: %s detected: "
1460                        "disabling all active thermal trip points\n", d->ident);
1461                act = -1;
1462        }
1463        return 0;
1464}
1465static int thermal_nocrt(const struct dmi_system_id *d) {
1466
1467        printk(KERN_NOTICE "ACPI: %s detected: "
1468                "disabling all critical thermal trip point actions.\n", d->ident);
1469        nocrt = 1;
1470        return 0;
1471}
1472static int thermal_tzp(const struct dmi_system_id *d) {
1473
1474        if (tzp == 0) {
1475                printk(KERN_NOTICE "ACPI: %s detected: "
1476                        "enabling thermal zone polling\n", d->ident);
1477                tzp = 300;      /* 300 dS = 30 Seconds */
1478        }
1479        return 0;
1480}
1481static int thermal_psv(const struct dmi_system_id *d) {
1482
1483        if (psv == 0) {
1484                printk(KERN_NOTICE "ACPI: %s detected: "
1485                        "disabling all passive thermal trip points\n", d->ident);
1486                psv = -1;
1487        }
1488        return 0;
1489}
1490
1491static struct dmi_system_id thermal_dmi_table[] __initdata = {
1492        /*
1493         * Award BIOS on this AOpen makes thermal control almost worthless.
1494         * http://bugzilla.kernel.org/show_bug.cgi?id=8842
1495         */
1496        {
1497         .callback = thermal_act,
1498         .ident = "AOpen i915GMm-HFS",
1499         .matches = {
1500                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1501                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1502                },
1503        },
1504        {
1505         .callback = thermal_psv,
1506         .ident = "AOpen i915GMm-HFS",
1507         .matches = {
1508                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1509                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1510                },
1511        },
1512        {
1513         .callback = thermal_tzp,
1514         .ident = "AOpen i915GMm-HFS",
1515         .matches = {
1516                DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1517                DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1518                },
1519        },
1520        {
1521         .callback = thermal_nocrt,
1522         .ident = "Gigabyte GA-7ZX",
1523         .matches = {
1524                DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
1525                DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
1526                },
1527        },
1528        {}
1529};
1530
1531static int __init acpi_thermal_init(void)
1532{
1533        int result = 0;
1534
1535        dmi_check_system(thermal_dmi_table);
1536
1537        if (off) {
1538                printk(KERN_NOTICE "ACPI: thermal control disabled\n");
1539                return -ENODEV;
1540        }
1541        acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
1542        if (!acpi_thermal_dir)
1543                return -ENODEV;
1544
1545        result = acpi_bus_register_driver(&acpi_thermal_driver);
1546        if (result < 0) {
1547                remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1548                return -ENODEV;
1549        }
1550
1551        return 0;
1552}
1553
1554static void __exit acpi_thermal_exit(void)
1555{
1556
1557        acpi_bus_unregister_driver(&acpi_thermal_driver);
1558
1559        remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1560
1561        return;
1562}
1563
1564module_init(acpi_thermal_init);
1565module_exit(acpi_thermal_exit);
1566