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