VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[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_PATH_POWEROFF      "/sbin/poweroff"
64
65 #define ACPI_THERMAL_MAX_ACTIVE 10
66
67 #define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
68 #define CELSIUS_TO_KELVIN(t)    ((t+273)*10)
69
70 #define _COMPONENT              ACPI_THERMAL_COMPONENT
71 ACPI_MODULE_NAME                ("acpi_thermal")
72
73 MODULE_AUTHOR("Paul Diefenbaugh");
74 MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
75 MODULE_LICENSE("GPL");
76
77 static int tzp;
78 MODULE_PARM(tzp, "i");
79 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
80
81
82 static int acpi_thermal_add (struct acpi_device *device);
83 static int acpi_thermal_remove (struct acpi_device *device, int type);
84 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
85 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
86 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
87 static ssize_t acpi_thermal_write_trip_points (struct file*,const char __user *,size_t,loff_t *);
88 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
89 static ssize_t acpi_thermal_write_cooling_mode (struct file*,const char __user *,size_t,loff_t *);
90 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
91 static ssize_t acpi_thermal_write_polling(struct file*,const char __user *,size_t,loff_t *);
92
93 static struct acpi_driver acpi_thermal_driver = {
94         .name =         ACPI_THERMAL_DRIVER_NAME,
95         .class =        ACPI_THERMAL_CLASS,
96         .ids =          ACPI_THERMAL_HID,
97         .ops =          {
98                                 .add =          acpi_thermal_add,
99                                 .remove =       acpi_thermal_remove,
100                         },
101 };
102
103 struct acpi_thermal_state {
104         u8                      critical:1;
105         u8                      hot:1;
106         u8                      passive:1;
107         u8                      active:1;
108         u8                      reserved:4;
109         int                     active_index;
110 };
111
112 struct acpi_thermal_state_flags {
113         u8                      valid:1;
114         u8                      enabled:1;
115         u8                      reserved:6;
116 };
117
118 struct acpi_thermal_critical {
119         struct acpi_thermal_state_flags flags;
120         unsigned long           temperature;
121 };
122
123 struct acpi_thermal_hot {
124         struct acpi_thermal_state_flags flags;
125         unsigned long           temperature;
126 };
127
128 struct acpi_thermal_passive {
129         struct acpi_thermal_state_flags flags;
130         unsigned long           temperature;
131         unsigned long           tc1;
132         unsigned long           tc2;
133         unsigned long           tsp;
134         struct acpi_handle_list devices;
135 };
136
137 struct acpi_thermal_active {
138         struct acpi_thermal_state_flags flags;
139         unsigned long           temperature;
140         struct acpi_handle_list devices;
141 };
142
143 struct acpi_thermal_trips {
144         struct acpi_thermal_critical critical;
145         struct acpi_thermal_hot hot;
146         struct acpi_thermal_passive passive;
147         struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
148 };
149
150 struct acpi_thermal_flags {
151         u8                      cooling_mode:1;         /* _SCP */
152         u8                      devices:1;              /* _TZD */
153         u8                      reserved:6;
154 };
155
156 struct acpi_thermal {
157         acpi_handle             handle;
158         acpi_bus_id             name;
159         unsigned long           temperature;
160         unsigned long           last_temperature;
161         unsigned long           polling_frequency;
162         u8                      cooling_mode;
163         struct acpi_thermal_flags flags;
164         struct acpi_thermal_state state;
165         struct acpi_thermal_trips trips;
166         struct acpi_handle_list devices;
167         struct timer_list       timer;
168 };
169
170 static struct file_operations acpi_thermal_state_fops = {
171         .open           = acpi_thermal_state_open_fs,
172         .read           = seq_read,
173         .llseek         = seq_lseek,
174         .release        = single_release,
175 };
176
177 static struct file_operations acpi_thermal_temp_fops = {
178         .open           = acpi_thermal_temp_open_fs,
179         .read           = seq_read,
180         .llseek         = seq_lseek,
181         .release        = single_release,
182 };
183
184 static struct file_operations acpi_thermal_trip_fops = {
185         .open           = acpi_thermal_trip_open_fs,
186         .read           = seq_read,
187         .write          = acpi_thermal_write_trip_points,
188         .llseek         = seq_lseek,
189         .release        = single_release,
190 };
191
192 static struct file_operations acpi_thermal_cooling_fops = {
193         .open           = acpi_thermal_cooling_open_fs,
194         .read           = seq_read,
195         .write          = acpi_thermal_write_cooling_mode,
196         .llseek         = seq_lseek,
197         .release        = single_release,
198 };
199
200 static struct file_operations acpi_thermal_polling_fops = {
201         .open           = acpi_thermal_polling_open_fs,
202         .read           = seq_read,
203         .write          = acpi_thermal_write_polling,
204         .llseek         = seq_lseek,
205         .release        = single_release,
206 };
207
208 /* --------------------------------------------------------------------------
209                              Thermal Zone Management
210    -------------------------------------------------------------------------- */
211
212 static int
213 acpi_thermal_get_temperature (
214         struct acpi_thermal *tz)
215 {
216         acpi_status             status = AE_OK;
217
218         ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature");
219
220         if (!tz)
221                 return_VALUE(-EINVAL);
222
223         tz->last_temperature = tz->temperature;
224
225         status = acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
226         if (ACPI_FAILURE(status))
227                 return -ENODEV;
228
229         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature));
230
231         return_VALUE(0);
232 }
233
234
235 static int
236 acpi_thermal_get_polling_frequency (
237         struct acpi_thermal     *tz)
238 {
239         acpi_status             status = AE_OK;
240
241         ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency");
242
243         if (!tz)
244                 return_VALUE(-EINVAL);
245
246         status = acpi_evaluate_integer(tz->handle, "_TZP", NULL, &tz->polling_frequency);
247         if (ACPI_FAILURE(status))
248                 return_VALUE(-ENODEV);
249
250         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency));
251
252         return_VALUE(0);
253 }
254
255
256 static int
257 acpi_thermal_set_polling (
258         struct acpi_thermal     *tz,
259         int                     seconds)
260 {
261         ACPI_FUNCTION_TRACE("acpi_thermal_set_polling");
262
263         if (!tz)
264                 return_VALUE(-EINVAL);
265
266         tz->polling_frequency = seconds * 10;   /* Convert value to deci-seconds */
267
268         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", tz->polling_frequency));
269
270         return_VALUE(0);
271 }
272
273
274 static int
275 acpi_thermal_set_cooling_mode (
276         struct acpi_thermal     *tz,
277         int                     mode)
278 {
279         acpi_status             status = AE_OK;
280         union acpi_object       arg0 = {ACPI_TYPE_INTEGER};
281         struct acpi_object_list arg_list = {1, &arg0};
282         acpi_handle             handle = NULL;
283
284         ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode");
285
286         if (!tz)
287                 return_VALUE(-EINVAL);
288
289         status = acpi_get_handle(tz->handle, "_SCP", &handle);
290         if (ACPI_FAILURE(status)) {
291                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
292                 status = acpi_get_handle(tz->handle, "_PSV", &handle);
293                 if(!ACPI_FAILURE(status)) {
294                         tz->cooling_mode = 1;
295                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", 
296                                 mode?"passive":"active"));
297                         return_VALUE(0);
298                 }
299                 return_VALUE(-ENODEV);
300         }
301
302         arg0.integer.value = mode;
303
304         status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
305         if (ACPI_FAILURE(status))
306                 return_VALUE(-ENODEV);
307
308         tz->cooling_mode = mode;
309
310         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n", 
311                 mode?"passive":"active"));
312
313         return_VALUE(0);
314 }
315
316
317 static int
318 acpi_thermal_get_trip_points (
319         struct acpi_thermal *tz)
320 {
321         acpi_status             status = AE_OK;
322         int                     i = 0;
323
324         ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points");
325
326         if (!tz)
327                 return_VALUE(-EINVAL);
328
329         /* Critical Shutdown (required) */
330
331         status = acpi_evaluate_integer(tz->handle, "_CRT", NULL, 
332                 &tz->trips.critical.temperature);
333         if (ACPI_FAILURE(status)) {
334                 tz->trips.critical.flags.valid = 0;
335                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
336                 return -ENODEV;
337         }
338         else {
339                 tz->trips.critical.flags.valid = 1;
340                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%lu]\n", tz->trips.critical.temperature));
341         }
342
343         /* Critical Sleep (optional) */
344
345         status = acpi_evaluate_integer(tz->handle, "_HOT", NULL, &tz->trips.hot.temperature);
346         if (ACPI_FAILURE(status)) {
347                 tz->trips.hot.flags.valid = 0;
348                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
349         }
350         else {
351                 tz->trips.hot.flags.valid = 1;
352                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", tz->trips.hot.temperature));
353         }
354
355         /* Passive: Processors (optional) */
356
357         status = acpi_evaluate_integer(tz->handle, "_PSV", NULL, &tz->trips.passive.temperature);
358         if (ACPI_FAILURE(status)) {
359                 tz->trips.passive.flags.valid = 0;
360                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
361         }
362         else {
363                 tz->trips.passive.flags.valid = 1;
364
365                 status = acpi_evaluate_integer(tz->handle, "_TC1", NULL, &tz->trips.passive.tc1);
366                 if (ACPI_FAILURE(status))
367                         tz->trips.passive.flags.valid = 0;
368
369                 status = acpi_evaluate_integer(tz->handle, "_TC2", NULL, &tz->trips.passive.tc2);
370                 if (ACPI_FAILURE(status))
371                         tz->trips.passive.flags.valid = 0;
372
373                 status = acpi_evaluate_integer(tz->handle, "_TSP", NULL, &tz->trips.passive.tsp);
374                 if (ACPI_FAILURE(status))
375                         tz->trips.passive.flags.valid = 0;
376
377                 status = acpi_evaluate_reference(tz->handle, "_PSL", NULL, &tz->trips.passive.devices);
378                 if (ACPI_FAILURE(status))
379                         tz->trips.passive.flags.valid = 0;
380
381                 if (!tz->trips.passive.flags.valid)
382                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid passive threshold\n"));
383                 else
384                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%lu]\n", tz->trips.passive.temperature));
385         }
386
387         /* Active: Fans, etc. (optional) */
388
389         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
390
391                 char name[5] = {'_','A','C',('0'+i),'\0'};
392
393                 status = acpi_evaluate_integer(tz->handle, name, NULL, &tz->trips.active[i].temperature);
394                 if (ACPI_FAILURE(status))
395                         break;
396
397                 name[2] = 'L';
398                 status = acpi_evaluate_reference(tz->handle, name, NULL, &tz->trips.active[i].devices);
399                 if (ACPI_SUCCESS(status)) {
400                         tz->trips.active[i].flags.valid = 1;
401                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%lu]\n", i, tz->trips.active[i].temperature));
402                 }
403                 else
404                         ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i));
405         }
406
407         return_VALUE(0);
408 }
409
410
411 static int
412 acpi_thermal_get_devices (
413         struct acpi_thermal     *tz)
414 {
415         acpi_status             status = AE_OK;
416
417         ACPI_FUNCTION_TRACE("acpi_thermal_get_devices");
418
419         if (!tz)
420                 return_VALUE(-EINVAL);
421
422         status = acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
423         if (ACPI_FAILURE(status))
424                 return_VALUE(-ENODEV);
425
426         return_VALUE(0);
427 }
428
429
430 static int
431 acpi_thermal_call_usermode (
432         char                    *path)
433 {
434         char                    *argv[2] = {NULL, NULL};
435         char                    *envp[3] = {NULL, NULL, NULL};
436
437         ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode");
438
439         if (!path)
440                 return_VALUE(-EINVAL);
441
442         argv[0] = path;
443
444         /* minimal command environment */
445         envp[0] = "HOME=/";
446         envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
447         
448         call_usermodehelper(argv[0], argv, envp, 0);
449
450         return_VALUE(0);
451 }
452
453
454 static int
455 acpi_thermal_critical (
456         struct acpi_thermal     *tz)
457 {
458         int                     result = 0;
459         struct acpi_device      *device = NULL;
460
461         ACPI_FUNCTION_TRACE("acpi_thermal_critical");
462
463         if (!tz || !tz->trips.critical.flags.valid)
464                 return_VALUE(-EINVAL);
465
466         if (tz->temperature >= tz->trips.critical.temperature) {
467                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
468                 tz->trips.critical.flags.enabled = 1;
469         }
470         else if (tz->trips.critical.flags.enabled)
471                 tz->trips.critical.flags.enabled = 0;
472
473         result = acpi_bus_get_device(tz->handle, &device);
474         if (result)
475                 return_VALUE(result);
476
477         printk(KERN_EMERG "Critical temperature reached (%ld C), shutting down.\n", KELVIN_TO_CELSIUS(tz->temperature));
478         acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled);
479
480         acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
481
482         return_VALUE(0);
483 }
484
485
486 static int
487 acpi_thermal_hot (
488         struct acpi_thermal     *tz)
489 {
490         int                     result = 0;
491         struct acpi_device      *device = NULL;
492
493         ACPI_FUNCTION_TRACE("acpi_thermal_hot");
494
495         if (!tz || !tz->trips.hot.flags.valid)
496                 return_VALUE(-EINVAL);
497
498         if (tz->temperature >= tz->trips.hot.temperature) {
499                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
500                 tz->trips.hot.flags.enabled = 1;
501         }
502         else if (tz->trips.hot.flags.enabled)
503                 tz->trips.hot.flags.enabled = 0;
504
505         result = acpi_bus_get_device(tz->handle, &device);
506         if (result)
507                 return_VALUE(result);
508
509         acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT, tz->trips.hot.flags.enabled);
510
511         /* TBD: Call user-mode "sleep(S4)" function */
512
513         return_VALUE(0);
514 }
515
516
517 static int
518 acpi_thermal_passive (
519         struct acpi_thermal     *tz)
520 {
521         int                     result = 0;
522         struct acpi_thermal_passive *passive = NULL;
523         int                     trend = 0;
524         int                     i = 0;
525
526         ACPI_FUNCTION_TRACE("acpi_thermal_passive");
527
528         if (!tz || !tz->trips.passive.flags.valid)
529                 return_VALUE(-EINVAL);
530
531         passive = &(tz->trips.passive);
532
533         /*
534          * Above Trip?
535          * -----------
536          * Calculate the thermal trend (using the passive cooling equation)
537          * and modify the performance limit for all passive cooling devices
538          * accordingly.  Note that we assume symmetry.
539          */
540         if (tz->temperature >= passive->temperature) {
541                 trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
542                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
543                         "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", 
544                         trend, passive->tc1, tz->temperature, 
545                         tz->last_temperature, passive->tc2, 
546                         tz->temperature, passive->temperature));
547                 tz->trips.passive.flags.enabled = 1;
548                 /* Heating up? */
549                 if (trend > 0)
550                         for (i=0; i<passive->devices.count; i++)
551                                 acpi_processor_set_thermal_limit(
552                                         passive->devices.handles[i], 
553                                         ACPI_PROCESSOR_LIMIT_INCREMENT);
554                 /* Cooling off? */
555                 else if (trend < 0)
556                         for (i=0; i<passive->devices.count; i++)
557                                 acpi_processor_set_thermal_limit(
558                                         passive->devices.handles[i], 
559                                         ACPI_PROCESSOR_LIMIT_DECREMENT);
560         }
561
562         /*
563          * Below Trip?
564          * -----------
565          * Implement passive cooling hysteresis to slowly increase performance
566          * and avoid thrashing around the passive trip point.  Note that we
567          * assume symmetry.
568          */
569         else if (tz->trips.passive.flags.enabled) {
570                 for (i=0; i<passive->devices.count; i++)
571                         result = acpi_processor_set_thermal_limit(
572                                 passive->devices.handles[i], 
573                                 ACPI_PROCESSOR_LIMIT_DECREMENT);
574                 if (result == 1) {
575                         tz->trips.passive.flags.enabled = 0;
576                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
577                                 "Disabling passive cooling (zone is cool)\n"));
578                 }
579         }
580
581         return_VALUE(0);
582 }
583
584
585 static int
586 acpi_thermal_active (
587         struct acpi_thermal     *tz)
588 {
589         int                     result = 0;
590         struct acpi_thermal_active *active = NULL;
591         int                     i = 0;
592         int                     j = 0;
593         unsigned long           maxtemp = 0;
594
595         ACPI_FUNCTION_TRACE("acpi_thermal_active");
596
597         if (!tz)
598                 return_VALUE(-EINVAL);
599
600         for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
601
602                 active = &(tz->trips.active[i]);
603                 if (!active || !active->flags.valid)
604                         break;
605
606                 /*
607                  * Above Threshold?
608                  * ----------------
609                  * If not already enabled, turn ON all cooling devices
610                  * associated with this active threshold.
611                  */
612                 if (tz->temperature >= active->temperature) {
613                         if (active->temperature > maxtemp)
614                                 tz->state.active_index = i, maxtemp = active->temperature;
615                         if (!active->flags.enabled) {
616                                 for (j = 0; j < active->devices.count; j++) {
617                                         result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0);
618                                         if (result) {
619                                                 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'on'\n", active->devices.handles[j]));
620                                                 continue;
621                                         }
622                                         active->flags.enabled = 1;
623                                         ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'on'\n", active->devices.handles[j]));
624                                 }
625                         }
626                 }
627                 /*
628                  * Below Threshold?
629                  * ----------------
630                  * Turn OFF all cooling devices associated with this
631                  * threshold.
632                  */
633                 else if (active->flags.enabled) {
634                         for (j = 0; j < active->devices.count; j++) {
635                                 result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D3);
636                                 if (result) {
637                                         ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'off'\n", active->devices.handles[j]));
638                                         continue;
639                                 }
640                                 active->flags.enabled = 0;
641                                 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'off'\n", active->devices.handles[j]));
642                         }
643                 }
644         }
645
646         return_VALUE(0);
647 }
648
649
650 static void acpi_thermal_check (void *context);
651
652 static void
653 acpi_thermal_run (
654         unsigned long           data)
655 {
656         acpi_os_queue_for_execution(OSD_PRIORITY_GPE,  acpi_thermal_check, (void *) data);
657 }
658
659
660 static void
661 acpi_thermal_check (
662         void                    *data)
663 {
664         int                     result = 0;
665         struct acpi_thermal     *tz = (struct acpi_thermal *) data;
666         unsigned long           sleep_time = 0;
667         int                     i = 0;
668         struct acpi_thermal_state state = tz->state;
669
670         ACPI_FUNCTION_TRACE("acpi_thermal_check");
671
672         if (!tz) {
673                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
674                 return_VOID;
675         }
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[25] = {'\0'};
903         int                     critical, hot, passive, active0, active1;
904
905         ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
906
907         if (!tz || (count > sizeof(limit_string) - 1)) {
908                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
909                 return_VALUE(-EINVAL);
910         }
911         
912         if (copy_from_user(limit_string, buffer, count)) {
913                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
914                 return_VALUE(-EFAULT);
915         }
916         
917         limit_string[count] = '\0';
918
919         if (sscanf(limit_string, "%d:%d:%d:%d:%d", &critical, &hot, &passive, &active0, &active1) != 5) {
920                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
921                 return_VALUE(-EINVAL);
922         }
923
924         tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
925         tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
926         tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
927         tz->trips.active[0].temperature = CELSIUS_TO_KELVIN(active0);
928         tz->trips.active[1].temperature = CELSIUS_TO_KELVIN(active1);
929         
930         return_VALUE(count);
931 }
932
933
934 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
935 {
936         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
937
938         ACPI_FUNCTION_TRACE("acpi_thermal_cooling_seq_show");
939
940         if (!tz)
941                 goto end;
942
943         if (!tz->flags.cooling_mode) {
944                 seq_puts(seq, "<not supported>\n");
945                 goto end;
946         }
947
948         seq_printf(seq, "cooling mode:            %s\n",
949                 tz->cooling_mode?"passive":"active");
950
951 end:
952         return 0;
953 }
954
955 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
956 {
957         return single_open(file, acpi_thermal_cooling_seq_show,
958                                                         PDE(inode)->data);
959 }
960
961 static ssize_t
962 acpi_thermal_write_cooling_mode (
963         struct file             *file,
964         const char              __user *buffer,
965         size_t                  count,
966         loff_t                  *ppos)
967 {
968         struct seq_file         *m = (struct seq_file *)file->private_data;
969         struct acpi_thermal     *tz = (struct acpi_thermal *)m->private;
970         int                     result = 0;
971         char                    mode_string[12] = {'\0'};
972
973         ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode");
974
975         if (!tz || (count > sizeof(mode_string) - 1))
976                 return_VALUE(-EINVAL);
977
978         if (!tz->flags.cooling_mode)
979                 return_VALUE(-ENODEV);
980
981         if (copy_from_user(mode_string, buffer, count))
982                 return_VALUE(-EFAULT);
983         
984         mode_string[count] = '\0';
985         
986         result = acpi_thermal_set_cooling_mode(tz, 
987                 simple_strtoul(mode_string, NULL, 0));
988         if (result)
989                 return_VALUE(result);
990
991         return_VALUE(count);
992 }
993
994
995 static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
996 {
997         struct acpi_thermal     *tz = (struct acpi_thermal *)seq->private;
998
999         ACPI_FUNCTION_TRACE("acpi_thermal_polling_seq_show");
1000
1001         if (!tz)
1002                 goto end;
1003
1004         if (!tz->polling_frequency) {
1005                 seq_puts(seq, "<polling disabled>\n");
1006                 goto end;
1007         }
1008
1009         seq_printf(seq, "polling frequency:       %lu seconds\n",
1010                 (tz->polling_frequency / 10));
1011
1012 end:
1013         return 0;
1014 }
1015
1016 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
1017 {
1018         return single_open(file, acpi_thermal_polling_seq_show,
1019                                                         PDE(inode)->data);
1020 }
1021
1022 static ssize_t
1023 acpi_thermal_write_polling (
1024         struct file             *file,
1025         const char              __user *buffer,
1026         size_t                  count,
1027         loff_t                  *ppos)
1028 {
1029         struct seq_file         *m = (struct seq_file *)file->private_data;
1030         struct acpi_thermal     *tz = (struct acpi_thermal *)m->private;
1031         int                     result = 0;
1032         char                    polling_string[12] = {'\0'};
1033         int                     seconds = 0;
1034
1035         ACPI_FUNCTION_TRACE("acpi_thermal_write_polling");
1036
1037         if (!tz || (count > sizeof(polling_string) - 1))
1038                 return_VALUE(-EINVAL);
1039         
1040         if (copy_from_user(polling_string, buffer, count))
1041                 return_VALUE(-EFAULT);
1042         
1043         polling_string[count] = '\0';
1044
1045         seconds = simple_strtoul(polling_string, NULL, 0);
1046         
1047         result = acpi_thermal_set_polling(tz, seconds);
1048         if (result)
1049                 return_VALUE(result);
1050
1051         acpi_thermal_check(tz);
1052
1053         return_VALUE(count);
1054 }
1055
1056
1057 static int
1058 acpi_thermal_add_fs (
1059         struct acpi_device      *device)
1060 {
1061         struct proc_dir_entry   *entry = NULL;
1062
1063         ACPI_FUNCTION_TRACE("acpi_thermal_add_fs");
1064
1065         if (!acpi_device_dir(device)) {
1066                 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1067                         acpi_thermal_dir);
1068                 if (!acpi_device_dir(device))
1069                         return_VALUE(-ENODEV);
1070                 acpi_device_dir(device)->owner = THIS_MODULE;
1071         }
1072
1073         /* 'state' [R] */
1074         entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
1075                 S_IRUGO, acpi_device_dir(device));
1076         if (!entry)
1077                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1078                         "Unable to create '%s' fs entry\n",
1079                         ACPI_THERMAL_FILE_STATE));
1080         else {
1081                 entry->proc_fops = &acpi_thermal_state_fops;
1082                 entry->data = acpi_driver_data(device);
1083                 entry->owner = THIS_MODULE;
1084         }
1085
1086         /* 'temperature' [R] */
1087         entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
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_TEMPERATURE));
1093         else {
1094                 entry->proc_fops = &acpi_thermal_temp_fops;
1095                 entry->data = acpi_driver_data(device);
1096                 entry->owner = THIS_MODULE;
1097         }
1098
1099         /* 'trip_points' [R/W] */
1100         entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1101                 S_IFREG|S_IRUGO|S_IWUSR, 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_TRIP_POINTS));
1106         else {
1107                 entry->proc_fops = &acpi_thermal_trip_fops;
1108                 entry->data = acpi_driver_data(device);
1109                 entry->owner = THIS_MODULE;
1110         }
1111
1112         /* 'cooling_mode' [R/W] */
1113         entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
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_COOLING_MODE));
1119         else {
1120                 entry->proc_fops = &acpi_thermal_cooling_fops;
1121                 entry->data = acpi_driver_data(device);
1122                 entry->owner = THIS_MODULE;
1123         }
1124
1125         /* 'polling_frequency' [R/W] */
1126         entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
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_POLLING_FREQ));
1132         else {
1133                 entry->proc_fops = &acpi_thermal_polling_fops;
1134                 entry->data = acpi_driver_data(device);
1135                 entry->owner = THIS_MODULE;
1136         }
1137
1138         return_VALUE(0);
1139 }
1140
1141
1142 static int
1143 acpi_thermal_remove_fs (
1144         struct acpi_device      *device)
1145 {
1146         ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");
1147
1148         if (acpi_device_dir(device)) {
1149                 remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1150                                   acpi_device_dir(device));
1151                 remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1152                                   acpi_device_dir(device));
1153                 remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1154                                   acpi_device_dir(device));
1155                 remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1156                                   acpi_device_dir(device));
1157                 remove_proc_entry(ACPI_THERMAL_FILE_STATE,
1158                                   acpi_device_dir(device));
1159                 remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
1160                 acpi_device_dir(device) = NULL;
1161         }
1162
1163         return_VALUE(0);
1164 }
1165
1166
1167 /* --------------------------------------------------------------------------
1168                                  Driver Interface
1169    -------------------------------------------------------------------------- */
1170
1171 static void
1172 acpi_thermal_notify (
1173         acpi_handle             handle,
1174         u32                     event,
1175         void                    *data)
1176 {
1177         struct acpi_thermal     *tz = (struct acpi_thermal *) data;
1178         struct acpi_device      *device = NULL;
1179
1180         ACPI_FUNCTION_TRACE("acpi_thermal_notify");
1181
1182         if (!tz)
1183                 return_VOID;
1184
1185         if (acpi_bus_get_device(tz->handle, &device))
1186                 return_VOID;
1187
1188         switch (event) {
1189         case ACPI_THERMAL_NOTIFY_TEMPERATURE:
1190                 acpi_thermal_check(tz);
1191                 break;
1192         case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1193                 acpi_thermal_get_trip_points(tz);
1194                 acpi_thermal_check(tz);
1195                 acpi_bus_generate_event(device, event, 0);
1196                 break;
1197         case ACPI_THERMAL_NOTIFY_DEVICES:
1198                 if (tz->flags.devices)
1199                         acpi_thermal_get_devices(tz);
1200                 acpi_bus_generate_event(device, event, 0);
1201                 break;
1202         default:
1203                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1204                         "Unsupported event [0x%x]\n", event));
1205                 break;
1206         }
1207
1208         return_VOID;
1209 }
1210
1211
1212 static int
1213 acpi_thermal_get_info (
1214         struct acpi_thermal     *tz)
1215 {
1216         int                     result = 0;
1217
1218         ACPI_FUNCTION_TRACE("acpi_thermal_get_info");
1219
1220         if (!tz)
1221                 return_VALUE(-EINVAL);
1222
1223         /* Get temperature [_TMP] (required) */
1224         result = acpi_thermal_get_temperature(tz);
1225         if (result)
1226                 return_VALUE(result);
1227
1228         /* Set the cooling mode [_SCP] to active cooling (default) */
1229         result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1230         if (!result)
1231                 tz->flags.cooling_mode = 1;
1232
1233         /* Get trip points [_CRT, _PSV, etc.] (required) */
1234         result = acpi_thermal_get_trip_points(tz);
1235         if (result)
1236                 return_VALUE(result);
1237
1238         /* Get default polling frequency [_TZP] (optional) */
1239         if (tzp)
1240                 tz->polling_frequency = tzp;
1241         else
1242                 acpi_thermal_get_polling_frequency(tz);
1243
1244         /* Get devices in this thermal zone [_TZD] (optional) */
1245         result = acpi_thermal_get_devices(tz);
1246         if (!result)
1247                 tz->flags.devices = 1;
1248
1249         return_VALUE(0);
1250 }
1251
1252
1253 static int
1254 acpi_thermal_add (
1255         struct acpi_device              *device)
1256 {
1257         int                     result = 0;
1258         acpi_status             status = AE_OK;
1259         struct acpi_thermal     *tz = NULL;
1260
1261         ACPI_FUNCTION_TRACE("acpi_thermal_add");
1262
1263         if (!device)
1264                 return_VALUE(-EINVAL);
1265
1266         tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1267         if (!tz)
1268                 return_VALUE(-ENOMEM);
1269         memset(tz, 0, sizeof(struct acpi_thermal));
1270
1271         tz->handle = device->handle;
1272         strcpy(tz->name, device->pnp.bus_id);
1273         strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1274         strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1275         acpi_driver_data(device) = tz;
1276
1277         result = acpi_thermal_get_info(tz);
1278         if (result)
1279                 goto end;
1280
1281         result = acpi_thermal_add_fs(device);
1282         if (result)
1283                 return_VALUE(result);
1284
1285         init_timer(&tz->timer);
1286
1287         acpi_thermal_check(tz);
1288
1289         status = acpi_install_notify_handler(tz->handle,
1290                 ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz);
1291         if (ACPI_FAILURE(status)) {
1292                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1293                         "Error installing notify handler\n"));
1294                 result = -ENODEV;
1295                 goto end;
1296         }
1297
1298         printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1299                 acpi_device_name(device), acpi_device_bid(device),
1300                 KELVIN_TO_CELSIUS(tz->temperature));
1301
1302 end:
1303         if (result) {
1304                 acpi_thermal_remove_fs(device);
1305                 kfree(tz);
1306         }
1307
1308         return_VALUE(result);
1309 }
1310
1311
1312 static int
1313 acpi_thermal_remove (
1314         struct acpi_device      *device,
1315         int                     type)
1316 {
1317         acpi_status             status = AE_OK;
1318         struct acpi_thermal     *tz = NULL;
1319
1320         ACPI_FUNCTION_TRACE("acpi_thermal_remove");
1321
1322         if (!device || !acpi_driver_data(device))
1323                 return_VALUE(-EINVAL);
1324
1325         tz = (struct acpi_thermal *) acpi_driver_data(device);
1326
1327         if (timer_pending(&(tz->timer)))
1328                 del_timer(&(tz->timer));
1329
1330         status = acpi_remove_notify_handler(tz->handle,
1331                 ACPI_DEVICE_NOTIFY, acpi_thermal_notify);
1332         if (ACPI_FAILURE(status))
1333                 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1334                         "Error removing notify handler\n"));
1335
1336         /* Terminate policy */
1337         if (tz->trips.passive.flags.valid
1338                 && tz->trips.passive.flags.enabled) {
1339                 tz->trips.passive.flags.enabled = 0;
1340                 acpi_thermal_passive(tz);
1341         }
1342         if (tz->trips.active[0].flags.valid
1343                 && tz->trips.active[0].flags.enabled) {
1344                 tz->trips.active[0].flags.enabled = 0;
1345                 acpi_thermal_active(tz);
1346         }
1347
1348         acpi_thermal_remove_fs(device);
1349
1350         return_VALUE(0);
1351 }
1352
1353
1354 static int __init
1355 acpi_thermal_init (void)
1356 {
1357         int                     result = 0;
1358
1359         ACPI_FUNCTION_TRACE("acpi_thermal_init");
1360
1361         acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
1362         if (!acpi_thermal_dir)
1363                 return_VALUE(-ENODEV);
1364         acpi_thermal_dir->owner = THIS_MODULE;
1365
1366         result = acpi_bus_register_driver(&acpi_thermal_driver);
1367         if (result < 0) {
1368                 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1369                 return_VALUE(-ENODEV);
1370         }
1371
1372         return_VALUE(0);
1373 }
1374
1375
1376 static void __exit
1377 acpi_thermal_exit (void)
1378 {
1379         ACPI_FUNCTION_TRACE("acpi_thermal_exit");
1380
1381         acpi_bus_unregister_driver(&acpi_thermal_driver);
1382
1383         remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1384
1385         return_VOID;
1386 }
1387
1388
1389 module_init(acpi_thermal_init);
1390 module_exit(acpi_thermal_exit);