aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/apm-emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/apm-emulation.c')
-rw-r--r--drivers/char/apm-emulation.c46
1 files changed, 21 insertions, 25 deletions
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 033e1505fca..dd9dfa15e9d 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -7,13 +7,13 @@
* Intel Corporation, Microsoft Corporation. Advanced Power Management
* (APM) BIOS Interface Specification, Revision 1.2, February 1996.
*
- * [This document is available from Microsoft at:
- * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ * This document is available from Microsoft at:
+ * http://www.microsoft.com/whdc/archive/amp_12.mspx
*/
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/miscdevice.h>
@@ -31,7 +31,6 @@
#include <linux/kthread.h>
#include <linux/delay.h>
-#include <asm/system.h>
/*
* The apm_bios device is one of the misc char devices.
@@ -40,10 +39,7 @@
#define APM_MINOR_DEV 134
/*
- * See Documentation/Config.help for the configuration options.
- *
- * Various options can be changed at boot time as follows:
- * (We allow underscores for compatibility with the modules code)
+ * One option can be changed at boot time as follows:
* apm=on/off enable/disable APM
*/
@@ -274,7 +270,6 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
if (!as->suser || !as->writer)
return -EPERM;
- lock_kernel();
switch (cmd) {
case APM_IOC_SUSPEND:
mutex_lock(&state_lock);
@@ -301,17 +296,13 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
/*
* Wait for the suspend/resume to complete. If there
* are pending acknowledges, we wait here for them.
+ * wait_event_freezable() is interruptible and pending
+ * signal can cause busy looping. We aren't doing
+ * anything critical, chill a bit on each iteration.
*/
- freezer_do_not_count();
-
- wait_event(apm_suspend_waitqueue,
- as->suspend_state == SUSPEND_DONE);
-
- /*
- * Since we are waiting until the suspend is done, the
- * try_to_freeze() in freezer_count() will not trigger
- */
- freezer_count();
+ while (wait_event_freezable(apm_suspend_waitqueue,
+ as->suspend_state != SUSPEND_ACKED))
+ msleep(10);
break;
case SUSPEND_ACKTO:
as->suspend_result = -ETIMEDOUT;
@@ -335,7 +326,6 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
mutex_unlock(&state_lock);
break;
}
- unlock_kernel();
return err;
}
@@ -370,7 +360,6 @@ static int apm_open(struct inode * inode, struct file * filp)
{
struct apm_user *as;
- lock_kernel();
as = kzalloc(sizeof(*as), GFP_KERNEL);
if (as) {
/*
@@ -390,7 +379,6 @@ static int apm_open(struct inode * inode, struct file * filp)
filp->private_data = as;
}
- unlock_kernel();
return as ? 0 : -ENOMEM;
}
@@ -402,6 +390,7 @@ static const struct file_operations apm_bios_fops = {
.unlocked_ioctl = apm_ioctl,
.open = apm_open,
.release = apm_release,
+ .llseek = noop_llseek,
};
static struct miscdevice apm_device = {
@@ -542,6 +531,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
{
struct apm_user *as;
int err;
+ unsigned long apm_event;
/* short-cut emergency suspends */
if (atomic_read(&userspace_notification_inhibit))
@@ -549,6 +539,9 @@ static int apm_suspend_notifier(struct notifier_block *nb,
switch (event) {
case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ apm_event = (event == PM_SUSPEND_PREPARE) ?
+ APM_USER_SUSPEND : APM_USER_HIBERNATION;
/*
* Queue an event to all "writer" users that we want
* to suspend and need their ack.
@@ -561,7 +554,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
as->writer && as->suser) {
as->suspend_state = SUSPEND_PENDING;
atomic_inc(&suspend_acks_pending);
- queue_add_event(&as->queue, APM_USER_SUSPEND);
+ queue_add_event(&as->queue, apm_event);
}
}
@@ -609,14 +602,17 @@ static int apm_suspend_notifier(struct notifier_block *nb,
return NOTIFY_OK;
/* interrupted by signal */
- return NOTIFY_BAD;
+ return notifier_from_errno(err);
case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ apm_event = (event == PM_POST_SUSPEND) ?
+ APM_NORMAL_RESUME : APM_HIBERNATION_RESUME;
/*
* Anyone on the APM queues will think we're still suspended.
* Send a message so everyone knows we're now awake again.
*/
- queue_event(APM_NORMAL_RESUME);
+ queue_event(apm_event);
/*
* Finally, wake up anyone who is sleeping on the suspend.