fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / i386 / kernel / apm.c
index 0ff65ab..1990169 100644 (file)
  *   (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]
+ *    http://www.microsoft.com/whdc/archive/amp_12.mspx]
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/poll.h>
 #include <linux/time.h>
 #include <linux/sched.h>
 #include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/kthread.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
+#include <asm/i8253.h>
+#include <asm/paravirt.h>
 
 #include "io_ports.h"
 
-extern spinlock_t i8253_lock;
 extern unsigned long get_cmos_time(void);
 extern void machine_real_restart(unsigned char *, int);
 
@@ -301,17 +304,6 @@ extern int (*console_blank_hook)(int);
 
 #include "apm.h"
 
-/*
- * Define to make all _set_limit calls use 64k limits.  The APM 1.1 BIOS is
- * supposed to provide limit information that it recognizes.  Many machines
- * do this correctly, but many others do not restrict themselves to their
- * claimed limit.  When this happens, they will cause a segmentation
- * violation in the kernel at boot time.  Most BIOS's, however, will
- * respect a 64k limit, so we use that.  If you want to be pedantic and
- * hold your BIOS to its claims, then undefine this.
- */
-#define APM_RELAX_SEGMENTS
-
 /*
  * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
  * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
@@ -346,10 +338,10 @@ extern int (*console_blank_hook)(int);
 struct apm_user {
        int             magic;
        struct apm_user *       next;
-       int             suser: 1;
-       int             writer: 1;
-       int             reader: 1;
-       int             suspend_wait: 1;
+       unsigned int    suser: 1;
+       unsigned int    writer: 1;
+       unsigned int    reader: 1;
+       unsigned int    suspend_wait: 1;
        int             suspend_result;
        int             suspends_pending;
        int             standbys_pending;
@@ -383,14 +375,14 @@ static struct {
        unsigned short  segment;
 }                              apm_bios_entry;
 static int                     clock_slowed;
-static int                     idle_threshold = DEFAULT_IDLE_THRESHOLD;
-static int                     idle_period = DEFAULT_IDLE_PERIOD;
+static int                     idle_threshold __read_mostly = DEFAULT_IDLE_THRESHOLD;
+static int                     idle_period __read_mostly = DEFAULT_IDLE_PERIOD;
 static int                     set_pm_idle;
 static int                     suspends_pending;
 static int                     standbys_pending;
 static int                     ignore_sys_suspend;
 static int                     ignore_normal_resume;
-static int                     bounce_interval = DEFAULT_BOUNCE_INTERVAL;
+static int                     bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
 
 #ifdef CONFIG_APM_RTC_IS_GMT
 #      define  clock_cmos_diff 0
@@ -399,8 +391,8 @@ static int                  bounce_interval = DEFAULT_BOUNCE_INTERVAL;
 static long                    clock_cmos_diff;
 static int                     got_clock_diff;
 #endif
-static int                     debug;
-static int                     smp;
+static int                     debug __read_mostly;
+static int                     smp __read_mostly;
 static int                     apm_disabled = -1;
 #ifdef CONFIG_SMP
 static int                     power_off;
@@ -412,8 +404,6 @@ static int                  realmode_power_off = 1;
 #else
 static int                     realmode_power_off;
 #endif
-static int                     exit_kapmd;
-static int                     kapmd_running;
 #ifdef CONFIG_APM_ALLOW_INTS
 static int                     allow_ints = 1;
 #else
@@ -425,15 +415,17 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
 static struct apm_user *       user_list;
 static DEFINE_SPINLOCK(user_list_lock);
-static struct desc_struct      bad_bios_desc = { 0, 0x00409200 };
+static const struct desc_struct        bad_bios_desc = { 0, 0x00409200 };
 
-static char                    driver_version[] = "1.16ac";    /* no spaces */
+static const char              driver_version[] = "1.16ac";    /* no spaces */
+
+static struct task_struct *kapmd_task;
 
 /*
  *     APM event names taken from the APM 1.2 specification. These are
  *     the message codes that the BIOS uses to tell us about events
  */
