Pull bugzilla-5534 into test branch
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
index 71aa403..e50595b 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/ibm-acpi.txt
@@ -30,9 +30,10 @@
 	- ACPI sounds
 	- temperature sensors
 	- Experimental: embedded controller register dump
-	- Experimental: LCD brightness control
-	- Experimental: volume control
+	- LCD brightness control
+	- Volume control
 	- Experimental: fan speed, fan enable/disable
+	- Experimental: WAN enable and disable
 
 A compatibility table by model and feature is maintained on the web
 site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -52,40 +53,7 @@
 
 If you are compiling this driver as included in the Linux kernel
 sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
-how to install this driver when downloaded from the web site.
-
-First, you need to get a kernel with ACPI support up and running.
-Please refer to http://acpi.sourceforge.net/ for help with this
-step. How successful you will be depends a lot on you ThinkPad model,
-the kernel you are using and any additional patches applied. The
-kernel provided with your distribution may not be good enough. I
-needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
-ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
-be supported at all.
-
-Assuming you have the basic ACPI support working (e.g. you can see the
-/proc/acpi directory), follow the following steps to install this
-driver:
-
-	- unpack the archive:
-
-		tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
-
-	- compile the driver:
-
-		make
-
-	- install the module in your kernel modules directory:
-
-		make install
-
-	- load the module:
-
-		modprobe ibm_acpi
-
-After loading the module, check the "dmesg" output for any error messages.
-
+ACPI / IBM ThinkPad Laptop Extras).
 
 Features
 --------
@@ -523,13 +491,8 @@
 with this, do send me your results (including some complete dumps with
 a description of the conditions when they were taken.)
 
-EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
------------------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+LCD brightness control -- /proc/acpi/ibm/brightness
+---------------------------------------------------
 
 This feature allows software control of the LCD brightness on ThinkPad
 models which don't have a hardware brightness slider. The available
@@ -542,13 +505,8 @@
 The <level> number range is 0 to 7, although not all of them may be
 distinct. The current brightness level is shown in the file.
 
-EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+Volume control -- /proc/acpi/ibm/volume
+---------------------------------------
 
 This feature allows volume control on ThinkPad models which don't have
 a hardware volume knob. The available commands are:
@@ -611,6 +569,23 @@
 
 	echo 'level <level>' > /proc/acpi/ibm/thermal
 
+EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
+---------------------------------------
+
+This feature is marked EXPERIMENTAL because the implementation
+directly accesses hardware registers and may not work as expected. USE
+WITH CAUTION! To use this feature, you need to supply the
+experimental=1 parameter when loading the module.
+
+This feature shows the presence and current state of a WAN (Sierra
+Wireless EV-DO) device. If WAN is installed, the following commands can
+be used:
+
+	echo enable > /proc/acpi/ibm/wan
+	echo disable > /proc/acpi/ibm/wan
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
 
 Multiple Commands, Module Parameters
 ------------------------------------
diff --git a/MAINTAINERS b/MAINTAINERS
index 1b5430a..a2b6d9f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1998,6 +1998,13 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+MSI LAPTOP SUPPORT
+P:	Lennart Poettering
+M:	mzxreary@0pointer.de
+L:	https://tango.0pointer.de/mailman/listinfo/s270-linux
+W:	http://0pointer.de/lennart/tchibo.html
+S:	Maintained
+
 MTRR AND SIMILAR SUPPORT [i386]
 P:	Richard Gooch
 M:	rgooch@atnf.csiro.au
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
index 25db49e..20563e5 100644
--- a/arch/i386/kernel/acpi/cstate.c
+++ b/arch/i386/kernel/acpi/cstate.c
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/cpu.h>
 
 #include <acpi/processor.h>
 #include <asm/acpi.h>
@@ -41,5 +42,124 @@
 		flags->bm_check = 1;
 	}
 }
-
 EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
+
+/* The code below handles cstate entry with monitor-mwait pair on Intel*/
+
+struct cstate_entry_s {
+	struct {
+		unsigned int eax;
+		unsigned int ecx;
+	} states[ACPI_PROCESSOR_MAX_POWER];
+};
+static struct cstate_entry_s *cpu_cstate_entry;	/* per CPU ptr */
+
+static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
+
+#define MWAIT_SUBSTATE_MASK	(0xf)
+#define MWAIT_SUBSTATE_SIZE	(4)
+
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK	(0x2)
+
+#define MWAIT_ECX_INTERRUPT_BREAK	(0x1)
+
+#define NATIVE_CSTATE_BEYOND_HALT	(2)
+
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+		struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+	struct cstate_entry_s *percpu_entry;
+	struct cpuinfo_x86 *c = cpu_data + cpu;
+
+	cpumask_t saved_mask;
+	int retval;
+	unsigned int eax, ebx, ecx, edx;
+	unsigned int edx_part;
+	unsigned int cstate_type; /* C-state type and not ACPI C-state type */
+	unsigned int num_cstate_subtype;
+
+	if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF )
+		return -1;
+
+	if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
+		return -1;
+
+	percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+	percpu_entry->states[cx->index].eax = 0;
+	percpu_entry->states[cx->index].ecx = 0;
+
+	/* Make sure we are running on right CPU */
+	saved_mask = current->cpus_allowed;
+	retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	if (retval)
+		return -1;
+
+	cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+	/* Check whether this particular cx_type (in CST) is supported or not */
+	cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1;
+	edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
+	num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
+
+	retval = 0;
+	if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
+		retval = -1;
+		goto out;
+	}
+
+	/* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
+	if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+	    !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
+		retval = -1;
+		goto out;
+	}
+	percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
+
+	/* Use the hint in CST */
+	percpu_entry->states[cx->index].eax = cx->address;
+
+	if (!mwait_supported[cstate_type]) {
+		mwait_supported[cstate_type] = 1;
+		printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d "
+		       "state\n", cx->type);
+	}
+
+out:
+	set_cpus_allowed(current, saved_mask);
+	return retval;
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
+
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+{
+	unsigned int cpu = smp_processor_id();
+	struct cstate_entry_s *percpu_entry;
+
+	percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+	mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
+	                      percpu_entry->states[cx->index].ecx);
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
+
+static int __init ffh_cstate_init(void)
+{
+	struct cpuinfo_x86 *c = &boot_cpu_data;
+	if (c->x86_vendor != X86_VENDOR_INTEL)
+		return -1;
+
+	cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
+	return 0;
+}
+
+static void __exit ffh_cstate_exit(void)
+{
+	if (cpu_cstate_entry) {
+		free_percpu(cpu_cstate_entry);
+		cpu_cstate_entry = NULL;
+	}
+}
+
+arch_initcall(ffh_cstate_init);
+__exitcall(ffh_cstate_exit);
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index b0a0780..57d3759 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -236,18 +236,26 @@
  * We execute MONITOR against need_resched and enter optimized wait state
  * through MWAIT. Whenever someone changes need_resched, we would be woken
  * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
  */
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
+{
+	if (!need_resched()) {
+		__monitor((void *)&current_thread_info()->flags, 0, 0);
+		smp_mb();
+		if (!need_resched())
+			__mwait(eax, ecx);
+	}
+}
+
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
 static void mwait_idle(void)
 {
 	local_irq_enable();
-
-	while (!need_resched()) {
-		__monitor((void *)&current_thread_info()->flags, 0, 0);
-		smp_mb();
-		if (need_resched())
-			break;
-		__mwait(0, 0);
-	}
+	while (!need_resched())
+		mwait_idle_with_hints(0, 0);
 }
 
 void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 5e95b25..49f7fac 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -238,18 +238,26 @@
  * We execute MONITOR against need_resched and enter optimized wait state
  * through MWAIT. Whenever someone changes need_resched, we would be woken
  * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
  */
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
+{
+	if (!need_resched()) {
+		__monitor((void *)&current_thread_info()->flags, 0, 0);
+		smp_mb();
+		if (!need_resched())
+			__mwait(eax, ecx);
+	}
+}
+
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
 static void mwait_idle(void)
 {
 	local_irq_enable();
-
-	while (!need_resched()) {
-		__monitor((void *)&current_thread_info()->flags, 0, 0);
-		smp_mb();
-		if (need_resched())
-			break;
-		__mwait(0, 0);
-	}
+	while (!need_resched())
+		mwait_idle_with_hints(0,0);
 }
 
 void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index e9ee4c5..c7ac929 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -138,6 +138,7 @@
 		S2x,		//S200 (J1 reported), Victor MP-XP7210
 		W1N,		//W1000N
 		W5A,		//W5A
+		W3V,            //W3030V
 		xxN,		//M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
 		//(Centrino)
 		END_MODEL
