1/******************************************************************************
2 *
3 * Module Name: tz_osl.c
4 *   $Revision: 1.1.1.1 $
5 *
6 *****************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 Andrew Grover
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/types.h>
31#include <linux/proc_fs.h>
32#include <acpi.h>
33#include "tz.h"
34
35
36MODULE_AUTHOR("Andrew Grover");
37MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver");
38MODULE_LICENSE("GPL");
39
40int TZP = 0;
41MODULE_PARM(TZP, "i");
42MODULE_PARM_DESC(TZP, "Thermal zone polling frequency, in 1/10 seconds.\n");
43
44
45#define TZ_PROC_ROOT		"thermal"
46#define TZ_PROC_STATUS		"status"
47#define TZ_PROC_INFO		"info"
48
49extern struct proc_dir_entry	*bm_proc_root;
50static struct proc_dir_entry	*tz_proc_root = NULL;
51
52
53/****************************************************************************
54 *
55 * FUNCTION:	tz_osl_proc_read_info
56 *
57 ****************************************************************************/
58
59static int
60tz_osl_proc_read_info (
61	char			*page,
62	char			**start,
63	off_t			off,
64	int 			count,
65	int 			*eof,
66	void			*context)
67{
68	acpi_status		status = AE_OK;
69	char			name[5];
70	acpi_buffer		buffer = {sizeof(name), &name};
71	TZ_CONTEXT		*tz = NULL;
72	TZ_THRESHOLDS		*thresholds = NULL;
73	char			*p = page;
74	int 			len = 0;
75	u32			i,j;
76	u32			t = 0;
77
78	if (!context || (off != 0))
79		goto end;
80
81	tz = (TZ_CONTEXT*)context;
82
83	thresholds = &(tz->policy.thresholds);
84
85	p += sprintf(p, "critical (S5): trip=%d\n", thresholds->critical.temperature);
86
87	if (thresholds->hot.is_valid)
88		p += sprintf(p, "critical (S4): trip=%d\n", thresholds->hot.temperature);
89
90	if (thresholds->passive.is_valid) {
91		p += sprintf(p, "passive:       trip=%d tc1=%d tc2=%d tsp=%d devices=", thresholds->passive.temperature, thresholds->passive.tc1, thresholds->passive.tc2, thresholds->passive.tsp);
92		for (j=0; j<thresholds->passive.devices.count; j++)
93			p += sprintf(p, "%08x%c", thresholds->passive.devices.handles[j], (j==thresholds->passive.devices.count-1)?'\n':',');
94	}
95
96	for (i=0; i<TZ_MAX_ACTIVE_THRESHOLDS; i++) {
97		if (!(thresholds->active[i].is_valid))
98			break;
99		p += sprintf(p, "active[%d]:     trip=%d devices=", i, thresholds->active[i].temperature);
100		for (j=0; j<thresholds->active[i].devices.count; j++)
101			p += sprintf(p, "%08x%c", thresholds->active[i].devices.handles[j], (j==thresholds->passive.devices.count-1)?'\n':',');
102	}
103
104	p += sprintf(p, "cooling mode:  ");
105	switch (tz->policy.cooling_mode) {
106	case TZ_COOLING_MODE_ACTIVE:
107		p += sprintf(p, "active (noisy)\n");
108		break;
109	case TZ_COOLING_MODE_PASSIVE:
110		p += sprintf(p, "passive (quiet)\n");
111		break;
112	default:
113		p += sprintf(p, "unknown\n");
114		break;
115	}
116
117	p += sprintf(p, "polling:       ");
118	switch (tz->policy.polling_freq) {
119	case 0:
120		p += sprintf(p, "disabled\n");
121		break;
122	default:
123		p += sprintf(p, "%d dS\n", tz->policy.polling_freq);
124		break;
125	}
126
127end:
128	len = (p - page);
129	if (len <= off+count) *eof = 1;
130	*start = page + off;
131	len -= off;
132	if (len>count) len = count;
133	if (len<0) len = 0;
134
135	return len;
136}
137
138
139/****************************************************************************
140 *
141 * FUNCTION:	tz_osl_proc_write_info
142 *
143 ****************************************************************************/
144
145static int tz_osl_proc_write_info (
146        struct file		*file,
147        const char		*buffer,
148        unsigned long		count,
149        void			*data)
150{
151	TZ_CONTEXT		*tz = NULL;
152	u32			state = 0;
153	u32			size = 0;
154
155	if (!buffer || (count==0) || !data) {
156		goto end;
157	}
158
159	tz = (TZ_CONTEXT*)data;
160
161	size = strlen(buffer);
162	if (size < 4)
163		goto end;
164
165	/* Cooling preference: "scp=0" (active) or "scp=1" (passive) */
166	if (0 == strncmp(buffer, "scp=", 4)) {
167		tz_set_cooling_preference(tz, (buffer[4] - '0'));
168	}
169
170	/* Polling frequency: "tzp=X" (poll every X [0-9] seconds) */
171	else if (0 == strncmp(buffer, "tzp=", 4)) {
172		tz->policy.polling_freq = (buffer[4] - '0') * 10;
173		tz_policy_check(tz);
174	}
175
176end:
177        return count;
178}
179
180
181/****************************************************************************
182 *
183 * FUNCTION:	tz_osl_proc_read_status
184 *
185 ****************************************************************************/
186
187static int
188tz_osl_proc_read_status (
189	char			*page,
190	char			**start,
191	off_t			off,
192	int 			count,
193	int 			*eof,
194	void			*context)
195{
196	TZ_CONTEXT		*tz = NULL;
197	char			*p = page;
198	int 			len = 0;
199
200	if (!context || (off != 0)) {
201		goto end;
202	}
203
204	tz = (TZ_CONTEXT*)context;
205
206	/* Temperature */
207
208	tz_get_temperature(tz);
209
210	p += sprintf(p, "temperature:   %d dK\n", tz->policy.temperature);
211
212	p += sprintf(p, "state:         ");
213	if (tz->policy.state == 0)
214		p += sprintf(p, "ok\n");
215	else if (tz->policy.state & TZ_STATE_CRITICAL)
216		p += sprintf(p, "critical\n");
217	else if (tz->policy.state & TZ_STATE_HOT)
218		p += sprintf(p, "hot\n");
219	else {
220		if (tz->policy.state & TZ_STATE_ACTIVE)
221			p += sprintf(p, "active[%d] ", tz->policy.state & 0x07);
222		if (tz->policy.state & TZ_STATE_PASSIVE)
223			p += sprintf(p, "passive ");
224		p += sprintf(p, "\n");
225	}
226
227end:
228	len = (p - page);
229	if (len <= off+count) *eof = 1;
230	*start = page + off;
231	len -= off;
232	if (len>count) len = count;
233	if (len<0) len = 0;
234
235	return(len);
236}
237
238
239/****************************************************************************
240 *
241 * FUNCTION:	tz_osl_add_device
242 *
243 ****************************************************************************/
244
245acpi_status
246tz_osl_add_device(
247	TZ_CONTEXT		*tz)
248{
249	struct proc_dir_entry	*proc_entry = NULL;
250	struct proc_dir_entry	*proc_child_entry = NULL;
251
252	if (!tz) {
253		return(AE_BAD_PARAMETER);
254	}
255
256	printk("ACPI: Thermal Zone found\n");
257
258	proc_entry = proc_mkdir(tz->uid, tz_proc_root);
259	if (!proc_entry)
260		return(AE_ERROR);
261
262	proc_child_entry = create_proc_read_entry(TZ_PROC_STATUS, S_IFREG | S_IRUGO, proc_entry, tz_osl_proc_read_status, (void*)tz);
263	if (!proc_child_entry)
264		return(AE_ERROR);
265
266	proc_child_entry = create_proc_entry(TZ_PROC_INFO, S_IFREG | 0644, proc_entry);
267	if (!proc_child_entry)
268		return(AE_ERROR);
269
270	proc_child_entry->read_proc = tz_osl_proc_read_info;
271	proc_child_entry->write_proc = tz_osl_proc_write_info;
272	proc_child_entry->data = (void*)tz;
273
274	return(AE_OK);
275}
276
277
278/****************************************************************************
279 *
280 * FUNCTION:	tz_osl_remove_device
281 *
282 ****************************************************************************/
283
284acpi_status
285tz_osl_remove_device (
286	TZ_CONTEXT		*tz)
287{
288	char			proc_entry[64];
289
290	if (!tz) {
291		return(AE_BAD_PARAMETER);
292	}
293
294	sprintf(proc_entry, "%s/%s", tz->uid, TZ_PROC_INFO);
295	remove_proc_entry(proc_entry, tz_proc_root);
296
297	sprintf(proc_entry, "%s/%s", tz->uid, TZ_PROC_STATUS);
298	remove_proc_entry(proc_entry, tz_proc_root);
299
300	sprintf(proc_entry, "%s", tz->uid);
301	remove_proc_entry(proc_entry, tz_proc_root);
302
303	return(AE_OK);
304}
305
306
307/****************************************************************************
308 *
309 * FUNCTION:	tz_osl_generate_event
310 *
311 ****************************************************************************/
312
313acpi_status
314tz_osl_generate_event (
315	u32			event,
316	TZ_CONTEXT		*tz)
317{
318	acpi_status		status = AE_OK;
319
320	if (!tz) {
321		return(AE_BAD_PARAMETER);
322	}
323
324	switch (event) {
325
326	case TZ_NOTIFY_TEMPERATURE_CHANGE:
327		status = bm_osl_generate_event(tz->device_handle,
328			TZ_PROC_ROOT, tz->uid, event,
329			tz->policy.temperature);
330		break;
331
332	case TZ_NOTIFY_THRESHOLD_CHANGE:
333	case TZ_NOTIFY_DEVICE_LISTS_CHANGE:
334		status = bm_osl_generate_event(tz->device_handle,
335			TZ_PROC_ROOT, tz->uid, event, 0);
336		break;
337
338	default:
339		return(AE_BAD_PARAMETER);
340		break;
341	}
342
343	return(status);
344}
345
346
347/****************************************************************************
348 *
349 * FUNCTION:	tz_osl_init
350 *
351 ****************************************************************************/
352
353static int __init
354tz_osl_init (void)
355{
356	acpi_status		status = AE_OK;
357
358	/* abort if no busmgr */
359	if (!bm_proc_root)
360		return -ENODEV;
361
362	tz_proc_root = proc_mkdir(TZ_PROC_ROOT, bm_proc_root);
363	if (!tz_proc_root) {
364		status = AE_ERROR;
365	}
366	else {
367		status = tz_initialize();
368		if (ACPI_FAILURE(status)) {
369			remove_proc_entry(TZ_PROC_ROOT, bm_proc_root);
370		}
371
372	}
373
374	return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
375}
376
377
378/****************************************************************************
379 *
380 * FUNCTION:	tz_osl_cleanup
381 *
382 ****************************************************************************/
383
384static void __exit
385tz_osl_cleanup (void)
386{
387	tz_terminate();
388
389	if (tz_proc_root) {
390		remove_proc_entry(TZ_PROC_ROOT, bm_proc_root);
391	}
392
393	return;
394}
395
396
397module_init(tz_osl_init);
398module_exit(tz_osl_cleanup);
399