-static char *  apm_event_name[] = {
+static const char *    const apm_event_name[] = {
        "system standby",
        "system suspend",
        "normal resume",
@@ -447,8 +439,7 @@ static char *       apm_event_name[] = {
        "system standby resume",
        "capabilities change"
 };
-#define NR_APM_EVENT_NAME      \
-               (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
+#define NR_APM_EVENT_NAME ARRAY_SIZE(apm_event_name)
 
 typedef struct lookup_t {
        int     key;
@@ -479,7 +470,7 @@ static const lookup_t error_table[] = {
        { APM_NO_ERROR,         "BIOS did not set a return code" },
        { APM_NOT_PRESENT,      "No APM present" }
 };
-#define ERROR_COUNT    (sizeof(error_table)/sizeof(lookup_t))
+#define ERROR_COUNT    ARRAY_SIZE(error_table)
 
 /**
  *     apm_error       -       display an APM error
@@ -550,12 +541,31 @@ static inline void apm_restore_cpus(cpumask_t mask)
  * Also, we KNOW that for the non error case of apm_bios_call, there
  * is no useful data returned in the low order 8 bits of eax.
  */
-#define APM_DO_CLI     \
-       if (apm_info.allow_ints) \
-               local_irq_enable(); \
-       else \
+
+static inline unsigned long __apm_irq_save(void)
+{
+       unsigned long flags;
+       local_save_flags(flags);
+       if (apm_info.allow_ints) {
+               if (irqs_disabled_flags(flags))
+                       local_irq_enable();
+       } else
                local_irq_disable();
 
+       return flags;
+}
+
+#define apm_irq_save(flags) \
+       do { flags = __apm_irq_save(); } while (0)
+
+static inline void apm_irq_restore(unsigned long flags)
+{
+       if (irqs_disabled_flags(flags))
+               local_irq_disable();
+       else if (irqs_disabled())
+               local_irq_enable();
+}
+
 #ifdef APM_ZERO_SEGS
 #      define APM_DECL_SEGS \
                unsigned int saved_fs; unsigned int saved_gs;
@@ -597,20 +607,21 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
        cpumask_t               cpus;
        int                     cpu;
        struct desc_struct      save_desc_40;
+       struct desc_struct      *gdt;
 
        cpus = apm_save_cpus();
        
        cpu = get_cpu();
-       save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8];
-       per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc;
+       gdt = get_cpu_gdt_table(cpu);
+       save_desc_40 = gdt[0x40 / 8];
+       gdt[0x40 / 8] = bad_bios_desc;
 
-       local_save_flags(flags);
-       APM_DO_CLI;
+       apm_irq_save(flags);
        APM_DO_SAVE_SEGS;
        apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi);
        APM_DO_RESTORE_SEGS;
-       local_irq_restore(flags);
-       per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = save_desc_40;
+       apm_irq_restore(flags);
+       gdt[0x40 / 8] = save_desc_40;
        put_cpu();
        apm_restore_cpus(cpus);
        
@@ -624,7 +635,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
  *     @ecx_in: ECX register value for BIOS call
  *     @eax: EAX register on return from the BIOS call
  *
- *     Make a BIOS call that does only returns one value, or just status.
+ *     Make a BIOS call that returns one value only, or just status.
  *     If there is an error, then the error code is returned in AH
  *     (bits 8-15 of eax) and this function returns non-zero. This is
  *     used for simpler BIOS operations. This call may hold interrupts
@@ -639,21 +650,21 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
        cpumask_t               cpus;
        int                     cpu;
        struct desc_struct      save_desc_40;
-
+       struct desc_struct      *gdt;
 
        cpus = apm_save_cpus();
        
        cpu = get_cpu();
-       save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8];
-       per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc;
+       gdt = get_cpu_gdt_table(cpu);
+       save_desc_40 = gdt[0x40 / 8];
+       gdt[0x40 / 8] = bad_bios_desc;
 
-       local_save_flags(flags);
-       APM_DO_CLI;
+       apm_irq_save(flags);
        APM_DO_SAVE_SEGS;
        error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax);
        APM_DO_RESTORE_SEGS;
-       local_irq_restore(flags);
-       __get_cpu_var(cpu_gdt_table)[0x40 / 8] = save_desc_40;
+       apm_irq_restore(flags);
+       gdt[0x40 / 8] = save_desc_40;
        put_cpu();
        apm_restore_cpus(cpus);
        return error;
