Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
new file mode 100644
index 0000000..d6c0177
--- /dev/null
+++ b/drivers/acpi/sleep/Makefile
@@ -0,0 +1,5 @@
+obj-y					:= poweroff.o wakeup.o
+obj-$(CONFIG_ACPI_SLEEP)		+= main.o
+obj-$(CONFIG_ACPI_SLEEP_PROC_FS)	+= proc.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
new file mode 100644
index 0000000..0a5d2a9
--- /dev/null
+++ b/drivers/acpi/sleep/main.c
@@ -0,0 +1,234 @@
+/*
+ * sleep.c - ACPI sleep support.
+ *
+ * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
+ * Copyright (c) 2000-2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <asm/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include "sleep.h"
+
+u8 sleep_states[ACPI_S_STATE_COUNT];
+
+static struct pm_ops acpi_pm_ops;
+
+extern void do_suspend_lowlevel_s4bios(void);
+extern void do_suspend_lowlevel(void);
+
+static u32 acpi_suspend_states[] = {
+	[PM_SUSPEND_ON]		= ACPI_STATE_S0,
+	[PM_SUSPEND_STANDBY]	= ACPI_STATE_S1,
+	[PM_SUSPEND_MEM]	= ACPI_STATE_S3,
+	[PM_SUSPEND_DISK]	= ACPI_STATE_S4,
+};
+
+static int init_8259A_after_S1;
+
+/**
+ *	acpi_pm_prepare - Do preliminary suspend work.
+ *	@pm_state:		suspend state we're entering.
+ *
+ *	Make sure we support the state. If we do, and we need it, set the
+ *	firmware waking vector and do arch-specific nastiness to get the 
+ *	wakeup code to the waking vector. 
+ */
+
+static int acpi_pm_prepare(suspend_state_t pm_state)
+{
+	u32 acpi_state = acpi_suspend_states[pm_state];
+
+	if (!sleep_states[acpi_state])
+		return -EPERM;
+
+	/* do we have a wakeup address for S2 and S3? */
+	/* Here, we support only S4BIOS, those we set the wakeup address */
+	/* S4OS is only supported for now via swsusp.. */
+	if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) {
+		if (!acpi_wakeup_address)
+			return -EFAULT;
+		acpi_set_firmware_waking_vector(
+			(acpi_physical_address) virt_to_phys(
+				(void *)acpi_wakeup_address));
+	}
+	ACPI_FLUSH_CPU_CACHE();
+	acpi_enable_wakeup_device_prep(acpi_state);
+	acpi_enter_sleep_state_prep(acpi_state);
+	return 0;
+}
+
+
+/**
+ *	acpi_pm_enter - Actually enter a sleep state.
+ *	@pm_state:		State we're entering.
+ *
+ *	Flush caches and go to sleep. For STR or STD, we have to call 
+ *	arch-specific assembly, which in turn call acpi_enter_sleep_state().
+ *	It's unfortunate, but it works. Please fix if you're feeling frisky.
+ */
+
+static int acpi_pm_enter(suspend_state_t pm_state)
+{
+	acpi_status status = AE_OK;
+	unsigned long flags = 0;
+	u32 acpi_state = acpi_suspend_states[pm_state];
+
+	ACPI_FLUSH_CPU_CACHE();
+
+	/* Do arch specific saving of state. */
+	if (pm_state > PM_SUSPEND_STANDBY) {
+		int error = acpi_save_state_mem();
+		if (error)
+			return error;
+	}
+
+
+	local_irq_save(flags);
+	acpi_enable_wakeup_device(acpi_state);
+	switch (pm_state)
+	{
+	case PM_SUSPEND_STANDBY:
+		barrier();
+		status = acpi_enter_sleep_state(acpi_state);
+		break;
+
+	case PM_SUSPEND_MEM:
+		do_suspend_lowlevel();
+		break;
+
+	case PM_SUSPEND_DISK:
+		if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
+			status = acpi_enter_sleep_state(acpi_state);
+		else
+			do_suspend_lowlevel_s4bios();
+		break;
+	default:
+		return -EINVAL;
+	}
+	local_irq_restore(flags);
+	printk(KERN_DEBUG "Back to C!\n");
+
+	/* restore processor state
+	 * We should only be here if we're coming back from STR or STD.
+	 * And, in the case of the latter, the memory image should have already
+	 * been loaded from disk.
+	 */
+	if (pm_state > PM_SUSPEND_STANDBY)
+		acpi_restore_state_mem();
+
+
+	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+
+/**
+ *	acpi_pm_finish - Finish up suspend sequence.
+ *	@pm_state:		State we're coming out of.
+ *
+ *	This is called after we wake back up (or if entering the sleep state
+ *	failed). 
+ */
+
+static int acpi_pm_finish(suspend_state_t pm_state)
+{
+	u32 acpi_state = acpi_suspend_states[pm_state];
+
+	acpi_leave_sleep_state(acpi_state);
+	acpi_disable_wakeup_device(acpi_state);
+
+	/* reset firmware waking vector */
+	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+	if (init_8259A_after_S1) {
+		printk("Broken toshiba laptop -> kicking interrupts\n");
+		init_8259A(0);
+	}
+	return 0;
+}
+
+
+int acpi_suspend(u32 acpi_state)
+{
+	suspend_state_t states[] = {
+		[1]	= PM_SUSPEND_STANDBY,
+		[3]	= PM_SUSPEND_MEM,
+		[4]	= PM_SUSPEND_DISK,
+	};
+
+	if (acpi_state <= 4 && states[acpi_state])
+		return pm_suspend(states[acpi_state]);
+	return -EINVAL;
+}
+
+static struct pm_ops acpi_pm_ops = {
+	.prepare	= acpi_pm_prepare,
+	.enter		= acpi_pm_enter,
+	.finish		= acpi_pm_finish,
+};
+
+
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(struct dmi_system_id *d)
+{
+	printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+	init_8259A_after_S1 = 1;
+	return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+	{
+		.callback = init_ints_after_s1,
+		.ident = "Toshiba Satellite 4030cdt",
+		.matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), },
+	},
+	{ },
+};
+
+static int __init acpi_sleep_init(void)
+{
+	int			i = 0;
+
+	dmi_check_system(acpisleep_dmi_table);
+
+	if (acpi_disabled)
+		return 0;
+
+	printk(KERN_INFO PREFIX "(supports");
+	for (i=0; i < ACPI_S_STATE_COUNT; i++) {
+		acpi_status status;
+		u8 type_a, type_b;
+		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+		if (ACPI_SUCCESS(status)) {
+			sleep_states[i] = 1;
+			printk(" S%d", i);
+		}
+		if (i == ACPI_STATE_S4) {
+			if (acpi_gbl_FACS->S4bios_f) {
+				sleep_states[i] = 1;
+				printk(" S4bios");
+				acpi_pm_ops.pm_disk_mode = PM_DISK_FIRMWARE;
+			}
+			if (sleep_states[i])
+				acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
+		}
+	}
+	printk(")\n");
+
+	pm_set_ops(&acpi_pm_ops);
+	return 0;
+}
+
+late_initcall(acpi_sleep_init);
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
new file mode 100644
index 0000000..da23775
--- /dev/null
+++ b/drivers/acpi/sleep/poweroff.c
@@ -0,0 +1,39 @@
+/*
+ * poweroff.c - ACPI handler for powering off the system.
+ *
+ * AKA S5, but it is independent of whether or not the kernel supports
+ * any other sleep support in the system.
+ */
+
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <acpi/acpi_bus.h>
+#include <linux/sched.h>
+#include "sleep.h"
+
+static void
+acpi_power_off (void)
+{
+	printk("%s called\n",__FUNCTION__);
+	/* Some SMP machines only can poweroff in boot CPU */
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	acpi_wakeup_gpe_poweroff_prepare();
+	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
+	ACPI_DISABLE_IRQS();
+	acpi_enter_sleep_state(ACPI_STATE_S5);
+}
+
+static int acpi_poweroff_init(void)
+{
+	if (!acpi_disabled) {
+		u8 type_a, type_b;
+		acpi_status status;
+
+		status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+		if (ACPI_SUCCESS(status))
+			pm_power_off = acpi_power_off;
+	}
+	return 0;
+}
+
+late_initcall(acpi_poweroff_init);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
new file mode 100644
index 0000000..fd7c5a0
--- /dev/null
+++ b/drivers/acpi/sleep/proc.c
@@ -0,0 +1,509 @@
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/suspend.h>
+#include <linux/bcd.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#ifdef CONFIG_X86
+#include <linux/mc146818rtc.h>
+#endif
+
+#include "sleep.h"
+
+#define ACPI_SYSTEM_FILE_SLEEP		"sleep"
+#define ACPI_SYSTEM_FILE_ALARM		"alarm"
+#define ACPI_SYSTEM_FILE_WAKEUP_DEVICE   "wakeup"
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("sleep")
+
+
+static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
+{
+	int			i;
+
+	ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show");
+
+	for (i = 0; i <= ACPI_STATE_S5; i++) {
+		if (sleep_states[i]) {
+			seq_printf(seq,"S%d ", i);
+			if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f)
+				seq_printf(seq, "S4bios ");
+		}
+	}
+
+	seq_puts(seq, "\n");
+
+	return 0;
+}
+
+static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_system_write_sleep (
+	struct file		*file,
+	const char __user	*buffer,
+	size_t			count,
+	loff_t			*ppos)
+{
+	char	str[12];
+	u32	state = 0;
+	int	error = 0;
+
+	if (count > sizeof(str) - 1)
+		goto Done;
+	memset(str,0,sizeof(str));
+	if (copy_from_user(str, buffer, count))
+		return -EFAULT;
+
+	/* Check for S4 bios request */
+	if (!strcmp(str,"4b")) {
+		error = acpi_suspend(4);
+		goto Done;
+	}
+	state = simple_strtoul(str, NULL, 0);
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	if (state == 4) {
+		error = software_suspend();
+		goto Done;
+	}
+#endif
+	error = acpi_suspend(state);
+ Done:
+	return error ? error : count;
+}
+
+static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
+{
+	u32			sec, min, hr;
+	u32			day, mo, yr;
+	unsigned char		rtc_control = 0;
+	unsigned long 		flags;
+
+	ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
+
+	spin_lock_irqsave(&rtc_lock, flags);
+
+	sec = CMOS_READ(RTC_SECONDS_ALARM);
+	min = CMOS_READ(RTC_MINUTES_ALARM);
+	hr = CMOS_READ(RTC_HOURS_ALARM);
+	rtc_control = CMOS_READ(RTC_CONTROL);
+
+	/* If we ever get an FACP with proper values... */
+	if (acpi_gbl_FADT->day_alrm)
+		/* ACPI spec: only low 6 its should be cared */
+		day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+	else
+		day =  CMOS_READ(RTC_DAY_OF_MONTH);
+	if (acpi_gbl_FADT->mon_alrm)
+		mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+	else
+		mo = CMOS_READ(RTC_MONTH);
+	if (acpi_gbl_FADT->century)
+		yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
+	else
+		yr = CMOS_READ(RTC_YEAR);
+
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hr);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mo);
+		BCD_TO_BIN(yr);
+	}
+
+	/* we're trusting the FADT (see above)*/
+	if (!acpi_gbl_FADT->century)
+	/* If we're not trusting the FADT, we should at least make it
+	 * right for _this_ century... ehm, what is _this_ century?
+	 *
+	 * TBD:
+	 *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
+	 *        which we can trust to determine the century correctly. Atom
+	 *        watch driver would be nice, too...
+	 *
+	 *  if that has not happened, change for first release in 2050:
+ 	 *        if (yr<50)
+	 *                yr += 2100;
+	 *        else
+	 *                yr += 2000;   // current line of code
+	 *
+	 *  if that has not happened either, please do on 2099/12/31:23:59:59
+	 *        s/2000/2100
+	 *
+	 */
+		yr += 2000;
+
+	seq_printf(seq,"%4.4u-", yr);
+	(mo > 12)  ? seq_puts(seq, "**-")  : seq_printf(seq, "%2.2u-", mo);
+	(day > 31) ? seq_puts(seq, "** ")  : seq_printf(seq, "%2.2u ", day);
+	(hr > 23)  ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", hr);
+	(min > 59) ? seq_puts(seq, "**:")  : seq_printf(seq, "%2.2u:", min);
+	(sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec);
+
+	return 0;
+}
+
+static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
+}
+
+
+static int
+get_date_field (
+	char			**p,
+	u32			*value)
+{
+	char			*next = NULL;
+	char			*string_end = NULL;
+	int			result = -EINVAL;
+
+	/*
+	 * Try to find delimeter, only to insert null.  The end of the
+	 * string won't have one, but is still valid.
+	 */
+	next = strpbrk(*p, "- :");
+	if (next)
+		*next++ = '\0';
+
+	*value = simple_strtoul(*p, &string_end, 10);
+
+	/* Signal success if we got a good digit */
+	if (string_end != *p)
+		result = 0;
+
+	if (next)
+		*p = next;
+
+	return result;
+}
+
+
+static ssize_t
+acpi_system_write_alarm (
+	struct file		*file,
+	const char __user	*buffer,
+	size_t			count,
+	loff_t			*ppos)
+{
+	int			result = 0;
+	char			alarm_string[30] = {'\0'};
+	char			*p = alarm_string;
+	u32			sec, min, hr, day, mo, yr;
+	int			adjust = 0;
+	unsigned char		rtc_control = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
+
+	if (count > sizeof(alarm_string) - 1)
+		return_VALUE(-EINVAL);
+	
+	if (copy_from_user(alarm_string, buffer, count))
+		return_VALUE(-EFAULT);
+
+	alarm_string[count] = '\0';
+
+	/* check for time adjustment */
+	if (alarm_string[0] == '+') {
+		p++;
+		adjust = 1;
+	}
+
+	if ((result = get_date_field(&p, &yr)))
+		goto end;
+	if ((result = get_date_field(&p, &mo)))
+		goto end;
+	if ((result = get_date_field(&p, &day)))
+		goto end;
+	if ((result = get_date_field(&p, &hr)))
+		goto end;
+	if ((result = get_date_field(&p, &min)))
+		goto end;
+	if ((result = get_date_field(&p, &sec)))
+		goto end;
+
+	if (sec > 59) {
+		min += 1;
+		sec -= 60;
+	}
+	if (min > 59) {
+		hr += 1;
+		min -= 60;
+	}
+	if (hr > 23) {
+		day += 1;
+		hr -= 24;
+	}
+	if (day > 31) {
+		mo += 1;
+		day -= 31;
+	}
+	if (mo > 12) {
+		yr += 1;
+		mo -= 12;
+	}
+
+	spin_lock_irq(&rtc_lock);
+
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(yr);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(hr);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(sec);
+	}
+
+	if (adjust) {
+		yr  += CMOS_READ(RTC_YEAR);
+		mo  += CMOS_READ(RTC_MONTH);
+		day += CMOS_READ(RTC_DAY_OF_MONTH);
+		hr  += CMOS_READ(RTC_HOURS);
+		min += CMOS_READ(RTC_MINUTES);
+		sec += CMOS_READ(RTC_SECONDS);
+	}
+
+	spin_unlock_irq(&rtc_lock);
+
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(yr);
+		BCD_TO_BIN(mo);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(hr);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(sec);
+	}
+
+	if (sec > 59) {
+		min++;
+		sec -= 60;
+	}
+	if (min > 59) {
+		hr++;
+		min -= 60;
+	}
+	if (hr > 23) {
+		day++;
+		hr -= 24;
+	}
+	if (day > 31) {
+		mo++;
+		day -= 31;
+	}
+	if (mo > 12) {
+		yr++;
+		mo -= 12;
+	}
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(yr);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(hr);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(sec);
+	}
+
+	spin_lock_irq(&rtc_lock);
+	/*
+	 * Disable alarm interrupt before setting alarm timer or else
+	 * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs
+	 */
+	rtc_control &= ~RTC_AIE;
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+
+	/* write the fields the rtc knows about */
+	CMOS_WRITE(hr, RTC_HOURS_ALARM);
+	CMOS_WRITE(min, RTC_MINUTES_ALARM);
+	CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+
+	/*
+	 * If the system supports an enhanced alarm it will have non-zero
+	 * offsets into the CMOS RAM here -- which for some reason are pointing
+	 * to the RTC area of memory.
+	 */
+	if (acpi_gbl_FADT->day_alrm)
+		CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
+	if (acpi_gbl_FADT->mon_alrm)
+		CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
+	if (acpi_gbl_FADT->century)
+		CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
+	/* enable the rtc alarm interrupt */
+	rtc_control |= RTC_AIE;
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+
+	spin_unlock_irq(&rtc_lock);
+
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_enable_event(ACPI_EVENT_RTC, 0);
+
+	*ppos += count;
+
+	result = 0;
+end:
+	return_VALUE(result ? result : count);
+}
+
+extern struct list_head	acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+static int
+acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
+{
+	struct list_head * node, * next;
+
+	seq_printf(seq, "Device	Sleep state	Status\n");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+		if (!dev->wakeup.flags.valid)
+			continue;
+		spin_unlock(&acpi_device_lock);
+		if (dev->wakeup.flags.run_wake)
+			seq_printf(seq, "%4s	%4d		%8s\n",
+				dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
+				dev->wakeup.state.enabled ? "*enabled" : "*disabled");
+		else
+			seq_printf(seq, "%4s	%4d		%8s\n",
+				dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
+				dev->wakeup.state.enabled ? "enabled" : "disabled");
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+	return 0;
+}
+
+static ssize_t
+acpi_system_write_wakeup_device (
+	struct file		*file,
+	const char __user	*buffer,
+	size_t			count,
+	loff_t			*ppos)
+{
+	struct list_head * node, * next;
+	char		strbuf[5];
+	char		str[5] = "";
+	int 		len = count;
+	struct acpi_device *found_dev = NULL;
+
+	if (len > 4) len = 4;
+
+	if (copy_from_user(strbuf, buffer, len))
+		return -EFAULT;
+	strbuf[len] = '\0';
+	sscanf(strbuf, "%s", str);
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+		if (!dev->wakeup.flags.valid)
+			continue;
+
+		if (!strncmp(dev->pnp.bus_id, str, 4)) {
+			dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1;
+			found_dev = dev;
+			break;
+		}
+	}
+	if (found_dev) {
+		list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+			struct acpi_device * dev = container_of(node,
+				struct acpi_device, wakeup_list);
+
+			if ((dev != found_dev) &&
+				(dev->wakeup.gpe_number == found_dev->wakeup.gpe_number) &&
+				(dev->wakeup.gpe_device == found_dev->wakeup.gpe_device)) {
+				printk(KERN_WARNING "ACPI: '%s' and '%s' have the same GPE, "
+					"can't disable/enable one seperately\n",
+					dev->pnp.bus_id, found_dev->pnp.bus_id);
+				dev->wakeup.state.enabled = found_dev->wakeup.state.enabled;
+			}
+		}
+	}
+	spin_unlock(&acpi_device_lock);
+	return count;
+}
+
+static int
+acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data);
+}
+
+static struct file_operations acpi_system_wakeup_device_fops = {
+	.open		= acpi_system_wakeup_device_open_fs,
+	.read		= seq_read,
+	.write		= acpi_system_write_wakeup_device,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static struct file_operations acpi_system_sleep_fops = {
+	.open		= acpi_system_sleep_open_fs,
+	.read		= seq_read,
+	.write		= acpi_system_write_sleep,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static struct file_operations acpi_system_alarm_fops = {
+	.open		= acpi_system_alarm_open_fs,
+	.read		= seq_read,
+	.write		= acpi_system_write_alarm,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+
+static u32 rtc_handler(void * context)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+
+	return ACPI_INTERRUPT_HANDLED;
+}
+
+static int acpi_sleep_proc_init(void)
+{
+	struct proc_dir_entry	*entry = NULL;
+
+	if (acpi_disabled)
+		return 0;
+ 
+	/* 'sleep' [R/W]*/
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
+				  S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (entry)
+		entry->proc_fops = &acpi_system_sleep_fops;
+
+	/* 'alarm' [R/W] */
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
+		S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (entry)
+		entry->proc_fops = &acpi_system_alarm_fops;
+
+	/* 'wakeup device' [R/W]*/
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE,
+				  S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (entry)
+		entry->proc_fops = &acpi_system_wakeup_device_fops;
+
+	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+	return 0;
+}
+
+late_initcall(acpi_sleep_proc_init);
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
new file mode 100644
index 0000000..efd0001
--- /dev/null
+++ b/drivers/acpi/sleep/sleep.h
@@ -0,0 +1,8 @@
+
+extern u8 sleep_states[];
+extern int acpi_suspend (u32 state);
+
+extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
+extern void acpi_enable_wakeup_device(u8 sleep_state);
+extern void acpi_disable_wakeup_device(u8 sleep_state);
+extern void acpi_wakeup_gpe_poweroff_prepare(void);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
new file mode 100644
index 0000000..d9b1999
--- /dev/null
+++ b/drivers/acpi/sleep/wakeup.c
@@ -0,0 +1,209 @@
+/*
+ * wakeup.c - support wakeup devices
+ * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <acpi/acevents.h>
+#include "sleep.h"
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("wakeup_devices")
+
+extern struct list_head	acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+#ifdef CONFIG_ACPI_SLEEP
+/**
+ * acpi_enable_wakeup_device_prep - prepare wakeup devices
+ *	@sleep_state:	ACPI state
+ * Enable all wakup devices power if the devices' wakeup level
+ * is higher than requested sleep level
+ */
+
+void
+acpi_enable_wakeup_device_prep(
+	u8		sleep_state)
+{
+	struct list_head * node, * next;
+
+	ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, 
+			struct acpi_device, wakeup_list);
+		
+		if (!dev->wakeup.flags.valid || 
+			!dev->wakeup.state.enabled ||
+			(sleep_state > (u32) dev->wakeup.sleep_state))
+			continue;
+
+		spin_unlock(&acpi_device_lock);
+		acpi_enable_wakeup_device_power(dev);
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_enable_wakeup_device - enable wakeup devices
+ *	@sleep_state:	ACPI state
+ * Enable all wakup devices's GPE
+ */
+void
+acpi_enable_wakeup_device(
+	u8		sleep_state)
+{
+	struct list_head * node, * next;
+
+	/* 
+	 * Caution: this routine must be invoked when interrupt is disabled 
+	 * Refer ACPI2.0: P212
+	 */
+	ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, 
+			struct acpi_device, wakeup_list);
+
+		/* If users want to disable run-wake GPE,
+		 * we only disable it for wake and leave it for runtime
+		 */
+		if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+			spin_unlock(&acpi_device_lock);
+			acpi_set_gpe_type(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+			/* Re-enable it, since set_gpe_type will disable it */
+			acpi_enable_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_ISR);
+			spin_lock(&acpi_device_lock);
+			continue;
+		}
+
+		if (!dev->wakeup.flags.valid ||
+			!dev->wakeup.state.enabled ||
+			(sleep_state > (u32) dev->wakeup.sleep_state))
+			continue;
+
+		spin_unlock(&acpi_device_lock);
+		/* run-wake GPE has been enabled */
+		if (!dev->wakeup.flags.run_wake)
+			acpi_enable_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_ISR);
+		dev->wakeup.state.active = 1;
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_disable_wakeup_device - disable devices' wakeup capability
+ *	@sleep_state:	ACPI state
+ * Disable all wakup devices's GPE and wakeup capability
+ */
+void
+acpi_disable_wakeup_device (
+	u8		sleep_state)
+{
+	struct list_head * node, * next;
+
+	ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, 
+			struct acpi_device, wakeup_list);
+
+		if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+			spin_unlock(&acpi_device_lock);
+			acpi_set_gpe_type(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+			/* Re-enable it, since set_gpe_type will disable it */
+			acpi_enable_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_NOT_ISR);
+			spin_lock(&acpi_device_lock);
+			continue;
+		}
+
+		if (!dev->wakeup.flags.valid || 
+			!dev->wakeup.state.active ||
+			(sleep_state > (u32) dev->wakeup.sleep_state))
+			continue;
+
+		spin_unlock(&acpi_device_lock);
+		acpi_disable_wakeup_device_power(dev);
+		/* Never disable run-wake GPE */
+		if (!dev->wakeup.flags.run_wake) {
+			acpi_disable_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_NOT_ISR);
+			acpi_clear_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_NOT_ISR);
+		}
+		dev->wakeup.state.active = 0;
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+}
+
+static int __init acpi_wakeup_device_init(void)
+{
+	struct list_head * node, * next;
+
+	if (acpi_disabled)
+		return 0;
+	printk("ACPI wakeup devices: \n");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node, 
+			struct acpi_device, wakeup_list);
+		
+		/* In case user doesn't load button driver */
+		if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+			spin_unlock(&acpi_device_lock);
+			acpi_set_gpe_type(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+			acpi_enable_gpe(dev->wakeup.gpe_device, 
+				dev->wakeup.gpe_number, ACPI_NOT_ISR);
+			dev->wakeup.state.enabled = 1;
+			spin_lock(&acpi_device_lock);
+		}
+		printk("%4s ", dev->pnp.bus_id);
+	}
+	spin_unlock(&acpi_device_lock);
+	printk("\n");
+
+	return 0;
+}
+
+late_initcall(acpi_wakeup_device_init);
+#endif
+
+/*
+ * Disable all wakeup GPEs before power off.
+ * 
+ * Since acpi_enter_sleep_state() will disable all
+ * RUNTIME GPEs, we simply mark all GPES that
+ * are not enabled for wakeup from S5 as RUNTIME.
+ */
+void acpi_wakeup_gpe_poweroff_prepare(void)
+{
+	struct list_head * node, * next;
+
+	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+		struct acpi_device * dev = container_of(node,
+			struct acpi_device, wakeup_list);
+
+		/* The GPE can wakeup system from S5, don't touch it */
+		if ((u32)dev->wakeup.sleep_state == ACPI_STATE_S5)
+			continue;
+		/* acpi_set_gpe_type will automatically disable GPE */
+		acpi_set_gpe_type(dev->wakeup.gpe_device,
+			dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+	}
+}