@@ -376,6 +377,17 @@
 	 .display_get = "\\ADVG"},
 
 	{
+	 .name = "W3V",
+	 .mt_mled = "MLED",
+	 .mt_wled = "WLED",
+	 .mt_lcd_switch = xxN_PREFIX "_Q10",
+	 .lcd_status = "\\BKLT",
+	 .brightness_set = "SPLV",
+	 .brightness_get = "GPLV",
+	 .display_set = "SDSP",
+	 .display_get = "\\INFB"},
+
+       {
 	 .name = "xxN",
 	 .mt_mled = "MLED",
 /* WLED present, but not controlled by ACPI */
@@ -555,11 +567,11 @@
 write_led(const char __user * buffer, unsigned long count,
 	  char *ledname, int ledmask, int invert)
 {
-	int value;
+	int rv, value;
 	int led_out = 0;
 
-	count = parse_arg(buffer, count, &value);
-	if (count > 0)
+	rv = parse_arg(buffer, count, &value);
+	if (rv > 0)
 		led_out = value ? 1 : 0;
 
 	hotk->status =
@@ -572,7 +584,7 @@
 		printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
 		       ledname);
 
-	return count;
+	return rv;
 }
 
 /*
@@ -607,20 +619,18 @@
 proc_write_ledd(struct file *file, const char __user * buffer,
 		unsigned long count, void *data)
 {
-	int value;
+	int rv, value;
 
-	count = parse_arg(buffer, count, &value);
-	if (count > 0) {
+	rv = parse_arg(buffer, count, &value);
+	if (rv > 0) {
 		if (!write_acpi_int
 		    (hotk->handle, hotk->methods->mt_ledd, value, NULL))
 			printk(KERN_WARNING
 			       "Asus ACPI: LED display write failed\n");
 		else
 			hotk->ledd_status = (u32) value;
-	} else if (count < 0)
-		printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
-	return count;
+	}
+	return rv;
 }
 
 /*
@@ -761,12 +771,12 @@
 proc_write_lcd(struct file *file, const char __user * buffer,
 	       unsigned long count, void *data)
 {
-	int value;
+	int rv, value;
 
-	count = parse_arg(buffer, count, &value);
-	if (count > 0)
+	rv = parse_arg(buffer, count, &value);
+	if (rv > 0)
 		set_lcd_state(value);
-	return count;
+	return rv;
 }
 
 static int read_brightness(void)
@@ -830,18 +840,15 @@
 proc_write_brn(struct file *file, const char __user * buffer,
 	       unsigned long count, void *data)
 {
-	int value;
+	int rv, value;
 
-	count = parse_arg(buffer, count, &value);
-	if (count > 0) {
+	rv = parse_arg(buffer, count, &value);
+	if (rv > 0) {
 		value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
 		/* 0 <= value <= 15 */
 		set_brightness(value);
-	} else if (count < 0) {
-		printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
 	}
-
-	return count;
+	return rv;
 }
 
 static void set_display(int value)
@@ -880,15 +887,12 @@
 proc_write_disp(struct file *file, const char __user * buffer,
 		unsigned long count, void *data)
 {
-	int value;
+	int rv, value;
 
-	count = parse_arg(buffer, count, &value);
-	if (count > 0)
+	rv = parse_arg(buffer, count, &value);
+	if (rv > 0)
 		set_display(value);
-	else if (count < 0)
-		printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
-	return count;
+	return rv;
 }
 
 typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
@@ -1097,6 +1101,8 @@
 		return A4G;
 	else if (strncmp(model, "W1N", 3) == 0)
 		return W1N;
+	else if (strncmp(model, "W3V", 3) == 0)
+		return W3V;
 	else if (strncmp(model, "W5A", 3) == 0)
 		return W5A;
 	else
@@ -1200,9 +1206,10 @@
 		hotk->methods->mt_wled = NULL;
 	/* L5D's WLED is not controlled by ACPI */
 	else if (strncmp(string, "M2N", 3) == 0 ||
+		 strncmp(string, "W3V", 3) == 0 ||
 		 strncmp(string, "S1N", 3) == 0)
 		hotk->methods->mt_wled = "WLED";
-	/* M2N and S1N have a usable WLED */
+	/* M2N, S1N and W3V have a usable WLED */
 	else if (asus_info) {
 		if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
 			hotk->methods->mled_status = NULL;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 9810e2a..026e4075 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,6 +64,7 @@
 
 static int acpi_battery_add(struct acpi_device *device);
 static int acpi_battery_remove(struct acpi_device *device, int type);
+static int acpi_battery_resume(struct acpi_device *device, int status);
 
 static struct acpi_driver acpi_battery_driver = {
 	.name = ACPI_BATTERY_DRIVER_NAME,
@@ -71,6 +72,7 @@
 	.ids = ACPI_BATTERY_HID,
 	.ops = {
 		.add = acpi_battery_add,
+		.resume = acpi_battery_resume,
 		.remove = acpi_battery_remove,
 		},
 };
@@ -753,6 +755,18 @@
 	return 0;
 }
 
+/* this is needed to learn about changes made in suspended state */
+static int acpi_battery_resume(struct acpi_device *device, int state)
+{
+	struct acpi_battery *battery;
+
+	if (!device)
+		return -EINVAL;
+
+	battery = device->driver_data;
+	return acpi_battery_check(battery);
+}
+
 static int __init acpi_battery_init(void)
 {
 	int result;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e5d7963..e6d4b08 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -45,206 +45,143 @@
 #define ACPI_EC_DRIVER_NAME		"ACPI Embedded Controller Driver"
 #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
 #define ACPI_EC_FILE_INFO		"info"
+
+/* EC status register */
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
 #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
 #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
 #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
-#define ACPI_EC_EVENT_OBF	0x01	/* Output buffer full */
-#define ACPI_EC_EVENT_IBE	0x02	/* Input buffer empty */
-#define ACPI_EC_DELAY		50	/* Wait 50ms max. during EC ops */
-#define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
-#define ACPI_EC_UDELAY         100	/* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT   1000	/* Wait 10ms max. during EC ops */
+
+/* EC commands */
 #define ACPI_EC_COMMAND_READ	0x80
 #define ACPI_EC_COMMAND_WRITE	0x81
 #define ACPI_EC_BURST_ENABLE	0x82
 #define ACPI_EC_BURST_DISABLE	0x83
 #define ACPI_EC_COMMAND_QUERY	0x84
-#define EC_POLL			0xFF
-#define EC_INTR			0x00
+
+/* EC events */
+enum {
+	ACPI_EC_EVENT_OBF_1 = 1,	/* Output buffer full */
+	ACPI_EC_EVENT_IBF_0,		/* Input buffer empty */
+};
+
+#define ACPI_EC_DELAY		50	/* Wait 50ms max. during EC ops */
+#define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY         100	/* Poll @ 100us increments */
+#define ACPI_EC_UDELAY_COUNT   1000	/* Wait 10ms max. during EC ops */
+
+enum {
+	EC_INTR = 1,	/* Output buffer full */
+	EC_POLL,	/* Input buffer empty */
+};
+
 static int acpi_ec_remove(struct acpi_device *device, int type);
 static int acpi_ec_start(struct acpi_device *device);
 static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_intr_add(struct acpi_device *device);
-static int acpi_ec_poll_add(struct acpi_device *device);
+static int acpi_ec_add(struct acpi_device *device);
 
 static struct acpi_driver acpi_ec_driver = {
 	.name = ACPI_EC_DRIVER_NAME,
 	.class = ACPI_EC_CLASS,
 	.ids = ACPI_EC_HID,
 	.ops = {
-		.add = acpi_ec_intr_add,
+		.add = acpi_ec_add,
 		.remove = acpi_ec_remove,
 		.start = acpi_ec_start,
 		.stop = acpi_ec_stop,
 		},
 };
-union acpi_ec {
-	struct {
-		u32 mode;
-		acpi_handle handle;
-		unsigned long uid;
-		unsigned long gpe_bit;
-		struct acpi_generic_address status_addr;
-		struct acpi_generic_address command_addr;
-		struct acpi_generic_address data_addr;
-		unsigned long global_lock;
-	} common;
 
-	struct {
-		u32 mode;
-		acpi_handle handle;
-		unsigned long uid;
-		unsigned long gpe_bit;
-		struct acpi_generic_address status_addr;
-		struct acpi_generic_address command_addr;
-		struct acpi_generic_address data_addr;
-		unsigned long global_lock;
-		unsigned int expect_event;
-		atomic_t leaving_burst;	/* 0 : No, 1 : Yes, 2: abort */
-		atomic_t pending_gpe;
-		struct semaphore sem;
-		wait_queue_head_t wait;
-	} intr;
-
-	struct {
-		u32 mode;
-		acpi_handle handle;
-		unsigned long uid;
-		unsigned long gpe_bit;
-		struct acpi_generic_address status_addr;
-		struct acpi_generic_address command_addr;
-		struct acpi_generic_address data_addr;
-		unsigned long global_lock;
-		struct semaphore sem;
-	} poll;
-};
-
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
-static void acpi_ec_gpe_poll_query(void *ec_cxt);
-static void acpi_ec_gpe_intr_query(void *ec_cxt);
-static u32 acpi_ec_gpe_poll_handler(void *data);
-static u32 acpi_ec_gpe_intr_handler(void *data);
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
-				u32 Level, void *context, void **retval);
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
-			      u32 Level, void *context, void **retval);
-
-static int __init acpi_ec_poll_get_real_ecdt(void);
-static int __init acpi_ec_intr_get_real_ecdt(void);
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
-static union acpi_ec *ec_ecdt;
+struct acpi_ec {
+	acpi_handle handle;
+	unsigned long uid;
+	unsigned long gpe_bit;
+	unsigned long command_addr;
+	unsigned long data_addr;
+	unsigned long global_lock;
+	struct semaphore sem;
+	unsigned int expect_event;
+	atomic_t leaving_burst;	/* 0 : No, 1 : Yes, 2: abort */
+	wait_queue_head_t wait;
+} *ec_ecdt;
 
 /* External interfaces use first EC only, so remember */
 static struct acpi_device *first_ec;