@@ -767,8 +778,30 @@ static int set_system_power_state(u_short state)
 static int apm_do_idle(void)
 {
        u32     eax;
+       u8      ret = 0;
+       int     idled = 0;
+       int     polling;
 
-       if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
+       polling = !!(current_thread_info()->status & TS_POLLING);
+       if (polling) {
+               current_thread_info()->status &= ~TS_POLLING;
+               /*
+                * TS_POLLING-cleared state must be visible before we
+                * test NEED_RESCHED:
+                */
+               smp_mb();
+       }
+       if (!need_resched()) {
+               idled = 1;
+               ret = apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax);
+       }
+       if (polling)
+               current_thread_info()->status |= TS_POLLING;
+
+       if (!idled)
+               return 0;
+
+       if (ret) {
                static unsigned long t;
 
                /* This always fails on some SMP boards running UP kernels.
@@ -811,9 +844,7 @@ static void apm_do_busy(void)
 #define IDLE_CALC_LIMIT   (HZ * 100)
 #define IDLE_LEAKY_MAX    16
 
-static void (*original_pm_idle)(void);
-
-extern void default_idle(void);
+static void (*original_pm_idle)(void) __read_mostly;
 
 /**
  * apm_cpu_idle                -       cpu idling for APM capable Linux
@@ -911,14 +942,7 @@ static void apm_power_off(void)
                0xcd, 0x15              /* int   $0x15       */
        };
 
-       /*
-        * This may be called on an SMP machine.
-        */
-#ifdef CONFIG_SMP
        /* Some bioses don't like being called from CPU != 0 */
