vserver 1.9.3
[linux-2.6.git] / drivers / acpi / thermal.c
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/init.h>
37 #include <linux/types.h>
38 #include <linux/proc_fs.h>
39 #include <linux/sched.h>
40 #include <linux/kmod.h>
41 #include <linux/seq_file.h>
42 #include <asm/uaccess.h>
43
44 #include <acpi/acpi_bus.h>
45 #include <acpi/acpi_drivers.h>
46
47 #define ACPI_THERMAL_COMPONENT          0x04000000
48 #define ACPI_THERMAL_CLASS              "thermal_zone"
49 #define ACPI_THERMAL_DRIVER_NAME        "ACPI Thermal Zone Driver"
50 #define ACPI_THERMAL_DEVICE_NAME        "Thermal Zone"
51 #define ACPI_THERMAL_FILE_STATE         "state"
52 #define ACPI_THERMAL_FILE_TEMPERATURE   "temperature"
53 #define ACPI_THERMAL_FILE_TRIP_POINTS   "trip_points"
54 #define ACPI_THERMAL_FILE_COOLING_MODE  "cooling_mode"
55 #define ACPI_THERMAL_FILE_POLLING_FREQ  "polling_frequency"
56 #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
57 #define ACPI_THERMAL_NOTIFY_THRESHOLDS  0x81
58 #define ACPI_THERMAL_NOTIFY_DEVICES     0x82
59 #define ACPI_THERMAL_NOTIFY_CRITICAL    0xF0
60 #define ACPI_THERMAL_NOTIFY_HOT         0xF1
61 #define ACPI_THERMAL_MODE_ACTIVE        0x00
62 #define ACPI_THERMAL_MODE_PASSIVE       0x01
63 #define ACPI_THERMAL_MODE_CRT           0xff
64 #define ACPI_THERMAL_PATH_POWEROFF      "/sbin/poweroff"
65
66 #define ACPI_THERMAL_MAX_ACTIVE 10
67
68 #define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
69 #define CELSIUS_TO_KELVIN(t)    ((t+273)*10)
70
71 #define _COMPONENT              ACPI_THERMAL_COMPONENT
72 ACPI_MODULE_NAME                ("acpi_thermal")
73
74 MODULE_AUTHOR("Paul Diefenbaugh");
75 MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
76 MODULE_LICENSE("GPL");
77
78 static int tzp;
79 MODULE_PARM(tzp, "i");
80 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
81
82
83 static int acpi_thermal_add (struct acpi_device *device);
84 static int acpi_thermal_remove (struct acpi_device *device, int type);
85 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
86 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
87 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
88 static ssize_t acpi_thermal_write_trip_points (struct file*,const char __user *,size_t,loff_t *);
89 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
90 static ssize_t acpi_thermal_write_cooling_mode (struct file*,const char __user *,size_t,loff_t *);
91 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
92 static ssize_t acpi_thermal_write_polling(struct file*,const char __user *,size_t,loff_t *);
93
94 static struct acpi_driver acpi_thermal_driver = {
95         .name =         ACPI_THERMAL_DRIVER_NAME,
96         .class =        ACPI_THERMAL_CLASS,
97         .ids =          ACPI_THERMAL_HID,
98         .ops =          {
99                                 .add =          acpi_thermal_add,
100                                 .remove =       acpi_thermal_remove,
101                         },
102 };
103
104 struct acpi_thermal_state {
105         u8                      critical:1;
106         u8                      hot:1;
107         u8                      passive:1;
108         u8                      active:1;
109         u8                      reserved:4;
110         int                     active_index;
111 };
112
113 struct acpi_thermal_state_flags {
114         u8                      valid:1;
115         u8                      enabled:1;
116         u8                      reserved:6;
117 };
118
119 struct acpi_thermal_critical {
120         struct acpi_thermal_state_flags flags;
121         unsigned long           temperature;
122 };
123
124 struct acpi_thermal_hot {
125         struct acpi_thermal_state_flags flags;
126         unsigned long           temperature;
127 };
128
129 struct acpi_thermal_passive {
130         struct acpi_thermal_state_flags flags;
131         unsigned long           temperature;
132         unsigned long           tc1;
133         unsigned long           tc2;
134         unsigned long           tsp;
135         struct acpi_handle_list devices;
136 };
137
138 struct acpi_thermal_active {
139         struct acpi_thermal_state_flags flags;
140         unsigned long           temperature;
141         struct acpi_handle_list devices;
142 };
143
144 struct acpi_thermal_trips {
145         struct acpi_thermal_critical critical;
146         struct acpi_thermal_hot hot;
147         struct acpi_thermal_passive passive;
148         struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
149 };
150
151 struct acpi_thermal_flags {
152         u8                      cooling_mode:1;         /* _SCP */
153         u8                      devices:1;              /* _TZD */
154         u8                      reserved:6;
155 };
156
157 struct acpi_thermal {
158         acpi_handle             handle;
159         acpi_bus_id             name;
160         unsigned long           temperature;
161         unsigned long           last_temperature;
162         unsigned long           polling_frequency;
163         u8                      cooling_mode;
164         volatile u8             zombie;
165         struct acpi_thermal_flags flags;
166         struct acpi_thermal_state state;
167         struct acpi_thermal_trips trips;
168         struct acpi_handle_list devices;
169         struct timer_list       timer;
170 };
171
172 static struct file_operations acpi_thermal_state_fops = {
173         .open           = acpi_thermal_state_open_fs,
174         .read           = seq_read,
175         .llseek         = seq_lseek,
176         .release        = single_release,
177 };
178
179 static struct file_operations acpi_thermal_temp_fops = {
180         .open           = acpi_thermal_temp_open_fs,
181         .read           = seq_read,
182         .llseek         = seq_lseek,
183         .release        = single_release,
184 };
185
186 static struct file_operations acpi_thermal_trip_fops = {
187         .open           = acpi_thermal_trip_open_fs,
188         .read           = seq_read,
189         .write          = acpi_thermal_write_trip_points,
190         .llseek         = seq_lseek,
191         .release        = single_release,
192 };
193
194 static struct file_operations acpi_thermal_cooling_fops = {
195         .open           = acpi_thermal_cooling_open_fs,
196         .read           = seq_read,
197         .write          = acpi_thermal_write_cooling_mode,
198         .llseek         = seq_lseek,
199         .release        = single_release,
200 };
201
202 static struct file_operations acpi_thermal_polling_fops = {
203         .open           = acpi_thermal_polling_open_fs,
204         .read           = seq_read,
205         .write          = acpi_thermal_write_polling,
206         .llseek         = seq_lseek,
207         .release        = single_release,
208 };
209
210 /* --------------------------------------------------------------------------
211                              Thermal Zone Management
212    -------------------------------------------------------------------------- */
213
214 static int
215 acpi_thermal_get_temperature (
216         struct acpi_thermal *tz)
217 {
218         acpi_status             status = AE_OK;
219
220         ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature");
221
222         if (!tz)
223                 return_VALUE(-EINVAL);
224
225         tz->last_temperature = tz->temperature;
226
227         status = acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
228         if (ACPI_FAILURE(status))
229                 return -ENODEV;
230
231         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature));
232
233         return_VALUE(0);
234 }
235
236
237 static int
238 acpi_thermal_get_polling_frequency (
239         struct acpi_thermal     *tz)
240 {
241         acpi_status             status = AE_OK;
242
243         ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency");
244
245         if (!tz)
246                 return_VALUE(-EINVAL);
247
248         status = acpi_evaluate_integer(tz->handle, "_TZP", NULL, &tz->polling_frequency);
249         if (ACPI_FAILURE(status))
250                 return_VALUE(-ENODEV);
251
252         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency));
253
254         return_VALUE(0);
255 }
256
257
258 static int
259 acpi_thermal_set_polling (
260         struct acpi_thermal     *tz,
261         int                     seconds)
262 {
263         ACPI_FUNCTION_TRACE("acpi_thermal_set_polling");
264
265         if (!tz)
266                 return_VALUE(-EINVAL);
267
268         tz->polling_frequency = seconds * 10;   /* Convert value to deci-seconds */
269
270         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", tz->polling_frequency));
271
272         return_VALUE(0);
273 }
274
275
276 static int
277 acpi_thermal_set_cooling_mode (
278         struct acpi_thermal     *tz,
279         int                     mode)
280 {
281         acpi_status             status = AE_OK;
282         union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
283         struct acpi_object_list arg_list = {1, &arg0};
284         acpi_handle             handle = NULL;
285
286         ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode");
287
288         if (!tz)
289                 return_VALUE(-EINVAL);
290
291         status = acpi_get_handle(tz->handle, "_SCP", &handle);
292         if (ACPI_FAILURE(status)) {
293                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
294                 return_VALUE(-ENODEV);
295         }
296
297         arg0.integer.value = mode;
298
299         status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
300         if (ACPI_FAILURE(status))
301                 return_VALUE(-ENODEV);
302
303         tz->cooling_mode = mode;
304
305         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", 
306                 mode?"passive":"active"));
307
308         return_VALUE(0);
309 }
310
311
312 static int
313 acpi_thermal_get_trip_points (
314         struct acpi_thermal *tz)
315 {
316         acpi_status             status = AE_OK;
317         int                     i = 0;
318
319         ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points");
320
321         if (!tz)
322                 return_VALUE(-EINVAL);
323
324         /* Critical Shutdown (required) */
325
326         status = acpi_evaluate_integer(tz->handle, "_CRT", NULL, 
327                 &tz->trips.critical.temperature);
328         if (ACPI_FAILURE(status)) {
329                 tz->trips.critical.flags.valid = 0;
330                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
331                 return -ENODEV;
332         }
333         else {
334                 tz->trips.critical.flags.valid = 1;
335                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%lu]\n", tz->trips.critical.temperature));
336         }
337
338         /* Critical Sleep (optional) */
339
340         status = acpi_evaluate_integer(tz->handle, "_HOT", NULL, &tz->trips.hot.temperature);
341         if (ACPI_FAILURE(status)) {
342                 tz->trips.hot.flags.valid = 0;
343                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
344         }
345         else {
346                 tz->trips.hot.flags.valid = 1;
347                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", tz->trips.hot.temperature));
348         }
349
350         /* Passive: Processors (optional) */
351
352         status = acpi_evaluate_integer(tz->handle, "_PSV", NULL, &tz->trips.passive.temperature);
353         if (ACPI_FAILURE(status)) {
354                 tz->trips.passive.flags.valid = 0;
355                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
356         }
357         else {
358                 tz->trips.passive.flags.valid = 1;
359
360                 status = acpi_evaluate_integer(tz->handle, "_TC1", NULL, &tz->trips.passive.tc1);
361                 if (ACPI_FAILURE(status))
362                         tz->trips.passive.flags.valid = 0;
363
364                 status = acpi_evaluate_integer(tz->handle, "_TC2", NULL, &tz->trips.passive.tc2);
365                 if (ACPI_FAILURE(status))
366                         tz->trips.passive.flags.valid = 0;
367
368                 status = acpi_evaluate_integer(tz->handle, "_TSP", NULL, &tz->trips.passive.tsp);
369                 if (ACPI_FAILURE(status))
370                         tz->trips.passive.flags.valid = 0;
371
372                 status = acpi_evaluate_reference(tz->handle, "_PSL", NULL, &tz->trips.passive.devices);
373                 if (ACPI_FAILURE(status))
374                         tz->trips.passive.flags.valid = 0;
375
376                 if (!tz->trips.passive.flags.valid)
377                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid passive threshold\n"));
378                 else
379                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%lu]\n", tz->trips.passive.temperature));
380         }
381
382         /* Active: Fans, etc. (optional) */
383
384         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
385
386                 char name[5] = {'_','A','C',('0'+i),'\0'};
387
388                 status = acpi_evaluate_integer(tz->handle, name, NULL, &tz->trips.active[i].temperature);
389                 if (ACPI_FAILURE(status))
390                         break;
391
392                 name[2] = 'L';
393                 status = acpi_evaluate_reference(tz->handle, name, NULL, &tz->trips.active[i].devices);
394                 if (ACPI_SUCCESS(status)) {
395                         tz->trips.active[i].flags.valid = 1;
396                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%lu]\n", i, tz->trips.active[i].temperature));
397                 }
398                 else
399                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i));
400         }
401
402         return_VALUE(0);
403 }
404
405
406 static int
407 acpi_thermal_get_devices (
408         struct acpi_thermal     *tz)
409 {
410         acpi_status             status = AE_OK;
411
412         ACPI_FUNCTION_TRACE("acpi_thermal_get_devices");
413
414         if (!tz)
415                 return_VALUE(-EINVAL);
416
417         status = acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
418         if (ACPI_FAILURE(status))
419                 return_VALUE(-ENODEV);
420
421         return_VALUE(0);
422 }
423
424
425 static int
426 acpi_thermal_call_usermode (
427         char                    *path)
428 {
429         char                    *argv[2] = {NULL, NULL};
430         char                    *envp[3] = {NULL, NULL, NULL};
431
432         ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode");
433
434         if (!path)
435                 return_VALUE(-EINVAL);
436
437         argv[0] = path;
438
439         /* minimal command environment */
440         envp[0] = "HOME=/";
441         envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
442         
443         call_usermodehelper(argv[0], argv, envp, 0);
444
445         return_VALUE(0);
446 }
447
448
449 static int
450 acpi_thermal_critical (
451         struct acpi_thermal     *tz)
452 {
453         int                     result = 0;
454         struct acpi_device      *device = NULL;
455
456         ACPI_FUNCTION_TRACE("acpi_thermal_critical");
457
458         if (!tz || !tz->trips.critical.flags.valid)
459                 return_VALUE(-EINVAL);
460
461         if (tz->temperature >= tz->trips.critical.temperature) {
462                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
463                 tz->trips.critical.flags.enabled = 1;
464         }
465         else if (tz->trips.critical.flags.enabled)
466                 tz->trips.critical.flags.enabled = 0;
467
468         result = acpi_bus_get_device(tz->handle, &device);
469         if (result)
470                 return_VALUE(result);
471
472         printk(KERN_EMERG "Critical temperature reached (%ld C), shutting down.\n", KELVIN_TO_CELSIUS(tz->temperature));
473         acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled);
474
475         acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
476
477         return_VALUE(0);
478 }
479
480
481 static int
482 acpi_thermal_hot (
483         struct acpi_thermal     *tz)
484 {
485         int                     result = 0;
486         struct acpi_device      *device = NULL;
487
488         ACPI_FUNCTION_TRACE("acpi_thermal_hot");
489
490         if (!tz || !tz->trips.hot.flags.valid)
491                 return_VALUE(-EINVAL);
492
493         if (tz->temperature >= tz->trips.hot.temperature) {
494                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
495                 tz->trips.hot.flags.enabled = 1;
496         }
497         else if (tz->trips.hot.flags.enabled)
498                 tz->trips.hot.flags.enabled = 0;
499
500         result = acpi_bus_get_device(tz->handle, &device);
501         if (result)
502                 return_VALUE(result);
503
504         acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT, tz->trips.hot.flags.enabled);
505
506         /* TBD: Call user-mode "sleep(S4)" function */
507
508         return_VALUE(0);
509 }
510
511
512 static int
513 acpi_thermal_passive (
514         struct acpi_thermal     *tz)
515 {
516         int                     result = 0;
517         struct acpi_thermal_passive *passive = NULL;
518         int                     trend = 0;
519         int                     i = 0;
520
521         ACPI_FUNCTION_TRACE("acpi_thermal_passive");
522
523         if (!tz || !tz->trips.passive.flags.valid)
524                 return_VALUE(-EINVAL);
525
526         passive = &(tz->trips.passive);
527
528         /*
529          * Above Trip?
530          * -----------
531          * Calculate the thermal trend (using the passive cooling equation)
532          * and modify the performance limit for all passive cooling devices
533          * accordingly.  Note that we assume symmetry.
534          */
535         if (tz->temperature >= passive->temperature) {
536                 trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
537                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
538                         "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", 
539                         trend, passive->tc1, tz->temperature, 
540                         tz->last_temperature, passive->tc2, 
541                         tz->temperature, passive->temperature));
542                 tz->trips.passive.flags.enabled = 1;
543                 /* Heating up? */
544                 if (trend > 0)
545                         for (i=0; i<passive->devices.count; i++)
546                                 acpi_processor_set_thermal_limit(
547                                         passive->devices.handles[i], 
548                                         ACPI_PROCESSOR_LIMIT_INCREMENT);
549                 /* Cooling off? */
550                 else if (trend < 0)
551                         for (i=0; i<passive->devices.count; i++)
552                                 acpi_processor_set_thermal_limit(
553                                         passive->devices.handles[i], 
554                                         ACPI_PROCESSOR_LIMIT_DECREMENT);
555         }
556
557         /*
558          * Below Trip?
559          * -----------
560          * Implement passive cooling hysteresis to slowly increase performance
561          * and avoid thrashing around the passive trip point.  Note that we
562          * assume symmetry.
563          */
564         else if (tz->trips.passive.flags.enabled) {
565                 for (i=0; i<passive->devices.count; i++)
566                         result = acpi_processor_set_thermal_limit(
567                                 passive->devices.handles[i], 
568                                 ACPI_PROCESSOR_LIMIT_DECREMENT);
569                 if (result == 1) {
570                         tz->trips.passive.flags.enabled = 0;
571                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
572                                 "Disabling passive cooling (zone is cool)\n"));
573                 }
574         }
575
576         return_VALUE(0);
577 }
578
579
580 static int
581 acpi_thermal_active (
582         struct acpi_thermal     *tz)
583 {
584         int                     result = 0;
585         struct acpi_thermal_active *active = NULL;
586         int                     i = 0;
587         int                     j = 0;
588         unsigned long           maxtemp = 0;
589
590         ACPI_FUNCTION_TRACE("acpi_thermal_active");
591
592         if (!tz)
593                 return_VALUE(-EINVAL);
594
595         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
596
597                 active = &(tz->trips.active[i]);
598                 if (!active || !active->flags.valid)
599                         break;
600
601                 /*
602                  * Above Threshold?
603                  * ----------------
604                  * If not already enabled, turn ON all cooling devices
605                  * associated with this active threshold.
606                  */
607                 if (tz->temperature >= active->temperature) {
608                         if (active->temperature > maxtemp)
609                                 tz->state.active_index = i, maxtemp = active->temperature;
610                         if (!active->flags.enabled) {
611                                 for (j = 0; j < active->devices.count; j++) {
612                                         result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0);
613                                         if (result) {
614                                                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'on'\n", active->devices.handles[j]));
615                                                 continue;
616                                         }
617                                         active->flags.enabled = 1;
618                                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'on'\n", active->devices.handles[j]));
619                                 }
620                         }
621                 }
622                 /*
623                  * Below Threshold?
624                  * ----------------
625                  * Turn OFF all cooling devices associated with this
626                  * threshold.
627                  */
628                 else if (active->flags.enabled) {
629                         for (j = 0; j < active->devices.count; j++) {
630                                 result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D3);
631                                 if (result) {
632                                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'off'\n", active->devices.handles[j]));
633                                         continue;
634                                 }
635                                 active->flags.enabled = 0;
636                                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'off'\n", active->devices.handles[j]));
637                         }
638                 }
639         }
640
641         return_VALUE(0);
642 }
643
644
645 static void acpi_thermal_check (void *context);
646
647 static void
648 acpi_thermal_run (
649         unsigned long           data)
650 {
651         struct acpi_thermal *tz = (struct acpi_thermal *)data;
652         if (!tz->zombie)
653                 acpi_os_queue_for_execution(OSD_PRIORITY_GPE,  
654                         acpi_thermal_check, (void *) data);
655 }
656
657
658 static void
659 acpi_thermal_check (
660         void                    *data)
661 {
662         int                     result = 0;
663         struct acpi_thermal     *tz = (struct acpi_thermal *) data;
664         unsigned long           sleep_time = 0;
665         int                     i = 0;
666         struct acpi_thermal_state state;
667
668         ACPI_FUNCTION_TRACE("acpi_thermal_check");
669
670         if (!tz) {
671                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
672                 return_VOID;
673         }
674
675         state = tz->state;
676
677         result = acpi_thermal_get_temperature(tz);
678         if (result)
679                 return_VOID;
680         
681         memset(&tz->state, 0, sizeof(tz->state));
682         
683         /*
684          * Check Trip Points
685          * -----------------
686          * Compare the current temperature to the trip point values to see
687          * if we've entered one of the thermal policy states.  Note that
688          * this function determines when a state is entered, but the 
689          * individual policy decides when it is exited (e.g. hysteresis).
690          */
691         if (tz->trips.critical.flags.valid)
692                 state.critical |= (tz->temperature >= tz->trips.critical.temperature);
693         if (tz->trips.hot.flags.valid)
694                 state.hot |= (tz->temperature >= tz->trips.hot.temperature);
695         if (tz->trips.passive.flags.valid)
696                 state.passive |= (tz->temperature >= tz->trips.passive.temperature);
697         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++)
698                 if (tz->trips.active[i].flags.valid)
699                         state.active |= (tz->temperature >= tz->trips.active[i].temperature);
700
701         /*
702          * Invoke Policy
703          * -------------
704          * Separated from the above check to allow individual policy to 
705          * determine when to exit a given state.
706          */
707         if (state.critical)
708                 acpi_thermal_critical(tz);
709         if (state.hot)
710                 acpi_thermal_hot(tz);
711         if (state.passive)
712                 acpi_thermal_passive(tz);
713         if (state.active)
714                 acpi_thermal_active(tz);
715
716         /*
717          * Calculate State
718          * ---------------
719          * Again, separated from the above two to allow independent policy
720          * decisions.
721          */
722         if (tz->trips.critical.flags.enabled)
723                 tz->state.critical = 1;
724         if (tz->trips.hot.flags.enabled)
725                 tz->state.hot = 1;
726         if (tz->trips.passive.flags.enabled)
727                 tz->state.passive = 1;
728         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++)
729                 if (tz->trips.active[i].flags.enabled)
730                         tz->state.active = 1;
731
732         /*
733          * Calculate Sleep Time
734          * --------------------
735          * If we're in the passive state, use _TSP's value.  Otherwise
736          * use the default polling frequency (e.g. _TZP).  If no polling
737          * frequency is specified then we'll wait forever (at least until
738          * a thermal event occurs).  Note that _TSP and _TZD values are
739          * given in 1/10th seconds (we must covert to milliseconds).
740          */
741         if (tz->state.passive)
742                 sleep_time = tz->trips.passive.tsp * 100;
743         else if (tz->polling_frequency > 0)
744                 sleep_time = tz->polling_frequency * 100;
745
746         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n", 
747                 tz->name, tz->temperature, sleep_time));
748
749         /*
750          * Schedule Next Poll
751          * ------------------
752          */
753         if (!sleep_time) {
754                 if (timer_pending(&(tz->timer)))
755                         del_timer(&(tz->timer));
756         }
757         else {
758                 if (timer_pending(&(tz->timer)))
759                         mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
760                 else {
761                         tz->timer.data = (unsigned long) tz;
762                         tz->timer.function = acpi_thermal_run;
763                         tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
764                         add_timer(&(tz->timer));
765                 }
766         }
767
768         return_VOID;
769 }
770
771
772 /* --------------------------------------------------------------------------
773                               FS Interface (/proc)
774    -------------------------------------------------------------------------- */
775
776 struct proc_dir_entry           *acpi_thermal_dir;
777
778 static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
779 {
780         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
781
782         ACPI_FUNCTION_TRACE("acpi_thermal_state_seq_show");
783
784         if (!tz)
785                 goto end;
786
787         seq_puts(seq, "state:                   ");
788
789         if (!tz->state.critical && !tz->state.hot && !tz->state.passive && !tz->state.active)
790                 seq_puts(seq, "ok\n");
791         else {
792                 if (tz->state.critical)
793                         seq_puts(seq, "critical ");
794                 if (tz->state.hot)
795                         seq_puts(seq, "hot ");
796                 if (tz->state.passive)
797                         seq_puts(seq, "passive ");
798                 if (tz->state.active)
799                         seq_printf(seq, "active[%d]", tz->state.active_index);
800                 seq_puts(seq, "\n");
801         }
802
803 end:
804         return 0;
805 }
806
807 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
808 {
809         return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
810 }
811
812
813 static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
814 {
815         int                     result = 0;
816         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
817
818         ACPI_FUNCTION_TRACE("acpi_thermal_temp_seq_show");
819
820         if (!tz)
821                 goto end;
822
823         result = acpi_thermal_get_temperature(tz);
824         if (result)
825                 goto end;
826
827         seq_printf(seq, "temperature:             %ld C\n", 
828                 KELVIN_TO_CELSIUS(tz->temperature));
829
830 end:
831         return 0;
832 }
833
834 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
835 {
836         return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
837 }
838
839
840 static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
841 {
842         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
843         int                     i = 0;
844         int                     j = 0;
845
846         ACPI_FUNCTION_TRACE("acpi_thermal_trip_seq_show");
847
848         if (!tz)
849                 goto end;
850
851         if (tz->trips.critical.flags.valid)
852                 seq_printf(seq, "critical (S5):           %ld C\n",
853                         KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
854
855         if (tz->trips.hot.flags.valid)
856                 seq_printf(seq, "hot (S4):                %ld C\n",
857                         KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
858
859         if (tz->trips.passive.flags.valid) {
860                 seq_printf(seq, "passive:                 %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
861                         KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
862                         tz->trips.passive.tc1,
863                         tz->trips.passive.tc2, 
864                         tz->trips.passive.tsp);
865                 for (j=0; j<tz->trips.passive.devices.count; j++) {
866
867                         seq_printf(seq, "0x%p ", tz->trips.passive.devices.handles[j]);
868                 }
869                 seq_puts(seq, "\n");
870         }
871
872         for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
873                 if (!(tz->trips.active[i].flags.valid))
874                         break;
875                 seq_printf(seq, "active[%d]:               %ld C: devices=",
876                         i, KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
877                 for (j = 0; j < tz->trips.active[i].devices.count; j++) 
878                         seq_printf(seq, "0x%p ",
879                                 tz->trips.active[i].devices.handles[j]);
880                 seq_puts(seq, "\n");
881         }
882
883 end:
884         return 0;
885 }
886
887 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
888 {
889         return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
890 }
891
892 static ssize_t
893 acpi_thermal_write_trip_points (
894         struct file             *file,
895         const char              __user *buffer,
896         size_t                  count,
897         loff_t                  *ppos)
898 {
899         struct seq_file         *m = (struct seq_file *)file->private_data;
900         struct acpi_thermal     *tz = (struct acpi_thermal *)m->private;
901
902         char                    limit_string[65] = {'\0'};
903         int                     num, critical, hot, passive;
904         int                     active[ACPI_THERMAL_MAX_ACTIVE];
905         int                     i = 0;
906
907         ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
908
909         if (!tz || (count > sizeof(limit_string) - 1)) {
910                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
911                 return_VALUE(-EINVAL);
912         }
913         
914         if (copy_from_user(limit_string, buffer, count)) {
915                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
916                 return_VALUE(-EFAULT);
917         }
918         
919         limit_string[count] = '\0';
920
921         num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
922                                 &critical, &hot, &passive,
923                                 &active[0], &active[1], &active[2], &active[3], &active[4],
924                                 &active[5], &active[6], &active[7], &active[8], &active[9]);
925         if(!(num >=5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
926                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
927                 return_VALUE(-EINVAL);
928         }
929
930         tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
931         tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
932         tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
933         for (i = 0; i < num - 3; i++) {
934                 if (!(tz->trips.active[i].flags.valid))
935                         break;
936                 tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
937         }
938         
939         return_VALUE(count);
940 }
941
942
943 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
944 {
945         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
946
947         ACPI_FUNCTION_TRACE("acpi_thermal_cooling_seq_show");
948
949         if (!tz)
950                 goto end;
951
952         if (!tz->flags.cooling_mode) {
953                 seq_puts(seq, "<setting not supported>\n");
954         }
955
956         if ( tz->cooling_mode == ACPI_THERMAL_MODE_CRT )
957                 seq_printf(seq, "cooling mode:  critical\n");
958         else
959                 seq_printf(seq, "cooling mode:  %s\n",
960                         tz->cooling_mode?"passive":"active");
961
962 end:
963         return 0;
964 }
965
966 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
967 {
968         return single_open(file, acpi_thermal_cooling_seq_show,
969                                                         PDE(inode)->data);
970 }
971
972 static ssize_t
973 acpi_thermal_write_cooling_mode (
974         struct file             *file,
975         const char              __user *buffer,
976         size_t                  count,
977         loff_t                  *ppos)
978 {
979         struct seq_file         *m = (struct seq_file *)file->private_data;
980         struct acpi_thermal     *tz = (struct acpi_thermal *)m->private;
981         int                     result = 0;
982         char                    mode_string[12] = {'\0'};
983
984         ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode");
985
986         if (!tz || (count > sizeof(mode_string) - 1))
987                 return_VALUE(-EINVAL);
988
989         if (!tz->flags.cooling_mode)
990                 return_VALUE(-ENODEV);
991
992         if (copy_from_user(mode_string, buffer, count))
993                 return_VALUE(-EFAULT);
994         
995         mode_string[count] = '\0';
996         
997         result = acpi_thermal_set_cooling_mode(tz, 
998                 simple_strtoul(mode_string, NULL, 0));
999         if (result)
1000                 return_VALUE(result);
1001
1002         acpi_thermal_check(tz);
1003
1004         return_VALUE(count);
1005 }
1006
1007
1008 static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
1009 {
1010         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
1011
1012         ACPI_FUNCTION_TRACE("acpi_thermal_polling_seq_show");
1013
1014         if (!tz)
1015                 goto end;
1016
1017         if (!tz->polling_frequency) {
1018                 seq_puts(seq, "<polling disabled>\n");
1019                 goto end;
1020         }
1021
1022         seq_printf(seq, "polling frequency:       %lu seconds\n",
1023                 (tz->polling_frequency / 10));
1024
1025 end:
1026         return 0;
1027 }
1028
1029 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
1030 {
1031         return single_open(file, acpi_thermal_polling_seq_show,
1032                                                         PDE(inode)->data);
1033 }
1034
1035 static ssize_t
1036 acpi_thermal_write_polling (
1037         struct file             *file,
1038         const char              __user *buffer,
1039         size_t                  count,
1040         loff_t                  *ppos)
1041 {
1042         struct seq_file         *m = (struct seq_file *)file->private_data;
1043         struct acpi_thermal     *tz = (struct acpi_thermal *)m->private;
1044         int                     result = 0;
1045         char                    polling_string[12] = {'\0'};
1046         int                     seconds = 0;
1047
1048         ACPI_FUNCTION_TRACE("acpi_thermal_write_polling");
1049
1050         if (!tz || (count > sizeof(polling_string) - 1))
1051                 return_VALUE(-EINVAL);
1052         
1053         if (copy_from_user(polling_string, buffer, count))
1054                 return_VALUE(-EFAULT);
1055         
1056         polling_string[count] = '\0';
1057
1058         seconds = simple_strtoul(polling_string, NULL, 0);
1059         
1060         result = acpi_thermal_set_polling(tz, seconds);
1061         if (result)
1062                 return_VALUE(result);
1063
1064         acpi_thermal_check(tz);
1065
1066         return_VALUE(count);
1067 }
1068
1069
1070 static int
1071 acpi_thermal_add_fs (
1072         struct acpi_device      *device)
1073 {
1074         struct proc_dir_entry   *entry = NULL;
1075
1076         ACPI_FUNCTION_TRACE("acpi_thermal_add_fs");
1077
1078         if (!acpi_device_dir(device)) {
1079                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1080                         acpi_thermal_dir);
1081                 if (!acpi_device_dir(device))
1082                         return_VALUE(-ENODEV);
1083                 acpi_device_dir(device)->owner = THIS_MODULE;
1084         }
1085
1086         /* 'state' [R] */
1087         entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
1088                 S_IRUGO, acpi_device_dir(device));
1089         if (!entry)
1090                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1091                         "Unable to create '%s' fs entry\n",
1092                         ACPI_THERMAL_FILE_STATE));
1093         else {
1094                 entry->proc_fops = &acpi_thermal_state_fops;
1095                 entry->data = acpi_driver_data(device);
1096                 entry->owner = THIS_MODULE;
1097         }
1098
1099         /* 'temperature' [R] */
1100         entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1101                 S_IRUGO, acpi_device_dir(device));
1102         if (!entry)
1103                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1104                         "Unable to create '%s' fs entry\n",
1105                         ACPI_THERMAL_FILE_TEMPERATURE));
1106         else {
1107                 entry->proc_fops = &acpi_thermal_temp_fops;
1108                 entry->data = acpi_driver_data(device);
1109                 entry->owner = THIS_MODULE;
1110         }
1111
1112         /* 'trip_points' [R/W] */
1113         entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1114                 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1115         if (!entry)
1116                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1117                         "Unable to create '%s' fs entry\n",
1118                         ACPI_THERMAL_FILE_TRIP_POINTS));
1119         else {
1120                 entry->proc_fops = &acpi_thermal_trip_fops;
1121                 entry->data = acpi_driver_data(device);
1122                 entry->owner = THIS_MODULE;
1123         }
1124
1125         /* 'cooling_mode' [R/W] */
1126         entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1127                 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1128         if (!entry)
1129                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1130                         "Unable to create '%s' fs entry\n",
1131                         ACPI_THERMAL_FILE_COOLING_MODE));
1132         else {
1133                 entry->proc_fops = &acpi_thermal_cooling_fops;
1134                 entry->data = acpi_driver_data(device);
1135                 entry->owner = THIS_MODULE;
1136         }
1137
1138         /* 'polling_frequency' [R/W] */
1139         entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1140                 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1141         if (!entry)
1142                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1143                         "Unable to create '%s' fs entry\n",
1144                         ACPI_THERMAL_FILE_POLLING_FREQ));
1145         else {
1146                 entry->proc_fops = &acpi_thermal_polling_fops;
1147                 entry->data = acpi_driver_data(device);
1148                 entry->owner = THIS_MODULE;
1149         }
1150
1151         return_VALUE(0);
1152 }
1153
1154
1155 static int
1156 acpi_thermal_remove_fs (
1157         struct acpi_device      *device)
1158 {
1159         ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");
1160
1161         if (acpi_device_dir(device)) {
1162                 remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1163                                   acpi_device_dir(device));
1164                 remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1165                                   acpi_device_dir(device));
1166                 remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1167                                   acpi_device_dir(device));
1168                 remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1169                                   acpi_device_dir(device));
1170                 remove_proc_entry(ACPI_THERMAL_FILE_STATE,
1171                                   acpi_device_dir(device));
1172                 remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
1173                 acpi_device_dir(device) = NULL;
1174         }
1175
1176         return_VALUE(0);
1177 }
1178
1179
1180 /* --------------------------------------------------------------------------
1181                                  Driver Interface
1182    -------------------------------------------------------------------------- */
1183
1184 static void
1185 acpi_thermal_notify (
1186         acpi_handle             handle,
1187         u32                     event,
1188         void                    *data)
1189 {
1190         struct acpi_thermal     *tz = (struct acpi_thermal *) data;
1191         struct acpi_device      *device = NULL;
1192
1193         ACPI_FUNCTION_TRACE("acpi_thermal_notify");
1194
1195         if (!tz)
1196                 return_VOID;
1197
1198         if (acpi_bus_get_device(tz->handle, &device))
1199                 return_VOID;
1200
1201         switch (event) {
1202         case ACPI_THERMAL_NOTIFY_TEMPERATURE:
1203                 acpi_thermal_check(tz);
1204                 break;
1205         case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1206                 acpi_thermal_get_trip_points(tz);
1207                 acpi_thermal_check(tz);
1208                 acpi_bus_generate_event(device, event, 0);
1209                 break;
1210         case ACPI_THERMAL_NOTIFY_DEVICES:
1211                 if (tz->flags.devices)
1212                         acpi_thermal_get_devices(tz);
1213                 acpi_bus_generate_event(device, event, 0);
1214                 break;
1215         default:
1216                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1217                         "Unsupported event [0x%x]\n", event));
1218                 break;
1219         }
1220
1221         return_VOID;
1222 }
1223
1224
1225 static int
1226 acpi_thermal_get_info (
1227         struct acpi_thermal     *tz)
1228 {
1229         int                     result = 0;
1230
1231         ACPI_FUNCTION_TRACE("acpi_thermal_get_info");
1232
1233         if (!tz)
1234                 return_VALUE(-EINVAL);
1235
1236         /* Get temperature [_TMP] (required) */
1237         result = acpi_thermal_get_temperature(tz);
1238         if (result)
1239                 return_VALUE(result);
1240
1241         /* Get trip points [_CRT, _PSV, etc.] (required) */
1242         result = acpi_thermal_get_trip_points(tz);
1243         if (result)
1244                 return_VALUE(result);
1245
1246         /* Set the cooling mode [_SCP] to active cooling (default) */
1247         result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1248         if (!result) 
1249                 tz->flags.cooling_mode = 1;
1250         else { 
1251                 /* Oh,we have not _SCP method.
1252                    Generally show cooling_mode by _ACx, _PSV,spec 12.2*/
1253                 tz->flags.cooling_mode = 0;
1254                 if ( tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
1255                         if ( tz->trips.passive.temperature > tz->trips.active[0].temperature )
1256                                 tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1257                         else 
1258                                 tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1259                 } else if ( !tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
1260                         tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1261                 } else if ( tz->trips.active[0].flags.valid && !tz->trips.passive.flags.valid ) {
1262                         tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1263                 } else {
1264                         /* _ACx and _PSV are optional, but _CRT is required */
1265                         tz->cooling_mode = ACPI_THERMAL_MODE_CRT;
1266                 }
1267         }
1268
1269         /* Get default polling frequency [_TZP] (optional) */
1270         if (tzp)
1271                 tz->polling_frequency = tzp;
1272         else
1273                 acpi_thermal_get_polling_frequency(tz);
1274
1275         /* Get devices in this thermal zone [_TZD] (optional) */
1276         result = acpi_thermal_get_devices(tz);
1277         if (!result)
1278                 tz->flags.devices = 1;
1279
1280         return_VALUE(0);
1281 }
1282
1283
1284 static int
1285 acpi_thermal_add (
1286         struct acpi_device              *device)
1287 {
1288         int                     result = 0;
1289         acpi_status             status = AE_OK;
1290         struct acpi_thermal     *tz = NULL;
1291
1292         ACPI_FUNCTION_TRACE("acpi_thermal_add");
1293
1294         if (!device)
1295                 return_VALUE(-EINVAL);
1296
1297         tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1298         if (!tz)
1299                 return_VALUE(-ENOMEM);
1300         memset(tz, 0, sizeof(struct acpi_thermal));
1301
1302         tz->handle = device->handle;
1303         strcpy(tz->name, device->pnp.bus_id);
1304         strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1305         strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1306         acpi_driver_data(device) = tz;
1307
1308         result = acpi_thermal_get_info(tz);
1309         if (result)
1310                 goto end;
1311
1312         result = acpi_thermal_add_fs(device);
1313         if (result)
1314                 return_VALUE(result);
1315
1316         init_timer(&tz->timer);
1317
1318         acpi_thermal_check(tz);
1319
1320         status = acpi_install_notify_handler(tz->handle,
1321                 ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz);
1322         if (ACPI_FAILURE(status)) {
1323                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1324                         "Error installing notify handler\n"));
1325                 result = -ENODEV;
1326                 goto end;
1327         }
1328
1329         printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1330                 acpi_device_name(device), acpi_device_bid(device),
1331                 KELVIN_TO_CELSIUS(tz->temperature));
1332
1333 end:
1334         if (result) {
1335                 acpi_thermal_remove_fs(device);
1336                 kfree(tz);
1337         }
1338
1339         return_VALUE(result);
1340 }
1341
1342
1343 static int
1344 acpi_thermal_remove (
1345         struct acpi_device      *device,
1346         int                     type)
1347 {
1348         acpi_status             status = AE_OK;
1349         struct acpi_thermal     *tz = NULL;
1350
1351         ACPI_FUNCTION_TRACE("acpi_thermal_remove");
1352
1353         if (!device || !acpi_driver_data(device))
1354                 return_VALUE(-EINVAL);
1355
1356         tz = (struct acpi_thermal *) acpi_driver_data(device);
1357
1358         /* avoid timer adding new defer task */
1359         tz->zombie = 1;
1360         /* wait for running timer (on other CPUs) finish */
1361         del_timer_sync(&(tz->timer));
1362         /* synchronize deferred task */
1363         acpi_os_wait_events_complete(NULL);
1364         /* deferred task may reinsert timer */
1365         del_timer_sync(&(tz->timer));
1366
1367         status = acpi_remove_notify_handler(tz->handle,
1368                 ACPI_DEVICE_NOTIFY, acpi_thermal_notify);
1369         if (ACPI_FAILURE(status))
1370                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1371                         "Error removing notify handler\n"));
1372
1373         /* Terminate policy */
1374         if (tz->trips.passive.flags.valid
1375                 && tz->trips.passive.flags.enabled) {
1376                 tz->trips.passive.flags.enabled = 0;
1377                 acpi_thermal_passive(tz);
1378         }
1379         if (tz->trips.active[0].flags.valid
1380                 && tz->trips.active[0].flags.enabled) {
1381                 tz->trips.active[0].flags.enabled = 0;
1382                 acpi_thermal_active(tz);
1383         }
1384
1385         acpi_thermal_remove_fs(device);
1386
1387         kfree(tz);
1388         return_VALUE(0);
1389 }
1390
1391
1392 static int __init
1393 acpi_thermal_init (void)
1394 {
1395         int                     result = 0;
1396
1397         ACPI_FUNCTION_TRACE("acpi_thermal_init");
1398
1399         acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
1400         if (!acpi_thermal_dir)
1401                 return_VALUE(-ENODEV);
1402         acpi_thermal_dir->owner = THIS_MODULE;
1403
1404         result = acpi_bus_register_driver(&acpi_thermal_driver);
1405         if (result < 0) {
1406                 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1407                 return_VALUE(-ENODEV);
1408         }
1409
1410         return_VALUE(0);
1411 }
1412
1413
1414 static void __exit
1415 acpi_thermal_exit (void)
1416 {
1417         ACPI_FUNCTION_TRACE("acpi_thermal_exit");
1418
1419         acpi_bus_unregister_driver(&acpi_thermal_driver);
1420
1421         remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1422
1423         return_VOID;
1424 }
1425
1426
1427 module_init(acpi_thermal_init);
1428 module_exit(acpi_thermal_exit);