-static int acpi_ec_poll_mode = EC_INTR;
+static int acpi_ec_mode = EC_INTR;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
-static u32 acpi_ec_read_status(union acpi_ec *ec)
+static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
 {
-	u32 status = 0;
-
-	acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
-	return status;
+	return inb(ec->command_addr);
 }
 
-static int acpi_ec_wait(union acpi_ec *ec, u8 event)
+static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
-	if (acpi_ec_poll_mode)
-		return acpi_ec_poll_wait(ec, event);
-	else
-		return acpi_ec_intr_wait(ec, event);
+	return inb(ec->data_addr);
 }
 
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event)
+static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
-	u32 acpi_ec_status = 0;
-	u32 i = ACPI_EC_UDELAY_COUNT;
+	outb(command, ec->command_addr);
+}
 
-	if (!ec)
-		return -EINVAL;
+static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
+{
+	outb(data, ec->data_addr);
+}
 
-	/* Poll the EC status register waiting for the event to occur. */
+static int acpi_ec_check_status(u8 status, u8 event)
+{
 	switch (event) {
-	case ACPI_EC_EVENT_OBF:
-		do {
-			acpi_hw_low_level_read(8, &acpi_ec_status,
-					       &ec->common.status_addr);
-			if (acpi_ec_status & ACPI_EC_FLAG_OBF)
-				return 0;
-			udelay(ACPI_EC_UDELAY);
-		} while (--i > 0);
+	case ACPI_EC_EVENT_OBF_1:
+		if (status & ACPI_EC_FLAG_OBF)
+			return 1;
 		break;
-	case ACPI_EC_EVENT_IBE:
-		do {
-			acpi_hw_low_level_read(8, &acpi_ec_status,
-					       &ec->common.status_addr);
-			if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
-				return 0;
-			udelay(ACPI_EC_UDELAY);
-		} while (--i > 0);
+	case ACPI_EC_EVENT_IBF_0:
+		if (!(status & ACPI_EC_FLAG_IBF))
+			return 1;
 		break;
 	default:
-		return -EINVAL;
+		break;
 	}
 
-	return -ETIME;
+	return 0;
 }
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
+
+static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
 {
-	int result = 0;
+	int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
+	long time_left;
 
+	ec->expect_event = event;
+	if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+		ec->expect_event = 0;
+		return 0;
+	}
 
-	ec->intr.expect_event = event;
-	smp_mb();
-
-	switch (event) {
-	case ACPI_EC_EVENT_IBE:
-		if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
-			ec->intr.expect_event = 0;
+	do {
+		if (acpi_ec_mode == EC_POLL) {
+			udelay(ACPI_EC_UDELAY);
+		} else {
+			time_left = wait_event_timeout(ec->wait,
+				    !ec->expect_event,
+				    msecs_to_jiffies(ACPI_EC_DELAY));
+			if (time_left > 0) {
+				ec->expect_event = 0;
+				return 0;
+			}
+		}
+		if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+			ec->expect_event = 0;
 			return 0;
 		}
-		break;
-	default:
-		break;
-	}
+	} while (--i > 0);
 
-	result = wait_event_timeout(ec->intr.wait,
-				    !ec->intr.expect_event,
-				    msecs_to_jiffies(ACPI_EC_DELAY));
-
-	ec->intr.expect_event = 0;
-	smp_mb();
-
-	/*
-	 * Verify that the event in question has actually happened by
-	 * querying EC status. Do the check even if operation timed-out
-	 * to make sure that we did not miss interrupt.
-	 */
-	switch (event) {
-	case ACPI_EC_EVENT_OBF:
-		if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
-			return 0;
-		break;
-
-	case ACPI_EC_EVENT_IBE:
-		if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
-			return 0;
-		break;
-	}
+	ec->expect_event = 0;
 
 	return -ETIME;
 }
@@ -254,272 +191,150 @@
  * Note: samsung nv5000 doesn't work with ec burst mode.
  * http://bugzilla.kernel.org/show_bug.cgi?id=4980
  */
-int acpi_ec_enter_burst_mode(union acpi_ec *ec)
+int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
 {
-	u32 tmp = 0;
-	int status = 0;
+	u8 tmp = 0;
+	u8 status = 0;
 
 
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
-		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
 		if (status)
 			goto end;
-		acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE,
-					&ec->common.command_addr);
-		status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-		acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
+		acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
+		status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+		tmp = acpi_ec_read_data(ec);
 		if (tmp != 0x90) {	/* Burst ACK byte */
 			return -EINVAL;
 		}
 	}
 
-	atomic_set(&ec->intr.leaving_burst, 0);
+	atomic_set(&ec->leaving_burst, 0);
 	return 0;
-      end:
-	ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
+  end:
+	ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
 	return -1;
 }
 
-int acpi_ec_leave_burst_mode(union acpi_ec *ec)
+int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
 {
-	int status = 0;
+	u8 status = 0;
 
 
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
-		status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
+		status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
 		if(status)
 			goto end;
-		acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
-		acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
-	} 
-	atomic_set(&ec->intr.leaving_burst, 1);
+		acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
+		acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+	}
+	atomic_set(&ec->leaving_burst, 1);
 	return 0;
-end:
-	ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
+  end:
+	ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
 	return -1;
 }
 #endif /* ACPI_FUTURE_USAGE */
 
-static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
+					const u8 *wdata, unsigned wdata_len,
+					u8 *rdata, unsigned rdata_len)
 {
-	if (acpi_ec_poll_mode)
-		return acpi_ec_poll_read(ec, address, data);
-	else
-		return acpi_ec_intr_read(ec, address, data);
-}
-static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
-{
-	if (acpi_ec_poll_mode)
-		return acpi_ec_poll_write(ec, address, data);
-	else
-		return acpi_ec_intr_write(ec, address, data);
-}
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
-{
-	acpi_status status = AE_OK;
-	int result = 0;
-	u32 glk = 0;
+	int result;
 
+	acpi_ec_write_cmd(ec, command);
 
-	if (!ec || !data)
-		return -EINVAL;
-
-	*data = 0;
-
-	if (ec->common.global_lock) {
-		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
+	for (; wdata_len > 0; wdata_len --) {
+		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+		if (result)
+			return result;
+		acpi_ec_write_data(ec, *(wdata++));
 	}
 
-	if (down_interruptible(&ec->poll.sem)) {
-		result = -ERESTARTSYS;
-		goto end_nosem;
+	if (command == ACPI_EC_COMMAND_WRITE) {
+		result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+		if (result)
+			return result;
 	}
-	
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
-				&ec->common.command_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (result)
-		goto end;
 
-	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-	if (result)
-		goto end;
+	for (; rdata_len > 0; rdata_len --) {
+		result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+		if (result)
+			return result;
 
-	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+		*(rdata++) = acpi_ec_read_data(ec);
+	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
-			  *data, address));
-
-      end:
-	up(&ec->poll.sem);
-end_nosem:
-	if (ec->common.global_lock)
-		acpi_release_global_lock(glk);
-
-	return result;
+	return 0;
 }
 
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
+				const u8 *wdata, unsigned wdata_len,
+				u8 *rdata, unsigned rdata_len)
 {
-	int result = 0;
-	acpi_status status = AE_OK;
-	u32 glk = 0;
-
-
-	if (!ec)
-		return -EINVAL;
-
-	if (ec->common.global_lock) {
-		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-	}
-
-	if (down_interruptible(&ec->poll.sem)) {
-		result = -ERESTARTSYS;
-		goto end_nosem;
-	}
-	
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
-				&ec->common.command_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (result)
-		goto end;
-
-	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (result)
-		goto end;
-
-	acpi_hw_low_level_write(8, data, &ec->common.data_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (result)
-		goto end;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
-			  data, address));
-
-      end:
-	up(&ec->poll.sem);
-end_nosem:
-	if (ec->common.global_lock)
-		acpi_release_global_lock(glk);
-
-	return result;
-}
-
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
-{
-	int status = 0;
+	int status;
 	u32 glk;
 
-
-	if (!ec || !data)
+	if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
 		return -EINVAL;
 
-	*data = 0;
+        if (rdata)
+                memset(rdata, 0, rdata_len);
 
-	if (ec->common.global_lock) {
+	if (ec->global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status))
 			return -ENODEV;
 	}
+	down(&ec->sem);
 
-	WARN_ON(in_interrupt());
-	down(&ec->intr.sem);
-
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
 	if (status) {
 		printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
 		goto end;
 	}
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
-				&ec->common.command_addr);
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
-	}
 
-	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
-		goto end;
-	}
-	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
-			  *data, address));
+        status = acpi_ec_transaction_unlocked(ec, command,
+                                              wdata, wdata_len,
+                                              rdata, rdata_len);
 
-      end:
-	up(&ec->intr.sem);
+end:
+	up(&ec->sem);
 