-       set_cpus_allowed(current, cpumask_of_cpu(0));
-       BUG_ON(smp_processor_id() != 0);
-#endif
        if (apm_info.realmode_power_off)
        {
                (void)apm_save_cpus();
@@ -1061,21 +1085,23 @@ static int apm_engage_power_management(u_short device, int enable)
  
 static int apm_console_blank(int blank)
 {
-       int     error;
-       u_short state;
+       int error = APM_NOT_ENGAGED; /* silence gcc */
+       int i;
+       u_short state;
+       static const u_short dev[3] = { 0x100, 0x1FF, 0x101 };
 
        state = blank ? APM_STATE_STANDBY : APM_STATE_READY;
-       /* Blank the first display device */
-       error = set_power_state(0x100, state);
-       if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {
-               /* try to blank them all instead */
-               error = set_power_state(0x1ff, state);
-               if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))
-                       /* try to blank device one instead */
-                       error = set_power_state(0x101, state);
+
+       for (i = 0; i < ARRAY_SIZE(dev); i++) {
+               error = set_power_state(dev[i], state);
+
+               if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
+                       return 1;
+
+               if (error == APM_NOT_ENGAGED)
+                       break;
        }
-       if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
-               return 1;
+
        if (error == APM_NOT_ENGAGED) {
                static int tried;
                int eng_error;
@@ -1101,7 +1127,8 @@ static int queue_empty(struct apm_user *as)
 
 static apm_event_t get_queued_event(struct apm_user *as)
 {
-       as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+       if (++as->event_tail >= APM_MAX_EVENTS)
+               as->event_tail = 0;
        return as->events[as->event_tail];
 }
 
@@ -1115,13 +1142,16 @@ static void queue_event(apm_event_t event, struct apm_user *sender)
        for (as = user_list; as != NULL; as = as->next) {
                if ((as == sender) || (!as->reader))
                        continue;
-               as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
+               if (++as->event_head >= APM_MAX_EVENTS)
+                       as->event_head = 0;
+
                if (as->event_head == as->event_tail) {
                        static int notified;
 
                        if (notified++ == 0)
                            printk(KERN_ERR "apm: an event queue overflowed\n");
-                       as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
+                       if (++as->event_tail >= APM_MAX_EVENTS)
+                               as->event_tail = 0;
                }
                as->events[as->event_head] = event;
                if ((!as->suser) || (!as->writer))
@@ -1147,9 +1177,11 @@ out:
 
 static void set_time(void)
 {
+       struct timespec ts;
        if (got_clock_diff) {   /* Must know time zone in order to set clock */
-               xtime.tv_sec = get_cmos_time() + clock_cmos_diff;
-               xtime.tv_nsec = 0; 
+               ts.tv_sec = get_cmos_time() + clock_cmos_diff;
+               ts.tv_nsec = 0;
+               do_settimeofday(&ts);
        } 
 }
 
@@ -1168,8 +1200,7 @@ static void get_time_diff(void)
 static void reinit_timer(void)
 {
 #ifdef INIT_TIMER_AFTER_SUSPEND
-       unsigned long   flags;
-       extern spinlock_t i8253_lock;
+       unsigned long flags;
 
        spin_lock_irqsave(&i8253_lock, flags);
        /* set the clock to 100 Hz */
@@ -1226,13 +1257,8 @@ static int suspend(int vetoable)
        restore_processor_state();
 
        local_irq_disable();
-       write_seqlock(&xtime_lock);
-       spin_lock(&i8253_lock);
-       reinit_timer();
        set_time();
-
-       spin_unlock(&i8253_lock);
-       write_sequnlock(&xtime_lock);
+       reinit_timer();
 
        if (err == APM_NO_ERROR)
                err = APM_SUCCESS;
@@ -1280,7 +1306,7 @@ static void standby(void)
 static apm_event_t get_event(void)
 {
        int             error;
-       apm_event_t     event;
+       apm_event_t     event = APM_NO_EVENTS; /* silence gcc */
        apm_eventinfo_t info;
 
        static int notified;
@@ -1359,9 +1385,7 @@ static void check_events(void)
                        ignore_bounce = 1;
                        if ((event != APM_NORMAL_RESUME)
                            || (ignore_normal_resume == 0)) {
-                               write_seqlock_irq(&xtime_lock);
                                set_time();
-                               write_sequnlock_irq(&xtime_lock);
                                device_resume();
                                pm_send_all(PM_RESUME, (void *)0);
                                queue_event(event, NULL);
@@ -1377,9 +1401,7 @@ static void check_events(void)
                        break;
 
                case APM_UPDATE_TIME:
-                       write_seqlock_irq(&xtime_lock);
                        set_time();
-                       write_sequnlock_irq(&xtime_lock);
                        break;
 
                case APM_CRITICAL_SUSPEND:
@@ -1424,7 +1446,7 @@ static void apm_mainloop(void)
        set_current_state(TASK_INTERRUPTIBLE);
        for (;;) {
                schedule_timeout(APM_CHECK_TIMEOUT);
-               if (exit_kapmd)
+               if (kthread_should_stop())
                        break;
                /*
                 * Ok, check all events, check for idle (and mark us sleeping
@@ -1586,7 +1608,7 @@ static int do_open(struct inode * inode, struct file * filp)
 {
        struct apm_user *       as;
 
-       as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
+       as = kmalloc(sizeof(*as), GFP_KERNEL);
        if (as == NULL) {
                printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
                       sizeof(*as));
@@ -1707,12 +1729,6 @@ static int apm(void *unused)
        char *          power_stat;
        char *          bat_stat;
 
-       kapmd_running = 1;
-
-       daemonize("kapmd");
-
-       current->flags |= PF_NOFREEZE;
-
 #ifdef CONFIG_SMP
        /* 2002/08/01 - WT
         * This is to avoid random crashes at boot time during initialization
@@ -1822,7 +1838,6 @@ static int apm(void *unused)
                console_blank_hook = NULL;
 #endif
        }
-       kapmd_running = 0;
 
        return 0;
 }
@@ -2220,12 +2235,12 @@ static struct dmi_system_id __initdata apm_dmi_table[] = {
 static int __init apm_init(void)
 {
        struct proc_dir_entry *apm_proc;
-       int ret;
-       int i;
+       struct desc_struct *gdt;
+       int err;
 
        dmi_check_system(apm_dmi_table);
 
-       if (apm_info.bios.version == 0) {
+       if (apm_info.bios.version == 0 || paravirt_enabled()) {
                printk(KERN_INFO "apm: BIOS not found.\n");
                return -ENODEV;
        }
@@ -2288,7 +2303,9 @@ static int __init apm_init(void)
                apm_info.disabled = 1;
                return -ENODEV;
        }
+#ifdef CONFIG_PM_LEGACY
        pm_active = 1;
+#endif
 
        /*
         * Set up a segment that references the real mode segment 0x40
@@ -2299,54 +2316,46 @@ static int __init apm_init(void)
        set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
        _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
 
+       /*
+        * Set up the long jump entry point to the APM BIOS, which is called
+        * from inline assembly.
+        */
        apm_bios_entry.offset = apm_info.bios.offset;
        apm_bios_entry.segment = APM_CS;
 
-       for (i = 0; i < NR_CPUS; i++) {
-               set_base(per_cpu(cpu_gdt_table, i)[APM_CS >> 3],
-                        __va((unsigned long)apm_info.bios.cseg << 4));
-               set_base(per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3],
-                        __va((unsigned long)apm_info.bios.cseg_16 << 4));
-               set_base(per_cpu(cpu_gdt_table, i)[APM_DS >> 3],
-                        __va((unsigned long)apm_info.bios.dseg << 4));
-#ifndef APM_RELAX_SEGMENTS
-               if (apm_info.bios.version == 0x100) {
-#endif
-                       /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 - 1);
-                       /* For some unknown machine. */
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], 64 * 1024 - 1);
-                       /* For the DEC Hinote Ultra CT475 (and others?) */
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], 64 * 1024 - 1);
-#ifndef APM_RELAX_SEGMENTS
-               } else {
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3],
-                               (apm_info.bios.cseg_len - 1) & 0xffff);
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3],
-                               (apm_info.bios.cseg_16_len - 1) & 0xffff);
-                       _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3],
-                               (apm_info.bios.dseg_len - 1) & 0xffff);
-                     /* workaround for broken BIOSes */
-                       if (apm_info.bios.cseg_len <= apm_info.bios.offset)
-                               _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 -1);
-                       if (apm_info.bios.dseg_len <= 0x40) { /* 0x40 * 4kB == 64kB */
-                               /* for the BIOS that assumes granularity = 1 */
-                               per_cpu(cpu_gdt_table, i)[APM_DS >> 3].b |= 0x800000;
-                               printk(KERN_NOTICE "apm: we set the granularity of dseg.\n");
-                       }
-               }
-#endif
-       }
+       /*
+        * The APM 1.1 BIOS is supposed to provide limit information that it
+        * recognizes.  Many machines do this correctly, but many others do
+        * not restrict themselves to their claimed limit.  When this happens,
+        * they will cause a segmentation violation in the kernel at boot time.
+        * Most BIOS's, however, will respect a 64k limit, so we use that.
+        *
+        * Note we only set APM segments on CPU zero, since we pin the APM
+        * code to that CPU.
+        */
+       gdt = get_cpu_gdt_table(0);
+       set_base(gdt[APM_CS >> 3],
+                __va((unsigned long)apm_info.bios.cseg << 4));
+       set_base(gdt[APM_CS_16 >> 3],
+                __va((unsigned long)apm_info.bios.cseg_16 << 4));
+       set_base(gdt[APM_DS >> 3],
+                __va((unsigned long)apm_info.bios.dseg << 4));
 
        apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
        if (apm_proc)
                apm_proc->owner = THIS_MODULE;
 
