#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_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
MODULE_LICENSE("GPL");
static int tzp;
-module_param(tzp, int, 0);
+module_param(tzp, int, 0444);
MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+static int nocrt;
+module_param(nocrt, int, 0);
+MODULE_PARM_DESC(nocrt, "Set to disable action on ACPI thermal zone critical and hot trips.\n");
+
+static int off;
+module_param(off, int, 0);
+MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.\n");
+
+static int psv;
+module_param(psv, int, 0644);
+MODULE_PARM_DESC(psv, "Disable or override all passive trip points.\n");
+
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 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 = ACPI_THERMAL_HID,
+ .ids = thermal_device_ids,
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
/* Passive: Processors (optional) */
- status =
- acpi_evaluate_integer(tz->device->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"));
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)
{
- if (!tz || !tz->trips.critical.flags.valid)
+ if (!tz || !tz->trips.critical.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
acpi_bus_generate_event(tz->device, 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)
{
- if (!tz || !tz->trips.hot.flags.valid)
+ if (!tz || !tz->trips.hot.flags.valid || nocrt)
return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
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,
{
int result = 0;
-
+ 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;