-	if (ec->common.global_lock)
+	if (ec->global_lock)
 		acpi_release_global_lock(glk);
 
 	return status;
 }
 
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
 {
-	int status = 0;
-	u32 glk;
+	int result;
+	u8 d;
 
+	result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
+				     &address, 1, &d, 1);
+	*data = d;
+	return result;
+}
 
-	if (!ec)
-		return -EINVAL;
-
-	if (ec->common.global_lock) {
-		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-	}
-
-	WARN_ON(in_interrupt());
-	down(&ec->intr.sem);
-
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-	}
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
-				&ec->common.command_addr);
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-	}
-
-	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
-	}
-
-	acpi_hw_low_level_write(8, data, &ec->common.data_addr);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
-			  data, address));
-
-	up(&ec->intr.sem);
-
-	if (ec->common.global_lock)
-		acpi_release_global_lock(glk);
-
-	return status;
+static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
+{
+        u8 wdata[2] = { address, data };
+        return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
+				   wdata, 2, NULL, 0);
 }
 
 /*
  * Externally callable EC access functions. For now, assume 1 EC only
  */
-int ec_read(u8 addr, u8 * val)
+int ec_read(u8 addr, u8 *val)
 {
-	union acpi_ec *ec;
+	struct acpi_ec *ec;
 	int err;
-	u32 temp_data;
+	u8 temp_data;
 
 	if (!first_ec)
 		return -ENODEV;
@@ -539,7 +354,7 @@
 
 int ec_write(u8 addr, u8 val)
 {
-	union acpi_ec *ec;
+	struct acpi_ec *ec;
 	int err;
 
 	if (!first_ec)
@@ -554,255 +369,106 @@
 
 EXPORT_SYMBOL(ec_write);
 
-static int acpi_ec_query(union acpi_ec *ec, u32 * data)
+extern int ec_transaction(u8 command,
+                          const u8 *wdata, unsigned wdata_len,
+                          u8 *rdata, unsigned rdata_len)
 {
-	if (acpi_ec_poll_mode)
-		return acpi_ec_poll_query(ec, data);
-	else
-		return acpi_ec_intr_query(ec, data);
+	struct acpi_ec *ec;
+
+	if (!first_ec)
+		return -ENODEV;
+
+	ec = acpi_driver_data(first_ec);
+
+	return acpi_ec_transaction(ec, command, wdata,
+				   wdata_len, rdata, rdata_len);
 }
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
+
+EXPORT_SYMBOL(ec_transaction);
+
+static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
 {
-	int result = 0;
-	acpi_status status = AE_OK;
-	u32 glk = 0;
+	int result;
+        u8 d;
 
+        if (!ec || !data)
+                return -EINVAL;
 
-	if (!ec || !data)
-		return -EINVAL;
+        /*
+         * Query the EC to find out which _Qxx method we need to evaluate.
+         * Note that successful completion of the query causes the ACPI_EC_SCI
+         * bit to be cleared (and thus clearing the interrupt source).
+         */
 
-	*data = 0;
+        result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+        if (result)
+                return result;
 
-	if (ec->common.global_lock) {
-		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-	}
+        if (!d)
+                return -ENODATA;
 
-	/*
-	 * Query the EC to find out which _Qxx method we need to evaluate.
-	 * Note that successful completion of the query causes the ACPI_EC_SCI
-	 * bit to be cleared (and thus clearing the interrupt source).
-	 */
-	if (down_interruptible(&ec->poll.sem)) {
-		result = -ERESTARTSYS;
-		goto end_nosem;
-	}
-	
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
-				&ec->common.command_addr);
-	result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-	if (result)
-		goto end;
-
-	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-	if (!*data)
-		result = -ENODATA;
-
-      end:
-	up(&ec->poll.sem);
-end_nosem:
-	if (ec->common.global_lock)
-		acpi_release_global_lock(glk);
-
-	return result;
-}
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
-{
-	int status = 0;
-	u32 glk;
-
-
-	if (!ec || !data)
-		return -EINVAL;
-	*data = 0;
-
-	if (ec->common.global_lock) {
-		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
-		if (ACPI_FAILURE(status))
-			return -ENODEV;
-	}
-
-	down(&ec->intr.sem);
-
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
-		goto end;
-	}
-	/*
-	 * Query the EC to find out which _Qxx method we need to evaluate.
-	 * Note that successful completion of the query causes the ACPI_EC_SCI
-	 * bit to be cleared (and thus clearing the interrupt source).
-	 */
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
-				&ec->common.command_addr);
-	status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
-	if (status) {
-		printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
-		goto end;
-	}
-
-	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-	if (!*data)
-		status = -ENODATA;
-
-      end:
-	up(&ec->intr.sem);
-
-	if (ec->common.global_lock)
-		acpi_release_global_lock(glk);
-
-	return status;
+        *data = d;
+        return 0;
 }
 
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
 
-union acpi_ec_query_data {
+struct acpi_ec_query_data {
 	acpi_handle handle;
 	u8 data;
 };
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
-	if (acpi_ec_poll_mode)
-		acpi_ec_gpe_poll_query(ec_cxt);
-	else
-		acpi_ec_gpe_intr_query(ec_cxt);
-}
+	struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+	u8 value = 0;
+	static char object_name[8];
 
-static void acpi_ec_gpe_poll_query(void *ec_cxt)
-{
-	union acpi_ec *ec = (union acpi_ec *)ec_cxt;
-	u32 value = 0;
-	static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
-	const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
-		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-	};
-
-
-	if (!ec_cxt)
+	if (!ec)
 		goto end;
 
-	if (down_interruptible (&ec->poll.sem)) {
-		return;
-	}
-	acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
-	up(&ec->poll.sem);
+	value = acpi_ec_read_status(ec);
 
-	/* TBD: Implement asynch events!
-	 * NOTE: All we care about are EC-SCI's.  Other EC events are
-	 * handled via polling (yuck!).  This is because some systems
-	 * treat EC-SCIs as level (versus EDGE!) triggered, preventing
-	 *  a purely interrupt-driven approach (grumble, grumble).
-	 */
 	if (!(value & ACPI_EC_FLAG_SCI))
 		goto end;
 
 	if (acpi_ec_query(ec, &value))
 		goto end;
 
-	object_name[2] = hex[((value >> 4) & 0x0F)];
-	object_name[3] = hex[(value & 0x0F)];
+	snprintf(object_name, 8, "_Q%2.2X", value);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
 
-	acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
+	acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
 
       end:
-	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
-}
-static void acpi_ec_gpe_intr_query(void *ec_cxt)
-{
-	union acpi_ec *ec = (union acpi_ec *)ec_cxt;
-	u32 value;
-	int result = -ENODATA;
-	static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
-	const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
-		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-	};
-
-
-	if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
-		result = acpi_ec_query(ec, &value);
-
-	if (result)
-		goto end;
-
-	object_name[2] = hex[((value >> 4) & 0x0F)];
-	object_name[3] = hex[(value & 0x0F)];
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
-
-	acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
-      end:
-	atomic_dec(&ec->intr.pending_gpe);
-	return;
+	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
 {
-	if (acpi_ec_poll_mode)
-		return acpi_ec_gpe_poll_handler(data);
-	else
-		return acpi_ec_gpe_intr_handler(data);
-}
-static u32 acpi_ec_gpe_poll_handler(void *data)
-{
 	acpi_status status = AE_OK;
-	union acpi_ec *ec = (union acpi_ec *)data;
+	u8 value;
+	struct acpi_ec *ec = (struct acpi_ec *)data;
 
-	if (!ec)
-		return ACPI_INTERRUPT_NOT_HANDLED;
-
-	acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
-
-	status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
-
-	if (status == AE_OK)
-		return ACPI_INTERRUPT_HANDLED;
-	else
-		return ACPI_INTERRUPT_NOT_HANDLED;
-}
-static u32 acpi_ec_gpe_intr_handler(void *data)
-{
-	acpi_status status = AE_OK;
-	u32 value;
-	union acpi_ec *ec = (union acpi_ec *)data;
-
-	if (!ec)
-		return ACPI_INTERRUPT_NOT_HANDLED;
-
-	acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+	acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
 	value = acpi_ec_read_status(ec);
 
-	switch (ec->intr.expect_event) {
-	case ACPI_EC_EVENT_OBF:
-		if (!(value & ACPI_EC_FLAG_OBF))
-			break;
-		ec->intr.expect_event = 0;
-		wake_up(&ec->intr.wait);
-		break;
-	case ACPI_EC_EVENT_IBE:
-		if ((value & ACPI_EC_FLAG_IBF))
-			break;
-		ec->intr.expect_event = 0;
-		wake_up(&ec->intr.wait);
-		break;
-	default:
-		break;
+	if (acpi_ec_mode == EC_INTR) {
+		if (acpi_ec_check_status(value, ec->expect_event)) {
+			ec->expect_event = 0;
+			wake_up(&ec->wait);
+		}
 	}
 
 	if (value & ACPI_EC_FLAG_SCI) {
-		atomic_add(1, &ec->intr.pending_gpe);
-		status = acpi_os_execute(OSL_EC_BURST_HANDLER,
-						     acpi_ec_gpe_query, ec);
+		status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
 		return status == AE_OK ?
 		    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 	}
-	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
 	return status == AE_OK ?
 	    ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 }
@@ -833,7 +499,7 @@
 		      void *handler_context, void *region_context)
 {
 	int result = 0;
-	union acpi_ec *ec = NULL;
+	struct acpi_ec *ec = NULL;
 	u64 temp = *value;
 	acpi_integer f_v = 0;
 	int i = 0;
@@ -843,18 +509,16 @@
 		return AE_BAD_PARAMETER;
 
 	if (bit_width != 8 && acpi_strict) {
-		printk(KERN_WARNING PREFIX
-		       "acpi_ec_space_handler: bit_width should be 8\n");
 		return AE_BAD_PARAMETER;
 	}
 
-	ec = (union acpi_ec *)handler_context;
+	ec = (struct acpi_ec *)handler_context;
 
       next_byte:
 	switch (function) {
 	case ACPI_READ:
 		temp = 0;
-		result = acpi_ec_read(ec, (u8) address, (u32 *) & temp);
+		result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
 		break;
 	case ACPI_WRITE:
 		result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -905,20 +569,20 @@
 
 static int acpi_ec_read_info(struct seq_file *seq, void *offset)
 {
-	union acpi_ec *ec = (union acpi_ec *)seq->private;
+	struct acpi_ec *ec = (struct acpi_ec *)seq->private;
 
 
 	if (!ec)
 		goto end;
 
 	seq_printf(seq, "gpe bit:                 0x%02x\n",
-		   (u32) ec->common.gpe_bit);
+		   (u32) ec->gpe_bit);
 	seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-		   (u32) ec->common.status_addr.address,
-		   (u32) ec->common.data_addr.address);
+		   (u32) ec->command_addr,
+		   (u32) ec->data_addr);
 	seq_printf(seq, "use global lock:         %s\n",
-		   ec->common.global_lock ? "yes" : "no");
-	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+		   ec->global_lock ? "yes" : "no");
+	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 
       end:
 	return 0;