-       ret = kernel_thread(apm, NULL, CLONE_KERNEL | SIGCHLD);
-       if (ret < 0) {
-               printk(KERN_ERR "apm: disabled - Unable to start kernel thread.\n");
-               return -ENOMEM;
+       kapmd_task = kthread_create(apm, NULL, "kapmd");
+       if (IS_ERR(kapmd_task)) {
+               printk(KERN_ERR "apm: disabled - Unable to start kernel "
+                               "thread.\n");
+               err = PTR_ERR(kapmd_task);
+               kapmd_task = NULL;
+               remove_proc_entry("apm", NULL);
+               return err;
        }
+       kapmd_task->flags |= PF_NOFREEZE;
+       wake_up_process(kapmd_task);
 
        if (num_online_cpus() > 1 && !smp ) {
                printk(KERN_NOTICE
@@ -2354,7 +2363,13 @@ static int __init apm_init(void)
                return 0;
        }
 
-       misc_register(&apm_device);
+       /*
+        * Note we don't actually care if the misc_device cannot be registered.
+        * this driver can do its job without it, even if userspace can't
+        * control it.  just log the error
+        */
+       if (misc_register(&apm_device))
+               printk(KERN_WARNING "apm: Could not register misc device.\n");
 
        if (HZ != 100)
                idle_period = (idle_period * HZ) / 100;
@@ -2390,10 +2405,13 @@ static void __exit apm_exit(void)
        remove_proc_entry("apm", NULL);
        if (power_off)
                pm_power_off = NULL;
-       exit_kapmd = 1;
-       while (kapmd_running)
-               schedule();
+       if (kapmd_task) {
+               kthread_stop(kapmd_task);
+               kapmd_task = NULL;
+       }
+#ifdef CONFIG_PM_LEGACY
        pm_active = 0;
+#endif
 }
 
 module_init(apm_init);