OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [acpi/] [thermal.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.