MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / acpi / thermal.c
blob05388672d41a03cd18737358ce23eb8a819d1664
1 /*
2 * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 * This driver fully implements the ACPI thermal policy as described in the
26 * ACPI 2.0 Specification.
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.
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>
44 #include <acpi/acpi_bus.h>
45 #include <acpi/acpi_drivers.h>
47 #define ACPI_THERMAL_COMPONENT 0x04000000
48 #define ACPI_THERMAL_CLASS "thermal_zone"
49 #define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver"
50 #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
51 #define ACPI_THERMAL_FILE_STATE "state"
52 #define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
53 #define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points"
54 #define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode"
55 #define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency"
56 #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
57 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
58 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
59 #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
60 #define ACPI_THERMAL_NOTIFY_HOT 0xF1
61 #define ACPI_THERMAL_MODE_ACTIVE 0x00
62 #define ACPI_THERMAL_MODE_PASSIVE 0x01
63 #define ACPI_THERMAL_MODE_CRT 0xff
64 #define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
66 #define ACPI_THERMAL_MAX_ACTIVE 10
68 #define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
69 #define CELSIUS_TO_KELVIN(t) ((t+273)*10)
71 #define _COMPONENT ACPI_THERMAL_COMPONENT
72 ACPI_MODULE_NAME ("acpi_thermal")
74 MODULE_AUTHOR("Paul Diefenbaugh");
75 MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
76 MODULE_LICENSE("GPL");
78 static int tzp;
79 MODULE_PARM(tzp, "i");
80 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
83 static int acpi_thermal_add (struct acpi_device *device);
84 static int acpi_thermal_remove (struct acpi_device *device, int type);
85 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
86 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
87 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
88 static ssize_t acpi_thermal_write_trip_points (struct file*,const char __user *,size_t,loff_t *);
89 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
90 static ssize_t acpi_thermal_write_cooling_mode (struct file*,const char __user *,size_t,loff_t *);
91 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
92 static ssize_t acpi_thermal_write_polling(struct file*,const char __user *,size_t,loff_t *);
94 static struct acpi_driver acpi_thermal_driver = {
95 .name = ACPI_THERMAL_DRIVER_NAME,
96 .class = ACPI_THERMAL_CLASS,
97 .ids = ACPI_THERMAL_HID,
98 .ops = {
99 .add = acpi_thermal_add,
100 .remove = acpi_thermal_remove,
104 struct acpi_thermal_state {
105 u8 critical:1;
106 u8 hot:1;
107 u8 passive:1;
108 u8 active:1;
109 u8 reserved:4;
110 int active_index;
113 struct acpi_thermal_state_flags {
114 u8 valid:1;
115 u8 enabled:1;
116 u8 reserved:6;
119 struct acpi_thermal_critical {
120 struct acpi_thermal_state_flags flags;
121 unsigned long temperature;
124 struct acpi_thermal_hot {
125 struct acpi_thermal_state_flags flags;
126 unsigned long temperature;
129 struct acpi_thermal_passive {
130 struct acpi_thermal_state_flags flags;
131 unsigned long temperature;
132 unsigned long tc1;
133 unsigned long tc2;
134 unsigned long tsp;
135 struct acpi_handle_list devices;
138 struct acpi_thermal_active {
139 struct acpi_thermal_state_flags flags;
140 unsigned long temperature;
141 struct acpi_handle_list devices;
144 struct acpi_thermal_trips {
145 struct acpi_thermal_critical critical;
146 struct acpi_thermal_hot hot;
147 struct acpi_thermal_passive passive;
148 struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
151 struct acpi_thermal_flags {
152 u8 cooling_mode:1; /* _SCP */
153 u8 devices:1; /* _TZD */
154 u8 reserved:6;
157 struct acpi_thermal {
158 acpi_handle handle;
159 acpi_bus_id name;
160 unsigned long temperature;
161 unsigned long last_temperature;
162 unsigned long polling_frequency;
163 u8 cooling_mode;
164 volatile u8 zombie;
165 struct acpi_thermal_flags flags;
166 struct acpi_thermal_state state;
167 struct acpi_thermal_trips trips;
168 struct acpi_handle_list devices;
169 struct timer_list timer;
172 static struct file_operations acpi_thermal_state_fops = {
173 .open = acpi_thermal_state_open_fs,
174 .read = seq_read,
175 .llseek = seq_lseek,
176 .release = single_release,
179 static struct file_operations acpi_thermal_temp_fops = {
180 .open = acpi_thermal_temp_open_fs,
181 .read = seq_read,
182 .llseek = seq_lseek,
183 .release = single_release,
186 static struct file_operations acpi_thermal_trip_fops = {
187 .open = acpi_thermal_trip_open_fs,
188 .read = seq_read,
189 .write = acpi_thermal_write_trip_points,
190 .llseek = seq_lseek,
191 .release = single_release,
194 static struct file_operations acpi_thermal_cooling_fops = {
195 .open = acpi_thermal_cooling_open_fs,
196 .read = seq_read,
197 .write = acpi_thermal_write_cooling_mode,
198 .llseek = seq_lseek,
199 .release = single_release,
202 static struct file_operations acpi_thermal_polling_fops = {
203 .open = acpi_thermal_polling_open_fs,
204 .read = seq_read,
205 .write = acpi_thermal_write_polling,
206 .llseek = seq_lseek,
207 .release = single_release,
210 /* --------------------------------------------------------------------------
211 Thermal Zone Management
212 -------------------------------------------------------------------------- */
214 static int
215 acpi_thermal_get_temperature (
216 struct acpi_thermal *tz)
218 acpi_status status = AE_OK;
220 ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature");
222 if (!tz)
223 return_VALUE(-EINVAL);
225 tz->last_temperature = tz->temperature;
227 status = acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
228 if (ACPI_FAILURE(status))
229 return -ENODEV;
231 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature));
233 return_VALUE(0);
237 static int
238 acpi_thermal_get_polling_frequency (
239 struct acpi_thermal *tz)
241 acpi_status status = AE_OK;
243 ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency");
245 if (!tz)
246 return_VALUE(-EINVAL);
248 status = acpi_evaluate_integer(tz->handle, "_TZP", NULL, &tz->polling_frequency);
249 if (ACPI_FAILURE(status))
250 return_VALUE(-ENODEV);
252 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency));
254 return_VALUE(0);
258 static int
259 acpi_thermal_set_polling (
260 struct acpi_thermal *tz,
261 int seconds)
263 ACPI_FUNCTION_TRACE("acpi_thermal_set_polling");
265 if (!tz)
266 return_VALUE(-EINVAL);
268 tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
270 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", tz->polling_frequency));
272 return_VALUE(0);
276 static int
277 acpi_thermal_set_cooling_mode (
278 struct acpi_thermal *tz,
279 int mode)
281 acpi_status status = AE_OK;
282 union acpi_object arg0 = {ACPI_TYPE_INTEGER};
283 struct acpi_object_list arg_list = {1, &arg0};
284 acpi_handle handle = NULL;
286 ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode");
288 if (!tz)
289 return_VALUE(-EINVAL);
291 status = acpi_get_handle(tz->handle, "_SCP", &handle);
292 if (ACPI_FAILURE(status)) {
293 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
294 return_VALUE(-ENODEV);
297 arg0.integer.value = mode;
299 status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
300 if (ACPI_FAILURE(status))
301 return_VALUE(-ENODEV);
303 tz->cooling_mode = mode;
305 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
306 mode?"passive":"active"));
308 return_VALUE(0);
312 static int
313 acpi_thermal_get_trip_points (
314 struct acpi_thermal *tz)
316 acpi_status status = AE_OK;
317 int i = 0;
319 ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points");
321 if (!tz)
322 return_VALUE(-EINVAL);
324 /* Critical Shutdown (required) */
326 status = acpi_evaluate_integer(tz->handle, "_CRT", NULL,
327 &tz->trips.critical.temperature);
328 if (ACPI_FAILURE(status)) {
329 tz->trips.critical.flags.valid = 0;
330 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
331 return -ENODEV;
333 else {
334 tz->trips.critical.flags.valid = 1;
335 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%lu]\n", tz->trips.critical.temperature));
338 /* Critical Sleep (optional) */
340 status = acpi_evaluate_integer(tz->handle, "_HOT", NULL, &tz->trips.hot.temperature);
341 if (ACPI_FAILURE(status)) {
342 tz->trips.hot.flags.valid = 0;
343 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
345 else {
346 tz->trips.hot.flags.valid = 1;
347 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", tz->trips.hot.temperature));
350 /* Passive: Processors (optional) */
352 status = acpi_evaluate_integer(tz->handle, "_PSV", NULL, &tz->trips.passive.temperature);
353 if (ACPI_FAILURE(status)) {
354 tz->trips.passive.flags.valid = 0;
355 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
357 else {
358 tz->trips.passive.flags.valid = 1;
360 status = acpi_evaluate_integer(tz->handle, "_TC1", NULL, &tz->trips.passive.tc1);
361 if (ACPI_FAILURE(status))
362 tz->trips.passive.flags.valid = 0;
364 status = acpi_evaluate_integer(tz->handle, "_TC2", NULL, &tz->trips.passive.tc2);
365 if (ACPI_FAILURE(status))
366 tz->trips.passive.flags.valid = 0;
368 status = acpi_evaluate_integer(tz->handle, "_TSP", NULL, &tz->trips.passive.tsp);
369 if (ACPI_FAILURE(status))
370 tz->trips.passive.flags.valid = 0;
372 status = acpi_evaluate_reference(tz->handle, "_PSL", NULL, &tz->trips.passive.devices);
373 if (ACPI_FAILURE(status))
374 tz->trips.passive.flags.valid = 0;
376 if (!tz->trips.passive.flags.valid)
377 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid passive threshold\n"));
378 else
379 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%lu]\n", tz->trips.passive.temperature));
382 /* Active: Fans, etc. (optional) */
384 for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
386 char name[5] = {'_','A','C',('0'+i),'\0'};
388 status = acpi_evaluate_integer(tz->handle, name, NULL, &tz->trips.active[i].temperature);
389 if (ACPI_FAILURE(status))
390 break;
392 name[2] = 'L';
393 status = acpi_evaluate_reference(tz->handle, name, NULL, &tz->trips.active[i].devices);
394 if (ACPI_SUCCESS(status)) {
395 tz->trips.active[i].flags.valid = 1;
396 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%lu]\n", i, tz->trips.active[i].temperature));
398 else
399 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i));
402 return_VALUE(0);
406 static int
407 acpi_thermal_get_devices (
408 struct acpi_thermal *tz)
410 acpi_status status = AE_OK;
412 ACPI_FUNCTION_TRACE("acpi_thermal_get_devices");
414 if (!tz)
415 return_VALUE(-EINVAL);
417 status = acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
418 if (ACPI_FAILURE(status))
419 return_VALUE(-ENODEV);
421 return_VALUE(0);
425 static int
426 acpi_thermal_call_usermode (
427 char *path)
429 char *argv[2] = {NULL, NULL};
430 char *envp[3] = {NULL, NULL, NULL};
432 ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode");
434 if (!path)
435 return_VALUE(-EINVAL);
437 argv[0] = path;
439 /* minimal command environment */
440 envp[0] = "HOME=/";
441 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
443 call_usermodehelper(argv[0], argv, envp, 0);
445 return_VALUE(0);
449 static int
450 acpi_thermal_critical (
451 struct acpi_thermal *tz)
453 int result = 0;
454 struct acpi_device *device = NULL;
456 ACPI_FUNCTION_TRACE("acpi_thermal_critical");
458 if (!tz || !tz->trips.critical.flags.valid)
459 return_VALUE(-EINVAL);
461 if (tz->temperature >= tz->trips.critical.temperature) {
462 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
463 tz->trips.critical.flags.enabled = 1;
465 else if (tz->trips.critical.flags.enabled)
466 tz->trips.critical.flags.enabled = 0;
468 result = acpi_bus_get_device(tz->handle, &device);
469 if (result)
470 return_VALUE(result);
472 printk(KERN_EMERG "Critical temperature reached (%ld C), shutting down.\n", KELVIN_TO_CELSIUS(tz->temperature));
473 acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled);
475 acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
477 return_VALUE(0);
481 static int
482 acpi_thermal_hot (
483 struct acpi_thermal *tz)
485 int result = 0;
486 struct acpi_device *device = NULL;
488 ACPI_FUNCTION_TRACE("acpi_thermal_hot");
490 if (!tz || !tz->trips.hot.flags.valid)
491 return_VALUE(-EINVAL);
493 if (tz->temperature >= tz->trips.hot.temperature) {
494 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
495 tz->trips.hot.flags.enabled = 1;
497 else if (tz->trips.hot.flags.enabled)
498 tz->trips.hot.flags.enabled = 0;
500 result = acpi_bus_get_device(tz->handle, &device);
501 if (result)
502 return_VALUE(result);
504 acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT, tz->trips.hot.flags.enabled);
506 /* TBD: Call user-mode "sleep(S4)" function */
508 return_VALUE(0);
512 static int
513 acpi_thermal_passive (
514 struct acpi_thermal *tz)
516 int result = 0;
517 struct acpi_thermal_passive *passive = NULL;
518 int trend = 0;
519 int i = 0;
521 ACPI_FUNCTION_TRACE("acpi_thermal_passive");
523 if (!tz || !tz->trips.passive.flags.valid)
524 return_VALUE(-EINVAL);
526 passive = &(tz->trips.passive);
529 * Above Trip?
530 * -----------
531 * Calculate the thermal trend (using the passive cooling equation)
532 * and modify the performance limit for all passive cooling devices
533 * accordingly. Note that we assume symmetry.
535 if (tz->temperature >= passive->temperature) {
536 trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
537 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
538 "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
539 trend, passive->tc1, tz->temperature,
540 tz->last_temperature, passive->tc2,
541 tz->temperature, passive->temperature));
542 tz->trips.passive.flags.enabled = 1;
543 /* Heating up? */
544 if (trend > 0)
545 for (i=0; i<passive->devices.count; i++)
546 acpi_processor_set_thermal_limit(
547 passive->devices.handles[i],
548 ACPI_PROCESSOR_LIMIT_INCREMENT);
549 /* Cooling off? */
550 else if (trend < 0)
551 for (i=0; i<passive->devices.count; i++)
552 acpi_processor_set_thermal_limit(
553 passive->devices.handles[i],
554 ACPI_PROCESSOR_LIMIT_DECREMENT);
558 * Below Trip?
559 * -----------
560 * Implement passive cooling hysteresis to slowly increase performance
561 * and avoid thrashing around the passive trip point. Note that we
562 * assume symmetry.
564 else if (tz->trips.passive.flags.enabled) {
565 for (i=0; i<passive->devices.count; i++)
566 result = acpi_processor_set_thermal_limit(
567 passive->devices.handles[i],
568 ACPI_PROCESSOR_LIMIT_DECREMENT);
569 if (result == 1) {
570 tz->trips.passive.flags.enabled = 0;
571 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
572 "Disabling passive cooling (zone is cool)\n"));
576 return_VALUE(0);
580 static int
581 acpi_thermal_active (
582 struct acpi_thermal *tz)
584 int result = 0;
585 struct acpi_thermal_active *active = NULL;
586 int i = 0;
587 int j = 0;
588 unsigned long maxtemp = 0;
590 ACPI_FUNCTION_TRACE("acpi_thermal_active");
592 if (!tz)
593 return_VALUE(-EINVAL);
595 for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
597 active = &(tz->trips.active[i]);
598 if (!active || !active->flags.valid)
599 break;
602 * Above Threshold?
603 * ----------------
604 * If not already enabled, turn ON all cooling devices
605 * associated with this active threshold.
607 if (tz->temperature >= active->temperature) {
608 if (active->temperature > maxtemp)
609 tz->state.active_index = i, maxtemp = active->temperature;
610 if (!active->flags.enabled) {
611 for (j = 0; j < active->devices.count; j++) {
612 result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0);
613 if (result) {
614 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'on'\n", active->devices.handles[j]));
615 continue;
617 active->flags.enabled = 1;
618 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'on'\n", active->devices.handles[j]));
623 * Below Threshold?
624 * ----------------
625 * Turn OFF all cooling devices associated with this
626 * threshold.
628 else if (active->flags.enabled) {
629 for (j = 0; j < active->devices.count; j++) {
630 result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D3);
631 if (result) {
632 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'off'\n", active->devices.handles[j]));
633 continue;
635 active->flags.enabled = 0;
636 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'off'\n", active->devices.handles[j]));
641 return_VALUE(0);
645 static void acpi_thermal_check (void *context);
647 static void
648 acpi_thermal_run (
649 unsigned long data)
651 struct acpi_thermal *tz = (struct acpi_thermal *)data;
652 if (!tz->zombie)
653 acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
654 acpi_thermal_check, (void *) data);
658 static void
659 acpi_thermal_check (
660 void *data)
662 int result = 0;
663 struct acpi_thermal *tz = (struct acpi_thermal *) data;
664 unsigned long sleep_time = 0;
665 int i = 0;
666 struct acpi_thermal_state state;
668 ACPI_FUNCTION_TRACE("acpi_thermal_check");
670 if (!tz) {
671 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
672 return_VOID;
675 state = tz->state;
677 result = acpi_thermal_get_temperature(tz);
678 if (result)
679 return_VOID;
681 memset(&tz->state, 0, sizeof(tz->state));
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).
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);
702 * Invoke Policy
703 * -------------
704 * Separated from the above check to allow individual policy to
705 * determine when to exit a given state.
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);
717 * Calculate State
718 * ---------------
719 * Again, separated from the above two to allow independent policy
720 * decisions.
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;
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).
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;
746 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
747 tz->name, tz->temperature, sleep_time));
750 * Schedule Next Poll
751 * ------------------
753 if (!sleep_time) {
754 if (timer_pending(&(tz->timer)))
755 del_timer(&(tz->timer));
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));
768 return_VOID;
772 /* --------------------------------------------------------------------------
773 FS Interface (/proc)
774 -------------------------------------------------------------------------- */
776 struct proc_dir_entry *acpi_thermal_dir;
778 static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
780 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
782 ACPI_FUNCTION_TRACE("acpi_thermal_state_seq_show");
784 if (!tz)
785 goto end;
787 seq_puts(seq, "state: ");
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");
803 end:
804 return 0;
807 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
809 return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
813 static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
815 int result = 0;
816 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
818 ACPI_FUNCTION_TRACE("acpi_thermal_temp_seq_show");
820 if (!tz)
821 goto end;
823 result = acpi_thermal_get_temperature(tz);
824 if (result)
825 goto end;
827 seq_printf(seq, "temperature: %ld C\n",
828 KELVIN_TO_CELSIUS(tz->temperature));
830 end:
831 return 0;
834 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
836 return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
840 static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
842 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
843 int i = 0;
844 int j = 0;
846 ACPI_FUNCTION_TRACE("acpi_thermal_trip_seq_show");
848 if (!tz)
849 goto end;
851 if (tz->trips.critical.flags.valid)
852 seq_printf(seq, "critical (S5): %ld C\n",
853 KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
855 if (tz->trips.hot.flags.valid)
856 seq_printf(seq, "hot (S4): %ld C\n",
857 KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
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++) {
867 seq_printf(seq, "0x%p ", tz->trips.passive.devices.handles[j]);
869 seq_puts(seq, "\n");
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");
883 end:
884 return 0;
887 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
889 return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
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)
899 struct seq_file *m = (struct seq_file *)file->private_data;
900 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
902 char limit_string[65] = {'\0'};
903 int num, critical, hot, passive;
904 int active[ACPI_THERMAL_MAX_ACTIVE];
905 int i = 0;
907 ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
909 if (!tz || (count > sizeof(limit_string) - 1)) {
910 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
911 return_VALUE(-EINVAL);
914 if (copy_from_user(limit_string, buffer, count)) {
915 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
916 return_VALUE(-EFAULT);
919 limit_string[count] = '\0';
921 num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
922 &critical, &hot, &passive,
923 &active[0], &active[1], &active[2], &active[3], &active[4],
924 &active[5], &active[6], &active[7], &active[8], &active[9]);
925 if(!(num >=5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
926 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
927 return_VALUE(-EINVAL);
930 tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
931 tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
932 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
933 for (i = 0; i < num - 3; i++) {
934 if (!(tz->trips.active[i].flags.valid))
935 break;
936 tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
939 return_VALUE(count);
943 static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
945 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
947 ACPI_FUNCTION_TRACE("acpi_thermal_cooling_seq_show");
949 if (!tz)
950 goto end;
952 if (!tz->flags.cooling_mode) {
953 seq_puts(seq, "<setting not supported>\n");
956 if ( tz->cooling_mode == ACPI_THERMAL_MODE_CRT )
957 seq_printf(seq, "cooling mode: critical\n");
958 else
959 seq_printf(seq, "cooling mode: %s\n",
960 tz->cooling_mode?"passive":"active");
962 end:
963 return 0;
966 static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
968 return single_open(file, acpi_thermal_cooling_seq_show,
969 PDE(inode)->data);
972 static ssize_t
973 acpi_thermal_write_cooling_mode (
974 struct file *file,
975 const char __user *buffer,
976 size_t count,
977 loff_t *ppos)
979 struct seq_file *m = (struct seq_file *)file->private_data;
980 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
981 int result = 0;
982 char mode_string[12] = {'\0'};
984 ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode");
986 if (!tz || (count > sizeof(mode_string) - 1))
987 return_VALUE(-EINVAL);
989 if (!tz->flags.cooling_mode)
990 return_VALUE(-ENODEV);
992 if (copy_from_user(mode_string, buffer, count))
993 return_VALUE(-EFAULT);
995 mode_string[count] = '\0';
997 result = acpi_thermal_set_cooling_mode(tz,
998 simple_strtoul(mode_string, NULL, 0));
999 if (result)
1000 return_VALUE(result);
1002 acpi_thermal_check(tz);
1004 return_VALUE(count);
1008 static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
1010 struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
1012 ACPI_FUNCTION_TRACE("acpi_thermal_polling_seq_show");
1014 if (!tz)
1015 goto end;
1017 if (!tz->polling_frequency) {
1018 seq_puts(seq, "<polling disabled>\n");
1019 goto end;
1022 seq_printf(seq, "polling frequency: %lu seconds\n",
1023 (tz->polling_frequency / 10));
1025 end:
1026 return 0;
1029 static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
1031 return single_open(file, acpi_thermal_polling_seq_show,
1032 PDE(inode)->data);
1035 static ssize_t
1036 acpi_thermal_write_polling (
1037 struct file *file,
1038 const char __user *buffer,
1039 size_t count,
1040 loff_t *ppos)
1042 struct seq_file *m = (struct seq_file *)file->private_data;
1043 struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
1044 int result = 0;
1045 char polling_string[12] = {'\0'};
1046 int seconds = 0;
1048 ACPI_FUNCTION_TRACE("acpi_thermal_write_polling");
1050 if (!tz || (count > sizeof(polling_string) - 1))
1051 return_VALUE(-EINVAL);
1053 if (copy_from_user(polling_string, buffer, count))
1054 return_VALUE(-EFAULT);
1056 polling_string[count] = '\0';
1058 seconds = simple_strtoul(polling_string, NULL, 0);
1060 result = acpi_thermal_set_polling(tz, seconds);
1061 if (result)
1062 return_VALUE(result);
1064 acpi_thermal_check(tz);
1066 return_VALUE(count);
1070 static int
1071 acpi_thermal_add_fs (
1072 struct acpi_device *device)
1074 struct proc_dir_entry *entry = NULL;
1076 ACPI_FUNCTION_TRACE("acpi_thermal_add_fs");
1078 if (!acpi_device_dir(device)) {
1079 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
1080 acpi_thermal_dir);
1081 if (!acpi_device_dir(device))
1082 return_VALUE(-ENODEV);
1083 acpi_device_dir(device)->owner = THIS_MODULE;
1086 /* 'state' [R] */
1087 entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
1088 S_IRUGO, acpi_device_dir(device));
1089 if (!entry)
1090 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1091 "Unable to create '%s' fs entry\n",
1092 ACPI_THERMAL_FILE_STATE));
1093 else {
1094 entry->proc_fops = &acpi_thermal_state_fops;
1095 entry->data = acpi_driver_data(device);
1096 entry->owner = THIS_MODULE;
1099 /* 'temperature' [R] */
1100 entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1101 S_IRUGO, acpi_device_dir(device));
1102 if (!entry)
1103 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1104 "Unable to create '%s' fs entry\n",
1105 ACPI_THERMAL_FILE_TEMPERATURE));
1106 else {
1107 entry->proc_fops = &acpi_thermal_temp_fops;
1108 entry->data = acpi_driver_data(device);
1109 entry->owner = THIS_MODULE;
1112 /* 'trip_points' [R/W] */
1113 entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1114 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1115 if (!entry)
1116 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1117 "Unable to create '%s' fs entry\n",
1118 ACPI_THERMAL_FILE_TRIP_POINTS));
1119 else {
1120 entry->proc_fops = &acpi_thermal_trip_fops;
1121 entry->data = acpi_driver_data(device);
1122 entry->owner = THIS_MODULE;
1125 /* 'cooling_mode' [R/W] */
1126 entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1127 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1128 if (!entry)
1129 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1130 "Unable to create '%s' fs entry\n",
1131 ACPI_THERMAL_FILE_COOLING_MODE));
1132 else {
1133 entry->proc_fops = &acpi_thermal_cooling_fops;
1134 entry->data = acpi_driver_data(device);
1135 entry->owner = THIS_MODULE;
1138 /* 'polling_frequency' [R/W] */
1139 entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1140 S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
1141 if (!entry)
1142 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1143 "Unable to create '%s' fs entry\n",
1144 ACPI_THERMAL_FILE_POLLING_FREQ));
1145 else {
1146 entry->proc_fops = &acpi_thermal_polling_fops;
1147 entry->data = acpi_driver_data(device);
1148 entry->owner = THIS_MODULE;
1151 return_VALUE(0);
1155 static int
1156 acpi_thermal_remove_fs (
1157 struct acpi_device *device)
1159 ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");
1161 if (acpi_device_dir(device)) {
1162 remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
1163 acpi_device_dir(device));
1164 remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
1165 acpi_device_dir(device));
1166 remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
1167 acpi_device_dir(device));
1168 remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
1169 acpi_device_dir(device));
1170 remove_proc_entry(ACPI_THERMAL_FILE_STATE,
1171 acpi_device_dir(device));
1172 remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
1173 acpi_device_dir(device) = NULL;
1176 return_VALUE(0);
1180 /* --------------------------------------------------------------------------
1181 Driver Interface
1182 -------------------------------------------------------------------------- */
1184 static void
1185 acpi_thermal_notify (
1186 acpi_handle handle,
1187 u32 event,
1188 void *data)
1190 struct acpi_thermal *tz = (struct acpi_thermal *) data;
1191 struct acpi_device *device = NULL;
1193 ACPI_FUNCTION_TRACE("acpi_thermal_notify");
1195 if (!tz)
1196 return_VOID;
1198 if (acpi_bus_get_device(tz->handle, &device))
1199 return_VOID;
1201 switch (event) {
1202 case ACPI_THERMAL_NOTIFY_TEMPERATURE:
1203 acpi_thermal_check(tz);
1204 break;
1205 case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1206 acpi_thermal_get_trip_points(tz);
1207 acpi_thermal_check(tz);
1208 acpi_bus_generate_event(device, event, 0);
1209 break;
1210 case ACPI_THERMAL_NOTIFY_DEVICES:
1211 if (tz->flags.devices)
1212 acpi_thermal_get_devices(tz);
1213 acpi_bus_generate_event(device, event, 0);
1214 break;
1215 default:
1216 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
1217 "Unsupported event [0x%x]\n", event));
1218 break;
1221 return_VOID;
1225 static int
1226 acpi_thermal_get_info (
1227 struct acpi_thermal *tz)
1229 int result = 0;
1231 ACPI_FUNCTION_TRACE("acpi_thermal_get_info");
1233 if (!tz)
1234 return_VALUE(-EINVAL);
1236 /* Get temperature [_TMP] (required) */
1237 result = acpi_thermal_get_temperature(tz);
1238 if (result)
1239 return_VALUE(result);
1241 /* Get trip points [_CRT, _PSV, etc.] (required) */
1242 result = acpi_thermal_get_trip_points(tz);
1243 if (result)
1244 return_VALUE(result);
1246 /* Set the cooling mode [_SCP] to active cooling (default) */
1247 result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1248 if (!result)
1249 tz->flags.cooling_mode = 1;
1250 else {
1251 /* Oh,we have not _SCP method.
1252 Generally show cooling_mode by _ACx, _PSV,spec 12.2*/
1253 tz->flags.cooling_mode = 0;
1254 if ( tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
1255 if ( tz->trips.passive.temperature > tz->trips.active[0].temperature )
1256 tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1257 else
1258 tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1259 } else if ( !tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
1260 tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
1261 } else if ( tz->trips.active[0].flags.valid && !tz->trips.passive.flags.valid ) {
1262 tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
1263 } else {
1264 /* _ACx and _PSV are optional, but _CRT is required */
1265 tz->cooling_mode = ACPI_THERMAL_MODE_CRT;
1269 /* Get default polling frequency [_TZP] (optional) */
1270 if (tzp)
1271 tz->polling_frequency = tzp;
1272 else
1273 acpi_thermal_get_polling_frequency(tz);
1275 /* Get devices in this thermal zone [_TZD] (optional) */
1276 result = acpi_thermal_get_devices(tz);
1277 if (!result)
1278 tz->flags.devices = 1;
1280 return_VALUE(0);
1284 static int
1285 acpi_thermal_add (
1286 struct acpi_device *device)
1288 int result = 0;
1289 acpi_status status = AE_OK;
1290 struct acpi_thermal *tz = NULL;
1292 ACPI_FUNCTION_TRACE("acpi_thermal_add");
1294 if (!device)
1295 return_VALUE(-EINVAL);
1297 tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1298 if (!tz)
1299 return_VALUE(-ENOMEM);
1300 memset(tz, 0, sizeof(struct acpi_thermal));
1302 tz->handle = device->handle;
1303 strcpy(tz->name, device->pnp.bus_id);
1304 strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1305 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1306 acpi_driver_data(device) = tz;
1308 result = acpi_thermal_get_info(tz);
1309 if (result)
1310 goto end;
1312 result = acpi_thermal_add_fs(device);
1313 if (result)
1314 return_VALUE(result);
1316 init_timer(&tz->timer);
1318 acpi_thermal_check(tz);
1320 status = acpi_install_notify_handler(tz->handle,
1321 ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz);
1322 if (ACPI_FAILURE(status)) {
1323 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1324 "Error installing notify handler\n"));
1325 result = -ENODEV;
1326 goto end;
1329 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1330 acpi_device_name(device), acpi_device_bid(device),
1331 KELVIN_TO_CELSIUS(tz->temperature));
1333 end:
1334 if (result) {
1335 acpi_thermal_remove_fs(device);
1336 kfree(tz);
1339 return_VALUE(result);
1343 static int
1344 acpi_thermal_remove (
1345 struct acpi_device *device,
1346 int type)
1348 acpi_status status = AE_OK;
1349 struct acpi_thermal *tz = NULL;
1351 ACPI_FUNCTION_TRACE("acpi_thermal_remove");
1353 if (!device || !acpi_driver_data(device))
1354 return_VALUE(-EINVAL);
1356 tz = (struct acpi_thermal *) acpi_driver_data(device);
1358 /* avoid timer adding new defer task */
1359 tz->zombie = 1;
1360 /* wait for running timer (on other CPUs) finish */
1361 del_timer_sync(&(tz->timer));
1362 /* synchronize deferred task */
1363 acpi_os_wait_events_complete(NULL);
1364 /* deferred task may reinsert timer */
1365 del_timer_sync(&(tz->timer));
1367 status = acpi_remove_notify_handler(tz->handle,
1368 ACPI_DEVICE_NOTIFY, acpi_thermal_notify);
1369 if (ACPI_FAILURE(status))
1370 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1371 "Error removing notify handler\n"));
1373 /* Terminate policy */
1374 if (tz->trips.passive.flags.valid
1375 && tz->trips.passive.flags.enabled) {
1376 tz->trips.passive.flags.enabled = 0;
1377 acpi_thermal_passive(tz);
1379 if (tz->trips.active[0].flags.valid
1380 && tz->trips.active[0].flags.enabled) {
1381 tz->trips.active[0].flags.enabled = 0;
1382 acpi_thermal_active(tz);
1385 acpi_thermal_remove_fs(device);
1387 kfree(tz);
1388 return_VALUE(0);
1392 static int __init
1393 acpi_thermal_init (void)
1395 int result = 0;
1397 ACPI_FUNCTION_TRACE("acpi_thermal_init");
1399 acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
1400 if (!acpi_thermal_dir)
1401 return_VALUE(-ENODEV);
1402 acpi_thermal_dir->owner = THIS_MODULE;
1404 result = acpi_bus_register_driver(&acpi_thermal_driver);
1405 if (result < 0) {
1406 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1407 return_VALUE(-ENODEV);
1410 return_VALUE(0);
1414 static void __exit
1415 acpi_thermal_exit (void)
1417 ACPI_FUNCTION_TRACE("acpi_thermal_exit");
1419 acpi_bus_unregister_driver(&acpi_thermal_driver);
1421 remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
1423 return_VOID;
1427 module_init(acpi_thermal_init);
1428 module_exit(acpi_thermal_exit);