@@ -929,7 +593,7 @@
 	return single_open(file, acpi_ec_read_info, PDE(inode)->data);
 }
 
-static const struct file_operations acpi_ec_info_ops = {
+static struct file_operations acpi_ec_info_ops = {
 	.open = acpi_ec_info_open_fs,
 	.read = seq_read,
 	.llseek = seq_lseek,
@@ -978,31 +642,35 @@
                                Driver Interface
    -------------------------------------------------------------------------- */
 
-static int acpi_ec_poll_add(struct acpi_device *device)
+static int acpi_ec_add(struct acpi_device *device)
 {
 	int result = 0;
 	acpi_status status = AE_OK;
-	union acpi_ec *ec = NULL;
+	struct acpi_ec *ec = NULL;
 
 
 	if (!device)
 		return -EINVAL;
 
-	ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+	ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec)
 		return -ENOMEM;
-	memset(ec, 0, sizeof(union acpi_ec));
+	memset(ec, 0, sizeof(struct acpi_ec));
 
-	ec->common.handle = device->handle;
-	ec->common.uid = -1;
-	init_MUTEX(&ec->poll.sem);
+	ec->handle = device->handle;
+	ec->uid = -1;
+	init_MUTEX(&ec->sem);
+	if (acpi_ec_mode == EC_INTR) {
+		atomic_set(&ec->leaving_burst, 1);
+		init_waitqueue_head(&ec->wait);
+	}
 	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 	acpi_driver_data(device) = ec;
 
 	/* Use the global lock for all EC transactions? */
-	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
-			      &ec->common.global_lock);
+	acpi_evaluate_integer(ec->handle, "_GLK", NULL,
+			      &ec->global_lock);
 
 	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
 	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
@@ -1011,7 +679,7 @@
 						  ACPI_ADR_SPACE_EC,
 						  &acpi_ec_space_handler);
 
-		acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
 					&acpi_ec_gpe_handler);
 
 		kfree(ec_ecdt);
@@ -1020,10 +688,10 @@
 	/* Get GPE bit assignment (EC events). */
 	/* TODO: Add support for _GPE returning a package */
 	status =
-	    acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
-				  &ec->common.gpe_bit);
+	    acpi_evaluate_integer(ec->handle, "_GPE", NULL,
+				  &ec->gpe_bit);
 	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
+		ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -1032,84 +700,14 @@
 	if (result)
 		goto end;
 
-	printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n",
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
 	       acpi_device_name(device), acpi_device_bid(device),
-	       (u32) ec->common.gpe_bit);
+	       (u32) ec->gpe_bit));
 
 	if (!first_ec)
 		first_ec = device;
 
-      end:
-	if (result)
-		kfree(ec);
-
-	return result;
-}
-static int acpi_ec_intr_add(struct acpi_device *device)
-{
-	int result = 0;
-	acpi_status status = AE_OK;
-	union acpi_ec *ec = NULL;
-
-
-	if (!device)
-		return -EINVAL;
-
-	ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
-	if (!ec)
-		return -ENOMEM;
-	memset(ec, 0, sizeof(union acpi_ec));
-
-	ec->common.handle = device->handle;
-	ec->common.uid = -1;
-	atomic_set(&ec->intr.pending_gpe, 0);
-	atomic_set(&ec->intr.leaving_burst, 1);
-	init_MUTEX(&ec->intr.sem);
-	init_waitqueue_head(&ec->intr.wait);
-	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
-	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
-	acpi_driver_data(device) = ec;
-
-	/* Use the global lock for all EC transactions? */
-	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
-			      &ec->common.global_lock);
-
-	/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
-	   http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
-	if (ec_ecdt) {
-		acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
-						  ACPI_ADR_SPACE_EC,
-						  &acpi_ec_space_handler);
-
-		acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
-					&acpi_ec_gpe_handler);
-
-		kfree(ec_ecdt);
-	}
-
-	/* Get GPE bit assignment (EC events). */
-	/* TODO: Add support for _GPE returning a package */
-	status =
-	    acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
-				  &ec->common.gpe_bit);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
-		result = -ENODEV;
-		goto end;
-	}
-
-	result = acpi_ec_add_fs(device);
-	if (result)
-		goto end;
-
-	printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n",
-	       acpi_device_name(device), acpi_device_bid(device),
-	       (u32) ec->common.gpe_bit);
-
-	if (!first_ec)
-		first_ec = device;
-
-      end:
+  end:
 	if (result)
 		kfree(ec);
 
@@ -1118,7 +716,7 @@
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
-	union acpi_ec *ec = NULL;
+	struct acpi_ec *ec = NULL;
 
 
 	if (!device)
@@ -1136,8 +734,7 @@
 static acpi_status
 acpi_ec_io_ports(struct acpi_resource *resource, void *context)
 {
-	union acpi_ec *ec = (union acpi_ec *)context;
-	struct acpi_generic_address *addr;
+	struct acpi_ec *ec = (struct acpi_ec *)context;
 
 	if (resource->type != ACPI_RESOURCE_TYPE_IO) {
 		return AE_OK;
@@ -1148,26 +745,21 @@
 	 * the second address region returned is the status/command
 	 * port.
 	 */
-	if (ec->common.data_addr.register_bit_width == 0) {
-		addr = &ec->common.data_addr;
-	} else if (ec->common.command_addr.register_bit_width == 0) {
-		addr = &ec->common.command_addr;
+	if (ec->data_addr == 0) {
+		ec->data_addr = resource->data.io.minimum;
+	} else if (ec->command_addr == 0) {
+		ec->command_addr = resource->data.io.minimum;
 	} else {
 		return AE_CTRL_TERMINATE;
 	}
 
-	addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
-	addr->register_bit_width = 8;
-	addr->register_bit_offset = 0;
-	addr->address = resource->data.io.minimum;
-
 	return AE_OK;
 }
 
 static int acpi_ec_start(struct acpi_device *device)
 {
 	acpi_status status = AE_OK;
-	union acpi_ec *ec = NULL;
+	struct acpi_ec *ec = NULL;
 
 
 	if (!device)
@@ -1181,39 +773,35 @@
 	/*
 	 * Get I/O port addresses. Convert to GAS format.
 	 */
-	status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
+	status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
 				     acpi_ec_io_ports, ec);
-	if (ACPI_FAILURE(status)
-	    || ec->common.command_addr.register_bit_width == 0) {
-		printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
+	if (ACPI_FAILURE(status) || ec->command_addr == 0) {
+		ACPI_EXCEPTION((AE_INFO, status,
+				"Error getting I/O port addresses"));
 		return -ENODEV;
 	}
 
-	ec->common.status_addr = ec->common.command_addr;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
-			  (u32) ec->common.gpe_bit,
-			  (u32) ec->common.command_addr.address,
-			  (u32) ec->common.data_addr.address));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+			  ec->gpe_bit, ec->command_addr, ec->data_addr));
 
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
 					  ACPI_GPE_EDGE_TRIGGERED,
 					  &acpi_ec_gpe_handler, ec);
 	if (ACPI_FAILURE(status)) {
 		return -ENODEV;
 	}
-	acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+	acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
 
-	status = acpi_install_address_space_handler(ec->common.handle,
+	status = acpi_install_address_space_handler(ec->handle,
 						    ACPI_ADR_SPACE_EC,
 						    &acpi_ec_space_handler,
 						    &acpi_ec_space_setup, ec);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec->gpe_bit,
 					&acpi_ec_gpe_handler);
 		return -ENODEV;
 	}
