#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/sched.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>
#define ACPI_THERMAL_COMPONENT 0x04000000
#define ACPI_THERMAL_CLASS "thermal_zone"
-#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver"
#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
#define ACPI_THERMAL_FILE_STATE "state"
#define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_MODE_PASSIVE 0x01
-#define ACPI_THERMAL_MODE_CRITICAL 0xff
-#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
#define _COMPONENT ACPI_THERMAL_COMPONENT
-ACPI_MODULE_NAME("acpi_thermal")
+ACPI_MODULE_NAME("thermal");
MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
+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, 0);
-MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+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, int state);
+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 ssize_t acpi_thermal_write_trip_points(struct file *,
- const char __user *, size_t,
- loff_t *);
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,
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 = ACPI_THERMAL_DRIVER_NAME,
+ .name = "thermal",
.class = ACPI_THERMAL_CLASS,
- .ids = ACPI_THERMAL_HID,
+ .ids = thermal_device_ids,
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
};
struct acpi_thermal {
- acpi_handle handle;
+ struct acpi_device * device;
acpi_bus_id name;
unsigned long temperature;
unsigned long last_temperature;
unsigned long polling_frequency;
- u8 cooling_mode;
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 struct file_operations acpi_thermal_state_fops = {
+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 struct file_operations acpi_thermal_temp_fops = {
+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 struct file_operations acpi_thermal_trip_fops = {
+static const struct file_operations acpi_thermal_trip_fops = {
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
- .write = acpi_thermal_write_trip_points,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_thermal_cooling_fops = {
+static const struct file_operations acpi_thermal_cooling_fops = {
.open = acpi_thermal_cooling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_cooling_mode,
.release = single_release,
};
-static struct file_operations acpi_thermal_polling_fops = {
+static const struct file_operations acpi_thermal_polling_fops = {
.open = acpi_thermal_polling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_polling,
tz->last_temperature = tz->temperature;
status =
- acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
+ acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
if (ACPI_FAILURE(status))
return -ENODEV;
return -EINVAL;
status =
- acpi_evaluate_integer(tz->handle, "_TZP", NULL,
+ 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 set to %lu seconds\n",
- tz->polling_frequency));
+ tz->polling_frequency/10));
return 0;
}
if (!tz)
return -EINVAL;
- status = acpi_get_handle(tz->handle, "_SCP", &handle);
+ 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;
if (ACPI_FAILURE(status))
return -ENODEV;
- tz->cooling_mode = mode;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
- mode ? "passive" : "active"));
-
return 0;
}
/* Critical Shutdown (required) */
- status = acpi_evaluate_integer(tz->handle, "_CRT", NULL,
+ status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
&tz->trips.critical.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.critical.flags.valid = 0;
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->handle, "_HOT", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
&tz->trips.hot.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0;
/* Passive: Processors (optional) */
- status =
- acpi_evaluate_integer(tz->handle, "_PSV", NULL,
- &tz->trips.passive.temperature);
+ 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"));
tz->trips.passive.flags.valid = 1;
status =
- acpi_evaluate_integer(tz->handle, "_TC1", NULL,
+ 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->handle, "_TC2", NULL,
+ 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->handle, "_TSP", NULL,
+ 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->handle, "_PSL", NULL,
+ acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
&tz->trips.passive.devices);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
- status =
- acpi_evaluate_integer(tz->handle, name, NULL,
- &tz->trips.active[i].temperature);
- if (ACPI_FAILURE(status))
+ 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->handle, name, NULL,
+ acpi_evaluate_reference(tz->device->handle, name, NULL,
&tz->trips.active[i].devices);
if (ACPI_SUCCESS(status)) {
tz->trips.active[i].flags.valid = 1;
return -EINVAL;
status =
- acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
+ acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
-static int acpi_thermal_call_usermode(char *path)
-{
- char *argv[2] = { NULL, NULL };
- char *envp[3] = { NULL, NULL, NULL };
-
-
- if (!path)
- return -EINVAL;
-
- argv[0] = path;
-
- /* minimal command environment */
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- call_usermodehelper(argv[0], argv, envp, 0);
-
- return 0;
-}
-
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
-
- if (!tz || !tz->trips.critical.flags.valid)
+ if (!tz || !tz->trips.critical.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
} else if (tz->trips.critical.flags.enabled)
tz->trips.critical.flags.enabled = 0;
- result = acpi_bus_get_device(tz->handle, &device);
- if (result)
- return result;
-
printk(KERN_EMERG
"Critical temperature reached (%ld C), shutting down.\n",
KELVIN_TO_CELSIUS(tz->temperature));
- acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL,
+ acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id,
+ ACPI_THERMAL_NOTIFY_CRITICAL,
+ tz->trips.critical.flags.enabled);
- acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+ orderly_poweroff(true);
return 0;
}
static int acpi_thermal_hot(struct acpi_thermal *tz)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
-
- if (!tz || !tz->trips.hot.flags.valid)
+ if (!tz || !tz->trips.hot.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
} else if (tz->trips.hot.flags.enabled)
tz->trips.hot.flags.enabled = 0;
- result = acpi_bus_get_device(tz->handle, &device);
- if (result)
- return result;
-
- acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT,
+ acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id,
+ ACPI_THERMAL_NOTIFY_HOT,
+ tz->trips.hot.flags.enabled);
/* TBD: Call user-mode "sleep(S4)" function */
static void acpi_thermal_check(void *data)
{
int result = 0;
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
+ struct acpi_thermal *tz = data;
unsigned long sleep_time = 0;
+ unsigned long timeout_jiffies = 0;
int i = 0;
struct acpi_thermal_state state;
return;
}
+ /* Check if someone else is already running */
+ if (!mutex_trylock(&tz->lock))
+ return;
+
state = tz->state;
result = acpi_thermal_get_temperature(tz);
if (result)
- return;
+ goto unlock;
memset(&tz->state, 0, sizeof(tz->state));
* a thermal event occurs). Note that _TSP and _TZD values are
* given in 1/10th seconds (we must covert to milliseconds).
*/
- if (tz->state.passive)
+ if (tz->state.passive) {
sleep_time = tz->trips.passive.tsp * 100;
- else if (tz->polling_frequency > 0)
+ timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
+ } else if (tz->polling_frequency > 0) {
sleep_time = tz->polling_frequency * 100;
+ timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
tz->name, tz->temperature, sleep_time));
del_timer(&(tz->timer));
} else {
if (timer_pending(&(tz->timer)))
- mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
+ mod_timer(&(tz->timer), timeout_jiffies);
else {
tz->timer.data = (unsigned long)tz;
tz->timer.function = acpi_thermal_run;
- tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+ tz->timer.expires = timeout_jiffies;
add_timer(&(tz->timer));
}
}
-
- return;
+ unlock:
+ mutex_unlock(&tz->lock);
}
/* --------------------------------------------------------------------------
static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
{
int result = 0;
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
+ struct acpi_device *device;
+ acpi_status status;
+
int i = 0;
int j = 0;
goto end;
if (tz->trips.critical.flags.valid)
- seq_printf(seq, "critical (S5): %ld C\n",
- KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
+ seq_printf(seq, "critical (S5): %ld C%s",
+ KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
+ nocrt ? " <disabled>\n" : "\n");
if (tz->trips.hot.flags.valid)
- seq_printf(seq, "hot (S4): %ld C\n",
- KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
+ seq_printf(seq, "hot (S4): %ld C%s",
+ KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
+ nocrt ? " <disabled>\n" : "\n");
if (tz->trips.passive.flags.valid) {
seq_printf(seq,
tz->trips.passive.tc1, tz->trips.passive.tc2,
tz->trips.passive.tsp);
for (j = 0; j < tz->trips.passive.devices.count; j++) {
-
- seq_printf(seq, "0x%p ",
- tz->trips.passive.devices.handles[j]);
+ status = acpi_bus_get_device(tz->trips.passive.devices.
+ handles[j], &device);
+ seq_printf(seq, "%4.4s ", status ? "" :
+ acpi_device_bid(device));
}
seq_puts(seq, "\n");
}
seq_printf(seq, "active[%d]: %ld C: devices=",
i,
KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
- for (j = 0; j < tz->trips.active[i].devices.count; j++)
- seq_printf(seq, "0x%p ",
- tz->trips.active[i].devices.handles[j]);
+ for (j = 0; j < tz->trips.active[i].devices.count; j++){
+ status = acpi_bus_get_device(tz->trips.active[i].
+ devices.handles[j],
+ &device);
+ seq_printf(seq, "%4.4s ", status ? "" :
+ acpi_device_bid(device));
+ }
seq_puts(seq, "\n");
}
return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
}
-static ssize_t
-acpi_thermal_write_trip_points(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
-
- char *limit_string;
- int num, critical, hot, passive;
- int *active;
- int i = 0;
-
-
- limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
- if (!limit_string)
- return -ENOMEM;
-
- memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
-
- active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
- if (!active) {
- kfree(limit_string);
- return -ENOMEM;
- }
-
- if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
- count = -EINVAL;
- goto end;
- }
-
- if (copy_from_user(limit_string, buffer, count)) {
- count = -EFAULT;
- goto end;
- }
-
- limit_string[count] = '\0';
-
- num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
- &critical, &hot, &passive,
- &active[0], &active[1], &active[2], &active[3], &active[4],
- &active[5], &active[6], &active[7], &active[8],
- &active[9]);
- if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
- count = -EINVAL;
- goto end;
- }
-
- tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
- tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
- for (i = 0; i < num - 3; i++) {
- if (!(tz->trips.active[i].flags.valid))
- break;
- tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
- }
-
- end:
- kfree(active);
- kfree(limit_string);
- return count;
-}
-
static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
goto end;
- if (!tz->flags.cooling_mode) {
+ if (!tz->flags.cooling_mode)
seq_puts(seq, "<setting not supported>\n");
- }
-
- if (tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL)
- seq_printf(seq, "cooling mode: critical\n");
else
- seq_printf(seq, "cooling mode: %s\n",
- tz->cooling_mode ? "passive" : "active");
+ seq_puts(seq, "0 - Active; 1 - Passive\n");
end:
return 0;
const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_thermal *tz = m->private;
int result = 0;
char mode_string[12] = { '\0' };
static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ struct acpi_thermal *tz = seq->private;
if (!tz)
const char __user * buffer,
size_t count, loff_t * ppos)
{
- struct seq_file *m = (struct seq_file *)file->private_data;
- struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ struct seq_file *m = file->private_data;
+ struct acpi_thermal *tz = m->private;
int result = 0;
char polling_string[12] = { '\0' };
int seconds = 0;
entry->owner = THIS_MODULE;
}
- /* 'trip_points' [R/W] */
+ /* 'trip_points' [R] */
entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
- S_IFREG | S_IRUGO | S_IWUSR,
+ S_IRUGO,
acpi_device_dir(device));
if (!entry)
return -ENODEV;
static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
+ struct acpi_thermal *tz = data;
struct acpi_device *device = NULL;
if (!tz)
return;
- if (acpi_bus_get_device(tz->handle, &device))
- return;
+ device = tz->device;
switch (event) {
case ACPI_THERMAL_NOTIFY_TEMPERATURE:
case ACPI_THERMAL_NOTIFY_THRESHOLDS:
acpi_thermal_get_trip_points(tz);
acpi_thermal_check(tz);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
case ACPI_THERMAL_NOTIFY_DEVICES:
if (tz->flags.devices)
acpi_thermal_get_devices(tz);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
if (!result)
tz->flags.cooling_mode = 1;
- else {
- /* Oh,we have not _SCP method.
- Generally show cooling_mode by _ACx, _PSV,spec 12.2 */
- tz->flags.cooling_mode = 0;
- if (tz->trips.active[0].flags.valid
- && tz->trips.passive.flags.valid) {
- if (tz->trips.passive.temperature >
- tz->trips.active[0].temperature)
- tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
- else
- tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
- } else if (!tz->trips.active[0].flags.valid
- && tz->trips.passive.flags.valid) {
- tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
- } else if (tz->trips.active[0].flags.valid
- && !tz->trips.passive.flags.valid) {
- tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
- } else {
- /* _ACx and _PSV are optional, but _CRT is required */
- tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL;
- }
- }
/* Get default polling frequency [_TZP] (optional) */
if (tzp)
if (!device)
return -EINVAL;
- tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
+ tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
if (!tz)
return -ENOMEM;
- memset(tz, 0, sizeof(struct acpi_thermal));
- tz->handle = device->handle;
+ tz->device = device;
strcpy(tz->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz;
-
+ mutex_init(&tz->lock);
result = acpi_thermal_get_info(tz);
if (result)
goto end;
acpi_thermal_check(tz);
- status = acpi_install_notify_handler(tz->handle,
+ status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify, tz);
if (ACPI_FAILURE(status)) {
if (!device || !acpi_driver_data(device))
return -EINVAL;
- tz = (struct acpi_thermal *)acpi_driver_data(device);
+ tz = acpi_driver_data(device);
/* avoid timer adding new defer task */
tz->zombie = 1;
/* deferred task may reinsert timer */
del_timer_sync(&(tz->timer));
- status = acpi_remove_notify_handler(tz->handle,
+ status = acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify);
}
acpi_thermal_remove_fs(device);
-
+ mutex_destroy(&tz->lock);
kfree(tz);
return 0;
}
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
+ int i, j, power_state, result;
+
if (!device || !acpi_driver_data(device))
return -EINVAL;
- tz = (struct acpi_thermal *)acpi_driver_data(device);
+ tz = acpi_driver_data(device);
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ if (!(&tz->trips.active[i]))
+ break;
+ if (!tz->trips.active[i].flags.valid)
+ break;
+ tz->trips.active[i].flags.enabled = 1;
+ for (j = 0; j < tz->trips.active[i].devices.count; j++) {
+ result = acpi_bus_get_power(tz->trips.active[i].devices.
+ handles[j], &power_state);
+ if (result || (power_state != ACPI_STATE_D0)) {
+ tz->trips.active[i].flags.enabled = 0;
+ break;
+ }
+ }
+ tz->state.active |= tz->trips.active[i].flags.enabled;
+ }
acpi_thermal_check(tz);
return AE_OK;
}
+#ifdef CONFIG_DMI
+static int thermal_act(const struct dmi_system_id *d) {
+
+ if (act == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all active thermal trip points\n", d->ident);
+ act = -1;
+ }
+ return 0;
+}
+static int thermal_nocrt(const struct dmi_system_id *d) {
+
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all critical thermal trip point actions.\n", d->ident);
+ nocrt = 1;
+ return 0;
+}
+static int thermal_tzp(const struct dmi_system_id *d) {
+
+ if (tzp == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "enabling thermal zone polling\n", d->ident);
+ tzp = 300; /* 300 dS = 30 Seconds */
+ }
+ return 0;
+}
+static int thermal_psv(const struct dmi_system_id *d) {
+
+ if (psv == 0) {
+ printk(KERN_NOTICE "ACPI: %s detected: "
+ "disabling all passive thermal trip points\n", d->ident);
+ psv = -1;
+ }
+ return 0;
+}
+
+static struct dmi_system_id thermal_dmi_table[] __initdata = {
+ /*
+ * Award BIOS on this AOpen makes thermal control almost worthless.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=8842
+ */
+ {
+ .callback = thermal_act,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_psv,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_tzp,
+ .ident = "AOpen i915GMm-HFS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+ DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+ },
+ },
+ {
+ .callback = thermal_nocrt,
+ .ident = "Gigabyte GA-7ZX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
+ },
+ },
+ {}
+};
+#endif /* CONFIG_DMI */
+
static int __init acpi_thermal_init(void)
{
int result = 0;
+ dmi_check_system(thermal_dmi_table);
+ if (off) {
+ printk(KERN_NOTICE "ACPI: thermal control disabled\n");
+ return -ENODEV;
+ }
acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
if (!acpi_thermal_dir)
return -ENODEV;