summaryrefslogtreecommitdiffstats
path: root/drivers/misc/thinkpad_acpi.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-04-24 11:48:15 -0300
committerLen Brown <len.brown@intel.com>2007-04-25 02:00:27 -0400
commit40ca9fdf8aa7d929e2b8939be1e6380d107381e1 (patch)
tree285d9e5a577b87064ecb06ee7aea46e206d1a3ac /drivers/misc/thinkpad_acpi.c
parent7252374a39d794879f5e47bcfa0a16e7599b27b5 (diff)
ACPI: thinkpad-acpi: protect fan and hotkey data structures
Add proper mutex locking to some data structures access subject to races due to concurrent access of driver functions on the hotkey and fan subdrivers. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r--drivers/misc/thinkpad_acpi.c114
1 files changed, 87 insertions, 27 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index ca6d15cdc5f..aa69ff0c1c9 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -704,6 +704,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
IBM_ACPIHANDLE_INIT(hkey);
+ mutex_init(&hotkey_mutex);
/* hotkey not supported on 570 */
tp_features.hotkey = hkey_handle != NULL;
@@ -752,6 +753,9 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
}
}
+/*
+ * Call with hotkey_mutex held
+ */
static int hotkey_get(int *status, int *mask)
{
if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
@@ -764,6 +768,9 @@ static int hotkey_get(int *status, int *mask)
return 0;
}
+/*
+ * Call with hotkey_mutex held
+ */
static int hotkey_set(int status, int mask)
{
int i;
@@ -792,7 +799,11 @@ static int hotkey_read(char *p)
return len;
}
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
res = hotkey_get(&status, &mask);
+ mutex_unlock(&hotkey_mutex);
if (res)
return res;
@@ -818,10 +829,15 @@ static int hotkey_write(char *buf)
if (!tp_features.hotkey)
return -ENODEV;
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
+
res = hotkey_get(&status, &mask);
if (res)
- return res;
+ goto errexit;
+ res = 0;
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "enable") == 0) {
status = 1;
@@ -834,18 +850,19 @@ static int hotkey_write(char *buf)
/* mask set */
} else if (sscanf(cmd, "%x", &mask) == 1) {
/* mask set */
- } else
- return -EINVAL;
+ } else {
+ res = -EINVAL;
+ goto errexit;
+ }
do_cmd = 1;
}
- if (do_cmd) {
+ if (do_cmd)
res = hotkey_set(status, mask);
- if (res)
- return res;
- }
- return 0;
+errexit:
+ mutex_unlock(&hotkey_mutex);
+ return res;
}
static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
@@ -2575,6 +2592,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
{
vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+ mutex_init(&fan_mutex);
fan_status_access_mode = TPACPI_FAN_NONE;
fan_control_access_mode = TPACPI_FAN_WR_NONE;
fan_control_commands = 0;
@@ -2764,10 +2782,17 @@ static void fan_watchdog_reset(void)
static int fan_set_level(int level)
{
+ int res;
+
switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_SFAN:
if (level >= 0 && level <= 7) {
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+ res = mutex_lock_interruptible(&fan_mutex);
+ if (res < 0)
+ return res;
+ res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level);
+ mutex_unlock(&fan_mutex);
+ if (!res)
return -EIO;
} else
return -EINVAL;
@@ -2780,7 +2805,12 @@ static int fan_set_level(int level)
((level < 0) || (level > 7)))
return -EINVAL;
- if (!acpi_ec_write(fan_status_offset, level))
+ res = mutex_lock_interruptible(&fan_mutex);
+ if (res < 0)
+ return res;
+ res = acpi_ec_write(fan_status_offset, level);
+ mutex_unlock(&fan_mutex);
+ if (!res)
return -EIO;
else
tp_features.fan_ctrl_status_undef = 0;
@@ -2797,25 +2827,33 @@ static int fan_set_enable(void)
u8 s;
int rc;
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_FANS:
case TPACPI_FAN_WR_TPEC:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
/* Don't go out of emergency fan mode */
if (s != 7)
s = TP_EC_FAN_AUTO;
if (!acpi_ec_write(fan_status_offset, s))
- return -EIO;
- else
+ rc = -EIO;
+ else {
tp_features.fan_ctrl_status_undef = 0;
+ rc = 0;
+ }
break;
case TPACPI_FAN_WR_ACPI_SFAN:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
s &= 0x07;
@@ -2824,53 +2862,75 @@ static int fan_set_enable(void)
s = 4;
if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
- return -EIO;
+ rc= -EIO;
+ else
+ rc = 0;
break;
default:
- return -ENXIO;
+ rc = -ENXIO;
}
- return 0;
+
+ mutex_unlock(&fan_mutex);
+ return rc;
}
static int fan_set_disable(void)
{
+ int rc;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_FANS:
case TPACPI_FAN_WR_TPEC:
if (!acpi_ec_write(fan_status_offset, 0x00))
- return -EIO;
+ rc = -EIO;
else
tp_features.fan_ctrl_status_undef = 0;
break;
case TPACPI_FAN_WR_ACPI_SFAN:
if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
- return -EIO;
+ rc = -EIO;
break;
default:
- return -ENXIO;
+ rc = -ENXIO;
}
- return 0;
+
+ mutex_unlock(&fan_mutex);
+ return rc;
}
static int fan_set_speed(int speed)
{
+ int rc;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
switch (fan_control_access_mode) {
case TPACPI_FAN_WR_ACPI_FANS:
if (speed >= 0 && speed <= 65535) {
if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
speed, speed, speed))
- return -EIO;
+ rc = -EIO;
} else
- return -EINVAL;
+ rc = -EINVAL;
break;
default:
- return -ENXIO;
+ rc = -ENXIO;
}
- return 0;
+
+ mutex_unlock(&fan_mutex);
+ return rc;
}
static int fan_read(char *p)