@@ -1224,7 +812,7 @@
 static int acpi_ec_stop(struct acpi_device *device, int type)
 {
 	acpi_status status = AE_OK;
-	union acpi_ec *ec = NULL;
+	struct acpi_ec *ec = NULL;
 
 
 	if (!device)
@@ -1232,14 +820,14 @@
 
 	ec = acpi_driver_data(device);
 
-	status = acpi_remove_address_space_handler(ec->common.handle,
+	status = acpi_remove_address_space_handler(ec->handle,
 						   ACPI_ADR_SPACE_EC,
 						   &acpi_ec_space_handler);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
 	status =
-	    acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+	    acpi_remove_gpe_handler(NULL, ec->gpe_bit,
 				    &acpi_ec_gpe_handler);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
@@ -1251,76 +839,30 @@
 acpi_fake_ecdt_callback(acpi_handle handle,
 			u32 Level, void *context, void **retval)
 {
-
-	if (acpi_ec_poll_mode)
-		return acpi_fake_ecdt_poll_callback(handle,
-						       Level, context, retval);
-	else
-		return acpi_fake_ecdt_intr_callback(handle,
-						     Level, context, retval);
-}
-
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
-				u32 Level, void *context, void **retval)
-{
 	acpi_status status;
 
+	init_MUTEX(&ec_ecdt->sem);
+	if (acpi_ec_mode == EC_INTR) {
+		init_waitqueue_head(&ec_ecdt->wait);
+	}
 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
 				     acpi_ec_io_ports, ec_ecdt);
 	if (ACPI_FAILURE(status))
 		return status;
-	ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
 
-	ec_ecdt->common.uid = -1;
-	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
+	ec_ecdt->uid = -1;
+	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
 
 	status =
 	    acpi_evaluate_integer(handle, "_GPE", NULL,
-				  &ec_ecdt->common.gpe_bit);
+				  &ec_ecdt->gpe_bit);
 	if (ACPI_FAILURE(status))
 		return status;
-	init_MUTEX(&ec_ecdt->poll.sem);
-	ec_ecdt->common.global_lock = TRUE;
-	ec_ecdt->common.handle = handle;
+	ec_ecdt->global_lock = TRUE;
+	ec_ecdt->handle = handle;
 
-	printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
-	       (u32) ec_ecdt->common.gpe_bit,
-	       (u32) ec_ecdt->common.command_addr.address,
-	       (u32) ec_ecdt->common.data_addr.address);
-
-	return AE_CTRL_TERMINATE;
-}
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
-			      u32 Level, void *context, void **retval)
-{
-	acpi_status status;
-
-	init_MUTEX(&ec_ecdt->intr.sem);
-	init_waitqueue_head(&ec_ecdt->intr.wait);
-	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-				     acpi_ec_io_ports, ec_ecdt);
-	if (ACPI_FAILURE(status))
-		return status;
-	ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
-
-	ec_ecdt->common.uid = -1;
-	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
-
-	status =
-	    acpi_evaluate_integer(handle, "_GPE", NULL,
-				  &ec_ecdt->common.gpe_bit);
-	if (ACPI_FAILURE(status))
-		return status;
-	ec_ecdt->common.global_lock = TRUE;
-	ec_ecdt->common.handle = handle;
-
-	printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
-	       (u32) ec_ecdt->common.gpe_bit,
-	       (u32) ec_ecdt->common.command_addr.address,
-	       (u32) ec_ecdt->common.data_addr.address);
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+	       ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr));
 
 	return AE_CTRL_TERMINATE;
 }
@@ -1340,14 +882,14 @@
 	acpi_status status;
 	int ret = 0;
 
-	printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
 
-	ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt) {
 		ret = -ENOMEM;
 		goto error;
 	}
-	memset(ec_ecdt, 0, sizeof(union acpi_ec));
+	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
 	status = acpi_get_devices(ACPI_EC_HID,
 				  acpi_fake_ecdt_callback, NULL, NULL);
@@ -1355,24 +897,16 @@
 		kfree(ec_ecdt);
 		ec_ecdt = NULL;
 		ret = -ENODEV;
+		ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
 		goto error;
 	}
 	return 0;
-      error:
-	printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
+  error:
 	return ret;
 }
 
 static int __init acpi_ec_get_real_ecdt(void)
 {
-	if (acpi_ec_poll_mode)
-		return acpi_ec_poll_get_real_ecdt();
-	else
-		return acpi_ec_intr_get_real_ecdt();
-}
-
-static int __init acpi_ec_poll_get_real_ecdt(void)
-{
 	acpi_status status;
 	struct acpi_table_ecdt *ecdt_ptr;
 
@@ -1382,80 +916,36 @@
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	printk(KERN_INFO PREFIX "Found ECDT\n");
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
 
 	/*
 	 * Generate a temporary ec context to use until the namespace is scanned
 	 */
-	ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt)
 		return -ENOMEM;
-	memset(ec_ecdt, 0, sizeof(union acpi_ec));
+	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
 
-	ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
-	ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
-	ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
-	ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
-	init_MUTEX(&ec_ecdt->poll.sem);
+	init_MUTEX(&ec_ecdt->sem);
+	if (acpi_ec_mode == EC_INTR) {
+		init_waitqueue_head(&ec_ecdt->wait);
+	}
+	ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
+	ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
+	ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
 	/* use the GL just to be safe */
-	ec_ecdt->common.global_lock = TRUE;
-	ec_ecdt->common.uid = ecdt_ptr->uid;
+	ec_ecdt->global_lock = TRUE;
+	ec_ecdt->uid = ecdt_ptr->uid;
 
 	status =
-	    acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
+	    acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
 
 	return 0;
-      error:
-	printk(KERN_ERR PREFIX "Could not use ECDT\n");
-	kfree(ec_ecdt);
-	ec_ecdt = NULL;
-
-	return -ENODEV;
-}
-
-static int __init acpi_ec_intr_get_real_ecdt(void)
-{
-	acpi_status status;
-	struct acpi_table_ecdt *ecdt_ptr;
-
-	status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
-					 (struct acpi_table_header **)
-					 &ecdt_ptr);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
-
-	printk(KERN_INFO PREFIX "Found ECDT\n");
-
-	/*
-	 * Generate a temporary ec context to use until the namespace is scanned
-	 */
-	ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
-	if (!ec_ecdt)
-		return -ENOMEM;
-	memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
-	init_MUTEX(&ec_ecdt->intr.sem);
-	init_waitqueue_head(&ec_ecdt->intr.wait);
-	ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
-	ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
-	ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
-	ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
-	/* use the GL just to be safe */
-	ec_ecdt->common.global_lock = TRUE;
-	ec_ecdt->common.uid = ecdt_ptr->uid;
-
-	status =
-	    acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
-	if (ACPI_FAILURE(status)) {
-		goto error;
-	}
-
-	return 0;
-      error:
-	printk(KERN_ERR PREFIX "Could not use ECDT\n");
+  error:
+	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
 	kfree(ec_ecdt);
 	ec_ecdt = NULL;
 
@@ -1480,14 +970,14 @@
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
 					  ACPI_GPE_EDGE_TRIGGERED,
 					  &acpi_ec_gpe_handler, ec_ecdt);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
-	acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR);
+	acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+	acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
 
 	status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
 						    ACPI_ADR_SPACE_EC,
@@ -1495,7 +985,7 @@
 						    &acpi_ec_space_setup,
 						    ec_ecdt);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
 					&acpi_ec_gpe_handler);
 		goto error;
 	}
@@ -1503,7 +993,7 @@
 	return 0;
 
       error:
-	printk(KERN_ERR PREFIX "Could not use ECDT\n");
+	ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
 	kfree(ec_ecdt);
 	ec_ecdt = NULL;
 
@@ -1562,13 +1052,13 @@
 		return 0;
 
 	if (intr) {
-		acpi_ec_poll_mode = EC_INTR;
-		acpi_ec_driver.ops.add = acpi_ec_intr_add;
+		acpi_ec_mode = EC_INTR;
 	} else {
-		acpi_ec_poll_mode = EC_POLL;
-		acpi_ec_driver.ops.add = acpi_ec_poll_add;
+		acpi_ec_mode = EC_POLL;
 	}
