⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thermal.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $) * *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or (at *  your option) any later version. * *  This program is distributed in the hope that it will be useful, but *  WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  General Public License for more details. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *  This driver fully implements the ACPI thermal policy as described in the *  ACPI 2.0 Specification. * *  TBD: 1. Implement passive cooling hysteresis. *       2. Enhance passive cooling (CPU) states/limit interface to support *          concepts of 'multiple limiters', upper/lower limits, etc. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/dmi.h>#include <linux/init.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <linux/timer.h>#include <linux/jiffies.h>#include <linux/kmod.h>#include <linux/seq_file.h>#include <linux/reboot.h>#include <asm/uaccess.h>#include <acpi/acpi_bus.h>#include <acpi/acpi_drivers.h>#define ACPI_THERMAL_COMPONENT		0x04000000#define ACPI_THERMAL_CLASS		"thermal_zone"#define ACPI_THERMAL_DEVICE_NAME	"Thermal Zone"#define ACPI_THERMAL_FILE_STATE		"state"#define ACPI_THERMAL_FILE_TEMPERATURE	"temperature"#define ACPI_THERMAL_FILE_TRIP_POINTS	"trip_points"#define ACPI_THERMAL_FILE_COOLING_MODE	"cooling_mode"#define ACPI_THERMAL_FILE_POLLING_FREQ	"polling_frequency"#define ACPI_THERMAL_NOTIFY_TEMPERATURE	0x80#define ACPI_THERMAL_NOTIFY_THRESHOLDS	0x81#define ACPI_THERMAL_NOTIFY_DEVICES	0x82#define ACPI_THERMAL_NOTIFY_CRITICAL	0xF0#define ACPI_THERMAL_NOTIFY_HOT		0xF1#define ACPI_THERMAL_MODE_ACTIVE	0x00#define ACPI_THERMAL_MAX_ACTIVE	10#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65#define KELVIN_TO_CELSIUS(t)    (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)#define CELSIUS_TO_KELVIN(t)	((t+273)*10)#define _COMPONENT		ACPI_THERMAL_COMPONENTACPI_MODULE_NAME("thermal");MODULE_AUTHOR("Paul Diefenbaugh");MODULE_DESCRIPTION("ACPI Thermal Zone Driver");MODULE_LICENSE("GPL");static int act;module_param(act, int, 0644);MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");static int crt;module_param(crt, int, 0644);MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");static int tzp;module_param(tzp, int, 0444);MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");static int nocrt;module_param(nocrt, int, 0);MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");static int off;module_param(off, int, 0);MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");static int psv;module_param(psv, int, 0644);MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");static int acpi_thermal_add(struct acpi_device *device);static int acpi_thermal_remove(struct acpi_device *device, int type);static int acpi_thermal_resume(struct acpi_device *device);static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);static ssize_t acpi_thermal_write_cooling_mode(struct file *,					       const char __user *, size_t,					       loff_t *);static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,					  size_t, loff_t *);static const struct acpi_device_id  thermal_device_ids[] = {	{ACPI_THERMAL_HID, 0},	{"", 0},};MODULE_DEVICE_TABLE(acpi, thermal_device_ids);static struct acpi_driver acpi_thermal_driver = {	.name = "thermal",	.class = ACPI_THERMAL_CLASS,	.ids = thermal_device_ids,	.ops = {		.add = acpi_thermal_add,		.remove = acpi_thermal_remove,		.resume = acpi_thermal_resume,		},};struct acpi_thermal_state {	u8 critical:1;	u8 hot:1;	u8 passive:1;	u8 active:1;	u8 reserved:4;	int active_index;};struct acpi_thermal_state_flags {	u8 valid:1;	u8 enabled:1;	u8 reserved:6;};struct acpi_thermal_critical {	struct acpi_thermal_state_flags flags;	unsigned long temperature;};struct acpi_thermal_hot {	struct acpi_thermal_state_flags flags;	unsigned long temperature;};struct acpi_thermal_passive {	struct acpi_thermal_state_flags flags;	unsigned long temperature;	unsigned long tc1;	unsigned long tc2;	unsigned long tsp;	struct acpi_handle_list devices;};struct acpi_thermal_active {	struct acpi_thermal_state_flags flags;	unsigned long temperature;	struct acpi_handle_list devices;};struct acpi_thermal_trips {	struct acpi_thermal_critical critical;	struct acpi_thermal_hot hot;	struct acpi_thermal_passive passive;	struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];};struct acpi_thermal_flags {	u8 cooling_mode:1;	/* _SCP */	u8 devices:1;		/* _TZD */	u8 reserved:6;};struct acpi_thermal {	struct acpi_device * device;	acpi_bus_id name;	unsigned long temperature;	unsigned long last_temperature;	unsigned long polling_frequency;	volatile u8 zombie;	struct acpi_thermal_flags flags;	struct acpi_thermal_state state;	struct acpi_thermal_trips trips;	struct acpi_handle_list devices;	struct timer_list timer;	struct mutex lock;};static const struct file_operations acpi_thermal_state_fops = {	.open = acpi_thermal_state_open_fs,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};static const struct file_operations acpi_thermal_temp_fops = {	.open = acpi_thermal_temp_open_fs,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};static const struct file_operations acpi_thermal_trip_fops = {	.open = acpi_thermal_trip_open_fs,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};static const struct file_operations acpi_thermal_cooling_fops = {	.open = acpi_thermal_cooling_open_fs,	.read = seq_read,	.write = acpi_thermal_write_cooling_mode,	.llseek = seq_lseek,	.release = single_release,};static const struct file_operations acpi_thermal_polling_fops = {	.open = acpi_thermal_polling_open_fs,	.read = seq_read,	.write = acpi_thermal_write_polling,	.llseek = seq_lseek,	.release = single_release,};/* --------------------------------------------------------------------------                             Thermal Zone Management   -------------------------------------------------------------------------- */static int acpi_thermal_get_temperature(struct acpi_thermal *tz){	acpi_status status = AE_OK;	if (!tz)		return -EINVAL;	tz->last_temperature = tz->temperature;	status =	    acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);	if (ACPI_FAILURE(status))		return -ENODEV;	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",			  tz->temperature));	return 0;}static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz){	acpi_status status = AE_OK;	if (!tz)		return -EINVAL;	status =	    acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,				  &tz->polling_frequency);	if (ACPI_FAILURE(status))		return -ENODEV;	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",			  tz->polling_frequency));	return 0;}static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds){	if (!tz)		return -EINVAL;	tz->polling_frequency = seconds * 10;	/* Convert value to deci-seconds */	ACPI_DEBUG_PRINT((ACPI_DB_INFO,			  "Polling frequency set to %lu seconds\n",			  tz->polling_frequency/10));	return 0;}static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode){	acpi_status status = AE_OK;	union acpi_object arg0 = { ACPI_TYPE_INTEGER };	struct acpi_object_list arg_list = { 1, &arg0 };	acpi_handle handle = NULL;	if (!tz)		return -EINVAL;	status = acpi_get_handle(tz->device->handle, "_SCP", &handle);	if (ACPI_FAILURE(status)) {		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));		return -ENODEV;	}	arg0.integer.value = mode;	status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);	if (ACPI_FAILURE(status))		return -ENODEV;	return 0;}static int acpi_thermal_get_trip_points(struct acpi_thermal *tz){	acpi_status status = AE_OK;	int i = 0;	if (!tz)		return -EINVAL;	/* Critical Shutdown (required) */	status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,				       &tz->trips.critical.temperature);	if (ACPI_FAILURE(status)) {		tz->trips.critical.flags.valid = 0;		ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));		return -ENODEV;	} else {		tz->trips.critical.flags.valid = 1;		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "Found critical threshold [%lu]\n",				  tz->trips.critical.temperature));	}	if (tz->trips.critical.flags.valid == 1) {		if (crt == -1) {			tz->trips.critical.flags.valid = 0;		} else if (crt > 0) {			unsigned long crt_k = CELSIUS_TO_KELVIN(crt);			/*			 * Allow override to lower critical threshold			 */			if (crt_k < tz->trips.critical.temperature)				tz->trips.critical.temperature = crt_k;		}	}	/* Critical Sleep (optional) */	status =	    acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,				  &tz->trips.hot.temperature);	if (ACPI_FAILURE(status)) {		tz->trips.hot.flags.valid = 0;		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));	} else {		tz->trips.hot.flags.valid = 1;		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",				  tz->trips.hot.temperature));	}	/* Passive: Processors (optional) */	if (psv == -1) {		status = AE_SUPPORT;	} else if (psv > 0) {		tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);		status = AE_OK;	} else {		status = acpi_evaluate_integer(tz->device->handle,			"_PSV", NULL, &tz->trips.passive.temperature);	}	if (ACPI_FAILURE(status)) {		tz->trips.passive.flags.valid = 0;		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));	} else {		tz->trips.passive.flags.valid = 1;		status =		    acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,					  &tz->trips.passive.tc1);		if (ACPI_FAILURE(status))			tz->trips.passive.flags.valid = 0;		status =		    acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,					  &tz->trips.passive.tc2);		if (ACPI_FAILURE(status))			tz->trips.passive.flags.valid = 0;		status =		    acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,					  &tz->trips.passive.tsp);		if (ACPI_FAILURE(status))			tz->trips.passive.flags.valid = 0;		status =		    acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,					    &tz->trips.passive.devices);		if (ACPI_FAILURE(status))			tz->trips.passive.flags.valid = 0;		if (!tz->trips.passive.flags.valid)			printk(KERN_WARNING PREFIX "Invalid passive threshold\n");		else			ACPI_DEBUG_PRINT((ACPI_DB_INFO,					  "Found passive threshold [%lu]\n",					  tz->trips.passive.temperature));	}	/* Active: Fans, etc. (optional) */	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {		char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };		if (act == -1)			break;	/* disable all active trip points */		status = acpi_evaluate_integer(tz->device->handle,			name, NULL, &tz->trips.active[i].temperature);		if (ACPI_FAILURE(status)) {			if (i == 0)	/* no active trip points */				break;			if (act <= 0)	/* no override requested */				break;			if (i == 1) {	/* 1 trip point */				tz->trips.active[0].temperature =					CELSIUS_TO_KELVIN(act);			} else {	/* multiple trips */				/*				 * Don't allow override higher than				 * the next higher trip point				 */				tz->trips.active[i - 1].temperature =				    (tz->trips.active[i - 2].temperature <					CELSIUS_TO_KELVIN(act) ?					tz->trips.active[i - 2].temperature :					CELSIUS_TO_KELVIN(act));			}			break;		}		name[2] = 'L';		status =		    acpi_evaluate_reference(tz->device->handle, name, NULL,					    &tz->trips.active[i].devices);		if (ACPI_SUCCESS(status)) {			tz->trips.active[i].flags.valid = 1;			ACPI_DEBUG_PRINT((ACPI_DB_INFO,					  "Found active threshold [%d]:[%lu]\n",					  i, tz->trips.active[i].temperature));		} else			ACPI_EXCEPTION((AE_INFO, status,					"Invalid active threshold [%d]", i));	}	return 0;}static int acpi_thermal_get_devices(struct acpi_thermal *tz){	acpi_status status = AE_OK;	if (!tz)		return -EINVAL;	status =	    acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);	if (ACPI_FAILURE(status))		return -ENODEV;	return 0;}static int acpi_thermal_critical(struct acpi_thermal *tz){	if (!tz || !tz->trips.critical.flags.valid || nocrt)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -