Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 44973
b: refs/heads/master
c: 16663a8
h: refs/heads/master
i:
  44971: d8331a8
v: v3
  • Loading branch information
Henrique de Moraes Holschuh authored and Len Brown committed Dec 7, 2006
1 parent 8b7071d commit 2ab20d2
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 778b4d742b210b9cac31f223527f30f1fc70312b
refs/heads/master: 16663a87ad1df7022661bc8813b7a2e84e7f5e66
20 changes: 20 additions & 0 deletions trunk/Documentation/ibm-acpi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,26 @@ example:

modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable

The ibm-acpi kernel driver can be programmed to revert the fan level
to a safe setting if userspace does not issue one of the fan commands:
"enable", "disable", "level" or "watchdog" within a configurable
ammount of time. To do this, use the "watchdog" command.

echo 'watchdog <interval>' > /proc/acpi/ibm/fan

Interval is the ammount of time in seconds to wait for one of the
above mentioned fan commands before reseting the fan level to a safe
one. If set to zero, the watchdog is disabled (default). When the
watchdog timer runs out, it does the exact equivalent of the "enable"
fan command.

Note that the watchdog timer stops after it enables the fan. It will
be rearmed again automatically (using the same interval) when one of
the above mentioned fan commands is received. The fan watchdog is,
therefore, not suitable to protect against fan mode changes made
through means other than the "enable", "disable", and "level" fan
commands.


Example Configuration
---------------------
Expand Down
70 changes: 67 additions & 3 deletions trunk/drivers/acpi/ibm_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@
#include <linux/backlight.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>

#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
Expand Down Expand Up @@ -348,7 +350,8 @@ enum fan_control_access_mode {
enum fan_control_commands {
IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd */
IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
* and also watchdog cmd */
};

enum { /* Fan control constants */
Expand Down Expand Up @@ -1797,12 +1800,17 @@ static enum fan_control_commands fan_control_commands;
static int fan_control_status_known;
static u8 fan_control_initial_status;

static void fan_watchdog_fire(void *ignored);
static int fan_watchdog_maxinterval;
static DECLARE_WORK(fan_watchdog_task, fan_watchdog_fire, NULL);

static int fan_init(void)
{
fan_status_access_mode = IBMACPI_FAN_NONE;
fan_control_access_mode = IBMACPI_FAN_WR_NONE;
fan_control_commands = 0;
fan_control_status_known = 1;
fan_watchdog_maxinterval = 0;

if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
Expand Down Expand Up @@ -1934,6 +1942,31 @@ static int fan_get_speed(unsigned int *speed)
return 0;
}

static void fan_exit(void)
{
cancel_delayed_work(&fan_watchdog_task);
flush_scheduled_work();
}

static void fan_watchdog_reset(void)
{
static int fan_watchdog_active = 0;

if (fan_watchdog_active)
cancel_delayed_work(&fan_watchdog_task);

if (fan_watchdog_maxinterval > 0) {
fan_watchdog_active = 1;
if (!schedule_delayed_work(&fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
* 1000))) {
printk(IBM_ERR "failed to schedule the fan watchdog, "
"watchdog will not trigger\n");
}
} else
fan_watchdog_active = 0;
}

static int fan_read(char *p)
{
int len = 0;
Expand Down Expand Up @@ -2007,7 +2040,9 @@ static int fan_read(char *p)
}

if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
len += sprintf(p + len, "commands:\tenable, disable\n");
len += sprintf(p + len, "commands:\tenable, disable\n"
"commands:\twatchdog <timeout> (<timeout> is 0 (off), "
"1-120 (seconds))\n");

if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
len += sprintf(p + len, "commands:\tspeed <speed>"
Expand Down Expand Up @@ -2186,6 +2221,21 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
return 1;
}

static int fan_write_cmd_watchdog(const char *cmd, int *rc)
{
int interval;

if (sscanf(cmd, "watchdog %d", &interval) != 1)
return 0;

if (interval < 0 || interval > 120)
*rc = -EINVAL;
else
fan_watchdog_maxinterval = interval;

return 1;
}

static int fan_write(char *buf)
{
char *cmd;
Expand All @@ -2196,16 +2246,29 @@ static int fan_write(char *buf)
fan_write_cmd_level(cmd, &rc)) &&
!((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
(fan_write_cmd_enable(cmd, &rc) ||
fan_write_cmd_disable(cmd, &rc))) &&
fan_write_cmd_disable(cmd, &rc) ||
fan_write_cmd_watchdog(cmd, &rc))) &&
!((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
fan_write_cmd_speed(cmd, &rc))
)
rc = -EINVAL;
else if (!rc)
fan_watchdog_reset();
}

return rc;
}

static void fan_watchdog_fire(void *ignored)
{
printk(IBM_NOTICE "fan watchdog: enabling fan\n");
if (fan_set_enable()) {
printk(IBM_ERR "fan watchdog: error while enabling fan\n");
/* reschedule for later */
fan_watchdog_reset();
}
}

static struct ibm_struct ibms[] = {
{
.name = "driver",
Expand Down Expand Up @@ -2317,6 +2380,7 @@ static struct ibm_struct ibms[] = {
.read = fan_read,
.write = fan_write,
.init = fan_init,
.exit = fan_exit,
.experimental = 1,
},
};
Expand Down

0 comments on commit 2ab20d2

Please sign in to comment.