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