-	printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
+	acpi_ec_driver.ops.add = acpi_ec_add;
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
+
 	return 1;
 }
 
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 5b3c7a8..203d135 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -225,13 +225,12 @@
 				if (!
 				    (ACPI_STRNCMP
 				     (object_hID.value, PCI_ROOT_HID_STRING,
-				      sizeof(PCI_ROOT_HID_STRING))
-				     ||
-				     !(ACPI_STRNCMP
-				       (object_hID.value,
-					PCI_EXPRESS_ROOT_HID_STRING,
-					sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
-				{
+				      sizeof(PCI_ROOT_HID_STRING)))
+				    ||
+				    !(ACPI_STRNCMP
+				      (object_hID.value,
+				       PCI_EXPRESS_ROOT_HID_STRING,
+				       sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
 
 					/* Install a handler for this PCI root bridge */
 
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 15fc124..003a987 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -1702,13 +1702,11 @@
 	 .name = "brightness",
 	 .read = brightness_read,
 	 .write = brightness_write,
-	 .experimental = 1,
 	 },
 	{
 	 .name = "volume",
 	 .read = volume_read,
 	 .write = volume_write,
-	 .experimental = 1,
 	 },
 	{
 	 .name = "fan",
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 0a395fc..429a39d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -219,6 +219,23 @@
 
 static atomic_t c3_cpu_count;
 
+/* Common C-state entry for C2, C3, .. */
+static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
+{
+	if (cstate->space_id == ACPI_CSTATE_FFH) {
+		/* Call into architectural FFH based C-state */
+		acpi_processor_ffh_cstate_enter(cstate);
+	} else {
+		int unused;
+		/* IO port based C-state */
+		inb(cstate->address);
+		/* Dummy wait op - must do something useless after P_LVL2 read
+		   because chipsets cannot guarantee that STPCLK# signal
+		   gets asserted in time to freeze execution properly. */
+		unused = inl(acpi_fadt.xpm_tmr_blk.address);
+	}
+}
+
 static void acpi_processor_idle(void)
 {
 	struct acpi_processor *pr = NULL;
@@ -361,11 +378,7 @@
 		/* Get start time (ticks) */
 		t1 = inl(acpi_fadt.xpm_tmr_blk.address);
 		/* Invoke C2 */
-		inb(cx->address);
-		/* Dummy wait op - must do something useless after P_LVL2 read
-		   because chipsets cannot guarantee that STPCLK# signal
-		   gets asserted in time to freeze execution properly. */
-		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 
@@ -401,9 +414,7 @@
 		/* Get start time (ticks) */
 		t1 = inl(acpi_fadt.xpm_tmr_blk.address);
 		/* Invoke C3 */
-		inb(cx->address);
-		/* Dummy wait op (see above) */
-		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_fadt.xpm_tmr_blk.address);
 		if (pr->flags.bm_check) {
@@ -628,20 +639,16 @@
 	return 0;
 }
 
-static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
+static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
 {
-
-	/* Zero initialize all the C-states info. */
-	memset(pr->power.states, 0, sizeof(pr->power.states));
-
-	/* set the first C-State to C1 */
-	pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
-
-	/* the C0 state only exists as a filler in our array,
-	 * and all processors need to support C1 */
+	if (!pr->power.states[ACPI_STATE_C1].valid) {
+		/* set the first C-State to C1 */
+		/* all processors need to support C1 */
+		pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+		pr->power.states[ACPI_STATE_C1].valid = 1;
+	}
+	/* the C0 state only exists as a filler in our array */
 	pr->power.states[ACPI_STATE_C0].valid = 1;
-	pr->power.states[ACPI_STATE_C1].valid = 1;
-
 	return 0;
 }
 
@@ -658,12 +665,7 @@
 	if (nocst)
 		return -ENODEV;
 
-	current_count = 1;
-
-	/* Zero initialize C2 onwards and prepare for fresh CST lookup */
-	for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
-		memset(&(pr->power.states[i]), 0, 
-				sizeof(struct acpi_processor_cx));
+	current_count = 0;
 
 	status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
@@ -718,22 +720,39 @@
 		    (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
 			continue;
 
-		cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
-		    0 : reg->address;
-
 		/* There should be an easy way to extract an integer... */
 		obj = (union acpi_object *)&(element->package.elements[1]);
 		if (obj->type != ACPI_TYPE_INTEGER)
 			continue;
 
 		cx.type = obj->integer.value;
+		/*
+		 * Some buggy BIOSes won't list C1 in _CST -
+		 * Let acpi_processor_get_power_info_default() handle them later
+		 */
+		if (i == 1 && cx.type != ACPI_STATE_C1)
+			current_count++;
 
-		if ((cx.type != ACPI_STATE_C1) &&
-		    (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
-			continue;
+		cx.address = reg->address;
+		cx.index = current_count + 1;
 
-		if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
-			continue;
+		cx.space_id = ACPI_CSTATE_SYSTEMIO;
+		if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+			if (acpi_processor_ffh_cstate_probe
+					(pr->id, &cx, reg) == 0) {
+				cx.space_id = ACPI_CSTATE_FFH;
+			} else if (cx.type != ACPI_STATE_C1) {
+				/*
+				 * C1 is a special case where FIXED_HARDWARE
+				 * can be handled in non-MWAIT way as well.
+				 * In that case, save this _CST entry info.
+				 * That is, we retain space_id of SYSTEM_IO for
+				 * halt based C1.
+				 * Otherwise, ignore this info and continue.
+				 */
+				continue;
+			}
+		}
 
 		obj = (union acpi_object *)&(element->package.elements[2]);
 		if (obj->type != ACPI_TYPE_INTEGER)
@@ -938,12 +957,18 @@
 	/* NOTE: the idle thread may not be running while calling
 	 * this function */
 
-	/* Adding C1 state */
-	acpi_processor_get_power_info_default_c1(pr);
+	/* Zero initialize all the C-states info. */
+	memset(pr->power.states, 0, sizeof(pr->power.states));
+
 	result = acpi_processor_get_power_info_cst(pr);
 	if (result == -ENODEV)
 		acpi_processor_get_power_info_fadt(pr);
 
+	if (result)
+		return result;
+
+	acpi_processor_get_power_info_default(pr);
+
 	pr->power.count = acpi_processor_power_verify(pr);
 
 	/*
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 62bef0b..8908a97 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -98,11 +98,11 @@
 static int update_time = UPDATE_TIME;
 static int update_time2 = UPDATE_TIME2;
 
-module_param(capacity_mode, int, CAPACITY_UNIT);
-module_param(update_mode, int, UPDATE_MODE);
-module_param(update_info_mode, int, UPDATE_INFO_MODE);
-module_param(update_time, int, UPDATE_TIME);
-module_param(update_time2, int, UPDATE_TIME2);
+module_param(capacity_mode, int, 0);
+module_param(update_mode, int, 0);
+module_param(update_info_mode, int, 0);
+module_param(update_time, int, 0);
+module_param(update_time2, int, 0);
 
 static int acpi_sbs_add(struct acpi_device *device);
 static int acpi_sbs_remove(struct acpi_device *device, int type);
@@ -1685,10 +1685,16 @@
 
 int acpi_sbs_remove(struct acpi_device *device, int type)
 {
-	struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
+	struct acpi_sbs *sbs = NULL;
 	int id;
 
-	if (!device || !sbs) {
+	if (!device) {
+		return -EINVAL;
+	}
+
+	sbs = (struct acpi_sbs *)acpi_driver_data(device);
+
+	if (!sbs) {
 		return -EINVAL;
 	}
 
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3df0e7a..fa7acc2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -57,4 +57,23 @@
           To compile this driver as a module, choose M here: the module will
 	  be called tifm_7xx1.
 
+config MSI_LAPTOP
+        tristate "MSI Laptop Extras"
+        depends on X86
+        depends on ACPI_EC
+        depends on BACKLIGHT_CLASS_DEVICE
+        ---help---
+	  This is a driver for laptops built by MSI (MICRO-STAR
+	  INTERNATIONAL):
+
+	  MSI MegaBook S270 (MS-1013)
+	  Cytron/TCM/Medion/Tchibo MD96100/SAM2000
+
+	  It adds support for Bluetooth, WLAN and LCD brightness control.
+
+	  More information about this driver is available at
+	  <http://0pointer.de/lennart/tchibo.html>.
+
+	  If you have an MSI S270 laptop, say Y or M here.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index d65ece7..9a91c1e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
+obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
new file mode 100644
index 0000000..fdb7153
--- /dev/null
+++ b/drivers/misc/msi-laptop.c
@@ -0,0 +1,395 @@
+/*-*-linux-c-*-*/
+
+/*
+  Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) de>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+  02110-1301, USA.
+ */
+
+/*
+ * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
+ * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
+ *
+ * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
+ *
+ *   lcd_level - Screen brightness: contains a single integer in the
+ *   range 0..8. (rw)
+ *
+ *   auto_brightness - Enable automatic brightness control: contains
+ *   either 0 or 1. If set to 1 the hardware adjusts the screen
+ *   brightness automatically when the power cord is
+ *   plugged/unplugged. (rw)
+ *
+ *   wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
+ *
+ *   bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
+ *   Please note that this file is constantly 0 if no Bluetooth
+ *   hardware is available. (ro)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control subsystem and is
+ * available to userspace under /sys/class/backlight/msi-laptop-bl/.
+ *
+ * This driver might work on other laptops produced by MSI. If you
+ * want to try it you can pass force=1 as argument to the module which
+ * will force it to load even when the DMI data doesn't identify the
+ * laptop as MSI S270. YMMV.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/autoconf.h>
+
+#define MSI_DRIVER_VERSION "0.5"
+
+#define MSI_LCD_LEVEL_MAX 9
+
+#define MSI_EC_COMMAND_WIRELESS 0x10
+#define MSI_EC_COMMAND_LCD_LEVEL 0x11
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int auto_brightness;
+module_param(auto_brightness, int, 0);
+MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
+
+/* Hardware access */
+
+static int set_lcd_level(int level)
+{
+	u8 buf[2];
+
+	if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
+		return -EINVAL;
+
+	buf[0] = 0x80;
+	buf[1] = (u8) (level*31);
+
+	return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
+}
+
+static int get_lcd_level(void)
+{
+	u8 wdata = 0, rdata;
+	int result;
+
+	result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+	if (result < 0)
+		return result;
+
+	return (int) rdata / 31;
+}
+
+static int get_auto_brightness(void)
+{
+	u8 wdata = 4, rdata;
+	int result;
+
+	result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+	if (result < 0)
+		return result;
+
+	return !!(rdata & 8);
+}
+
+static int set_auto_brightness(int enable)
+{
+	u8 wdata[2], rdata;
+	int result;
+
+	wdata[0] = 4;
+
+	result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
+	if (result < 0)
+		return result;
+
+	wdata[0] = 0x84;
+	wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
+
+	return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
+}
+
+static int get_wireless_state(int *wlan, int *bluetooth)
+{
+	u8 wdata = 0, rdata;
+	int result;
+
+	result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
+	if (result < 0)
+		return -1;
+
+	if (wlan)
+		*wlan = !!(rdata & 8);
+
+	if (bluetooth)
+		*bluetooth = !!(rdata & 128);
+
+	return 0;
+}
+
+/* Backlight device stuff */
+
+static int bl_get_brightness(struct backlight_device *b)
+{
+	return get_lcd_level();
+}
+
+
+static int bl_update_status(struct backlight_device *b)
+{
+	return set_lcd_level(b->props->brightness);
+}
+
+static struct backlight_properties msibl_props = {
+	.owner		= THIS_MODULE,
+	.get_brightness = bl_get_brightness,
+	.update_status  = bl_update_status,
+	.max_brightness = MSI_LCD_LEVEL_MAX-1,
+};
+
+static struct backlight_device *msibl_device;
+
+/* Platform device */
+
+static ssize_t show_wlan(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+
+	int ret, enabled;
+
+	ret = get_wireless_state(&enabled, NULL);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_bluetooth(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+
+	int ret, enabled;
+
+	ret = get_wireless_state(NULL, &enabled);
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_lcd_level(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+
+	int ret;
+
+	ret = get_lcd_level();
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_lcd_level(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+
+	int level, ret;
+
+	if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
+		return -EINVAL;
+
+	ret = set_lcd_level(level);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t show_auto_brightness(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+
+	int ret;
+
+	ret = get_auto_brightness();
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_auto_brightness(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+
+	int enable, ret;
+
+	if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
+		return -EINVAL;
+
+	ret = set_auto_brightness(enable);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
+static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
+static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
+static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+
+static struct attribute *msipf_attributes[] = {
+	&dev_attr_lcd_level.attr,
+	&dev_attr_auto_brightness.attr,
+	&dev_attr_bluetooth.attr,
+	&dev_attr_wlan.attr,
+	NULL
+};
+
+static struct attribute_group msipf_attribute_group = {
+	.attrs = msipf_attributes
+};
+
+static struct platform_driver msipf_driver = {
+	.driver = {
+		.name = "msi-laptop-pf",
+		.owner = THIS_MODULE,
+	}
+};
+
+static struct platform_device *msipf_device;
+
+/* Initialization */
+
+static struct dmi_system_id __initdata msi_dmi_table[] = {
+	{
+		.ident = "MSI S270",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
+		}
+	},
+	{
+		.ident = "Medion MD96100",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
+		}
+	},
+	{ }
+};
+
+
+static int __init msi_init(void)
+{
+	int ret;
+
+	if (acpi_disabled)
+		return -ENODEV;
+
+	if (!force && !dmi_check_system(msi_dmi_table))
+		return -ENODEV;
+
+	if (auto_brightness < 0 || auto_brightness > 2)
+		return -EINVAL;
+
+	/* Register backlight stuff */
+
+	msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
+	if (IS_ERR(msibl_device))
+		return PTR_ERR(msibl_device);
+
+	ret = platform_driver_register(&msipf_driver);
+	if (ret)
+		goto fail_backlight;
+
+	/* Register platform stuff */
+
+	msipf_device = platform_device_alloc("msi-laptop-pf", -1);
+	if (!msipf_device) {
+		ret = -ENOMEM;
+		goto fail_platform_driver;
+	}
+
+	ret = platform_device_add(msipf_device);
+	if (ret)
+		goto fail_platform_device1;
+
+	ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+	if (ret)
+		goto fail_platform_device2;
+
+	/* Disable automatic brightness control by default because
+	 * this module was probably loaded to do brightness control in
+	 * software. */
+
+	if (auto_brightness != 2)
+		set_auto_brightness(auto_brightness);
+
+	printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
+
+	return 0;
+
+fail_platform_device2:
+
+	platform_device_del(msipf_device);
+
+fail_platform_device1:
+
+	platform_device_put(msipf_device);
+
+fail_platform_driver:
+
+	platform_driver_unregister(&msipf_driver);
+
+fail_backlight:
+
+	backlight_device_unregister(msibl_device);
+
+	return ret;
+}
+
+static void __exit msi_cleanup(void)
+{
+
+	sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+	platform_device_unregister(msipf_device);
+	platform_driver_unregister(&msipf_driver);
+	backlight_device_unregister(msibl_device);
+
+	/* Enable automatic brightness control again */
+	if (auto_brightness != 2)
+		set_auto_brightness(1);
+
+	printk(KERN_INFO "msi-laptop: driver unloaded.\n");
+}
+
+module_init(msi_init);
+module_exit(msi_cleanup);
+
+MODULE_AUTHOR("Lennart Poettering");
+MODULE_DESCRIPTION("MSI Laptop Support");
+MODULE_VERSION(MSI_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
index c5472be..e72bfdd 100644
--- a/include/acpi/pdc_intel.h
+++ b/include/acpi/pdc_intel.h
@@ -13,6 +13,7 @@
 #define ACPI_PDC_SMP_C_SWCOORD		(0x0040)
 #define ACPI_PDC_SMP_T_SWCOORD		(0x0080)
 #define ACPI_PDC_C_C1_FFH		(0x0100)
+#define ACPI_PDC_C_C2C3_FFH		(0x0200)
 
 #define ACPI_PDC_EST_CAPABILITY_SMP	(ACPI_PDC_SMP_C1PT | \
 					 ACPI_PDC_C_C1_HALT | \
@@ -23,8 +24,10 @@
 					 ACPI_PDC_SMP_P_SWCOORD | \
 					 ACPI_PDC_P_FFH)
 
-#define ACPI_PDC_C_CAPABILITY_SMP	(ACPI_PDC_SMP_C2C3 | \
-					 ACPI_PDC_SMP_C1PT | \
-					 ACPI_PDC_C_C1_HALT)
+#define ACPI_PDC_C_CAPABILITY_SMP	(ACPI_PDC_SMP_C2C3  | \
+					 ACPI_PDC_SMP_C1PT  | \
+					 ACPI_PDC_C_C1_HALT | \
+					 ACPI_PDC_C_C1_FFH  | \
+					 ACPI_PDC_C_C2C3_FFH)
 
 #endif				/* __PDC_INTEL_H__ */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 9dd5b75..7798d2a 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -29,6 +29,9 @@
 #define DOMAIN_COORD_TYPE_SW_ANY	0xfd
 #define DOMAIN_COORD_TYPE_HW_ALL	0xfe
 
+#define ACPI_CSTATE_SYSTEMIO	(0)
+#define ACPI_CSTATE_FFH		(1)
+
 /* Power Management */
 
 struct acpi_processor_cx;
@@ -58,6 +61,8 @@
 	u8 valid;
 	u8 type;
 	u32 address;
+	u8 space_id;
+	u8 index;
 	u32 latency;
 	u32 latency_ticks;
 	u32 power;
@@ -206,6 +211,9 @@
 #ifdef ARCH_HAS_POWER_INIT
 void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
 					unsigned int cpu);
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+		struct acpi_processor_cx *cx, struct acpi_power_register *reg);
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
 #else
 static inline void acpi_processor_power_init_bm_check(struct
 						      acpi_processor_flags
@@ -214,6 +222,16 @@
 	flags->bm_check = 1;
 	return;
 }
+static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+		struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+	return -1;
+}
+static inline void acpi_processor_ffh_cstate_enter(
+		struct acpi_processor_cx *cstate)
+{
+	return;
+}
 #endif
 
 /* in processor_perflib.c */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 2277127..e0ddca9 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -306,6 +306,8 @@
 		: :"a" (eax), "c" (ecx));
 }
 
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
 /* from system description table in BIOS.  Mostly for MCA use, but
 others may find it useful. */
 extern unsigned int machine_id;
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index de9c314..cef17e0 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -475,6 +475,8 @@
 		: :"a" (eax), "c" (ecx));
 }
 
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
 #define stack_current() \
 ({								\
 	struct thread_info *ti;					\
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 88b5dfd..2b0c955 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -494,6 +494,9 @@
 
 extern int ec_read(u8 addr, u8 *val);
 extern int ec_write(u8 addr, u8 val);
+extern int ec_transaction(u8 command,
+                          const u8 *wdata, unsigned wdata_len,
+                          u8 *rdata, unsigned rdata_len);
 
 #endif /*CONFIG_ACPI_EC*/